diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 030209c47dea..95f91b2a78be 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -1,14 +1,7 @@ module.exports = { root: true, extends: ['plugin:prettier/recommended'], - plugins: [ - '@nx', - 'prefer-arrow', - 'import', - 'simple-import-sort', - 'unused-imports', - 'unicorn', - ], + plugins: ['@nx', 'prefer-arrow', 'import', 'unused-imports', 'unicorn'], rules: { 'func-style': ['error', 'declaration', { allowArrowFunctions: true }], 'no-console': ['warn', { allow: ['group', 'groupCollapsed', 'groupEnd'] }], @@ -53,26 +46,6 @@ module.exports = { }, ], - 'simple-import-sort/imports': [ - 'error', - { - groups: [ - // Packages - ['^react', '^@?\\w'], - // Internal modules - ['^(@|~|src|@ui)(/.*|$)'], - // Side effect imports - ['^\\u0000'], - // Relative imports - ['^\\.\\.(?!/?$)', '^\\.\\./?$'], - ['^\\./(?=.*/)(?!/?$)', '^\\.(?!/?$)', '^\\./?$'], - // CSS imports - ['^.+\\.?(css)$'], - ], - }, - ], - 'simple-import-sort/exports': 'error', - 'unused-imports/no-unused-imports': 'warn', 'unused-imports/no-unused-vars': [ 'warn', diff --git a/.github/workflows/ci-front.yaml b/.github/workflows/ci-front.yaml index 265bf6d03a0d..aa6955723796 100644 --- a/.github/workflows/ci-front.yaml +++ b/.github/workflows/ci-front.yaml @@ -39,7 +39,7 @@ jobs: - name: Front / Write .env run: npx nx reset:env twenty-front - name: Front / Build storybook - run: npx nx storybook:build twenty-front --configuration=test + run: npx nx storybook:build twenty-front front-sb-test: runs-on: ci-8-cores needs: front-sb-build @@ -64,7 +64,7 @@ jobs: - name: Front / Write .env run: npx nx reset:env twenty-front - name: Run storybook tests - run: npx nx storybook:static:test twenty-front --configuration=${{ matrix.storybook_scope }} + run: npx nx storybook:serve-and-test:static twenty-front --configuration=${{ matrix.storybook_scope }} front-sb-test-performance: runs-on: ci-8-cores env: @@ -80,7 +80,7 @@ jobs: - name: Front / Write .env run: npx nx reset:env twenty-front - name: Run storybook tests - run: npx nx storybook:performance:test twenty-front + run: npx nx storybook:serve-and-test:static:performance twenty-front front-chromatic-deployment: if: contains(github.event.pull_request.labels.*.name, 'run-chromatic') || github.event_name == 'push' needs: front-sb-build diff --git a/.vscode/settings.json b/.vscode/settings.json index c6ff47f129ec..d63c92973cfc 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,21 +5,24 @@ "editor.formatOnSave": false, "editor.codeActionsOnSave": { "source.fixAll.eslint": "explicit", - "source.addMissingImports": "always" + "source.addMissingImports": "always", + "source.organizeImports": "always" } }, "[javascript]": { "editor.formatOnSave": false, "editor.codeActionsOnSave": { "source.fixAll.eslint": "explicit", - "source.addMissingImports": "always" + "source.addMissingImports": "always", + "source.organizeImports": "always" } }, "[typescriptreact]": { "editor.formatOnSave": false, "editor.codeActionsOnSave": { "source.fixAll.eslint": "explicit", - "source.addMissingImports": "always" + "source.addMissingImports": "always", + "source.organizeImports": "always" } }, "[json]": { diff --git a/.vscode/twenty.code-workspace b/.vscode/twenty.code-workspace index 49c9ebed098c..c791ac11a0c8 100644 --- a/.vscode/twenty.code-workspace +++ b/.vscode/twenty.code-workspace @@ -43,21 +43,21 @@ "[typescript]": { "editor.formatOnSave": false, "editor.codeActionsOnSave": { - "source.fixAll.eslint": true, + "source.fixAll.eslint": "explicit", "source.addMissingImports": "always" } }, "[javascript]": { "editor.formatOnSave": false, "editor.codeActionsOnSave": { - "source.fixAll.eslint": true, + "source.fixAll.eslint": "explicit", "source.addMissingImports": "always" } }, "[typescriptreact]": { "editor.formatOnSave": false, "editor.codeActionsOnSave": { - "source.fixAll.eslint": true, + "source.fixAll.eslint": "explicit", "source.addMissingImports": "always" } }, diff --git a/nx.json b/nx.json index 40a7d1a3d77e..35b6e7501700 100644 --- a/nx.json +++ b/nx.json @@ -116,14 +116,9 @@ "command": "storybook build", "output-dir": "storybook-static", "config-dir": ".storybook" - }, - "configurations": { - "test": { - "command": "storybook build --test" - } } }, - "storybook:dev": { + "storybook:serve:dev": { "executor": "nx:run-commands", "cache": true, "dependsOn": ["^build"], @@ -133,7 +128,7 @@ "config-dir": ".storybook" } }, - "storybook:static": { + "storybook:serve:static": { "executor": "nx:run-commands", "dependsOn": ["storybook:build"], "options": { @@ -143,30 +138,6 @@ "host": "localhost", "port": 6006, "silent": true - }, - "configurations": { - "test": {} - } - }, - "storybook:coverage": { - "executor": "nx:run-commands", - "cache": true, - "inputs": [ - "^default", - "excludeTests", - "{projectRoot}/coverage/storybook/coverage-storybook.json" - ], - "outputs": [ - "{projectRoot}/coverage/storybook", - "!{projectRoot}/coverage/storybook/coverage-storybook.json" - ], - "options": { - "command": "npx nyc report --reporter={args.reporter} --reporter=text-summary -t {args.coverageDir} --report-dir {args.coverageDir} --check-coverage --cwd={projectRoot}", - "coverageDir": "coverage/storybook", - "reporter": "lcov" - }, - "configurations": { - "text": { "reporter": "text" } } }, "storybook:test": { @@ -185,31 +156,52 @@ "port": 6006 } }, - "storybook:test:nocoverage": { + "storybook:test:no-coverage": { "executor": "nx:run-commands", "inputs": ["^default", "excludeTests"], "options": { "cwd": "{projectRoot}", "commands": [ - "test-storybook --url http://localhost:{args.port} --maxWorkers=3" + "test-storybook --url http://localhost:{args.port} --maxWorkers=2" ], "port": 6006 } }, - "storybook:static:test": { + "storybook:coverage": { + "executor": "nx:run-commands", + "cache": true, + "inputs": [ + "^default", + "excludeTests", + "{projectRoot}/coverage/storybook/coverage-storybook.json" + ], + "outputs": [ + "{projectRoot}/coverage/storybook", + "!{projectRoot}/coverage/storybook/coverage-storybook.json" + ], + "options": { + "command": "npx nyc report --reporter={args.reporter} --reporter=text-summary -t {args.coverageDir} --report-dir {args.coverageDir} --check-coverage --cwd={projectRoot}", + "coverageDir": "coverage/storybook", + "reporter": "lcov" + }, + "configurations": { + "text": { "reporter": "text" } + } + }, + "storybook:serve-and-test:static": { "executor": "nx:run-commands", "options": { "commands": [ - "npx concurrently --kill-others --success=first -n SB,TEST 'nx storybook:static {projectName} --port={args.port} --configuration=test' 'npx wait-on tcp:{args.port} && nx storybook:test {projectName} --port={args.port}'" + "npx concurrently --kill-others --success=first -n SB,TEST 'nx storybook:serve:static {projectName} --port={args.port}' 'npx wait-on tcp:{args.port} && nx storybook:test {projectName} --port={args.port}'" ], "port": 6006 } }, - "storybook:performance:test": { + "storybook:serve-and-test:static:performance": { "executor": "nx:run-commands", "options": { "commands": [ - "npx concurrently --kill-others --success=first -n SB,TEST 'nx storybook:dev {projectName} --configuration=performance --port={args.port}' 'npx wait-on tcp:{args.port} && nx storybook:test:nocoverage {projectName} --port={args.port} --configuration=performance'" + "npx concurrently --kill-others --success=first -n SB,TEST 'nx storybook:serve:dev {projectName} --configuration=performance --port={args.port}' 'npx wait-on tcp:{args.port} && nx storybook:test:no-coverage {projectName} --port={args.port} --configuration=performance'" ], "port": 6006 } @@ -220,7 +212,7 @@ "cwd": "{projectRoot}", "commands": [ { - "command": "nx storybook:build {projectName} --configuration=test", + "command": "nx storybook:build {projectName}", "forwardAllArgs": false }, "cross-var chromatic --project-token=$CHROMATIC_PROJECT_TOKEN --storybook-build-dir=storybook-static {args.ci}" diff --git a/package.json b/package.json index eec9a9e57987..04271989c853 100644 --- a/package.json +++ b/package.json @@ -59,6 +59,7 @@ "@types/dompurify": "^3.0.5", "@types/facepaint": "^1.2.5", "@types/lodash.camelcase": "^4.3.7", + "@types/lodash.chunk": "^4.2.9", "@types/lodash.merge": "^4.6.7", "@types/lodash.pick": "^4.3.7", "@types/nodemailer": "^6.4.14", @@ -114,6 +115,7 @@ "jsonwebtoken": "^9.0.0", "libphonenumber-js": "^1.10.26", "lodash.camelcase": "^4.3.0", + "lodash.chunk": "^4.2.0", "lodash.compact": "^3.0.1", "lodash.debounce": "^4.0.8", "lodash.groupby": "^4.6.0", diff --git a/packages/twenty-chrome-extension/src/generated/graphql.tsx b/packages/twenty-chrome-extension/src/generated/graphql.tsx index 69e043e63d65..14a8def8fc05 100644 --- a/packages/twenty-chrome-extension/src/generated/graphql.tsx +++ b/packages/twenty-chrome-extension/src/generated/graphql.tsx @@ -1,5 +1,5 @@ -import { gql } from '@apollo/client'; import * as Apollo from '@apollo/client'; +import { gql } from '@apollo/client'; export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; @@ -74,7 +74,7 @@ export type ActivityActivityTargetsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -86,7 +86,7 @@ export type ActivityAttachmentsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -98,7 +98,7 @@ export type ActivityCommentsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; /** An activity */ @@ -397,6 +397,10 @@ export type Analytics = { success: Scalars['Boolean']; }; +export type ApiConfig = { + mutationMaximumAffectedRecords: Scalars['Float']; +}; + /** An api key */ export type ApiKey = { /** Creation date */ @@ -853,8 +857,8 @@ export type Billing = { export type BillingSubscription = { id: Scalars['UUID']; - interval?: Maybe; - status: Scalars['String']; + interval?: Maybe; + status: SubscriptionStatus; }; export type BillingSubscriptionFilter = { @@ -980,6 +984,8 @@ export type CalendarChannel = { connectedAccount?: Maybe; /** Connected Account id foreign key */ connectedAccountId?: Maybe; + /** Automatically create records for people you participated with in an event. */ + contactAutoCreationPolicy?: Maybe; /** Creation date */ createdAt?: Maybe; /** Handle */ @@ -992,6 +998,12 @@ export type CalendarChannel = { isSyncEnabled?: Maybe; /** Sync Cursor. Used for syncing events from the calendar provider */ syncCursor?: Maybe; + /** Sync stage */ + syncStage?: Maybe; + /** Sync stage started at */ + syncStageStartedAt?: Maybe; + /** Sync status */ + syncStatus?: Maybe; /** Throttle Failure Count */ throttleFailureCount?: Maybe; /** Update date */ @@ -1009,7 +1021,7 @@ export type CalendarChannelCalendarChannelEventAssociationsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; /** Calendar Channels */ @@ -1020,10 +1032,31 @@ export type CalendarChannelConnection = { totalCount?: Maybe; }; +/** Automatically create records for people you participated with in an event. */ +export enum CalendarChannelContactAutoCreationPolicyEnum { + /** As Organizer */ + AsOrganizer = 'AS_ORGANIZER', + /** As Participant */ + AsParticipant = 'AS_PARTICIPANT', + /** As Participant and Organizer */ + AsParticipantAndOrganizer = 'AS_PARTICIPANT_AND_ORGANIZER', + /** None */ + None = 'NONE' +} + +export type CalendarChannelContactAutoCreationPolicyEnumFilter = { + eq?: InputMaybe; + in?: InputMaybe>>; + is?: InputMaybe; + neq?: InputMaybe; +}; + /** Calendar Channels */ export type CalendarChannelCreateInput = { /** Connected Account id foreign key */ connectedAccountId: Scalars['UUID']; + /** Automatically create records for people you participated with in an event. */ + contactAutoCreationPolicy?: InputMaybe; /** Creation date */ createdAt?: InputMaybe; /** Handle */ @@ -1036,6 +1069,12 @@ export type CalendarChannelCreateInput = { isSyncEnabled?: InputMaybe; /** Sync Cursor. Used for syncing events from the calendar provider */ syncCursor?: InputMaybe; + /** Sync stage */ + syncStage?: InputMaybe; + /** Sync stage started at */ + syncStageStartedAt?: InputMaybe; + /** Sync status */ + syncStatus?: InputMaybe; /** Throttle Failure Count */ throttleFailureCount?: InputMaybe; /** Update date */ @@ -1156,6 +1195,8 @@ export type CalendarChannelFilterInput = { and?: InputMaybe>>; /** Connected Account id foreign key */ connectedAccountId?: InputMaybe; + /** Automatically create records for people you participated with in an event. */ + contactAutoCreationPolicy?: InputMaybe; /** Creation date */ createdAt?: InputMaybe; /** Handle */ @@ -1170,6 +1211,12 @@ export type CalendarChannelFilterInput = { or?: InputMaybe>>; /** Sync Cursor. Used for syncing events from the calendar provider */ syncCursor?: InputMaybe; + /** Sync stage */ + syncStage?: InputMaybe; + /** Sync stage started at */ + syncStageStartedAt?: InputMaybe; + /** Sync status */ + syncStatus?: InputMaybe; /** Throttle Failure Count */ throttleFailureCount?: InputMaybe; /** Update date */ @@ -1182,6 +1229,8 @@ export type CalendarChannelFilterInput = { export type CalendarChannelOrderByInput = { /** Connected Account id foreign key */ connectedAccountId?: InputMaybe; + /** Automatically create records for people you participated with in an event. */ + contactAutoCreationPolicy?: InputMaybe; /** Creation date */ createdAt?: InputMaybe; /** Handle */ @@ -1194,6 +1243,12 @@ export type CalendarChannelOrderByInput = { isSyncEnabled?: InputMaybe; /** Sync Cursor. Used for syncing events from the calendar provider */ syncCursor?: InputMaybe; + /** Sync stage */ + syncStage?: InputMaybe; + /** Sync stage started at */ + syncStageStartedAt?: InputMaybe; + /** Sync status */ + syncStatus?: InputMaybe; /** Throttle Failure Count */ throttleFailureCount?: InputMaybe; /** Update date */ @@ -1202,10 +1257,56 @@ export type CalendarChannelOrderByInput = { visibility?: InputMaybe; }; +/** Sync stage */ +export enum CalendarChannelSyncStageEnum { + /** Calendar events import ongoing */ + CalendarEventsImportOngoing = 'CALENDAR_EVENTS_IMPORT_ONGOING', + /** Calendar events import pending */ + CalendarEventsImportPending = 'CALENDAR_EVENTS_IMPORT_PENDING', + /** Calendar event list fetch ongoing */ + CalendarEventListFetchOngoing = 'CALENDAR_EVENT_LIST_FETCH_ONGOING', + /** Failed */ + Failed = 'FAILED', + /** Full calendar event list fetch pending */ + FullCalendarEventListFetchPending = 'FULL_CALENDAR_EVENT_LIST_FETCH_PENDING', + /** Partial calendar event list fetch pending */ + PartialCalendarEventListFetchPending = 'PARTIAL_CALENDAR_EVENT_LIST_FETCH_PENDING' +} + +export type CalendarChannelSyncStageEnumFilter = { + eq?: InputMaybe; + in?: InputMaybe>>; + is?: InputMaybe; + neq?: InputMaybe; +}; + +/** Sync status */ +export enum CalendarChannelSyncStatusEnum { + /** Active */ + Active = 'ACTIVE', + /** Failed Insufficient Permissions */ + FailedInsufficientPermissions = 'FAILED_INSUFFICIENT_PERMISSIONS', + /** Failed Unknown */ + FailedUnknown = 'FAILED_UNKNOWN', + /** Not Synced */ + NotSynced = 'NOT_SYNCED', + /** Ongoing */ + Ongoing = 'ONGOING' +} + +export type CalendarChannelSyncStatusEnumFilter = { + eq?: InputMaybe; + in?: InputMaybe>>; + is?: InputMaybe; + neq?: InputMaybe; +}; + /** Calendar Channels */ export type CalendarChannelUpdateInput = { /** Connected Account id foreign key */ connectedAccountId?: InputMaybe; + /** Automatically create records for people you participated with in an event. */ + contactAutoCreationPolicy?: InputMaybe; /** Creation date */ createdAt?: InputMaybe; /** Handle */ @@ -1218,6 +1319,12 @@ export type CalendarChannelUpdateInput = { isSyncEnabled?: InputMaybe; /** Sync Cursor. Used for syncing events from the calendar provider */ syncCursor?: InputMaybe; + /** Sync stage */ + syncStage?: InputMaybe; + /** Sync stage started at */ + syncStageStartedAt?: InputMaybe; + /** Sync status */ + syncStatus?: InputMaybe; /** Throttle Failure Count */ throttleFailureCount?: InputMaybe; /** Update date */ @@ -1296,7 +1403,7 @@ export type CalendarEventCalendarChannelEventAssociationsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -1308,7 +1415,7 @@ export type CalendarEventCalendarEventParticipantsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; /** Calendar events */ @@ -1640,11 +1747,12 @@ export type Captcha = { }; export enum CaptchaDriverType { - GoogleRecatpcha = 'GoogleRecatpcha', + GoogleRecaptcha = 'GoogleRecaptcha', Turnstile = 'Turnstile' } export type ClientConfig = { + api: ApiConfig; authProviders: AuthProviders; billing: Billing; captcha: Captcha; @@ -1811,7 +1919,7 @@ export type CompanyActivityTargetsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -1823,7 +1931,7 @@ export type CompanyAttachmentsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -1835,7 +1943,7 @@ export type CompanyFavoritesArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -1847,7 +1955,7 @@ export type CompanyOpportunitiesArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -1859,7 +1967,7 @@ export type CompanyPeopleArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -1871,7 +1979,7 @@ export type CompanyTimelineActivitiesArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; /** A company */ @@ -2050,7 +2158,7 @@ export type ConnectedAccountCalendarChannelsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -2062,7 +2170,7 @@ export type ConnectedAccountMessageChannelsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; /** A connected account */ @@ -2420,7 +2528,6 @@ export enum FieldMetadataType { Numeric = 'NUMERIC', Phone = 'PHONE', Position = 'POSITION', - Probability = 'PROBABILITY', Rating = 'RATING', RawJson = 'RAW_JSON', Relation = 'RELATION', @@ -2597,7 +2704,7 @@ export type MessageMessageChannelMessageAssociationsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -2609,7 +2716,7 @@ export type MessageMessageParticipantsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; /** Message Channels */ @@ -2618,8 +2725,14 @@ export type MessageChannel = { connectedAccount?: Maybe; /** Connected Account id foreign key */ connectedAccountId?: Maybe; + /** Automatically create People records when receiving or sending emails */ + contactAutoCreationPolicy?: Maybe; /** Creation date */ createdAt?: Maybe; + /** Exclude group emails */ + excludeGroupEmails?: Maybe; + /** Exclude non professional emails */ + excludeNonProfessionalEmails?: Maybe; /** Handle */ handle?: Maybe; /** Id */ @@ -2659,7 +2772,7 @@ export type MessageChannelMessageChannelMessageAssociationsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; /** Message Channels */ @@ -2670,12 +2783,35 @@ export type MessageChannelConnection = { totalCount?: Maybe; }; +/** Automatically create People records when receiving or sending emails */ +export enum MessageChannelContactAutoCreationPolicyEnum { + /** None */ + None = 'NONE', + /** Sent */ + Sent = 'SENT', + /** Sent and Received */ + SentAndReceived = 'SENT_AND_RECEIVED' +} + +export type MessageChannelContactAutoCreationPolicyEnumFilter = { + eq?: InputMaybe; + in?: InputMaybe>>; + is?: InputMaybe; + neq?: InputMaybe; +}; + /** Message Channels */ export type MessageChannelCreateInput = { /** Connected Account id foreign key */ connectedAccountId: Scalars['UUID']; + /** Automatically create People records when receiving or sending emails */ + contactAutoCreationPolicy?: InputMaybe; /** Creation date */ createdAt?: InputMaybe; + /** Exclude group emails */ + excludeGroupEmails?: InputMaybe; + /** Exclude non professional emails */ + excludeNonProfessionalEmails?: InputMaybe; /** Handle */ handle?: InputMaybe; /** Id */ @@ -2715,8 +2851,14 @@ export type MessageChannelFilterInput = { and?: InputMaybe>>; /** Connected Account id foreign key */ connectedAccountId?: InputMaybe; + /** Automatically create People records when receiving or sending emails */ + contactAutoCreationPolicy?: InputMaybe; /** Creation date */ createdAt?: InputMaybe; + /** Exclude group emails */ + excludeGroupEmails?: InputMaybe; + /** Exclude non professional emails */ + excludeNonProfessionalEmails?: InputMaybe; /** Handle */ handle?: InputMaybe; /** Id */ @@ -2874,8 +3016,14 @@ export type MessageChannelMessageAssociationUpdateInput = { export type MessageChannelOrderByInput = { /** Connected Account id foreign key */ connectedAccountId?: InputMaybe; + /** Automatically create People records when receiving or sending emails */ + contactAutoCreationPolicy?: InputMaybe; /** Creation date */ createdAt?: InputMaybe; + /** Exclude group emails */ + excludeGroupEmails?: InputMaybe; + /** Exclude non professional emails */ + excludeNonProfessionalEmails?: InputMaybe; /** Handle */ handle?: InputMaybe; /** Id */ @@ -2973,8 +3121,14 @@ export type MessageChannelTypeEnumFilter = { export type MessageChannelUpdateInput = { /** Connected Account id foreign key */ connectedAccountId?: InputMaybe; + /** Automatically create People records when receiving or sending emails */ + contactAutoCreationPolicy?: InputMaybe; /** Creation date */ createdAt?: InputMaybe; + /** Exclude group emails */ + excludeGroupEmails?: InputMaybe; + /** Exclude non professional emails */ + excludeNonProfessionalEmails?: InputMaybe; /** Handle */ handle?: InputMaybe; /** Id */ @@ -3300,7 +3454,7 @@ export type MessageThreadMessageChannelMessageAssociationsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -3312,7 +3466,7 @@ export type MessageThreadMessagesArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; /** Message Thread */ @@ -3517,7 +3671,9 @@ export type Mutation = { deleteWebhooks?: Maybe>; deleteWorkspaceMember?: Maybe; deleteWorkspaceMembers?: Maybe>; + disablePostgresProxy: PostgresCredentials; emailPasswordResetLink: EmailPasswordResetLink; + enablePostgresProxy: PostgresCredentials; exchangeAuthorizationCode: ExchangeAuthCode; executeQuickActionOnActivity?: Maybe; executeQuickActionOnActivityTarget?: Maybe; @@ -3649,288 +3805,344 @@ export type MutationChallengeArgs = { export type MutationCheckoutSessionArgs = { - recurringInterval: Scalars['String']; + recurringInterval: SubscriptionInterval; successUrlPath?: InputMaybe; }; export type MutationCreateActivitiesArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; export type MutationCreateActivityArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreateActivityTargetArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreateActivityTargetsArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; export type MutationCreateApiKeyArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreateApiKeysArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; export type MutationCreateAttachmentArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreateAttachmentsArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; export type MutationCreateAuditLogArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreateAuditLogsArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; export type MutationCreateBlocklistArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreateBlocklistsArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; export type MutationCreateCalendarChannelArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreateCalendarChannelEventAssociationArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreateCalendarChannelEventAssociationsArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; export type MutationCreateCalendarChannelsArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; export type MutationCreateCalendarEventArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreateCalendarEventParticipantArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreateCalendarEventParticipantsArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; export type MutationCreateCalendarEventsArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; export type MutationCreateCommentArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreateCommentsArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; export type MutationCreateCompaniesArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; export type MutationCreateCompanyArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreateConnectedAccountArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreateConnectedAccountsArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; export type MutationCreateFavoriteArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreateFavoritesArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; export type MutationCreateMessageArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreateMessageChannelArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreateMessageChannelMessageAssociationArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreateMessageChannelMessageAssociationsArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; export type MutationCreateMessageChannelsArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; export type MutationCreateMessageParticipantArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreateMessageParticipantsArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; export type MutationCreateMessageThreadArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreateMessageThreadsArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; export type MutationCreateMessagesArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; export type MutationCreateOpportunitiesArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; export type MutationCreateOpportunityArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreatePeopleArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; export type MutationCreatePersonArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreateTimelineActivitiesArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; export type MutationCreateTimelineActivityArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreateViewArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreateViewFieldArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreateViewFieldsArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; export type MutationCreateViewFilterArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreateViewFiltersArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; export type MutationCreateViewSortArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreateViewSortsArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; export type MutationCreateViewsArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; export type MutationCreateWebhookArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreateWebhooksArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; export type MutationCreateWorkspaceMemberArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreateWorkspaceMembersArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; @@ -4803,10 +5015,14 @@ export type ObjectFieldsConnection = { pageInfo: PageInfo; }; -/** Onboarding step */ -export enum OnboardingStep { +/** Onboarding status */ +export enum OnboardingStatus { + Completed = 'COMPLETED', InviteTeam = 'INVITE_TEAM', - SyncEmail = 'SYNC_EMAIL' + PlanRequired = 'PLAN_REQUIRED', + ProfileCreation = 'PROFILE_CREATION', + SyncEmail = 'SYNC_EMAIL', + WorkspaceActivation = 'WORKSPACE_ACTIVATION' } export type OnboardingStepSuccess = { @@ -4861,7 +5077,7 @@ export type OpportunityActivityTargetsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -4873,7 +5089,7 @@ export type OpportunityAttachmentsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -4885,7 +5101,7 @@ export type OpportunityFavoritesArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -4897,7 +5113,7 @@ export type OpportunityTimelineActivitiesArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; /** An opportunity */ @@ -5120,7 +5336,7 @@ export type PersonActivityTargetsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -5132,7 +5348,7 @@ export type PersonAttachmentsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -5144,7 +5360,7 @@ export type PersonCalendarEventParticipantsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -5156,7 +5372,7 @@ export type PersonFavoritesArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -5168,7 +5384,7 @@ export type PersonMessageParticipantsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -5180,7 +5396,7 @@ export type PersonPointOfContactForOpportunitiesArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -5192,7 +5408,7 @@ export type PersonTimelineActivitiesArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; /** A person */ @@ -5332,9 +5548,16 @@ export type PersonUpdateInput = { xLink?: InputMaybe; }; +export type PostgresCredentials = { + id: Scalars['UUID']; + password: Scalars['String']; + user: Scalars['String']; + workspaceId: Scalars['String']; +}; + export type ProductPriceEntity = { created: Scalars['Float']; - recurringInterval: Scalars['String']; + recurringInterval: SubscriptionInterval; stripePriceId: Scalars['String']; unitAmount: Scalars['Float']; }; @@ -5347,53 +5570,54 @@ export type ProductPricesEntity = { export type Query = { activities?: Maybe; activity?: Maybe; - activityDuplicates?: Maybe; + activityDuplicates?: Maybe>; activityTarget?: Maybe; - activityTargetDuplicates?: Maybe; + activityTargetDuplicates?: Maybe>; activityTargets?: Maybe; apiKey?: Maybe; - apiKeyDuplicates?: Maybe; + apiKeyDuplicates?: Maybe>; apiKeys?: Maybe; attachment?: Maybe; - attachmentDuplicates?: Maybe; + attachmentDuplicates?: Maybe>; attachments?: Maybe; auditLog?: Maybe; - auditLogDuplicates?: Maybe; + auditLogDuplicates?: Maybe>; auditLogs?: Maybe; billingPortalSession: SessionEntity; blocklist?: Maybe; - blocklistDuplicates?: Maybe; + blocklistDuplicates?: Maybe>; blocklists?: Maybe; calendarChannel?: Maybe; - calendarChannelDuplicates?: Maybe; + calendarChannelDuplicates?: Maybe>; calendarChannelEventAssociation?: Maybe; - calendarChannelEventAssociationDuplicates?: Maybe; + calendarChannelEventAssociationDuplicates?: Maybe>; calendarChannelEventAssociations?: Maybe; calendarChannels?: Maybe; calendarEvent?: Maybe; - calendarEventDuplicates?: Maybe; + calendarEventDuplicates?: Maybe>; calendarEventParticipant?: Maybe; - calendarEventParticipantDuplicates?: Maybe; + calendarEventParticipantDuplicates?: Maybe>; calendarEventParticipants?: Maybe; calendarEvents?: Maybe; checkUserExists: UserExists; checkWorkspaceInviteHashIsValid: WorkspaceInviteHashValid; clientConfig: ClientConfig; comment?: Maybe; - commentDuplicates?: Maybe; + commentDuplicates?: Maybe>; comments?: Maybe; companies?: Maybe; company?: Maybe; - companyDuplicates?: Maybe; + companyDuplicates?: Maybe>; connectedAccount?: Maybe; - connectedAccountDuplicates?: Maybe; + connectedAccountDuplicates?: Maybe>; connectedAccounts?: Maybe; currentUser: User; currentWorkspace: Workspace; favorite?: Maybe; - favoriteDuplicates?: Maybe; + favoriteDuplicates?: Maybe>; favorites?: Maybe; findWorkspaceFromInviteHash: Workspace; + getPostgresCredentials?: Maybe; getProductPrices: ProductPricesEntity; getTimelineCalendarEventsFromCompanyId: TimelineCalendarEventsWithTotal; getTimelineCalendarEventsFromPersonId: TimelineCalendarEventsWithTotal; @@ -5401,48 +5625,48 @@ export type Query = { getTimelineThreadsFromPersonId: TimelineThreadsWithTotal; message?: Maybe; messageChannel?: Maybe; - messageChannelDuplicates?: Maybe; + messageChannelDuplicates?: Maybe>; messageChannelMessageAssociation?: Maybe; - messageChannelMessageAssociationDuplicates?: Maybe; + messageChannelMessageAssociationDuplicates?: Maybe>; messageChannelMessageAssociations?: Maybe; messageChannels?: Maybe; - messageDuplicates?: Maybe; + messageDuplicates?: Maybe>; messageParticipant?: Maybe; - messageParticipantDuplicates?: Maybe; + messageParticipantDuplicates?: Maybe>; messageParticipants?: Maybe; messageThread?: Maybe; - messageThreadDuplicates?: Maybe; + messageThreadDuplicates?: Maybe>; messageThreads?: Maybe; messages?: Maybe; object: Object; objects: ObjectConnection; opportunities?: Maybe; opportunity?: Maybe; - opportunityDuplicates?: Maybe; + opportunityDuplicates?: Maybe>; people?: Maybe; person?: Maybe; - personDuplicates?: Maybe; + personDuplicates?: Maybe>; timelineActivities?: Maybe; timelineActivity?: Maybe; - timelineActivityDuplicates?: Maybe; + timelineActivityDuplicates?: Maybe>; validatePasswordResetToken: ValidatePasswordResetToken; view?: Maybe; - viewDuplicates?: Maybe; + viewDuplicates?: Maybe>; viewField?: Maybe; - viewFieldDuplicates?: Maybe; + viewFieldDuplicates?: Maybe>; viewFields?: Maybe; viewFilter?: Maybe; - viewFilterDuplicates?: Maybe; + viewFilterDuplicates?: Maybe>; viewFilters?: Maybe; viewSort?: Maybe; - viewSortDuplicates?: Maybe; + viewSortDuplicates?: Maybe>; viewSorts?: Maybe; views?: Maybe; webhook?: Maybe; - webhookDuplicates?: Maybe; + webhookDuplicates?: Maybe>; webhooks?: Maybe; workspaceMember?: Maybe; - workspaceMemberDuplicates?: Maybe; + workspaceMemberDuplicates?: Maybe>; workspaceMembers?: Maybe; }; @@ -5454,7 +5678,7 @@ export type QueryActivitiesArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -5464,8 +5688,8 @@ export type QueryActivityArgs = { export type QueryActivityDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -5475,8 +5699,8 @@ export type QueryActivityTargetArgs = { export type QueryActivityTargetDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -5487,7 +5711,7 @@ export type QueryActivityTargetsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -5497,8 +5721,8 @@ export type QueryApiKeyArgs = { export type QueryApiKeyDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -5509,7 +5733,7 @@ export type QueryApiKeysArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -5519,8 +5743,8 @@ export type QueryAttachmentArgs = { export type QueryAttachmentDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -5531,7 +5755,7 @@ export type QueryAttachmentsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -5541,8 +5765,8 @@ export type QueryAuditLogArgs = { export type QueryAuditLogDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -5553,7 +5777,7 @@ export type QueryAuditLogsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -5568,8 +5792,8 @@ export type QueryBlocklistArgs = { export type QueryBlocklistDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -5580,7 +5804,7 @@ export type QueryBlocklistsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -5590,8 +5814,8 @@ export type QueryCalendarChannelArgs = { export type QueryCalendarChannelDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -5601,8 +5825,8 @@ export type QueryCalendarChannelEventAssociationArgs = { export type QueryCalendarChannelEventAssociationDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -5613,7 +5837,7 @@ export type QueryCalendarChannelEventAssociationsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -5624,7 +5848,7 @@ export type QueryCalendarChannelsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -5634,8 +5858,8 @@ export type QueryCalendarEventArgs = { export type QueryCalendarEventDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -5645,8 +5869,8 @@ export type QueryCalendarEventParticipantArgs = { export type QueryCalendarEventParticipantDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -5657,7 +5881,7 @@ export type QueryCalendarEventParticipantsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -5668,7 +5892,7 @@ export type QueryCalendarEventsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -5689,8 +5913,8 @@ export type QueryCommentArgs = { export type QueryCommentDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -5701,7 +5925,7 @@ export type QueryCommentsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -5712,7 +5936,7 @@ export type QueryCompaniesArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -5722,8 +5946,8 @@ export type QueryCompanyArgs = { export type QueryCompanyDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -5733,8 +5957,8 @@ export type QueryConnectedAccountArgs = { export type QueryConnectedAccountDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -5745,7 +5969,7 @@ export type QueryConnectedAccountsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -5755,8 +5979,8 @@ export type QueryFavoriteArgs = { export type QueryFavoriteDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -5767,7 +5991,7 @@ export type QueryFavoritesArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -5820,8 +6044,8 @@ export type QueryMessageChannelArgs = { export type QueryMessageChannelDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -5831,8 +6055,8 @@ export type QueryMessageChannelMessageAssociationArgs = { export type QueryMessageChannelMessageAssociationDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -5843,7 +6067,7 @@ export type QueryMessageChannelMessageAssociationsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -5854,13 +6078,13 @@ export type QueryMessageChannelsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; export type QueryMessageDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -5870,8 +6094,8 @@ export type QueryMessageParticipantArgs = { export type QueryMessageParticipantDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -5882,7 +6106,7 @@ export type QueryMessageParticipantsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -5892,8 +6116,8 @@ export type QueryMessageThreadArgs = { export type QueryMessageThreadDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -5904,7 +6128,7 @@ export type QueryMessageThreadsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -5915,7 +6139,7 @@ export type QueryMessagesArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -5926,7 +6150,7 @@ export type QueryOpportunitiesArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -5936,8 +6160,8 @@ export type QueryOpportunityArgs = { export type QueryOpportunityDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -5948,7 +6172,7 @@ export type QueryPeopleArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -5958,8 +6182,8 @@ export type QueryPersonArgs = { export type QueryPersonDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -5970,7 +6194,7 @@ export type QueryTimelineActivitiesArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -5980,8 +6204,8 @@ export type QueryTimelineActivityArgs = { export type QueryTimelineActivityDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -5996,8 +6220,8 @@ export type QueryViewArgs = { export type QueryViewDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -6007,8 +6231,8 @@ export type QueryViewFieldArgs = { export type QueryViewFieldDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -6019,7 +6243,7 @@ export type QueryViewFieldsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -6029,8 +6253,8 @@ export type QueryViewFilterArgs = { export type QueryViewFilterDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -6041,7 +6265,7 @@ export type QueryViewFiltersArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -6051,8 +6275,8 @@ export type QueryViewSortArgs = { export type QueryViewSortDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -6063,7 +6287,7 @@ export type QueryViewSortsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -6074,7 +6298,7 @@ export type QueryViewsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -6084,8 +6308,8 @@ export type QueryWebhookArgs = { export type QueryWebhookDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -6096,7 +6320,7 @@ export type QueryWebhooksArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -6106,8 +6330,8 @@ export type QueryWorkspaceMemberArgs = { export type QueryWorkspaceMemberDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -6118,7 +6342,7 @@ export type QueryWorkspaceMembersArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; export type RawJsonFilter = { @@ -6226,13 +6450,30 @@ export type StringFilter = { startsWith?: InputMaybe; }; +export enum SubscriptionInterval { + Day = 'Day', + Month = 'Month', + Week = 'Week', + Year = 'Year' +} + +export enum SubscriptionStatus { + Active = 'Active', + Canceled = 'Canceled', + Incomplete = 'Incomplete', + IncompleteExpired = 'IncompleteExpired', + PastDue = 'PastDue', + Paused = 'Paused', + Trialing = 'Trialing', + Unpaid = 'Unpaid' +} + export type Support = { supportDriver: Scalars['String']; supportFrontChatId?: Maybe; }; export type Telemetry = { - anonymizationEnabled: Scalars['Boolean']; enabled: Scalars['Boolean']; }; @@ -6534,7 +6775,7 @@ export type User = { firstName: Scalars['String']; id: Scalars['UUID']; lastName: Scalars['String']; - onboardingStep?: Maybe; + onboardingStatus?: Maybe; passwordHash?: Maybe; /** @deprecated field migrated into the AppTokens Table ref: https://github.com/twentyhq/twenty/issues/5021 */ passwordResetToken?: Maybe; @@ -6623,7 +6864,7 @@ export type ViewViewFieldsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -6635,7 +6876,7 @@ export type ViewViewFiltersArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -6647,7 +6888,7 @@ export type ViewViewSortsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; /** (System) Views */ @@ -7222,8 +7463,8 @@ export type Workspace = { id: Scalars['UUID']; inviteHash?: Maybe; logo?: Maybe; - subscriptionStatus: Scalars['String']; updatedAt: Scalars['DateTime']; + workspaceMembersCount?: Maybe; }; @@ -7304,7 +7545,7 @@ export type WorkspaceMemberAccountOwnerForCompaniesArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -7316,7 +7557,7 @@ export type WorkspaceMemberAssignedActivitiesArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -7328,7 +7569,7 @@ export type WorkspaceMemberAuditLogsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -7340,7 +7581,7 @@ export type WorkspaceMemberAuthoredActivitiesArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -7352,7 +7593,7 @@ export type WorkspaceMemberAuthoredAttachmentsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -7364,7 +7605,7 @@ export type WorkspaceMemberAuthoredCommentsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -7376,7 +7617,7 @@ export type WorkspaceMemberBlocklistArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -7388,7 +7629,7 @@ export type WorkspaceMemberCalendarEventParticipantsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -7400,7 +7641,7 @@ export type WorkspaceMemberConnectedAccountsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -7412,7 +7653,7 @@ export type WorkspaceMemberFavoritesArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -7424,7 +7665,7 @@ export type WorkspaceMemberMessageParticipantsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -7436,7 +7677,7 @@ export type WorkspaceMemberTimelineActivitiesArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; /** A workspace member */ diff --git a/packages/twenty-docker/k8s/README.md b/packages/twenty-docker/k8s/README.md new file mode 100644 index 000000000000..df1cde709784 --- /dev/null +++ b/packages/twenty-docker/k8s/README.md @@ -0,0 +1,113 @@ +# README + +## Overview + +This repository contains Kubernetes manifests and Terraform files to help you deploy and manage the TwentyCRM application. The files are located in the `packages/twenty-docker/k8s` directory. + +## Prerequisites + +Before using these files, ensure you have the following installed and configured on your system: + +- Kubernetes cluster (e.g., Minikube, EKS, GKE) +- kubectl +- Terraform +- Docker + +## Setup Instructions + +### Step 1: Clone the Repository + +Clone the repository to your local machine: + +``` bash +git clone https://github.com/twentyhq/twenty.git +cd twentycrm/packages/twenty-docker/k8s +``` + +### Step 2: Customize the Manifests and Terraform Files + +**Important:** These files require customization for your specific implementation. Update the placeholders and configurations according to your environment and requirements. + +### Step 3: Deploy with Terraform + +1. Navigate to the Terraform directory: + + ```bash + cd terraform + ``` + +2. Initialize Terraform: + + ```bash + terraform init + ``` + +3. Plan the deployment: + + ```bash + terraform plan + ``` + +4. Apply the deployment: + + ```bash + terraform apply + ``` + +## OR + +### Step 3: Deploy with Kubernetes Manifests + +1. Navigate to the Kubernetes manifests directory: + + ```bash + cd ../k8s + ``` + +2. Create Server Secret + + ``` bash + kubectl create secret generic -n twentycrm tokens --from-literal accessToken=changeme --from-literal loginToken="changeme" --from-literal refreshToken="changeme" --from-literal fileToken="changeme" + ``` + +3. Apply the manifests: + + ```bash + kubectl apply -f . + ``` + +## Customization + +### Kubernetes Manifests + +- **Namespace:** Update the `namespace` in the manifests as needed. +- **Resource Limits:** Adjust the resource limits and requests according to your application's requirements. +- **Environment Variables:** Configure server tokens in the `Secret` command above. + +### Terraform Files + +- **Variables:** Update the variables in the `variables.tf` file to match your environment. +- **Locals:** Update the locals in the `main.tf` file to match your environment. +- **Providers:** Ensure the provider configurations (e.g., AWS, GCP) are correct for your setup. +- **Resources:** Modify the resource definitions as needed to fit your infrastructure. + +## Troubleshooting + +### Common Issues + +- **Connectivity:** Ensure your Kubernetes cluster is accessible and configured correctly. +- **Permissions:** Verify that you have the necessary permissions to deploy resources in your cloud provider. +- **Resource Limits:** Adjust resource limits if you encounter issues related to insufficient resources. + +### Logs and Debugging + +- Use `kubectl logs` to check the logs of your Kubernetes pods. +- Use `terraform show` and `terraform state` to inspect your Terraform state and configurations. + +## Conclusion + +This setup provides a basic structure for deploying the TwentyCRM application using Kubernetes and Terraform. Ensure you thoroughly customize the manifests and Terraform files to suit your specific needs. For any issues or questions, please refer to the official documentation of Kubernetes and Terraform or seek support from your cloud provider. + +--- + +Feel free to contribute and improve this repository by submitting pull requests or opening issues. Happy deploying! diff --git a/packages/twenty-docker/k8s/manifests/deployment-db.yaml b/packages/twenty-docker/k8s/manifests/deployment-db.yaml new file mode 100644 index 000000000000..8d9dec9df404 --- /dev/null +++ b/packages/twenty-docker/k8s/manifests/deployment-db.yaml @@ -0,0 +1,54 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: twentycrm-db + name: twentycrm-db + namespace: twentycrm +spec: + progressDeadlineSeconds: 600 + replicas: 1 + strategy: + rollingUpdate: + maxSurge: 1 + maxUnavailable: 1 + type: RollingUpdate + selector: + matchLabels: + app: twentycrm-db + template: + metadata: + labels: + app: twentycrm-db + spec: + volumes: + - name: twentycrm-db-data + persistentVolumeClaim: + claimName: twentycrm-db-pvc + containers: + - env: + - name: POSTGRES_PASSWORD + value: "twenty" + - name: BITNAMI_DEBUG + value: "true" + - image: twentycrm/twenty-postgres:latest + imagePullPolicy: Always + name: twentycrm + ports: + - containerPort: 5432 + name: tcp + protocol: TCP + resources: + requests: + memory: "256Mi" + cpu: "250m" + limits: + memory: "1024Mi" + cpu: "1000m" + stdin: true + tty: true + volumeMounts: + - mountPath: /bitnami/postgresql + name: twentycrm-db-data + dnsPolicy: ClusterFirst + restartPolicy: Always diff --git a/packages/twenty-docker/k8s/manifests/deployment-server.yaml b/packages/twenty-docker/k8s/manifests/deployment-server.yaml new file mode 100644 index 000000000000..cf740722f55e --- /dev/null +++ b/packages/twenty-docker/k8s/manifests/deployment-server.yaml @@ -0,0 +1,82 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: twentycrm-server + name: twentycrm-server + namespace: twentycrm +spec: + progressDeadlineSeconds: 600 + replicas: 1 + strategy: + rollingUpdate: + maxSurge: 1 + maxUnavailable: 1 + type: RollingUpdate + selector: + matchLabels: + app: twentycrm-server + template: + metadata: + labels: + app: twentycrm-server + spec: + volumes: + - name: twentycrm-server-data + persistentVolumeClaim: + claimName: twentycrm-server-pvc + containers: + - env: + - name: PORT + value: 3000 + - name: SERVER_URL + value: "https://crm.example.com:443" + - name: PG_DATABASE_URL + value: "postgres://twenty:twenty@twenty-db.twentycrm.svc.cluster.local/default" + - name: ENABLE_DB_MIGRATIONS + value: "true" + - name: SIGN_IN_PREFILLED + value: "true" + - name: STORAGE_TYPE + value: "local" + - name: ACCESS_TOKEN_SECRET + valueFrom: + secretKeyRef: + name: tokens + key: accessToken + - name: LOGIN_TOKEN_SECRET + valueFrom: + secretKeyRef: + name: tokens + key: loginToken + - name: REFRESH_TOKEN_SECRET + valueFrom: + secretKeyRef: + name: tokens + key: refreshToken + - name: FILE_TOKEN_SECRET + valueFrom: + secretKeyRef: + name: tokens + key: fileToken + - image: twentycrm/twenty:latest + imagePullPolicy: Always + name: twentycrm + ports: + - containerPort: 3000 + name: http-tcp + protocol: TCP + resources: + requests: + memory: "256Mi" + cpu: "250m" + limits: + memory: "1024Mi" + cpu: "1000m" + stdin: true + tty: true + volumeMounts: + - mountPath: /app/.local-storage + name: twentycrm-server-data + dnsPolicy: ClusterFirst + restartPolicy: Always diff --git a/packages/twenty-docker/k8s/manifests/ingress.yaml b/packages/twenty-docker/k8s/manifests/ingress.yaml new file mode 100644 index 000000000000..19663f7a4f51 --- /dev/null +++ b/packages/twenty-docker/k8s/manifests/ingress.yaml @@ -0,0 +1,24 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: twentycrm + namespace: twentycrm + annotations: + nginx.ingress.kubernetes.io/configuration-snippet: | + more_set_headers "X-Forwarded-For $http_x_forwarded_for"; + nginx.ingress.kubernetes.io/force-ssl-redirect: "false" + kubernetes.io/ingress.class: "nginx" + nginx.ingress.kubernetes.io/backend-protocol: "HTTP" +spec: + ingressClassName: nginx + rules: + - host: crm.example.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: twentycrm-server + port: + name: http-tcp diff --git a/packages/twenty-docker/k8s/manifests/pv-db.yaml b/packages/twenty-docker/k8s/manifests/pv-db.yaml new file mode 100644 index 000000000000..9caa4ca4d919 --- /dev/null +++ b/packages/twenty-docker/k8s/manifests/pv-db.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: twentycrm-db-pv +spec: + storageClassName: default + capacity: + storage: 10Gi + accessModes: + - ReadWriteOnce + persistentVolumeReclaimPolicy: Retain diff --git a/packages/twenty-docker/k8s/manifests/pv-server.yaml b/packages/twenty-docker/k8s/manifests/pv-server.yaml new file mode 100644 index 000000000000..721de7d5668a --- /dev/null +++ b/packages/twenty-docker/k8s/manifests/pv-server.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: twentycrm-server-pv + namespace: twentycrm +spec: + storageClassName: default + capacity: + storage: 10Gi + accessModes: + - ReadWriteOnce + persistentVolumeReclaimPolicy: Retain diff --git a/packages/twenty-docker/k8s/manifests/pvc-db.yaml b/packages/twenty-docker/k8s/manifests/pvc-db.yaml new file mode 100644 index 000000000000..146596ea1050 --- /dev/null +++ b/packages/twenty-docker/k8s/manifests/pvc-db.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: twentycrm-db-pvc + namespace: twentycrm +spec: + storageClassName: default + volumeName: twentycrm-db-pv + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 10Gi diff --git a/packages/twenty-docker/k8s/manifests/pvc-server.yaml b/packages/twenty-docker/k8s/manifests/pvc-server.yaml new file mode 100644 index 000000000000..f265057cf569 --- /dev/null +++ b/packages/twenty-docker/k8s/manifests/pvc-server.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: twentycrm-server-pvc + namespace: twentycrm +spec: + storageClassName: default + volumeName: twentycrm-server-pv + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 10Gi diff --git a/packages/twenty-docker/k8s/manifests/service-db.yaml b/packages/twenty-docker/k8s/manifests/service-db.yaml new file mode 100644 index 000000000000..bb0e38df6d6d --- /dev/null +++ b/packages/twenty-docker/k8s/manifests/service-db.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Service +metadata: + name: twentycrm-db + namespace: twentycrm +spec: + internalTrafficPolicy: Cluster + ports: + - port: 5432 + protocol: TCP + targetPort: 5432 + selector: + app: twentycrm-db + sessionAffinity: ClientIP + sessionAffinityConfig: + clientIP: + timeoutSeconds: 10800 + type: ClusterIP diff --git a/packages/twenty-docker/k8s/manifests/service-server.yaml b/packages/twenty-docker/k8s/manifests/service-server.yaml new file mode 100644 index 000000000000..7fcc869a6edc --- /dev/null +++ b/packages/twenty-docker/k8s/manifests/service-server.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: twentycrm-server + namespace: twentycrm +spec: + internalTrafficPolicy: Cluster + ports: + - name: http-tcp + port: 3000 + protocol: TCP + targetPort: 3000 + selector: + app: twentycrm-server + sessionAffinity: ClientIP + sessionAffinityConfig: + clientIP: + timeoutSeconds: 10800 + type: ClusterIP diff --git a/packages/twenty-docker/k8s/terraform/deployment-db.tf b/packages/twenty-docker/k8s/terraform/deployment-db.tf new file mode 100644 index 000000000000..c2a5a64b11a2 --- /dev/null +++ b/packages/twenty-docker/k8s/terraform/deployment-db.tf @@ -0,0 +1,90 @@ +resource "kubernetes_deployment" "twentycrm_db" { + metadata { + name = "${local.twentycrm_app_name}-db" + namespace = kubernetes_namespace.twentycrm.metadata.0.name + labels = { + app = "${local.twentycrm_app_name}-db" + } + } + + spec { + replicas = 1 + selector { + match_labels = { + app = "${local.twentycrm_app_name}-db" + } + } + + strategy { + type = "RollingUpdate" + rolling_update { + max_surge = "1" + max_unavailable = "1" + } + } + + template { + metadata { + labels = { + app = "${local.twentycrm_app_name}-db" + } + } + + spec { + # security_context { + # fs_group = 0 + # } + container { + image = local.twentycrm_db_image + name = local.twentycrm_app_name + stdin = true + tty = true + security_context { + allow_privilege_escalation = true + } + + env { + name = "POSTGRES_PASSWORD" + value = "twenty" + } + env { + name = "BITNAMI_DEBUG" + value = true + } + + port { + container_port = 5432 + protocol = "TCP" + } + + resources { + requests = { + cpu = "250m" + memory = "256Mi" + } + limits = { + cpu = "1000m" + memory = "1024Mi" + } + } + + volume_mount { + name = "nfs-twentycrm-db-data" + mount_path = "/bitnami/postgresql" + } + } + + volume { + name = "nfs-twentycrm-db-data" + + persistent_volume_claim { + claim_name = "nfs-twentycrm-db-data-pvc" + } + } + + dns_policy = "ClusterFirst" + restart_policy = "Always" + } + } + } +} diff --git a/packages/twenty-docker/k8s/terraform/deployment-server.tf b/packages/twenty-docker/k8s/terraform/deployment-server.tf new file mode 100644 index 000000000000..13a4d30bf708 --- /dev/null +++ b/packages/twenty-docker/k8s/terraform/deployment-server.tf @@ -0,0 +1,169 @@ +resource "kubernetes_deployment" "twentycrm_server" { + metadata { + name = "${local.twentycrm_app_name}-server" + namespace = kubernetes_namespace.twentycrm.metadata.0.name + labels = { + app = "${local.twentycrm_app_name}-server" + } + } + + spec { + replicas = 1 + selector { + match_labels = { + app = "${local.twentycrm_app_name}-server" + } + } + + strategy { + type = "RollingUpdate" + rolling_update { + max_surge = "1" + max_unavailable = "1" + } + } + + template { + metadata { + labels = { + app = "${local.twentycrm_app_name}-server" + } + } + + spec { + container { + image = local.twentycrm_server_image + name = local.twentycrm_app_name + stdin = true + tty = true + + security_context { + allow_privilege_escalation = true + privileged = true + run_as_user = 1000 + } + + env { + name = "PORT" + value = "3000" + } + env { + name = "DEBUG_MODE" + value = false + } + + env { + name = "SERVER_URL" + value = "https://crm.example.com:443" + } + + env { + name = "FRONT_BASE_URL" + value = "https://crm.example.com:443" + } + + env { + name = "BACKEND_SERVER_URL" + value = "https://crm.example.com:443" + } + + env { + name = "PG_DATABASE_URL" + value = "postgres://twenty:twenty@twentycrm-db.twentycrm.svc.cluster.local/default" + } + + env { + name = "ENABLE_DB_MIGRATIONS" + value = "true" + } + + env { + name = "SIGN_IN_PREFILLED" + value = "true" + } + + env { + name = "STORAGE_TYPE" + value = "local" + } + + env { + name = "ACCESS_TOKEN_SECRET" + value_from { + secret_key_ref { + name = "tokens" + key = "accessToken" + } + } + } + + env { + name = "LOGIN_TOKEN_SECRET" + value_from { + secret_key_ref { + name = "tokens" + key = "loginToken" + } + } + } + + env { + name = "REFRESH_TOKEN_SECRET" + value_from { + secret_key_ref { + name = "tokens" + key = "refreshToken" + } + } + } + + env { + name = "FILE_TOKEN_SECRET" + value_from { + secret_key_ref { + name = "tokens" + key = "fileToken" + } + } + } + + port { + container_port = 3000 + protocol = "TCP" + } + + resources { + requests = { + cpu = "250m" + memory = "256Mi" + } + limits = { + cpu = "1000m" + memory = "1024Mi" + } + } + + volume_mount { + name = "nfs-twentycrm-server-data" + mount_path = "/app/.local-storage" + } + } + + volume { + name = "nfs-twentycrm-server-data" + + persistent_volume_claim { + claim_name = "nfs-twentycrm-server-data-pvc" + } + } + + dns_policy = "ClusterFirst" + restart_policy = "Always" + } + } + } + depends_on = [ + kubernetes_deployment.twentycrm_db, + kubernetes_secret.twentycrm_tokens + ] +} diff --git a/packages/twenty-docker/k8s/terraform/ingress.tf b/packages/twenty-docker/k8s/terraform/ingress.tf new file mode 100644 index 000000000000..4276333b7f54 --- /dev/null +++ b/packages/twenty-docker/k8s/terraform/ingress.tf @@ -0,0 +1,30 @@ +resource "kubernetes_ingress" "twentycrm" { + wait_for_load_balancer = true + metadata { + name = "${local.twentycrm_app_name}-ingress" + namespace = kubernetes_namespace.twentycrm.metadata.0.name + annotations = { + "kubernetes.io/ingress.class" = "nginx" + "nginx.ingress.kubernetes.io/configuration-snippet" = < { + link, + workspace, + sender, + serverUrl, + }: SendInviteLinkEmailProps) => { + const workspaceLogo = getImageAbsoluteURIOrBase64(workspace.logo, serverUrl); return ( @@ -34,7 +38,7 @@ export const SendInviteLinkEmail = ({ <br /> </MainText> <HighlightedContainer> - {workspace.logo && <Img src={workspace.logo} width={40} height={40} />} + {workspaceLogo && <Img src={workspaceLogo} width={40} height={40} />} {workspace.name && <HighlightedText value={workspace.name} />} <CallToAction href={link} value="Accept invite" /> </HighlightedContainer> diff --git a/packages/twenty-emails/src/utils/getImageAbsoluteURIOrBase64.ts b/packages/twenty-emails/src/utils/getImageAbsoluteURIOrBase64.ts new file mode 100644 index 000000000000..cab930f76518 --- /dev/null +++ b/packages/twenty-emails/src/utils/getImageAbsoluteURIOrBase64.ts @@ -0,0 +1,16 @@ +export const getImageAbsoluteURIOrBase64 = ( + imageUrl?: string | null, + serverUrl?: string, +) => { + if (!imageUrl) { + return null; + } + + if (imageUrl?.startsWith('data:') || imageUrl?.startsWith('https:')) { + return imageUrl; + } + + return serverUrl?.endsWith('/') + ? `${serverUrl.substring(0, serverUrl.length - 1)}/files/${imageUrl}` + : `${serverUrl || ''}/files/${imageUrl}`; +}; diff --git a/packages/twenty-front/.storybook/main.ts b/packages/twenty-front/.storybook/main.ts index 764ae8aecf5e..633df49b3dae 100644 --- a/packages/twenty-front/.storybook/main.ts +++ b/packages/twenty-front/.storybook/main.ts @@ -45,17 +45,5 @@ const config: StorybookConfig = { name: '@storybook/react-vite', options: {}, }, - build: { - test: { - disableMDXEntries: true, - disabledAddons: [ - '@storybook/addon-docs', - '@storybook/addon-essentials/docs', - ], - }, - }, - docs: { - autodocs: false, - }, }; export default config; diff --git a/packages/twenty-front/codegen-metadata.cjs b/packages/twenty-front/codegen-metadata.cjs index 2d4e3fa895cf..d7ee2eb00c09 100644 --- a/packages/twenty-front/codegen-metadata.cjs +++ b/packages/twenty-front/codegen-metadata.cjs @@ -1,5 +1,5 @@ module.exports = { - schema: process.env.REACT_APP_SERVER_BASE_URL + '/metadata', + schema: (process.env.REACT_APP_SERVER_BASE_URL ?? 'http://localhost:3000') + '/metadata', documents: [ './src/modules/databases/graphql/**/*.ts', './src/modules/object-metadata/graphql/*.ts', diff --git a/packages/twenty-front/codegen.cjs b/packages/twenty-front/codegen.cjs index 461f7366cb99..fcc0ef27a5ce 100644 --- a/packages/twenty-front/codegen.cjs +++ b/packages/twenty-front/codegen.cjs @@ -1,5 +1,5 @@ module.exports = { - schema: process.env.REACT_APP_SERVER_BASE_URL + '/graphql', + schema: (process.env.REACT_APP_SERVER_BASE_URL ?? 'http://localhost:3000') + '/graphql', documents: [ '!./src/modules/databases/**', '!./src/modules/object-metadata/**', diff --git a/packages/twenty-front/jest.config.ts b/packages/twenty-front/jest.config.ts index 63c026a8c4ae..e21e9cbaf0a7 100644 --- a/packages/twenty-front/jest.config.ts +++ b/packages/twenty-front/jest.config.ts @@ -25,7 +25,7 @@ const jestConfig: JestConfigWithTsJest = { coverageThreshold: { global: { statements: 65, - lines: 65, + lines: 64, functions: 55, }, }, diff --git a/packages/twenty-front/package.json b/packages/twenty-front/package.json index 0e009c59c675..8ff1595fab09 100644 --- a/packages/twenty-front/package.json +++ b/packages/twenty-front/package.json @@ -1,6 +1,6 @@ { "name": "twenty-front", - "version": "0.20.0", + "version": "0.22.0", "private": true, "type": "module", "scripts": { diff --git a/packages/twenty-front/project.json b/packages/twenty-front/project.json index 332bfc4fafb1..4c427109b051 100644 --- a/packages/twenty-front/project.json +++ b/packages/twenty-front/project.json @@ -62,12 +62,9 @@ "storybook:build": { "options": { "env": { "NODE_OPTIONS": "--max_old_space_size=5000" } - }, - "configurations": { - "test": {} } }, - "storybook:dev": { + "storybook:serve:dev": { "options": { "port": 6006 }, "configurations": { "docs": { "env": { "STORYBOOK_SCOPE": "ui-docs" } }, @@ -76,11 +73,8 @@ "performance": { "env": { "STORYBOOK_SCOPE": "performance" } } } }, - "storybook:static": { - "options": { "port": 6006 }, - "configurations": { - "test": {} - } + "storybook:serve:static": { + "options": { "port": 6006 } }, "storybook:coverage": { "configurations": { @@ -100,18 +94,10 @@ "performance": { "env": { "STORYBOOK_SCOPE": "performance" } } } }, - "storybook:test:nocoverage": { - "configurations": { - "docs": { "env": { "STORYBOOK_SCOPE": "ui-docs" } }, - "modules": { "env": { "STORYBOOK_SCOPE": "modules" } }, - "pages": { "env": { "STORYBOOK_SCOPE": "pages" } }, - "performance": { "env": { "STORYBOOK_SCOPE": "performance" } } - } - }, - "storybook:static:test": { + "storybook:serve-and-test:static": { "options": { "commands": [ - "npx concurrently --kill-others --success=first -n SB,TEST 'nx storybook:static {projectName} --configuration=test --port={args.port}' 'npx wait-on tcp:{args.port} && nx storybook:test {projectName} --port={args.port} --configuration={args.scope}'" + "npx concurrently --kill-others --success=first -n SB,TEST 'nx storybook:serve:static {projectName} --port={args.port}' 'npx wait-on tcp:{args.port} && nx storybook:test {projectName} --port={args.port} --configuration={args.scope}'" ], "port": 6006 }, @@ -122,7 +108,15 @@ "performance": { "scope": "performance" } } }, - "storybook:performance:test": {}, + "storybook:serve-and-test:static:performance": {}, + "storybook:test:no-coverage": { + "configurations": { + "docs": { "env": { "STORYBOOK_SCOPE": "ui-docs" } }, + "modules": { "env": { "STORYBOOK_SCOPE": "modules" } }, + "pages": { "env": { "STORYBOOK_SCOPE": "pages" } }, + "performance": { "env": { "STORYBOOK_SCOPE": "performance" } } + } + }, "graphql:generate": { "executor": "nx:run-commands", "defaultConfiguration": "data", diff --git a/packages/twenty-front/src/App.tsx b/packages/twenty-front/src/App.tsx index 956a6c59e33a..4ea9a6ad3df5 100644 --- a/packages/twenty-front/src/App.tsx +++ b/packages/twenty-front/src/App.tsx @@ -53,9 +53,7 @@ import { PaymentSuccess } from '~/pages/onboarding/PaymentSuccess'; import { SyncEmails } from '~/pages/onboarding/SyncEmails'; import { SettingsAccounts } from '~/pages/settings/accounts/SettingsAccounts'; import { SettingsAccountsCalendars } from '~/pages/settings/accounts/SettingsAccountsCalendars'; -import { SettingsAccountsCalendarsSettings } from '~/pages/settings/accounts/SettingsAccountsCalendarsSettings'; import { SettingsAccountsEmails } from '~/pages/settings/accounts/SettingsAccountsEmails'; -import { SettingsAccountsEmailsInboxSettings } from '~/pages/settings/accounts/SettingsAccountsEmailsInboxSettings'; import { SettingsNewAccount } from '~/pages/settings/accounts/SettingsNewAccount'; import { SettingsNewObject } from '~/pages/settings/data-model/SettingsNewObject'; import { SettingsObjectDetail } from '~/pages/settings/data-model/SettingsObjectDetail'; @@ -180,18 +178,10 @@ const createRouter = (isBillingEnabled?: boolean) => path={SettingsPath.AccountsCalendars} element={<SettingsAccountsCalendars />} /> - <Route - path={SettingsPath.AccountsCalendarsSettings} - element={<SettingsAccountsCalendarsSettings />} - /> <Route path={SettingsPath.AccountsEmails} element={<SettingsAccountsEmails />} /> - <Route - path={SettingsPath.AccountsEmailsInboxSettings} - element={<SettingsAccountsEmailsInboxSettings />} - /> <Route path={SettingsPath.Billing} element={<SettingsBilling />} diff --git a/packages/twenty-front/src/__stories__/App.stories.tsx b/packages/twenty-front/src/__stories__/App.stories.tsx index 761c64f3bb82..c5314b5652a1 100644 --- a/packages/twenty-front/src/__stories__/App.stories.tsx +++ b/packages/twenty-front/src/__stories__/App.stories.tsx @@ -13,7 +13,7 @@ import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/Sn import { GET_CURRENT_USER } from '@/users/graphql/queries/getCurrentUser'; import { App } from '~/App'; import { graphqlMocks } from '~/testing/graphqlMocks'; -import { mockedUsersData } from '~/testing/mock-data/users'; +import { mockedUserData } from '~/testing/mock-data/users'; const meta: Meta<typeof App> = { title: 'App/App', @@ -67,9 +67,9 @@ export const DarkMode: Story = { return HttpResponse.json({ data: { currentUser: { - ...mockedUsersData[0], + ...mockedUserData, workspaceMember: { - ...mockedUsersData[0].workspaceMember, + ...mockedUserData.workspaceMember, colorScheme: 'Dark', }, }, diff --git a/packages/twenty-front/src/generated-metadata/graphql.ts b/packages/twenty-front/src/generated-metadata/graphql.ts index 05155eaa108e..958328038e5c 100644 --- a/packages/twenty-front/src/generated-metadata/graphql.ts +++ b/packages/twenty-front/src/generated-metadata/graphql.ts @@ -36,6 +36,11 @@ export type Analytics = { success: Scalars['Boolean']['output']; }; +export type ApiConfig = { + __typename?: 'ApiConfig'; + mutationMaximumAffectedRecords: Scalars['Float']['output']; +}; + export type ApiKeyToken = { __typename?: 'ApiKeyToken'; token: Scalars['String']['output']; @@ -98,8 +103,8 @@ export type Billing = { export type BillingSubscription = { __typename?: 'BillingSubscription'; id: Scalars['UUID']['output']; - interval?: Maybe<Scalars['String']['output']>; - status: Scalars['String']['output']; + interval?: Maybe<SubscriptionInterval>; + status: SubscriptionStatus; }; export type BillingSubscriptionFilter = { @@ -136,12 +141,13 @@ export type Captcha = { }; export enum CaptchaDriverType { - GoogleRecatpcha = 'GoogleRecatpcha', + GoogleRecaptcha = 'GoogleRecaptcha', Turnstile = 'Turnstile' } export type ClientConfig = { __typename?: 'ClientConfig'; + api: ApiConfig; authProviders: AuthProviders; billing: Billing; captcha: Captcha; @@ -327,7 +333,6 @@ export enum FieldMetadataType { Numeric = 'NUMERIC', Phone = 'PHONE', Position = 'POSITION', - Probability = 'PROBABILITY', Rating = 'RATING', RawJson = 'RAW_JSON', Relation = 'RELATION', @@ -398,7 +403,9 @@ export type Mutation = { deleteOneRelation: Relation; deleteOneRemoteServer: RemoteServer; deleteUser: User; + disablePostgresProxy: PostgresCredentials; emailPasswordResetLink: EmailPasswordResetLink; + enablePostgresProxy: PostgresCredentials; exchangeAuthorizationCode: ExchangeAuthCode; generateApiKeyToken: ApiKeyToken; generateJWT: AuthTokens; @@ -451,7 +458,7 @@ export type MutationChallengeArgs = { export type MutationCheckoutSessionArgs = { - recurringInterval: Scalars['String']['input']; + recurringInterval: SubscriptionInterval; successUrlPath?: InputMaybe<Scalars['String']['input']>; }; @@ -636,10 +643,14 @@ export type ObjectFieldsConnection = { pageInfo: PageInfo; }; -/** Onboarding step */ -export enum OnboardingStep { +/** Onboarding status */ +export enum OnboardingStatus { + Completed = 'COMPLETED', InviteTeam = 'INVITE_TEAM', - SyncEmail = 'SYNC_EMAIL' + PlanRequired = 'PLAN_REQUIRED', + ProfileCreation = 'PROFILE_CREATION', + SyncEmail = 'SYNC_EMAIL', + WorkspaceActivation = 'WORKSPACE_ACTIVATION' } export type OnboardingStepSuccess = { @@ -660,10 +671,18 @@ export type PageInfo = { startCursor?: Maybe<Scalars['ConnectionCursor']['output']>; }; +export type PostgresCredentials = { + __typename?: 'PostgresCredentials'; + id: Scalars['UUID']['output']; + password: Scalars['String']['output']; + user: Scalars['String']['output']; + workspaceId: Scalars['String']['output']; +}; + export type ProductPriceEntity = { __typename?: 'ProductPriceEntity'; created: Scalars['Float']['output']; - recurringInterval: Scalars['String']['output']; + recurringInterval: SubscriptionInterval; stripePriceId: Scalars['String']['output']; unitAmount: Scalars['Float']['output']; }; @@ -688,6 +707,7 @@ export type Query = { findManyRemoteServersByType: Array<RemoteServer>; findOneRemoteServerById: RemoteServer; findWorkspaceFromInviteHash: Workspace; + getPostgresCredentials?: Maybe<PostgresCredentials>; getProductPrices: ProductPricesEntity; getTimelineCalendarEventsFromCompanyId: TimelineCalendarEventsWithTotal; getTimelineCalendarEventsFromPersonId: TimelineCalendarEventsWithTotal; @@ -912,6 +932,24 @@ export enum SortNulls { NullsLast = 'NULLS_LAST' } +export enum SubscriptionInterval { + Day = 'Day', + Month = 'Month', + Week = 'Week', + Year = 'Year' +} + +export enum SubscriptionStatus { + Active = 'Active', + Canceled = 'Canceled', + Incomplete = 'Incomplete', + IncompleteExpired = 'IncompleteExpired', + PastDue = 'PastDue', + Paused = 'Paused', + Trialing = 'Trialing', + Unpaid = 'Unpaid' +} + export type Support = { __typename?: 'Support'; supportDriver: Scalars['String']['output']; @@ -1084,7 +1122,7 @@ export type User = { firstName: Scalars['String']['output']; id: Scalars['UUID']['output']; lastName: Scalars['String']['output']; - onboardingStep?: Maybe<OnboardingStep>; + onboardingStatus?: Maybe<OnboardingStatus>; passwordHash?: Maybe<Scalars['String']['output']>; /** @deprecated field migrated into the AppTokens Table ref: https://github.com/twentyhq/twenty/issues/5021 */ passwordResetToken?: Maybe<Scalars['String']['output']>; @@ -1163,8 +1201,8 @@ export type Workspace = { id: Scalars['UUID']['output']; inviteHash?: Maybe<Scalars['String']['output']>; logo?: Maybe<Scalars['String']['output']>; - subscriptionStatus: Scalars['String']['output']; updatedAt: Scalars['DateTime']['output']; + workspaceMembersCount?: Maybe<Scalars['Float']['output']>; }; diff --git a/packages/twenty-front/src/generated/graphql.tsx b/packages/twenty-front/src/generated/graphql.tsx index d153c73c0ada..4b1a828b4469 100644 --- a/packages/twenty-front/src/generated/graphql.tsx +++ b/packages/twenty-front/src/generated/graphql.tsx @@ -20,6 +20,13 @@ export type Scalars = { Upload: any; }; +export type AisqlQueryResult = { + __typename?: 'AISQLQueryResult'; + queryFailedErrorMessage?: Maybe<Scalars['String']>; + sqlQuery: Scalars['String']; + sqlQueryResult?: Maybe<Scalars['String']>; +}; + export type ActivateWorkspaceInput = { displayName?: InputMaybe<Scalars['String']>; }; @@ -30,6 +37,11 @@ export type Analytics = { success: Scalars['Boolean']; }; +export type ApiConfig = { + __typename?: 'ApiConfig'; + mutationMaximumAffectedRecords: Scalars['Float']; +}; + export type ApiKeyToken = { __typename?: 'ApiKeyToken'; token: Scalars['String']; @@ -92,8 +104,8 @@ export type Billing = { export type BillingSubscription = { __typename?: 'BillingSubscription'; id: Scalars['UUID']; - interval?: Maybe<Scalars['String']>; - status: Scalars['String']; + interval?: Maybe<SubscriptionInterval>; + status: SubscriptionStatus; }; export type BillingSubscriptionFilter = { @@ -130,12 +142,13 @@ export type Captcha = { }; export enum CaptchaDriverType { - GoogleRecatpcha = 'GoogleRecatpcha', + GoogleRecaptcha = 'GoogleRecaptcha', Turnstile = 'Turnstile' } export type ClientConfig = { __typename?: 'ClientConfig'; + api: ApiConfig; authProviders: AuthProviders; billing: Billing; captcha: Captcha; @@ -233,7 +246,6 @@ export enum FieldMetadataType { Numeric = 'NUMERIC', Phone = 'PHONE', Position = 'POSITION', - Probability = 'PROBABILITY', Rating = 'RATING', RawJson = 'RAW_JSON', Relation = 'RELATION', @@ -291,7 +303,9 @@ export type Mutation = { deleteCurrentWorkspace: Workspace; deleteOneObject: Object; deleteUser: User; + disablePostgresProxy: PostgresCredentials; emailPasswordResetLink: EmailPasswordResetLink; + enablePostgresProxy: PostgresCredentials; exchangeAuthorizationCode: ExchangeAuthCode; generateApiKeyToken: ApiKeyToken; generateJWT: AuthTokens; @@ -339,7 +353,7 @@ export type MutationChallengeArgs = { export type MutationCheckoutSessionArgs = { - recurringInterval: Scalars['String']; + recurringInterval: SubscriptionInterval; successUrlPath?: InputMaybe<Scalars['String']>; }; @@ -459,10 +473,14 @@ export type ObjectFieldsConnection = { pageInfo: PageInfo; }; -/** Onboarding step */ -export enum OnboardingStep { +/** Onboarding status */ +export enum OnboardingStatus { + Completed = 'COMPLETED', InviteTeam = 'INVITE_TEAM', - SyncEmail = 'SYNC_EMAIL' + PlanRequired = 'PLAN_REQUIRED', + ProfileCreation = 'PROFILE_CREATION', + SyncEmail = 'SYNC_EMAIL', + WorkspaceActivation = 'WORKSPACE_ACTIVATION' } export type OnboardingStepSuccess = { @@ -483,10 +501,18 @@ export type PageInfo = { startCursor?: Maybe<Scalars['ConnectionCursor']>; }; +export type PostgresCredentials = { + __typename?: 'PostgresCredentials'; + id: Scalars['UUID']; + password: Scalars['String']; + user: Scalars['String']; + workspaceId: Scalars['String']; +}; + export type ProductPriceEntity = { __typename?: 'ProductPriceEntity'; created: Scalars['Float']; - recurringInterval: Scalars['String']; + recurringInterval: SubscriptionInterval; stripePriceId: Scalars['String']; unitAmount: Scalars['Float']; }; @@ -506,6 +532,8 @@ export type Query = { currentUser: User; currentWorkspace: Workspace; findWorkspaceFromInviteHash: Workspace; + getAISQLQuery: AisqlQueryResult; + getPostgresCredentials?: Maybe<PostgresCredentials>; getProductPrices: ProductPricesEntity; getTimelineCalendarEventsFromCompanyId: TimelineCalendarEventsWithTotal; getTimelineCalendarEventsFromPersonId: TimelineCalendarEventsWithTotal; @@ -538,6 +566,11 @@ export type QueryFindWorkspaceFromInviteHashArgs = { }; +export type QueryGetAisqlQueryArgs = { + text: Scalars['String']; +}; + + export type QueryGetProductPricesArgs = { product: Scalars['String']; }; @@ -667,6 +700,24 @@ export enum SortNulls { NullsLast = 'NULLS_LAST' } +export enum SubscriptionInterval { + Day = 'Day', + Month = 'Month', + Week = 'Week', + Year = 'Year' +} + +export enum SubscriptionStatus { + Active = 'Active', + Canceled = 'Canceled', + Incomplete = 'Incomplete', + IncompleteExpired = 'IncompleteExpired', + PastDue = 'PastDue', + Paused = 'Paused', + Trialing = 'Trialing', + Unpaid = 'Unpaid' +} + export type Support = { __typename?: 'Support'; supportDriver: Scalars['String']; @@ -810,7 +861,7 @@ export type User = { firstName: Scalars['String']; id: Scalars['UUID']; lastName: Scalars['String']; - onboardingStep?: Maybe<OnboardingStep>; + onboardingStatus?: Maybe<OnboardingStatus>; passwordHash?: Maybe<Scalars['String']>; /** @deprecated field migrated into the AppTokens Table ref: https://github.com/twentyhq/twenty/issues/5021 */ passwordResetToken?: Maybe<Scalars['String']>; @@ -879,8 +930,8 @@ export type Workspace = { id: Scalars['UUID']; inviteHash?: Maybe<Scalars['String']>; logo?: Maybe<Scalars['String']>; - subscriptionStatus: Scalars['String']; updatedAt: Scalars['DateTime']; + workspaceMembersCount?: Maybe<Scalars['Float']>; }; @@ -1061,8 +1112,6 @@ export type GetTimelineThreadsFromPersonIdQueryVariables = Exact<{ export type GetTimelineThreadsFromPersonIdQuery = { __typename?: 'Query', getTimelineThreadsFromPersonId: { __typename?: 'TimelineThreadsWithTotal', totalNumberOfThreads: number, timelineThreads: Array<{ __typename?: 'TimelineThread', id: any, read: boolean, visibility: MessageChannelVisibility, lastMessageReceivedAt: string, lastMessageBody: string, subject: string, numberOfMessagesInThread: number, participantCount: number, firstParticipant: { __typename?: 'TimelineThreadParticipant', personId?: any | null, workspaceMemberId?: any | null, firstName: string, lastName: string, displayName: string, avatarUrl: string, handle: string }, lastTwoParticipants: Array<{ __typename?: 'TimelineThreadParticipant', personId?: any | null, workspaceMemberId?: any | null, firstName: string, lastName: string, displayName: string, avatarUrl: string, handle: string }> }> } }; -export type TimelineThreadFragment = { __typename?: 'TimelineThread', id: any, subject: string, lastMessageReceivedAt: string }; - export type TrackMutationVariables = Exact<{ type: Scalars['String']; data: Scalars['JSON']; @@ -1141,7 +1190,7 @@ export type ImpersonateMutationVariables = Exact<{ }>; -export type ImpersonateMutation = { __typename?: 'Mutation', impersonate: { __typename?: 'Verify', user: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, onboardingStep?: OnboardingStep | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } }; +export type ImpersonateMutation = { __typename?: 'Mutation', impersonate: { __typename?: 'Verify', user: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, onboardingStatus?: OnboardingStatus | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, activationStatus: string, currentCacheVersion?: string | null, workspaceMembersCount?: number | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, interval?: SubscriptionInterval | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } }; export type RenewTokenMutationVariables = Exact<{ appToken: Scalars['String']; @@ -1173,7 +1222,7 @@ export type VerifyMutationVariables = Exact<{ }>; -export type VerifyMutation = { __typename?: 'Mutation', verify: { __typename?: 'Verify', user: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, onboardingStep?: OnboardingStep | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } }; +export type VerifyMutation = { __typename?: 'Mutation', verify: { __typename?: 'Verify', user: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, onboardingStatus?: OnboardingStatus | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, activationStatus: string, currentCacheVersion?: string | null, workspaceMembersCount?: number | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, interval?: SubscriptionInterval | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } }; export type CheckUserExistsQueryVariables = Exact<{ email: Scalars['String']; @@ -1198,7 +1247,7 @@ export type BillingPortalSessionQueryVariables = Exact<{ export type BillingPortalSessionQuery = { __typename?: 'Query', billingPortalSession: { __typename?: 'SessionEntity', url?: string | null } }; export type CheckoutSessionMutationVariables = Exact<{ - recurringInterval: Scalars['String']; + recurringInterval: SubscriptionInterval; successUrlPath?: InputMaybe<Scalars['String']>; }>; @@ -1210,7 +1259,7 @@ export type GetProductPricesQueryVariables = Exact<{ }>; -export type GetProductPricesQuery = { __typename?: 'Query', getProductPrices: { __typename?: 'ProductPricesEntity', productPrices: Array<{ __typename?: 'ProductPriceEntity', created: number, recurringInterval: string, stripePriceId: string, unitAmount: number }> } }; +export type GetProductPricesQuery = { __typename?: 'Query', getProductPrices: { __typename?: 'ProductPricesEntity', productPrices: Array<{ __typename?: 'ProductPriceEntity', created: number, recurringInterval: SubscriptionInterval, stripePriceId: string, unitAmount: number }> } }; export type UpdateBillingSubscriptionMutationVariables = Exact<{ [key: string]: never; }>; @@ -1220,14 +1269,21 @@ export type UpdateBillingSubscriptionMutation = { __typename?: 'Mutation', updat export type GetClientConfigQueryVariables = Exact<{ [key: string]: never; }>; -export type GetClientConfigQuery = { __typename?: 'Query', clientConfig: { __typename?: 'ClientConfig', signInPrefilled: boolean, signUpDisabled: boolean, debugMode: boolean, chromeExtensionId?: string | null, authProviders: { __typename?: 'AuthProviders', google: boolean, password: boolean, microsoft: boolean }, billing: { __typename?: 'Billing', isBillingEnabled: boolean, billingUrl?: string | null, billingFreeTrialDurationInDays?: number | null }, telemetry: { __typename?: 'Telemetry', enabled: boolean }, support: { __typename?: 'Support', supportDriver: string, supportFrontChatId?: string | null }, sentry: { __typename?: 'Sentry', dsn?: string | null, environment?: string | null, release?: string | null }, captcha: { __typename?: 'Captcha', provider?: CaptchaDriverType | null, siteKey?: string | null } } }; +export type GetClientConfigQuery = { __typename?: 'Query', clientConfig: { __typename?: 'ClientConfig', signInPrefilled: boolean, signUpDisabled: boolean, debugMode: boolean, chromeExtensionId?: string | null, authProviders: { __typename?: 'AuthProviders', google: boolean, password: boolean, microsoft: boolean }, billing: { __typename?: 'Billing', isBillingEnabled: boolean, billingUrl?: string | null, billingFreeTrialDurationInDays?: number | null }, telemetry: { __typename?: 'Telemetry', enabled: boolean }, support: { __typename?: 'Support', supportDriver: string, supportFrontChatId?: string | null }, sentry: { __typename?: 'Sentry', dsn?: string | null, environment?: string | null, release?: string | null }, captcha: { __typename?: 'Captcha', provider?: CaptchaDriverType | null, siteKey?: string | null }, api: { __typename?: 'ApiConfig', mutationMaximumAffectedRecords: number } } }; export type SkipSyncEmailOnboardingStepMutationVariables = Exact<{ [key: string]: never; }>; export type SkipSyncEmailOnboardingStepMutation = { __typename?: 'Mutation', skipSyncEmailOnboardingStep: { __typename?: 'OnboardingStepSuccess', success: boolean } }; -export type UserQueryFragmentFragment = { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, onboardingStep?: OnboardingStep | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }; +export type GetAisqlQueryQueryVariables = Exact<{ + text: Scalars['String']; +}>; + + +export type GetAisqlQueryQuery = { __typename?: 'Query', getAISQLQuery: { __typename?: 'AISQLQueryResult', sqlQuery: string, sqlQueryResult?: string | null, queryFailedErrorMessage?: string | null } }; + +export type UserQueryFragmentFragment = { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, onboardingStatus?: OnboardingStatus | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, activationStatus: string, currentCacheVersion?: string | null, workspaceMembersCount?: number | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, interval?: SubscriptionInterval | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }; export type DeleteUserAccountMutationVariables = Exact<{ [key: string]: never; }>; @@ -1244,7 +1300,7 @@ export type UploadProfilePictureMutation = { __typename?: 'Mutation', uploadProf export type GetCurrentUserQueryVariables = Exact<{ [key: string]: never; }>; -export type GetCurrentUserQuery = { __typename?: 'Query', currentUser: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, onboardingStep?: OnboardingStep | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> } }; +export type GetCurrentUserQuery = { __typename?: 'Query', currentUser: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, onboardingStatus?: OnboardingStatus | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, activationStatus: string, currentCacheVersion?: string | null, workspaceMembersCount?: number | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, interval?: SubscriptionInterval | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> } }; export type AddUserToWorkspaceMutationVariables = Exact<{ inviteHash: Scalars['String']; @@ -1277,7 +1333,7 @@ export type UpdateWorkspaceMutationVariables = Exact<{ }>; -export type UpdateWorkspaceMutation = { __typename?: 'Mutation', updateWorkspace: { __typename?: 'Workspace', id: any, domainName?: string | null, displayName?: string | null, logo?: string | null, allowImpersonation: boolean, subscriptionStatus: string } }; +export type UpdateWorkspaceMutation = { __typename?: 'Mutation', updateWorkspace: { __typename?: 'Workspace', id: any, domainName?: string | null, displayName?: string | null, logo?: string | null, allowImpersonation: boolean } }; export type UploadWorkspaceLogoMutationVariables = Exact<{ file: Scalars['Upload']; @@ -1364,13 +1420,6 @@ export const TimelineThreadsWithTotalFragmentFragmentDoc = gql` } } ${TimelineThreadFragmentFragmentDoc}`; -export const TimelineThreadFragmentDoc = gql` - fragment timelineThread on TimelineThread { - id - subject - lastMessageReceivedAt -} - `; export const AuthTokenFragmentFragmentDoc = gql` fragment AuthTokenFragment on AuthToken { token @@ -1395,7 +1444,7 @@ export const UserQueryFragmentFragmentDoc = gql` email canImpersonate supportUserHash - onboardingStep + onboardingStatus workspaceMember { id name { @@ -1413,7 +1462,6 @@ export const UserQueryFragmentFragmentDoc = gql` domainName inviteHash allowImpersonation - subscriptionStatus activationStatus featureFlags { id @@ -1427,6 +1475,7 @@ export const UserQueryFragmentFragmentDoc = gql` status interval } + workspaceMembersCount } workspaces { workspace { @@ -2213,7 +2262,7 @@ export type BillingPortalSessionQueryHookResult = ReturnType<typeof useBillingPo export type BillingPortalSessionLazyQueryHookResult = ReturnType<typeof useBillingPortalSessionLazyQuery>; export type BillingPortalSessionQueryResult = Apollo.QueryResult<BillingPortalSessionQuery, BillingPortalSessionQueryVariables>; export const CheckoutSessionDocument = gql` - mutation CheckoutSession($recurringInterval: String!, $successUrlPath: String) { + mutation CheckoutSession($recurringInterval: SubscriptionInterval!, $successUrlPath: String) { checkoutSession( recurringInterval: $recurringInterval successUrlPath: $successUrlPath @@ -2353,6 +2402,9 @@ export const GetClientConfigDocument = gql` provider siteKey } + api { + mutationMaximumAffectedRecords + } chromeExtensionId } } @@ -2416,6 +2468,43 @@ export function useSkipSyncEmailOnboardingStepMutation(baseOptions?: Apollo.Muta export type SkipSyncEmailOnboardingStepMutationHookResult = ReturnType<typeof useSkipSyncEmailOnboardingStepMutation>; export type SkipSyncEmailOnboardingStepMutationResult = Apollo.MutationResult<SkipSyncEmailOnboardingStepMutation>; export type SkipSyncEmailOnboardingStepMutationOptions = Apollo.BaseMutationOptions<SkipSyncEmailOnboardingStepMutation, SkipSyncEmailOnboardingStepMutationVariables>; +export const GetAisqlQueryDocument = gql` + query GetAISQLQuery($text: String!) { + getAISQLQuery(text: $text) { + sqlQuery + sqlQueryResult + queryFailedErrorMessage + } +} + `; + +/** + * __useGetAisqlQueryQuery__ + * + * To run a query within a React component, call `useGetAisqlQueryQuery` and pass it any options that fit your needs. + * When your component renders, `useGetAisqlQueryQuery` 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 } = useGetAisqlQueryQuery({ + * variables: { + * text: // value for 'text' + * }, + * }); + */ +export function useGetAisqlQueryQuery(baseOptions: Apollo.QueryHookOptions<GetAisqlQueryQuery, GetAisqlQueryQueryVariables>) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery<GetAisqlQueryQuery, GetAisqlQueryQueryVariables>(GetAisqlQueryDocument, options); + } +export function useGetAisqlQueryLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<GetAisqlQueryQuery, GetAisqlQueryQueryVariables>) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery<GetAisqlQueryQuery, GetAisqlQueryQueryVariables>(GetAisqlQueryDocument, options); + } +export type GetAisqlQueryQueryHookResult = ReturnType<typeof useGetAisqlQueryQuery>; +export type GetAisqlQueryLazyQueryHookResult = ReturnType<typeof useGetAisqlQueryLazyQuery>; +export type GetAisqlQueryQueryResult = Apollo.QueryResult<GetAisqlQueryQuery, GetAisqlQueryQueryVariables>; export const DeleteUserAccountDocument = gql` mutation DeleteUserAccount { deleteUser { @@ -2652,7 +2741,6 @@ export const UpdateWorkspaceDocument = gql` displayName logo allowImpersonation - subscriptionStatus } } `; diff --git a/packages/twenty-front/src/hooks/__tests__/useDefaultHomePagePath.test.ts b/packages/twenty-front/src/hooks/__tests__/useDefaultHomePagePath.test.ts index 1d2834937e35..709c071cce76 100644 --- a/packages/twenty-front/src/hooks/__tests__/useDefaultHomePagePath.test.ts +++ b/packages/twenty-front/src/hooks/__tests__/useDefaultHomePagePath.test.ts @@ -7,7 +7,7 @@ import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMet import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData'; import { AppPath } from '@/types/AppPath'; import { useDefaultHomePagePath } from '~/hooks/useDefaultHomePagePath'; -import { mockedUsersData } from '~/testing/mock-data/users'; +import { mockedUserData } from '~/testing/mock-data/users'; const objectMetadataItem = getObjectMetadataItemsMock()[0]; jest.mock('@/object-metadata/hooks/useObjectMetadataItem'); @@ -36,7 +36,7 @@ const renderHooks = (withCurrentUser: boolean) => { () => { const setCurrentUser = useSetRecoilState(currentUserState); if (withCurrentUser) { - setCurrentUser(mockedUsersData[0]); + setCurrentUser(mockedUserData); } return useDefaultHomePagePath(); }, diff --git a/packages/twenty-front/src/hooks/__tests__/usePageChangeEffectNavigateLocation.test.ts b/packages/twenty-front/src/hooks/__tests__/usePageChangeEffectNavigateLocation.test.ts index cf9a7730cd94..327e940ac3a5 100644 --- a/packages/twenty-front/src/hooks/__tests__/usePageChangeEffectNavigateLocation.test.ts +++ b/packages/twenty-front/src/hooks/__tests__/usePageChangeEffectNavigateLocation.test.ts @@ -1,15 +1,26 @@ -import { useOnboardingStatus } from '@/auth/hooks/useOnboardingStatus'; -import { OnboardingStatus } from '@/auth/utils/getOnboardingStatus'; +import { useIsLogged } from '@/auth/hooks/useIsLogged'; +import { useOnboardingStatus } from '@/onboarding/hooks/useOnboardingStatus'; import { AppPath } from '@/types/AppPath'; +import { useSubscriptionStatus } from '@/workspace/hooks/useSubscriptionStatus'; +import { OnboardingStatus, SubscriptionStatus } from '~/generated/graphql'; import { useDefaultHomePagePath } from '~/hooks/useDefaultHomePagePath'; import { useIsMatchingLocation } from '~/hooks/useIsMatchingLocation'; import { usePageChangeEffectNavigateLocation } from '~/hooks/usePageChangeEffectNavigateLocation'; -jest.mock('@/auth/hooks/useOnboardingStatus'); -const setupMockOnboardingStatus = (onboardingStatus: OnboardingStatus) => { +jest.mock('@/onboarding/hooks/useOnboardingStatus'); +const setupMockOnboardingStatus = ( + onboardingStatus: OnboardingStatus | undefined, +) => { jest.mocked(useOnboardingStatus).mockReturnValueOnce(onboardingStatus); }; +jest.mock('@/workspace/hooks/useSubscriptionStatus'); +const setupMockSubscriptionStatus = ( + subscriptionStatus: SubscriptionStatus | undefined, +) => { + jest.mocked(useSubscriptionStatus).mockReturnValueOnce(subscriptionStatus); +}; + jest.mock('~/hooks/useIsMatchingLocation'); const mockUseIsMatchingLocation = jest.mocked(useIsMatchingLocation); @@ -19,281 +30,276 @@ const setupMockIsMatchingLocation = (pathname: string) => { ); }; +jest.mock('@/auth/hooks/useIsLogged'); +const setupMockIsLogged = (isLogged: boolean) => { + jest.mocked(useIsLogged).mockReturnValueOnce(isLogged); +}; + const defaultHomePagePath = '/objects/companies'; jest.mock('~/hooks/useDefaultHomePagePath'); jest.mocked(useDefaultHomePagePath).mockReturnValue({ - defaultHomePagePath: '/objects/companies', + defaultHomePagePath, }); // prettier-ignore const testCases = [ - { loc: AppPath.Verify, status: OnboardingStatus.Incomplete, res: AppPath.PlanRequired }, - { loc: AppPath.Verify, status: OnboardingStatus.Canceled, res: '/settings/billing' }, - { loc: AppPath.Verify, status: OnboardingStatus.Unpaid, res: '/settings/billing' }, - { loc: AppPath.Verify, status: OnboardingStatus.PastDue, res: undefined }, - { loc: AppPath.Verify, status: OnboardingStatus.OngoingUserCreation, res: undefined }, - { loc: AppPath.Verify, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace }, - { loc: AppPath.Verify, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile }, - { loc: AppPath.Verify, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails }, - { loc: AppPath.Verify, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam }, - { loc: AppPath.Verify, status: OnboardingStatus.Completed, res: defaultHomePagePath }, - { loc: AppPath.Verify, status: OnboardingStatus.CompletedWithoutSubscription, res: defaultHomePagePath }, + { loc: AppPath.Verify, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired }, + { loc: AppPath.Verify, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.Verify, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.Verify, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: defaultHomePagePath }, + { loc: AppPath.Verify, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: undefined }, + { loc: AppPath.Verify, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: AppPath.CreateWorkspace }, + { loc: AppPath.Verify, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile }, + { loc: AppPath.Verify, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails }, + { loc: AppPath.Verify, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam }, + { loc: AppPath.Verify, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: defaultHomePagePath }, - { loc: AppPath.SignInUp, status: OnboardingStatus.Incomplete, res: AppPath.PlanRequired }, - { loc: AppPath.SignInUp, status: OnboardingStatus.Canceled, res: '/settings/billing' }, - { loc: AppPath.SignInUp, status: OnboardingStatus.Unpaid, res: '/settings/billing' }, - { loc: AppPath.SignInUp, status: OnboardingStatus.PastDue, res: undefined }, - { loc: AppPath.SignInUp, status: OnboardingStatus.OngoingUserCreation, res: undefined }, - { loc: AppPath.SignInUp, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace }, - { loc: AppPath.SignInUp, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile }, - { loc: AppPath.SignInUp, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails }, - { loc: AppPath.SignInUp, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam }, - { loc: AppPath.SignInUp, status: OnboardingStatus.Completed, res: defaultHomePagePath }, - { loc: AppPath.SignInUp, status: OnboardingStatus.CompletedWithoutSubscription, res: defaultHomePagePath }, + { loc: AppPath.SignInUp, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired }, + { loc: AppPath.SignInUp, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.SignInUp, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.SignInUp, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: defaultHomePagePath }, + { loc: AppPath.SignInUp, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: undefined }, + { loc: AppPath.SignInUp, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: AppPath.CreateWorkspace }, + { loc: AppPath.SignInUp, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile }, + { loc: AppPath.SignInUp, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails }, + { loc: AppPath.SignInUp, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam }, + { loc: AppPath.SignInUp, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: defaultHomePagePath }, - { loc: AppPath.Invite, status: OnboardingStatus.Incomplete, res: undefined }, - { loc: AppPath.Invite, status: OnboardingStatus.Canceled, res: undefined }, - { loc: AppPath.Invite, status: OnboardingStatus.Unpaid, res: undefined }, - { loc: AppPath.Invite, status: OnboardingStatus.PastDue, res: undefined }, - { loc: AppPath.Invite, status: OnboardingStatus.OngoingUserCreation, res: undefined }, - { loc: AppPath.Invite, status: OnboardingStatus.OngoingWorkspaceActivation, res: undefined }, - { loc: AppPath.Invite, status: OnboardingStatus.OngoingProfileCreation, res: undefined }, - { loc: AppPath.Invite, status: OnboardingStatus.OngoingSyncEmail, res: undefined }, - { loc: AppPath.Invite, status: OnboardingStatus.OngoingInviteTeam, res: undefined }, - { loc: AppPath.Invite, status: OnboardingStatus.Completed, res: undefined }, - { loc: AppPath.Invite, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined }, + { loc: AppPath.Invite, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: undefined }, + { loc: AppPath.Invite, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: undefined }, + { loc: AppPath.Invite, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: undefined }, + { loc: AppPath.Invite, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: undefined }, + { loc: AppPath.Invite, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: undefined }, + { loc: AppPath.Invite, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: undefined }, + { loc: AppPath.Invite, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: undefined }, + { loc: AppPath.Invite, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: undefined }, + { loc: AppPath.Invite, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: undefined }, + { loc: AppPath.Invite, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: undefined }, - { loc: AppPath.ResetPassword, status: OnboardingStatus.Incomplete, res: undefined }, - { loc: AppPath.ResetPassword, status: OnboardingStatus.Canceled, res: undefined }, - { loc: AppPath.ResetPassword, status: OnboardingStatus.Unpaid, res: undefined }, - { loc: AppPath.ResetPassword, status: OnboardingStatus.PastDue, res: undefined }, - { loc: AppPath.ResetPassword, status: OnboardingStatus.OngoingUserCreation, res: undefined }, - { loc: AppPath.ResetPassword, status: OnboardingStatus.OngoingWorkspaceActivation, res: undefined }, - { loc: AppPath.ResetPassword, status: OnboardingStatus.OngoingProfileCreation, res: undefined }, - { loc: AppPath.ResetPassword, status: OnboardingStatus.OngoingSyncEmail, res: undefined }, - { loc: AppPath.ResetPassword, status: OnboardingStatus.OngoingInviteTeam, res: undefined }, - { loc: AppPath.ResetPassword, status: OnboardingStatus.Completed, res: undefined }, - { loc: AppPath.ResetPassword, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined }, + { loc: AppPath.ResetPassword, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: undefined }, + { loc: AppPath.ResetPassword, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: undefined }, + { loc: AppPath.ResetPassword, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: undefined }, + { loc: AppPath.ResetPassword, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: undefined }, + { loc: AppPath.ResetPassword, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: undefined }, + { loc: AppPath.ResetPassword, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: undefined }, + { loc: AppPath.ResetPassword, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: undefined }, + { loc: AppPath.ResetPassword, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: undefined }, + { loc: AppPath.ResetPassword, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: undefined }, + { loc: AppPath.ResetPassword, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: undefined }, - { loc: AppPath.CreateWorkspace, status: OnboardingStatus.Incomplete, res: AppPath.PlanRequired }, - { loc: AppPath.CreateWorkspace, status: OnboardingStatus.Canceled, res: '/settings/billing' }, - { loc: AppPath.CreateWorkspace, status: OnboardingStatus.Unpaid, res: '/settings/billing' }, - { loc: AppPath.CreateWorkspace, status: OnboardingStatus.PastDue, res: undefined }, - { loc: AppPath.CreateWorkspace, status: OnboardingStatus.OngoingUserCreation, res: AppPath.SignInUp }, - { loc: AppPath.CreateWorkspace, status: OnboardingStatus.OngoingWorkspaceActivation, res: undefined }, - { loc: AppPath.CreateWorkspace, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile }, - { loc: AppPath.CreateWorkspace, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails }, - { loc: AppPath.CreateWorkspace, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam }, - { loc: AppPath.CreateWorkspace, status: OnboardingStatus.Completed, res: defaultHomePagePath }, - { loc: AppPath.CreateWorkspace, status: OnboardingStatus.CompletedWithoutSubscription, res: defaultHomePagePath }, + { loc: AppPath.CreateWorkspace, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired }, + { loc: AppPath.CreateWorkspace, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.CreateWorkspace, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.CreateWorkspace, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: defaultHomePagePath }, + { loc: AppPath.CreateWorkspace, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: AppPath.SignInUp }, + { loc: AppPath.CreateWorkspace, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: undefined }, + { loc: AppPath.CreateWorkspace, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile }, + { loc: AppPath.CreateWorkspace, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails }, + { loc: AppPath.CreateWorkspace, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam }, + { loc: AppPath.CreateWorkspace, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: defaultHomePagePath }, - { loc: AppPath.CreateProfile, status: OnboardingStatus.Incomplete, res: AppPath.PlanRequired }, - { loc: AppPath.CreateProfile, status: OnboardingStatus.Canceled, res: '/settings/billing' }, - { loc: AppPath.CreateProfile, status: OnboardingStatus.Unpaid, res: '/settings/billing' }, - { loc: AppPath.CreateProfile, status: OnboardingStatus.PastDue, res: undefined }, - { loc: AppPath.CreateProfile, status: OnboardingStatus.OngoingUserCreation, res: AppPath.SignInUp }, - { loc: AppPath.CreateProfile, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace }, - { loc: AppPath.CreateProfile, status: OnboardingStatus.OngoingProfileCreation, res: undefined }, - { loc: AppPath.CreateProfile, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails }, - { loc: AppPath.CreateProfile, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam }, - { loc: AppPath.CreateProfile, status: OnboardingStatus.Completed, res: defaultHomePagePath }, - { loc: AppPath.CreateProfile, status: OnboardingStatus.CompletedWithoutSubscription, res: defaultHomePagePath }, + { loc: AppPath.CreateProfile, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired }, + { loc: AppPath.CreateProfile, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.CreateProfile, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.CreateProfile, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: defaultHomePagePath }, + { loc: AppPath.CreateProfile, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: AppPath.SignInUp }, + { loc: AppPath.CreateProfile, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: AppPath.CreateWorkspace }, + { loc: AppPath.CreateProfile, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: undefined }, + { loc: AppPath.CreateProfile, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails }, + { loc: AppPath.CreateProfile, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam }, + { loc: AppPath.CreateProfile, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: defaultHomePagePath }, - { loc: AppPath.SyncEmails, status: OnboardingStatus.Incomplete, res: AppPath.PlanRequired }, - { loc: AppPath.SyncEmails, status: OnboardingStatus.Canceled, res: '/settings/billing' }, - { loc: AppPath.SyncEmails, status: OnboardingStatus.Unpaid, res: '/settings/billing' }, - { loc: AppPath.SyncEmails, status: OnboardingStatus.PastDue, res: undefined }, - { loc: AppPath.SyncEmails, status: OnboardingStatus.OngoingUserCreation, res: AppPath.SignInUp }, - { loc: AppPath.SyncEmails, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace }, - { loc: AppPath.SyncEmails, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile }, - { loc: AppPath.SyncEmails, status: OnboardingStatus.OngoingSyncEmail, res: undefined }, - { loc: AppPath.SyncEmails, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam }, - { loc: AppPath.SyncEmails, status: OnboardingStatus.Completed, res: defaultHomePagePath }, - { loc: AppPath.SyncEmails, status: OnboardingStatus.CompletedWithoutSubscription, res: defaultHomePagePath }, + { loc: AppPath.SyncEmails, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired }, + { loc: AppPath.SyncEmails, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.SyncEmails, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.SyncEmails, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: defaultHomePagePath }, + { loc: AppPath.SyncEmails, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: AppPath.SignInUp }, + { loc: AppPath.SyncEmails, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: AppPath.CreateWorkspace }, + { loc: AppPath.SyncEmails, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile }, + { loc: AppPath.SyncEmails, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: undefined }, + { loc: AppPath.SyncEmails, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam }, + { loc: AppPath.SyncEmails, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: defaultHomePagePath }, - { loc: AppPath.InviteTeam, status: OnboardingStatus.Incomplete, res: AppPath.PlanRequired }, - { loc: AppPath.InviteTeam, status: OnboardingStatus.Canceled, res: '/settings/billing' }, - { loc: AppPath.InviteTeam, status: OnboardingStatus.Unpaid, res: '/settings/billing' }, - { loc: AppPath.InviteTeam, status: OnboardingStatus.PastDue, res: undefined }, - { loc: AppPath.InviteTeam, status: OnboardingStatus.OngoingUserCreation, res: AppPath.SignInUp }, - { loc: AppPath.InviteTeam, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace }, - { loc: AppPath.InviteTeam, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile }, - { loc: AppPath.InviteTeam, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails }, - { loc: AppPath.InviteTeam, status: OnboardingStatus.OngoingInviteTeam, res: undefined }, - { loc: AppPath.InviteTeam, status: OnboardingStatus.Completed, res: defaultHomePagePath }, - { loc: AppPath.InviteTeam, status: OnboardingStatus.CompletedWithoutSubscription, res: defaultHomePagePath }, + { loc: AppPath.InviteTeam, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired }, + { loc: AppPath.InviteTeam, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.InviteTeam, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.InviteTeam, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: defaultHomePagePath }, + { loc: AppPath.InviteTeam, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: AppPath.SignInUp }, + { loc: AppPath.InviteTeam, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: AppPath.CreateWorkspace }, + { loc: AppPath.InviteTeam, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile }, + { loc: AppPath.InviteTeam, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails }, + { loc: AppPath.InviteTeam, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: undefined }, + { loc: AppPath.InviteTeam, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: defaultHomePagePath }, - { loc: AppPath.PlanRequired, status: OnboardingStatus.Incomplete, res: undefined }, - { loc: AppPath.PlanRequired, status: OnboardingStatus.Canceled, res: undefined }, - { loc: AppPath.PlanRequired, status: OnboardingStatus.Unpaid, res: undefined }, - { loc: AppPath.PlanRequired, status: OnboardingStatus.PastDue, res: undefined }, - { loc: AppPath.PlanRequired, status: OnboardingStatus.OngoingUserCreation, res: AppPath.SignInUp }, - { loc: AppPath.PlanRequired, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace }, - { loc: AppPath.PlanRequired, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile }, - { loc: AppPath.PlanRequired, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails }, - { loc: AppPath.PlanRequired, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam }, - { loc: AppPath.PlanRequired, status: OnboardingStatus.Completed, res: defaultHomePagePath }, - { loc: AppPath.PlanRequired, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined }, + { loc: AppPath.PlanRequired, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: undefined }, + { loc: AppPath.PlanRequired, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: undefined }, + { loc: AppPath.PlanRequired, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.PlanRequired, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: defaultHomePagePath }, + { loc: AppPath.PlanRequired, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: AppPath.SignInUp }, + { loc: AppPath.PlanRequired, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: AppPath.CreateWorkspace }, + { loc: AppPath.PlanRequired, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile }, + { loc: AppPath.PlanRequired, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails }, + { loc: AppPath.PlanRequired, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam }, + { loc: AppPath.PlanRequired, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: defaultHomePagePath }, - { loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.Incomplete, res: AppPath.PlanRequired }, - { loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.Canceled, res: '/settings/billing' }, - { loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.Unpaid, res: '/settings/billing' }, - { loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.PastDue, res: undefined }, - { loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.OngoingUserCreation, res: AppPath.SignInUp }, - { loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.OngoingWorkspaceActivation, res: undefined }, - { loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile }, - { loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails }, - { loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam }, - { loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.Completed, res: defaultHomePagePath }, - { loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.CompletedWithoutSubscription, res: defaultHomePagePath }, + { loc: AppPath.PlanRequiredSuccess, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired }, + { loc: AppPath.PlanRequiredSuccess, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.PlanRequiredSuccess, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.PlanRequiredSuccess, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: defaultHomePagePath }, + { loc: AppPath.PlanRequiredSuccess, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: AppPath.SignInUp }, + { loc: AppPath.PlanRequiredSuccess, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: undefined }, + { loc: AppPath.PlanRequiredSuccess, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile }, + { loc: AppPath.PlanRequiredSuccess, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails }, + { loc: AppPath.PlanRequiredSuccess, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam }, + { loc: AppPath.PlanRequiredSuccess, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: defaultHomePagePath }, - { loc: AppPath.Index, status: OnboardingStatus.Incomplete, res: AppPath.PlanRequired }, - { loc: AppPath.Index, status: OnboardingStatus.Canceled, res: '/settings/billing' }, - { loc: AppPath.Index, status: OnboardingStatus.Unpaid, res: '/settings/billing' }, - { loc: AppPath.Index, status: OnboardingStatus.PastDue, res: defaultHomePagePath }, - { loc: AppPath.Index, status: OnboardingStatus.OngoingUserCreation, res: AppPath.SignInUp }, - { loc: AppPath.Index, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace }, - { loc: AppPath.Index, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile }, - { loc: AppPath.Index, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails }, - { loc: AppPath.Index, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam }, - { loc: AppPath.Index, status: OnboardingStatus.Completed, res: defaultHomePagePath }, - { loc: AppPath.Index, status: OnboardingStatus.CompletedWithoutSubscription, res: defaultHomePagePath }, + { loc: AppPath.Index, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired }, + { loc: AppPath.Index, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.Index, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.Index, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: defaultHomePagePath }, + { loc: AppPath.Index, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: AppPath.SignInUp }, + { loc: AppPath.Index, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: AppPath.CreateWorkspace }, + { loc: AppPath.Index, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile }, + { loc: AppPath.Index, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails }, + { loc: AppPath.Index, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam }, + { loc: AppPath.Index, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: defaultHomePagePath }, - { loc: AppPath.TasksPage, status: OnboardingStatus.Incomplete, res: AppPath.PlanRequired }, - { loc: AppPath.TasksPage, status: OnboardingStatus.Canceled, res: '/settings/billing' }, - { loc: AppPath.TasksPage, status: OnboardingStatus.Unpaid, res: '/settings/billing' }, - { loc: AppPath.TasksPage, status: OnboardingStatus.PastDue, res: undefined }, - { loc: AppPath.TasksPage, status: OnboardingStatus.OngoingUserCreation, res: AppPath.SignInUp }, - { loc: AppPath.TasksPage, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace }, - { loc: AppPath.TasksPage, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile }, - { loc: AppPath.TasksPage, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails }, - { loc: AppPath.TasksPage, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam }, - { loc: AppPath.TasksPage, status: OnboardingStatus.Completed, res: undefined }, - { loc: AppPath.TasksPage, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined }, + { loc: AppPath.TasksPage, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired }, + { loc: AppPath.TasksPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.TasksPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.TasksPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: undefined }, + { loc: AppPath.TasksPage, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: AppPath.SignInUp }, + { loc: AppPath.TasksPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: AppPath.CreateWorkspace }, + { loc: AppPath.TasksPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile }, + { loc: AppPath.TasksPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails }, + { loc: AppPath.TasksPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam }, + { loc: AppPath.TasksPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: undefined }, - { loc: AppPath.OpportunitiesPage, status: OnboardingStatus.Incomplete, res: AppPath.PlanRequired }, - { loc: AppPath.OpportunitiesPage, status: OnboardingStatus.Canceled, res: '/settings/billing' }, - { loc: AppPath.OpportunitiesPage, status: OnboardingStatus.Unpaid, res: '/settings/billing' }, - { loc: AppPath.OpportunitiesPage, status: OnboardingStatus.PastDue, res: undefined }, - { loc: AppPath.OpportunitiesPage, status: OnboardingStatus.OngoingUserCreation, res: AppPath.SignInUp }, - { loc: AppPath.OpportunitiesPage, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace }, - { loc: AppPath.OpportunitiesPage, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile }, - { loc: AppPath.OpportunitiesPage, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails }, - { loc: AppPath.OpportunitiesPage, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam }, - { loc: AppPath.OpportunitiesPage, status: OnboardingStatus.Completed, res: undefined }, - { loc: AppPath.OpportunitiesPage, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined }, + { loc: AppPath.OpportunitiesPage, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired }, + { loc: AppPath.OpportunitiesPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.OpportunitiesPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.OpportunitiesPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: undefined }, + { loc: AppPath.OpportunitiesPage, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: AppPath.SignInUp }, + { loc: AppPath.OpportunitiesPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: AppPath.CreateWorkspace }, + { loc: AppPath.OpportunitiesPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile }, + { loc: AppPath.OpportunitiesPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails }, + { loc: AppPath.OpportunitiesPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam }, + { loc: AppPath.OpportunitiesPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: undefined }, - { loc: AppPath.RecordIndexPage, status: OnboardingStatus.Incomplete, res: AppPath.PlanRequired }, - { loc: AppPath.RecordIndexPage, status: OnboardingStatus.Canceled, res: '/settings/billing' }, - { loc: AppPath.RecordIndexPage, status: OnboardingStatus.Unpaid, res: '/settings/billing' }, - { loc: AppPath.RecordIndexPage, status: OnboardingStatus.PastDue, res: undefined }, - { loc: AppPath.RecordIndexPage, status: OnboardingStatus.OngoingUserCreation, res: AppPath.SignInUp }, - { loc: AppPath.RecordIndexPage, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace }, - { loc: AppPath.RecordIndexPage, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile }, - { loc: AppPath.RecordIndexPage, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails }, - { loc: AppPath.RecordIndexPage, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam }, - { loc: AppPath.RecordIndexPage, status: OnboardingStatus.Completed, res: undefined }, - { loc: AppPath.RecordIndexPage, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined }, + { loc: AppPath.RecordIndexPage, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired }, + { loc: AppPath.RecordIndexPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.RecordIndexPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.RecordIndexPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: undefined }, + { loc: AppPath.RecordIndexPage, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: AppPath.SignInUp }, + { loc: AppPath.RecordIndexPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: AppPath.CreateWorkspace }, + { loc: AppPath.RecordIndexPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile }, + { loc: AppPath.RecordIndexPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails }, + { loc: AppPath.RecordIndexPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam }, + { loc: AppPath.RecordIndexPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: undefined }, - { loc: AppPath.RecordShowPage, status: OnboardingStatus.Incomplete, res: AppPath.PlanRequired }, - { loc: AppPath.RecordShowPage, status: OnboardingStatus.Canceled, res: '/settings/billing' }, - { loc: AppPath.RecordShowPage, status: OnboardingStatus.Unpaid, res: '/settings/billing' }, - { loc: AppPath.RecordShowPage, status: OnboardingStatus.PastDue, res: undefined }, - { loc: AppPath.RecordShowPage, status: OnboardingStatus.OngoingUserCreation, res: AppPath.SignInUp }, - { loc: AppPath.RecordShowPage, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace }, - { loc: AppPath.RecordShowPage, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile }, - { loc: AppPath.RecordShowPage, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails }, - { loc: AppPath.RecordShowPage, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam }, - { loc: AppPath.RecordShowPage, status: OnboardingStatus.Completed, res: undefined }, - { loc: AppPath.RecordShowPage, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined }, + { loc: AppPath.RecordShowPage, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired }, + { loc: AppPath.RecordShowPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.RecordShowPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.RecordShowPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: undefined }, + { loc: AppPath.RecordShowPage, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: AppPath.SignInUp }, + { loc: AppPath.RecordShowPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: AppPath.CreateWorkspace }, + { loc: AppPath.RecordShowPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile }, + { loc: AppPath.RecordShowPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails }, + { loc: AppPath.RecordShowPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam }, + { loc: AppPath.RecordShowPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: undefined }, - { loc: AppPath.SettingsCatchAll, status: OnboardingStatus.Incomplete, res: AppPath.PlanRequired }, - { loc: AppPath.SettingsCatchAll, status: OnboardingStatus.Canceled, res: undefined }, - { loc: AppPath.SettingsCatchAll, status: OnboardingStatus.Unpaid, res: undefined }, - { loc: AppPath.SettingsCatchAll, status: OnboardingStatus.PastDue, res: undefined }, - { loc: AppPath.SettingsCatchAll, status: OnboardingStatus.OngoingUserCreation, res: AppPath.SignInUp }, - { loc: AppPath.SettingsCatchAll, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace }, - { loc: AppPath.SettingsCatchAll, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile }, - { loc: AppPath.SettingsCatchAll, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails }, - { loc: AppPath.SettingsCatchAll, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam }, - { loc: AppPath.SettingsCatchAll, status: OnboardingStatus.Completed, res: undefined }, - { loc: AppPath.SettingsCatchAll, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined }, + { loc: AppPath.SettingsCatchAll, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired }, + { loc: AppPath.SettingsCatchAll, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: undefined }, + { loc: AppPath.SettingsCatchAll, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: undefined }, + { loc: AppPath.SettingsCatchAll, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: undefined }, + { loc: AppPath.SettingsCatchAll, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: AppPath.SignInUp }, + { loc: AppPath.SettingsCatchAll, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: AppPath.CreateWorkspace }, + { loc: AppPath.SettingsCatchAll, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile }, + { loc: AppPath.SettingsCatchAll, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails }, + { loc: AppPath.SettingsCatchAll, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam }, + { loc: AppPath.SettingsCatchAll, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: undefined }, - { loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.Incomplete, res: AppPath.PlanRequired }, - { loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.Canceled, res: '/settings/billing' }, - { loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.Unpaid, res: '/settings/billing' }, - { loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.PastDue, res: undefined }, - { loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.OngoingUserCreation, res: AppPath.SignInUp }, - { loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace }, - { loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile }, - { loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails }, - { loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam }, - { loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.Completed, res: undefined }, - { loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined }, + { loc: AppPath.DevelopersCatchAll, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired }, + { loc: AppPath.DevelopersCatchAll, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.DevelopersCatchAll, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.DevelopersCatchAll, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: undefined }, + { loc: AppPath.DevelopersCatchAll, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: AppPath.SignInUp }, + { loc: AppPath.DevelopersCatchAll, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: AppPath.CreateWorkspace }, + { loc: AppPath.DevelopersCatchAll, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile }, + { loc: AppPath.DevelopersCatchAll, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails }, + { loc: AppPath.DevelopersCatchAll, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam }, + { loc: AppPath.DevelopersCatchAll, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: undefined }, - { loc: AppPath.Impersonate, status: OnboardingStatus.Incomplete, res: AppPath.PlanRequired }, - { loc: AppPath.Impersonate, status: OnboardingStatus.Canceled, res: '/settings/billing' }, - { loc: AppPath.Impersonate, status: OnboardingStatus.Unpaid, res: '/settings/billing' }, - { loc: AppPath.Impersonate, status: OnboardingStatus.PastDue, res: undefined }, - { loc: AppPath.Impersonate, status: OnboardingStatus.OngoingUserCreation, res: AppPath.SignInUp }, - { loc: AppPath.Impersonate, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace }, - { loc: AppPath.Impersonate, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile }, - { loc: AppPath.Impersonate, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails }, - { loc: AppPath.Impersonate, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam }, - { loc: AppPath.Impersonate, status: OnboardingStatus.Completed, res: undefined }, - { loc: AppPath.Impersonate, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined }, + { loc: AppPath.Impersonate, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired }, + { loc: AppPath.Impersonate, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.Impersonate, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.Impersonate, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: undefined }, + { loc: AppPath.Impersonate, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: AppPath.SignInUp }, + { loc: AppPath.Impersonate, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: AppPath.CreateWorkspace }, + { loc: AppPath.Impersonate, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile }, + { loc: AppPath.Impersonate, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails }, + { loc: AppPath.Impersonate, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam }, + { loc: AppPath.Impersonate, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: undefined }, - { loc: AppPath.Authorize, status: OnboardingStatus.Incomplete, res: AppPath.PlanRequired }, - { loc: AppPath.Authorize, status: OnboardingStatus.Canceled, res: '/settings/billing' }, - { loc: AppPath.Authorize, status: OnboardingStatus.Unpaid, res: '/settings/billing' }, - { loc: AppPath.Authorize, status: OnboardingStatus.PastDue, res: undefined }, - { loc: AppPath.Authorize, status: OnboardingStatus.OngoingUserCreation, res: AppPath.SignInUp }, - { loc: AppPath.Authorize, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace }, - { loc: AppPath.Authorize, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile }, - { loc: AppPath.Authorize, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails }, - { loc: AppPath.Authorize, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam }, - { loc: AppPath.Authorize, status: OnboardingStatus.Completed, res: undefined }, - { loc: AppPath.Authorize, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined }, + { loc: AppPath.Authorize, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired }, + { loc: AppPath.Authorize, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.Authorize, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.Authorize, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: undefined }, + { loc: AppPath.Authorize, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: AppPath.SignInUp }, + { loc: AppPath.Authorize, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: AppPath.CreateWorkspace }, + { loc: AppPath.Authorize, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile }, + { loc: AppPath.Authorize, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails }, + { loc: AppPath.Authorize, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam }, + { loc: AppPath.Authorize, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: undefined }, - { loc: AppPath.NotFoundWildcard, status: OnboardingStatus.Incomplete, res: AppPath.PlanRequired }, - { loc: AppPath.NotFoundWildcard, status: OnboardingStatus.Canceled, res: '/settings/billing' }, - { loc: AppPath.NotFoundWildcard, status: OnboardingStatus.Unpaid, res: '/settings/billing' }, - { loc: AppPath.NotFoundWildcard, status: OnboardingStatus.PastDue, res: undefined }, - { loc: AppPath.NotFoundWildcard, status: OnboardingStatus.OngoingUserCreation, res: AppPath.SignInUp }, - { loc: AppPath.NotFoundWildcard, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace }, - { loc: AppPath.NotFoundWildcard, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile }, - { loc: AppPath.NotFoundWildcard, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails }, - { loc: AppPath.NotFoundWildcard, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam }, - { loc: AppPath.NotFoundWildcard, status: OnboardingStatus.Completed, res: undefined }, - { loc: AppPath.NotFoundWildcard, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined }, + { loc: AppPath.NotFoundWildcard, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired }, + { loc: AppPath.NotFoundWildcard, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.NotFoundWildcard, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.NotFoundWildcard, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: undefined }, + { loc: AppPath.NotFoundWildcard, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: AppPath.SignInUp }, + { loc: AppPath.NotFoundWildcard, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: AppPath.CreateWorkspace }, + { loc: AppPath.NotFoundWildcard, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile }, + { loc: AppPath.NotFoundWildcard, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails }, + { loc: AppPath.NotFoundWildcard, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam }, + { loc: AppPath.NotFoundWildcard, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: undefined }, - { loc: AppPath.NotFound, status: OnboardingStatus.Incomplete, res: AppPath.PlanRequired }, - { loc: AppPath.NotFound, status: OnboardingStatus.Canceled, res: '/settings/billing' }, - { loc: AppPath.NotFound, status: OnboardingStatus.Unpaid, res: '/settings/billing' }, - { loc: AppPath.NotFound, status: OnboardingStatus.PastDue, res: undefined }, - { loc: AppPath.NotFound, status: OnboardingStatus.OngoingUserCreation, res: AppPath.SignInUp }, - { loc: AppPath.NotFound, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace }, - { loc: AppPath.NotFound, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile }, - { loc: AppPath.NotFound, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails }, - { loc: AppPath.NotFound, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam }, - { loc: AppPath.NotFound, status: OnboardingStatus.Completed, res: undefined }, - { loc: AppPath.NotFound, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined }, + { loc: AppPath.NotFound, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired }, + { loc: AppPath.NotFound, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.NotFound, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.NotFound, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: undefined }, + { loc: AppPath.NotFound, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: AppPath.SignInUp }, + { loc: AppPath.NotFound, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: AppPath.CreateWorkspace }, + { loc: AppPath.NotFound, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile }, + { loc: AppPath.NotFound, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails }, + { loc: AppPath.NotFound, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam }, + { loc: AppPath.NotFound, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: undefined }, ]; describe('usePageChangeEffectNavigateLocation', () => { testCases.forEach((testCase) => { - it(`with location ${testCase.loc} and onboardingStatus ${testCase.status} should return ${testCase.res}`, () => { + it(`with location ${testCase.loc} and onboardingStatus ${testCase.onboardingStatus} and subscriptionStatus ${testCase.subscriptionStatus} should return ${testCase.res}`, () => { setupMockIsMatchingLocation(testCase.loc); - setupMockOnboardingStatus(testCase.status); + setupMockOnboardingStatus(testCase.onboardingStatus); + setupMockSubscriptionStatus(testCase.subscriptionStatus); + setupMockIsLogged(testCase.isLoggedIn); expect(usePageChangeEffectNavigateLocation()).toEqual(testCase.res); }); }); describe('tests should be exhaustive', () => { it('all location and onboarding status should be tested', () => { + const untestedSubscriptionStatus = [ + SubscriptionStatus.Incomplete, + SubscriptionStatus.IncompleteExpired, + SubscriptionStatus.Paused, + SubscriptionStatus.Trialing, + ]; expect(testCases.length).toEqual( - Object.keys(AppPath).length * Object.keys(OnboardingStatus).length, + Object.keys(AppPath).length * + (Object.keys(OnboardingStatus).length + + (Object.keys(SubscriptionStatus).length - + untestedSubscriptionStatus.length)), ); }); }); diff --git a/packages/twenty-front/src/hooks/usePageChangeEffectNavigateLocation.ts b/packages/twenty-front/src/hooks/usePageChangeEffectNavigateLocation.ts index 5b34f0771ed4..5492b7b988a7 100644 --- a/packages/twenty-front/src/hooks/usePageChangeEffectNavigateLocation.ts +++ b/packages/twenty-front/src/hooks/usePageChangeEffectNavigateLocation.ts @@ -1,14 +1,18 @@ -import { useOnboardingStatus } from '@/auth/hooks/useOnboardingStatus'; -import { OnboardingStatus } from '@/auth/utils/getOnboardingStatus'; +import { useIsLogged } from '@/auth/hooks/useIsLogged'; +import { useOnboardingStatus } from '@/onboarding/hooks/useOnboardingStatus'; import { AppPath } from '@/types/AppPath'; import { SettingsPath } from '@/types/SettingsPath'; +import { useSubscriptionStatus } from '@/workspace/hooks/useSubscriptionStatus'; +import { OnboardingStatus, SubscriptionStatus } from '~/generated/graphql'; import { useDefaultHomePagePath } from '~/hooks/useDefaultHomePagePath'; import { useIsMatchingLocation } from '~/hooks/useIsMatchingLocation'; import { isDefined } from '~/utils/isDefined'; export const usePageChangeEffectNavigateLocation = () => { const isMatchingLocation = useIsMatchingLocation(); + const isLoggedIn = useIsLogged(); const onboardingStatus = useOnboardingStatus(); + const subscriptionStatus = useSubscriptionStatus(); const { defaultHomePagePath } = useDefaultHomePagePath(); const isMatchingOpenRoute = @@ -33,25 +37,28 @@ export const usePageChangeEffectNavigateLocation = () => { return; } - if ( - onboardingStatus === OnboardingStatus.OngoingUserCreation && - !isMatchingOngoingUserCreationRoute - ) { + if (!isLoggedIn && !isMatchingOngoingUserCreationRoute) { return AppPath.SignInUp; } if ( - onboardingStatus === OnboardingStatus.Incomplete && + onboardingStatus === OnboardingStatus.PlanRequired && !isMatchingLocation(AppPath.PlanRequired) ) { return AppPath.PlanRequired; } if ( - isDefined(onboardingStatus) && - [OnboardingStatus.Unpaid, OnboardingStatus.Canceled].includes( - onboardingStatus, - ) && + subscriptionStatus === SubscriptionStatus.Unpaid && + !isMatchingLocation(AppPath.SettingsCatchAll) + ) { + return `${AppPath.SettingsCatchAll.replace('/*', '')}/${ + SettingsPath.Billing + }`; + } + + if ( + subscriptionStatus === SubscriptionStatus.Canceled && !( isMatchingLocation(AppPath.SettingsCatchAll) || isMatchingLocation(AppPath.PlanRequired) @@ -63,7 +70,7 @@ export const usePageChangeEffectNavigateLocation = () => { } if ( - onboardingStatus === OnboardingStatus.OngoingWorkspaceActivation && + onboardingStatus === OnboardingStatus.WorkspaceActivation && !isMatchingLocation(AppPath.CreateWorkspace) && !isMatchingLocation(AppPath.PlanRequiredSuccess) ) { @@ -71,21 +78,21 @@ export const usePageChangeEffectNavigateLocation = () => { } if ( - onboardingStatus === OnboardingStatus.OngoingProfileCreation && + onboardingStatus === OnboardingStatus.ProfileCreation && !isMatchingLocation(AppPath.CreateProfile) ) { return AppPath.CreateProfile; } if ( - onboardingStatus === OnboardingStatus.OngoingSyncEmail && + onboardingStatus === OnboardingStatus.SyncEmail && !isMatchingLocation(AppPath.SyncEmails) ) { return AppPath.SyncEmails; } if ( - onboardingStatus === OnboardingStatus.OngoingInviteTeam && + onboardingStatus === OnboardingStatus.InviteTeam && !isMatchingLocation(AppPath.InviteTeam) ) { return AppPath.InviteTeam; @@ -93,15 +100,9 @@ export const usePageChangeEffectNavigateLocation = () => { if ( onboardingStatus === OnboardingStatus.Completed && - isMatchingOnboardingRoute - ) { - return defaultHomePagePath; - } - - if ( - onboardingStatus === OnboardingStatus.CompletedWithoutSubscription && isMatchingOnboardingRoute && - !isMatchingLocation(AppPath.PlanRequired) + subscriptionStatus !== SubscriptionStatus.Canceled && + (isDefined(subscriptionStatus) || !isMatchingLocation(AppPath.PlanRequired)) ) { return defaultHomePagePath; } diff --git a/packages/twenty-front/src/hooks/useScrollToPosition.ts b/packages/twenty-front/src/hooks/useScrollToPosition.ts new file mode 100644 index 000000000000..34994c1f3b5a --- /dev/null +++ b/packages/twenty-front/src/hooks/useScrollToPosition.ts @@ -0,0 +1,20 @@ +import { overlayScrollbarsState } from '@/ui/utilities/scroll/states/overlayScrollbarsState'; +import { useRecoilCallback } from 'recoil'; + +export const useScrollToPosition = () => { + const scrollToPosition = useRecoilCallback( + ({ snapshot }) => + (scrollPositionInPx: number) => { + const overlayScrollbars = snapshot + .getLoadable(overlayScrollbarsState) + .getValue(); + + const scrollWrapper = overlayScrollbars?.elements().viewport; + + scrollWrapper?.scrollTo({ top: scrollPositionInPx }); + }, + [], + ); + + return { scrollToPosition }; +}; diff --git a/packages/twenty-front/src/loading/components/LeftPanelSkeletonLoader.tsx b/packages/twenty-front/src/loading/components/LeftPanelSkeletonLoader.tsx index e1f73257f0bb..a6caf8861aee 100644 --- a/packages/twenty-front/src/loading/components/LeftPanelSkeletonLoader.tsx +++ b/packages/twenty-front/src/loading/components/LeftPanelSkeletonLoader.tsx @@ -1,6 +1,6 @@ -import Skeleton, { SkeletonTheme } from 'react-loading-skeleton'; import styled from '@emotion/styled'; import { motion } from 'framer-motion'; +import Skeleton, { SkeletonTheme } from 'react-loading-skeleton'; import { ANIMATION, BACKGROUND_LIGHT, GRAY_SCALE } from 'twenty-ui'; import { DESKTOP_NAV_DRAWER_WIDTHS } from '@/ui/navigation/navigation-drawer/constants/DesktopNavDrawerWidths'; @@ -18,7 +18,7 @@ const StyledItemsContainer = styled.div` gap: 32px; margin-bottom: auto; overflow-y: auto; - height: calc(100vh - 32px); + height: calc(100dvh - 32px); min-width: 216px; max-width: 216px; `; diff --git a/packages/twenty-front/src/loading/components/UserOrMetadataLoader.tsx b/packages/twenty-front/src/loading/components/UserOrMetadataLoader.tsx index d4d078619bb9..da129175ef2c 100644 --- a/packages/twenty-front/src/loading/components/UserOrMetadataLoader.tsx +++ b/packages/twenty-front/src/loading/components/UserOrMetadataLoader.tsx @@ -11,7 +11,7 @@ const StyledContainer = styled.div` display: flex; flex-direction: row; gap: 12px; - height: 100vh; + height: 100dvh; min-width: ${DESKTOP_NAV_DRAWER_WIDTHS.menu}px; width: 100%; padding: 12px 8px 12px; diff --git a/packages/twenty-front/src/loading/components/__stories__/UserOrMetadataLoader.stories.tsx b/packages/twenty-front/src/loading/components/__stories__/UserOrMetadataLoader.stories.tsx index 15c18390f697..ac5a371869be 100644 --- a/packages/twenty-front/src/loading/components/__stories__/UserOrMetadataLoader.stories.tsx +++ b/packages/twenty-front/src/loading/components/__stories__/UserOrMetadataLoader.stories.tsx @@ -14,7 +14,7 @@ import { } from '~/testing/decorators/PageDecorator'; import { graphqlMocks, metadataGraphql } from '~/testing/graphqlMocks'; import { mockedClientConfig } from '~/testing/mock-data/config'; -import { mockedUsersData } from '~/testing/mock-data/users'; +import { mockedUserData } from '~/testing/mock-data/users'; const userMetadataLoaderMocks = { msw: { @@ -22,7 +22,7 @@ const userMetadataLoaderMocks = { graphql.query(getOperationName(GET_CURRENT_USER) ?? '', () => { return HttpResponse.json({ data: { - currentUser: mockedUsersData[0], + currentUser: mockedUserData, }, }); }), diff --git a/packages/twenty-front/src/modules/accounts/types/MessageChannel.ts b/packages/twenty-front/src/modules/accounts/types/MessageChannel.ts index b875854f191c..33df519b4503 100644 --- a/packages/twenty-front/src/modules/accounts/types/MessageChannel.ts +++ b/packages/twenty-front/src/modules/accounts/types/MessageChannel.ts @@ -1,9 +1,17 @@ import { MessageChannelVisibility } from '~/generated/graphql'; +export enum MessageChannelContactAutoCreationPolicy { + SENT_AND_RECEIVED = 'SENT_AND_RECEIVED', + SENT = 'SENT', + NONE = 'NONE', +} + export type MessageChannel = { id: string; handle: string; - isContactAutoCreationEnabled?: boolean; + contactAutoCreationPolicy?: MessageChannelContactAutoCreationPolicy; + excludeNonProfessionalEmails: boolean; + excludeGroupEmails: boolean; isSyncEnabled: boolean; visibility: MessageChannelVisibility; syncStatus: string; diff --git a/packages/twenty-front/src/modules/activities/calendar/components/Calendar.tsx b/packages/twenty-front/src/modules/activities/calendar/components/Calendar.tsx index 7032895aadd1..5bc8afa2171a 100644 --- a/packages/twenty-front/src/modules/activities/calendar/components/Calendar.tsx +++ b/packages/twenty-front/src/modules/activities/calendar/components/Calendar.tsx @@ -9,6 +9,7 @@ import { useCalendarEvents } from '@/activities/calendar/hooks/useCalendarEvents import { getTimelineCalendarEventsFromCompanyId } from '@/activities/calendar/queries/getTimelineCalendarEventsFromCompanyId'; import { getTimelineCalendarEventsFromPersonId } from '@/activities/calendar/queries/getTimelineCalendarEventsFromPersonId'; import { CustomResolverFetchMoreLoader } from '@/activities/components/CustomResolverFetchMoreLoader'; +import { SkeletonLoader } from '@/activities/components/SkeletonLoader'; import { useCustomResolver } from '@/activities/hooks/useCustomResolver'; import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; @@ -18,6 +19,7 @@ import { AnimatedPlaceholderEmptySubTitle, AnimatedPlaceholderEmptyTextContainer, AnimatedPlaceholderEmptyTitle, + EMPTY_PLACEHOLDER_TRANSITION_PROPS, } from '@/ui/layout/animated-placeholder/components/EmptyPlaceholderStyled'; import { Section } from '@/ui/layout/section/components/Section'; import { TimelineCalendarEventsWithTotal } from '~/generated/graphql'; @@ -74,14 +76,16 @@ export const Calendar = ({ } = useCalendarEvents(timelineCalendarEvents || []); if (firstQueryLoading) { - // TODO: implement loader - return; + return <SkeletonLoader />; } if (!firstQueryLoading && !timelineCalendarEvents?.length) { // TODO: change animated placeholder return ( - <AnimatedPlaceholderEmptyContainer> + <AnimatedPlaceholderEmptyContainer + // eslint-disable-next-line react/jsx-props-no-spreading + {...EMPTY_PLACEHOLDER_TRANSITION_PROPS} + > <AnimatedPlaceholder type="noMatchRecord" /> <AnimatedPlaceholderEmptyTextContainer> <AnimatedPlaceholderEmptyTitle> diff --git a/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventDetailsEffect.tsx b/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventDetailsEffect.tsx new file mode 100644 index 000000000000..970cfc412b55 --- /dev/null +++ b/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventDetailsEffect.tsx @@ -0,0 +1,23 @@ +import { CalendarEvent } from '@/activities/calendar/types/CalendarEvent'; +import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore'; +import { useEffect } from 'react'; + +type CalendarEventDetailsEffectProps = { + record: CalendarEvent; +}; + +export const CalendarEventDetailsEffect = ({ + record, +}: CalendarEventDetailsEffectProps) => { + const { upsertRecords } = useUpsertRecordsInStore(); + + useEffect(() => { + if (!record) { + return; + } + + upsertRecords([record]); + }, [record, upsertRecords]); + + return <></>; +}; diff --git a/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventRow.tsx b/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventRow.tsx index 2a658225bb0f..e5ad988d3153 100644 --- a/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventRow.tsx +++ b/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventRow.tsx @@ -1,7 +1,7 @@ -import { useContext } from 'react'; import { css, useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { format } from 'date-fns'; +import { useContext } from 'react'; import { useRecoilValue } from 'recoil'; import { Avatar, AvatarGroup, IconArrowRight, IconLock } from 'twenty-ui'; @@ -14,8 +14,8 @@ import { hasCalendarEventEnded } from '@/activities/calendar/utils/hasCalendarEv import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; import { Card } from '@/ui/layout/card/components/Card'; import { CardContent } from '@/ui/layout/card/components/CardContent'; -import { CalendarChannelVisibility } from '~/generated/graphql'; import { TimelineCalendarEvent } from '~/generated-metadata/graphql'; +import { CalendarChannelVisibility } from '~/generated/graphql'; import { getImageAbsoluteURIOrBase64 } from '~/utils/image/getImageAbsoluteURIOrBase64'; import { isDefined } from '~/utils/isDefined'; @@ -169,7 +169,9 @@ export const CalendarEventRow = ({ ? `${participant.firstName} ${participant.lastName}` : participant.displayName } - entityId={participant.workspaceMemberId ?? participant.personId} + placeholderColorSeed={ + participant.workspaceMemberId ?? participant.personId + } type="rounded" /> ))} diff --git a/packages/twenty-front/src/modules/activities/calendar/right-drawer/components/RightDrawerCalendarEvent.tsx b/packages/twenty-front/src/modules/activities/calendar/right-drawer/components/RightDrawerCalendarEvent.tsx index 06aa66012f55..24f78d71539e 100644 --- a/packages/twenty-front/src/modules/activities/calendar/right-drawer/components/RightDrawerCalendarEvent.tsx +++ b/packages/twenty-front/src/modules/activities/calendar/right-drawer/components/RightDrawerCalendarEvent.tsx @@ -1,26 +1,35 @@ import { useRecoilValue } from 'recoil'; import { CalendarEventDetails } from '@/activities/calendar/components/CalendarEventDetails'; +import { CalendarEventDetailsEffect } from '@/activities/calendar/components/CalendarEventDetailsEffect'; import { FIND_ONE_CALENDAR_EVENT_OPERATION_SIGNATURE } from '@/activities/calendar/graphql/operation-signatures/FindOneCalendarEventOperationSignature'; import { CalendarEvent } from '@/activities/calendar/types/CalendarEvent'; import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord'; import { viewableRecordIdState } from '@/object-record/record-right-drawer/states/viewableRecordIdState'; -import { useSetRecordInStore } from '@/object-record/record-store/hooks/useSetRecordInStore'; +import { RecordValueSetterEffect } from '@/object-record/record-store/components/RecordValueSetterEffect'; +import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore'; export const RightDrawerCalendarEvent = () => { - const { setRecords } = useSetRecordInStore(); + const { upsertRecords } = useUpsertRecordsInStore(); const viewableRecordId = useRecoilValue(viewableRecordIdState); + const { record: calendarEvent } = useFindOneRecord<CalendarEvent>({ objectNameSingular: FIND_ONE_CALENDAR_EVENT_OPERATION_SIGNATURE.objectNameSingular, objectRecordId: viewableRecordId ?? '', recordGqlFields: FIND_ONE_CALENDAR_EVENT_OPERATION_SIGNATURE.fields, - onCompleted: (record) => setRecords([record]), + onCompleted: (record) => upsertRecords([record]), }); if (!calendarEvent) { return null; } - return <CalendarEventDetails calendarEvent={calendarEvent} />; + return ( + <> + <CalendarEventDetailsEffect record={calendarEvent} /> + <RecordValueSetterEffect recordId={calendarEvent.id} /> + <CalendarEventDetails calendarEvent={calendarEvent} /> + </> + ); }; diff --git a/packages/twenty-front/src/modules/activities/comment/CommentHeader.tsx b/packages/twenty-front/src/modules/activities/comment/CommentHeader.tsx index 13ed1aa16352..d48f114e9d7f 100644 --- a/packages/twenty-front/src/modules/activities/comment/CommentHeader.tsx +++ b/packages/twenty-front/src/modules/activities/comment/CommentHeader.tsx @@ -1,6 +1,5 @@ -import { Tooltip } from 'react-tooltip'; import styled from '@emotion/styled'; -import { Avatar } from 'twenty-ui'; +import { AppTooltip, Avatar } from 'twenty-ui'; import { Comment } from '@/activities/types/Comment'; import { @@ -42,21 +41,6 @@ const StyledDate = styled.div` margin-left: ${({ theme }) => theme.spacing(1)}; `; -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; -`; - type CommentHeaderProps = { comment: Pick<Comment, 'id' | 'author' | 'createdAt'>; actionBar?: React.ReactNode; @@ -78,7 +62,7 @@ export const CommentHeader = ({ comment, actionBar }: CommentHeaderProps) => { <Avatar avatarUrl={getImageAbsoluteURIOrBase64(avatarUrl)} size="md" - entityId={author?.id} + placeholderColorSeed={author?.id} placeholder={authorName} /> <StyledName>{authorName}</StyledName> @@ -87,7 +71,7 @@ export const CommentHeader = ({ comment, actionBar }: CommentHeaderProps) => { <StyledDate id={`id-${commentId}`}> {beautifiedCreatedAt} </StyledDate> - <StyledTooltip + <AppTooltip anchorSelect={`#id-${commentId}`} content={exactCreatedAt} clickable diff --git a/packages/twenty-front/src/modules/activities/components/ActivityEditorFields.tsx b/packages/twenty-front/src/modules/activities/components/ActivityEditorFields.tsx index 9f221d840559..e8b189258544 100644 --- a/packages/twenty-front/src/modules/activities/components/ActivityEditorFields.tsx +++ b/packages/twenty-front/src/modules/activities/components/ActivityEditorFields.tsx @@ -86,14 +86,6 @@ export const ActivityEditorFields = ({ customUseUpdateOneObjectHook: useUpsertOneActivityMutation, }); - const { FieldContextProvider: ActivityTargetsContextProvider } = - useFieldContext({ - objectNameSingular: CoreObjectNameSingular.Activity, - objectRecordId: activityId, - fieldMetadataName: 'activityTargets', - fieldPosition: 3, - }); - return ( <StyledPropertyBox> {activity.type === 'Task' && @@ -112,16 +104,12 @@ export const ActivityEditorFields = ({ </AssigneeFieldContextProvider> </> )} - {ActivityTargetsContextProvider && - isDefined(activityFromCache) && - isRightDrawerAnimationCompleted && ( - <ActivityTargetsContextProvider> - <ActivityTargetsInlineCell - activity={activityFromCache} - maxWidth={340} - /> - </ActivityTargetsContextProvider> - )} + {isDefined(activityFromCache) && isRightDrawerAnimationCompleted && ( + <ActivityTargetsInlineCell + activity={activityFromCache} + maxWidth={340} + /> + )} </StyledPropertyBox> ); }; diff --git a/packages/twenty-front/src/modules/activities/timeline/components/TimelineSkeletonLoader.tsx b/packages/twenty-front/src/modules/activities/components/SkeletonLoader.tsx similarity index 62% rename from packages/twenty-front/src/modules/activities/timeline/components/TimelineSkeletonLoader.tsx rename to packages/twenty-front/src/modules/activities/components/SkeletonLoader.tsx index f328fda44085..21478ed73c32 100644 --- a/packages/twenty-front/src/modules/activities/timeline/components/TimelineSkeletonLoader.tsx +++ b/packages/twenty-front/src/modules/activities/components/SkeletonLoader.tsx @@ -18,18 +18,14 @@ const StyledSkeletonSubSection = styled.div` gap: ${({ theme }) => theme.spacing(4)}; `; -const StyledSkeletonColumn = styled.div` +const StyledSkeletonSubSectionContent = styled.div` display: flex; flex-direction: column; gap: ${({ theme }) => theme.spacing(3)}; justify-content: center; `; -const StyledSkeletonLoader = ({ - isSecondColumn, -}: { - isSecondColumn: boolean; -}) => { +const SkeletonColumnLoader = ({ height }: { height: number }) => { const theme = useTheme(); return ( <SkeletonTheme @@ -37,12 +33,16 @@ const StyledSkeletonLoader = ({ highlightColor={theme.background.transparent.lighter} borderRadius={80} > - <Skeleton width={24} height={isSecondColumn ? 120 : 84} /> + <Skeleton width={24} height={height} /> </SkeletonTheme> ); }; -export const TimelineSkeletonLoader = () => { +export const SkeletonLoader = ({ + withSubSections = false, +}: { + withSubSections?: boolean; +}) => { const theme = useTheme(); const skeletonItems = Array.from({ length: 3 }).map((_, index) => ({ id: `skeleton-item-${index}`, @@ -56,16 +56,17 @@ export const TimelineSkeletonLoader = () => { > <StyledSkeletonContainer> <Skeleton width={440} height={16} /> - {skeletonItems.map(({ id }, index) => ( - <StyledSkeletonSubSection key={id}> - <StyledSkeletonLoader isSecondColumn={index === 1} /> - <StyledSkeletonColumn> - <Skeleton width={400} height={24} /> - <Skeleton width={400} height={24} /> - {index === 1 && <Skeleton width={400} height={24} />} - </StyledSkeletonColumn> - </StyledSkeletonSubSection> - ))} + {withSubSections && + skeletonItems.map(({ id }, index) => ( + <StyledSkeletonSubSection key={id}> + <SkeletonColumnLoader height={index === 1 ? 120 : 84} /> + <StyledSkeletonSubSectionContent> + <Skeleton width={400} height={24} /> + <Skeleton width={400} height={24} /> + {index === 1 && <Skeleton width={400} height={24} />} + </StyledSkeletonSubSectionContent> + </StyledSkeletonSubSection> + ))} </StyledSkeletonContainer> </SkeletonTheme> ); diff --git a/packages/twenty-front/src/modules/activities/copilot/right-drawer/components/RightDrawerAIChat.tsx b/packages/twenty-front/src/modules/activities/copilot/right-drawer/components/RightDrawerAIChat.tsx new file mode 100644 index 000000000000..4ad2c423c77b --- /dev/null +++ b/packages/twenty-front/src/modules/activities/copilot/right-drawer/components/RightDrawerAIChat.tsx @@ -0,0 +1,54 @@ +import styled from '@emotion/styled'; +import { useSetRecoilState } from 'recoil'; + +import { copilotQueryState } from '@/activities/copilot/right-drawer/states/copilotQueryState'; +import { + AutosizeTextInput, + AutosizeTextInputVariant, +} from '@/ui/input/components/AutosizeTextInput'; + +const StyledContainer = styled.div` + box-sizing: border-box; + display: flex; + flex-direction: column; + height: 100%; + justify-content: flex-start; + overflow-y: auto; + position: relative; +`; + +const StyledChatArea = styled.div` + flex: 1; + display: flex; + flex-direction: column; + overflow-y: scroll; + padding: ${({ theme }) => theme.spacing(6)}; + padding-bottom: 0px; +`; + +const StyledNewMessageArea = styled.div` + display: flex; + flex-direction: column; + padding: ${({ theme }) => theme.spacing(6)}; + padding-top: 0px; +`; + +export const RightDrawerAIChat = () => { + const setCopilotQuery = useSetRecoilState(copilotQueryState); + + return ( + <StyledContainer> + <StyledChatArea>{/* TODO */}</StyledChatArea> + <StyledNewMessageArea> + <AutosizeTextInput + autoFocus + placeholder="Ask anything" + variant={AutosizeTextInputVariant.Icon} + onValidate={(text) => { + setCopilotQuery(text); + }} + /> + </StyledNewMessageArea> + </StyledContainer> + ); +}; diff --git a/packages/twenty-front/src/modules/activities/copilot/right-drawer/hooks/useOpenCopilotRightDrawer.ts b/packages/twenty-front/src/modules/activities/copilot/right-drawer/hooks/useOpenCopilotRightDrawer.ts new file mode 100644 index 000000000000..5369451624e1 --- /dev/null +++ b/packages/twenty-front/src/modules/activities/copilot/right-drawer/hooks/useOpenCopilotRightDrawer.ts @@ -0,0 +1,14 @@ +import { useRightDrawer } from '@/ui/layout/right-drawer/hooks/useRightDrawer'; +import { RightDrawerHotkeyScope } from '@/ui/layout/right-drawer/types/RightDrawerHotkeyScope'; +import { RightDrawerPages } from '@/ui/layout/right-drawer/types/RightDrawerPages'; +import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope'; + +export const useOpenCopilotRightDrawer = () => { + const { openRightDrawer } = useRightDrawer(); + const setHotkeyScope = useSetHotkeyScope(); + + return () => { + setHotkeyScope(RightDrawerHotkeyScope.RightDrawer, { goto: false }); + openRightDrawer(RightDrawerPages.Copilot); + }; +}; diff --git a/packages/twenty-front/src/modules/activities/copilot/right-drawer/states/copilotQueryState.ts b/packages/twenty-front/src/modules/activities/copilot/right-drawer/states/copilotQueryState.ts new file mode 100644 index 000000000000..ee56e8b0fe80 --- /dev/null +++ b/packages/twenty-front/src/modules/activities/copilot/right-drawer/states/copilotQueryState.ts @@ -0,0 +1,6 @@ +import { createState } from 'twenty-ui'; + +export const copilotQueryState = createState({ + key: 'activities/copilot-query', + defaultValue: '', +}); diff --git a/packages/twenty-front/src/modules/activities/emails/components/EmailThreads.tsx b/packages/twenty-front/src/modules/activities/emails/components/EmailThreads.tsx index d0766c517b17..53038755dc88 100644 --- a/packages/twenty-front/src/modules/activities/emails/components/EmailThreads.tsx +++ b/packages/twenty-front/src/modules/activities/emails/components/EmailThreads.tsx @@ -2,7 +2,7 @@ import styled from '@emotion/styled'; import { H1Title, H1TitleFontColor } from 'twenty-ui'; import { CustomResolverFetchMoreLoader } from '@/activities/components/CustomResolverFetchMoreLoader'; -import { EmailLoader } from '@/activities/emails/components/EmailLoader'; +import { SkeletonLoader } from '@/activities/components/SkeletonLoader'; import { EmailThreadPreview } from '@/activities/emails/components/EmailThreadPreview'; import { TIMELINE_THREADS_DEFAULT_PAGE_SIZE } from '@/activities/emails/constants/Messaging'; import { getTimelineThreadsFromCompanyId } from '@/activities/emails/queries/getTimelineThreadsFromCompanyId'; @@ -16,6 +16,7 @@ import { AnimatedPlaceholderEmptySubTitle, AnimatedPlaceholderEmptyTextContainer, AnimatedPlaceholderEmptyTitle, + EMPTY_PLACEHOLDER_TRANSITION_PROPS, } from '@/ui/layout/animated-placeholder/components/EmptyPlaceholderStyled'; import { Card } from '@/ui/layout/card/components/Card'; import { Section } from '@/ui/layout/section/components/Section'; @@ -61,12 +62,15 @@ export const EmailThreads = ({ const { totalNumberOfThreads, timelineThreads } = data?.[queryName] ?? {}; if (firstQueryLoading) { - return <EmailLoader />; + return <SkeletonLoader />; } if (!firstQueryLoading && !timelineThreads?.length) { return ( - <AnimatedPlaceholderEmptyContainer> + <AnimatedPlaceholderEmptyContainer + // eslint-disable-next-line react/jsx-props-no-spreading + {...EMPTY_PLACEHOLDER_TRANSITION_PROPS} + > <AnimatedPlaceholder type="emptyInbox" /> <AnimatedPlaceholderEmptyTextContainer> <AnimatedPlaceholderEmptyTitle> diff --git a/packages/twenty-front/src/modules/activities/emails/graphql/operation-signatures/factories/fetchAllThreadMessagesOperationSignatureFactory.ts b/packages/twenty-front/src/modules/activities/emails/graphql/operation-signatures/factories/fetchAllThreadMessagesOperationSignatureFactory.ts index 619a99b0dd23..ee5e93da74fa 100644 --- a/packages/twenty-front/src/modules/activities/emails/graphql/operation-signatures/factories/fetchAllThreadMessagesOperationSignatureFactory.ts +++ b/packages/twenty-front/src/modules/activities/emails/graphql/operation-signatures/factories/fetchAllThreadMessagesOperationSignatureFactory.ts @@ -10,9 +10,11 @@ export const fetchAllThreadMessagesOperationSignatureFactory: RecordGqlOperation eq: messageThreadId || '', }, }, - orderBy: { - receivedAt: 'AscNullsLast', - }, + orderBy: [ + { + receivedAt: 'AscNullsLast', + }, + ], limit: 10, }, fields: { diff --git a/packages/twenty-front/src/modules/activities/emails/right-drawer/components/RightDrawerEmailThread.tsx b/packages/twenty-front/src/modules/activities/emails/right-drawer/components/RightDrawerEmailThread.tsx index d7d040726145..09c98810b2e3 100644 --- a/packages/twenty-front/src/modules/activities/emails/right-drawer/components/RightDrawerEmailThread.tsx +++ b/packages/twenty-front/src/modules/activities/emails/right-drawer/components/RightDrawerEmailThread.tsx @@ -71,6 +71,7 @@ export const RightDrawerEmailThread = () => { ? visibleMessages.slice(2, visibleMessagesCount - 1) : []; const lastMessage = visibleMessages[visibleMessagesCount - 1]; + const subject = visibleMessages[0]?.subject; return ( <StyledContainer> @@ -79,7 +80,7 @@ export const RightDrawerEmailThread = () => { ) : ( <> <EmailThreadHeader - subject={thread.subject} + subject={subject} lastMessageSentAt={lastMessage.receivedAt} /> {firstMessages.map((message) => ( diff --git a/packages/twenty-front/src/modules/activities/emails/right-drawer/hooks/useRightDrawerEmailThread.ts b/packages/twenty-front/src/modules/activities/emails/right-drawer/hooks/useRightDrawerEmailThread.ts index b63e429ef26c..47c30f4d0eb4 100644 --- a/packages/twenty-front/src/modules/activities/emails/right-drawer/hooks/useRightDrawerEmailThread.ts +++ b/packages/twenty-front/src/modules/activities/emails/right-drawer/hooks/useRightDrawerEmailThread.ts @@ -8,11 +8,11 @@ import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSi import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord'; import { viewableRecordIdState } from '@/object-record/record-right-drawer/states/viewableRecordIdState'; -import { useSetRecordInStore } from '@/object-record/record-store/hooks/useSetRecordInStore'; +import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore'; export const useRightDrawerEmailThread = () => { const viewableRecordId = useRecoilValue(viewableRecordIdState); - const { setRecords } = useSetRecordInStore(); + const { upsertRecords } = useUpsertRecordsInStore(); const { record: thread } = useFindOneRecord<EmailThread>({ objectNameSingular: CoreObjectNameSingular.MessageThread, @@ -20,7 +20,7 @@ export const useRightDrawerEmailThread = () => { recordGqlFields: { id: true, }, - onCompleted: (record) => setRecords([record]), + onCompleted: (record) => upsertRecords([record]), }); const FETCH_ALL_MESSAGES_OPERATION_SIGNATURE = diff --git a/packages/twenty-front/src/modules/activities/files/components/Attachments.tsx b/packages/twenty-front/src/modules/activities/files/components/Attachments.tsx index aacc0ec6ad3f..482b8e18f88f 100644 --- a/packages/twenty-front/src/modules/activities/files/components/Attachments.tsx +++ b/packages/twenty-front/src/modules/activities/files/components/Attachments.tsx @@ -1,8 +1,8 @@ import { ChangeEvent, useRef, useState } from 'react'; import styled from '@emotion/styled'; -import { isNonEmptyArray } from '@sniptt/guards'; import { IconPlus } from 'twenty-ui'; +import { SkeletonLoader } from '@/activities/components/SkeletonLoader'; import { AttachmentList } from '@/activities/files/components/AttachmentList'; import { DropZone } from '@/activities/files/components/DropZone'; import { useAttachments } from '@/activities/files/hooks/useAttachments'; @@ -15,6 +15,7 @@ import { AnimatedPlaceholderEmptySubTitle, AnimatedPlaceholderEmptyTextContainer, AnimatedPlaceholderEmptyTitle, + EMPTY_PLACEHOLDER_TRANSITION_PROPS, } from '@/ui/layout/animated-placeholder/components/EmptyPlaceholderStyled'; import { isDefined } from '~/utils/isDefined'; @@ -41,7 +42,7 @@ export const Attachments = ({ targetableObject: ActivityTargetableObject; }) => { const inputFileRef = useRef<HTMLInputElement>(null); - const { attachments } = useAttachments(targetableObject); + const { attachments, loading } = useAttachments(targetableObject); const { uploadAttachmentFile } = useUploadAttachmentFile(); const [isDraggingFile, setIsDraggingFile] = useState(false); @@ -58,7 +59,13 @@ export const Attachments = ({ await uploadAttachmentFile(file, targetableObject); }; - if (!isNonEmptyArray(attachments)) { + const isAttachmentsEmpty = !attachments || attachments.length === 0; + + if (loading && isAttachmentsEmpty) { + return <SkeletonLoader />; + } + + if (isAttachmentsEmpty) { return ( <StyledDropZoneContainer onDragEnter={() => setIsDraggingFile(true)}> {isDraggingFile ? ( @@ -67,7 +74,10 @@ export const Attachments = ({ onUploadFile={onUploadFile} /> ) : ( - <AnimatedPlaceholderEmptyContainer> + <AnimatedPlaceholderEmptyContainer + // eslint-disable-next-line react/jsx-props-no-spreading + {...EMPTY_PLACEHOLDER_TRANSITION_PROPS} + > <AnimatedPlaceholder type="noFile" /> <AnimatedPlaceholderEmptyTextContainer> <AnimatedPlaceholderEmptyTitle> diff --git a/packages/twenty-front/src/modules/activities/files/hooks/useAttachments.tsx b/packages/twenty-front/src/modules/activities/files/hooks/useAttachments.tsx index 2d8539889d27..a91eb40313f3 100644 --- a/packages/twenty-front/src/modules/activities/files/hooks/useAttachments.tsx +++ b/packages/twenty-front/src/modules/activities/files/hooks/useAttachments.tsx @@ -4,25 +4,27 @@ import { getActivityTargetObjectFieldIdName } from '@/activities/utils/getActivi import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; -// do we need to test this? export const useAttachments = (targetableObject: ActivityTargetableObject) => { const targetableObjectFieldIdName = getActivityTargetObjectFieldIdName({ nameSingular: targetableObject.targetObjectNameSingular, }); - const { records: attachments } = useFindManyRecords<Attachment>({ + const { records: attachments, loading } = useFindManyRecords<Attachment>({ objectNameSingular: CoreObjectNameSingular.Attachment, filter: { [targetableObjectFieldIdName]: { eq: targetableObject.id, }, }, - orderBy: { - createdAt: 'DescNullsFirst', - }, + orderBy: [ + { + createdAt: 'DescNullsFirst', + }, + ], }); return { attachments, + loading, }; }; diff --git a/packages/twenty-front/src/modules/activities/hooks/__tests__/useActivities.test.tsx b/packages/twenty-front/src/modules/activities/hooks/__tests__/useActivities.test.tsx index 4e149d280fbf..b3ca9e5349d2 100644 --- a/packages/twenty-front/src/modules/activities/hooks/__tests__/useActivities.test.tsx +++ b/packages/twenty-front/src/modules/activities/hooks/__tests__/useActivities.test.tsx @@ -49,7 +49,7 @@ const mocks: MockedResponse[] = [ query: gql` query FindManyActivityTargets( $filter: ActivityTargetFilterInput - $orderBy: ActivityTargetOrderByInput + $orderBy: [ActivityTargetOrderByInput] $lastCursor: String $limit: Int ) { @@ -103,7 +103,7 @@ const mocks: MockedResponse[] = [ query: gql` query FindManyActivities( $filter: ActivityFilterInput - $orderBy: ActivityOrderByInput + $orderBy: [ActivityOrderByInput] $lastCursor: String $limit: Int ) { @@ -142,7 +142,7 @@ const mocks: MockedResponse[] = [ variables: { filter: { id: { in: ['234'] } }, limit: undefined, - orderBy: {}, + orderBy: [{}], }, }, result: jest.fn(() => ({ @@ -178,7 +178,7 @@ describe('useActivities', () => { useActivities({ targetableObjects: [], activitiesFilters: {}, - activitiesOrderByVariables: {}, + activitiesOrderByVariables: [{}], skip: false, }), { wrapper: Wrapper }, @@ -202,7 +202,7 @@ describe('useActivities', () => { { targetObjectNameSingular: 'company', id: '123' }, ], activitiesFilters: {}, - activitiesOrderByVariables: {}, + activitiesOrderByVariables: [{}], skip: false, }); return { activities, setCurrentWorkspaceMember }; diff --git a/packages/twenty-front/src/modules/activities/hooks/__tests__/useActivityTargetsForTargetableObject.test.tsx b/packages/twenty-front/src/modules/activities/hooks/__tests__/useActivityTargetsForTargetableObject.test.tsx index 9426e1cb7fbb..21f429c6b8c6 100644 --- a/packages/twenty-front/src/modules/activities/hooks/__tests__/useActivityTargetsForTargetableObject.test.tsx +++ b/packages/twenty-front/src/modules/activities/hooks/__tests__/useActivityTargetsForTargetableObject.test.tsx @@ -34,7 +34,7 @@ const mocks: MockedResponse[] = [ query: gql` query FindManyActivityTargets( $filter: ActivityTargetFilterInput - $orderBy: ActivityTargetOrderByInput + $orderBy: [ActivityTargetOrderByInput] $lastCursor: String $limit: Int ) { diff --git a/packages/twenty-front/src/modules/activities/hooks/useCreateActivityInDB.ts b/packages/twenty-front/src/modules/activities/hooks/useCreateActivityInDB.ts index 961514ede05e..470e9fda030e 100644 --- a/packages/twenty-front/src/modules/activities/hooks/useCreateActivityInDB.ts +++ b/packages/twenty-front/src/modules/activities/hooks/useCreateActivityInDB.ts @@ -3,35 +3,98 @@ import { isNonEmptyArray } from '@sniptt/guards'; import { CREATE_ONE_ACTIVITY_OPERATION_SIGNATURE } from '@/activities/graphql/operation-signatures/CreateOneActivityOperationSignature'; import { ActivityForEditor } from '@/activities/types/ActivityForEditor'; import { ActivityTarget } from '@/activities/types/ActivityTarget'; +import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; +import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; +import { getRecordConnectionFromRecords } from '@/object-record/cache/utils/getRecordConnectionFromRecords'; +import { modifyRecordFromCache } from '@/object-record/cache/utils/modifyRecordFromCache'; import { useCreateManyRecords } from '@/object-record/hooks/useCreateManyRecords'; import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord'; +import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; +import { useApolloClient } from '@apollo/client'; + +import { useRecoilCallback } from 'recoil'; +import { capitalize } from '~/utils/string/capitalize'; export const useCreateActivityInDB = () => { const { createOneRecord: createOneActivity } = useCreateOneRecord({ objectNameSingular: CREATE_ONE_ACTIVITY_OPERATION_SIGNATURE.objectNameSingular, recordGqlFields: CREATE_ONE_ACTIVITY_OPERATION_SIGNATURE.fields, + shouldMatchRootQueryFilter: true, }); const { createManyRecords: createManyActivityTargets } = useCreateManyRecords<ActivityTarget>({ objectNameSingular: CoreObjectNameSingular.ActivityTarget, - skipPostOptmisticEffect: true, + shouldMatchRootQueryFilter: true, + }); + + const { objectMetadataItems } = useObjectMetadataItems(); + + const { objectMetadataItem: objectMetadataItemActivityTarget } = + useObjectMetadataItem({ + objectNameSingular: CoreObjectNameSingular.ActivityTarget, }); - const createActivityInDB = async (activityToCreate: ActivityForEditor) => { - await createOneActivity?.({ - ...activityToCreate, - updatedAt: new Date().toISOString(), + const { objectMetadataItem: objectMetadataItemActivity } = + useObjectMetadataItem({ + objectNameSingular: CoreObjectNameSingular.Activity, }); - const activityTargetsToCreate = activityToCreate.activityTargets ?? []; + const cache = useApolloClient().cache; - if (isNonEmptyArray(activityTargetsToCreate)) { - await createManyActivityTargets(activityTargetsToCreate); - } - }; + const createActivityInDB = useRecoilCallback( + ({ set }) => + async (activityToCreate: ActivityForEditor) => { + const createdActivity = await createOneActivity?.({ + ...activityToCreate, + updatedAt: new Date().toISOString(), + }); + + const activityTargetsToCreate = activityToCreate.activityTargets ?? []; + + if (isNonEmptyArray(activityTargetsToCreate)) { + await createManyActivityTargets(activityTargetsToCreate); + } + + const activityTargetsConnection = getRecordConnectionFromRecords({ + objectMetadataItems, + objectMetadataItem: objectMetadataItemActivityTarget, + records: activityTargetsToCreate.map((activityTarget) => ({ + ...activityTarget, + __typename: capitalize( + objectMetadataItemActivityTarget.nameSingular, + ), + })), + withPageInfo: false, + computeReferences: true, + isRootLevel: false, + }); + + modifyRecordFromCache({ + recordId: createdActivity.id, + cache, + fieldModifiers: { + activityTargets: () => activityTargetsConnection, + }, + objectMetadataItem: objectMetadataItemActivity, + }); + + set(recordStoreFamilyState(createdActivity.id), { + ...createdActivity, + activityTargets: activityTargetsToCreate, + }); + }, + [ + cache, + createManyActivityTargets, + createOneActivity, + objectMetadataItemActivity, + objectMetadataItemActivityTarget, + objectMetadataItems, + ], + ); return { createActivityInDB, diff --git a/packages/twenty-front/src/modules/activities/hooks/useObjectRecordMultiSelectScopedStates.ts b/packages/twenty-front/src/modules/activities/hooks/useObjectRecordMultiSelectScopedStates.ts new file mode 100644 index 000000000000..b49c9aefa47b --- /dev/null +++ b/packages/twenty-front/src/modules/activities/hooks/useObjectRecordMultiSelectScopedStates.ts @@ -0,0 +1,35 @@ +import { objectRecordsIdsMultiSelecComponentState } from '@/activities/states/objectRecordsIdsMultiSelectComponentState'; +import { objectRecordMultiSelectCheckedRecordsIdsComponentState } from '@/object-record/record-field/states/objectRecordMultiSelectCheckedRecordsIdsComponentState'; +import { objectRecordMultiSelectComponentFamilyState } from '@/object-record/record-field/states/objectRecordMultiSelectComponentFamilyState'; +import { recordMultiSelectIsLoadingComponentState } from '@/object-record/record-field/states/recordMultiSelectIsLoadingComponentState'; +import { extractComponentFamilyState } from '@/ui/utilities/state/component-state/utils/extractComponentFamilyState'; +import { extractComponentState } from '@/ui/utilities/state/component-state/utils/extractComponentState'; + +export const useObjectRecordMultiSelectScopedStates = (scopeId: string) => { + const objectRecordsIdsMultiSelectState = extractComponentState( + objectRecordsIdsMultiSelecComponentState, + scopeId, + ); + + const objectRecordMultiSelectCheckedRecordsIdsState = extractComponentState( + objectRecordMultiSelectCheckedRecordsIdsComponentState, + scopeId, + ); + + const objectRecordMultiSelectFamilyState = extractComponentFamilyState( + objectRecordMultiSelectComponentFamilyState, + scopeId, + ); + + const recordMultiSelectIsLoadingState = extractComponentState( + recordMultiSelectIsLoadingComponentState, + scopeId, + ); + + return { + objectRecordsIdsMultiSelectState, + objectRecordMultiSelectCheckedRecordsIdsState, + objectRecordMultiSelectFamilyState, + recordMultiSelectIsLoadingState, + }; +}; diff --git a/packages/twenty-front/src/modules/activities/hooks/usePrepareFindManyActivitiesQuery.ts b/packages/twenty-front/src/modules/activities/hooks/usePrepareFindManyActivitiesQuery.ts index 7f5d9c492c8a..2951b7522ce0 100644 --- a/packages/twenty-front/src/modules/activities/hooks/usePrepareFindManyActivitiesQuery.ts +++ b/packages/twenty-front/src/modules/activities/hooks/usePrepareFindManyActivitiesQuery.ts @@ -109,7 +109,7 @@ export const usePrepareFindManyActivitiesQuery = () => { objectRecordsToOverwrite: filteredActivities, queryVariables: { ...nextFindManyActivitiesQueryFilter, - orderBy: { createdAt: 'DescNullsFirst' }, + orderBy: [{ createdAt: 'DescNullsFirst' }], }, recordGqlFields: FIND_ACTIVITIES_OPERATION_SIGNATURE.fields, computeReferences: true, diff --git a/packages/twenty-front/src/modules/activities/inline-cell/components/ActivityTargetInlineCellEditMode.tsx b/packages/twenty-front/src/modules/activities/inline-cell/components/ActivityTargetInlineCellEditMode.tsx index 0c884b2035a0..0b85e20074b7 100644 --- a/packages/twenty-front/src/modules/activities/inline-cell/components/ActivityTargetInlineCellEditMode.tsx +++ b/packages/twenty-front/src/modules/activities/inline-cell/components/ActivityTargetInlineCellEditMode.tsx @@ -1,9 +1,10 @@ import styled from '@emotion/styled'; -import { isNonEmptyArray, isNull } from '@sniptt/guards'; -import { useRecoilState, useSetRecoilState } from 'recoil'; +import { isNull } from '@sniptt/guards'; +import { useRecoilCallback, useRecoilState, useSetRecoilState } from 'recoil'; import { v4 } from 'uuid'; import { useUpsertActivity } from '@/activities/hooks/useUpsertActivity'; +import { ActivityTargetObjectRecordEffect } from '@/activities/inline-cell/components/ActivityTargetObjectRecordEffect'; import { isActivityInCreateModeState } from '@/activities/states/isActivityInCreateModeState'; import { Activity } from '@/activities/types/Activity'; import { ActivityTarget } from '@/activities/types/ActivityTarget'; @@ -15,16 +16,23 @@ import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSi import { useCreateManyRecordsInCache } from '@/object-record/cache/hooks/useCreateManyRecordsInCache'; import { useCreateManyRecords } from '@/object-record/hooks/useCreateManyRecords'; import { useDeleteManyRecords } from '@/object-record/hooks/useDeleteManyRecords'; +import { activityTargetObjectRecordFamilyState } from '@/object-record/record-field/states/activityTargetObjectRecordFamilyState'; +import { objectRecordMultiSelectCheckedRecordsIdsComponentState } from '@/object-record/record-field/states/objectRecordMultiSelectCheckedRecordsIdsComponentState'; +import { + ObjectRecordAndSelected, + objectRecordMultiSelectComponentFamilyState, +} from '@/object-record/record-field/states/objectRecordMultiSelectComponentFamilyState'; import { useInlineCell } from '@/object-record/record-inline-cell/hooks/useInlineCell'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; -import { MultipleObjectRecordSelect } from '@/object-record/relation-picker/components/MultipleObjectRecordSelect'; -import { ObjectRecordForSelect } from '@/object-record/relation-picker/hooks/useMultiObjectSearch'; +import { ActivityTargetInlineCellEditModeMultiRecordsEffect } from '@/object-record/relation-picker/components/ActivityTargetInlineCellEditModeMultiRecordsEffect'; +import { MultiRecordSelect } from '@/object-record/relation-picker/components/MultiRecordSelect'; +import { RelationPickerScope } from '@/object-record/relation-picker/scopes/RelationPickerScope'; import { prefillRecord } from '@/object-record/utils/prefillRecord'; const StyledSelectContainer = styled.div` - left: 0px; position: absolute; - top: -8px; + left: 0; + top: 0; `; type ActivityTargetInlineCellEditModeProps = { @@ -37,6 +45,7 @@ export const ActivityTargetInlineCellEditMode = ({ activityTargetWithTargetRecords, }: ActivityTargetInlineCellEditModeProps) => { const [isActivityInCreateMode] = useRecoilState(isActivityInCreateModeState); + const relationPickerScopeId = `relation-picker-${activity.id}`; const selectedTargetObjectIds = activityTargetWithTargetRecords.map( (activityTarget) => ({ @@ -74,109 +83,181 @@ export const ActivityTargetInlineCellEditMode = ({ objectNameSingular: CoreObjectNameSingular.ActivityTarget, }); - const handleSubmit = async (selectedRecords: ObjectRecordForSelect[]) => { - closeEditableField(); - - const activityTargetsToDelete = activityTargetWithTargetRecords.filter( - (activityTargetObjectRecord) => - !selectedRecords.some( - (selectedRecord) => - selectedRecord.recordIdentifier.id === - activityTargetObjectRecord.targetObject.id, - ), - ); - - const selectedTargetObjectsToCreate = selectedRecords.filter( - (selectedRecord) => - !activityTargetWithTargetRecords.some( - (activityTargetWithTargetRecord) => - activityTargetWithTargetRecord.targetObject.id === - selectedRecord.recordIdentifier.id, - ), - ); - - const existingActivityTargets = activityTargetWithTargetRecords.map( - (activityTargetObjectRecord) => activityTargetObjectRecord.activityTarget, - ); - - let activityTargetsAfterUpdate = Array.from(existingActivityTargets); - - const activityTargetsToCreate = selectedTargetObjectsToCreate.map( - (selectedRecord) => { - const emptyActivityTarget = prefillRecord<ActivityTarget>({ - objectMetadataItem: objectMetadataItemActivityTarget, - input: { - id: v4(), - activityId: activity.id, - activity, - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), - [getActivityTargetObjectFieldName({ - nameSingular: selectedRecord.objectMetadataItem.nameSingular, - })]: selectedRecord.record, - [getActivityTargetObjectFieldIdName({ - nameSingular: selectedRecord.objectMetadataItem.nameSingular, - })]: selectedRecord.recordIdentifier.id, - }, - }); + const handleSubmit = useRecoilCallback( + ({ snapshot }) => + async () => { + const activityTargetsAfterUpdate = + activityTargetWithTargetRecords.filter((activityTarget) => { + const record = snapshot + .getLoadable( + objectRecordMultiSelectComponentFamilyState({ + scopeId: relationPickerScopeId, + familyKey: activityTarget.targetObject.id, + }), + ) + .getValue() as ObjectRecordAndSelected; + + return record.selected; + }); + setActivityFromStore((currentActivity) => { + if (isNull(currentActivity)) { + return null; + } - return emptyActivityTarget; + return { + ...currentActivity, + activityTargets: activityTargetsAfterUpdate, + }; + }); + closeEditableField(); }, - ); - - activityTargetsAfterUpdate.push(...activityTargetsToCreate); - - if (isNonEmptyArray(activityTargetsToDelete)) { - activityTargetsAfterUpdate = activityTargetsAfterUpdate.filter( - (activityTarget) => - !activityTargetsToDelete.some( - (activityTargetToDelete) => - activityTargetToDelete.activityTarget.id === activityTarget.id, - ), - ); - } - - if (isActivityInCreateMode) { - createManyActivityTargetsInCache(activityTargetsToCreate); - upsertActivity({ - activity, - input: { - activityTargets: activityTargetsAfterUpdate, - }, - }); - } else { - if (activityTargetsToCreate.length > 0) { - await createManyActivityTargets(activityTargetsToCreate); - } - - if (activityTargetsToDelete.length > 0) { - await deleteManyActivityTargets( - activityTargetsToDelete.map( - (activityTargetObjectRecord) => - activityTargetObjectRecord.activityTarget.id, - ), + [ + activityTargetWithTargetRecords, + closeEditableField, + relationPickerScopeId, + setActivityFromStore, + ], + ); + + const handleChange = useRecoilCallback( + ({ snapshot, set }) => + async (recordId: string) => { + const existingActivityTargets = activityTargetWithTargetRecords.map( + (activityTargetObjectRecord) => + activityTargetObjectRecord.activityTarget, ); - } - } - - setActivityFromStore((currentActivity) => { - if (isNull(currentActivity)) { - return null; - } - - return { - ...currentActivity, - activityTargets: activityTargetsAfterUpdate, - }; - }); - }; + + let activityTargetsAfterUpdate = Array.from(existingActivityTargets); + + const previouslyCheckedRecordsIds = snapshot + .getLoadable( + objectRecordMultiSelectCheckedRecordsIdsComponentState({ + scopeId: relationPickerScopeId, + }), + ) + .getValue(); + + const isNewlySelected = !previouslyCheckedRecordsIds.includes(recordId); + + if (isNewlySelected) { + const record = snapshot + .getLoadable( + objectRecordMultiSelectComponentFamilyState({ + scopeId: relationPickerScopeId, + familyKey: recordId, + }), + ) + .getValue(); + + if (!record) { + throw new Error( + `Could not find selected record with id ${recordId}`, + ); + } + + set( + objectRecordMultiSelectCheckedRecordsIdsComponentState({ + scopeId: relationPickerScopeId, + }), + (prev) => [...prev, recordId], + ); + + const newActivityTargetId = v4(); + const fieldName = getActivityTargetObjectFieldName({ + nameSingular: record.objectMetadataItem.nameSingular, + }); + const fieldNameWithIdSuffix = getActivityTargetObjectFieldIdName({ + nameSingular: record.objectMetadataItem.nameSingular, + }); + const newActivityTarget = prefillRecord<ActivityTarget>({ + objectMetadataItem: objectMetadataItemActivityTarget, + input: { + id: newActivityTargetId, + activityId: activity.id, + activity, + createdAt: new Date().toISOString(), + updatedAt: new Date().toISOString(), + [fieldName]: record.record, + [fieldNameWithIdSuffix]: recordId, + }, + }); + + activityTargetsAfterUpdate.push(newActivityTarget); + + if (isActivityInCreateMode) { + createManyActivityTargetsInCache([newActivityTarget]); + upsertActivity({ + activity, + input: { + activityTargets: activityTargetsAfterUpdate, + }, + }); + } else { + await createManyActivityTargets([newActivityTarget]); + } + + set(activityTargetObjectRecordFamilyState(recordId), { + activityTargetId: newActivityTargetId, + }); + } else { + const activityTargetToDeleteId = snapshot + .getLoadable(activityTargetObjectRecordFamilyState(recordId)) + .getValue().activityTargetId; + + if (!activityTargetToDeleteId) { + throw new Error('Could not delete this activity target.'); + } + + set( + objectRecordMultiSelectCheckedRecordsIdsComponentState({ + scopeId: relationPickerScopeId, + }), + previouslyCheckedRecordsIds.filter((id) => id !== recordId), + ); + activityTargetsAfterUpdate = activityTargetsAfterUpdate.filter( + (activityTarget) => activityTarget.id !== activityTargetToDeleteId, + ); + + if (isActivityInCreateMode) { + upsertActivity({ + activity, + input: { + activityTargets: activityTargetsAfterUpdate, + }, + }); + } else { + await deleteManyActivityTargets([activityTargetToDeleteId]); + } + + set(activityTargetObjectRecordFamilyState(recordId), { + activityTargetId: null, + }); + } + }, + [ + activity, + activityTargetWithTargetRecords, + createManyActivityTargets, + createManyActivityTargetsInCache, + deleteManyActivityTargets, + isActivityInCreateMode, + objectMetadataItemActivityTarget, + relationPickerScopeId, + upsertActivity, + ], + ); return ( <StyledSelectContainer> - <MultipleObjectRecordSelect - selectedObjectRecordIds={selectedTargetObjectIds} - onSubmit={handleSubmit} - /> + <RelationPickerScope relationPickerScopeId={relationPickerScopeId}> + <ActivityTargetObjectRecordEffect + activityTargetWithTargetRecords={activityTargetWithTargetRecords} + /> + <ActivityTargetInlineCellEditModeMultiRecordsEffect + selectedObjectRecordIds={selectedTargetObjectIds} + /> + <MultiRecordSelect onSubmit={handleSubmit} onChange={handleChange} /> + </RelationPickerScope> </StyledSelectContainer> ); }; diff --git a/packages/twenty-front/src/modules/activities/inline-cell/components/ActivityTargetObjectRecordEffect.tsx b/packages/twenty-front/src/modules/activities/inline-cell/components/ActivityTargetObjectRecordEffect.tsx new file mode 100644 index 000000000000..aee9ea49d2d6 --- /dev/null +++ b/packages/twenty-front/src/modules/activities/inline-cell/components/ActivityTargetObjectRecordEffect.tsx @@ -0,0 +1,42 @@ +import { useEffect } from 'react'; +import { useRecoilCallback } from 'recoil'; + +import { ActivityTargetWithTargetRecord } from '@/activities/types/ActivityTargetObject'; +import { activityTargetObjectRecordFamilyState } from '@/object-record/record-field/states/activityTargetObjectRecordFamilyState'; +import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; + +export const ActivityTargetObjectRecordEffect = ({ + activityTargetWithTargetRecords, +}: { + activityTargetWithTargetRecords: ActivityTargetWithTargetRecord[]; +}) => { + const updateActivityTargets = useRecoilCallback( + ({ snapshot, set }) => + (newActivityTargets: ActivityTargetWithTargetRecord[]) => { + for (const newActivityTarget of newActivityTargets) { + const objectRecordId = newActivityTarget.targetObject.id; + const record = snapshot + .getLoadable(activityTargetObjectRecordFamilyState(objectRecordId)) + .getValue(); + + if ( + !isDeeplyEqual( + record.activityTargetId, + newActivityTarget.activityTarget.id, + ) + ) { + set(activityTargetObjectRecordFamilyState(objectRecordId), { + activityTargetId: newActivityTarget.activityTarget.id, + }); + } + } + }, + [], + ); + + useEffect(() => { + updateActivityTargets(activityTargetWithTargetRecords); + }, [activityTargetWithTargetRecords, updateActivityTargets]); + + return <></>; +}; diff --git a/packages/twenty-front/src/modules/activities/inline-cell/components/ActivityTargetsInlineCell.tsx b/packages/twenty-front/src/modules/activities/inline-cell/components/ActivityTargetsInlineCell.tsx index 2755acefd1c4..f1490e1d49b0 100644 --- a/packages/twenty-front/src/modules/activities/inline-cell/components/ActivityTargetsInlineCell.tsx +++ b/packages/twenty-front/src/modules/activities/inline-cell/components/ActivityTargetsInlineCell.tsx @@ -7,6 +7,8 @@ import { useActivityTargetObjectRecords } from '@/activities/hooks/useActivityTa import { ActivityTargetInlineCellEditMode } from '@/activities/inline-cell/components/ActivityTargetInlineCellEditMode'; import { Activity } from '@/activities/types/Activity'; import { ActivityEditorHotkeyScope } from '@/activities/types/ActivityEditorHotkeyScope'; +import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; +import { useFieldContext } from '@/object-record/hooks/useFieldContext'; import { FieldContext } from '@/object-record/record-field/contexts/FieldContext'; import { FieldFocusContextProvider } from '@/object-record/record-field/contexts/FieldFocusContextProvider'; import { RecordFieldInputScope } from '@/object-record/record-field/scopes/RecordFieldInputScope'; @@ -41,33 +43,45 @@ export const ActivityTargetsInlineCell = ({ ActivityEditorHotkeyScope.ActivityTargets, ); + const { FieldContextProvider: ActivityTargetsContextProvider } = + useFieldContext({ + objectNameSingular: CoreObjectNameSingular.Activity, + objectRecordId: activity.id, + fieldMetadataName: 'activityTargets', + fieldPosition: 3, + overridenIsFieldEmpty: activityTargetObjectRecords.length === 0, + }); + return ( <RecordFieldInputScope recordFieldInputScopeId={activity?.id ?? ''}> <FieldFocusContextProvider> - <RecordInlineCellContainer - buttonIcon={IconPencil} - customEditHotkeyScope={{ - scope: ActivityEditorHotkeyScope.ActivityTargets, - }} - IconLabel={showLabel ? IconArrowUpRight : undefined} - showLabel={showLabel} - readonly={readonly} - labelWidth={fieldDefinition?.labelWidth} - editModeContent={ - <ActivityTargetInlineCellEditMode - activity={activity} - activityTargetWithTargetRecords={activityTargetObjectRecords} - /> - } - label="Relations" - displayModeContent={ - <ActivityTargetChips - activityTargetObjectRecords={activityTargetObjectRecords} - maxWidth={maxWidth} + {ActivityTargetsContextProvider && ( + <ActivityTargetsContextProvider> + <RecordInlineCellContainer + buttonIcon={IconPencil} + customEditHotkeyScope={{ + scope: ActivityEditorHotkeyScope.ActivityTargets, + }} + IconLabel={showLabel ? IconArrowUpRight : undefined} + showLabel={showLabel} + readonly={readonly} + labelWidth={fieldDefinition?.labelWidth} + editModeContent={ + <ActivityTargetInlineCellEditMode + activity={activity} + activityTargetWithTargetRecords={activityTargetObjectRecords} + /> + } + label="Relations" + displayModeContent={ + <ActivityTargetChips + activityTargetObjectRecords={activityTargetObjectRecords} + maxWidth={maxWidth} + /> + } /> - } - isDisplayModeContentEmpty={activityTargetObjectRecords.length === 0} - /> + </ActivityTargetsContextProvider> + )} </FieldFocusContextProvider> </RecordFieldInputScope> ); diff --git a/packages/twenty-front/src/modules/activities/notes/components/Notes.tsx b/packages/twenty-front/src/modules/activities/notes/components/Notes.tsx index 173bda4ede21..4f3e83656eb4 100644 --- a/packages/twenty-front/src/modules/activities/notes/components/Notes.tsx +++ b/packages/twenty-front/src/modules/activities/notes/components/Notes.tsx @@ -1,6 +1,7 @@ import styled from '@emotion/styled'; import { IconPlus } from 'twenty-ui'; +import { SkeletonLoader } from '@/activities/components/SkeletonLoader'; import { useOpenCreateActivityDrawer } from '@/activities/hooks/useOpenCreateActivityDrawer'; import { NoteList } from '@/activities/notes/components/NoteList'; import { useNotes } from '@/activities/notes/hooks/useNotes'; @@ -12,6 +13,7 @@ import { AnimatedPlaceholderEmptySubTitle, AnimatedPlaceholderEmptyTextContainer, AnimatedPlaceholderEmptyTitle, + EMPTY_PLACEHOLDER_TRANSITION_PROPS, } from '@/ui/layout/animated-placeholder/components/EmptyPlaceholderStyled'; const StyledNotesContainer = styled.div` @@ -27,13 +29,22 @@ export const Notes = ({ }: { targetableObject: ActivityTargetableObject; }) => { - const { notes } = useNotes(targetableObject); + const { notes, loading } = useNotes(targetableObject); const openCreateActivity = useOpenCreateActivityDrawer(); - if (notes?.length === 0) { + const isNotesEmpty = !notes || notes.length === 0; + + if (loading && isNotesEmpty) { + return <SkeletonLoader />; + } + + if (isNotesEmpty) { return ( - <AnimatedPlaceholderEmptyContainer> + <AnimatedPlaceholderEmptyContainer + // eslint-disable-next-line react/jsx-props-no-spreading + {...EMPTY_PLACEHOLDER_TRANSITION_PROPS} + > <AnimatedPlaceholder type="noNote" /> <AnimatedPlaceholderEmptyTextContainer> <AnimatedPlaceholderEmptyTitle> @@ -62,7 +73,7 @@ export const Notes = ({ <StyledNotesContainer> <NoteList title="All" - notes={notes ?? []} + notes={notes} button={ <Button Icon={IconPlus} diff --git a/packages/twenty-front/src/modules/activities/notes/hooks/useNotes.ts b/packages/twenty-front/src/modules/activities/notes/hooks/useNotes.ts index b50231f9e413..383061c5e04f 100644 --- a/packages/twenty-front/src/modules/activities/notes/hooks/useNotes.ts +++ b/packages/twenty-front/src/modules/activities/notes/hooks/useNotes.ts @@ -24,7 +24,7 @@ export const useNotes = (targetableObject: ActivityTargetableObject) => { const { activities, loading } = useActivities({ activitiesFilters: notesQueryVariables.filter ?? {}, - activitiesOrderByVariables: notesQueryVariables.orderBy ?? {}, + activitiesOrderByVariables: notesQueryVariables.orderBy ?? [{}], targetableObjects: [targetableObject], }); diff --git a/packages/twenty-front/src/modules/activities/states/objectRecordsIdsMultiSelectComponentState.ts b/packages/twenty-front/src/modules/activities/states/objectRecordsIdsMultiSelectComponentState.ts new file mode 100644 index 000000000000..67959df63be7 --- /dev/null +++ b/packages/twenty-front/src/modules/activities/states/objectRecordsIdsMultiSelectComponentState.ts @@ -0,0 +1,8 @@ +import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; + +export const objectRecordsIdsMultiSelecComponentState = createComponentState< + string[] +>({ + key: 'objectRecordsIdsMultiSelectComponentState', + defaultValue: [], +}); diff --git a/packages/twenty-front/src/modules/activities/tasks/components/TaskGroups.tsx b/packages/twenty-front/src/modules/activities/tasks/components/TaskGroups.tsx index 9103bb2d630b..03c2bdb97863 100644 --- a/packages/twenty-front/src/modules/activities/tasks/components/TaskGroups.tsx +++ b/packages/twenty-front/src/modules/activities/tasks/components/TaskGroups.tsx @@ -2,6 +2,7 @@ import styled from '@emotion/styled'; import { useRecoilValue } from 'recoil'; import { IconPlus } from 'twenty-ui'; +import { SkeletonLoader } from '@/activities/components/SkeletonLoader'; import { useOpenCreateActivityDrawer } from '@/activities/hooks/useOpenCreateActivityDrawer'; import { TASKS_TAB_LIST_COMPONENT_ID } from '@/activities/tasks/constants/TasksTabListComponentId'; import { useTasks } from '@/activities/tasks/hooks/useTasks'; @@ -13,6 +14,7 @@ import { AnimatedPlaceholderEmptySubTitle, AnimatedPlaceholderEmptyTextContainer, AnimatedPlaceholderEmptyTitle, + EMPTY_PLACEHOLDER_TRANSITION_PROPS, } from '@/ui/layout/animated-placeholder/components/EmptyPlaceholderStyled'; import { useTabList } from '@/ui/layout/tab/hooks/useTabList'; @@ -40,6 +42,8 @@ export const TaskGroups = ({ upcomingTasks, unscheduledTasks, completedTasks, + incompleteTasksLoading, + completeTasksLoading, } = useTasks({ filterDropdownId: filterDropdownId, targetableObjects: targetableObjects ?? [], @@ -50,15 +54,27 @@ export const TaskGroups = ({ const { activeTabIdState } = useTabList(TASKS_TAB_LIST_COMPONENT_ID); const activeTabId = useRecoilValue(activeTabIdState); - if ( + const isLoading = + (activeTabId !== 'done' && incompleteTasksLoading) || + (activeTabId === 'done' && completeTasksLoading); + + const isTasksEmpty = (activeTabId !== 'done' && todayOrPreviousTasks?.length === 0 && upcomingTasks?.length === 0 && unscheduledTasks?.length === 0) || - (activeTabId === 'done' && completedTasks?.length === 0) - ) { + (activeTabId === 'done' && completedTasks?.length === 0); + + if (isLoading && isTasksEmpty) { + return <SkeletonLoader />; + } + + if (isTasksEmpty) { return ( - <AnimatedPlaceholderEmptyContainer> + <AnimatedPlaceholderEmptyContainer + // eslint-disable-next-line react/jsx-props-no-spreading + {...EMPTY_PLACEHOLDER_TRANSITION_PROPS} + > <AnimatedPlaceholder type="noTask" /> <AnimatedPlaceholderEmptyTextContainer> <AnimatedPlaceholderEmptyTitle> diff --git a/packages/twenty-front/src/modules/activities/tasks/hooks/useTasks.ts b/packages/twenty-front/src/modules/activities/tasks/hooks/useTasks.ts index bb8fb16566ac..e560e2607940 100644 --- a/packages/twenty-front/src/modules/activities/tasks/hooks/useTasks.ts +++ b/packages/twenty-front/src/modules/activities/tasks/hooks/useTasks.ts @@ -107,17 +107,19 @@ export const useTasks = ({ setCurrentIncompleteTaskQueryVariables, ]); - const { activities: completeTasksData } = useActivities({ - targetableObjects, - activitiesFilters: completedQueryVariables.filter ?? {}, - activitiesOrderByVariables: completedQueryVariables.orderBy ?? {}, - }); - - const { activities: incompleteTaskData } = useActivities({ - targetableObjects, - activitiesFilters: incompleteQueryVariables.filter ?? {}, - activitiesOrderByVariables: incompleteQueryVariables.orderBy ?? {}, - }); + const { activities: completeTasksData, loading: completeTasksLoading } = + useActivities({ + targetableObjects, + activitiesFilters: completedQueryVariables.filter ?? {}, + activitiesOrderByVariables: completedQueryVariables.orderBy ?? [{}], + }); + + const { activities: incompleteTaskData, loading: incompleteTasksLoading } = + useActivities({ + targetableObjects, + activitiesFilters: incompleteQueryVariables.filter ?? {}, + activitiesOrderByVariables: incompleteQueryVariables.orderBy ?? [{}], + }); const todayOrPreviousTasks = incompleteTaskData?.filter((task) => { if (!task.dueAt) { @@ -148,5 +150,7 @@ export const useTasks = ({ upcomingTasks: (upcomingTasks ?? []) as Activity[], unscheduledTasks: (unscheduledTasks ?? []) as Activity[], completedTasks: (completedTasks ?? []) as Activity[], + completeTasksLoading, + incompleteTasksLoading, }; }; diff --git a/packages/twenty-front/src/modules/activities/timeline/components/Timeline.tsx b/packages/twenty-front/src/modules/activities/timeline/components/Timeline.tsx deleted file mode 100644 index 8ee67657592d..000000000000 --- a/packages/twenty-front/src/modules/activities/timeline/components/Timeline.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import styled from '@emotion/styled'; -import { useRecoilValue } from 'recoil'; - -import { TimelineCreateButtonGroup } from '@/activities/timeline/components/TimelineCreateButtonGroup'; -import { TimelineSkeletonLoader } from '@/activities/timeline/components/TimelineSkeletonLoader'; -import { timelineActivitiesForGroupState } from '@/activities/timeline/states/timelineActivitiesForGroupState'; -import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity'; -import AnimatedPlaceholder from '@/ui/layout/animated-placeholder/components/AnimatedPlaceholder'; -import { - AnimatedPlaceholderEmptyContainer, - AnimatedPlaceholderEmptySubTitle, - AnimatedPlaceholderEmptyTextContainer, - AnimatedPlaceholderEmptyTitle, -} from '@/ui/layout/animated-placeholder/components/EmptyPlaceholderStyled'; -import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; - -import { TimelineItemsContainer } from './TimelineItemsContainer'; - -const StyledMainContainer = styled.div` - align-items: flex-start; - align-self: stretch; - border-top: ${({ theme }) => - useIsMobile() ? `1px solid ${theme.border.color.medium}` : 'none'}; - display: flex; - flex-direction: column; - height: 100%; - - justify-content: center; -`; - -export const Timeline = ({ - targetableObject, - loading, -}: { - targetableObject: ActivityTargetableObject; - loading: boolean; -}) => { - const timelineActivitiesForGroup = useRecoilValue( - timelineActivitiesForGroupState, - ); - - if (loading) { - return <TimelineSkeletonLoader />; - } - - if (timelineActivitiesForGroup.length === 0) { - return ( - <AnimatedPlaceholderEmptyContainer> - <AnimatedPlaceholder type="emptyTimeline" /> - <AnimatedPlaceholderEmptyTextContainer> - <AnimatedPlaceholderEmptyTitle> - Add your first Activity - </AnimatedPlaceholderEmptyTitle> - <AnimatedPlaceholderEmptySubTitle> - There are no activities associated with this record.{' '} - </AnimatedPlaceholderEmptySubTitle> - </AnimatedPlaceholderEmptyTextContainer> - <TimelineCreateButtonGroup targetableObject={targetableObject} /> - </AnimatedPlaceholderEmptyContainer> - ); - } - - return ( - <StyledMainContainer> - <TimelineItemsContainer /> - </StyledMainContainer> - ); -}; diff --git a/packages/twenty-front/src/modules/activities/timeline/components/TimelineActivity.tsx b/packages/twenty-front/src/modules/activities/timeline/components/TimelineActivity.tsx index 2b4ff934ff95..fc915a1ce1bc 100644 --- a/packages/twenty-front/src/modules/activities/timeline/components/TimelineActivity.tsx +++ b/packages/twenty-front/src/modules/activities/timeline/components/TimelineActivity.tsx @@ -1,8 +1,7 @@ -import { Tooltip } from 'react-tooltip'; import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { useRecoilValue } from 'recoil'; -import { Avatar, IconCheckbox, IconNotes } from 'twenty-ui'; +import { AppTooltip, Avatar, IconCheckbox, IconNotes } from 'twenty-ui'; import { useOpenActivityRightDrawer } from '@/activities/hooks/useOpenActivityRightDrawer'; import { timelineActivityWithoutTargetsFamilyState } from '@/activities/timeline/states/timelineActivityWithoutTargetsFamilyState'; @@ -109,21 +108,6 @@ const StyledVerticalLine = styled.div` width: 2px; `; -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: ${({ theme }) => theme.spacing(2)}; -`; - const StyledTimelineItemContainer = styled.div<{ isGap?: boolean }>` align-items: center; align-self: stretch; @@ -217,7 +201,7 @@ export const TimelineActivity = ({ <StyledItemTitleDate id={`id-${activityForTimeline.id}`}> {beautifiedCreatedAt} </StyledItemTitleDate> - <StyledTooltip + <AppTooltip anchorSelect={`#id-${activityForTimeline.id}`} content={exactCreatedAt} clickable diff --git a/packages/twenty-front/src/modules/activities/timeline/components/TimelineCreateButtonGroup.tsx b/packages/twenty-front/src/modules/activities/timeline/components/TimelineCreateButtonGroup.tsx index 21c0c5713014..a4ca491496d0 100644 --- a/packages/twenty-front/src/modules/activities/timeline/components/TimelineCreateButtonGroup.tsx +++ b/packages/twenty-front/src/modules/activities/timeline/components/TimelineCreateButtonGroup.tsx @@ -1,44 +1,30 @@ import { useSetRecoilState } from 'recoil'; import { IconCheckbox, IconNotes, IconPaperclip } from 'twenty-ui'; -import { useOpenCreateActivityDrawer } from '@/activities/hooks/useOpenCreateActivityDrawer'; -import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity'; import { Button } from '@/ui/input/button/components/Button'; import { ButtonGroup } from '@/ui/input/button/components/ButtonGroup'; import { TAB_LIST_COMPONENT_ID } from '@/ui/layout/show-page/components/ShowPageRightContainer'; import { useTabList } from '@/ui/layout/tab/hooks/useTabList'; -export const TimelineCreateButtonGroup = ({ - targetableObject, -}: { - targetableObject: ActivityTargetableObject; -}) => { +export const TimelineCreateButtonGroup = () => { const { activeTabIdState } = useTabList(TAB_LIST_COMPONENT_ID); const setActiveTabId = useSetRecoilState(activeTabIdState); - const openCreateActivity = useOpenCreateActivityDrawer(); - return ( <ButtonGroup variant={'secondary'}> <Button Icon={IconNotes} title="Note" - onClick={() => - openCreateActivity({ - type: 'Note', - targetableObjects: [targetableObject], - }) - } + onClick={() => { + setActiveTabId('notes'); + }} /> <Button Icon={IconCheckbox} title="Task" - onClick={() => - openCreateActivity({ - type: 'Task', - targetableObjects: [targetableObject], - }) - } + onClick={() => { + setActiveTabId('tasks'); + }} /> <Button Icon={IconPaperclip} diff --git a/packages/twenty-front/src/modules/activities/timeline/components/TimelineQueryEffect.tsx b/packages/twenty-front/src/modules/activities/timeline/components/TimelineQueryEffect.tsx index 88c9669119b4..60367044b336 100644 --- a/packages/twenty-front/src/modules/activities/timeline/components/TimelineQueryEffect.tsx +++ b/packages/twenty-front/src/modules/activities/timeline/components/TimelineQueryEffect.tsx @@ -4,7 +4,7 @@ import { useRecoilCallback, useRecoilState, useSetRecoilState } from 'recoil'; import { useActivities } from '@/activities/hooks/useActivities'; import { FIND_MANY_TIMELINE_ACTIVITIES_ORDER_BY } from '@/activities/timeline/constants/FindManyTimelineActivitiesOrderBy'; import { objectShowPageTargetableObjectState } from '@/activities/timeline/states/objectShowPageTargetableObjectIdState'; -import { timelineActivitiesFammilyState } from '@/activities/timeline/states/timelineActivitiesFamilyState'; +import { timelineActivitiesFamilyState } from '@/activities/timeline/states/timelineActivitiesFamilyState'; import { timelineActivitiesForGroupState } from '@/activities/timeline/states/timelineActivitiesForGroupState'; import { timelineActivityWithoutTargetsFamilyState } from '@/activities/timeline/states/timelineActivityWithoutTargetsFamilyState'; import { Activity } from '@/activities/types/Activity'; @@ -68,11 +68,11 @@ export const TimelineQueryEffect = ({ (newActivities: Activity[]) => { for (const newActivity of newActivities) { const currentActivity = snapshot - .getLoadable(timelineActivitiesFammilyState(newActivity.id)) + .getLoadable(timelineActivitiesFamilyState(newActivity.id)) .getValue(); if (!isDeeplyEqual(newActivity, currentActivity)) { - set(timelineActivitiesFammilyState(newActivity.id), newActivity); + set(timelineActivitiesFamilyState(newActivity.id), newActivity); } const currentActivityWithoutTarget = snapshot diff --git a/packages/twenty-front/src/modules/activities/timeline/constants/FindManyTimelineActivitiesOrderBy.ts b/packages/twenty-front/src/modules/activities/timeline/constants/FindManyTimelineActivitiesOrderBy.ts index 4e48c6dc5f65..ea6c4763571a 100644 --- a/packages/twenty-front/src/modules/activities/timeline/constants/FindManyTimelineActivitiesOrderBy.ts +++ b/packages/twenty-front/src/modules/activities/timeline/constants/FindManyTimelineActivitiesOrderBy.ts @@ -1,6 +1,8 @@ import { RecordGqlOperationOrderBy } from '@/object-record/graphql/types/RecordGqlOperationOrderBy'; export const FIND_MANY_TIMELINE_ACTIVITIES_ORDER_BY: RecordGqlOperationOrderBy = - { - createdAt: 'DescNullsFirst', - }; + [ + { + createdAt: 'DescNullsFirst', + }, + ]; diff --git a/packages/twenty-front/src/modules/activities/timeline/states/timelineActivitiesFamilyState.ts b/packages/twenty-front/src/modules/activities/timeline/states/timelineActivitiesFamilyState.ts index f2acc7a3312f..88903b6c8e38 100644 --- a/packages/twenty-front/src/modules/activities/timeline/states/timelineActivitiesFamilyState.ts +++ b/packages/twenty-front/src/modules/activities/timeline/states/timelineActivitiesFamilyState.ts @@ -1,10 +1,10 @@ import { Activity } from '@/activities/types/Activity'; import { createFamilyState } from '@/ui/utilities/state/utils/createFamilyState'; -export const timelineActivitiesFammilyState = createFamilyState< +export const timelineActivitiesFamilyState = createFamilyState< Activity | null, string >({ - key: 'timelineActivitiesFammilyState', + key: 'timelineActivitiesFamilyState', defaultValue: null, }); diff --git a/packages/twenty-front/src/modules/activities/timeline/utils/makeTimelineActivitiesQueryVariables.ts b/packages/twenty-front/src/modules/activities/timeline/utils/makeTimelineActivitiesQueryVariables.ts index c8a7030d2d99..4a9c67f5b54c 100644 --- a/packages/twenty-front/src/modules/activities/timeline/utils/makeTimelineActivitiesQueryVariables.ts +++ b/packages/twenty-front/src/modules/activities/timeline/utils/makeTimelineActivitiesQueryVariables.ts @@ -13,8 +13,10 @@ export const makeTimelineActivitiesQueryVariables = ({ in: [...activityIds].sort(sortByAscString), }, }, - orderBy: { - createdAt: 'DescNullsFirst', - }, + orderBy: [ + { + createdAt: 'DescNullsFirst', + }, + ], }; }; diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/components/EventRow.tsx b/packages/twenty-front/src/modules/activities/timelineActivities/components/EventRow.tsx index b1072ee5790e..050b5c1b3206 100644 --- a/packages/twenty-front/src/modules/activities/timelineActivities/components/EventRow.tsx +++ b/packages/twenty-front/src/modules/activities/timelineActivities/components/EventRow.tsx @@ -10,10 +10,23 @@ import { TimelineActivity } from '@/activities/timelineActivities/types/Timeline import { getTimelineActivityAuthorFullName } from '@/activities/timelineActivities/utils/getTimelineActivityAuthorFullName'; import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; -import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; import { beautifyPastDateRelativeToNow } from '~/utils/date-utils'; import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull'; +const StyledTimelineItemContainer = styled.div` + display: flex; + gap: ${({ theme }) => theme.spacing(4)}; + height: 'auto'; + justify-content: space-between; + overflow: hidden; + white-space: nowrap; +`; + +const StyledLeftContainer = styled.div` + display: flex; + flex-direction: column; +`; + const StyledIconContainer = styled.div` display: flex; align-items: center; @@ -25,62 +38,50 @@ const StyledIconContainer = styled.div` user-select: none; text-decoration-line: underline; z-index: 2; - align-self: normal; -`; - -const StyledItemContainer = styled.div` - display: flex; - align-items: center; - gap: ${({ theme }) => theme.spacing(1)}; - flex: 1; - overflow: hidden; -`; - -const StyledItemTitleDate = styled.div` - align-items: center; - color: ${({ theme }) => theme.font.color.tertiary}; - display: flex; - gap: ${({ theme }) => theme.spacing(2)}; - justify-content: flex-end; - margin-left: auto; - align-self: baseline; `; const StyledVerticalLineContainer = styled.div` - align-items: center; - align-self: stretch; display: flex; - gap: ${({ theme }) => theme.spacing(2)}; + flex-shrink: 0; justify-content: center; - width: 26px; z-index: 2; + height: 100%; `; const StyledVerticalLine = styled.div` - align-self: stretch; background: ${({ theme }) => theme.border.color.light}; - flex-shrink: 0; width: 2px; + height: 100%; `; -const StyledTimelineItemContainer = styled.div<{ isGap?: boolean }>` - display: flex; +const StyledSummary = styled.summary` align-items: center; - justify-content: space-between; - gap: ${({ theme }) => theme.spacing(4)}; - height: ${({ isGap, theme }) => - isGap ? (useIsMobile() ? theme.spacing(6) : theme.spacing(3)) : 'auto'}; - overflow: hidden; - white-space: nowrap; + display: flex; + flex: 1; + flex-direction: row; + gap: ${({ theme }) => theme.spacing(1)}; `; -const StyledSummary = styled.summary` +const StyledItemContainer = styled.div<{ isMarginBottom?: boolean }>` + align-items: flex-start; display: flex; flex: 1; - flex-direction: row; + flex-direction: column; gap: ${({ theme }) => theme.spacing(1)}; - align-items: center; overflow: hidden; + margin-bottom: ${({ isMarginBottom, theme }) => + isMarginBottom ? theme.spacing(3) : 0}; + min-height: 26px; +`; + +const StyledItemTitleDate = styled.div` + align-items: flex-start; + padding-top: ${({ theme }) => theme.spacing(1)}; + color: ${({ theme }) => theme.font.color.tertiary}; + display: flex; + gap: ${({ theme }) => theme.spacing(1)}; + justify-content: flex-end; + margin-left: auto; `; type EventRowProps = { @@ -118,13 +119,20 @@ export const EventRow = ({ return ( <> <StyledTimelineItemContainer> - <StyledIconContainer> - <EventIconDynamicComponent - event={event} - linkedObjectMetadataItem={linkedObjectMetadataItem} - /> - </StyledIconContainer> - <StyledItemContainer> + <StyledLeftContainer> + <StyledIconContainer> + <EventIconDynamicComponent + event={event} + linkedObjectMetadataItem={linkedObjectMetadataItem} + /> + </StyledIconContainer> + {!isLastEvent && ( + <StyledVerticalLineContainer> + <StyledVerticalLine /> + </StyledVerticalLineContainer> + )} + </StyledLeftContainer> + <StyledItemContainer isMarginBottom={!isLastEvent}> <StyledSummary> <EventRowDynamicComponent authorFullName={authorFullName} @@ -134,18 +142,11 @@ export const EventRow = ({ linkedObjectMetadataItem={linkedObjectMetadataItem} /> </StyledSummary> - <StyledItemTitleDate id={`id-${event.id}`}> - {beautifiedCreatedAt} - </StyledItemTitleDate> </StyledItemContainer> + <StyledItemTitleDate id={`id-${event.id}`}> + {beautifiedCreatedAt} + </StyledItemTitleDate> </StyledTimelineItemContainer> - {!isLastEvent && ( - <StyledTimelineItemContainer isGap> - <StyledVerticalLineContainer> - <StyledVerticalLine /> - </StyledVerticalLineContainer> - </StyledTimelineItemContainer> - )} </> ); }; diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/components/TimelineActivities.tsx b/packages/twenty-front/src/modules/activities/timelineActivities/components/TimelineActivities.tsx index c0b47efdac09..f24972e9509c 100644 --- a/packages/twenty-front/src/modules/activities/timelineActivities/components/TimelineActivities.tsx +++ b/packages/twenty-front/src/modules/activities/timelineActivities/components/TimelineActivities.tsx @@ -1,7 +1,7 @@ import styled from '@emotion/styled'; -import { isNonEmptyArray } from '@sniptt/guards'; import { CustomResolverFetchMoreLoader } from '@/activities/components/CustomResolverFetchMoreLoader'; +import { SkeletonLoader } from '@/activities/components/SkeletonLoader'; import { TimelineCreateButtonGroup } from '@/activities/timeline/components/TimelineCreateButtonGroup'; import { EventList } from '@/activities/timelineActivities/components/EventList'; import { useTimelineActivities } from '@/activities/timelineActivities/hooks/useTimelineActivities'; @@ -12,6 +12,7 @@ import { AnimatedPlaceholderEmptySubTitle, AnimatedPlaceholderEmptyTextContainer, AnimatedPlaceholderEmptyTitle, + EMPTY_PLACEHOLDER_TRANSITION_PROPS, } from '@/ui/layout/animated-placeholder/components/EmptyPlaceholderStyled'; import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; @@ -23,11 +24,11 @@ const StyledMainContainer = styled.div` display: flex; flex-direction: column; height: 100%; + overflow: auto; justify-content: center; padding-top: ${({ theme }) => theme.spacing(6)}; padding-right: ${({ theme }) => theme.spacing(6)}; - padding-bottom: ${({ theme }) => theme.spacing(16)}; padding-left: ${({ theme }) => theme.spacing(6)}; gap: ${({ theme }) => theme.spacing(4)}; `; @@ -40,9 +41,19 @@ export const TimelineActivities = ({ const { timelineActivities, loading, fetchMoreRecords } = useTimelineActivities(targetableObject); - if (!isNonEmptyArray(timelineActivities)) { + const isTimelineActivitiesEmpty = + !timelineActivities || timelineActivities.length === 0; + + if (loading && isTimelineActivitiesEmpty) { + return <SkeletonLoader withSubSections />; + } + + if (isTimelineActivitiesEmpty) { return ( - <AnimatedPlaceholderEmptyContainer> + <AnimatedPlaceholderEmptyContainer + // eslint-disable-next-line react/jsx-props-no-spreading + {...EMPTY_PLACEHOLDER_TRANSITION_PROPS} + > <AnimatedPlaceholder type="emptyTimeline" /> <AnimatedPlaceholderEmptyTextContainer> <AnimatedPlaceholderEmptyTitle> @@ -52,7 +63,7 @@ export const TimelineActivities = ({ There are no activities associated with this record.{' '} </AnimatedPlaceholderEmptySubTitle> </AnimatedPlaceholderEmptyTextContainer> - <TimelineCreateButtonGroup targetableObject={targetableObject} /> + <TimelineCreateButtonGroup /> </AnimatedPlaceholderEmptyContainer> ); } diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/hooks/useTimelineActivities.tsx b/packages/twenty-front/src/modules/activities/timelineActivities/hooks/useTimelineActivities.tsx index a6173b5d9953..e18dff4befe6 100644 --- a/packages/twenty-front/src/modules/activities/timelineActivities/hooks/useTimelineActivities.tsx +++ b/packages/twenty-front/src/modules/activities/timelineActivities/hooks/useTimelineActivities.tsx @@ -23,9 +23,11 @@ export const useTimelineActivities = ( eq: targetableObject.id, }, }, - orderBy: { - createdAt: 'DescNullsFirst', - }, + orderBy: [ + { + createdAt: 'DescNullsFirst', + }, + ], recordGqlFields: { id: true, createdAt: true, diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/rows/calendar/components/EventCardCalendarEvent.tsx b/packages/twenty-front/src/modules/activities/timelineActivities/rows/calendar/components/EventCardCalendarEvent.tsx index 413a70e213ca..8d572594f4fc 100644 --- a/packages/twenty-front/src/modules/activities/timelineActivities/rows/calendar/components/EventCardCalendarEvent.tsx +++ b/packages/twenty-front/src/modules/activities/timelineActivities/rows/calendar/components/EventCardCalendarEvent.tsx @@ -5,7 +5,7 @@ import { useOpenCalendarEventRightDrawer } from '@/activities/calendar/right-dra import { CalendarEvent } from '@/activities/calendar/types/CalendarEvent'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord'; -import { useSetRecordInStore } from '@/object-record/record-store/hooks/useSetRecordInStore'; +import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore'; import { formatToHumanReadableDay, formatToHumanReadableMonth, @@ -85,7 +85,7 @@ export const EventCardCalendarEvent = ({ }: { calendarEventId: string; }) => { - const { setRecords } = useSetRecordInStore(); + const { upsertRecords } = useUpsertRecordsInStore(); const { record: calendarEvent, @@ -101,7 +101,7 @@ export const EventCardCalendarEvent = ({ endsAt: true, }, onCompleted: (data) => { - setRecords([data]); + upsertRecords([data]); }, }); diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/rows/components/EventCard.tsx b/packages/twenty-front/src/modules/activities/timelineActivities/rows/components/EventCard.tsx index baed69eb738a..67e4f78cd726 100644 --- a/packages/twenty-front/src/modules/activities/timelineActivities/rows/components/EventCard.tsx +++ b/packages/twenty-front/src/modules/activities/timelineActivities/rows/components/EventCard.tsx @@ -15,7 +15,7 @@ const StyledCardContainer = styled.div` gap: ${({ theme }) => theme.spacing(2)}; width: 400px; padding: ${({ theme }) => theme.spacing(2)} 0px - ${({ theme }) => theme.spacing(4)} 0px; + ${({ theme }) => theme.spacing(1)} 0px; `; const StyledCard = styled(Card)` diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/rows/message/components/EventCardMessage.tsx b/packages/twenty-front/src/modules/activities/timelineActivities/rows/message/components/EventCardMessage.tsx index 9c2b41dd4d7f..134dd95ba3a7 100644 --- a/packages/twenty-front/src/modules/activities/timelineActivities/rows/message/components/EventCardMessage.tsx +++ b/packages/twenty-front/src/modules/activities/timelineActivities/rows/message/components/EventCardMessage.tsx @@ -7,7 +7,7 @@ import { EmailThreadMessage } from '@/activities/emails/types/EmailThreadMessage import { EventCardMessageNotShared } from '@/activities/timelineActivities/rows/message/components/EventCardMessageNotShared'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord'; -import { useSetRecordInStore } from '@/object-record/record-store/hooks/useSetRecordInStore'; +import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore'; import { isDefined } from '~/utils/isDefined'; const StyledEventCardMessageContainer = styled.div` @@ -56,7 +56,7 @@ export const EventCardMessage = ({ messageId: string; authorFullName: string; }) => { - const { setRecords } = useSetRecordInStore(); + const { upsertRecords } = useUpsertRecordsInStore(); const { record: message, @@ -75,7 +75,7 @@ export const EventCardMessage = ({ }, }, onCompleted: (data) => { - setRecords([data]); + upsertRecords([data]); }, }); diff --git a/packages/twenty-front/src/modules/apollo/optimistic-effect/utils/sortCachedObjectEdges.ts b/packages/twenty-front/src/modules/apollo/optimistic-effect/utils/sortCachedObjectEdges.ts index aa8434f0ba80..6f76dd66a5a8 100644 --- a/packages/twenty-front/src/modules/apollo/optimistic-effect/utils/sortCachedObjectEdges.ts +++ b/packages/twenty-front/src/modules/apollo/optimistic-effect/utils/sortCachedObjectEdges.ts @@ -16,7 +16,7 @@ export const sortCachedObjectEdges = ({ orderBy: RecordGqlOperationOrderBy; readCacheField: ReadFieldFunction; }) => { - const [orderByFieldName, orderByFieldValue] = Object.entries(orderBy)[0]; + const [orderByFieldName, orderByFieldValue] = Object.entries(orderBy[0])[0]; const [orderBySubFieldName, orderBySubFieldValue] = typeof orderByFieldValue === 'string' ? [] diff --git a/packages/twenty-front/src/modules/apollo/optimistic-effect/utils/triggerCreateRecordsOptimisticEffect.ts b/packages/twenty-front/src/modules/apollo/optimistic-effect/utils/triggerCreateRecordsOptimisticEffect.ts index 5df2b2acbcc7..057f93006fa0 100644 --- a/packages/twenty-front/src/modules/apollo/optimistic-effect/utils/triggerCreateRecordsOptimisticEffect.ts +++ b/packages/twenty-front/src/modules/apollo/optimistic-effect/utils/triggerCreateRecordsOptimisticEffect.ts @@ -7,7 +7,11 @@ import { RecordGqlRefEdge } from '@/object-record/cache/types/RecordGqlRefEdge'; import { getEdgeTypename } from '@/object-record/cache/utils/getEdgeTypename'; import { isObjectRecordConnectionWithRefs } from '@/object-record/cache/utils/isObjectRecordConnectionWithRefs'; import { RecordGqlNode } from '@/object-record/graphql/types/RecordGqlNode'; +import { isRecordMatchingFilter } from '@/object-record/record-filter/utils/isRecordMatchingFilter'; + +import { CachedObjectRecordQueryVariables } from '@/apollo/types/CachedObjectRecordQueryVariables'; import { isDefined } from '~/utils/isDefined'; +import { parseApolloStoreFieldName } from '~/utils/parseApolloStoreFieldName'; /* TODO: for now new records are added to all cached record lists, no matter what the variables (filters, orderBy, etc.) are. @@ -19,11 +23,13 @@ export const triggerCreateRecordsOptimisticEffect = ({ objectMetadataItem, recordsToCreate, objectMetadataItems, + shouldMatchRootQueryFilter, }: { cache: ApolloCache<unknown>; objectMetadataItem: ObjectMetadataItem; recordsToCreate: RecordGqlNode[]; objectMetadataItems: ObjectMetadataItem[]; + shouldMatchRootQueryFilter?: boolean; }) => { recordsToCreate.forEach((record) => triggerUpdateRelationsOptimisticEffect({ @@ -39,12 +45,7 @@ export const triggerCreateRecordsOptimisticEffect = ({ fields: { [objectMetadataItem.namePlural]: ( rootQueryCachedResponse, - { - DELETE: _DELETE, - readField, - storeFieldName: _storeFieldName, - toReference, - }, + { DELETE: _DELETE, readField, storeFieldName, toReference }, ) => { const shouldSkip = !isObjectRecordConnectionWithRefs( objectMetadataItem.nameSingular, @@ -55,6 +56,13 @@ export const triggerCreateRecordsOptimisticEffect = ({ return rootQueryCachedResponse; } + const { fieldVariables: rootQueryVariables } = + parseApolloStoreFieldName<CachedObjectRecordQueryVariables>( + storeFieldName, + ); + + const rootQueryFilter = rootQueryVariables?.filter; + const rootQueryCachedObjectRecordConnection = rootQueryCachedResponse; const rootQueryCachedRecordEdges = readField<RecordGqlRefEdge[]>( @@ -74,6 +82,22 @@ export const triggerCreateRecordsOptimisticEffect = ({ const hasAddedRecords = recordsToCreate .map((recordToCreate) => { if (isNonEmptyString(recordToCreate.id)) { + if ( + isDefined(rootQueryFilter) && + shouldMatchRootQueryFilter === true + ) { + const recordToCreateMatchesThisRootQueryFilter = + isRecordMatchingFilter({ + record: recordToCreate, + filter: rootQueryFilter, + objectMetadataItem, + }); + + if (!recordToCreateMatchesThisRootQueryFilter) { + return false; + } + } + const recordToCreateReference = toReference(recordToCreate); if (!recordToCreateReference) { diff --git a/packages/twenty-front/src/modules/apollo/optimistic-effect/utils/triggerUpdateRelationsOptimisticEffect.ts b/packages/twenty-front/src/modules/apollo/optimistic-effect/utils/triggerUpdateRelationsOptimisticEffect.ts index 0b12d7524bd0..16d103532b77 100644 --- a/packages/twenty-front/src/modules/apollo/optimistic-effect/utils/triggerUpdateRelationsOptimisticEffect.ts +++ b/packages/twenty-front/src/modules/apollo/optimistic-effect/utils/triggerUpdateRelationsOptimisticEffect.ts @@ -70,6 +70,7 @@ export const triggerUpdateRelationsOptimisticEffect = ({ isDeeplyEqual( currentFieldValueOnSourceRecord, updatedFieldValueOnSourceRecord, + { strict: true }, ) ) { return; diff --git a/packages/twenty-front/src/modules/auth/hooks/__test__/useOnboardingStatus.test.ts b/packages/twenty-front/src/modules/auth/hooks/__test__/useOnboardingStatus.test.ts deleted file mode 100644 index 13d8e23fdaff..000000000000 --- a/packages/twenty-front/src/modules/auth/hooks/__test__/useOnboardingStatus.test.ts +++ /dev/null @@ -1,373 +0,0 @@ -import { act } from 'react-dom/test-utils'; -import { renderHook } from '@testing-library/react'; -import { RecoilRoot, useSetRecoilState } from 'recoil'; - -import { useOnboardingStatus } from '@/auth/hooks/useOnboardingStatus'; -import { CurrentUser, currentUserState } from '@/auth/states/currentUserState'; -import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; -import { - CurrentWorkspace, - currentWorkspaceState, -} from '@/auth/states/currentWorkspaceState'; -import { isVerifyPendingState } from '@/auth/states/isVerifyPendingState'; -import { tokenPairState } from '@/auth/states/tokenPairState'; -import { billingState } from '@/client-config/states/billingState'; -import { OnboardingStep } from '~/generated/graphql'; - -const tokenPair = { - accessToken: { token: 'accessToken', expiresAt: 'expiresAt' }, - refreshToken: { token: 'refreshToken', expiresAt: 'expiresAt' }, -}; -const billing = { - billingUrl: 'testing.com', - isBillingEnabled: true, -}; -const currentUser = { - id: '1', - email: 'test@test', - supportUserHash: '1', - canImpersonate: false, - onboardingStep: null, -} as CurrentUser; -const currentWorkspace = { - activationStatus: 'active', - id: '1', - allowImpersonation: true, - currentBillingSubscription: { - status: 'trialing', - }, -} as CurrentWorkspace; -const currentWorkspaceMember = { - id: '1', - locale: '', - name: { - firstName: '', - lastName: '', - }, -}; - -const renderHooks = () => { - const { result } = renderHook( - () => { - const onboardingStatus = useOnboardingStatus(); - const setBilling = useSetRecoilState(billingState); - const setCurrentWorkspace = useSetRecoilState(currentWorkspaceState); - const setCurrentWorkspaceMember = useSetRecoilState( - currentWorkspaceMemberState, - ); - const setCurrentUser = useSetRecoilState(currentUserState); - const setTokenPair = useSetRecoilState(tokenPairState); - const setVerifyPending = useSetRecoilState(isVerifyPendingState); - - return { - onboardingStatus, - setBilling, - setCurrentUser, - setCurrentWorkspace, - setCurrentWorkspaceMember, - setTokenPair, - setVerifyPending, - }; - }, - { - wrapper: RecoilRoot, - }, - ); - return { result }; -}; - -describe('useOnboardingStatus', () => { - it('should return "ongoing_user_creation" when user is not logged in', async () => { - const { result } = renderHooks(); - - expect(result.current.onboardingStatus).toBe('ongoing_user_creation'); - }); - - it('should return "incomplete"', async () => { - const { result } = renderHooks(); - const { - setTokenPair, - setBilling, - setCurrentUser, - setCurrentWorkspace, - setCurrentWorkspaceMember, - } = result.current; - - act(() => { - setTokenPair(tokenPair); - setBilling(billing); - setCurrentUser(currentUser); - setCurrentWorkspace({ - ...currentWorkspace, - subscriptionStatus: 'incomplete', - }); - setCurrentWorkspaceMember(currentWorkspaceMember); - }); - - expect(result.current.onboardingStatus).toBe('incomplete'); - }); - - it('should return "canceled"', async () => { - const { result } = renderHooks(); - const { - setTokenPair, - setBilling, - setCurrentUser, - setCurrentWorkspace, - setCurrentWorkspaceMember, - } = result.current; - - act(() => { - setTokenPair(tokenPair); - setBilling(billing); - setCurrentUser(currentUser); - setCurrentWorkspace({ - ...currentWorkspace, - subscriptionStatus: 'canceled', - }); - setCurrentWorkspaceMember({ - ...currentWorkspaceMember, - name: { - firstName: 'John', - lastName: 'Doe', - }, - }); - }); - - expect(result.current.onboardingStatus).toBe('canceled'); - }); - - it('should return "ongoing_workspace_activation"', async () => { - const { result } = renderHooks(); - const { setTokenPair, setBilling, setCurrentUser, setCurrentWorkspace } = - result.current; - - act(() => { - setTokenPair(tokenPair); - setBilling(billing); - setCurrentUser(currentUser); - setCurrentWorkspace({ - ...currentWorkspace, - activationStatus: 'inactive', - subscriptionStatus: 'active', - }); - }); - - expect(result.current.onboardingStatus).toBe( - 'ongoing_workspace_activation', - ); - }); - - it('should return "ongoing_profile_creation"', async () => { - const { result } = renderHooks(); - const { - setTokenPair, - setBilling, - setCurrentUser, - setCurrentWorkspace, - setCurrentWorkspaceMember, - } = result.current; - - act(() => { - setTokenPair(tokenPair); - setBilling(billing); - setCurrentUser(currentUser); - setCurrentWorkspace({ - ...currentWorkspace, - subscriptionStatus: 'active', - }); - setCurrentWorkspaceMember(currentWorkspaceMember); - }); - - expect(result.current.onboardingStatus).toBe('ongoing_profile_creation'); - }); - - it('should return "ongoing_sync_email"', async () => { - const { result } = renderHooks(); - const { - setTokenPair, - setBilling, - setCurrentUser, - setCurrentWorkspace, - setCurrentWorkspaceMember, - } = result.current; - - act(() => { - setTokenPair(tokenPair); - setBilling(billing); - setCurrentUser({ - ...currentUser, - onboardingStep: OnboardingStep.SyncEmail, - }); - setCurrentWorkspace({ - ...currentWorkspace, - subscriptionStatus: 'active', - }); - setCurrentWorkspaceMember({ - ...currentWorkspaceMember, - name: { - firstName: 'John', - lastName: 'Doe', - }, - }); - }); - - expect(result.current.onboardingStatus).toBe('ongoing_sync_email'); - }); - - it('should return "ongoing_invite_team"', async () => { - const { result } = renderHooks(); - const { - setTokenPair, - setBilling, - setCurrentUser, - setCurrentWorkspace, - setCurrentWorkspaceMember, - } = result.current; - - act(() => { - setTokenPair(tokenPair); - setBilling(billing); - setCurrentUser({ - ...currentUser, - onboardingStep: OnboardingStep.InviteTeam, - }); - setCurrentWorkspace({ - ...currentWorkspace, - subscriptionStatus: 'active', - }); - setCurrentWorkspaceMember({ - ...currentWorkspaceMember, - name: { - firstName: 'John', - lastName: 'Doe', - }, - }); - }); - - expect(result.current.onboardingStatus).toBe('ongoing_invite_team'); - }); - - it('should return "completed"', async () => { - const { result } = renderHooks(); - const { - setTokenPair, - setBilling, - setCurrentUser, - setCurrentWorkspace, - setCurrentWorkspaceMember, - } = result.current; - - act(() => { - setTokenPair(tokenPair); - setBilling(billing); - setCurrentUser(currentUser); - setCurrentWorkspace({ - ...currentWorkspace, - subscriptionStatus: 'active', - }); - setCurrentWorkspaceMember({ - ...currentWorkspaceMember, - name: { - firstName: 'John', - lastName: 'Doe', - }, - }); - }); - - expect(result.current.onboardingStatus).toBe('completed'); - }); - - it('should return "past_due"', async () => { - const { result } = renderHooks(); - const { - setTokenPair, - setBilling, - setCurrentUser, - setCurrentWorkspace, - setCurrentWorkspaceMember, - } = result.current; - - act(() => { - setTokenPair(tokenPair); - setBilling(billing); - setCurrentUser(currentUser); - setCurrentWorkspace({ - ...currentWorkspace, - subscriptionStatus: 'past_due', - }); - setCurrentWorkspaceMember({ - ...currentWorkspaceMember, - name: { - firstName: 'John', - lastName: 'Doe', - }, - }); - }); - - expect(result.current.onboardingStatus).toBe('past_due'); - }); - - it('should return "unpaid"', async () => { - const { result } = renderHooks(); - const { - setTokenPair, - setBilling, - setCurrentUser, - setCurrentWorkspace, - setCurrentWorkspaceMember, - } = result.current; - - act(() => { - setTokenPair(tokenPair); - setBilling(billing); - setCurrentUser(currentUser); - setCurrentWorkspace({ - ...currentWorkspace, - subscriptionStatus: 'unpaid', - }); - setCurrentWorkspaceMember({ - ...currentWorkspaceMember, - name: { - firstName: 'John', - lastName: 'Doe', - }, - }); - }); - - expect(result.current.onboardingStatus).toBe('unpaid'); - }); - - it('should return "completed_without_subscription"', async () => { - const { result } = renderHooks(); - const { - setTokenPair, - setBilling, - setCurrentUser, - setCurrentWorkspace, - setCurrentWorkspaceMember, - } = result.current; - - act(() => { - setTokenPair(tokenPair); - setBilling(billing); - setCurrentUser(currentUser); - setCurrentWorkspace({ - ...currentWorkspace, - subscriptionStatus: 'trialing', - currentBillingSubscription: null, - }); - setCurrentWorkspaceMember({ - ...currentWorkspaceMember, - name: { - firstName: 'John', - lastName: 'Doe', - }, - }); - }); - - expect(result.current.onboardingStatus).toBe( - 'completed_without_subscription', - ); - }); -}); diff --git a/packages/twenty-front/src/modules/auth/hooks/useOnboardingStatus.ts b/packages/twenty-front/src/modules/auth/hooks/useOnboardingStatus.ts deleted file mode 100644 index b638b19da85f..000000000000 --- a/packages/twenty-front/src/modules/auth/hooks/useOnboardingStatus.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { useRecoilValue } from 'recoil'; - -import { currentUserState } from '@/auth/states/currentUserState'; -import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; -import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState'; -import { billingState } from '@/client-config/states/billingState'; - -import { useIsLogged } from '../hooks/useIsLogged'; -import { - getOnboardingStatus, - OnboardingStatus, -} from '../utils/getOnboardingStatus'; - -export const useOnboardingStatus = (): OnboardingStatus | undefined => { - const billing = useRecoilValue(billingState); - const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState); - const currentWorkspace = useRecoilValue(currentWorkspaceState); - const currentUser = useRecoilValue(currentUserState); - const isLoggedIn = useIsLogged(); - - return getOnboardingStatus({ - isLoggedIn, - currentWorkspaceMember, - currentWorkspace, - currentUser, - isBillingEnabled: billing?.isBillingEnabled || false, - }); -}; diff --git a/packages/twenty-front/src/modules/auth/sign-in-up/components/FooterNote.tsx b/packages/twenty-front/src/modules/auth/sign-in-up/components/FooterNote.tsx index c9d5066d9585..3bad98dcb083 100644 --- a/packages/twenty-front/src/modules/auth/sign-in-up/components/FooterNote.tsx +++ b/packages/twenty-front/src/modules/auth/sign-in-up/components/FooterNote.tsx @@ -1,15 +1,23 @@ -import React from 'react'; import styled from '@emotion/styled'; +import React from 'react'; type FooterNoteProps = { children: React.ReactNode }; const StyledContainer = styled.div` align-items: center; color: ${({ theme }) => theme.font.color.tertiary}; - display: flex; font-size: ${({ theme }) => theme.font.size.sm}; max-width: 280px; text-align: center; + + & > a { + color: ${({ theme }) => theme.font.color.tertiary}; + text-decoration: none; + + &:hover { + text-decoration: underline; + } + } `; export const FooterNote = ({ children }: FooterNoteProps) => ( diff --git a/packages/twenty-front/src/modules/auth/sign-in-up/components/SignInUpForm.tsx b/packages/twenty-front/src/modules/auth/sign-in-up/components/SignInUpForm.tsx index 86565460419a..1ebbfd9bf112 100644 --- a/packages/twenty-front/src/modules/auth/sign-in-up/components/SignInUpForm.tsx +++ b/packages/twenty-front/src/modules/auth/sign-in-up/components/SignInUpForm.tsx @@ -1,8 +1,8 @@ -import { useMemo, useState } from 'react'; -import { Controller } from 'react-hook-form'; import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { motion } from 'framer-motion'; +import { useMemo, useState } from 'react'; +import { Controller } from 'react-hook-form'; import { useRecoilState, useRecoilValue } from 'recoil'; import { Key } from 'ts-key-enum'; import { IconGoogle, IconMicrosoft } from 'twenty-ui'; @@ -28,23 +28,23 @@ import { ActionLink } from '@/ui/navigation/link/components/ActionLink'; import { isDefined } from '~/utils/isDefined'; const StyledContentContainer = styled.div` - margin-bottom: ${({ theme }) => theme.spacing(8)}; - margin-top: ${({ theme }) => theme.spacing(4)}; + margin-bottom: ${({ theme }) => theme.spacing(8)}; + margin-top: ${({ theme }) => theme.spacing(4)}; `; const StyledForm = styled.form` - align-items: center; - display: flex; - flex-direction: column; - width: 100%; + align-items: center; + display: flex; + flex-direction: column; + width: 100%; `; const StyledFullWidthMotionDiv = styled(motion.div)` - width: 100%; + width: 100%; `; const StyledInputContainer = styled.div` - margin-bottom: ${({ theme }) => theme.spacing(3)}; + margin-bottom: ${({ theme }) => theme.spacing(3)}; `; export const SignInUpForm = () => { @@ -168,9 +168,9 @@ export const SignInUpForm = () => { name="email" control={form.control} render={({ - field: { onChange, onBlur, value }, - fieldState: { error }, - }) => ( + field: { onChange, onBlur, value }, + fieldState: { error }, + }) => ( <StyledInputContainer> <TextInput autoFocus @@ -207,9 +207,9 @@ export const SignInUpForm = () => { name="password" control={form.control} render={({ - field: { onChange, onBlur, value }, - fieldState: { error }, - }) => ( + field: { onChange, onBlur, value }, + fieldState: { error }, + }) => ( <StyledInputContainer> <TextInput autoFocus @@ -258,7 +258,23 @@ export const SignInUpForm = () => { )} {signInUpStep === SignInUpStep.Init && ( <FooterNote> - By using Funnelmink, you agree to the Terms of Service and Privacy Policy. + By using Funnelmink, you agree to the{' '} + <a + href="https://funnelmink.com/legal/terms" + target="_blank" + rel="noopener noreferrer" + > + Terms of Service + </a>{' '} + and{' '} + <a + href="https://funnelmink.com/legal/privacy" + target="_blank" + rel="noopener noreferrer" + > + Privacy Policy + </a> + . </FooterNote> )} </> diff --git a/packages/twenty-front/src/modules/auth/sign-in-up/hooks/useWorkspaceFromInviteHash.ts b/packages/twenty-front/src/modules/auth/sign-in-up/hooks/useWorkspaceFromInviteHash.ts index ee6234feb343..feee086ef7c0 100644 --- a/packages/twenty-front/src/modules/auth/sign-in-up/hooks/useWorkspaceFromInviteHash.ts +++ b/packages/twenty-front/src/modules/auth/sign-in-up/hooks/useWorkspaceFromInviteHash.ts @@ -22,8 +22,8 @@ export const useWorkspaceFromInviteHash = () => { const { data: workspaceFromInviteHash, loading } = useGetWorkspaceFromInviteHashQuery({ variables: { inviteHash: workspaceInviteHash || '' }, - onError: () => { - enqueueSnackBar('workspace does not exist', { + onError: (error) => { + enqueueSnackBar(error.message, { variant: SnackBarVariant.Error, }); navigate(AppPath.Index); diff --git a/packages/twenty-front/src/modules/auth/states/currentUserState.ts b/packages/twenty-front/src/modules/auth/states/currentUserState.ts index 07efc7dfb1ec..2aab02507ff6 100644 --- a/packages/twenty-front/src/modules/auth/states/currentUserState.ts +++ b/packages/twenty-front/src/modules/auth/states/currentUserState.ts @@ -4,7 +4,7 @@ import { User } from '~/generated/graphql'; export type CurrentUser = Pick< User, - 'id' | 'email' | 'supportUserHash' | 'canImpersonate' | 'onboardingStep' + 'id' | 'email' | 'supportUserHash' | 'canImpersonate' | 'onboardingStatus' >; export const currentUserState = createState<CurrentUser | null>({ diff --git a/packages/twenty-front/src/modules/auth/states/currentWorkspaceState.ts b/packages/twenty-front/src/modules/auth/states/currentWorkspaceState.ts index c9187c3ea694..a66d7bd1cb06 100644 --- a/packages/twenty-front/src/modules/auth/states/currentWorkspaceState.ts +++ b/packages/twenty-front/src/modules/auth/states/currentWorkspaceState.ts @@ -10,9 +10,9 @@ export type CurrentWorkspace = Pick< | 'displayName' | 'allowImpersonation' | 'featureFlags' - | 'subscriptionStatus' | 'activationStatus' | 'currentBillingSubscription' + | 'workspaceMembersCount' | 'currentCacheVersion' >; diff --git a/packages/twenty-front/src/modules/auth/utils/__test__/getOnboardingStatus.test.ts b/packages/twenty-front/src/modules/auth/utils/__test__/getOnboardingStatus.test.ts deleted file mode 100644 index 813e9b38299b..000000000000 --- a/packages/twenty-front/src/modules/auth/utils/__test__/getOnboardingStatus.test.ts +++ /dev/null @@ -1,174 +0,0 @@ -import { CurrentUser } from '@/auth/states/currentUserState'; -import { CurrentWorkspace } from '@/auth/states/currentWorkspaceState'; -import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember'; -import { OnboardingStep } from '~/generated/graphql'; - -import { getOnboardingStatus } from '../getOnboardingStatus'; - -describe('getOnboardingStatus', () => { - it('should return the correct status', () => { - const ongoingUserCreation = getOnboardingStatus({ - isLoggedIn: false, - currentWorkspaceMember: null, - currentWorkspace: null, - currentUser: null, - isBillingEnabled: false, - }); - - const ongoingWorkspaceActivation = getOnboardingStatus({ - isLoggedIn: true, - currentWorkspaceMember: null, - currentWorkspace: { - id: '1', - activationStatus: 'inactive', - } as CurrentWorkspace, - currentUser: { - onboardingStep: null, - } as CurrentUser, - isBillingEnabled: false, - }); - - const ongoingProfileCreation = getOnboardingStatus({ - isLoggedIn: true, - currentWorkspaceMember: { - id: '1', - name: {}, - } as WorkspaceMember, - currentWorkspace: { - id: '1', - activationStatus: 'active', - } as CurrentWorkspace, - currentUser: { - onboardingStep: null, - } as CurrentUser, - isBillingEnabled: false, - }); - - const ongoingSyncEmail = getOnboardingStatus({ - isLoggedIn: true, - currentWorkspaceMember: { - id: '1', - name: { - firstName: 'John', - lastName: 'Doe', - }, - } as WorkspaceMember, - currentWorkspace: { - id: '1', - activationStatus: 'active', - } as CurrentWorkspace, - currentUser: { - onboardingStep: OnboardingStep.SyncEmail, - } as CurrentUser, - isBillingEnabled: false, - }); - - const ongoingInviteTeam = getOnboardingStatus({ - isLoggedIn: true, - currentWorkspaceMember: { - id: '1', - name: { - firstName: 'John', - lastName: 'Doe', - }, - } as WorkspaceMember, - currentWorkspace: { - id: '1', - activationStatus: 'active', - } as CurrentWorkspace, - currentUser: { - onboardingStep: OnboardingStep.InviteTeam, - } as CurrentUser, - isBillingEnabled: false, - }); - - const completed = getOnboardingStatus({ - isLoggedIn: true, - currentWorkspaceMember: { - id: '1', - name: { - firstName: 'John', - lastName: 'Doe', - }, - } as WorkspaceMember, - currentWorkspace: { - id: '1', - activationStatus: 'active', - } as CurrentWorkspace, - currentUser: { - onboardingStep: null, - } as CurrentUser, - isBillingEnabled: false, - }); - - const incomplete = getOnboardingStatus({ - isLoggedIn: true, - currentWorkspaceMember: { - id: '1', - name: { - firstName: 'John', - lastName: 'Doe', - }, - } as WorkspaceMember, - currentWorkspace: { - id: '1', - activationStatus: 'active', - subscriptionStatus: 'incomplete', - } as CurrentWorkspace, - currentUser: { - onboardingStep: null, - } as CurrentUser, - isBillingEnabled: true, - }); - - const incompleteButBillingDisabled = getOnboardingStatus({ - isLoggedIn: true, - currentWorkspaceMember: { - id: '1', - name: { - firstName: 'John', - lastName: 'Doe', - }, - } as WorkspaceMember, - currentWorkspace: { - id: '1', - activationStatus: 'active', - subscriptionStatus: 'incomplete', - } as CurrentWorkspace, - currentUser: { - onboardingStep: null, - } as CurrentUser, - isBillingEnabled: false, - }); - - const canceled = getOnboardingStatus({ - isLoggedIn: true, - currentWorkspaceMember: { - id: '1', - name: { - firstName: 'John', - lastName: 'Doe', - }, - } as WorkspaceMember, - currentWorkspace: { - id: '1', - activationStatus: 'active', - subscriptionStatus: 'canceled', - } as CurrentWorkspace, - currentUser: { - onboardingStep: null, - } as CurrentUser, - isBillingEnabled: true, - }); - - expect(ongoingUserCreation).toBe('ongoing_user_creation'); - expect(ongoingWorkspaceActivation).toBe('ongoing_workspace_activation'); - expect(ongoingProfileCreation).toBe('ongoing_profile_creation'); - expect(ongoingSyncEmail).toBe('ongoing_sync_email'); - expect(ongoingInviteTeam).toBe('ongoing_invite_team'); - expect(completed).toBe('completed'); - expect(incomplete).toBe('incomplete'); - expect(canceled).toBe('canceled'); - expect(incompleteButBillingDisabled).toBe('completed'); - }); -}); diff --git a/packages/twenty-front/src/modules/auth/utils/getOnboardingStatus.ts b/packages/twenty-front/src/modules/auth/utils/getOnboardingStatus.ts deleted file mode 100644 index 0dc254705228..000000000000 --- a/packages/twenty-front/src/modules/auth/utils/getOnboardingStatus.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { CurrentUser } from '@/auth/states/currentUserState'; -import { CurrentWorkspace } from '@/auth/states/currentWorkspaceState'; -import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember'; -import { OnboardingStep } from '~/generated/graphql'; - -export enum OnboardingStatus { - Incomplete = 'incomplete', - Canceled = 'canceled', - Unpaid = 'unpaid', - PastDue = 'past_due', - OngoingUserCreation = 'ongoing_user_creation', - OngoingWorkspaceActivation = 'ongoing_workspace_activation', - OngoingProfileCreation = 'ongoing_profile_creation', - OngoingSyncEmail = 'ongoing_sync_email', - OngoingInviteTeam = 'ongoing_invite_team', - Completed = 'completed', - CompletedWithoutSubscription = 'completed_without_subscription', -} - -export const getOnboardingStatus = ({ - isLoggedIn, - currentWorkspaceMember, - currentWorkspace, - currentUser, - isBillingEnabled, -}: { - isLoggedIn: boolean; - currentWorkspaceMember: Omit< - WorkspaceMember, - 'createdAt' | 'updatedAt' | 'userId' | 'userEmail' | '__typename' - > | null; - currentWorkspace: CurrentWorkspace | null; - currentUser: CurrentUser | null; - isBillingEnabled: boolean; -}) => { - if (!isLoggedIn) { - return OnboardingStatus.OngoingUserCreation; - } - - // After SignInUp, the user should have a current workspace assigned. - // If not, it indicates that the data is still being requested. - if (!currentWorkspace || !currentUser) { - return undefined; - } - - if ( - isBillingEnabled && - currentWorkspace.subscriptionStatus === 'incomplete' - ) { - return OnboardingStatus.Incomplete; - } - - if (currentWorkspace.activationStatus !== 'active') { - return OnboardingStatus.OngoingWorkspaceActivation; - } - - if ( - !currentWorkspaceMember?.name.firstName || - !currentWorkspaceMember?.name.lastName - ) { - return OnboardingStatus.OngoingProfileCreation; - } - - if (currentUser.onboardingStep === OnboardingStep.SyncEmail) { - return OnboardingStatus.OngoingSyncEmail; - } - - if (currentUser.onboardingStep === OnboardingStep.InviteTeam) { - return OnboardingStatus.OngoingInviteTeam; - } - - if (isBillingEnabled && currentWorkspace.subscriptionStatus === 'canceled') { - return OnboardingStatus.Canceled; - } - - if (isBillingEnabled && currentWorkspace.subscriptionStatus === 'past_due') { - return OnboardingStatus.PastDue; - } - - if (isBillingEnabled && currentWorkspace.subscriptionStatus === 'unpaid') { - return OnboardingStatus.Unpaid; - } - - if (isBillingEnabled && !currentWorkspace.currentBillingSubscription) { - return OnboardingStatus.CompletedWithoutSubscription; - } - - return OnboardingStatus.Completed; -}; diff --git a/packages/twenty-front/src/modules/billing/graphql/checkoutSession.ts b/packages/twenty-front/src/modules/billing/graphql/checkoutSession.ts index bff619a82f85..53821543cef2 100644 --- a/packages/twenty-front/src/modules/billing/graphql/checkoutSession.ts +++ b/packages/twenty-front/src/modules/billing/graphql/checkoutSession.ts @@ -2,7 +2,7 @@ import { gql } from '@apollo/client'; export const CHECKOUT_SESSION = gql` mutation CheckoutSession( - $recurringInterval: String! + $recurringInterval: SubscriptionInterval! $successUrlPath: String ) { checkoutSession( diff --git a/packages/twenty-front/src/modules/captcha/components/CaptchaProviderScriptLoaderEffect.tsx b/packages/twenty-front/src/modules/captcha/components/CaptchaProviderScriptLoaderEffect.tsx index 59dedab8fee3..aae90964f1dd 100644 --- a/packages/twenty-front/src/modules/captcha/components/CaptchaProviderScriptLoaderEffect.tsx +++ b/packages/twenty-front/src/modules/captcha/components/CaptchaProviderScriptLoaderEffect.tsx @@ -32,7 +32,7 @@ export const CaptchaProviderScriptLoaderEffect = () => { scriptElement = document.createElement('script'); scriptElement.src = scriptUrl; scriptElement.onload = () => { - if (captchaProvider.provider === CaptchaDriverType.GoogleRecatpcha) { + if (captchaProvider.provider === CaptchaDriverType.GoogleRecaptcha) { window.grecaptcha?.ready(() => { setIsCaptchaScriptLoaded(true); }); diff --git a/packages/twenty-front/src/modules/captcha/hooks/useRequestFreshCaptchaToken.ts b/packages/twenty-front/src/modules/captcha/hooks/useRequestFreshCaptchaToken.ts index f2e2821fc27f..63e6ee725480 100644 --- a/packages/twenty-front/src/modules/captcha/hooks/useRequestFreshCaptchaToken.ts +++ b/packages/twenty-front/src/modules/captcha/hooks/useRequestFreshCaptchaToken.ts @@ -35,7 +35,7 @@ export const useRequestFreshCaptchaToken = () => { let captchaWidget: any; switch (captchaProvider.provider) { - case CaptchaDriverType.GoogleRecatpcha: + case CaptchaDriverType.GoogleRecaptcha: window.grecaptcha .execute(captchaProvider.siteKey, { action: 'submit', diff --git a/packages/twenty-front/src/modules/captcha/utils/__tests__/getCaptchaUrlByProvider.test.ts b/packages/twenty-front/src/modules/captcha/utils/__tests__/getCaptchaUrlByProvider.test.ts new file mode 100644 index 000000000000..40cba1f43081 --- /dev/null +++ b/packages/twenty-front/src/modules/captcha/utils/__tests__/getCaptchaUrlByProvider.test.ts @@ -0,0 +1,38 @@ +import { expect } from '@storybook/test'; + +import { CaptchaDriverType } from '~/generated/graphql'; + +import { getCaptchaUrlByProvider } from '../getCaptchaUrlByProvider'; + +describe('getCaptchaUrlByProvider', () => { + it('handles GoogleRecaptcha', async () => { + const captchaUrl = getCaptchaUrlByProvider( + CaptchaDriverType.GoogleRecaptcha, + 'siteKey', + ); + + expect(captchaUrl).toEqual( + 'https://www.google.com/recaptcha/api.js?render=siteKey', + ); + + expect(() => + getCaptchaUrlByProvider(CaptchaDriverType.GoogleRecaptcha, ''), + ).toThrow( + 'SiteKey must be provided while generating url for GoogleRecaptcha provider', + ); + }); + + it('handles Turnstile', async () => { + const captchaUrl = getCaptchaUrlByProvider(CaptchaDriverType.Turnstile, ''); + + expect(captchaUrl).toEqual( + 'https://challenges.cloudflare.com/turnstile/v0/api.js', + ); + }); + + it('handles unknown provider', async () => { + expect(() => + getCaptchaUrlByProvider('Unknown' as CaptchaDriverType, ''), + ).toThrow('Unknown captcha provider'); + }); +}); diff --git a/packages/twenty-front/src/modules/captcha/utils/getCaptchaUrlByProvider.ts b/packages/twenty-front/src/modules/captcha/utils/getCaptchaUrlByProvider.ts index 5c0abe89e8a1..b3c1874ea897 100644 --- a/packages/twenty-front/src/modules/captcha/utils/getCaptchaUrlByProvider.ts +++ b/packages/twenty-front/src/modules/captcha/utils/getCaptchaUrlByProvider.ts @@ -1,16 +1,22 @@ -import { CaptchaDriverType } from '~/generated-metadata/graphql'; +import { isNonEmptyString } from '@sniptt/guards'; -export const getCaptchaUrlByProvider = (name: string, siteKey: string) => { - if (!name) { - return ''; - } +import { CaptchaDriverType } from '~/generated-metadata/graphql'; +export const getCaptchaUrlByProvider = ( + name: CaptchaDriverType, + siteKey: string, +) => { switch (name) { - case CaptchaDriverType.GoogleRecatpcha: + case CaptchaDriverType.GoogleRecaptcha: + if (!isNonEmptyString(siteKey)) { + throw new Error( + 'SiteKey must be provided while generating url for GoogleRecaptcha provider', + ); + } return `https://www.google.com/recaptcha/api.js?render=${siteKey}`; case CaptchaDriverType.Turnstile: return 'https://challenges.cloudflare.com/turnstile/v0/api.js'; default: - return ''; + throw new Error('Unknown captcha provider'); } }; diff --git a/packages/twenty-front/src/modules/client-config/components/ClientConfigProviderEffect.tsx b/packages/twenty-front/src/modules/client-config/components/ClientConfigProviderEffect.tsx index af45dc0fd34b..8bec4cc7dbd6 100644 --- a/packages/twenty-front/src/modules/client-config/components/ClientConfigProviderEffect.tsx +++ b/packages/twenty-front/src/modules/client-config/components/ClientConfigProviderEffect.tsx @@ -1,6 +1,7 @@ import { useEffect } from 'react'; import { useRecoilState, useSetRecoilState } from 'recoil'; +import { apiConfigState } from '@/client-config/states/apiConfigState'; import { authProvidersState } from '@/client-config/states/authProvidersState'; import { billingState } from '@/client-config/states/billingState'; import { captchaProviderState } from '@/client-config/states/captchaProviderState'; @@ -35,6 +36,8 @@ export const ClientConfigProviderEffect = () => { const setChromeExtensionId = useSetRecoilState(chromeExtensionIdState); + const setApiConfig = useSetRecoilState(apiConfigState); + const { data, loading } = useGetClientConfigQuery({ skip: isClientConfigLoaded, }); @@ -68,6 +71,7 @@ export const ClientConfigProviderEffect = () => { }); setChromeExtensionId(data?.clientConfig?.chromeExtensionId); + setApiConfig(data?.clientConfig?.api); } }, [ data, @@ -83,6 +87,7 @@ export const ClientConfigProviderEffect = () => { setIsClientConfigLoaded, setCaptchaProvider, setChromeExtensionId, + setApiConfig, ]); return <></>; diff --git a/packages/twenty-front/src/modules/client-config/graphql/queries/getClientConfig.ts b/packages/twenty-front/src/modules/client-config/graphql/queries/getClientConfig.ts index 6b98067167c4..3143bbc5f65a 100644 --- a/packages/twenty-front/src/modules/client-config/graphql/queries/getClientConfig.ts +++ b/packages/twenty-front/src/modules/client-config/graphql/queries/getClientConfig.ts @@ -32,6 +32,9 @@ export const GET_CLIENT_CONFIG = gql` provider siteKey } + api { + mutationMaximumAffectedRecords + } chromeExtensionId } } diff --git a/packages/twenty-front/src/modules/client-config/states/apiConfigState.ts b/packages/twenty-front/src/modules/client-config/states/apiConfigState.ts new file mode 100644 index 000000000000..9a01493e4f84 --- /dev/null +++ b/packages/twenty-front/src/modules/client-config/states/apiConfigState.ts @@ -0,0 +1,8 @@ +import { createState } from 'twenty-ui'; + +import { ApiConfig } from '~/generated/graphql'; + +export const apiConfigState = createState<ApiConfig | null>({ + key: 'apiConfigState', + defaultValue: null, +}); diff --git a/packages/twenty-front/src/modules/command-menu/components/CommandMenu.tsx b/packages/twenty-front/src/modules/command-menu/components/CommandMenu.tsx index efd72c3b9373..cb941c4e1861 100644 --- a/packages/twenty-front/src/modules/command-menu/components/CommandMenu.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/CommandMenu.tsx @@ -1,10 +1,12 @@ -import { useMemo, useRef } from 'react'; import styled from '@emotion/styled'; import { isNonEmptyString } from '@sniptt/guards'; -import { useRecoilState, useRecoilValue } from 'recoil'; +import { useMemo, useRef } from 'react'; +import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil'; import { Key } from 'ts-key-enum'; -import { Avatar, IconNotes } from 'twenty-ui'; +import { Avatar, IconNotes, IconSparkles } from 'twenty-ui'; +import { useOpenCopilotRightDrawer } from '@/activities/copilot/right-drawer/hooks/useOpenCopilotRightDrawer'; +import { copilotQueryState } from '@/activities/copilot/right-drawer/states/copilotQueryState'; import { useOpenActivityRightDrawer } from '@/activities/hooks/useOpenActivityRightDrawer'; import { Activity } from '@/activities/types/Activity'; import { commandMenuSearchState } from '@/command-menu/states/commandMenuSearchState'; @@ -21,6 +23,7 @@ import { AppHotkeyScope } from '@/ui/utilities/hotkey/types/AppHotkeyScope'; import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside'; import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper'; +import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; import { getLogoUrlFromDomainName } from '~/utils'; import { generateILikeFiltersForCompositeFields } from '~/utils/array/generateILikeFiltersForCompositeFields'; import { isDefined } from '~/utils/isDefined'; @@ -248,8 +251,27 @@ export const CommandMenu = () => { callback: closeCommandMenu, }); - const selectableItemIds = matchingCreateCommand + const isCopilotEnabled = useIsFeatureEnabled('IS_COPILOT_ENABLED'); + const setCopilotQuery = useSetRecoilState(copilotQueryState); + const openCopilotRightDrawer = useOpenCopilotRightDrawer(); + + const copilotCommand: Command = { + id: 'copilot', + to: '', // TODO + Icon: IconSparkles, + label: 'Open Copilot', + type: CommandType.Navigate, + onCommandClick: () => { + setCopilotQuery(commandMenuSearch); + openCopilotRightDrawer(); + }, + }; + + const copilotCommands: Command[] = isCopilotEnabled ? [copilotCommand] : []; + + const selectableItemIds = copilotCommands .map((cmd) => cmd.id) + .concat(matchingCreateCommand.map((cmd) => cmd.id)) .concat(matchingNavigateCommand.map((cmd) => cmd.id)) .concat(people.map((person) => person.id)) .concat(companies.map((company) => company.id)) @@ -275,6 +297,7 @@ export const CommandMenu = () => { hotkeyScope={AppHotkeyScope.CommandMenu} onEnter={(itemId) => { const command = [ + ...copilotCommands, ...commandMenuCommands, ...otherCommands, ].find((cmd) => cmd.id === itemId); @@ -292,6 +315,22 @@ export const CommandMenu = () => { !activities.length && ( <StyledEmpty>No results found</StyledEmpty> )} + {isCopilotEnabled && ( + <CommandGroup heading="Copilot"> + <SelectableItem itemId={copilotCommand.id}> + <CommandMenuItem + id={copilotCommand.id} + Icon={copilotCommand.Icon} + label={`${copilotCommand.label} ${ + commandMenuSearch.length > 2 + ? `"${commandMenuSearch}"` + : '' + }`} + onClick={copilotCommand.onCommandClick} + /> + </SelectableItem> + </CommandGroup> + )} <CommandGroup heading="Create"> {matchingCreateCommand.map((cmd) => ( <SelectableItem itemId={cmd.id} key={cmd.id}> @@ -338,7 +377,7 @@ export const CommandMenu = () => { <Avatar type="rounded" avatarUrl={null} - entityId={person.id} + placeholderColorSeed={person.id} placeholder={ person.name.firstName + ' ' + @@ -360,7 +399,7 @@ export const CommandMenu = () => { to={`object/company/${company.id}`} Icon={() => ( <Avatar - entityId={company.id} + placeholderColorSeed={company.id} placeholder={company.name} avatarUrl={getLogoUrlFromDomainName( company.domainName, diff --git a/packages/twenty-front/src/modules/databases/utils/__tests__/getForeignDataWrapperType.test.ts b/packages/twenty-front/src/modules/databases/utils/__tests__/getForeignDataWrapperType.test.ts new file mode 100644 index 000000000000..3db265dd9444 --- /dev/null +++ b/packages/twenty-front/src/modules/databases/utils/__tests__/getForeignDataWrapperType.test.ts @@ -0,0 +1,15 @@ +import { getForeignDataWrapperType } from '../getForeignDataWrapperType'; + +describe('getForeignDataWrapperType', () => { + it('should handle postgres', () => { + expect(getForeignDataWrapperType('postgresql')).toBe('postgres_fdw'); + }); + + it('should handle stripe', () => { + expect(getForeignDataWrapperType('stripe')).toBe('stripe_fdw'); + }); + + it('should return null for unknown', () => { + expect(getForeignDataWrapperType('unknown')).toBeNull(); + }); +}); diff --git a/packages/twenty-front/src/modules/error-handler/components/GenericErrorFallback.tsx b/packages/twenty-front/src/modules/error-handler/components/GenericErrorFallback.tsx index 87f84036911b..2109891aca14 100644 --- a/packages/twenty-front/src/modules/error-handler/components/GenericErrorFallback.tsx +++ b/packages/twenty-front/src/modules/error-handler/components/GenericErrorFallback.tsx @@ -1,4 +1,6 @@ +import { useEffect, useState } from 'react'; import { FallbackProps } from 'react-error-boundary'; +import { useLocation } from 'react-router-dom'; import { ThemeProvider, useTheme } from '@emotion/react'; import isEmpty from 'lodash.isempty'; import { IconRefresh, THEME_LIGHT } from 'twenty-ui'; @@ -11,6 +13,7 @@ import { AnimatedPlaceholderEmptyTextContainer, AnimatedPlaceholderEmptyTitle, } from '@/ui/layout/animated-placeholder/components/EmptyPlaceholderStyled'; +import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; type GenericErrorFallbackProps = FallbackProps; @@ -18,7 +21,18 @@ export const GenericErrorFallback = ({ error, resetErrorBoundary, }: GenericErrorFallbackProps) => { + const location = useLocation(); + + const [previousLocation] = useState(location); + + useEffect(() => { + if (!isDeeplyEqual(previousLocation, location)) { + resetErrorBoundary(); + } + }, [previousLocation, location, resetErrorBoundary]); + const theme = useTheme(); + return ( <ThemeProvider theme={isEmpty(theme) ? THEME_LIGHT : theme}> <AnimatedPlaceholderEmptyContainer> diff --git a/packages/twenty-front/src/modules/favorites/components/Favorites.tsx b/packages/twenty-front/src/modules/favorites/components/Favorites.tsx index c3bfeeb6aefe..9835a860b41f 100644 --- a/packages/twenty-front/src/modules/favorites/components/Favorites.tsx +++ b/packages/twenty-front/src/modules/favorites/components/Favorites.tsx @@ -1,4 +1,5 @@ import styled from '@emotion/styled'; +import { useRecoilValue } from 'recoil'; import { Avatar } from 'twenty-ui'; import { FavoritesSkeletonLoader } from '@/favorites/components/FavoritesSkeletonLoader'; @@ -8,6 +9,7 @@ import { DraggableList } from '@/ui/layout/draggable-list/components/DraggableLi import { NavigationDrawerItem } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerItem'; import { NavigationDrawerSection } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSection'; import { NavigationDrawerSectionTitle } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSectionTitle'; +import { useNavigationSection } from '@/ui/navigation/navigation-drawer/hooks/useNavigationSection'; import { getImageAbsoluteURIOrBase64 } from '~/utils/image/getImageAbsoluteURIOrBase64'; import { useFavorites } from '../hooks/useFavorites'; @@ -36,6 +38,10 @@ export const Favorites = () => { const { favorites, handleReorderFavorite } = useFavorites(); const loading = useIsPrefetchLoading(); + const { toggleNavigationSection, isNavigationSectionOpenState } = + useNavigationSection('Favorites'); + const isNavigationSectionOpen = useRecoilValue(isNavigationSectionOpenState); + if (loading) { return <FavoritesSkeletonLoader />; } @@ -44,48 +50,53 @@ export const Favorites = () => { return ( <StyledContainer> - <NavigationDrawerSectionTitle label="Favorites" /> - <DraggableList - onDragEnd={handleReorderFavorite} - draggableItems={ - <> - {favorites.map((favorite, index) => { - const { - id, - labelIdentifier, - avatarUrl, - avatarType, - link, - recordId, - } = favorite; - - return ( - <DraggableItem - key={id} - draggableId={id} - index={index} - itemComponent={ - <StyledNavigationDrawerItem - key={id} - label={labelIdentifier} - Icon={() => ( - <StyledAvatar - entityId={recordId} - avatarUrl={getImageAbsoluteURIOrBase64(avatarUrl)} - type={avatarType} - placeholder={labelIdentifier} - className="fav-avatar" - /> - )} - to={link} - /> - } - /> - ); - })} - </> - } + <NavigationDrawerSectionTitle + label="Favorites" + onClick={() => toggleNavigationSection()} /> + {isNavigationSectionOpen && ( + <DraggableList + onDragEnd={handleReorderFavorite} + draggableItems={ + <> + {favorites.map((favorite, index) => { + const { + id, + labelIdentifier, + avatarUrl, + avatarType, + link, + recordId, + } = favorite; + + return ( + <DraggableItem + key={id} + draggableId={id} + index={index} + itemComponent={ + <StyledNavigationDrawerItem + key={id} + label={labelIdentifier} + Icon={() => ( + <StyledAvatar + placeholderColorSeed={recordId} + avatarUrl={getImageAbsoluteURIOrBase64(avatarUrl)} + type={avatarType} + placeholder={labelIdentifier} + className="fav-avatar" + /> + )} + to={link} + /> + } + /> + ); + })} + </> + } + /> + )} </StyledContainer> ); }; diff --git a/packages/twenty-front/src/modules/favorites/hooks/__mocks__/useFavorites.ts b/packages/twenty-front/src/modules/favorites/hooks/__mocks__/useFavorites.ts index 73b4c855a610..c00b9f5da9ba 100644 --- a/packages/twenty-front/src/modules/favorites/hooks/__mocks__/useFavorites.ts +++ b/packages/twenty-front/src/modules/favorites/hooks/__mocks__/useFavorites.ts @@ -145,7 +145,16 @@ export const mocks = [ currencyCode } createdAt - address + address { + addressStreet1 + addressStreet2 + addressCity + addressState + addressCountry + addressPostcode + addressLat + addressLng + } updatedAt name accountOwnerId @@ -262,7 +271,16 @@ export const mocks = [ currencyCode } createdAt - address + address { + addressStreet1 + addressStreet2 + addressCity + addressState + addressCountry + addressPostcode + addressLat + addressLng + } updatedAt name accountOwnerId diff --git a/packages/twenty-front/src/modules/navigation/components/MainNavigationDrawerItems.tsx b/packages/twenty-front/src/modules/navigation/components/MainNavigationDrawerItems.tsx index a002010e8b9f..43d7b3da3eb9 100644 --- a/packages/twenty-front/src/modules/navigation/components/MainNavigationDrawerItems.tsx +++ b/packages/twenty-front/src/modules/navigation/components/MainNavigationDrawerItems.tsx @@ -9,7 +9,6 @@ import { Favorites } from '@/favorites/components/Favorites'; import { ObjectMetadataNavItems } from '@/object-metadata/components/ObjectMetadataNavItems'; import { NavigationDrawerItem } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerItem'; import { NavigationDrawerSection } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSection'; -import { NavigationDrawerSectionTitle } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSectionTitle'; import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMemorizedUrlState'; import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; @@ -56,10 +55,8 @@ export const MainNavigationDrawerItems = () => { <Favorites /> - <NavigationDrawerSection> - <NavigationDrawerSectionTitle label="Workspace" /> - <ObjectMetadataNavItems /> - </NavigationDrawerSection> + <ObjectMetadataNavItems isRemote={false} /> + <ObjectMetadataNavItems isRemote={true} /> </> ); }; diff --git a/packages/twenty-front/src/modules/navigation/utils/__tests__/indexAppPath.test.ts b/packages/twenty-front/src/modules/navigation/utils/__tests__/indexAppPath.test.ts new file mode 100644 index 000000000000..8920f6fa7445 --- /dev/null +++ b/packages/twenty-front/src/modules/navigation/utils/__tests__/indexAppPath.test.ts @@ -0,0 +1,10 @@ +import { AppPath } from '@/types/AppPath'; + +import indexAppPath from '../indexAppPath'; + +describe('getIndexAppPath', () => { + it('returns the index app path', () => { + const { getIndexAppPath } = indexAppPath; + expect(getIndexAppPath()).toEqual(AppPath.Index); + }); +}); diff --git a/packages/twenty-front/src/modules/object-metadata/components/ObjectMetadataItemsProvider.tsx b/packages/twenty-front/src/modules/object-metadata/components/ObjectMetadataItemsProvider.tsx index 8071b00b65a8..7f18bb2c254f 100644 --- a/packages/twenty-front/src/modules/object-metadata/components/ObjectMetadataItemsProvider.tsx +++ b/packages/twenty-front/src/modules/object-metadata/components/ObjectMetadataItemsProvider.tsx @@ -1,11 +1,10 @@ -import React, { useMemo } from 'react'; +import React from 'react'; import { useRecoilValue } from 'recoil'; import { ObjectMetadataItemsLoadEffect } from '@/object-metadata/components/ObjectMetadataItemsLoadEffect'; -import { PreComputedChipGeneratorsContext } from '@/object-metadata/context/PreComputedChipGeneratorsContext'; +import { PreComputedChipGeneratorsProvider } from '@/object-metadata/components/PreComputedChipGeneratorsProvider'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; import { RelationPickerScope } from '@/object-record/relation-picker/scopes/RelationPickerScope'; -import { getRecordChipGeneratorPerObjectPerField } from '@/object-record/utils/getRecordChipGeneratorPerObjectPerField'; import { UserOrMetadataLoader } from '~/loading/components/UserOrMetadataLoader'; export const ObjectMetadataItemsProvider = ({ @@ -15,23 +14,15 @@ export const ObjectMetadataItemsProvider = ({ const shouldDisplayChildren = objectMetadataItems.length > 0; - const chipGeneratorPerObjectPerField = useMemo(() => { - return getRecordChipGeneratorPerObjectPerField(objectMetadataItems); - }, [objectMetadataItems]); - return ( <> <ObjectMetadataItemsLoadEffect /> {shouldDisplayChildren ? ( - <PreComputedChipGeneratorsContext.Provider - value={{ - chipGeneratorPerObjectPerField, - }} - > + <PreComputedChipGeneratorsProvider> <RelationPickerScope relationPickerScopeId="relation-picker"> {children} </RelationPickerScope> - </PreComputedChipGeneratorsContext.Provider> + </PreComputedChipGeneratorsProvider> ) : ( <UserOrMetadataLoader /> )} diff --git a/packages/twenty-front/src/modules/object-metadata/components/ObjectMetadataNavItems.tsx b/packages/twenty-front/src/modules/object-metadata/components/ObjectMetadataNavItems.tsx index cb28ad6d31d2..10a89da89cfb 100644 --- a/packages/twenty-front/src/modules/object-metadata/components/ObjectMetadataNavItems.tsx +++ b/packages/twenty-front/src/modules/object-metadata/components/ObjectMetadataNavItems.tsx @@ -1,17 +1,32 @@ import { useLocation } from 'react-router-dom'; +import { useRecoilValue } from 'recoil'; import { useIcons } from 'twenty-ui'; -import { ObjectMetadataNavItemsSkeletonLoader } from '@/object-metadata/components/ObjectMetadataNavItemsSkeletonLoader'; +import { + ObjectMetadataNavItemsSkeletonLoader, +} from '@/object-metadata/components/ObjectMetadataNavItemsSkeletonLoader'; import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems'; import { useIsPrefetchLoading } from '@/prefetch/hooks/useIsPrefetchLoading'; import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData'; import { PrefetchKey } from '@/prefetch/types/PrefetchKey'; import { NavigationDrawerItem } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerItem'; +import { NavigationDrawerSection } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSection'; +import { + NavigationDrawerSectionTitle, +} from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSectionTitle'; +import { useNavigationSection } from '@/ui/navigation/navigation-drawer/hooks/useNavigationSection'; import { View } from '@/views/types/View'; import { getObjectMetadataItemViews } from '@/views/utils/getObjectMetadataItemViews'; -export const ObjectMetadataNavItems = () => { +export const ObjectMetadataNavItems = ({ isRemote }: { isRemote: boolean }) => { + const { toggleNavigationSection, isNavigationSectionOpenState } = + useNavigationSection('Objects' + (isRemote ? 'Remote' : 'Workspace')); + const isNavigationSectionOpen = useRecoilValue(isNavigationSectionOpenState); + const { activeObjectMetadataItems } = useFilteredObjectMetadataItems(); + const filteredActiveObjectMetadataItems = activeObjectMetadataItems.filter( + (item) => (isRemote ? item.isRemote : !item.isRemote), + ); const { getIcon } = useIcons(); const currentPath = useLocation().pathname; @@ -23,55 +38,41 @@ export const ObjectMetadataNavItems = () => { } return ( - <> - {[ - ...activeObjectMetadataItems - .filter((item) => - ['person', 'company', 'opportunity'].includes(item.nameSingular), - ) - .sort((objectMetadataItemA, objectMetadataItemB) => { - const order = ['person', 'company', 'opportunity']; - const indexA = order.indexOf(objectMetadataItemA.nameSingular); - const indexB = order.indexOf(objectMetadataItemB.nameSingular); - if (indexA === -1 || indexB === -1) { - return objectMetadataItemA.nameSingular.localeCompare( - objectMetadataItemB.nameSingular, + filteredActiveObjectMetadataItems.length > 0 && ( + <NavigationDrawerSection> + <NavigationDrawerSectionTitle + label={isRemote ? 'Remote' : 'Workspace'} + onClick={() => toggleNavigationSection()} + /> + + {isNavigationSectionOpen && + filteredActiveObjectMetadataItems + .sort((objectMetadataItemA, objectMetadataItemB) => + objectMetadataItemA.labelPlural.localeCompare(objectMetadataItemB.labelPlural)) + .map((objectMetadataItem) => { + const objectMetadataViews = getObjectMetadataItemViews( + objectMetadataItem.id, + views, ); - } - return indexA - indexB; - }), - ...activeObjectMetadataItems - .filter( - (item) => - !['person', 'company', 'opportunity'].includes(item.nameSingular), - ) - .sort((objectMetadataItemA, objectMetadataItemB) => { - return new Date(objectMetadataItemA.createdAt) < - new Date(objectMetadataItemB.createdAt) - ? 1 - : -1; - }), - ].map((objectMetadataItem) => { - const objectMetadataViews = getObjectMetadataItemViews( - objectMetadataItem.id, - views, - ); - const viewId = objectMetadataViews[0]?.id; + const viewId = objectMetadataViews[0]?.id; - const navigationPath = `/objects/${objectMetadataItem.namePlural}${ - viewId ? `?view=${viewId}` : '' - }`; + const navigationPath = `/objects/${objectMetadataItem.namePlural}${ + viewId ? `?view=${viewId}` : '' + }`; - return ( - <NavigationDrawerItem - key={objectMetadataItem.id} - label={objectMetadataItem.labelPlural} - to={navigationPath} - active={currentPath === `/objects/${objectMetadataItem.namePlural}`} - Icon={getIcon(objectMetadataItem.icon)} - /> - ); - })} - </> + return ( + <NavigationDrawerItem + key={objectMetadataItem.id} + label={objectMetadataItem.labelPlural} + to={navigationPath} + active={ + currentPath === `/objects/${objectMetadataItem.namePlural}` + } + Icon={getIcon(objectMetadataItem.icon)} + /> + ); + })} + </NavigationDrawerSection> + ) ); }; diff --git a/packages/twenty-front/src/modules/object-metadata/components/PreComputedChipGeneratorsProvider.tsx b/packages/twenty-front/src/modules/object-metadata/components/PreComputedChipGeneratorsProvider.tsx new file mode 100644 index 000000000000..dcf9bc5cc73d --- /dev/null +++ b/packages/twenty-front/src/modules/object-metadata/components/PreComputedChipGeneratorsProvider.tsx @@ -0,0 +1,30 @@ +import React, { useMemo } from 'react'; +import { useRecoilValue } from 'recoil'; + +import { PreComputedChipGeneratorsContext } from '@/object-metadata/context/PreComputedChipGeneratorsContext'; +import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; +import { getRecordChipGenerators } from '@/object-record/utils/getRecordChipGenerators'; + +export const PreComputedChipGeneratorsProvider = ({ + children, +}: React.PropsWithChildren) => { + const objectMetadataItems = useRecoilValue(objectMetadataItemsState); + + const { chipGeneratorPerObjectPerField, identifierChipGeneratorPerObject } = + useMemo(() => { + return getRecordChipGenerators(objectMetadataItems); + }, [objectMetadataItems]); + + return ( + <> + <PreComputedChipGeneratorsContext.Provider + value={{ + chipGeneratorPerObjectPerField, + identifierChipGeneratorPerObject, + }} + > + {children} + </PreComputedChipGeneratorsContext.Provider> + </> + ); +}; diff --git a/packages/twenty-front/src/modules/object-metadata/context/PreComputedChipGeneratorsContext.ts b/packages/twenty-front/src/modules/object-metadata/context/PreComputedChipGeneratorsContext.ts index fcb5b7d46b68..ed7b734bcc98 100644 --- a/packages/twenty-front/src/modules/object-metadata/context/PreComputedChipGeneratorsContext.ts +++ b/packages/twenty-front/src/modules/object-metadata/context/PreComputedChipGeneratorsContext.ts @@ -3,13 +3,19 @@ import { createContext } from 'react'; import { RecordChipData } from '@/object-record/record-field/types/RecordChipData'; import { ObjectRecord } from '@/object-record/types/ObjectRecord'; -export type ChipGeneratorPerObjectPerField = Record< +export type ChipGeneratorPerObjectNameSingularPerFieldName = Record< string, Record<string, (record: ObjectRecord) => RecordChipData> >; +export type IdentifierChipGeneratorPerObject = Record< + string, + (record: ObjectRecord) => RecordChipData +>; + export type PreComputedChipGeneratorsContextProps = { - chipGeneratorPerObjectPerField: ChipGeneratorPerObjectPerField; + chipGeneratorPerObjectPerField: ChipGeneratorPerObjectNameSingularPerFieldName; + identifierChipGeneratorPerObject: IdentifierChipGeneratorPerObject; }; export const PreComputedChipGeneratorsContext = diff --git a/packages/twenty-front/src/modules/object-metadata/hooks/__mocks__/useCreateOneObjectMetadataItem.ts b/packages/twenty-front/src/modules/object-metadata/hooks/__mocks__/useCreateOneObjectMetadataItem.ts index f142bffbde25..ce4d5cfbe41b 100644 --- a/packages/twenty-front/src/modules/object-metadata/hooks/__mocks__/useCreateOneObjectMetadataItem.ts +++ b/packages/twenty-front/src/modules/object-metadata/hooks/__mocks__/useCreateOneObjectMetadataItem.ts @@ -24,7 +24,7 @@ export const query = gql` export const findManyViewsQuery = gql` query FindManyViews( $filter: ViewFilterInput - $orderBy: ViewOrderByInput + $orderBy: [ViewOrderByInput] $lastCursor: String $limit: Int ) { diff --git a/packages/twenty-front/src/modules/object-metadata/hooks/__tests__/useGetObjectOrderByField.test.tsx b/packages/twenty-front/src/modules/object-metadata/hooks/__tests__/useGetObjectOrderByField.test.tsx index 646806c9762a..21ec56ad60b4 100644 --- a/packages/twenty-front/src/modules/object-metadata/hooks/__tests__/useGetObjectOrderByField.test.tsx +++ b/packages/twenty-front/src/modules/object-metadata/hooks/__tests__/useGetObjectOrderByField.test.tsx @@ -26,8 +26,8 @@ describe('useGetObjectOrderByField', () => { }, ); - expect(result.current).toEqual({ - name: { firstName: 'AscNullsLast', lastName: 'AscNullsLast' }, - }); + expect(result.current).toEqual([ + { name: { firstName: 'AscNullsLast', lastName: 'AscNullsLast' } }, + ]); }); }); diff --git a/packages/twenty-front/src/modules/object-metadata/utils/__tests__/getObjectMetadataItemBySingularName.test.ts b/packages/twenty-front/src/modules/object-metadata/utils/__tests__/getObjectMetadataItemBySingularName.test.ts new file mode 100644 index 000000000000..07e88a26f066 --- /dev/null +++ b/packages/twenty-front/src/modules/object-metadata/utils/__tests__/getObjectMetadataItemBySingularName.test.ts @@ -0,0 +1,17 @@ +import { getObjectMetadataItemByNameSingular } from '@/object-metadata/utils/getObjectMetadataItemBySingularName'; +import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock'; + +const mockObjectMetadataItems = getObjectMetadataItemsMock(); + +describe('getObjectMetadataItemBySingularName', () => { + it('should work as expected', () => { + const firstObjectMetadataItem = mockObjectMetadataItems[0]; + + const foundObjectMetadataItem = getObjectMetadataItemByNameSingular({ + objectMetadataItems: mockObjectMetadataItems, + objectNameSingular: firstObjectMetadataItem.nameSingular, + }); + + expect(foundObjectMetadataItem.id).toEqual(firstObjectMetadataItem.id); + }); +}); diff --git a/packages/twenty-front/src/modules/object-metadata/utils/__tests__/getObjectOrderByField.test.ts b/packages/twenty-front/src/modules/object-metadata/utils/__tests__/getObjectOrderByField.test.ts index 7cecf5668b25..baa61c853751 100644 --- a/packages/twenty-front/src/modules/object-metadata/utils/__tests__/getObjectOrderByField.test.ts +++ b/packages/twenty-front/src/modules/object-metadata/utils/__tests__/getObjectOrderByField.test.ts @@ -9,8 +9,8 @@ describe('getObjectOrderByField', () => { (item) => item.nameSingular === 'person', )!; const res = getOrderByFieldForObjectMetadataItem(objectMetadataItem); - expect(res).toEqual({ - name: { firstName: 'AscNullsLast', lastName: 'AscNullsLast' }, - }); + expect(res).toEqual([ + { name: { firstName: 'AscNullsLast', lastName: 'AscNullsLast' } }, + ]); }); }); diff --git a/packages/twenty-front/src/modules/object-metadata/utils/__tests__/mapFieldMetadataToGraphQLQuery.test.tsx b/packages/twenty-front/src/modules/object-metadata/utils/__tests__/mapFieldMetadataToGraphQLQuery.test.tsx index 116874b23290..fc841bd27068 100644 --- a/packages/twenty-front/src/modules/object-metadata/utils/__tests__/mapFieldMetadataToGraphQLQuery.test.tsx +++ b/packages/twenty-front/src/modules/object-metadata/utils/__tests__/mapFieldMetadataToGraphQLQuery.test.tsx @@ -66,6 +66,16 @@ annualRecurringRevenue } createdAt address +{ + addressStreet1 + addressStreet2 + addressCity + addressState + addressCountry + addressPostcode + addressLat + addressLng +} updatedAt name accountOwnerId @@ -86,7 +96,7 @@ idealCustomerProfile domainName: true, annualRecurringRevenue: true, createdAt: true, - address: true, + address: { addressStreet1: true }, updatedAt: true, name: true, accountOwnerId: true, @@ -129,6 +139,16 @@ annualRecurringRevenue } createdAt address +{ + addressStreet1 + addressStreet2 + addressCity + addressState + addressCountry + addressPostcode + addressLat + addressLng +} updatedAt people { diff --git a/packages/twenty-front/src/modules/object-metadata/utils/__tests__/mapObjectMetadataToGraphQLQuery.test.tsx b/packages/twenty-front/src/modules/object-metadata/utils/__tests__/mapObjectMetadataToGraphQLQuery.test.tsx index a5261cbfdc01..53442862491e 100644 --- a/packages/twenty-front/src/modules/object-metadata/utils/__tests__/mapObjectMetadataToGraphQLQuery.test.tsx +++ b/packages/twenty-front/src/modules/object-metadata/utils/__tests__/mapObjectMetadataToGraphQLQuery.test.tsx @@ -65,6 +65,16 @@ annualRecurringRevenue } createdAt address +{ + addressStreet1 + addressStreet2 + addressCity + addressState + addressCountry + addressPostcode + addressLat + addressLng +} updatedAt name accountOwnerId diff --git a/packages/twenty-front/src/modules/object-metadata/utils/formatFieldMetadataItemAsFieldDefinition.ts b/packages/twenty-front/src/modules/object-metadata/utils/formatFieldMetadataItemAsFieldDefinition.ts index 0c1cc9a3dae1..a579d5ce4de3 100644 --- a/packages/twenty-front/src/modules/object-metadata/utils/formatFieldMetadataItemAsFieldDefinition.ts +++ b/packages/twenty-front/src/modules/object-metadata/utils/formatFieldMetadataItemAsFieldDefinition.ts @@ -40,6 +40,7 @@ export const formatFieldMetadataItemAsFieldDefinition = ({ targetFieldMetadataName: field.relationDefinition?.targetFieldMetadata?.name ?? '', options: field.options, + isNullable: field.isNullable, }; return { diff --git a/packages/twenty-front/src/modules/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions.ts b/packages/twenty-front/src/modules/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions.ts index c5df10c85c8f..318073af17bd 100644 --- a/packages/twenty-front/src/modules/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions.ts +++ b/packages/twenty-front/src/modules/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions.ts @@ -1,6 +1,8 @@ import { FilterDefinition } from '@/object-record/object-filter-dropdown/types/FilterDefinition'; -import { FieldMetadataType } from '~/generated-metadata/graphql'; -import { isDefined } from '~/utils/isDefined'; +import { + FieldMetadataType, + RelationDefinitionType, +} from '~/generated-metadata/graphql'; import { ObjectMetadataItem } from '../types/ObjectMetadataItem'; @@ -10,6 +12,15 @@ export const formatFieldMetadataItemsAsFilterDefinitions = ({ fields: Array<ObjectMetadataItem['fields'][0]>; }): FilterDefinition[] => fields.reduce((acc, field) => { + if ( + field.type === FieldMetadataType.Relation && + field.relationDefinition?.direction !== + RelationDefinitionType.ManyToOne && + field.relationDefinition?.direction !== RelationDefinitionType.OneToOne + ) { + return acc; + } + if ( ![ FieldMetadataType.DateTime, @@ -22,24 +33,12 @@ export const formatFieldMetadataItemsAsFilterDefinitions = ({ FieldMetadataType.Address, FieldMetadataType.Relation, FieldMetadataType.Select, - FieldMetadataType.MultiSelect, FieldMetadataType.Currency, ].includes(field.type) ) { return acc; } - // Todo: remove once Rating fieldtype is implemented - if (field.name === 'probability') { - return acc; - } - - if (field.type === FieldMetadataType.Relation) { - if (isDefined(field.fromRelationMetadata)) { - return acc; - } - } - return [...acc, formatFieldMetadataItemAsFilterDefinition({ field })]; }, [] as FilterDefinition[]); @@ -52,9 +51,9 @@ export const formatFieldMetadataItemAsFilterDefinition = ({ label: field.label, iconName: field.icon ?? 'Icon123', relationObjectMetadataNamePlural: - field.toRelationMetadata?.fromObjectMetadata.namePlural, + field.relationDefinition?.targetObjectMetadata.namePlural, relationObjectMetadataNameSingular: - field.toRelationMetadata?.fromObjectMetadata.nameSingular, + field.relationDefinition?.targetObjectMetadata.nameSingular, type: getFilterTypeFromFieldType(field.type), }); diff --git a/packages/twenty-front/src/modules/object-metadata/utils/formatFieldMetadataItemsAsSortDefinitions.ts b/packages/twenty-front/src/modules/object-metadata/utils/formatFieldMetadataItemsAsSortDefinitions.ts index 56b84aec08ac..b62f7fb35ba6 100644 --- a/packages/twenty-front/src/modules/object-metadata/utils/formatFieldMetadataItemsAsSortDefinitions.ts +++ b/packages/twenty-front/src/modules/object-metadata/utils/formatFieldMetadataItemsAsSortDefinitions.ts @@ -18,6 +18,8 @@ export const formatFieldMetadataItemsAsSortDefinitions = ({ FieldMetadataType.Boolean, FieldMetadataType.Select, FieldMetadataType.Phone, + FieldMetadataType.Email, + FieldMetadataType.FullName, ].includes(field.type) ) { return acc; diff --git a/packages/twenty-front/src/modules/object-metadata/utils/getLabelIdentifierFieldValue.ts b/packages/twenty-front/src/modules/object-metadata/utils/getLabelIdentifierFieldValue.ts index 7960047804ba..001cf4ecb06b 100644 --- a/packages/twenty-front/src/modules/object-metadata/utils/getLabelIdentifierFieldValue.ts +++ b/packages/twenty-front/src/modules/object-metadata/utils/getLabelIdentifierFieldValue.ts @@ -8,7 +8,7 @@ export const getLabelIdentifierFieldValue = ( record: ObjectRecord, labelIdentifierFieldMetadataItem: FieldMetadataItem | undefined, objectNameSingular: string, -) => { +): string => { if ( objectNameSingular === CoreObjectNameSingular.WorkspaceMember || labelIdentifierFieldMetadataItem?.type === FieldMetadataType.FullName @@ -17,7 +17,7 @@ export const getLabelIdentifierFieldValue = ( } if (isDefined(labelIdentifierFieldMetadataItem?.name)) { - return record[labelIdentifierFieldMetadataItem.name] as string | number; + return String(record[labelIdentifierFieldMetadataItem.name]); } return ''; diff --git a/packages/twenty-front/src/modules/object-metadata/utils/getLinkToShowPage.ts b/packages/twenty-front/src/modules/object-metadata/utils/getLinkToShowPage.ts index c5b747a1ebbb..4a6510dea2c1 100644 --- a/packages/twenty-front/src/modules/object-metadata/utils/getLinkToShowPage.ts +++ b/packages/twenty-front/src/modules/object-metadata/utils/getLinkToShowPage.ts @@ -4,7 +4,7 @@ import { ObjectRecord } from '@/object-record/types/ObjectRecord'; export const getLinkToShowPage = ( objectNameSingular: string, - record: ObjectRecord, + record: Pick<ObjectRecord, 'id'>, ) => { const basePathToShowPage = getBasePathToShowPage({ objectNameSingular, diff --git a/packages/twenty-front/src/modules/object-metadata/utils/getObjectMetadataItemsMock.ts b/packages/twenty-front/src/modules/object-metadata/utils/getObjectMetadataItemsMock.ts index c50755a51f92..7ae1d86e7993 100644 --- a/packages/twenty-front/src/modules/object-metadata/utils/getObjectMetadataItemsMock.ts +++ b/packages/twenty-front/src/modules/object-metadata/utils/getObjectMetadataItemsMock.ts @@ -466,23 +466,6 @@ export const getObjectMetadataItemsMock = () => { fromRelationMetadata: null, toRelationMetadata: null, }, - { - __typename: 'field', - id: '20202020-3b9c-4e58-a3d2-c617d3b596b1', - type: 'TEXT', - name: 'probability', - label: 'Probability', - description: 'Opportunity probability', - icon: 'IconProgressCheck', - isCustom: false, - isActive: true, - isSystem: false, - isNullable: true, - createdAt: '2023-11-30T11:13:15.308Z', - updatedAt: '2023-11-30T11:13:15.308Z', - fromRelationMetadata: null, - toRelationMetadata: null, - }, { __typename: 'fieldEdge', node: { @@ -3039,7 +3022,7 @@ export const getObjectMetadataItemsMock = () => { { __typename: 'field', id: '20202020-ad10-4117-a039-3f04b7a5f939', - type: 'TEXT', + type: 'ADDRESS', name: 'address', label: 'Address', description: 'The company address', @@ -3155,6 +3138,14 @@ export const getObjectMetadataItemsMock = () => { }, toFieldMetadataId: '20202020-64e1-4080-b6ad-db03c3809885', }, + relationDefinition: { + targetObjectMetadata: { + nameSingular: 'person', + }, + targetFieldMetadata: { + name: 'company', + }, + }, toRelationMetadata: null, }, { diff --git a/packages/twenty-front/src/modules/object-metadata/utils/getObjectOrderByField.ts b/packages/twenty-front/src/modules/object-metadata/utils/getObjectOrderByField.ts index 97d31c9a6b55..4b3b080f848a 100644 --- a/packages/twenty-front/src/modules/object-metadata/utils/getObjectOrderByField.ts +++ b/packages/twenty-front/src/modules/object-metadata/utils/getObjectOrderByField.ts @@ -15,20 +15,26 @@ export const getOrderByFieldForObjectMetadataItem = ( if (isDefined(labelIdentifierFieldMetadata)) { switch (labelIdentifierFieldMetadata.type) { case FieldMetadataType.FullName: - return { - [labelIdentifierFieldMetadata.name]: { - firstName: orderBy ?? 'AscNullsLast', - lastName: orderBy ?? 'AscNullsLast', + return [ + { + [labelIdentifierFieldMetadata.name]: { + firstName: orderBy ?? 'AscNullsLast', + lastName: orderBy ?? 'AscNullsLast', + }, }, - }; + ]; default: - return { - [labelIdentifierFieldMetadata.name]: orderBy ?? 'AscNullsLast', - }; + return [ + { + [labelIdentifierFieldMetadata.name]: orderBy ?? 'AscNullsLast', + }, + ]; } } else { - return { - createdAt: orderBy ?? 'DescNullsLast', - }; + return [ + { + createdAt: orderBy ?? 'DescNullsLast', + }, + ]; } }; diff --git a/packages/twenty-front/src/modules/object-metadata/utils/getObjectSlug.ts b/packages/twenty-front/src/modules/object-metadata/utils/getObjectSlug.ts index 465af568df1c..fa2132f9c369 100644 --- a/packages/twenty-front/src/modules/object-metadata/utils/getObjectSlug.ts +++ b/packages/twenty-front/src/modules/object-metadata/utils/getObjectSlug.ts @@ -3,5 +3,5 @@ import toKebabCase from 'lodash.kebabcase'; import { ObjectMetadataItem } from '../types/ObjectMetadataItem'; export const getObjectSlug = ( - objectMetadataItem: Pick<ObjectMetadataItem, 'labelPlural'>, -) => toKebabCase(objectMetadataItem.labelPlural); + objectMetadataItem: Pick<ObjectMetadataItem, 'namePlural'>, +) => toKebabCase(objectMetadataItem.namePlural); diff --git a/packages/twenty-front/src/modules/object-record/cache/utils/__tests__/isObjectRecordConnection.test.ts b/packages/twenty-front/src/modules/object-record/cache/utils/__tests__/isObjectRecordConnection.test.ts new file mode 100644 index 000000000000..bbe8b38db7bb --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/cache/utils/__tests__/isObjectRecordConnection.test.ts @@ -0,0 +1,27 @@ +import { peopleQueryResult } from '~/testing/mock-data/people'; + +import { isObjectRecordConnection } from '@/object-record/cache/utils/isObjectRecordConnection'; + +describe('isObjectRecordConnection', () => { + it('should work with query result', () => { + const validQueryResult = peopleQueryResult.people; + + const isValidQueryResult = isObjectRecordConnection( + 'person', + validQueryResult, + ); + + expect(isValidQueryResult).toEqual(true); + }); + + it('should fail with invalid result', () => { + const invalidResult = { test: 123 }; + + const isValidQueryResult = isObjectRecordConnection( + 'person', + invalidResult, + ); + + expect(isValidQueryResult).toEqual(false); + }); +}); diff --git a/packages/twenty-front/src/modules/object-record/cache/utils/getRecordNodeFromRecord.ts b/packages/twenty-front/src/modules/object-record/cache/utils/getRecordNodeFromRecord.ts index f162131f526c..d7faf5a77f29 100644 --- a/packages/twenty-front/src/modules/object-record/cache/utils/getRecordNodeFromRecord.ts +++ b/packages/twenty-front/src/modules/object-record/cache/utils/getRecordNodeFromRecord.ts @@ -4,6 +4,7 @@ import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { getNodeTypename } from '@/object-record/cache/utils/getNodeTypename'; import { getObjectTypename } from '@/object-record/cache/utils/getObjectTypename'; import { getRecordConnectionFromRecords } from '@/object-record/cache/utils/getRecordConnectionFromRecords'; +import { getRefName } from '@/object-record/cache/utils/getRefName'; import { RecordGqlNode } from '@/object-record/graphql/types/RecordGqlNode'; import { ObjectRecord } from '@/object-record/types/ObjectRecord'; import { @@ -39,7 +40,7 @@ export const getRecordNodeFromRecord = <T extends ObjectRecord>({ if (!isRootLevel && computeReferences) { return { - __ref: `${nodeTypeName}:${record.id}`, + __ref: getRefName(objectMetadataItem.nameSingular, record.id), } as unknown as RecordGqlNode; // Fix typing: we want a Reference in computeReferences mode } diff --git a/packages/twenty-front/src/modules/object-record/cache/utils/getRefName.ts b/packages/twenty-front/src/modules/object-record/cache/utils/getRefName.ts new file mode 100644 index 000000000000..3a2e12a88976 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/cache/utils/getRefName.ts @@ -0,0 +1,7 @@ +import { getNodeTypename } from '@/object-record/cache/utils/getNodeTypename'; + +export const getRefName = (objectNameSingular: string, id: string) => { + const nodeTypeName = getNodeTypename(objectNameSingular); + + return `${nodeTypeName}:${id}`; +}; diff --git a/packages/twenty-front/src/modules/object-record/cache/utils/updateRecordFromCache.ts b/packages/twenty-front/src/modules/object-record/cache/utils/updateRecordFromCache.ts index 7ce423c09222..26df70cecd18 100644 --- a/packages/twenty-front/src/modules/object-record/cache/utils/updateRecordFromCache.ts +++ b/packages/twenty-front/src/modules/object-record/cache/utils/updateRecordFromCache.ts @@ -13,11 +13,13 @@ export const updateRecordFromCache = <T extends ObjectRecord>({ objectMetadataItems, objectMetadataItem, cache, + recordGqlFields = undefined, record, }: { objectMetadataItems: ObjectMetadataItem[]; objectMetadataItem: ObjectMetadataItem; cache: ApolloCache<object>; + recordGqlFields?: Record<string, any>; record: T; }) => { if (isUndefinedOrNull(objectMetadataItem)) { @@ -32,6 +34,7 @@ export const updateRecordFromCache = <T extends ObjectRecord>({ objectMetadataItems, objectMetadataItem, computeReferences: true, + recordGqlFields, }, )} `; diff --git a/packages/twenty-front/src/modules/object-record/components/RecordChip.tsx b/packages/twenty-front/src/modules/object-record/components/RecordChip.tsx index ad5cc2217b79..94674aa57b21 100644 --- a/packages/twenty-front/src/modules/object-record/components/RecordChip.tsx +++ b/packages/twenty-front/src/modules/object-record/components/RecordChip.tsx @@ -1,14 +1,17 @@ -import { EntityChip, EntityChipVariant } from 'twenty-ui'; +import { AvatarChip, AvatarChipVariant } from 'twenty-ui'; -import { useMapToObjectRecordIdentifier } from '@/object-metadata/hooks/useMapToObjectRecordIdentifier'; +import { getLinkToShowPage } from '@/object-metadata/utils/getLinkToShowPage'; +import { useRecordChipData } from '@/object-record/hooks/useRecordChipData'; import { ObjectRecord } from '@/object-record/types/ObjectRecord'; -import { getImageAbsoluteURIOrBase64 } from '~/utils/image/getImageAbsoluteURIOrBase64'; +import { isNonEmptyString } from '@sniptt/guards'; +import { MouseEvent } from 'react'; +import { useNavigate } from 'react-router-dom'; export type RecordChipProps = { objectNameSingular: string; record: ObjectRecord; className?: string; - variant?: EntityChipVariant; + variant?: AvatarChipVariant; }; export const RecordChip = ({ @@ -17,21 +20,29 @@ export const RecordChip = ({ className, variant, }: RecordChipProps) => { - const { mapToObjectRecordIdentifier } = useMapToObjectRecordIdentifier({ + const navigate = useNavigate(); + + const { recordChipData } = useRecordChipData({ objectNameSingular, + record, }); - const objectRecordIdentifier = mapToObjectRecordIdentifier(record); + const handleAvatarChipClick = (event: MouseEvent) => { + const linkToShowPage = getLinkToShowPage(objectNameSingular, record); + + if (isNonEmptyString(linkToShowPage)) { + event.stopPropagation(); + navigate(linkToShowPage); + } + }; return ( - <EntityChip - entityId={record.id} - name={objectRecordIdentifier.name} - avatarType={objectRecordIdentifier.avatarType} - avatarUrl={ - getImageAbsoluteURIOrBase64(objectRecordIdentifier.avatarUrl) || '' - } - linkToEntity={objectRecordIdentifier.linkToShowPage} + <AvatarChip + placeholderColorSeed={record.id} + name={recordChipData.name} + avatarType={recordChipData.avatarType} + avatarUrl={recordChipData.avatarUrl ?? ''} + onClick={handleAvatarChipClick} className={className} variant={variant} /> diff --git a/packages/twenty-front/src/modules/object-record/constants/DefaultMutationBatchSize.ts b/packages/twenty-front/src/modules/object-record/constants/DefaultMutationBatchSize.ts new file mode 100644 index 000000000000..6864c5e05e4b --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/constants/DefaultMutationBatchSize.ts @@ -0,0 +1 @@ +export const DEFAULT_MUTATION_BATCH_SIZE = 30; diff --git a/packages/twenty-front/src/modules/object-record/constants/DefaultQueryPageSize.ts b/packages/twenty-front/src/modules/object-record/constants/DefaultQueryPageSize.ts new file mode 100644 index 000000000000..cb8e9f295d4d --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/constants/DefaultQueryPageSize.ts @@ -0,0 +1 @@ +export const DEFAULT_QUERY_PAGE_SIZE = 30; diff --git a/packages/twenty-front/src/modules/object-record/constants/DeleteMaxCount.ts b/packages/twenty-front/src/modules/object-record/constants/DeleteMaxCount.ts new file mode 100644 index 000000000000..0f1b3a7c3bdf --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/constants/DeleteMaxCount.ts @@ -0,0 +1 @@ +export const DELETE_MAX_COUNT = 10000; diff --git a/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlConnection.ts b/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlConnection.ts index 543a55b2fc48..df64c8e35fe2 100644 --- a/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlConnection.ts +++ b/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlConnection.ts @@ -6,6 +6,7 @@ export type RecordGqlConnection = { __typename?: string; edges: RecordGqlEdge[]; pageInfo: { + __typename?: string; hasNextPage?: boolean; hasPreviousPage?: boolean; startCursor?: Nullable<string>; diff --git a/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlOperationFilter.ts b/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlOperationFilter.ts index 66acadc80bee..fd6de3f7090d 100644 --- a/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlOperationFilter.ts +++ b/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlOperationFilter.ts @@ -9,6 +9,11 @@ export type UUIDFilter = { is?: IsFilter; }; +export type RelationFilter = { + is?: IsFilter; + in?: UUIDFilterValue[]; +}; + export type BooleanFilter = { eq?: boolean; is?: IsFilter; diff --git a/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlOperationFindDuplicatesResults.ts b/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlOperationFindDuplicatesResults.ts new file mode 100644 index 000000000000..09134da76d41 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlOperationFindDuplicatesResults.ts @@ -0,0 +1,5 @@ +import { RecordGqlConnection } from '@/object-record/graphql/types/RecordGqlConnection'; + +export type RecordGqlOperationFindDuplicatesResult = { + [objectNamePlural: string]: RecordGqlConnection[]; +}; diff --git a/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlOperationOrderBy.ts b/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlOperationOrderBy.ts index 67592770d176..b1180d6c6860 100644 --- a/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlOperationOrderBy.ts +++ b/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlOperationOrderBy.ts @@ -1,5 +1,5 @@ import { OrderBy } from '@/object-metadata/types/OrderBy'; -export type RecordGqlOperationOrderBy = { +export type RecordGqlOperationOrderBy = Array<{ [fieldName: string]: OrderBy | { [subFieldName: string]: OrderBy }; -}; +}>; diff --git a/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlOperationVariables.ts b/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlOperationVariables.ts index 9dc0fed4f010..3abc3358a654 100644 --- a/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlOperationVariables.ts +++ b/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlOperationVariables.ts @@ -1,8 +1,14 @@ import { RecordGqlOperationFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter'; import { RecordGqlOperationOrderBy } from '@/object-record/graphql/types/RecordGqlOperationOrderBy'; +import { QueryCursorDirection } from '@/object-record/utils/generateFindManyRecordsQuery'; export type RecordGqlOperationVariables = { filter?: RecordGqlOperationFilter; orderBy?: RecordGqlOperationOrderBy; limit?: number; + cursorFilter?: { + cursor: string; + cursorDirection: QueryCursorDirection; + limit: number; + }; }; diff --git a/packages/twenty-front/src/modules/object-record/graphql/utils/generateDepthOneRecordGqlFields.ts b/packages/twenty-front/src/modules/object-record/graphql/utils/generateDepthOneRecordGqlFields.ts index ce52cd786d3f..7870c00cc9fb 100644 --- a/packages/twenty-front/src/modules/object-record/graphql/utils/generateDepthOneRecordGqlFields.ts +++ b/packages/twenty-front/src/modules/object-record/graphql/utils/generateDepthOneRecordGqlFields.ts @@ -1,14 +1,31 @@ import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; +import { isDefined } from '~/utils/isDefined'; export const generateDepthOneRecordGqlFields = ({ objectMetadataItem, + record, }: { objectMetadataItem: ObjectMetadataItem; + record?: Record<string, any>; }) => { - return objectMetadataItem.fields.reduce((acc, field) => { - return { - ...acc, - [field.name]: true, - }; - }, {}); + const gqlFieldsFromObjectMetadataItem = objectMetadataItem.fields.reduce( + (acc, field) => { + return { + ...acc, + [field.name]: true, + }; + }, + {}, + ); + + if (isDefined(record)) { + return Object.keys(gqlFieldsFromObjectMetadataItem).reduce((acc, key) => { + return { + ...acc, + [key]: Object.keys(record).includes(key), + }; + }, gqlFieldsFromObjectMetadataItem); + } + + return gqlFieldsFromObjectMetadataItem; }; diff --git a/packages/twenty-front/src/modules/object-record/hooks/__mocks__/useCreateManyRecords.ts b/packages/twenty-front/src/modules/object-record/hooks/__mocks__/useCreateManyRecords.ts index d0a867d70924..7a8a4bf3a78a 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/__mocks__/useCreateManyRecords.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/__mocks__/useCreateManyRecords.ts @@ -3,8 +3,8 @@ import { gql } from '@apollo/client'; import { Person } from '@/people/types/Person'; export const query = gql` - mutation CreatePeople($data: [PersonCreateInput!]!) { - createPeople(data: $data) { + mutation CreatePeople($data: [PersonCreateInput!]!, $upsert: Boolean) { + createPeople(data: $data, upsert: $upsert) { __typename xLink { label diff --git a/packages/twenty-front/src/modules/object-record/hooks/__mocks__/useFetchAllRecordIds.ts b/packages/twenty-front/src/modules/object-record/hooks/__mocks__/useFetchAllRecordIds.ts new file mode 100644 index 000000000000..6309686fb9e2 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/hooks/__mocks__/useFetchAllRecordIds.ts @@ -0,0 +1,81 @@ +import { RecordGqlConnection } from '@/object-record/graphql/types/RecordGqlConnection'; +import { gql } from '@apollo/client'; + +import { peopleQueryResult } from '~/testing/mock-data/people'; + + +export const query = gql` + query FindManyPeople($filter: PersonFilterInput, $orderBy: [PersonOrderByInput], $lastCursor: String, $limit: Int) { + people(filter: $filter, orderBy: $orderBy, first: $limit, after: $lastCursor){ + edges { + node { + __typename + id + } + cursor + } + pageInfo { + hasNextPage + startCursor + endCursor + } + totalCount + } + } +`; + +export const mockPageSize = 2; + +export const peopleMockWithIdsOnly: RecordGqlConnection = { ...peopleQueryResult.people,edges: peopleQueryResult.people.edges.map((edge) => ({ ...edge, node: { __typename: 'Person', id: edge.node.id } })) }; + +export const firstRequestLastCursor = peopleMockWithIdsOnly.edges[mockPageSize].cursor; +export const secondRequestLastCursor = peopleMockWithIdsOnly.edges[mockPageSize * 2].cursor; +export const thirdRequestLastCursor = peopleMockWithIdsOnly.edges[mockPageSize * 3].cursor; + +export const variablesFirstRequest = { + filter: undefined, + limit: mockPageSize, + orderBy: undefined +}; + +export const variablesSecondRequest = { + filter: undefined, + limit: mockPageSize, + orderBy: undefined, + lastCursor: firstRequestLastCursor +}; + +export const variablesThirdRequest = { + filter: undefined, + limit: mockPageSize, + orderBy: undefined, + lastCursor: secondRequestLastCursor +} + +const paginateRequestResponse = (response: RecordGqlConnection, start: number, end: number, hasNextPage: boolean, totalCount: number) => { + return { + ...response, + edges: [ + ...response.edges.slice(start, end) + ], + pageInfo: { + ...response.pageInfo, + startCursor: response.edges[start].cursor, + endCursor: response.edges[end].cursor, + hasNextPage, + } satisfies RecordGqlConnection['pageInfo'], + totalCount, + } +} + +export const responseFirstRequest = { + people: paginateRequestResponse(peopleMockWithIdsOnly, 0, mockPageSize, true, 6), +}; + +export const responseSecondRequest = { + people: paginateRequestResponse(peopleMockWithIdsOnly, mockPageSize, mockPageSize * 2, true, 6), +}; + +export const responseThirdRequest = { + people: paginateRequestResponse(peopleMockWithIdsOnly, mockPageSize * 2, mockPageSize * 3, false, 6), +}; diff --git a/packages/twenty-front/src/modules/object-record/hooks/__mocks__/useFindDuplicateRecords.ts b/packages/twenty-front/src/modules/object-record/hooks/__mocks__/useFindDuplicateRecords.ts index 6cc35d507098..fec1fb988a94 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/__mocks__/useFindDuplicateRecords.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/__mocks__/useFindDuplicateRecords.ts @@ -4,8 +4,8 @@ import { getPeopleMock } from '~/testing/mock-data/people'; const peopleMock = getPeopleMock(); export const query = gql` - query FindDuplicatePerson($id: ID!) { - personDuplicates(id: $id) { + query FindDuplicatePerson($ids: [ID!]!) { + personDuplicates(ids: $ids) { edges { node { __typename @@ -38,32 +38,32 @@ export const query = gql` startCursor endCursor } - totalCount } } `; export const variables = { - id: '6205681e-7c11-40b4-9e32-f523dbe54590', + ids: ['6205681e-7c11-40b4-9e32-f523dbe54590'], }; export const responseData = { - personDuplicates: { - edges: [ - { - node: { ...peopleMock[0], updatedAt: '' }, - cursor: 'cursor1', + personDuplicates: [ + { + edges: [ + { + node: { ...peopleMock[0], updatedAt: '' }, + cursor: 'cursor1', + }, + { + node: { ...peopleMock[1], updatedAt: '' }, + cursor: 'cursor2', + }, + ], + pageInfo: { + hasNextPage: false, + startCursor: 'cursor1', + endCursor: 'cursor2', }, - { - node: { ...peopleMock[1], updatedAt: '' }, - cursor: 'cursor2', - }, - ], - pageInfo: { - hasNextPage: false, - startCursor: 'cursor1', - endCursor: 'cursor2', }, - totalCount: 2, - }, + ], }; diff --git a/packages/twenty-front/src/modules/object-record/hooks/__mocks__/useFindManyRecords.ts b/packages/twenty-front/src/modules/object-record/hooks/__mocks__/useFindManyRecords.ts index 6de4625bfa7c..22caeadc1cf5 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/__mocks__/useFindManyRecords.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/__mocks__/useFindManyRecords.ts @@ -27,7 +27,6 @@ export const query = gql` updatedAt companyId stage - probability closeDate amount { amountMicros @@ -53,7 +52,6 @@ export const query = gql` updatedAt companyId stage - probability closeDate amount { amountMicros @@ -82,7 +80,16 @@ export const query = gql` currencyCode } createdAt - address + address { + addressStreet1 + addressStreet2 + addressCity + addressState + addressCountry + addressPostcode + addressLat + addressLng + } updatedAt name accountOwnerId diff --git a/packages/twenty-front/src/modules/object-record/hooks/__tests__/useCreateManyRecordsMutation.test.tsx b/packages/twenty-front/src/modules/object-record/hooks/__tests__/useCreateManyRecordsMutation.test.tsx index 131707d0fbd0..9574e3b28b7d 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/__tests__/useCreateManyRecordsMutation.test.tsx +++ b/packages/twenty-front/src/modules/object-record/hooks/__tests__/useCreateManyRecordsMutation.test.tsx @@ -5,8 +5,8 @@ import { RecoilRoot } from 'recoil'; import { useCreateManyRecordsMutation } from '@/object-record/hooks/useCreateManyRecordsMutation'; const expectedQueryTemplate = ` - mutation CreatePeople($data: [PersonCreateInput!]!) { - createPeople(data: $data) { + mutation CreatePeople($data: [PersonCreateInput!]!, $upsert: Boolean) { + createPeople(data: $data, upsert: $upsert) { __typename xLink { label diff --git a/packages/twenty-front/src/modules/object-record/hooks/__tests__/useDeleteManyRecords.test.tsx b/packages/twenty-front/src/modules/object-record/hooks/__tests__/useDeleteManyRecords.test.tsx index 548c1f0d6aa5..1c7dd33d33e6 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/__tests__/useDeleteManyRecords.test.tsx +++ b/packages/twenty-front/src/modules/object-record/hooks/__tests__/useDeleteManyRecords.test.tsx @@ -1,6 +1,6 @@ -import { ReactNode } from 'react'; import { MockedProvider } from '@apollo/client/testing'; import { act, renderHook } from '@testing-library/react'; +import { ReactNode } from 'react'; import { RecoilRoot } from 'recoil'; import { @@ -23,7 +23,7 @@ const mocks = [ }, result: jest.fn(() => ({ data: { - deletePeople: responseData, + deletePeople: [responseData], }, })), }, @@ -49,7 +49,7 @@ describe('useDeleteManyRecords', () => { await act(async () => { const res = await result.current.deleteManyRecords(people); expect(res).toBeDefined(); - expect(res).toHaveProperty('id'); + expect(res[0]).toHaveProperty('id'); }); expect(mocks[0].result).toHaveBeenCalled(); diff --git a/packages/twenty-front/src/modules/object-record/hooks/__tests__/useFetchAllRecordIds.test.tsx b/packages/twenty-front/src/modules/object-record/hooks/__tests__/useFetchAllRecordIds.test.tsx new file mode 100644 index 000000000000..fc32df77ebb0 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/hooks/__tests__/useFetchAllRecordIds.test.tsx @@ -0,0 +1,107 @@ +import { MockedProvider } from '@apollo/client/testing'; +import { act, renderHook } from '@testing-library/react'; +import { ReactNode, useEffect } from 'react'; +import { RecoilRoot, useRecoilState } from 'recoil'; + +import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; +import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock'; +import { + mockPageSize, + peopleMockWithIdsOnly, + query, + responseFirstRequest, + responseSecondRequest, + responseThirdRequest, + variablesFirstRequest, + variablesSecondRequest, + variablesThirdRequest, +} from '@/object-record/hooks/__mocks__/useFetchAllRecordIds'; +import { useFetchAllRecordIds } from '@/object-record/hooks/useFetchAllRecordIds'; +import { SnackBarManagerScopeInternalContext } from '@/ui/feedback/snack-bar-manager/scopes/scope-internal-context/SnackBarManagerScopeInternalContext'; + +const mocks = [ + { + delay: 100, + request: { + query, + variables: variablesFirstRequest, + }, + result: jest.fn(() => ({ + data: responseFirstRequest, + })), + }, + { + delay: 100, + request: { + query, + variables: variablesSecondRequest, + }, + result: jest.fn(() => ({ + data: responseSecondRequest, + })), + }, + { + delay: 100, + request: { + query, + variables: variablesThirdRequest, + }, + result: jest.fn(() => ({ + data: responseThirdRequest, + })), + }, +]; + +describe('useFetchAllRecordIds', () => { + it('fetches all record ids with fetch more synchronous loop', async () => { + const Wrapper = ({ children }: { children: ReactNode }) => ( + <RecoilRoot> + <SnackBarManagerScopeInternalContext.Provider + value={{ + scopeId: 'snack-bar-manager', + }} + > + <MockedProvider mocks={mocks} addTypename={false}> + {children} + </MockedProvider> + </SnackBarManagerScopeInternalContext.Provider> + </RecoilRoot> + ); + + const { result } = renderHook( + () => { + const [, setObjectMetadataItems] = useRecoilState( + objectMetadataItemsState, + ); + + useEffect(() => { + setObjectMetadataItems(getObjectMetadataItemsMock()); + }, [setObjectMetadataItems]); + + return useFetchAllRecordIds({ + objectNameSingular: 'person', + pageSize: mockPageSize, + }); + }, + { + wrapper: Wrapper, + }, + ); + + const { fetchAllRecordIds } = result.current; + + let recordIds: string[] = []; + + await act(async () => { + recordIds = await fetchAllRecordIds(); + }); + + expect(mocks[0].result).toHaveBeenCalled(); + expect(mocks[1].result).toHaveBeenCalled(); + expect(mocks[2].result).toHaveBeenCalled(); + + expect(recordIds).toEqual( + peopleMockWithIdsOnly.edges.map((edge) => edge.node.id).slice(0, 6), + ); + }); +}); diff --git a/packages/twenty-front/src/modules/object-record/hooks/__tests__/useFindDuplicateRecords.test.tsx b/packages/twenty-front/src/modules/object-record/hooks/__tests__/useFindDuplicateRecords.test.tsx index 98d3cad285c0..e8616d1da1a7 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/__tests__/useFindDuplicateRecords.test.tsx +++ b/packages/twenty-front/src/modules/object-record/hooks/__tests__/useFindDuplicateRecords.test.tsx @@ -42,7 +42,7 @@ describe('useFindDuplicateRecords', () => { const { result } = renderHook( () => useFindDuplicateRecords({ - objectRecordId, + objectRecordIds: [objectRecordId], objectNameSingular, }), { @@ -54,7 +54,7 @@ describe('useFindDuplicateRecords', () => { await waitFor(() => { expect(result.current.loading).toBe(false); - expect(result.current.records).toBeDefined(); + expect(result.current.results).toBeDefined(); }); expect(mocks[0].result).toHaveBeenCalled(); diff --git a/packages/twenty-front/src/modules/object-record/hooks/__tests__/useFindDuplicateRecordsQuery.test.tsx b/packages/twenty-front/src/modules/object-record/hooks/__tests__/useFindDuplicateRecordsQuery.test.tsx index 5650e59e13aa..a32f1a6f24d0 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/__tests__/useFindDuplicateRecordsQuery.test.tsx +++ b/packages/twenty-front/src/modules/object-record/hooks/__tests__/useFindDuplicateRecordsQuery.test.tsx @@ -5,8 +5,8 @@ import { RecoilRoot } from 'recoil'; import { useFindDuplicateRecordsQuery } from '@/object-record/hooks/useFindDuplicatesRecordsQuery'; const expectedQueryTemplate = ` - query FindDuplicatePerson($id: ID!) { - personDuplicates(id: $id) { + query FindDuplicatePerson($ids: [ID!]!) { + personDuplicates(ids: $ids) { edges { node { __typename @@ -39,7 +39,6 @@ const expectedQueryTemplate = ` startCursor endCursor } - totalCount } } `.replace(/\s/g, ''); diff --git a/packages/twenty-front/src/modules/object-record/hooks/__tests__/useFindManyRecords.test.tsx b/packages/twenty-front/src/modules/object-record/hooks/__tests__/useFindManyRecords.test.tsx index 57e18be23cba..6b7d71c18b5d 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/__tests__/useFindManyRecords.test.tsx +++ b/packages/twenty-front/src/modules/object-record/hooks/__tests__/useFindManyRecords.test.tsx @@ -1,6 +1,6 @@ -import { ReactNode } from 'react'; import { MockedProvider } from '@apollo/client/testing'; import { renderHook } from '@testing-library/react'; +import { ReactNode } from 'react'; import { RecoilRoot, useSetRecoilState } from 'recoil'; import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; diff --git a/packages/twenty-front/src/modules/object-record/hooks/__tests__/useFindManyRecordsQuery.test.tsx b/packages/twenty-front/src/modules/object-record/hooks/__tests__/useFindManyRecordsQuery.test.tsx index 21cfb7f0f2e9..47082dec0f2f 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/__tests__/useFindManyRecordsQuery.test.tsx +++ b/packages/twenty-front/src/modules/object-record/hooks/__tests__/useFindManyRecordsQuery.test.tsx @@ -5,7 +5,7 @@ import { RecoilRoot } from 'recoil'; import { useFindManyRecordsQuery } from '@/object-record/hooks/useFindManyRecordsQuery'; const expectedQueryTemplate = ` - query FindManyPeople($filter: PersonFilterInput, $orderBy: PersonOrderByInput, $lastCursor: String, $limit: Int) { + query FindManyPeople($filter: PersonFilterInput, $orderBy: [PersonOrderByInput], $lastCursor: String, $limit: Int) { people(filter: $filter, orderBy: $orderBy, first: $limit, after: $lastCursor) { edges { node { diff --git a/packages/twenty-front/src/modules/object-record/hooks/useAttachRelatedRecordFromRecord.ts b/packages/twenty-front/src/modules/object-record/hooks/useAttachRelatedRecordFromRecord.ts new file mode 100644 index 000000000000..17c80b4c1887 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/hooks/useAttachRelatedRecordFromRecord.ts @@ -0,0 +1,113 @@ +import { useApolloClient } from '@apollo/client'; + +import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; +import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems'; +import { useGetRecordFromCache } from '@/object-record/cache/hooks/useGetRecordFromCache'; +import { updateRecordFromCache } from '@/object-record/cache/utils/updateRecordFromCache'; +import { generateDepthOneRecordGqlFields } from '@/object-record/graphql/utils/generateDepthOneRecordGqlFields'; +import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord'; +import { ObjectRecord } from '@/object-record/types/ObjectRecord'; +import { isDefined } from '~/utils/isDefined'; + +type useAttachRelatedRecordFromRecordProps = { + recordObjectNameSingular: string; + fieldNameOnRecordObject: string; +}; + +export const useAttachRelatedRecordFromRecord = ({ + recordObjectNameSingular, + fieldNameOnRecordObject, +}: useAttachRelatedRecordFromRecordProps) => { + const apolloClient = useApolloClient(); + + const { objectMetadataItem } = useObjectMetadataItem({ + objectNameSingular: recordObjectNameSingular, + }); + + const fieldOnObject = objectMetadataItem.fields.find((field) => { + return field.name === fieldNameOnRecordObject; + }); + + const relatedRecordObjectNameSingular = + fieldOnObject?.relationDefinition?.targetObjectMetadata.nameSingular; + + if (!relatedRecordObjectNameSingular) { + throw new Error( + `Could not find record related to ${recordObjectNameSingular}`, + ); + } + const { objectMetadataItem: relatedObjectMetadataItem } = + useObjectMetadataItem({ + objectNameSingular: relatedRecordObjectNameSingular, + }); + + const fieldOnRelatedObject = + fieldOnObject?.relationDefinition?.targetFieldMetadata.name; + + if (!fieldOnRelatedObject) { + throw new Error(`Missing target field for ${fieldNameOnRecordObject}`); + } + + const { updateOneRecord } = useUpdateOneRecord({ + objectNameSingular: relatedRecordObjectNameSingular, + }); + + const getRecordFromCache = useGetRecordFromCache({ + objectNameSingular: recordObjectNameSingular, + }); + + const getRelatedRecordFromCache = useGetRecordFromCache({ + objectNameSingular: relatedRecordObjectNameSingular, + }); + + const { objectMetadataItems } = useObjectMetadataItems(); + + const updateOneRecordAndAttachRelations = async ({ + recordId, + relatedRecordId, + }: { + recordId: string; + relatedRecordId: string; + }) => { + const cachedRelatedRecord = + getRelatedRecordFromCache<ObjectRecord>(relatedRecordId); + + if (!cachedRelatedRecord) { + throw new Error('could not find cached related record'); + } + + const previousRecordId = cachedRelatedRecord?.[`${fieldOnRelatedObject}Id`]; + + if (isDefined(previousRecordId)) { + const previousRecord = getRecordFromCache<ObjectRecord>(previousRecordId); + + const previousRecordWithRelation = { + ...cachedRelatedRecord, + [fieldOnRelatedObject]: previousRecord, + }; + const gqlFields = generateDepthOneRecordGqlFields({ + objectMetadataItem: relatedObjectMetadataItem, + record: previousRecordWithRelation, + }); + updateRecordFromCache({ + objectMetadataItems, + objectMetadataItem: relatedObjectMetadataItem, + cache: apolloClient.cache, + record: { + ...cachedRelatedRecord, + [fieldOnRelatedObject]: previousRecord, + }, + recordGqlFields: gqlFields, + }); + } + + await updateOneRecord({ + idToUpdate: relatedRecordId, + updateOneRecordInput: { + [`${fieldOnRelatedObject}Id`]: recordId, + }, + }); + }; + + return { updateOneRecordAndAttachRelations }; +}; diff --git a/packages/twenty-front/src/modules/object-record/hooks/useCreateManyRecords.ts b/packages/twenty-front/src/modules/object-record/hooks/useCreateManyRecords.ts index e95cbad37edf..b9313fae3ecc 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useCreateManyRecords.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useCreateManyRecords.ts @@ -18,6 +18,7 @@ type useCreateManyRecordsProps = { objectNameSingular: string; recordGqlFields?: RecordGqlOperationGqlRecordFields; skipPostOptmisticEffect?: boolean; + shouldMatchRootQueryFilter?: boolean; }; export const useCreateManyRecords = < @@ -26,6 +27,7 @@ export const useCreateManyRecords = < objectNameSingular, recordGqlFields, skipPostOptmisticEffect = false, + shouldMatchRootQueryFilter, }: useCreateManyRecordsProps) => { const apolloClient = useApolloClient(); @@ -49,10 +51,11 @@ export const useCreateManyRecords = < const createManyRecords = async ( recordsToCreate: Partial<CreatedObjectRecord>[], + upsert?: boolean, ) => { const sanitizedCreateManyRecordsInput = recordsToCreate.map( (recordToCreate) => { - const idForCreation = recordToCreate?.id ?? v4(); + const idForCreation = recordToCreate?.id ?? (upsert ? undefined : v4()); return { ...sanitizeRecordInput({ @@ -67,8 +70,12 @@ export const useCreateManyRecords = < const recordsCreatedInCache = []; for (const recordToCreate of sanitizedCreateManyRecordsInput) { + if (recordToCreate.id === null) { + continue; + } + const recordCreatedInCache = createOneRecordInCache({ - ...recordToCreate, + ...(recordToCreate as { id: string }), __typename: getObjectTypename(objectMetadataItem.nameSingular), }); @@ -83,6 +90,7 @@ export const useCreateManyRecords = < objectMetadataItem, recordsToCreate: recordsCreatedInCache, objectMetadataItems, + shouldMatchRootQueryFilter, }); } @@ -94,6 +102,7 @@ export const useCreateManyRecords = < mutation: createManyRecordsMutation, variables: { data: sanitizedCreateManyRecordsInput, + upsert: upsert, }, update: (cache, { data }) => { const records = data?.[mutationResponseField]; @@ -105,6 +114,7 @@ export const useCreateManyRecords = < objectMetadataItem, recordsToCreate: records, objectMetadataItems, + shouldMatchRootQueryFilter, }); }, }); diff --git a/packages/twenty-front/src/modules/object-record/hooks/useCreateManyRecordsMutation.ts b/packages/twenty-front/src/modules/object-record/hooks/useCreateManyRecordsMutation.ts index f038531dc586..28e499acbcca 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useCreateManyRecordsMutation.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useCreateManyRecordsMutation.ts @@ -34,12 +34,16 @@ export const useCreateManyRecordsMutation = ({ const createManyRecordsMutation = gql` mutation Create${capitalize( objectMetadataItem.namePlural, - )}($data: [${capitalize(objectMetadataItem.nameSingular)}CreateInput!]!) { - ${mutationResponseField}(data: $data) ${mapObjectMetadataToGraphQLQuery({ - objectMetadataItems, - objectMetadataItem, - recordGqlFields, - })} + )}($data: [${capitalize( + objectMetadataItem.nameSingular, + )}CreateInput!]!, $upsert: Boolean) { + ${mutationResponseField}(data: $data, upsert: $upsert) ${mapObjectMetadataToGraphQLQuery( + { + objectMetadataItems, + objectMetadataItem, + recordGqlFields, + }, + )} }`; return { diff --git a/packages/twenty-front/src/modules/object-record/hooks/useCreateOneRecord.ts b/packages/twenty-front/src/modules/object-record/hooks/useCreateOneRecord.ts index 5cb2d9a436cf..f34ce0692f7a 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useCreateOneRecord.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useCreateOneRecord.ts @@ -1,5 +1,5 @@ -import { useState } from 'react'; import { useApolloClient } from '@apollo/client'; +import { useState } from 'react'; import { v4 } from 'uuid'; import { triggerCreateRecordsOptimisticEffect } from '@/apollo/optimistic-effect/utils/triggerCreateRecordsOptimisticEffect'; @@ -19,6 +19,7 @@ type useCreateOneRecordProps = { objectNameSingular: string; recordGqlFields?: RecordGqlOperationGqlRecordFields; skipPostOptmisticEffect?: boolean; + shouldMatchRootQueryFilter?: boolean; }; export const useCreateOneRecord = < @@ -27,6 +28,7 @@ export const useCreateOneRecord = < objectNameSingular, recordGqlFields, skipPostOptmisticEffect = false, + shouldMatchRootQueryFilter, }: useCreateOneRecordProps) => { const apolloClient = useApolloClient(); const [loading, setLoading] = useState(false); @@ -76,6 +78,7 @@ export const useCreateOneRecord = < objectMetadataItem, recordsToCreate: [recordCreatedInCache], objectMetadataItems, + shouldMatchRootQueryFilter, }); } @@ -97,7 +100,9 @@ export const useCreateOneRecord = < objectMetadataItem, recordsToCreate: [record], objectMetadataItems, + shouldMatchRootQueryFilter, }); + setLoading(false); }, }); diff --git a/packages/twenty-front/src/modules/object-record/hooks/useDeleteManyRecords.ts b/packages/twenty-front/src/modules/object-record/hooks/useDeleteManyRecords.ts index f189d516da1b..1d3d82f3fe60 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useDeleteManyRecords.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useDeleteManyRecords.ts @@ -1,12 +1,16 @@ import { useApolloClient } from '@apollo/client'; import { triggerDeleteRecordsOptimisticEffect } from '@/apollo/optimistic-effect/utils/triggerDeleteRecordsOptimisticEffect'; +import { apiConfigState } from '@/client-config/states/apiConfigState'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems'; import { useGetRecordFromCache } from '@/object-record/cache/hooks/useGetRecordFromCache'; +import { DEFAULT_MUTATION_BATCH_SIZE } from '@/object-record/constants/DefaultMutationBatchSize'; import { useDeleteManyRecordsMutation } from '@/object-record/hooks/useDeleteManyRecordsMutation'; import { getDeleteManyRecordsMutationResponseField } from '@/object-record/utils/getDeleteManyRecordsMutationResponseField'; +import { useRecoilValue } from 'recoil'; import { isDefined } from '~/utils/isDefined'; +import { sleep } from '~/utils/sleep'; import { capitalize } from '~/utils/string/capitalize'; type useDeleteOneRecordProps = { @@ -16,11 +20,17 @@ type useDeleteOneRecordProps = { type DeleteManyRecordsOptions = { skipOptimisticEffect?: boolean; + delayInMsBetweenRequests?: number; }; export const useDeleteManyRecords = ({ objectNameSingular, }: useDeleteOneRecordProps) => { + const apiConfig = useRecoilValue(apiConfigState); + + const mutationPageSize = + apiConfig?.mutationMaximumAffectedRecords ?? DEFAULT_MUTATION_BATCH_SIZE; + const apolloClient = useApolloClient(); const { objectMetadataItem } = useObjectMetadataItem({ @@ -45,40 +55,60 @@ export const useDeleteManyRecords = ({ idsToDelete: string[], options?: DeleteManyRecordsOptions, ) => { - const deletedRecords = await apolloClient.mutate({ - mutation: deleteManyRecordsMutation, - variables: { - filter: { id: { in: idsToDelete } }, - }, - optimisticResponse: options?.skipOptimisticEffect - ? undefined - : { - [mutationResponseField]: idsToDelete.map((idToDelete) => ({ - __typename: capitalize(objectNameSingular), - id: idToDelete, - })), - }, - update: options?.skipOptimisticEffect - ? undefined - : (cache, { data }) => { - const records = data?.[mutationResponseField]; - - if (!records?.length) return; - - const cachedRecords = records - .map((record) => getRecordFromCache(record.id, cache)) - .filter(isDefined); - - triggerDeleteRecordsOptimisticEffect({ - cache, - objectMetadataItem, - recordsToDelete: cachedRecords, - objectMetadataItems, - }); - }, - }); - - return deletedRecords.data?.[mutationResponseField] ?? null; + const numberOfBatches = Math.ceil(idsToDelete.length / mutationPageSize); + + const deletedRecords = []; + + for (let batchIndex = 0; batchIndex < numberOfBatches; batchIndex++) { + const batchIds = idsToDelete.slice( + batchIndex * mutationPageSize, + (batchIndex + 1) * mutationPageSize, + ); + + const deletedRecordsResponse = await apolloClient.mutate({ + mutation: deleteManyRecordsMutation, + variables: { + filter: { id: { in: batchIds } }, + }, + optimisticResponse: options?.skipOptimisticEffect + ? undefined + : { + [mutationResponseField]: batchIds.map((idToDelete) => ({ + __typename: capitalize(objectNameSingular), + id: idToDelete, + })), + }, + update: options?.skipOptimisticEffect + ? undefined + : (cache, { data }) => { + const records = data?.[mutationResponseField]; + + if (!records?.length) return; + + const cachedRecords = records + .map((record) => getRecordFromCache(record.id, cache)) + .filter(isDefined); + + triggerDeleteRecordsOptimisticEffect({ + cache, + objectMetadataItem, + recordsToDelete: cachedRecords, + objectMetadataItems, + }); + }, + }); + + const deletedRecordsForThisBatch = + deletedRecordsResponse.data?.[mutationResponseField] ?? []; + + deletedRecords.push(...deletedRecordsForThisBatch); + + if (isDefined(options?.delayInMsBetweenRequests)) { + await sleep(options.delayInMsBetweenRequests); + } + } + + return deletedRecords; }; return { deleteManyRecords }; diff --git a/packages/twenty-front/src/modules/object-record/hooks/useDetachRelatedRecordFromRecord.ts b/packages/twenty-front/src/modules/object-record/hooks/useDetachRelatedRecordFromRecord.ts new file mode 100644 index 000000000000..b441ab37a808 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/hooks/useDetachRelatedRecordFromRecord.ts @@ -0,0 +1,88 @@ +import { Reference, useApolloClient } from '@apollo/client'; + +import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; +import { getRefName } from '@/object-record/cache/utils/getRefName'; +import { modifyRecordFromCache } from '@/object-record/cache/utils/modifyRecordFromCache'; +import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord'; + +type useDetachRelatedRecordFromRecordProps = { + recordObjectNameSingular: string; + fieldNameOnRecordObject: string; +}; + +export const useDetachRelatedRecordFromRecord = ({ + recordObjectNameSingular, + fieldNameOnRecordObject, +}: useDetachRelatedRecordFromRecordProps) => { + const apolloClient = useApolloClient(); + + const { objectMetadataItem } = useObjectMetadataItem({ + objectNameSingular: recordObjectNameSingular, + }); + + const fieldOnObject = objectMetadataItem.fields.find((field) => { + return field.name === fieldNameOnRecordObject; + }); + + const relatedRecordObjectNameSingular = + fieldOnObject?.relationDefinition?.targetObjectMetadata.nameSingular; + + const fieldOnRelatedObject = + fieldOnObject?.relationDefinition?.targetFieldMetadata.name; + + if (!relatedRecordObjectNameSingular) { + throw new Error( + `Could not find record related to ${recordObjectNameSingular}`, + ); + } + + const { updateOneRecord } = useUpdateOneRecord({ + objectNameSingular: relatedRecordObjectNameSingular, + }); + + const updateOneRecordAndDetachRelations = async ({ + recordId, + relatedRecordId, + }: { + recordId: string; + relatedRecordId: string; + }) => { + modifyRecordFromCache({ + objectMetadataItem, + cache: apolloClient.cache, + fieldModifiers: { + [fieldNameOnRecordObject]: ( + fieldNameOnRecordObjectConnection, + { readField }, + ) => { + const edges = readField<{ node: Reference }[]>( + 'edges', + fieldNameOnRecordObjectConnection, + ); + + if (!edges) return fieldNameOnRecordObjectConnection; + + return { + ...fieldNameOnRecordObjectConnection, + edges: edges.filter( + (edge) => + !( + edge.node.__ref === + getRefName(relatedRecordObjectNameSingular, relatedRecordId) + ), + ), + }; + }, + }, + recordId, + }); + await updateOneRecord({ + idToUpdate: relatedRecordId, + updateOneRecordInput: { + [`${fieldOnRelatedObject}Id`]: null, + }, + }); + }; + + return { updateOneRecordAndDetachRelations }; +}; diff --git a/packages/twenty-front/src/modules/object-record/hooks/useFetchAllRecordIds.ts b/packages/twenty-front/src/modules/object-record/hooks/useFetchAllRecordIds.ts new file mode 100644 index 000000000000..715cdc5af15d --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/hooks/useFetchAllRecordIds.ts @@ -0,0 +1,88 @@ +import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; +import { DEFAULT_QUERY_PAGE_SIZE } from '@/object-record/constants/DefaultQueryPageSize'; +import { UseFindManyRecordsParams } from '@/object-record/hooks/useFetchMoreRecordsWithPagination'; +import { useLazyFindManyRecords } from '@/object-record/hooks/useLazyFindManyRecords'; +import { useCallback } from 'react'; +import { isDefined } from '~/utils/isDefined'; + +type UseLazyFetchAllRecordIdsParams<T> = Omit< + UseFindManyRecordsParams<T>, + 'skip' +> & { pageSize?: number }; + +export const useFetchAllRecordIds = <T>({ + objectNameSingular, + filter, + orderBy, + pageSize = DEFAULT_QUERY_PAGE_SIZE, +}: UseLazyFetchAllRecordIdsParams<T>) => { + const { fetchMore, findManyRecords } = useLazyFindManyRecords({ + objectNameSingular, + filter, + orderBy, + limit: pageSize, + recordGqlFields: { id: true }, + }); + + const { objectMetadataItem } = useObjectMetadataItem({ + objectNameSingular, + }); + + const fetchAllRecordIds = useCallback(async () => { + if (!isDefined(findManyRecords)) { + return []; + } + + const findManyRecordsDataResult = await findManyRecords(); + + const firstQueryResult = + findManyRecordsDataResult?.data?.[objectMetadataItem.namePlural]; + + const totalCount = firstQueryResult?.totalCount ?? 0; + + const recordsCount = firstQueryResult?.edges.length ?? 0; + + const recordIdSet = new Set( + firstQueryResult?.edges?.map((edge) => edge.node.id) ?? [], + ); + + const remainingCount = totalCount - recordsCount; + + const remainingPages = Math.ceil(remainingCount / pageSize); + + let lastCursor = firstQueryResult?.pageInfo.endCursor ?? null; + + for (let pageIndex = 0; pageIndex < remainingPages; pageIndex++) { + if (lastCursor === null) { + break; + } + + const rawResult = await fetchMore?.({ + variables: { + lastCursor: lastCursor, + limit: pageSize, + }, + }); + + const fetchMoreResult = rawResult?.data?.[objectMetadataItem.namePlural]; + + for (const edge of fetchMoreResult.edges) { + recordIdSet.add(edge.node.id); + } + + if (fetchMoreResult.pageInfo.hasNextPage === false) { + break; + } + + lastCursor = fetchMoreResult.pageInfo.endCursor ?? null; + } + + const recordIds = Array.from(recordIdSet); + + return recordIds; + }, [fetchMore, findManyRecords, objectMetadataItem.namePlural, pageSize]); + + return { + fetchAllRecordIds, + }; +}; diff --git a/packages/twenty-front/src/modules/object-record/hooks/useFetchMoreRecordsWithPagination.ts b/packages/twenty-front/src/modules/object-record/hooks/useFetchMoreRecordsWithPagination.ts new file mode 100644 index 000000000000..2cc6be1c0b87 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/hooks/useFetchMoreRecordsWithPagination.ts @@ -0,0 +1,229 @@ +import { + ApolloError, + ApolloQueryResult, + FetchMoreQueryOptions, + OperationVariables, + WatchQueryFetchPolicy, +} from '@apollo/client'; +import { isNonEmptyArray } from '@apollo/client/utilities'; +import { isNonEmptyString } from '@sniptt/guards'; +import { useMemo } from 'react'; +import { useRecoilCallback, useRecoilState, useSetRecoilState } from 'recoil'; + +import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; +import { ObjectMetadataItemIdentifier } from '@/object-metadata/types/ObjectMetadataItemIdentifier'; +import { isAggregationEnabled } from '@/object-metadata/utils/isAggregationEnabled'; +import { getRecordsFromRecordConnection } from '@/object-record/cache/utils/getRecordsFromRecordConnection'; +import { RecordGqlEdge } from '@/object-record/graphql/types/RecordGqlEdge'; +import { RecordGqlOperationFindManyResult } from '@/object-record/graphql/types/RecordGqlOperationFindManyResult'; +import { RecordGqlOperationGqlRecordFields } from '@/object-record/graphql/types/RecordGqlOperationGqlRecordFields'; +import { RecordGqlOperationVariables } from '@/object-record/graphql/types/RecordGqlOperationVariables'; +import { useHandleFindManyRecordsError } from '@/object-record/hooks/useHandleFindManyRecordsError'; +import { ObjectRecord } from '@/object-record/types/ObjectRecord'; +import { OnFindManyRecordsCompleted } from '@/object-record/types/OnFindManyRecordsCompleted'; +import { filterUniqueRecordEdgesByCursor } from '@/object-record/utils/filterUniqueRecordEdgesByCursor'; +import { getQueryIdentifier } from '@/object-record/utils/getQueryIdentifier'; +import { isDefined } from '~/utils/isDefined'; +import { capitalize } from '~/utils/string/capitalize'; + +import { cursorFamilyState } from '../states/cursorFamilyState'; +import { hasNextPageFamilyState } from '../states/hasNextPageFamilyState'; +import { isFetchingMoreRecordsFamilyState } from '../states/isFetchingMoreRecordsFamilyState'; + +export type UseFindManyRecordsParams<T> = ObjectMetadataItemIdentifier & + RecordGqlOperationVariables & { + onCompleted?: OnFindManyRecordsCompleted<T>; + skip?: boolean; + recordGqlFields?: RecordGqlOperationGqlRecordFields; + fetchPolicy?: WatchQueryFetchPolicy; + }; + +type UseFindManyRecordsStateParams< + T, + TData = RecordGqlOperationFindManyResult, +> = Omit< + UseFindManyRecordsParams<T>, + 'skip' | 'recordGqlFields' | 'fetchPolicy' +> & { + data: RecordGqlOperationFindManyResult | undefined; + error: ApolloError | undefined; + fetchMore< + TFetchData = TData, + TFetchVars extends OperationVariables = OperationVariables, + >( + fetchMoreOptions: FetchMoreQueryOptions<TFetchVars, TFetchData> & { + updateQuery?: ( + previousQueryResult: TData, + options: { + fetchMoreResult: TFetchData; + variables: TFetchVars; + }, + ) => TData; + }, + ): Promise<ApolloQueryResult<TFetchData>>; + objectMetadataItem: ObjectMetadataItem; +}; + +export const useFetchMoreRecordsWithPagination = < + T extends ObjectRecord = ObjectRecord, +>({ + objectNameSingular, + filter, + orderBy, + limit, + data, + error, + fetchMore, + objectMetadataItem, + onCompleted, +}: UseFindManyRecordsStateParams<T>) => { + const queryIdentifier = getQueryIdentifier({ + objectNameSingular, + filter, + limit, + orderBy, + }); + + const [hasNextPage] = useRecoilState(hasNextPageFamilyState(queryIdentifier)); + + const setIsFetchingMoreObjects = useSetRecoilState( + isFetchingMoreRecordsFamilyState(queryIdentifier), + ); + + const { handleFindManyRecordsError } = useHandleFindManyRecordsError({ + objectMetadataItem, + }); + + // TODO: put this into a util inspired from https://github.com/apollographql/apollo-client/blob/master/src/utilities/policies/pagination.ts + // This function is equivalent to merge function + read function in field policy + const fetchMoreRecords = useRecoilCallback( + ({ snapshot, set }) => + async () => { + const hasNextPageLocal = snapshot + .getLoadable(hasNextPageFamilyState(queryIdentifier)) + .getValue(); + + const lastCursorLocal = snapshot + .getLoadable(cursorFamilyState(queryIdentifier)) + .getValue(); + + // Remote objects does not support hasNextPage. We cannot rely on it to fetch more records. + if ( + hasNextPageLocal || + (!isAggregationEnabled(objectMetadataItem) && !error) + ) { + setIsFetchingMoreObjects(true); + + try { + const { data: fetchMoreDataResult } = await fetchMore({ + variables: { + filter, + orderBy, + lastCursor: isNonEmptyString(lastCursorLocal) + ? lastCursorLocal + : undefined, + }, + updateQuery: (prev, { fetchMoreResult }) => { + const previousEdges = + prev?.[objectMetadataItem.namePlural]?.edges; + const nextEdges = + fetchMoreResult?.[objectMetadataItem.namePlural]?.edges; + + let newEdges: RecordGqlEdge[] = previousEdges ?? []; + + if (isNonEmptyArray(nextEdges)) { + newEdges = filterUniqueRecordEdgesByCursor([ + ...newEdges, + ...(fetchMoreResult?.[objectMetadataItem.namePlural] + ?.edges ?? []), + ]); + } + + const pageInfo = + fetchMoreResult?.[objectMetadataItem.namePlural]?.pageInfo; + + if (isDefined(data?.[objectMetadataItem.namePlural])) { + set( + cursorFamilyState(queryIdentifier), + pageInfo.endCursor ?? '', + ); + set( + hasNextPageFamilyState(queryIdentifier), + pageInfo.hasNextPage ?? false, + ); + } + + const records = getRecordsFromRecordConnection({ + recordConnection: { + edges: newEdges, + pageInfo, + }, + }) as T[]; + + onCompleted?.(records, { + pageInfo, + totalCount: + fetchMoreResult?.[objectMetadataItem.namePlural] + ?.totalCount, + }); + + return Object.assign({}, prev, { + [objectMetadataItem.namePlural]: { + __typename: `${capitalize( + objectMetadataItem.nameSingular, + )}Connection`, + edges: newEdges, + pageInfo: + fetchMoreResult?.[objectMetadataItem.namePlural].pageInfo, + totalCount: + fetchMoreResult?.[objectMetadataItem.namePlural] + .totalCount, + }, + } as RecordGqlOperationFindManyResult); + }, + }); + + return { + data: fetchMoreDataResult?.[objectMetadataItem.namePlural], + }; + } catch (error) { + handleFindManyRecordsError(error as ApolloError); + } finally { + setIsFetchingMoreObjects(false); + } + } + }, + [ + objectMetadataItem, + error, + setIsFetchingMoreObjects, + fetchMore, + filter, + orderBy, + data, + onCompleted, + handleFindManyRecordsError, + queryIdentifier, + ], + ); + + const totalCount = data?.[objectMetadataItem.namePlural]?.totalCount; + + const records = useMemo( + () => + data?.[objectMetadataItem.namePlural] + ? getRecordsFromRecordConnection<T>({ + recordConnection: data?.[objectMetadataItem.namePlural], + }) + : ([] as T[]), + + [data, objectMetadataItem.namePlural], + ); + + return { + fetchMoreRecords, + totalCount, + records, + hasNextPage, + }; +}; diff --git a/packages/twenty-front/src/modules/object-record/hooks/useFieldContext.tsx b/packages/twenty-front/src/modules/object-record/hooks/useFieldContext.tsx index cbd002af74a7..9a4be7849d8f 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useFieldContext.tsx +++ b/packages/twenty-front/src/modules/object-record/hooks/useFieldContext.tsx @@ -19,6 +19,7 @@ export const useFieldContext = ({ objectNameSingular, objectRecordId, customUseUpdateOneObjectHook, + overridenIsFieldEmpty, }: { clearable?: boolean; fieldMetadataName: string; @@ -27,6 +28,7 @@ export const useFieldContext = ({ objectNameSingular: string; objectRecordId: string; customUseUpdateOneObjectHook?: RecordUpdateHook; + overridenIsFieldEmpty?: boolean; }) => { const { objectMetadataItem } = useObjectMetadataItem({ objectNameSingular, @@ -78,6 +80,7 @@ export const useFieldContext = ({ customUseUpdateOneObjectHook ?? useUpdateOneObjectMutation, hotkeyScope: InlineCellHotkeyScope.InlineCell, clearable, + overridenIsFieldEmpty, }} > {children} diff --git a/packages/twenty-front/src/modules/object-record/hooks/useFindDuplicateRecords.ts b/packages/twenty-front/src/modules/object-record/hooks/useFindDuplicateRecords.ts index 4bf2d0c1ebfd..bd75db4a75a4 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useFindDuplicateRecords.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useFindDuplicateRecords.ts @@ -5,7 +5,7 @@ import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadata import { ObjectMetadataItemIdentifier } from '@/object-metadata/types/ObjectMetadataItemIdentifier'; import { getRecordsFromRecordConnection } from '@/object-record/cache/utils/getRecordsFromRecordConnection'; import { RecordGqlConnection } from '@/object-record/graphql/types/RecordGqlConnection'; -import { RecordGqlOperationFindManyResult } from '@/object-record/graphql/types/RecordGqlOperationFindManyResult'; +import { RecordGqlOperationFindDuplicatesResult } from '@/object-record/graphql/types/RecordGqlOperationFindDuplicatesResults'; import { useFindDuplicateRecordsQuery } from '@/object-record/hooks/useFindDuplicatesRecordsQuery'; import { ObjectRecord } from '@/object-record/types/ObjectRecord'; import { getFindDuplicateRecordsQueryResponseField } from '@/object-record/utils/getFindDuplicateRecordsQueryResponseField'; @@ -14,12 +14,12 @@ import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; import { logError } from '~/utils/logError'; export const useFindDuplicateRecords = <T extends ObjectRecord = ObjectRecord>({ - objectRecordId = '', + objectRecordIds = [], objectNameSingular, onCompleted, }: ObjectMetadataItemIdentifier & { - objectRecordId: string | undefined; - onCompleted?: (data: RecordGqlConnection) => void; + objectRecordIds: string[] | undefined; + onCompleted?: (data: RecordGqlConnection[]) => void; skip?: boolean; }) => { const findDuplicateQueryStateIdentifier = objectNameSingular; @@ -38,46 +38,48 @@ export const useFindDuplicateRecords = <T extends ObjectRecord = ObjectRecord>({ objectMetadataItem.nameSingular, ); - const { data, loading, error } = useQuery<RecordGqlOperationFindManyResult>( - findDuplicateRecordsQuery, - { - variables: { - id: objectRecordId, + const { data, loading, error } = + useQuery<RecordGqlOperationFindDuplicatesResult>( + findDuplicateRecordsQuery, + { + variables: { + ids: objectRecordIds, + }, + onCompleted: (data) => { + onCompleted?.(data[queryResponseField]); + }, + onError: (error) => { + logError( + `useFindDuplicateRecords for "${objectMetadataItem.nameSingular}" error : ` + + error, + ); + enqueueSnackBar( + `Error during useFindDuplicateRecords for "${objectMetadataItem.nameSingular}", ${error.message}`, + { + variant: SnackBarVariant.Error, + }, + ); + }, }, - onCompleted: (data) => { - onCompleted?.(data[queryResponseField]); - }, - onError: (error) => { - logError( - `useFindDuplicateRecords for "${objectMetadataItem.nameSingular}" error : ` + - error, - ); - enqueueSnackBar( - `Error during useFindDuplicateRecords for "${objectMetadataItem.nameSingular}", ${error.message}`, - { - variant: SnackBarVariant.Error, - }, - ); - }, - }, - ); + ); - const objectRecordConnection = data?.[queryResponseField]; + const objectResults = data?.[queryResponseField]; - const records = useMemo( + const results = useMemo( () => - objectRecordConnection - ? (getRecordsFromRecordConnection({ - recordConnection: objectRecordConnection, - }) as T[]) - : [], - [objectRecordConnection], + objectResults?.map((result: RecordGqlConnection) => { + return result + ? (getRecordsFromRecordConnection({ + recordConnection: result, + }) as T[]) + : []; + }), + [objectResults], ); return { objectMetadataItem, - records, - totalCount: objectRecordConnection?.totalCount, + results, loading, error, queryStateIdentifier: findDuplicateQueryStateIdentifier, diff --git a/packages/twenty-front/src/modules/object-record/hooks/useFindDuplicatesRecordsQuery.ts b/packages/twenty-front/src/modules/object-record/hooks/useFindDuplicatesRecordsQuery.ts index 9968d2d46a72..b3b95e270b95 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useFindDuplicatesRecordsQuery.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useFindDuplicatesRecordsQuery.ts @@ -22,10 +22,10 @@ export const useFindDuplicateRecordsQuery = ({ const findDuplicateRecordsQuery = gql` query FindDuplicate${capitalize( objectMetadataItem.nameSingular, - )}($id: ID!) { + )}($ids: [ID!]!) { ${getFindDuplicateRecordsQueryResponseField( objectMetadataItem.nameSingular, - )}(id: $id) { + )}(ids: $ids) { edges { node ${mapObjectMetadataToGraphQLQuery({ objectMetadataItems, @@ -38,7 +38,6 @@ export const useFindDuplicateRecordsQuery = ({ startCursor endCursor } - ${isAggregationEnabled(objectMetadataItem) ? 'totalCount' : ''} } } `; diff --git a/packages/twenty-front/src/modules/object-record/hooks/useFindManyRecords.ts b/packages/twenty-front/src/modules/object-record/hooks/useFindManyRecords.ts index befc85849d7e..da5dc238af89 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useFindManyRecords.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useFindManyRecords.ts @@ -1,236 +1,97 @@ -import { useCallback, useMemo } from 'react'; import { useQuery, WatchQueryFetchPolicy } from '@apollo/client'; -import { isNonEmptyArray } from '@apollo/client/utilities'; -import { isNonEmptyString } from '@sniptt/guards'; -import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil'; +import { useRecoilValue } from 'recoil'; import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { ObjectMetadataItemIdentifier } from '@/object-metadata/types/ObjectMetadataItemIdentifier'; -import { isAggregationEnabled } from '@/object-metadata/utils/isAggregationEnabled'; -import { getRecordsFromRecordConnection } from '@/object-record/cache/utils/getRecordsFromRecordConnection'; -import { RecordGqlConnection } from '@/object-record/graphql/types/RecordGqlConnection'; -import { RecordGqlEdge } from '@/object-record/graphql/types/RecordGqlEdge'; import { RecordGqlOperationFindManyResult } from '@/object-record/graphql/types/RecordGqlOperationFindManyResult'; import { RecordGqlOperationGqlRecordFields } from '@/object-record/graphql/types/RecordGqlOperationGqlRecordFields'; import { RecordGqlOperationVariables } from '@/object-record/graphql/types/RecordGqlOperationVariables'; +import { useFetchMoreRecordsWithPagination } from '@/object-record/hooks/useFetchMoreRecordsWithPagination'; import { useFindManyRecordsQuery } from '@/object-record/hooks/useFindManyRecordsQuery'; +import { useHandleFindManyRecordsCompleted } from '@/object-record/hooks/useHandleFindManyRecordsCompleted'; +import { useHandleFindManyRecordsError } from '@/object-record/hooks/useHandleFindManyRecordsError'; import { ObjectRecord } from '@/object-record/types/ObjectRecord'; -import { filterUniqueRecordEdgesByCursor } from '@/object-record/utils/filterUniqueRecordEdgesByCursor'; -import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar'; -import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; -import { isDefined } from '~/utils/isDefined'; -import { logError } from '~/utils/logError'; -import { capitalize } from '~/utils/string/capitalize'; +import { OnFindManyRecordsCompleted } from '@/object-record/types/OnFindManyRecordsCompleted'; +import { getQueryIdentifier } from '@/object-record/utils/getQueryIdentifier'; -import { cursorFamilyState } from '../states/cursorFamilyState'; -import { hasNextPageFamilyState } from '../states/hasNextPageFamilyState'; -import { isFetchingMoreRecordsFamilyState } from '../states/isFetchingMoreRecordsFamilyState'; +export type UseFindManyRecordsParams<T> = ObjectMetadataItemIdentifier & + RecordGqlOperationVariables & { + onError?: (error?: Error) => void; + onCompleted?: OnFindManyRecordsCompleted<T>; + skip?: boolean; + recordGqlFields?: RecordGqlOperationGqlRecordFields; + fetchPolicy?: WatchQueryFetchPolicy; + }; export const useFindManyRecords = <T extends ObjectRecord = ObjectRecord>({ objectNameSingular, filter, orderBy, limit, - onCompleted, - onError, skip, recordGqlFields, fetchPolicy, -}: ObjectMetadataItemIdentifier & - RecordGqlOperationVariables & { - onCompleted?: ( - records: T[], - options?: { - pageInfo?: RecordGqlConnection['pageInfo']; - totalCount?: number; - }, - ) => void; - onError?: (error?: Error) => void; - skip?: boolean; - recordGqlFields?: RecordGqlOperationGqlRecordFields; - fetchPolicy?: WatchQueryFetchPolicy; - }) => { - const findManyQueryStateIdentifier = - objectNameSingular + - JSON.stringify(filter) + - JSON.stringify(orderBy) + - limit; - - const [lastCursor, setLastCursor] = useRecoilState( - cursorFamilyState(findManyQueryStateIdentifier), - ); - - const [hasNextPage, setHasNextPage] = useRecoilState( - hasNextPageFamilyState(findManyQueryStateIdentifier), - ); - - const setIsFetchingMoreObjects = useSetRecoilState( - isFetchingMoreRecordsFamilyState(findManyQueryStateIdentifier), - ); - + onError, + onCompleted, + cursorFilter, +}: UseFindManyRecordsParams<T>) => { + const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState); const { objectMetadataItem } = useObjectMetadataItem({ objectNameSingular, }); - const { findManyRecordsQuery } = useFindManyRecordsQuery({ objectNameSingular, recordGqlFields, + cursorDirection: cursorFilter?.cursorDirection, }); - const { enqueueSnackBar } = useSnackBar(); - const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState); + const { handleFindManyRecordsError } = useHandleFindManyRecordsError({ + objectMetadataItem, + handleError: onError, + }); + + const queryIdentifier = getQueryIdentifier({ + objectNameSingular, + filter, + orderBy, + limit, + }); + + const { handleFindManyRecordsCompleted } = useHandleFindManyRecordsCompleted({ + objectMetadataItem, + queryIdentifier, + onCompleted, + }); const { data, loading, error, fetchMore } = useQuery<RecordGqlOperationFindManyResult>(findManyRecordsQuery, { skip: skip || !objectMetadataItem || !currentWorkspaceMember, variables: { filter, - limit, orderBy, + lastCursor: cursorFilter?.cursor ?? undefined, + limit: cursorFilter?.limit ?? limit, }, fetchPolicy: fetchPolicy, - onCompleted: (data) => { - if (!isDefined(data)) { - onCompleted?.([]); - } - - const pageInfo = data?.[objectMetadataItem.namePlural]?.pageInfo; - - const records = getRecordsFromRecordConnection({ - recordConnection: data?.[objectMetadataItem.namePlural], - }) as T[]; - - onCompleted?.(records, { - pageInfo, - totalCount: data?.[objectMetadataItem.namePlural]?.totalCount, - }); - - if (isDefined(data?.[objectMetadataItem.namePlural])) { - setLastCursor(pageInfo.endCursor ?? ''); - setHasNextPage(pageInfo.hasNextPage ?? false); - } - }, - onError: (error) => { - logError( - `useFindManyRecords for "${objectMetadataItem.namePlural}" error : ` + - error, - ); - enqueueSnackBar( - `Error during useFindManyRecords for "${objectMetadataItem.namePlural}", ${error.message}`, - { - variant: SnackBarVariant.Error, - }, - ); - onError?.(error); - }, + onCompleted: handleFindManyRecordsCompleted, + onError: handleFindManyRecordsError, }); - const fetchMoreRecords = useCallback(async () => { - // Remote objects does not support hasNextPage. We cannot rely on it to fetch more records. - if (hasNextPage || (!isAggregationEnabled(objectMetadataItem) && !error)) { - setIsFetchingMoreObjects(true); - - try { - await fetchMore({ - variables: { - filter, - orderBy, - lastCursor: isNonEmptyString(lastCursor) ? lastCursor : undefined, - }, - updateQuery: (prev, { fetchMoreResult }) => { - const previousEdges = prev?.[objectMetadataItem.namePlural]?.edges; - const nextEdges = - fetchMoreResult?.[objectMetadataItem.namePlural]?.edges; - - let newEdges: RecordGqlEdge[] = previousEdges ?? []; - - if (isNonEmptyArray(nextEdges)) { - newEdges = filterUniqueRecordEdgesByCursor([ - ...newEdges, - ...(fetchMoreResult?.[objectMetadataItem.namePlural]?.edges ?? - []), - ]); - } - - const pageInfo = - fetchMoreResult?.[objectMetadataItem.namePlural]?.pageInfo; - - if (isDefined(data?.[objectMetadataItem.namePlural])) { - setLastCursor(pageInfo.endCursor ?? ''); - setHasNextPage(pageInfo.hasNextPage ?? false); - } - - const records = getRecordsFromRecordConnection({ - recordConnection: { - edges: newEdges, - pageInfo, - }, - }) as T[]; - - onCompleted?.(records, { - pageInfo, - totalCount: - fetchMoreResult?.[objectMetadataItem.namePlural]?.totalCount, - }); - - return Object.assign({}, prev, { - [objectMetadataItem.namePlural]: { - __typename: `${capitalize( - objectMetadataItem.nameSingular, - )}Connection`, - edges: newEdges, - pageInfo: - fetchMoreResult?.[objectMetadataItem.namePlural].pageInfo, - totalCount: - fetchMoreResult?.[objectMetadataItem.namePlural].totalCount, - }, - } as RecordGqlOperationFindManyResult); - }, - }); - } catch (error) { - logError( - `fetchMoreObjects for "${objectMetadataItem.namePlural}" error : ` + - error, - ); - enqueueSnackBar( - `Error during fetchMoreObjects for "${objectMetadataItem.namePlural}", ${error}`, - { - variant: SnackBarVariant.Error, - }, - ); - } finally { - setIsFetchingMoreObjects(false); - } - } - }, [ - hasNextPage, - objectMetadataItem, - error, - setIsFetchingMoreObjects, - fetchMore, - filter, - orderBy, - lastCursor, - data, - onCompleted, - setLastCursor, - setHasNextPage, - enqueueSnackBar, - ]); - - const totalCount = data?.[objectMetadataItem.namePlural]?.totalCount; - - const records = useMemo( - () => - data?.[objectMetadataItem.namePlural] - ? getRecordsFromRecordConnection<T>({ - recordConnection: data?.[objectMetadataItem.namePlural], - }) - : ([] as T[]), + const { fetchMoreRecords, records, hasNextPage } = + useFetchMoreRecordsWithPagination<T>({ + objectNameSingular, + filter, + orderBy, + limit, + fetchMore, + data, + error, + objectMetadataItem, + }); - [data, objectMetadataItem.namePlural], - ); + const pageInfo = data?.[objectMetadataItem.namePlural].pageInfo; + const totalCount = data?.[objectMetadataItem.namePlural].totalCount; return { objectMetadataItem, @@ -239,7 +100,8 @@ export const useFindManyRecords = <T extends ObjectRecord = ObjectRecord>({ loading, error, fetchMoreRecords, - queryStateIdentifier: findManyQueryStateIdentifier, + queryStateIdentifier: queryIdentifier, hasNextPage, + pageInfo, }; }; diff --git a/packages/twenty-front/src/modules/object-record/hooks/useFindManyRecordsQuery.ts b/packages/twenty-front/src/modules/object-record/hooks/useFindManyRecordsQuery.ts index 55a6f270dcef..0ede4f9f009c 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useFindManyRecordsQuery.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useFindManyRecordsQuery.ts @@ -3,16 +3,21 @@ import { useRecoilValue } from 'recoil'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; import { RecordGqlOperationGqlRecordFields } from '@/object-record/graphql/types/RecordGqlOperationGqlRecordFields'; -import { generateFindManyRecordsQuery } from '@/object-record/utils/generateFindManyRecordsQuery'; +import { + generateFindManyRecordsQuery, + QueryCursorDirection, +} from '@/object-record/utils/generateFindManyRecordsQuery'; export const useFindManyRecordsQuery = ({ objectNameSingular, recordGqlFields, computeReferences, + cursorDirection = 'after', }: { objectNameSingular: string; recordGqlFields?: RecordGqlOperationGqlRecordFields; computeReferences?: boolean; + cursorDirection?: QueryCursorDirection; }) => { const { objectMetadataItem } = useObjectMetadataItem({ objectNameSingular, @@ -25,6 +30,7 @@ export const useFindManyRecordsQuery = ({ objectMetadataItems, recordGqlFields, computeReferences, + cursorDirection, }); return { diff --git a/packages/twenty-front/src/modules/object-record/hooks/useFindOneRecord.ts b/packages/twenty-front/src/modules/object-record/hooks/useFindOneRecord.ts index af72ad296adc..76c9645bd850 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useFindOneRecord.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useFindOneRecord.ts @@ -1,5 +1,5 @@ -import { useMemo } from 'react'; import { useQuery } from '@apollo/client'; +import { useMemo } from 'react'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { ObjectMetadataItemIdentifier } from '@/object-metadata/types/ObjectMetadataItemIdentifier'; diff --git a/packages/twenty-front/src/modules/object-record/hooks/useHandleFindManyRecordsCompleted.ts b/packages/twenty-front/src/modules/object-record/hooks/useHandleFindManyRecordsCompleted.ts new file mode 100644 index 000000000000..f0f89bfb2e6f --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/hooks/useHandleFindManyRecordsCompleted.ts @@ -0,0 +1,53 @@ +import { useRecoilState } from 'recoil'; + +import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; +import { getRecordsFromRecordConnection } from '@/object-record/cache/utils/getRecordsFromRecordConnection'; +import { RecordGqlOperationFindManyResult } from '@/object-record/graphql/types/RecordGqlOperationFindManyResult'; +import { cursorFamilyState } from '@/object-record/states/cursorFamilyState'; +import { hasNextPageFamilyState } from '@/object-record/states/hasNextPageFamilyState'; +import { OnFindManyRecordsCompleted } from '@/object-record/types/OnFindManyRecordsCompleted'; +import { isDefined } from '~/utils/isDefined'; + +export const useHandleFindManyRecordsCompleted = <T>({ + queryIdentifier, + onCompleted, + objectMetadataItem, +}: { + queryIdentifier: string; + objectMetadataItem: ObjectMetadataItem; + onCompleted?: OnFindManyRecordsCompleted<T>; +}) => { + const [, setLastCursor] = useRecoilState(cursorFamilyState(queryIdentifier)); + + const [, setHasNextPage] = useRecoilState( + hasNextPageFamilyState(queryIdentifier), + ); + + const handleFindManyRecordsCompleted = ( + data: RecordGqlOperationFindManyResult, + ) => { + if (!isDefined(data)) { + onCompleted?.([]); + } + + const pageInfo = data?.[objectMetadataItem.namePlural]?.pageInfo; + + const records = getRecordsFromRecordConnection({ + recordConnection: data?.[objectMetadataItem.namePlural], + }) as T[]; + + onCompleted?.(records, { + pageInfo, + totalCount: data?.[objectMetadataItem.namePlural]?.totalCount, + }); + + if (isDefined(data?.[objectMetadataItem.namePlural])) { + setLastCursor(pageInfo.endCursor ?? ''); + setHasNextPage(pageInfo.hasNextPage ?? false); + } + }; + + return { + handleFindManyRecordsCompleted, + }; +}; diff --git a/packages/twenty-front/src/modules/object-record/hooks/useHandleFindManyRecordsError.ts b/packages/twenty-front/src/modules/object-record/hooks/useHandleFindManyRecordsError.ts new file mode 100644 index 000000000000..1b5a8cae64ef --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/hooks/useHandleFindManyRecordsError.ts @@ -0,0 +1,34 @@ +import { ApolloError } from '@apollo/client'; + +import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; +import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar'; +import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; +import { logError } from '~/utils/logError'; + +export const useHandleFindManyRecordsError = ({ + handleError, + objectMetadataItem, +}: { + objectMetadataItem: ObjectMetadataItem; + handleError?: (error?: Error) => void; +}) => { + const { enqueueSnackBar } = useSnackBar(); + + const handleFindManyRecordsError = (error: ApolloError) => { + logError( + `useFindManyRecords for "${objectMetadataItem.namePlural}" error : ` + + error, + ); + enqueueSnackBar( + `Error during useFindManyRecords for "${objectMetadataItem.namePlural}", ${error.message}`, + { + variant: SnackBarVariant.Error, + }, + ); + handleError?.(error); + }; + + return { + handleFindManyRecordsError, + }; +}; diff --git a/packages/twenty-front/src/modules/object-record/hooks/useLazyFindManyRecords.ts b/packages/twenty-front/src/modules/object-record/hooks/useLazyFindManyRecords.ts new file mode 100644 index 000000000000..caf315296d4c --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/hooks/useLazyFindManyRecords.ts @@ -0,0 +1,115 @@ +import { useLazyQuery } from '@apollo/client'; +import { useRecoilCallback } from 'recoil'; + +import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; +import { RecordGqlOperationFindManyResult } from '@/object-record/graphql/types/RecordGqlOperationFindManyResult'; +import { useFetchMoreRecordsWithPagination } from '@/object-record/hooks/useFetchMoreRecordsWithPagination'; +import { UseFindManyRecordsParams } from '@/object-record/hooks/useFindManyRecords'; +import { useFindManyRecordsQuery } from '@/object-record/hooks/useFindManyRecordsQuery'; +import { useHandleFindManyRecordsCompleted } from '@/object-record/hooks/useHandleFindManyRecordsCompleted'; +import { useHandleFindManyRecordsError } from '@/object-record/hooks/useHandleFindManyRecordsError'; +import { cursorFamilyState } from '@/object-record/states/cursorFamilyState'; +import { hasNextPageFamilyState } from '@/object-record/states/hasNextPageFamilyState'; +import { ObjectRecord } from '@/object-record/types/ObjectRecord'; +import { getQueryIdentifier } from '@/object-record/utils/getQueryIdentifier'; + +type UseLazyFindManyRecordsParams<T> = Omit< + UseFindManyRecordsParams<T>, + 'skip' +>; + +export const useLazyFindManyRecords = <T extends ObjectRecord = ObjectRecord>({ + objectNameSingular, + filter, + orderBy, + limit, + recordGqlFields, + fetchPolicy, + onCompleted, + onError, +}: UseLazyFindManyRecordsParams<T>) => { + const { objectMetadataItem } = useObjectMetadataItem({ + objectNameSingular, + }); + + const { findManyRecordsQuery } = useFindManyRecordsQuery({ + objectNameSingular, + recordGqlFields, + }); + + const { handleFindManyRecordsError } = useHandleFindManyRecordsError({ + objectMetadataItem, + handleError: onError, + }); + + const queryIdentifier = getQueryIdentifier({ + objectNameSingular, + filter, + orderBy, + limit, + }); + + const { handleFindManyRecordsCompleted } = useHandleFindManyRecordsCompleted({ + objectMetadataItem, + queryIdentifier, + onCompleted, + }); + + const [findManyRecords, { data, loading, error, fetchMore }] = + useLazyQuery<RecordGqlOperationFindManyResult>(findManyRecordsQuery, { + variables: { + filter, + limit, + orderBy, + }, + fetchPolicy: fetchPolicy, + onCompleted: handleFindManyRecordsCompleted, + onError: handleFindManyRecordsError, + }); + + const { fetchMoreRecords, totalCount, records } = + useFetchMoreRecordsWithPagination<T>({ + objectNameSingular, + filter, + orderBy, + limit, + onCompleted, + fetchMore, + data, + error, + objectMetadataItem, + }); + + const findManyRecordsLazy = useRecoilCallback( + ({ set }) => + async () => { + const result = await findManyRecords(); + + const hasNextPage = + result?.data?.[objectMetadataItem.namePlural]?.pageInfo.hasNextPage ?? + false; + + const lastCursor = + result?.data?.[objectMetadataItem.namePlural]?.pageInfo.endCursor ?? + ''; + + set(hasNextPageFamilyState(queryIdentifier), hasNextPage); + set(cursorFamilyState(queryIdentifier), lastCursor); + + return result; + }, + [queryIdentifier, findManyRecords, objectMetadataItem], + ); + + return { + objectMetadataItem, + records, + totalCount, + loading, + error, + fetchMore, + fetchMoreRecordsWithPagination: fetchMoreRecords, + queryStateIdentifier: queryIdentifier, + findManyRecords: findManyRecordsLazy, + }; +}; diff --git a/packages/twenty-front/src/modules/object-record/hooks/useRecordChipData.ts b/packages/twenty-front/src/modules/object-record/hooks/useRecordChipData.ts new file mode 100644 index 000000000000..1958a09eb535 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/hooks/useRecordChipData.ts @@ -0,0 +1,24 @@ +import { PreComputedChipGeneratorsContext } from '@/object-metadata/context/PreComputedChipGeneratorsContext'; +import { generateDefaultRecordChipData } from '@/object-metadata/utils/generateDefaultRecordChipData'; +import { ObjectRecord } from '@/object-record/types/ObjectRecord'; +import { useContext } from 'react'; + +export const useRecordChipData = ({ + objectNameSingular, + record, +}: { + objectNameSingular: string; + record: ObjectRecord; +}) => { + const { identifierChipGeneratorPerObject } = useContext( + PreComputedChipGeneratorsContext, + ); + + const generateRecordChipData = + identifierChipGeneratorPerObject[objectNameSingular] ?? + generateDefaultRecordChipData; + + const recordChipData = generateRecordChipData(record); + + return { recordChipData }; +}; diff --git a/packages/twenty-front/src/modules/object-record/hooks/useUpdateOneRecord.ts b/packages/twenty-front/src/modules/object-record/hooks/useUpdateOneRecord.ts index fc0b5a1eb903..427c48547172 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useUpdateOneRecord.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useUpdateOneRecord.ts @@ -47,9 +47,11 @@ export const useUpdateOneRecord = < const updateOneRecord = async ({ idToUpdate, updateOneRecordInput, + optimisticRecord, }: { idToUpdate: string; updateOneRecordInput: Partial<Omit<UpdatedObjectRecord, 'id'>>; + optimisticRecord?: Partial<ObjectRecord>; }) => { const sanitizedInput = { ...sanitizeRecordInput({ @@ -68,16 +70,16 @@ export const useUpdateOneRecord = < computeReferences: true, }); - const optimisticRecord = { + const computedOptimisticRecord = { ...cachedRecord, - ...sanitizedInput, + ...(optimisticRecord ?? sanitizedInput), ...{ id: idToUpdate }, ...{ __typename: capitalize(objectMetadataItem.nameSingular) }, }; const optimisticRecordWithConnection = getRecordNodeFromRecord<ObjectRecord>({ - record: optimisticRecord, + record: computedOptimisticRecord, objectMetadataItem, objectMetadataItems, recordGqlFields: computedRecordGqlFields, @@ -92,7 +94,7 @@ export const useUpdateOneRecord = < objectMetadataItems, objectMetadataItem, cache: apolloClient.cache, - record: optimisticRecord, + record: computedOptimisticRecord, }); triggerUpdateRecordOptimisticEffect({ diff --git a/packages/twenty-front/src/modules/object-record/multiple-objects/hooks/useGenerateCombinedFindManyRecordsQuery.ts b/packages/twenty-front/src/modules/object-record/multiple-objects/hooks/useGenerateCombinedFindManyRecordsQuery.ts index a60d7d5b67aa..9e7935792c6c 100644 --- a/packages/twenty-front/src/modules/object-record/multiple-objects/hooks/useGenerateCombinedFindManyRecordsQuery.ts +++ b/packages/twenty-front/src/modules/object-record/multiple-objects/hooks/useGenerateCombinedFindManyRecordsQuery.ts @@ -32,9 +32,9 @@ export const useGenerateCombinedFindManyRecordsQuery = ({ const orderByPerMetadataItemArray = operationSignatures .map( ({ objectNameSingular }) => - `$orderBy${capitalize(objectNameSingular)}: ${capitalize( + `$orderBy${capitalize(objectNameSingular)}: [${capitalize( objectNameSingular, - )}OrderByInput`, + )}OrderByInput]`, ) .join(', '); diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/GenericEntityFilterChip.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/GenericEntityFilterChip.tsx index e11ae14c966d..fae9454c187a 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/GenericEntityFilterChip.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/GenericEntityFilterChip.tsx @@ -1,4 +1,4 @@ -import { EntityChip, IconComponent } from 'twenty-ui'; +import { AvatarChip, IconComponent } from 'twenty-ui'; import { getImageAbsoluteURIOrBase64 } from '~/utils/image/getImageAbsoluteURIOrBase64'; @@ -13,8 +13,8 @@ export const GenericEntityFilterChip = ({ filter, Icon, }: GenericEntityFilterChipProps) => ( - <EntityChip - entityId={filter.value} + <AvatarChip + placeholderColorSeed={filter.value} name={filter.displayValue} avatarType="rounded" avatarUrl={getImageAbsoluteURIOrBase64(filter.displayAvatarUrl) || ''} diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/MultipleFiltersDropdownContent.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/MultipleFiltersDropdownContent.tsx index 1bd909b72f98..cd49fd096b89 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/MultipleFiltersDropdownContent.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/MultipleFiltersDropdownContent.tsx @@ -3,6 +3,7 @@ import { useRecoilValue } from 'recoil'; import { ObjectFilterDropdownSearchInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownSearchInput'; import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown'; import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator'; +import { ViewFilterOperand } from '@/views/types/ViewFilterOperand'; import { MultipleFiltersDropdownFilterOnFilterChangedEffect } from './MultipleFiltersDropdownFilterOnFilterChangedEffect'; import { ObjectFilterDropdownDateInput } from './ObjectFilterDropdownDateInput'; @@ -36,6 +37,11 @@ export const MultipleFiltersDropdownContent = ({ const selectedOperandInDropdown = useRecoilValue( selectedOperandInDropdownState, ); + const isEmptyOperand = + selectedOperandInDropdown && + [ViewFilterOperand.IsEmpty, ViewFilterOperand.IsNotEmpty].includes( + selectedOperandInDropdown, + ); return ( <> @@ -43,6 +49,8 @@ export const MultipleFiltersDropdownContent = ({ <ObjectFilterDropdownFilterSelect /> ) : isObjectFilterDropdownOperandSelectUnfolded ? ( <ObjectFilterDropdownOperandSelect /> + ) : isEmptyOperand ? ( + <ObjectFilterDropdownOperandButton /> ) : ( selectedOperandInDropdown && ( <> diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownDateInput.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownDateInput.tsx index 11c9f1ab2820..741b448ab07c 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownDateInput.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownDateInput.tsx @@ -1,13 +1,18 @@ import { useRecoilValue } from 'recoil'; +import { v4 } from 'uuid'; import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown'; import { InternalDatePicker } from '@/ui/input/components/internal/date/components/InternalDatePicker'; +import { useState } from 'react'; import { isDefined } from '~/utils/isDefined'; export const ObjectFilterDropdownDateInput = () => { + const [internalDate, setInternalDate] = useState<Date | null>(new Date()); + const { filterDefinitionUsedInDropdownState, selectedOperandInDropdownState, + selectedFilterState, setIsObjectFilterDropdownUnfolded, selectFilter, } = useFilterDropdown(); @@ -19,10 +24,14 @@ export const ObjectFilterDropdownDateInput = () => { selectedOperandInDropdownState, ); + const selectedFilter = useRecoilValue(selectedFilterState); + const handleChange = (date: Date | null) => { - if (!filterDefinitionUsedInDropdown || !selectedOperandInDropdown) return; + setInternalDate(date); + if (!filterDefinitionUsedInDropdown || !selectedOperandInDropdown) return; selectFilter?.({ + id: selectedFilter?.id ? selectedFilter.id : v4(), fieldMetadataId: filterDefinitionUsedInDropdown.fieldMetadataId, value: isDefined(date) ? date.toISOString() : '', operand: selectedOperandInDropdown, @@ -35,7 +44,7 @@ export const ObjectFilterDropdownDateInput = () => { return ( <InternalDatePicker - date={new Date()} + date={internalDate} onChange={handleChange} onMouseSelect={handleChange} /> diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownEntitySearchSelect.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownEntitySearchSelect.tsx deleted file mode 100644 index 27b155975058..000000000000 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownEntitySearchSelect.tsx +++ /dev/null @@ -1,127 +0,0 @@ -import { useEffect, useState } from 'react'; -import { useRecoilValue } from 'recoil'; - -import { OBJECT_FILTER_DROPDOWN_ID } from '@/object-record/object-filter-dropdown/constants/ObjectFilterDropdownId'; -import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown'; -import { SingleEntitySelectMenuItems } from '@/object-record/relation-picker/components/SingleEntitySelectMenuItems'; -import { EntitiesForMultipleEntitySelect } from '@/object-record/relation-picker/types/EntitiesForMultipleEntitySelect'; -import { EntityForSelect } from '@/object-record/relation-picker/types/EntityForSelect'; -import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown'; -import { ViewFilterOperand } from '@/views/types/ViewFilterOperand'; - -export const ObjectFilterDropdownEntitySearchSelect = ({ - entitiesForSelect, -}: { - entitiesForSelect: EntitiesForMultipleEntitySelect<EntityForSelect>; -}) => { - const { - setObjectFilterDropdownSelectedEntityId, - filterDefinitionUsedInDropdownState, - selectedOperandInDropdownState, - objectFilterDropdownSearchInputState, - selectedFilterState, - selectFilter, - } = useFilterDropdown(); - - const filterDefinitionUsedInDropdown = useRecoilValue( - filterDefinitionUsedInDropdownState, - ); - const selectedOperandInDropdown = useRecoilValue( - selectedOperandInDropdownState, - ); - const objectFilterDropdownSearchInput = useRecoilValue( - objectFilterDropdownSearchInputState, - ); - const selectedFilter = useRecoilValue(selectedFilterState); - - const { closeDropdown } = useDropdown(OBJECT_FILTER_DROPDOWN_ID); - - const [isAllEntitySelected, setIsAllEntitySelected] = useState(false); - - const handleRecordSelected = ( - selectedEntity: EntityForSelect | null | undefined, - ) => { - if ( - !filterDefinitionUsedInDropdown || - !selectedOperandInDropdown || - !selectedEntity - ) { - return; - } - - if (isAllEntitySelected) { - setIsAllEntitySelected(false); - } - - setObjectFilterDropdownSelectedEntityId(selectedEntity.id); - - selectFilter?.({ - displayValue: selectedEntity.name, - fieldMetadataId: filterDefinitionUsedInDropdown.fieldMetadataId, - operand: selectedOperandInDropdown, - value: selectedEntity.id, - displayAvatarUrl: selectedEntity.avatarUrl, - definition: filterDefinitionUsedInDropdown, - }); - closeDropdown(); - }; - - const isAllEntitySelectShown = - !!filterDefinitionUsedInDropdown?.selectAllLabel && - !!filterDefinitionUsedInDropdown?.SelectAllIcon && - (isAllEntitySelected || - filterDefinitionUsedInDropdown?.selectAllLabel - .toLocaleLowerCase() - .includes(objectFilterDropdownSearchInput.toLocaleLowerCase())); - - const handleAllEntitySelectClick = () => { - if ( - !filterDefinitionUsedInDropdown || - !selectedOperandInDropdown || - !filterDefinitionUsedInDropdown.selectAllLabel - ) { - return; - } - - setIsAllEntitySelected(true); - setObjectFilterDropdownSelectedEntityId(null); - closeDropdown(); - - selectFilter?.({ - displayValue: filterDefinitionUsedInDropdown.selectAllLabel, - fieldMetadataId: filterDefinitionUsedInDropdown.fieldMetadataId, - operand: ViewFilterOperand.IsNotNull, - value: '', - definition: filterDefinitionUsedInDropdown, - }); - }; - - useEffect(() => { - if (!selectedFilter) { - setObjectFilterDropdownSelectedEntityId(null); - } else { - setObjectFilterDropdownSelectedEntityId(selectedFilter.value); - setIsAllEntitySelected( - selectedFilter.operand === ViewFilterOperand.IsNotNull, - ); - } - }, [ - selectedFilter, - setObjectFilterDropdownSelectedEntityId, - entitiesForSelect.selectedEntities, - ]); - - return ( - <SingleEntitySelectMenuItems - entitiesToSelect={entitiesForSelect.entitiesToSelect} - selectedEntity={entitiesForSelect.selectedEntities[0]} - loading={entitiesForSelect.loading} - onEntitySelected={handleRecordSelected} - SelectAllIcon={filterDefinitionUsedInDropdown?.SelectAllIcon} - selectAllLabel={filterDefinitionUsedInDropdown?.selectAllLabel} - isAllEntitySelected={isAllEntitySelected} - isAllEntitySelectShown={isAllEntitySelectShown} - onAllEntitySelected={handleAllEntitySelectClick} - /> - ); -}; diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownNumberInput.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownNumberInput.tsx index d6cc92eaaf1f..b0ad3cc85386 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownNumberInput.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownNumberInput.tsx @@ -1,5 +1,6 @@ import { ChangeEvent } from 'react'; import { useRecoilValue } from 'recoil'; +import { v4 } from 'uuid'; import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown'; import { DropdownMenuInput } from '@/ui/layout/dropdown/components/DropdownMenuInput'; @@ -8,6 +9,7 @@ export const ObjectFilterDropdownNumberInput = () => { const { selectedOperandInDropdownState, filterDefinitionUsedInDropdownState, + selectedFilterState, selectFilter, } = useFilterDropdown(); @@ -18,6 +20,8 @@ export const ObjectFilterDropdownNumberInput = () => { selectedOperandInDropdownState, ); + const selectedFilter = useRecoilValue(selectedFilterState); + return ( filterDefinitionUsedInDropdown && selectedOperandInDropdown && ( @@ -27,6 +31,7 @@ export const ObjectFilterDropdownNumberInput = () => { placeholder={filterDefinitionUsedInDropdown.label} onChange={(event: ChangeEvent<HTMLInputElement>) => { selectFilter?.({ + id: selectedFilter?.id ? selectedFilter.id : v4(), fieldMetadataId: filterDefinitionUsedInDropdown.fieldMetadataId, value: event.target.value, operand: selectedOperandInDropdown, diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownOperandSelect.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownOperandSelect.tsx index d3f0ccccfd6a..5f500b916461 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownOperandSelect.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownOperandSelect.tsx @@ -1,6 +1,8 @@ import { useRecoilValue } from 'recoil'; +import { v4 } from 'uuid'; import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown'; +import { FilterDefinition } from '@/object-record/object-filter-dropdown/types/FilterDefinition'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem'; import { ViewFilterOperand } from '@/views/types/ViewFilterOperand'; @@ -33,15 +35,33 @@ export const ObjectFilterDropdownOperandSelect = () => { filterDefinitionUsedInDropdown?.type, ); - const handleOperangeChange = (newOperand: ViewFilterOperand) => { + const handleOperandChange = (newOperand: ViewFilterOperand) => { + const isEmptyOperand = [ + ViewFilterOperand.IsEmpty, + ViewFilterOperand.IsNotEmpty, + ].includes(newOperand); + setSelectedOperandInDropdown(newOperand); setIsObjectFilterDropdownOperandSelectUnfolded(false); + if (isEmptyOperand) { + selectFilter?.({ + id: v4(), + fieldMetadataId: filterDefinitionUsedInDropdown?.fieldMetadataId ?? '', + displayValue: '', + operand: newOperand, + value: '', + definition: filterDefinitionUsedInDropdown as FilterDefinition, + }); + return; + } + if ( isDefined(filterDefinitionUsedInDropdown) && isDefined(selectedFilter) ) { selectFilter?.({ + id: selectedFilter.id ? selectedFilter.id : v4(), fieldMetadataId: selectedFilter.fieldMetadataId, displayValue: selectedFilter.displayValue, operand: newOperand, @@ -61,7 +81,7 @@ export const ObjectFilterDropdownOperandSelect = () => { <MenuItem key={`select-filter-operand-${index}`} onClick={() => { - handleOperangeChange(filterOperand); + handleOperandChange(filterOperand); }} text={getOperandLabel(filterOperand)} /> diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownOptionSelect.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownOptionSelect.tsx index 46b294b1ebd8..6180ff3d3ce7 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownOptionSelect.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownOptionSelect.tsx @@ -1,5 +1,6 @@ import { useEffect, useState } from 'react'; import { useRecoilValue } from 'recoil'; +import { v4 } from 'uuid'; import { FieldMetadataItemOption } from '@/object-metadata/types/FieldMetadataItem'; import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown'; @@ -22,6 +23,7 @@ export const ObjectFilterDropdownOptionSelect = () => { objectFilterDropdownSearchInputState, selectedOperandInDropdownState, objectFilterDropdownSelectedOptionValuesState, + selectedFilterState, selectFilter, } = useFilterDropdown(); @@ -38,6 +40,8 @@ export const ObjectFilterDropdownOptionSelect = () => { objectFilterDropdownSelectedOptionValuesState, ); + const selectedFilter = useRecoilValue(selectedFilterState); + const fieldMetaDataId = filterDefinitionUsedInDropdown?.fieldMetadataId ?? ''; const { selectOptions } = useOptionsForSelect(fieldMetaDataId); @@ -96,6 +100,7 @@ export const ObjectFilterDropdownOptionSelect = () => { : EMPTY_FILTER_VALUE; selectFilter({ + id: selectedFilter?.id ? selectedFilter.id : v4(), definition: filterDefinitionUsedInDropdown, operand: selectedOperandInDropdown, displayValue: filterDisplayValue, diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownRecordSelect.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownRecordSelect.tsx index 65a2c3263dc3..a5cf8185455d 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownRecordSelect.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownRecordSelect.tsx @@ -1,25 +1,39 @@ +import { useState } from 'react'; import { useRecoilValue } from 'recoil'; +import { v4 } from 'uuid'; import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown'; import { MultipleRecordSelectDropdown } from '@/object-record/select/components/MultipleRecordSelectDropdown'; import { useRecordsForSelect } from '@/object-record/select/hooks/useRecordsForSelect'; import { SelectableRecord } from '@/object-record/select/types/SelectableRecord'; +import { useCombinedViewFilters } from '@/views/hooks/useCombinedViewFilters'; +import { useGetCurrentView } from '@/views/hooks/useGetCurrentView'; import { isDefined } from '~/utils/isDefined'; export const EMPTY_FILTER_VALUE = '[]'; export const MAX_RECORDS_TO_DISPLAY = 3; -export const ObjectFilterDropdownRecordSelect = () => { +type ObjectFilterDropdownRecordSelectProps = { + viewComponentId?: string; +}; +export const ObjectFilterDropdownRecordSelect = ({ + viewComponentId, +}: ObjectFilterDropdownRecordSelectProps) => { const { filterDefinitionUsedInDropdownState, objectFilterDropdownSearchInputState, selectedOperandInDropdownState, + selectedFilterState, setObjectFilterDropdownSelectedRecordIds, objectFilterDropdownSelectedRecordIdsState, selectFilter, emptyFilterButKeepDefinition, } = useFilterDropdown(); + const { removeCombinedViewFilter } = useCombinedViewFilters(viewComponentId); + const { currentViewWithCombinedFiltersAndSorts } = + useGetCurrentView(viewComponentId); + const filterDefinitionUsedInDropdown = useRecoilValue( filterDefinitionUsedInDropdownState, ); @@ -32,6 +46,9 @@ export const ObjectFilterDropdownRecordSelect = () => { const objectFilterDropdownSelectedRecordIds = useRecoilValue( objectFilterDropdownSelectedRecordIdsState, ); + const [fieldId] = useState(v4()); + + const selectedFilter = useRecoilValue(selectedFilterState); const objectNameSingular = filterDefinitionUsedInDropdown?.relationObjectMetadataNameSingular ?? ''; @@ -60,6 +77,7 @@ export const ObjectFilterDropdownRecordSelect = () => { if (newSelectedRecordIds.length === 0) { emptyFilterButKeepDefinition(); + removeCombinedViewFilter(fieldId); return; } @@ -91,7 +109,17 @@ export const ObjectFilterDropdownRecordSelect = () => { ? JSON.stringify(newSelectedRecordIds) : EMPTY_FILTER_VALUE; + const viewFilter = + currentViewWithCombinedFiltersAndSorts?.viewFilters.find( + (viewFilter) => + viewFilter.fieldMetadataId === + filterDefinitionUsedInDropdown.fieldMetadataId, + ); + + const filterId = viewFilter?.id ?? fieldId; + selectFilter({ + id: selectedFilter?.id ? selectedFilter.id : filterId, definition: filterDefinitionUsedInDropdown, operand: selectedOperandInDropdown, displayValue: filterDisplayValue, diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownTextSearchInput.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownTextSearchInput.tsx index 445d080ad699..f2e1bbeb9ce7 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownTextSearchInput.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownTextSearchInput.tsx @@ -1,5 +1,6 @@ -import { ChangeEvent } from 'react'; +import { ChangeEvent, useState } from 'react'; import { useRecoilValue } from 'recoil'; +import { v4 } from 'uuid'; import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown'; import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput'; @@ -14,6 +15,8 @@ export const ObjectFilterDropdownTextSearchInput = () => { selectFilter, } = useFilterDropdown(); + const [filterId] = useState(v4()); + const filterDefinitionUsedInDropdown = useRecoilValue( filterDefinitionUsedInDropdownState, ); @@ -37,6 +40,7 @@ export const ObjectFilterDropdownTextSearchInput = () => { setObjectFilterDropdownSearchInput(event.target.value); selectFilter?.({ + id: selectedFilter?.id ? selectedFilter.id : filterId, fieldMetadataId: filterDefinitionUsedInDropdown.fieldMetadataId, value: event.target.value, operand: selectedOperandInDropdown, diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/SingleEntityObjectFilterDropdownButton.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/SingleEntityObjectFilterDropdownButton.tsx index 7ddbdb5f5d59..5f57a990d365 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/SingleEntityObjectFilterDropdownButton.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/SingleEntityObjectFilterDropdownButton.tsx @@ -17,6 +17,8 @@ import { GenericEntityFilterChip } from './GenericEntityFilterChip'; import { ObjectFilterDropdownRecordSelect } from './ObjectFilterDropdownRecordSelect'; import { ObjectFilterDropdownSearchInput } from './ObjectFilterDropdownSearchInput'; +const SINGLE_ENTITY_FILTER_DROPDOWN_ID = 'single-entity-filter-dropdown'; + export const SingleEntityObjectFilterDropdownButton = ({ hotkeyScope, }: { @@ -50,7 +52,7 @@ export const SingleEntityObjectFilterDropdownButton = ({ return ( <Dropdown - dropdownId="single-entity-filter-dropdown" + dropdownId={SINGLE_ENTITY_FILTER_DROPDOWN_ID} dropdownHotkeyScope={hotkeyScope} dropdownOffset={{ x: 0, y: -28 }} clickableComponent={ @@ -75,7 +77,9 @@ export const SingleEntityObjectFilterDropdownButton = ({ <ObjectFilterDropdownSearchInput /> <DropdownMenuSeparator /> <ObjectFilterDropdownRecordRemoveFilterMenuItem /> - <ObjectFilterDropdownRecordSelect /> + <ObjectFilterDropdownRecordSelect + viewComponentId={SINGLE_ENTITY_FILTER_DROPDOWN_ID} + /> </> } /> diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/__tests__/useFilterDropdown.test.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/__tests__/useFilterDropdown.test.tsx index 311764d5892a..d6757cd310c4 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/__tests__/useFilterDropdown.test.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/__tests__/useFilterDropdown.test.tsx @@ -23,6 +23,7 @@ const filterDefinitions: FilterDefinition[] = [ ]; const mockFilter: Filter = { + id: 'id', definition: filterDefinitions[0], displayValue: '', fieldMetadataId: '', diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/types/Filter.ts b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/types/Filter.ts index bb72dfd46ae1..862e99bed5f4 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/types/Filter.ts +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/types/Filter.ts @@ -3,6 +3,7 @@ import { ViewFilterOperand } from '@/views/types/ViewFilterOperand'; import { FilterDefinition } from './FilterDefinition'; export type Filter = { + id: string; fieldMetadataId: string; value: string; displayValue: string; diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/__tests__/getOperandsForFilterType.test.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/__tests__/getOperandsForFilterType.test.tsx index 1644d9472545..d5eded8bf666 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/__tests__/getOperandsForFilterType.test.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/__tests__/getOperandsForFilterType.test.tsx @@ -4,20 +4,34 @@ import { ViewFilterOperand } from '@/views/types/ViewFilterOperand'; import { getOperandsForFilterType } from '../getOperandsForFilterType'; describe('getOperandsForFilterType', () => { + const emptyOperands = [ + ViewFilterOperand.IsEmpty, + ViewFilterOperand.IsNotEmpty, + ]; + + const containsOperands = [ + ViewFilterOperand.Contains, + ViewFilterOperand.DoesNotContain, + ]; + + const numberOperands = [ + ViewFilterOperand.GreaterThan, + ViewFilterOperand.LessThan, + ]; + + const relationOperand = [ViewFilterOperand.Is, ViewFilterOperand.IsNot]; + const testCases = [ - ['TEXT', [ViewFilterOperand.Contains, ViewFilterOperand.DoesNotContain]], - ['EMAIL', [ViewFilterOperand.Contains, ViewFilterOperand.DoesNotContain]], - [ - 'FULL_NAME', - [ViewFilterOperand.Contains, ViewFilterOperand.DoesNotContain], - ], - ['ADDRESS', [ViewFilterOperand.Contains, ViewFilterOperand.DoesNotContain]], - ['LINK', [ViewFilterOperand.Contains, ViewFilterOperand.DoesNotContain]], - ['LINKS', [ViewFilterOperand.Contains, ViewFilterOperand.DoesNotContain]], - ['CURRENCY', [ViewFilterOperand.GreaterThan, ViewFilterOperand.LessThan]], - ['NUMBER', [ViewFilterOperand.GreaterThan, ViewFilterOperand.LessThan]], - ['DATE_TIME', [ViewFilterOperand.GreaterThan, ViewFilterOperand.LessThan]], - ['RELATION', [ViewFilterOperand.Is, ViewFilterOperand.IsNot]], + ['TEXT', [...containsOperands, ...emptyOperands]], + ['EMAIL', [...containsOperands, ...emptyOperands]], + ['FULL_NAME', [...containsOperands, ...emptyOperands]], + ['ADDRESS', [...containsOperands, ...emptyOperands]], + ['LINK', [...containsOperands, ...emptyOperands]], + ['LINKS', [...containsOperands, ...emptyOperands]], + ['CURRENCY', [...numberOperands, ...emptyOperands]], + ['NUMBER', [...numberOperands, ...emptyOperands]], + ['DATE_TIME', [...numberOperands, ...emptyOperands]], + ['RELATION', [...relationOperand, ...emptyOperands]], [undefined, []], [null, []], ['UNKNOWN_TYPE', []], diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/getOperandLabel.ts b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/getOperandLabel.ts index a58bc9db53c8..9c9e297ef960 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/getOperandLabel.ts +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/getOperandLabel.ts @@ -18,6 +18,10 @@ export const getOperandLabel = ( return 'Is not'; case ViewFilterOperand.IsNotNull: return 'Is not null'; + case ViewFilterOperand.IsEmpty: + return 'Is empty'; + case ViewFilterOperand.IsNotEmpty: + return 'Is not empty'; default: return ''; } @@ -35,6 +39,10 @@ export const getOperandLabelShort = ( return ': Not'; case ViewFilterOperand.IsNotNull: return ': NotNull'; + case ViewFilterOperand.IsNotEmpty: + return ': NotEmpty'; + case ViewFilterOperand.IsEmpty: + return ': Empty'; case ViewFilterOperand.GreaterThan: return '\u00A0> '; case ViewFilterOperand.LessThan: diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/getOperandsForFilterType.ts b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/getOperandsForFilterType.ts index 147e6ee9ecd5..7f189009b41a 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/getOperandsForFilterType.ts +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/getOperandsForFilterType.ts @@ -5,6 +5,13 @@ import { FilterType } from '../types/FilterType'; export const getOperandsForFilterType = ( filterType: FilterType | null | undefined, ): ViewFilterOperand[] => { + const emptyOperands = [ + ViewFilterOperand.IsEmpty, + ViewFilterOperand.IsNotEmpty, + ]; + + const relationOperands = [ViewFilterOperand.Is, ViewFilterOperand.IsNot]; + switch (filterType) { case 'TEXT': case 'EMAIL': @@ -12,17 +19,25 @@ export const getOperandsForFilterType = ( case 'ADDRESS': case 'PHONE': case 'LINK': - return [ViewFilterOperand.Contains, ViewFilterOperand.DoesNotContain]; case 'LINKS': - return [ViewFilterOperand.Contains, ViewFilterOperand.DoesNotContain]; + return [ + ViewFilterOperand.Contains, + ViewFilterOperand.DoesNotContain, + ...emptyOperands, + ]; case 'CURRENCY': case 'NUMBER': case 'DATE_TIME': case 'DATE': - return [ViewFilterOperand.GreaterThan, ViewFilterOperand.LessThan]; + return [ + ViewFilterOperand.GreaterThan, + ViewFilterOperand.LessThan, + ...emptyOperands, + ]; case 'RELATION': + return [...relationOperands, ...emptyOperands]; case 'SELECT': - return [ViewFilterOperand.Is, ViewFilterOperand.IsNot]; + return [...relationOperands]; default: return []; } diff --git a/packages/twenty-front/src/modules/object-record/object-sort-dropdown/utils/__tests__/turnSortsIntoOrderBy.test.tsx b/packages/twenty-front/src/modules/object-record/object-sort-dropdown/utils/__tests__/turnSortsIntoOrderBy.test.tsx index 0abde78e58e3..8534f11cabc3 100644 --- a/packages/twenty-front/src/modules/object-record/object-sort-dropdown/utils/__tests__/turnSortsIntoOrderBy.test.tsx +++ b/packages/twenty-front/src/modules/object-record/object-sort-dropdown/utils/__tests__/turnSortsIntoOrderBy.test.tsx @@ -30,9 +30,11 @@ describe('turnSortsIntoOrderBy', () => { it('should sort by recordPosition if no sorts', () => { const fields = [{ id: 'field1', name: 'createdAt' }] as FieldMetadataItem[]; expect(turnSortsIntoOrderBy({ ...objectMetadataItem, fields }, [])).toEqual( - { - position: 'AscNullsFirst', - }, + [ + { + position: 'AscNullsFirst', + }, + ], ); }); @@ -47,10 +49,7 @@ describe('turnSortsIntoOrderBy', () => { const fields = [{ id: 'field1', name: 'field1' }] as FieldMetadataItem[]; expect( turnSortsIntoOrderBy({ ...objectMetadataItem, fields }, sorts), - ).toEqual({ - field1: 'AscNullsFirst', - position: 'AscNullsFirst', - }); + ).toEqual([{ field1: 'AscNullsFirst' }, { position: 'AscNullsFirst' }]); }); it('should create OrderByField with multiple sorts', () => { @@ -72,11 +71,11 @@ describe('turnSortsIntoOrderBy', () => { ] as FieldMetadataItem[]; expect( turnSortsIntoOrderBy({ ...objectMetadataItem, fields }, sorts), - ).toEqual({ - field1: 'AscNullsFirst', - field2: 'DescNullsLast', - position: 'AscNullsFirst', - }); + ).toEqual([ + { field1: 'AscNullsFirst' }, + { field2: 'DescNullsLast' }, + { position: 'AscNullsFirst' }, + ]); }); it('should ignore if field not found', () => { @@ -87,9 +86,9 @@ describe('turnSortsIntoOrderBy', () => { definition: sortDefinition, }, ]; - expect(turnSortsIntoOrderBy(objectMetadataItem, sorts)).toEqual({ - position: 'AscNullsFirst', - }); + expect(turnSortsIntoOrderBy(objectMetadataItem, sorts)).toEqual([ + { position: 'AscNullsFirst' }, + ]); }); it('should not return position for remotes', () => { @@ -102,6 +101,6 @@ describe('turnSortsIntoOrderBy', () => { ]; expect( turnSortsIntoOrderBy({ ...objectMetadataItem, isRemote: true }, sorts), - ).toEqual({}); + ).toEqual([]); }); }); diff --git a/packages/twenty-front/src/modules/object-record/object-sort-dropdown/utils/turnSortsIntoOrderBy.ts b/packages/twenty-front/src/modules/object-record/object-sort-dropdown/utils/turnSortsIntoOrderBy.ts index b30f245707f6..04e877109434 100644 --- a/packages/twenty-front/src/modules/object-record/object-sort-dropdown/utils/turnSortsIntoOrderBy.ts +++ b/packages/twenty-front/src/modules/object-record/object-sort-dropdown/utils/turnSortsIntoOrderBy.ts @@ -2,7 +2,7 @@ import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { OrderBy } from '@/object-metadata/types/OrderBy'; import { hasPositionField } from '@/object-metadata/utils/hasPositionField'; import { RecordGqlOperationOrderBy } from '@/object-record/graphql/types/RecordGqlOperationOrderBy'; -import { Field } from '~/generated/graphql'; +import { Field, FieldMetadataType } from '~/generated/graphql'; import { mapArrayToObject } from '~/utils/array/mapArrayToObject'; import { isDefined } from '~/utils/isDefined'; import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull'; @@ -13,31 +13,45 @@ export const turnSortsIntoOrderBy = ( objectMetadataItem: ObjectMetadataItem, sorts: Sort[], ): RecordGqlOperationOrderBy => { - const fields: Pick<Field, 'id' | 'name'>[] = objectMetadataItem?.fields ?? []; + const fields: Pick<Field, 'id' | 'name' | 'type'>[] = + objectMetadataItem?.fields ?? []; const fieldsById = mapArrayToObject(fields, ({ id }) => id); - const sortsOrderBy = Object.fromEntries( - sorts - .map((sort) => { - const correspondingField = fieldsById[sort.fieldMetadataId]; + const sortsOrderBy = sorts + .map((sort) => { + const correspondingField = fieldsById[sort.fieldMetadataId]; - if (isUndefinedOrNull(correspondingField)) { - return undefined; - } + if (isUndefinedOrNull(correspondingField)) { + return undefined; + } - const direction: OrderBy = - sort.direction === 'asc' ? 'AscNullsFirst' : 'DescNullsLast'; + const direction: OrderBy = + sort.direction === 'asc' ? 'AscNullsFirst' : 'DescNullsLast'; - return [correspondingField.name, direction]; - }) - .filter(isDefined), - ); + return getOrderByForFieldMetadataType(correspondingField, direction); + }) + .filter(isDefined); if (hasPositionField(objectMetadataItem)) { - return { - ...sortsOrderBy, - position: 'AscNullsFirst', - }; + return [...sortsOrderBy, { position: 'AscNullsFirst' }]; } return sortsOrderBy; }; + +const getOrderByForFieldMetadataType = ( + field: Pick<Field, 'id' | 'name' | 'type'>, + direction: OrderBy, +) => { + switch (field.type) { + case FieldMetadataType.FullName: + return { + [field.name]: { + firstName: direction, + lastName: direction, + }, + }; + + default: + return { [field.name]: direction }; + } +}; diff --git a/packages/twenty-front/src/modules/object-record/record-action-bar/hooks/useRecordActionBar.tsx b/packages/twenty-front/src/modules/object-record/record-action-bar/hooks/useRecordActionBar.tsx index 3333ead34719..490467dae757 100644 --- a/packages/twenty-front/src/modules/object-record/record-action-bar/hooks/useRecordActionBar.tsx +++ b/packages/twenty-front/src/modules/object-record/record-action-bar/hooks/useRecordActionBar.tsx @@ -1,5 +1,5 @@ -import { useCallback, useMemo, useState } from 'react'; import { isNonEmptyString } from '@sniptt/guards'; +import { useCallback, useMemo, useState } from 'react'; import { useRecoilCallback, useSetRecoilState } from 'recoil'; import { IconClick, @@ -13,8 +13,9 @@ import { import { useFavorites } from '@/favorites/hooks/useFavorites'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; -import { useDeleteManyRecords } from '@/object-record/hooks/useDeleteManyRecords'; +import { DELETE_MAX_COUNT } from '@/object-record/constants/DeleteMaxCount'; import { useExecuteQuickActionOnOneRecord } from '@/object-record/hooks/useExecuteQuickActionOnOneRecord'; +import { useDeleteTableData } from '@/object-record/record-index/options/hooks/useDeleteTableData'; import { displayedExportProgress, useExportTableData, @@ -31,12 +32,14 @@ type useRecordActionBarProps = { objectMetadataItem: ObjectMetadataItem; selectedRecordIds: string[]; callback?: () => void; + totalNumberOfRecordsSelected?: number; }; export const useRecordActionBar = ({ objectMetadataItem, selectedRecordIds, callback, + totalNumberOfRecordsSelected, }: useRecordActionBarProps) => { const setContextMenuEntries = useSetRecoilState(contextMenuEntriesState); const setActionBarEntriesState = useSetRecoilState(actionBarEntriesState); @@ -45,10 +48,6 @@ export const useRecordActionBar = ({ const { createFavorite, favorites, deleteFavorite } = useFavorites(); - const { deleteManyRecords } = useDeleteManyRecords({ - objectNameSingular: objectMetadataItem.nameSingular, - }); - const { executeQuickActionOnOneRecord } = useExecuteQuickActionOnOneRecord({ objectNameSingular: objectMetadataItem.nameSingular, }); @@ -88,24 +87,17 @@ export const useRecordActionBar = ({ ], ); - const handleDeleteClick = useCallback(async () => { - callback?.(); - selectedRecordIds.forEach((recordId) => { - const foundFavorite = favorites?.find( - (favorite) => favorite.recordId === recordId, - ); - if (foundFavorite !== undefined) { - deleteFavorite(foundFavorite.id); - } - }); - await deleteManyRecords(selectedRecordIds); - }, [ - callback, - deleteManyRecords, - selectedRecordIds, - favorites, - deleteFavorite, - ]); + const baseTableDataParams = { + delayMs: 100, + objectNameSingular: objectMetadataItem.nameSingular, + recordIndexId: objectMetadataItem.namePlural, + }; + + const { deleteTableData } = useDeleteTableData(baseTableDataParams); + + const handleDeleteClick = useCallback(() => { + deleteTableData(); + }, [deleteTableData]); const handleExecuteQuickActionOnClick = useCallback(async () => { callback?.(); @@ -117,56 +109,63 @@ export const useRecordActionBar = ({ }, [callback, executeQuickActionOnOneRecord, selectedRecordIds]); const { progress, download } = useExportTableData({ - delayMs: 100, + ...baseTableDataParams, filename: `${objectMetadataItem.nameSingular}.csv`, - objectNameSingular: objectMetadataItem.nameSingular, - recordIndexId: objectMetadataItem.namePlural, }); const isRemoteObject = objectMetadataItem.isRemote; - const baseActions: ContextMenuEntry[] = useMemo( - () => [ - { - label: displayedExportProgress(progress), - Icon: IconFileExport, - accent: 'default', - onClick: () => download(), - }, - ], - [download, progress], - ); - - const deletionActions: ContextMenuEntry[] = useMemo( - () => [ - { - label: 'Delete', - Icon: IconTrash, - accent: 'danger', - onClick: () => setIsDeleteRecordsModalOpen(true), - ConfirmationModal: ( - <ConfirmationModal - isOpen={isDeleteRecordsModalOpen} - setIsOpen={setIsDeleteRecordsModalOpen} - title={`Delete ${selectedRecordIds.length} ${ - selectedRecordIds.length === 1 ? `record` : 'records' - }`} - subtitle={`This action cannot be undone. This will permanently delete ${ - selectedRecordIds.length === 1 ? 'this record' : 'these records' - }`} - onConfirmClick={() => handleDeleteClick()} - deleteButtonText={`Delete ${ - selectedRecordIds.length > 1 ? 'Records' : 'Record' - }`} - /> - ), - }, - ], + const numberOfSelectedRecords = + totalNumberOfRecordsSelected ?? selectedRecordIds.length; + const canDelete = + !isRemoteObject && numberOfSelectedRecords < DELETE_MAX_COUNT; + + const menuActions: ContextMenuEntry[] = useMemo( + () => + [ + { + label: displayedExportProgress(progress), + Icon: IconFileExport, + accent: 'default', + onClick: () => download(), + } satisfies ContextMenuEntry, + canDelete + ? ({ + label: 'Delete', + Icon: IconTrash, + accent: 'danger', + onClick: () => { + setIsDeleteRecordsModalOpen(true); + handleDeleteClick(); + }, + ConfirmationModal: ( + <ConfirmationModal + isOpen={isDeleteRecordsModalOpen} + setIsOpen={setIsDeleteRecordsModalOpen} + title={`Delete ${numberOfSelectedRecords} ${ + numberOfSelectedRecords === 1 ? `record` : 'records' + }`} + subtitle={`This action cannot be undone. This will permanently delete ${ + numberOfSelectedRecords === 1 + ? 'this record' + : 'these records' + }`} + onConfirmClick={() => handleDeleteClick()} + deleteButtonText={`Delete ${ + numberOfSelectedRecords > 1 ? 'Records' : 'Record' + }`} + /> + ), + } satisfies ContextMenuEntry) + : undefined, + ].filter(isDefined), [ + download, + progress, + canDelete, handleDeleteClick, - selectedRecordIds, isDeleteRecordsModalOpen, - setIsDeleteRecordsModalOpen, + numberOfSelectedRecords, ], ); @@ -183,8 +182,7 @@ export const useRecordActionBar = ({ return { setContextMenuEntries: useCallback(() => { setContextMenuEntries([ - ...(isRemoteObject ? [] : deletionActions), - ...baseActions, + ...menuActions, ...(!isRemoteObject && isFavorite && hasOnlyOneRecordSelected ? [ { @@ -205,8 +203,7 @@ export const useRecordActionBar = ({ : []), ]); }, [ - baseActions, - deletionActions, + menuActions, handleFavoriteButtonClick, hasOnlyOneRecordSelected, isFavorite, @@ -235,15 +232,12 @@ export const useRecordActionBar = ({ }, ] : []), - ...(isRemoteObject ? [] : deletionActions), - ...baseActions, + ...menuActions, ]); }, [ - baseActions, + menuActions, dataExecuteQuickActionOnmentEnabled, - deletionActions, handleExecuteQuickActionOnClick, - isRemoteObject, setActionBarEntriesState, ]), }; diff --git a/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoard.tsx b/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoard.tsx index 23aa8612882b..d6ffe57f2e22 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoard.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoard.tsx @@ -1,6 +1,6 @@ -import { useContext, useRef } from 'react'; import styled from '@emotion/styled'; import { DragDropContext, OnDragEndResponder } from '@hello-pangea/dnd'; // Atlassian dnd does not support StrictMode from RN 18, so we use a fork @hello-pangea/dnd https://github.com/atlassian/react-beautiful-dnd/issues/2350 +import { useContext, useRef } from 'react'; import { useRecoilCallback, useRecoilValue } from 'recoil'; import { Key } from 'ts-key-enum'; diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCard.tsx b/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCard.tsx index 9b695a3f3c83..a551db4cb58f 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCard.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCard.tsx @@ -1,10 +1,9 @@ +import styled from '@emotion/styled'; import { ReactNode, useContext, useState } from 'react'; import { useInView } from 'react-intersection-observer'; -import styled from '@emotion/styled'; import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil'; -import { EntityChipVariant, IconEye } from 'twenty-ui'; +import { AvatarChipVariant, IconEye } from 'twenty-ui'; -import { RecordChip } from '@/object-record/components/RecordChip'; import { RecordBoardContext } from '@/object-record/record-board/contexts/RecordBoardContext'; import { useRecordBoardStates } from '@/object-record/record-board/hooks/internal/useRecordBoardStates'; import { RecordBoardCardContext } from '@/object-record/record-board/record-board-card/contexts/RecordBoardCardContext'; @@ -14,6 +13,7 @@ import { RecordUpdateHookParams, } from '@/object-record/record-field/contexts/FieldContext'; import { getFieldButtonIcon } from '@/object-record/record-field/utils/getFieldButtonIcon'; +import { RecordIndexRecordChip } from '@/object-record/record-index/components/RecordIndexRecordChip'; import { RecordInlineCell } from '@/object-record/record-inline-cell/components/RecordInlineCell'; import { InlineCellHotkeyScope } from '@/object-record/record-inline-cell/types/InlineCellHotkeyScope'; import { RecordValueSetterEffect } from '@/object-record/record-store/components/RecordValueSetterEffect'; @@ -66,7 +66,7 @@ const StyledBoardCardWrapper = styled.div` width: 100%; `; -const StyledBoardCardHeader = styled.div<{ +export const StyledBoardCardHeader = styled.div<{ showCompactView: boolean; }>` align-items: center; @@ -89,7 +89,7 @@ const StyledBoardCardHeader = styled.div<{ } `; -const StyledBoardCardBody = styled.div` +export const StyledBoardCardBody = styled.div` display: flex; flex-direction: column; gap: ${({ theme }) => theme.spacing(0.5)}; @@ -117,6 +117,7 @@ const StyledFieldContainer = styled.div` display: flex; flex-direction: row; width: fit-content; + max-width: 100%; `; const StyledCompactIconContainer = styled.div` @@ -221,10 +222,10 @@ export const RecordBoardCard = () => { }} > <StyledBoardCardHeader showCompactView={isCompactModeActive}> - <RecordChip + <RecordIndexRecordChip objectNameSingular={objectMetadataItem.nameSingular} record={record} - variant={EntityChipVariant.Transparent} + variant={AvatarChipVariant.Transparent} /> {isCompactModeActive && ( <StyledCompactIconContainer className="compact-icon-container"> @@ -262,7 +263,7 @@ export const RecordBoardCard = () => { recoilScopeId: recordId + fieldDefinition.fieldMetadataId, isLabelIdentifier: false, fieldDefinition: { - disableTooltip: true, + disableTooltip: false, fieldMetadataId: fieldDefinition.fieldMetadataId, label: fieldDefinition.label, iconName: fieldDefinition.iconName, diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnCardContainerSkeletonLoader.tsx b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnCardContainerSkeletonLoader.tsx new file mode 100644 index 000000000000..4aeafd96f1fd --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnCardContainerSkeletonLoader.tsx @@ -0,0 +1,61 @@ +import Skeleton, { SkeletonTheme } from 'react-loading-skeleton'; +import { useTheme } from '@emotion/react'; +import styled from '@emotion/styled'; + +import { + StyledBoardCardBody, + StyledBoardCardHeader, +} from '@/object-record/record-board/record-board-card/components/RecordBoardCard'; + +const StyledSkeletonIconAndText = styled.div` + display: flex; + gap: ${({ theme }) => theme.spacing(1)}; +`; + +const StyledSkeletonTitle = styled.div` + padding-left: ${({ theme }) => theme.spacing(2)}; +`; + +const StyledSeparator = styled.div` + height: ${({ theme }) => theme.spacing(2)}; +`; + +export const RecordBoardColumnCardContainerSkeletonLoader = ({ + numberOfFields, + titleSkeletonWidth, + isCompactModeActive, +}: { + numberOfFields: number; + titleSkeletonWidth: number; + isCompactModeActive: boolean; +}) => { + const theme = useTheme(); + const skeletonItems = Array.from({ length: numberOfFields }).map( + (_, index) => ({ + id: `skeleton-item-${index}`, + }), + ); + return ( + <SkeletonTheme + baseColor={theme.background.tertiary} + highlightColor={theme.background.transparent.lighter} + borderRadius={4} + > + <StyledBoardCardHeader showCompactView={isCompactModeActive}> + <StyledSkeletonTitle> + <Skeleton width={titleSkeletonWidth} height={16} /> + </StyledSkeletonTitle> + </StyledBoardCardHeader> + <StyledSeparator /> + {!isCompactModeActive && + skeletonItems.map(({ id }) => ( + <StyledBoardCardBody key={id}> + <StyledSkeletonIconAndText> + <Skeleton width={16} height={16} /> + <Skeleton width={151} height={16} /> + </StyledSkeletonIconAndText> + </StyledBoardCardBody> + ))} + </SkeletonTheme> + ); +}; diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnCardsContainer.tsx b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnCardsContainer.tsx index 96d14a011bd4..79c786df1225 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnCardsContainer.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnCardsContainer.tsx @@ -1,14 +1,19 @@ import React, { useContext } from 'react'; import styled from '@emotion/styled'; import { Draggable, DroppableProvided } from '@hello-pangea/dnd'; +import { useRecoilValue } from 'recoil'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { RecordBoardContext } from '@/object-record/record-board/contexts/RecordBoardContext'; +import { useRecordBoardStates } from '@/object-record/record-board/hooks/internal/useRecordBoardStates'; +import { RecordBoardColumnCardContainerSkeletonLoader } from '@/object-record/record-board/record-board-column/components/RecordBoardColumnCardContainerSkeletonLoader'; import { RecordBoardColumnCardsMemo } from '@/object-record/record-board/record-board-column/components/RecordBoardColumnCardsMemo'; import { RecordBoardColumnFetchMoreLoader } from '@/object-record/record-board/record-board-column/components/RecordBoardColumnFetchMoreLoader'; import { RecordBoardColumnNewButton } from '@/object-record/record-board/record-board-column/components/RecordBoardColumnNewButton'; import { RecordBoardColumnNewOpportunityButton } from '@/object-record/record-board/record-board-column/components/RecordBoardColumnNewOpportunityButton'; import { RecordBoardColumnContext } from '@/object-record/record-board/record-board-column/contexts/RecordBoardColumnContext'; +import { getNumberOfCardsPerColumnForSkeletonLoading } from '@/object-record/record-board/record-board-column/utils/getNumberOfCardsPerColumnForSkeletonLoading'; +import { isRecordIndexBoardColumnLoadingFamilyState } from '@/object-record/states/isRecordBoardColumnLoadingFamilyState'; const StyledColumnCardsContainer = styled.div` display: flex; @@ -20,6 +25,17 @@ const StyledNewButtonContainer = styled.div` padding-bottom: ${({ theme }) => theme.spacing(4)}; `; +const StyledSkeletonCardContainer = styled.div` + background-color: ${({ theme }) => theme.background.secondary}; + border: 1px solid ${({ theme }) => theme.background.quaternary}; + border-radius: ${({ theme }) => theme.border.radius.md}; + box-shadow: + 0px 4px 8px 0px rgba(0, 0, 0, 0.08), + 0px 0px 4px 0px rgba(0, 0, 0, 0.08); + color: ${({ theme }) => theme.font.color.primary}; + margin-bottom: ${({ theme }) => theme.spacing(2)}; +`; + type RecordBoardColumnCardsContainerProps = { recordIds: string[]; droppableProvided: DroppableProvided; @@ -32,13 +48,51 @@ export const RecordBoardColumnCardsContainer = ({ const { columnDefinition } = useContext(RecordBoardColumnContext); const { objectMetadataItem } = useContext(RecordBoardContext); + const columnId = columnDefinition.id; + + const isRecordIndexBoardColumnLoading = useRecoilValue( + isRecordIndexBoardColumnLoadingFamilyState(columnId), + ); + + const { isCompactModeActiveState, visibleFieldDefinitionsState } = + useRecordBoardStates(); + + const visibleFieldDefinitions = useRecoilValue( + visibleFieldDefinitionsState(), + ); + + const numberOfFields = visibleFieldDefinitions.length; + + const isCompactModeActive = useRecoilValue(isCompactModeActiveState); + return ( <StyledColumnCardsContainer ref={droppableProvided?.innerRef} // eslint-disable-next-line react/jsx-props-no-spreading {...droppableProvided?.droppableProps} > - <RecordBoardColumnCardsMemo recordIds={recordIds} /> + {isRecordIndexBoardColumnLoading ? ( + Array.from( + { + length: getNumberOfCardsPerColumnForSkeletonLoading( + columnDefinition.position, + ), + }, + (_, index) => ( + <StyledSkeletonCardContainer + key={`${columnDefinition.id}-${index}`} + > + <RecordBoardColumnCardContainerSkeletonLoader + numberOfFields={numberOfFields} + titleSkeletonWidth={isCompactModeActive ? 72 : 54} + isCompactModeActive={isCompactModeActive} + /> + </StyledSkeletonCardContainer> + ), + ) + ) : ( + <RecordBoardColumnCardsMemo recordIds={recordIds} /> + )} <RecordBoardColumnFetchMoreLoader /> <Draggable draggableId={`new-${columnDefinition.id}`} diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnHeader.tsx b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnHeader.tsx index e4f59a85a238..a4c76e5bcfbd 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnHeader.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnHeader.tsx @@ -1,10 +1,11 @@ -import React, { useContext, useState } from 'react'; import styled from '@emotion/styled'; +import { useContext, useState } from 'react'; import { IconDotsVertical, Tag } from 'twenty-ui'; import { RecordBoardColumnDropdownMenu } from '@/object-record/record-board/record-board-column/components/RecordBoardColumnDropdownMenu'; import { RecordBoardColumnContext } from '@/object-record/record-board/record-board-column/contexts/RecordBoardColumnContext'; import { RecordBoardColumnHotkeyScope } from '@/object-record/record-board/types/BoardColumnHotkeyScope'; +import { RecordBoardColumnDefinitionType } from '@/object-record/record-board/types/RecordBoardColumnDefinition'; import { LightIconButton } from '@/ui/input/button/components/LightIconButton'; import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope'; @@ -79,14 +80,23 @@ export const RecordBoardColumnHeader = () => { > <Tag onClick={handleBoardColumnMenuOpen} - color={columnDefinition.color} + variant={ + columnDefinition.type === RecordBoardColumnDefinitionType.Value + ? 'solid' + : 'outline' + } + color={ + columnDefinition.type === RecordBoardColumnDefinitionType.Value + ? columnDefinition.color + : 'transparent' + } text={columnDefinition.title} /> {!!boardColumnTotal && <StyledAmount>${boardColumnTotal}</StyledAmount>} {!isHeaderHovered && ( <StyledNumChildren>{recordCount}</StyledNumChildren> )} - {isHeaderHovered && ( + {isHeaderHovered && columnDefinition.actions.length > 0 && ( <StyledHeaderActions> <LightIconButton accent="tertiary" @@ -96,7 +106,7 @@ export const RecordBoardColumnHeader = () => { </StyledHeaderActions> )} </StyledHeader> - {isBoardColumnMenuOpen && ( + {isBoardColumnMenuOpen && columnDefinition.actions.length > 0 && ( <RecordBoardColumnDropdownMenu onClose={handleBoardColumnMenuClose} stageId={columnDefinition.id} diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/utils/getNumberOfCardsPerColumnForSkeletonLoading.ts b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/utils/getNumberOfCardsPerColumnForSkeletonLoading.ts new file mode 100644 index 000000000000..1f6fc58aaa95 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/utils/getNumberOfCardsPerColumnForSkeletonLoading.ts @@ -0,0 +1,13 @@ +export const getNumberOfCardsPerColumnForSkeletonLoading = ( + columnIndex: number, +): number => { + const skeletonCounts: Record<number, number> = { + 0: 2, + 1: 1, + 2: 3, + 3: 0, + 4: 1, + }; + + return skeletonCounts[columnIndex] || 0; +}; diff --git a/packages/twenty-front/src/modules/object-record/record-board/types/RecordBoardColumnDefinition.ts b/packages/twenty-front/src/modules/object-record/record-board/types/RecordBoardColumnDefinition.ts index 5a9197dff42a..b5e443b0fd9a 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/types/RecordBoardColumnDefinition.ts +++ b/packages/twenty-front/src/modules/object-record/record-board/types/RecordBoardColumnDefinition.ts @@ -2,11 +2,30 @@ import { ThemeColor } from 'twenty-ui'; import { RecordBoardColumnAction } from '@/object-record/record-board/types/RecordBoardColumnAction'; -export type RecordBoardColumnDefinition = { +export const enum RecordBoardColumnDefinitionType { + Value = 'value', + NoValue = 'no-value', +} + +export type RecordBoardColumnDefinitionNoValue = { + id: 'no-value'; + type: RecordBoardColumnDefinitionType.NoValue; + title: 'No Value'; + position: number; + value: null; + actions: RecordBoardColumnAction[]; +}; + +export type RecordBoardColumnDefinitionValue = { id: string; + type: RecordBoardColumnDefinitionType.Value; title: string; value: string; - position: number; color: ThemeColor; + position: number; actions: RecordBoardColumnAction[]; }; + +export type RecordBoardColumnDefinition = + | RecordBoardColumnDefinitionValue + | RecordBoardColumnDefinitionNoValue; diff --git a/packages/twenty-front/src/modules/object-record/record-field/__mocks__/fieldDefinitions.ts b/packages/twenty-front/src/modules/object-record/record-field/__mocks__/fieldDefinitions.ts index 9ea73c15dfc3..4be023caf378 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/__mocks__/fieldDefinitions.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/__mocks__/fieldDefinitions.ts @@ -7,7 +7,6 @@ import { FieldSelectMetadata, FieldTextMetadata, } from '@/object-record/record-field/types/FieldMetadata'; -import { type } from 'os'; import { FieldMetadataType } from '~/generated-metadata/graphql'; import { mockedCompanyObjectMetadataItem, @@ -44,6 +43,7 @@ export const selectFieldDefinition: FieldDefinition<FieldSelectMetadata> = { metadata: { fieldName: 'accountOwner', options: [{ label: 'Elon Musk', color: 'blue', value: 'userId' }], + isNullable: true, }, }; diff --git a/packages/twenty-front/src/modules/object-record/record-field/components/FieldDisplay.tsx b/packages/twenty-front/src/modules/object-record/record-field/components/FieldDisplay.tsx index 31a7692f21e5..f3448846d214 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/components/FieldDisplay.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/components/FieldDisplay.tsx @@ -2,11 +2,15 @@ import { useContext } from 'react'; import { BooleanFieldDisplay } from '@/object-record/record-field/meta-types/display/components/BooleanFieldDisplay'; import { LinksFieldDisplay } from '@/object-record/record-field/meta-types/display/components/LinksFieldDisplay'; +import { RatingFieldDisplay } from '@/object-record/record-field/meta-types/display/components/RatingFieldDisplay'; +import { RelationFromManyFieldDisplay } from '@/object-record/record-field/meta-types/display/components/RelationFromManyFieldDisplay'; +import { isFieldChipDisplay } from '@/object-record/record-field/meta-types/display/utils/isFieldChipDisplay'; import { isFieldBoolean } from '@/object-record/record-field/types/guards/isFieldBoolean'; import { isFieldDisplayedAsPhone } from '@/object-record/record-field/types/guards/isFieldDisplayedAsPhone'; import { isFieldLinks } from '@/object-record/record-field/types/guards/isFieldLinks'; -import { isFieldChipDisplay } from '@/object-record/utils/getRecordChipGeneratorPerObjectPerField'; - +import { isFieldRating } from '@/object-record/record-field/types/guards/isFieldRating'; +import { isFieldRelationFromManyObjects } from '@/object-record/record-field/types/guards/isFieldRelationFromManyObjects'; +import { isFieldRelationToOneObject } from '@/object-record/record-field/types/guards/isFieldRelationToOneObject'; import { FieldContext } from '../contexts/FieldContext'; import { AddressFieldDisplay } from '../meta-types/display/components/AddressFieldDisplay'; import { ChipFieldDisplay } from '../meta-types/display/components/ChipFieldDisplay'; @@ -20,7 +24,7 @@ import { LinkFieldDisplay } from '../meta-types/display/components/LinkFieldDisp import { MultiSelectFieldDisplay } from '../meta-types/display/components/MultiSelectFieldDisplay'; import { NumberFieldDisplay } from '../meta-types/display/components/NumberFieldDisplay'; import { PhoneFieldDisplay } from '../meta-types/display/components/PhoneFieldDisplay'; -import { RelationFieldDisplay } from '../meta-types/display/components/RelationFieldDisplay'; +import { RelationToOneFieldDisplay } from '../meta-types/display/components/RelationToOneFieldDisplay'; import { SelectFieldDisplay } from '../meta-types/display/components/SelectFieldDisplay'; import { TextFieldDisplay } from '../meta-types/display/components/TextFieldDisplay'; import { UuidFieldDisplay } from '../meta-types/display/components/UuidFieldDisplay'; @@ -35,7 +39,6 @@ import { isFieldMultiSelect } from '../types/guards/isFieldMultiSelect'; import { isFieldNumber } from '../types/guards/isFieldNumber'; import { isFieldPhone } from '../types/guards/isFieldPhone'; import { isFieldRawJson } from '../types/guards/isFieldRawJson'; -import { isFieldRelation } from '../types/guards/isFieldRelation'; import { isFieldSelect } from '../types/guards/isFieldSelect'; import { isFieldText } from '../types/guards/isFieldText'; import { isFieldUuid } from '../types/guards/isFieldUuid'; @@ -47,8 +50,10 @@ export const FieldDisplay = () => { return isChipDisplay ? ( <ChipFieldDisplay /> - ) : isFieldRelation(fieldDefinition) ? ( - <RelationFieldDisplay /> + ) : isFieldRelationToOneObject(fieldDefinition) ? ( + <RelationToOneFieldDisplay /> + ) : isFieldRelationFromManyObjects(fieldDefinition) ? ( + <RelationFromManyFieldDisplay /> ) : isFieldPhone(fieldDefinition) || isFieldDisplayedAsPhone(fieldDefinition) ? ( <PhoneFieldDisplay /> @@ -82,5 +87,7 @@ export const FieldDisplay = () => { <JsonFieldDisplay /> ) : isFieldBoolean(fieldDefinition) ? ( <BooleanFieldDisplay /> + ) : isFieldRating(fieldDefinition) ? ( + <RatingFieldDisplay /> ) : null; }; diff --git a/packages/twenty-front/src/modules/object-record/record-field/components/FieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/components/FieldInput.tsx index ce1240e6449c..5ac286d7e745 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/components/FieldInput.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/components/FieldInput.tsx @@ -6,7 +6,7 @@ import { FullNameFieldInput } from '@/object-record/record-field/meta-types/inpu import { LinksFieldInput } from '@/object-record/record-field/meta-types/input/components/LinksFieldInput'; import { MultiSelectFieldInput } from '@/object-record/record-field/meta-types/input/components/MultiSelectFieldInput'; import { RawJsonFieldInput } from '@/object-record/record-field/meta-types/input/components/RawJsonFieldInput'; -import { RelationManyFieldInput } from '@/object-record/record-field/meta-types/input/components/RelationManyFieldInput'; +import { RelationFromManyFieldInput } from '@/object-record/record-field/meta-types/input/components/RelationFromManyFieldInput'; import { SelectFieldInput } from '@/object-record/record-field/meta-types/input/components/SelectFieldInput'; import { RecordFieldInputScope } from '@/object-record/record-field/scopes/RecordFieldInputScope'; import { isFieldDate } from '@/object-record/record-field/types/guards/isFieldDate'; @@ -16,6 +16,7 @@ import { isFieldLinks } from '@/object-record/record-field/types/guards/isFieldL import { isFieldMultiSelect } from '@/object-record/record-field/types/guards/isFieldMultiSelect'; import { isFieldRawJson } from '@/object-record/record-field/types/guards/isFieldRawJson'; import { isFieldRelationFromManyObjects } from '@/object-record/record-field/types/guards/isFieldRelationFromManyObjects'; +import { isFieldRelationToOneObject } from '@/object-record/record-field/types/guards/isFieldRelationToOneObject'; import { isFieldSelect } from '@/object-record/record-field/types/guards/isFieldSelect'; import { getScopeIdFromComponentId } from '@/ui/utilities/recoil-scope/utils/getScopeIdFromComponentId'; @@ -28,7 +29,7 @@ import { LinkFieldInput } from '../meta-types/input/components/LinkFieldInput'; import { NumberFieldInput } from '../meta-types/input/components/NumberFieldInput'; import { PhoneFieldInput } from '../meta-types/input/components/PhoneFieldInput'; import { RatingFieldInput } from '../meta-types/input/components/RatingFieldInput'; -import { RelationFieldInput } from '../meta-types/input/components/RelationFieldInput'; +import { RelationToOneFieldInput } from '../meta-types/input/components/RelationToOneFieldInput'; import { TextFieldInput } from '../meta-types/input/components/TextFieldInput'; import { FieldInputEvent } from '../types/FieldInputEvent'; import { isFieldAddress } from '../types/guards/isFieldAddress'; @@ -40,7 +41,6 @@ import { isFieldLink } from '../types/guards/isFieldLink'; import { isFieldNumber } from '../types/guards/isFieldNumber'; import { isFieldPhone } from '../types/guards/isFieldPhone'; import { isFieldRating } from '../types/guards/isFieldRating'; -import { isFieldRelation } from '../types/guards/isFieldRelation'; import { isFieldText } from '../types/guards/isFieldText'; type FieldInputProps = { @@ -72,16 +72,10 @@ export const FieldInput = ({ <RecordFieldInputScope recordFieldInputScopeId={getScopeIdFromComponentId(recordFieldInputdId)} > - {isFieldRelation(fieldDefinition) ? ( - isFieldRelationFromManyObjects(fieldDefinition) ? ( - <RelationManyFieldInput - relationPickerScopeId={getScopeIdFromComponentId( - `relation-picker-${fieldDefinition.fieldMetadataId}`, - )} - /> - ) : ( - <RelationFieldInput onSubmit={onSubmit} onCancel={onCancel} /> - ) + {isFieldRelationToOneObject(fieldDefinition) ? ( + <RelationToOneFieldInput onSubmit={onSubmit} onCancel={onCancel} /> + ) : isFieldRelationFromManyObjects(fieldDefinition) ? ( + <RelationFromManyFieldInput onSubmit={onSubmit} /> ) : isFieldPhone(fieldDefinition) || isFieldDisplayedAsPhone(fieldDefinition) ? ( <PhoneFieldInput @@ -121,6 +115,7 @@ export const FieldInput = ({ onEscape={onEscape} onClickOutside={onClickOutside} onClear={onSubmit} + onSubmit={onSubmit} /> ) : isFieldDate(fieldDefinition) ? ( <DateFieldInput @@ -128,6 +123,7 @@ export const FieldInput = ({ onEscape={onEscape} onClickOutside={onClickOutside} onClear={onSubmit} + onSubmit={onSubmit} /> ) : isFieldNumber(fieldDefinition) ? ( <NumberFieldInput diff --git a/packages/twenty-front/src/modules/object-record/record-field/contexts/FieldContext.ts b/packages/twenty-front/src/modules/object-record/record-field/contexts/FieldContext.ts index 824e7a3b5f74..571e39cbe9e4 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/contexts/FieldContext.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/contexts/FieldContext.ts @@ -30,6 +30,7 @@ export type GenericFieldContextType = { clearable?: boolean; maxWidth?: number; isCentered?: boolean; + overridenIsFieldEmpty?: boolean; }; export const FieldContext = createContext<GenericFieldContextType>( diff --git a/packages/twenty-front/src/modules/object-record/record-field/hooks/__tests__/useToggleEditOnlyInput.test.tsx b/packages/twenty-front/src/modules/object-record/record-field/hooks/__tests__/useToggleEditOnlyInput.test.tsx index 3a073219f9b6..3000ca0eb5b5 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/hooks/__tests__/useToggleEditOnlyInput.test.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/hooks/__tests__/useToggleEditOnlyInput.test.tsx @@ -40,7 +40,16 @@ const mocks: MockedResponse[] = [ currencyCode } createdAt - address + address { + addressStreet1 + addressStreet2 + addressCity + addressState + addressCountry + addressPostcode + addressLat + addressLng + } updatedAt name accountOwnerId diff --git a/packages/twenty-front/src/modules/object-record/record-field/hooks/useClearField.ts b/packages/twenty-front/src/modules/object-record/record-field/hooks/useClearField.ts index 548e212f98c7..30577442254f 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/hooks/useClearField.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/hooks/useClearField.ts @@ -2,6 +2,7 @@ import { useContext } from 'react'; import { useRecoilCallback } from 'recoil'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; +import { useSetRecordFieldValue } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext'; import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector'; import { generateEmptyFieldValue } from '@/object-record/utils/generateEmptyFieldValue'; @@ -16,6 +17,8 @@ export const useClearField = () => { const [updateRecord] = useUpdateRecord(); + const setRecordFieldValue = useSetRecordFieldValue(); + const clearField = useRecoilCallback( ({ snapshot, set }) => () => { @@ -46,6 +49,8 @@ export const useClearField = () => { emptyFieldValue, ); + setRecordFieldValue(entityId, fieldName, emptyFieldValue); + updateRecord?.({ variables: { where: { id: entityId }, @@ -55,7 +60,7 @@ export const useClearField = () => { }, }); }, - [entityId, fieldDefinition, updateRecord], + [entityId, fieldDefinition, updateRecord, setRecordFieldValue], ); return clearField; diff --git a/packages/twenty-front/src/modules/object-record/record-field/hooks/useIsFieldEmpty.ts b/packages/twenty-front/src/modules/object-record/record-field/hooks/useIsFieldEmpty.ts index 01c4573c0000..f1e100566e72 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/hooks/useIsFieldEmpty.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/hooks/useIsFieldEmpty.ts @@ -2,17 +2,23 @@ import { useContext } from 'react'; import { isFieldValueEmpty } from '@/object-record/record-field/utils/isFieldValueEmpty'; import { useRecordFieldValue } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext'; +import { isDefined } from '~/utils/isDefined'; import { FieldContext } from '../contexts/FieldContext'; export const useIsFieldEmpty = () => { - const { entityId, fieldDefinition } = useContext(FieldContext); + const { entityId, fieldDefinition, overridenIsFieldEmpty } = + useContext(FieldContext); const fieldValue = useRecordFieldValue( entityId, - fieldDefinition.metadata.fieldName, + fieldDefinition?.metadata?.fieldName ?? '', ); + if (isDefined(overridenIsFieldEmpty)) { + return overridenIsFieldEmpty; + } + return isFieldValueEmpty({ fieldDefinition, fieldValue, diff --git a/packages/twenty-front/src/modules/object-record/record-field/hooks/usePersistField.ts b/packages/twenty-front/src/modules/object-record/record-field/hooks/usePersistField.ts index d2f1a1db8bca..946b6046dc10 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/hooks/usePersistField.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/hooks/usePersistField.ts @@ -15,7 +15,8 @@ import { isFieldMultiSelect } from '@/object-record/record-field/types/guards/is import { isFieldMultiSelectValue } from '@/object-record/record-field/types/guards/isFieldMultiSelectValue'; import { isFieldRawJson } from '@/object-record/record-field/types/guards/isFieldRawJson'; import { isFieldRawJsonValue } from '@/object-record/record-field/types/guards/isFieldRawJsonValue'; -import { isFieldRelationFromManyObjects } from '@/object-record/record-field/types/guards/isFieldRelationFromManyObjects'; +import { isFieldRelationToOneObject } from '@/object-record/record-field/types/guards/isFieldRelationToOneObject'; +import { isFieldRelationToOneValue } from '@/object-record/record-field/types/guards/isFieldRelationToOneValue'; import { isFieldSelect } from '@/object-record/record-field/types/guards/isFieldSelect'; import { isFieldSelectValue } from '@/object-record/record-field/types/guards/isFieldSelectValue'; import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector'; @@ -38,8 +39,6 @@ import { isFieldPhone } from '../types/guards/isFieldPhone'; import { isFieldPhoneValue } from '../types/guards/isFieldPhoneValue'; import { isFieldRating } from '../types/guards/isFieldRating'; import { isFieldRatingValue } from '../types/guards/isFieldRatingValue'; -import { isFieldRelation } from '../types/guards/isFieldRelation'; -import { isFieldRelationValue } from '../types/guards/isFieldRelationValue'; import { isFieldText } from '../types/guards/isFieldText'; import { isFieldTextValue } from '../types/guards/isFieldTextValue'; @@ -55,14 +54,10 @@ export const usePersistField = () => { const persistField = useRecoilCallback( ({ set }) => (valueToPersist: unknown) => { - const fieldIsRelation = - isFieldRelation(fieldDefinition) && - isFieldRelationValue(valueToPersist); - - const fieldIsRelationFromManyObjects = - isFieldRelationFromManyObjects( + const fieldIsRelationToOneObject = + isFieldRelationToOneObject( fieldDefinition as FieldDefinition<FieldRelationMetadata>, - ) && isFieldRelationValue(valueToPersist); + ) && isFieldRelationToOneValue(valueToPersist); const fieldIsText = isFieldText(fieldDefinition) && isFieldTextValue(valueToPersist); @@ -87,7 +82,7 @@ export const usePersistField = () => { isFieldBoolean(fieldDefinition) && isFieldBooleanValue(valueToPersist); - const fieldIsProbability = + const fieldIsRating = isFieldRating(fieldDefinition) && isFieldRatingValue(valueToPersist); const fieldIsNumber = @@ -120,11 +115,11 @@ export const usePersistField = () => { isFieldRawJsonValue(valueToPersist); const isValuePersistable = - (fieldIsRelation && !fieldIsRelationFromManyObjects) || + fieldIsRelationToOneObject || fieldIsText || fieldIsBoolean || fieldIsEmail || - fieldIsProbability || + fieldIsRating || fieldIsNumber || fieldIsDateTime || fieldIsDate || @@ -145,7 +140,7 @@ export const usePersistField = () => { valueToPersist, ); - if (fieldIsRelation && !fieldIsRelationFromManyObjects) { + if (fieldIsRelationToOneObject) { const value = valueToPersist as EntityForSelect; updateRecord?.({ variables: { diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/ChipFieldDisplay.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/ChipFieldDisplay.tsx index 30fdcb7a7774..4a8682f3859e 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/ChipFieldDisplay.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/ChipFieldDisplay.tsx @@ -1,24 +1,21 @@ -import { EntityChip } from 'twenty-ui'; - +import { RecordChip } from '@/object-record/components/RecordChip'; import { useChipFieldDisplay } from '@/object-record/record-field/meta-types/hooks/useChipFieldDisplay'; -import { getImageAbsoluteURIOrBase64 } from '~/utils/image/getImageAbsoluteURIOrBase64'; +import { RecordIndexRecordChip } from '@/object-record/record-index/components/RecordIndexRecordChip'; export const ChipFieldDisplay = () => { - const { recordValue, generateRecordChipData } = useChipFieldDisplay(); + const { recordValue, objectNameSingular, isLabelIdentifier } = + useChipFieldDisplay(); if (!recordValue) { return null; } - const recordChipData = generateRecordChipData(recordValue); - - return ( - <EntityChip - entityId={recordValue.id} - name={recordChipData.name as any} - avatarType={recordChipData.avatarType} - avatarUrl={getImageAbsoluteURIOrBase64(recordChipData.avatarUrl) ?? ''} - linkToEntity={recordChipData.linkToShowPage} + return isLabelIdentifier ? ( + <RecordIndexRecordChip + objectNameSingular={objectNameSingular} + record={recordValue} /> + ) : ( + <RecordChip objectNameSingular={objectNameSingular} record={recordValue} /> ); }; diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/RatingFieldDisplay.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/RatingFieldDisplay.tsx new file mode 100644 index 000000000000..7514480e4b00 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/RatingFieldDisplay.tsx @@ -0,0 +1,8 @@ +import { useRatingFieldDisplay } from '@/object-record/record-field/meta-types/hooks/useRatingFieldDisplay'; +import { RatingInput } from '@/ui/field/input/components/RatingInput'; + +export const RatingFieldDisplay = () => { + const { rating } = useRatingFieldDisplay(); + + return <RatingInput value={rating} readonly />; +}; diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/RelationFieldDisplay.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/RelationFieldDisplay.tsx deleted file mode 100644 index dace0123781c..000000000000 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/RelationFieldDisplay.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import { isArray } from '@sniptt/guards'; -import { EntityChip } from 'twenty-ui'; - -import { RelationFromManyFieldDisplay } from '@/object-record/record-field/meta-types/display/components/RelationFromManyFieldDisplay'; -import { useRelationFieldDisplay } from '@/object-record/record-field/meta-types/hooks/useRelationFieldDisplay'; -import { isFieldRelationFromManyObjects } from '@/object-record/record-field/types/guards/isFieldRelationFromManyObjects'; -import { ObjectRecord } from '@/object-record/types/ObjectRecord'; -import { getImageAbsoluteURIOrBase64 } from '~/utils/image/getImageAbsoluteURIOrBase64'; - -export const RelationFieldDisplay = () => { - const { fieldValue, fieldDefinition, generateRecordChipData } = - useRelationFieldDisplay(); - - if ( - !fieldValue || - !fieldDefinition?.metadata.relationObjectMetadataNameSingular - ) { - return null; - } - - if (isArray(fieldValue) && isFieldRelationFromManyObjects(fieldDefinition)) { - return ( - <RelationFromManyFieldDisplay fieldValue={fieldValue as ObjectRecord[]} /> - ); - } - - const recordChipData = generateRecordChipData(fieldValue); - - return ( - <EntityChip - entityId={fieldValue.id} - name={recordChipData.name as any} - avatarType={recordChipData.avatarType} - avatarUrl={getImageAbsoluteURIOrBase64(recordChipData.avatarUrl) || ''} - linkToEntity={recordChipData.linkToShowPage} - /> - ); -}; diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/RelationFromManyFieldDisplay.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/RelationFromManyFieldDisplay.tsx index 808565a5a932..adfaea988958 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/RelationFromManyFieldDisplay.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/RelationFromManyFieldDisplay.tsx @@ -1,34 +1,27 @@ -import { EntityChip } from 'twenty-ui'; - +import { RecordChip } from '@/object-record/components/RecordChip'; import { useFieldFocus } from '@/object-record/record-field/hooks/useFieldFocus'; -import { useRelationFieldDisplay } from '@/object-record/record-field/meta-types/hooks/useRelationFieldDisplay'; -import { ObjectRecord } from '@/object-record/types/ObjectRecord'; +import { useRelationFromManyFieldDisplay } from '@/object-record/record-field/meta-types/hooks/useRelationFromManyFieldDisplay'; import { ExpandableList } from '@/ui/layout/expandable-list/components/ExpandableList'; -import { getImageAbsoluteURIOrBase64 } from '~/utils/image/getImageAbsoluteURIOrBase64'; -export const RelationFromManyFieldDisplay = ({ - fieldValue, -}: { - fieldValue: ObjectRecord[]; -}) => { +export const RelationFromManyFieldDisplay = () => { + const { fieldValue, fieldDefinition } = useRelationFromManyFieldDisplay(); const { isFocused } = useFieldFocus(); - const { generateRecordChipData } = useRelationFieldDisplay(); - const recordChipsData = fieldValue.map((fieldValueItem) => - generateRecordChipData(fieldValueItem), - ); + const relationObjectNameSingular = + fieldDefinition?.metadata.relationObjectMetadataNameSingular; + + if (!fieldValue || !relationObjectNameSingular) { + return null; + } return ( <ExpandableList isChipCountDisplayed={isFocused}> - {recordChipsData.map((record) => { + {fieldValue.map((record) => { return ( - <EntityChip - key={record.recordId} - entityId={record.recordId} - name={record.name as any} - avatarType={record.avatarType} - avatarUrl={getImageAbsoluteURIOrBase64(record.avatarUrl) || ''} - linkToEntity={record.linkToShowPage} + <RecordChip + key={record.id} + objectNameSingular={relationObjectNameSingular} + record={record} /> ); })} diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/RelationToOneFieldDisplay.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/RelationToOneFieldDisplay.tsx new file mode 100644 index 000000000000..dede0f879534 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/RelationToOneFieldDisplay.tsx @@ -0,0 +1,24 @@ +import { RecordChip } from '@/object-record/components/RecordChip'; +import { useRelationToOneFieldDisplay } from '@/object-record/record-field/meta-types/hooks/useRelationToOneFieldDisplay'; + +export const RelationToOneFieldDisplay = () => { + const { fieldValue, fieldDefinition, generateRecordChipData } = + useRelationToOneFieldDisplay(); + + if ( + !fieldValue || + !fieldDefinition?.metadata.relationObjectMetadataNameSingular + ) { + return null; + } + + const recordChipData = generateRecordChipData(fieldValue); + + return ( + <RecordChip + key={recordChipData.recordId} + objectNameSingular={recordChipData.objectNameSingular} + record={fieldValue} + /> + ); +}; diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/AddressFieldDisplay.perf.stories.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/AddressFieldDisplay.perf.stories.tsx index 6c138c79548e..f97418a5af23 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/AddressFieldDisplay.perf.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/AddressFieldDisplay.perf.stories.tsx @@ -49,6 +49,6 @@ export const Elipsis: Story = { export const Performance = getProfilingStory({ componentName: 'AddressFieldDisplay', averageThresholdInMs: 0.15, - numberOfRuns: 50, + numberOfRuns: 20, numberOfTestsPerRun: 100, }); diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/RatingFieldDisplay.perf.stories.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/RatingFieldDisplay.perf.stories.tsx new file mode 100644 index 000000000000..cffa101426cf --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/RatingFieldDisplay.perf.stories.tsx @@ -0,0 +1,34 @@ +import { Meta, StoryObj } from '@storybook/react'; +import { ComponentDecorator } from 'twenty-ui'; + +import { RatingFieldDisplay } from '@/object-record/record-field/meta-types/display/components/RatingFieldDisplay'; +import { getFieldDecorator } from '~/testing/decorators/getFieldDecorator'; +import { MemoryRouterDecorator } from '~/testing/decorators/MemoryRouterDecorator'; +import { getProfilingStory } from '~/testing/profiling/utils/getProfilingStory'; + +const meta: Meta = { + title: 'UI/Data/Field/Display/RatingFieldDisplay', + decorators: [ + MemoryRouterDecorator, + getFieldDecorator('person', 'testRating'), + ComponentDecorator, + ], + component: RatingFieldDisplay, + args: {}, + parameters: { + chromatic: { disableSnapshot: true }, + }, +}; + +export default meta; + +type Story = StoryObj<typeof RatingFieldDisplay>; + +export const Default: Story = {}; + +export const Performance = getProfilingStory({ + componentName: 'RatingFieldDisplay', + averageThresholdInMs: 0.5, + numberOfRuns: 50, + numberOfTestsPerRun: 100, +}); diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/RelationFromManyFieldDisplay.perf.stories.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/RelationFromManyFieldDisplay.perf.stories.tsx index 7c9ce09da874..f4f2a3393b3a 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/RelationFromManyFieldDisplay.perf.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/RelationFromManyFieldDisplay.perf.stories.tsx @@ -9,7 +9,7 @@ import { FieldDefinition } from '@/object-record/record-field/types/FieldDefinit import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata'; import { RecordFieldValueSelectorContextProvider, - useSetRecordValue, + useSetRecordFieldValue, } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; import { ChipGeneratorsDecorator } from '~/testing/decorators/ChipGeneratorsDecorator'; @@ -18,6 +18,7 @@ import { getProfilingStory } from '~/testing/profiling/utils/getProfilingStory'; import { fieldValue, + otherPersonMock, relationFromManyFieldDisplayMock, } from './relationFromManyFieldDisplayMock'; @@ -30,21 +31,26 @@ const RelationFieldValueSetterEffect = () => { recordStoreFamilyState(relationFromManyFieldDisplayMock.relationEntityId), ); - const setRecordValue = useSetRecordValue(); + const setRecordFieldValue = useSetRecordFieldValue(); useEffect(() => { setEntity(relationFromManyFieldDisplayMock.entityValue); setRelationEntity(relationFromManyFieldDisplayMock.relationFieldValue); - setRecordValue( + setRecordFieldValue( relationFromManyFieldDisplayMock.entityValue.id, - relationFromManyFieldDisplayMock.entityValue, + 'company', + [relationFromManyFieldDisplayMock.entityValue], ); - setRecordValue( + setRecordFieldValue(otherPersonMock.entityValue.id, 'company', [ + relationFromManyFieldDisplayMock.entityValue, + ]); + setRecordFieldValue( relationFromManyFieldDisplayMock.relationFieldValue.id, + 'company', relationFromManyFieldDisplayMock.relationFieldValue, ); - }, [setEntity, setRelationEntity, setRecordValue]); + }, [setEntity, setRelationEntity, setRecordFieldValue]); return null; }; diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/RelationFieldDisplay.perf.stories.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/RelationToOneFieldDisplay.perf.stories.tsx similarity index 80% rename from packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/RelationFieldDisplay.perf.stories.tsx rename to packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/RelationToOneFieldDisplay.perf.stories.tsx index 6c985926d94e..49a076d80a47 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/RelationFieldDisplay.perf.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/RelationToOneFieldDisplay.perf.stories.tsx @@ -1,7 +1,7 @@ import { Meta, StoryObj } from '@storybook/react'; import { ComponentDecorator } from 'twenty-ui'; -import { RelationFieldDisplay } from '@/object-record/record-field/meta-types/display/components/RelationFieldDisplay'; +import { RelationToOneFieldDisplay } from '@/object-record/record-field/meta-types/display/components/RelationToOneFieldDisplay'; import { ChipGeneratorsDecorator } from '~/testing/decorators/ChipGeneratorsDecorator'; import { getFieldDecorator } from '~/testing/decorators/getFieldDecorator'; import { MemoryRouterDecorator } from '~/testing/decorators/MemoryRouterDecorator'; @@ -15,7 +15,7 @@ const meta: Meta = { getFieldDecorator('person', 'company'), ComponentDecorator, ], - component: RelationFieldDisplay, + component: RelationToOneFieldDisplay, args: {}, parameters: { chromatic: { disableSnapshot: true }, @@ -24,7 +24,7 @@ const meta: Meta = { export default meta; -type Story = StoryObj<typeof RelationFieldDisplay>; +type Story = StoryObj<typeof RelationToOneFieldDisplay>; export const Default: Story = {}; diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/relationFromManyFieldDisplayMock.ts b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/relationFromManyFieldDisplayMock.ts index cbc63cb40be5..674d00fe90e2 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/relationFromManyFieldDisplayMock.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/relationFromManyFieldDisplayMock.ts @@ -59,6 +59,60 @@ export const fieldValue = [ }, ]; +export const otherPersonMock = { + entityValue: { + __typename: 'Person', + asd: '', + city: 'Paris', + jobTitle: '', + name: 'John Doe', + createdAt: '2024-05-01T13:16:29.046Z', + company: { + __typename: 'Company', + domainName: 'google.com', + xLink: { + __typename: 'Link', + label: '', + url: '', + }, + name: 'Google', + annualRecurringRevenue: { + __typename: 'Currency', + amountMicros: null, + currencyCode: '', + }, + employees: null, + accountOwnerId: null, + address: '', + idealCustomerProfile: false, + createdAt: '2024-05-01T13:16:29.046Z', + id: '20202020-c21e-4ec2-873b-de4264d89025', + position: 6, + updatedAt: '2024-05-01T13:16:29.046Z', + linkedinLink: { + __typename: 'Link', + label: '', + url: '', + }, + }, + id: 'd3e70589-c449-4e64-8268-065640fdaff0', + email: 'john.doe@google.com', + phone: '+33744332211', + linkedinLink: { + __typename: 'Link', + label: '', + url: '', + }, + xLink: { + __typename: 'Link', + label: '', + url: '', + }, + tEst: '', + position: 14, + }, +}; + export const relationFromManyFieldDisplayMock = { entityId: '20202020-2d40-4e49-8df4-9c6a049191df', relationEntityId: '20202020-c21e-4ec2-873b-de4264d89025', @@ -67,11 +121,7 @@ export const relationFromManyFieldDisplayMock = { asd: '', city: 'Seattle', jobTitle: '', - name: { - __typename: 'FullName', - firstName: 'Lorie', - lastName: 'Vladim', - }, + name: 'Lorie Vladim', createdAt: '2024-05-01T13:16:29.046Z', company: { __typename: 'Company', diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/utils/isFieldChipDisplay.ts b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/utils/isFieldChipDisplay.ts new file mode 100644 index 000000000000..cb45decfe7c3 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/utils/isFieldChipDisplay.ts @@ -0,0 +1,11 @@ +import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; +import { isFieldFullName } from '@/object-record/record-field/types/guards/isFieldFullName'; +import { isFieldNumber } from '@/object-record/record-field/types/guards/isFieldNumber'; +import { isFieldText } from '@/object-record/record-field/types/guards/isFieldText'; + +export const isFieldChipDisplay = ( + field: Pick<FieldMetadataItem, 'type'>, + isLabelIdentifier: boolean, +) => + isLabelIdentifier && + (isFieldText(field) || isFieldFullName(field) || isFieldNumber(field)); diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useChipFieldDisplay.ts b/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useChipFieldDisplay.ts index 29cf1d3dc651..c0840bf7c06a 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useChipFieldDisplay.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useChipFieldDisplay.ts @@ -1,8 +1,7 @@ -import { useContext } from 'react'; import { isNonEmptyString } from '@sniptt/guards'; +import { useContext } from 'react'; import { PreComputedChipGeneratorsContext } from '@/object-metadata/context/PreComputedChipGeneratorsContext'; -import { generateDefaultRecordChipData } from '@/object-metadata/utils/generateDefaultRecordChipData'; import { isFieldFullName } from '@/object-record/record-field/types/guards/isFieldFullName'; import { isFieldNumber } from '@/object-record/record-field/types/guards/isFieldNumber'; import { isFieldText } from '@/object-record/record-field/types/guards/isFieldText'; @@ -12,7 +11,8 @@ import { isDefined } from '~/utils/isDefined'; import { FieldContext } from '../../contexts/FieldContext'; export const useChipFieldDisplay = () => { - const { entityId, fieldDefinition } = useContext(FieldContext); + const { entityId, fieldDefinition, isLabelIdentifier } = + useContext(FieldContext); const { chipGeneratorPerObjectPerField } = useContext( PreComputedChipGeneratorsContext, @@ -31,18 +31,13 @@ export const useChipFieldDisplay = () => { const recordValue = useRecordValue(entityId); - if (!isNonEmptyString(fieldDefinition.metadata.objectMetadataNameSingular)) { + if (!isNonEmptyString(objectNameSingular)) { throw new Error('Object metadata name singular is not a non-empty string'); } - const generateRecordChipData = - chipGeneratorPerObjectPerField[ - fieldDefinition.metadata.objectMetadataNameSingular - ]?.[fieldDefinition.metadata.fieldName] ?? generateDefaultRecordChipData; - return { objectNameSingular, recordValue, - generateRecordChipData, + isLabelIdentifier, }; }; diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useRatingFieldDisplay.ts b/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useRatingFieldDisplay.ts new file mode 100644 index 000000000000..f6d0ff6603f2 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useRatingFieldDisplay.ts @@ -0,0 +1,23 @@ +import { useContext } from 'react'; + +import { FieldRatingValue } from '@/object-record/record-field/types/FieldMetadata'; +import { useRecordFieldValue } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext'; + +import { FieldContext } from '../../contexts/FieldContext'; + +export const useRatingFieldDisplay = () => { + const { entityId, fieldDefinition } = useContext(FieldContext); + + const fieldName = fieldDefinition.metadata.fieldName; + + const fieldValue = useRecordFieldValue(entityId, fieldName) as + | FieldRatingValue + | undefined; + + const rating = fieldValue ?? 'RATING_1'; + + return { + fieldDefinition, + rating, + }; +}; diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useRelationFromManyFieldDisplay.ts b/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useRelationFromManyFieldDisplay.ts new file mode 100644 index 000000000000..251852afd987 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useRelationFromManyFieldDisplay.ts @@ -0,0 +1,63 @@ +import { useContext } from 'react'; +import { isNonEmptyString } from '@sniptt/guards'; + +import { PreComputedChipGeneratorsContext } from '@/object-metadata/context/PreComputedChipGeneratorsContext'; +import { generateDefaultRecordChipData } from '@/object-metadata/utils/generateDefaultRecordChipData'; +import { useRecordFieldValue } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext'; +import { ObjectRecord } from '@/object-record/types/ObjectRecord'; +import { FIELD_EDIT_BUTTON_WIDTH } from '@/ui/field/display/constants/FieldEditButtonWidth'; +import { FieldMetadataType } from '~/generated-metadata/graphql'; +import { isDefined } from '~/utils/isDefined'; + +import { FieldContext } from '../../contexts/FieldContext'; +import { assertFieldMetadata } from '../../types/guards/assertFieldMetadata'; +import { isFieldRelation } from '../../types/guards/isFieldRelation'; + +export const useRelationFromManyFieldDisplay = () => { + const { entityId, fieldDefinition, maxWidth } = useContext(FieldContext); + + const { chipGeneratorPerObjectPerField } = useContext( + PreComputedChipGeneratorsContext, + ); + + if (!isDefined(chipGeneratorPerObjectPerField)) { + throw new Error('Chip generator per object per field is not defined'); + } + + assertFieldMetadata( + FieldMetadataType.Relation, + isFieldRelation, + fieldDefinition, + ); + + const button = fieldDefinition.editButtonIcon; + + const fieldName = fieldDefinition.metadata.fieldName; + + const fieldValue = useRecordFieldValue<ObjectRecord[] | undefined>( + entityId, + fieldName, + ); + + const maxWidthForField = + isDefined(button) && isDefined(maxWidth) + ? maxWidth - FIELD_EDIT_BUTTON_WIDTH + : maxWidth; + + if (!isNonEmptyString(fieldDefinition.metadata.objectMetadataNameSingular)) { + throw new Error('Object metadata name singular is not a non-empty string'); + } + + const generateRecordChipData = + chipGeneratorPerObjectPerField[ + fieldDefinition.metadata.objectMetadataNameSingular + ]?.[fieldDefinition.metadata.fieldName] ?? generateDefaultRecordChipData; + + return { + fieldDefinition, + fieldValue, + maxWidth: maxWidthForField, + entityId, + generateRecordChipData, + }; +}; diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useRelationFieldDisplay.ts b/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useRelationToOneFieldDisplay.ts similarity index 97% rename from packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useRelationFieldDisplay.ts rename to packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useRelationToOneFieldDisplay.ts index 510cd7fbc2f4..c33464dc37b3 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useRelationFieldDisplay.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useRelationToOneFieldDisplay.ts @@ -13,7 +13,7 @@ import { FieldContext } from '../../contexts/FieldContext'; import { assertFieldMetadata } from '../../types/guards/assertFieldMetadata'; import { isFieldRelation } from '../../types/guards/isFieldRelation'; -export const useRelationFieldDisplay = () => { +export const useRelationToOneFieldDisplay = () => { const { entityId, fieldDefinition, maxWidth } = useContext(FieldContext); const { chipGeneratorPerObjectPerField } = useContext( diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/DateFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/DateFieldInput.tsx index acc4dfff175b..4776642e91cd 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/DateFieldInput.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/DateFieldInput.tsx @@ -13,6 +13,7 @@ export type DateFieldInputProps = { onEnter?: FieldInputEvent; onEscape?: FieldInputEvent; onClear?: FieldInputEvent; + onSubmit?: FieldInputEvent; }; export const DateFieldInput = ({ @@ -20,6 +21,7 @@ export const DateFieldInput = ({ onEscape, onClickOutside, onClear, + onSubmit, }: DateFieldInputProps) => { const { fieldValue, setDraftValue } = useDateField(); @@ -39,6 +41,10 @@ export const DateFieldInput = ({ onEnter?.(() => persistDate(newDate)); }; + const handleSubmit = (newDate: Nullable<Date>) => { + onSubmit?.(() => persistDate(newDate)); + }; + const handleEscape = (newDate: Nullable<Date>) => { onEscape?.(() => persistDate(newDate)); }; @@ -69,6 +75,7 @@ export const DateFieldInput = ({ clearable onChange={handleChange} onClear={handleClear} + onSubmit={handleSubmit} /> ); }; diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/DateTimeFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/DateTimeFieldInput.tsx index 15c6280ee9ac..6a57490084ac 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/DateTimeFieldInput.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/DateTimeFieldInput.tsx @@ -12,6 +12,7 @@ export type DateTimeFieldInputProps = { onEnter?: FieldInputEvent; onEscape?: FieldInputEvent; onClear?: FieldInputEvent; + onSubmit?: FieldInputEvent; }; export const DateTimeFieldInput = ({ @@ -19,6 +20,7 @@ export const DateTimeFieldInput = ({ onEscape, onClickOutside, onClear, + onSubmit, }: DateTimeFieldInputProps) => { const { fieldValue, setDraftValue } = useDateTimeField(); @@ -57,6 +59,10 @@ export const DateTimeFieldInput = ({ onClear?.(() => persistDate(null)); }; + const handleSubmit = (newDate: Nullable<Date>) => { + onSubmit?.(() => persistDate(newDate)); + }; + const dateValue = fieldValue ? new Date(fieldValue) : null; return ( @@ -69,6 +75,7 @@ export const DateTimeFieldInput = ({ onChange={handleChange} isDateTimeInput onClear={handleClear} + onSubmit={handleSubmit} /> ); }; diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/LinksFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/LinksFieldInput.tsx index 9724bc3e6836..3fdbb0abf5f1 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/LinksFieldInput.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/LinksFieldInput.tsx @@ -124,6 +124,33 @@ export const LinksFieldInput = ({ onCancel }: LinksFieldInputProps) => { }; const handleDeleteLink = (index: number) => { + const hasOnlyOneLastLink = links.length === 1; + + if (hasOnlyOneLastLink) { + persistLinksField({ + primaryLinkUrl: '', + primaryLinkLabel: '', + secondaryLinks: null, + }); + + handleDropdownClose(); + + return; + } + + const isRemovingPrimary = index === 0; + if (isRemovingPrimary) { + const [, nextPrimaryLink, ...nextSecondaryLinks] = links; + + persistLinksField({ + primaryLinkUrl: nextPrimaryLink.url ?? '', + primaryLinkLabel: nextPrimaryLink.label ?? '', + secondaryLinks: nextSecondaryLinks, + }); + + return; + } + persistLinksField({ ...fieldValue, secondaryLinks: toSpliced(fieldValue.secondaryLinks ?? [], index - 1, 1), @@ -151,7 +178,7 @@ export const LinksFieldInput = ({ onCancel }: LinksFieldInputProps) => { <DropdownMenuSeparator /> </> )} - {isInputDisplayed ? ( + {isInputDisplayed || !links.length ? ( <DropdownMenuInput autoFocus placeholder="URL" diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/LinksFieldMenuItem.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/LinksFieldMenuItem.tsx index 39be332373aa..5b1fedb88486 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/LinksFieldMenuItem.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/LinksFieldMenuItem.tsx @@ -46,6 +46,11 @@ export const LinksFieldMenuItem = ({ const handleMouseEnter = () => setIsHovered(true); const handleMouseLeave = () => setIsHovered(false); + const handleDeleteClick = () => { + setIsHovered(false); + onDelete?.(); + }; + // Make sure dropdown closes on unmount. useEffect(() => { if (isDropdownOpen) { @@ -86,14 +91,12 @@ export const LinksFieldMenuItem = ({ text="Edit" onClick={onEdit} /> - {!isPrimary && ( - <MenuItem - accent="danger" - LeftIcon={IconTrash} - text="Delete" - onClick={onDelete} - /> - )} + <MenuItem + accent="danger" + LeftIcon={IconTrash} + text="Delete" + onClick={handleDeleteClick} + /> </DropdownMenuItemsContainer> } /> diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/RelationFromManyFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/RelationFromManyFieldInput.tsx new file mode 100644 index 000000000000..92e1dc80c5f3 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/RelationFromManyFieldInput.tsx @@ -0,0 +1,37 @@ +import { useContext } from 'react'; + +import { ObjectMetadataItemsRelationPickerEffect } from '@/object-metadata/components/ObjectMetadataItemsRelationPickerEffect'; +import { FieldContext } from '@/object-record/record-field/contexts/FieldContext'; +import { RelationFromManyFieldInputMultiRecordsEffect } from '@/object-record/record-field/meta-types/input/components/RelationFromManyFieldInputMultiRecordsEffect'; +import { useUpdateRelationFromManyFieldInput } from '@/object-record/record-field/meta-types/input/hooks/useUpdateRelationFromManyFieldInput'; +import { FieldInputEvent } from '@/object-record/record-field/types/FieldInputEvent'; +import { MultiRecordSelect } from '@/object-record/relation-picker/components/MultiRecordSelect'; +import { RelationPickerScope } from '@/object-record/relation-picker/scopes/RelationPickerScope'; + +export type RelationFromManyFieldInputProps = { + onSubmit?: FieldInputEvent; +}; + +export const RelationFromManyFieldInput = ({ + onSubmit, +}: RelationFromManyFieldInputProps) => { + const { fieldDefinition } = useContext(FieldContext); + const relationPickerScopeId = `relation-picker-${fieldDefinition.fieldMetadataId}`; + const { updateRelation } = useUpdateRelationFromManyFieldInput({ + scopeId: relationPickerScopeId, + }); + + const handleSubmit = () => { + onSubmit?.(() => {}); + }; + + return ( + <> + <RelationPickerScope relationPickerScopeId={relationPickerScopeId}> + <ObjectMetadataItemsRelationPickerEffect /> + <RelationFromManyFieldInputMultiRecordsEffect /> + <MultiRecordSelect onSubmit={handleSubmit} onChange={updateRelation} /> + </RelationPickerScope> + </> + ); +}; diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/RelationFromManyFieldInputMultiRecordsEffect.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/RelationFromManyFieldInputMultiRecordsEffect.tsx new file mode 100644 index 000000000000..6f42a7fbad2e --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/RelationFromManyFieldInputMultiRecordsEffect.tsx @@ -0,0 +1,126 @@ +import { useEffect, useMemo } from 'react'; +import { useRecoilCallback, useRecoilState, useSetRecoilState } from 'recoil'; + +import { useObjectRecordMultiSelectScopedStates } from '@/activities/hooks/useObjectRecordMultiSelectScopedStates'; +import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; +import { useRelationField } from '@/object-record/record-field/meta-types/hooks/useRelationField'; +import { objectRecordMultiSelectComponentFamilyState } from '@/object-record/record-field/states/objectRecordMultiSelectComponentFamilyState'; +import { ObjectRecordForSelect } from '@/object-record/relation-picker/hooks/useMultiObjectSearch'; +import { useRelationPickerEntitiesOptions } from '@/object-record/relation-picker/hooks/useRelationPickerEntitiesOptions'; +import { RelationPickerScopeInternalContext } from '@/object-record/relation-picker/scopes/scope-internal-context/RelationPickerScopeInternalContext'; +import { EntityForSelect } from '@/object-record/relation-picker/types/EntityForSelect'; +import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId'; +import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; + +export const RelationFromManyFieldInputMultiRecordsEffect = () => { + const { fieldValue, fieldDefinition } = useRelationField<EntityForSelect[]>(); + const scopeId = useAvailableScopeIdOrThrow( + RelationPickerScopeInternalContext, + ); + const { + objectRecordsIdsMultiSelectState, + objectRecordMultiSelectCheckedRecordsIdsState, + recordMultiSelectIsLoadingState, + } = useObjectRecordMultiSelectScopedStates(scopeId); + const [objectRecordsIdsMultiSelect, setObjectRecordsIdsMultiSelect] = + useRecoilState(objectRecordsIdsMultiSelectState); + + const { entities } = useRelationPickerEntitiesOptions({ + relationObjectNameSingular: + fieldDefinition.metadata.relationObjectMetadataNameSingular, + }); + + const setRecordMultiSelectIsLoading = useSetRecoilState( + recordMultiSelectIsLoadingState, + ); + + const { objectMetadataItem } = useObjectMetadataItem({ + objectNameSingular: + fieldDefinition.metadata.relationObjectMetadataNameSingular, + }); + + const allRecords = useMemo( + () => [ + ...entities.entitiesToSelect.map((entity) => { + const { record, ...recordIdentifier } = entity; + return { + objectMetadataItem: objectMetadataItem, + record: record, + recordIdentifier: recordIdentifier, + }; + }), + ], + [entities.entitiesToSelect, objectMetadataItem], + ); + + const [ + objectRecordMultiSelectCheckedRecordsIds, + setObjectRecordMultiSelectCheckedRecordsIds, + ] = useRecoilState(objectRecordMultiSelectCheckedRecordsIdsState); + + const updateRecords = useRecoilCallback( + ({ snapshot, set }) => + (newRecords: ObjectRecordForSelect[]) => { + for (const newRecord of newRecords) { + const currentRecord = snapshot + .getLoadable( + objectRecordMultiSelectComponentFamilyState({ + scopeId: scopeId, + familyKey: newRecord.record.id, + }), + ) + .getValue(); + + const newRecordWithSelected = { + ...newRecord, + selected: objectRecordMultiSelectCheckedRecordsIds.includes( + newRecord.record.id, + ), + }; + + if ( + !isDeeplyEqual( + newRecordWithSelected.selected, + currentRecord?.selected, + ) + ) { + set( + objectRecordMultiSelectComponentFamilyState({ + scopeId: scopeId, + familyKey: newRecordWithSelected.record.id, + }), + newRecordWithSelected, + ); + } + } + }, + [objectRecordMultiSelectCheckedRecordsIds, scopeId], + ); + + useEffect(() => { + updateRecords(allRecords); + const allRecordsIds = allRecords.map((record) => record.record.id); + if (!isDeeplyEqual(allRecordsIds, objectRecordsIdsMultiSelect)) { + setObjectRecordsIdsMultiSelect(allRecordsIds); + } + }, [ + allRecords, + objectRecordsIdsMultiSelect, + setObjectRecordsIdsMultiSelect, + updateRecords, + ]); + + useEffect(() => { + setObjectRecordMultiSelectCheckedRecordsIds( + fieldValue + ? fieldValue.map((fieldValueItem: EntityForSelect) => fieldValueItem.id) + : [], + ); + }, [fieldValue, setObjectRecordMultiSelectCheckedRecordsIds]); + + useEffect(() => { + setRecordMultiSelectIsLoading(entities.loading); + }, [entities.loading, setRecordMultiSelectIsLoading]); + + return <></>; +}; diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/RelationManyFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/RelationManyFieldInput.tsx deleted file mode 100644 index 9e3629528463..000000000000 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/RelationManyFieldInput.tsx +++ /dev/null @@ -1,82 +0,0 @@ -import { useMemo } from 'react'; - -import { ObjectMetadataItemsRelationPickerEffect } from '@/object-metadata/components/ObjectMetadataItemsRelationPickerEffect'; -import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; -import { useUpdateRelationManyFieldInput } from '@/object-record/record-field/meta-types/input/hooks/useUpdateRelationManyFieldInput'; -import { useInlineCell } from '@/object-record/record-inline-cell/hooks/useInlineCell'; -import { MultiRecordSelect } from '@/object-record/relation-picker/components/MultiRecordSelect'; -import { useRelationPicker } from '@/object-record/relation-picker/hooks/useRelationPicker'; -import { useRelationPickerEntitiesOptions } from '@/object-record/relation-picker/hooks/useRelationPickerEntitiesOptions'; -import { EntityForSelect } from '@/object-record/relation-picker/types/EntityForSelect'; - -import { useRelationField } from '../../hooks/useRelationField'; - -export const RelationManyFieldInput = ({ - relationPickerScopeId = 'relation-picker', -}: { - relationPickerScopeId?: string; -}) => { - const { closeInlineCell: closeEditableField } = useInlineCell(); - - const { fieldDefinition, fieldValue } = useRelationField<EntityForSelect[]>(); - const { entities, relationPickerSearchFilter } = - useRelationPickerEntitiesOptions({ - relationObjectNameSingular: - fieldDefinition.metadata.relationObjectMetadataNameSingular, - relationPickerScopeId, - }); - - const { setRelationPickerSearchFilter } = useRelationPicker({ - relationPickerScopeId, - }); - - const { handleChange } = useUpdateRelationManyFieldInput({ entities }); - - const { objectMetadataItem } = useObjectMetadataItem({ - objectNameSingular: - fieldDefinition.metadata.relationObjectMetadataNameSingular, - }); - const allRecords = useMemo( - () => [ - ...entities.entitiesToSelect.map((entity) => { - const { record, ...recordIdentifier } = entity; - return { - objectMetadataItem: objectMetadataItem, - record: record, - recordIdentifier: recordIdentifier, - }; - }), - ], - [entities.entitiesToSelect, objectMetadataItem], - ); - - const selectedRecords = useMemo( - () => - allRecords.filter( - (entity) => - fieldValue?.some((f) => { - return f.id === entity.recordIdentifier.id; - }), - ), - [allRecords, fieldValue], - ); - - return ( - <> - <ObjectMetadataItemsRelationPickerEffect - relationPickerScopeId={relationPickerScopeId} - /> - <MultiRecordSelect - allRecords={allRecords} - selectedObjectRecords={selectedRecords} - loading={entities.loading} - searchFilter={relationPickerSearchFilter} - setSearchFilter={setRelationPickerSearchFilter} - onSubmit={() => { - closeEditableField(); - }} - onChange={handleChange} - /> - </> - ); -}; diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/RelationFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/RelationToOneFieldInput.tsx similarity index 90% rename from packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/RelationFieldInput.tsx rename to packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/RelationToOneFieldInput.tsx index ed752bef9130..5366907c9332 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/RelationFieldInput.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/RelationToOneFieldInput.tsx @@ -14,15 +14,15 @@ const StyledRelationPickerContainer = styled.div` top: -1px; `; -export type RelationFieldInputProps = { +export type RelationToOneFieldInputProps = { onSubmit?: FieldInputEvent; onCancel?: () => void; }; -export const RelationFieldInput = ({ +export const RelationToOneFieldInput = ({ onSubmit, onCancel, -}: RelationFieldInputProps) => { +}: RelationToOneFieldInputProps) => { const { fieldDefinition, initialSearchValue, fieldValue } = useRelationField<EntityForSelect>(); diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/SelectFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/SelectFieldInput.tsx index 0f745de75420..a1d9a8631a72 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/SelectFieldInput.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/SelectFieldInput.tsx @@ -1,7 +1,8 @@ -import React, { useRef, useState } from 'react'; import styled from '@emotion/styled'; +import { useRef, useState } from 'react'; import { Key } from 'ts-key-enum'; +import { useClearField } from '@/object-record/record-field/hooks/useClearField'; import { useSelectField } from '@/object-record/record-field/meta-types/hooks/useSelectField'; import { FieldInputEvent } from '@/object-record/record-field/types/FieldInputEvent'; import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu'; @@ -30,12 +31,15 @@ export const SelectFieldInput = ({ }: SelectFieldInputProps) => { const { persistField, fieldDefinition, fieldValue, hotkeyScope } = useSelectField(); + const clearField = useClearField(); + const [searchFilter, setSearchFilter] = useState(''); const containerRef = useRef<HTMLDivElement>(null); const selectedOption = fieldDefinition.metadata.options.find( (option) => option.value === fieldValue, ); + const optionsToSelect = fieldDefinition.metadata.options.filter((option) => { return ( @@ -43,10 +47,17 @@ export const SelectFieldInput = ({ option.label.toLowerCase().includes(searchFilter.toLowerCase()) ); }) || []; + const optionsInDropDown = selectedOption ? [selectedOption, ...optionsToSelect] : optionsToSelect; + // handlers + const handleClearField = () => { + clearField(); + onCancel?.(); + }; + useListenClickOutside({ refs: [containerRef], callback: (event) => { @@ -85,7 +96,19 @@ export const SelectFieldInput = ({ autoFocus /> <DropdownMenuSeparator /> + <DropdownMenuItemsContainer hasMaxHeight> + {fieldDefinition.metadata.isNullable && ( + <MenuItemSelectTag + key={`No ${fieldDefinition.label}`} + selected={false} + text={`No ${fieldDefinition.label}`} + color="transparent" + variant="outline" + onClick={handleClearField} + /> + )} + {optionsInDropDown.map((option) => { return ( <MenuItemSelectTag diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/DateTimeFieldInput.stories.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/DateTimeFieldInput.stories.tsx index 00813a0bb1a5..5a8d23898b32 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/DateTimeFieldInput.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/DateTimeFieldInput.stories.tsx @@ -12,7 +12,7 @@ import { DateTimeFieldInputProps, } from '../DateTimeFieldInput'; -const formattedDate = new Date(2022, 1, 1); +const formattedDate = new Date(2022, 0, 1, 2, 0, 0); const DateFieldValueSetterEffect = ({ value }: { value: Date }) => { const { setFieldValue } = useDateTimeField(); @@ -126,9 +126,9 @@ type Story = StoryObj<typeof DateFieldInputWithContext>; export const Default: Story = { play: async ({ canvasElement }) => { const canvas = within(canvasElement); - const div = await canvas.findByText('February'); + const div = await canvas.findByText('January'); - await expect(div.innerText).toContain('February'); + await expect(div.innerText).toContain('January'); }, }; @@ -138,7 +138,7 @@ export const ClickOutside: Story = { await expect(clickOutsideJestFn).toHaveBeenCalledTimes(0); - await canvas.findByText('February'); + await canvas.findByText('January'); const emptyDiv = canvas.getByTestId('data-field-input-click-outside-div'); await userEvent.click(emptyDiv); @@ -151,7 +151,7 @@ export const Escape: Story = { await expect(escapeJestFn).toHaveBeenCalledTimes(0); const canvas = within(canvasElement); - await canvas.findByText('February'); + await canvas.findByText('January'); await userEvent.keyboard('{escape}'); await expect(escapeJestFn).toHaveBeenCalledTimes(1); @@ -163,7 +163,7 @@ export const Enter: Story = { await expect(enterJestFn).toHaveBeenCalledTimes(0); const canvas = within(canvasElement); - await canvas.findByText('February'); + await canvas.findByText('January'); await userEvent.keyboard('{enter}'); await expect(enterJestFn).toHaveBeenCalledTimes(1); diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/RelationManyFieldInput.stories.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/RelationManyFieldInput.stories.tsx index b768056cb87f..a02b1ffb38d1 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/RelationManyFieldInput.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/RelationManyFieldInput.stories.tsx @@ -5,7 +5,7 @@ import { useSetRecoilState } from 'recoil'; import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; -import { RelationManyFieldInput } from '@/object-record/record-field/meta-types/input/components/RelationManyFieldInput'; +import { RelationFromManyFieldInput } from '@/object-record/record-field/meta-types/input/components/RelationFromManyFieldInput'; import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope'; import { FieldMetadataType } from '~/generated/graphql'; import { ComponentWithRecoilScopeDecorator } from '~/testing/decorators/ComponentWithRecoilScopeDecorator'; @@ -45,22 +45,21 @@ const RelationManyFieldInputWithContext = () => { <FieldContextProvider fieldDefinition={{ fieldMetadataId: 'relation', - label: 'Relation', + label: 'People', type: FieldMetadataType.Relation, iconName: 'IconLink', metadata: { - fieldName: 'Relation', - relationObjectMetadataNamePlural: 'workspaceMembers', - relationObjectMetadataNameSingular: - CoreObjectNameSingular.WorkspaceMember, - objectMetadataNameSingular: 'person', + fieldName: 'people', + relationObjectMetadataNamePlural: 'companies', + relationObjectMetadataNameSingular: CoreObjectNameSingular.Company, + objectMetadataNameSingular: 'company', relationFieldMetadataId: '20202020-8c37-4163-ba06-1dada334ce3e', }, }} entityId={'entityId'} > <RelationWorkspaceSetterEffect /> - <RelationManyFieldInput /> + <RelationFromManyFieldInput /> </FieldContextProvider> <div data-testid="data-field-input-click-outside-div" /> </div> diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/RelationFieldInput.stories.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/RelationToOneFieldInput.stories.tsx similarity index 83% rename from packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/RelationFieldInput.stories.tsx rename to packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/RelationToOneFieldInput.stories.tsx index 9874373e81fd..30b723880b7b 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/RelationFieldInput.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/RelationToOneFieldInput.stories.tsx @@ -13,6 +13,7 @@ import { useSetRecoilState } from 'recoil'; import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; +import { RelationPickerScope } from '@/object-record/relation-picker/scopes/RelationPickerScope'; import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope'; import { FieldMetadataType } from '~/generated/graphql'; import { ComponentWithRecoilScopeDecorator } from '~/testing/decorators/ComponentWithRecoilScopeDecorator'; @@ -26,9 +27,9 @@ import { import { FieldContextProvider } from '../../../__stories__/FieldContextProvider'; import { - RelationFieldInput, - RelationFieldInputProps, -} from '../RelationFieldInput'; + RelationToOneFieldInput, + RelationToOneFieldInputProps, +} from '../RelationToOneFieldInput'; const RelationWorkspaceSetterEffect = () => { const setCurrentWorkspace = useSetRecoilState(currentWorkspaceState); @@ -44,16 +45,16 @@ const RelationWorkspaceSetterEffect = () => { return <></>; }; -type RelationFieldInputWithContextProps = RelationFieldInputProps & { +type RelationToOneFieldInputWithContextProps = RelationToOneFieldInputProps & { value: number; entityId?: string; }; -const RelationFieldInputWithContext = ({ +const RelationToOneFieldInputWithContext = ({ entityId, onSubmit, onCancel, -}: RelationFieldInputWithContextProps) => { +}: RelationToOneFieldInputWithContextProps) => { const setHotKeyScope = useSetHotkeyScope(); useEffect(() => { @@ -79,8 +80,12 @@ const RelationFieldInputWithContext = ({ }} entityId={entityId} > - <RelationWorkspaceSetterEffect /> - <RelationFieldInput onSubmit={onSubmit} onCancel={onCancel} /> + <RelationPickerScope + relationPickerScopeId={'relation-to-one-field-input'} + > + <RelationWorkspaceSetterEffect /> + <RelationToOneFieldInput onSubmit={onSubmit} onCancel={onCancel} /> + </RelationPickerScope> </FieldContextProvider> <div data-testid="data-field-input-click-outside-div" /> </div> @@ -99,8 +104,8 @@ const clearMocksDecorator: Decorator = (Story, context) => { }; const meta: Meta = { - title: 'UI/Data/Field/Input/RelationFieldInput', - component: RelationFieldInputWithContext, + title: 'UI/Data/Field/Input/RelationToOneFieldInput', + component: RelationToOneFieldInputWithContext, args: { useEditButton: true, onSubmit: submitJestFn, @@ -123,7 +128,7 @@ const meta: Meta = { export default meta; -type Story = StoryObj<typeof RelationFieldInputWithContext>; +type Story = StoryObj<typeof RelationToOneFieldInputWithContext>; export const Default: Story = { decorators: [ComponentWithRecoilScopeDecorator], diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/hooks/useUpdateRelationFromManyFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/hooks/useUpdateRelationFromManyFieldInput.tsx new file mode 100644 index 000000000000..ec07c96c205c --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/hooks/useUpdateRelationFromManyFieldInput.tsx @@ -0,0 +1,93 @@ +import { useContext } from 'react'; +import { useRecoilCallback } from 'recoil'; + +import { useAttachRelatedRecordFromRecord } from '@/object-record/hooks/useAttachRelatedRecordFromRecord'; +import { useDetachRelatedRecordFromRecord } from '@/object-record/hooks/useDetachRelatedRecordFromRecord'; +import { FieldContext } from '@/object-record/record-field/contexts/FieldContext'; +import { objectRecordMultiSelectCheckedRecordsIdsComponentState } from '@/object-record/record-field/states/objectRecordMultiSelectCheckedRecordsIdsComponentState'; +import { assertFieldMetadata } from '@/object-record/record-field/types/guards/assertFieldMetadata'; +import { isFieldRelation } from '@/object-record/record-field/types/guards/isFieldRelation'; +import { FieldMetadataType } from '~/generated-metadata/graphql'; + +export const useUpdateRelationFromManyFieldInput = ({ + scopeId, +}: { + scopeId: string; +}) => { + const { entityId, fieldDefinition } = useContext(FieldContext); + + assertFieldMetadata( + FieldMetadataType.Relation, + isFieldRelation, + fieldDefinition, + ); + + if (!fieldDefinition.metadata.objectMetadataNameSingular) { + throw new Error('ObjectMetadataNameSingular is required'); + } + + const { updateOneRecordAndDetachRelations } = + useDetachRelatedRecordFromRecord({ + recordObjectNameSingular: + fieldDefinition.metadata.objectMetadataNameSingular, + fieldNameOnRecordObject: fieldDefinition.metadata.fieldName, + }); + + const { updateOneRecordAndAttachRelations } = + useAttachRelatedRecordFromRecord({ + recordObjectNameSingular: + fieldDefinition.metadata.objectMetadataNameSingular, + fieldNameOnRecordObject: fieldDefinition.metadata.fieldName, + }); + + const updateRelation = useRecoilCallback( + ({ snapshot, set }) => + async (objectRecordId: string) => { + const previouslyCheckedRecordsIds = snapshot + .getLoadable( + objectRecordMultiSelectCheckedRecordsIdsComponentState({ + scopeId, + }), + ) + .getValue(); + + const isNewlySelected = + !previouslyCheckedRecordsIds.includes(objectRecordId); + if (isNewlySelected) { + set( + objectRecordMultiSelectCheckedRecordsIdsComponentState({ + scopeId, + }), + (prev) => [...prev, objectRecordId], + ); + } else { + set( + objectRecordMultiSelectCheckedRecordsIdsComponentState({ + scopeId, + }), + (prev) => prev.filter((id) => id !== objectRecordId), + ); + } + + if (isNewlySelected) { + await updateOneRecordAndAttachRelations({ + recordId: entityId, + relatedRecordId: objectRecordId, + }); + } else { + await updateOneRecordAndDetachRelations({ + recordId: entityId, + relatedRecordId: objectRecordId, + }); + } + }, + [ + entityId, + scopeId, + updateOneRecordAndAttachRelations, + updateOneRecordAndDetachRelations, + ], + ); + + return { updateRelation }; +}; diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/hooks/useUpdateRelationManyFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/hooks/useUpdateRelationManyFieldInput.tsx deleted file mode 100644 index a0d274418af5..000000000000 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/hooks/useUpdateRelationManyFieldInput.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord'; -import { useRelationField } from '@/object-record/record-field/meta-types/hooks/useRelationField'; -import { ObjectRecordForSelect } from '@/object-record/relation-picker/hooks/useMultiObjectSearch'; -import { EntitiesForMultipleEntitySelect } from '@/object-record/relation-picker/types/EntitiesForMultipleEntitySelect'; -import { EntityForSelect } from '@/object-record/relation-picker/types/EntityForSelect'; -import { isDefined } from '~/utils/isDefined'; - -export const useUpdateRelationManyFieldInput = ({ - entities, -}: { - entities: EntitiesForMultipleEntitySelect<EntityForSelect>; -}) => { - const { fieldDefinition, fieldValue, setFieldValue, entityId } = - useRelationField<EntityForSelect[]>(); - - const { updateOneRecord } = useUpdateOneRecord({ - objectNameSingular: - fieldDefinition.metadata.relationObjectMetadataNameSingular, - }); - - const fieldName = fieldDefinition.metadata.targetFieldMetadataName; - - const handleChange = ( - objectRecord: ObjectRecordForSelect | null, - isSelected: boolean, - ) => { - const entityToAddOrRemove = entities.entitiesToSelect.find( - (entity) => entity.id === objectRecord?.recordIdentifier.id, - ); - - const updatedFieldValue = isSelected - ? [...(fieldValue ?? []), entityToAddOrRemove] - : (fieldValue ?? []).filter( - (value) => value.id !== objectRecord?.recordIdentifier.id, - ); - setFieldValue( - updatedFieldValue.filter((value) => - isDefined(value), - ) as EntityForSelect[], - ); - if (isDefined(objectRecord)) { - updateOneRecord({ - idToUpdate: objectRecord.record?.id, - updateOneRecordInput: { - [`${fieldName}Id`]: isSelected ? entityId : null, - }, - }); - } - }; - - return { handleChange }; -}; diff --git a/packages/twenty-front/src/modules/object-record/record-field/states/activityTargetObjectRecordFamilyState.ts b/packages/twenty-front/src/modules/object-record/record-field/states/activityTargetObjectRecordFamilyState.ts new file mode 100644 index 000000000000..45d54e009ce1 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-field/states/activityTargetObjectRecordFamilyState.ts @@ -0,0 +1,13 @@ +import { createFamilyState } from '@/ui/utilities/state/utils/createFamilyState'; + +export type ActivityTargetObjectRecord = { + activityTargetId: string | null; +}; + +export const activityTargetObjectRecordFamilyState = createFamilyState< + ActivityTargetObjectRecord, + string +>({ + key: 'activityTargetObjectRecordFamilyState', + defaultValue: { activityTargetId: null }, +}); diff --git a/packages/twenty-front/src/modules/object-record/record-field/states/lastShowPageRecordId.ts b/packages/twenty-front/src/modules/object-record/record-field/states/lastShowPageRecordId.ts new file mode 100644 index 000000000000..dce923b37bda --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-field/states/lastShowPageRecordId.ts @@ -0,0 +1,6 @@ +import { createState } from 'twenty-ui'; + +export const lastShowPageRecordIdState = createState<string | null>({ + key: 'lastShowPageRecordIdState', + defaultValue: null, +}); diff --git a/packages/twenty-front/src/modules/object-record/record-field/states/objectRecordMultiSelectCheckedRecordsIdsComponentState.ts b/packages/twenty-front/src/modules/object-record/record-field/states/objectRecordMultiSelectCheckedRecordsIdsComponentState.ts new file mode 100644 index 000000000000..4f51db21d8dd --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-field/states/objectRecordMultiSelectCheckedRecordsIdsComponentState.ts @@ -0,0 +1,7 @@ +import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; + +export const objectRecordMultiSelectCheckedRecordsIdsComponentState = + createComponentState<string[]>({ + key: 'objectRecordMultiSelectCheckedRecordsIdsComponentState', + defaultValue: [], + }); diff --git a/packages/twenty-front/src/modules/object-record/record-field/states/objectRecordMultiSelectComponentFamilyState.ts b/packages/twenty-front/src/modules/object-record/record-field/states/objectRecordMultiSelectComponentFamilyState.ts new file mode 100644 index 000000000000..0e15c962e11b --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-field/states/objectRecordMultiSelectComponentFamilyState.ts @@ -0,0 +1,12 @@ +import { ObjectRecordForSelect } from '@/object-record/relation-picker/hooks/useMultiObjectSearch'; +import { createComponentFamilyState } from '@/ui/utilities/state/component-state/utils/createComponentFamilyState'; + +export type ObjectRecordAndSelected = ObjectRecordForSelect & { + selected: boolean; +}; + +export const objectRecordMultiSelectComponentFamilyState = + createComponentFamilyState<ObjectRecordAndSelected | undefined, string>({ + key: 'objectRecordMultiSelectComponentFamilyState', + defaultValue: undefined, + }); diff --git a/packages/twenty-front/src/modules/object-record/record-field/states/recordMultiSelectIsLoadingComponentState.ts b/packages/twenty-front/src/modules/object-record/record-field/states/recordMultiSelectIsLoadingComponentState.ts new file mode 100644 index 000000000000..880207ecbeae --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-field/states/recordMultiSelectIsLoadingComponentState.ts @@ -0,0 +1,7 @@ +import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; + +export const recordMultiSelectIsLoadingComponentState = + createComponentState<boolean>({ + key: 'recordMultiSelectIsLoadingComponentState', + defaultValue: false, + }); diff --git a/packages/twenty-front/src/modules/object-record/record-field/states/recordPositionInternalState.ts b/packages/twenty-front/src/modules/object-record/record-field/states/recordPositionInternalState.ts new file mode 100644 index 000000000000..9b83e0dcd8d7 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-field/states/recordPositionInternalState.ts @@ -0,0 +1,6 @@ +import { createState } from 'twenty-ui'; + +export const recordPositionInternalState = createState<number | null>({ + key: 'recordPositionInternalState', + defaultValue: null, +}); diff --git a/packages/twenty-front/src/modules/object-record/record-field/types/CurrencyCode.ts b/packages/twenty-front/src/modules/object-record/record-field/types/CurrencyCode.ts index 71e58d242553..9e86b3c87939 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/types/CurrencyCode.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/types/CurrencyCode.ts @@ -10,7 +10,11 @@ export enum CurrencyCode { USD = 'USD', NOK = 'NOK', SEK = 'SEK', + BHT = 'BHT', MAD = 'MAD', QAR = 'QAR', AED = 'AED', + KRW = 'KRW', + BRL = 'BRL', + AUD = 'AUD', } diff --git a/packages/twenty-front/src/modules/object-record/record-field/types/FieldInputDraftValue.ts b/packages/twenty-front/src/modules/object-record/record-field/types/FieldInputDraftValue.ts index 0282ccd02f86..ae1d63e549eb 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/types/FieldInputDraftValue.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/types/FieldInputDraftValue.ts @@ -13,12 +13,12 @@ import { FieldNumberValue, FieldPhoneValue, FieldRatingValue, - FieldRelationValue, + FieldRelationFromManyValue, + FieldRelationToOneValue, FieldSelectValue, FieldTextValue, FieldUUidValue, } from '@/object-record/record-field/types/FieldMetadata'; -import { EntityForSelect } from '@/object-record/relation-picker/types/EntityForSelect'; export type FieldTextDraftValue = string; export type FieldNumberDraftValue = string; @@ -28,6 +28,7 @@ export type FieldEmailDraftValue = string; export type FieldSelectDraftValue = string; export type FieldMultiSelectDraftValue = string[]; export type FieldRelationDraftValue = string; +export type FieldRelationManyDraftValue = string[]; export type FieldLinkDraftValue = { url: string; label: string }; export type FieldLinksDraftValue = { primaryLinkLabel: string; @@ -79,12 +80,12 @@ export type FieldInputDraftValue<FieldValue> = FieldValue extends FieldTextValue ? FieldSelectDraftValue : FieldValue extends FieldMultiSelectValue ? FieldMultiSelectDraftValue - : FieldValue extends - | FieldRelationValue<EntityForSelect> - | FieldRelationValue<EntityForSelect[]> + : FieldValue extends FieldRelationToOneValue ? FieldRelationDraftValue - : FieldValue extends FieldAddressValue - ? FieldAddressDraftValue - : FieldValue extends FieldJsonValue - ? FieldJsonDraftValue - : never; + : FieldValue extends FieldRelationFromManyValue + ? FieldRelationManyDraftValue + : FieldValue extends FieldAddressValue + ? FieldAddressDraftValue + : FieldValue extends FieldJsonValue + ? FieldJsonDraftValue + : never; diff --git a/packages/twenty-front/src/modules/object-record/record-field/types/FieldMetadata.ts b/packages/twenty-front/src/modules/object-record/record-field/types/FieldMetadata.ts index f54794613652..3208e5debbae 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/types/FieldMetadata.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/types/FieldMetadata.ts @@ -1,7 +1,9 @@ import { ThemeColor } from 'twenty-ui'; import { RATING_VALUES } from '@/object-record/record-field/meta-types/constants/RatingValues'; +import { ZodHelperLiteral } from '@/object-record/record-field/types/ZodHelperLiteral'; import { EntityForSelect } from '@/object-record/relation-picker/types/EntityForSelect'; +import { WithNarrowedStringLiteralProperty } from '~/types/WithNarrowedStringLiteralProperty'; import { CurrencyCode } from './CurrencyCode'; @@ -110,10 +112,23 @@ export type FieldRelationMetadata = { useEditButton?: boolean; }; +export type FieldRelationOneMetadata = WithNarrowedStringLiteralProperty< + FieldRelationMetadata, + 'relationType', + 'TO_ONE_OBJECT' +>; + +export type FieldRelationManyMetadata = WithNarrowedStringLiteralProperty< + FieldRelationMetadata, + 'relationType', + 'FROM_MANY_OBJECTS' +>; + export type FieldSelectMetadata = { objectMetadataNameSingular?: string; fieldName: string; options: { label: string; color: ThemeColor; value: string }[]; + isNullable: boolean; }; export type FieldMultiSelectMetadata = { @@ -174,10 +189,13 @@ export type FieldRatingValue = (typeof RATING_VALUES)[number]; export type FieldSelectValue = string | null; export type FieldMultiSelectValue = string[] | null; -export type FieldRelationValue<T extends EntityForSelect | EntityForSelect[]> = - T | null; +export type FieldRelationToOneValue = EntityForSelect | null; + +export type FieldRelationFromManyValue = EntityForSelect[] | []; + +export type FieldRelationValue< + T extends FieldRelationToOneValue | FieldRelationFromManyValue, +> = T; -// See https://zod.dev/?id=json-type -type Literal = string | number | boolean | null; -export type Json = Literal | { [key: string]: Json } | Json[]; +export type Json = ZodHelperLiteral | { [key: string]: Json } | Json[]; export type FieldJsonValue = Record<string, Json> | Json[] | null; diff --git a/packages/twenty-front/src/modules/object-record/record-field/types/RecordChipData.ts b/packages/twenty-front/src/modules/object-record/record-field/types/RecordChipData.ts index 13eb99f84cd0..d6ef0c2f6948 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/types/RecordChipData.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/types/RecordChipData.ts @@ -2,8 +2,9 @@ import { AvatarType } from 'twenty-ui'; export type RecordChipData = { recordId: string; - name: string | number; + name: string; avatarType: AvatarType; avatarUrl: string; - linkToShowPage: string; + isLabelIdentifier: boolean; + objectNameSingular: string; }; diff --git a/packages/twenty-front/src/modules/object-record/record-field/types/ZodHelperLiteral.ts b/packages/twenty-front/src/modules/object-record/record-field/types/ZodHelperLiteral.ts new file mode 100644 index 000000000000..81c9b3dbde06 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-field/types/ZodHelperLiteral.ts @@ -0,0 +1,2 @@ +/** See https://zod.dev/?id=json-type */ +export type ZodHelperLiteral = string | number | boolean | null; diff --git a/packages/twenty-front/src/modules/object-record/record-field/types/guards/assertFieldMetadata.ts b/packages/twenty-front/src/modules/object-record/record-field/types/guards/assertFieldMetadata.ts index 9d1f8782848b..c82974a1a7b8 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/types/guards/assertFieldMetadata.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/types/guards/assertFieldMetadata.ts @@ -51,19 +51,17 @@ type AssertFieldMetadataFunction = < ? FieldNumberMetadata : E extends 'PHONE' ? FieldPhoneMetadata - : E extends 'PROBABILITY' - ? FieldRatingMetadata - : E extends 'RELATION' - ? FieldRelationMetadata - : E extends 'TEXT' - ? FieldTextMetadata - : E extends 'UUID' - ? FieldUuidMetadata - : E extends 'ADDRESS' - ? FieldAddressMetadata - : E extends 'RAW_JSON' - ? FieldRawJsonMetadata - : never, + : E extends 'RELATION' + ? FieldRelationMetadata + : E extends 'TEXT' + ? FieldTextMetadata + : E extends 'UUID' + ? FieldUuidMetadata + : E extends 'ADDRESS' + ? FieldAddressMetadata + : E extends 'RAW_JSON' + ? FieldRawJsonMetadata + : never, >( fieldType: E, fieldTypeGuard: ( diff --git a/packages/twenty-front/src/modules/object-record/record-field/types/guards/isFieldRelationFromManyObjects.ts b/packages/twenty-front/src/modules/object-record/record-field/types/guards/isFieldRelationFromManyObjects.ts index 03b56892afd6..03559df5d356 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/types/guards/isFieldRelationFromManyObjects.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/types/guards/isFieldRelationFromManyObjects.ts @@ -1,10 +1,9 @@ -import { FieldMetadataType } from '~/generated-metadata/graphql'; +import { isFieldRelation } from '@/object-record/record-field/types/guards/isFieldRelation'; import { FieldDefinition } from '../FieldDefinition'; -import { FieldRelationMetadata } from '../FieldMetadata'; +import { FieldMetadata, FieldRelationManyMetadata } from '../FieldMetadata'; export const isFieldRelationFromManyObjects = ( - field: Pick<FieldDefinition<FieldRelationMetadata>, 'type' | 'metadata'>, -): field is FieldDefinition<FieldRelationMetadata> => - field.type === FieldMetadataType.Relation && - field.metadata.relationType === 'FROM_MANY_OBJECTS'; + field: Pick<FieldDefinition<FieldMetadata>, 'type' | 'metadata'>, +): field is FieldDefinition<FieldRelationManyMetadata> => + isFieldRelation(field) && field.metadata.relationType === 'FROM_MANY_OBJECTS'; diff --git a/packages/twenty-front/src/modules/object-record/record-field/types/guards/isFieldRelationFromManyValue.ts b/packages/twenty-front/src/modules/object-record/record-field/types/guards/isFieldRelationFromManyValue.ts new file mode 100644 index 000000000000..a2d0df7d995c --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-field/types/guards/isFieldRelationFromManyValue.ts @@ -0,0 +1,9 @@ +import { isNull, isObject, isUndefined } from '@sniptt/guards'; + +import { FieldRelationFromManyValue } from '@/object-record/record-field/types/FieldMetadata'; + +// TODO: add zod +export const isFieldRelationFromManyValue = ( + fieldValue: unknown, +): fieldValue is FieldRelationFromManyValue => + !isUndefined(fieldValue) && (isObject(fieldValue) || isNull(fieldValue)); diff --git a/packages/twenty-front/src/modules/object-record/record-field/types/guards/isFieldRelationToOneObject.ts b/packages/twenty-front/src/modules/object-record/record-field/types/guards/isFieldRelationToOneObject.ts new file mode 100644 index 000000000000..d1a1bb365aab --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-field/types/guards/isFieldRelationToOneObject.ts @@ -0,0 +1,9 @@ +import { isFieldRelation } from '@/object-record/record-field/types/guards/isFieldRelation'; + +import { FieldDefinition } from '../FieldDefinition'; +import { FieldMetadata, FieldRelationOneMetadata } from '../FieldMetadata'; + +export const isFieldRelationToOneObject = ( + field: Pick<FieldDefinition<FieldMetadata>, 'type' | 'metadata'>, +): field is FieldDefinition<FieldRelationOneMetadata> => + isFieldRelation(field) && field.metadata.relationType === 'TO_ONE_OBJECT'; diff --git a/packages/twenty-front/src/modules/object-record/record-field/types/guards/isFieldRelationToOneValue.ts b/packages/twenty-front/src/modules/object-record/record-field/types/guards/isFieldRelationToOneValue.ts new file mode 100644 index 000000000000..dc1f5b3615a1 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-field/types/guards/isFieldRelationToOneValue.ts @@ -0,0 +1,9 @@ +import { isNull, isObject, isUndefined } from '@sniptt/guards'; + +import { FieldRelationToOneValue } from '@/object-record/record-field/types/FieldMetadata'; + +// TODO: add zod +export const isFieldRelationToOneValue = ( + fieldValue: unknown, +): fieldValue is FieldRelationToOneValue => + !isUndefined(fieldValue) && (isObject(fieldValue) || isNull(fieldValue)); diff --git a/packages/twenty-front/src/modules/object-record/record-field/types/guards/isFieldRelationValue.ts b/packages/twenty-front/src/modules/object-record/record-field/types/guards/isFieldRelationValue.ts deleted file mode 100644 index 1919c493e327..000000000000 --- a/packages/twenty-front/src/modules/object-record/record-field/types/guards/isFieldRelationValue.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { isNull, isObject, isUndefined } from '@sniptt/guards'; - -import { EntityForSelect } from '@/object-record/relation-picker/types/EntityForSelect'; - -import { FieldRelationValue } from '../FieldMetadata'; - -// TODO: add zod -export const isFieldRelationValue = < - T extends EntityForSelect | EntityForSelect[], ->( - fieldValue: unknown, -): fieldValue is FieldRelationValue<T> => - !isUndefined(fieldValue) && (isObject(fieldValue) || isNull(fieldValue)); diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/turnObjectDropdownFilterIntoQueryFilter.ts b/packages/twenty-front/src/modules/object-record/record-filter/utils/turnObjectDropdownFilterIntoQueryFilter.ts index 3235ac572dbe..1b08eace5a6b 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/turnObjectDropdownFilterIntoQueryFilter.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter/utils/turnObjectDropdownFilterIntoQueryFilter.ts @@ -6,10 +6,12 @@ import { DateFilter, FloatFilter, RecordGqlOperationFilter, + RelationFilter, StringFilter, URLFilter, UUIDFilter, } from '@/object-record/graphql/types/RecordGqlOperationFilter'; +import { FilterType } from '@/object-record/object-filter-dropdown/types/FilterType'; import { makeAndFilterVariables } from '@/object-record/utils/makeAndFilterVariables'; import { ViewFilterOperand } from '@/views/types/ViewFilterOperand'; import { Field } from '~/generated/graphql'; @@ -24,6 +26,200 @@ export type ObjectDropdownFilter = Omit<Filter, 'definition'> & { }; }; +const applyEmptyFilters = ( + operand: ViewFilterOperand, + correspondingField: Pick<Field, 'id' | 'name'>, + objectRecordFilters: RecordGqlOperationFilter[], + filterType: FilterType, +) => { + let emptyRecordFilter: RecordGqlOperationFilter = {}; + + switch (filterType) { + case 'TEXT': + case 'EMAIL': + case 'PHONE': + emptyRecordFilter = { + or: [ + { [correspondingField.name]: { ilike: '' } as StringFilter }, + { [correspondingField.name]: { is: 'NULL' } as StringFilter }, + ], + }; + break; + case 'CURRENCY': + emptyRecordFilter = { + or: [ + { + [correspondingField.name]: { + amountMicros: { is: 'NULL' }, + } as CurrencyFilter, + }, + ], + }; + break; + case 'FULL_NAME': { + const fullNameFilters = generateILikeFiltersForCompositeFields( + '', + correspondingField.name, + ['firstName', 'lastName'], + true, + ); + + emptyRecordFilter = { + and: fullNameFilters, + }; + break; + } + case 'LINK': + emptyRecordFilter = { + or: [ + { [correspondingField.name]: { url: { ilike: '' } } as URLFilter }, + { + [correspondingField.name]: { url: { is: 'NULL' } } as URLFilter, + }, + ], + }; + break; + case 'LINKS': { + const linksFilters = generateILikeFiltersForCompositeFields( + '', + correspondingField.name, + ['primaryLinkLabel', 'primaryLinkUrl'], + true, + ); + + emptyRecordFilter = { + and: linksFilters, + }; + break; + } + case 'ADDRESS': + emptyRecordFilter = { + and: [ + { + or: [ + { + [correspondingField.name]: { + addressStreet1: { ilike: '' }, + } as AddressFilter, + }, + { + [correspondingField.name]: { + addressStreet1: { is: 'NULL' }, + } as AddressFilter, + }, + ], + }, + { + or: [ + { + [correspondingField.name]: { + addressStreet2: { ilike: '' }, + } as AddressFilter, + }, + { + [correspondingField.name]: { + addressStreet2: { is: 'NULL' }, + } as AddressFilter, + }, + ], + }, + { + or: [ + { + [correspondingField.name]: { + addressCity: { ilike: '' }, + } as AddressFilter, + }, + { + [correspondingField.name]: { + addressCity: { is: 'NULL' }, + } as AddressFilter, + }, + ], + }, + { + or: [ + { + [correspondingField.name]: { + addressState: { ilike: '' }, + } as AddressFilter, + }, + { + [correspondingField.name]: { + addressState: { is: 'NULL' }, + } as AddressFilter, + }, + ], + }, + { + or: [ + { + [correspondingField.name]: { + addressCountry: { ilike: '' }, + } as AddressFilter, + }, + { + [correspondingField.name]: { + addressCountry: { is: 'NULL' }, + } as AddressFilter, + }, + ], + }, + { + or: [ + { + [correspondingField.name]: { + addressPostcode: { ilike: '' }, + } as AddressFilter, + }, + { + [correspondingField.name]: { + addressPostcode: { is: 'NULL' }, + } as AddressFilter, + }, + ], + }, + ], + }; + break; + case 'NUMBER': + emptyRecordFilter = { + [correspondingField.name]: { is: 'NULL' } as FloatFilter, + }; + break; + case 'DATE_TIME': + emptyRecordFilter = { + [correspondingField.name]: { is: 'NULL' } as DateFilter, + }; + break; + case 'SELECT': + emptyRecordFilter = { + [correspondingField.name]: { is: 'NULL' } as UUIDFilter, + }; + break; + case 'RELATION': + emptyRecordFilter = { + [correspondingField.name + 'Id']: { is: 'NULL' } as RelationFilter, + }; + break; + default: + throw new Error(`Unsupported empty filter type ${filterType}`); + } + + switch (operand) { + case ViewFilterOperand.IsEmpty: + objectRecordFilters.push(emptyRecordFilter); + break; + case ViewFilterOperand.IsNotEmpty: + objectRecordFilters.push({ + not: emptyRecordFilter, + }); + break; + default: + throw new Error(`Unknown operand ${operand} for ${filterType} filter`); + } +}; + export const turnObjectDropdownFilterIntoQueryFilter = ( rawUIFilters: ObjectDropdownFilter[], fields: Pick<Field, 'id' | 'name'>[], @@ -35,12 +231,19 @@ export const turnObjectDropdownFilterIntoQueryFilter = ( (field) => field.id === rawUIFilter.fieldMetadataId, ); + const isEmptyOperand = [ + ViewFilterOperand.IsEmpty, + ViewFilterOperand.IsNotEmpty, + ].includes(rawUIFilter.operand); + if (!correspondingField) { continue; } - if (!isDefined(rawUIFilter.value) || rawUIFilter.value === '') { - continue; + if (!isEmptyOperand) { + if (!isDefined(rawUIFilter.value) || rawUIFilter.value === '') { + continue; + } } switch (rawUIFilter.definition.type) { @@ -64,6 +267,15 @@ export const turnObjectDropdownFilterIntoQueryFilter = ( }, }); break; + case ViewFilterOperand.IsEmpty: + case ViewFilterOperand.IsNotEmpty: + applyEmptyFilters( + rawUIFilter.operand, + correspondingField, + objectRecordFilters, + rawUIFilter.definition.type, + ); + break; default: throw new Error( `Unknown operand ${rawUIFilter.operand} for ${rawUIFilter.definition.type} filter`, @@ -86,6 +298,15 @@ export const turnObjectDropdownFilterIntoQueryFilter = ( } as DateFilter, }); break; + case ViewFilterOperand.IsEmpty: + case ViewFilterOperand.IsNotEmpty: + applyEmptyFilters( + rawUIFilter.operand, + correspondingField, + objectRecordFilters, + rawUIFilter.definition.type, + ); + break; default: throw new Error( `Unknown operand ${rawUIFilter.operand} for ${rawUIFilter.definition.type} filter`, @@ -108,6 +329,15 @@ export const turnObjectDropdownFilterIntoQueryFilter = ( } as FloatFilter, }); break; + case ViewFilterOperand.IsEmpty: + case ViewFilterOperand.IsNotEmpty: + applyEmptyFilters( + rawUIFilter.operand, + correspondingField, + objectRecordFilters, + rawUIFilter.definition.type, + ); + break; default: throw new Error( `Unknown operand ${rawUIFilter.operand} for ${rawUIFilter.definition.type} filter`, @@ -115,39 +345,57 @@ export const turnObjectDropdownFilterIntoQueryFilter = ( } break; case 'RELATION': { - try { - JSON.parse(rawUIFilter.value); - } catch (e) { - throw new Error( - `Cannot parse filter value for RELATION filter : "${rawUIFilter.value}"`, - ); - } + if (!isEmptyOperand) { + try { + JSON.parse(rawUIFilter.value); + } catch (e) { + throw new Error( + `Cannot parse filter value for RELATION filter : "${rawUIFilter.value}"`, + ); + } - const parsedRecordIds = JSON.parse(rawUIFilter.value) as string[]; + const parsedRecordIds = JSON.parse(rawUIFilter.value) as string[]; - if (parsedRecordIds.length > 0) { - switch (rawUIFilter.operand) { - case ViewFilterOperand.Is: - objectRecordFilters.push({ - [correspondingField.name + 'Id']: { - in: parsedRecordIds, - } as UUIDFilter, - }); - break; - case ViewFilterOperand.IsNot: - if (parsedRecordIds.length > 0) { + if (parsedRecordIds.length > 0) { + switch (rawUIFilter.operand) { + case ViewFilterOperand.Is: objectRecordFilters.push({ - not: { - [correspondingField.name + 'Id']: { - in: parsedRecordIds, - } as UUIDFilter, - }, + [correspondingField.name + 'Id']: { + in: parsedRecordIds, + } as RelationFilter, }); - } + break; + case ViewFilterOperand.IsNot: + if (parsedRecordIds.length > 0) { + objectRecordFilters.push({ + not: { + [correspondingField.name + 'Id']: { + in: parsedRecordIds, + } as RelationFilter, + }, + }); + } + break; + default: + throw new Error( + `Unknown operand ${rawUIFilter.operand} for ${rawUIFilter.definition.type} filter`, + ); + } + } + } else { + switch (rawUIFilter.operand) { + case ViewFilterOperand.IsEmpty: + case ViewFilterOperand.IsNotEmpty: + applyEmptyFilters( + rawUIFilter.operand, + correspondingField, + objectRecordFilters, + rawUIFilter.definition.type, + ); break; default: throw new Error( - `Unknown operand ${rawUIFilter.operand} for ${rawUIFilter.definition.type} filter`, + `Unknown empty operand ${rawUIFilter.operand} for ${rawUIFilter.definition.type} filter`, ); } } @@ -169,6 +417,15 @@ export const turnObjectDropdownFilterIntoQueryFilter = ( } as CurrencyFilter, }); break; + case ViewFilterOperand.IsEmpty: + case ViewFilterOperand.IsNotEmpty: + applyEmptyFilters( + rawUIFilter.operand, + correspondingField, + objectRecordFilters, + rawUIFilter.definition.type, + ); + break; default: throw new Error( `Unknown operand ${rawUIFilter.operand} for ${rawUIFilter.definition.type} filter`, @@ -197,6 +454,15 @@ export const turnObjectDropdownFilterIntoQueryFilter = ( }, }); break; + case ViewFilterOperand.IsEmpty: + case ViewFilterOperand.IsNotEmpty: + applyEmptyFilters( + rawUIFilter.operand, + correspondingField, + objectRecordFilters, + rawUIFilter.definition.type, + ); + break; default: throw new Error( `Unknown operand ${rawUIFilter.operand} for ${rawUIFilter.definition.type} filter`, @@ -224,6 +490,15 @@ export const turnObjectDropdownFilterIntoQueryFilter = ( }), }); break; + case ViewFilterOperand.IsEmpty: + case ViewFilterOperand.IsNotEmpty: + applyEmptyFilters( + rawUIFilter.operand, + correspondingField, + objectRecordFilters, + rawUIFilter.definition.type, + ); + break; default: throw new Error( `Unknown operand ${rawUIFilter.operand} for ${rawUIFilter.definition.type} filter`, @@ -231,7 +506,6 @@ export const turnObjectDropdownFilterIntoQueryFilter = ( } break; } - case 'FULL_NAME': { const fullNameFilters = generateILikeFiltersForCompositeFields( rawUIFilter.value, @@ -253,6 +527,15 @@ export const turnObjectDropdownFilterIntoQueryFilter = ( }), }); break; + case ViewFilterOperand.IsEmpty: + case ViewFilterOperand.IsNotEmpty: + applyEmptyFilters( + rawUIFilter.operand, + correspondingField, + objectRecordFilters, + rawUIFilter.definition.type, + ); + break; default: throw new Error( `Unknown operand ${rawUIFilter.operand} for ${rawUIFilter.definition.type} filter`, @@ -286,6 +569,27 @@ export const turnObjectDropdownFilterIntoQueryFilter = ( }, } as AddressFilter, }, + { + [correspondingField.name]: { + addressState: { + ilike: `%${rawUIFilter.value}%`, + }, + } as AddressFilter, + }, + { + [correspondingField.name]: { + addressCountry: { + ilike: `%${rawUIFilter.value}%`, + }, + } as AddressFilter, + }, + { + [correspondingField.name]: { + addressPostcode: { + ilike: `%${rawUIFilter.value}%`, + }, + } as AddressFilter, + }, ], }); break; @@ -322,6 +626,15 @@ export const turnObjectDropdownFilterIntoQueryFilter = ( ], }); break; + case ViewFilterOperand.IsEmpty: + case ViewFilterOperand.IsNotEmpty: + applyEmptyFilters( + rawUIFilter.operand, + correspondingField, + objectRecordFilters, + rawUIFilter.definition.type, + ); + break; default: throw new Error( `Unknown operand ${rawUIFilter.operand} for ${rawUIFilter.definition.type} filter`, @@ -329,6 +642,15 @@ export const turnObjectDropdownFilterIntoQueryFilter = ( } break; case 'SELECT': { + if (isEmptyOperand) { + applyEmptyFilters( + rawUIFilter.operand, + correspondingField, + objectRecordFilters, + rawUIFilter.definition.type, + ); + break; + } const stringifiedSelectValues = rawUIFilter.value; let parsedOptionValues: string[] = []; diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexBoardColumnLoaderEffect.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexBoardColumnLoaderEffect.tsx index 804df9806dd5..e9c909b72418 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexBoardColumnLoaderEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexBoardColumnLoaderEffect.tsx @@ -1,9 +1,10 @@ import { useEffect } from 'react'; -import { useRecoilState } from 'recoil'; +import { useRecoilState, useSetRecoilState } from 'recoil'; import { isRecordBoardFetchingRecordsByColumnFamilyState } from '@/object-record/record-board/states/isRecordBoardFetchingRecordsByColumnFamilyState'; import { recordBoardShouldFetchMoreInColumnComponentFamilyState } from '@/object-record/record-board/states/recordBoardShouldFetchMoreInColumnComponentFamilyState'; import { useLoadRecordIndexBoardColumn } from '@/object-record/record-index/hooks/useLoadRecordIndexBoardColumn'; +import { isRecordIndexBoardColumnLoadingFamilyState } from '@/object-record/states/isRecordBoardColumnLoadingFamilyState'; import { getScopeIdFromComponentId } from '@/ui/utilities/recoil-scope/utils/getScopeIdFromComponentId'; export const RecordIndexBoardColumnLoaderEffect = ({ @@ -15,7 +16,7 @@ export const RecordIndexBoardColumnLoaderEffect = ({ }: { recordBoardId: string; objectNameSingular: string; - boardFieldSelectValue: string; + boardFieldSelectValue: string | null; boardFieldMetadataId: string | null; columnId: string; }) => { @@ -34,7 +35,7 @@ export const RecordIndexBoardColumnLoaderEffect = ({ }), ); - const { fetchMoreRecords, loading, hasNextPage } = + const { fetchMoreRecords, loading, records, hasNextPage } = useLoadRecordIndexBoardColumn({ objectNameSingular, recordBoardId, @@ -43,6 +44,14 @@ export const RecordIndexBoardColumnLoaderEffect = ({ columnId, }); + const setIsRecordIndexLoading = useSetRecoilState( + isRecordIndexBoardColumnLoadingFamilyState(columnId), + ); + + useEffect(() => { + setIsRecordIndexLoading(loading && records.length === 0); + }, [records, loading, setIsRecordIndexLoading]); + useEffect(() => { const run = async () => { if (!loading && shouldFetchMore && hasNextPage) { diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexBoardDataLoader.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexBoardDataLoader.tsx index d6ca8ddfd8ab..1906285f521f 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexBoardDataLoader.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexBoardDataLoader.tsx @@ -45,6 +45,15 @@ export const RecordIndexBoardDataLoader = ({ columnId={columnIds[index]} /> ))} + {recordIndexKanbanFieldMetadataItem?.isNullable && ( + <RecordIndexBoardColumnLoaderEffect + objectNameSingular={objectNameSingular} + boardFieldMetadataId={recordIndexKanbanFieldMetadataId} + boardFieldSelectValue={null} + recordBoardId={recordBoardId} + columnId={'no-value'} + /> + )} </> ); }; diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexBoardDataLoaderEffect.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexBoardDataLoaderEffect.tsx index b7b31f73c985..79c0e606817c 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexBoardDataLoaderEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexBoardDataLoaderEffect.tsx @@ -3,6 +3,7 @@ import { useNavigate } from 'react-router-dom'; import { useRecoilValue, useSetRecoilState } from 'recoil'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; +import { getObjectSlug } from '@/object-metadata/utils/getObjectSlug'; import { useRecordActionBar } from '@/object-record/record-action-bar/hooks/useRecordActionBar'; import { useRecordBoard } from '@/object-record/record-board/hooks/useRecordBoard'; import { useRecordBoardSelection } from '@/object-record/record-board/hooks/useRecordBoardSelection'; @@ -59,10 +60,9 @@ export const RecordIndexBoardDataLoaderEffect = ({ }, [recordIndexFieldDefinitions, setFieldDefinitions]); const navigate = useNavigate(); - const navigateToSelectSettings = useCallback(() => { - navigate(`/settings/objects/${objectMetadataItem.namePlural}`); - }, [navigate, objectMetadataItem.namePlural]); + navigate(`/settings/objects/${getObjectSlug(objectMetadataItem)}`); + }, [navigate, objectMetadataItem]); const { resetRecordSelection } = useRecordBoardSelection(recordBoardId); diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainer.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainer.tsx index 28b6aa9a6a9d..c7098481c06d 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainer.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainer.tsx @@ -1,15 +1,24 @@ import styled from '@emotion/styled'; -import { useRecoilCallback, useRecoilState, useSetRecoilState } from 'recoil'; +import { + useRecoilCallback, + useRecoilState, + useRecoilValue, + useSetRecoilState, +} from 'recoil'; import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural'; +import { turnSortsIntoOrderBy } from '@/object-record/object-sort-dropdown/utils/turnSortsIntoOrderBy'; +import { lastShowPageRecordIdState } from '@/object-record/record-field/states/lastShowPageRecordId'; +import { turnObjectDropdownFilterIntoQueryFilter } from '@/object-record/record-filter/utils/turnObjectDropdownFilterIntoQueryFilter'; import { RecordIndexBoardContainer } from '@/object-record/record-index/components/RecordIndexBoardContainer'; import { RecordIndexBoardDataLoader } from '@/object-record/record-index/components/RecordIndexBoardDataLoader'; import { RecordIndexBoardDataLoaderEffect } from '@/object-record/record-index/components/RecordIndexBoardDataLoaderEffect'; import { RecordIndexTableContainer } from '@/object-record/record-index/components/RecordIndexTableContainer'; import { RecordIndexTableContainerEffect } from '@/object-record/record-index/components/RecordIndexTableContainerEffect'; import { RecordIndexViewBarEffect } from '@/object-record/record-index/components/RecordIndexViewBarEffect'; +import { RecordIndexEventContext } from '@/object-record/record-index/contexts/RecordIndexEventContext'; import { RecordIndexOptionsDropdown } from '@/object-record/record-index/options/components/RecordIndexOptionsDropdown'; import { recordIndexFieldDefinitionsState } from '@/object-record/record-index/states/recordIndexFieldDefinitionsState'; import { recordIndexFiltersState } from '@/object-record/record-index/states/recordIndexFiltersState'; @@ -17,15 +26,22 @@ import { recordIndexIsCompactModeActiveState } from '@/object-record/record-inde import { recordIndexKanbanFieldMetadataIdState } from '@/object-record/record-index/states/recordIndexKanbanFieldMetadataIdState'; import { recordIndexSortsState } from '@/object-record/record-index/states/recordIndexSortsState'; import { recordIndexViewTypeState } from '@/object-record/record-index/states/recordIndexViewTypeState'; +import { useFindRecordCursorFromFindManyCacheRootQuery } from '@/object-record/record-show/hooks/useFindRecordCursorFromFindManyCacheRootQuery'; +import { findView } from '@/object-record/record-show/hooks/useRecordShowPagePagination'; import { RecordFieldValueSelectorContextProvider } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext'; import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable'; +import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData'; +import { PrefetchKey } from '@/prefetch/types/PrefetchKey'; import { SpreadsheetImportProvider } from '@/spreadsheet-import/provider/components/SpreadsheetImportProvider'; import { ViewBar } from '@/views/components/ViewBar'; +import { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState'; +import { View } from '@/views/types/View'; import { ViewField } from '@/views/types/ViewField'; import { ViewType } from '@/views/types/ViewType'; import { mapViewFieldsToColumnDefinitions } from '@/views/utils/mapViewFieldsToColumnDefinitions'; import { mapViewFiltersToFilters } from '@/views/utils/mapViewFiltersToFilters'; import { mapViewSortsToSorts } from '@/views/utils/mapViewSortsToSorts'; +import { useNavigate } from 'react-router-dom'; import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; const StyledContainer = styled.div` @@ -108,6 +124,63 @@ export const RecordIndexContainer = ({ [columnDefinitions, setTableColumns], ); + const navigate = useNavigate(); + + const { records: views } = usePrefetchedData<View>(PrefetchKey.AllViews); + + const currentViewId = useRecoilValue( + currentViewIdComponentState({ + scopeId: recordIndexId, + }), + ); + + const view = findView({ + objectMetadataItemId: objectMetadataItem?.id ?? '', + viewId: currentViewId ?? null, + views, + }); + + const filter = turnObjectDropdownFilterIntoQueryFilter( + mapViewFiltersToFilters(view?.viewFilters ?? [], filterDefinitions), + objectMetadataItem?.fields ?? [], + ); + + const orderBy = turnSortsIntoOrderBy( + objectMetadataItem, + mapViewSortsToSorts(view?.viewSorts ?? [], sortDefinitions), + ); + + const { findCursorInCache } = useFindRecordCursorFromFindManyCacheRootQuery({ + fieldVariables: { + filter, + orderBy, + }, + objectNamePlural: objectNamePlural, + }); + + const handleIndexIdentifierClick = (recordId: string) => { + const cursor = findCursorInCache(recordId); + + // TODO: use URL builder + navigate( + `/object/${objectNameSingular}/${recordId}?view=${currentViewId}`, + { + state: { + cursor, + }, + }, + ); + }; + + const handleIndexRecordsLoaded = useRecoilCallback( + ({ set }) => + () => { + // TODO: find a better way to reset this state ? + set(lastShowPageRecordIdState, null); + }, + [], + ); + return ( <StyledContainer> <RecordFieldValueSelectorContextProvider> @@ -153,41 +226,46 @@ export const RecordIndexContainer = ({ /> </StyledContainerWithPadding> </SpreadsheetImportProvider> - - {recordIndexViewType === ViewType.Table && ( - <> - <RecordIndexTableContainer - recordTableId={recordIndexId} - viewBarId={recordIndexId} - objectNameSingular={objectNameSingular} - createRecord={createRecord} - /> - <RecordIndexTableContainerEffect - objectNameSingular={objectNameSingular} - recordTableId={recordIndexId} - viewBarId={recordIndexId} - /> - </> - )} - - {recordIndexViewType === ViewType.Kanban && ( - <StyledContainerWithPadding> - <RecordIndexBoardContainer - recordBoardId={recordIndexId} - viewBarId={recordIndexId} - objectNameSingular={objectNameSingular} - createRecord={createRecord} - /> - <RecordIndexBoardDataLoader - objectNameSingular={objectNameSingular} - recordBoardId={recordIndexId} - /> - <RecordIndexBoardDataLoaderEffect - objectNameSingular={objectNameSingular} - recordBoardId={recordIndexId} - /> - </StyledContainerWithPadding> - )} + <RecordIndexEventContext.Provider + value={{ + onIndexIdentifierClick: handleIndexIdentifierClick, + onIndexRecordsLoaded: handleIndexRecordsLoaded, + }} + > + {recordIndexViewType === ViewType.Table && ( + <> + <RecordIndexTableContainer + recordTableId={recordIndexId} + viewBarId={recordIndexId} + objectNameSingular={objectNameSingular} + createRecord={createRecord} + /> + <RecordIndexTableContainerEffect + objectNameSingular={objectNameSingular} + recordTableId={recordIndexId} + viewBarId={recordIndexId} + /> + </> + )} + {recordIndexViewType === ViewType.Kanban && ( + <StyledContainerWithPadding> + <RecordIndexBoardContainer + recordBoardId={recordIndexId} + viewBarId={recordIndexId} + objectNameSingular={objectNameSingular} + createRecord={createRecord} + /> + <RecordIndexBoardDataLoader + objectNameSingular={objectNameSingular} + recordBoardId={recordIndexId} + /> + <RecordIndexBoardDataLoaderEffect + objectNameSingular={objectNameSingular} + recordBoardId={recordIndexId} + /> + </StyledContainerWithPadding> + )} + </RecordIndexEventContext.Provider> </RecordFieldValueSelectorContextProvider> </StyledContainer> ); diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexRecordChip.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexRecordChip.tsx new file mode 100644 index 000000000000..1a064570ca56 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexRecordChip.tsx @@ -0,0 +1,40 @@ +import { AvatarChip, AvatarChipVariant } from 'twenty-ui'; + +import { useRecordChipData } from '@/object-record/hooks/useRecordChipData'; +import { RecordIndexEventContext } from '@/object-record/record-index/contexts/RecordIndexEventContext'; +import { ObjectRecord } from '@/object-record/types/ObjectRecord'; +import { useContext } from 'react'; + +export type RecordIndexRecordChipProps = { + objectNameSingular: string; + record: ObjectRecord; + variant?: AvatarChipVariant; +}; + +export const RecordIndexRecordChip = ({ + objectNameSingular, + record, + variant, +}: RecordIndexRecordChipProps) => { + const { onIndexIdentifierClick } = useContext(RecordIndexEventContext); + + const { recordChipData } = useRecordChipData({ + objectNameSingular, + record, + }); + + const handleAvatarChipClick = () => { + onIndexIdentifierClick(record.id); + }; + + return ( + <AvatarChip + placeholderColorSeed={record.id} + name={recordChipData.name} + avatarType={recordChipData.avatarType} + avatarUrl={recordChipData.avatarUrl ?? ''} + onClick={handleAvatarChipClick} + variant={variant} + /> + ); +}; diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RemoveSortingModal.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexRemoveSortingModal.tsx similarity index 96% rename from packages/twenty-front/src/modules/object-record/record-table/components/RemoveSortingModal.tsx rename to packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexRemoveSortingModal.tsx index 9bfb93b60430..efe7e4cb9236 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RemoveSortingModal.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexRemoveSortingModal.tsx @@ -5,7 +5,7 @@ import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModa import { useCombinedViewSorts } from '@/views/hooks/useCombinedViewSorts'; import { useGetCurrentView } from '@/views/hooks/useGetCurrentView'; -export const RemoveSortingModal = ({ +export const RecordIndexRemoveSortingModal = ({ recordTableId, }: { recordTableId: string; diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexTableContainer.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexTableContainer.tsx index 31be052ff407..f5af2e96fa20 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexTableContainer.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexTableContainer.tsx @@ -1,8 +1,8 @@ import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord'; import { RecordUpdateHookParams } from '@/object-record/record-field/contexts/FieldContext'; +import { RecordIndexRemoveSortingModal } from '@/object-record/record-index/components/RecordIndexRemoveSortingModal'; import { RecordTableActionBar } from '@/object-record/record-table/action-bar/components/RecordTableActionBar'; import { RecordTableWithWrappers } from '@/object-record/record-table/components/RecordTableWithWrappers'; -import { RemoveSortingModal } from '@/object-record/record-table/components/RemoveSortingModal'; import { RecordTableContextMenu } from '@/object-record/record-table/context-menu/components/RecordTableContextMenu'; type RecordIndexTableContainerProps = { @@ -39,7 +39,7 @@ export const RecordIndexTableContainer = ({ createRecord={createRecord} /> <RecordTableActionBar recordTableId={recordTableId} /> - <RemoveSortingModal recordTableId={recordTableId} /> + <RecordIndexRemoveSortingModal recordTableId={recordTableId} /> <RecordTableContextMenu recordTableId={recordTableId} /> </> ); diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexTableContainerEffect.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexTableContainerEffect.tsx index 6677d042665d..32ae2ffc5091 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexTableContainerEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexTableContainerEffect.tsx @@ -6,7 +6,9 @@ import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadata import { useRecordActionBar } from '@/object-record/record-action-bar/hooks/useRecordActionBar'; import { useHandleToggleColumnFilter } from '@/object-record/record-index/hooks/useHandleToggleColumnFilter'; import { useHandleToggleColumnSort } from '@/object-record/record-index/hooks/useHandleToggleColumnSort'; +import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates'; import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable'; +import { useViewStates } from '@/views/hooks/internal/useViewStates'; import { useSetRecordCountInCurrentView } from '@/views/hooks/useSetRecordCountInCurrentView'; type RecordIndexTableContainerEffectProps = { @@ -45,12 +47,31 @@ export const RecordIndexTableContainerEffect = ({ setAvailableTableColumns(columnDefinitions); }, [columnDefinitions, setAvailableTableColumns]); + const { tableRowIdsState, hasUserSelectedAllRowsState } = + useRecordTableStates(recordTableId); + + const { entityCountInCurrentViewState } = useViewStates(recordTableId); + const entityCountInCurrentView = useRecoilValue( + entityCountInCurrentViewState, + ); + const hasUserSelectedAllRows = useRecoilValue(hasUserSelectedAllRowsState); + const tableRowIds = useRecoilValue(tableRowIdsState); + const selectedRowIds = useRecoilValue(selectedRowIdsSelector()); + const numSelected = + hasUserSelectedAllRows && entityCountInCurrentView + ? selectedRowIds.length === tableRowIds.length + ? entityCountInCurrentView + : entityCountInCurrentView - + (tableRowIds.length - selectedRowIds.length) // unselected row Ids + : selectedRowIds.length; + const { setActionBarEntries, setContextMenuEntries } = useRecordActionBar({ objectMetadataItem, selectedRecordIds: selectedRowIds, callback: resetTableRowSelection, + totalNumberOfRecordsSelected: numSelected, }); const handleToggleColumnFilter = useHandleToggleColumnFilter({ diff --git a/packages/twenty-front/src/modules/object-record/record-index/contexts/RecordIndexEventContext.tsx b/packages/twenty-front/src/modules/object-record/record-index/contexts/RecordIndexEventContext.tsx new file mode 100644 index 000000000000..7de19221dc79 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-index/contexts/RecordIndexEventContext.tsx @@ -0,0 +1,9 @@ +import { createEventContext } from '~/utils/createEventContext'; + +export type RecordIndexEventContextProps = { + onIndexIdentifierClick: (recordId: string) => void; + onIndexRecordsLoaded: () => void; +}; + +export const RecordIndexEventContext = + createEventContext<RecordIndexEventContextProps>(); diff --git a/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleToggleColumnFilter.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleToggleColumnFilter.ts index 774e604178af..18997fbadbae 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleToggleColumnFilter.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleToggleColumnFilter.ts @@ -1,4 +1,5 @@ import { useCallback } from 'react'; +import { v4 } from 'uuid'; import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; @@ -46,6 +47,7 @@ export const useHandleToggleColumnFilter = ({ const defaultOperand = availableOperandsForFilter[0]; const newFilter: Filter = { + id: v4(), fieldMetadataId, operand: defaultOperand, displayValue: '', @@ -60,8 +62,8 @@ export const useHandleToggleColumnFilter = ({ upsertCombinedViewFilter(newFilter); - openDropdown(fieldMetadataId, { - scope: fieldMetadataId, + openDropdown(newFilter.id, { + scope: newFilter.id, }); }, [columnDefinitions, upsertCombinedViewFilter, openDropdown], diff --git a/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexBoard.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexBoard.ts index 9cd621effee5..297f1dcf8088 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexBoard.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexBoard.ts @@ -11,7 +11,7 @@ import { recordIndexFieldDefinitionsState } from '@/object-record/record-index/s import { recordIndexFiltersState } from '@/object-record/record-index/states/recordIndexFiltersState'; import { recordIndexIsCompactModeActiveState } from '@/object-record/record-index/states/recordIndexIsCompactModeActiveState'; import { recordIndexSortsState } from '@/object-record/record-index/states/recordIndexSortsState'; -import { useSetRecordInStore } from '@/object-record/record-store/hooks/useSetRecordInStore'; +import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore'; import { useSetRecordCountInCurrentView } from '@/views/hooks/useSetRecordCountInCurrentView'; type UseLoadRecordIndexBoardProps = { @@ -33,7 +33,7 @@ export const useLoadRecordIndexBoard = ({ setFieldDefinitions, isCompactModeActiveState, } = useRecordBoard(recordBoardId); - const { setRecords: setRecordsInStore } = useSetRecordInStore(); + const { upsertRecords: upsertRecordsInStore } = useUpsertRecordsInStore(); const recordIndexFieldDefinitions = useRecoilValue( recordIndexFieldDefinitionsState, @@ -82,8 +82,8 @@ export const useLoadRecordIndexBoard = ({ }, [records, setRecordIdsInBoard]); useEffect(() => { - setRecordsInStore(records); - }, [records, setRecordsInStore]); + upsertRecordsInStore(records); + }, [records, upsertRecordsInStore]); useEffect(() => { setRecordCountInCurrentView(totalCount); diff --git a/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexBoardColumn.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexBoardColumn.ts index a65d67abf679..02485fe0d78b 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexBoardColumn.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexBoardColumn.ts @@ -9,13 +9,14 @@ import { turnObjectDropdownFilterIntoQueryFilter } from '@/object-record/record- import { useRecordBoardRecordGqlFields } from '@/object-record/record-index/hooks/useRecordBoardRecordGqlFields'; import { recordIndexFiltersState } from '@/object-record/record-index/states/recordIndexFiltersState'; import { recordIndexSortsState } from '@/object-record/record-index/states/recordIndexSortsState'; -import { useSetRecordInStore } from '@/object-record/record-store/hooks/useSetRecordInStore'; +import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore'; +import { isDefined } from '~/utils/isDefined'; type UseLoadRecordIndexBoardProps = { objectNameSingular: string; boardFieldMetadataId: string | null; recordBoardId: string; - columnFieldSelectValue: string; + columnFieldSelectValue: string | null; columnId: string; }; @@ -30,7 +31,7 @@ export const useLoadRecordIndexBoardColumn = ({ objectNameSingular, }); const { setRecordIdsForColumn } = useRecordBoard(recordBoardId); - const { setRecords: setRecordsInStore } = useSetRecordInStore(); + const { upsertRecords: upsertRecordsInStore } = useUpsertRecordsInStore(); const recordIndexFilters = useRecoilValue(recordIndexFiltersState); const recordIndexSorts = useRecoilValue(recordIndexSortsState); @@ -51,9 +52,11 @@ export const useLoadRecordIndexBoardColumn = ({ const filter = { ...requestFilters, - [recordIndexKanbanFieldMetadataItem?.name ?? '']: { - in: [columnFieldSelectValue], - }, + [recordIndexKanbanFieldMetadataItem?.name ?? '']: isDefined( + columnFieldSelectValue, + ) + ? { in: [columnFieldSelectValue] } + : { is: 'NULL' }, }; const { @@ -75,8 +78,8 @@ export const useLoadRecordIndexBoardColumn = ({ }, [records, setRecordIdsForColumn, columnId]); useEffect(() => { - setRecordsInStore(records); - }, [records, setRecordsInStore]); + upsertRecordsInStore(records); + }, [records, upsertRecordsInStore]); return { records, diff --git a/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexTable.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexTable.ts index c6a26daada1d..99f613521b2d 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexTable.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexTable.ts @@ -1,4 +1,4 @@ -import { useRecoilValue, useSetRecoilState } from 'recoil'; +import { useRecoilValue } from 'recoil'; import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; @@ -41,8 +41,6 @@ export const useLoadRecordIndexTable = (objectNameSingular: string) => { const { setRecordTableData, setIsRecordTableInitialLoading } = useRecordTable(); - const { tableLastRowVisibleState } = useRecordTableStates(); - const setLastRowVisible = useSetRecoilState(tableLastRowVisibleState); const currentWorkspace = useRecoilValue(currentWorkspaceState); const params = useFindManyParams(objectNameSingular); @@ -58,7 +56,6 @@ export const useLoadRecordIndexTable = (objectNameSingular: string) => { ...params, recordGqlFields, onCompleted: () => { - setLastRowVisible(false); setIsRecordTableInitialLoading(false); }, onError: () => { diff --git a/packages/twenty-front/src/modules/object-record/record-index/options/components/RecordIndexOptionsDropdownContent.tsx b/packages/twenty-front/src/modules/object-record/record-index/options/components/RecordIndexOptionsDropdownContent.tsx index 73149fb6eba5..c93c8bfdadf1 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/options/components/RecordIndexOptionsDropdownContent.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/options/components/RecordIndexOptionsDropdownContent.tsx @@ -132,6 +132,7 @@ export const RecordIndexOptionsDropdownContent = ({ onClick={() => handleSelectMenu('fields')} LeftIcon={IconTag} text="Fields" + hasSubMenu /> <MenuItem onClick={() => openRecordSpreadsheetImport()} diff --git a/packages/twenty-front/src/modules/object-record/record-index/options/hooks/__tests__/useExportTableData.test.ts b/packages/twenty-front/src/modules/object-record/record-index/options/hooks/__tests__/useExportTableData.test.ts index f5d35d92bcbe..b7dfc586016f 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/options/hooks/__tests__/useExportTableData.test.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/options/hooks/__tests__/useExportTableData.test.ts @@ -40,6 +40,7 @@ describe('generateCsv', () => { ] as ColumnDefinition<FieldMetadata>[]; const rows = [ { + id: '1', bar: 'another field', empty: null, foo: 'some field', @@ -48,8 +49,8 @@ describe('generateCsv', () => { }, ]; const csv = generateCsv({ columns, rows }); - expect(csv).toEqual(`Foo,Empty,Nested Foo,Nested Nested,Relation -some field,,foo,nested,a relation`); + expect(csv).toEqual(`Id,Foo,Empty,Nested Foo,Nested Nested,Relation +1,some field,,foo,nested,a relation`); }); }); @@ -62,6 +63,7 @@ describe('csvDownloader', () => { { id: 2, name: 'Alice' }, ], columns: [], + objectNameSingular: '', }; const link = document.createElement('a'); diff --git a/packages/twenty-front/src/modules/object-record/record-index/options/hooks/useDeleteTableData.ts b/packages/twenty-front/src/modules/object-record/record-index/options/hooks/useDeleteTableData.ts new file mode 100644 index 000000000000..8c2fca1b9ede --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-index/options/hooks/useDeleteTableData.ts @@ -0,0 +1,76 @@ +import { useFavorites } from '@/favorites/hooks/useFavorites'; +import { useDeleteManyRecords } from '@/object-record/hooks/useDeleteManyRecords'; +import { useFetchAllRecordIds } from '@/object-record/hooks/useFetchAllRecordIds'; +import { UseTableDataOptions } from '@/object-record/record-index/options/hooks/useTableData'; +import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable'; +import { tableRowIdsComponentState } from '@/object-record/record-table/states/tableRowIdsComponentState'; +import { getScopeIdFromComponentId } from '@/ui/utilities/recoil-scope/utils/getScopeIdFromComponentId'; +import { useRecoilValue } from 'recoil'; + +type UseDeleteTableDataOptions = Omit<UseTableDataOptions, 'callback'>; + +export const useDeleteTableData = ({ + objectNameSingular, + recordIndexId, +}: UseDeleteTableDataOptions) => { + const { fetchAllRecordIds } = useFetchAllRecordIds({ + objectNameSingular, + }); + + const { + resetTableRowSelection, + selectedRowIdsSelector, + hasUserSelectedAllRowsState, + } = useRecordTable({ + recordTableId: recordIndexId, + }); + + const tableRowIds = useRecoilValue( + tableRowIdsComponentState({ + scopeId: getScopeIdFromComponentId(recordIndexId), + }), + ); + + const { deleteManyRecords } = useDeleteManyRecords({ + objectNameSingular, + }); + const { favorites, deleteFavorite } = useFavorites(); + + const selectedRowIds = useRecoilValue(selectedRowIdsSelector()); + + const hasUserSelectedAllRows = useRecoilValue(hasUserSelectedAllRowsState); + + const deleteRecords = async () => { + let recordIdsToDelete = selectedRowIds; + + if (hasUserSelectedAllRows) { + const allRecordIds = await fetchAllRecordIds(); + + const unselectedRecordIds = tableRowIds.filter( + (recordId) => !selectedRowIds.includes(recordId), + ); + + recordIdsToDelete = allRecordIds.filter( + (recordId) => !unselectedRecordIds.includes(recordId), + ); + } + + resetTableRowSelection(); + + for (const recordIdToDelete of recordIdsToDelete) { + const foundFavorite = favorites?.find( + (favorite) => favorite.recordId === recordIdToDelete, + ); + + if (foundFavorite !== undefined) { + deleteFavorite(foundFavorite.id); + } + } + + await deleteManyRecords(recordIdsToDelete, { + delayInMsBetweenRequests: 50, + }); + }; + + return { deleteTableData: deleteRecords }; +}; diff --git a/packages/twenty-front/src/modules/object-record/record-index/options/hooks/useExportTableData.ts b/packages/twenty-front/src/modules/object-record/record-index/options/hooks/useExportTableData.ts index 785bb8f51d94..c186bf1e2903 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/options/hooks/useExportTableData.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/options/hooks/useExportTableData.ts @@ -1,16 +1,16 @@ -import { useEffect, useState } from 'react'; +import { useMemo } from 'react'; import { json2csv } from 'json-2-csv'; -import { useRecoilValue } from 'recoil'; -import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata'; -import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates'; +import { + useTableData, + UseTableDataOptions, +} from '@/object-record/record-index/options/hooks/useTableData'; import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition'; +import { ObjectRecord } from '@/object-record/types/ObjectRecord'; +import { FieldMetadataType } from '~/generated/graphql'; import { isDefined } from '~/utils/isDefined'; import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull'; -import { sleep } from '~/utils/sleep'; - -import { useFindManyParams } from '../../hooks/useLoadRecordIndexTable'; export const download = (blob: Blob, filename: string) => { const url = URL.createObjectURL(blob); @@ -45,14 +45,27 @@ export const generateCsv: GenerateExport = ({ col.metadata.relationType === 'TO_ONE_OBJECT', ); - const keys = columnsToExport.flatMap((col) => { + const objectIdColumn: ColumnDefinition<FieldMetadata> = { + fieldMetadataId: '', + type: FieldMetadataType.Uuid, + iconName: '', + label: `Id`, + metadata: { + fieldName: 'id', + }, + position: 0, + size: 0, + }; + + const columnsToExportWithIdColumn = [objectIdColumn, ...columnsToExport]; + + const keys = columnsToExportWithIdColumn.flatMap((col) => { const column = { field: `${col.metadata.fieldName}${col.type === 'RELATION' ? 'Id' : ''}`, title: [col.label, col.type === 'RELATION' ? 'Id' : null] .filter(isDefined) .join(' '), }; - const fieldsWithSubFields = rows.find((row) => { const fieldValue = (row as any)[column.field]; const hasSubFields = @@ -113,13 +126,8 @@ const downloader = (mimeType: string, generator: GenerateExport) => { export const csvDownloader = downloader('text/csv', generateCsv); -type UseExportTableDataOptions = { - delayMs: number; +type UseExportTableDataOptions = Omit<UseTableDataOptions, 'callback'> & { filename: string; - maximumRequests?: number; - objectNameSingular: string; - pageSize?: number; - recordIndexId: string; }; export const useExportTableData = ({ @@ -130,100 +138,22 @@ export const useExportTableData = ({ pageSize = 30, recordIndexId, }: UseExportTableDataOptions) => { - const [isDownloading, setIsDownloading] = useState(false); - const [inflight, setInflight] = useState(false); - const [pageCount, setPageCount] = useState(0); - const [progress, setProgress] = useState<ExportProgress>({ - displayType: 'number', - }); - const [previousRecordCount, setPreviousRecordCount] = useState(0); - - const { visibleTableColumnsSelector, selectedRowIdsSelector } = - useRecordTableStates(recordIndexId); - - const columns = useRecoilValue(visibleTableColumnsSelector()); - const selectedRowIds = useRecoilValue(selectedRowIdsSelector()); - - const hasSelectedRows = selectedRowIds.length > 0; - - const findManyRecordsParams = useFindManyParams( - objectNameSingular, - recordIndexId, - ); - - const selectedFindManyParams = { - ...findManyRecordsParams, - filter: { - ...findManyRecordsParams.filter, - id: { - in: selectedRowIds, + const downloadCsv = useMemo( + () => + (rows: ObjectRecord[], columns: ColumnDefinition<FieldMetadata>[]) => { + csvDownloader(filename, { rows, columns }); }, - }, - }; - - const usedFindManyParams = hasSelectedRows - ? selectedFindManyParams - : findManyRecordsParams; - - // Todo: this needs to be done on click on the Export not button, not to be reactive. Use Lazy query for example - const { totalCount, records, fetchMoreRecords } = useFindManyRecords({ - ...usedFindManyParams, - limit: pageSize, - }); - - useEffect(() => { - const MAXIMUM_REQUESTS = isDefined(totalCount) - ? Math.min(maximumRequests, totalCount / pageSize) - : maximumRequests; - - const downloadCsv = (rows: object[]) => { - csvDownloader(filename, { rows, columns }); - setIsDownloading(false); - setProgress({ - displayType: 'number', - }); - }; - - const fetchNextPage = async () => { - setInflight(true); - setPreviousRecordCount(records.length); - await fetchMoreRecords(); - setPageCount((state) => state + 1); - setProgress({ - exportedRecordCount: records.length, - totalRecordCount: totalCount, - displayType: totalCount ? 'percentage' : 'number', - }); - await sleep(delayMs); - setInflight(false); - }; - - if (!isDownloading || inflight) { - return; - } + [filename], + ); - if ( - pageCount >= MAXIMUM_REQUESTS || - records.length === previousRecordCount - ) { - downloadCsv(records); - } else { - fetchNextPage(); - } - }, [ + const { getTableData: download, progress } = useTableData({ delayMs, - fetchMoreRecords, - filename, - inflight, - isDownloading, - pageCount, - records, - totalCount, - columns, maximumRequests, + objectNameSingular, pageSize, - previousRecordCount, - ]); + recordIndexId, + callback: downloadCsv, + }); - return { progress, download: () => setIsDownloading(true) }; + return { progress, download }; }; diff --git a/packages/twenty-front/src/modules/object-record/record-index/options/hooks/useTableData.ts b/packages/twenty-front/src/modules/object-record/record-index/options/hooks/useTableData.ts new file mode 100644 index 000000000000..b389d906dbb8 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-index/options/hooks/useTableData.ts @@ -0,0 +1,204 @@ +import { useEffect, useMemo, useState } from 'react'; +import { useRecoilValue } from 'recoil'; + +import { useLazyFindManyRecords } from '@/object-record/hooks/useLazyFindManyRecords'; +import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata'; +import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates'; +import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition'; +import { ObjectRecord } from '@/object-record/types/ObjectRecord'; +import { isDefined } from '~/utils/isDefined'; + +import { useFindManyParams } from '../../hooks/useLoadRecordIndexTable'; + +export const sleep = (ms: number) => + new Promise((resolve) => setTimeout(resolve, ms)); + +export const percentage = (part: number, whole: number): number => { + return Math.round((part / whole) * 100); +}; + +export type UseTableDataOptions = { + delayMs: number; + maximumRequests?: number; + objectNameSingular: string; + pageSize?: number; + recordIndexId: string; + callback: ( + rows: ObjectRecord[], + columns: ColumnDefinition<FieldMetadata>[], + ) => void | Promise<void>; +}; + +type ExportProgress = { + exportedRecordCount?: number; + totalRecordCount?: number; + displayType: 'percentage' | 'number'; +}; + +export const useTableData = ({ + delayMs, + maximumRequests = 100, + objectNameSingular, + pageSize = 30, + recordIndexId, + callback, +}: UseTableDataOptions) => { + const [isDownloading, setIsDownloading] = useState(false); + const [inflight, setInflight] = useState(false); + const [pageCount, setPageCount] = useState(0); + const [progress, setProgress] = useState<ExportProgress>({ + displayType: 'number', + }); + const [previousRecordCount, setPreviousRecordCount] = useState(0); + + const { + visibleTableColumnsSelector, + selectedRowIdsSelector, + tableRowIdsState, + hasUserSelectedAllRowsState, + } = useRecordTableStates(recordIndexId); + + const columns = useRecoilValue(visibleTableColumnsSelector()); + const selectedRowIds = useRecoilValue(selectedRowIdsSelector()); + + const hasUserSelectedAllRows = useRecoilValue(hasUserSelectedAllRowsState); + const tableRowIds = useRecoilValue(tableRowIdsState); + + // user has checked select all and then unselected some rows + const userHasUnselectedSomeRows = + hasUserSelectedAllRows && selectedRowIds.length < tableRowIds.length; + + const hasSelectedRows = + selectedRowIds.length > 0 && + !(hasUserSelectedAllRows && selectedRowIds.length === tableRowIds.length); + + const unselectedRowIds = useMemo( + () => + userHasUnselectedSomeRows + ? tableRowIds.filter((id) => !selectedRowIds.includes(id)) + : [], + [userHasUnselectedSomeRows, tableRowIds, selectedRowIds], + ); + + const findManyRecordsParams = useFindManyParams( + objectNameSingular, + recordIndexId, + ); + + const selectedFindManyParams = { + ...findManyRecordsParams, + filter: { + ...findManyRecordsParams.filter, + id: { + in: selectedRowIds, + }, + }, + }; + + const unselectedFindManyParams = { + ...findManyRecordsParams, + filter: { + ...findManyRecordsParams.filter, + not: { + id: { + in: unselectedRowIds, + }, + }, + }, + }; + + const usedFindManyParams = + hasSelectedRows && !userHasUnselectedSomeRows + ? selectedFindManyParams + : userHasUnselectedSomeRows + ? unselectedFindManyParams + : findManyRecordsParams; + + const { + findManyRecords, + totalCount, + records, + fetchMoreRecordsWithPagination, + loading, + } = useLazyFindManyRecords({ + ...usedFindManyParams, + limit: pageSize, + }); + + useEffect(() => { + const MAXIMUM_REQUESTS = isDefined(totalCount) + ? Math.min(maximumRequests, totalCount / pageSize) + : maximumRequests; + + const fetchNextPage = async () => { + setInflight(true); + setPreviousRecordCount(records.length); + + await fetchMoreRecordsWithPagination(); + + setPageCount((state) => state + 1); + setProgress({ + exportedRecordCount: records.length, + totalRecordCount: totalCount, + displayType: totalCount ? 'percentage' : 'number', + }); + await sleep(delayMs); + setInflight(false); + }; + + if (!isDownloading || inflight || loading) { + return; + } + + if ( + pageCount >= MAXIMUM_REQUESTS || + (isDefined(totalCount) && records.length === totalCount) + ) { + setPageCount(0); + + const complete = () => { + setPageCount(0); + setPreviousRecordCount(0); + setIsDownloading(false); + setProgress({ + displayType: 'number', + }); + }; + + const res = callback(records, columns); + + if (res instanceof Promise) { + res.then(complete); + } else { + complete(); + } + } else { + fetchNextPage(); + } + }, [ + delayMs, + fetchMoreRecordsWithPagination, + inflight, + isDownloading, + pageCount, + records, + totalCount, + columns, + maximumRequests, + pageSize, + loading, + callback, + previousRecordCount, + ]); + + return { + progress, + isDownloading, + getTableData: () => { + setPageCount(0); + setPreviousRecordCount(0); + setIsDownloading(true); + findManyRecords?.(); + }, + }; +}; diff --git a/packages/twenty-front/src/modules/object-record/record-index/options/states/recordDeleteProgressState.ts b/packages/twenty-front/src/modules/object-record/record-index/options/states/recordDeleteProgressState.ts new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCell.tsx b/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCell.tsx index 8eef4e126c5c..f7927be24ece 100644 --- a/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCell.tsx +++ b/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCell.tsx @@ -6,7 +6,6 @@ import { FieldInput } from '@/object-record/record-field/components/FieldInput'; import { FieldContext } from '@/object-record/record-field/contexts/FieldContext'; import { FieldFocusContextProvider } from '@/object-record/record-field/contexts/FieldFocusContextProvider'; import { useGetButtonIcon } from '@/object-record/record-field/hooks/useGetButtonIcon'; -import { useIsFieldEmpty } from '@/object-record/record-field/hooks/useIsFieldEmpty'; import { useIsFieldInputOnly } from '@/object-record/record-field/hooks/useIsFieldInputOnly'; import { FieldInputEvent } from '@/object-record/record-field/types/FieldInputEvent'; import { isFieldRelation } from '@/object-record/record-field/types/guards/isFieldRelation'; @@ -26,11 +25,8 @@ export const RecordInlineCell = ({ loading, }: RecordInlineCellProps) => { const { fieldDefinition, entityId } = useContext(FieldContext); - const buttonIcon = useGetButtonIcon(); - const isFieldEmpty = useIsFieldEmpty(); - const isFieldInputOnly = useIsFieldInputOnly(); const { closeInlineCell } = useInlineCell(); @@ -104,7 +100,6 @@ export const RecordInlineCell = ({ /> } displayModeContent={<FieldDisplay />} - isDisplayModeContentEmpty={isFieldEmpty} isDisplayModeFixHeight editModeContentOnly={isFieldInputOnly} loading={loading} diff --git a/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCellContainer.tsx b/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCellContainer.tsx index 926d934c8f8e..4e6073c9c383 100644 --- a/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCellContainer.tsx +++ b/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCellContainer.tsx @@ -1,8 +1,7 @@ import React, { ReactElement, useContext } from 'react'; -import { Tooltip } from 'react-tooltip'; import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; -import { IconComponent } from 'twenty-ui'; +import { AppTooltip, IconComponent, TooltipDelay } from 'twenty-ui'; import { FieldContext } from '@/object-record/record-field/contexts/FieldContext'; import { useFieldFocus } from '@/object-record/record-field/hooks/useFieldFocus'; @@ -34,7 +33,8 @@ const StyledLabelAndIconContainer = styled.div` const StyledValueContainer = styled.div` display: flex; - min-width: 100%; + flex-grow: 1; + min-width: 0; `; const StyledLabelContainer = styled.div<{ width?: number }>` @@ -54,17 +54,6 @@ const StyledInlineCellBaseContainer = styled.div` user-select: none; `; -const StyledTooltip = styled(Tooltip)` - background-color: ${({ theme }) => theme.background.primary}; - box-shadow: ${({ theme }) => theme.boxShadow.light}; - - color: ${({ theme }) => theme.font.color.primary}; - - font-size: ${({ theme }) => theme.font.size.sm}; - font-weight: ${({ theme }) => theme.font.weight.regular}; - padding: ${({ theme }) => theme.spacing(2)}; -`; - export const StyledSkeletonDiv = styled.div` height: 24px; `; @@ -80,7 +69,6 @@ export type RecordInlineCellContainerProps = { editModeContentOnly?: boolean; displayModeContent: ReactElement; customEditHotkeyScope?: HotkeyScope; - isDisplayModeContentEmpty?: boolean; isDisplayModeFixHeight?: boolean; disableHoverEffect?: boolean; loading?: boolean; @@ -96,7 +84,6 @@ export const RecordInlineCellContainer = ({ editModeContent, displayModeContent, customEditHotkeyScope, - isDisplayModeContentEmpty, editModeContentOnly, isDisplayModeFixHeight, disableHoverEffect, @@ -140,13 +127,14 @@ export const RecordInlineCellContainer = ({ )} {/* TODO: Displaying Tooltips on the board is causing performance issues https://react-tooltip.com/docs/examples/render */} {!showLabel && !fieldDefinition?.disableTooltip && ( - <StyledTooltip + <AppTooltip anchorSelect={`#${labelId}`} content={label} clickable noArrow place="bottom" positionStrategy="fixed" + delay={TooltipDelay.shortDelay} /> )} </StyledLabelAndIconContainer> @@ -159,7 +147,6 @@ export const RecordInlineCellContainer = ({ disableHoverEffect, editModeContent, editModeContentOnly, - isDisplayModeContentEmpty, isDisplayModeFixHeight, buttonIcon, label, diff --git a/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCellDisplayMode.tsx b/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCellDisplayMode.tsx index 0b8770973598..eacdf2dc4b7f 100644 --- a/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCellDisplayMode.tsx +++ b/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCellDisplayMode.tsx @@ -1,13 +1,16 @@ import { css } from '@emotion/react'; import styled from '@emotion/styled'; +import { useFieldFocus } from '@/object-record/record-field/hooks/useFieldFocus'; +import { useIsFieldEmpty } from '@/object-record/record-field/hooks/useIsFieldEmpty'; +import { useIsFieldInputOnly } from '@/object-record/record-field/hooks/useIsFieldInputOnly'; +import { RecordInlineCellContainerProps } from '@/object-record/record-inline-cell/components/RecordInlineCellContainer'; +import { RecordInlineCellButton } from '@/object-record/record-inline-cell/components/RecordInlineCellEditButton'; + const StyledRecordInlineCellNormalModeOuterContainer = styled.div< Pick< RecordInlineCellDisplayModeProps, - | 'isDisplayModeContentEmpty' - | 'disableHoverEffect' - | 'isDisplayModeFixHeight' - | 'isHovered' + 'disableHoverEffect' | 'isDisplayModeFixHeight' | 'isHovered' > >` align-items: center; @@ -51,33 +54,50 @@ const StyledEmptyField = styled.div` `; type RecordInlineCellDisplayModeProps = { - isDisplayModeContentEmpty?: boolean; disableHoverEffect?: boolean; isDisplayModeFixHeight?: boolean; isHovered?: boolean; emptyPlaceholder?: string; -}; +} & Pick<RecordInlineCellContainerProps, 'buttonIcon' | 'editModeContentOnly'>; export const RecordInlineCellDisplayMode = ({ children, - isDisplayModeContentEmpty, disableHoverEffect, isDisplayModeFixHeight, emptyPlaceholder = 'Empty', isHovered, -}: React.PropsWithChildren<RecordInlineCellDisplayModeProps>) => ( - <StyledRecordInlineCellNormalModeOuterContainer - isDisplayModeContentEmpty={isDisplayModeContentEmpty} - disableHoverEffect={disableHoverEffect} - isDisplayModeFixHeight={isDisplayModeFixHeight} - isHovered={isHovered} - > - <StyledRecordInlineCellNormalModeInnerContainer> - {isDisplayModeContentEmpty || !children ? ( - <StyledEmptyField>{emptyPlaceholder}</StyledEmptyField> - ) : ( - children - )} - </StyledRecordInlineCellNormalModeInnerContainer> - </StyledRecordInlineCellNormalModeOuterContainer> -); + buttonIcon, + editModeContentOnly, +}: React.PropsWithChildren<RecordInlineCellDisplayModeProps>) => { + const { isFocused } = useFieldFocus(); + const isDisplayModeContentEmpty = useIsFieldEmpty(); + const showEditButton = + buttonIcon && + isFocused && + !isDisplayModeContentEmpty && + !editModeContentOnly; + + const isFieldInputOnly = useIsFieldInputOnly(); + + const shouldDisplayEditModeOnFocus = isFocused && isFieldInputOnly; + + return ( + <> + <StyledRecordInlineCellNormalModeOuterContainer + disableHoverEffect={disableHoverEffect} + isDisplayModeFixHeight={isDisplayModeFixHeight} + isHovered={isHovered} + > + <StyledRecordInlineCellNormalModeInnerContainer> + {(isDisplayModeContentEmpty && !shouldDisplayEditModeOnFocus) || + !children ? ( + <StyledEmptyField>{emptyPlaceholder}</StyledEmptyField> + ) : ( + children + )} + </StyledRecordInlineCellNormalModeInnerContainer> + </StyledRecordInlineCellNormalModeOuterContainer> + {showEditButton && <RecordInlineCellButton Icon={buttonIcon} />} + </> + ); +}; diff --git a/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCellEditButton.tsx b/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCellEditButton.tsx index 0475a925606a..2af1e91d7c21 100644 --- a/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCellEditButton.tsx +++ b/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCellEditButton.tsx @@ -1,8 +1,8 @@ import styled from '@emotion/styled'; import { IconComponent } from 'twenty-ui'; -import { AnimatedContainer } from '@/object-record/record-table/components/AnimatedContainer'; import { FloatingIconButton } from '@/ui/input/button/components/FloatingIconButton'; +import { AnimatedContainer } from '@/ui/utilities/animation/components/AnimatedContainer'; const StyledInlineCellButtonContainer = styled.div` align-items: center; diff --git a/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCellValue.tsx b/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCellValue.tsx index a1042ddd0593..152ef8927a1f 100644 --- a/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCellValue.tsx +++ b/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCellValue.tsx @@ -4,7 +4,6 @@ import styled from '@emotion/styled'; import { useFieldFocus } from '@/object-record/record-field/hooks/useFieldFocus'; import { RecordInlineCellContainerProps } from '@/object-record/record-inline-cell/components/RecordInlineCellContainer'; import { RecordInlineCellDisplayMode } from '@/object-record/record-inline-cell/components/RecordInlineCellDisplayMode'; -import { RecordInlineCellButton } from '@/object-record/record-inline-cell/components/RecordInlineCellEditButton'; import { RecordInlineCellEditMode } from '@/object-record/record-inline-cell/components/RecordInlineCellEditMode'; import { RecordInlineCellSkeletonLoader } from '@/object-record/record-inline-cell/components/RecordInlineCellSkeletonLoader'; import { useInlineCell } from '@/object-record/record-inline-cell/hooks/useInlineCell'; @@ -27,7 +26,6 @@ type RecordInlineCellValueProps = Pick< | 'customEditHotkeyScope' | 'editModeContent' | 'editModeContentOnly' - | 'isDisplayModeContentEmpty' | 'isDisplayModeFixHeight' | 'disableHoverEffect' | 'readonly' @@ -43,7 +41,6 @@ export const RecordInlineCellValue = ({ disableHoverEffect, editModeContent, editModeContentOnly, - isDisplayModeContentEmpty, isDisplayModeFixHeight, readonly, buttonIcon, @@ -61,46 +58,43 @@ export const RecordInlineCellValue = ({ } }; - const showEditButton = - buttonIcon && - !isInlineCellInEditMode && - isFocused && - !editModeContentOnly && - !isDisplayModeContentEmpty; - if (loading === true) { return <RecordInlineCellSkeletonLoader />; } - return !readonly && isInlineCellInEditMode ? ( - <RecordInlineCellEditMode>{editModeContent}</RecordInlineCellEditMode> - ) : editModeContentOnly ? ( - <StyledClickableContainer readonly={readonly}> - <RecordInlineCellDisplayMode - disableHoverEffect={disableHoverEffect} - isDisplayModeContentEmpty={isDisplayModeContentEmpty} - isDisplayModeFixHeight={isDisplayModeFixHeight} - isHovered={isFocused} - emptyPlaceholder={showLabel ? 'Empty' : label} - > - {editModeContent} - </RecordInlineCellDisplayMode> - </StyledClickableContainer> - ) : ( - <StyledClickableContainer - readonly={readonly} - onClick={handleDisplayModeClick} - > - <RecordInlineCellDisplayMode - disableHoverEffect={disableHoverEffect} - isDisplayModeContentEmpty={isDisplayModeContentEmpty} - isDisplayModeFixHeight={isDisplayModeFixHeight} - isHovered={isFocused} - emptyPlaceholder={showLabel ? 'Empty' : label} - > - {displayModeContent} - </RecordInlineCellDisplayMode> - {showEditButton && <RecordInlineCellButton Icon={buttonIcon} />} - </StyledClickableContainer> + return ( + <> + {!readonly && isInlineCellInEditMode && ( + <RecordInlineCellEditMode>{editModeContent}</RecordInlineCellEditMode> + )} + {editModeContentOnly ? ( + <StyledClickableContainer readonly={readonly}> + <RecordInlineCellDisplayMode + disableHoverEffect={disableHoverEffect} + isDisplayModeFixHeight={isDisplayModeFixHeight} + isHovered={isFocused} + emptyPlaceholder={showLabel ? 'Empty' : label} + > + {editModeContent} + </RecordInlineCellDisplayMode> + </StyledClickableContainer> + ) : ( + <StyledClickableContainer + readonly={readonly} + onClick={handleDisplayModeClick} + > + <RecordInlineCellDisplayMode + disableHoverEffect={disableHoverEffect} + isDisplayModeFixHeight={isDisplayModeFixHeight} + isHovered={isFocused} + emptyPlaceholder={showLabel ? 'Empty' : label} + buttonIcon={buttonIcon} + editModeContentOnly={editModeContentOnly} + > + {displayModeContent} + </RecordInlineCellDisplayMode> + </StyledClickableContainer> + )} + </> ); }; diff --git a/packages/twenty-front/src/modules/object-record/record-show/hooks/useFindRecordCursorFromFindManyCacheRootQuery.ts b/packages/twenty-front/src/modules/object-record/record-show/hooks/useFindRecordCursorFromFindManyCacheRootQuery.ts new file mode 100644 index 000000000000..878309217a11 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-show/hooks/useFindRecordCursorFromFindManyCacheRootQuery.ts @@ -0,0 +1,34 @@ +import { RecordGqlRefEdge } from '@/object-record/cache/types/RecordGqlRefEdge'; +import { useApolloClient } from '@apollo/client'; +import { createApolloStoreFieldName } from '~/utils/createApolloStoreFieldName'; + +export const useFindRecordCursorFromFindManyCacheRootQuery = ({ + objectNamePlural, + fieldVariables, +}: { + objectNamePlural: string; + fieldVariables: { + filter: any; + orderBy: any; + }; +}) => { + const apollo = useApolloClient(); + + const testsFieldNameOnRootQuery = createApolloStoreFieldName({ + fieldName: objectNamePlural, + fieldVariables: fieldVariables, + }); + + const findCursorInCache = (recordId: string) => { + const extractedCache = apollo.cache.extract() as any; + + const edgesInCache = + extractedCache?.['ROOT_QUERY']?.[testsFieldNameOnRootQuery]?.edges ?? []; + + return edgesInCache.find( + (edge: RecordGqlRefEdge) => edge.node?.__ref.split(':')[1] === recordId, + )?.cursor; + }; + + return { findCursorInCache }; +}; diff --git a/packages/twenty-front/src/modules/object-record/record-show/hooks/useRecordIdsFromFindManyCacheRootQuery.ts b/packages/twenty-front/src/modules/object-record/record-show/hooks/useRecordIdsFromFindManyCacheRootQuery.ts new file mode 100644 index 000000000000..522c8112f219 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-show/hooks/useRecordIdsFromFindManyCacheRootQuery.ts @@ -0,0 +1,30 @@ +import { RecordGqlRefEdge } from '@/object-record/cache/types/RecordGqlRefEdge'; +import { useApolloClient } from '@apollo/client'; +import { createApolloStoreFieldName } from '~/utils/createApolloStoreFieldName'; + +export const useRecordIdsFromFindManyCacheRootQuery = ({ + objectNamePlural, + fieldVariables, +}: { + objectNamePlural: string; + fieldVariables: { + filter: any; + orderBy: any; + }; +}) => { + const apollo = useApolloClient(); + + const testsFieldNameOnRootQuery = createApolloStoreFieldName({ + fieldName: objectNamePlural, + fieldVariables: fieldVariables, + }); + + const extractedCache = apollo.cache.extract() as any; + + const recordIdsInCache: string[] = + extractedCache?.['ROOT_QUERY']?.[testsFieldNameOnRootQuery]?.edges?.map( + (edge: RecordGqlRefEdge) => edge.node?.__ref.split(':')[1], + ) ?? []; + + return { recordIdsInCache }; +}; diff --git a/packages/twenty-front/src/modules/object-record/record-show/hooks/useRecordShowPagePagination.ts b/packages/twenty-front/src/modules/object-record/record-show/hooks/useRecordShowPagePagination.ts new file mode 100644 index 000000000000..0909fcf78cd7 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-show/hooks/useRecordShowPagePagination.ts @@ -0,0 +1,253 @@ +/* eslint-disable @nx/workspace-no-navigate-prefer-link */ +import { useMemo, useState } from 'react'; +import { + useLocation, + useNavigate, + useParams, + useSearchParams, +} from 'react-router-dom'; +import { useSetRecoilState } from 'recoil'; + +import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; +import { formatFieldMetadataItemsAsFilterDefinitions } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions'; +import { formatFieldMetadataItemsAsSortDefinitions } from '@/object-metadata/utils/formatFieldMetadataItemsAsSortDefinitions'; +import { generateDepthOneRecordGqlFields } from '@/object-record/graphql/utils/generateDepthOneRecordGqlFields'; +import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; +import { turnSortsIntoOrderBy } from '@/object-record/object-sort-dropdown/utils/turnSortsIntoOrderBy'; +import { lastShowPageRecordIdState } from '@/object-record/record-field/states/lastShowPageRecordId'; +import { turnObjectDropdownFilterIntoQueryFilter } from '@/object-record/record-filter/utils/turnObjectDropdownFilterIntoQueryFilter'; +import { useRecordIdsFromFindManyCacheRootQuery } from '@/object-record/record-show/hooks/useRecordIdsFromFindManyCacheRootQuery'; +import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData'; +import { PrefetchKey } from '@/prefetch/types/PrefetchKey'; +import { View } from '@/views/types/View'; +import { mapViewFiltersToFilters } from '@/views/utils/mapViewFiltersToFilters'; +import { mapViewSortsToSorts } from '@/views/utils/mapViewSortsToSorts'; +import { isNonEmptyString } from '@sniptt/guards'; +import { capitalize } from '~/utils/string/capitalize'; + +export const findView = ({ + viewId, + objectMetadataItemId, + views, +}: { + viewId: string | null; + objectMetadataItemId: string; + views: View[]; +}) => { + if (!viewId) { + return views.find( + (view: any) => + view.key === 'INDEX' && view?.objectMetadataId === objectMetadataItemId, + ) as View; + } else { + return views.find( + (view: any) => + view?.id === viewId && view?.objectMetadataId === objectMetadataItemId, + ) as View; + } +}; + +export const useRecordShowPagePagination = ( + propsObjectNameSingular: string, + propsObjectRecordId: string, +) => { + const { + objectNameSingular: paramObjectNameSingular, + objectRecordId: paramObjectRecordId, + } = useParams(); + const navigate = useNavigate(); + const [searchParams] = useSearchParams(); + const viewIdQueryParam = searchParams.get('view'); + + const setLastShowPageRecordId = useSetRecoilState(lastShowPageRecordIdState); + + const [isLoadedRecords, setIsLoadedRecords] = useState(false); + + const objectNameSingular = propsObjectNameSingular || paramObjectNameSingular; + const objectRecordId = propsObjectRecordId || paramObjectRecordId; + + if (!objectNameSingular || !objectRecordId) { + throw new Error('Object name or Record id is not defined'); + } + + const { objectMetadataItem } = useObjectMetadataItem({ objectNameSingular }); + const { records: views } = usePrefetchedData<View>(PrefetchKey.AllViews); + + const view = useMemo(() => { + return findView({ + objectMetadataItemId: objectMetadataItem?.id ?? '', + viewId: viewIdQueryParam, + views, + }); + }, [viewIdQueryParam, objectMetadataItem, views]); + + const activeFieldMetadataItems = useMemo( + () => + objectMetadataItem + ? objectMetadataItem.fields.filter( + ({ isActive, isSystem }) => isActive && !isSystem, + ) + : [], + [objectMetadataItem], + ); + + const filterDefinitions = formatFieldMetadataItemsAsFilterDefinitions({ + fields: activeFieldMetadataItems, + }); + + const sortDefinitions = formatFieldMetadataItemsAsSortDefinitions({ + fields: activeFieldMetadataItems, + }); + + const filter = turnObjectDropdownFilterIntoQueryFilter( + mapViewFiltersToFilters(view?.viewFilters ?? [], filterDefinitions), + objectMetadataItem?.fields ?? [], + ); + + const orderBy = turnSortsIntoOrderBy( + objectMetadataItem, + mapViewSortsToSorts(view?.viewSorts ?? [], sortDefinitions), + ); + + const recordGqlFields = generateDepthOneRecordGqlFields({ + objectMetadataItem, + }); + + const { state } = useLocation(); + + const cursorFromIndexPage = state?.cursor; + + const { loading: loadingCurrentRecord, pageInfo: currentRecordsPageInfo } = + useFindManyRecords({ + filter: { + id: { eq: objectRecordId }, + }, + orderBy, + skip: isLoadedRecords, + limit: 1, + objectNameSingular, + recordGqlFields, + }); + + const currentRecordCursor = currentRecordsPageInfo?.endCursor; + + const cursor = cursorFromIndexPage ?? currentRecordCursor; + + const { + loading: loadingRecordBefore, + records: recordsBefore, + pageInfo: pageInfoBefore, + totalCount: totalCountBefore, + } = useFindManyRecords({ + filter, + orderBy, + skip: isLoadedRecords, + cursorFilter: isNonEmptyString(cursor) + ? { + cursorDirection: 'before', + cursor: cursor, + limit: 1, + } + : undefined, + objectNameSingular, + recordGqlFields, + }); + + const { + loading: loadingRecordAfter, + records: recordsAfter, + pageInfo: pageInfoAfter, + totalCount: totalCountAfter, + } = useFindManyRecords({ + filter, + orderBy, + skip: isLoadedRecords, + cursorFilter: cursor + ? { + cursorDirection: 'after', + cursor: cursor, + limit: 1, + } + : undefined, + objectNameSingular, + recordGqlFields, + }); + + const totalCount = Math.max(totalCountBefore ?? 0, totalCountAfter ?? 0); + + const loading = + loadingRecordAfter || loadingRecordBefore || loadingCurrentRecord; + + const isThereARecordBefore = recordsBefore.length > 0; + const isThereARecordAfter = recordsAfter.length > 0; + + const recordBefore = recordsBefore[0]; + const recordAfter = recordsAfter[0]; + + const recordBeforeCursor = pageInfoBefore?.endCursor; + const recordAfterCursor = pageInfoAfter?.endCursor; + + const navigateToPreviousRecord = () => { + navigate( + `/object/${objectNameSingular}/${recordBefore.id}${ + viewIdQueryParam ? `?view=${viewIdQueryParam}` : '' + }`, + { + state: { + cursor: recordBeforeCursor, + }, + }, + ); + }; + + const navigateToNextRecord = () => { + navigate( + `/object/${objectNameSingular}/${recordAfter.id}${ + viewIdQueryParam ? `?view=${viewIdQueryParam}` : '' + }`, + { + state: { + cursor: recordAfterCursor, + }, + }, + ); + }; + + const navigateToIndexView = () => { + const indexPath = `/objects/${objectMetadataItem.namePlural}${ + viewIdQueryParam ? `?view=${viewIdQueryParam}` : '' + }`; + + setLastShowPageRecordId(objectRecordId); + + navigate(indexPath); + }; + + const { recordIdsInCache } = useRecordIdsFromFindManyCacheRootQuery({ + objectNamePlural: objectMetadataItem.namePlural, + fieldVariables: { + filter, + orderBy, + }, + }); + + const rankInView = recordIdsInCache.findIndex((id) => id === objectRecordId); + + const rankFoundInFiew = rankInView > -1; + + const objectLabel = capitalize(objectMetadataItem.namePlural); + + const viewNameWithCount = rankFoundInFiew + ? `${rankInView + 1} of ${totalCount} in ${objectLabel}` + : `${objectLabel} (${totalCount})`; + + return { + viewName: viewNameWithCount, + hasPreviousRecord: isThereARecordBefore, + isLoadingPagination: loading, + hasNextRecord: isThereARecordAfter, + navigateToPreviousRecord, + navigateToNextRecord, + navigateToIndexView, + }; +}; diff --git a/packages/twenty-front/src/modules/object-record/record-show/record-detail-section/components/RecordDetailDuplicatesSection.tsx b/packages/twenty-front/src/modules/object-record/record-show/record-detail-section/components/RecordDetailDuplicatesSection.tsx index 3a82313b87e7..74690db36295 100644 --- a/packages/twenty-front/src/modules/object-record/record-show/record-detail-section/components/RecordDetailDuplicatesSection.tsx +++ b/packages/twenty-front/src/modules/object-record/record-show/record-detail-section/components/RecordDetailDuplicatesSection.tsx @@ -12,18 +12,19 @@ export const RecordDetailDuplicatesSection = ({ objectRecordId: string; objectNameSingular: string; }) => { - const { records: duplicateRecords } = useFindDuplicateRecords({ - objectRecordId, + const { results: queryResults } = useFindDuplicateRecords({ + objectRecordIds: [objectRecordId], objectNameSingular, }); - if (!duplicateRecords.length) return null; + if (!queryResults || !queryResults[0] || queryResults[0].length === 0) + return null; return ( <RecordDetailSection> <RecordDetailSectionHeader title="Duplicates" /> <RecordDetailRecordsList> - {duplicateRecords.slice(0, 5).map((duplicateRecord) => ( + {queryResults[0].slice(0, 5).map((duplicateRecord) => ( <RecordDetailRecordsListItem key={duplicateRecord.id}> <RecordChip record={duplicateRecord} diff --git a/packages/twenty-front/src/modules/object-record/record-show/record-detail-section/components/RecordDetailRelationRecordsList.tsx b/packages/twenty-front/src/modules/object-record/record-show/record-detail-section/components/RecordDetailRelationRecordsList.tsx index c8ce45c0b9ad..e4dae45402b3 100644 --- a/packages/twenty-front/src/modules/object-record/record-show/record-detail-section/components/RecordDetailRelationRecordsList.tsx +++ b/packages/twenty-front/src/modules/object-record/record-show/record-detail-section/components/RecordDetailRelationRecordsList.tsx @@ -1,7 +1,8 @@ -import { useState } from 'react'; +import { Fragment, useState } from 'react'; import { RecordDetailRecordsList } from '@/object-record/record-show/record-detail-section/components/RecordDetailRecordsList'; import { RecordDetailRelationRecordsListItem } from '@/object-record/record-show/record-detail-section/components/RecordDetailRelationRecordsListItem'; +import { RecordDetailRelationRecordsListItemEffect } from '@/object-record/record-show/record-detail-section/components/RecordDetailRelationRecordsListItemEffect'; import { ObjectRecord } from '@/object-record/types/ObjectRecord'; type RecordDetailRelationRecordsListProps = { @@ -19,12 +20,18 @@ export const RecordDetailRelationRecordsList = ({ return ( <RecordDetailRecordsList> {relationRecords.slice(0, 5).map((relationRecord) => ( - <RecordDetailRelationRecordsListItem - key={relationRecord.id} - isExpanded={expandedItem === relationRecord.id} - onClick={handleItemClick} - relationRecord={relationRecord} - /> + <Fragment key={relationRecord.id}> + <RecordDetailRelationRecordsListItemEffect + key={`${relationRecord.id}-effect`} + relationRecordId={relationRecord.id} + /> + <RecordDetailRelationRecordsListItem + key={relationRecord.id} + isExpanded={expandedItem === relationRecord.id} + onClick={handleItemClick} + relationRecord={relationRecord} + /> + </Fragment> ))} </RecordDetailRecordsList> ); diff --git a/packages/twenty-front/src/modules/object-record/record-show/record-detail-section/components/RecordDetailRelationRecordsListItem.tsx b/packages/twenty-front/src/modules/object-record/record-show/record-detail-section/components/RecordDetailRelationRecordsListItem.tsx index 8e35a01b0c66..a0653f933e5b 100644 --- a/packages/twenty-front/src/modules/object-record/record-show/record-detail-section/components/RecordDetailRelationRecordsListItem.tsx +++ b/packages/twenty-front/src/modules/object-record/record-show/record-detail-section/components/RecordDetailRelationRecordsListItem.tsx @@ -15,7 +15,6 @@ import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSi import { formatFieldMetadataItemAsColumnDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsColumnDefinition'; import { RecordChip } from '@/object-record/components/RecordChip'; import { useDeleteOneRecord } from '@/object-record/hooks/useDeleteOneRecord'; -import { useLazyFindOneRecord } from '@/object-record/hooks/useLazyFindOneRecord'; import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord'; import { FieldContext, @@ -29,7 +28,6 @@ import { PropertyBox } from '@/object-record/record-inline-cell/property-box/com import { InlineCellHotkeyScope } from '@/object-record/record-inline-cell/types/InlineCellHotkeyScope'; import { RecordDetailRecordsListItem } from '@/object-record/record-show/record-detail-section/components/RecordDetailRecordsListItem'; import { RecordValueSetterEffect } from '@/object-record/record-store/components/RecordValueSetterEffect'; -import { useSetRecordInStore } from '@/object-record/record-store/hooks/useSetRecordInStore'; import { ObjectRecord } from '@/object-record/types/ObjectRecord'; import { isFieldCellSupported } from '@/object-record/utils/isFieldCellSupported'; import { LightIconButton } from '@/ui/input/button/components/LightIconButton'; @@ -99,12 +97,6 @@ export const RecordDetailRelationRecordsListItem = ({ const persistField = usePersistField(); - const { - called: hasFetchedRelationRecord, - findOneRecord: findOneRelationRecord, - } = useLazyFindOneRecord({ - objectNameSingular: relationObjectMetadataNameSingular, - }); const { updateOneRecord: updateOneRelationRecord } = useUpdateOneRecord({ objectNameSingular: relationObjectMetadataNameSingular, }); @@ -168,8 +160,6 @@ export const RecordDetailRelationRecordsListItem = ({ return [updateEntity, { loading: false }]; }; - const { setRecords } = useSetRecordInStore(); - const handleClick = () => onClick(relationRecord.id); const AnimatedIconChevronDown = useCallback<IconComponent>( @@ -194,16 +184,7 @@ export const RecordDetailRelationRecordsListItem = ({ record={relationRecord} objectNameSingular={relationObjectMetadataItem.nameSingular} /> - <StyledClickableZone - onClick={handleClick} - onMouseOver={() => - !hasFetchedRelationRecord && - findOneRelationRecord({ - objectRecordId: relationRecord.id, - onCompleted: (record) => setRecords([record]), - }) - } - > + <StyledClickableZone onClick={handleClick}> <LightIconButton className="displayOnHover" Icon={AnimatedIconChevronDown} diff --git a/packages/twenty-front/src/modules/object-record/record-show/record-detail-section/components/RecordDetailRelationRecordsListItemEffect.tsx b/packages/twenty-front/src/modules/object-record/record-show/record-detail-section/components/RecordDetailRelationRecordsListItemEffect.tsx new file mode 100644 index 000000000000..0d7451bd5ce5 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-show/record-detail-section/components/RecordDetailRelationRecordsListItemEffect.tsx @@ -0,0 +1,35 @@ +import { useContext, useEffect } from 'react'; + +import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord'; +import { FieldContext } from '@/object-record/record-field/contexts/FieldContext'; +import { FieldRelationMetadata } from '@/object-record/record-field/types/FieldMetadata'; +import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore'; +import { isDefined } from '~/utils/isDefined'; + +type RecordDetailRelationRecordsListItemEffectProps = { + relationRecordId: string; +}; + +export const RecordDetailRelationRecordsListItemEffect = ({ + relationRecordId, +}: RecordDetailRelationRecordsListItemEffectProps) => { + const { fieldDefinition } = useContext(FieldContext); + + const { relationObjectMetadataNameSingular } = + fieldDefinition.metadata as FieldRelationMetadata; + + const { record } = useFindOneRecord({ + objectNameSingular: relationObjectMetadataNameSingular, + objectRecordId: relationRecordId, + }); + + const { upsertRecords } = useUpsertRecordsInStore(); + + useEffect(() => { + if (isDefined(record)) { + upsertRecords([record]); + } + }, [record, upsertRecords]); + + return null; +}; diff --git a/packages/twenty-front/src/modules/object-record/record-store/hooks/useSetRecordInStore.ts b/packages/twenty-front/src/modules/object-record/record-store/hooks/useUpsertRecordsInStore.ts similarity index 85% rename from packages/twenty-front/src/modules/object-record/record-store/hooks/useSetRecordInStore.ts rename to packages/twenty-front/src/modules/object-record/record-store/hooks/useUpsertRecordsInStore.ts index 63c4b9836c5b..0c7692749768 100644 --- a/packages/twenty-front/src/modules/object-record/record-store/hooks/useSetRecordInStore.ts +++ b/packages/twenty-front/src/modules/object-record/record-store/hooks/useUpsertRecordsInStore.ts @@ -3,8 +3,8 @@ import { useRecoilCallback } from 'recoil'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; import { ObjectRecord } from '@/object-record/types/ObjectRecord'; -export const useSetRecordInStore = () => { - const setRecords = useRecoilCallback( +export const useUpsertRecordsInStore = () => { + const upsertRecords = useRecoilCallback( ({ set, snapshot }) => (records: ObjectRecord[]) => { for (const record of records) { @@ -21,6 +21,6 @@ export const useSetRecordInStore = () => { ); return { - setRecords, + upsertRecords, }; }; diff --git a/packages/twenty-front/src/modules/object-record/record-table/action-bar/components/RecordTableActionBar.tsx b/packages/twenty-front/src/modules/object-record/record-table/action-bar/components/RecordTableActionBar.tsx index f7241a5e2a48..f41025398c22 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/action-bar/components/RecordTableActionBar.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/action-bar/components/RecordTableActionBar.tsx @@ -2,19 +2,43 @@ import { useRecoilValue } from 'recoil'; import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates'; import { ActionBar } from '@/ui/navigation/action-bar/components/ActionBar'; +import { useViewStates } from '@/views/hooks/internal/useViewStates'; export const RecordTableActionBar = ({ recordTableId, }: { recordTableId: string; }) => { - const { selectedRowIdsSelector } = useRecordTableStates(recordTableId); + const { + selectedRowIdsSelector, + tableRowIdsState, + hasUserSelectedAllRowsState, + } = useRecordTableStates(recordTableId); + const { entityCountInCurrentViewState } = useViewStates(recordTableId); + const entityCountInCurrentView = useRecoilValue( + entityCountInCurrentViewState, + ); + const hasUserSelectedAllRows = useRecoilValue(hasUserSelectedAllRowsState); + const tableRowIds = useRecoilValue(tableRowIdsState); const selectedRowIds = useRecoilValue(selectedRowIdsSelector()); + const totalNumberOfSelectedRecords = + hasUserSelectedAllRows && entityCountInCurrentView + ? selectedRowIds.length === tableRowIds.length + ? entityCountInCurrentView + : entityCountInCurrentView - + (tableRowIds.length - selectedRowIds.length) // unselected row Ids + : selectedRowIds.length; + if (!selectedRowIds.length) { return null; } - return <ActionBar selectedIds={selectedRowIds} />; + return ( + <ActionBar + selectedIds={selectedRowIds} + totalNumberOfSelectedRecords={totalNumberOfSelectedRecords} + /> + ); }; diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/GripCell.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/GripCell.tsx deleted file mode 100644 index b9900026dbf6..000000000000 --- a/packages/twenty-front/src/modules/object-record/record-table/components/GripCell.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import styled from '@emotion/styled'; - -import { IconListViewGrip } from '@/ui/input/components/IconListViewGrip'; - -const StyledContainer = styled.div` - cursor: grab; - width: 16px; - height: 32px; - z-index: 200; - display: flex; - &:hover .icon { - opacity: 1; - } -`; - -const StyledIconWrapper = styled.div<{ isDragging: boolean }>` - opacity: ${({ isDragging }) => (isDragging ? 1 : 0)}; - transition: opacity 0.1s; -`; - -export const GripCell = ({ isDragging }: { isDragging: boolean }) => { - return ( - <StyledContainer> - <StyledIconWrapper className="icon" isDragging={isDragging}> - <IconListViewGrip /> - </StyledIconWrapper> - </StyledContainer> - ); -}; diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTable.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTable.tsx index 2afb86e9875c..5e3b8c23af3e 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTable.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTable.tsx @@ -1,155 +1,27 @@ -import { css } from '@emotion/react'; import styled from '@emotion/styled'; -import { useRecoilValue } from 'recoil'; -import { MOBILE_VIEWPORT, RGBA } from 'twenty-ui'; +import { isNonEmptyString, isNull } from '@sniptt/guards'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; -import { RecordTableBody } from '@/object-record/record-table/components/RecordTableBody'; -import { RecordTableBodyEffect } from '@/object-record/record-table/components/RecordTableBodyEffect'; -import { RecordTableHeader } from '@/object-record/record-table/components/RecordTableHeader'; -import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext'; -import { useHandleContainerMouseEnter } from '@/object-record/record-table/hooks/internal/useHandleContainerMouseEnter'; +import { RecordTableContextProvider } from '@/object-record/record-table/components/RecordTableContextProvider'; +import { RecordTableEmptyState } from '@/object-record/record-table/components/RecordTableEmptyState'; import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates'; -import { useRecordTableMoveFocus } from '@/object-record/record-table/hooks/useRecordTableMoveFocus'; -import { useCloseRecordTableCellV2 } from '@/object-record/record-table/record-table-cell/hooks/useCloseRecordTableCellV2'; -import { useMoveSoftFocusToCellOnHoverV2 } from '@/object-record/record-table/record-table-cell/hooks/useMoveSoftFocusToCellOnHoverV2'; -import { - OpenTableCellArgs, - useOpenRecordTableCellV2, -} from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2'; -import { useTriggerContextMenu } from '@/object-record/record-table/record-table-cell/hooks/useTriggerContextMenu'; -import { useUpsertRecordV2 } from '@/object-record/record-table/record-table-cell/hooks/useUpsertRecordV2'; +import { RecordTableBody } from '@/object-record/record-table/record-table-body/components/RecordTableBody'; +import { RecordTableBodyEffect } from '@/object-record/record-table/record-table-body/components/RecordTableBodyEffect'; +import { RecordTableHeader } from '@/object-record/record-table/record-table-header/components/RecordTableHeader'; import { RecordTableScope } from '@/object-record/record-table/scopes/RecordTableScope'; -import { MoveFocusDirection } from '@/object-record/record-table/types/MoveFocusDirection'; -import { TableCellPosition } from '@/object-record/record-table/types/TableCellPosition'; +import { useRecoilValue } from 'recoil'; -const StyledTable = styled.table<{ - freezeFirstColumns?: boolean; -}>` +const StyledTable = styled.table` border-radius: ${({ theme }) => theme.border.radius.sm}; border-spacing: 0; margin-right: ${({ theme }) => theme.table.horizontalCellMargin}; table-layout: fixed; width: calc(100% - ${({ theme }) => theme.table.horizontalCellMargin} * 2); - - th { - border-block: 1px solid ${({ theme }) => theme.border.color.light}; - color: ${({ theme }) => theme.font.color.tertiary}; - padding: 0; - text-align: left; - - :last-child { - border-right-color: transparent; - } - :first-of-type { - border-top-color: transparent; - border-bottom-color: transparent; - } - } - - td { - border-bottom: 1px solid ${({ theme }) => theme.border.color.light}; - color: ${({ theme }) => theme.font.color.primary}; - border-right: 1px solid ${({ theme }) => theme.border.color.light}; - - text-align: left; - - :last-child { - border-right-color: transparent; - } - :first-of-type { - border-top-color: transparent; - border-bottom-color: transparent; - } - } - - th { - background-color: ${({ theme }) => theme.background.primary}; - border-right: 1px solid ${({ theme }) => theme.border.color.light}; - } - - thead th { - position: sticky; - top: 0; - z-index: 9; - } - - thead th:nth-of-type(1), - thead th:nth-of-type(2), - thead th:nth-of-type(3) { - z-index: 12; - background-color: ${({ theme }) => theme.background.primary}; - } - - thead th:nth-of-type(1) { - width: 9px; - left: 0; - border-right-color: ${({ theme }) => theme.background.primary}; - } - - thead th:nth-of-type(2) { - left: 9px; - border-right-color: ${({ theme }) => theme.background.primary}; - } - - thead th:nth-of-type(3) { - left: 39px; - } - - tbody td:nth-of-type(1), - tbody td:nth-of-type(2), - tbody td:nth-of-type(3) { - position: sticky; - z-index: 1; - } - - tbody td:nth-of-type(1) { - left: 0; - z-index: 7; - } - - tbody td:nth-of-type(2) { - left: 9px; - z-index: 5; - } - - tbody td:nth-of-type(3) { - left: 39px; - z-index: 6; - } - - thead th:nth-of-type(3), - tbody td:nth-of-type(3) { - ${({ freezeFirstColumns }) => - freezeFirstColumns && - css` - @media (max-width: ${MOBILE_VIEWPORT}px) { - width: 35px; - max-width: 35px; - } - `} - - &::after { - content: ''; - height: calc(100% + 1px); - position: absolute; - width: 4px; - right: -4px; - top: 0; - - ${({ freezeFirstColumns, theme }) => - freezeFirstColumns && - css` - box-shadow: 4px 0px 4px -4px ${theme.name === 'dark' - ? RGBA(theme.grayScale.gray50, 0.8) - : RGBA(theme.grayScale.gray100, 0.25)} inset; - `} - } - } `; type RecordTableProps = { + viewBarId: string; recordTableId: string; objectNameSingular: string; onColumnsChange: (columns: any) => void; @@ -157,102 +29,66 @@ type RecordTableProps = { }; export const RecordTable = ({ + viewBarId, recordTableId, objectNameSingular, onColumnsChange, createRecord, }: RecordTableProps) => { - const { scopeId, visibleTableColumnsSelector } = - useRecordTableStates(recordTableId); + const { scopeId } = useRecordTableStates(recordTableId); - const { objectMetadataItem } = useObjectMetadataItem({ - objectNameSingular, - }); + const { + isRecordTableInitialLoadingState, + tableRowIdsState, + pendingRecordIdState, + } = useRecordTableStates(recordTableId); - const { upsertRecord } = useUpsertRecordV2({ - objectNameSingular, - }); - - const handleUpsertRecord = ({ - persistField, - entityId, - fieldName, - }: { - persistField: () => void; - entityId: string; - fieldName: string; - }) => { - upsertRecord(persistField, entityId, fieldName, recordTableId); - }; - - const { openTableCell } = useOpenRecordTableCellV2(recordTableId); - - const handleOpenTableCell = (args: OpenTableCellArgs) => { - openTableCell(args); - }; - - const { moveFocus } = useRecordTableMoveFocus(recordTableId); - - const handleMoveFocus = (direction: MoveFocusDirection) => { - moveFocus(direction); - }; - - const { closeTableCell } = useCloseRecordTableCellV2(recordTableId); - - const handleCloseTableCell = () => { - closeTableCell(); - }; - - const { moveSoftFocusToCell } = - useMoveSoftFocusToCellOnHoverV2(recordTableId); + const isRecordTableInitialLoading = useRecoilValue( + isRecordTableInitialLoadingState, + ); - const handleMoveSoftFocusToCell = (cellPosition: TableCellPosition) => { - moveSoftFocusToCell(cellPosition); - }; + const tableRowIds = useRecoilValue(tableRowIdsState); - const { triggerContextMenu } = useTriggerContextMenu({ - recordTableId, - }); + const pendingRecordId = useRecoilValue(pendingRecordIdState); - const handleContextMenu = (event: React.MouseEvent, recordId: string) => { - triggerContextMenu(event, recordId); - }; + const { objectMetadataItem: foundObjectMetadataItem } = useObjectMetadataItem( + { objectNameSingular }, + ); - const { handleContainerMouseEnter } = useHandleContainerMouseEnter({ - recordTableId, - }); + const objectLabel = foundObjectMetadataItem?.labelSingular; + const isRemote = foundObjectMetadataItem?.isRemote ?? false; - const visibleTableColumns = useRecoilValue(visibleTableColumnsSelector()); + if (!isNonEmptyString(objectNameSingular)) { + return <></>; + } return ( <RecordTableScope recordTableScopeId={scopeId} onColumnsChange={onColumnsChange} > - {!!objectNameSingular && ( - <RecordTableContext.Provider - value={{ - objectMetadataItem, - onUpsertRecord: handleUpsertRecord, - onOpenTableCell: handleOpenTableCell, - onMoveFocus: handleMoveFocus, - onCloseTableCell: handleCloseTableCell, - onMoveSoftFocusToCell: handleMoveSoftFocusToCell, - onContextMenu: handleContextMenu, - onCellMouseEnter: handleContainerMouseEnter, - visibleTableColumns, - }} - > + <RecordTableContextProvider + objectNameSingular={objectNameSingular} + recordTableId={recordTableId} + viewBarId={viewBarId} + > + <RecordTableBodyEffect /> + {!isRecordTableInitialLoading && + tableRowIds.length === 0 && + isNull(pendingRecordId) ? ( + <RecordTableEmptyState + objectNameSingular={objectNameSingular} + objectLabel={objectLabel} + createRecord={createRecord} + isRemote={isRemote} + /> + ) : ( <StyledTable className="entity-table-cell"> <RecordTableHeader createRecord={createRecord} /> - <RecordTableBodyEffect objectNameSingular={objectNameSingular} /> - <RecordTableBody - objectNameSingular={objectNameSingular} - recordTableId={recordTableId} - /> + <RecordTableBody /> </StyledTable> - </RecordTableContext.Provider> - )} + )} + </RecordTableContextProvider> </RecordTableScope> ); }; diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableBody.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableBody.tsx deleted file mode 100644 index 640bfffee55b..000000000000 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableBody.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import { useRecoilValue } from 'recoil'; - -import { RecordTableBodyFetchMoreLoader } from '@/object-record/record-table/components/RecordTableBodyFetchMoreLoader'; -import { RecordTableRow } from '@/object-record/record-table/components/RecordTableRow'; -import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates'; -import { DraggableTableBody } from '@/ui/layout/draggable-list/components/DraggableTableBody'; - -type RecordTableBodyProps = { - objectNameSingular: string; - recordTableId: string; -}; - -export const RecordTableBody = ({ - objectNameSingular, - recordTableId, -}: RecordTableBodyProps) => { - const { tableRowIdsState } = useRecordTableStates(); - - const tableRowIds = useRecoilValue(tableRowIdsState); - - return ( - <> - <DraggableTableBody - objectNameSingular={objectNameSingular} - recordTableId={recordTableId} - draggableItems={ - <> - {tableRowIds.map((recordId, rowIndex) => { - return ( - <RecordTableRow - key={recordId} - recordId={recordId} - rowIndex={rowIndex} - /> - ); - })} - </> - } - /> - <RecordTableBodyFetchMoreLoader objectNameSingular={objectNameSingular} /> - </> - ); -}; diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableBodyEffect.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableBodyEffect.tsx deleted file mode 100644 index 4bea69f3d446..000000000000 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableBodyEffect.tsx +++ /dev/null @@ -1,58 +0,0 @@ -import { useEffect } from 'react'; -import { useRecoilState, useRecoilValue } from 'recoil'; - -import { useLoadRecordIndexTable } from '@/object-record/record-index/hooks/useLoadRecordIndexTable'; -import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates'; -import { isFetchingMoreRecordsFamilyState } from '@/object-record/states/isFetchingMoreRecordsFamilyState'; -import { useScrollRestoration } from '~/hooks/useScrollRestoration'; - -type RecordTableBodyEffectProps = { - objectNameSingular: string; -}; - -export const RecordTableBodyEffect = ({ - objectNameSingular, -}: RecordTableBodyEffectProps) => { - const { - fetchMoreRecords: fetchMoreObjects, - records, - totalCount, - setRecordTableData, - queryStateIdentifier, - loading, - } = useLoadRecordIndexTable(objectNameSingular); - - const { tableLastRowVisibleState } = useRecordTableStates(); - - const [tableLastRowVisible, setTableLastRowVisible] = useRecoilState( - tableLastRowVisibleState, - ); - - const isFetchingMoreObjects = useRecoilValue( - isFetchingMoreRecordsFamilyState(queryStateIdentifier), - ); - - const rowHeight = 32; - const viewportHeight = records.length * rowHeight; - - useScrollRestoration(viewportHeight); - - useEffect(() => { - if (!loading) { - setRecordTableData(records, totalCount); - } - }, [records, totalCount, setRecordTableData, loading]); - - useEffect(() => { - if (tableLastRowVisible && !isFetchingMoreObjects) { - fetchMoreObjects(); - } - }, [ - fetchMoreObjects, - isFetchingMoreObjects, - setTableLastRowVisible, - tableLastRowVisible, - ]); - - return <></>; -}; diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableContextProvider.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableContextProvider.tsx new file mode 100644 index 000000000000..7fe7343c9298 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableContextProvider.tsx @@ -0,0 +1,112 @@ +import { ReactNode } from 'react'; +import { useRecoilValue } from 'recoil'; + +import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; +import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext'; +import { useHandleContainerMouseEnter } from '@/object-record/record-table/hooks/internal/useHandleContainerMouseEnter'; +import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates'; +import { useRecordTableMoveFocus } from '@/object-record/record-table/hooks/useRecordTableMoveFocus'; +import { useCloseRecordTableCellV2 } from '@/object-record/record-table/record-table-cell/hooks/useCloseRecordTableCellV2'; +import { useMoveSoftFocusToCellOnHoverV2 } from '@/object-record/record-table/record-table-cell/hooks/useMoveSoftFocusToCellOnHoverV2'; +import { + OpenTableCellArgs, + useOpenRecordTableCellV2, +} from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2'; +import { useTriggerContextMenu } from '@/object-record/record-table/record-table-cell/hooks/useTriggerContextMenu'; +import { useUpsertRecord } from '@/object-record/record-table/record-table-cell/hooks/useUpsertRecord'; +import { MoveFocusDirection } from '@/object-record/record-table/types/MoveFocusDirection'; +import { TableCellPosition } from '@/object-record/record-table/types/TableCellPosition'; + +export const RecordTableContextProvider = ({ + viewBarId, + recordTableId, + objectNameSingular, + children, +}: { + viewBarId: string; + recordTableId: string; + objectNameSingular: string; + children: ReactNode; +}) => { + const { visibleTableColumnsSelector } = useRecordTableStates(recordTableId); + + const { objectMetadataItem } = useObjectMetadataItem({ + objectNameSingular, + }); + + const { upsertRecord } = useUpsertRecord({ + objectNameSingular, + }); + + const handleUpsertRecord = ({ + persistField, + entityId, + fieldName, + }: { + persistField: () => void; + entityId: string; + fieldName: string; + }) => { + upsertRecord(persistField, entityId, fieldName, recordTableId); + }; + + const { openTableCell } = useOpenRecordTableCellV2(recordTableId); + + const handleOpenTableCell = (args: OpenTableCellArgs) => { + openTableCell(args); + }; + + const { moveFocus } = useRecordTableMoveFocus(recordTableId); + + const handleMoveFocus = (direction: MoveFocusDirection) => { + moveFocus(direction); + }; + + const { closeTableCell } = useCloseRecordTableCellV2(recordTableId); + + const handleCloseTableCell = () => { + closeTableCell(); + }; + + const { moveSoftFocusToCell } = + useMoveSoftFocusToCellOnHoverV2(recordTableId); + + const handleMoveSoftFocusToCell = (cellPosition: TableCellPosition) => { + moveSoftFocusToCell(cellPosition); + }; + + const { triggerContextMenu } = useTriggerContextMenu({ + recordTableId, + }); + + const handleContextMenu = (event: React.MouseEvent, recordId: string) => { + triggerContextMenu(event, recordId); + }; + + const { handleContainerMouseEnter } = useHandleContainerMouseEnter({ + recordTableId, + }); + + const visibleTableColumns = useRecoilValue(visibleTableColumnsSelector()); + + return ( + <RecordTableContext.Provider + value={{ + viewBarId, + objectMetadataItem, + onUpsertRecord: handleUpsertRecord, + onOpenTableCell: handleOpenTableCell, + onMoveFocus: handleMoveFocus, + onCloseTableCell: handleCloseTableCell, + onMoveSoftFocusToCell: handleMoveSoftFocusToCell, + onContextMenu: handleContextMenu, + onCellMouseEnter: handleContainerMouseEnter, + visibleTableColumns, + recordTableId, + objectNameSingular, + }} + > + {children} + </RecordTableContext.Provider> + ); +}; diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableHeader.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableHeader.tsx deleted file mode 100644 index 9fe828dd9750..000000000000 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableHeader.tsx +++ /dev/null @@ -1,112 +0,0 @@ -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; -import { useRecoilValue } from 'recoil'; -import { IconPlus } from 'twenty-ui'; - -import { RecordTableHeaderCell } from '@/object-record/record-table/components/RecordTableHeaderCell'; -import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates'; -import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; -import { useScrollWrapperScopedRef } from '@/ui/utilities/scroll/hooks/useScrollWrapperScopedRef'; - -import { RecordTableHeaderPlusButtonContent } from './RecordTableHeaderPlusButtonContent'; -import { SelectAllCheckbox } from './SelectAllCheckbox'; - -const StyledTableHead = styled.thead` - cursor: pointer; -`; - -const StyledPlusIconHeaderCell = styled.th<{ isTableWiderThanScreen: boolean }>` - ${({ theme }) => { - return ` - &:hover { - background: ${theme.background.transparent.light}; - }; - padding-left: ${theme.spacing(3)}; - `; - }}; - border-left: none !important; - min-width: 32px; - ${({ isTableWiderThanScreen, theme }) => - isTableWiderThanScreen && - ` - width: 32px; - border-right: none !important; - background-color: ${theme.background.primary}; - `}; - z-index: 1; -`; - -const StyledPlusIconContainer = styled.div` - align-items: center; - display: flex; - height: 32px; - justify-content: center; - width: 32px; -`; - -export const HIDDEN_TABLE_COLUMN_DROPDOWN_ID = - 'hidden-table-columns-dropdown-scope-id'; - -const HIDDEN_TABLE_COLUMN_DROPDOWN_HOTKEY_SCOPE_ID = - 'hidden-table-columns-dropdown-hotkey-scope-id'; - -export const RecordTableHeader = ({ - createRecord, -}: { - createRecord: () => void; -}) => { - const { visibleTableColumnsSelector } = useRecordTableStates(); - - const scrollWrapper = useScrollWrapperScopedRef(); - const isTableWiderThanScreen = - (scrollWrapper.current?.clientWidth ?? 0) < - (scrollWrapper.current?.scrollWidth ?? 0); - - const visibleTableColumns = useRecoilValue(visibleTableColumnsSelector()); - const hiddenTableColumns = useRecoilValue(visibleTableColumnsSelector()); - - const theme = useTheme(); - - return ( - <StyledTableHead data-select-disable> - <tr> - <th></th> - <th - style={{ - width: 30, - minWidth: 30, - maxWidth: 30, - }} - > - <SelectAllCheckbox /> - </th> - {visibleTableColumns.map((column) => ( - <RecordTableHeaderCell - key={column.fieldMetadataId} - column={column} - createRecord={createRecord} - /> - ))} - <StyledPlusIconHeaderCell - isTableWiderThanScreen={isTableWiderThanScreen} - > - {hiddenTableColumns.length > 0 && ( - <Dropdown - dropdownId={HIDDEN_TABLE_COLUMN_DROPDOWN_ID} - clickableComponent={ - <StyledPlusIconContainer> - <IconPlus size={theme.icon.size.md} /> - </StyledPlusIconContainer> - } - dropdownComponents={<RecordTableHeaderPlusButtonContent />} - dropdownPlacement="bottom-start" - dropdownHotkeyScope={{ - scope: HIDDEN_TABLE_COLUMN_DROPDOWN_HOTKEY_SCOPE_ID, - }} - /> - )} - </StyledPlusIconHeaderCell> - </tr> - </StyledTableHead> - ); -}; diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableInternalEffect.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableInternalEffect.tsx index 9a3f062e0f2c..8b94a325f36a 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableInternalEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableInternalEffect.tsx @@ -5,7 +5,10 @@ import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTabl import { TableHotkeyScope } from '@/object-record/record-table/types/TableHotkeyScope'; import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys'; import { useClickOutsideListener } from '@/ui/utilities/pointer-event/hooks/useClickOutsideListener'; -import { useListenClickOutsideByClassName } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside'; +import { + ClickOutsideMode, + useListenClickOutsideByClassName, +} from '@/ui/utilities/pointer-event/hooks/useListenClickOutside'; type RecordTableInternalEffectProps = { recordTableId: string; @@ -30,6 +33,7 @@ export const RecordTableInternalEffect = ({ callback: () => { leaveTableFocus(); }, + mode: ClickOutsideMode.compareHTMLRef, }); useScopedHotkeys( diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableRow.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableRow.tsx deleted file mode 100644 index 5ec7e8ff4269..000000000000 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableRow.tsx +++ /dev/null @@ -1,156 +0,0 @@ -import { useContext } from 'react'; -import { useInView } from 'react-intersection-observer'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; -import { Draggable } from '@hello-pangea/dnd'; -import { useRecoilValue } from 'recoil'; - -import { getBasePathToShowPage } from '@/object-metadata/utils/getBasePathToShowPage'; -import { RecordValueSetterEffect } from '@/object-record/record-store/components/RecordValueSetterEffect'; -import { RecordTableCellFieldContextWrapper } from '@/object-record/record-table/components/RecordTableCellFieldContextWrapper'; -import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext'; -import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext'; -import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext'; -import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates'; -import { ScrollWrapperContext } from '@/ui/utilities/scroll/components/ScrollWrapper'; - -import { CheckboxCell } from './CheckboxCell'; -import { GripCell } from './GripCell'; - -type RecordTableRowProps = { - recordId: string; - rowIndex: number; - isPendingRow?: boolean; -}; - -const StyledTd = styled.td` - position: relative; - user-select: none; -`; - -const StyledTr = styled.tr<{ isDragging: boolean }>` - border: 1px solid transparent; - transition: border-left-color 0.2s ease-in-out; - - td:nth-of-type(-n + 2) { - background-color: ${({ theme }) => theme.background.primary}; - border-right-color: ${({ theme }) => theme.background.primary}; - } - - ${({ isDragging }) => - isDragging && - ` - td:nth-of-type(1) { - background-color: transparent; - border-color: transparent; - } - - td:nth-of-type(2) { - background-color: transparent; - border-color: transparent; - } - - td:nth-of-type(3) { - background-color: transparent; - border-color: transparent; - } - - `} -`; - -export const RecordTableRow = ({ - recordId, - rowIndex, - isPendingRow, -}: RecordTableRowProps) => { - const { visibleTableColumnsSelector, isRowSelectedFamilyState } = - useRecordTableStates(); - const currentRowSelected = useRecoilValue(isRowSelectedFamilyState(recordId)); - const { objectMetadataItem } = useContext(RecordTableContext); - - const visibleTableColumns = useRecoilValue(visibleTableColumnsSelector()); - - const scrollWrapperRef = useContext(ScrollWrapperContext); - - const { ref: elementRef, inView } = useInView({ - root: scrollWrapperRef.current?.querySelector( - '[data-overlayscrollbars-viewport="scrollbarHidden"]', - ), - rootMargin: '1000px', - }); - - const theme = useTheme(); - - return ( - <RecordTableRowContext.Provider - value={{ - recordId, - rowIndex, - pathToShowPage: - getBasePathToShowPage({ - objectNameSingular: objectMetadataItem.nameSingular, - }) + recordId, - objectNameSingular: objectMetadataItem.nameSingular, - isSelected: currentRowSelected, - isReadOnly: objectMetadataItem.isRemote ?? false, - isPendingRow, - }} - > - <RecordValueSetterEffect recordId={recordId} /> - - <Draggable key={recordId} draggableId={recordId} index={rowIndex}> - {(draggableProvided, draggableSnapshot) => ( - <StyledTr - ref={(node) => { - elementRef(node); - draggableProvided.innerRef(node); - }} - // eslint-disable-next-line react/jsx-props-no-spreading - {...draggableProvided.draggableProps} - style={{ - ...draggableProvided.draggableProps.style, - background: draggableSnapshot.isDragging - ? theme.background.transparent.light - : 'none', - borderColor: draggableSnapshot.isDragging - ? `${theme.border.color.medium}` - : 'transparent', - }} - isDragging={draggableSnapshot.isDragging} - data-testid={`row-id-${recordId}`} - data-selectable-id={recordId} - > - <StyledTd - // eslint-disable-next-line react/jsx-props-no-spreading - {...draggableProvided.dragHandleProps} - data-select-disable - > - <GripCell isDragging={draggableSnapshot.isDragging} /> - </StyledTd> - <StyledTd> - {!draggableSnapshot.isDragging && <CheckboxCell />} - </StyledTd> - {inView || draggableSnapshot.isDragging - ? visibleTableColumns.map((column, columnIndex) => ( - <RecordTableCellContext.Provider - value={{ - columnDefinition: column, - columnIndex, - }} - key={column.fieldMetadataId} - > - {draggableSnapshot.isDragging && columnIndex > 0 ? null : ( - <RecordTableCellFieldContextWrapper /> - )} - </RecordTableCellContext.Provider> - )) - : visibleTableColumns.map((column) => ( - <StyledTd key={column.fieldMetadataId}></StyledTd> - ))} - <StyledTd /> - </StyledTr> - )} - </Draggable> - </RecordTableRowContext.Provider> - ); -}; diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableRows.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableRows.tsx new file mode 100644 index 000000000000..40db65bbb80c --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableRows.tsx @@ -0,0 +1,16 @@ +import { useRecoilValue } from 'recoil'; + +import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates'; +import { RecordTableRow } from '@/object-record/record-table/record-table-row/components/RecordTableRow'; + +export const RecordTableRows = () => { + const { tableRowIdsState } = useRecordTableStates(); + + const tableRowIds = useRecoilValue(tableRowIdsState); + + return tableRowIds.map((recordId, rowIndex) => { + return ( + <RecordTableRow key={recordId} recordId={recordId} rowIndex={rowIndex} /> + ); + }); +}; diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableWithWrappers.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableWithWrappers.tsx index 63cced18d373..85e860436e93 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableWithWrappers.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableWithWrappers.tsx @@ -1,14 +1,11 @@ -import { useRef } from 'react'; import styled from '@emotion/styled'; -import { useRecoilCallback, useRecoilValue } from 'recoil'; +import { useRef } from 'react'; +import { useRecoilCallback } from 'recoil'; -import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { useDeleteOneRecord } from '@/object-record/hooks/useDeleteOneRecord'; import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata'; import { RecordTable } from '@/object-record/record-table/components/RecordTable'; -import { RecordTableEmptyState } from '@/object-record/record-table/components/RecordTableEmptyState'; import { EntityDeleteContext } from '@/object-record/record-table/contexts/EntityDeleteHookContext'; -import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates'; import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition'; import { DragSelect } from '@/ui/utilities/drag-select/components/DragSelect'; import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper'; @@ -31,6 +28,10 @@ const StyledTableContainer = styled.div` position: relative; `; +const StyledTableInternalContainer = styled.div` + height: 100%; +`; + type RecordTableWithWrappersProps = { objectNameSingular: string; recordTableId: string; @@ -48,32 +49,24 @@ export const RecordTableWithWrappers = ({ }: RecordTableWithWrappersProps) => { const tableBodyRef = useRef<HTMLDivElement>(null); - const { isRecordTableInitialLoadingState, tableRowIdsState } = - useRecordTableStates(recordTableId); - - const isRecordTableInitialLoading = useRecoilValue( - isRecordTableInitialLoadingState, - ); - - const tableRowIds = useRecoilValue(tableRowIdsState); - const { resetTableRowSelection, setRowSelected } = useRecordTable({ recordTableId, }); - const { objectMetadataItem: foundObjectMetadataItem } = useObjectMetadataItem( - { - objectNameSingular, - }, - ); - const { saveViewFields } = useSaveCurrentViewFields(viewBarId); const { deleteOneRecord } = useDeleteOneRecord({ objectNameSingular }); - const objectLabel = foundObjectMetadataItem?.labelSingular; - - const isRemote = foundObjectMetadataItem?.isRemote ?? false; + const handleColumnsChange = useRecoilCallback( + () => (columns) => { + saveViewFields( + mapColumnDefinitionsToViewFields( + columns as ColumnDefinition<FieldMetadata>[], + ), + ); + }, + [saveViewFields], + ); return ( <EntityDeleteContext.Provider value={deleteOneRecord}> @@ -81,20 +74,12 @@ export const RecordTableWithWrappers = ({ <RecordUpdateContext.Provider value={updateRecordMutation}> <StyledTableWithHeader> <StyledTableContainer> - <div ref={tableBodyRef}> + <StyledTableInternalContainer ref={tableBodyRef}> <RecordTable + viewBarId={viewBarId} recordTableId={recordTableId} objectNameSingular={objectNameSingular} - onColumnsChange={useRecoilCallback( - () => (columns) => { - saveViewFields( - mapColumnDefinitionsToViewFields( - columns as ColumnDefinition<FieldMetadata>[], - ), - ); - }, - [saveViewFields], - )} + onColumnsChange={handleColumnsChange} createRecord={createRecord} /> <DragSelect @@ -102,21 +87,11 @@ export const RecordTableWithWrappers = ({ onDragSelectionStart={resetTableRowSelection} onDragSelectionChange={setRowSelected} /> - </div> + </StyledTableInternalContainer> <RecordTableInternalEffect recordTableId={recordTableId} tableBodyRef={tableBodyRef} /> - {!isRecordTableInitialLoading && - // we cannot rely on count states because this is not available for remote objects - tableRowIds.length === 0 && ( - <RecordTableEmptyState - objectNameSingular={objectNameSingular} - objectLabel={objectLabel} - createRecord={createRecord} - isRemote={isRemote} - /> - )} </StyledTableContainer> </StyledTableWithHeader> </RecordUpdateContext.Provider> diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/__stories__/perf/RecordTableCell.perf.stories.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/__stories__/perf/RecordTableCell.perf.stories.tsx index 487465b609a2..add76f790a97 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/__stories__/perf/RecordTableCell.perf.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/components/__stories__/perf/RecordTableCell.perf.stories.tsx @@ -1,5 +1,5 @@ -import { useEffect } from 'react'; import { Meta, StoryObj } from '@storybook/react'; +import { useEffect } from 'react'; import { useRecoilState, useSetRecoilState } from 'recoil'; import { ComponentDecorator } from 'twenty-ui'; @@ -12,7 +12,6 @@ import { useSetRecordValue, } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; -import { RecordTableCellFieldContextWrapper } from '@/object-record/record-table/components/RecordTableCellFieldContextWrapper'; import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext'; import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext'; import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext'; @@ -21,6 +20,7 @@ import { ChipGeneratorsDecorator } from '~/testing/decorators/ChipGeneratorsDeco import { MemoryRouterDecorator } from '~/testing/decorators/MemoryRouterDecorator'; import { getProfilingStory } from '~/testing/profiling/utils/getProfilingStory'; +import { RecordTableCellFieldContextWrapper } from '@/object-record/record-table/record-table-cell/components/RecordTableCellFieldContextWrapper'; import { mockPerformance } from './mock'; const objectMetadataItems = getObjectMetadataItemsMock(); @@ -64,6 +64,7 @@ const meta: Meta = { <RecordFieldValueSelectorContextProvider> <RecordTableContext.Provider value={{ + viewBarId: mockPerformance.entityId, objectMetadataItem: mockPerformance.objectMetadataItem as any, onUpsertRecord: () => {}, onOpenTableCell: () => {}, @@ -73,6 +74,9 @@ const meta: Meta = { onContextMenu: () => {}, onCellMouseEnter: () => {}, visibleTableColumns: mockPerformance.visibleTableColumns as any, + objectNameSingular: + mockPerformance.objectMetadataItem.nameSingular, + recordTableId: 'recordTableId', }} > <RecordTableScope @@ -92,12 +96,19 @@ const meta: Meta = { }) + mockPerformance.entityId, isSelected: false, isReadOnly: false, + isDragging: false, + dragHandleProps: null, + inView: true, + isPendingRow: false, }} > <RecordTableCellContext.Provider value={{ columnDefinition: mockPerformance.fieldDefinition, columnIndex: 0, + cellPosition: { row: 0, column: 0 }, + hasSoftFocus: false, + isInEditMode: false, }} > <FieldContext.Provider diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/__stories__/perf/mock.ts b/packages/twenty-front/src/modules/object-record/record-table/components/__stories__/perf/mock.ts index ec60d500fbb4..925e8c70e7a7 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/__stories__/perf/mock.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/components/__stories__/perf/mock.ts @@ -800,7 +800,9 @@ export const mockPerformance = { }, employees: null, accountOwnerId: null, - address: '', + address: { + addressCity: 'San Francisco', + }, idealCustomerProfile: false, createdAt: '2024-05-01T13:16:29.046Z', id: '20202020-c21e-4ec2-873b-de4264d89025', @@ -844,7 +846,7 @@ export const mockPerformance = { }, employees: null, accountOwnerId: null, - address: '', + address: { addressCity: 'San Francisco' }, idealCustomerProfile: false, createdAt: '2024-05-01T13:16:29.046Z', id: '20202020-ed89-413a-b31a-962986e67bb4', diff --git a/packages/twenty-front/src/modules/object-record/record-table/constants/ColumnHeadDropdownId.ts b/packages/twenty-front/src/modules/object-record/record-table/constants/ColumnHeadDropdownId.ts deleted file mode 100644 index 8598c854650d..000000000000 --- a/packages/twenty-front/src/modules/object-record/record-table/constants/ColumnHeadDropdownId.ts +++ /dev/null @@ -1 +0,0 @@ -export const COLUMN_HEAD_DROPDOWN_ID = 'table-head-options-dropdown-id'; diff --git a/packages/twenty-front/src/modules/object-record/record-table/constants/HiddenTableColumnDropdownId.ts b/packages/twenty-front/src/modules/object-record/record-table/constants/HiddenTableColumnDropdownId.ts new file mode 100644 index 000000000000..b2a90ce6fedf --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-table/constants/HiddenTableColumnDropdownId.ts @@ -0,0 +1,2 @@ +export const HIDDEN_TABLE_COLUMN_DROPDOWN_ID = + 'hidden-table-columns-dropdown-scope-id'; diff --git a/packages/twenty-front/src/modules/object-record/record-table/contexts/RecordTableCellContext.ts b/packages/twenty-front/src/modules/object-record/record-table/contexts/RecordTableCellContext.ts index 3a17eedacbae..78eb5a8a55cb 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/contexts/RecordTableCellContext.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/contexts/RecordTableCellContext.ts @@ -2,12 +2,15 @@ import { createContext } from 'react'; import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata'; import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition'; +import { TableCellPosition } from '@/object-record/record-table/types/TableCellPosition'; -type RecordTableRowContextProps = { +export type RecordTableCellContextProps = { columnDefinition: ColumnDefinition<FieldMetadata>; columnIndex: number; + isInEditMode: boolean; + hasSoftFocus: boolean; + cellPosition: TableCellPosition; }; -export const RecordTableCellContext = createContext<RecordTableRowContextProps>( - {} as RecordTableRowContextProps, -); +export const RecordTableCellContext = + createContext<RecordTableCellContextProps>({} as RecordTableCellContextProps); diff --git a/packages/twenty-front/src/modules/object-record/record-table/contexts/RecordTableContext.ts b/packages/twenty-front/src/modules/object-record/record-table/contexts/RecordTableContext.ts index 4d25606854c0..960e544620a2 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/contexts/RecordTableContext.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/contexts/RecordTableContext.ts @@ -9,6 +9,7 @@ import { MoveFocusDirection } from '@/object-record/record-table/types/MoveFocus import { TableCellPosition } from '@/object-record/record-table/types/TableCellPosition'; export type RecordTableContextProps = { + viewBarId: string; objectMetadataItem: ObjectMetadataItem; onUpsertRecord: ({ persistField, @@ -26,6 +27,8 @@ export type RecordTableContextProps = { onContextMenu: (event: React.MouseEvent, recordId: string) => void; onCellMouseEnter: (args: HandleContainerMouseEnterArgs) => void; visibleTableColumns: ColumnDefinition<FieldMetadata>[]; + recordTableId: string; + objectNameSingular: string; }; export const RecordTableContext = createContext<RecordTableContextProps>( diff --git a/packages/twenty-front/src/modules/object-record/record-table/contexts/RecordTableRowContext.ts b/packages/twenty-front/src/modules/object-record/record-table/contexts/RecordTableRowContext.ts index f04afe492820..d0ed1aea296b 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/contexts/RecordTableRowContext.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/contexts/RecordTableRowContext.ts @@ -1,4 +1,5 @@ import { createContext } from 'react'; +import { DraggableProvidedDragHandleProps } from '@hello-pangea/dnd'; export type RecordTableRowContextProps = { pathToShowPage: string; @@ -8,6 +9,9 @@ export type RecordTableRowContextProps = { isSelected: boolean; isReadOnly: boolean; isPendingRow?: boolean; + isDragging: boolean; + dragHandleProps: DraggableProvidedDragHandleProps | null; + inView?: boolean; }; export const RecordTableRowContext = createContext<RecordTableRowContextProps>( diff --git a/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useCloseCurrentTableCellInEditMode.ts b/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useCloseCurrentTableCellInEditMode.ts index b894046ce057..a9976aa05fac 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useCloseCurrentTableCellInEditMode.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useCloseCurrentTableCellInEditMode.ts @@ -21,13 +21,6 @@ export const useCloseCurrentTableCellInEditMode = (recordTableId?: string) => { isTableCellInEditModeFamilyState(currentTableCellInEditModePosition), false, ); - - document.dispatchEvent( - new CustomEvent( - `edit-mode-change-${currentTableCellInEditModePosition.row}:${currentTableCellInEditModePosition.column}`, - { detail: false }, - ), - ); }; }, [currentTableCellInEditModePositionState, isTableCellInEditModeFamilyState], diff --git a/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useLeaveTableFocus.ts b/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useLeaveTableFocus.ts index 0ee3aa62d6a8..0a52eb083239 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useLeaveTableFocus.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useLeaveTableFocus.ts @@ -8,12 +8,17 @@ import { TableHotkeyScope } from '../../types/TableHotkeyScope'; import { useCloseCurrentTableCellInEditMode } from './useCloseCurrentTableCellInEditMode'; import { useDisableSoftFocus } from './useDisableSoftFocus'; +import { useSetHasUserSelectedAllRows } from './useSetAllRowSelectedState'; export const useLeaveTableFocus = (recordTableId?: string) => { const disableSoftFocus = useDisableSoftFocus(recordTableId); const closeCurrentCellInEditMode = useCloseCurrentTableCellInEditMode(recordTableId); + const setHasUserSelectedAllRows = useSetHasUserSelectedAllRows(recordTableId); + + const selectAllRows = useSetHasUserSelectedAllRows(recordTableId); + const { isSoftFocusActiveState } = useRecordTableStates(recordTableId); return useRecoilCallback( @@ -38,7 +43,15 @@ export const useLeaveTableFocus = (recordTableId?: string) => { closeCurrentCellInEditMode(); disableSoftFocus(); + setHasUserSelectedAllRows(false); + selectAllRows(false); }, - [closeCurrentCellInEditMode, disableSoftFocus, isSoftFocusActiveState], + [ + closeCurrentCellInEditMode, + disableSoftFocus, + isSoftFocusActiveState, + selectAllRows, + setHasUserSelectedAllRows, + ], ); }; diff --git a/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useMoveEditModeToCellPosition.ts b/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useMoveEditModeToCellPosition.ts index c51be2fa6bdb..02e04a259d31 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useMoveEditModeToCellPosition.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useMoveEditModeToCellPosition.ts @@ -24,23 +24,9 @@ export const useMoveEditModeToTableCellPosition = (recordTableId?: string) => { false, ); - document.dispatchEvent( - new CustomEvent( - `edit-mode-change-${currentTableCellInEditModePosition.row}:${currentTableCellInEditModePosition.column}`, - { detail: false }, - ), - ); - set(currentTableCellInEditModePositionState, newPosition); set(isTableCellInEditModeFamilyState(newPosition), true); - - document.dispatchEvent( - new CustomEvent( - `edit-mode-change-${newPosition.row}:${newPosition.column}`, - { detail: true }, - ), - ); }; }, [currentTableCellInEditModePositionState, isTableCellInEditModeFamilyState], diff --git a/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useRecordTableStates.ts b/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useRecordTableStates.ts index 1e178da5bd7a..1fbc4a8bd810 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useRecordTableStates.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useRecordTableStates.ts @@ -109,7 +109,7 @@ export const useRecordTableStates = (recordTableId?: string) => { isRowSelectedComponentFamilyState, scopeId, ), - hasUserSelectedAllRowState: extractComponentState( + hasUserSelectedAllRowsState: extractComponentState( hasUserSelectedAllRowsComponentState, scopeId, ), diff --git a/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useResetTableRowSelection.ts b/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useResetTableRowSelection.ts index 7e86f581909c..1b6263739111 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useResetTableRowSelection.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useResetTableRowSelection.ts @@ -4,8 +4,11 @@ import { useRecordTableStates } from '@/object-record/record-table/hooks/interna import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue'; export const useResetTableRowSelection = (recordTableId?: string) => { - const { tableRowIdsState, isRowSelectedFamilyState } = - useRecordTableStates(recordTableId); + const { + tableRowIdsState, + isRowSelectedFamilyState, + hasUserSelectedAllRowsState, + } = useRecordTableStates(recordTableId); return useRecoilCallback( ({ snapshot, set }) => @@ -15,7 +18,9 @@ export const useResetTableRowSelection = (recordTableId?: string) => { for (const rowId of tableRowIds) { set(isRowSelectedFamilyState(rowId), false); } + + set(hasUserSelectedAllRowsState, false); }, - [tableRowIdsState, isRowSelectedFamilyState], + [tableRowIdsState, isRowSelectedFamilyState, hasUserSelectedAllRowsState], ); }; diff --git a/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useSetAllRowSelectedState.ts b/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useSetAllRowSelectedState.ts index 4544c4b71f95..5df32d9006d2 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useSetAllRowSelectedState.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useSetAllRowSelectedState.ts @@ -3,14 +3,13 @@ import { useRecoilCallback } from 'recoil'; import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates'; export const useSetHasUserSelectedAllRows = (recordTableId?: string) => { - const { hasUserSelectedAllRowState: hasUserSelectedAllRowFamilyState } = - useRecordTableStates(recordTableId); + const { hasUserSelectedAllRowsState } = useRecordTableStates(recordTableId); return useRecoilCallback( ({ set }) => (selected: boolean) => { - set(hasUserSelectedAllRowFamilyState, selected); + set(hasUserSelectedAllRowsState, selected); }, - [hasUserSelectedAllRowFamilyState], + [hasUserSelectedAllRowsState], ); }; diff --git a/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useSetRecordTableData.ts b/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useSetRecordTableData.ts index 64ca715b896a..eeaf15147c4a 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useSetRecordTableData.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useSetRecordTableData.ts @@ -19,7 +19,7 @@ export const useSetRecordTableData = ({ tableRowIdsState, numberOfTableRowsState, isRowSelectedFamilyState, - hasUserSelectedAllRowState, + hasUserSelectedAllRowsState, } = useRecordTableStates(recordTableId); return useRecoilCallback( @@ -39,7 +39,7 @@ export const useSetRecordTableData = ({ const hasUserSelectedAllRows = getSnapshotValue( snapshot, - hasUserSelectedAllRowState, + hasUserSelectedAllRowsState, ); const entityIds = newEntityArray.map((entity) => entity.id); @@ -62,7 +62,7 @@ export const useSetRecordTableData = ({ tableRowIdsState, onEntityCountChange, isRowSelectedFamilyState, - hasUserSelectedAllRowState, + hasUserSelectedAllRowsState, ], ); }; diff --git a/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useSetSoftFocusPosition.ts b/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useSetSoftFocusPosition.ts index d645c7bb9036..edf8f7a904e0 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useSetSoftFocusPosition.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useSetSoftFocusPosition.ts @@ -24,23 +24,9 @@ export const useSetSoftFocusPosition = (recordTableId?: string) => { set(isSoftFocusOnTableCellFamilyState(currentPosition), false); - document.dispatchEvent( - new CustomEvent( - `soft-focus-move-${currentPosition.row}:${currentPosition.column}`, - { detail: false }, - ), - ); - set(softFocusPositionState, newPosition); set(isSoftFocusOnTableCellFamilyState(newPosition), true); - - document.dispatchEvent( - new CustomEvent( - `soft-focus-move-${newPosition.row}:${newPosition.column}`, - { detail: true }, - ), - ); }; }, [ diff --git a/packages/twenty-front/src/modules/object-record/record-table/hooks/useRecordTable.ts b/packages/twenty-front/src/modules/object-record/record-table/hooks/useRecordTable.ts index 785baebe165c..6cad63df5448 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/hooks/useRecordTable.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/hooks/useRecordTable.ts @@ -45,6 +45,7 @@ export const useRecordTable = (props?: useRecordTableProps) => { onToggleColumnFilterState, onToggleColumnSortState, pendingRecordIdState, + hasUserSelectedAllRowsState, } = useRecordTableStates(recordTableId); const setAvailableTableColumns = useRecoilCallback( @@ -226,5 +227,6 @@ export const useRecordTable = (props?: useRecordTableProps) => { setOnToggleColumnFilter, setOnToggleColumnSort, setPendingRecordId, + hasUserSelectedAllRowsState, }; }; diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBody.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBody.tsx new file mode 100644 index 000000000000..2a6e46c21987 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBody.tsx @@ -0,0 +1,38 @@ +import { useRecoilValue } from 'recoil'; + +import { RecordTableRows } from '@/object-record/record-table/components/RecordTableRows'; +import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext'; +import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates'; +import { RecordTableBodyDragDropContext } from '@/object-record/record-table/record-table-body/components/RecordTableBodyDragDropContext'; +import { RecordTableBodyDroppable } from '@/object-record/record-table/record-table-body/components/RecordTableBodyDroppable'; +import { RecordTableBodyFetchMoreLoader } from '@/object-record/record-table/record-table-body/components/RecordTableBodyFetchMoreLoader'; +import { RecordTableBodyLoading } from '@/object-record/record-table/record-table-body/components/RecordTableBodyLoading'; +import { RecordTablePendingRow } from '@/object-record/record-table/record-table-row/components/RecordTablePendingRow'; +import { useContext } from 'react'; + +export const RecordTableBody = () => { + const { tableRowIdsState, isRecordTableInitialLoadingState } = + useRecordTableStates(); + + const { objectNameSingular } = useContext(RecordTableContext); + + const tableRowIds = useRecoilValue(tableRowIdsState); + + const isRecordTableInitialLoading = useRecoilValue( + isRecordTableInitialLoadingState, + ); + + if (isRecordTableInitialLoading && tableRowIds.length === 0) { + return <RecordTableBodyLoading />; + } + + return ( + <RecordTableBodyDragDropContext> + <RecordTableBodyDroppable> + <RecordTablePendingRow /> + <RecordTableRows /> + </RecordTableBodyDroppable> + <RecordTableBodyFetchMoreLoader objectNameSingular={objectNameSingular} /> + </RecordTableBodyDragDropContext> + ); +}; diff --git a/packages/twenty-front/src/modules/ui/layout/draggable-list/components/DraggableTableBody.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyDragDropContext.tsx similarity index 58% rename from packages/twenty-front/src/modules/ui/layout/draggable-list/components/DraggableTableBody.tsx rename to packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyDragDropContext.tsx index c1513d828b74..ae352714590e 100644 --- a/packages/twenty-front/src/modules/ui/layout/draggable-list/components/DraggableTableBody.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyDragDropContext.tsx @@ -1,42 +1,30 @@ -import { useState } from 'react'; -import styled from '@emotion/styled'; -import { DragDropContext, Droppable, DropResult } from '@hello-pangea/dnd'; +import { ReactNode, useContext } from 'react'; +import { DragDropContext, DropResult } from '@hello-pangea/dnd'; import { useRecoilValue, useSetRecoilState } from 'recoil'; -import { v4 } from 'uuid'; import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord'; -import { RecordTablePendingRow } from '@/object-record/record-table/components/RecordTablePendingRow'; +import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext'; import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates'; import { useComputeNewRowPosition } from '@/object-record/record-table/hooks/useComputeNewRowPosition'; import { isRemoveSortingModalOpenState } from '@/object-record/record-table/states/isRemoveSortingModalOpenState'; import { useGetCurrentView } from '@/views/hooks/useGetCurrentView'; import { isDefined } from '~/utils/isDefined'; -type DraggableTableBodyProps = { - draggableItems: React.ReactNode; - objectNameSingular: string; - recordTableId: string; -}; - -const StyledTbody = styled.tbody` - overflow: hidden; -`; +export const RecordTableBodyDragDropContext = ({ + children, +}: { + children: ReactNode; +}) => { + const { objectNameSingular, recordTableId } = useContext(RecordTableContext); -export const DraggableTableBody = ({ - objectNameSingular, - draggableItems, - recordTableId, -}: DraggableTableBodyProps) => { - const [v4Persistable] = useState(v4()); + const { updateOneRecord: updateOneRow } = useUpdateOneRecord({ + objectNameSingular, + }); const { tableRowIdsState } = useRecordTableStates(); const tableRowIds = useRecoilValue(tableRowIdsState); - const { updateOneRecord: updateOneRow } = useUpdateOneRecord({ - objectNameSingular, - }); - const { currentViewWithCombinedFiltersAndSorts } = useGetCurrentView(recordTableId); @@ -45,6 +33,7 @@ export const DraggableTableBody = ({ const setIsRemoveSortingModalOpenState = useSetRecoilState( isRemoveSortingModalOpenState, ); + const computeNewRowPosition = useComputeNewRowPosition(); const handleDragEnd = (result: DropResult) => { @@ -68,20 +57,6 @@ export const DraggableTableBody = ({ }; return ( - <DragDropContext onDragEnd={handleDragEnd}> - <Droppable droppableId={v4Persistable}> - {(provided) => ( - <StyledTbody - ref={provided.innerRef} - // eslint-disable-next-line react/jsx-props-no-spreading - {...provided.droppableProps} - > - <RecordTablePendingRow /> - {draggableItems} - {provided.placeholder} - </StyledTbody> - )} - </Droppable> - </DragDropContext> + <DragDropContext onDragEnd={handleDragEnd}>{children}</DragDropContext> ); }; diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyDroppable.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyDroppable.tsx new file mode 100644 index 000000000000..bd062d3abb4f --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyDroppable.tsx @@ -0,0 +1,67 @@ +import { Theme } from '@emotion/react'; +import { Droppable } from '@hello-pangea/dnd'; +import { styled } from '@linaria/react'; +import { ReactNode, useContext, useState } from 'react'; +import { ThemeContext } from 'twenty-ui'; +import { v4 } from 'uuid'; + +const StyledTbody = styled.tbody<{ + theme: Theme; +}>` + overflow: hidden; + + &.first-columns-sticky { + td:nth-of-type(1) { + position: sticky; + left: 0; + z-index: 5; + } + td:nth-of-type(2) { + position: sticky; + left: 9px; + z-index: 5; + } + td:nth-of-type(3) { + position: sticky; + left: 39px; + z-index: 5; + &::after { + content: ''; + position: absolute; + top: -1px; + height: calc(100% + 2px); + width: 4px; + right: 0px; + box-shadow: ${({ theme }) => theme.boxShadow.light}; + clip-path: inset(0px -4px 0px 0px); + } + } + } +`; + +export const RecordTableBodyDroppable = ({ + children, +}: { + children: ReactNode; +}) => { + const [v4Persistable] = useState(v4()); + + const { theme } = useContext(ThemeContext); + + return ( + <Droppable droppableId={v4Persistable}> + {(provided) => ( + <StyledTbody + id="record-table-body" + theme={theme} + ref={provided.innerRef} + // eslint-disable-next-line react/jsx-props-no-spreading + {...provided.droppableProps} + > + {children} + {provided.placeholder} + </StyledTbody> + )} + </Droppable> + ); +}; diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyEffect.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyEffect.tsx new file mode 100644 index 000000000000..33816ad4d3ec --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyEffect.tsx @@ -0,0 +1,148 @@ +import { useContext, useEffect, useState } from 'react'; +import { useRecoilState, useRecoilValue } from 'recoil'; +import { useDebouncedCallback } from 'use-debounce'; + +import { lastShowPageRecordIdState } from '@/object-record/record-field/states/lastShowPageRecordId'; +import { useLoadRecordIndexTable } from '@/object-record/record-index/hooks/useLoadRecordIndexTable'; +import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext'; +import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates'; +import { isRecordTableScrolledLeftComponentState } from '@/object-record/record-table/states/isRecordTableScrolledLeftComponentState'; +import { isRecordTableScrolledTopComponentState } from '@/object-record/record-table/states/isRecordTableScrolledTopComponentState'; +import { isFetchingMoreRecordsFamilyState } from '@/object-record/states/isFetchingMoreRecordsFamilyState'; +import { scrollLeftState } from '@/ui/utilities/scroll/states/scrollLeftState'; +import { scrollTopState } from '@/ui/utilities/scroll/states/scrollTopState'; +import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { isNonEmptyString } from '@sniptt/guards'; +import { useScrollRestoration } from '~/hooks/useScrollRestoration'; +import { useScrollToPosition } from '~/hooks/useScrollToPosition'; + +export const ROW_HEIGHT = 32; + +export const RecordTableBodyEffect = () => { + const { objectNameSingular } = useContext(RecordTableContext); + + const [hasInitializedScroll, setHasInitiazedScroll] = useState(false); + + const { + fetchMoreRecords: fetchMoreObjects, + records, + totalCount, + setRecordTableData, + loading, + queryStateIdentifier, + } = useLoadRecordIndexTable(objectNameSingular); + + const isFetchingMoreObjects = useRecoilValue( + isFetchingMoreRecordsFamilyState(queryStateIdentifier), + ); + + const { tableLastRowVisibleState } = useRecordTableStates(); + + const tableLastRowVisible = useRecoilValue(tableLastRowVisibleState); + + const scrollTop = useRecoilValue(scrollTopState); + const setIsRecordTableScrolledTop = useSetRecoilComponentState( + isRecordTableScrolledTopComponentState, + ); + + useEffect(() => { + setIsRecordTableScrolledTop(scrollTop === 0); + if (scrollTop > 0) { + document + .getElementById('record-table-header') + ?.classList.add('header-sticky'); + } else { + document + .getElementById('record-table-header') + ?.classList.remove('header-sticky'); + } + }, [scrollTop, setIsRecordTableScrolledTop]); + + const scrollLeft = useRecoilValue(scrollLeftState); + + const setIsRecordTableScrolledLeft = useSetRecoilComponentState( + isRecordTableScrolledLeftComponentState, + ); + + useEffect(() => { + setIsRecordTableScrolledLeft(scrollLeft === 0); + if (scrollLeft > 0) { + document + .getElementById('record-table-body') + ?.classList.add('first-columns-sticky'); + document + .getElementById('record-table-header') + ?.classList.add('first-columns-sticky'); + } else { + document + .getElementById('record-table-body') + ?.classList.remove('first-columns-sticky'); + document + .getElementById('record-table-header') + ?.classList.remove('first-columns-sticky'); + } + }, [scrollLeft, setIsRecordTableScrolledLeft]); + + const rowHeight = ROW_HEIGHT; + const viewportHeight = records.length * rowHeight; + + const [lastShowPageRecordId, setLastShowPageRecordId] = useRecoilState( + lastShowPageRecordIdState, + ); + + const { scrollToPosition } = useScrollToPosition(); + + useEffect(() => { + if (isNonEmptyString(lastShowPageRecordId) && !hasInitializedScroll) { + const isRecordAlreadyFetched = records.some( + (record) => record.id === lastShowPageRecordId, + ); + + if (isRecordAlreadyFetched) { + const recordPosition = records.findIndex( + (record) => record.id === lastShowPageRecordId, + ); + + const positionInPx = recordPosition * ROW_HEIGHT; + + scrollToPosition(positionInPx); + + setHasInitiazedScroll(true); + } + } + }, [ + loading, + isFetchingMoreObjects, + lastShowPageRecordId, + fetchMoreObjects, + records, + scrollToPosition, + hasInitializedScroll, + setLastShowPageRecordId, + ]); + + useScrollRestoration(viewportHeight); + + useEffect(() => { + if (!loading) { + setRecordTableData(records, totalCount); + } + }, [records, totalCount, setRecordTableData, loading]); + + const fetchMoreDebouncedIfRequested = useDebouncedCallback(async () => { + // We are debouncing here to give the user some room to scroll if they want to within this throttle window + await fetchMoreObjects(); + }, 100); + + useEffect(() => { + if (!isFetchingMoreObjects && tableLastRowVisible) { + fetchMoreDebouncedIfRequested(); + } + }, [ + fetchMoreDebouncedIfRequested, + isFetchingMoreObjects, + tableLastRowVisible, + ]); + + return <></>; +}; diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableBodyFetchMoreLoader.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyFetchMoreLoader.tsx similarity index 100% rename from packages/twenty-front/src/modules/object-record/record-table/components/RecordTableBodyFetchMoreLoader.tsx rename to packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyFetchMoreLoader.tsx diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyLoading.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyLoading.tsx new file mode 100644 index 000000000000..8a80403ded4f --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyLoading.tsx @@ -0,0 +1,31 @@ +import { useRecoilValue } from 'recoil'; + +import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates'; +import { RecordTableCellCheckbox } from '@/object-record/record-table/record-table-cell/components/RecordTableCellCheckbox'; +import { RecordTableCellGrip } from '@/object-record/record-table/record-table-cell/components/RecordTableCellGrip'; +import { RecordTableCellLoading } from '@/object-record/record-table/record-table-cell/components/RecordTableCellLoading'; +import { RecordTableTr } from '@/object-record/record-table/record-table-row/components/RecordTableTr'; + +export const RecordTableBodyLoading = () => { + const { visibleTableColumnsSelector } = useRecordTableStates(); + const visibleTableColumns = useRecoilValue(visibleTableColumnsSelector()); + + return ( + <tbody> + {Array.from({ length: 8 }).map((_, rowIndex) => ( + <RecordTableTr + isDragging={false} + data-testid={`row-id-${rowIndex}`} + data-selectable-id={`row-id-${rowIndex}`} + key={rowIndex} + > + <RecordTableCellGrip /> + <RecordTableCellCheckbox /> + {visibleTableColumns.map((column) => ( + <RecordTableCellLoading key={column.fieldMetadataId} /> + ))} + </RecordTableTr> + ))} + </tbody> + ); +}; diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCell.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCell.tsx index a38d61a39dc5..4d6fcdd74fab 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCell.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCell.tsx @@ -1,109 +1,13 @@ -import { useContext } from 'react'; - import { FieldDisplay } from '@/object-record/record-field/components/FieldDisplay'; -import { FieldInput } from '@/object-record/record-field/components/FieldInput'; -import { FieldContext } from '@/object-record/record-field/contexts/FieldContext'; import { FieldFocusContextProvider } from '@/object-record/record-field/contexts/FieldFocusContextProvider'; -import { FieldInputEvent } from '@/object-record/record-field/types/FieldInputEvent'; -import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext'; -import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext'; import { RecordTableCellContainer } from '@/object-record/record-table/record-table-cell/components/RecordTableCellContainer'; -import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope'; - -export const RecordTableCell = ({ - customHotkeyScope, -}: { - customHotkeyScope: HotkeyScope; -}) => { - const { onUpsertRecord, onMoveFocus, onCloseTableCell } = - useContext(RecordTableContext); - const { entityId, fieldDefinition } = useContext(FieldContext); - const { isReadOnly } = useContext(RecordTableRowContext); - - const handleEnter: FieldInputEvent = (persistField) => { - onUpsertRecord({ - persistField, - entityId, - fieldName: fieldDefinition.metadata.fieldName, - }); - - onCloseTableCell(); - onMoveFocus('down'); - }; - - const handleSubmit: FieldInputEvent = (persistField) => { - onUpsertRecord({ - persistField, - entityId, - fieldName: fieldDefinition.metadata.fieldName, - }); - - onCloseTableCell(); - }; - - const handleCancel = () => { - onCloseTableCell(); - }; - - const handleClickOutside: FieldInputEvent = (persistField) => { - onUpsertRecord({ - persistField, - entityId, - fieldName: fieldDefinition.metadata.fieldName, - }); - - onCloseTableCell(); - }; - - const handleEscape: FieldInputEvent = (persistField) => { - onUpsertRecord({ - persistField, - entityId, - fieldName: fieldDefinition.metadata.fieldName, - }); - - onCloseTableCell(); - }; - - const handleTab: FieldInputEvent = (persistField) => { - onUpsertRecord({ - persistField, - entityId, - fieldName: fieldDefinition.metadata.fieldName, - }); - - onCloseTableCell(); - onMoveFocus('right'); - }; - - const handleShiftTab: FieldInputEvent = (persistField) => { - onUpsertRecord({ - persistField, - entityId, - fieldName: fieldDefinition.metadata.fieldName, - }); - - onCloseTableCell(); - onMoveFocus('left'); - }; +import { RecordTableCellFieldInput } from '@/object-record/record-table/record-table-cell/components/RecordTableCellFieldInput'; +export const RecordTableCell = () => { return ( <FieldFocusContextProvider> <RecordTableCellContainer - editHotkeyScope={customHotkeyScope} - editModeContent={ - <FieldInput - recordFieldInputdId={`${entityId}-${fieldDefinition?.metadata?.fieldName}`} - onCancel={handleCancel} - onClickOutside={handleClickOutside} - onEnter={handleEnter} - onEscape={handleEscape} - onShiftTab={handleShiftTab} - onSubmit={handleSubmit} - onTab={handleTab} - isReadOnly={isReadOnly} - /> - } + editModeContent={<RecordTableCellFieldInput />} nonEditModeContent={<FieldDisplay />} /> </FieldFocusContextProvider> diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellBaseContainer.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellBaseContainer.tsx new file mode 100644 index 000000000000..3a2a8c5c9bf8 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellBaseContainer.tsx @@ -0,0 +1,101 @@ +import { ReactNode, useContext } from 'react'; +import { styled } from '@linaria/react'; +import { BORDER_COMMON, ThemeContext } from 'twenty-ui'; + +import { FieldContext } from '@/object-record/record-field/contexts/FieldContext'; +import { useFieldFocus } from '@/object-record/record-field/hooks/useFieldFocus'; +import { CellHotkeyScopeContext } from '@/object-record/record-table/contexts/CellHotkeyScopeContext'; +import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext'; +import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext'; +import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext'; +import { + DEFAULT_CELL_SCOPE, + useOpenRecordTableCellFromCell, +} from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellFromCell'; + +const StyledBaseContainer = styled.div<{ + hasSoftFocus: boolean; + fontColorExtraLight: string; + backgroundColorTransparentSecondary: string; +}>` + align-items: center; + box-sizing: border-box; + cursor: pointer; + display: flex; + height: 32px; + position: relative; + user-select: none; + + background: ${({ hasSoftFocus, backgroundColorTransparentSecondary }) => + hasSoftFocus ? backgroundColorTransparentSecondary : 'none'}; + + border-radius: ${({ hasSoftFocus }) => + hasSoftFocus ? BORDER_COMMON.radius.sm : 'none'}; + + outline: ${({ hasSoftFocus, fontColorExtraLight }) => + hasSoftFocus ? `1px solid ${fontColorExtraLight}` : 'none'}; +`; + +export const RecordTableCellBaseContainer = ({ + children, +}: { + children: ReactNode; +}) => { + const { setIsFocused } = useFieldFocus(); + const { openTableCell } = useOpenRecordTableCellFromCell(); + const { theme } = useContext(ThemeContext); + const { recordId } = useContext(RecordTableRowContext); + + const { hasSoftFocus, cellPosition } = useContext(RecordTableCellContext); + + const { onMoveSoftFocusToCell, onCellMouseEnter } = + useContext(RecordTableContext); + + const handleContainerMouseMove = () => { + setIsFocused(true); + if (!hasSoftFocus) { + onCellMouseEnter({ + cellPosition, + }); + } + }; + + const handleContainerMouseLeave = () => { + setIsFocused(false); + }; + + const handleContainerClick = () => { + if (!hasSoftFocus) { + onMoveSoftFocusToCell(cellPosition); + openTableCell(); + } + }; + + const { onContextMenu } = useContext(RecordTableContext); + + const handleContextMenu = (event: React.MouseEvent) => { + onContextMenu(event, recordId); + }; + + const { hotkeyScope } = useContext(FieldContext); + + const editHotkeyScope = { scope: hotkeyScope } ?? DEFAULT_CELL_SCOPE; + + return ( + <CellHotkeyScopeContext.Provider value={editHotkeyScope}> + <StyledBaseContainer + onMouseLeave={handleContainerMouseLeave} + onMouseMove={handleContainerMouseMove} + onClick={handleContainerClick} + onContextMenu={handleContextMenu} + backgroundColorTransparentSecondary={ + theme.background.transparent.secondary + } + fontColorExtraLight={theme.font.color.extraLight} + hasSoftFocus={hasSoftFocus} + > + {children} + </StyledBaseContainer> + </CellHotkeyScopeContext.Provider> + ); +}; diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellButton.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellButton.tsx index 287df8331f07..25b0e10f6379 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellButton.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellButton.tsx @@ -1,8 +1,8 @@ import styled from '@emotion/styled'; import { IconComponent } from 'twenty-ui'; -import { AnimatedContainer } from '@/object-record/record-table/components/AnimatedContainer'; import { FloatingIconButton } from '@/ui/input/button/components/FloatingIconButton'; +import { AnimatedContainer } from '@/ui/utilities/animation/components/AnimatedContainer'; const StyledButtonContainer = styled.div` margin: ${({ theme }) => theme.spacing(1)}; diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/CheckboxCell.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellCheckbox.tsx similarity index 75% rename from packages/twenty-front/src/modules/object-record/record-table/components/CheckboxCell.tsx rename to packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellCheckbox.tsx index 2aff77e1b162..a261fa2ae375 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/CheckboxCell.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellCheckbox.tsx @@ -1,9 +1,10 @@ -import { useCallback, useContext } from 'react'; import styled from '@emotion/styled'; +import { useCallback, useContext } from 'react'; import { useRecoilValue, useSetRecoilState } from 'recoil'; import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext'; import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates'; +import { RecordTableTd } from '@/object-record/record-table/record-table-cell/components/RecordTableTd'; import { useSetCurrentRowSelected } from '@/object-record/record-table/record-table-row/hooks/useSetCurrentRowSelected'; import { Checkbox } from '@/ui/input/components/Checkbox'; import { actionBarOpenState } from '@/ui/navigation/action-bar/states/actionBarIsOpenState'; @@ -16,10 +17,11 @@ const StyledContainer = styled.div` height: 32px; justify-content: center; - background-color: ${({ theme }) => theme.background.primary}; `; -export const CheckboxCell = () => { +export const RecordTableCellCheckbox = () => { + const { isSelected } = useContext(RecordTableRowContext); + const { recordId } = useContext(RecordTableRowContext); const { isRowSelectedFamilyState } = useRecordTableStates(); const setActionBarOpenState = useSetRecoilState(actionBarOpenState); @@ -32,8 +34,10 @@ export const CheckboxCell = () => { }, [currentRowSelected, setActionBarOpenState, setCurrentRowSelected]); return ( - <StyledContainer onClick={handleClick}> - <Checkbox checked={currentRowSelected} /> - </StyledContainer> + <RecordTableTd isSelected={isSelected} hasRightBorder={false}> + <StyledContainer onClick={handleClick}> + <Checkbox checked={currentRowSelected} /> + </StyledContainer> + </RecordTableTd> ); }; diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellContainer.module.css b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellContainer.module.css deleted file mode 100644 index eef506c67a98..000000000000 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellContainer.module.css +++ /dev/null @@ -1,32 +0,0 @@ -.td-in-edit-mode { - z-index: 4 !important; -} - -.td-not-in-edit-mode { - z-index: 3; -} - -.td-is-selected { - background: var(--twentycrm-accent-quaternary); -} - -.td-is-not-selected { - background: var(--twentycrm-background-primary); -} - -.cell-base-container { - align-items: center; - box-sizing: border-box; - cursor: pointer; - display: flex; - height: 32px; - position: relative; - user-select: none; -} - -.cell-base-container-soft-focus { - background: var(--twentycrm-background-transparent-secondary); - border-radius: var(--twentycrm-border-radius-sm); - outline: 1px solid var(--twentycrm-font-color-extra-light); -} - diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellContainer.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellContainer.tsx index 6ff27ac7339b..0197e7e02697 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellContainer.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellContainer.tsx @@ -1,163 +1,41 @@ -import React, { ReactElement, useContext, useEffect, useState } from 'react'; -import { clsx } from 'clsx'; +import { ReactElement, useContext } from 'react'; -import { FieldContext } from '@/object-record/record-field/contexts/FieldContext'; -import { useFieldFocus } from '@/object-record/record-field/hooks/useFieldFocus'; -import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext'; -import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext'; +import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext'; +import { RecordTableCellBaseContainer } from '@/object-record/record-table/record-table-cell/components/RecordTableCellBaseContainer'; import { RecordTableCellSoftFocusMode } from '@/object-record/record-table/record-table-cell/components/RecordTableCellSoftFocusMode'; -import { useCurrentTableCellPosition } from '@/object-record/record-table/record-table-cell/hooks/useCurrentCellPosition'; -import { useOpenRecordTableCellFromCell } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellFromCell'; -import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope'; - -import { CellHotkeyScopeContext } from '../../contexts/CellHotkeyScopeContext'; -import { TableHotkeyScope } from '../../types/TableHotkeyScope'; import { RecordTableCellDisplayMode } from './RecordTableCellDisplayMode'; import { RecordTableCellEditMode } from './RecordTableCellEditMode'; -import styles from './RecordTableCellContainer.module.css'; - export type RecordTableCellContainerProps = { editModeContent: ReactElement; nonEditModeContent: ReactElement; - editHotkeyScope?: HotkeyScope; transparent?: boolean; maxContentWidth?: number; onSubmit?: () => void; onCancel?: () => void; }; -const DEFAULT_CELL_SCOPE: HotkeyScope = { - scope: TableHotkeyScope.CellEditMode, -}; - export const RecordTableCellContainer = ({ editModeContent, nonEditModeContent, - editHotkeyScope, }: RecordTableCellContainerProps) => { - const { setIsFocused } = useFieldFocus(); - const { openTableCell } = useOpenRecordTableCellFromCell(); - - const { isSelected, recordId, isPendingRow } = useContext( - RecordTableRowContext, - ); - const { isLabelIdentifier } = useContext(FieldContext); - const { onContextMenu, onCellMouseEnter } = useContext(RecordTableContext); - - const shouldBeInitiallyInEditMode = - isPendingRow === true && isLabelIdentifier; - - const [hasSoftFocus, setHasSoftFocus] = useState(false); - const [isInEditMode, setIsInEditMode] = useState(shouldBeInitiallyInEditMode); - - const cellPosition = useCurrentTableCellPosition(); - - const handleContextMenu = (event: React.MouseEvent) => { - onContextMenu(event, recordId); - }; - - const handleContainerMouseMove = () => { - if (!hasSoftFocus) { - onCellMouseEnter({ - cellPosition, - }); - } - }; - - const handleContainerMouseLeave = () => { - setHasSoftFocus(false); - setIsFocused(false); - }; - - const handleContainerClick = () => { - if (!hasSoftFocus) { - openTableCell(); - } - }; - - useEffect(() => { - const customEventListener = (event: any) => { - event.stopPropagation(); - - const newHasSoftFocus = event.detail; - - setHasSoftFocus(newHasSoftFocus); - setIsFocused(newHasSoftFocus); - }; - - document.addEventListener( - `soft-focus-move-${cellPosition.row}:${cellPosition.column}`, - customEventListener, - ); - - return () => { - document.removeEventListener( - `soft-focus-move-${cellPosition.row}:${cellPosition.column}`, - customEventListener, - ); - }; - }, [cellPosition, setIsFocused]); - - useEffect(() => { - const customEventListener = (event: any) => { - const newIsInEditMode = event.detail; - - setIsInEditMode(newIsInEditMode); - }; - - document.addEventListener( - `edit-mode-change-${cellPosition.row}:${cellPosition.column}`, - customEventListener, - ); - - return () => { - document.removeEventListener( - `edit-mode-change-${cellPosition.row}:${cellPosition.column}`, - customEventListener, - ); - }; - }, [cellPosition]); + const { hasSoftFocus, isInEditMode } = useContext(RecordTableCellContext); return ( - <td - className={clsx({ - [styles.tdInEditMode]: isInEditMode, - [styles.tdNotInEditMode]: !isInEditMode, - [styles.tdIsSelected]: isSelected, - [styles.tdIsNotSelected]: !isSelected, - })} - onContextMenu={handleContextMenu} - > - <CellHotkeyScopeContext.Provider - value={editHotkeyScope ?? DEFAULT_CELL_SCOPE} - > - <div - onMouseLeave={handleContainerMouseLeave} - onMouseMove={handleContainerMouseMove} - onClick={handleContainerClick} - className={clsx({ - [styles.cellBaseContainer]: true, - [styles.cellBaseContainerSoftFocus]: hasSoftFocus, - })} - > - {isInEditMode ? ( - <RecordTableCellEditMode>{editModeContent}</RecordTableCellEditMode> - ) : hasSoftFocus ? ( - <> - <RecordTableCellSoftFocusMode - editModeContent={editModeContent} - nonEditModeContent={nonEditModeContent} - /> - </> - ) : ( - <RecordTableCellDisplayMode> - {nonEditModeContent} - </RecordTableCellDisplayMode> - )} - </div> - </CellHotkeyScopeContext.Provider> - </td> + <RecordTableCellBaseContainer> + {isInEditMode ? ( + <RecordTableCellEditMode>{editModeContent}</RecordTableCellEditMode> + ) : hasSoftFocus ? ( + <RecordTableCellSoftFocusMode + editModeContent={editModeContent} + nonEditModeContent={nonEditModeContent} + /> + ) : ( + <RecordTableCellDisplayMode> + {nonEditModeContent} + </RecordTableCellDisplayMode> + )} + </RecordTableCellBaseContainer> ); }; diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellDisplayContainer.module.css b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellDisplayContainer.module.css deleted file mode 100644 index d2184fcda0ba..000000000000 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellDisplayContainer.module.css +++ /dev/null @@ -1,24 +0,0 @@ -.cell-display-outer-container { - align-items: center; - display: flex; - height: 100%; - overflow: hidden; - padding-left: 8px; - padding-right: 4px; - width: 100%; -} - -.cell-display-outer-container-soft-focus { - background: var(--twentycrm-background-transparent-secondary); - border-radius: var(--twentycrm-border-radius-sm); - outline: 1px solid var(--twentycrm-font-color-extra-light); -} - -.cell-display-inner-container { - align-items: center; - display: flex; - height: 100%; - overflow: hidden; - width: 100%; -} - diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellDisplayContainer.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellDisplayContainer.tsx index f2db2901da0e..20941b7c63a6 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellDisplayContainer.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellDisplayContainer.tsx @@ -1,7 +1,24 @@ import { Ref } from 'react'; -import clsx from 'clsx'; +import { styled } from '@linaria/react'; -import styles from './RecordTableCellDisplayContainer.module.css'; +const StyledOuterContainer = styled.div<{ + hasSoftFocus?: boolean; +}>` + align-items: center; + display: flex; + height: 100%; + overflow: hidden; + padding-left: 6px; + width: 100%; +`; + +const StyledInnerContainer = styled.div` + align-items: center; + display: flex; + height: 100%; + overflow: hidden; + width: 100%; +`; export type EditableCellDisplayContainerProps = { softFocus?: boolean; @@ -16,17 +33,14 @@ export const RecordTableCellDisplayContainer = ({ onClick, scrollRef, }: React.PropsWithChildren<EditableCellDisplayContainerProps>) => ( - <div + <StyledOuterContainer data-testid={ softFocus ? 'editable-cell-soft-focus-mode' : 'editable-cell-display-mode' } onClick={onClick} - className={clsx({ - [styles.cellDisplayOuterContainer]: true, - [styles.cellDisplayOuterContainerSoftFocus]: softFocus, - })} ref={scrollRef} + hasSoftFocus={softFocus} > - <div className={clsx(styles.cellDisplayInnerContainer)}>{children}</div> - </div> + <StyledInnerContainer>{children}</StyledInnerContainer> + </StyledOuterContainer> ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellDisplayMode.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellDisplayMode.tsx index 566be79baf32..f562348e7974 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellDisplayMode.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellDisplayMode.tsx @@ -4,7 +4,8 @@ import { RecordTableCellDisplayContainer } from './RecordTableCellDisplayContain export const RecordTableCellDisplayMode = ({ children, -}: React.PropsWithChildren<unknown>) => { + softFocus, +}: React.PropsWithChildren<{ softFocus?: boolean }>) => { const isEmpty = useIsFieldEmpty(); if (isEmpty) { @@ -12,7 +13,7 @@ export const RecordTableCellDisplayMode = ({ } return ( - <RecordTableCellDisplayContainer> + <RecordTableCellDisplayContainer softFocus={softFocus}> {children} </RecordTableCellDisplayContainer> ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellEditMode.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellEditMode.tsx index 99c52de425dc..16e59db8d559 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellEditMode.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellEditMode.tsx @@ -4,6 +4,7 @@ import styled from '@emotion/styled'; import { autoUpdate, flip, offset, useFloating } from '@floating-ui/react'; const StyledEditableCellEditModeContainer = styled.div<RecordTableCellEditModeProps>` + position: absolute; align-items: center; display: flex; min-width: 200px; diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableCellFieldContextWrapper.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellFieldContextWrapper.tsx similarity index 89% rename from packages/twenty-front/src/modules/object-record/record-table/components/RecordTableCellFieldContextWrapper.tsx rename to packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellFieldContextWrapper.tsx index ec30ebe03eba..16a571fcd5cc 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableCellFieldContextWrapper.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellFieldContextWrapper.tsx @@ -1,4 +1,4 @@ -import { useContext } from 'react'; +import { ReactNode, useContext } from 'react'; import { isLabelIdentifierField } from '@/object-metadata/utils/isLabelIdentifierField'; import { FieldContext } from '@/object-record/record-field/contexts/FieldContext'; @@ -8,13 +8,16 @@ import { RecordUpdateContext } from '@/object-record/record-table/contexts/Entit import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext'; import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext'; import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext'; -import { RecordTableCell } from '@/object-record/record-table/record-table-cell/components/RecordTableCell'; import { TableHotkeyScope } from '@/object-record/record-table/types/TableHotkeyScope'; import { RelationPickerHotkeyScope } from '@/object-record/relation-picker/types/RelationPickerHotkeyScope'; import { SelectFieldHotkeyScope } from '@/object-record/select/types/SelectFieldHotkeyScope'; import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull'; -export const RecordTableCellFieldContextWrapper = () => { +export const RecordTableCellFieldContextWrapper = ({ + children, +}: { + children: ReactNode; +}) => { const { objectMetadataItem } = useContext(RecordTableContext); const { columnDefinition } = useContext(RecordTableCellContext); const { recordId, pathToShowPage } = useContext(RecordTableRowContext); @@ -49,7 +52,7 @@ export const RecordTableCellFieldContextWrapper = () => { }), }} > - <RecordTableCell customHotkeyScope={{ scope: customHotkeyScope }} /> + {children} </FieldContext.Provider> ); }; diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellFieldInput.tsx new file mode 100644 index 000000000000..8b56f8d24b39 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellFieldInput.tsx @@ -0,0 +1,95 @@ +import { useContext } from 'react'; + +import { FieldInput } from '@/object-record/record-field/components/FieldInput'; +import { FieldContext } from '@/object-record/record-field/contexts/FieldContext'; +import { FieldInputEvent } from '@/object-record/record-field/types/FieldInputEvent'; +import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext'; +import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext'; + +export const RecordTableCellFieldInput = () => { + const { onUpsertRecord, onMoveFocus, onCloseTableCell } = + useContext(RecordTableContext); + const { entityId, fieldDefinition } = useContext(FieldContext); + const { isReadOnly } = useContext(RecordTableRowContext); + + const handleEnter: FieldInputEvent = (persistField) => { + onUpsertRecord({ + persistField, + entityId, + fieldName: fieldDefinition.metadata.fieldName, + }); + + onCloseTableCell(); + onMoveFocus('down'); + }; + + const handleSubmit: FieldInputEvent = (persistField) => { + onUpsertRecord({ + persistField, + entityId, + fieldName: fieldDefinition.metadata.fieldName, + }); + + onCloseTableCell(); + }; + + const handleCancel = () => { + onCloseTableCell(); + }; + + const handleClickOutside: FieldInputEvent = (persistField) => { + onUpsertRecord({ + persistField, + entityId, + fieldName: fieldDefinition.metadata.fieldName, + }); + + onCloseTableCell(); + }; + + const handleEscape: FieldInputEvent = (persistField) => { + onUpsertRecord({ + persistField, + entityId, + fieldName: fieldDefinition.metadata.fieldName, + }); + + onCloseTableCell(); + }; + + const handleTab: FieldInputEvent = (persistField) => { + onUpsertRecord({ + persistField, + entityId, + fieldName: fieldDefinition.metadata.fieldName, + }); + + onCloseTableCell(); + onMoveFocus('right'); + }; + + const handleShiftTab: FieldInputEvent = (persistField) => { + onUpsertRecord({ + persistField, + entityId, + fieldName: fieldDefinition.metadata.fieldName, + }); + + onCloseTableCell(); + onMoveFocus('left'); + }; + + return ( + <FieldInput + recordFieldInputdId={`${entityId}-${fieldDefinition?.metadata?.fieldName}`} + onCancel={handleCancel} + onClickOutside={handleClickOutside} + onEnter={handleEnter} + onEscape={handleEscape} + onShiftTab={handleShiftTab} + onSubmit={handleSubmit} + onTab={handleTab} + isReadOnly={isReadOnly} + /> + ); +}; diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellGrip.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellGrip.tsx new file mode 100644 index 000000000000..563646604447 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellGrip.tsx @@ -0,0 +1,44 @@ +import styled from '@emotion/styled'; +import { useContext } from 'react'; + +import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext'; +import { RecordTableTd } from '@/object-record/record-table/record-table-cell/components/RecordTableTd'; +import { IconListViewGrip } from '@/ui/input/components/IconListViewGrip'; + +const StyledContainer = styled.div` + cursor: grab; + width: 16px; + height: 32px; + z-index: 200; + display: flex; + &:hover .icon { + opacity: 1; + } + + border-color: transparent; +`; + +const StyledIconWrapper = styled.div<{ isDragging: boolean }>` + opacity: ${({ isDragging }) => (isDragging ? 1 : 0)}; + transition: opacity 0.1s; +`; + +export const RecordTableCellGrip = () => { + const { dragHandleProps, isDragging } = useContext(RecordTableRowContext); + + return ( + <RecordTableTd + // eslint-disable-next-line react/jsx-props-no-spreading + {...dragHandleProps} + data-select-disable + hasRightBorder={false} + hasBottomBorder={false} + > + <StyledContainer> + <StyledIconWrapper className="icon" isDragging={isDragging}> + <IconListViewGrip /> + </StyledIconWrapper> + </StyledContainer> + </RecordTableTd> + ); +}; diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellLoading.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellLoading.tsx new file mode 100644 index 000000000000..a8ca441b60e7 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellLoading.tsx @@ -0,0 +1,10 @@ +import { RecordTableCellSkeletonLoader } from '@/object-record/record-table/record-table-cell/components/RecordTableCellSkeletonLoader'; +import { RecordTableTd } from '@/object-record/record-table/record-table-cell/components/RecordTableTd'; + +export const RecordTableCellLoading = () => { + return ( + <RecordTableTd> + <RecordTableCellSkeletonLoader /> + </RecordTableTd> + ); +}; diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellSkeletonLoader.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellSkeletonLoader.tsx new file mode 100644 index 000000000000..b010bdaecd6d --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellSkeletonLoader.tsx @@ -0,0 +1,29 @@ +import Skeleton, { SkeletonTheme } from 'react-loading-skeleton'; +import { useTheme } from '@emotion/react'; +import styled from '@emotion/styled'; + +const StyledSkeletonContainer = styled.div` + padding-left: ${({ theme }) => theme.spacing(2)}; + padding-right: ${({ theme }) => theme.spacing(1)}; +`; + +const StyledRecordTableCellLoader = ({ width }: { width?: number }) => { + const theme = useTheme(); + return ( + <SkeletonTheme + baseColor={theme.background.tertiary} + highlightColor={theme.background.transparent.lighter} + borderRadius={4} + > + <Skeleton width={width} height={16} /> + </SkeletonTheme> + ); +}; + +export const RecordTableCellSkeletonLoader = () => { + return ( + <StyledSkeletonContainer> + <StyledRecordTableCellLoader /> + </StyledSkeletonContainer> + ); +}; diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellSoftFocusMode.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellSoftFocusMode.tsx index e7f3a03599e3..4a2ebb10c88e 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellSoftFocusMode.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellSoftFocusMode.tsx @@ -13,7 +13,6 @@ import { RecordTableCellContext } from '@/object-record/record-table/contexts/Re import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext'; import { useCloseCurrentTableCellInEditMode } from '@/object-record/record-table/hooks/internal/useCloseCurrentTableCellInEditMode'; import { RecordTableCellButton } from '@/object-record/record-table/record-table-cell/components/RecordTableCellButton'; -import { useCurrentTableCellPosition } from '@/object-record/record-table/record-table-cell/hooks/useCurrentCellPosition'; import { useOpenRecordTableCellFromCell } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellFromCell'; import { isSoftFocusUsingMouseState } from '@/object-record/record-table/states/isSoftFocusUsingMouseState'; import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys'; @@ -130,15 +129,10 @@ export const RecordTableCellSoftFocusMode = ({ */ }; - const { column, row } = useCurrentTableCellPosition(); - useListenClickOutside({ refs: [scrollRef], callback: () => { closeCurrentTableCell(); - document.dispatchEvent( - new CustomEvent(`soft-focus-move-${row}:${column}`, { detail: false }), - ); }, }); @@ -159,6 +153,7 @@ export const RecordTableCellSoftFocusMode = ({ <RecordTableCellDisplayContainer onClick={handleClick} scrollRef={scrollRef} + softFocus > {editModeContentOnly ? editModeContent : nonEditModeContent} </RecordTableCellDisplayContainer> diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellWrapper.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellWrapper.tsx new file mode 100644 index 000000000000..c552fa47beb6 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellWrapper.tsx @@ -0,0 +1,75 @@ +import { useContext, useMemo } from 'react'; +import { useRecoilValue } from 'recoil'; + +import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata'; +import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext'; +import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext'; +import { RecordTableCellFieldContextWrapper } from '@/object-record/record-table/record-table-cell/components/RecordTableCellFieldContextWrapper'; +import { RecordTableScopeInternalContext } from '@/object-record/record-table/scopes/scope-internal-context/RecordTableScopeInternalContext'; +import { isSoftFocusOnTableCellComponentFamilyState } from '@/object-record/record-table/states/isSoftFocusOnTableCellComponentFamilyState'; +import { isTableCellInEditModeComponentFamilyState } from '@/object-record/record-table/states/isTableCellInEditModeComponentFamilyState'; +import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition'; +import { TableCellPosition } from '@/object-record/record-table/types/TableCellPosition'; +import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId'; +import { getScopeIdOrUndefinedFromComponentId } from '@/ui/utilities/recoil-scope/utils/getScopeIdOrUndefinedFromComponentId'; +import { extractComponentFamilyState } from '@/ui/utilities/state/component-state/utils/extractComponentFamilyState'; + +export const RecordTableCellWrapper = ({ + children, + column, + columnIndex, +}: { + column: ColumnDefinition<FieldMetadata>; + columnIndex: number; + children: React.ReactNode; +}) => { + const tableScopeId = useAvailableScopeIdOrThrow( + RecordTableScopeInternalContext, + getScopeIdOrUndefinedFromComponentId(), + ); + + const { rowIndex } = useContext(RecordTableRowContext); + + const currentTableCellPosition: TableCellPosition = useMemo( + () => ({ + column: columnIndex, + row: rowIndex, + }), + [columnIndex, rowIndex], + ); + + const isTableCellInEditModeFamilyState = extractComponentFamilyState( + isTableCellInEditModeComponentFamilyState, + tableScopeId, + ); + + const isSoftFocusOnTableCellFamilyState = extractComponentFamilyState( + isSoftFocusOnTableCellComponentFamilyState, + tableScopeId, + ); + + const isInEditMode = useRecoilValue( + isTableCellInEditModeFamilyState(currentTableCellPosition), + ); + + const hasSoftFocus = useRecoilValue( + isSoftFocusOnTableCellFamilyState(currentTableCellPosition), + ); + + return ( + <RecordTableCellContext.Provider + value={{ + columnDefinition: column, + columnIndex, + isInEditMode, + hasSoftFocus, + cellPosition: currentTableCellPosition, + }} + key={column.fieldMetadataId} + > + <RecordTableCellFieldContextWrapper> + {children} + </RecordTableCellFieldContextWrapper> + </RecordTableCellContext.Provider> + ); +}; diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableLastEmptyCell.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableLastEmptyCell.tsx new file mode 100644 index 000000000000..c8f5bccdfed7 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableLastEmptyCell.tsx @@ -0,0 +1,10 @@ +import { useContext } from 'react'; + +import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext'; +import { RecordTableTd } from '@/object-record/record-table/record-table-cell/components/RecordTableTd'; + +export const RecordTableLastEmptyCell = () => { + const { isSelected } = useContext(RecordTableRowContext); + + return <RecordTableTd isSelected={isSelected} hasRightBorder={false} />; +}; diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableTd.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableTd.tsx new file mode 100644 index 000000000000..49f51197db11 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableTd.tsx @@ -0,0 +1,102 @@ +import { DraggableProvidedDragHandleProps } from '@hello-pangea/dnd'; +import { styled } from '@linaria/react'; +import { ReactNode, useContext } from 'react'; +import { MOBILE_VIEWPORT, ThemeContext } from 'twenty-ui'; + +import { isDefined } from '~/utils/isDefined'; + +const StyledTd = styled.td<{ + zIndex?: number; + backgroundColor: string; + borderColor: string; + isDragging?: boolean; + fontColor: string; + sticky?: boolean; + freezeFirstColumns?: boolean; + left?: number; + hasRightBorder?: boolean; + hasBottomBorder?: boolean; +}>` + border-bottom: 1px solid + ${({ borderColor, hasBottomBorder }) => + hasBottomBorder ? borderColor : 'transparent'}; + color: ${({ fontColor }) => fontColor}; + border-right: 1px solid + ${({ borderColor, hasRightBorder }) => + hasRightBorder ? borderColor : 'transparent'}; + + padding: 0; + + text-align: left; + + background: ${({ backgroundColor }) => backgroundColor}; + z-index: ${({ zIndex }) => (isDefined(zIndex) ? zIndex : 'auto')}; + + ${({ isDragging }) => + isDragging + ? ` + background-color: transparent; + border-color: transparent; + ` + : ''} + + ${({ freezeFirstColumns }) => + freezeFirstColumns + ? `@media (max-width: ${MOBILE_VIEWPORT}px) { + width: 35px; + max-width: 35px; + }` + : ''} +`; + +export const RecordTableTd = ({ + children, + zIndex, + isSelected, + isDragging, + sticky, + freezeFirstColumns, + left, + hasRightBorder = true, + hasBottomBorder = true, + ...dragHandleProps +}: { + className?: string; + children?: ReactNode; + zIndex?: number; + isSelected?: boolean; + isDragging?: boolean; + sticky?: boolean; + freezeFirstColumns?: boolean; + hasRightBorder?: boolean; + hasBottomBorder?: boolean; + left?: number; +} & (Partial<DraggableProvidedDragHandleProps> | null)) => { + const { theme } = useContext(ThemeContext); + + const tdBackgroundColor = isSelected + ? theme.accent.quaternary + : theme.background.primary; + + const borderColor = theme.border.color.light; + const fontColor = theme.font.color.primary; + + return ( + <StyledTd + isDragging={isDragging} + zIndex={zIndex} + backgroundColor={tdBackgroundColor} + borderColor={borderColor} + fontColor={fontColor} + sticky={sticky} + freezeFirstColumns={freezeFirstColumns} + left={left} + hasRightBorder={hasRightBorder} + hasBottomBorder={hasBottomBorder} + // eslint-disable-next-line react/jsx-props-no-spreading + {...dragHandleProps} + > + {children} + </StyledTd> + ); +}; diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/__mocks__/cell.ts b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/__mocks__/cell.ts index 792b33adc009..9aad45bc4e26 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/__mocks__/cell.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/__mocks__/cell.ts @@ -1,6 +1,5 @@ -import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata'; +import { RecordTableCellContextProps } from '@/object-record/record-table/contexts/RecordTableCellContext'; import { RecordTableRowContextProps } from '@/object-record/record-table/contexts/RecordTableRowContext'; -import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition'; import { FieldMetadataType } from '~/generated-metadata/graphql'; export const recordTableRow: RecordTableRowContextProps = { @@ -10,12 +9,13 @@ export const recordTableRow: RecordTableRowContextProps = { pathToShowPage: '/', objectNameSingular: 'objectNameSingular', isReadOnly: false, + dragHandleProps: {} as any, + isDragging: false, + inView: true, + isPendingRow: false, }; -export const recordTableCell: { - columnDefinition: ColumnDefinition<FieldMetadata>; - columnIndex: number; -} = { +export const recordTableCell:RecordTableCellContextProps= { columnIndex: 3, columnDefinition: { size: 1, @@ -29,4 +29,10 @@ export const recordTableCell: { fieldName: 'fieldName', }, }, + cellPosition: { + row: 2, + column: 3, + }, + hasSoftFocus: false, + isInEditMode: false, }; diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/__tests__/useUpsertRecord.test.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/__tests__/useUpsertRecord.test.tsx index 291c7407df60..2bf6ff27a658 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/__tests__/useUpsertRecord.test.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/__tests__/useUpsertRecord.test.tsx @@ -1,5 +1,5 @@ -import { ReactNode } from 'react'; import { act, renderHook } from '@testing-library/react'; +import { ReactNode } from 'react'; import { RecoilRoot } from 'recoil'; import { createState } from 'twenty-ui'; @@ -10,9 +10,10 @@ import { FieldContext } from '@/object-record/record-field/contexts/FieldContext import { useUpsertRecord } from '@/object-record/record-table/record-table-cell/hooks/useUpsertRecord'; import { TableHotkeyScope } from '@/object-record/record-table/types/TableHotkeyScope'; -const pendingRecordId = 'a7286b9a-c039-4a89-9567-2dfa7953cda9'; const draftValue = 'updated Name'; +// Todo refactor this test to inject the states in a cleaner way instead of mocking hooks +// (this is not easy to maintain while refactoring) jest.mock('@/object-record/hooks/useCreateOneRecord', () => ({ __esModule: true, useCreateOneRecord: jest.fn(), @@ -93,17 +94,25 @@ describe('useUpsertRecord', () => { }); it('calls update record if there is no pending record', async () => { - const { result } = renderHook(() => useUpsertRecord(), { - wrapper: ({ children }) => - Wrapper({ - pendingRecordIdMockedValue: null, - draftValueMockedValue: null, - children, - }), - }); + const { result } = renderHook( + () => useUpsertRecord({ objectNameSingular: 'person' }), + { + wrapper: ({ children }) => + Wrapper({ + pendingRecordIdMockedValue: null, + draftValueMockedValue: null, + children, + }), + }, + ); await act(async () => { - await result.current.upsertRecord(updateOneRecordMock); + await result.current.upsertRecord( + updateOneRecordMock, + 'entityId', + 'name', + 'recordTableId', + ); }); expect(createOneRecordMock).not.toHaveBeenCalled(); @@ -111,42 +120,28 @@ describe('useUpsertRecord', () => { }); it('calls update record if pending record is empty', async () => { - const { result } = renderHook(() => useUpsertRecord(), { - wrapper: ({ children }) => - Wrapper({ - pendingRecordIdMockedValue: null, - draftValueMockedValue: draftValue, - children, - }), - }); + const { result } = renderHook( + () => useUpsertRecord({ objectNameSingular: 'person' }), + { + wrapper: ({ children }) => + Wrapper({ + pendingRecordIdMockedValue: null, + draftValueMockedValue: draftValue, + children, + }), + }, + ); await act(async () => { - await result.current.upsertRecord(updateOneRecordMock); + await result.current.upsertRecord( + updateOneRecordMock, + 'entityId', + 'name', + 'recordTableId', + ); }); expect(createOneRecordMock).not.toHaveBeenCalled(); expect(updateOneRecordMock).toHaveBeenCalled(); }); - - it('calls create record if pending record is not empty', async () => { - const { result } = renderHook(() => useUpsertRecord(), { - wrapper: ({ children }) => - Wrapper({ - pendingRecordIdMockedValue: pendingRecordId, - draftValueMockedValue: draftValue, - children, - }), - }); - - await act(async () => { - await result.current.upsertRecord(updateOneRecordMock); - }); - - expect(createOneRecordMock).toHaveBeenCalledWith({ - id: pendingRecordId, - name: draftValue, - position: 'first', - }); - expect(updateOneRecordMock).not.toHaveBeenCalled(); - }); }); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useCurrentCellPosition.ts b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useCurrentCellPosition.ts index d3384909cf9d..383a81de4050 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useCurrentCellPosition.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useCurrentCellPosition.ts @@ -1,21 +1,9 @@ -import { useContext, useMemo } from 'react'; +import { useContext } from 'react'; import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext'; -import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext'; - -import { TableCellPosition } from '../../types/TableCellPosition'; export const useCurrentTableCellPosition = () => { - const { rowIndex } = useContext(RecordTableRowContext); - const { columnIndex } = useContext(RecordTableCellContext); - - const currentTableCellPosition: TableCellPosition = useMemo( - () => ({ - column: columnIndex, - row: rowIndex, - }), - [columnIndex, rowIndex], - ); + const { cellPosition } = useContext(RecordTableCellContext); - return currentTableCellPosition; + return cellPosition; }; diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2.ts b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2.ts index b9e279b0b77a..2a379840276f 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2.ts @@ -1,4 +1,3 @@ -import { useNavigate } from 'react-router-dom'; import { useRecoilCallback, useSetRecoilState } from 'recoil'; import { useInitDraftValueV2 } from '@/object-record/record-field/hooks/useInitDraftValueV2'; @@ -21,6 +20,8 @@ import { useClickOutsideListener } from '@/ui/utilities/pointer-event/hooks/useC import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; import { isDefined } from '~/utils/isDefined'; +import { RecordIndexEventContext } from '@/object-record/record-index/contexts/RecordIndexEventContext'; +import { useContext } from 'react'; import { TableHotkeyScope } from '../../types/TableHotkeyScope'; export const DEFAULT_CELL_SCOPE: HotkeyScope = { @@ -40,13 +41,13 @@ export type OpenTableCellArgs = { }; export const useOpenRecordTableCellV2 = (tableScopeId: string) => { + const { onIndexIdentifierClick } = useContext(RecordIndexEventContext); const moveEditModeToTableCellPosition = useMoveEditModeToTableCellPosition(tableScopeId); const setHotkeyScope = useSetHotkeyScope(); const { setDragSelectionStartEnabled } = useDragSelect(); - const navigate = useNavigate(); const leaveTableFocus = useLeaveTableFocus(tableScopeId); const { toggleClickOutsideListener } = useClickOutsideListener( SOFT_FOCUS_CLICK_OUTSIDE_LISTENER_ID, @@ -66,7 +67,6 @@ export const useOpenRecordTableCellV2 = (tableScopeId: string) => { initialValue, cellPosition, isReadOnly, - pathToShowPage, objectNameSingular, customCellHotkeyScope, fieldDefinition, @@ -94,7 +94,8 @@ export const useOpenRecordTableCellV2 = (tableScopeId: string) => { if (isFirstColumnCell && !isEmpty && !isActionButtonClick) { leaveTableFocus(); - navigate(pathToShowPage); + + onIndexIdentifierClick(entityId); return; } @@ -142,7 +143,7 @@ export const useOpenRecordTableCellV2 = (tableScopeId: string) => { openRightDrawer, setViewableRecordId, setViewableRecordNameSingular, - navigate, + onIndexIdentifierClick, ], ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useUpsertRecord.ts b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useUpsertRecord.ts index 230e4a5d321a..553c6aa835e0 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useUpsertRecord.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useUpsertRecord.ts @@ -1,41 +1,65 @@ -import { useContext } from 'react'; -import { useRecoilValue } from 'recoil'; +import { useRecoilCallback } from 'recoil'; import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord'; -import { FieldContext } from '@/object-record/record-field/contexts/FieldContext'; -import { useRecordFieldInputStates } from '@/object-record/record-field/hooks/internal/useRecordFieldInputStates'; -import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates'; +import { recordFieldInputDraftValueComponentSelector } from '@/object-record/record-field/states/selectors/recordFieldInputDraftValueComponentSelector'; +import { recordTablePendingRecordIdComponentState } from '@/object-record/record-table/states/recordTablePendingRecordIdComponentState'; +import { getScopeIdFromComponentId } from '@/ui/utilities/recoil-scope/utils/getScopeIdFromComponentId'; +import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue'; +import { extractComponentSelector } from '@/ui/utilities/state/component-state/utils/extractComponentSelector'; +import { extractComponentState } from '@/ui/utilities/state/component-state/utils/extractComponentState'; import { isDefined } from '~/utils/isDefined'; -export const useUpsertRecord = () => { - const { entityId, fieldDefinition } = useContext(FieldContext); - - const { pendingRecordIdState } = useRecordTableStates(); - - const pendingRecordId = useRecoilValue(pendingRecordIdState); - const fieldName = fieldDefinition.metadata.fieldName; - const { getDraftValueSelector } = useRecordFieldInputStates( - `${entityId}-${fieldName}`, - ); - const draftValue = useRecoilValue(getDraftValueSelector()); - - const objectNameSingular = - fieldDefinition.metadata.objectMetadataNameSingular ?? ''; +export const useUpsertRecord = ({ + objectNameSingular, +}: { + objectNameSingular: string; +}) => { const { createOneRecord } = useCreateOneRecord({ objectNameSingular, }); - const upsertRecord = (persistField: () => void) => { - if (isDefined(pendingRecordId) && isDefined(draftValue)) { - createOneRecord({ - id: pendingRecordId, - name: draftValue, - position: 'first', - }); - } else if (!pendingRecordId) { - persistField(); - } - }; + const upsertRecord = useRecoilCallback( + ({ snapshot }) => + ( + persistField: () => void, + entityId: string, + fieldName: string, + recordTableId: string, + ) => { + const tableScopeId = getScopeIdFromComponentId(recordTableId); + + const recordTablePendingRecordIdState = extractComponentState( + recordTablePendingRecordIdComponentState, + tableScopeId, + ); + + const recordTablePendingRecordId = getSnapshotValue( + snapshot, + recordTablePendingRecordIdState, + ); + const fieldScopeId = getScopeIdFromComponentId( + `${entityId}-${fieldName}`, + ); + + const draftValueSelector = extractComponentSelector( + recordFieldInputDraftValueComponentSelector, + fieldScopeId, + ); + + const draftValue = getSnapshotValue(snapshot, draftValueSelector()); + + if (isDefined(recordTablePendingRecordId) && isDefined(draftValue)) { + createOneRecord({ + id: recordTablePendingRecordId, + name: draftValue, + position: 'first', + }); + } else if (!recordTablePendingRecordId) { + persistField(); + } + }, + [createOneRecord], + ); return { upsertRecord }; }; diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useUpsertRecordV2.ts b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useUpsertRecordV2.ts deleted file mode 100644 index c0b714ab2cc4..000000000000 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useUpsertRecordV2.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { useRecoilCallback } from 'recoil'; - -import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord'; -import { recordFieldInputDraftValueComponentSelector } from '@/object-record/record-field/states/selectors/recordFieldInputDraftValueComponentSelector'; -import { recordTablePendingRecordIdComponentState } from '@/object-record/record-table/states/recordTablePendingRecordIdComponentState'; -import { getScopeIdFromComponentId } from '@/ui/utilities/recoil-scope/utils/getScopeIdFromComponentId'; -import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue'; -import { extractComponentSelector } from '@/ui/utilities/state/component-state/utils/extractComponentSelector'; -import { extractComponentState } from '@/ui/utilities/state/component-state/utils/extractComponentState'; -import { isDefined } from '~/utils/isDefined'; - -export const useUpsertRecordV2 = ({ - objectNameSingular, -}: { - objectNameSingular: string; -}) => { - const { createOneRecord } = useCreateOneRecord({ - objectNameSingular, - }); - - const upsertRecord = useRecoilCallback( - ({ snapshot }) => - ( - persistField: () => void, - entityId: string, - fieldName: string, - recordTableId: string, - ) => { - const tableScopeId = getScopeIdFromComponentId(recordTableId); - - const recordTablePendingRecordIdState = extractComponentState( - recordTablePendingRecordIdComponentState, - tableScopeId, - ); - - const recordTablePendingRecordId = getSnapshotValue( - snapshot, - recordTablePendingRecordIdState, - ); - const fieldScopeId = getScopeIdFromComponentId( - `${entityId}-${fieldName}`, - ); - - const draftValueSelector = extractComponentSelector( - recordFieldInputDraftValueComponentSelector, - fieldScopeId, - ); - - const draftValue = getSnapshotValue(snapshot, draftValueSelector()); - - if (isDefined(recordTablePendingRecordId) && isDefined(draftValue)) { - createOneRecord({ - id: recordTablePendingRecordId, - name: draftValue, - position: 'first', - }); - } else if (!recordTablePendingRecordId) { - persistField(); - } - }, - [createOneRecord], - ); - - return { upsertRecord }; -}; diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/ColumnHead.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableColumnHead.tsx similarity index 67% rename from packages/twenty-front/src/modules/object-record/record-table/components/ColumnHead.tsx rename to packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableColumnHead.tsx index 89caf5a48fc3..7a5c9f3cd6f7 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/ColumnHead.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableColumnHead.tsx @@ -1,14 +1,14 @@ import { css, useTheme } from '@emotion/react'; import styled from '@emotion/styled'; -import { useRecoilValue } from 'recoil'; import { MOBILE_VIEWPORT, useIcons } from 'twenty-ui'; import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata'; -import { scrollLeftState } from '@/ui/utilities/scroll/states/scrollLeftState'; +import { isRecordTableScrolledLeftComponentState } from '@/object-record/record-table/states/isRecordTableScrolledLeftComponentState'; +import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { ColumnDefinition } from '../types/ColumnDefinition'; +import { ColumnDefinition } from '../../types/ColumnDefinition'; -type ColumnHeadProps = { +type RecordTableColumnHeadProps = { column: ColumnDefinition<FieldMetadata>; }; @@ -46,16 +46,22 @@ const StyledText = styled.span` white-space: nowrap; `; -export const ColumnHead = ({ column }: ColumnHeadProps) => { +export const RecordTableColumnHead = ({ + column, +}: RecordTableColumnHeadProps) => { const theme = useTheme(); const { getIcon } = useIcons(); const Icon = getIcon(column.iconName); - const scrollLeft = useRecoilValue(scrollLeftState); + const isRecordTableScrolledLeft = useRecoilComponentValue( + isRecordTableScrolledLeftComponentState, + ); return ( - <StyledTitle hideTitle={!!column.isLabelIdentifier && scrollLeft > 0}> + <StyledTitle + hideTitle={!!column.isLabelIdentifier && !isRecordTableScrolledLeft} + > <StyledIcon> <Icon size={theme.icon.size.md} /> </StyledIcon> diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableColumnDropdownMenu.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableColumnHeadDropdownMenu.tsx similarity index 82% rename from packages/twenty-front/src/modules/object-record/record-table/components/RecordTableColumnDropdownMenu.tsx rename to packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableColumnHeadDropdownMenu.tsx index 96a257041fe1..6065e45a1198 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableColumnDropdownMenu.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableColumnHeadDropdownMenu.tsx @@ -14,16 +14,16 @@ import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownM import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown'; import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem'; -import { useTableColumns } from '../hooks/useTableColumns'; -import { ColumnDefinition } from '../types/ColumnDefinition'; +import { useTableColumns } from '../../hooks/useTableColumns'; +import { ColumnDefinition } from '../../types/ColumnDefinition'; -export type RecordTableColumnDropdownMenuProps = { +export type RecordTableColumnHeadDropdownMenuProps = { column: ColumnDefinition<FieldMetadata>; }; -export const RecordTableColumnDropdownMenu = ({ +export const RecordTableColumnHeadDropdownMenu = ({ column, -}: RecordTableColumnDropdownMenuProps) => { +}: RecordTableColumnHeadDropdownMenuProps) => { const { visibleTableColumnsSelector, onToggleColumnFilterState, @@ -33,12 +33,13 @@ export const RecordTableColumnDropdownMenu = ({ const visibleTableColumns = useRecoilValue(visibleTableColumnsSelector()); const secondVisibleColumn = visibleTableColumns[1]; + const canMove = column.isLabelIdentifier !== true; const canMoveLeft = - column.fieldMetadataId !== secondVisibleColumn?.fieldMetadataId; + column.fieldMetadataId !== secondVisibleColumn?.fieldMetadataId && canMove; const lastVisibleColumn = visibleTableColumns[visibleTableColumns.length - 1]; const canMoveRight = - column.fieldMetadataId !== lastVisibleColumn?.fieldMetadataId; + column.fieldMetadataId !== lastVisibleColumn?.fieldMetadataId && canMove; const { handleColumnVisibilityChange, handleMoveTableColumn } = useTableColumns(); @@ -83,7 +84,9 @@ export const RecordTableColumnDropdownMenu = ({ const isSortable = column.isSortable === true; const isFilterable = column.isFilterable === true; - const showSeparator = isFilterable || isSortable; + const showSeparator = + (isFilterable || isSortable) && column.isLabelIdentifier !== true; + const canHide = column.isLabelIdentifier !== true; return ( <DropdownMenuItemsContainer> @@ -116,11 +119,13 @@ export const RecordTableColumnDropdownMenu = ({ text="Move right" /> )} - <MenuItem - LeftIcon={IconEyeOff} - onClick={handleColumnVisibility} - text="Hide" - /> + {canHide && ( + <MenuItem + LeftIcon={IconEyeOff} + onClick={handleColumnVisibility} + text="Hide" + /> + )} </DropdownMenuItemsContainer> ); }; diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/ColumnHeadWithDropdown.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableColumnHeadWithDropdown.tsx similarity index 55% rename from packages/twenty-front/src/modules/object-record/record-table/components/ColumnHeadWithDropdown.tsx rename to packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableColumnHeadWithDropdown.tsx index 475fb4beba60..6298c77f1dac 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/ColumnHeadWithDropdown.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableColumnHeadWithDropdown.tsx @@ -4,27 +4,31 @@ import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata' import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition'; import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; -import { ColumnHead } from './ColumnHead'; -import { RecordTableColumnDropdownMenu } from './RecordTableColumnDropdownMenu'; +import { RecordTableColumnHeadDropdownMenu } from './RecordTableColumnHeadDropdownMenu'; -type ColumnHeadWithDropdownProps = { +import { RecordTableColumnHead } from './RecordTableColumnHead'; + +type RecordTableColumnHeadWithDropdownProps = { column: ColumnDefinition<FieldMetadata>; }; const StyledDropdown = styled(Dropdown)` display: flex; + flex: 1; + z-index: ${({ theme }) => theme.lastLayerZIndex}; `; -export const ColumnHeadWithDropdown = ({ +export const RecordTableColumnHeadWithDropdown = ({ column, -}: ColumnHeadWithDropdownProps) => { +}: RecordTableColumnHeadWithDropdownProps) => { return ( <StyledDropdown dropdownId={column.fieldMetadataId + '-header'} - clickableComponent={<ColumnHead column={column} />} - dropdownComponents={<RecordTableColumnDropdownMenu column={column} />} + clickableComponent={<RecordTableColumnHead column={column} />} + dropdownComponents={<RecordTableColumnHeadDropdownMenu column={column} />} dropdownOffset={{ x: -1 }} + usePortal dropdownPlacement="bottom-start" dropdownHotkeyScope={{ scope: column.fieldMetadataId + '-header' }} /> diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeader.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeader.tsx new file mode 100644 index 000000000000..34009d15421d --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeader.tsx @@ -0,0 +1,101 @@ +import styled from '@emotion/styled'; +import { useRecoilValue } from 'recoil'; +import { MOBILE_VIEWPORT } from 'twenty-ui'; + +import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates'; +import { RecordTableHeaderCell } from '@/object-record/record-table/record-table-header/components/RecordTableHeaderCell'; +import { RecordTableHeaderCheckboxColumn } from '@/object-record/record-table/record-table-header/components/RecordTableHeaderCheckboxColumn'; +import { RecordTableHeaderDragDropColumn } from '@/object-record/record-table/record-table-header/components/RecordTableHeaderDragDropColumn'; +import { RecordTableHeaderLastColumn } from '@/object-record/record-table/record-table-header/components/RecordTableHeaderLastColumn'; + +const StyledTableHead = styled.thead<{ + isScrolledTop?: boolean; + isScrolledLeft?: boolean; +}>` + cursor: pointer; + + th:nth-of-type(1) { + width: 9px; + left: 0; + border-right-color: ${({ theme }) => theme.background.primary}; + } + + th:nth-of-type(2) { + border-right-color: ${({ theme }) => theme.background.primary}; + } + + &.first-columns-sticky { + th:nth-of-type(1) { + position: sticky; + left: 0; + z-index: 5; + } + th:nth-of-type(2) { + position: sticky; + left: 9px; + z-index: 5; + } + th:nth-of-type(3) { + position: sticky; + left: 39px; + z-index: 5; + &::after { + content: ''; + position: absolute; + top: -1px; + height: calc(100% + 2px); + width: 4px; + right: 0px; + box-shadow: ${({ theme }) => theme.boxShadow.light}; + clip-path: inset(0px -4px 0px 0px); + } + @media (max-width: ${MOBILE_VIEWPORT}px) { + width: 35px; + max-width: 35px; + } + } + } + + &.header-sticky { + th { + position: sticky; + top: 0; + z-index: 5; + } + } + + &.header-sticky.first-columns-sticky { + th:nth-of-type(1), + th:nth-of-type(2), + th:nth-of-type(3) { + z-index: 10; + } + } +`; + +export const RecordTableHeader = ({ + createRecord, +}: { + createRecord: () => void; +}) => { + const { visibleTableColumnsSelector } = useRecordTableStates(); + + const visibleTableColumns = useRecoilValue(visibleTableColumnsSelector()); + + return ( + <StyledTableHead id="record-table-header" data-select-disable> + <tr> + <RecordTableHeaderDragDropColumn /> + <RecordTableHeaderCheckboxColumn /> + {visibleTableColumns.map((column) => ( + <RecordTableHeaderCell + key={column.fieldMetadataId} + column={column} + createRecord={createRecord} + /> + ))} + <RecordTableHeaderLastColumn /> + </tr> + </StyledTableHead> + ); +}; diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableHeaderCell.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderCell.tsx similarity index 83% rename from packages/twenty-front/src/modules/object-record/record-table/components/RecordTableHeaderCell.tsx rename to packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderCell.tsx index 698939c85b8c..d243b2a29b6e 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableHeaderCell.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderCell.tsx @@ -1,28 +1,35 @@ -import { useCallback, useMemo, useState } from 'react'; import styled from '@emotion/styled'; +import { useCallback, useMemo, useState } from 'react'; import { useRecoilCallback, useRecoilState, useRecoilValue } from 'recoil'; import { IconPlus } from 'twenty-ui'; import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata'; -import { ColumnHead } from '@/object-record/record-table/components/ColumnHead'; import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates'; import { useTableColumns } from '@/object-record/record-table/hooks/useTableColumns'; +import { RecordTableColumnHeadWithDropdown } from '@/object-record/record-table/record-table-header/components/RecordTableColumnHeadWithDropdown'; +import { isRecordTableScrolledLeftComponentState } from '@/object-record/record-table/states/isRecordTableScrolledLeftComponentState'; import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition'; import { LightIconButton } from '@/ui/input/button/components/LightIconButton'; import { useTrackPointer } from '@/ui/utilities/pointer-event/hooks/useTrackPointer'; import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue'; import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; -import { scrollLeftState } from '@/ui/utilities/scroll/states/scrollLeftState'; +import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { mapArrayToObject } from '~/utils/array/mapArrayToObject'; -import { ColumnHeadWithDropdown } from './ColumnHeadWithDropdown'; - const COLUMN_MIN_WIDTH = 104; const StyledColumnHeaderCell = styled.th<{ columnWidth: number; isResizing?: boolean; }>` + border-bottom: 1px solid ${({ theme }) => theme.border.color.light}; + border-top: 1px solid ${({ theme }) => theme.border.color.light}; + color: ${({ theme }) => theme.font.color.tertiary}; + padding: 0; + text-align: left; + + background-color: ${({ theme }) => theme.background.primary}; + border-right: 1px solid ${({ theme }) => theme.border.color.light}; ${({ columnWidth }) => ` min-width: ${columnWidth}px; width: ${columnWidth}px; @@ -32,7 +39,10 @@ const StyledColumnHeaderCell = styled.th<{ ${({ theme }) => { return ` &:hover { - background: ${theme.background.quaternary}; + background: ${theme.background.secondary}; + }; + &:active { + background: ${theme.background.tertiary}; }; `; }}; @@ -163,11 +173,14 @@ export const RecordTableHeaderCell = ({ onMouseUp: handleResizeHandlerEnd, }); + const isRecordTableScrolledLeft = useRecoilComponentValue( + isRecordTableScrolledLeftComponentState, + ); + const isMobile = useIsMobile(); - const scrollLeft = useRecoilValue(scrollLeftState); const disableColumnResize = - column.isLabelIdentifier && isMobile && scrollLeft > 0; + column.isLabelIdentifier && isMobile && !isRecordTableScrolledLeft; return ( <StyledColumnHeaderCell @@ -183,11 +196,7 @@ export const RecordTableHeaderCell = ({ onMouseLeave={() => setIconVisibility(false)} > <StyledColumnHeadContainer> - {column.isLabelIdentifier ? ( - <ColumnHead column={column} /> - ) : ( - <ColumnHeadWithDropdown column={column} /> - )} + <RecordTableColumnHeadWithDropdown column={column} /> {(useIsMobile() || iconVisibility) && !!column.isLabelIdentifier && ( <StyledHeaderIcon> <LightIconButton diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/SelectAllCheckbox.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderCheckboxColumn.tsx similarity index 61% rename from packages/twenty-front/src/modules/object-record/record-table/components/SelectAllCheckbox.tsx rename to packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderCheckboxColumn.tsx index 870b49a19d3d..ef88ebee3021 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/SelectAllCheckbox.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderCheckboxColumn.tsx @@ -2,9 +2,9 @@ import styled from '@emotion/styled'; import { useRecoilValue } from 'recoil'; import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates'; +import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable'; import { Checkbox } from '@/ui/input/components/Checkbox'; - -import { useRecordTable } from '../hooks/useRecordTable'; +import { useTheme } from '@emotion/react'; const StyledContainer = styled.div` align-items: center; @@ -16,7 +16,7 @@ const StyledContainer = styled.div` background-color: ${({ theme }) => theme.background.primary}; `; -export const SelectAllCheckbox = () => { +export const RecordTableHeaderCheckboxColumn = () => { const { allRowsSelectedStatusSelector } = useRecordTableStates(); const allRowsSelectedStatus = useRecoilValue(allRowsSelectedStatusSelector()); @@ -36,13 +36,26 @@ export const SelectAllCheckbox = () => { } }; + const theme = useTheme(); + return ( - <StyledContainer> - <Checkbox - checked={checked} - onChange={onChange} - indeterminate={indeterminate} - /> - </StyledContainer> + <th + style={{ + borderBottom: `1px solid ${theme.border.color.light}`, + borderTop: `1px solid ${theme.border.color.light}`, + width: 30, + minWidth: 30, + maxWidth: 30, + borderRight: 'transparent', + }} + > + <StyledContainer> + <Checkbox + checked={checked} + onChange={onChange} + indeterminate={indeterminate} + /> + </StyledContainer> + </th> ); }; diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderDragDropColumn.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderDragDropColumn.tsx new file mode 100644 index 000000000000..3acf7afa9ad1 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderDragDropColumn.tsx @@ -0,0 +1,10 @@ +import { styled } from '@linaria/react'; + +const StyledTh = styled.th` + border-bottom: none; + border-top: none; +`; + +export const RecordTableHeaderDragDropColumn = () => { + return <StyledTh></StyledTh>; +}; diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderLastColumn.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderLastColumn.tsx new file mode 100644 index 000000000000..170ec63f74b9 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderLastColumn.tsx @@ -0,0 +1,89 @@ +import { Theme } from '@emotion/react'; +import styled from '@emotion/styled'; +import { useContext } from 'react'; +import { useRecoilValue } from 'recoil'; +import { IconPlus, ThemeContext } from 'twenty-ui'; + +import { HIDDEN_TABLE_COLUMN_DROPDOWN_ID } from '@/object-record/record-table/constants/HiddenTableColumnDropdownId'; +import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates'; +import { RecordTableHeaderPlusButtonContent } from '@/object-record/record-table/record-table-header/components/RecordTableHeaderPlusButtonContent'; +import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; +import { useScrollWrapperScopedRef } from '@/ui/utilities/scroll/hooks/useScrollWrapperScopedRef'; + +const StyledPlusIconHeaderCell = styled.th<{ + theme: Theme; + isTableWiderThanScreen: boolean; +}>` + ${({ theme }) => { + return ` + &:hover { + background: ${theme.background.transparent.light}; + }; + padding-left: ${theme.spacing(3)}; + `; + }}; + border-bottom: 1px solid ${({ theme }) => theme.border.color.light}; + border-top: 1px solid ${({ theme }) => theme.border.color.light}; + background-color: ${({ theme }) => theme.background.primary}; + border-left: none !important; + color: ${({ theme }) => theme.font.color.tertiary}; + min-width: 32px; + border-right: none !important; + + ${({ isTableWiderThanScreen, theme }) => + isTableWiderThanScreen + ? ` + width: 32px; + background-color: ${theme.background.primary}; + ` + : ''}; + z-index: 1; +`; + +const StyledPlusIconContainer = styled.div` + align-items: center; + display: flex; + height: 32px; + justify-content: center; + width: 32px; +`; + +const HIDDEN_TABLE_COLUMN_DROPDOWN_HOTKEY_SCOPE_ID = + 'hidden-table-columns-dropdown-hotkey-scope-id'; + +export const RecordTableHeaderLastColumn = () => { + const { theme } = useContext(ThemeContext); + + const scrollWrapper = useScrollWrapperScopedRef(); + + const isTableWiderThanScreen = + (scrollWrapper.current?.clientWidth ?? 0) < + (scrollWrapper.current?.scrollWidth ?? 0); + + const { hiddenTableColumnsSelector } = useRecordTableStates(); + + const hiddenTableColumns = useRecoilValue(hiddenTableColumnsSelector()); + + return ( + <StyledPlusIconHeaderCell + theme={theme} + isTableWiderThanScreen={isTableWiderThanScreen} + > + {hiddenTableColumns.length > 0 && ( + <Dropdown + dropdownId={HIDDEN_TABLE_COLUMN_DROPDOWN_ID} + clickableComponent={ + <StyledPlusIconContainer> + <IconPlus size={theme.icon.size.md} /> + </StyledPlusIconContainer> + } + dropdownComponents={<RecordTableHeaderPlusButtonContent />} + dropdownPlacement="bottom-start" + dropdownHotkeyScope={{ + scope: HIDDEN_TABLE_COLUMN_DROPDOWN_HOTKEY_SCOPE_ID, + }} + /> + )} + </StyledPlusIconHeaderCell> + ); +}; diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableHeaderPlusButtonContent.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderPlusButtonContent.tsx similarity index 94% rename from packages/twenty-front/src/modules/object-record/record-table/components/RecordTableHeaderPlusButtonContent.tsx rename to packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderPlusButtonContent.tsx index 2a19bc15f248..3fd2cc60e8b5 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableHeaderPlusButtonContent.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderPlusButtonContent.tsx @@ -4,6 +4,7 @@ import styled from '@emotion/styled'; import { useRecoilValue } from 'recoil'; import { IconSettings, useIcons } from 'twenty-ui'; +import { getObjectSlug } from '@/object-metadata/utils/getObjectSlug'; import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata'; import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext'; import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates'; @@ -57,7 +58,7 @@ export const RecordTableHeaderPlusButtonContent = () => { )} <DropdownMenuItemsContainer> <StyledMenuItemLink - to={`/settings/objects/${objectMetadataItem.namePlural}`} + to={`/settings/objects/${getObjectSlug(objectMetadataItem)}`} > <MenuItem LeftIcon={IconSettings} text="Customize fields" /> </StyledMenuItemLink> diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableCells.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableCells.tsx new file mode 100644 index 000000000000..25c557144d9f --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableCells.tsx @@ -0,0 +1,17 @@ +import { useContext } from 'react'; + +import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext'; +import { RecordTableCellsEmpty } from '@/object-record/record-table/record-table-row/components/RecordTableCellsEmpty'; +import { RecordTableCellsVisible } from '@/object-record/record-table/record-table-row/components/RecordTableCellsVisible'; + +export const RecordTableCells = () => { + const { inView, isDragging } = useContext(RecordTableRowContext); + + const areCellsVisible = inView || isDragging; + + return areCellsVisible ? ( + <RecordTableCellsVisible /> + ) : ( + <RecordTableCellsEmpty /> + ); +}; diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableCellsEmpty.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableCellsEmpty.tsx new file mode 100644 index 000000000000..2df7a27f4a5a --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableCellsEmpty.tsx @@ -0,0 +1,17 @@ +import { useContext } from 'react'; +import { useRecoilValue } from 'recoil'; + +import { RecordTableTd } from '@/object-record/record-table/record-table-cell/components/RecordTableTd'; +import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext'; +import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates'; + +export const RecordTableCellsEmpty = () => { + const { isSelected } = useContext(RecordTableRowContext); + const { visibleTableColumnsSelector } = useRecordTableStates(); + + const visibleTableColumns = useRecoilValue(visibleTableColumnsSelector()); + + return visibleTableColumns.map((column) => ( + <RecordTableTd isSelected={isSelected} key={column.fieldMetadataId} /> + )); +}; diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableCellsVisible.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableCellsVisible.tsx new file mode 100644 index 000000000000..e6b75b265074 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableCellsVisible.tsx @@ -0,0 +1,39 @@ +import { useContext } from 'react'; +import { useRecoilValue } from 'recoil'; + +import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext'; +import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates'; +import { RecordTableCell } from '@/object-record/record-table/record-table-cell/components/RecordTableCell'; +import { RecordTableCellWrapper } from '@/object-record/record-table/record-table-cell/components/RecordTableCellWrapper'; +import { RecordTableTd } from '@/object-record/record-table/record-table-cell/components/RecordTableTd'; + +export const RecordTableCellsVisible = () => { + const { isDragging } = useContext(RecordTableRowContext); + const { visibleTableColumnsSelector } = useRecordTableStates(); + + const visibleTableColumns = useRecoilValue(visibleTableColumnsSelector()); + + const tableColumnsAfterFirst = visibleTableColumns.slice(1); + + return ( + <> + <RecordTableCellWrapper column={visibleTableColumns[0]} columnIndex={0}> + <RecordTableTd> + <RecordTableCell /> + </RecordTableTd> + </RecordTableCellWrapper> + {!isDragging && + tableColumnsAfterFirst.map((column, columnIndex) => ( + <RecordTableCellWrapper + key={column.fieldMetadataId} + column={column} + columnIndex={columnIndex + 1} + > + <RecordTableTd> + <RecordTableCell /> + </RecordTableTd> + </RecordTableCellWrapper> + ))} + </> + ); +}; diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTablePendingRow.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTablePendingRow.tsx similarity index 76% rename from packages/twenty-front/src/modules/object-record/record-table/components/RecordTablePendingRow.tsx rename to packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTablePendingRow.tsx index cde96d52e1a3..addf2d747b8a 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTablePendingRow.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTablePendingRow.tsx @@ -1,13 +1,13 @@ import { useRecoilValue } from 'recoil'; -import { RecordTableRow } from '@/object-record/record-table/components/RecordTableRow'; import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates'; +import { RecordTableRow } from '@/object-record/record-table/record-table-row/components/RecordTableRow'; export const RecordTablePendingRow = () => { const { pendingRecordIdState } = useRecordTableStates(); const pendingRecordId = useRecoilValue(pendingRecordIdState); - if (!pendingRecordId) return; + if (!pendingRecordId) return <></>; return ( <RecordTableRow diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableRow.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableRow.tsx new file mode 100644 index 000000000000..382fdc230372 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableRow.tsx @@ -0,0 +1,32 @@ +import { RecordValueSetterEffect } from '@/object-record/record-store/components/RecordValueSetterEffect'; +import { RecordTableCellCheckbox } from '@/object-record/record-table/record-table-cell/components/RecordTableCellCheckbox'; +import { RecordTableCellGrip } from '@/object-record/record-table/record-table-cell/components/RecordTableCellGrip'; +import { RecordTableLastEmptyCell } from '@/object-record/record-table/record-table-cell/components/RecordTableLastEmptyCell'; +import { RecordTableCells } from '@/object-record/record-table/record-table-row/components/RecordTableCells'; +import { RecordTableRowWrapper } from '@/object-record/record-table/record-table-row/components/RecordTableRowWrapper'; + +type RecordTableRowProps = { + recordId: string; + rowIndex: number; + isPendingRow?: boolean; +}; + +export const RecordTableRow = ({ + recordId, + rowIndex, + isPendingRow, +}: RecordTableRowProps) => { + return ( + <RecordTableRowWrapper + recordId={recordId} + rowIndex={rowIndex} + isPendingRow={isPendingRow} + > + <RecordTableCellGrip /> + <RecordTableCellCheckbox /> + <RecordTableCells /> + <RecordTableLastEmptyCell /> + <RecordValueSetterEffect recordId={recordId} /> + </RecordTableRowWrapper> + ); +}; diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableRowWrapper.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableRowWrapper.tsx new file mode 100644 index 000000000000..193c852d9e88 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableRowWrapper.tsx @@ -0,0 +1,96 @@ +import { useTheme } from '@emotion/react'; +import { Draggable } from '@hello-pangea/dnd'; +import { ReactNode, useContext, useEffect } from 'react'; +import { useInView } from 'react-intersection-observer'; +import { useRecoilValue } from 'recoil'; + +import { getBasePathToShowPage } from '@/object-metadata/utils/getBasePathToShowPage'; +import { RecordIndexEventContext } from '@/object-record/record-index/contexts/RecordIndexEventContext'; +import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext'; +import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext'; +import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates'; +import { RecordTableTr } from '@/object-record/record-table/record-table-row/components/RecordTableTr'; +import { ScrollWrapperContext } from '@/ui/utilities/scroll/components/ScrollWrapper'; + +export const RecordTableRowWrapper = ({ + recordId, + rowIndex, + isPendingRow, + children, +}: { + recordId: string; + rowIndex: number; + isPendingRow?: boolean; + children: ReactNode; +}) => { + const { objectMetadataItem } = useContext(RecordTableContext); + const { onIndexRecordsLoaded } = useContext(RecordIndexEventContext); + + const theme = useTheme(); + + const { isRowSelectedFamilyState } = useRecordTableStates(); + const currentRowSelected = useRecoilValue(isRowSelectedFamilyState(recordId)); + + const scrollWrapperRef = useContext(ScrollWrapperContext); + + const { ref: elementRef, inView } = useInView({ + root: scrollWrapperRef.current?.querySelector( + '[data-overlayscrollbars-viewport="scrollbarHidden"]', + ), + rootMargin: '1000px', + }); + + // TODO: find a better way to emit this event + useEffect(() => { + if (inView) { + onIndexRecordsLoaded?.(); + } + }, [inView, onIndexRecordsLoaded]); + + return ( + <Draggable key={recordId} draggableId={recordId} index={rowIndex}> + {(draggableProvided, draggableSnapshot) => ( + <RecordTableTr + ref={(node) => { + elementRef(node); + draggableProvided.innerRef(node); + }} + // eslint-disable-next-line react/jsx-props-no-spreading + {...draggableProvided.draggableProps} + style={{ + ...draggableProvided.draggableProps.style, + background: draggableSnapshot.isDragging + ? theme.background.transparent.light + : 'none', + borderColor: draggableSnapshot.isDragging + ? `${theme.border.color.medium}` + : 'transparent', + }} + isDragging={draggableSnapshot.isDragging} + data-testid={`row-id-${recordId}`} + data-selectable-id={recordId} + > + <RecordTableRowContext.Provider + value={{ + recordId, + rowIndex, + pathToShowPage: + getBasePathToShowPage({ + objectNameSingular: objectMetadataItem.nameSingular, + }) + recordId, + objectNameSingular: objectMetadataItem.nameSingular, + isSelected: currentRowSelected, + isReadOnly: objectMetadataItem.isRemote ?? false, + isPendingRow, + isDragging: draggableSnapshot.isDragging, + dragHandleProps: draggableProvided.dragHandleProps, + inView, + }} + > + {children} + </RecordTableRowContext.Provider> + </RecordTableTr> + )} + </Draggable> + ); +}; diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableTr.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableTr.tsx new file mode 100644 index 000000000000..0ccfc98ac751 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableTr.tsx @@ -0,0 +1,11 @@ +import styled from '@emotion/styled'; + +const StyledTr = styled.tr<{ isDragging: boolean }>` + border: ${({ isDragging, theme }) => + isDragging + ? `1px solid ${theme.border.color.medium}` + : '1px solid transparent'}; + transition: border-left-color 0.2s ease-in-out; +`; + +export const RecordTableTr = StyledTr; diff --git a/packages/twenty-front/src/modules/object-record/record-table/states/isRecordTableScrolledLeftComponentState.ts b/packages/twenty-front/src/modules/object-record/record-table/states/isRecordTableScrolledLeftComponentState.ts new file mode 100644 index 000000000000..6f26d8a6082a --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-table/states/isRecordTableScrolledLeftComponentState.ts @@ -0,0 +1,9 @@ +import { RecordTableScopeInternalContext } from '@/object-record/record-table/scopes/scope-internal-context/RecordTableScopeInternalContext'; +import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2'; + +export const isRecordTableScrolledLeftComponentState = + createComponentStateV2<boolean>({ + key: 'isRecordTableScrolledLeftComponentState', + componentContext: RecordTableScopeInternalContext, + defaultValue: true, + }); diff --git a/packages/twenty-front/src/modules/object-record/record-table/states/isRecordTableScrolledTopComponentState.ts b/packages/twenty-front/src/modules/object-record/record-table/states/isRecordTableScrolledTopComponentState.ts new file mode 100644 index 000000000000..564c567a6062 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-table/states/isRecordTableScrolledTopComponentState.ts @@ -0,0 +1,9 @@ +import { RecordTableScopeInternalContext } from '@/object-record/record-table/scopes/scope-internal-context/RecordTableScopeInternalContext'; +import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2'; + +export const isRecordTableScrolledTopComponentState = + createComponentStateV2<boolean>({ + key: 'isRecordTableScrolledTopComponentState', + componentContext: RecordTableScopeInternalContext, + defaultValue: true, + }); diff --git a/packages/twenty-front/src/modules/object-record/record-table/states/selectors/allRowsSelectedStatusComponentSelector.ts b/packages/twenty-front/src/modules/object-record/record-table/states/selectors/allRowsSelectedStatusComponentSelector.ts index c0a42ea81015..6ce6b42ff6c7 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/states/selectors/allRowsSelectedStatusComponentSelector.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/states/selectors/allRowsSelectedStatusComponentSelector.ts @@ -1,5 +1,5 @@ -import { numberOfTableRowsComponentState } from '@/object-record/record-table/states/numberOfTableRowsComponentState'; import { selectedRowIdsComponentSelector } from '@/object-record/record-table/states/selectors/selectedRowIdsComponentSelector'; +import { tableRowIdsComponentState } from '@/object-record/record-table/states/tableRowIdsComponentState'; import { createComponentReadOnlySelector } from '@/ui/utilities/state/component-state/utils/createComponentReadOnlySelector'; import { AllRowsSelectedStatus } from '../../types/AllRowSelectedStatus'; @@ -10,7 +10,7 @@ export const allRowsSelectedStatusComponentSelector = get: ({ scopeId }) => ({ get }) => { - const numberOfRows = get(numberOfTableRowsComponentState({ scopeId })); + const tableRowIds = get(tableRowIdsComponentState({ scopeId })); const selectedRowIds = get( selectedRowIdsComponentSelector({ scopeId }), @@ -21,7 +21,7 @@ export const allRowsSelectedStatusComponentSelector = const allRowsSelectedStatus = numberOfSelectedRows === 0 ? 'none' - : numberOfRows === numberOfSelectedRows + : selectedRowIds.length === tableRowIds.length ? 'all' : 'some'; diff --git a/packages/twenty-front/src/modules/object-record/relation-picker/components/ActivityTargetInlineCellEditModeMultiRecordsEffect.tsx b/packages/twenty-front/src/modules/object-record/relation-picker/components/ActivityTargetInlineCellEditModeMultiRecordsEffect.tsx new file mode 100644 index 000000000000..440bab3c780d --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/relation-picker/components/ActivityTargetInlineCellEditModeMultiRecordsEffect.tsx @@ -0,0 +1,132 @@ +import { useEffect } from 'react'; +import { + useRecoilCallback, + useRecoilState, + useRecoilValue, + useSetRecoilState, +} from 'recoil'; + +import { useObjectRecordMultiSelectScopedStates } from '@/activities/hooks/useObjectRecordMultiSelectScopedStates'; +import { objectRecordMultiSelectComponentFamilyState } from '@/object-record/record-field/states/objectRecordMultiSelectComponentFamilyState'; +import { useRelationPickerScopedStates } from '@/object-record/relation-picker/hooks/internal/useRelationPickerScopedStates'; +import { + ObjectRecordForSelect, + SelectedObjectRecordId, + useMultiObjectSearch, +} from '@/object-record/relation-picker/hooks/useMultiObjectSearch'; +import { RelationPickerScopeInternalContext } from '@/object-record/relation-picker/scopes/scope-internal-context/RelationPickerScopeInternalContext'; +import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId'; +import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; + +export const ActivityTargetInlineCellEditModeMultiRecordsEffect = ({ + selectedObjectRecordIds, +}: { + selectedObjectRecordIds: SelectedObjectRecordId[]; +}) => { + const scopeId = useAvailableScopeIdOrThrow( + RelationPickerScopeInternalContext, + ); + const { + objectRecordsIdsMultiSelectState, + objectRecordMultiSelectCheckedRecordsIdsState, + recordMultiSelectIsLoadingState, + } = useObjectRecordMultiSelectScopedStates(scopeId); + const [objectRecordsIdsMultiSelect, setObjectRecordsIdsMultiSelect] = + useRecoilState(objectRecordsIdsMultiSelectState); + + const setRecordMultiSelectIsLoading = useSetRecoilState( + recordMultiSelectIsLoadingState, + ); + + const relationPickerScopedId = useAvailableScopeIdOrThrow( + RelationPickerScopeInternalContext, + ); + + const { relationPickerSearchFilterState } = useRelationPickerScopedStates({ + relationPickerScopedId, + }); + const relationPickerSearchFilter = useRecoilValue( + relationPickerSearchFilterState, + ); + const { filteredSelectedObjectRecords, loading, objectRecordsToSelect } = + useMultiObjectSearch({ + searchFilterValue: relationPickerSearchFilter, + selectedObjectRecordIds, + excludedObjectRecordIds: [], + limit: 10, + }); + + const [ + objectRecordMultiSelectCheckedRecordsIds, + setObjectRecordMultiSelectCheckedRecordsIds, + ] = useRecoilState(objectRecordMultiSelectCheckedRecordsIdsState); + + const updateRecords = useRecoilCallback( + ({ snapshot, set }) => + (newRecords: ObjectRecordForSelect[]) => { + for (const newRecord of newRecords) { + const currentRecord = snapshot + .getLoadable( + objectRecordMultiSelectComponentFamilyState({ + scopeId: scopeId, + familyKey: newRecord.record.id, + }), + ) + .getValue(); + + const newRecordWithSelected = { + ...newRecord, + selected: objectRecordMultiSelectCheckedRecordsIds.some( + (checkedRecordId) => checkedRecordId === newRecord.record.id, + ), + }; + + if ( + !isDeeplyEqual( + newRecordWithSelected.selected, + currentRecord?.selected, + ) + ) { + set( + objectRecordMultiSelectComponentFamilyState({ + scopeId: scopeId, + familyKey: newRecordWithSelected.record.id, + }), + newRecordWithSelected, + ); + } + } + }, + [objectRecordMultiSelectCheckedRecordsIds, scopeId], + ); + + useEffect(() => { + const allRecords = [ + ...(filteredSelectedObjectRecords ?? []), + ...(objectRecordsToSelect ?? []), + ]; + updateRecords(allRecords); + const allRecordsIds = allRecords.map((record) => record.record.id); + if (!isDeeplyEqual(allRecordsIds, objectRecordsIdsMultiSelect)) { + setObjectRecordsIdsMultiSelect(allRecordsIds); + } + }, [ + filteredSelectedObjectRecords, + objectRecordsIdsMultiSelect, + objectRecordsToSelect, + setObjectRecordsIdsMultiSelect, + updateRecords, + ]); + + useEffect(() => { + setObjectRecordMultiSelectCheckedRecordsIds( + selectedObjectRecordIds.map((rec) => rec.id), + ); + }, [selectedObjectRecordIds, setObjectRecordMultiSelectCheckedRecordsIds]); + + useEffect(() => { + setRecordMultiSelectIsLoading(loading); + }, [loading, setRecordMultiSelectIsLoading]); + + return <></>; +}; diff --git a/packages/twenty-front/src/modules/object-record/relation-picker/components/MultiRecordSelect.tsx b/packages/twenty-front/src/modules/object-record/relation-picker/components/MultiRecordSelect.tsx index 049176e6cb08..fe0f3453a2ea 100644 --- a/packages/twenty-front/src/modules/object-record/relation-picker/components/MultiRecordSelect.tsx +++ b/packages/twenty-front/src/modules/object-record/relation-picker/components/MultiRecordSelect.tsx @@ -1,12 +1,14 @@ -import { useEffect, useMemo, useRef, useState } from 'react'; +import { useCallback, useRef } from 'react'; import styled from '@emotion/styled'; -import { isNonEmptyString } from '@sniptt/guards'; +import { useRecoilValue, useSetRecoilState } from 'recoil'; import { useDebouncedCallback } from 'use-debounce'; +import { useObjectRecordMultiSelectScopedStates } from '@/activities/hooks/useObjectRecordMultiSelectScopedStates'; import { MultipleObjectRecordOnClickOutsideEffect } from '@/object-record/relation-picker/components/MultipleObjectRecordOnClickOutsideEffect'; import { MultipleObjectRecordSelectItem } from '@/object-record/relation-picker/components/MultipleObjectRecordSelectItem'; import { MULTI_OBJECT_RECORD_SELECT_SELECTABLE_LIST_ID } from '@/object-record/relation-picker/constants/MultiObjectRecordSelectSelectableListId'; -import { ObjectRecordForSelect } from '@/object-record/relation-picker/hooks/useMultiObjectSearch'; +import { useRelationPickerScopedStates } from '@/object-record/relation-picker/hooks/internal/useRelationPickerScopedStates'; +import { RelationPickerScopeInternalContext } from '@/object-record/relation-picker/scopes/scope-internal-context/RelationPickerScopeInternalContext'; import { RelationPickerHotkeyScope } from '@/object-record/relation-picker/types/RelationPickerHotkeyScope'; import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; @@ -15,7 +17,7 @@ import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownM import { SelectableItem } from '@/ui/layout/selectable-list/components/SelectableItem'; import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList'; import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem'; -import { isDefined } from '~/utils/isDefined'; +import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId'; export const StyledSelectableItem = styled(SelectableItem)` height: 100%; @@ -24,134 +26,80 @@ export const StyledSelectableItem = styled(SelectableItem)` export const MultiRecordSelect = ({ onChange, onSubmit, - selectedObjectRecords, - allRecords, - loading, - searchFilter, - setSearchFilter, }: { - onChange?: ( - changedRecordForSelect: ObjectRecordForSelect, - newSelectedValue: boolean, - ) => void; - onSubmit?: (objectRecordsForSelect: ObjectRecordForSelect[]) => void; - selectedObjectRecords: ObjectRecordForSelect[]; - allRecords: ObjectRecordForSelect[]; - loading: boolean; - searchFilter: string; - setSearchFilter: (searchFilter: string) => void; + onChange?: (changedRecordForSelectId: string) => void; + onSubmit?: () => void; }) => { const containerRef = useRef<HTMLDivElement>(null); - const [internalSelectedRecords, setInternalSelectedRecords] = useState< - ObjectRecordForSelect[] - >([]); - - useEffect(() => { - if (!loading) { - setInternalSelectedRecords(selectedObjectRecords); - } - }, [selectedObjectRecords, loading]); - - const debouncedSetSearchFilter = useDebouncedCallback(setSearchFilter, 100, { - leading: true, - }); - - const handleFilterChange = (event: React.ChangeEvent<HTMLInputElement>) => { - debouncedSetSearchFilter(event.currentTarget.value); - }; + const relationPickerScopedId = useAvailableScopeIdOrThrow( + RelationPickerScopeInternalContext, + ); - const handleSelectChange = ( - changedRecordForSelect: ObjectRecordForSelect, - newSelectedValue: boolean, - ) => { - const newSelectedRecords = newSelectedValue - ? [...internalSelectedRecords, changedRecordForSelect] - : internalSelectedRecords.filter( - (selectedRecord) => - selectedRecord.record.id !== changedRecordForSelect.record.id, - ); + const { objectRecordsIdsMultiSelectState, recordMultiSelectIsLoadingState } = + useObjectRecordMultiSelectScopedStates(relationPickerScopedId); - setInternalSelectedRecords(newSelectedRecords); + const recordMultiSelectIsLoading = useRecoilValue( + recordMultiSelectIsLoadingState, + ); + const objectRecordsIdsMultiSelect = useRecoilValue( + objectRecordsIdsMultiSelectState, + ); - onChange?.(changedRecordForSelect, newSelectedValue); - }; + const { relationPickerSearchFilterState } = useRelationPickerScopedStates({ + relationPickerScopedId, + }); - const entitiesInDropdown = useMemo( - () => - [...(allRecords ?? [])].filter((entity) => - isNonEmptyString(entity.recordIdentifier.id), - ), - [allRecords], + const setSearchFilter = useSetRecoilState(relationPickerSearchFilterState); + const relationPickerSearchFilter = useRecoilValue( + relationPickerSearchFilterState, ); + const debouncedSetSearchFilter = useDebouncedCallback(setSearchFilter, 100, { + leading: true, + }); - const selectableItemIds = entitiesInDropdown.map( - (entity) => entity.record.id, + const handleFilterChange = useCallback( + (event: React.ChangeEvent<HTMLInputElement>) => { + debouncedSetSearchFilter(event.currentTarget.value); + }, + [debouncedSetSearchFilter], ); - return ( <> <MultipleObjectRecordOnClickOutsideEffect containerRef={containerRef} onClickOutside={() => { - onSubmit?.(internalSelectedRecords); + onSubmit?.(); }} /> <DropdownMenu ref={containerRef} data-select-disable> <DropdownMenuSearchInput - value={searchFilter} + value={relationPickerSearchFilter} onChange={handleFilterChange} autoFocus /> <DropdownMenuSeparator /> <DropdownMenuItemsContainer hasMaxHeight> - {loading ? ( + {recordMultiSelectIsLoading ? ( <MenuItem text="Loading..." /> ) : ( <> <SelectableList selectableListId={MULTI_OBJECT_RECORD_SELECT_SELECTABLE_LIST_ID} - selectableItemIdArray={selectableItemIds} + selectableItemIdArray={objectRecordsIdsMultiSelect} hotkeyScope={RelationPickerHotkeyScope.RelationPicker} - onEnter={(recordId) => { - const recordIsSelected = internalSelectedRecords?.some( - (selectedRecord) => selectedRecord.record.id === recordId, - ); - - const correspondingRecordForSelect = entitiesInDropdown?.find( - (entity) => entity.record.id === recordId, - ); - - if (isDefined(correspondingRecordForSelect)) { - handleSelectChange( - correspondingRecordForSelect, - !recordIsSelected, - ); - } - }} > - {entitiesInDropdown?.map((objectRecordForSelect) => ( - <MultipleObjectRecordSelectItem - key={objectRecordForSelect.record.id} - objectRecordForSelect={objectRecordForSelect} - onSelectedChange={(newSelectedValue) => - handleSelectChange( - objectRecordForSelect, - newSelectedValue, - ) - } - selected={internalSelectedRecords?.some( - (selectedRecord) => { - return ( - selectedRecord.record.id === - objectRecordForSelect.record.id - ); - }, - )} - /> - ))} + {objectRecordsIdsMultiSelect?.map((recordId) => { + return ( + <MultipleObjectRecordSelectItem + key={recordId} + objectRecordId={recordId} + onChange={onChange} + /> + ); + })} </SelectableList> - {entitiesInDropdown?.length === 0 && ( + {objectRecordsIdsMultiSelect?.length === 0 && ( <MenuItem text="No result" /> )} </> diff --git a/packages/twenty-front/src/modules/object-record/relation-picker/components/MultipleObjectRecordSelect.tsx b/packages/twenty-front/src/modules/object-record/relation-picker/components/MultipleObjectRecordSelect.tsx deleted file mode 100644 index 659461a30d57..000000000000 --- a/packages/twenty-front/src/modules/object-record/relation-picker/components/MultipleObjectRecordSelect.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import { useMemo, useState } from 'react'; -import styled from '@emotion/styled'; - -import { MultiRecordSelect } from '@/object-record/relation-picker/components/MultiRecordSelect'; -import { - ObjectRecordForSelect, - SelectedObjectRecordId, - useMultiObjectSearch, -} from '@/object-record/relation-picker/hooks/useMultiObjectSearch'; -import { SelectableItem } from '@/ui/layout/selectable-list/components/SelectableItem'; - -export const StyledSelectableItem = styled(SelectableItem)` - height: 100%; - width: 100%; -`; -export const MultipleObjectRecordSelect = ({ - onChange, - onSubmit, - selectedObjectRecordIds, -}: { - onChange?: ( - changedRecordForSelect: ObjectRecordForSelect, - newSelectedValue: boolean, - ) => void; - onSubmit?: (objectRecordsForSelect: ObjectRecordForSelect[]) => void; - selectedObjectRecordIds: SelectedObjectRecordId[]; -}) => { - const [searchFilter, setSearchFilter] = useState<string>(''); - - const { - filteredSelectedObjectRecords, - loading, - objectRecordsToSelect, - selectedObjectRecords, - } = useMultiObjectSearch({ - searchFilterValue: searchFilter, - selectedObjectRecordIds, - excludedObjectRecordIds: [], - limit: 10, - }); - - const selectedObjectRecordsForSelect = useMemo( - () => - selectedObjectRecords.filter((selectedObjectRecord) => - selectedObjectRecordIds.some( - (selectedObjectRecordId) => - selectedObjectRecordId.id === - selectedObjectRecord.recordIdentifier.id, - ), - ), - [selectedObjectRecords, selectedObjectRecordIds], - ); - - return ( - <MultiRecordSelect - onChange={onChange} - onSubmit={onSubmit} - selectedObjectRecords={selectedObjectRecordsForSelect} - allRecords={[ - ...(filteredSelectedObjectRecords ?? []), - ...(objectRecordsToSelect ?? []), - ]} - loading={loading} - searchFilter={searchFilter} - setSearchFilter={setSearchFilter} - /> - ); -}; diff --git a/packages/twenty-front/src/modules/object-record/relation-picker/components/MultipleObjectRecordSelectItem.tsx b/packages/twenty-front/src/modules/object-record/relation-picker/components/MultipleObjectRecordSelectItem.tsx index ed975e2bbe3f..af92fedd19f0 100644 --- a/packages/twenty-front/src/modules/object-record/relation-picker/components/MultipleObjectRecordSelectItem.tsx +++ b/packages/twenty-front/src/modules/object-record/relation-picker/components/MultipleObjectRecordSelectItem.tsx @@ -3,12 +3,15 @@ import { useRecoilValue } from 'recoil'; import { Avatar } from 'twenty-ui'; import { v4 } from 'uuid'; +import { useObjectRecordMultiSelectScopedStates } from '@/activities/hooks/useObjectRecordMultiSelectScopedStates'; import { MULTI_OBJECT_RECORD_SELECT_SELECTABLE_LIST_ID } from '@/object-record/relation-picker/constants/MultiObjectRecordSelectSelectableListId'; -import { ObjectRecordForSelect } from '@/object-record/relation-picker/hooks/useMultiObjectSearch'; +import { RelationPickerScopeInternalContext } from '@/object-record/relation-picker/scopes/scope-internal-context/RelationPickerScopeInternalContext'; import { SelectableItem } from '@/ui/layout/selectable-list/components/SelectableItem'; import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList'; import { MenuItemMultiSelectAvatar } from '@/ui/navigation/menu-item/components/MenuItemMultiSelectAvatar'; +import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId'; import { getImageAbsoluteURIOrBase64 } from '~/utils/image/getImageAbsoluteURIOrBase64'; +import { isDefined } from '~/utils/isDefined'; export const StyledSelectableItem = styled(SelectableItem)` height: 100%; @@ -16,45 +19,60 @@ export const StyledSelectableItem = styled(SelectableItem)` `; export const MultipleObjectRecordSelectItem = ({ - objectRecordForSelect, - onSelectedChange, - selected, + objectRecordId, + onChange, }: { - objectRecordForSelect: ObjectRecordForSelect; - onSelectedChange?: (selected: boolean) => void; - selected: boolean; + objectRecordId: string; + onChange?: (changedRecordForSelectId: string) => void; }) => { const { isSelectedItemIdSelector } = useSelectableList( MULTI_OBJECT_RECORD_SELECT_SELECTABLE_LIST_ID, ); const isSelectedByKeyboard = useRecoilValue( - isSelectedItemIdSelector(objectRecordForSelect.record.id), + isSelectedItemIdSelector(objectRecordId), ); + const scopeId = useAvailableScopeIdOrThrow( + RelationPickerScopeInternalContext, + ); + + const { objectRecordMultiSelectFamilyState } = + useObjectRecordMultiSelectScopedStates(scopeId); + + const record = useRecoilValue( + objectRecordMultiSelectFamilyState(objectRecordId), + ); + + if (!record) { + return null; + } + + const handleSelectChange = () => { + onChange?.(objectRecordId); + }; + + const { selected, recordIdentifier } = record; + + if (!isDefined(recordIdentifier)) { + return null; + } return ( - <StyledSelectableItem - itemId={objectRecordForSelect.record.id} - key={objectRecordForSelect.record.id + v4()} - > + <StyledSelectableItem itemId={objectRecordId} key={objectRecordId + v4()}> <MenuItemMultiSelectAvatar - selected={selected} - onSelectChange={onSelectedChange} + onSelectChange={(_isNewlySelectedValue) => handleSelectChange()} isKeySelected={isSelectedByKeyboard} + selected={selected} avatar={ <Avatar - avatarUrl={getImageAbsoluteURIOrBase64( - objectRecordForSelect.recordIdentifier.avatarUrl, - )} - entityId={objectRecordForSelect.record.id} - placeholder={objectRecordForSelect.recordIdentifier.name} + avatarUrl={getImageAbsoluteURIOrBase64(recordIdentifier.avatarUrl)} + placeholderColorSeed={objectRecordId} + placeholder={recordIdentifier.name} size="md" - type={ - objectRecordForSelect.recordIdentifier.avatarType ?? 'rounded' - } + type={recordIdentifier.avatarType ?? 'rounded'} /> } - text={objectRecordForSelect.recordIdentifier.name} + text={recordIdentifier.name} /> </StyledSelectableItem> ); diff --git a/packages/twenty-front/src/modules/object-record/relation-picker/components/SelectableMenuItemSelect.tsx b/packages/twenty-front/src/modules/object-record/relation-picker/components/SelectableMenuItemSelect.tsx index bd6e4a2f99e7..16eb58fad271 100644 --- a/packages/twenty-front/src/modules/object-record/relation-picker/components/SelectableMenuItemSelect.tsx +++ b/packages/twenty-front/src/modules/object-record/relation-picker/components/SelectableMenuItemSelect.tsx @@ -41,7 +41,7 @@ export const SelectableMenuItemSelect = ({ avatar={ <Avatar avatarUrl={getImageAbsoluteURIOrBase64(entity.avatarUrl)} - entityId={entity.id} + placeholderColorSeed={entity.id} placeholder={entity.name} size="md" type={entity.avatarType ?? 'rounded'} diff --git a/packages/twenty-front/src/modules/object-record/relation-picker/components/SingleEntitySelectMenuItemsWithSearch.tsx b/packages/twenty-front/src/modules/object-record/relation-picker/components/SingleEntitySelectMenuItemsWithSearch.tsx index 70c777c7bfd3..537c2fd088da 100644 --- a/packages/twenty-front/src/modules/object-record/relation-picker/components/SingleEntitySelectMenuItemsWithSearch.tsx +++ b/packages/twenty-front/src/modules/object-record/relation-picker/components/SingleEntitySelectMenuItemsWithSearch.tsx @@ -44,7 +44,6 @@ export const SingleEntitySelectMenuItemsWithSearch = ({ const { entities, relationPickerSearchFilter } = useRelationPickerEntitiesOptions({ relationObjectNameSingular, - relationPickerScopeId, selectedRelationRecordIds, excludedRelationRecordIds, }); diff --git a/packages/twenty-front/src/modules/object-record/relation-picker/constants/TableColumnsDenyList.ts b/packages/twenty-front/src/modules/object-record/relation-picker/constants/TableColumnsDenyList.ts new file mode 100644 index 000000000000..8feab843fc81 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/relation-picker/constants/TableColumnsDenyList.ts @@ -0,0 +1,5 @@ +export const TABLE_COLUMNS_DENY_LIST = [ + 'attachments', + 'activities', + 'timelineActivities', +]; diff --git a/packages/twenty-front/src/modules/object-record/relation-picker/hooks/__tests__/useMultiObjectSearch.test.tsx b/packages/twenty-front/src/modules/object-record/relation-picker/hooks/__tests__/useMultiObjectSearch.test.tsx index a84dfcce9497..63868f068611 100644 --- a/packages/twenty-front/src/modules/object-record/relation-picker/hooks/__tests__/useMultiObjectSearch.test.tsx +++ b/packages/twenty-front/src/modules/object-record/relation-picker/hooks/__tests__/useMultiObjectSearch.test.tsx @@ -11,7 +11,7 @@ import { FieldMetadataType } from '~/generated/graphql'; const query = gql` query CombinedFindManyRecords( $filterNameSingular: NameSingularFilterInput - $orderByNameSingular: NameSingularOrderByInput + $orderByNameSingular: [NameSingularOrderByInput] $lastCursorNameSingular: String $limitNameSingular: Int ) { @@ -50,7 +50,7 @@ const mocks = [ query, variables: { filterNameSingular: { id: { in: ['1'] } }, - orderByNameSingular: { createdAt: 'DescNullsLast' }, + orderByNameSingular: [{ createdAt: 'DescNullsLast' }], limitNameSingular: 60, }, }, @@ -63,7 +63,7 @@ const mocks = [ query, variables: { filterNameSingular: { and: [{}, { id: { in: ['1'] } }] }, - orderByNameSingular: { createdAt: 'DescNullsLast' }, + orderByNameSingular: [{ createdAt: 'DescNullsLast' }], limitNameSingular: 60, }, }, @@ -77,7 +77,7 @@ const mocks = [ variables: { limitNameSingular: 60, filterNameSingular: { not: { id: { in: ['1'] } } }, - orderByNameSingular: { createdAt: 'DescNullsLast' }, + orderByNameSingular: [{ createdAt: 'DescNullsLast' }], }, }, result: jest.fn(() => ({ diff --git a/packages/twenty-front/src/modules/object-record/relation-picker/hooks/useOrderByFieldPerMetadataItem.ts b/packages/twenty-front/src/modules/object-record/relation-picker/hooks/useOrderByFieldPerMetadataItem.ts index 07f60b012fce..ec20862e0807 100644 --- a/packages/twenty-front/src/modules/object-record/relation-picker/hooks/useOrderByFieldPerMetadataItem.ts +++ b/packages/twenty-front/src/modules/object-record/relation-picker/hooks/useOrderByFieldPerMetadataItem.ts @@ -16,9 +16,7 @@ export const useOrderByFieldPerMetadataItem = ({ return [ `orderBy${capitalize(objectMetadataItem.nameSingular)}`, - { - ...orderByField, - }, + [...orderByField], ]; }) .filter(isDefined), diff --git a/packages/twenty-front/src/modules/object-record/relation-picker/hooks/useRelationPickerEntitiesOptions.ts b/packages/twenty-front/src/modules/object-record/relation-picker/hooks/useRelationPickerEntitiesOptions.ts index 9eb5f990c622..efb3f9934267 100644 --- a/packages/twenty-front/src/modules/object-record/relation-picker/hooks/useRelationPickerEntitiesOptions.ts +++ b/packages/twenty-front/src/modules/object-record/relation-picker/hooks/useRelationPickerEntitiesOptions.ts @@ -1,22 +1,26 @@ import { useRecoilValue } from 'recoil'; import { useRelationPickerScopedStates } from '@/object-record/relation-picker/hooks/internal/useRelationPickerScopedStates'; +import { RelationPickerScopeInternalContext } from '@/object-record/relation-picker/scopes/scope-internal-context/RelationPickerScopeInternalContext'; import { useFilteredSearchEntityQuery } from '@/search/hooks/useFilteredSearchEntityQuery'; +import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId'; export const useRelationPickerEntitiesOptions = ({ relationObjectNameSingular, - relationPickerScopeId = 'relation-picker', selectedRelationRecordIds = [], excludedRelationRecordIds = [], }: { relationObjectNameSingular: string; - relationPickerScopeId?: string; selectedRelationRecordIds?: string[]; excludedRelationRecordIds?: string[]; }) => { + const scopeId = useAvailableScopeIdOrThrow( + RelationPickerScopeInternalContext, + ); + const { searchQueryState, relationPickerSearchFilterState } = useRelationPickerScopedStates({ - relationPickerScopedId: relationPickerScopeId, + relationPickerScopedId: scopeId, }); const relationPickerSearchFilter = useRecoilValue( relationPickerSearchFilterState, diff --git a/packages/twenty-front/src/modules/object-record/select/components/MultipleRecordSelectDropdown.tsx b/packages/twenty-front/src/modules/object-record/select/components/MultipleRecordSelectDropdown.tsx index 455cedced398..af608e0077d5 100644 --- a/packages/twenty-front/src/modules/object-record/select/components/MultipleRecordSelectDropdown.tsx +++ b/packages/twenty-front/src/modules/object-record/select/components/MultipleRecordSelectDropdown.tsx @@ -70,7 +70,7 @@ export const MultipleRecordSelectDropdown = ({ avatar={ <Avatar avatarUrl={getImageAbsoluteURIOrBase64(record.avatarUrl)} - entityId={record.id} + placeholderColorSeed={record.id} placeholder={record.name} size="md" type={record.avatarType ?? 'rounded'} diff --git a/packages/twenty-front/src/modules/object-record/spreadsheet-import/__tests__/useSpreadsheetRecordImport.test.tsx b/packages/twenty-front/src/modules/object-record/spreadsheet-import/__tests__/useSpreadsheetRecordImport.test.tsx index a925b36c8c74..33f43785b2b2 100644 --- a/packages/twenty-front/src/modules/object-record/spreadsheet-import/__tests__/useSpreadsheetRecordImport.test.tsx +++ b/packages/twenty-front/src/modules/object-record/spreadsheet-import/__tests__/useSpreadsheetRecordImport.test.tsx @@ -20,8 +20,11 @@ const companyMocks = [ { request: { query: gql` - mutation CreateCompanies($data: [CompanyCreateInput!]!) { - createCompanies(data: $data) { + mutation CreateCompanies( + $data: [CompanyCreateInput!]! + $upsert: Boolean + ) { + createCompanies(data: $data, upsert: $upsert) { __typename xLink { label @@ -37,7 +40,16 @@ const companyMocks = [ currencyCode } createdAt - address + address { + addressStreet1 + addressStreet2 + addressCity + addressState + addressCountry + addressPostcode + addressLat + addressLng + } updatedAt name accountOwnerId @@ -58,6 +70,7 @@ const companyMocks = [ id: companyId, }, ], + upsert: true, }, }, result: jest.fn(() => ({ diff --git a/packages/twenty-front/src/modules/object-record/spreadsheet-import/useSpreadsheetRecordImport.ts b/packages/twenty-front/src/modules/object-record/spreadsheet-import/useSpreadsheetRecordImport.ts index 700cc44622a0..28516c7939e6 100644 --- a/packages/twenty-front/src/modules/object-record/spreadsheet-import/useSpreadsheetRecordImport.ts +++ b/packages/twenty-front/src/modules/object-record/spreadsheet-import/useSpreadsheetRecordImport.ts @@ -1,11 +1,11 @@ import { isNonEmptyString } from '@sniptt/guards'; -import { IconComponent, useIcons } from 'twenty-ui'; +import { useIcons } from 'twenty-ui'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { useCreateManyRecords } from '@/object-record/hooks/useCreateManyRecords'; import { getSpreadSheetValidation } from '@/object-record/spreadsheet-import/util/getSpreadSheetValidation'; import { useSpreadsheetImport } from '@/spreadsheet-import/hooks/useSpreadsheetImport'; -import { SpreadsheetOptions, Validation } from '@/spreadsheet-import/types'; +import { Field, SpreadsheetOptions } from '@/spreadsheet-import/types'; import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar'; import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; import { FieldMetadataType } from '~/generated-metadata/graphql'; @@ -26,21 +26,13 @@ export const useSpreadsheetRecordImport = (objectNameSingular: string) => { .filter( (x) => x.isActive && - !x.isSystem && + (!x.isSystem || x.name === 'id') && x.name !== 'createdAt' && (x.type !== FieldMetadataType.Relation || x.toRelationMetadata), ) .sort((a, b) => a.name.localeCompare(b.name)); - const templateFields: { - icon: IconComponent; - label: string; - key: string; - fieldType: { - type: 'input' | 'checkbox'; - }; - validations?: Validation[]; - }[] = []; + const templateFields: Field<string>[] = []; for (const field of fields) { if (field.type === FieldMetadataType.FullName) { templateFields.push({ @@ -80,6 +72,34 @@ export const useSpreadsheetRecordImport = (objectNameSingular: string) => { field.label + ' (ID)', ), }); + } else if (field.type === FieldMetadataType.Select) { + templateFields.push({ + icon: getIcon(field.icon), + label: field.label, + key: field.name, + fieldType: { + type: 'select', + options: + field.options?.map((option) => ({ + label: option.label, + value: option.value, + })) || [], + }, + validations: getSpreadSheetValidation( + field.type, + field.label + ' (ID)', + ), + }); + } else if (field.type === FieldMetadataType.Boolean) { + templateFields.push({ + icon: getIcon(field.icon), + label: field.label, + key: field.name, + fieldType: { + type: 'checkbox', + }, + validations: getSpreadSheetValidation(field.type, field.label), + }); } else { templateFields.push({ icon: getIcon(field.icon), @@ -110,11 +130,15 @@ export const useSpreadsheetRecordImport = (objectNameSingular: string) => { switch (field.type) { case FieldMetadataType.Boolean: - fieldMapping[field.name] = value === 'true' || value === true; + if (value !== undefined) { + fieldMapping[field.name] = value === 'true' || value === true; + } break; case FieldMetadataType.Number: case FieldMetadataType.Numeric: - fieldMapping[field.name] = Number(value); + if (value !== undefined) { + fieldMapping[field.name] = Number(value); + } break; case FieldMetadataType.Currency: if (value !== undefined) { @@ -154,14 +178,16 @@ export const useSpreadsheetRecordImport = (objectNameSingular: string) => { } break; default: - fieldMapping[field.name] = value; + if (value !== undefined) { + fieldMapping[field.name] = value; + } break; } } return fieldMapping; }); try { - await createManyRecords(createInputs); + await createManyRecords(createInputs, true); } catch (error: any) { enqueueSnackBar(error?.message || 'Something went wrong', { variant: SnackBarVariant.Error, diff --git a/packages/twenty-front/src/modules/object-record/states/isRecordBoardColumnLoadingFamilyState.ts b/packages/twenty-front/src/modules/object-record/states/isRecordBoardColumnLoadingFamilyState.ts new file mode 100644 index 000000000000..8804ff588ba1 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/states/isRecordBoardColumnLoadingFamilyState.ts @@ -0,0 +1,9 @@ +import { createFamilyState } from '@/ui/utilities/state/utils/createFamilyState'; + +export const isRecordIndexBoardColumnLoadingFamilyState = createFamilyState< + boolean, + string | undefined +>({ + key: 'isRecordIndexBoardColumnLoadingFamilyState', + defaultValue: false, +}); diff --git a/packages/twenty-front/src/modules/object-record/types/OnFindManyRecordsCompleted.ts b/packages/twenty-front/src/modules/object-record/types/OnFindManyRecordsCompleted.ts new file mode 100644 index 000000000000..97003380167d --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/types/OnFindManyRecordsCompleted.ts @@ -0,0 +1,9 @@ +import { RecordGqlConnection } from '@/object-record/graphql/types/RecordGqlConnection'; + +export type OnFindManyRecordsCompleted<T> = ( + records: T[], + options?: { + pageInfo?: RecordGqlConnection['pageInfo']; + totalCount?: number; + }, +) => void; diff --git a/packages/twenty-front/src/modules/object-record/types/UseFindManyRecordsParams.ts b/packages/twenty-front/src/modules/object-record/types/UseFindManyRecordsParams.ts new file mode 100644 index 000000000000..1a15c6040ecc --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/types/UseFindManyRecordsParams.ts @@ -0,0 +1,14 @@ +import { WatchQueryFetchPolicy } from '@apollo/client'; + +import { ObjectMetadataItemIdentifier } from '@/object-metadata/types/ObjectMetadataItemIdentifier'; +import { RecordGqlOperationGqlRecordFields } from '@/object-record/graphql/types/RecordGqlOperationGqlRecordFields'; +import { RecordGqlOperationVariables } from '@/object-record/graphql/types/RecordGqlOperationVariables'; +import { OnFindManyRecordsCompleted } from '@/object-record/types/OnFindManyRecordsCompleted'; + +export type UseFindManyRecordsParams<T> = ObjectMetadataItemIdentifier & + RecordGqlOperationVariables & { + onCompleted?: OnFindManyRecordsCompleted<T>; + skip?: boolean; + recordGqlFields?: RecordGqlOperationGqlRecordFields; + fetchPolicy?: WatchQueryFetchPolicy; + }; diff --git a/packages/twenty-front/src/modules/object-record/utils/computeRecordBoardColumnDefinitionsFromObjectMetadata.ts b/packages/twenty-front/src/modules/object-record/utils/computeRecordBoardColumnDefinitionsFromObjectMetadata.ts index 4df6d4afd655..4abbba702a98 100644 --- a/packages/twenty-front/src/modules/object-record/utils/computeRecordBoardColumnDefinitionsFromObjectMetadata.ts +++ b/packages/twenty-front/src/modules/object-record/utils/computeRecordBoardColumnDefinitionsFromObjectMetadata.ts @@ -1,7 +1,12 @@ import { IconPencil } from 'twenty-ui'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; -import { RecordBoardColumnDefinition } from '@/object-record/record-board/types/RecordBoardColumnDefinition'; +import { + RecordBoardColumnDefinition, + RecordBoardColumnDefinitionNoValue, + RecordBoardColumnDefinitionType, + RecordBoardColumnDefinitionValue, +} from '@/object-record/record-board/types/RecordBoardColumnDefinition'; import { FieldMetadataType } from '~/generated-metadata/graphql'; export const computeRecordBoardColumnDefinitionsFromObjectMetadata = ( @@ -25,20 +30,42 @@ export const computeRecordBoardColumnDefinitionsFromObjectMetadata = ( ); } - return selectFieldMetadataItem.options.map((selectOption) => ({ - id: selectOption.id, - title: selectOption.label, - value: selectOption.value, - color: selectOption.color, - position: selectOption.position, - actions: [ - { - id: 'edit', - label: 'Edit from settings', - icon: IconPencil, - position: 0, - callback: navigateToSelectSettings, - }, - ], - })); + const valueColumns = selectFieldMetadataItem.options.map( + (selectOption) => + ({ + id: selectOption.id, + type: RecordBoardColumnDefinitionType.Value, + title: selectOption.label, + value: selectOption.value, + color: selectOption.color, + position: selectOption.position, + actions: [ + { + id: 'edit', + label: 'Edit from settings', + icon: IconPencil, + position: 0, + callback: navigateToSelectSettings, + }, + ], + }) satisfies RecordBoardColumnDefinitionValue, + ); + + const noValueColumn = { + id: 'no-value', + title: 'No Value', + type: RecordBoardColumnDefinitionType.NoValue, + value: null, + actions: [], + position: + selectFieldMetadataItem.options + .map((option) => option.position) + .reduce((a, b) => Math.max(a, b), 0) + 1, + } satisfies RecordBoardColumnDefinitionNoValue; + + if (selectFieldMetadataItem.isNullable === true) { + return [...valueColumns, noValueColumn]; + } + + return valueColumns; }; diff --git a/packages/twenty-front/src/modules/object-record/utils/filterAvailableTableColumns.ts b/packages/twenty-front/src/modules/object-record/utils/filterAvailableTableColumns.ts index bb7cc3578b3d..eadb16fd47c8 100644 --- a/packages/twenty-front/src/modules/object-record/utils/filterAvailableTableColumns.ts +++ b/packages/twenty-front/src/modules/object-record/utils/filterAvailableTableColumns.ts @@ -1,17 +1,23 @@ import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata'; import { isFieldRelation } from '@/object-record/record-field/types/guards/isFieldRelation'; import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition'; +import { TABLE_COLUMNS_DENY_LIST } from '@/object-record/relation-picker/constants/TableColumnsDenyList'; export const filterAvailableTableColumns = ( columnDefinition: ColumnDefinition<FieldMetadata>, ): boolean => { if ( isFieldRelation(columnDefinition) && - columnDefinition.metadata?.relationType !== 'TO_ONE_OBJECT' + columnDefinition.metadata?.relationType !== 'TO_ONE_OBJECT' && + columnDefinition.metadata?.relationType !== 'FROM_MANY_OBJECTS' ) { return false; } + if (TABLE_COLUMNS_DENY_LIST.includes(columnDefinition.metadata.fieldName)) { + return false; + } + if (columnDefinition.type === 'UUID') { return false; } diff --git a/packages/twenty-front/src/modules/object-record/utils/generateFindManyRecordsQuery.ts b/packages/twenty-front/src/modules/object-record/utils/generateFindManyRecordsQuery.ts index ea68c231cbad..a62ae2c0d77f 100644 --- a/packages/twenty-front/src/modules/object-record/utils/generateFindManyRecordsQuery.ts +++ b/packages/twenty-front/src/modules/object-record/utils/generateFindManyRecordsQuery.ts @@ -1,32 +1,37 @@ import gql from 'graphql-tag'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; -import { isAggregationEnabled } from '@/object-metadata/utils/isAggregationEnabled'; import { mapObjectMetadataToGraphQLQuery } from '@/object-metadata/utils/mapObjectMetadataToGraphQLQuery'; import { RecordGqlOperationGqlRecordFields } from '@/object-record/graphql/types/RecordGqlOperationGqlRecordFields'; import { capitalize } from '~/utils/string/capitalize'; +export type QueryCursorDirection = 'before' | 'after'; + export const generateFindManyRecordsQuery = ({ objectMetadataItem, objectMetadataItems, recordGqlFields, computeReferences, + cursorDirection, }: { objectMetadataItem: ObjectMetadataItem; objectMetadataItems: ObjectMetadataItem[]; recordGqlFields?: RecordGqlOperationGqlRecordFields; computeReferences?: boolean; + cursorDirection?: QueryCursorDirection; }) => gql` query FindMany${capitalize( objectMetadataItem.namePlural, )}($filter: ${capitalize( objectMetadataItem.nameSingular, -)}FilterInput, $orderBy: ${capitalize( +)}FilterInput, $orderBy: [${capitalize( objectMetadataItem.nameSingular, -)}OrderByInput, $lastCursor: String, $limit: Int) { - ${ - objectMetadataItem.namePlural - }(filter: $filter, orderBy: $orderBy, first: $limit, after: $lastCursor){ +)}OrderByInput], $lastCursor: String, $limit: Int) { + ${objectMetadataItem.namePlural}(filter: $filter, orderBy: $orderBy, ${ + cursorDirection === 'before' + ? 'last: $limit, before: $lastCursor' + : 'first: $limit, after: $lastCursor' + } ){ edges { node ${mapObjectMetadataToGraphQLQuery({ objectMetadataItems, @@ -37,11 +42,12 @@ query FindMany${capitalize( cursor } pageInfo { - ${isAggregationEnabled(objectMetadataItem) ? 'hasNextPage' : ''} + hasNextPage + hasPreviousPage startCursor endCursor } - ${isAggregationEnabled(objectMetadataItem) ? 'totalCount' : ''} + totalCount } } `; diff --git a/packages/twenty-front/src/modules/object-record/utils/getQueryIdentifier.ts b/packages/twenty-front/src/modules/object-record/utils/getQueryIdentifier.ts new file mode 100644 index 000000000000..c43f7807a451 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/utils/getQueryIdentifier.ts @@ -0,0 +1,16 @@ +import { RecordGqlOperationVariables } from '@/object-record/graphql/types/RecordGqlOperationVariables'; + +export const getQueryIdentifier = ({ + objectNameSingular, + filter, + orderBy, + limit, + cursorFilter, +}: RecordGqlOperationVariables & { + objectNameSingular: string; +}) => + objectNameSingular + + JSON.stringify(filter) + + JSON.stringify(orderBy) + + limit + + (cursorFilter ? JSON.stringify(cursorFilter) : undefined); diff --git a/packages/twenty-front/src/modules/object-record/utils/getRecordChipGeneratorPerObjectPerField.ts b/packages/twenty-front/src/modules/object-record/utils/getRecordChipGeneratorPerObjectPerField.ts deleted file mode 100644 index f127e275ec39..000000000000 --- a/packages/twenty-front/src/modules/object-record/utils/getRecordChipGeneratorPerObjectPerField.ts +++ /dev/null @@ -1,116 +0,0 @@ -import { ChipGeneratorPerObjectPerField } from '@/object-metadata/context/PreComputedChipGeneratorsContext'; -import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; -import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; -import { getAvatarType } from '@/object-metadata/utils/getAvatarType'; -import { getAvatarUrl } from '@/object-metadata/utils/getAvatarUrl'; -import { getLabelIdentifierFieldMetadataItem } from '@/object-metadata/utils/getLabelIdentifierFieldMetadataItem'; -import { getLabelIdentifierFieldValue } from '@/object-metadata/utils/getLabelIdentifierFieldValue'; -import { getLinkToShowPage } from '@/object-metadata/utils/getLinkToShowPage'; -import { isLabelIdentifierField } from '@/object-metadata/utils/isLabelIdentifierField'; -import { isFieldFullName } from '@/object-record/record-field/types/guards/isFieldFullName'; -import { isFieldNumber } from '@/object-record/record-field/types/guards/isFieldNumber'; -import { isFieldRelation } from '@/object-record/record-field/types/guards/isFieldRelation'; -import { isFieldText } from '@/object-record/record-field/types/guards/isFieldText'; -import { RecordChipData } from '@/object-record/record-field/types/RecordChipData'; -import { ObjectRecord } from '@/object-record/types/ObjectRecord'; -import { FieldMetadataType } from '~/generated-metadata/graphql'; -import { isDefined } from '~/utils/isDefined'; - -export const isFieldChipDisplay = ( - field: Pick<FieldMetadataItem, 'type'>, - isLabelIdentifier: boolean, -) => - isLabelIdentifier && - (isFieldText(field) || isFieldFullName(field) || isFieldNumber(field)); - -export const getRecordChipGeneratorPerObjectPerField = ( - objectMetadataItems: ObjectMetadataItem[], -) => { - const recordChipGeneratorPerObjectPerField: ChipGeneratorPerObjectPerField = - {}; - - for (const objectMetadataItem of objectMetadataItems) { - const generatorPerField = Object.fromEntries< - (record: ObjectRecord) => RecordChipData - >( - objectMetadataItem.fields - .filter( - (fieldMetadataItem) => - isLabelIdentifierField({ - fieldMetadataItem: fieldMetadataItem, - objectMetadataItem, - }) || - fieldMetadataItem.type === FieldMetadataType.Relation || - isFieldChipDisplay( - fieldMetadataItem, - isLabelIdentifierField({ - fieldMetadataItem: fieldMetadataItem, - objectMetadataItem, - }), - ), - ) - .map((fieldMetadataItem) => { - const objectNameSingularToFind = isLabelIdentifierField({ - fieldMetadataItem: fieldMetadataItem, - objectMetadataItem: objectMetadataItem, - }) - ? objectMetadataItem.nameSingular - : isFieldRelation(fieldMetadataItem) - ? fieldMetadataItem.relationDefinition?.targetObjectMetadata - .nameSingular ?? undefined - : undefined; - - const objectMetadataItemToUse = objectMetadataItems.find( - (objectMetadataItem) => - objectMetadataItem.nameSingular === objectNameSingularToFind, - ); - - if ( - !isDefined(objectMetadataItemToUse) || - !isDefined(objectNameSingularToFind) - ) { - return ['', () => ({}) as any]; - } - - const labelIdentifierFieldMetadataItem = - getLabelIdentifierFieldMetadataItem(objectMetadataItemToUse); - - const imageIdentifierFieldMetadata = - objectMetadataItemToUse.fields.find( - (field) => - field.id === - objectMetadataItemToUse.imageIdentifierFieldMetadataId, - ); - - const avatarType = getAvatarType(objectNameSingularToFind); - - return [ - fieldMetadataItem.name, - (record: ObjectRecord) => ({ - recordId: record.id, - name: getLabelIdentifierFieldValue( - record, - labelIdentifierFieldMetadataItem, - objectMetadataItemToUse.nameSingular, - ), - avatarUrl: getAvatarUrl( - objectMetadataItemToUse.nameSingular, - record, - imageIdentifierFieldMetadata, - ), - avatarType, - linkToShowPage: getLinkToShowPage( - objectMetadataItemToUse.nameSingular, - record, - ), - }), - ]; - }), - ); - - recordChipGeneratorPerObjectPerField[objectMetadataItem.nameSingular] = - generatorPerField; - } - - return recordChipGeneratorPerObjectPerField; -}; diff --git a/packages/twenty-front/src/modules/object-record/utils/getRecordChipGenerators.ts b/packages/twenty-front/src/modules/object-record/utils/getRecordChipGenerators.ts new file mode 100644 index 000000000000..c80fe1b76312 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/utils/getRecordChipGenerators.ts @@ -0,0 +1,120 @@ +import { + ChipGeneratorPerObjectNameSingularPerFieldName, + IdentifierChipGeneratorPerObject, +} from '@/object-metadata/context/PreComputedChipGeneratorsContext'; +import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; +import { getAvatarType } from '@/object-metadata/utils/getAvatarType'; +import { getAvatarUrl } from '@/object-metadata/utils/getAvatarUrl'; +import { getLabelIdentifierFieldMetadataItem } from '@/object-metadata/utils/getLabelIdentifierFieldMetadataItem'; +import { getLabelIdentifierFieldValue } from '@/object-metadata/utils/getLabelIdentifierFieldValue'; +import { isLabelIdentifierField } from '@/object-metadata/utils/isLabelIdentifierField'; +import { isFieldChipDisplay } from '@/object-record/record-field/meta-types/display/utils/isFieldChipDisplay'; +import { RecordChipData } from '@/object-record/record-field/types/RecordChipData'; +import { ObjectRecord } from '@/object-record/types/ObjectRecord'; +import { FieldMetadataType } from '~/generated-metadata/graphql'; +import { isDefined } from '~/utils/isDefined'; + +export const getRecordChipGenerators = ( + objectMetadataItems: ObjectMetadataItem[], +) => { + const chipGeneratorPerObjectPerField: ChipGeneratorPerObjectNameSingularPerFieldName = + {}; + + const identifierChipGeneratorPerObject: IdentifierChipGeneratorPerObject = {}; + + for (const objectMetadataItem of objectMetadataItems) { + const labelIdentifierFieldMetadataItem = + getLabelIdentifierFieldMetadataItem(objectMetadataItem); + + const generatorPerField = Object.fromEntries< + (record: ObjectRecord) => RecordChipData + >( + objectMetadataItem.fields + .filter( + (fieldMetadataItem) => + labelIdentifierFieldMetadataItem?.id === fieldMetadataItem.id || + fieldMetadataItem.type === FieldMetadataType.Relation || + isFieldChipDisplay( + fieldMetadataItem, + isLabelIdentifierField({ + fieldMetadataItem: fieldMetadataItem, + objectMetadataItem, + }), + ), + ) + .map((fieldMetadataItem) => { + const isLabelIdentifier = + labelIdentifierFieldMetadataItem?.id === fieldMetadataItem.id; + + const currentObjectNameSingular = objectMetadataItem.nameSingular; + const fieldRelationObjectNameSingular = + fieldMetadataItem.relationDefinition?.targetObjectMetadata + .nameSingular ?? undefined; + + const objectNameSingularToFind = isLabelIdentifier + ? currentObjectNameSingular + : fieldRelationObjectNameSingular; + + const objectMetadataItemToUse = objectMetadataItems.find( + (objectMetadataItem) => + objectMetadataItem.nameSingular === objectNameSingularToFind, + ); + + if ( + !isDefined(objectMetadataItemToUse) || + !isDefined(objectNameSingularToFind) + ) { + return ['', () => ({}) as any]; + } + + const labelIdentifierFieldMetadataItemToUse = + getLabelIdentifierFieldMetadataItem(objectMetadataItemToUse); + + const imageIdentifierFieldMetadataToUse = + objectMetadataItemToUse.fields.find( + (field) => + field.id === + objectMetadataItemToUse.imageIdentifierFieldMetadataId, + ); + + const avatarType = getAvatarType(objectNameSingularToFind); + + return [ + fieldMetadataItem.name, + (record: ObjectRecord) => + ({ + recordId: record.id, + name: getLabelIdentifierFieldValue( + record, + labelIdentifierFieldMetadataItemToUse, + objectMetadataItemToUse.nameSingular, + ), + avatarUrl: getAvatarUrl( + objectMetadataItemToUse.nameSingular, + record, + imageIdentifierFieldMetadataToUse, + ), + avatarType, + isLabelIdentifier, + objectNameSingular: objectNameSingularToFind, + }) satisfies RecordChipData, + ]; + }), + ); + + chipGeneratorPerObjectPerField[objectMetadataItem.nameSingular] = + generatorPerField; + + if (isDefined(labelIdentifierFieldMetadataItem)) { + identifierChipGeneratorPerObject[objectMetadataItem.nameSingular] = + chipGeneratorPerObjectPerField[objectMetadataItem.nameSingular]?.[ + labelIdentifierFieldMetadataItem.name + ]; + } + } + + return { + chipGeneratorPerObjectPerField, + identifierChipGeneratorPerObject, + }; +}; diff --git a/packages/twenty-front/src/modules/object-record/utils/sanitizeRecordInput.ts b/packages/twenty-front/src/modules/object-record/utils/sanitizeRecordInput.ts index fce402359687..314fa1e9153e 100644 --- a/packages/twenty-front/src/modules/object-record/utils/sanitizeRecordInput.ts +++ b/packages/twenty-front/src/modules/object-record/utils/sanitizeRecordInput.ts @@ -2,8 +2,7 @@ import { isString } from '@sniptt/guards'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; -import { isFieldRelationValue } from '@/object-record/record-field/types/guards/isFieldRelationValue'; -import { EntityForSelect } from '@/object-record/relation-picker/types/EntityForSelect'; +import { isFieldRelationToOneValue } from '@/object-record/record-field/types/guards/isFieldRelationToOneValue'; import { ObjectRecord } from '@/object-record/types/ObjectRecord'; import { FieldMetadataType } from '~/generated/graphql'; import { isDefined } from '~/utils/isDefined'; @@ -31,7 +30,7 @@ export const sanitizeRecordInput = ({ if ( fieldMetadataItem.type === FieldMetadataType.Relation && - isFieldRelationValue<EntityForSelect>(fieldValue) + isFieldRelationToOneValue(fieldValue) ) { const relationIdFieldName = `${fieldMetadataItem.name}Id`; const relationIdFieldMetadataItem = objectMetadataItem.fields.find( diff --git a/packages/twenty-front/src/modules/onboarding/components/OnboardingSyncEmailsSettingsCard.tsx b/packages/twenty-front/src/modules/onboarding/components/OnboardingSyncEmailsSettingsCard.tsx index 61605ec00389..2a01962fdfe1 100644 --- a/packages/twenty-front/src/modules/onboarding/components/OnboardingSyncEmailsSettingsCard.tsx +++ b/packages/twenty-front/src/modules/onboarding/components/OnboardingSyncEmailsSettingsCard.tsx @@ -12,6 +12,7 @@ export const OnboardingSyncEmailsSettingsCard = ({ value = MessageChannelVisibility.ShareEverything, }: OnboardingSyncEmailsSettingsCardProps) => ( <SettingsAccountsRadioSettingsCard + name="sync-emails-visiblity" options={onboardingSyncEmailsOptions} value={value} onChange={onChange} diff --git a/packages/twenty-front/src/modules/onboarding/components/onboardingSyncEmailsOptions.tsx b/packages/twenty-front/src/modules/onboarding/components/onboardingSyncEmailsOptions.tsx index 71e53d472f0f..121408787316 100644 --- a/packages/twenty-front/src/modules/onboarding/components/onboardingSyncEmailsOptions.tsx +++ b/packages/twenty-front/src/modules/onboarding/components/onboardingSyncEmailsOptions.tsx @@ -1,9 +1,9 @@ +import { SettingsAccountsVisibilityIcon } from '@/settings/accounts/components/SettingsAccountsVisibilityIcon'; import styled from '@emotion/styled'; -import { SettingsAccountsVisibilitySettingCardMedia } from '@/settings/accounts/components/SettingsAccountsVisibilitySettingCardMedia'; import { MessageChannelVisibility } from '~/generated/graphql'; -const StyledCardMedia = styled(SettingsAccountsVisibilitySettingCardMedia)` +const StyledCardMedia = styled(SettingsAccountsVisibilityIcon)` width: ${({ theme }) => theme.spacing(10)}; `; diff --git a/packages/twenty-front/src/modules/onboarding/hooks/__tests__/useOnboardingStatus.test.ts b/packages/twenty-front/src/modules/onboarding/hooks/__tests__/useOnboardingStatus.test.ts new file mode 100644 index 000000000000..3aaf6449502f --- /dev/null +++ b/packages/twenty-front/src/modules/onboarding/hooks/__tests__/useOnboardingStatus.test.ts @@ -0,0 +1,61 @@ +import { act } from 'react-dom/test-utils'; +import { renderHook } from '@testing-library/react'; +import { RecoilRoot, useSetRecoilState } from 'recoil'; + +import { CurrentUser, currentUserState } from '@/auth/states/currentUserState'; +import { tokenPairState } from '@/auth/states/tokenPairState'; +import { useOnboardingStatus } from '@/onboarding/hooks/useOnboardingStatus'; +import { OnboardingStatus } from '~/generated/graphql'; + +const tokenPair = { + accessToken: { token: 'accessToken', expiresAt: 'expiresAt' }, + refreshToken: { token: 'refreshToken', expiresAt: 'expiresAt' }, +}; +const currentUser = { + id: '1', + onboardingStatus: null, +} as CurrentUser; + +const renderHooks = () => { + const { result } = renderHook( + () => { + const onboardingStatus = useOnboardingStatus(); + const setCurrentUser = useSetRecoilState(currentUserState); + const setTokenPair = useSetRecoilState(tokenPairState); + + return { + onboardingStatus, + setCurrentUser, + setTokenPair, + }; + }, + { + wrapper: RecoilRoot, + }, + ); + return { result }; +}; + +describe('useOnboardingStatus', () => { + it(`should return "undefined" when user is not logged in`, async () => { + const { result } = renderHooks(); + expect(result.current.onboardingStatus).toBe(undefined); + }); + + Object.values(OnboardingStatus).forEach((onboardingStatus) => { + it(`should return "${onboardingStatus}"`, async () => { + const { result } = renderHooks(); + const { setTokenPair, setCurrentUser } = result.current; + + act(() => { + setTokenPair(tokenPair); + setCurrentUser({ + ...currentUser, + onboardingStatus, + }); + }); + + expect(result.current.onboardingStatus).toBe(onboardingStatus); + }); + }); +}); diff --git a/packages/twenty-front/src/modules/onboarding/hooks/__tests__/useSetNextOnboardingStatus.test.ts b/packages/twenty-front/src/modules/onboarding/hooks/__tests__/useSetNextOnboardingStatus.test.ts new file mode 100644 index 000000000000..260e3d6aa48a --- /dev/null +++ b/packages/twenty-front/src/modules/onboarding/hooks/__tests__/useSetNextOnboardingStatus.test.ts @@ -0,0 +1,87 @@ +import { act, renderHook } from '@testing-library/react'; +import { RecoilRoot, useRecoilState, useSetRecoilState } from 'recoil'; +import { v4 } from 'uuid'; + +import { currentUserState } from '@/auth/states/currentUserState'; +import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState'; +import { useSetNextOnboardingStatus } from '@/onboarding/hooks/useSetNextOnboardingStatus'; +import { OnboardingStatus, SubscriptionStatus } from '~/generated/graphql'; +import { + mockDefaultWorkspace, + mockedUserData, +} from '~/testing/mock-data/users'; + +const renderHooks = ( + onboardingStatus: OnboardingStatus, + withCurrentBillingSubscription: boolean, + withOneWorkspaceMember = true, +) => { + const { result } = renderHook( + () => { + const [currentUser, setCurrentUser] = useRecoilState(currentUserState); + const setCurrentWorkspace = useSetRecoilState(currentWorkspaceState); + const setNextOnboardingStatus = useSetNextOnboardingStatus(); + return { + currentUser, + setCurrentUser, + setCurrentWorkspace, + setNextOnboardingStatus, + }; + }, + { + wrapper: RecoilRoot, + }, + ); + act(() => { + result.current.setCurrentUser({ ...mockedUserData, onboardingStatus }); + result.current.setCurrentWorkspace({ + ...mockDefaultWorkspace, + currentBillingSubscription: withCurrentBillingSubscription + ? { id: v4(), status: SubscriptionStatus.Active } + : undefined, + workspaceMembersCount: withOneWorkspaceMember ? 1 : 2, + }); + }); + act(() => { + result.current.setNextOnboardingStatus(); + }); + return result.current.currentUser?.onboardingStatus; +}; + +describe('useSetNextOnboardingStatus', () => { + it('should set next onboarding status for ProfileCreation', () => { + const nextOnboardingStatus = renderHooks( + OnboardingStatus.ProfileCreation, + false, + true, + ); + expect(nextOnboardingStatus).toEqual(OnboardingStatus.SyncEmail); + }); + + it('should set next onboarding status for SyncEmail', () => { + const nextOnboardingStatus = renderHooks( + OnboardingStatus.SyncEmail, + false, + true, + ); + expect(nextOnboardingStatus).toEqual(OnboardingStatus.InviteTeam); + }); + + it('should skip invite when more than 1 workspaceMember exist', () => { + const nextOnboardingStatus = renderHooks( + OnboardingStatus.SyncEmail, + true, + false, + ); + expect(nextOnboardingStatus).toEqual(OnboardingStatus.Completed); + }); + + it('should set next onboarding status for Completed', () => { + const nextOnboardingStatus = renderHooks( + OnboardingStatus.InviteTeam, + true, + true, + ); + expect(nextOnboardingStatus).toEqual(OnboardingStatus.Completed); + }); +}); diff --git a/packages/twenty-front/src/modules/onboarding/hooks/useOnboardingStatus.ts b/packages/twenty-front/src/modules/onboarding/hooks/useOnboardingStatus.ts new file mode 100644 index 000000000000..28bef7fd4a58 --- /dev/null +++ b/packages/twenty-front/src/modules/onboarding/hooks/useOnboardingStatus.ts @@ -0,0 +1,9 @@ +import { useRecoilValue } from 'recoil'; + +import { currentUserState } from '@/auth/states/currentUserState'; +import { OnboardingStatus } from '~/generated/graphql'; + +export const useOnboardingStatus = (): OnboardingStatus | null | undefined => { + const currentUser = useRecoilValue(currentUserState); + return currentUser?.onboardingStatus; +}; diff --git a/packages/twenty-front/src/modules/onboarding/hooks/useSetNextOnboardingStatus.ts b/packages/twenty-front/src/modules/onboarding/hooks/useSetNextOnboardingStatus.ts new file mode 100644 index 000000000000..abc0a2b31810 --- /dev/null +++ b/packages/twenty-front/src/modules/onboarding/hooks/useSetNextOnboardingStatus.ts @@ -0,0 +1,50 @@ +import { useRecoilCallback, useRecoilValue } from 'recoil'; + +import { CurrentUser, currentUserState } from '@/auth/states/currentUserState'; +import { + CurrentWorkspace, + currentWorkspaceState, +} from '@/auth/states/currentWorkspaceState'; +import { OnboardingStatus } from '~/generated/graphql'; +import { isDefined } from '~/utils/isDefined'; + +const getNextOnboardingStatus = ( + currentUser: CurrentUser | null, + currentWorkspace: CurrentWorkspace | null, +) => { + if (currentUser?.onboardingStatus === OnboardingStatus.ProfileCreation) { + return OnboardingStatus.SyncEmail; + } + if ( + currentUser?.onboardingStatus === OnboardingStatus.SyncEmail && + currentWorkspace?.workspaceMembersCount === 1 + ) { + return OnboardingStatus.InviteTeam; + } + return OnboardingStatus.Completed; +}; + +export const useSetNextOnboardingStatus = () => { + const currentUser = useRecoilValue(currentUserState); + const currentWorkspace = useRecoilValue(currentWorkspaceState); + + return useRecoilCallback( + ({ set }) => + () => { + const nextOnboardingStatus = getNextOnboardingStatus( + currentUser, + currentWorkspace, + ); + set(currentUserState, (current) => { + if (isDefined(current)) { + return { + ...current, + onboardingStatus: nextOnboardingStatus, + }; + } + return current; + }); + }, + [currentWorkspace, currentUser], + ); +}; diff --git a/packages/twenty-front/src/modules/onboarding/hooks/useSetNextOnboardingStep.ts b/packages/twenty-front/src/modules/onboarding/hooks/useSetNextOnboardingStep.ts deleted file mode 100644 index 42acf8feb0ac..000000000000 --- a/packages/twenty-front/src/modules/onboarding/hooks/useSetNextOnboardingStep.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { useRecoilCallback, useSetRecoilState } from 'recoil'; - -import { currentUserState } from '@/auth/states/currentUserState'; -import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; -import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; -import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember'; -import { OnboardingStep } from '~/generated/graphql'; - -const getNextOnboardingStep = ( - currentOnboardingStep: OnboardingStep, - workspaceMembers: WorkspaceMember[], -) => { - if (currentOnboardingStep === OnboardingStep.SyncEmail) { - return workspaceMembers && workspaceMembers.length > 1 - ? null - : OnboardingStep.InviteTeam; - } - return null; -}; - -export const useSetNextOnboardingStep = () => { - const setCurrentUser = useSetRecoilState(currentUserState); - const { records: workspaceMembers } = useFindManyRecords<WorkspaceMember>({ - objectNameSingular: CoreObjectNameSingular.WorkspaceMember, - }); - return useRecoilCallback( - () => (currentOnboardingStep: OnboardingStep) => { - setCurrentUser( - (current) => - ({ - ...current, - onboardingStep: getNextOnboardingStep( - currentOnboardingStep, - workspaceMembers, - ), - }) as any, - ); - }, - [setCurrentUser, workspaceMembers], - ); -}; diff --git a/packages/twenty-front/src/modules/search/hooks/__mocks__/useFilteredSearchEntityQuery.ts b/packages/twenty-front/src/modules/search/hooks/__mocks__/useFilteredSearchEntityQuery.ts index d8a0481242c5..34aaee597da5 100644 --- a/packages/twenty-front/src/modules/search/hooks/__mocks__/useFilteredSearchEntityQuery.ts +++ b/packages/twenty-front/src/modules/search/hooks/__mocks__/useFilteredSearchEntityQuery.ts @@ -3,7 +3,7 @@ import { gql } from '@apollo/client'; export const query = gql` query FindManyPeople( $filter: PersonFilterInput - $orderBy: PersonOrderByInput + $orderBy: [PersonOrderByInput] $lastCursor: String $limit: Int = 60 ) { @@ -25,7 +25,6 @@ export const query = gql` updatedAt companyId stage - probability closeDate amount { amountMicros @@ -50,7 +49,6 @@ export const query = gql` updatedAt companyId stage - probability closeDate amount { amountMicros @@ -78,7 +76,9 @@ export const query = gql` currencyCode } createdAt - address + address { + adressCity + } updatedAt name accountOwnerId @@ -166,7 +166,7 @@ export const variables = { { not: { id: { in: ['1', '2'] } } }, ], }, - orderBy: { name: 'AscNullsLast' }, + orderBy: [{ name: 'AscNullsLast' }], }, filteredSelectedEntities: { limit: 60, @@ -176,12 +176,12 @@ export const variables = { { id: { in: ['1'] } }, ], }, - orderBy: { name: 'AscNullsLast' }, + orderBy: [{ name: 'AscNullsLast' }], }, selectedEntities: { limit: 60, filter: { id: { in: ['1'] } }, - orderBy: { name: 'AscNullsLast' }, + orderBy: [{ name: 'AscNullsLast' }], }, }; diff --git a/packages/twenty-front/src/modules/search/hooks/useFilteredSearchEntityQuery.ts b/packages/twenty-front/src/modules/search/hooks/useFilteredSearchEntityQuery.ts index b4d337c007a8..d43468a3ff37 100644 --- a/packages/twenty-front/src/modules/search/hooks/useFilteredSearchEntityQuery.ts +++ b/packages/twenty-front/src/modules/search/hooks/useFilteredSearchEntityQuery.ts @@ -49,7 +49,7 @@ export const useFilteredSearchEntityQuery = ({ useFindManyRecords({ objectNameSingular, filter: selectedIdsFilter, - orderBy: { [orderByField]: sortOrder }, + orderBy: [{ [orderByField]: sortOrder }], skip: !selectedIds.length, }); @@ -93,7 +93,7 @@ export const useFilteredSearchEntityQuery = ({ } = useFindManyRecords({ objectNameSingular, filter: makeAndFilterVariables([...searchFilters, selectedIdsFilter]), - orderBy: { [orderByField]: sortOrder }, + orderBy: [{ [orderByField]: sortOrder }], skip: !selectedIds.length, }); @@ -106,7 +106,7 @@ export const useFilteredSearchEntityQuery = ({ objectNameSingular, filter: makeAndFilterVariables([...searchFilters, notFilter]), limit: limit ?? DEFAULT_SEARCH_REQUEST_LIMIT, - orderBy: { [orderByField]: sortOrder }, + orderBy: [{ [orderByField]: sortOrder }], }); return { diff --git a/packages/twenty-front/src/modules/search/queries/getTextToSQL.ts b/packages/twenty-front/src/modules/search/queries/getTextToSQL.ts new file mode 100644 index 000000000000..6758209824b6 --- /dev/null +++ b/packages/twenty-front/src/modules/search/queries/getTextToSQL.ts @@ -0,0 +1,11 @@ +import { gql } from '@apollo/client'; + +export const getCopilot = gql` + query GetAISQLQuery($text: String!) { + getAISQLQuery(text: $text) { + sqlQuery + sqlQueryResult + queryFailedErrorMessage + } + } +`; diff --git a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsEmailsBlocklistInput.tsx b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsBlocklistInput.tsx similarity index 94% rename from packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsEmailsBlocklistInput.tsx rename to packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsBlocklistInput.tsx index 1794eb1d42bf..9bb4fdd98ce5 100644 --- a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsEmailsBlocklistInput.tsx +++ b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsBlocklistInput.tsx @@ -19,7 +19,7 @@ const StyledLinkContainer = styled.div` margin-right: ${({ theme }) => theme.spacing(2)}; `; -type SettingsAccountsEmailsBlocklistInputProps = { +type SettingsAccountsBlocklistInputProps = { updateBlockedEmailList: (email: string) => void; blockedEmailOrDomainList: string[]; }; @@ -50,10 +50,10 @@ type FormInput = { emailOrDomain: string; }; -export const SettingsAccountsEmailsBlocklistInput = ({ +export const SettingsAccountsBlocklistInput = ({ updateBlockedEmailList, blockedEmailOrDomainList, -}: SettingsAccountsEmailsBlocklistInputProps) => { +}: SettingsAccountsBlocklistInputProps) => { const { reset, handleSubmit, control, formState } = useForm<FormInput>({ mode: 'onSubmit', resolver: zodResolver(validationSchema(blockedEmailOrDomainList)), diff --git a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsEmailsBlocklistSection.tsx b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsBlocklistSection.tsx similarity index 81% rename from packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsEmailsBlocklistSection.tsx rename to packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsBlocklistSection.tsx index 39b789fae57a..51ff642b1b35 100644 --- a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsEmailsBlocklistSection.tsx +++ b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsBlocklistSection.tsx @@ -7,11 +7,11 @@ import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSi import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord'; import { useDeleteOneRecord } from '@/object-record/hooks/useDeleteOneRecord'; import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; -import { SettingsAccountsEmailsBlocklistInput } from '@/settings/accounts/components/SettingsAccountsEmailsBlocklistInput'; -import { SettingsAccountsEmailsBlocklistTable } from '@/settings/accounts/components/SettingsAccountsEmailsBlocklistTable'; +import { SettingsAccountsBlocklistInput } from '@/settings/accounts/components/SettingsAccountsBlocklistInput'; +import { SettingsAccountsBlocklistTable } from '@/settings/accounts/components/SettingsAccountsBlocklistTable'; import { Section } from '@/ui/layout/section/components/Section'; -export const SettingsAccountsEmailsBlocklistSection = () => { +export const SettingsAccountsBlocklistSection = () => { const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState); const { records: blocklist } = useFindManyRecords<BlocklistItem>({ @@ -44,11 +44,11 @@ export const SettingsAccountsEmailsBlocklistSection = () => { title="Blocklist" description="Exclude the following people and domains from my email sync" /> - <SettingsAccountsEmailsBlocklistInput + <SettingsAccountsBlocklistInput blockedEmailOrDomainList={blocklist.map((item) => item.handle)} updateBlockedEmailList={updateBlockedEmailList} /> - <SettingsAccountsEmailsBlocklistTable + <SettingsAccountsBlocklistTable blocklist={blocklist} handleBlockedEmailRemove={handleBlockedEmailRemove} /> diff --git a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsEmailsBlocklistTable.tsx b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsBlocklistTable.tsx similarity index 79% rename from packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsEmailsBlocklistTable.tsx rename to packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsBlocklistTable.tsx index a238ef6e5e03..a4c9f5306fad 100644 --- a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsEmailsBlocklistTable.tsx +++ b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsBlocklistTable.tsx @@ -1,13 +1,13 @@ import styled from '@emotion/styled'; import { BlocklistItem } from '@/accounts/types/BlocklistItem'; -import { SettingsAccountsEmailsBlocklistTableRow } from '@/settings/accounts/components/SettingsAccountsEmailsBlocklistTableRow'; +import { SettingsAccountsBlocklistTableRow } from '@/settings/accounts/components/SettingsAccountsBlocklistTableRow'; import { Table } from '@/ui/layout/table/components/Table'; import { TableBody } from '@/ui/layout/table/components/TableBody'; import { TableHeader } from '@/ui/layout/table/components/TableHeader'; import { TableRow } from '@/ui/layout/table/components/TableRow'; -type SettingsAccountsEmailsBlocklistTableProps = { +type SettingsAccountsBlocklistTableProps = { blocklist: BlocklistItem[]; handleBlockedEmailRemove: (id: string) => void; }; @@ -20,10 +20,10 @@ const StyledTableBody = styled(TableBody)` border-bottom: 1px solid ${({ theme }) => theme.border.color.light}; `; -export const SettingsAccountsEmailsBlocklistTable = ({ +export const SettingsAccountsBlocklistTable = ({ blocklist, handleBlockedEmailRemove, -}: SettingsAccountsEmailsBlocklistTableProps) => { +}: SettingsAccountsBlocklistTableProps) => { return ( <> {blocklist.length > 0 && ( @@ -35,7 +35,7 @@ export const SettingsAccountsEmailsBlocklistTable = ({ </TableRow> <StyledTableBody> {blocklist.map((blocklistItem) => ( - <SettingsAccountsEmailsBlocklistTableRow + <SettingsAccountsBlocklistTableRow key={blocklistItem.id} blocklistItem={blocklistItem} onRemove={handleBlockedEmailRemove} diff --git a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsEmailsBlocklistTableRow.tsx b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsBlocklistTableRow.tsx similarity index 85% rename from packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsEmailsBlocklistTableRow.tsx rename to packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsBlocklistTableRow.tsx index a09a092ed234..9a1148447a17 100644 --- a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsEmailsBlocklistTableRow.tsx +++ b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsBlocklistTableRow.tsx @@ -6,15 +6,15 @@ import { TableCell } from '@/ui/layout/table/components/TableCell'; import { TableRow } from '@/ui/layout/table/components/TableRow'; import { formatToHumanReadableDate } from '~/utils/date-utils'; -type SettingsAccountsEmailsBlocklistTableRowProps = { +type SettingsAccountsBlocklistTableRowProps = { blocklistItem: BlocklistItem; onRemove: (id: string) => void; }; -export const SettingsAccountsEmailsBlocklistTableRow = ({ +export const SettingsAccountsBlocklistTableRow = ({ blocklistItem, onRemove, -}: SettingsAccountsEmailsBlocklistTableRowProps) => { +}: SettingsAccountsBlocklistTableRowProps) => { return ( <TableRow key={blocklistItem.id}> <TableCell>{blocklistItem.handle}</TableCell> diff --git a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarChannelDetails.tsx b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarChannelDetails.tsx new file mode 100644 index 000000000000..3955904289ab --- /dev/null +++ b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarChannelDetails.tsx @@ -0,0 +1,79 @@ +import { CalendarChannel } from '@/accounts/types/CalendarChannel'; +import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; +import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord'; +import { SettingsAccountsEventVisibilitySettingsCard } from '@/settings/accounts/components/SettingsAccountsCalendarVisibilitySettingsCard'; +import { SettingsAccountsToggleSettingCard } from '@/settings/accounts/components/SettingsAccountsToggleSettingCard'; +import styled from '@emotion/styled'; +import { Section } from '@react-email/components'; +import { H2Title } from 'twenty-ui'; +import { CalendarChannelVisibility } from '~/generated-metadata/graphql'; + +const StyledDetailsContainer = styled.div` + display: flex; + flex-direction: column; + gap: ${({ theme }) => theme.spacing(6)}; +`; + +type SettingsAccountsCalendarChannelDetailsProps = { + calendarChannel: Pick< + CalendarChannel, + 'id' | 'visibility' | 'isContactAutoCreationEnabled' | 'isSyncEnabled' + >; +}; + +export const SettingsAccountsCalendarChannelDetails = ({ + calendarChannel, +}: SettingsAccountsCalendarChannelDetailsProps) => { + const { updateOneRecord } = useUpdateOneRecord<CalendarChannel>({ + objectNameSingular: CoreObjectNameSingular.CalendarChannel, + }); + + const handleVisibilityChange = (value: CalendarChannelVisibility) => { + updateOneRecord({ + idToUpdate: calendarChannel.id, + updateOneRecordInput: { + visibility: value, + }, + }); + }; + + const handleContactAutoCreationToggle = (value: boolean) => { + updateOneRecord({ + idToUpdate: calendarChannel.id, + updateOneRecordInput: { + isContactAutoCreationEnabled: value, + }, + }); + }; + + return ( + <StyledDetailsContainer> + <Section> + <H2Title + title="Event visibility" + description="Define what will be visible to other users in your workspace" + /> + <SettingsAccountsEventVisibilitySettingsCard + value={calendarChannel.visibility} + onChange={handleVisibilityChange} + /> + </Section> + <Section> + <H2Title + title="Contact auto-creation" + description="Automatically create contacts for people you've participated in an event with." + /> + <SettingsAccountsToggleSettingCard + parameters={[ + { + value: !!calendarChannel.isContactAutoCreationEnabled, + title: 'Auto-creation', + description: 'Automatically create contacts for people.', + onToggle: handleContactAutoCreationToggle, + }, + ]} + /> + </Section> + </StyledDetailsContainer> + ); +}; diff --git a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarChannelsContainer.tsx b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarChannelsContainer.tsx new file mode 100644 index 000000000000..10e7017d501d --- /dev/null +++ b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarChannelsContainer.tsx @@ -0,0 +1,85 @@ +import styled from '@emotion/styled'; +import { useRecoilValue } from 'recoil'; + +import { CalendarChannel } from '@/accounts/types/CalendarChannel'; +import { ConnectedAccount } from '@/accounts/types/ConnectedAccount'; +import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; +import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; +import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; +import { SettingsAccountsCalendarChannelDetails } from '@/settings/accounts/components/SettingsAccountsCalendarChannelDetails'; +import { SettingsAccountsCalendarChannelsGeneral } from '@/settings/accounts/components/SettingsAccountsCalendarChannelsGeneral'; +import { SettingsAccountsListEmptyStateCard } from '@/settings/accounts/components/SettingsAccountsListEmptyStateCard'; +import { SETTINGS_ACCOUNT_CALENDAR_CHANNELS_TAB_LIST_COMPONENT_ID } from '@/settings/accounts/constants/SettingsAccountCalendarChannelsTabListComponentId'; +import { TabList } from '@/ui/layout/tab/components/TabList'; +import { useTabList } from '@/ui/layout/tab/hooks/useTabList'; +import React from 'react'; + +const StyledCalenderContainer = styled.div` + padding-bottom: ${({ theme }) => theme.spacing(6)}; +`; + +export const SettingsAccountsCalendarChannelsContainer = () => { + const { activeTabIdState } = useTabList( + SETTINGS_ACCOUNT_CALENDAR_CHANNELS_TAB_LIST_COMPONENT_ID, + ); + const activeTabId = useRecoilValue(activeTabIdState); + const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState); + + const { records: accounts } = useFindManyRecords<ConnectedAccount>({ + objectNameSingular: CoreObjectNameSingular.ConnectedAccount, + filter: { + accountOwnerId: { + eq: currentWorkspaceMember?.id, + }, + }, + }); + + const { records: calendarChannels } = useFindManyRecords< + CalendarChannel & { + connectedAccount: ConnectedAccount; + } + >({ + objectNameSingular: CoreObjectNameSingular.CalendarChannel, + filter: { + connectedAccountId: { + in: accounts.map((account) => account.id), + }, + }, + }); + + const tabs = [ + ...calendarChannels.map((calendarChannel) => ({ + id: calendarChannel.id, + title: calendarChannel.handle, + })), + ]; + + if (!calendarChannels.length) { + return <SettingsAccountsListEmptyStateCard />; + } + + return ( + <> + {tabs.length > 1 && ( + <StyledCalenderContainer> + <TabList + tabListId={SETTINGS_ACCOUNT_CALENDAR_CHANNELS_TAB_LIST_COMPONENT_ID} + tabs={tabs} + /> + </StyledCalenderContainer> + )} + {calendarChannels.map((calendarChannel) => ( + <React.Fragment key={calendarChannel.id}> + {calendarChannel.id === activeTabId && ( + <SettingsAccountsCalendarChannelDetails + calendarChannel={calendarChannel} + /> + )} + </React.Fragment> + ))} + {false && activeTabId === 'general' && ( + <SettingsAccountsCalendarChannelsGeneral /> + )} + </> + ); +}; diff --git a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarChannelsGeneral.tsx b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarChannelsGeneral.tsx new file mode 100644 index 000000000000..14ffba7842a9 --- /dev/null +++ b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarChannelsGeneral.tsx @@ -0,0 +1,93 @@ +import { CalendarMonthCard } from '@/activities/calendar/components/CalendarMonthCard'; +import { CalendarContext } from '@/activities/calendar/contexts/CalendarContext'; +import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; +import { SettingsAccountsCalendarDisplaySettings } from '@/settings/accounts/components/SettingsAccountsCalendarDisplaySettings'; +import styled from '@emotion/styled'; +import { Section } from '@react-email/components'; +import { addMinutes, endOfDay, min, startOfDay } from 'date-fns'; +import { useRecoilValue } from 'recoil'; +import { H2Title } from 'twenty-ui'; +import { + CalendarChannelVisibility, + TimelineCalendarEvent, +} from '~/generated-metadata/graphql'; + +const StyledGeneralContainer = styled.div` + display: flex; + flex-direction: column; + gap: ${({ theme }) => theme.spacing(6)}; + padding-top: ${({ theme }) => theme.spacing(6)}; +`; + +export const SettingsAccountsCalendarChannelsGeneral = () => { + const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState); + + const exampleStartDate = new Date(); + const exampleEndDate = min([ + addMinutes(exampleStartDate, 30), + endOfDay(exampleStartDate), + ]); + const exampleDayTime = startOfDay(exampleStartDate).getTime(); + const exampleCalendarEvent: TimelineCalendarEvent = { + id: '', + participants: [ + { + firstName: currentWorkspaceMember?.name.firstName || '', + lastName: currentWorkspaceMember?.name.lastName || '', + displayName: currentWorkspaceMember + ? [ + currentWorkspaceMember.name.firstName, + currentWorkspaceMember.name.lastName, + ].join(' ') + : '', + avatarUrl: currentWorkspaceMember?.avatarUrl || '', + handle: '', + personId: '', + workspaceMemberId: currentWorkspaceMember?.id || '', + }, + ], + endsAt: exampleEndDate.toISOString(), + isFullDay: false, + startsAt: exampleStartDate.toISOString(), + conferenceSolution: '', + conferenceLink: { + label: '', + url: '', + }, + description: '', + isCanceled: false, + location: '', + title: 'Onboarding call', + visibility: CalendarChannelVisibility.ShareEverything, + }; + + return ( + <StyledGeneralContainer> + <Section> + <H2Title + title="Display" + description="Configure how we should display your events in your calendar" + /> + <SettingsAccountsCalendarDisplaySettings /> + </Section> + <Section> + <H2Title + title="Color code" + description="Events you participated in are displayed in red." + /> + <CalendarContext.Provider + value={{ + currentCalendarEvent: exampleCalendarEvent, + calendarEventsByDayTime: { + [exampleDayTime]: [exampleCalendarEvent], + }, + getNextCalendarEvent: () => undefined, + updateCurrentCalendarEvent: () => {}, + }} + > + <CalendarMonthCard dayTimes={[exampleDayTime]} /> + </CalendarContext.Provider> + </Section> + </StyledGeneralContainer> + ); +}; diff --git a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarChannelsListCard.tsx b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarChannelsListCard.tsx deleted file mode 100644 index e00f32398c76..000000000000 --- a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarChannelsListCard.tsx +++ /dev/null @@ -1,95 +0,0 @@ -import { useNavigate } from 'react-router-dom'; -import styled from '@emotion/styled'; -import { useRecoilValue } from 'recoil'; -import { IconChevronRight, IconGoogleCalendar } from 'twenty-ui'; - -import { CalendarChannel } from '@/accounts/types/CalendarChannel'; -import { ConnectedAccount } from '@/accounts/types/ConnectedAccount'; -import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; -import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; -import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; -import { generateDepthOneRecordGqlFields } from '@/object-record/graphql/utils/generateDepthOneRecordGqlFields'; -import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; -import { SettingsAccountsListEmptyStateCard } from '@/settings/accounts/components/SettingsAccountsListEmptyStateCard'; -import { - SettingsAccountsSynchronizationStatus, - SettingsAccountsSynchronizationStatusProps, -} from '@/settings/accounts/components/SettingsAccountsSynchronizationStatus'; -import { SettingsListCard } from '@/settings/components/SettingsListCard'; -import { LightIconButton } from '@/ui/input/button/components/LightIconButton'; - -const StyledRowRightContainer = styled.div` - align-items: center; - display: flex; - gap: ${({ theme }) => theme.spacing(1)}; -`; - -export const SettingsAccountsCalendarChannelsListCard = () => { - const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState); - const navigate = useNavigate(); - const { objectMetadataItem } = useObjectMetadataItem({ - objectNameSingular: CoreObjectNameSingular.CalendarChannel, - }); - - const { records: accounts, loading: accountsLoading } = - useFindManyRecords<ConnectedAccount>({ - objectNameSingular: CoreObjectNameSingular.ConnectedAccount, - filter: { - accountOwnerId: { - eq: currentWorkspaceMember?.id, - }, - }, - }); - - const { records: calendarChannels, loading: calendarChannelsLoading } = - useFindManyRecords< - CalendarChannel & { - connectedAccount: ConnectedAccount; - } - >({ - objectNameSingular: CoreObjectNameSingular.CalendarChannel, - skip: !accounts.length, - filter: { - connectedAccountId: { - in: accounts.map((account) => account.id), - }, - }, - recordGqlFields: generateDepthOneRecordGqlFields({ objectMetadataItem }), - }); - - if (!calendarChannels.length) { - return <SettingsAccountsListEmptyStateCard />; - } - - const calendarChannelsWithSyncStatus: (CalendarChannel & { - connectedAccount: ConnectedAccount; - } & SettingsAccountsSynchronizationStatusProps)[] = calendarChannels.map( - (calendarChannel) => ({ - ...calendarChannel, - syncStatus: calendarChannel.connectedAccount?.authFailedAt - ? 'FAILED' - : 'SUCCEEDED', - }), - ); - - return ( - <SettingsListCard - items={calendarChannelsWithSyncStatus} - getItemLabel={(calendarChannel) => calendarChannel.handle} - isLoading={accountsLoading || calendarChannelsLoading} - onRowClick={(calendarChannel) => - navigate(`/settings/accounts/calendars/${calendarChannel.id}`) - } - RowIcon={IconGoogleCalendar} - RowRightComponent={({ item: calendarChannel }) => ( - <StyledRowRightContainer> - <SettingsAccountsSynchronizationStatus - syncStatus={calendarChannel.syncStatus} - isSyncEnabled={calendarChannel.isSyncEnabled} - /> - <LightIconButton Icon={IconChevronRight} accent="tertiary" /> - </StyledRowRightContainer> - )} - /> - ); -}; diff --git a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarVisibilitySettingsCard.tsx b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarVisibilitySettingsCard.tsx index b1a26e3ca493..20344671bb85 100644 --- a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarVisibilitySettingsCard.tsx +++ b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarVisibilitySettingsCard.tsx @@ -1,7 +1,7 @@ import styled from '@emotion/styled'; import { SettingsAccountsRadioSettingsCard } from '@/settings/accounts/components/SettingsAccountsRadioSettingsCard'; -import { SettingsAccountsVisibilitySettingCardMedia } from '@/settings/accounts/components/SettingsAccountsVisibilitySettingCardMedia'; +import { SettingsAccountsVisibilityIcon } from '@/settings/accounts/components/SettingsAccountsVisibilityIcon'; import { CalendarChannelVisibility } from '~/generated/graphql'; type SettingsAccountsEventVisibilitySettingsCardProps = { @@ -9,7 +9,7 @@ type SettingsAccountsEventVisibilitySettingsCardProps = { value?: CalendarChannelVisibility; }; -const StyledCardMedia = styled(SettingsAccountsVisibilitySettingCardMedia)` +const StyledCardMedia = styled(SettingsAccountsVisibilityIcon)` height: ${({ theme }) => theme.spacing(6)}; `; @@ -33,6 +33,7 @@ export const SettingsAccountsEventVisibilitySettingsCard = ({ value = CalendarChannelVisibility.ShareEverything, }: SettingsAccountsEventVisibilitySettingsCardProps) => ( <SettingsAccountsRadioSettingsCard + name="event-visibility" options={eventSettingsVisibilityOptions} value={value} onChange={onChange} diff --git a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsMessageAutoCreationCard.tsx b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsMessageAutoCreationCard.tsx new file mode 100644 index 000000000000..ea01199a02e4 --- /dev/null +++ b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsMessageAutoCreationCard.tsx @@ -0,0 +1,48 @@ +import { MessageChannelContactAutoCreationPolicy } from '@/accounts/types/MessageChannel'; +import { SettingsAccountsMessageAutoCreationIcon } from '@/settings/accounts/components/SettingsAccountsMessageAutoCreationIcon'; +import { SettingsAccountsRadioSettingsCard } from '@/settings/accounts/components/SettingsAccountsRadioSettingsCard'; + +type SettingsAccountsMessageAutoCreationCardProps = { + onChange: (nextValue: MessageChannelContactAutoCreationPolicy) => void; + value?: MessageChannelContactAutoCreationPolicy; +}; + +const autoCreationOptions = [ + { + title: 'Send and Received', + description: 'People I’ve sent emails to and received emails from.', + value: MessageChannelContactAutoCreationPolicy.SENT_AND_RECEIVED, + cardMedia: ( + <SettingsAccountsMessageAutoCreationIcon isSentActive isReceivedActive /> + ), + }, + { + title: 'Sent', + description: 'People I’ve sent emails to.', + value: MessageChannelContactAutoCreationPolicy.SENT, + cardMedia: <SettingsAccountsMessageAutoCreationIcon isSentActive />, + }, + { + title: 'None', + description: 'Don’t auto-create contacts.', + value: MessageChannelContactAutoCreationPolicy.NONE, + cardMedia: ( + <SettingsAccountsMessageAutoCreationIcon + isSentActive={false} + isReceivedActive={false} + /> + ), + }, +]; + +export const SettingsAccountsMessageAutoCreationCard = ({ + onChange, + value = MessageChannelContactAutoCreationPolicy.SENT_AND_RECEIVED, +}: SettingsAccountsMessageAutoCreationCardProps) => ( + <SettingsAccountsRadioSettingsCard + name="message-auto-creation" + options={autoCreationOptions} + value={value} + onChange={onChange} + /> +); diff --git a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsMessageAutoCreationIcon.tsx b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsMessageAutoCreationIcon.tsx new file mode 100644 index 000000000000..d628f347c9d6 --- /dev/null +++ b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsMessageAutoCreationIcon.tsx @@ -0,0 +1,31 @@ +import styled from '@emotion/styled'; + +import { SettingsAccountsCardMedia } from '@/settings/accounts/components/SettingsAccountsCardMedia'; + +type SettingsAccountsMessageAutoCreationIconProps = { + className?: string; + isSentActive?: boolean; + isReceivedActive?: boolean; +}; + +const StyledIconContainer = styled(SettingsAccountsCardMedia)` + align-items: stretch; +`; + +const StyledDirectionSkeleton = styled.div<{ isActive?: boolean }>` + background-color: ${({ isActive, theme }) => + isActive ? theme.accent.accent4060 : theme.background.quaternary}; + border-radius: 1px; + height: 24px; +`; + +export const SettingsAccountsMessageAutoCreationIcon = ({ + className, + isSentActive, + isReceivedActive, +}: SettingsAccountsMessageAutoCreationIconProps) => ( + <StyledIconContainer className={className}> + <StyledDirectionSkeleton isActive={isSentActive} /> + <StyledDirectionSkeleton isActive={isReceivedActive} /> + </StyledIconContainer> +); diff --git a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsMessageChannelDetails.tsx b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsMessageChannelDetails.tsx new file mode 100644 index 000000000000..930d749abd39 --- /dev/null +++ b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsMessageChannelDetails.tsx @@ -0,0 +1,121 @@ +import styled from '@emotion/styled'; +import { H2Title } from 'twenty-ui'; + +import { + MessageChannel, + MessageChannelContactAutoCreationPolicy, +} from '@/accounts/types/MessageChannel'; +import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; +import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord'; +import { SettingsAccountsMessageAutoCreationCard } from '@/settings/accounts/components/SettingsAccountsMessageAutoCreationCard'; +import { SettingsAccountsMessageVisibilityCard } from '@/settings/accounts/components/SettingsAccountsMessageVisibilityCard'; +import { SettingsAccountsToggleSettingCard } from '@/settings/accounts/components/SettingsAccountsToggleSettingCard'; +import { Section } from '@/ui/layout/section/components/Section'; +import { MessageChannelVisibility } from '~/generated-metadata/graphql'; + +type SettingsAccountsMessageChannelDetailsProps = { + messageChannel: Pick< + MessageChannel, + | 'id' + | 'visibility' + | 'contactAutoCreationPolicy' + | 'excludeNonProfessionalEmails' + | 'excludeGroupEmails' + | 'isSyncEnabled' + >; +}; + +const StyledDetailsContainer = styled.div` + display: flex; + flex-direction: column; + gap: ${({ theme }) => theme.spacing(6)}; +`; + +export const SettingsAccountsMessageChannelDetails = ({ + messageChannel, +}: SettingsAccountsMessageChannelDetailsProps) => { + const { updateOneRecord } = useUpdateOneRecord<MessageChannel>({ + objectNameSingular: CoreObjectNameSingular.MessageChannel, + }); + + const handleVisibilityChange = (value: MessageChannelVisibility) => { + updateOneRecord({ + idToUpdate: messageChannel.id, + updateOneRecordInput: { + visibility: value, + }, + }); + }; + + const handleContactAutoCreationChange = ( + value: MessageChannelContactAutoCreationPolicy, + ) => { + updateOneRecord({ + idToUpdate: messageChannel.id, + updateOneRecordInput: { + contactAutoCreationPolicy: value, + }, + }); + }; + + const handleIsGroupEmailExcludedToggle = (value: boolean) => { + updateOneRecord({ + idToUpdate: messageChannel.id, + updateOneRecordInput: { + excludeGroupEmails: value, + }, + }); + }; + + const handleIsNonProfessionalEmailExcludedToggle = (value: boolean) => { + updateOneRecord({ + idToUpdate: messageChannel.id, + updateOneRecordInput: { + excludeNonProfessionalEmails: value, + }, + }); + }; + + return ( + <StyledDetailsContainer> + <Section> + <H2Title + title="Visibility" + description="Define what will be visible to other users in your workspace" + /> + <SettingsAccountsMessageVisibilityCard + value={messageChannel.visibility} + onChange={handleVisibilityChange} + /> + </Section> + <Section> + <H2Title + title="Contact auto-creation" + description="Automatically create People records when receiving or sending emails" + /> + <SettingsAccountsMessageAutoCreationCard + value={messageChannel.contactAutoCreationPolicy} + onChange={handleContactAutoCreationChange} + /> + </Section> + <Section> + <SettingsAccountsToggleSettingCard + parameters={[ + { + title: 'Exclude non-professional emails', + description: 'Don’t sync emails from/to Gmail, Outlook...', + value: !!messageChannel.excludeNonProfessionalEmails, + onToggle: handleIsNonProfessionalEmailExcludedToggle, + }, + { + title: 'Exclude group emails', + description: 'Don’t sync emails from team@ support@ noreply@...', + value: !!messageChannel.excludeGroupEmails, + onToggle: handleIsGroupEmailExcludedToggle, + }, + ]} + /> + </Section> + </StyledDetailsContainer> + ); +}; diff --git a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsMessageChannelsContainer.tsx b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsMessageChannelsContainer.tsx new file mode 100644 index 000000000000..24a5f62fa1b0 --- /dev/null +++ b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsMessageChannelsContainer.tsx @@ -0,0 +1,81 @@ +import styled from '@emotion/styled'; +import { useRecoilValue } from 'recoil'; + +import { ConnectedAccount } from '@/accounts/types/ConnectedAccount'; +import { MessageChannel } from '@/accounts/types/MessageChannel'; +import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; +import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; +import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; +import { SettingsAccountsListEmptyStateCard } from '@/settings/accounts/components/SettingsAccountsListEmptyStateCard'; +import { SettingsAccountsMessageChannelDetails } from '@/settings/accounts/components/SettingsAccountsMessageChannelDetails'; +import { SETTINGS_ACCOUNT_MESSAGE_CHANNELS_TAB_LIST_COMPONENT_ID } from '@/settings/accounts/constants/SettingsAccountMessageChannelsTabListComponentId'; +import { TabList } from '@/ui/layout/tab/components/TabList'; +import { useTabList } from '@/ui/layout/tab/hooks/useTabList'; +import React from 'react'; + +const StyledMessageContainer = styled.div` + padding-bottom: ${({ theme }) => theme.spacing(6)}; +`; + +export const SettingsAccountsMessageChannelsContainer = () => { + const { activeTabIdState } = useTabList( + SETTINGS_ACCOUNT_MESSAGE_CHANNELS_TAB_LIST_COMPONENT_ID, + ); + const activeTabId = useRecoilValue(activeTabIdState); + const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState); + + const { records: accounts } = useFindManyRecords<ConnectedAccount>({ + objectNameSingular: CoreObjectNameSingular.ConnectedAccount, + filter: { + accountOwnerId: { + eq: currentWorkspaceMember?.id, + }, + }, + }); + + const { records: messageChannels } = useFindManyRecords< + MessageChannel & { + connectedAccount: ConnectedAccount; + } + >({ + objectNameSingular: CoreObjectNameSingular.MessageChannel, + filter: { + connectedAccountId: { + in: accounts.map((account) => account.id), + }, + }, + }); + + const tabs = [ + ...messageChannels.map((messageChannel) => ({ + id: messageChannel.id, + title: messageChannel.handle, + })), + ]; + + if (!messageChannels.length) { + return <SettingsAccountsListEmptyStateCard />; + } + + return ( + <> + {tabs.length > 1 && ( + <StyledMessageContainer> + <TabList + tabListId={SETTINGS_ACCOUNT_MESSAGE_CHANNELS_TAB_LIST_COMPONENT_ID} + tabs={tabs} + /> + </StyledMessageContainer> + )} + {messageChannels.map((messageChannel) => ( + <React.Fragment key={messageChannel.id}> + {messageChannel.id === activeTabId && ( + <SettingsAccountsMessageChannelDetails + messageChannel={messageChannel} + /> + )} + </React.Fragment> + ))} + </> + ); +}; diff --git a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsMessageChannelsListCard.tsx b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsMessageChannelsListCard.tsx deleted file mode 100644 index addc376b4d12..000000000000 --- a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsMessageChannelsListCard.tsx +++ /dev/null @@ -1,86 +0,0 @@ -import { useNavigate } from 'react-router-dom'; -import styled from '@emotion/styled'; -import { useRecoilValue } from 'recoil'; -import { IconChevronRight, IconGmail } from 'twenty-ui'; - -import { ConnectedAccount } from '@/accounts/types/ConnectedAccount'; -import { MessageChannel } from '@/accounts/types/MessageChannel'; -import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; -import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; -import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; -import { SettingsAccountsListEmptyStateCard } from '@/settings/accounts/components/SettingsAccountsListEmptyStateCard'; -import { - SettingsAccountsSynchronizationStatus, - SettingsAccountsSynchronizationStatusProps, -} from '@/settings/accounts/components/SettingsAccountsSynchronizationStatus'; -import { SettingsListCard } from '@/settings/components/SettingsListCard'; -import { LightIconButton } from '@/ui/input/button/components/LightIconButton'; - -const StyledRowRightContainer = styled.div` - align-items: center; - display: flex; - gap: ${({ theme }) => theme.spacing(1)}; -`; - -export const SettingsAccountsMessageChannelsListCard = () => { - const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState); - const navigate = useNavigate(); - - const { records: accounts, loading: accountsLoading } = - useFindManyRecords<ConnectedAccount>({ - objectNameSingular: CoreObjectNameSingular.ConnectedAccount, - filter: { - accountOwnerId: { - eq: currentWorkspaceMember?.id, - }, - }, - }); - - const { records: messageChannels, loading: messageChannelsLoading } = - useFindManyRecords< - MessageChannel & { - connectedAccount: ConnectedAccount; - } - >({ - objectNameSingular: CoreObjectNameSingular.MessageChannel, - filter: { - connectedAccountId: { - in: accounts.map((account) => account.id), - }, - }, - }); - - const messageChannelsWithSyncedEmails: (MessageChannel & { - connectedAccount: ConnectedAccount; - } & SettingsAccountsSynchronizationStatusProps)[] = messageChannels.map( - (messageChannel) => ({ - ...messageChannel, - syncStatus: messageChannel.syncStatus, - }), - ); - - if (!messageChannelsWithSyncedEmails.length) { - return <SettingsAccountsListEmptyStateCard />; - } - - return ( - <SettingsListCard - items={messageChannelsWithSyncedEmails} - getItemLabel={(messageChannel) => messageChannel.handle} - isLoading={accountsLoading || messageChannelsLoading} - onRowClick={(messageChannel) => - navigate(`/settings/accounts/emails/${messageChannel.id}`) - } - RowIcon={IconGmail} - RowRightComponent={({ item: messageChannel }) => ( - <StyledRowRightContainer> - <SettingsAccountsSynchronizationStatus - syncStatus={messageChannel.syncStatus} - isSyncEnabled={messageChannel.isSyncEnabled} - /> - <LightIconButton Icon={IconChevronRight} accent="tertiary" /> - </StyledRowRightContainer> - )} - /> - ); -}; diff --git a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsInboxVisibilitySettingsCard.tsx b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsMessageVisibilityCard.tsx similarity index 74% rename from packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsInboxVisibilitySettingsCard.tsx rename to packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsMessageVisibilityCard.tsx index 9f9469f46d2c..e0aa3172fd00 100644 --- a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsInboxVisibilitySettingsCard.tsx +++ b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsMessageVisibilityCard.tsx @@ -1,8 +1,8 @@ import { SettingsAccountsRadioSettingsCard } from '@/settings/accounts/components/SettingsAccountsRadioSettingsCard'; -import { SettingsAccountsVisibilitySettingCardMedia } from '@/settings/accounts/components/SettingsAccountsVisibilitySettingCardMedia'; +import { SettingsAccountsVisibilityIcon } from '@/settings/accounts/components/SettingsAccountsVisibilityIcon'; import { MessageChannelVisibility } from '~/generated/graphql'; -type SettingsAccountsInboxVisibilitySettingsCardProps = { +type SettingsAccountsMessageVisibilityCardProps = { onChange: (nextValue: MessageChannelVisibility) => void; value?: MessageChannelVisibility; }; @@ -13,7 +13,7 @@ const inboxSettingsVisibilityOptions = [ description: 'Subject, body and attachments will be shared with your team.', value: MessageChannelVisibility.ShareEverything, cardMedia: ( - <SettingsAccountsVisibilitySettingCardMedia + <SettingsAccountsVisibilityIcon metadata="active" subject="active" body="active" @@ -25,7 +25,7 @@ const inboxSettingsVisibilityOptions = [ description: 'Subject and metadata will be shared with your team.', value: MessageChannelVisibility.Subject, cardMedia: ( - <SettingsAccountsVisibilitySettingCardMedia + <SettingsAccountsVisibilityIcon metadata="active" subject="active" body="inactive" @@ -37,7 +37,7 @@ const inboxSettingsVisibilityOptions = [ description: 'Timestamp and participants will be shared with your team.', value: MessageChannelVisibility.Metadata, cardMedia: ( - <SettingsAccountsVisibilitySettingCardMedia + <SettingsAccountsVisibilityIcon metadata="active" subject="inactive" body="inactive" @@ -46,11 +46,12 @@ const inboxSettingsVisibilityOptions = [ }, ]; -export const SettingsAccountsInboxVisibilitySettingsCard = ({ +export const SettingsAccountsMessageVisibilityCard = ({ onChange, value = MessageChannelVisibility.ShareEverything, -}: SettingsAccountsInboxVisibilitySettingsCardProps) => ( +}: SettingsAccountsMessageVisibilityCardProps) => ( <SettingsAccountsRadioSettingsCard + name="message-visibility" options={inboxSettingsVisibilityOptions} value={value} onChange={onChange} diff --git a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsRadioSettingsCard.tsx b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsRadioSettingsCard.tsx index 4592b42b4c2a..aaf856456fcf 100644 --- a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsRadioSettingsCard.tsx +++ b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsRadioSettingsCard.tsx @@ -1,5 +1,5 @@ -import { ReactNode } from 'react'; import styled from '@emotion/styled'; +import { ReactNode } from 'react'; import { Radio } from '@/ui/input/components/Radio'; import { Card } from '@/ui/layout/card/components/Card'; @@ -10,6 +10,7 @@ type SettingsAccountsRadioSettingsCardProps<Option extends { value: string }> = onChange: (nextValue: Option['value']) => void; options: Option[]; value: Option['value']; + name: string; }; const StyledCardContent = styled(CardContent)` @@ -49,6 +50,7 @@ export const SettingsAccountsRadioSettingsCard = < onChange, options, value, + name, }: SettingsAccountsRadioSettingsCardProps<Option>) => ( <Card rounded> {options.map((option, index) => ( @@ -63,6 +65,7 @@ export const SettingsAccountsRadioSettingsCard = < <StyledDescription>{option.description}</StyledDescription> </div> <StyledRadio + name={name} value={option.value} onCheckedChange={() => onChange(option.value)} checked={value === option.value} diff --git a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsRowDropdownMenu.tsx b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsRowDropdownMenu.tsx index 8e5afcec6125..515dce50a610 100644 --- a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsRowDropdownMenu.tsx +++ b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsRowDropdownMenu.tsx @@ -54,9 +54,7 @@ export const SettingsAccountsRowDropdownMenu = ({ LeftIcon={IconMail} text="Emails settings" onClick={() => { - navigate( - `/settings/accounts/emails/${account.messageChannels[0].id}`, - ); + navigate(`/settings/accounts/emails`); closeDropdown(); }} /> @@ -64,9 +62,7 @@ export const SettingsAccountsRowDropdownMenu = ({ LeftIcon={IconCalendarEvent} text="Calendar settings" onClick={() => { - navigate( - `/settings/accounts/calendars/${account.calendarChannels[0].id}`, - ); + navigate(`/settings/accounts/calendars`); closeDropdown(); }} /> diff --git a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsSynchronizationStatus.tsx b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsSynchronizationStatus.tsx deleted file mode 100644 index b0f59f6a4acc..000000000000 --- a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsSynchronizationStatus.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import { useGetSyncStatusOptions } from '@/settings/accounts/hooks//useGetSyncStatusOptions'; -import { Status } from '@/ui/display/status/components/Status'; - -export type SettingsAccountsSynchronizationStatusProps = { - syncStatus: string; - isSyncEnabled?: boolean; -}; - -export const SettingsAccountsSynchronizationStatus = ({ - syncStatus, - isSyncEnabled, -}: SettingsAccountsSynchronizationStatusProps) => { - const syncStatusOptions = useGetSyncStatusOptions(); - - const syncStatusOption = syncStatusOptions?.find( - (option) => option.value === syncStatus, - ); - - if (!isSyncEnabled) { - return <Status color="gray" text="Not synced" weight="medium" />; - } - - return ( - <Status - color={syncStatusOption?.color ?? 'gray'} - isLoaderVisible={syncStatus === 'ONGOING' || syncStatus === 'PENDING'} - text={syncStatusOption?.label ?? 'Not synced'} - weight="medium" - /> - ); -}; diff --git a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsToggleSettingCard.tsx b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsToggleSettingCard.tsx index 7dee8347d9f2..62bfbaa40b8e 100644 --- a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsToggleSettingCard.tsx +++ b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsToggleSettingCard.tsx @@ -1,22 +1,24 @@ -import { ReactNode } from 'react'; import styled from '@emotion/styled'; import { Toggle } from '@/ui/input/components/Toggle'; import { Card } from '@/ui/layout/card/components/Card'; import { CardContent } from '@/ui/layout/card/components/CardContent'; -type SettingsAccountsToggleSettingCardProps = { - cardMedia: ReactNode; +type Parameter = { value: boolean; - onToggle: (value: boolean) => void; title: string; + description: string; + onToggle: (value: boolean) => void; +}; + +type SettingsAccountsToggleSettingCardProps = { + parameters: Parameter[]; }; const StyledCardContent = styled(CardContent)` align-items: center; display: flex; gap: ${({ theme }) => theme.spacing(4)}; - padding: ${({ theme }) => theme.spacing(2, 4)}; cursor: pointer; &:hover { @@ -24,23 +26,37 @@ const StyledCardContent = styled(CardContent)` } `; -const StyledTitle = styled.span` +const StyledTitle = styled.div` color: ${({ theme }) => theme.font.color.primary}; font-weight: ${({ theme }) => theme.font.weight.medium}; - margin-right: auto; + margin-bottom: ${({ theme }) => theme.spacing(2)}; +`; + +const StyledDescription = styled.div` + color: ${({ theme }) => theme.font.color.tertiary}; + font-size: ${({ theme }) => theme.font.size.sm}; +`; + +const StyledToggle = styled(Toggle)` + margin-left: auto; `; export const SettingsAccountsToggleSettingCard = ({ - cardMedia, - value, - onToggle, - title, + parameters, }: SettingsAccountsToggleSettingCardProps) => ( <Card rounded> - <StyledCardContent onClick={() => onToggle(!value)}> - {cardMedia} - <StyledTitle>{title}</StyledTitle> - <Toggle value={value} onChange={onToggle} /> - </StyledCardContent> + {parameters.map((parameter, index) => ( + <StyledCardContent + key={index} + divider={index < parameters.length - 1} + onClick={() => parameter.onToggle(!parameter.value)} + > + <div> + <StyledTitle>{parameter.title}</StyledTitle> + <StyledDescription>{parameter.description}</StyledDescription> + </div> + <StyledToggle value={parameter.value} onChange={parameter.onToggle} /> + </StyledCardContent> + ))} </Card> ); diff --git a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsVisibilitySettingCardMedia.tsx b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsVisibilityIcon.tsx similarity index 87% rename from packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsVisibilitySettingCardMedia.tsx rename to packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsVisibilityIcon.tsx index 119fb26e0c67..5931d828ec00 100644 --- a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsVisibilitySettingCardMedia.tsx +++ b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsVisibilityIcon.tsx @@ -4,7 +4,7 @@ import { SettingsAccountsCardMedia } from '@/settings/accounts/components/Settin type VisibilityElementState = 'active' | 'inactive'; -type SettingsAccountsVisibilitySettingCardMediaProps = { +type SettingsAccountsVisibilityIconProps = { className?: string; metadata?: VisibilityElementState; subject?: VisibilityElementState; @@ -31,12 +31,12 @@ const StyledBodySkeleton = styled(StyledSubjectSkeleton)` flex: 1 0 auto; `; -export const SettingsAccountsVisibilitySettingCardMedia = ({ +export const SettingsAccountsVisibilityIcon = ({ className, metadata, subject, body, -}: SettingsAccountsVisibilitySettingCardMediaProps) => ( +}: SettingsAccountsVisibilityIconProps) => ( <StyledCardMedia className={className}> {!!metadata && <StyledMetadataSkeleton isActive={metadata === 'active'} />} {!!subject && <StyledSubjectSkeleton isActive={subject === 'active'} />} diff --git a/packages/twenty-front/src/modules/settings/accounts/components/__stories__/SettingsAccountsEmailsBlocklistInput.stories.tsx b/packages/twenty-front/src/modules/settings/accounts/components/__stories__/SettingsAccountsBlocklistInput.stories.tsx similarity index 77% rename from packages/twenty-front/src/modules/settings/accounts/components/__stories__/SettingsAccountsEmailsBlocklistInput.stories.tsx rename to packages/twenty-front/src/modules/settings/accounts/components/__stories__/SettingsAccountsBlocklistInput.stories.tsx index 3ceef7405d88..48a52896b524 100644 --- a/packages/twenty-front/src/modules/settings/accounts/components/__stories__/SettingsAccountsEmailsBlocklistInput.stories.tsx +++ b/packages/twenty-front/src/modules/settings/accounts/components/__stories__/SettingsAccountsBlocklistInput.stories.tsx @@ -2,7 +2,7 @@ import { Decorator, Meta, StoryObj } from '@storybook/react'; import { expect, fn, userEvent, within } from '@storybook/test'; import { ComponentDecorator } from 'twenty-ui'; -import { SettingsAccountsEmailsBlocklistInput } from '@/settings/accounts/components/SettingsAccountsEmailsBlocklistInput'; +import { SettingsAccountsBlocklistInput } from '@/settings/accounts/components/SettingsAccountsBlocklistInput'; const updateBlockedEmailListJestFn = fn(); @@ -13,10 +13,9 @@ const ClearMocksDecorator: Decorator = (Story, context) => { return <Story />; }; -const meta: Meta<typeof SettingsAccountsEmailsBlocklistInput> = { - title: - 'Modules/Settings/Accounts/Blocklist/SettingsAccountsEmailsBlocklistInput', - component: SettingsAccountsEmailsBlocklistInput, +const meta: Meta<typeof SettingsAccountsBlocklistInput> = { + title: 'Modules/Settings/Accounts/Blocklist/SettingsAccountsBlocklistInput', + component: SettingsAccountsBlocklistInput, decorators: [ComponentDecorator, ClearMocksDecorator], args: { updateBlockedEmailList: updateBlockedEmailListJestFn, @@ -31,7 +30,7 @@ const meta: Meta<typeof SettingsAccountsEmailsBlocklistInput> = { }; export default meta; -type Story = StoryObj<typeof SettingsAccountsEmailsBlocklistInput>; +type Story = StoryObj<typeof SettingsAccountsBlocklistInput>; export const Default: Story = {}; diff --git a/packages/twenty-front/src/modules/settings/accounts/components/__stories__/SettingsAccountsBlocklistSection.stories.tsx b/packages/twenty-front/src/modules/settings/accounts/components/__stories__/SettingsAccountsBlocklistSection.stories.tsx new file mode 100644 index 000000000000..bc3f9cb721e1 --- /dev/null +++ b/packages/twenty-front/src/modules/settings/accounts/components/__stories__/SettingsAccountsBlocklistSection.stories.tsx @@ -0,0 +1,16 @@ +import { Meta, StoryObj } from '@storybook/react'; +import { ComponentDecorator } from 'twenty-ui'; + +import { SettingsAccountsBlocklistInput } from '@/settings/accounts/components/SettingsAccountsBlocklistInput'; +import { SettingsAccountsBlocklistSection } from '@/settings/accounts/components/SettingsAccountsBlocklistSection'; + +const meta: Meta<typeof SettingsAccountsBlocklistSection> = { + title: 'Modules/Settings/Accounts/Blocklist/SettingsAccountsBlocklistSection', + component: SettingsAccountsBlocklistInput, + decorators: [ComponentDecorator], +}; + +export default meta; +type Story = StoryObj<typeof SettingsAccountsBlocklistSection>; + +export const Default: Story = {}; diff --git a/packages/twenty-front/src/modules/settings/accounts/components/__stories__/SettingsAccountsEmailsBlocklistTable.stories.tsx b/packages/twenty-front/src/modules/settings/accounts/components/__stories__/SettingsAccountsBlocklistTable.stories.tsx similarity index 81% rename from packages/twenty-front/src/modules/settings/accounts/components/__stories__/SettingsAccountsEmailsBlocklistTable.stories.tsx rename to packages/twenty-front/src/modules/settings/accounts/components/__stories__/SettingsAccountsBlocklistTable.stories.tsx index 7ab7f1c9b051..71126ba4e285 100644 --- a/packages/twenty-front/src/modules/settings/accounts/components/__stories__/SettingsAccountsEmailsBlocklistTable.stories.tsx +++ b/packages/twenty-front/src/modules/settings/accounts/components/__stories__/SettingsAccountsBlocklistTable.stories.tsx @@ -3,7 +3,7 @@ import { expect, fn, userEvent, within } from '@storybook/test'; import { ComponentDecorator } from 'twenty-ui'; import { mockedBlocklist } from '@/settings/accounts/components/__stories__/mockedBlocklist'; -import { SettingsAccountsEmailsBlocklistTable } from '@/settings/accounts/components/SettingsAccountsEmailsBlocklistTable'; +import { SettingsAccountsBlocklistTable } from '@/settings/accounts/components/SettingsAccountsBlocklistTable'; import { formatToHumanReadableDate } from '~/utils/date-utils'; const handleBlockedEmailRemoveJestFn = fn(); @@ -15,10 +15,9 @@ const ClearMocksDecorator: Decorator = (Story, context) => { return <Story />; }; -const meta: Meta<typeof SettingsAccountsEmailsBlocklistTable> = { - title: - 'Modules/Settings/Accounts/Blocklist/SettingsAccountsEmailsBlocklistTable', - component: SettingsAccountsEmailsBlocklistTable, +const meta: Meta<typeof SettingsAccountsBlocklistTable> = { + title: 'Modules/Settings/Accounts/Blocklist/SettingsAccountsBlocklistTable', + component: SettingsAccountsBlocklistTable, decorators: [ComponentDecorator, ClearMocksDecorator], args: { blocklist: mockedBlocklist, @@ -34,7 +33,7 @@ const meta: Meta<typeof SettingsAccountsEmailsBlocklistTable> = { }; export default meta; -type Story = StoryObj<typeof SettingsAccountsEmailsBlocklistTable>; +type Story = StoryObj<typeof SettingsAccountsBlocklistTable>; export const Default: Story = { play: async ({ canvasElement }) => { diff --git a/packages/twenty-front/src/modules/settings/accounts/components/__stories__/SettingsAccountsEmailsBlocklistTableRow.stories.tsx b/packages/twenty-front/src/modules/settings/accounts/components/__stories__/SettingsAccountsBlocklistTableRow.stories.tsx similarity index 80% rename from packages/twenty-front/src/modules/settings/accounts/components/__stories__/SettingsAccountsEmailsBlocklistTableRow.stories.tsx rename to packages/twenty-front/src/modules/settings/accounts/components/__stories__/SettingsAccountsBlocklistTableRow.stories.tsx index f24b0033f5ae..b4a1991e65b4 100644 --- a/packages/twenty-front/src/modules/settings/accounts/components/__stories__/SettingsAccountsEmailsBlocklistTableRow.stories.tsx +++ b/packages/twenty-front/src/modules/settings/accounts/components/__stories__/SettingsAccountsBlocklistTableRow.stories.tsx @@ -3,7 +3,7 @@ import { expect, fn, userEvent, within } from '@storybook/test'; import { ComponentDecorator } from 'twenty-ui'; import { mockedBlocklist } from '@/settings/accounts/components/__stories__/mockedBlocklist'; -import { SettingsAccountsEmailsBlocklistTableRow } from '@/settings/accounts/components/SettingsAccountsEmailsBlocklistTableRow'; +import { SettingsAccountsBlocklistTableRow } from '@/settings/accounts/components/SettingsAccountsBlocklistTableRow'; import { formatToHumanReadableDate } from '~/utils/date-utils'; const onRemoveJestFn = fn(); @@ -15,10 +15,10 @@ const ClearMocksDecorator: Decorator = (Story, context) => { return <Story />; }; -const meta: Meta<typeof SettingsAccountsEmailsBlocklistTableRow> = { +const meta: Meta<typeof SettingsAccountsBlocklistTableRow> = { title: - 'Modules/Settings/Accounts/Blocklist/SettingsAccountsEmailsBlocklistTableRow', - component: SettingsAccountsEmailsBlocklistTableRow, + 'Modules/Settings/Accounts/Blocklist/SettingsAccountsBlocklistTableRow', + component: SettingsAccountsBlocklistTableRow, decorators: [ComponentDecorator, ClearMocksDecorator], args: { blocklistItem: mockedBlocklist[0], @@ -34,7 +34,7 @@ const meta: Meta<typeof SettingsAccountsEmailsBlocklistTableRow> = { }; export default meta; -type Story = StoryObj<typeof SettingsAccountsEmailsBlocklistTableRow>; +type Story = StoryObj<typeof SettingsAccountsBlocklistTableRow>; export const Default: Story = { play: async ({ canvasElement }) => { diff --git a/packages/twenty-front/src/modules/settings/accounts/components/__stories__/SettingsAccountsCalendarChannelDetails.stories.tsx b/packages/twenty-front/src/modules/settings/accounts/components/__stories__/SettingsAccountsCalendarChannelDetails.stories.tsx new file mode 100644 index 000000000000..5ef756baf4c6 --- /dev/null +++ b/packages/twenty-front/src/modules/settings/accounts/components/__stories__/SettingsAccountsCalendarChannelDetails.stories.tsx @@ -0,0 +1,30 @@ +import { Meta, StoryObj } from '@storybook/react'; +import { ComponentDecorator } from 'twenty-ui'; + +import { SettingsAccountsCalendarChannelDetails } from '@/settings/accounts/components/SettingsAccountsCalendarChannelDetails'; +import { CalendarChannelVisibility } from '~/generated/graphql'; + +const meta: Meta<typeof SettingsAccountsCalendarChannelDetails> = { + title: + 'Modules/Settings/Accounts/CalendarChannels/SettingsAccountsCalendarChannelDetails', + component: SettingsAccountsCalendarChannelDetails, + decorators: [ComponentDecorator], + args: { + calendarChannel: { + id: '20202020-ef5a-4822-9e08-ce6e6a4dcb6a', + isContactAutoCreationEnabled: true, + isSyncEnabled: true, + visibility: CalendarChannelVisibility.ShareEverything, + }, + }, + argTypes: { + calendarChannel: { control: false }, + }, +}; + +export default meta; +type Story = StoryObj<typeof SettingsAccountsCalendarChannelDetails>; + +export const Default: Story = { + play: async () => {}, +}; diff --git a/packages/twenty-front/src/modules/settings/accounts/components/__stories__/SettingsAccountsCalendarChannelsGeneral.stories.tsx b/packages/twenty-front/src/modules/settings/accounts/components/__stories__/SettingsAccountsCalendarChannelsGeneral.stories.tsx new file mode 100644 index 000000000000..49f279316908 --- /dev/null +++ b/packages/twenty-front/src/modules/settings/accounts/components/__stories__/SettingsAccountsCalendarChannelsGeneral.stories.tsx @@ -0,0 +1,18 @@ +import { Meta, StoryObj } from '@storybook/react'; +import { ComponentDecorator } from 'twenty-ui'; + +import { SettingsAccountsCalendarChannelsGeneral } from '@/settings/accounts/components/SettingsAccountsCalendarChannelsGeneral'; + +const meta: Meta<typeof SettingsAccountsCalendarChannelsGeneral> = { + title: + 'Modules/Settings/Accounts/CalendarChannels/SettingsAccountsCalendarChannelsGeneral', + component: SettingsAccountsCalendarChannelsGeneral, + decorators: [ComponentDecorator], +}; + +export default meta; +type Story = StoryObj<typeof SettingsAccountsCalendarChannelsGeneral>; + +export const Default: Story = { + play: async () => {}, +}; diff --git a/packages/twenty-front/src/modules/settings/accounts/components/__stories__/SettingsAccountsEmailsBlocklistSection.stories.tsx b/packages/twenty-front/src/modules/settings/accounts/components/__stories__/SettingsAccountsEmailsBlocklistSection.stories.tsx deleted file mode 100644 index 7fa2183aae4f..000000000000 --- a/packages/twenty-front/src/modules/settings/accounts/components/__stories__/SettingsAccountsEmailsBlocklistSection.stories.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { Meta, StoryObj } from '@storybook/react'; -import { ComponentDecorator } from 'twenty-ui'; - -import { SettingsAccountsEmailsBlocklistInput } from '@/settings/accounts/components/SettingsAccountsEmailsBlocklistInput'; -import { SettingsAccountsEmailsBlocklistSection } from '@/settings/accounts/components/SettingsAccountsEmailsBlocklistSection'; - -const meta: Meta<typeof SettingsAccountsEmailsBlocklistSection> = { - title: - 'Modules/Settings/Accounts/Blocklist/SettingsAccountsEmailsBlocklistSection', - component: SettingsAccountsEmailsBlocklistInput, - decorators: [ComponentDecorator], -}; - -export default meta; -type Story = StoryObj<typeof SettingsAccountsEmailsBlocklistSection>; - -export const Default: Story = {}; diff --git a/packages/twenty-front/src/modules/settings/accounts/components/__stories__/SettingsAccountsMessageChannelDetails.stories.tsx b/packages/twenty-front/src/modules/settings/accounts/components/__stories__/SettingsAccountsMessageChannelDetails.stories.tsx new file mode 100644 index 000000000000..02264d8e66fe --- /dev/null +++ b/packages/twenty-front/src/modules/settings/accounts/components/__stories__/SettingsAccountsMessageChannelDetails.stories.tsx @@ -0,0 +1,33 @@ +import { Meta, StoryObj } from '@storybook/react'; +import { ComponentDecorator } from 'twenty-ui'; + +import { MessageChannelContactAutoCreationPolicy } from '@/accounts/types/MessageChannel'; +import { SettingsAccountsMessageChannelDetails } from '@/settings/accounts/components/SettingsAccountsMessageChannelDetails'; +import { MessageChannelVisibility } from '~/generated/graphql'; + +const meta: Meta<typeof SettingsAccountsMessageChannelDetails> = { + title: + 'Modules/Settings/Accounts/MessageChannels/SettingsAccountsMessageChannelDetails', + component: SettingsAccountsMessageChannelDetails, + decorators: [ComponentDecorator], + args: { + messageChannel: { + id: '20202020-ef5a-4822-9e08-ce6e6a4dcb6a', + contactAutoCreationPolicy: MessageChannelContactAutoCreationPolicy.SENT, + excludeNonProfessionalEmails: true, + excludeGroupEmails: false, + isSyncEnabled: true, + visibility: MessageChannelVisibility.ShareEverything, + }, + }, + argTypes: { + messageChannel: { control: false }, + }, +}; + +export default meta; +type Story = StoryObj<typeof SettingsAccountsMessageChannelDetails>; + +export const Default: Story = { + play: async () => {}, +}; diff --git a/packages/twenty-front/src/modules/settings/accounts/constants/SettingsAccountCalendarChannelsTabListComponentId.ts b/packages/twenty-front/src/modules/settings/accounts/constants/SettingsAccountCalendarChannelsTabListComponentId.ts new file mode 100644 index 000000000000..5d414496d292 --- /dev/null +++ b/packages/twenty-front/src/modules/settings/accounts/constants/SettingsAccountCalendarChannelsTabListComponentId.ts @@ -0,0 +1,2 @@ +export const SETTINGS_ACCOUNT_CALENDAR_CHANNELS_TAB_LIST_COMPONENT_ID = + 'settings-account-calendar-channels-tab-list'; diff --git a/packages/twenty-front/src/modules/settings/accounts/constants/SettingsAccountMessageChannelsTabListComponentId.ts b/packages/twenty-front/src/modules/settings/accounts/constants/SettingsAccountMessageChannelsTabListComponentId.ts new file mode 100644 index 000000000000..31f4638d767f --- /dev/null +++ b/packages/twenty-front/src/modules/settings/accounts/constants/SettingsAccountMessageChannelsTabListComponentId.ts @@ -0,0 +1,2 @@ +export const SETTINGS_ACCOUNT_MESSAGE_CHANNELS_TAB_LIST_COMPONENT_ID = + 'settings-account-message-channels-tab-list'; diff --git a/packages/twenty-front/src/modules/settings/components/SaveAndCancelButtons/CancelButton.tsx b/packages/twenty-front/src/modules/settings/components/SaveAndCancelButtons/CancelButton.tsx index f20d8737d7d7..e93d27a836d2 100644 --- a/packages/twenty-front/src/modules/settings/components/SaveAndCancelButtons/CancelButton.tsx +++ b/packages/twenty-front/src/modules/settings/components/SaveAndCancelButtons/CancelButton.tsx @@ -2,8 +2,19 @@ import { LightButton } from '@/ui/input/button/components/LightButton'; type CancelButtonProps = { onCancel?: () => void; + disabled?: boolean; }; -export const CancelButton = ({ onCancel }: CancelButtonProps) => { - return <LightButton title="Cancel" accent="tertiary" onClick={onCancel} />; +export const CancelButton = ({ + onCancel, + disabled = false, +}: CancelButtonProps) => { + return ( + <LightButton + title="Cancel" + accent="tertiary" + onClick={onCancel} + disabled={disabled} + /> + ); }; diff --git a/packages/twenty-front/src/modules/settings/components/SaveAndCancelButtons/SaveAndCancelButtons.tsx b/packages/twenty-front/src/modules/settings/components/SaveAndCancelButtons/SaveAndCancelButtons.tsx index 069e8aa201c4..5cb0e3677d6f 100644 --- a/packages/twenty-front/src/modules/settings/components/SaveAndCancelButtons/SaveAndCancelButtons.tsx +++ b/packages/twenty-front/src/modules/settings/components/SaveAndCancelButtons/SaveAndCancelButtons.tsx @@ -13,16 +13,18 @@ type SaveAndCancelButtonsProps = { onSave?: () => void; onCancel?: () => void; isSaveDisabled?: boolean; + isCancelDisabled?: boolean; }; export const SaveAndCancelButtons = ({ onSave, onCancel, isSaveDisabled, + isCancelDisabled, }: SaveAndCancelButtonsProps) => { return ( <StyledContainer> - <CancelButton onCancel={onCancel} /> + <CancelButton onCancel={onCancel} disabled={isCancelDisabled} /> <SaveButton onSave={onSave} disabled={isSaveDisabled} /> </StyledContainer> ); diff --git a/packages/twenty-front/src/modules/settings/data-model/constants/DatabaseIdentifierMaximumLength.ts b/packages/twenty-front/src/modules/settings/data-model/constants/DatabaseIdentifierMaximumLength.ts new file mode 100644 index 000000000000..d7ac7dd9a27f --- /dev/null +++ b/packages/twenty-front/src/modules/settings/data-model/constants/DatabaseIdentifierMaximumLength.ts @@ -0,0 +1 @@ +export const DATABASE_IDENTIFIER_MAXIMUM_LENGTH = 63; diff --git a/packages/twenty-front/src/modules/settings/data-model/constants/FieldNameMaximumLength.ts b/packages/twenty-front/src/modules/settings/data-model/constants/FieldNameMaximumLength.ts new file mode 100644 index 000000000000..bd647b2cbee5 --- /dev/null +++ b/packages/twenty-front/src/modules/settings/data-model/constants/FieldNameMaximumLength.ts @@ -0,0 +1,3 @@ +import { DATABASE_IDENTIFIER_MAXIMUM_LENGTH } from '@/settings/data-model/constants/DatabaseIdentifierMaximumLength'; + +export const FIELD_NAME_MAXIMUM_LENGTH = DATABASE_IDENTIFIER_MAXIMUM_LENGTH; diff --git a/packages/twenty-front/src/modules/settings/data-model/constants/ObjectNameMaximumLength.ts b/packages/twenty-front/src/modules/settings/data-model/constants/ObjectNameMaximumLength.ts new file mode 100644 index 000000000000..6ba3692374d2 --- /dev/null +++ b/packages/twenty-front/src/modules/settings/data-model/constants/ObjectNameMaximumLength.ts @@ -0,0 +1,3 @@ +import { DATABASE_IDENTIFIER_MAXIMUM_LENGTH } from '@/settings/data-model/constants/DatabaseIdentifierMaximumLength'; + +export const OBJECT_NAME_MAXIMUM_LENGTH = DATABASE_IDENTIFIER_MAXIMUM_LENGTH; diff --git a/packages/twenty-front/src/modules/settings/data-model/constants/OptionValueMaximumLength.ts b/packages/twenty-front/src/modules/settings/data-model/constants/OptionValueMaximumLength.ts new file mode 100644 index 000000000000..97f5cc7726c7 --- /dev/null +++ b/packages/twenty-front/src/modules/settings/data-model/constants/OptionValueMaximumLength.ts @@ -0,0 +1,3 @@ +import { DATABASE_IDENTIFIER_MAXIMUM_LENGTH } from '@/settings/data-model/constants/DatabaseIdentifierMaximumLength'; + +export const OPTION_VALUE_MAXIMUM_LENGTH = DATABASE_IDENTIFIER_MAXIMUM_LENGTH; diff --git a/packages/twenty-front/src/modules/settings/data-model/constants/SettingsFieldCurrencyCodes.ts b/packages/twenty-front/src/modules/settings/data-model/constants/SettingsFieldCurrencyCodes.ts index c84df4323d90..5e013b50ca26 100644 --- a/packages/twenty-front/src/modules/settings/data-model/constants/SettingsFieldCurrencyCodes.ts +++ b/packages/twenty-front/src/modules/settings/data-model/constants/SettingsFieldCurrencyCodes.ts @@ -1,5 +1,6 @@ import { IconComponent, + IconCurrencyBaht, IconCurrencyDirham, IconCurrencyDollar, IconCurrencyEuro, @@ -7,7 +8,9 @@ import { IconCurrencyKroneCzech, IconCurrencyKroneSwedish, IconCurrencyPound, + IconCurrencyReal, IconCurrencyRiyal, + IconCurrencyWon, IconCurrencyYen, IconCurrencyYuan, } from 'twenty-ui'; @@ -62,6 +65,10 @@ export const SETTINGS_FIELD_CURRENCY_CODES: Record< label: 'Swedish krona', Icon: IconCurrencyKroneSwedish, }, + BHT: { + label: 'Thai Baht', + Icon: IconCurrencyBaht, + }, MAD: { label: 'Moroccan dirham', Icon: IconCurrencyDirham, @@ -74,4 +81,16 @@ export const SETTINGS_FIELD_CURRENCY_CODES: Record< label: 'UAE dirham', Icon: IconCurrencyDirham, }, + KRW: { + label: 'South Korean won', + Icon: IconCurrencyWon, + }, + BRL: { + label: 'Brazilian real', + Icon: IconCurrencyReal, + }, + AUD: { + label: 'Australian dollar', + Icon: IconCurrencyDollar, + }, }; diff --git a/packages/twenty-front/src/modules/settings/data-model/constants/SettingsFieldTypeConfigs.ts b/packages/twenty-front/src/modules/settings/data-model/constants/SettingsFieldTypeConfigs.ts index a1b7135a89f4..9cc38edabd0c 100644 --- a/packages/twenty-front/src/modules/settings/data-model/constants/SettingsFieldTypeConfigs.ts +++ b/packages/twenty-front/src/modules/settings/data-model/constants/SettingsFieldTypeConfigs.ts @@ -102,11 +102,6 @@ export const SETTINGS_FIELD_TYPE_CONFIGS = { Icon: IconPhone, defaultValue: '+1234-567-890', }, - [FieldMetadataType.Probability]: { - label: 'Rating', - Icon: IconTwentyStar, - defaultValue: '3', - }, [FieldMetadataType.Rating]: { label: 'Rating', Icon: IconTwentyStar, diff --git a/packages/twenty-front/src/modules/settings/data-model/fields/forms/components/SettingsDataModelFieldAboutForm.tsx b/packages/twenty-front/src/modules/settings/data-model/fields/forms/components/SettingsDataModelFieldAboutForm.tsx index e4c5e2141d73..01411114ce1d 100644 --- a/packages/twenty-front/src/modules/settings/data-model/fields/forms/components/SettingsDataModelFieldAboutForm.tsx +++ b/packages/twenty-front/src/modules/settings/data-model/fields/forms/components/SettingsDataModelFieldAboutForm.tsx @@ -22,6 +22,7 @@ type SettingsDataModelFieldAboutFormValues = z.infer< type SettingsDataModelFieldAboutFormProps = { disabled?: boolean; fieldMetadataItem?: FieldMetadataItem; + maxLength?: number; }; const StyledInputsContainer = styled.div` @@ -34,6 +35,7 @@ const StyledInputsContainer = styled.div` export const SettingsDataModelFieldAboutForm = ({ disabled, fieldMetadataItem, + maxLength, }: SettingsDataModelFieldAboutFormProps) => { const { control } = useFormContext<SettingsDataModelFieldAboutFormValues>(); @@ -63,6 +65,7 @@ export const SettingsDataModelFieldAboutForm = ({ value={value} onChange={onChange} disabled={disabled} + maxLength={maxLength} fullWidth /> )} diff --git a/packages/twenty-front/src/modules/settings/data-model/fields/forms/components/__stories__/SettingsDataModelFieldTypeSelect.stories.tsx b/packages/twenty-front/src/modules/settings/data-model/fields/forms/components/__stories__/SettingsDataModelFieldTypeSelect.stories.tsx index 6292d9522323..01b5164d1f8d 100644 --- a/packages/twenty-front/src/modules/settings/data-model/fields/forms/components/__stories__/SettingsDataModelFieldTypeSelect.stories.tsx +++ b/packages/twenty-front/src/modules/settings/data-model/fields/forms/components/__stories__/SettingsDataModelFieldTypeSelect.stories.tsx @@ -31,8 +31,8 @@ export const Disabled: Story = { }; export const WithOpenSelect: Story = { - play: async ({ canvasElement }) => { - const canvas = within(canvasElement); + play: async () => { + const canvas = within(document.body); const inputField = await canvas.findByText('Text'); @@ -49,8 +49,8 @@ export const WithExcludedFieldTypes: Story = { args: { excludedFieldTypes: [FieldMetadataType.Uuid, FieldMetadataType.Numeric], }, - play: async ({ canvasElement }) => { - const canvas = within(canvasElement); + play: async () => { + const canvas = within(document.body); const inputField = await canvas.findByText('Text'); diff --git a/packages/twenty-front/src/modules/settings/data-model/fields/forms/relation/components/SettingsDataModelFieldRelationForm.tsx b/packages/twenty-front/src/modules/settings/data-model/fields/forms/relation/components/SettingsDataModelFieldRelationForm.tsx index f41b48bbf5fa..4415bc64aa72 100644 --- a/packages/twenty-front/src/modules/settings/data-model/fields/forms/relation/components/SettingsDataModelFieldRelationForm.tsx +++ b/packages/twenty-front/src/modules/settings/data-model/fields/forms/relation/components/SettingsDataModelFieldRelationForm.tsx @@ -7,6 +7,7 @@ import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilte import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; import { isObjectMetadataAvailableForRelation } from '@/object-metadata/utils/isObjectMetadataAvailableForRelation'; import { fieldMetadataItemSchema } from '@/object-metadata/validation-schemas/fieldMetadataItemSchema'; +import { FIELD_NAME_MAXIMUM_LENGTH } from '@/settings/data-model/constants/FieldNameMaximumLength'; import { RELATION_TYPES } from '@/settings/data-model/constants/RelationTypes'; import { useRelationSettingsFormInitialValues } from '@/settings/data-model/fields/forms/relation/hooks/useRelationSettingsFormInitialValues'; import { RelationType } from '@/settings/data-model/types/RelationType'; @@ -163,6 +164,7 @@ export const SettingsDataModelFieldRelationForm = ({ value={value} onChange={onChange} fullWidth + maxLength={FIELD_NAME_MAXIMUM_LENGTH} /> )} /> diff --git a/packages/twenty-front/src/modules/settings/data-model/fields/forms/select/components/SettingsDataModelFieldSelectForm.tsx b/packages/twenty-front/src/modules/settings/data-model/fields/forms/select/components/SettingsDataModelFieldSelectForm.tsx index 0f30a88b6caa..d23690fc3ff3 100644 --- a/packages/twenty-front/src/modules/settings/data-model/fields/forms/select/components/SettingsDataModelFieldSelectForm.tsx +++ b/packages/twenty-front/src/modules/settings/data-model/fields/forms/select/components/SettingsDataModelFieldSelectForm.tsx @@ -1,6 +1,8 @@ +import { useState } from 'react'; import { Controller, useFormContext } from 'react-hook-form'; import styled from '@emotion/styled'; import { DropResult } from '@hello-pangea/dnd'; +import { Key } from 'ts-key-enum'; import { IconPlus } from 'twenty-ui'; import { z } from 'zod'; @@ -19,6 +21,8 @@ import { CardContent } from '@/ui/layout/card/components/CardContent'; import { CardFooter } from '@/ui/layout/card/components/CardFooter'; import { DraggableItem } from '@/ui/layout/draggable-list/components/DraggableItem'; import { DraggableList } from '@/ui/layout/draggable-list/components/DraggableList'; +import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys'; +import { AppHotkeyScope } from '@/ui/utilities/hotkey/types/AppHotkeyScope'; import { FieldMetadataType } from '~/generated-metadata/graphql'; import { moveArrayItem } from '~/utils/array/moveArrayItem'; import { toSpliced } from '~/utils/array/toSpliced'; @@ -78,6 +82,7 @@ const StyledButton = styled(LightButton)` export const SettingsDataModelFieldSelectForm = ({ fieldMetadataItem, }: SettingsDataModelFieldSelectFormProps) => { + const [focusedOptionId, setFocusedOptionId] = useState(''); const { initialDefaultValue, initialOptions } = useSelectSettingsFormInitialValues({ fieldMetadataItem }); @@ -167,6 +172,37 @@ export const SettingsDataModelFieldSelectForm = ({ } }; + const getOptionsWithNewOption = () => { + const currentOptions = getValues('options'); + + const newOptions = [ + ...currentOptions, + generateNewSelectOption(currentOptions), + ]; + + return newOptions; + }; + + const handleAddOption = () => { + const newOptions = getOptionsWithNewOption(); + + setFormValue('options', newOptions); + }; + + useScopedHotkeys( + Key.Enter, + () => { + const newOptions = getOptionsWithNewOption(); + + setFormValue('options', newOptions); + + const lastOptionId = newOptions[newOptions.length - 1].id; + + setFocusedOptionId(lastOptionId); + }, + AppHotkeyScope.App, + ); + return ( <> <Controller @@ -197,6 +233,7 @@ export const SettingsDataModelFieldSelectForm = ({ <SettingsDataModelFieldSelectFormOptionRow key={option.id} option={option} + focused={focusedOptionId === option.id} onChange={(nextOption) => { const nextOptions = toSpliced( options, @@ -245,9 +282,7 @@ export const SettingsDataModelFieldSelectForm = ({ <StyledButton title="Add option" Icon={IconPlus} - onClick={() => - onChange([...options, generateNewSelectOption(options)]) - } + onClick={handleAddOption} /> </StyledFooter> </> diff --git a/packages/twenty-front/src/modules/settings/data-model/fields/forms/select/components/SettingsDataModelFieldSelectFormOptionRow.tsx b/packages/twenty-front/src/modules/settings/data-model/fields/forms/select/components/SettingsDataModelFieldSelectFormOptionRow.tsx index fdc99c137005..0cb96fc764df 100644 --- a/packages/twenty-front/src/modules/settings/data-model/fields/forms/select/components/SettingsDataModelFieldSelectFormOptionRow.tsx +++ b/packages/twenty-front/src/modules/settings/data-model/fields/forms/select/components/SettingsDataModelFieldSelectFormOptionRow.tsx @@ -1,4 +1,4 @@ -import { useMemo } from 'react'; +import { useEffect, useMemo, useRef } from 'react'; import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { @@ -13,6 +13,7 @@ import { import { v4 } from 'uuid'; import { FieldMetadataItemOption } from '@/object-metadata/types/FieldMetadataItem'; +import { OPTION_VALUE_MAXIMUM_LENGTH } from '@/settings/data-model/constants/OptionValueMaximumLength'; import { getOptionValueFromLabel } from '@/settings/data-model/fields/forms/select/utils/getOptionValueFromLabel'; import { LightIconButton } from '@/ui/input/button/components/LightIconButton'; import { TextInput } from '@/ui/input/components/TextInput'; @@ -31,6 +32,7 @@ type SettingsDataModelFieldSelectFormOptionRowProps = { onSetAsDefault?: () => void; onRemoveAsDefault?: () => void; option: FieldMetadataItemOption; + focused?: boolean; }; const StyledRow = styled.div` @@ -63,12 +65,18 @@ export const SettingsDataModelFieldSelectFormOptionRow = ({ onSetAsDefault, onRemoveAsDefault, option, + focused, }: SettingsDataModelFieldSelectFormOptionRowProps) => { + const inputRef = useRef<HTMLInputElement>(null); + const theme = useTheme(); const dropdownIds = useMemo(() => { const baseScopeId = `select-field-option-row-${v4()}`; - return { color: `${baseScopeId}-color`, actions: `${baseScopeId}-actions` }; + return { + color: `${baseScopeId}-color`, + actions: `${baseScopeId}-actions`, + }; }, []); const { closeDropdown: closeColorDropdown } = useDropdown(dropdownIds.color); @@ -76,6 +84,12 @@ export const SettingsDataModelFieldSelectFormOptionRow = ({ dropdownIds.actions, ); + useEffect(() => { + if (focused === true) { + inputRef.current?.focus(); + } + }, [focused]); + return ( <StyledRow className={className}> <IconGripVertical @@ -109,11 +123,18 @@ export const SettingsDataModelFieldSelectFormOptionRow = ({ } /> <StyledOptionInput + ref={inputRef} + disableHotkeys value={option.label} onChange={(label) => - onChange({ ...option, label, value: getOptionValueFromLabel(label) }) + onChange({ + ...option, + label, + value: getOptionValueFromLabel(label), + }) } RightIcon={isDefault ? IconCheck : undefined} + maxLength={OPTION_VALUE_MAXIMUM_LENGTH} /> <Dropdown dropdownId={dropdownIds.actions} diff --git a/packages/twenty-front/src/modules/settings/data-model/fields/preview/components/SettingsDataModelSetRecordEffect.tsx b/packages/twenty-front/src/modules/settings/data-model/fields/preview/components/SettingsDataModelSetRecordEffect.tsx index c34a07f773d3..7ef2d28c71ad 100644 --- a/packages/twenty-front/src/modules/settings/data-model/fields/preview/components/SettingsDataModelSetRecordEffect.tsx +++ b/packages/twenty-front/src/modules/settings/data-model/fields/preview/components/SettingsDataModelSetRecordEffect.tsx @@ -1,6 +1,6 @@ import { useEffect } from 'react'; -import { useSetRecordInStore } from '@/object-record/record-store/hooks/useSetRecordInStore'; +import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore'; import { ObjectRecord } from '@/object-record/types/ObjectRecord'; type SettingsDataModelSetRecordEffectProps = { @@ -10,11 +10,11 @@ type SettingsDataModelSetRecordEffectProps = { export const SettingsDataModelSetRecordEffect = ({ record, }: SettingsDataModelSetRecordEffectProps) => { - const { setRecords: setRecordsInStore } = useSetRecordInStore(); + const { upsertRecords: upsertRecordsInStore } = useUpsertRecordsInStore(); useEffect(() => { - setRecordsInStore([record]); - }, [record, setRecordsInStore]); + upsertRecordsInStore([record]); + }, [record, upsertRecordsInStore]); return null; }; diff --git a/packages/twenty-front/src/modules/settings/data-model/graph-overview/components/SettingsDataModelOverview.tsx b/packages/twenty-front/src/modules/settings/data-model/graph-overview/components/SettingsDataModelOverview.tsx index dd098c46bb79..e5bd42d0b4e3 100644 --- a/packages/twenty-front/src/modules/settings/data-model/graph-overview/components/SettingsDataModelOverview.tsx +++ b/packages/twenty-front/src/modules/settings/data-model/graph-overview/components/SettingsDataModelOverview.tsx @@ -203,7 +203,6 @@ export const SettingsDataModelOverview = () => { proOptions={{ hideAttribution: true }} > <Background /> - <IconButtonGroup className="react-flow__panel react-flow__controls bottom left" size="small" diff --git a/packages/twenty-front/src/modules/settings/data-model/graph-overview/components/SettingsDataModelOverviewObject.tsx b/packages/twenty-front/src/modules/settings/data-model/graph-overview/components/SettingsDataModelOverviewObject.tsx index 2c01bcb9f029..ff80c147e2fb 100644 --- a/packages/twenty-front/src/modules/settings/data-model/graph-overview/components/SettingsDataModelOverviewObject.tsx +++ b/packages/twenty-front/src/modules/settings/data-model/graph-overview/components/SettingsDataModelOverviewObject.tsx @@ -5,6 +5,7 @@ import styled from '@emotion/styled'; import { IconChevronDown, useIcons } from 'twenty-ui'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; +import { getObjectSlug } from '@/object-metadata/utils/getObjectSlug'; import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; import { ObjectFieldRow } from '@/settings/data-model/graph-overview/components/SettingsDataModelOverviewField'; import { SettingsDataModelObjectTypeTag } from '@/settings/data-model/objects/SettingsDataModelObjectTypeTag'; @@ -111,7 +112,7 @@ export const SettingsDataModelOverviewObject = ({ <StyledNode> <StyledHeader> <StyledObjectName onMouseEnter={() => {}} onMouseLeave={() => {}}> - <StyledObjectLink to={'/settings/objects/' + data.namePlural}> + <StyledObjectLink to={`/settings/objects/${getObjectSlug(data)}`}> {Icon && <Icon size={theme.icon.size.md} />} {capitalize(data.namePlural)} </StyledObjectLink> diff --git a/packages/twenty-front/src/modules/settings/data-model/objects/SettingsObjectCoverImage.tsx b/packages/twenty-front/src/modules/settings/data-model/objects/SettingsObjectCoverImage.tsx index 25886edaa279..23be86ff8ca0 100644 --- a/packages/twenty-front/src/modules/settings/data-model/objects/SettingsObjectCoverImage.tsx +++ b/packages/twenty-front/src/modules/settings/data-model/objects/SettingsObjectCoverImage.tsx @@ -1,7 +1,7 @@ import styled from '@emotion/styled'; import { IconEye } from 'twenty-ui'; -import { Button } from '@/ui/input/button/components/Button'; +import { FloatingButton } from '@/ui/input/button/components/FloatingButton'; import { Card } from '@/ui/layout/card/components/Card'; import DarkCoverImage from '../assets/cover-dark.png'; @@ -30,12 +30,12 @@ export const SettingsObjectCoverImage = () => { return ( <StyledCoverImageContainer> <StyledButtonContainer> - <Button + <FloatingButton Icon={IconEye} title="Visualize" size="small" to="/settings/objects/overview" - ></Button> + /> </StyledButtonContainer> </StyledCoverImageContainer> ); diff --git a/packages/twenty-front/src/modules/settings/data-model/objects/__stories__/SettingsObjectInactiveMenuDropDown.stories.tsx b/packages/twenty-front/src/modules/settings/data-model/objects/__stories__/SettingsObjectInactiveMenuDropDown.stories.tsx index c67607f7ccb7..8401f576c858 100644 --- a/packages/twenty-front/src/modules/settings/data-model/objects/__stories__/SettingsObjectInactiveMenuDropDown.stories.tsx +++ b/packages/twenty-front/src/modules/settings/data-model/objects/__stories__/SettingsObjectInactiveMenuDropDown.stories.tsx @@ -35,8 +35,8 @@ type Story = StoryObj<typeof SettingsObjectInactiveMenuDropDown>; export const Default: Story = {}; export const Open: Story = { - play: async ({ canvasElement }) => { - const canvas = within(canvasElement); + play: async () => { + const canvas = within(document.body); const dropdownButton = await canvas.getByRole('button'); @@ -45,8 +45,8 @@ export const Open: Story = { }; export const WithActivate: Story = { - play: async ({ canvasElement }) => { - const canvas = within(canvasElement); + play: async () => { + const canvas = within(document.body); const dropdownButton = await canvas.getByRole('button'); @@ -66,8 +66,8 @@ export const WithActivate: Story = { export const WithDelete: Story = { args: { isCustomObject: true }, - play: async ({ canvasElement }) => { - const canvas = within(canvasElement); + play: async () => { + const canvas = within(document.body); const dropdownButton = await canvas.getByRole('button'); diff --git a/packages/twenty-front/src/modules/settings/data-model/objects/forms/components/SettingsDataModelObjectAboutForm.tsx b/packages/twenty-front/src/modules/settings/data-model/objects/forms/components/SettingsDataModelObjectAboutForm.tsx index 11ddfc5b5787..7a40b61e7ab6 100644 --- a/packages/twenty-front/src/modules/settings/data-model/objects/forms/components/SettingsDataModelObjectAboutForm.tsx +++ b/packages/twenty-front/src/modules/settings/data-model/objects/forms/components/SettingsDataModelObjectAboutForm.tsx @@ -1,9 +1,10 @@ -import { Controller, useFormContext } from 'react-hook-form'; import styled from '@emotion/styled'; +import { Controller, useFormContext } from 'react-hook-form'; import { z } from 'zod'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { objectMetadataItemSchema } from '@/object-metadata/validation-schemas/objectMetadataItemSchema'; +import { OBJECT_NAME_MAXIMUM_LENGTH } from '@/settings/data-model/constants/ObjectNameMaximumLength'; import { IconPicker } from '@/ui/input/components/IconPicker'; import { TextArea } from '@/ui/input/components/TextArea'; import { TextInput } from '@/ui/input/components/TextInput'; @@ -97,6 +98,7 @@ export const SettingsDataModelObjectAboutForm = ({ onChange={onChange} disabled={disabled || disableNameEdit} fullWidth + maxLength={OBJECT_NAME_MAXIMUM_LENGTH} /> )} /> diff --git a/packages/twenty-front/src/modules/settings/integrations/utils/__tests__/getSettingsIntegrationAll.test.ts b/packages/twenty-front/src/modules/settings/integrations/utils/__tests__/getSettingsIntegrationAll.test.ts new file mode 100644 index 000000000000..f8815dab20f1 --- /dev/null +++ b/packages/twenty-front/src/modules/settings/integrations/utils/__tests__/getSettingsIntegrationAll.test.ts @@ -0,0 +1,48 @@ +import { getSettingsIntegrationAll } from '../getSettingsIntegrationAll'; + +describe('getSettingsIntegrationAll', () => { + it('should return null if imageUrl is null', () => { + expect( + getSettingsIntegrationAll({ + isAirtableIntegrationActive: true, + isAirtableIntegrationEnabled: true, + isPostgresqlIntegrationActive: true, + isPostgresqlIntegrationEnabled: true, + isStripeIntegrationActive: true, + isStripeIntegrationEnabled: true, + }), + ).toStrictEqual({ + integrations: [ + { + from: { + image: '/images/integrations/airtable-logo.png', + key: 'airtable', + }, + link: '/settings/integrations/airtable', + text: 'Airtable', + type: 'Active', + }, + { + from: { + image: '/images/integrations/postgresql-logo.png', + key: 'postgresql', + }, + link: '/settings/integrations/postgresql', + text: 'PostgreSQL', + type: 'Active', + }, + { + from: { + image: '/images/integrations/stripe-logo.png', + key: 'stripe', + }, + link: '/settings/integrations/stripe', + text: 'Stripe', + type: 'Active', + }, + ], + key: 'all', + title: 'All', + }); + }); +}); diff --git a/packages/twenty-front/src/modules/sign-in-background-mock/constants/SignInBackgroundMockColumnDefinitions.ts b/packages/twenty-front/src/modules/sign-in-background-mock/constants/SignInBackgroundMockColumnDefinitions.ts index d6072c52b178..cb0634772c95 100644 --- a/packages/twenty-front/src/modules/sign-in-background-mock/constants/SignInBackgroundMockColumnDefinitions.ts +++ b/packages/twenty-front/src/modules/sign-in-background-mock/constants/SignInBackgroundMockColumnDefinitions.ts @@ -64,7 +64,6 @@ export const SIGN_IN_BACKGROUND_MOCK_COLUMN_DEFINITIONS = ( type: FieldMetadataType.Relation, metadata: { fieldName: 'favorites', - placeHolder: 'Favorites', relationType: 'FROM_MANY_OBJECTS', relationObjectMetadataNameSingular: '', relationObjectMetadataNamePlural: '', @@ -79,7 +78,7 @@ export const SIGN_IN_BACKGROUND_MOCK_COLUMN_DEFINITIONS = ( fieldMetadataId: '20202020-ad10-4117-a039-3f04b7a5f939', label: 'Address', size: 100, - type: FieldMetadataType.Text, + type: FieldMetadataType.Address, metadata: { fieldName: 'address', placeHolder: 'Address', @@ -99,7 +98,6 @@ export const SIGN_IN_BACKGROUND_MOCK_COLUMN_DEFINITIONS = ( type: FieldMetadataType.Relation, metadata: { fieldName: 'accountOwner', - placeHolder: 'Account Owner', relationType: 'TO_ONE_OBJECT', relationObjectMetadataNameSingular: 'workspaceMember', relationObjectMetadataNamePlural: 'workspaceMembers', @@ -117,7 +115,6 @@ export const SIGN_IN_BACKGROUND_MOCK_COLUMN_DEFINITIONS = ( type: FieldMetadataType.Relation, metadata: { fieldName: 'people', - placeHolder: 'People', relationType: 'FROM_MANY_OBJECTS', relationObjectMetadataNameSingular: '', relationObjectMetadataNamePlural: '', @@ -135,7 +132,6 @@ export const SIGN_IN_BACKGROUND_MOCK_COLUMN_DEFINITIONS = ( type: FieldMetadataType.Relation, metadata: { fieldName: 'attachments', - placeHolder: 'Attachments', relationType: 'FROM_MANY_OBJECTS', relationObjectMetadataNameSingular: '', relationObjectMetadataNamePlural: '', @@ -204,7 +200,6 @@ export const SIGN_IN_BACKGROUND_MOCK_COLUMN_DEFINITIONS = ( type: FieldMetadataType.Relation, metadata: { fieldName: 'opportunities', - placeHolder: 'Opportunities', relationType: 'FROM_MANY_OBJECTS', relationObjectMetadataNameSingular: '', relationObjectMetadataNamePlural: '', @@ -239,7 +234,6 @@ export const SIGN_IN_BACKGROUND_MOCK_COLUMN_DEFINITIONS = ( type: FieldMetadataType.Relation, metadata: { fieldName: 'activityTargets', - placeHolder: 'Activities', relationType: 'FROM_MANY_OBJECTS', relationObjectMetadataNameSingular: '', relationObjectMetadataNamePlural: '', diff --git a/packages/twenty-front/src/modules/sign-in-background-mock/constants/SignInBackgroundMockCompanies.ts b/packages/twenty-front/src/modules/sign-in-background-mock/constants/SignInBackgroundMockCompanies.ts index f89118b90f17..c1bd907325af 100644 --- a/packages/twenty-front/src/modules/sign-in-background-mock/constants/SignInBackgroundMockCompanies.ts +++ b/packages/twenty-front/src/modules/sign-in-background-mock/constants/SignInBackgroundMockCompanies.ts @@ -10,7 +10,12 @@ export const SIGN_IN_BACKGROUND_MOCK_COMPANIES = [ __typename: 'FavoriteConnection', edges: [], }, - address: 'OLINDA SAS. 18 rue de Navarin, 75009 Paris', + address: { + addressStreet1: 'OLINDA SAS', + addressStreet2: '18 rue de Navarin', + addressCity: 'Paris', + addressPostcode: '75009', + }, accountOwner: null, people: { __typename: 'PersonConnection', @@ -115,7 +120,12 @@ export const SIGN_IN_BACKGROUND_MOCK_COMPANIES = [ __typename: 'FavoriteConnection', edges: [], }, - address: '1600 Amphitheatre Pkwy, Mountain View, CA 94043', + address: { + addressStreet1: '1600 Amphitheatre Pkwy', + addressStreet2: 'Mountain View', + addressState: 'CA', + addressPostcode: '94043', + }, accountOwner: null, people: { __typename: 'PersonConnection', @@ -314,7 +324,12 @@ export const SIGN_IN_BACKGROUND_MOCK_COMPANIES = [ __typename: 'FavoriteConnection', edges: [], }, - address: '1 Hacker Way, Menlo Park, CA 94025', + address: { + addressStreet1: '1 Hacker Way', + addressStreet2: 'Menlo Park', + addressState: 'CA', + addressPostcode: '94025', + }, accountOwner: null, people: { __typename: 'PersonConnection', @@ -400,7 +415,6 @@ export const SIGN_IN_BACKGROUND_MOCK_COMPANIES = [ node: { __typename: 'Opportunity', id: '53f66647-0543-4cc2-9f96-95cc699960f2', - probability: '0.5', pointOfContactId: '93c72d2e-f517-42fd-80ae-14173b3b70ae', stage: 'NEW', amount: { @@ -444,7 +458,12 @@ export const SIGN_IN_BACKGROUND_MOCK_COMPANIES = [ __typename: 'FavoriteConnection', edges: [], }, - address: '121 Albright Way, Los Gatos, CA 95032', + address: { + addressStreet1: '121 Albright Way', + addressStreet2: 'Los Gatos', + addressState: 'CA', + addressPostcode: '95032', + }, accountOwner: null, people: { __typename: 'PersonConnection', @@ -492,7 +511,12 @@ export const SIGN_IN_BACKGROUND_MOCK_COMPANIES = [ __typename: 'FavoriteConnection', edges: [], }, - address: '1 Microsoft Way, Redmond, WA 98052', + address: { + addressStreet1: '1 Microsoft Way', + addressStreet2: 'Redmond', + addressState: 'WA', + addressPostcode: '98052', + }, accountOwner: null, people: { __typename: 'PersonConnection', @@ -608,7 +632,6 @@ export const SIGN_IN_BACKGROUND_MOCK_COMPANIES = [ node: { __typename: 'Opportunity', id: '81ab695d-2f89-406f-90ea-180f433b2445', - probability: '0.5', stage: 'NEW', pointOfContactId: '9b324a88-6784-4449-afdf-dc62cb8702f2', amount: { @@ -628,7 +651,6 @@ export const SIGN_IN_BACKGROUND_MOCK_COMPANIES = [ node: { __typename: 'Opportunity', id: '9b059852-35b1-4045-9cde-42f715148954', - probability: '0.5', stage: 'NEW', pointOfContactId: '98406e26-80f1-4dff-b570-a74942528de3', amount: { @@ -672,7 +694,11 @@ export const SIGN_IN_BACKGROUND_MOCK_COMPANIES = [ __typename: 'FavoriteConnection', edges: [], }, - address: '42 Rue de Paradis, 75010 Paris', + address: { + addressStreet1: '42 rue de paradis', + addressCity: 'Paris', + addressPostcode: '75010', + }, accountOwner: null, people: { __typename: 'PersonConnection', @@ -720,7 +746,12 @@ export const SIGN_IN_BACKGROUND_MOCK_COMPANIES = [ __typename: 'FavoriteConnection', edges: [], }, - address: '888 Brannan Street San Francisco, CA 94103', + address: { + addressStreet1: '888 Brannan Street', + addressCity: 'San Francisco', + addressState: 'CA', + addressPostcode: '75010', + }, accountOwner: null, people: { __typename: 'PersonConnection', @@ -768,7 +799,13 @@ export const SIGN_IN_BACKGROUND_MOCK_COMPANIES = [ __typename: 'FavoriteConnection', edges: [], }, - address: '901 Fifth Avenue; Suite 1200; Seattle, WA 98164', + address: { + addressStreet1: '901 Fifth Avenue', + addressStreet2: 'Suite 1200', + addressCity: 'Seattle', + addressState: 'WA', + addressPostcode: '98164', + }, accountOwner: null, people: { __typename: 'PersonConnection', @@ -816,7 +853,13 @@ export const SIGN_IN_BACKGROUND_MOCK_COMPANIES = [ __typename: 'FavoriteConnection', edges: [], }, - address: '3790 El Camino Real, Unit 518, Palo Alto, CA 94306', + address: { + addressStreet1: '3790 El Camino Real', + addressStreet2: 'Unit 518', + addressCity: 'Palo Alto', + addressState: 'CA', + addressPostcode: '94306', + }, accountOwner: null, people: { __typename: 'PersonConnection', @@ -895,7 +938,11 @@ export const SIGN_IN_BACKGROUND_MOCK_COMPANIES = [ __typename: 'FavoriteConnection', edges: [], }, - address: '129, Samsung-ro, Yeongtong-gu, Suwon-si, Gyeonggi-do', + address: { + addressStreet1: '129, Samsung-ro', + addressStreet2: 'Yeongtong-gu, Suwon-si', + addressCity: 'Gyeonggi-do', + }, accountOwner: null, people: { __typename: 'PersonConnection', @@ -974,7 +1021,13 @@ export const SIGN_IN_BACKGROUND_MOCK_COMPANIES = [ __typename: 'FavoriteConnection', edges: [], }, - address: '576 Folsom St., Floor 3, San Francisco, CA 94105', + address: { + addressStreet1: '576 Folsom St.', + addressStreet2: 'Floor 3', + addressCity: 'San Francisco', + addressState: 'CA', + addressPostcode: '94105', + }, accountOwner: null, people: { __typename: 'PersonConnection', @@ -1022,7 +1075,10 @@ export const SIGN_IN_BACKGROUND_MOCK_COMPANIES = [ __typename: 'FavoriteConnection', edges: [], }, - address: '575 Lexington Ave 16th Floor, New York', + address: { + addressStreet1: '575 Lexington Ave 16th Floor', + addressCity: 'New York', + }, accountOwner: null, people: { __typename: 'PersonConnection', @@ -1070,7 +1126,13 @@ export const SIGN_IN_BACKGROUND_MOCK_COMPANIES = [ __typename: 'FavoriteConnection', edges: [], }, - address: '315 Montgomery St, 13th Fl. San Francisco, CA 94104', + address: { + addressStreet1: '315 Montgomery St', + addressStreet2: '13th Fl.', + addressCity: 'San Francisco', + addressState: 'CA', + addressPostcode: '94104', + }, accountOwner: null, people: { __typename: 'PersonConnection', @@ -1156,7 +1218,6 @@ export const SIGN_IN_BACKGROUND_MOCK_COMPANIES = [ node: { __typename: 'Opportunity', id: '7c887ee3-be10-412b-a663-16bd3c2228e1', - probability: '0.5', stage: 'NEW', pointOfContactId: '86083141-1c0e-494c-a1b6-85b1c6fefaa5', amount: { diff --git a/packages/twenty-front/src/modules/sign-in-background-mock/constants/SignInBackgroundMockFilterDefinitions.ts b/packages/twenty-front/src/modules/sign-in-background-mock/constants/SignInBackgroundMockFilterDefinitions.ts index 15a87498e30d..f53451ad7266 100644 --- a/packages/twenty-front/src/modules/sign-in-background-mock/constants/SignInBackgroundMockFilterDefinitions.ts +++ b/packages/twenty-front/src/modules/sign-in-background-mock/constants/SignInBackgroundMockFilterDefinitions.ts @@ -23,7 +23,7 @@ export const SIGN_IN_BACKGROUND_MOCK_FILTER_DEFINITIONS = [ fieldMetadataId: '20202020-ad10-4117-a039-3f04b7a5f939', label: 'Address', iconName: 'IconMap', - type: 'TEXT', + type: 'ADDRESS', }, { fieldMetadataId: '20202020-0739-495d-8e70-c0807f6b2268', diff --git a/packages/twenty-front/src/modules/spreadsheet-import/components/MatchColumnSelect.tsx b/packages/twenty-front/src/modules/spreadsheet-import/components/MatchColumnSelect.tsx index f4dbc49f0bcf..9908d66a94e9 100644 --- a/packages/twenty-front/src/modules/spreadsheet-import/components/MatchColumnSelect.tsx +++ b/packages/twenty-front/src/modules/spreadsheet-import/components/MatchColumnSelect.tsx @@ -66,7 +66,9 @@ export const MatchColumnSelect = ({ const handleSearchFilterChange = useCallback( (text: string) => { setOptions( - initialOptions.filter((option) => option.label.includes(text)), + initialOptions.filter((option) => + option.label.toLowerCase().includes(text.toLowerCase()), + ), ); }, [initialOptions], @@ -123,7 +125,7 @@ export const MatchColumnSelect = ({ <DropdownMenu data-select-disable ref={dropdownContainerRef} - width={refs.domReference.current?.clientWidth} + // width={refs.domReference.current?.clientWidth} > <DropdownMenuSearchInput value={searchFilter} diff --git a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/UploadFlow.tsx b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/UploadFlow.tsx index 7e79ed33fd5c..052082fe2941 100644 --- a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/UploadFlow.tsx +++ b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/UploadFlow.tsx @@ -12,7 +12,7 @@ import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/Snac import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; import { Modal } from '@/ui/layout/modal/components/Modal'; -import { MatchColumnsStep } from './MatchColumnsStep/MatchColumnsStep'; +import { Columns, MatchColumnsStep } from './MatchColumnsStep/MatchColumnsStep'; import { SelectHeaderStep } from './SelectHeaderStep/SelectHeaderStep'; import { SelectSheetStep } from './SelectSheetStep/SelectSheetStep'; import { UploadStep } from './UploadStep/UploadStep'; @@ -52,6 +52,7 @@ export type StepState = | { type: StepType.validateData; data: any[]; + importedColumns: Columns<string>; } | { type: StepType.loading; @@ -216,6 +217,7 @@ export const UploadFlow = ({ nextStep, prevStep }: UploadFlowProps) => { setState({ type: StepType.validateData, data, + importedColumns: columns, }); setPreviousState(state); nextStep(); @@ -233,6 +235,7 @@ export const UploadFlow = ({ nextStep, prevStep }: UploadFlowProps) => { return ( <ValidationStep initialData={state.data} + importedColumns={state.importedColumns} file={uploadedFile} onSubmitStart={() => setState({ diff --git a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/ValidationStep/ValidationStep.tsx b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/ValidationStep/ValidationStep.tsx index e9b6ebe8bbf0..ccf38c5be32f 100644 --- a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/ValidationStep/ValidationStep.tsx +++ b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/ValidationStep/ValidationStep.tsx @@ -8,6 +8,10 @@ import { Heading } from '@/spreadsheet-import/components/Heading'; import { StepNavigationButton } from '@/spreadsheet-import/components/StepNavigationButton'; import { Table } from '@/spreadsheet-import/components/Table'; import { useSpreadsheetImportInternal } from '@/spreadsheet-import/hooks/useSpreadsheetImportInternal'; +import { + Columns, + ColumnType, +} from '@/spreadsheet-import/steps/components/MatchColumnsStep/MatchColumnsStep'; import { Data } from '@/spreadsheet-import/types'; import { addErrorsAndRunHooks } from '@/spreadsheet-import/utils/dataMutations'; import { useDialogManager } from '@/ui/feedback/dialog-manager/hooks/useDialogManager'; @@ -62,6 +66,7 @@ const StyledNoRowsContainer = styled.div` type ValidationStepProps<T extends string> = { initialData: Data<T>[]; + importedColumns: Columns<string>; file: File; onSubmitStart?: () => void; onBack: () => void; @@ -69,6 +74,7 @@ type ValidationStepProps<T extends string> = { export const ValidationStep = <T extends string>({ initialData, + importedColumns, file, onSubmitStart, onBack, @@ -88,6 +94,7 @@ export const ValidationStep = <T extends string>({ ReadonlySet<number | string> >(new Set()); const [filterByErrors, setFilterByErrors] = useState(false); + const [showUnmatchedColumns, setShowUnmatchedColumns] = useState(false); const updateData = useCallback( (rows: typeof data) => { @@ -127,7 +134,30 @@ export const ValidationStep = <T extends string>({ [data, updateData], ); - const columns = useMemo(() => generateColumns(fields), [fields]); + const columns = useMemo( + () => + generateColumns(fields) + .map((column) => { + const hasBeenImported = + importedColumns.filter( + (importColumn) => + (importColumn.type === ColumnType.matched && + importColumn.value === column.key) || + (importColumn.type === ColumnType.matchedSelect && + importColumn.value === column.key) || + (importColumn.type === ColumnType.matchedSelectOptions && + importColumn.value === column.key) || + (importColumn.type === ColumnType.matchedCheckbox && + importColumn.value === column.key) || + column.key === 'select-row', + ).length > 0; + + if (!hasBeenImported && !showUnmatchedColumns) return null; + return column; + }) + .filter(Boolean), + [fields, importedColumns, showUnmatchedColumns], + ); const tableData = useMemo(() => { if (filterByErrors) { @@ -212,6 +242,15 @@ export const ValidationStep = <T extends string>({ Show only rows with errors </StyledErrorToggleDescription> </StyledErrorToggle> + <StyledErrorToggle> + <Toggle + value={showUnmatchedColumns} + onChange={() => setShowUnmatchedColumns(!showUnmatchedColumns)} + /> + <StyledErrorToggleDescription> + Show unmatched columns + </StyledErrorToggleDescription> + </StyledErrorToggle> <Button Icon={IconTrash} title="Remove" diff --git a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/__stories__/Validation.stories.tsx b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/__stories__/Validation.stories.tsx index e2d79644ab47..1a5adabc0346 100644 --- a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/__stories__/Validation.stories.tsx +++ b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/__stories__/Validation.stories.tsx @@ -5,6 +5,7 @@ import { Providers } from '@/spreadsheet-import/components/Providers'; import { ValidationStep } from '@/spreadsheet-import/steps/components/ValidationStep/ValidationStep'; import { editableTableInitialData, + importedColums, mockRsiValues, } from '@/spreadsheet-import/tests/mockRsiValues'; import { DialogManagerScope } from '@/ui/feedback/dialog-manager/scopes/DialogManagerScope'; @@ -28,6 +29,7 @@ export const Default = () => ( <ValidationStep initialData={editableTableInitialData} file={file} + importedColumns={importedColums} onBack={() => Promise.resolve()} /> </ModalWrapper> diff --git a/packages/twenty-front/src/modules/spreadsheet-import/tests/mockRsiValues.ts b/packages/twenty-front/src/modules/spreadsheet-import/tests/mockRsiValues.ts index 814dae7a29e3..27dc64dabd8d 100644 --- a/packages/twenty-front/src/modules/spreadsheet-import/tests/mockRsiValues.ts +++ b/packages/twenty-front/src/modules/spreadsheet-import/tests/mockRsiValues.ts @@ -1,4 +1,5 @@ import { defaultSpreadsheetImportProps } from '@/spreadsheet-import/provider/components/SpreadsheetImport'; +import { Columns } from '@/spreadsheet-import/steps/components/MatchColumnsStep/MatchColumnsStep'; import { Fields, SpreadsheetOptions } from '@/spreadsheet-import/types'; import { sleep } from '~/utils/sleep'; @@ -88,6 +89,33 @@ const fields = [ }, ] as Fields<string>; +export const importedColums: Columns<string> = [ + { + header: 'Name', + index: 0, + type: 2, + value: 'name', + }, + { + header: 'Surname', + index: 1, + type: 2, + value: 'surname', + }, + { + header: 'Age', + index: 2, + type: 2, + value: 'age', + }, + { + header: 'Team', + index: 3, + type: 2, + value: 'team', + }, +]; + const mockComponentBehaviourForTypes = <T extends string>( props: SpreadsheetOptions<T>, ) => props; diff --git a/packages/twenty-front/src/modules/spreadsheet-import/utils/__tests__/setColumn.test.ts b/packages/twenty-front/src/modules/spreadsheet-import/utils/__tests__/setColumn.test.ts index 012dfbabfc31..e71aaddfa869 100644 --- a/packages/twenty-front/src/modules/spreadsheet-import/utils/__tests__/setColumn.test.ts +++ b/packages/twenty-front/src/modules/spreadsheet-import/utils/__tests__/setColumn.test.ts @@ -20,10 +20,13 @@ describe('setColumn', () => { value: 'oldValue', }; - it('should return a matchedSelect column if field type is "select"', () => { + it('should return a matchedSelectOptions column if field type is "select"', () => { const field = { ...defaultField, - fieldType: { type: 'select' }, + fieldType: { + type: 'select', + options: [{ value: 'John' }, { value: 'Alice' }], + }, } as Field<'Name'>; const data = [['John'], ['Alice']]; @@ -32,14 +35,16 @@ describe('setColumn', () => { expect(result).toEqual({ index: 0, header: 'Name', - type: ColumnType.matchedSelect, + type: ColumnType.matchedSelectOptions, value: 'Name', matchedOptions: [ { entry: 'John', + value: 'John', }, { entry: 'Alice', + value: 'Alice', }, ], }); diff --git a/packages/twenty-front/src/modules/spreadsheet-import/utils/setColumn.ts b/packages/twenty-front/src/modules/spreadsheet-import/utils/setColumn.ts index 0b428321872c..191cdf2081cc 100644 --- a/packages/twenty-front/src/modules/spreadsheet-import/utils/setColumn.ts +++ b/packages/twenty-front/src/modules/spreadsheet-import/utils/setColumn.ts @@ -2,6 +2,7 @@ import { Column, ColumnType, MatchColumnsStepProps, + MatchedOptions, } from '@/spreadsheet-import/steps/components/MatchColumnsStep/MatchColumnsStep'; import { Field } from '@/spreadsheet-import/types'; @@ -12,33 +13,56 @@ export const setColumn = <T extends string>( field?: Field<T>, data?: MatchColumnsStepProps<T>['data'], ): Column<T> => { - switch (field?.fieldType.type) { - case 'select': - return { - ...oldColumn, - type: ColumnType.matchedSelect, - value: field.key, - matchedOptions: uniqueEntries(data || [], oldColumn.index), - }; - case 'checkbox': - return { - index: oldColumn.index, - type: ColumnType.matchedCheckbox, - value: field.key, - header: oldColumn.header, - }; - case 'input': - return { - index: oldColumn.index, - type: ColumnType.matched, - value: field.key, - header: oldColumn.header, - }; - default: - return { - index: oldColumn.index, - header: oldColumn.header, - type: ColumnType.empty, - }; + if (field?.fieldType.type === 'select') { + const fieldOptions = field.fieldType.options; + const uniqueData = uniqueEntries( + data || [], + oldColumn.index, + ) as MatchedOptions<T>[]; + const matchedOptions = uniqueData.map((record) => { + const value = fieldOptions.find( + (fieldOption) => + fieldOption.value === record.entry || + fieldOption.label === record.entry, + )?.value; + return value + ? ({ ...record, value } as MatchedOptions<T>) + : (record as MatchedOptions<T>); + }); + const allMatched = + matchedOptions.filter((o) => o.value).length === uniqueData?.length; + + return { + ...oldColumn, + type: allMatched + ? ColumnType.matchedSelectOptions + : ColumnType.matchedSelect, + value: field.key, + matchedOptions, + }; + } + + if (field?.fieldType.type === 'checkbox') { + return { + index: oldColumn.index, + type: ColumnType.matchedCheckbox, + value: field.key, + header: oldColumn.header, + }; } + + if (field?.fieldType.type === 'input') { + return { + index: oldColumn.index, + type: ColumnType.matched, + value: field.key, + header: oldColumn.header, + }; + } + + return { + index: oldColumn.index, + header: oldColumn.header, + type: ColumnType.empty, + }; }; diff --git a/packages/twenty-front/src/modules/support/components/__stories__/SupportChat.stories.tsx b/packages/twenty-front/src/modules/support/components/__stories__/SupportChat.stories.tsx index 7da022306500..da0c12334d18 100644 --- a/packages/twenty-front/src/modules/support/components/__stories__/SupportChat.stories.tsx +++ b/packages/twenty-front/src/modules/support/components/__stories__/SupportChat.stories.tsx @@ -10,7 +10,7 @@ import { supportChatState } from '@/client-config/states/supportChatState'; import { graphqlMocks } from '~/testing/graphqlMocks'; import { mockDefaultWorkspace, - mockedUsersData, + mockedUserData, mockedWorkspaceMemberData, } from '~/testing/mock-data/users'; @@ -30,7 +30,7 @@ const meta: Meta<typeof SupportChat> = { setCurrentWorkspace(mockDefaultWorkspace); setCurrentWorkspaceMember(mockedWorkspaceMemberData); - setCurrentUser(mockedUsersData[0]); + setCurrentUser(mockedUserData); setSupportChat({ supportDriver: 'front', supportFrontChatId: '1234' }); return <Story />; diff --git a/packages/twenty-front/src/modules/ui/display/info/components/Info.tsx b/packages/twenty-front/src/modules/ui/display/info/components/Info.tsx index 822c193e8d15..e97dbbb4388d 100644 --- a/packages/twenty-front/src/modules/ui/display/info/components/Info.tsx +++ b/packages/twenty-front/src/modules/ui/display/info/components/Info.tsx @@ -1,8 +1,10 @@ import React from 'react'; +import { Link } from 'react-router-dom'; import { css, useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { IconInfoCircle } from 'twenty-ui'; +import { AppPath } from '@/types/AppPath'; import { Button } from '@/ui/input/button/components/Button'; export type InfoAccent = 'blue' | 'danger'; @@ -11,6 +13,7 @@ export type InfoProps = { text: string; buttonTitle?: string; onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void; + to?: AppPath; }; const StyledTextContainer = styled.div` @@ -30,6 +33,7 @@ const StyledInfo = styled.div<Pick<InfoProps, 'accent'>>` font-weight: ${({ theme }) => theme.font.weight.medium}; justify-content: space-between; max-width: 512px; + gap: ${({ theme }) => theme.spacing(2)}; padding: ${({ theme }) => theme.spacing(2)}; ${({ theme, accent }) => { switch (accent) { @@ -46,11 +50,17 @@ const StyledInfo = styled.div<Pick<InfoProps, 'accent'>>` } }} `; + +const StyledLink = styled(Link)` + text-decoration: none; +`; + export const Info = ({ accent = 'blue', text, buttonTitle, onClick, + to, }: InfoProps) => { const theme = useTheme(); return ( @@ -59,12 +69,23 @@ export const Info = ({ <StyledIconInfoCircle size={theme.icon.size.md} /> {text} </StyledTextContainer> - {buttonTitle && onClick && ( + {buttonTitle && to && ( + <StyledLink to={to}> + <Button + title={buttonTitle} + size={'small'} + variant={'secondary'} + accent={accent} + /> + </StyledLink> + )} + {buttonTitle && onClick && !to && ( <Button title={buttonTitle} onClick={onClick} size={'small'} variant={'secondary'} + accent={accent} /> )} </StyledInfo> diff --git a/packages/twenty-front/src/modules/ui/feedback/dialog-manager/components/Dialog.tsx b/packages/twenty-front/src/modules/ui/feedback/dialog-manager/components/Dialog.tsx index 905bbe033638..90e0a4d22480 100644 --- a/packages/twenty-front/src/modules/ui/feedback/dialog-manager/components/Dialog.tsx +++ b/packages/twenty-front/src/modules/ui/feedback/dialog-manager/components/Dialog.tsx @@ -1,6 +1,6 @@ -import { useCallback } from 'react'; import styled from '@emotion/styled'; import { motion } from 'framer-motion'; +import { useCallback } from 'react'; import { Key } from 'ts-key-enum'; import { Button } from '@/ui/input/button/components/Button'; @@ -13,7 +13,7 @@ const StyledDialogOverlay = styled(motion.div)` align-items: center; background: ${({ theme }) => theme.background.overlay}; display: flex; - height: 100vh; + height: 100dvh; justify-content: center; left: 0; position: fixed; diff --git a/packages/twenty-front/src/modules/ui/field/display/components/LinksDisplay.tsx b/packages/twenty-front/src/modules/ui/field/display/components/LinksDisplay.tsx index ee58d124fbda..339859dfe62a 100644 --- a/packages/twenty-front/src/modules/ui/field/display/components/LinksDisplay.tsx +++ b/packages/twenty-front/src/modules/ui/field/display/components/LinksDisplay.tsx @@ -59,7 +59,7 @@ export const LinksDisplay = ({ value, isFocused }: LinksDisplayProps) => { ); return isFocused ? ( - <ExpandableList isChipCountDisplayed={isFocused}> + <ExpandableList isChipCountDisplayed> {links.map(({ url, label, type }, index) => type === LinkType.LinkedIn || type === LinkType.Twitter ? ( <SocialLink key={index} href={url} type={type} label={label} /> diff --git a/packages/twenty-front/src/modules/ui/field/input/components/DateInput.tsx b/packages/twenty-front/src/modules/ui/field/input/components/DateInput.tsx index 4b2131ad5ae5..1e74e447b5ac 100644 --- a/packages/twenty-front/src/modules/ui/field/input/components/DateInput.tsx +++ b/packages/twenty-front/src/modules/ui/field/input/components/DateInput.tsx @@ -33,6 +33,7 @@ export type DateInputProps = { onChange?: (newDate: Nullable<Date>) => void; isDateTimeInput?: boolean; onClear?: () => void; + onSubmit?: (newDate: Nullable<Date>) => void; }; export const DateInput = ({ @@ -44,6 +45,7 @@ export const DateInput = ({ onChange, isDateTimeInput, onClear, + onSubmit, }: DateInputProps) => { const [internalValue, setInternalValue] = useState(value); @@ -59,6 +61,11 @@ export const DateInput = ({ onClear?.(); }; + const handleMouseSelect = (newDate: Date | null) => { + setInternalValue(newDate); + onSubmit?.(newDate); + }; + const { closeDropdown } = useDropdown(MONTH_AND_YEAR_DROPDOWN_ID); const { closeDropdown: closeDropdownMonthSelect } = useDropdown( MONTH_AND_YEAR_DROPDOWN_MONTH_SELECT_ID, @@ -86,9 +93,7 @@ export const DateInput = ({ <InternalDatePicker date={internalValue ?? new Date()} onChange={handleChange} - onMouseSelect={(newDate: Date | null) => { - onEnter(newDate); - }} + onMouseSelect={handleMouseSelect} clearable={clearable ? clearable : false} isDateTimeInput={isDateTimeInput} onEnter={onEnter} diff --git a/packages/twenty-front/src/modules/ui/field/input/components/FieldTextAreaOverlay.tsx b/packages/twenty-front/src/modules/ui/field/input/components/FieldTextAreaOverlay.tsx index 6ebabfc23d5a..6be66c368982 100644 --- a/packages/twenty-front/src/modules/ui/field/input/components/FieldTextAreaOverlay.tsx +++ b/packages/twenty-front/src/modules/ui/field/input/components/FieldTextAreaOverlay.tsx @@ -2,10 +2,12 @@ import styled from '@emotion/styled'; import { OVERLAY_BACKGROUND } from 'twenty-ui'; const StyledFieldTextAreaOverlay = styled.div` + position: absolute; + top: 0; border-radius: ${({ theme }) => theme.border.radius.sm}; align-items: center; display: flex; - height: 32px; + max-height: 420px; margin: -1px; width: 100%; ${OVERLAY_BACKGROUND} diff --git a/packages/twenty-front/src/modules/ui/field/input/components/PhoneInput.tsx b/packages/twenty-front/src/modules/ui/field/input/components/PhoneInput.tsx index 2b8a406c8765..7094123dd18b 100644 --- a/packages/twenty-front/src/modules/ui/field/input/components/PhoneInput.tsx +++ b/packages/twenty-front/src/modules/ui/field/input/components/PhoneInput.tsx @@ -28,7 +28,7 @@ const StyledCustomPhoneInput = styled(ReactPhoneNumberInput)` padding: 0; .PhoneInputInput { - background: ${({ theme }) => theme.background.transparent.secondary}; + background: none; border: none; color: ${({ theme }) => theme.font.color.primary}; diff --git a/packages/twenty-front/src/modules/ui/field/input/components/RatingInput.tsx b/packages/twenty-front/src/modules/ui/field/input/components/RatingInput.tsx index 58d1fd060b06..c5dd404e59c9 100644 --- a/packages/twenty-front/src/modules/ui/field/input/components/RatingInput.tsx +++ b/packages/twenty-front/src/modules/ui/field/input/components/RatingInput.tsx @@ -1,7 +1,6 @@ -import { useState } from 'react'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; -import { IconTwentyStarFilled } from 'twenty-ui'; +import { useContext, useState } from 'react'; +import { styled } from '@linaria/react'; +import { IconTwentyStarFilled, THEME_COMMON, ThemeContext } from 'twenty-ui'; import { RATING_VALUES } from '@/object-record/record-field/meta-types/constants/RatingValues'; import { FieldRatingValue } from '@/object-record/record-field/types/FieldMetadata'; @@ -11,29 +10,38 @@ const StyledContainer = styled.div` display: flex; `; -const StyledRatingIconContainer = styled.div<{ isActive?: boolean }>` - color: ${({ isActive, theme }) => - isActive ? theme.font.color.secondary : theme.background.quaternary}; +const StyledRatingIconContainer = styled.div<{ + color: string; +}>` + color: ${({ color }) => color}; display: inline-flex; `; type RatingInputProps = { - onChange: (newValue: FieldRatingValue) => void; + onChange?: (newValue: FieldRatingValue) => void; value: FieldRatingValue; readonly?: boolean; }; +const iconSizeMd = THEME_COMMON.icon.size.md; + export const RatingInput = ({ onChange, value, readonly, }: RatingInputProps) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); + + const activeColor = theme.font.color.secondary; + const inactiveColor = theme.background.quaternary; + const [hoveredValue, setHoveredValue] = useState<FieldRatingValue | null>( null, ); const currentValue = hoveredValue ?? value; + const selectedIndex = RATING_VALUES.indexOf(currentValue); + return ( <StyledContainer role="slider" @@ -44,17 +52,17 @@ export const RatingInput = ({ tabIndex={0} > {RATING_VALUES.map((value, index) => { - const currentIndex = RATING_VALUES.indexOf(currentValue); + const isActive = index <= selectedIndex; return ( <StyledRatingIconContainer key={index} - isActive={index <= currentIndex} - onClick={readonly ? undefined : () => onChange(value)} + color={isActive ? activeColor : inactiveColor} + onClick={readonly ? undefined : () => onChange?.(value)} onMouseEnter={readonly ? undefined : () => setHoveredValue(value)} onMouseLeave={readonly ? undefined : () => setHoveredValue(null)} > - <IconTwentyStarFilled size={theme.icon.size.md} /> + <IconTwentyStarFilled size={iconSizeMd} /> </StyledRatingIconContainer> ); })} diff --git a/packages/twenty-front/src/modules/ui/field/input/components/TextAreaInput.tsx b/packages/twenty-front/src/modules/ui/field/input/components/TextAreaInput.tsx index d14efa233d55..b9a08ef1f87c 100644 --- a/packages/twenty-front/src/modules/ui/field/input/components/TextAreaInput.tsx +++ b/packages/twenty-front/src/modules/ui/field/input/components/TextAreaInput.tsx @@ -30,6 +30,7 @@ const StyledTextArea = styled(TextareaAutosize)` display: flex; justify-content: center; resize: none; + max-height: 400px; width: calc(100% - ${({ theme }) => theme.spacing(7)}); `; diff --git a/packages/twenty-front/src/modules/ui/input/button/components/Button.tsx b/packages/twenty-front/src/modules/ui/input/button/components/Button.tsx index 375b55fdf3ed..a90daab5bb9d 100644 --- a/packages/twenty-front/src/modules/ui/input/button/components/Button.tsx +++ b/packages/twenty-front/src/modules/ui/input/button/components/Button.tsx @@ -1,8 +1,8 @@ -import React from 'react'; -import { Link } from 'react-router-dom'; import isPropValid from '@emotion/is-prop-valid'; import { css, useTheme } from '@emotion/react'; import styled from '@emotion/styled'; +import React from 'react'; +import { Link } from 'react-router-dom'; import { IconComponent, Pill } from 'twenty-ui'; export type ButtonSize = 'medium' | 'small'; @@ -27,6 +27,7 @@ export type ButtonProps = { onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void; to?: string; target?: string; + dataTestId?: string; } & React.ComponentProps<'button'>; const StyledButton = styled('button', { @@ -374,6 +375,7 @@ export const Button = ({ onClick, to, target, + dataTestId, }: ButtonProps) => { const theme = useTheme(); @@ -393,6 +395,7 @@ export const Button = ({ to={to} as={to ? Link : 'button'} target={target} + data-testid={dataTestId} > {Icon && <Icon size={theme.icon.size.sm} />} {title} diff --git a/packages/twenty-front/src/modules/ui/input/button/components/FloatingButton.tsx b/packages/twenty-front/src/modules/ui/input/button/components/FloatingButton.tsx index 7ccecc0ffe6f..4f0dbcaf6c35 100644 --- a/packages/twenty-front/src/modules/ui/input/button/components/FloatingButton.tsx +++ b/packages/twenty-front/src/modules/ui/input/button/components/FloatingButton.tsx @@ -1,6 +1,6 @@ -import React from 'react'; import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; +import { Link } from 'react-router-dom'; import { IconComponent } from 'twenty-ui'; export type FloatingButtonSize = 'small' | 'medium'; @@ -16,12 +16,19 @@ export type FloatingButtonProps = { applyBlur?: boolean; disabled?: boolean; focus?: boolean; + to?: string; }; const StyledButton = styled.button< Pick< FloatingButtonProps, - 'size' | 'focus' | 'position' | 'applyBlur' | 'applyShadow' | 'position' + | 'size' + | 'focus' + | 'position' + | 'applyBlur' + | 'applyShadow' + | 'position' + | 'to' > >` align-items: center; @@ -87,6 +94,7 @@ const StyledButton = styled.button< &:focus { outline: none; } + text-decoration: none; `; export const FloatingButton = ({ @@ -99,6 +107,7 @@ export const FloatingButton = ({ applyShadow = true, disabled = false, focus = false, + to, }: FloatingButtonProps) => { const theme = useTheme(); return ( @@ -110,6 +119,8 @@ export const FloatingButton = ({ applyShadow={applyShadow} position={position} className={className} + to={to} + as={to ? Link : 'button'} > {Icon && <Icon size={theme.icon.size.sm} />} {title} diff --git a/packages/twenty-front/src/modules/ui/input/button/components/LightIconButton.tsx b/packages/twenty-front/src/modules/ui/input/button/components/LightIconButton.tsx index 5f03c700e0c9..868ed0c534a7 100644 --- a/packages/twenty-front/src/modules/ui/input/button/components/LightIconButton.tsx +++ b/packages/twenty-front/src/modules/ui/input/button/components/LightIconButton.tsx @@ -105,7 +105,7 @@ export const LightIconButton = ({ active={active} title={title} > - {Icon && <Icon size={theme.icon.size.sm} stroke={theme.icon.stroke.sm} />} + {Icon && <Icon size={theme.icon.size.sm} />} </StyledButton> ); }; diff --git a/packages/twenty-front/src/modules/ui/input/components/AutosizeTextInput.tsx b/packages/twenty-front/src/modules/ui/input/components/AutosizeTextInput.tsx index b827b8e08fd5..eb9afd68a398 100644 --- a/packages/twenty-front/src/modules/ui/input/components/AutosizeTextInput.tsx +++ b/packages/twenty-front/src/modules/ui/input/components/AutosizeTextInput.tsx @@ -30,6 +30,8 @@ type AutosizeTextInputProps = { value?: string; className?: string; onBlur?: () => void; + autoFocus?: boolean; + disabled?: boolean; }; const StyledContainer = styled.div` @@ -123,6 +125,8 @@ export const AutosizeTextInput = ({ value = '', className, onBlur, + autoFocus, + disabled, }: AutosizeTextInputProps) => { const [isFocused, setIsFocused] = useState(false); const [isHidden, setIsHidden] = useState( @@ -212,7 +216,9 @@ export const AutosizeTextInput = ({ {!isHidden && ( <StyledTextArea ref={textInputRef} - autoFocus={variant === AutosizeTextInputVariant.Button} + autoFocus={ + autoFocus || variant === AutosizeTextInputVariant.Button + } placeholder={placeholder ?? 'Write a comment'} maxRows={MAX_ROWS} minRows={computedMinRows} @@ -221,6 +227,7 @@ export const AutosizeTextInput = ({ onFocus={handleFocus} onBlur={handleBlur} variant={variant} + disabled={disabled} /> )} {variant === AutosizeTextInputVariant.Icon && ( diff --git a/packages/twenty-front/src/modules/ui/input/components/Radio.tsx b/packages/twenty-front/src/modules/ui/input/components/Radio.tsx index 1626e1321400..5530aaa3a332 100644 --- a/packages/twenty-front/src/modules/ui/input/components/Radio.tsx +++ b/packages/twenty-front/src/modules/ui/input/components/Radio.tsx @@ -1,8 +1,9 @@ -import * as React from 'react'; import styled from '@emotion/styled'; import { motion } from 'framer-motion'; +import * as React from 'react'; import { RGBA } from 'twenty-ui'; +import { v4 } from 'uuid'; import { RadioGroup } from './RadioGroup'; export enum RadioSize { @@ -105,6 +106,7 @@ const StyledLabel = styled.label<LabelProps>` export type RadioProps = { checked?: boolean; className?: string; + name?: string; disabled?: boolean; label?: string; labelPosition?: LabelPosition; @@ -118,6 +120,7 @@ export type RadioProps = { export const Radio = ({ checked, className, + name = 'input-radio', disabled = false, label, labelPosition = LabelPosition.Right, @@ -131,12 +134,14 @@ export const Radio = ({ onCheckedChange?.(event.target.checked); }; + const optionId = v4(); + return ( <StyledContainer className={className} labelPosition={labelPosition}> <StyledRadioInput type="radio" - id="input-radio" - name="input-radio" + id={optionId} + name={name} data-testid="input-radio" checked={checked} value={value || label} @@ -149,7 +154,7 @@ export const Radio = ({ /> {label && ( <StyledLabel - htmlFor="input-radio" + htmlFor={optionId} labelPosition={labelPosition} disabled={disabled} > diff --git a/packages/twenty-front/src/modules/ui/input/components/TextInputV2.tsx b/packages/twenty-front/src/modules/ui/input/components/TextInputV2.tsx index 19a0b92ada0a..530f27a7c1aa 100644 --- a/packages/twenty-front/src/modules/ui/input/components/TextInputV2.tsx +++ b/packages/twenty-front/src/modules/ui/input/components/TextInputV2.tsx @@ -145,6 +145,7 @@ const TextInputV2Component = ( RightIcon, LeftIcon, autoComplete, + maxLength, }: TextInputV2ComponentProps, // eslint-disable-next-line @nx/workspace-component-props-naming ref: ForwardedRef<HTMLInputElement>, @@ -182,7 +183,15 @@ const TextInputV2Component = ( onChange?.(event.target.value); }} onKeyDown={onKeyDown} - {...{ autoFocus, disabled, placeholder, required, value, LeftIcon }} + {...{ + autoFocus, + disabled, + placeholder, + required, + value, + LeftIcon, + maxLength, + }} /> <StyledTrailingIconContainer> {error && ( diff --git a/packages/twenty-front/src/modules/ui/input/components/__stories__/IconPicker.stories.tsx b/packages/twenty-front/src/modules/ui/input/components/__stories__/IconPicker.stories.tsx index 16499b234406..fc8faa2a7705 100644 --- a/packages/twenty-front/src/modules/ui/input/components/__stories__/IconPicker.stories.tsx +++ b/packages/twenty-front/src/modules/ui/input/components/__stories__/IconPicker.stories.tsx @@ -37,8 +37,8 @@ type Story = StoryObj<typeof IconPicker>; export const Default: Story = {}; export const WithOpen: Story = { - play: async ({ canvasElement }) => { - const canvas = within(canvasElement); + play: async () => { + const canvas = within(document.body); const iconPickerButton = await canvas.findByRole('button', { name: 'Click to select icon (no icon selected)', @@ -54,8 +54,8 @@ export const WithSelectedIcon: Story = { export const WithOpenAndSelectedIcon: Story = { ...WithSelectedIcon, - play: async ({ canvasElement }) => { - const canvas = within(canvasElement); + play: async () => { + const canvas = within(document.body); const iconPickerButton = await canvas.findByRole('button', { name: 'Click to select icon (selected: IconCalendarEvent)', @@ -67,8 +67,8 @@ export const WithOpenAndSelectedIcon: Story = { export const WithSearch: Story = { ...WithSelectedIcon, - play: async ({ canvasElement }) => { - const canvas = within(canvasElement); + play: async () => { + const canvas = within(document.body); const iconPickerButton = await canvas.findByRole('button', { name: 'Click to select icon (selected: IconCalendarEvent)', @@ -92,8 +92,8 @@ export const WithSearch: Story = { export const WithSearchAndClose: Story = { ...WithSelectedIcon, - play: async ({ canvasElement }) => { - const canvas = within(canvasElement); + play: async () => { + const canvas = within(document.body); let iconPickerButton = await canvas.findByRole('button', { name: 'Click to select icon (selected: IconCalendarEvent)', diff --git a/packages/twenty-front/src/modules/ui/input/components/internal/date/components/DateTimeInput.tsx b/packages/twenty-front/src/modules/ui/input/components/internal/date/components/DateTimeInput.tsx index 5d103375368a..239f8050922f 100644 --- a/packages/twenty-front/src/modules/ui/input/components/internal/date/components/DateTimeInput.tsx +++ b/packages/twenty-front/src/modules/ui/input/components/internal/date/components/DateTimeInput.tsx @@ -12,10 +12,13 @@ import { MAX_DATE } from '@/ui/input/components/internal/date/constants/MaxDate' import { MIN_DATE } from '@/ui/input/components/internal/date/constants/MinDate'; const StyledInputContainer = styled.div` - width: 100%; - display: flex; + align-items: center; border-bottom: 1px solid ${({ theme }) => theme.border.color.light}; + border-top-left-radius: ${({ theme }) => theme.border.radius.md}; + border-top-right-radius: ${({ theme }) => theme.border.radius.md}; + display: flex; height: ${({ theme }) => theme.spacing(8)}; + width: 100%; `; const StyledInput = styled.input<{ hasError?: boolean }>` @@ -23,7 +26,7 @@ const StyledInput = styled.input<{ hasError?: boolean }>` border: none; color: ${({ theme }) => theme.font.color.primary}; outline: none; - padding: 8px; + padding: 4px 8px 4px 8px; font-weight: 500; font-size: ${({ theme }) => theme.font.size.md}; width: 100%; @@ -54,11 +57,25 @@ export const DateTimeInput = ({ (date: any) => { const dateParsed = DateTime.fromJSDate(date); - const formattedDate = dateParsed.toFormat(parsingFormat); + const dateWithoutTime = DateTime.fromJSDate(date) + .toLocal() + .set({ + day: date.getUTCDate(), + month: date.getUTCMonth() + 1, + year: date.getUTCFullYear(), + hour: 0, + minute: 0, + second: 0, + millisecond: 0, + }); + + const formattedDate = isDateTimeInput + ? dateParsed.toFormat(parsingFormat) + : dateWithoutTime.toFormat(parsingFormat); return formattedDate; }, - [parsingFormat], + [parsingFormat, isDateTimeInput], ); const parseStringToDate = (str: string) => { diff --git a/packages/twenty-front/src/modules/ui/input/components/internal/date/components/InternalDatePicker.tsx b/packages/twenty-front/src/modules/ui/input/components/internal/date/components/InternalDatePicker.tsx index a45855074b33..95a1164cf79f 100644 --- a/packages/twenty-front/src/modules/ui/input/components/internal/date/components/InternalDatePicker.tsx +++ b/packages/twenty-front/src/modules/ui/input/components/internal/date/components/InternalDatePicker.tsx @@ -1,6 +1,6 @@ -import ReactDatePicker from 'react-datepicker'; import styled from '@emotion/styled'; import { DateTime } from 'luxon'; +import ReactDatePicker from 'react-datepicker'; import { Key } from 'ts-key-enum'; import { IconCalendarX, @@ -298,7 +298,7 @@ const StyledCustomDatePickerHeader = styled.div` `; export type InternalDatePickerProps = { - date: Date; + date: Date | null; onMouseSelect?: (date: Date | null) => void; onChange?: (date: Date | null) => void; clearable?: boolean; @@ -372,30 +372,47 @@ export const InternalDatePicker = ({ }; const handleChangeMonth = (month: number) => { - const newDate = new Date(date); + const newDate = new Date(internalDate); newDate.setMonth(month); onChange?.(newDate); }; const handleChangeYear = (year: number) => { - const newDate = new Date(date); + const newDate = new Date(internalDate); newDate.setFullYear(year); onChange?.(newDate); }; + const dateWithoutTime = DateTime.fromJSDate(internalDate) + .toLocal() + .set({ + day: internalDate.getUTCDate(), + month: internalDate.getUTCMonth() + 1, + year: internalDate.getUTCFullYear(), + hour: 0, + minute: 0, + second: 0, + millisecond: 0, + }) + .toJSDate(); + const dateToUse = isDateTimeInput ? date : dateWithoutTime; + return ( <StyledContainer onKeyDown={handleKeyDown}> <div className={clearable ? 'clearable ' : ''}> <ReactDatePicker open={true} - selected={internalDate} - openToDate={internalDate} + selected={dateToUse} + openToDate={isDefined(dateToUse) ? dateToUse : undefined} + disabledKeyboardNavigation onChange={(newDate) => { + newDate?.setHours(internalDate.getUTCHours()); + newDate?.setUTCMinutes(internalDate.getUTCMinutes()); onChange?.(newDate); }} customInput={ <DateTimeInput - date={internalDate} + date={dateToUse} isDateTimeInput={isDateTimeInput} onChange={onChange} /> @@ -424,13 +441,13 @@ export const InternalDatePicker = ({ options={months} disableBlur onChange={handleChangeMonth} - value={date.getMonth()} + value={internalDate.getUTCMonth()} fullWidth /> <Select dropdownId={MONTH_AND_YEAR_DROPDOWN_YEAR_SELECT_ID} onChange={handleChangeYear} - value={date.getFullYear()} + value={internalDate.getUTCFullYear()} options={years} disableBlur fullWidth @@ -450,16 +467,24 @@ export const InternalDatePicker = ({ </StyledCustomDatePickerHeader> </> )} - onSelect={(date: Date, event) => { - const dateUTC = DateTime.fromJSDate(date, { - zone: 'utc', - }).toJSDate(); - - if (event?.type === 'click') { - handleMouseSelect?.(dateUTC); - } else { - onChange?.(dateUTC); - } + onSelect={(date: Date) => { + const dateParsedWithoutTime = DateTime.fromObject( + { + day: date.getDate(), + month: date.getMonth() + 1, + year: date.getFullYear(), + hour: 0, + minute: 0, + second: 0, + }, + { zone: 'utc' }, + ).toJSDate(); + + const dateForUpdate = isDateTimeInput + ? date + : dateParsedWithoutTime; + + handleMouseSelect?.(dateForUpdate); }} /> </div> diff --git a/packages/twenty-front/src/modules/ui/input/components/internal/date/components/__stories__/DatePicker.stories.tsx b/packages/twenty-front/src/modules/ui/input/components/internal/date/components/__stories__/DatePicker.stories.tsx deleted file mode 100644 index 2d7360cd6b00..000000000000 --- a/packages/twenty-front/src/modules/ui/input/components/internal/date/components/__stories__/DatePicker.stories.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import { Meta, StoryObj } from '@storybook/react'; -import { expect, userEvent, within } from '@storybook/test'; -import { ComponentDecorator } from 'twenty-ui'; - -import { InternalDatePicker } from '../InternalDatePicker'; - -const meta: Meta<typeof InternalDatePicker> = { - title: 'UI/Input/Internal/InternalDatePicker', - component: InternalDatePicker, - decorators: [ComponentDecorator], - argTypes: { - date: { control: 'date' }, - }, - args: { date: new Date('January 1, 2023 00:00:00') }, -}; - -export default meta; -type Story = StoryObj<typeof InternalDatePicker>; - -export const Default: Story = {}; - -export const WithOpenMonthSelect: Story = { - play: async ({ canvasElement }) => { - const canvas = within(canvasElement); - - const monthSelect = await canvas.findByText('January'); - - await userEvent.click(monthSelect); - - [ - 'February', - 'March', - 'April', - 'May', - 'June', - 'July', - 'August', - 'September', - 'October', - 'November', - 'December', - ].forEach((monthLabel) => - expect(canvas.getByText(monthLabel)).toBeInTheDocument(), - ); - }, -}; diff --git a/packages/twenty-front/src/modules/ui/input/components/internal/date/components/__stories__/InternalDatePicker.stories.tsx b/packages/twenty-front/src/modules/ui/input/components/internal/date/components/__stories__/InternalDatePicker.stories.tsx new file mode 100644 index 000000000000..9d107b1eb0d3 --- /dev/null +++ b/packages/twenty-front/src/modules/ui/input/components/internal/date/components/__stories__/InternalDatePicker.stories.tsx @@ -0,0 +1,80 @@ +import { useArgs } from '@storybook/preview-api'; +import { Meta, StoryObj } from '@storybook/react'; +import { expect, userEvent, within } from '@storybook/test'; +import { ComponentDecorator } from 'twenty-ui'; + +import { isDefined } from '~/utils/isDefined'; +import { InternalDatePicker } from '../InternalDatePicker'; + +const meta: Meta<typeof InternalDatePicker> = { + title: 'UI/Input/Internal/InternalDatePicker', + component: InternalDatePicker, + decorators: [ComponentDecorator], + argTypes: { + date: { control: 'date' }, + }, + render: ({ date }) => { + // eslint-disable-next-line react-hooks/rules-of-hooks + const [, updateArgs] = useArgs(); + return ( + <InternalDatePicker + date={isDefined(date) ? new Date(date) : new Date()} + onChange={(newDate) => updateArgs({ date: newDate })} + /> + ); + }, + args: { date: new Date('January 1, 2023 02:00:00') }, +}; + +export default meta; +type Story = StoryObj<typeof InternalDatePicker>; + +export const Default: Story = {}; + +export const WithOpenMonthSelect: Story = { + play: async () => { + const canvas = within(document.body); + + const monthSelect = await canvas.findByText('January'); + + await userEvent.click(monthSelect); + + [ + 'February', + 'March', + 'April', + 'May', + 'June', + 'July', + 'August', + 'September', + 'October', + 'November', + 'December', + ].forEach((monthLabel) => + expect(canvas.getByText(monthLabel)).toBeInTheDocument(), + ); + + await userEvent.click(canvas.getByText('February')); + + expect(canvas.getByText('February')).toBeInTheDocument(); + }, +}; + +export const WithOpenYearSelect: Story = { + play: async () => { + const canvas = within(document.body); + + const yearSelect = await canvas.findByText('2023'); + + await userEvent.click(yearSelect); + + ['2024', '2025', '2026'].forEach((yearLabel) => + expect(canvas.getByText(yearLabel)).toBeInTheDocument(), + ); + + await userEvent.click(canvas.getByText('2024')); + + expect(canvas.getByText('2024')).toBeInTheDocument(); + }, +}; diff --git a/packages/twenty-front/src/modules/ui/input/components/internal/phone/components/PhoneCountryPickerDropdownButton.tsx b/packages/twenty-front/src/modules/ui/input/components/internal/phone/components/PhoneCountryPickerDropdownButton.tsx index df439a4862b1..5932bccabcb5 100644 --- a/packages/twenty-front/src/modules/ui/input/components/internal/phone/components/PhoneCountryPickerDropdownButton.tsx +++ b/packages/twenty-front/src/modules/ui/input/components/internal/phone/components/PhoneCountryPickerDropdownButton.tsx @@ -21,7 +21,7 @@ type StyledDropdownButtonProps = { export const StyledDropdownButtonContainer = styled.div<StyledDropdownButtonProps>` align-items: center; - background: ${({ theme }) => theme.background.primary}; + background: none; border-radius: ${({ theme }) => theme.border.radius.xs} 0 0 ${({ theme }) => theme.border.radius.xs}; color: ${({ color }) => color ?? 'none'}; diff --git a/packages/twenty-front/src/modules/ui/layout/animated-placeholder/components/EmptyPlaceholderStyled.tsx b/packages/twenty-front/src/modules/ui/layout/animated-placeholder/components/EmptyPlaceholderStyled.tsx index 9d98e821f6bc..d088ec7e53a2 100644 --- a/packages/twenty-front/src/modules/ui/layout/animated-placeholder/components/EmptyPlaceholderStyled.tsx +++ b/packages/twenty-front/src/modules/ui/layout/animated-placeholder/components/EmptyPlaceholderStyled.tsx @@ -1,6 +1,7 @@ import styled from '@emotion/styled'; +import { motion } from 'framer-motion'; -const StyledEmptyContainer = styled.div` +const StyledEmptyContainer = styled(motion.div)` align-items: center; width: 100%; height: 100%; @@ -13,6 +14,14 @@ const StyledEmptyContainer = styled.div` export { StyledEmptyContainer as AnimatedPlaceholderEmptyContainer }; +export const EMPTY_PLACEHOLDER_TRANSITION_PROPS = { + initial: { opacity: 0 }, + animate: { opacity: 1 }, + transition: { + duration: 0.15, + }, +}; + const StyledEmptyTextContainer = styled.div` align-items: center; display: flex; diff --git a/packages/twenty-front/src/modules/ui/layout/banner/components/Banner.tsx b/packages/twenty-front/src/modules/ui/layout/banner/components/Banner.tsx new file mode 100644 index 000000000000..f08b15ce0249 --- /dev/null +++ b/packages/twenty-front/src/modules/ui/layout/banner/components/Banner.tsx @@ -0,0 +1,22 @@ +import styled from '@emotion/styled'; + +const StyledBanner = styled.div` + align-items: center; + backdrop-filter: blur(5px); + background: ${({ theme }) => theme.color.blue}; + display: flex; + gap: ${({ theme }) => theme.spacing(3)}; + height: 40px; + justify-content: center; + padding: ${({ theme }) => theme.spacing(2) + ' ' + theme.spacing(3)}; + width: 100%; + color: ${({ theme }) => theme.font.color.inverted}; + font-family: Inter; + font-size: ${({ theme }) => theme.font.size.md}; + font-style: normal; + font-weight: ${({ theme }) => theme.font.weight.medium}; + line-height: 150%; + box-sizing: border-box; +`; + +export { StyledBanner as Banner }; diff --git a/packages/twenty-front/src/modules/ui/layout/banner/components/__stories__/Banner.stories.tsx b/packages/twenty-front/src/modules/ui/layout/banner/components/__stories__/Banner.stories.tsx new file mode 100644 index 000000000000..2becd60a9a1f --- /dev/null +++ b/packages/twenty-front/src/modules/ui/layout/banner/components/__stories__/Banner.stories.tsx @@ -0,0 +1,34 @@ +import { Meta, StoryObj } from '@storybook/react'; +import { ComponentDecorator, IconRefresh } from 'twenty-ui'; + +import { Button } from '@/ui/input/button/components/Button'; + +import { Banner } from '../Banner'; + +const meta: Meta<typeof Banner> = { + title: 'UI/Layout/Banner/Banner', + component: Banner, + decorators: [ComponentDecorator], + render: (args) => ( + // eslint-disable-next-line react/jsx-props-no-spreading + <Banner {...args}> + Sync lost with mailbox hello@twenty.com. Please reconnect for updates: + <Button + variant="secondary" + title="Reconnect" + Icon={IconRefresh} + size="small" + inverted + /> + </Banner> + ), + argTypes: { + as: { control: false }, + theme: { control: false }, + }, +}; + +export default meta; +type Story = StoryObj<typeof Banner>; + +export const Default: Story = {}; diff --git a/packages/twenty-front/src/modules/ui/layout/dropdown/components/Dropdown.tsx b/packages/twenty-front/src/modules/ui/layout/dropdown/components/Dropdown.tsx index 5964f92cc798..14ba3644193d 100644 --- a/packages/twenty-front/src/modules/ui/layout/dropdown/components/Dropdown.tsx +++ b/packages/twenty-front/src/modules/ui/layout/dropdown/components/Dropdown.tsx @@ -1,12 +1,13 @@ -import { useRef } from 'react'; -import { Keys } from 'react-hotkeys-hook'; import { autoUpdate, flip, + FloatingPortal, offset, Placement, useFloating, } from '@floating-ui/react'; +import { useRef } from 'react'; +import { Keys } from 'react-hotkeys-hook'; import { Key } from 'ts-key-enum'; import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope'; @@ -39,6 +40,7 @@ type DropdownProps = { dropdownStrategy?: 'fixed' | 'absolute'; disableBlur?: boolean; onClickOutside?: () => void; + usePortal?: boolean; onClose?: () => void; onOpen?: () => void; }; @@ -55,6 +57,7 @@ export const Dropdown = ({ dropdownStrategy = 'absolute', dropdownOffset = { x: 0, y: 0 }, disableBlur = false, + usePortal = false, onClickOutside, onClose, onOpen, @@ -85,7 +88,7 @@ export const Dropdown = ({ }; useListenClickOutside({ - refs: [containerRef], + refs: [refs.floating], callback: () => { onClickOutside?.(); @@ -130,7 +133,20 @@ export const Dropdown = ({ onHotkeyTriggered={handleHotkeyTriggered} /> )} - {isDropdownOpen && ( + {isDropdownOpen && usePortal && ( + <FloatingPortal> + <DropdownMenu + disableBlur={disableBlur} + width={dropdownMenuWidth ?? dropdownWidth} + data-select-disable + ref={refs.setFloating} + style={floatingStyles} + > + {dropdownComponents} + </DropdownMenu> + </FloatingPortal> + )} + {isDropdownOpen && !usePortal && ( <DropdownMenu disableBlur={disableBlur} width={dropdownMenuWidth ?? dropdownWidth} diff --git a/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenu.tsx b/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenu.tsx index 5689b9391162..5ac402f98e8e 100644 --- a/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenu.tsx +++ b/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenu.tsx @@ -24,7 +24,7 @@ const StyledDropdownMenu = styled.div<{ display: flex; flex-direction: column; - z-index: 1; + z-index: 30; width: ${({ width = 160 }) => typeof width === 'number' ? `${width}px` : width}; `; diff --git a/packages/twenty-front/src/modules/ui/layout/dropdown/components/__stories__/DropdownMenu.stories.tsx b/packages/twenty-front/src/modules/ui/layout/dropdown/components/__stories__/DropdownMenu.stories.tsx index 3d939b5be6f0..69c9c7b9ccb0 100644 --- a/packages/twenty-front/src/modules/ui/layout/dropdown/components/__stories__/DropdownMenu.stories.tsx +++ b/packages/twenty-front/src/modules/ui/layout/dropdown/components/__stories__/DropdownMenu.stories.tsx @@ -1,8 +1,8 @@ -import { useState } from 'react'; import styled from '@emotion/styled'; import { Decorator, Meta, StoryObj } from '@storybook/react'; import { expect, userEvent, waitFor, within } from '@storybook/test'; import { PlayFunction } from '@storybook/types'; +import { useState } from 'react'; import { Avatar, ComponentDecorator } from 'twenty-ui'; import { Button } from '@/ui/input/button/components/Button'; @@ -76,8 +76,8 @@ export const Empty: Story = { <StyledEmptyDropdownContent data-testid="dropdown-content" /> ), }, - play: async ({ canvasElement }) => { - const canvas = within(canvasElement); + play: async () => { + const canvas = within(document.body); const button = await canvas.findByRole('button'); userEvent.click(button); @@ -199,8 +199,8 @@ const FakeCheckableMenuItemList = ({ hasAvatar }: { hasAvatar?: boolean }) => { ); }; -const playInteraction: PlayFunction<any, any> = async ({ canvasElement }) => { - const canvas = within(canvasElement); +const playInteraction: PlayFunction<any, any> = async () => { + const canvas = within(document.body); const button = await canvas.findByRole('button'); userEvent.click(button); @@ -251,8 +251,8 @@ export const SearchWithLoadingMenu: Story = { </> ), }, - play: async ({ canvasElement }) => { - const canvas = within(canvasElement); + play: async () => { + const canvas = within(document.body); const button = await canvas.findByRole('button'); diff --git a/packages/twenty-front/src/modules/ui/layout/expandable-list/components/ExpandableList.tsx b/packages/twenty-front/src/modules/ui/layout/expandable-list/components/ExpandableList.tsx index 6e7acc7b3ead..9f669598b61e 100644 --- a/packages/twenty-front/src/modules/ui/layout/expandable-list/components/ExpandableList.tsx +++ b/packages/twenty-front/src/modules/ui/layout/expandable-list/components/ExpandableList.tsx @@ -1,10 +1,10 @@ -import { ReactElement, useCallback, useEffect, useRef, useState } from 'react'; import styled from '@emotion/styled'; +import { ReactElement, useCallback, useEffect, useRef, useState } from 'react'; import { Chip, ChipVariant } from 'twenty-ui'; -import { AnimatedContainer } from '@/object-record/record-table/components/AnimatedContainer'; import { ExpandedListDropdown } from '@/ui/layout/expandable-list/components/ExpandedListDropdown'; import { isFirstOverflowingChildElement } from '@/ui/layout/expandable-list/utils/isFirstOverflowingChildElement'; +import { AnimatedContainer } from '@/ui/utilities/animation/components/AnimatedContainer'; import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside'; import { isDefined } from '~/utils/isDefined'; diff --git a/packages/twenty-front/src/modules/ui/layout/hooks/__tests__/useShowAuthModal.test.tsx b/packages/twenty-front/src/modules/ui/layout/hooks/__tests__/useShowAuthModal.test.tsx index 375a5b7ff49d..270ab80b1aae 100644 --- a/packages/twenty-front/src/modules/ui/layout/hooks/__tests__/useShowAuthModal.test.tsx +++ b/packages/twenty-front/src/modules/ui/layout/hooks/__tests__/useShowAuthModal.test.tsx @@ -1,18 +1,34 @@ import { renderHook } from '@testing-library/react'; import { RecoilRoot, useSetRecoilState } from 'recoil'; -import { useOnboardingStatus } from '@/auth/hooks/useOnboardingStatus'; -import { OnboardingStatus } from '@/auth/utils/getOnboardingStatus'; +import { useIsLogged } from '@/auth/hooks/useIsLogged'; +import { useOnboardingStatus } from '@/onboarding/hooks/useOnboardingStatus'; import { AppPath } from '@/types/AppPath'; import { useShowAuthModal } from '@/ui/layout/hooks/useShowAuthModal'; import { isDefaultLayoutAuthModalVisibleState } from '@/ui/layout/states/isDefaultLayoutAuthModalVisibleState'; +import { useSubscriptionStatus } from '@/workspace/hooks/useSubscriptionStatus'; +import { OnboardingStatus, SubscriptionStatus } from '~/generated/graphql'; import { useIsMatchingLocation } from '~/hooks/useIsMatchingLocation'; -jest.mock('@/auth/hooks/useOnboardingStatus'); -const setupMockOnboardingStatus = (onboardingStatus: OnboardingStatus) => { +jest.mock('@/onboarding/hooks/useOnboardingStatus'); +const setupMockOnboardingStatus = ( + onboardingStatus: OnboardingStatus | undefined, +) => { jest.mocked(useOnboardingStatus).mockReturnValueOnce(onboardingStatus); }; +jest.mock('@/workspace/hooks/useSubscriptionStatus'); +const setupMockSubscriptionStatus = ( + subscriptionStatus: SubscriptionStatus | undefined, +) => { + jest.mocked(useSubscriptionStatus).mockReturnValueOnce(subscriptionStatus); +}; + +jest.mock('@/auth/hooks/useIsLogged'); +const setupMockIsLogged = (isLogged: boolean) => { + jest.mocked(useIsLogged).mockReturnValueOnce(isLogged); +}; + jest.mock('~/hooks/useIsMatchingLocation'); const mockUseIsMatchingLocation = jest.mocked(useIsMatchingLocation); @@ -39,264 +55,245 @@ const getResult = (isDefaultLayoutAuthModalVisible = true) => // prettier-ignore const testCases = [ - { loc: AppPath.Verify, status: OnboardingStatus.Incomplete, res: false }, - { loc: AppPath.Verify, status: OnboardingStatus.Canceled, res: false }, - { loc: AppPath.Verify, status: OnboardingStatus.Unpaid, res: false }, - { loc: AppPath.Verify, status: OnboardingStatus.PastDue, res: false }, - { loc: AppPath.Verify, status: OnboardingStatus.OngoingUserCreation, res: false }, - { loc: AppPath.Verify, status: OnboardingStatus.OngoingWorkspaceActivation, res: false }, - { loc: AppPath.Verify, status: OnboardingStatus.OngoingProfileCreation, res: false }, - { loc: AppPath.Verify, status: OnboardingStatus.OngoingSyncEmail, res: false }, - { loc: AppPath.Verify, status: OnboardingStatus.OngoingInviteTeam, res: false }, - { loc: AppPath.Verify, status: OnboardingStatus.Completed, res: false }, - { loc: AppPath.Verify, status: OnboardingStatus.CompletedWithoutSubscription, res: false }, - - { loc: AppPath.SignInUp, status: OnboardingStatus.Incomplete, res: true }, - { loc: AppPath.SignInUp, status: OnboardingStatus.Canceled, res: false }, - { loc: AppPath.SignInUp, status: OnboardingStatus.Unpaid, res: false }, - { loc: AppPath.SignInUp, status: OnboardingStatus.PastDue, res: false }, - { loc: AppPath.SignInUp, status: OnboardingStatus.OngoingUserCreation, res: true }, - { loc: AppPath.SignInUp, status: OnboardingStatus.OngoingWorkspaceActivation, res: true }, - { loc: AppPath.SignInUp, status: OnboardingStatus.OngoingProfileCreation, res: true }, - { loc: AppPath.SignInUp, status: OnboardingStatus.OngoingSyncEmail, res: true }, - { loc: AppPath.SignInUp, status: OnboardingStatus.OngoingInviteTeam, res: true }, - { loc: AppPath.SignInUp, status: OnboardingStatus.Completed, res: false }, - { loc: AppPath.SignInUp, status: OnboardingStatus.CompletedWithoutSubscription, res: false }, - - { loc: AppPath.Invite, status: OnboardingStatus.Incomplete, res: true }, - { loc: AppPath.Invite, status: OnboardingStatus.Canceled, res: true }, - { loc: AppPath.Invite, status: OnboardingStatus.Unpaid, res: true }, - { loc: AppPath.Invite, status: OnboardingStatus.PastDue, res: true }, - { loc: AppPath.Invite, status: OnboardingStatus.OngoingUserCreation, res: true }, - { loc: AppPath.Invite, status: OnboardingStatus.OngoingWorkspaceActivation, res: true }, - { loc: AppPath.Invite, status: OnboardingStatus.OngoingProfileCreation, res: true }, - { loc: AppPath.Invite, status: OnboardingStatus.OngoingSyncEmail, res: true }, - { loc: AppPath.Invite, status: OnboardingStatus.OngoingInviteTeam, res: true }, - { loc: AppPath.Invite, status: OnboardingStatus.Completed, res: true }, - { loc: AppPath.Invite, status: OnboardingStatus.CompletedWithoutSubscription, res: true }, - - { loc: AppPath.ResetPassword, status: OnboardingStatus.Incomplete, res: true }, - { loc: AppPath.ResetPassword, status: OnboardingStatus.Canceled, res: true }, - { loc: AppPath.ResetPassword, status: OnboardingStatus.Unpaid, res: true }, - { loc: AppPath.ResetPassword, status: OnboardingStatus.PastDue, res: true }, - { loc: AppPath.ResetPassword, status: OnboardingStatus.OngoingUserCreation, res: true }, - { loc: AppPath.ResetPassword, status: OnboardingStatus.OngoingWorkspaceActivation, res: true }, - { loc: AppPath.ResetPassword, status: OnboardingStatus.OngoingProfileCreation, res: true }, - { loc: AppPath.ResetPassword, status: OnboardingStatus.OngoingSyncEmail, res: true }, - { loc: AppPath.ResetPassword, status: OnboardingStatus.OngoingInviteTeam, res: true }, - { loc: AppPath.ResetPassword, status: OnboardingStatus.Completed, res: true }, - { loc: AppPath.ResetPassword, status: OnboardingStatus.CompletedWithoutSubscription, res: true }, - - { loc: AppPath.CreateWorkspace, status: OnboardingStatus.Incomplete, res: true }, - { loc: AppPath.CreateWorkspace, status: OnboardingStatus.Canceled, res: false }, - { loc: AppPath.CreateWorkspace, status: OnboardingStatus.Unpaid, res: false }, - { loc: AppPath.CreateWorkspace, status: OnboardingStatus.PastDue, res: false }, - { loc: AppPath.CreateWorkspace, status: OnboardingStatus.OngoingUserCreation, res: true }, - { loc: AppPath.CreateWorkspace, status: OnboardingStatus.OngoingWorkspaceActivation, res: true }, - { loc: AppPath.CreateWorkspace, status: OnboardingStatus.OngoingProfileCreation, res: true }, - { loc: AppPath.CreateWorkspace, status: OnboardingStatus.OngoingSyncEmail, res: true }, - { loc: AppPath.CreateWorkspace, status: OnboardingStatus.OngoingInviteTeam, res: true }, - { loc: AppPath.CreateWorkspace, status: OnboardingStatus.Completed, res: false }, - { loc: AppPath.CreateWorkspace, status: OnboardingStatus.CompletedWithoutSubscription, res: false }, - - { loc: AppPath.CreateProfile, status: OnboardingStatus.Incomplete, res: true }, - { loc: AppPath.CreateProfile, status: OnboardingStatus.Canceled, res: false }, - { loc: AppPath.CreateProfile, status: OnboardingStatus.Unpaid, res: false }, - { loc: AppPath.CreateProfile, status: OnboardingStatus.PastDue, res: false }, - { loc: AppPath.CreateProfile, status: OnboardingStatus.OngoingUserCreation, res: true }, - { loc: AppPath.CreateProfile, status: OnboardingStatus.OngoingWorkspaceActivation, res: true }, - { loc: AppPath.CreateProfile, status: OnboardingStatus.OngoingProfileCreation, res: true }, - { loc: AppPath.CreateProfile, status: OnboardingStatus.OngoingSyncEmail, res: true }, - { loc: AppPath.CreateProfile, status: OnboardingStatus.OngoingInviteTeam, res: true }, - { loc: AppPath.CreateProfile, status: OnboardingStatus.Completed, res: false }, - { loc: AppPath.CreateProfile, status: OnboardingStatus.CompletedWithoutSubscription, res: false }, - - { loc: AppPath.SyncEmails, status: OnboardingStatus.Incomplete, res: true }, - { loc: AppPath.SyncEmails, status: OnboardingStatus.Canceled, res: false }, - { loc: AppPath.SyncEmails, status: OnboardingStatus.Unpaid, res: false }, - { loc: AppPath.SyncEmails, status: OnboardingStatus.PastDue, res: false }, - { loc: AppPath.SyncEmails, status: OnboardingStatus.OngoingUserCreation, res: true }, - { loc: AppPath.SyncEmails, status: OnboardingStatus.OngoingWorkspaceActivation, res: true }, - { loc: AppPath.SyncEmails, status: OnboardingStatus.OngoingProfileCreation, res: true }, - { loc: AppPath.SyncEmails, status: OnboardingStatus.OngoingSyncEmail, res: true }, - { loc: AppPath.SyncEmails, status: OnboardingStatus.OngoingInviteTeam, res: true }, - { loc: AppPath.SyncEmails, status: OnboardingStatus.Completed, res: false }, - { loc: AppPath.SyncEmails, status: OnboardingStatus.CompletedWithoutSubscription, res: false }, - - { loc: AppPath.InviteTeam, status: OnboardingStatus.Incomplete, res: true }, - { loc: AppPath.InviteTeam, status: OnboardingStatus.Canceled, res: false }, - { loc: AppPath.InviteTeam, status: OnboardingStatus.Unpaid, res: false }, - { loc: AppPath.InviteTeam, status: OnboardingStatus.PastDue, res: false }, - { loc: AppPath.InviteTeam, status: OnboardingStatus.OngoingUserCreation, res: true }, - { loc: AppPath.InviteTeam, status: OnboardingStatus.OngoingWorkspaceActivation, res: true }, - { loc: AppPath.InviteTeam, status: OnboardingStatus.OngoingProfileCreation, res: true }, - { loc: AppPath.InviteTeam, status: OnboardingStatus.OngoingSyncEmail, res: true }, - { loc: AppPath.InviteTeam, status: OnboardingStatus.OngoingInviteTeam, res: true }, - { loc: AppPath.InviteTeam, status: OnboardingStatus.Completed, res: false }, - { loc: AppPath.InviteTeam, status: OnboardingStatus.CompletedWithoutSubscription, res: false }, - - { loc: AppPath.PlanRequired, status: OnboardingStatus.Incomplete, res: true }, - { loc: AppPath.PlanRequired, status: OnboardingStatus.Canceled, res: true }, - { loc: AppPath.PlanRequired, status: OnboardingStatus.Unpaid, res: false }, - { loc: AppPath.PlanRequired, status: OnboardingStatus.PastDue, res: false }, - { loc: AppPath.PlanRequired, status: OnboardingStatus.OngoingUserCreation, res: true }, - { loc: AppPath.PlanRequired, status: OnboardingStatus.OngoingWorkspaceActivation, res: true }, - { loc: AppPath.PlanRequired, status: OnboardingStatus.OngoingProfileCreation, res: true }, - { loc: AppPath.PlanRequired, status: OnboardingStatus.OngoingSyncEmail, res: true }, - { loc: AppPath.PlanRequired, status: OnboardingStatus.OngoingInviteTeam, res: true }, - { loc: AppPath.PlanRequired, status: OnboardingStatus.Completed, res: false }, - { loc: AppPath.PlanRequired, status: OnboardingStatus.CompletedWithoutSubscription, res: true }, - - { loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.Incomplete, res: true }, - { loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.Canceled, res: false }, - { loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.Unpaid, res: false }, - { loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.PastDue, res: false }, - { loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.OngoingUserCreation, res: true }, - { loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.OngoingWorkspaceActivation, res: true }, - { loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.OngoingProfileCreation, res: true }, - { loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.OngoingSyncEmail, res: true }, - { loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.OngoingInviteTeam, res: true }, - { loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.Completed, res: false }, - { loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.CompletedWithoutSubscription, res: false }, - - { loc: AppPath.Index, status: OnboardingStatus.Incomplete, res: true }, - { loc: AppPath.Index, status: OnboardingStatus.Canceled, res: false }, - { loc: AppPath.Index, status: OnboardingStatus.Unpaid, res: false }, - { loc: AppPath.Index, status: OnboardingStatus.PastDue, res: false }, - { loc: AppPath.Index, status: OnboardingStatus.OngoingUserCreation, res: true }, - { loc: AppPath.Index, status: OnboardingStatus.OngoingWorkspaceActivation, res: true }, - { loc: AppPath.Index, status: OnboardingStatus.OngoingProfileCreation, res: true }, - { loc: AppPath.Index, status: OnboardingStatus.OngoingSyncEmail, res: true }, - { loc: AppPath.Index, status: OnboardingStatus.OngoingInviteTeam, res: true }, - { loc: AppPath.Index, status: OnboardingStatus.Completed, res: false }, - { loc: AppPath.Index, status: OnboardingStatus.CompletedWithoutSubscription, res: false }, - - { loc: AppPath.TasksPage, status: OnboardingStatus.Incomplete, res: true }, - { loc: AppPath.TasksPage, status: OnboardingStatus.Canceled, res: false }, - { loc: AppPath.TasksPage, status: OnboardingStatus.Unpaid, res: false }, - { loc: AppPath.TasksPage, status: OnboardingStatus.PastDue, res: false }, - { loc: AppPath.TasksPage, status: OnboardingStatus.OngoingUserCreation, res: true }, - { loc: AppPath.TasksPage, status: OnboardingStatus.OngoingWorkspaceActivation, res: true }, - { loc: AppPath.TasksPage, status: OnboardingStatus.OngoingProfileCreation, res: true }, - { loc: AppPath.TasksPage, status: OnboardingStatus.OngoingSyncEmail, res: true }, - { loc: AppPath.TasksPage, status: OnboardingStatus.OngoingInviteTeam, res: true }, - { loc: AppPath.TasksPage, status: OnboardingStatus.Completed, res: false }, - { loc: AppPath.TasksPage, status: OnboardingStatus.CompletedWithoutSubscription, res: false }, - - { loc: AppPath.OpportunitiesPage, status: OnboardingStatus.Incomplete, res: true }, - { loc: AppPath.OpportunitiesPage, status: OnboardingStatus.Canceled, res: false }, - { loc: AppPath.OpportunitiesPage, status: OnboardingStatus.Unpaid, res: false }, - { loc: AppPath.OpportunitiesPage, status: OnboardingStatus.PastDue, res: false }, - { loc: AppPath.OpportunitiesPage, status: OnboardingStatus.OngoingUserCreation, res: true }, - { loc: AppPath.OpportunitiesPage, status: OnboardingStatus.OngoingWorkspaceActivation, res: true }, - { loc: AppPath.OpportunitiesPage, status: OnboardingStatus.OngoingProfileCreation, res: true }, - { loc: AppPath.OpportunitiesPage, status: OnboardingStatus.OngoingSyncEmail, res: true }, - { loc: AppPath.OpportunitiesPage, status: OnboardingStatus.OngoingInviteTeam, res: true }, - { loc: AppPath.OpportunitiesPage, status: OnboardingStatus.Completed, res: false }, - { loc: AppPath.OpportunitiesPage, status: OnboardingStatus.CompletedWithoutSubscription, res: false }, - - { loc: AppPath.RecordIndexPage, status: OnboardingStatus.Incomplete, res: true }, - { loc: AppPath.RecordIndexPage, status: OnboardingStatus.Canceled, res: false }, - { loc: AppPath.RecordIndexPage, status: OnboardingStatus.Unpaid, res: false }, - { loc: AppPath.RecordIndexPage, status: OnboardingStatus.PastDue, res: false }, - { loc: AppPath.RecordIndexPage, status: OnboardingStatus.OngoingUserCreation, res: true }, - { loc: AppPath.RecordIndexPage, status: OnboardingStatus.OngoingWorkspaceActivation, res: true }, - { loc: AppPath.RecordIndexPage, status: OnboardingStatus.OngoingProfileCreation, res: true }, - { loc: AppPath.RecordIndexPage, status: OnboardingStatus.OngoingSyncEmail, res: true }, - { loc: AppPath.RecordIndexPage, status: OnboardingStatus.OngoingInviteTeam, res: true }, - { loc: AppPath.RecordIndexPage, status: OnboardingStatus.Completed, res: false }, - { loc: AppPath.RecordIndexPage, status: OnboardingStatus.CompletedWithoutSubscription, res: false }, - - { loc: AppPath.RecordShowPage, status: OnboardingStatus.Incomplete, res: true }, - { loc: AppPath.RecordShowPage, status: OnboardingStatus.Canceled, res: false }, - { loc: AppPath.RecordShowPage, status: OnboardingStatus.Unpaid, res: false }, - { loc: AppPath.RecordShowPage, status: OnboardingStatus.PastDue, res: false }, - { loc: AppPath.RecordShowPage, status: OnboardingStatus.OngoingUserCreation, res: true }, - { loc: AppPath.RecordShowPage, status: OnboardingStatus.OngoingWorkspaceActivation, res: true }, - { loc: AppPath.RecordShowPage, status: OnboardingStatus.OngoingProfileCreation, res: true }, - { loc: AppPath.RecordShowPage, status: OnboardingStatus.OngoingSyncEmail, res: true }, - { loc: AppPath.RecordShowPage, status: OnboardingStatus.OngoingInviteTeam, res: true }, - { loc: AppPath.RecordShowPage, status: OnboardingStatus.Completed, res: false }, - { loc: AppPath.RecordShowPage, status: OnboardingStatus.CompletedWithoutSubscription, res: false }, - - { loc: AppPath.SettingsCatchAll, status: OnboardingStatus.Incomplete, res: true }, - { loc: AppPath.SettingsCatchAll, status: OnboardingStatus.Canceled, res: false }, - { loc: AppPath.SettingsCatchAll, status: OnboardingStatus.Unpaid, res: false }, - { loc: AppPath.SettingsCatchAll, status: OnboardingStatus.PastDue, res: false }, - { loc: AppPath.SettingsCatchAll, status: OnboardingStatus.OngoingUserCreation, res: true }, - { loc: AppPath.SettingsCatchAll, status: OnboardingStatus.OngoingWorkspaceActivation, res: true }, - { loc: AppPath.SettingsCatchAll, status: OnboardingStatus.OngoingProfileCreation, res: true }, - { loc: AppPath.SettingsCatchAll, status: OnboardingStatus.OngoingSyncEmail, res: true }, - { loc: AppPath.SettingsCatchAll, status: OnboardingStatus.OngoingInviteTeam, res: true }, - { loc: AppPath.SettingsCatchAll, status: OnboardingStatus.Completed, res: false }, - { loc: AppPath.SettingsCatchAll, status: OnboardingStatus.CompletedWithoutSubscription, res: false }, - - { loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.Incomplete, res: true }, - { loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.Canceled, res: false }, - { loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.Unpaid, res: false }, - { loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.PastDue, res: false }, - { loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.OngoingUserCreation, res: true }, - { loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.OngoingWorkspaceActivation, res: true }, - { loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.OngoingProfileCreation, res: true }, - { loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.OngoingSyncEmail, res: true }, - { loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.OngoingInviteTeam, res: true }, - { loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.Completed, res: false }, - { loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.CompletedWithoutSubscription, res: false }, - - { loc: AppPath.Impersonate, status: OnboardingStatus.Incomplete, res: true }, - { loc: AppPath.Impersonate, status: OnboardingStatus.Canceled, res: false }, - { loc: AppPath.Impersonate, status: OnboardingStatus.Unpaid, res: false }, - { loc: AppPath.Impersonate, status: OnboardingStatus.PastDue, res: false }, - { loc: AppPath.Impersonate, status: OnboardingStatus.OngoingUserCreation, res: true }, - { loc: AppPath.Impersonate, status: OnboardingStatus.OngoingWorkspaceActivation, res: true }, - { loc: AppPath.Impersonate, status: OnboardingStatus.OngoingProfileCreation, res: true }, - { loc: AppPath.Impersonate, status: OnboardingStatus.OngoingSyncEmail, res: true }, - { loc: AppPath.Impersonate, status: OnboardingStatus.OngoingInviteTeam, res: true }, - { loc: AppPath.Impersonate, status: OnboardingStatus.Completed, res: false }, - { loc: AppPath.Impersonate, status: OnboardingStatus.CompletedWithoutSubscription, res: false }, - - { loc: AppPath.Authorize, status: OnboardingStatus.Incomplete, res: true }, - { loc: AppPath.Authorize, status: OnboardingStatus.Canceled, res: false }, - { loc: AppPath.Authorize, status: OnboardingStatus.Unpaid, res: false }, - { loc: AppPath.Authorize, status: OnboardingStatus.PastDue, res: false }, - { loc: AppPath.Authorize, status: OnboardingStatus.OngoingUserCreation, res: true }, - { loc: AppPath.Authorize, status: OnboardingStatus.OngoingWorkspaceActivation, res: true }, - { loc: AppPath.Authorize, status: OnboardingStatus.OngoingProfileCreation, res: true }, - { loc: AppPath.Authorize, status: OnboardingStatus.OngoingSyncEmail, res: true }, - { loc: AppPath.Authorize, status: OnboardingStatus.OngoingInviteTeam, res: true }, - { loc: AppPath.Authorize, status: OnboardingStatus.Completed, res: false }, - { loc: AppPath.Authorize, status: OnboardingStatus.CompletedWithoutSubscription, res: false }, - - { loc: AppPath.NotFoundWildcard, status: OnboardingStatus.Incomplete, res: true }, - { loc: AppPath.NotFoundWildcard, status: OnboardingStatus.Canceled, res: false }, - { loc: AppPath.NotFoundWildcard, status: OnboardingStatus.Unpaid, res: false }, - { loc: AppPath.NotFoundWildcard, status: OnboardingStatus.PastDue, res: false }, - { loc: AppPath.NotFoundWildcard, status: OnboardingStatus.OngoingUserCreation, res: true }, - { loc: AppPath.NotFoundWildcard, status: OnboardingStatus.OngoingWorkspaceActivation, res: true }, - { loc: AppPath.NotFoundWildcard, status: OnboardingStatus.OngoingProfileCreation, res: true }, - { loc: AppPath.NotFoundWildcard, status: OnboardingStatus.OngoingSyncEmail, res: true }, - { loc: AppPath.NotFoundWildcard, status: OnboardingStatus.OngoingInviteTeam, res: true }, - { loc: AppPath.NotFoundWildcard, status: OnboardingStatus.Completed, res: false }, - { loc: AppPath.NotFoundWildcard, status: OnboardingStatus.CompletedWithoutSubscription, res: false }, - - { loc: AppPath.NotFound, status: OnboardingStatus.Incomplete, res: true }, - { loc: AppPath.NotFound, status: OnboardingStatus.Canceled, res: false }, - { loc: AppPath.NotFound, status: OnboardingStatus.Unpaid, res: false }, - { loc: AppPath.NotFound, status: OnboardingStatus.PastDue, res: false }, - { loc: AppPath.NotFound, status: OnboardingStatus.OngoingUserCreation, res: true }, - { loc: AppPath.NotFound, status: OnboardingStatus.OngoingWorkspaceActivation, res: true }, - { loc: AppPath.NotFound, status: OnboardingStatus.OngoingProfileCreation, res: true }, - { loc: AppPath.NotFound, status: OnboardingStatus.OngoingSyncEmail, res: true }, - { loc: AppPath.NotFound, status: OnboardingStatus.OngoingInviteTeam, res: true }, - { loc: AppPath.NotFound, status: OnboardingStatus.Completed, res: false }, - { loc: AppPath.NotFound, status: OnboardingStatus.CompletedWithoutSubscription, res: false }, + { loc: AppPath.Verify, isLogged: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: false }, + { loc: AppPath.Verify, isLogged: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.Verify, isLogged: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.Verify, isLogged: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.Verify, isLogged: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: false }, + { loc: AppPath.Verify, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: false }, + { loc: AppPath.Verify, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: false }, + { loc: AppPath.Verify, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: false }, + { loc: AppPath.Verify, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: false }, + { loc: AppPath.Verify, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: false }, + + { loc: AppPath.SignInUp, isLogged: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: true }, + { loc: AppPath.SignInUp, isLogged: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.SignInUp, isLogged: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.SignInUp, isLogged: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.SignInUp, isLogged: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: true }, + { loc: AppPath.SignInUp, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: true }, + { loc: AppPath.SignInUp, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: true }, + { loc: AppPath.SignInUp, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: true }, + { loc: AppPath.SignInUp, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: true }, + { loc: AppPath.SignInUp, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: false }, + + { loc: AppPath.Invite, isLogged: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: true }, + { loc: AppPath.Invite, isLogged: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: true }, + { loc: AppPath.Invite, isLogged: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: true }, + { loc: AppPath.Invite, isLogged: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: true }, + { loc: AppPath.Invite, isLogged: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: true }, + { loc: AppPath.Invite, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: true }, + { loc: AppPath.Invite, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: true }, + { loc: AppPath.Invite, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: true }, + { loc: AppPath.Invite, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: true }, + { loc: AppPath.Invite, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: true }, + + { loc: AppPath.ResetPassword, isLogged: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: true }, + { loc: AppPath.ResetPassword, isLogged: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: true }, + { loc: AppPath.ResetPassword, isLogged: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: true }, + { loc: AppPath.ResetPassword, isLogged: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: true }, + { loc: AppPath.ResetPassword, isLogged: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: true }, + { loc: AppPath.ResetPassword, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: true }, + { loc: AppPath.ResetPassword, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: true }, + { loc: AppPath.ResetPassword, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: true }, + { loc: AppPath.ResetPassword, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: true }, + { loc: AppPath.ResetPassword, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: true }, + + { loc: AppPath.CreateWorkspace, isLogged: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: true }, + { loc: AppPath.CreateWorkspace, isLogged: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.CreateWorkspace, isLogged: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.CreateWorkspace, isLogged: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.CreateWorkspace, isLogged: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: true }, + { loc: AppPath.CreateWorkspace, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: true }, + { loc: AppPath.CreateWorkspace, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: true }, + { loc: AppPath.CreateWorkspace, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: true }, + { loc: AppPath.CreateWorkspace, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: true }, + { loc: AppPath.CreateWorkspace, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: false }, + + { loc: AppPath.CreateProfile, isLogged: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: true }, + { loc: AppPath.CreateProfile, isLogged: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.CreateProfile, isLogged: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.CreateProfile, isLogged: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.CreateProfile, isLogged: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: true }, + { loc: AppPath.CreateProfile, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: true }, + { loc: AppPath.CreateProfile, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: true }, + { loc: AppPath.CreateProfile, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: true }, + { loc: AppPath.CreateProfile, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: true }, + { loc: AppPath.CreateProfile, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: false }, + + { loc: AppPath.SyncEmails, isLogged: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: true }, + { loc: AppPath.SyncEmails, isLogged: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.SyncEmails, isLogged: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.SyncEmails, isLogged: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.SyncEmails, isLogged: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: true }, + { loc: AppPath.SyncEmails, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: true }, + { loc: AppPath.SyncEmails, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: true }, + { loc: AppPath.SyncEmails, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: true }, + { loc: AppPath.SyncEmails, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: true }, + { loc: AppPath.SyncEmails, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: false }, + + { loc: AppPath.InviteTeam, isLogged: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: true }, + { loc: AppPath.InviteTeam, isLogged: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.InviteTeam, isLogged: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.InviteTeam, isLogged: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.InviteTeam, isLogged: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: true }, + { loc: AppPath.InviteTeam, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: true }, + { loc: AppPath.InviteTeam, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: true }, + { loc: AppPath.InviteTeam, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: true }, + { loc: AppPath.InviteTeam, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: true }, + { loc: AppPath.InviteTeam, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: false }, + + { loc: AppPath.PlanRequired, isLogged: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: true }, + { loc: AppPath.PlanRequired, isLogged: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: true }, + { loc: AppPath.PlanRequired, isLogged: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.PlanRequired, isLogged: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.PlanRequired, isLogged: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: true }, + { loc: AppPath.PlanRequired, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: true }, + { loc: AppPath.PlanRequired, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: true }, + { loc: AppPath.PlanRequired, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: true }, + { loc: AppPath.PlanRequired, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: true }, + { loc: AppPath.PlanRequired, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: false }, + + { loc: AppPath.PlanRequiredSuccess, isLogged: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: true }, + { loc: AppPath.PlanRequiredSuccess, isLogged: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.PlanRequiredSuccess, isLogged: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.PlanRequiredSuccess, isLogged: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.PlanRequiredSuccess, isLogged: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: true }, + { loc: AppPath.PlanRequiredSuccess, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: true }, + { loc: AppPath.PlanRequiredSuccess, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: true }, + { loc: AppPath.PlanRequiredSuccess, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: true }, + { loc: AppPath.PlanRequiredSuccess, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: true }, + { loc: AppPath.PlanRequiredSuccess, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: false }, + + { loc: AppPath.Index, isLogged: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: true }, + { loc: AppPath.Index, isLogged: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.Index, isLogged: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.Index, isLogged: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.Index, isLogged: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: true }, + { loc: AppPath.Index, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: true }, + { loc: AppPath.Index, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: true }, + { loc: AppPath.Index, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: true }, + { loc: AppPath.Index, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: true }, + { loc: AppPath.Index, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: false }, + + { loc: AppPath.TasksPage, isLogged: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: true }, + { loc: AppPath.TasksPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.TasksPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.TasksPage, isLogged: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.TasksPage, isLogged: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: true }, + { loc: AppPath.TasksPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: true }, + { loc: AppPath.TasksPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: true }, + { loc: AppPath.TasksPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: true }, + { loc: AppPath.TasksPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: true }, + { loc: AppPath.TasksPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: false }, + + { loc: AppPath.OpportunitiesPage, isLogged: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: true }, + { loc: AppPath.OpportunitiesPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.OpportunitiesPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.OpportunitiesPage, isLogged: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.OpportunitiesPage, isLogged: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: true }, + { loc: AppPath.OpportunitiesPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: true }, + { loc: AppPath.OpportunitiesPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: true }, + { loc: AppPath.OpportunitiesPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: true }, + { loc: AppPath.OpportunitiesPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: true }, + { loc: AppPath.OpportunitiesPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: false }, + + { loc: AppPath.RecordIndexPage, isLogged: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: true }, + { loc: AppPath.RecordIndexPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.RecordIndexPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.RecordIndexPage, isLogged: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.RecordIndexPage, isLogged: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: true }, + { loc: AppPath.RecordIndexPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: true }, + { loc: AppPath.RecordIndexPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: true }, + { loc: AppPath.RecordIndexPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: true }, + { loc: AppPath.RecordIndexPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: true }, + { loc: AppPath.RecordIndexPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: false }, + + { loc: AppPath.RecordShowPage, isLogged: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: true }, + { loc: AppPath.RecordShowPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.RecordShowPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.RecordShowPage, isLogged: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.RecordShowPage, isLogged: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: true }, + { loc: AppPath.RecordShowPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: true }, + { loc: AppPath.RecordShowPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: true }, + { loc: AppPath.RecordShowPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: true }, + { loc: AppPath.RecordShowPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: true }, + { loc: AppPath.RecordShowPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: false }, + + { loc: AppPath.SettingsCatchAll, isLogged: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: true }, + { loc: AppPath.SettingsCatchAll, isLogged: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.SettingsCatchAll, isLogged: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.SettingsCatchAll, isLogged: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.SettingsCatchAll, isLogged: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: true }, + { loc: AppPath.SettingsCatchAll, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: true }, + { loc: AppPath.SettingsCatchAll, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: true }, + { loc: AppPath.SettingsCatchAll, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: true }, + { loc: AppPath.SettingsCatchAll, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: true }, + { loc: AppPath.SettingsCatchAll, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: false }, + + { loc: AppPath.DevelopersCatchAll, isLogged: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: true }, + { loc: AppPath.DevelopersCatchAll, isLogged: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.DevelopersCatchAll, isLogged: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.DevelopersCatchAll, isLogged: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.DevelopersCatchAll, isLogged: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: true }, + { loc: AppPath.DevelopersCatchAll, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: true }, + { loc: AppPath.DevelopersCatchAll, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: true }, + { loc: AppPath.DevelopersCatchAll, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: true }, + { loc: AppPath.DevelopersCatchAll, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: true }, + { loc: AppPath.DevelopersCatchAll, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: false }, + + { loc: AppPath.Impersonate, isLogged: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: true }, + { loc: AppPath.Impersonate, isLogged: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.Impersonate, isLogged: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.Impersonate, isLogged: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.Impersonate, isLogged: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: true }, + { loc: AppPath.Impersonate, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: true }, + { loc: AppPath.Impersonate, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: true }, + { loc: AppPath.Impersonate, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: true }, + { loc: AppPath.Impersonate, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: true }, + { loc: AppPath.Impersonate, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: false }, + + { loc: AppPath.Authorize, isLogged: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: true }, + { loc: AppPath.Authorize, isLogged: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.Authorize, isLogged: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.Authorize, isLogged: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.Authorize, isLogged: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: true }, + { loc: AppPath.Authorize, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: true }, + { loc: AppPath.Authorize, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: true }, + { loc: AppPath.Authorize, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: true }, + { loc: AppPath.Authorize, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: true }, + { loc: AppPath.Authorize, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: false }, + + { loc: AppPath.NotFoundWildcard, isLogged: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: true }, + { loc: AppPath.NotFoundWildcard, isLogged: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.NotFoundWildcard, isLogged: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.NotFoundWildcard, isLogged: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.NotFoundWildcard, isLogged: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: true }, + { loc: AppPath.NotFoundWildcard, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: true }, + { loc: AppPath.NotFoundWildcard, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: true }, + { loc: AppPath.NotFoundWildcard, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: true }, + { loc: AppPath.NotFoundWildcard, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: true }, + { loc: AppPath.NotFoundWildcard, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: false }, + + { loc: AppPath.NotFound, isLogged: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: true }, + { loc: AppPath.NotFound, isLogged: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.NotFound, isLogged: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.NotFound, isLogged: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: false }, + { loc: AppPath.NotFound, isLogged: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: true }, + { loc: AppPath.NotFound, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: true }, + { loc: AppPath.NotFound, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: true }, + { loc: AppPath.NotFound, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: true }, + { loc: AppPath.NotFound, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: true }, + { loc: AppPath.NotFound, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: false }, ]; describe('useShowAuthModal', () => { testCases.forEach((testCase) => { - it(`testCase for location ${testCase.loc} with onboardingStatus ${testCase.status} should return ${testCase.res}`, () => { - setupMockOnboardingStatus(testCase.status); + it(`testCase for location ${testCase.loc} with onboardingStatus ${testCase.onboardingStatus} should return ${testCase.res}`, () => { + setupMockOnboardingStatus(testCase.onboardingStatus); + setupMockSubscriptionStatus(testCase.subscriptionStatus); setupMockIsMatchingLocation(testCase.loc); + setupMockIsLogged(testCase.isLogged); const { result } = getResult(); if (testCase.res) { expect(result.current).toBeTruthy(); @@ -309,13 +306,17 @@ describe('useShowAuthModal', () => { describe('test with token validation loading', () => { it(`with appPath ${AppPath.Invite} and isDefaultLayoutAuthModalVisible=false`, () => { setupMockOnboardingStatus(OnboardingStatus.Completed); + setupMockSubscriptionStatus(SubscriptionStatus.Active); setupMockIsMatchingLocation(AppPath.Invite); + setupMockIsLogged(true); const { result } = getResult(false); expect(result.current).toBeFalsy(); }); it(`with appPath ${AppPath.ResetPassword} and isDefaultLayoutAuthModalVisible=false`, () => { setupMockOnboardingStatus(OnboardingStatus.Completed); + setupMockSubscriptionStatus(SubscriptionStatus.Active); setupMockIsMatchingLocation(AppPath.ResetPassword); + setupMockIsLogged(true); const { result } = getResult(false); expect(result.current).toBeFalsy(); }); @@ -323,8 +324,17 @@ describe('useShowAuthModal', () => { describe('tests should be exhaustive', () => { it('all location and onboarding status should be tested', () => { + const untestedSubscriptionStatus = [ + SubscriptionStatus.Active, + SubscriptionStatus.IncompleteExpired, + SubscriptionStatus.Paused, + SubscriptionStatus.Trialing, + ]; expect(testCases.length).toEqual( - Object.keys(AppPath).length * Object.keys(OnboardingStatus).length, + Object.keys(AppPath).length * + (Object.keys(OnboardingStatus).length + + (Object.keys(SubscriptionStatus).length - + untestedSubscriptionStatus.length)), ); }); }); diff --git a/packages/twenty-front/src/modules/ui/layout/hooks/useShowAuthModal.ts b/packages/twenty-front/src/modules/ui/layout/hooks/useShowAuthModal.ts index 47a59bc29b8d..fc241a6655f7 100644 --- a/packages/twenty-front/src/modules/ui/layout/hooks/useShowAuthModal.ts +++ b/packages/twenty-front/src/modules/ui/layout/hooks/useShowAuthModal.ts @@ -1,15 +1,20 @@ import { useMemo } from 'react'; import { useRecoilValue } from 'recoil'; -import { useOnboardingStatus } from '@/auth/hooks/useOnboardingStatus'; -import { OnboardingStatus } from '@/auth/utils/getOnboardingStatus'; +import { useIsLogged } from '@/auth/hooks/useIsLogged'; +import { useOnboardingStatus } from '@/onboarding/hooks/useOnboardingStatus'; import { AppPath } from '@/types/AppPath'; import { isDefaultLayoutAuthModalVisibleState } from '@/ui/layout/states/isDefaultLayoutAuthModalVisibleState'; +import { useSubscriptionStatus } from '@/workspace/hooks/useSubscriptionStatus'; +import { OnboardingStatus, SubscriptionStatus } from '~/generated/graphql'; import { useIsMatchingLocation } from '~/hooks/useIsMatchingLocation'; +import { isDefined } from '~/utils/isDefined'; export const useShowAuthModal = () => { const isMatchingLocation = useIsMatchingLocation(); + const isLoggedIn = useIsLogged(); const onboardingStatus = useOnboardingStatus(); + const subscriptionStatus = useSubscriptionStatus(); const isDefaultLayoutAuthModalVisible = useRecoilValue( isDefaultLayoutAuthModalVisibleState, ); @@ -24,21 +29,28 @@ export const useShowAuthModal = () => { return isDefaultLayoutAuthModalVisible; } if ( - OnboardingStatus.Incomplete === onboardingStatus || - OnboardingStatus.OngoingUserCreation === onboardingStatus || - OnboardingStatus.OngoingProfileCreation === onboardingStatus || - OnboardingStatus.OngoingWorkspaceActivation === onboardingStatus || - OnboardingStatus.OngoingSyncEmail === onboardingStatus || - OnboardingStatus.OngoingInviteTeam === onboardingStatus + !isLoggedIn || + onboardingStatus === OnboardingStatus.PlanRequired || + onboardingStatus === OnboardingStatus.ProfileCreation || + onboardingStatus === OnboardingStatus.WorkspaceActivation || + onboardingStatus === OnboardingStatus.SyncEmail || + onboardingStatus === OnboardingStatus.InviteTeam ) { return true; } if (isMatchingLocation(AppPath.PlanRequired)) { return ( - OnboardingStatus.CompletedWithoutSubscription === onboardingStatus || - OnboardingStatus.Canceled === onboardingStatus + (onboardingStatus === OnboardingStatus.Completed && + !isDefined(subscriptionStatus)) || + subscriptionStatus === SubscriptionStatus.Canceled ); } return false; - }, [isDefaultLayoutAuthModalVisible, isMatchingLocation, onboardingStatus]); + }, [ + isLoggedIn, + isDefaultLayoutAuthModalVisible, + isMatchingLocation, + onboardingStatus, + subscriptionStatus, + ]); }; diff --git a/packages/twenty-front/src/modules/ui/layout/modal/components/ConfirmationModal.tsx b/packages/twenty-front/src/modules/ui/layout/modal/components/ConfirmationModal.tsx index c6775ba1e849..402b94c51c0c 100644 --- a/packages/twenty-front/src/modules/ui/layout/modal/components/ConfirmationModal.tsx +++ b/packages/twenty-front/src/modules/ui/layout/modal/components/ConfirmationModal.tsx @@ -1,6 +1,6 @@ -import { ReactNode, useState } from 'react'; import styled from '@emotion/styled'; import { AnimatePresence, LayoutGroup } from 'framer-motion'; +import { ReactNode, useState } from 'react'; import { H1Title, H1TitleFontColor } from 'twenty-ui'; import { useDebouncedCallback } from 'use-debounce'; @@ -130,6 +130,7 @@ export const ConfirmationModal = ({ title={deleteButtonText} disabled={!isValidValue} fullWidth + dataTestId="confirmation-modal-confirm-button" /> </StyledConfirmationModal> </LayoutGroup> diff --git a/packages/twenty-front/src/modules/ui/layout/modal/components/Modal.tsx b/packages/twenty-front/src/modules/ui/layout/modal/components/Modal.tsx index 445086b52123..d9fd4f181c1f 100644 --- a/packages/twenty-front/src/modules/ui/layout/modal/components/Modal.tsx +++ b/packages/twenty-front/src/modules/ui/layout/modal/components/Modal.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useRef } from 'react'; +import { useEffect, useRef } from 'react'; import { Key } from 'ts-key-enum'; import { @@ -7,11 +7,8 @@ import { } from '@/ui/layout/modal/components/ModalLayout'; import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope'; import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys'; -import { - ClickOutsideMode, - useListenClickOutside, -} from '@/ui/utilities/pointer-event/hooks/useListenClickOutside'; +import { useListenClickOutsideV2 } from '@/ui/utilities/pointer-event/hooks/useListenClickOutsideV2'; import { ModalHotkeyScope } from './types/ModalHotkeyScope'; type ModalProps = ModalLayoutProps & { @@ -68,10 +65,10 @@ export const Modal = ({ const modalRef = useRef<HTMLDivElement>(null); - useListenClickOutside({ + useListenClickOutsideV2({ refs: [modalRef], + listenerId: 'MODAL_CLICK_OUTSIDE_LISTENER_ID', callback: () => onClose?.(), - mode: ClickOutsideMode.comparePixels, }); return isOpen ? ( diff --git a/packages/twenty-front/src/modules/ui/layout/page/BlankLayout.tsx b/packages/twenty-front/src/modules/ui/layout/page/BlankLayout.tsx index 7836cd39d70f..ab2e3eba7f97 100644 --- a/packages/twenty-front/src/modules/ui/layout/page/BlankLayout.tsx +++ b/packages/twenty-front/src/modules/ui/layout/page/BlankLayout.tsx @@ -1,12 +1,12 @@ -import { Outlet } from 'react-router-dom'; import { css, Global, useTheme } from '@emotion/react'; import styled from '@emotion/styled'; +import { Outlet } from 'react-router-dom'; const StyledLayout = styled.div` background: ${({ theme }) => theme.background.noisy}; display: flex; flex-direction: column; - height: 100vh; + height: 100dvh; position: relative; scrollbar-width: 4px; width: 100%; diff --git a/packages/twenty-front/src/modules/ui/layout/page/DefaultLayout.tsx b/packages/twenty-front/src/modules/ui/layout/page/DefaultLayout.tsx index d347a23d9976..a41e7914249e 100644 --- a/packages/twenty-front/src/modules/ui/layout/page/DefaultLayout.tsx +++ b/packages/twenty-front/src/modules/ui/layout/page/DefaultLayout.tsx @@ -1,7 +1,7 @@ -import { Outlet } from 'react-router-dom'; import { css, Global, useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { AnimatePresence, LayoutGroup, motion } from 'framer-motion'; +import { Outlet } from 'react-router-dom'; import { AuthModal } from '@/auth/components/Modal'; import { CommandMenu } from '@/command-menu/components/CommandMenu'; @@ -21,7 +21,7 @@ const StyledLayout = styled.div` background: ${({ theme }) => theme.background.noisy}; display: flex; flex-direction: column; - height: 100vh; + height: 100dvh; position: relative; scrollbar-color: ${({ theme }) => theme.border.color.medium}; scrollbar-width: 4px; diff --git a/packages/twenty-front/src/modules/ui/layout/page/PageHeader.tsx b/packages/twenty-front/src/modules/ui/layout/page/PageHeader.tsx index ae92a178319c..49e7ba382dcb 100644 --- a/packages/twenty-front/src/modules/ui/layout/page/PageHeader.tsx +++ b/packages/twenty-front/src/modules/ui/layout/page/PageHeader.tsx @@ -4,14 +4,15 @@ import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { useRecoilValue } from 'recoil'; import { - IconChevronLeft, + IconChevronDown, + IconChevronUp, IconComponent, + IconX, MOBILE_VIEWPORT, OverflowingTextWithTooltip, } from 'twenty-ui'; import { IconButton } from '@/ui/input/button/components/IconButton'; -import { UndecoratedLink } from '@/ui/navigation/link/components/UndecoratedLink'; import { NavigationDrawerCollapseButton } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerCollapseButton'; import { isNavigationDrawerOpenState } from '@/ui/navigation/states/isNavigationDrawerOpenState'; import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; @@ -53,6 +54,7 @@ const StyledLeftContainer = styled.div` const StyledTitleContainer = styled.div` display: flex; font-size: ${({ theme }) => theme.font.size.md}; + font-weight: ${({ theme }) => theme.font.weight.medium}; margin-left: ${({ theme }) => theme.spacing(1)}; max-width: 50%; `; @@ -61,6 +63,7 @@ const StyledTopBarIconStyledTitleContainer = styled.div` align-items: center; display: flex; flex: 1 0 auto; + gap: ${({ theme }) => theme.spacing(1)}; flex-direction: row; `; @@ -89,7 +92,13 @@ const StyledSkeletonLoader = () => { type PageHeaderProps = ComponentProps<'div'> & { title: string; - hasBackButton?: boolean; + hasClosePageButton?: boolean; + onClosePage?: () => void; + hasPaginationButtons?: boolean; + hasPreviousRecord?: boolean; + hasNextRecord?: boolean; + navigateToPreviousRecord?: () => void; + navigateToNextRecord?: () => void; Icon: IconComponent; children?: ReactNode; loading?: boolean; @@ -97,7 +106,13 @@ type PageHeaderProps = ComponentProps<'div'> & { export const PageHeader = ({ title, - hasBackButton, + hasClosePageButton, + onClosePage, + hasPaginationButtons, + hasPreviousRecord, + hasNextRecord, + navigateToPreviousRecord, + navigateToNextRecord, Icon, children, loading, @@ -114,19 +129,36 @@ export const PageHeader = ({ <NavigationDrawerCollapseButton direction="right" /> </StyledTopBarButtonContainer> )} - {hasBackButton && ( - <UndecoratedLink to={-1}> - <IconButton - Icon={IconChevronLeft} - size="small" - variant="tertiary" - /> - </UndecoratedLink> + {hasClosePageButton && ( + <IconButton + Icon={IconX} + size="small" + variant="tertiary" + onClick={() => onClosePage?.()} + /> )} {loading ? ( <StyledSkeletonLoader /> ) : ( <StyledTopBarIconStyledTitleContainer> + {hasPaginationButtons && ( + <> + <IconButton + Icon={IconChevronUp} + size="small" + variant="secondary" + disabled={!hasPreviousRecord} + onClick={() => navigateToPreviousRecord?.()} + /> + <IconButton + Icon={IconChevronDown} + size="small" + variant="secondary" + disabled={!hasNextRecord} + onClick={() => navigateToNextRecord?.()} + /> + </> + )} {Icon && <Icon size={theme.icon.size.md} />} <StyledTitleContainer data-testid="top-bar-title"> <OverflowingTextWithTooltip text={title} /> diff --git a/packages/twenty-front/src/modules/ui/layout/page/ShowPageContainer.tsx b/packages/twenty-front/src/modules/ui/layout/page/ShowPageContainer.tsx index 2014dc960f80..ab9f308c5cd7 100644 --- a/packages/twenty-front/src/modules/ui/layout/page/ShowPageContainer.tsx +++ b/packages/twenty-front/src/modules/ui/layout/page/ShowPageContainer.tsx @@ -8,8 +8,7 @@ const StyledOuterContainer = styled.div` display: flex; gap: ${({ theme }) => (useIsMobile() ? theme.spacing(3) : '0')}; - height: ${() => (useIsMobile() ? '100%' : '100%')}; - overflow-x: ${() => (useIsMobile() ? 'hidden' : 'auto')}; + height: 100%; width: 100%; `; diff --git a/packages/twenty-front/src/modules/ui/layout/right-drawer/components/RightDrawerRouter.tsx b/packages/twenty-front/src/modules/ui/layout/right-drawer/components/RightDrawerRouter.tsx index c9b4ab44bed7..20c931f86a81 100644 --- a/packages/twenty-front/src/modules/ui/layout/right-drawer/components/RightDrawerRouter.tsx +++ b/packages/twenty-front/src/modules/ui/layout/right-drawer/components/RightDrawerRouter.tsx @@ -2,6 +2,7 @@ import styled from '@emotion/styled'; import { useRecoilState, useRecoilValue } from 'recoil'; import { RightDrawerCalendarEvent } from '@/activities/calendar/right-drawer/components/RightDrawerCalendarEvent'; +import { RightDrawerAIChat } from '@/activities/copilot/right-drawer/components/RightDrawerAIChat'; import { RightDrawerEmailThread } from '@/activities/emails/right-drawer/components/RightDrawerEmailThread'; import { RightDrawerCreateActivity } from '@/activities/right-drawer/components/create/RightDrawerCreateActivity'; import { RightDrawerEditActivity } from '@/activities/right-drawer/components/edit/RightDrawerEditActivity'; @@ -50,6 +51,10 @@ const RIGHT_DRAWER_PAGES_CONFIG = { page: <RightDrawerRecord />, topBar: <RightDrawerTopBar page={RightDrawerPages.ViewRecord} />, }, + [RightDrawerPages.Copilot]: { + page: <RightDrawerAIChat />, + topBar: <RightDrawerTopBar page={RightDrawerPages.Copilot} />, + }, }; export const RightDrawerRouter = () => { diff --git a/packages/twenty-front/src/modules/ui/layout/right-drawer/constants/RightDrawerPageIcons.ts b/packages/twenty-front/src/modules/ui/layout/right-drawer/constants/RightDrawerPageIcons.ts index f1c46ba194eb..429436b66038 100644 --- a/packages/twenty-front/src/modules/ui/layout/right-drawer/constants/RightDrawerPageIcons.ts +++ b/packages/twenty-front/src/modules/ui/layout/right-drawer/constants/RightDrawerPageIcons.ts @@ -6,4 +6,5 @@ export const RIGHT_DRAWER_PAGE_ICONS = { [RightDrawerPages.ViewEmailThread]: 'IconMail', [RightDrawerPages.ViewCalendarEvent]: 'IconCalendarEvent', [RightDrawerPages.ViewRecord]: 'Icon123', + [RightDrawerPages.Copilot]: 'IconSparkles', }; diff --git a/packages/twenty-front/src/modules/ui/layout/right-drawer/constants/RightDrawerPageTitles.ts b/packages/twenty-front/src/modules/ui/layout/right-drawer/constants/RightDrawerPageTitles.ts index 6edb8fec2116..18517c80dd02 100644 --- a/packages/twenty-front/src/modules/ui/layout/right-drawer/constants/RightDrawerPageTitles.ts +++ b/packages/twenty-front/src/modules/ui/layout/right-drawer/constants/RightDrawerPageTitles.ts @@ -6,4 +6,5 @@ export const RIGHT_DRAWER_PAGE_TITLES = { [RightDrawerPages.ViewEmailThread]: 'Email Thread', [RightDrawerPages.ViewCalendarEvent]: 'Calendar Event', [RightDrawerPages.ViewRecord]: 'Record Editor', + [RightDrawerPages.Copilot]: 'Copilot', }; diff --git a/packages/twenty-front/src/modules/ui/layout/right-drawer/types/RightDrawerPages.ts b/packages/twenty-front/src/modules/ui/layout/right-drawer/types/RightDrawerPages.ts index 487b1a16f841..e579b65448f1 100644 --- a/packages/twenty-front/src/modules/ui/layout/right-drawer/types/RightDrawerPages.ts +++ b/packages/twenty-front/src/modules/ui/layout/right-drawer/types/RightDrawerPages.ts @@ -4,4 +4,5 @@ export enum RightDrawerPages { ViewEmailThread = 'view-email-thread', ViewCalendarEvent = 'view-calendar-event', ViewRecord = 'view-record', + Copilot = 'copilot', } diff --git a/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageRightContainer.tsx b/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageRightContainer.tsx index be7c067f3ae8..2ef8c280b9a7 100644 --- a/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageRightContainer.tsx +++ b/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageRightContainer.tsx @@ -28,8 +28,7 @@ const StyledShowPageRightContainer = styled.div<{ isMobile: boolean }>` flex: 1 0 0; flex-direction: column; justify-content: start; - overflow: ${(isMobile) => (isMobile ? 'none' : 'hidden')}; - width: calc(100% + 4px); + width: 100%; `; const StyledTabListContainer = styled.div` @@ -67,9 +66,7 @@ export const ShowPageRightContainer = ({ summary, isRightDrawer = false, }: ShowPageRightContainerProps) => { - const { activeTabIdState } = useTabList( - TAB_LIST_COMPONENT_ID + isRightDrawer, - ); + const { activeTabIdState } = useTabList(TAB_LIST_COMPONENT_ID); const activeTabId = useRecoilValue(activeTabIdState); const targetObjectNameSingular = @@ -148,7 +145,7 @@ export const ShowPageRightContainer = ({ <StyledTabListContainer> <TabList loading={loading} - tabListId={TAB_LIST_COMPONENT_ID + isRightDrawer} + tabListId={TAB_LIST_COMPONENT_ID} tabs={tabs} /> </StyledTabListContainer> diff --git a/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageSummaryCard.tsx b/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageSummaryCard.tsx index 30b9085af956..6a6b26cc591c 100644 --- a/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageSummaryCard.tsx +++ b/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageSummaryCard.tsx @@ -1,9 +1,8 @@ -import { ChangeEvent, ReactNode, useRef } from 'react'; -import Skeleton, { SkeletonTheme } from 'react-loading-skeleton'; -import { Tooltip } from 'react-tooltip'; import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; -import { Avatar, AvatarType } from 'twenty-ui'; +import { ChangeEvent, ReactNode, useRef } from 'react'; +import Skeleton, { SkeletonTheme } from 'react-loading-skeleton'; +import { AppTooltip, Avatar, AvatarType } from 'twenty-ui'; import { v4 as uuidV4 } from 'uuid'; import { @@ -55,17 +54,6 @@ const StyledTitle = styled.div` justify-content: center; `; -const StyledTooltip = styled(Tooltip)` - background-color: ${({ theme }) => theme.background.primary}; - box-shadow: ${({ theme }) => theme.boxShadow.light}; - - color: ${({ theme }) => theme.font.color.primary}; - - font-size: ${({ theme }) => theme.font.size.sm}; - font-weight: ${({ theme }) => theme.font.weight.regular}; - padding: ${({ theme }) => theme.spacing(2)}; -`; - const StyledAvatarWrapper = styled.div` cursor: pointer; `; @@ -136,7 +124,7 @@ export const ShowPageSummaryCard = ({ avatarUrl={logoOrAvatar} onClick={onUploadPicture ? handleAvatarClick : undefined} size="xl" - entityId={id} + placeholderColorSeed={id} placeholder={avatarPlaceholder} type={avatarType} /> @@ -153,7 +141,7 @@ export const ShowPageSummaryCard = ({ Added {beautifiedCreatedAt} </StyledDate> )} - <StyledTooltip + <AppTooltip anchorSelect={`#${dateElementId}`} content={exactCreatedAt} clickable diff --git a/packages/twenty-front/src/modules/ui/layout/tab/components/Tab.tsx b/packages/twenty-front/src/modules/ui/layout/tab/components/Tab.tsx index ff024d20f9e0..e723f0ae84ad 100644 --- a/packages/twenty-front/src/modules/ui/layout/tab/components/Tab.tsx +++ b/packages/twenty-front/src/modules/ui/layout/tab/components/Tab.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { IconComponent, Pill } from 'twenty-ui'; @@ -11,7 +10,7 @@ type TabProps = { className?: string; onClick?: () => void; disabled?: boolean; - hasBetaPill?: boolean; + pill?: string; }; const StyledTab = styled.div<{ active?: boolean; disabled?: boolean }>` @@ -41,6 +40,7 @@ const StyledHover = styled.span` padding: ${({ theme }) => theme.spacing(1)}; padding-left: ${({ theme }) => theme.spacing(2)}; padding-right: ${({ theme }) => theme.spacing(2)}; + font-weight: ${({ theme }) => theme.font.weight.medium}; &:hover { background: ${({ theme }) => theme.background.tertiary}; @@ -59,7 +59,7 @@ export const Tab = ({ onClick, className, disabled, - hasBetaPill, + pill, }: TabProps) => { const theme = useTheme(); return ( @@ -73,7 +73,7 @@ export const Tab = ({ <StyledHover> {Icon && <Icon size={theme.icon.size.md} />} {title} - {hasBetaPill && <Pill label="Beta" />} + {pill && <Pill label={pill} />} </StyledHover> </StyledTab> ); diff --git a/packages/twenty-front/src/modules/ui/layout/tab/components/TabList.tsx b/packages/twenty-front/src/modules/ui/layout/tab/components/TabList.tsx index ba93d808f9d9..0cd5b4bccc11 100644 --- a/packages/twenty-front/src/modules/ui/layout/tab/components/TabList.tsx +++ b/packages/twenty-front/src/modules/ui/layout/tab/components/TabList.tsx @@ -15,7 +15,7 @@ type SingleTabProps = { id: string; hide?: boolean; disabled?: boolean; - hasBetaPill?: boolean; + pill?: string; }; type TabListProps = { @@ -62,7 +62,7 @@ export const TabList = ({ tabs, tabListId, loading }: TabListProps) => { setActiveTabId(tab.id); }} disabled={tab.disabled ?? loading} - hasBetaPill={tab.hasBetaPill} + pill={tab.pill} /> ))} </StyledContainer> diff --git a/packages/twenty-front/src/modules/ui/navigation/action-bar/components/ActionBar.tsx b/packages/twenty-front/src/modules/ui/navigation/action-bar/components/ActionBar.tsx index 97e565844f5c..1cb6a4af4f80 100644 --- a/packages/twenty-front/src/modules/ui/navigation/action-bar/components/ActionBar.tsx +++ b/packages/twenty-front/src/modules/ui/navigation/action-bar/components/ActionBar.tsx @@ -1,15 +1,17 @@ -import { useEffect, useRef } from 'react'; import styled from '@emotion/styled'; +import { useEffect, useRef } from 'react'; import { useRecoilValue, useSetRecoilState } from 'recoil'; import { actionBarEntriesState } from '@/ui/navigation/action-bar/states/actionBarEntriesState'; import { contextMenuIsOpenState } from '@/ui/navigation/context-menu/states/contextMenuIsOpenState'; import SharedNavigationModal from '@/ui/navigation/shared/components/NavigationModal'; +import { isDefined } from '~/utils/isDefined'; import { ActionBarItem } from './ActionBarItem'; type ActionBarProps = { selectedIds?: string[]; + totalNumberOfSelectedRecords?: number; }; const StyledContainerActionBar = styled.div` @@ -40,7 +42,10 @@ const StyledLabel = styled.div` padding-right: ${({ theme }) => theme.spacing(2)}; `; -export const ActionBar = ({ selectedIds = [] }: ActionBarProps) => { +export const ActionBar = ({ + selectedIds = [], + totalNumberOfSelectedRecords, +}: ActionBarProps) => { const setContextMenuOpenState = useSetRecoilState(contextMenuIsOpenState); useEffect(() => { @@ -57,6 +62,12 @@ export const ActionBar = ({ selectedIds = [] }: ActionBarProps) => { return null; } + const selectedNumberLabel = + totalNumberOfSelectedRecords ?? selectedIds?.length; + + const showSelectedNumberLabel = + isDefined(totalNumberOfSelectedRecords) || Array.isArray(selectedIds); + return ( <> <StyledContainerActionBar @@ -64,8 +75,8 @@ export const ActionBar = ({ selectedIds = [] }: ActionBarProps) => { className="action-bar" ref={wrapperRef} > - {selectedIds && ( - <StyledLabel>{selectedIds.length} selected:</StyledLabel> + {showSelectedNumberLabel && ( + <StyledLabel>{selectedNumberLabel} selected:</StyledLabel> )} {actionBarEntries.map((item, index) => ( <ActionBarItem key={index} item={item} /> diff --git a/packages/twenty-front/src/modules/ui/navigation/action-bar/types/ActionBarEntry.ts b/packages/twenty-front/src/modules/ui/navigation/action-bar/types/ActionBarEntry.ts index f37a9b2e84cb..a276736cfb1c 100644 --- a/packages/twenty-front/src/modules/ui/navigation/action-bar/types/ActionBarEntry.ts +++ b/packages/twenty-front/src/modules/ui/navigation/action-bar/types/ActionBarEntry.ts @@ -1,12 +1,5 @@ -import { IconComponent } from 'twenty-ui'; +import { ContextMenuEntry } from '@/ui/navigation/context-menu/types/ContextMenuEntry'; -import { MenuItemAccent } from '@/ui/navigation/menu-item/types/MenuItemAccent'; - -export type ActionBarEntry = { - label: string; - Icon: IconComponent; - accent?: MenuItemAccent; - onClick?: () => void; +export type ActionBarEntry = ContextMenuEntry & { subActions?: ActionBarEntry[]; - ConfirmationModal?: JSX.Element; }; diff --git a/packages/twenty-front/src/modules/ui/navigation/context-menu/types/ContextMenuEntry.ts b/packages/twenty-front/src/modules/ui/navigation/context-menu/types/ContextMenuEntry.ts index d56820d6ebe1..416a41419f62 100644 --- a/packages/twenty-front/src/modules/ui/navigation/context-menu/types/ContextMenuEntry.ts +++ b/packages/twenty-front/src/modules/ui/navigation/context-menu/types/ContextMenuEntry.ts @@ -1,3 +1,4 @@ +import { MouseEvent, ReactNode } from 'react'; import { IconComponent } from 'twenty-ui'; import { MenuItemAccent } from '@/ui/navigation/menu-item/types/MenuItemAccent'; @@ -6,5 +7,6 @@ export type ContextMenuEntry = { label: string; Icon: IconComponent; accent?: MenuItemAccent; - onClick: () => void; + onClick?: (event?: MouseEvent<HTMLElement>) => void; + ConfirmationModal?: ReactNode; }; diff --git a/packages/twenty-front/src/modules/ui/navigation/link/components/RoundedLink.tsx b/packages/twenty-front/src/modules/ui/navigation/link/components/RoundedLink.tsx index 4b63ca09029b..61480f17fd2a 100644 --- a/packages/twenty-front/src/modules/ui/navigation/link/components/RoundedLink.tsx +++ b/packages/twenty-front/src/modules/ui/navigation/link/components/RoundedLink.tsx @@ -1,7 +1,7 @@ -import { MouseEvent } from 'react'; +import { MouseEvent, useContext } from 'react'; import { styled } from '@linaria/react'; import { isNonEmptyString } from '@sniptt/guards'; -import { FONT_COMMON, THEME_COMMON } from 'twenty-ui'; +import { FONT_COMMON, THEME_COMMON, ThemeContext } from 'twenty-ui'; type RoundedLinkProps = { href: string; @@ -11,17 +11,23 @@ type RoundedLinkProps = { const fontSizeMd = FONT_COMMON.size.md; const spacing1 = THEME_COMMON.spacing(1); -const spacing3 = THEME_COMMON.spacing(3); +const spacing2 = THEME_COMMON.spacing(2); const spacingMultiplicator = THEME_COMMON.spacingMultiplicator; -const StyledLink = styled.a` +const StyledLink = styled.a<{ + color: string; + background: string; + backgroundHover: string; + backgroundActive: string; + border: string; +}>` align-items: center; - background-color: var(--twentycrm-background-transparent-light); - border: 1px solid var(--twentycrm-border-color-medium); + background-color: ${({ background }) => background}; + border: 1px solid ${({ border }) => border}; border-radius: 50px; - color: var(--twentycrm-font-color-primary); + color: ${({ color }) => color}; cursor: pointer; display: inline-flex; @@ -29,25 +35,39 @@ const StyledLink = styled.a` gap: ${spacing1}; - height: ${spacing3}; + height: 10px; justify-content: center; max-width: calc(100% - ${spacingMultiplicator} * 2px); - max-width: 100%; - min-width: fit-content; overflow: hidden; - padding: ${spacing1} ${spacing1}; + padding: ${spacing1} ${spacing2}; text-decoration: none; text-overflow: ellipsis; user-select: none; white-space: nowrap; + + &:hover { + background-color: ${({ backgroundHover }) => backgroundHover}; + } + + &:active { + background-color: ${({ backgroundActive }) => backgroundActive}; + } `; export const RoundedLink = ({ label, href, onClick }: RoundedLinkProps) => { + const { theme } = useContext(ThemeContext); + + const background = theme.background.transparent.lighter; + const backgroundHover = theme.background.transparent.light; + const backgroundActive = theme.background.transparent.medium; + const border = theme.border.color.strong; + const color = theme.font.color.primary; + if (!isNonEmptyString(label)) { return <></>; } @@ -64,6 +84,11 @@ export const RoundedLink = ({ label, href, onClick }: RoundedLinkProps) => { target="_blank" rel="noreferrer" onClick={handleClick} + color={color} + background={background} + backgroundHover={backgroundHover} + backgroundActive={backgroundActive} + border={border} > {label} </StyledLink> diff --git a/packages/twenty-front/src/modules/ui/navigation/menu-item/components/MenuItem.tsx b/packages/twenty-front/src/modules/ui/navigation/menu-item/components/MenuItem.tsx index 4e40759f9750..a8571280723c 100644 --- a/packages/twenty-front/src/modules/ui/navigation/menu-item/components/MenuItem.tsx +++ b/packages/twenty-front/src/modules/ui/navigation/menu-item/components/MenuItem.tsx @@ -1,5 +1,6 @@ import { FunctionComponent, MouseEvent, ReactElement, ReactNode } from 'react'; -import { IconComponent } from 'twenty-ui'; +import { useTheme } from '@emotion/react'; +import { IconChevronRight, IconComponent } from 'twenty-ui'; import { LightIconButtonProps } from '@/ui/input/button/components/LightIconButton'; import { LightIconButtonGroup } from '@/ui/input/button/components/LightIconButtonGroup'; @@ -30,6 +31,7 @@ export type MenuItemProps = { onMouseLeave?: (event: MouseEvent<HTMLDivElement>) => void; testId?: string; text: ReactNode; + hasSubMenu?: boolean; }; export const MenuItem = ({ @@ -43,7 +45,9 @@ export const MenuItem = ({ onMouseLeave, testId, text, + hasSubMenu = false, }: MenuItemProps) => { + const theme = useTheme(); const showIconButtons = Array.isArray(iconButtons) && iconButtons.length > 0; const handleMenuItemClick = (event: MouseEvent<HTMLDivElement>) => { @@ -72,6 +76,13 @@ export const MenuItem = ({ <LightIconButtonGroup iconButtons={iconButtons} size="small" /> )} </div> + + {hasSubMenu && ( + <IconChevronRight + size={theme.icon.size.sm} + color={theme.font.color.tertiary} + /> + )} </StyledHoverableMenuItemBase> ); }; diff --git a/packages/twenty-front/src/modules/ui/navigation/menu-item/components/MenuItemDraggable.tsx b/packages/twenty-front/src/modules/ui/navigation/menu-item/components/MenuItemDraggable.tsx index 9643b8665948..98c01586b93f 100644 --- a/packages/twenty-front/src/modules/ui/navigation/menu-item/components/MenuItemDraggable.tsx +++ b/packages/twenty-front/src/modules/ui/navigation/menu-item/components/MenuItemDraggable.tsx @@ -3,7 +3,10 @@ import { IconComponent } from 'twenty-ui'; import { LightIconButtonGroup } from '@/ui/input/button/components/LightIconButtonGroup'; import { MenuItemLeftContent } from '../internals/components/MenuItemLeftContent'; -import { StyledHoverableMenuItemBase } from '../internals/components/StyledMenuItemBase'; +import { + StyledHoverableMenuItemBase, + StyledMenuItemBase, +} from '../internals/components/StyledMenuItemBase'; import { MenuItemAccent } from '../types/MenuItemAccent'; import { MenuItemIconButton } from './MenuItem'; @@ -15,9 +18,11 @@ export type MenuItemDraggableProps = { isTooltipOpen?: boolean; onClick?: () => void; text: string; - isDragDisabled?: boolean; className?: string; isIconDisplayedOnHoverOnly?: boolean; + showGrip?: boolean; + isDragDisabled?: boolean; + isHoverDisabled?: boolean; }; export const MenuItemDraggable = ({ LeftIcon, @@ -28,9 +33,24 @@ export const MenuItemDraggable = ({ isDragDisabled = false, className, isIconDisplayedOnHoverOnly = true, + showGrip = false, + isHoverDisabled = false, }: MenuItemDraggableProps) => { const showIconButtons = Array.isArray(iconButtons) && iconButtons.length > 0; + if (isHoverDisabled) { + return ( + <StyledMenuItemBase accent={accent} isHoverBackgroundDisabled> + <MenuItemLeftContent + LeftIcon={LeftIcon} + text={text} + isDisabled={isDragDisabled} + showGrip={showGrip} + /> + </StyledMenuItemBase> + ); + } + return ( <StyledHoverableMenuItemBase onClick={onClick} @@ -41,7 +61,8 @@ export const MenuItemDraggable = ({ <MenuItemLeftContent LeftIcon={LeftIcon} text={text} - showGrip={!isDragDisabled} + isDisabled={isDragDisabled} + showGrip={showGrip} /> {showIconButtons && ( <LightIconButtonGroup diff --git a/packages/twenty-front/src/modules/ui/navigation/menu-item/components/MenuItemNavigate.tsx b/packages/twenty-front/src/modules/ui/navigation/menu-item/components/MenuItemNavigate.tsx index 07f5ff1e03a6..dd847b3048d6 100644 --- a/packages/twenty-front/src/modules/ui/navigation/menu-item/components/MenuItemNavigate.tsx +++ b/packages/twenty-front/src/modules/ui/navigation/menu-item/components/MenuItemNavigate.tsx @@ -27,7 +27,10 @@ export const MenuItemNavigate = ({ <StyledMenuItemLeftContent> <MenuItemLeftContent LeftIcon={LeftIcon} text={text} /> </StyledMenuItemLeftContent> - <IconChevronRight size={theme.icon.size.md} /> + <IconChevronRight + size={theme.icon.size.sm} + color={theme.font.color.tertiary} + /> </StyledMenuItemBase> ); }; diff --git a/packages/twenty-front/src/modules/ui/navigation/menu-item/components/MenuItemSelectTag.tsx b/packages/twenty-front/src/modules/ui/navigation/menu-item/components/MenuItemSelectTag.tsx index ce429c8cf0cf..8c3d2ef23d9d 100644 --- a/packages/twenty-front/src/modules/ui/navigation/menu-item/components/MenuItemSelectTag.tsx +++ b/packages/twenty-front/src/modules/ui/navigation/menu-item/components/MenuItemSelectTag.tsx @@ -9,8 +9,9 @@ type MenuItemSelectTagProps = { selected: boolean; className?: string; onClick?: () => void; - color: ThemeColor; + color: ThemeColor | 'transparent'; text: string; + variant?: 'solid' | 'outline'; }; export const MenuItemSelectTag = ({ @@ -19,6 +20,7 @@ export const MenuItemSelectTag = ({ className, onClick, text, + variant = 'solid', }: MenuItemSelectTagProps) => { const theme = useTheme(); @@ -29,7 +31,7 @@ export const MenuItemSelectTag = ({ selected={selected} > <StyledMenuItemLeftContent> - <Tag color={color} text={text} /> + <Tag variant={variant} color={color} text={text} /> </StyledMenuItemLeftContent> {selected && <IconCheck size={theme.icon.size.sm} />} </StyledMenuItemSelect> diff --git a/packages/twenty-front/src/modules/ui/navigation/menu-item/components/__stories__/MenuItemDraggable.stories.tsx b/packages/twenty-front/src/modules/ui/navigation/menu-item/components/__stories__/MenuItemDraggable.stories.tsx index b7d6dba3be91..05885c00a02b 100644 --- a/packages/twenty-front/src/modules/ui/navigation/menu-item/components/__stories__/MenuItemDraggable.stories.tsx +++ b/packages/twenty-front/src/modules/ui/navigation/menu-item/components/__stories__/MenuItemDraggable.stories.tsx @@ -104,3 +104,11 @@ export const Catalog: Story = { }, decorators: [CatalogDecorator], }; + +export const Grip: Story = { + args: { ...Default.args, showGrip: true, isDragDisabled: false }, +}; + +export const HoverDisabled: Story = { + args: { ...Default.args, isHoverDisabled: true }, +}; diff --git a/packages/twenty-front/src/modules/ui/navigation/menu-item/internals/components/MenuItemLeftContent.tsx b/packages/twenty-front/src/modules/ui/navigation/menu-item/internals/components/MenuItemLeftContent.tsx index ce6b2a188f4a..d2281aea7dad 100644 --- a/packages/twenty-front/src/modules/ui/navigation/menu-item/internals/components/MenuItemLeftContent.tsx +++ b/packages/twenty-front/src/modules/ui/navigation/menu-item/internals/components/MenuItemLeftContent.tsx @@ -8,6 +8,7 @@ import { } from 'twenty-ui'; import { + StyledDraggableItem, StyledMenuItemLabel, StyledMenuItemLeftContent, } from './StyledMenuItemBase'; @@ -16,6 +17,7 @@ type MenuItemLeftContentProps = { className?: string; LeftIcon: IconComponent | null | undefined; showGrip?: boolean; + isDisabled?: boolean; text: ReactNode; }; @@ -24,18 +26,34 @@ export const MenuItemLeftContent = ({ LeftIcon, text, showGrip = false, + isDisabled = false, }: MenuItemLeftContentProps) => { const theme = useTheme(); return ( <StyledMenuItemLeftContent className={className}> - {showGrip && ( - <IconGripVertical - size={theme.icon.size.md} - stroke={theme.icon.stroke.sm} - color={theme.font.color.extraLight} - /> - )} + {showGrip && + (isDisabled ? ( + <IconGripVertical + size={theme.icon.size.md} + stroke={theme.icon.stroke.sm} + color={ + isDisabled ? theme.font.color.extraLight : theme.font.color.light + } + /> + ) : ( + <StyledDraggableItem> + <IconGripVertical + size={theme.icon.size.md} + stroke={theme.icon.stroke.sm} + color={ + isDisabled + ? theme.font.color.extraLight + : theme.font.color.light + } + /> + </StyledDraggableItem> + ))} {LeftIcon && ( <LeftIcon size={theme.icon.size.md} stroke={theme.icon.stroke.sm} /> )} diff --git a/packages/twenty-front/src/modules/ui/navigation/menu-item/internals/components/StyledMenuItemBase.tsx b/packages/twenty-front/src/modules/ui/navigation/menu-item/internals/components/StyledMenuItemBase.tsx index 71cd27eae09e..a2489def35b9 100644 --- a/packages/twenty-front/src/modules/ui/navigation/menu-item/internals/components/StyledMenuItemBase.tsx +++ b/packages/twenty-front/src/modules/ui/navigation/menu-item/internals/components/StyledMenuItemBase.tsx @@ -7,6 +7,7 @@ import { MenuItemAccent } from '../../types/MenuItemAccent'; export type MenuItemBaseProps = { accent?: MenuItemAccent; isKeySelected?: boolean; + isHoverBackgroundDisabled?: boolean; }; export const StyledMenuItemBase = styled.div<MenuItemBaseProps>` @@ -31,7 +32,8 @@ export const StyledMenuItemBase = styled.div<MenuItemBaseProps>` padding: var(--vertical-padding) var(--horizontal-padding); - ${HOVER_BACKGROUND}; + ${({ isHoverBackgroundDisabled }) => + isHoverBackgroundDisabled ?? HOVER_BACKGROUND}; ${({ theme, accent }) => { switch (accent) { @@ -99,6 +101,10 @@ export const StyledMenuItemRightContent = styled.div` flex-direction: row; `; +export const StyledDraggableItem = styled.div` + cursor: grab; +`; + export const StyledHoverableMenuItemBase = styled(StyledMenuItemBase)<{ isIconDisplayedOnHoverOnly?: boolean; }>` diff --git a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/MultiWorkspaceDropdownButton.tsx b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/MultiWorkspaceDropdownButton.tsx index 0249de11c093..23d356aa4fea 100644 --- a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/MultiWorkspaceDropdownButton.tsx +++ b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/MultiWorkspaceDropdownButton.tsx @@ -33,10 +33,12 @@ const StyledContainer = styled.div` border: 1px solid transparent; display: flex; justify-content: space-between; - height: ${({ theme }) => theme.spacing(7)}; - padding: 0 ${({ theme }) => theme.spacing(2)}; + height: ${({ theme }) => theme.spacing(5)}; + padding: calc(${({ theme }) => theme.spacing(1)} - 1px); width: 100%; + gap: ${({ theme }) => theme.spacing(1)}; + &:hover { background-color: ${({ theme }) => theme.background.transparent.lighter}; border: 1px solid ${({ theme }) => theme.border.color.medium}; @@ -46,7 +48,6 @@ const StyledContainer = styled.div` const StyledLabel = styled.div` align-items: center; display: flex; - gap: ${({ theme }) => theme.spacing(2)}; `; const StyledIconChevronDown = styled(IconChevronDown)<{ disabled?: boolean }>` diff --git a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawer.tsx b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawer.tsx index 524e87947691..406402377646 100644 --- a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawer.tsx +++ b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawer.tsx @@ -53,7 +53,7 @@ const StyledContainer = styled.div<{ isSubMenu?: boolean }>` const StyledItemsContainer = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(8)}; + gap: ${({ theme }) => theme.spacing(3)}; margin-bottom: auto; overflow-y: auto; `; diff --git a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerCollapseButton.tsx b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerCollapseButton.tsx index 856cb3041a88..d555a43599d9 100644 --- a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerCollapseButton.tsx +++ b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerCollapseButton.tsx @@ -14,7 +14,7 @@ const StyledCollapseButton = styled.div` color: ${({ theme }) => theme.font.color.light}; cursor: pointer; display: flex; - height: ${({ theme }) => theme.spacing(6)}; + height: ${({ theme }) => theme.spacing(5)}; justify-content: center; user-select: none; width: ${({ theme }) => theme.spacing(6)}; diff --git a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerHeader.tsx b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerHeader.tsx index eae27e8c73d3..9ba91a1c5935 100644 --- a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerHeader.tsx +++ b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerHeader.tsx @@ -9,12 +9,14 @@ import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; import { NavigationDrawerCollapseButton } from './NavigationDrawerCollapseButton'; -const StyledContainer = styled.div` +const StyledContainer = styled.div<{ isMultiWorkspace: boolean }>` align-items: center; display: flex; - gap: ${({ theme }) => theme.spacing(2)}; - height: ${({ theme }) => theme.spacing(6)}; - padding: ${({ theme }) => theme.spacing(1)}; + gap: ${({ theme, isMultiWorkspace }) => + !isMultiWorkspace ? theme.spacing(2) : null}; + padding: ${({ theme, isMultiWorkspace }) => + !isMultiWorkspace ? theme.spacing(1) : null}; + height: ${({ theme }) => theme.spacing(7)}; user-select: none; `; @@ -55,10 +57,11 @@ export const NavigationDrawerHeader = ({ }: NavigationDrawerHeaderProps) => { const isMobile = useIsMobile(); const workspaces = useRecoilValue(workspacesState); + const isMultiWorkspace = workspaces !== null && workspaces.length > 1; return ( - <StyledContainer> - {workspaces !== null && workspaces.length > 1 ? ( + <StyledContainer isMultiWorkspace={isMultiWorkspace}> + {isMultiWorkspace ? ( <MultiWorkspaceDropdownButton workspaces={workspaces} /> ) : ( <> diff --git a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerItem.tsx b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerItem.tsx index 8f0dd6ed2f8b..d4f33fb82a1b 100644 --- a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerItem.tsx +++ b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerItem.tsx @@ -39,6 +39,7 @@ const StyledItem = styled('div', { align-items: center; background: ${(props) => props.active ? props.theme.background.transparent.light : 'inherit'}; + height: ${({ theme }) => theme.spacing(5)}; border: none; border-radius: ${({ theme }) => theme.border.radius.sm}; text-decoration: none; diff --git a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerSectionTitle.tsx b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerSectionTitle.tsx index 39052b65782d..4f8386e12d0f 100644 --- a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerSectionTitle.tsx +++ b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerSectionTitle.tsx @@ -2,21 +2,34 @@ import styled from '@emotion/styled'; import { useIsPrefetchLoading } from '@/prefetch/hooks/useIsPrefetchLoading'; import { NavigationDrawerSectionTitleSkeletonLoader } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSectionTitleSkeletonLoader'; +import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull'; type NavigationDrawerSectionTitleProps = { + onClick?: () => void; label: string; }; -const StyledTitle = styled.div` +const StyledTitle = styled.div<{ onClick?: () => void }>` + align-items: center; + border-radius: ${({ theme }) => theme.border.radius.sm}; color: ${({ theme }) => theme.font.color.light}; display: flex; font-size: ${({ theme }) => theme.font.size.xs}; font-weight: ${({ theme }) => theme.font.weight.semiBold}; + height: ${({ theme }) => theme.spacing(5)}; padding: ${({ theme }) => theme.spacing(1)}; - padding-top: 0; + + ${({ onClick, theme }) => + !isUndefinedOrNull(onClick) + ? `&:hover { + cursor: pointer; + background-color:${theme.background.transparent.light}; + }` + : ''} `; export const NavigationDrawerSectionTitle = ({ + onClick, label, }: NavigationDrawerSectionTitleProps) => { const loading = useIsPrefetchLoading(); @@ -24,5 +37,5 @@ export const NavigationDrawerSectionTitle = ({ if (loading) { return <NavigationDrawerSectionTitleSkeletonLoader />; } - return <StyledTitle>{label}</StyledTitle>; + return <StyledTitle onClick={onClick}>{label}</StyledTitle>; }; diff --git a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/hooks/useNavigationSection.ts b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/hooks/useNavigationSection.ts new file mode 100644 index 000000000000..b497319a09ac --- /dev/null +++ b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/hooks/useNavigationSection.ts @@ -0,0 +1,60 @@ +import { useRecoilCallback } from 'recoil'; + +import { isNavigationSectionOpenComponentState } from '@/ui/navigation/navigation-drawer/states/isNavigationSectionOpenComponentState'; +import { extractComponentState } from '@/ui/utilities/state/component-state/utils/extractComponentState'; + +export const useNavigationSection = (scopeId: string) => { + const closeNavigationSection = useRecoilCallback( + ({ set }) => + () => { + set( + isNavigationSectionOpenComponentState({ + scopeId, + }), + false, + ); + }, + [scopeId], + ); + + const openNavigationSection = useRecoilCallback( + ({ set }) => + () => { + set( + isNavigationSectionOpenComponentState({ + scopeId, + }), + true, + ); + }, + [scopeId], + ); + + const toggleNavigationSection = useRecoilCallback( + ({ snapshot }) => + () => { + const isNavigationSectionOpen = snapshot + .getLoadable(isNavigationSectionOpenComponentState({ scopeId })) + .getValue(); + + if (isNavigationSectionOpen) { + closeNavigationSection(); + } else { + openNavigationSection(); + } + }, + [closeNavigationSection, openNavigationSection, scopeId], + ); + + const isNavigationSectionOpenState = extractComponentState( + isNavigationSectionOpenComponentState, + scopeId, + ); + + return { + isNavigationSectionOpenState, + closeNavigationSection, + openNavigationSection, + toggleNavigationSection, + }; +}; diff --git a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/states/isNavigationSectionOpenComponentState.ts b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/states/isNavigationSectionOpenComponentState.ts new file mode 100644 index 000000000000..cd0fec7a0c99 --- /dev/null +++ b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/states/isNavigationSectionOpenComponentState.ts @@ -0,0 +1,9 @@ +import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { localStorageEffect } from '~/utils/recoil-effects'; + +export const isNavigationSectionOpenComponentState = + createComponentState<boolean>({ + key: 'isNavigationSectionOpenComponentState', + defaultValue: true, + effects: [localStorageEffect()], + }); diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/AnimatedContainer.tsx b/packages/twenty-front/src/modules/ui/utilities/animation/components/AnimatedContainer.tsx similarity index 65% rename from packages/twenty-front/src/modules/object-record/record-table/components/AnimatedContainer.tsx rename to packages/twenty-front/src/modules/ui/utilities/animation/components/AnimatedContainer.tsx index c821abb3794f..581e03cb7bc7 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/AnimatedContainer.tsx +++ b/packages/twenty-front/src/modules/ui/utilities/animation/components/AnimatedContainer.tsx @@ -1,20 +1,17 @@ -import React from 'react'; -import styled from '@emotion/styled'; import { motion } from 'framer-motion'; - -const StyledAnimatedChipContainer = styled(motion.div)``; +import React from 'react'; export const AnimatedContainer = ({ children, }: { children: React.ReactNode; }) => ( - <StyledAnimatedChipContainer + <motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} transition={{ duration: 0.1 }} whileHover={{ scale: 1.04 }} > {children} - </StyledAnimatedChipContainer> + </motion.div> ); diff --git a/packages/twenty-front/src/modules/ui/utilities/recoil-scope/hooks/__tests__/useContextScopeId.test.tsx b/packages/twenty-front/src/modules/ui/utilities/recoil-scope/hooks/__tests__/useContextScopeId.test.tsx index 83ad28a3f371..b14092d3b311 100644 --- a/packages/twenty-front/src/modules/ui/utilities/recoil-scope/hooks/__tests__/useContextScopeId.test.tsx +++ b/packages/twenty-front/src/modules/ui/utilities/recoil-scope/hooks/__tests__/useContextScopeId.test.tsx @@ -20,8 +20,8 @@ describe('useContextScopeId', () => { ), }); - const scopedId = result.current; - expect(scopedId).toBe(mockedContextValue); + const scopeId = result.current; + expect(scopeId).toBe(mockedContextValue); }); it('Should throw an error when used outside of the specified context', () => { diff --git a/packages/twenty-front/src/modules/ui/utilities/recoil-scope/hooks/__tests__/useRecoilScopeId.test.tsx b/packages/twenty-front/src/modules/ui/utilities/recoil-scope/hooks/__tests__/useRecoilScopeId.test.tsx index 80e690b24ab8..a8d5eafd19d8 100644 --- a/packages/twenty-front/src/modules/ui/utilities/recoil-scope/hooks/__tests__/useRecoilScopeId.test.tsx +++ b/packages/twenty-front/src/modules/ui/utilities/recoil-scope/hooks/__tests__/useRecoilScopeId.test.tsx @@ -20,8 +20,8 @@ describe('useRecoilScopeId', () => { ), }); - const scopedId = result.current; - expect(scopedId).toBe(mockedContextValue); + const scopeId = result.current; + expect(scopeId).toBe(mockedContextValue); }); it('Should throw an error when used outside of the specified context', () => { diff --git a/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useRecoilComponentValue.ts b/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useRecoilComponentValue.ts new file mode 100644 index 000000000000..d72ee3cae3f2 --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useRecoilComponentValue.ts @@ -0,0 +1,29 @@ +import { useRecoilValue } from 'recoil'; + +import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId'; +import { getScopeIdOrUndefinedFromComponentId } from '@/ui/utilities/recoil-scope/utils/getScopeIdOrUndefinedFromComponentId'; +import { ComponentState } from '@/ui/utilities/state/component-state/types/ComponentState'; + +export const useRecoilComponentValue = <StateType>( + componentState: ComponentState<StateType>, + componentId?: string, +) => { + const componentContext = (window as any).componentContextStateMap?.get( + componentState.key, + ); + + if (!componentContext) { + throw new Error( + `Component context for key "${componentState.key}" is not defined`, + ); + } + + const internalComponentId = useAvailableScopeIdOrThrow( + componentContext, + getScopeIdOrUndefinedFromComponentId(componentId), + ); + + return useRecoilValue( + componentState.atomFamily({ scopeId: internalComponentId }), + ); +}; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useSetRecoilComponentState.ts b/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useSetRecoilComponentState.ts new file mode 100644 index 000000000000..938d699b3f51 --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useSetRecoilComponentState.ts @@ -0,0 +1,29 @@ +import { useSetRecoilState } from 'recoil'; + +import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId'; +import { getScopeIdOrUndefinedFromComponentId } from '@/ui/utilities/recoil-scope/utils/getScopeIdOrUndefinedFromComponentId'; +import { ComponentState } from '@/ui/utilities/state/component-state/types/ComponentState'; + +export const useSetRecoilComponentState = <StateType>( + componentState: ComponentState<StateType>, + componentId?: string, +) => { + const componentContext = (window as any).componentContextStateMap?.get( + componentState.key, + ); + + if (!componentContext) { + throw new Error( + `Component context for key "${componentState.key}" is not defined`, + ); + } + + const internalComponentId = useAvailableScopeIdOrThrow( + componentContext, + getScopeIdOrUndefinedFromComponentId(componentId), + ); + + return useSetRecoilState( + componentState.atomFamily({ scopeId: internalComponentId }), + ); +}; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/component-state/types/ComponentState.ts b/packages/twenty-front/src/modules/ui/utilities/state/component-state/types/ComponentState.ts new file mode 100644 index 000000000000..8fc43e8a291b --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/state/component-state/types/ComponentState.ts @@ -0,0 +1,8 @@ +import { RecoilState } from 'recoil'; + +import { ComponentStateKey } from '@/ui/utilities/state/component-state/types/ComponentStateKey'; + +export type ComponentState<StateType> = { + key: string; + atomFamily: (componentStateKey: ComponentStateKey) => RecoilState<StateType>; +}; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/createComponentState.ts b/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/createComponentState.ts index 2e2cd8ada9d9..ffbd9dd7eb48 100644 --- a/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/createComponentState.ts +++ b/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/createComponentState.ts @@ -1,16 +1,21 @@ -import { atomFamily } from 'recoil'; +import { AtomEffect, atomFamily } from 'recoil'; import { ComponentStateKey } from '@/ui/utilities/state/component-state/types/ComponentStateKey'; +type CreateComponentStateType<ValueType> = { + key: string; + defaultValue: ValueType; + effects?: AtomEffect<ValueType>[]; +}; + export const createComponentState = <ValueType>({ key, defaultValue, -}: { - key: string; - defaultValue: ValueType; -}) => { + effects, +}: CreateComponentStateType<ValueType>) => { return atomFamily<ValueType, ComponentStateKey>({ key, default: defaultValue, + effects: effects, }); }; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/createComponentStateV2.ts b/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/createComponentStateV2.ts new file mode 100644 index 000000000000..1fda1db8210e --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/createComponentStateV2.ts @@ -0,0 +1,37 @@ +import { AtomEffect, atomFamily } from 'recoil'; + +import { ScopeInternalContext } from '@/ui/utilities/recoil-scope/scopes-internal/types/ScopeInternalContext'; +import { ComponentState } from '@/ui/utilities/state/component-state/types/ComponentState'; +import { ComponentStateKey } from '@/ui/utilities/state/component-state/types/ComponentStateKey'; +import { isDefined } from '~/utils/isDefined'; + +type CreateComponentStateV2Type<ValueType> = { + key: string; + defaultValue: ValueType; + componentContext?: ScopeInternalContext<any> | null; + effects?: AtomEffect<ValueType>[]; +}; + +export const createComponentStateV2 = <ValueType>({ + key, + defaultValue, + componentContext, + effects, +}: CreateComponentStateV2Type<ValueType>): ComponentState<ValueType> => { + if (isDefined(componentContext)) { + if (!isDefined((window as any).componentContextStateMap)) { + (window as any).componentContextStateMap = new Map(); + } + + (window as any).componentContextStateMap.set(key, componentContext); + } + + return { + key, + atomFamily: atomFamily<ValueType, ComponentStateKey>({ + key, + default: defaultValue, + effects: effects, + }), + }; +}; diff --git a/packages/twenty-front/src/modules/users/components/UserChip.tsx b/packages/twenty-front/src/modules/users/components/UserChip.tsx index 82beb9da53be..5f4fbc94ebf3 100644 --- a/packages/twenty-front/src/modules/users/components/UserChip.tsx +++ b/packages/twenty-front/src/modules/users/components/UserChip.tsx @@ -1,4 +1,4 @@ -import { EntityChip } from 'twenty-ui'; +import { AvatarChip } from 'twenty-ui'; import { getImageAbsoluteURIOrBase64 } from '~/utils/image/getImageAbsoluteURIOrBase64'; @@ -9,8 +9,8 @@ export type UserChipProps = { }; export const UserChip = ({ id, name, avatarUrl }: UserChipProps) => ( - <EntityChip - entityId={id} + <AvatarChip + placeholderColorSeed={id} name={name} avatarType="rounded" avatarUrl={getImageAbsoluteURIOrBase64(avatarUrl) || ''} diff --git a/packages/twenty-front/src/modules/users/graphql/fragments/userQueryFragment.ts b/packages/twenty-front/src/modules/users/graphql/fragments/userQueryFragment.ts index 32d358c64571..14dcf557a294 100644 --- a/packages/twenty-front/src/modules/users/graphql/fragments/userQueryFragment.ts +++ b/packages/twenty-front/src/modules/users/graphql/fragments/userQueryFragment.ts @@ -8,7 +8,7 @@ export const USER_QUERY_FRAGMENT = gql` email canImpersonate supportUserHash - onboardingStep + onboardingStatus workspaceMember { id name { @@ -26,7 +26,6 @@ export const USER_QUERY_FRAGMENT = gql` domainName inviteHash allowImpersonation - subscriptionStatus activationStatus featureFlags { id @@ -40,6 +39,7 @@ export const USER_QUERY_FRAGMENT = gql` status interval } + workspaceMembersCount } workspaces { workspace { diff --git a/packages/twenty-front/src/modules/views/components/EditableFilterChip.tsx b/packages/twenty-front/src/modules/views/components/EditableFilterChip.tsx index c7f727d8b0f6..86c413798fa5 100644 --- a/packages/twenty-front/src/modules/views/components/EditableFilterChip.tsx +++ b/packages/twenty-front/src/modules/views/components/EditableFilterChip.tsx @@ -16,8 +16,8 @@ export const EditableFilterChip = ({ const { getIcon } = useIcons(); return ( <SortOrFilterChip - key={viewFilter.fieldMetadataId} - testId={viewFilter.fieldMetadataId} + key={viewFilter.id} + testId={viewFilter.id} labelKey={viewFilter.definition.label} labelValue={`${getOperandLabelShort(viewFilter.operand)} ${ viewFilter.displayValue diff --git a/packages/twenty-front/src/modules/views/components/EditableFilterDropdownButton.tsx b/packages/twenty-front/src/modules/views/components/EditableFilterDropdownButton.tsx index ee7f4dedb1f7..ee5f17968ad3 100644 --- a/packages/twenty-front/src/modules/views/components/EditableFilterDropdownButton.tsx +++ b/packages/twenty-front/src/modules/views/components/EditableFilterDropdownButton.tsx @@ -62,13 +62,13 @@ export const EditableFilterDropdownButton = ({ const handleRemove = () => { closeDropdown(); - removeCombinedViewFilter(viewFilter.fieldMetadataId); + removeCombinedViewFilter(viewFilter.id); }; const handleDropdownClickOutside = useCallback(() => { - const { value, fieldMetadataId } = viewFilter; + const { id: fieldId, value } = viewFilter; if (!value) { - removeCombinedViewFilter(fieldMetadataId); + removeCombinedViewFilter(fieldId); } }, [viewFilter, removeCombinedViewFilter]); diff --git a/packages/twenty-front/src/modules/views/components/ViewBar.tsx b/packages/twenty-front/src/modules/views/components/ViewBar.tsx index d090b1f8c382..3c600daec05f 100644 --- a/packages/twenty-front/src/modules/views/components/ViewBar.tsx +++ b/packages/twenty-front/src/modules/views/components/ViewBar.tsx @@ -41,7 +41,6 @@ export const ViewBar = ({ const sortDropdownId = 'view-sort'; const loading = useIsPrefetchLoading(); - if (!objectNamePlural) { return; } diff --git a/packages/twenty-front/src/modules/views/components/ViewBarDetails.tsx b/packages/twenty-front/src/modules/views/components/ViewBarDetails.tsx index 6a0a2882dd4a..e51137f74461 100644 --- a/packages/twenty-front/src/modules/views/components/ViewBarDetails.tsx +++ b/packages/twenty-front/src/modules/views/components/ViewBarDetails.tsx @@ -153,19 +153,17 @@ export const ViewBarDetails = ({ availableFilterDefinitions, ).map((viewFilter) => ( <ObjectFilterDropdownScope - key={viewFilter.fieldMetadataId} - filterScopeId={viewFilter.fieldMetadataId} + key={viewFilter.id} + filterScopeId={viewFilter.id} > - <DropdownScope dropdownScopeId={viewFilter.fieldMetadataId}> - <ViewBarFilterEffect - filterDropdownId={viewFilter.fieldMetadataId} - /> + <DropdownScope dropdownScopeId={viewFilter.id}> + <ViewBarFilterEffect filterDropdownId={viewFilter.id} /> <EditableFilterDropdownButton viewFilter={viewFilter} hotkeyScope={{ - scope: viewFilter.fieldMetadataId, + scope: viewFilter.id, }} - viewFilterDropdownId={viewFilter.fieldMetadataId} + viewFilterDropdownId={viewFilter.id} /> </DropdownScope> </ObjectFilterDropdownScope> diff --git a/packages/twenty-front/src/modules/views/components/ViewBarEffect.tsx b/packages/twenty-front/src/modules/views/components/ViewBarEffect.tsx index 518ed1590b46..a23b73922d8b 100644 --- a/packages/twenty-front/src/modules/views/components/ViewBarEffect.tsx +++ b/packages/twenty-front/src/modules/views/components/ViewBarEffect.tsx @@ -1,5 +1,5 @@ -import { useEffect, useState } from 'react'; import { isUndefined } from '@sniptt/guards'; +import { useEffect, useState } from 'react'; import { useRecoilValue } from 'recoil'; import { useViewStates } from '@/views/hooks/internal/useViewStates'; diff --git a/packages/twenty-front/src/modules/views/components/ViewBarFilterEffect.tsx b/packages/twenty-front/src/modules/views/components/ViewBarFilterEffect.tsx index 1f19e48103da..544e3466fbb9 100644 --- a/packages/twenty-front/src/modules/views/components/ViewBarFilterEffect.tsx +++ b/packages/twenty-front/src/modules/views/components/ViewBarFilterEffect.tsx @@ -6,6 +6,7 @@ import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/ import { Filter } from '@/object-record/object-filter-dropdown/types/Filter'; import { useViewStates } from '@/views/hooks/internal/useViewStates'; import { useCombinedViewFilters } from '@/views/hooks/useCombinedViewFilters'; +import { useGetCurrentView } from '@/views/hooks/useGetCurrentView'; import { isDefined } from '~/utils/isDefined'; type ViewBarFilterEffectProps = { @@ -15,11 +16,12 @@ type ViewBarFilterEffectProps = { export const ViewBarFilterEffect = ({ filterDropdownId, }: ViewBarFilterEffectProps) => { - const { availableFilterDefinitionsState, unsavedToUpsertViewFiltersState } = - useViewStates(); + const { availableFilterDefinitionsState } = useViewStates(); const { upsertCombinedViewFilter } = useCombinedViewFilters(); + const { currentViewWithCombinedFiltersAndSorts } = useGetCurrentView(); + const availableFilterDefinitions = useRecoilValue( availableFilterDefinitionsState, ); @@ -51,47 +53,41 @@ export const ViewBarFilterEffect = ({ upsertCombinedViewFilter, ]); - const unsavedToUpsertViewFilters = useRecoilValue( - unsavedToUpsertViewFiltersState, - ); - useEffect(() => { if (filterDefinitionUsedInDropdown?.type === 'RELATION') { - const viewFilterUsedInDropdown = unsavedToUpsertViewFilters.find( - (filter) => - filter.fieldMetadataId === - filterDefinitionUsedInDropdown.fieldMetadataId, - ); + const viewFilterUsedInDropdown = + currentViewWithCombinedFiltersAndSorts?.viewFilters.find( + (filter) => + filter.fieldMetadataId === + filterDefinitionUsedInDropdown?.fieldMetadataId, + ); - const viewFilterSelectedRecordIds = isNonEmptyString( + const viewFilterSelectedRecords = isNonEmptyString( viewFilterUsedInDropdown?.value, ) ? JSON.parse(viewFilterUsedInDropdown.value) : []; - - setObjectFilterDropdownSelectedRecordIds(viewFilterSelectedRecordIds); + setObjectFilterDropdownSelectedRecordIds(viewFilterSelectedRecords); } else if (filterDefinitionUsedInDropdown?.type === 'SELECT') { - const viewFilterUsedInDropdown = unsavedToUpsertViewFilters.find( - (filter) => - filter.fieldMetadataId === - filterDefinitionUsedInDropdown.fieldMetadataId, - ); + const viewFilterUsedInDropdown = + currentViewWithCombinedFiltersAndSorts?.viewFilters.find( + (filter) => + filter.fieldMetadataId === + filterDefinitionUsedInDropdown?.fieldMetadataId, + ); - const viewFilterSelectedOptionValues = isNonEmptyString( + const viewFilterSelectedRecords = isNonEmptyString( viewFilterUsedInDropdown?.value, ) ? JSON.parse(viewFilterUsedInDropdown.value) : []; - - setObjectFilterDropdownSelectedOptionValues( - viewFilterSelectedOptionValues, - ); + setObjectFilterDropdownSelectedOptionValues(viewFilterSelectedRecords); } }, [ filterDefinitionUsedInDropdown, setObjectFilterDropdownSelectedRecordIds, setObjectFilterDropdownSelectedOptionValues, - unsavedToUpsertViewFilters, + currentViewWithCombinedFiltersAndSorts, ]); return <></>; diff --git a/packages/twenty-front/src/modules/views/components/ViewFieldsVisibilityDropdownSection.tsx b/packages/twenty-front/src/modules/views/components/ViewFieldsVisibilityDropdownSection.tsx index 9bc30f5a2359..edbbdf3c0a8d 100644 --- a/packages/twenty-front/src/modules/views/components/ViewFieldsVisibilityDropdownSection.tsx +++ b/packages/twenty-front/src/modules/views/components/ViewFieldsVisibilityDropdownSection.tsx @@ -19,7 +19,6 @@ import { DraggableItem } from '@/ui/layout/draggable-list/components/DraggableIt import { DraggableList } from '@/ui/layout/draggable-list/components/DraggableList'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { StyledDropdownMenuSubheader } from '@/ui/layout/dropdown/components/StyledDropdownMenuSubheader'; -import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem'; import { MenuItemDraggable } from '@/ui/navigation/menu-item/components/MenuItemDraggable'; import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside'; import { groupArrayItemsBy } from '~/utils/array/groupArrayItemsBy'; @@ -101,13 +100,17 @@ export const ViewFieldsVisibilityDropdownSection = ({ )} <DropdownMenuItemsContainer> {nonDraggableItems.map((field, fieldIndex) => ( - <MenuItem + <MenuItemDraggable key={field.fieldMetadataId} LeftIcon={getIcon(field.iconName)} iconButtons={getIconButtons(fieldIndex, field)} isTooltipOpen={openToolTipIndex === fieldIndex} text={field.label} className={`${title}-fixed-item-tooltip-anchor-${fieldIndex}`} + accent={'placeholder'} + isHoverDisabled={field.isVisible} + showGrip + isDragDisabled /> ))} {!!draggableItems.length && ( @@ -131,6 +134,7 @@ export const ViewFieldsVisibilityDropdownSection = ({ isTooltipOpen={openToolTipIndex === fieldIndex} text={field.label} className={`${title}-draggable-item-tooltip-anchor-${fieldIndex}`} + showGrip /> } /> diff --git a/packages/twenty-front/src/modules/views/hooks/useCombinedViewFilters.ts b/packages/twenty-front/src/modules/views/hooks/useCombinedViewFilters.ts index e3eceeed3ebd..042ef8f33ab2 100644 --- a/packages/twenty-front/src/modules/views/hooks/useCombinedViewFilters.ts +++ b/packages/twenty-front/src/modules/views/hooks/useCombinedViewFilters.ts @@ -1,5 +1,4 @@ import { useRecoilCallback } from 'recoil'; -import { v4 } from 'uuid'; import { Filter } from '@/object-record/object-filter-dropdown/types/Filter'; import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue'; @@ -43,13 +42,11 @@ export const useCombinedViewFilters = (viewBarComponentId?: string) => { } const matchingFilterInCurrentView = currentView.viewFilters.find( - (viewFilter) => - viewFilter.fieldMetadataId === upsertedFilter.fieldMetadataId, + (viewFilter) => viewFilter.id === upsertedFilter.id, ); const matchingFilterInUnsavedFilters = unsavedToUpsertViewFilters.find( - (viewFilter) => - viewFilter.fieldMetadataId === upsertedFilter.fieldMetadataId, + (viewFilter) => viewFilter.id === upsertedFilter.id, ); if (isDefined(matchingFilterInUnsavedFilters)) { @@ -81,7 +78,6 @@ export const useCombinedViewFilters = (viewBarComponentId?: string) => { ...unsavedToUpsertViewFilters, { ...upsertedFilter, - id: v4(), __typename: 'ViewFilter', } satisfies ViewFilter, ]); @@ -95,7 +91,7 @@ export const useCombinedViewFilters = (viewBarComponentId?: string) => { ); const removeCombinedViewFilter = useRecoilCallback( ({ snapshot, set }) => - async (fieldMetadataId: string) => { + async (fieldId: string) => { const unsavedToUpsertViewFilters = getSnapshotValue( snapshot, unsavedToUpsertViewFiltersState, @@ -119,18 +115,18 @@ export const useCombinedViewFilters = (viewBarComponentId?: string) => { } const matchingFilterInCurrentView = currentView.viewFilters.find( - (viewFilter) => viewFilter.fieldMetadataId === fieldMetadataId, + (viewFilter) => viewFilter.id === fieldId, ); const matchingFilterInUnsavedFilters = unsavedToUpsertViewFilters.find( - (viewFilter) => viewFilter.fieldMetadataId === fieldMetadataId, + (viewFilter) => viewFilter.id === fieldId, ); if (isDefined(matchingFilterInUnsavedFilters)) { set( unsavedToUpsertViewFiltersState, unsavedToUpsertViewFilters.filter( - (viewFilter) => viewFilter.fieldMetadataId !== fieldMetadataId, + (viewFilter) => viewFilter.id !== fieldId, ), ); } diff --git a/packages/twenty-front/src/modules/views/types/ViewFilterOperand.ts b/packages/twenty-front/src/modules/views/types/ViewFilterOperand.ts index fa1a27d68179..025d0085d49d 100644 --- a/packages/twenty-front/src/modules/views/types/ViewFilterOperand.ts +++ b/packages/twenty-front/src/modules/views/types/ViewFilterOperand.ts @@ -6,4 +6,6 @@ export enum ViewFilterOperand { GreaterThan = 'greaterThan', Contains = 'contains', DoesNotContain = 'doesNotContain', + IsEmpty = 'isEmpty', + IsNotEmpty = 'isNotEmpty', } diff --git a/packages/twenty-front/src/modules/views/utils/__tests__/viewMapFunctions.test.ts b/packages/twenty-front/src/modules/views/utils/__tests__/viewMapFunctions.test.ts index 8175b44d3cf3..68acdb054655 100644 --- a/packages/twenty-front/src/modules/views/utils/__tests__/viewMapFunctions.test.ts +++ b/packages/twenty-front/src/modules/views/utils/__tests__/viewMapFunctions.test.ts @@ -55,6 +55,7 @@ describe('mapViewFiltersToFilters', () => { ]; const expectedFilters: Filter[] = [ { + id: 'id', fieldMetadataId: '05731f68-6e7a-4903-8374-c0b6a9063482', value: 'testValue', displayValue: 'Test Display Value', diff --git a/packages/twenty-front/src/modules/views/utils/combinedViewFilters.ts b/packages/twenty-front/src/modules/views/utils/combinedViewFilters.ts index 84eefa8f5bc8..09dda1fd232d 100644 --- a/packages/twenty-front/src/modules/views/utils/combinedViewFilters.ts +++ b/packages/twenty-front/src/modules/views/utils/combinedViewFilters.ts @@ -28,9 +28,6 @@ export const combinedViewFilters = ( .concat(toCreateViewFilters); return Object.values( - combinedViewFilters.reduce( - (acc, obj) => ({ ...acc, [obj.fieldMetadataId]: obj }), - {}, - ), + combinedViewFilters.reduce((acc, obj) => ({ ...acc, [obj.id]: obj }), {}), ); }; diff --git a/packages/twenty-front/src/modules/views/utils/mapViewFiltersToFilters.ts b/packages/twenty-front/src/modules/views/utils/mapViewFiltersToFilters.ts index 4df8f1e993fb..104ba6afdaae 100644 --- a/packages/twenty-front/src/modules/views/utils/mapViewFiltersToFilters.ts +++ b/packages/twenty-front/src/modules/views/utils/mapViewFiltersToFilters.ts @@ -18,6 +18,7 @@ export const mapViewFiltersToFilters = ( if (!availableFilterDefinition) return null; return { + id: viewFilter.id, fieldMetadataId: viewFilter.fieldMetadataId, value: viewFilter.value, displayValue: viewFilter.displayValue, diff --git a/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerCreateOrEditContentEffect.tsx b/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerCreateOrEditContentEffect.tsx index 6124063e002c..45ba1209c18d 100644 --- a/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerCreateOrEditContentEffect.tsx +++ b/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerCreateOrEditContentEffect.tsx @@ -1,5 +1,5 @@ import { useEffect } from 'react'; -import { useRecoilValue, useSetRecoilState } from 'recoil'; +import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil'; import { useGetCurrentView } from '@/views/hooks/useGetCurrentView'; import { useGetAvailableFieldsForKanban } from '@/views/view-picker/hooks/useGetAvailableFieldsForKanban'; @@ -22,9 +22,8 @@ export const ViewPickerCreateOrEditContentEffect = () => { ); const setViewPickerInputName = useSetRecoilState(viewPickerInputNameState); - const setViewPickerKanbanFieldMetadataId = useSetRecoilState( - viewPickerKanbanFieldMetadataIdState, - ); + const [viewPickerKanbanFieldMetadataId, setViewPickerKanbanFieldMetadataId] = + useRecoilState(viewPickerKanbanFieldMetadataIdState); const setViewPickerType = useSetRecoilState(viewPickerTypeState); const viewPickerReferenceViewId = useRecoilValue( @@ -50,13 +49,11 @@ export const ViewPickerCreateOrEditContentEffect = () => { ) { setViewPickerSelectedIcon(referenceView.icon); setViewPickerInputName(referenceView.name); - setViewPickerKanbanFieldMetadataId(referenceView.kanbanFieldMetadataId); setViewPickerType(referenceView.type); } }, [ referenceView, setViewPickerInputName, - setViewPickerKanbanFieldMetadataId, setViewPickerSelectedIcon, setViewPickerType, viewPickerIsPersisting, @@ -64,13 +61,22 @@ export const ViewPickerCreateOrEditContentEffect = () => { ]); useEffect(() => { - if (availableFieldsForKanban.length > 0 && !viewPickerIsDirty) { - setViewPickerKanbanFieldMetadataId(availableFieldsForKanban[0].id); + if ( + isDefined(referenceView) && + availableFieldsForKanban.length > 0 && + viewPickerKanbanFieldMetadataId === '' + ) { + setViewPickerKanbanFieldMetadataId( + referenceView.kanbanFieldMetadataId !== '' + ? referenceView.kanbanFieldMetadataId + : availableFieldsForKanban[0].id, + ); } }, [ + referenceView, availableFieldsForKanban, + viewPickerKanbanFieldMetadataId, setViewPickerKanbanFieldMetadataId, - viewPickerIsDirty, ]); return <></>; diff --git a/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerListContent.tsx b/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerListContent.tsx index ef0a258b0dfd..91b18694dd2c 100644 --- a/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerListContent.tsx +++ b/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerListContent.tsx @@ -117,7 +117,7 @@ export const ViewPickerListContent = () => { )} /> {indexView && ( - <MenuItem + <MenuItemDraggable key={indexView.id} iconButtons={[ { @@ -128,6 +128,8 @@ export const ViewPickerListContent = () => { onClick={() => handleViewSelect(indexView.id)} LeftIcon={getIcon(indexView.icon)} text={indexView.name} + accent="placeholder" + isDragDisabled /> )} </DropdownMenuItemsContainer> diff --git a/packages/twenty-front/src/modules/views/view-picker/hooks/useGetAvailableFieldsForKanban.ts b/packages/twenty-front/src/modules/views/view-picker/hooks/useGetAvailableFieldsForKanban.ts index 21df6d23c257..0f47fcc78f15 100644 --- a/packages/twenty-front/src/modules/views/view-picker/hooks/useGetAvailableFieldsForKanban.ts +++ b/packages/twenty-front/src/modules/views/view-picker/hooks/useGetAvailableFieldsForKanban.ts @@ -1,16 +1,23 @@ import { useCallback } from 'react'; -import { useNavigate } from 'react-router-dom'; -import { useRecoilValue } from 'recoil'; +import { useLocation, useNavigate } from 'react-router-dom'; +import { useRecoilValue, useSetRecoilState } from 'recoil'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; +import { getObjectSlug } from '@/object-metadata/utils/getObjectSlug'; +import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMemorizedUrlState'; import { useViewStates } from '@/views/hooks/internal/useViewStates'; import { FieldMetadataType } from '~/generated-metadata/graphql'; +import { isDefined } from '~/utils/isDefined'; export const useGetAvailableFieldsForKanban = () => { const { viewObjectMetadataIdState } = useViewStates(); const viewObjectMetadataId = useRecoilValue(viewObjectMetadataIdState); const objectMetadataItems = useRecoilValue(objectMetadataItemsState); + const setNavigationMemorizedUrl = useSetRecoilState( + navigationMemorizedUrlState, + ); + const location = useLocation(); const objectMetadataItem = objectMetadataItems.find( (objectMetadata) => objectMetadata.id === viewObjectMetadataId, @@ -24,8 +31,24 @@ export const useGetAvailableFieldsForKanban = () => { const navigate = useNavigate(); const navigateToSelectSettings = useCallback(() => { - navigate(`/settings/objects/${objectMetadataItem?.namePlural}`); - }, [navigate, objectMetadataItem?.namePlural]); + setNavigationMemorizedUrl(location.pathname + location.search); + + if (isDefined(objectMetadataItem?.namePlural)) { + navigate( + `/settings/objects/${getObjectSlug( + objectMetadataItem, + )}/new-field/step-2`, + ); + } else { + navigate(`/settings/objects`); + } + }, [ + setNavigationMemorizedUrl, + location.pathname, + location.search, + objectMetadataItem, + navigate, + ]); return { availableFieldsForKanban, diff --git a/packages/twenty-front/src/modules/workspace/components/WorkspaceMemberCard.tsx b/packages/twenty-front/src/modules/workspace/components/WorkspaceMemberCard.tsx index cae6dff291c6..2fc774905ae0 100644 --- a/packages/twenty-front/src/modules/workspace/components/WorkspaceMemberCard.tsx +++ b/packages/twenty-front/src/modules/workspace/components/WorkspaceMemberCard.tsx @@ -40,7 +40,7 @@ export const WorkspaceMemberCard = ({ <StyledContainer> <Avatar avatarUrl={getImageAbsoluteURIOrBase64(workspaceMember.avatarUrl)} - entityId={workspaceMember.id} + placeholderColorSeed={workspaceMember.id} placeholder={workspaceMember.name.firstName || ''} type="squared" size="xl" @@ -53,7 +53,6 @@ export const WorkspaceMemberCard = ({ /> <StyledEmailText>{workspaceMember.userEmail}</StyledEmailText> </StyledContent> - {accessory} </StyledContainer> ); diff --git a/packages/twenty-front/src/modules/workspace/graphql/mutations/updateWorkspace.ts b/packages/twenty-front/src/modules/workspace/graphql/mutations/updateWorkspace.ts index c244ce041097..1d9a9b9fbed2 100644 --- a/packages/twenty-front/src/modules/workspace/graphql/mutations/updateWorkspace.ts +++ b/packages/twenty-front/src/modules/workspace/graphql/mutations/updateWorkspace.ts @@ -8,7 +8,6 @@ export const UPDATE_WORKSPACE = gql` displayName logo allowImpersonation - subscriptionStatus } } `; diff --git a/packages/twenty-front/src/modules/workspace/hooks/__tests__/useSubscriptionStatus.test.ts b/packages/twenty-front/src/modules/workspace/hooks/__tests__/useSubscriptionStatus.test.ts new file mode 100644 index 000000000000..3ba84ddb77dc --- /dev/null +++ b/packages/twenty-front/src/modules/workspace/hooks/__tests__/useSubscriptionStatus.test.ts @@ -0,0 +1,57 @@ +import { act } from 'react-dom/test-utils'; +import { renderHook } from '@testing-library/react'; +import { RecoilRoot, useSetRecoilState } from 'recoil'; +import { v4 } from 'uuid'; + +import { + CurrentWorkspace, + currentWorkspaceState, +} from '@/auth/states/currentWorkspaceState'; +import { useSubscriptionStatus } from '@/workspace/hooks/useSubscriptionStatus'; +import { SubscriptionStatus } from '~/generated/graphql'; + +const currentWorkspace = { + id: '1', + currentBillingSubscription: { status: SubscriptionStatus.Incomplete }, + activationStatus: 'active', + allowImpersonation: true, +} as CurrentWorkspace; + +const renderHooks = () => { + const { result } = renderHook( + () => { + const subscriptionStatus = useSubscriptionStatus(); + const setCurrentWorkspace = useSetRecoilState(currentWorkspaceState); + + return { + subscriptionStatus, + setCurrentWorkspace, + }; + }, + { + wrapper: RecoilRoot, + }, + ); + return { result }; +}; + +describe('useSubscriptionStatus', () => { + Object.values(SubscriptionStatus).forEach((subscriptionStatus) => { + it(`should return "${subscriptionStatus}"`, async () => { + const { result } = renderHooks(); + const { setCurrentWorkspace } = result.current; + + act(() => { + setCurrentWorkspace({ + ...currentWorkspace, + currentBillingSubscription: { + id: v4(), + status: subscriptionStatus, + }, + }); + }); + + expect(result.current.subscriptionStatus).toBe(subscriptionStatus); + }); + }); +}); diff --git a/packages/twenty-front/src/modules/workspace/hooks/useSubscriptionStatus.ts b/packages/twenty-front/src/modules/workspace/hooks/useSubscriptionStatus.ts new file mode 100644 index 000000000000..332675639a07 --- /dev/null +++ b/packages/twenty-front/src/modules/workspace/hooks/useSubscriptionStatus.ts @@ -0,0 +1,9 @@ +import { useRecoilValue } from 'recoil'; + +import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState'; +import { SubscriptionStatus } from '~/generated/graphql'; + +export const useSubscriptionStatus = (): SubscriptionStatus | undefined => { + const currentWorkspace = useRecoilValue(currentWorkspaceState); + return currentWorkspace?.currentBillingSubscription?.status; +}; diff --git a/packages/twenty-front/src/modules/workspace/types/FeatureFlagKey.ts b/packages/twenty-front/src/modules/workspace/types/FeatureFlagKey.ts index cb6262c2d008..d9b76577cbce 100644 --- a/packages/twenty-front/src/modules/workspace/types/FeatureFlagKey.ts +++ b/packages/twenty-front/src/modules/workspace/types/FeatureFlagKey.ts @@ -4,4 +4,5 @@ export type FeatureFlagKey = | 'IS_EVENT_OBJECT_ENABLED' | 'IS_AIRTABLE_INTEGRATION_ENABLED' | 'IS_POSTGRESQL_INTEGRATION_ENABLED' - | 'IS_STRIPE_INTEGRATION_ENABLED'; + | 'IS_STRIPE_INTEGRATION_ENABLED' + | 'IS_COPILOT_ENABLED'; diff --git a/packages/twenty-front/src/pages/auth/Authorize.tsx b/packages/twenty-front/src/pages/auth/Authorize.tsx index 8fa99481f4fa..8a247aad2235 100644 --- a/packages/twenty-front/src/pages/auth/Authorize.tsx +++ b/packages/twenty-front/src/pages/auth/Authorize.tsx @@ -1,6 +1,6 @@ +import styled from '@emotion/styled'; import { useEffect, useState } from 'react'; import { useNavigate, useSearchParams } from 'react-router-dom'; -import styled from '@emotion/styled'; import { AppPath } from '@/types/AppPath'; import { MainButton } from '@/ui/input/button/components/MainButton'; @@ -14,7 +14,7 @@ const StyledContainer = styled.div` display: flex; align-items: center; flex-direction: column; - height: 100vh; + height: 100dvh; justify-content: center; width: 100%; `; diff --git a/packages/twenty-front/src/pages/auth/Invite.tsx b/packages/twenty-front/src/pages/auth/Invite.tsx index 5c62531ef6f8..e643654519ae 100644 --- a/packages/twenty-front/src/pages/auth/Invite.tsx +++ b/packages/twenty-front/src/pages/auth/Invite.tsx @@ -1,5 +1,5 @@ -import { useMemo } from 'react'; import styled from '@emotion/styled'; +import { useMemo } from 'react'; import { useRecoilValue } from 'recoil'; import { Logo } from '@/auth/components/Logo'; @@ -17,8 +17,8 @@ import { useAddUserToWorkspaceMutation } from '~/generated/graphql'; import { isDefined } from '~/utils/isDefined'; const StyledContentContainer = styled.div` - margin-bottom: ${({ theme }) => theme.spacing(8)}; - margin-top: ${({ theme }) => theme.spacing(4)}; + margin-bottom: ${({ theme }) => theme.spacing(8)}; + margin-top: ${({ theme }) => theme.spacing(4)}; `; export const Invite = () => { @@ -74,8 +74,23 @@ export const Invite = () => { /> </StyledContentContainer> <FooterNote> - By using Funnelmink, you agree to the Terms of Service and Privacy - Policy. + By using Funnelmink, you agree to the{' '} + <a + href="https://funnelmink.com/legal/terms" + target="_blank" + rel="noopener noreferrer" + > + Terms of Service + </a>{' '} + and{' '} + <a + href="https://funnelmink.com/legal/privacy" + target="_blank" + rel="noopener noreferrer" + > + Privacy Policy + </a> + . </FooterNote> </> ) : ( diff --git a/packages/twenty-front/src/pages/auth/__stories__/Invite.stories.tsx b/packages/twenty-front/src/pages/auth/__stories__/Invite.stories.tsx new file mode 100644 index 000000000000..08369b84fb52 --- /dev/null +++ b/packages/twenty-front/src/pages/auth/__stories__/Invite.stories.tsx @@ -0,0 +1,84 @@ +import { getOperationName } from '@apollo/client/utilities'; +import { Meta, StoryObj } from '@storybook/react'; +import { fireEvent, within } from '@storybook/test'; +import { HttpResponse, graphql } from 'msw'; + +import { AppPath } from '@/types/AppPath'; +import { GET_CURRENT_USER } from '@/users/graphql/queries/getCurrentUser'; +import { GET_WORKSPACE_FROM_INVITE_HASH } from '@/workspace/graphql/queries/getWorkspaceFromInviteHash'; +import { + PageDecorator, + PageDecoratorArgs, +} from '~/testing/decorators/PageDecorator'; +import { graphqlMocks } from '~/testing/graphqlMocks'; + +import { Invite } from '../Invite'; + +const meta: Meta<PageDecoratorArgs> = { + title: 'Pages/Auth/Invite', + component: Invite, + decorators: [PageDecorator], + args: { + routePath: AppPath.Invite, + routeParams: { ':workspaceInviteHash': 'my-hash' }, + }, + parameters: { + msw: { + handlers: [ + graphql.query( + getOperationName(GET_WORKSPACE_FROM_INVITE_HASH) ?? '', + () => { + return HttpResponse.json({ + data: { + findWorkspaceFromInviteHash: { + __typename: 'Workspace', + id: '20202020-91f0-46d0-acab-cb5afef3cc3b', + displayName: 'Twenty dev', + logo: null, + allowImpersonation: false, + }, + }, + }); + }, + ), + graphql.query(getOperationName(GET_CURRENT_USER) ?? '', () => { + return HttpResponse.json({ + data: null, + errors: [ + { + message: 'Unauthorized', + extensions: { + code: 'UNAUTHENTICATED', + response: { + statusCode: 401, + message: 'Unauthorized', + }, + }, + }, + ], + }); + }), + graphqlMocks.handlers, + ], + }, + cookie: '', + }, +}; + +export default meta; + +export type Story = StoryObj<typeof Invite>; + +export const Default: Story = { + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + + await canvas.findByText('Join Twenty dev team'); + + const continueWithEmailButton = await canvas.findByText( + 'Continue With Email', + ); + + await fireEvent.click(continueWithEmailButton); + }, +}; diff --git a/packages/twenty-front/src/pages/auth/__stories__/PasswordReset.stories.tsx b/packages/twenty-front/src/pages/auth/__stories__/PasswordReset.stories.tsx index 234b06e795df..ea98157a1e4a 100644 --- a/packages/twenty-front/src/pages/auth/__stories__/PasswordReset.stories.tsx +++ b/packages/twenty-front/src/pages/auth/__stories__/PasswordReset.stories.tsx @@ -4,14 +4,21 @@ import { within } from '@storybook/test'; import { graphql, HttpResponse } from 'msw'; import { GET_CURRENT_USER } from '@/users/graphql/queries/getCurrentUser'; -import { ValidatePasswordResetTokenDocument } from '~/generated/graphql'; +import { + OnboardingStatus, + ValidatePasswordResetTokenDocument, +} from '~/generated/graphql'; import { PasswordReset } from '~/pages/auth/PasswordReset'; import { PageDecorator, PageDecoratorArgs, } from '~/testing/decorators/PageDecorator'; import { graphqlMocks } from '~/testing/graphqlMocks'; -import { mockedOnboardingUsersData } from '~/testing/mock-data/users'; +import { mockedOnboardingUserData } from '~/testing/mock-data/users'; + +const mockedOnboardingUsersData = mockedOnboardingUserData( + OnboardingStatus.Completed, +); const meta: Meta<PageDecoratorArgs> = { title: 'Pages/Auth/PasswordReset', @@ -30,8 +37,8 @@ const meta: Meta<PageDecoratorArgs> = { return HttpResponse.json({ data: { validatePasswordResetToken: { - id: mockedOnboardingUsersData[0].id, - email: mockedOnboardingUsersData[0].email, + id: mockedOnboardingUsersData.id, + email: mockedOnboardingUsersData.email, }, }, }); @@ -40,7 +47,7 @@ const meta: Meta<PageDecoratorArgs> = { graphql.query(getOperationName(GET_CURRENT_USER) ?? '', () => { return HttpResponse.json({ data: { - currentUser: mockedOnboardingUsersData[0], + currentUser: mockedOnboardingUsersData, }, }); }), diff --git a/packages/twenty-front/src/pages/object-record/RecordIndexPage.tsx b/packages/twenty-front/src/pages/object-record/RecordIndexPage.tsx index bcb3508dc359..2e4a0268ddac 100644 --- a/packages/twenty-front/src/pages/object-record/RecordIndexPage.tsx +++ b/packages/twenty-front/src/pages/object-record/RecordIndexPage.tsx @@ -1,5 +1,5 @@ -import { useParams } from 'react-router-dom'; import styled from '@emotion/styled'; +import { useParams } from 'react-router-dom'; import { v4 } from 'uuid'; import { RecordIndexContainer } from '@/object-record/record-index/components/RecordIndexContainer'; diff --git a/packages/twenty-front/src/pages/object-record/RecordShowPage.tsx b/packages/twenty-front/src/pages/object-record/RecordShowPage.tsx index e8d5bd90247c..1037467db9ff 100644 --- a/packages/twenty-front/src/pages/object-record/RecordShowPage.tsx +++ b/packages/twenty-front/src/pages/object-record/RecordShowPage.tsx @@ -3,6 +3,7 @@ import { useParams } from 'react-router-dom'; import { TimelineActivityContext } from '@/activities/timelineActivities/contexts/TimelineActivityContext'; import { RecordShowContainer } from '@/object-record/record-show/components/RecordShowContainer'; import { useRecordShowPage } from '@/object-record/record-show/hooks/useRecordShowPage'; +import { useRecordShowPagePagination } from '@/object-record/record-show/hooks/useRecordShowPagePagination'; import { RecordValueSetterEffect } from '@/object-record/record-store/components/RecordValueSetterEffect'; import { RecordFieldValueSelectorContextProvider } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext'; import { PageBody } from '@/ui/layout/page/PageBody'; @@ -35,16 +36,35 @@ export const RecordShowPage = () => { parameters.objectRecordId ?? '', ); + const { + viewName, + hasPreviousRecord, + hasNextRecord, + navigateToPreviousRecord, + navigateToNextRecord, + navigateToIndexView, + isLoadingPagination, + } = useRecordShowPagePagination( + parameters.objectNameSingular ?? '', + parameters.objectRecordId ?? '', + ); + return ( <RecordFieldValueSelectorContextProvider> <RecordValueSetterEffect recordId={objectRecordId} /> <PageContainer> <PageTitle title={pageTitle} /> <PageHeader - title={pageName ?? ''} - hasBackButton + title={viewName} + hasPaginationButtons + hasClosePageButton + onClosePage={navigateToIndexView} + hasPreviousRecord={hasPreviousRecord} + navigateToPreviousRecord={navigateToPreviousRecord} + hasNextRecord={hasNextRecord} + navigateToNextRecord={navigateToNextRecord} Icon={headerIcon} - loading={loading} + loading={loading || isLoadingPagination} > <> <PageFavoriteButton diff --git a/packages/twenty-front/src/pages/object-record/__stories__/RecordShowPage.stories.tsx b/packages/twenty-front/src/pages/object-record/__stories__/RecordShowPage.stories.tsx index efec731eefbd..2674fd4bdef7 100644 --- a/packages/twenty-front/src/pages/object-record/__stories__/RecordShowPage.stories.tsx +++ b/packages/twenty-front/src/pages/object-record/__stories__/RecordShowPage.stories.tsx @@ -8,7 +8,7 @@ import { PageDecoratorArgs, } from '~/testing/decorators/PageDecorator'; import { graphqlMocks } from '~/testing/graphqlMocks'; -import { getPeopleMock } from '~/testing/mock-data/people'; +import { getPeopleMock, peopleQueryResult } from '~/testing/mock-data/people'; import { mockedWorkspaceMemberData } from '~/testing/mock-data/users'; import { RecordShowPage } from '../RecordShowPage'; @@ -22,12 +22,17 @@ const meta: Meta<PageDecoratorArgs> = { routePath: '/object/:objectNameSingular/:objectRecordId', routeParams: { ':objectNameSingular': 'person', - ':objectRecordId': '1234', + ':objectRecordId': peopleMock[0].id, }, }, parameters: { msw: { handlers: [ + graphql.query('FindManyPeople', () => { + return HttpResponse.json({ + data: peopleQueryResult, + }); + }), graphql.query('FindOnePerson', () => { return HttpResponse.json({ data: { @@ -64,8 +69,8 @@ const meta: Meta<PageDecoratorArgs> = { edges: [], pageInfo: { hasNextPage: false, - startCursor: '1234', - endCursor: '1234', + startCursor: peopleMock[0].id, + endCursor: peopleMock[0].id, }, totalCount: 0, }, diff --git a/packages/twenty-front/src/pages/onboarding/ChooseYourPlan.tsx b/packages/twenty-front/src/pages/onboarding/ChooseYourPlan.tsx index 1c24f58aaeb6..1a85d31434c7 100644 --- a/packages/twenty-front/src/pages/onboarding/ChooseYourPlan.tsx +++ b/packages/twenty-front/src/pages/onboarding/ChooseYourPlan.tsx @@ -19,6 +19,7 @@ import { ActionLink } from '@/ui/navigation/link/components/ActionLink'; import { CAL_LINK } from '@/ui/navigation/link/constants/Cal'; import { ProductPriceEntity, + SubscriptionInterval, useCheckoutSessionMutation, useGetProductPricesQuery, } from '~/generated/graphql'; @@ -75,7 +76,7 @@ const benefits = [ export const ChooseYourPlan = () => { const billing = useRecoilValue(billingState); - const [planSelected, setPlanSelected] = useState('month'); + const [planSelected, setPlanSelected] = useState(SubscriptionInterval.Month); const [isSubmitting, setIsSubmitting] = useState(false); @@ -87,7 +88,7 @@ export const ChooseYourPlan = () => { const [checkoutSession] = useCheckoutSessionMutation(); - const handlePlanChange = (type?: string) => { + const handlePlanChange = (type?: SubscriptionInterval) => { return () => { if (isNonEmptyString(type) && planSelected !== type) { setPlanSelected(type); @@ -101,11 +102,11 @@ export const ChooseYourPlan = () => { price: ProductPriceEntity, prices: ProductPriceEntity[], ): string => { - if (price.recurringInterval !== 'year') { + if (price.recurringInterval !== SubscriptionInterval.Year) { return 'Cancel anytime'; } const monthPrice = prices.filter( - (price) => price.recurringInterval === 'month', + (price) => price.recurringInterval === SubscriptionInterval.Month, )?.[0]; if ( isDefined(monthPrice) && diff --git a/packages/twenty-front/src/pages/onboarding/CreateProfile.tsx b/packages/twenty-front/src/pages/onboarding/CreateProfile.tsx index fa588b34ee97..f5faa4ff4b19 100644 --- a/packages/twenty-front/src/pages/onboarding/CreateProfile.tsx +++ b/packages/twenty-front/src/pages/onboarding/CreateProfile.tsx @@ -9,11 +9,11 @@ import { z } from 'zod'; import { SubTitle } from '@/auth/components/SubTitle'; import { Title } from '@/auth/components/Title'; -import { useOnboardingStatus } from '@/auth/hooks/useOnboardingStatus'; import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; -import { OnboardingStatus } from '@/auth/utils/getOnboardingStatus'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord'; +import { useOnboardingStatus } from '@/onboarding/hooks/useOnboardingStatus'; +import { useSetNextOnboardingStatus } from '@/onboarding/hooks/useSetNextOnboardingStatus'; import { ProfilePictureUploader } from '@/settings/profile/components/ProfilePictureUploader'; import { PageHotkeyScope } from '@/types/PageHotkeyScope'; import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar'; @@ -22,6 +22,8 @@ import { MainButton } from '@/ui/input/button/components/MainButton'; import { TextInputV2 } from '@/ui/input/components/TextInputV2'; import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys'; import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember'; +import { OnboardingStatus } from '~/generated/graphql'; +import { isDefined } from '~/utils/isDefined'; const StyledContentContainer = styled.div` width: 100%; @@ -55,11 +57,11 @@ type Form = z.infer<typeof validationSchema>; export const CreateProfile = () => { const onboardingStatus = useOnboardingStatus(); + const setNextOnboardingStatus = useSetNextOnboardingStatus(); const { enqueueSnackBar } = useSnackBar(); const [currentWorkspaceMember, setCurrentWorkspaceMember] = useRecoilState( currentWorkspaceMemberState, ); - const { updateOneRecord } = useUpdateOneRecord<WorkspaceMember>({ objectNameSingular: CoreObjectNameSingular.WorkspaceMember, }); @@ -100,17 +102,20 @@ export const CreateProfile = () => { }, }); - setCurrentWorkspaceMember( - (current) => - ({ + setCurrentWorkspaceMember((current) => { + if (isDefined(current)) { + return { ...current, name: { firstName: data.firstName, lastName: data.lastName, }, colorScheme: 'System', - }) as any, - ); + }; + } + return current; + }); + setNextOnboardingStatus(); } catch (error: any) { enqueueSnackBar(error?.message, { variant: SnackBarVariant.Error, @@ -119,6 +124,7 @@ export const CreateProfile = () => { }, [ currentWorkspaceMember?.id, + setNextOnboardingStatus, enqueueSnackBar, setCurrentWorkspaceMember, updateOneRecord, @@ -137,7 +143,7 @@ export const CreateProfile = () => { PageHotkeyScope.CreateProfile, ); - if (onboardingStatus !== OnboardingStatus.OngoingProfileCreation) { + if (onboardingStatus !== OnboardingStatus.ProfileCreation) { return null; } diff --git a/packages/twenty-front/src/pages/onboarding/CreateWorkspace.tsx b/packages/twenty-front/src/pages/onboarding/CreateWorkspace.tsx index 5d37f13d27cb..b703ef13b0fd 100644 --- a/packages/twenty-front/src/pages/onboarding/CreateWorkspace.tsx +++ b/packages/twenty-front/src/pages/onboarding/CreateWorkspace.tsx @@ -9,18 +9,20 @@ import { z } from 'zod'; import { SubTitle } from '@/auth/components/SubTitle'; import { Title } from '@/auth/components/Title'; -import { useOnboardingStatus } from '@/auth/hooks/useOnboardingStatus'; import { isCurrentUserLoadedState } from '@/auth/states/isCurrentUserLoadingState'; -import { OnboardingStatus } from '@/auth/utils/getOnboardingStatus'; import { FIND_MANY_OBJECT_METADATA_ITEMS } from '@/object-metadata/graphql/queries'; import { useApolloMetadataClient } from '@/object-metadata/hooks/useApolloMetadataClient'; +import { useOnboardingStatus } from '@/onboarding/hooks/useOnboardingStatus'; import { WorkspaceLogoUploader } from '@/settings/workspace/components/WorkspaceLogoUploader'; import { Loader } from '@/ui/feedback/loader/components/Loader'; import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar'; import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; import { MainButton } from '@/ui/input/button/components/MainButton'; import { TextInputV2 } from '@/ui/input/components/TextInputV2'; -import { useActivateWorkspaceMutation } from '~/generated/graphql'; +import { + OnboardingStatus, + useActivateWorkspaceMutation, +} from '~/generated/graphql'; import { isDefined } from '~/utils/isDefined'; const StyledContentContainer = styled.div` @@ -105,7 +107,7 @@ export const CreateWorkspace = () => { } }; - if (onboardingStatus !== OnboardingStatus.OngoingWorkspaceActivation) { + if (onboardingStatus !== OnboardingStatus.WorkspaceActivation) { return null; } diff --git a/packages/twenty-front/src/pages/onboarding/InviteTeam.tsx b/packages/twenty-front/src/pages/onboarding/InviteTeam.tsx index 2395c4bb27d3..53a7b212494c 100644 --- a/packages/twenty-front/src/pages/onboarding/InviteTeam.tsx +++ b/packages/twenty-front/src/pages/onboarding/InviteTeam.tsx @@ -17,7 +17,7 @@ import { SubTitle } from '@/auth/components/SubTitle'; import { Title } from '@/auth/components/Title'; import { currentUserState } from '@/auth/states/currentUserState'; import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState'; -import { useSetNextOnboardingStep } from '@/onboarding/hooks/useSetNextOnboardingStep'; +import { useSetNextOnboardingStatus } from '@/onboarding/hooks/useSetNextOnboardingStatus'; import { PageHotkeyScope } from '@/types/PageHotkeyScope'; import { SeparatorLineText } from '@/ui/display/text/components/SeparatorLineText'; import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar'; @@ -27,7 +27,10 @@ import { MainButton } from '@/ui/input/button/components/MainButton'; import { TextInputV2 } from '@/ui/input/components/TextInputV2'; import { AnimatedTranslation } from '@/ui/utilities/animation/components/AnimatedTranslation'; import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys'; -import { OnboardingStep, useSendInviteLinkMutation } from '~/generated/graphql'; +import { + OnboardingStatus, + useSendInviteLinkMutation, +} from '~/generated/graphql'; import { isDefined } from '~/utils/isDefined'; const StyledAnimatedContainer = styled.div` @@ -63,7 +66,7 @@ export const InviteTeam = () => { const theme = useTheme(); const { enqueueSnackBar } = useSnackBar(); const [sendInviteLink] = useSendInviteLinkMutation(); - const setNextOnboardingStep = useSetNextOnboardingStep(); + const setNextOnboardingStatus = useSetNextOnboardingStatus(); const currentUser = useRecoilValue(currentUserState); const currentWorkspace = useRecoilValue(currentWorkspaceState); const { @@ -133,7 +136,7 @@ export const InviteTeam = () => { ); const result = await sendInviteLink({ variables: { emails } }); - setNextOnboardingStep(OnboardingStep.InviteTeam); + setNextOnboardingStatus(); if (isDefined(result.errors)) { throw result.errors; @@ -145,7 +148,7 @@ export const InviteTeam = () => { }); } }, - [enqueueSnackBar, sendInviteLink, setNextOnboardingStep], + [enqueueSnackBar, sendInviteLink, setNextOnboardingStatus], ); useScopedHotkeys( @@ -157,7 +160,7 @@ export const InviteTeam = () => { [handleSubmit], ); - if (currentUser?.onboardingStep !== OnboardingStep.InviteTeam) { + if (currentUser?.onboardingStatus !== OnboardingStatus.InviteTeam) { return <></>; } diff --git a/packages/twenty-front/src/pages/onboarding/PaymentSuccess.tsx b/packages/twenty-front/src/pages/onboarding/PaymentSuccess.tsx index f77d7360e65b..ce57c50795ad 100644 --- a/packages/twenty-front/src/pages/onboarding/PaymentSuccess.tsx +++ b/packages/twenty-front/src/pages/onboarding/PaymentSuccess.tsx @@ -1,14 +1,17 @@ import React from 'react'; import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; +import { useRecoilValue } from 'recoil'; import { IconCheck, RGBA } from 'twenty-ui'; import { SubTitle } from '@/auth/components/SubTitle'; import { Title } from '@/auth/components/Title'; +import { currentUserState } from '@/auth/states/currentUserState'; import { AppPath } from '@/types/AppPath'; import { MainButton } from '@/ui/input/button/components/MainButton'; import { UndecoratedLink } from '@/ui/navigation/link/components/UndecoratedLink'; import { AnimatedEaseIn } from '@/ui/utilities/animation/components/AnimatedEaseIn'; +import { OnboardingStatus } from '~/generated/graphql'; const StyledCheckContainer = styled.div` align-items: center; @@ -29,8 +32,14 @@ const StyledButtonContainer = styled.div` export const PaymentSuccess = () => { const theme = useTheme(); + const currentUser = useRecoilValue(currentUserState); const color = theme.name === 'light' ? theme.grayScale.gray90 : theme.grayScale.gray10; + + if (currentUser?.onboardingStatus === OnboardingStatus.Completed) { + return <></>; + } + return ( <> <AnimatedEaseIn> diff --git a/packages/twenty-front/src/pages/onboarding/SyncEmails.tsx b/packages/twenty-front/src/pages/onboarding/SyncEmails.tsx index 44828c33a837..4fd138ec7541 100644 --- a/packages/twenty-front/src/pages/onboarding/SyncEmails.tsx +++ b/packages/twenty-front/src/pages/onboarding/SyncEmails.tsx @@ -9,7 +9,7 @@ import { SubTitle } from '@/auth/components/SubTitle'; import { Title } from '@/auth/components/Title'; import { currentUserState } from '@/auth/states/currentUserState'; import { OnboardingSyncEmailsSettingsCard } from '@/onboarding/components/OnboardingSyncEmailsSettingsCard'; -import { useSetNextOnboardingStep } from '@/onboarding/hooks/useSetNextOnboardingStep'; +import { useSetNextOnboardingStatus } from '@/onboarding/hooks/useSetNextOnboardingStatus'; import { useTriggerGoogleApisOAuth } from '@/settings/accounts/hooks/useTriggerGoogleApisOAuth'; import { AppPath } from '@/types/AppPath'; import { PageHotkeyScope } from '@/types/PageHotkeyScope'; @@ -19,7 +19,7 @@ import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys'; import { CalendarChannelVisibility, MessageChannelVisibility, - OnboardingStep, + OnboardingStatus, useSkipSyncEmailOnboardingStepMutation, } from '~/generated/graphql'; @@ -40,12 +40,12 @@ const StyledActionLinkContainer = styled.div` export const SyncEmails = () => { const theme = useTheme(); const { triggerGoogleApisOAuth } = useTriggerGoogleApisOAuth(); - const setNextOnboardingStep = useSetNextOnboardingStep(); + const setNextOnboardingStatus = useSetNextOnboardingStatus(); const currentUser = useRecoilValue(currentUserState); const [visibility, setVisibility] = useState<MessageChannelVisibility>( MessageChannelVisibility.ShareEverything, ); - const [skipSyncEmailOnboardingStepMutation] = + const [skipSyncEmailOnboardingStatusMutation] = useSkipSyncEmailOnboardingStepMutation(); const handleButtonClick = async () => { @@ -62,8 +62,8 @@ export const SyncEmails = () => { }; const continueWithoutSync = async () => { - await skipSyncEmailOnboardingStepMutation(); - setNextOnboardingStep(OnboardingStep.SyncEmail); + await skipSyncEmailOnboardingStatusMutation(); + setNextOnboardingStatus(); }; useScopedHotkeys( @@ -75,7 +75,7 @@ export const SyncEmails = () => { [continueWithoutSync], ); - if (currentUser?.onboardingStep !== OnboardingStep.SyncEmail) { + if (currentUser?.onboardingStatus !== OnboardingStatus.SyncEmail) { return <></>; } diff --git a/packages/twenty-front/src/pages/onboarding/__stories__/ChooseYourPlan.stories.tsx b/packages/twenty-front/src/pages/onboarding/__stories__/ChooseYourPlan.stories.tsx index 7325383bfd54..b42177fedd01 100644 --- a/packages/twenty-front/src/pages/onboarding/__stories__/ChooseYourPlan.stories.tsx +++ b/packages/twenty-front/src/pages/onboarding/__stories__/ChooseYourPlan.stories.tsx @@ -5,13 +5,14 @@ import { graphql, HttpResponse } from 'msw'; import { AppPath } from '@/types/AppPath'; import { GET_CURRENT_USER } from '@/users/graphql/queries/getCurrentUser'; +import { OnboardingStatus } from '~/generated/graphql'; import { ChooseYourPlan } from '~/pages/onboarding/ChooseYourPlan'; import { PageDecorator, PageDecoratorArgs, } from '~/testing/decorators/PageDecorator'; import { graphqlMocks } from '~/testing/graphqlMocks'; -import { mockedOnboardingUsersData } from '~/testing/mock-data/users'; +import { mockedOnboardingUserData } from '~/testing/mock-data/users'; import { sleep } from '~/utils/sleep'; const meta: Meta<PageDecoratorArgs> = { @@ -25,7 +26,9 @@ const meta: Meta<PageDecoratorArgs> = { graphql.query(getOperationName(GET_CURRENT_USER) ?? '', () => { return HttpResponse.json({ data: { - currentUser: mockedOnboardingUsersData[0], + currentUser: mockedOnboardingUserData( + OnboardingStatus.PlanRequired, + ), }, }); }), diff --git a/packages/twenty-front/src/pages/onboarding/__stories__/CreateProfile.stories.tsx b/packages/twenty-front/src/pages/onboarding/__stories__/CreateProfile.stories.tsx index 026ef4c60332..19512ebe183e 100644 --- a/packages/twenty-front/src/pages/onboarding/__stories__/CreateProfile.stories.tsx +++ b/packages/twenty-front/src/pages/onboarding/__stories__/CreateProfile.stories.tsx @@ -5,13 +5,14 @@ import { graphql, HttpResponse } from 'msw'; import { AppPath } from '@/types/AppPath'; import { GET_CURRENT_USER } from '@/users/graphql/queries/getCurrentUser'; +import { OnboardingStatus } from '~/generated/graphql'; import { CreateProfile } from '~/pages/onboarding/CreateProfile'; import { PageDecorator, PageDecoratorArgs, } from '~/testing/decorators/PageDecorator'; import { graphqlMocks } from '~/testing/graphqlMocks'; -import { mockedOnboardingUsersData } from '~/testing/mock-data/users'; +import { mockedOnboardingUserData } from '~/testing/mock-data/users'; const meta: Meta<PageDecoratorArgs> = { title: 'Pages/Onboarding/CreateProfile', @@ -24,7 +25,9 @@ const meta: Meta<PageDecoratorArgs> = { graphql.query(getOperationName(GET_CURRENT_USER) ?? '', () => { return HttpResponse.json({ data: { - currentUser: mockedOnboardingUsersData[0], + currentUser: mockedOnboardingUserData( + OnboardingStatus.ProfileCreation, + ), }, }); }), diff --git a/packages/twenty-front/src/pages/onboarding/__stories__/CreateWorkspace.stories.tsx b/packages/twenty-front/src/pages/onboarding/__stories__/CreateWorkspace.stories.tsx index f881ef40ab3e..baccc13b2c80 100644 --- a/packages/twenty-front/src/pages/onboarding/__stories__/CreateWorkspace.stories.tsx +++ b/packages/twenty-front/src/pages/onboarding/__stories__/CreateWorkspace.stories.tsx @@ -2,30 +2,22 @@ import { getOperationName } from '@apollo/client/utilities'; import { Meta, StoryObj } from '@storybook/react'; import { within } from '@storybook/test'; import { graphql, HttpResponse } from 'msw'; -import { useSetRecoilState } from 'recoil'; -import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState'; import { AppPath } from '@/types/AppPath'; import { GET_CURRENT_USER } from '@/users/graphql/queries/getCurrentUser'; +import { OnboardingStatus } from '~/generated/graphql'; import { CreateWorkspace } from '~/pages/onboarding/CreateWorkspace'; import { PageDecorator, PageDecoratorArgs, } from '~/testing/decorators/PageDecorator'; import { graphqlMocks } from '~/testing/graphqlMocks'; -import { mockedOnboardingUsersData } from '~/testing/mock-data/users'; +import { mockedOnboardingUserData } from '~/testing/mock-data/users'; const meta: Meta<PageDecoratorArgs> = { title: 'Pages/Onboarding/CreateWorkspace', component: CreateWorkspace, - decorators: [ - (Story) => { - const setCurrentWorkspace = useSetRecoilState(currentWorkspaceState); - setCurrentWorkspace(mockedOnboardingUsersData[1].defaultWorkspace); - return <Story />; - }, - PageDecorator, - ], + decorators: [PageDecorator], args: { routePath: AppPath.CreateWorkspace }, parameters: { msw: { @@ -33,7 +25,9 @@ const meta: Meta<PageDecoratorArgs> = { graphql.query(getOperationName(GET_CURRENT_USER) ?? '', () => { return HttpResponse.json({ data: { - currentUser: mockedOnboardingUsersData[1], + currentUser: mockedOnboardingUserData( + OnboardingStatus.WorkspaceActivation, + ), }, }); }), diff --git a/packages/twenty-front/src/pages/onboarding/__stories__/InviteTeam.stories.tsx b/packages/twenty-front/src/pages/onboarding/__stories__/InviteTeam.stories.tsx index 799daa507379..e174fc517073 100644 --- a/packages/twenty-front/src/pages/onboarding/__stories__/InviteTeam.stories.tsx +++ b/packages/twenty-front/src/pages/onboarding/__stories__/InviteTeam.stories.tsx @@ -3,7 +3,7 @@ import { Meta, StoryObj } from '@storybook/react'; import { within } from '@storybook/test'; import { graphql, HttpResponse } from 'msw'; -import { OnboardingStep } from '~/generated/graphql'; +import { OnboardingStatus } from '~/generated/graphql'; import { AppPath } from '~/modules/types/AppPath'; import { GET_CURRENT_USER } from '~/modules/users/graphql/queries/getCurrentUser'; import { InviteTeam } from '~/pages/onboarding/InviteTeam'; @@ -12,7 +12,7 @@ import { PageDecoratorArgs, } from '~/testing/decorators/PageDecorator'; import { graphqlMocks } from '~/testing/graphqlMocks'; -import { mockedOnboardingUsersData } from '~/testing/mock-data/users'; +import { mockedOnboardingUserData } from '~/testing/mock-data/users'; const meta: Meta<PageDecoratorArgs> = { title: 'Pages/Onboarding/InviteTeam', @@ -25,10 +25,9 @@ const meta: Meta<PageDecoratorArgs> = { graphql.query(getOperationName(GET_CURRENT_USER) ?? '', () => { return HttpResponse.json({ data: { - currentUser: { - ...mockedOnboardingUsersData[0], - onboardingStep: OnboardingStep.InviteTeam, - }, + currentUser: mockedOnboardingUserData( + OnboardingStatus.InviteTeam, + ), }, }); }), diff --git a/packages/twenty-front/src/pages/onboarding/__stories__/PaymentSuccess.stories.tsx b/packages/twenty-front/src/pages/onboarding/__stories__/PaymentSuccess.stories.tsx index 79ad41ee12a8..fccb1e3c64eb 100644 --- a/packages/twenty-front/src/pages/onboarding/__stories__/PaymentSuccess.stories.tsx +++ b/packages/twenty-front/src/pages/onboarding/__stories__/PaymentSuccess.stories.tsx @@ -5,13 +5,14 @@ import { graphql, HttpResponse } from 'msw'; import { AppPath } from '@/types/AppPath'; import { GET_CURRENT_USER } from '@/users/graphql/queries/getCurrentUser'; +import { OnboardingStatus } from '~/generated/graphql'; import { PaymentSuccess } from '~/pages/onboarding/PaymentSuccess'; import { PageDecorator, PageDecoratorArgs, } from '~/testing/decorators/PageDecorator'; import { graphqlMocks } from '~/testing/graphqlMocks'; -import { mockedOnboardingUsersData } from '~/testing/mock-data/users'; +import { mockedOnboardingUserData } from '~/testing/mock-data/users'; const meta: Meta<PageDecoratorArgs> = { title: 'Pages/Onboarding/PaymentSuccess', @@ -24,7 +25,9 @@ const meta: Meta<PageDecoratorArgs> = { graphql.query(getOperationName(GET_CURRENT_USER) ?? '', () => { return HttpResponse.json({ data: { - currentUser: mockedOnboardingUsersData[0], + currentUser: mockedOnboardingUserData( + OnboardingStatus.WorkspaceActivation, + ), }, }); }), diff --git a/packages/twenty-front/src/pages/onboarding/__stories__/SyncEmails.stories.tsx b/packages/twenty-front/src/pages/onboarding/__stories__/SyncEmails.stories.tsx index d6f7ba36dd89..8d9b4261ef0b 100644 --- a/packages/twenty-front/src/pages/onboarding/__stories__/SyncEmails.stories.tsx +++ b/packages/twenty-front/src/pages/onboarding/__stories__/SyncEmails.stories.tsx @@ -3,7 +3,7 @@ import { Meta, StoryObj } from '@storybook/react'; import { within } from '@storybook/test'; import { graphql, HttpResponse } from 'msw'; -import { OnboardingStep } from '~/generated/graphql'; +import { OnboardingStatus } from '~/generated/graphql'; import { AppPath } from '~/modules/types/AppPath'; import { GET_CURRENT_USER } from '~/modules/users/graphql/queries/getCurrentUser'; import { SyncEmails } from '~/pages/onboarding/SyncEmails'; @@ -12,7 +12,7 @@ import { PageDecoratorArgs, } from '~/testing/decorators/PageDecorator'; import { graphqlMocks } from '~/testing/graphqlMocks'; -import { mockedOnboardingUsersData } from '~/testing/mock-data/users'; +import { mockedOnboardingUserData } from '~/testing/mock-data/users'; const meta: Meta<PageDecoratorArgs> = { title: 'Pages/Onboarding/SyncEmails', @@ -25,10 +25,7 @@ const meta: Meta<PageDecoratorArgs> = { graphql.query(getOperationName(GET_CURRENT_USER) ?? '', () => { return HttpResponse.json({ data: { - currentUser: { - ...mockedOnboardingUsersData[0], - onboardingStep: OnboardingStep.SyncEmail, - }, + currentUser: mockedOnboardingUserData(OnboardingStatus.SyncEmail), }, }); }), diff --git a/packages/twenty-front/src/pages/settings/SettingsBilling.tsx b/packages/twenty-front/src/pages/settings/SettingsBilling.tsx index 77763f68bce2..2e738952b376 100644 --- a/packages/twenty-front/src/pages/settings/SettingsBilling.tsx +++ b/packages/twenty-front/src/pages/settings/SettingsBilling.tsx @@ -10,10 +10,9 @@ import { IconCurrencyDollar, } from 'twenty-ui'; -import { useOnboardingStatus } from '@/auth/hooks/useOnboardingStatus'; import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState'; -import { OnboardingStatus } from '@/auth/utils/getOnboardingStatus'; import { SettingsBillingCoverImage } from '@/billing/components/SettingsBillingCoverImage'; +import { useOnboardingStatus } from '@/onboarding/hooks/useOnboardingStatus'; import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer'; import { SupportChat } from '@/support/components/SupportChat'; import { AppPath } from '@/types/AppPath'; @@ -24,8 +23,11 @@ import { Button } from '@/ui/input/button/components/Button'; import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal'; import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer'; import { Section } from '@/ui/layout/section/components/Section'; -import { UndecoratedLink } from '@/ui/navigation/link/components/UndecoratedLink'; +import { useSubscriptionStatus } from '@/workspace/hooks/useSubscriptionStatus'; import { + OnboardingStatus, + SubscriptionInterval, + SubscriptionStatus, useBillingPortalSessionQuery, useUpdateBillingSubscriptionMutation, } from '~/generated/graphql'; @@ -40,21 +42,21 @@ const StyledInvisibleChat = styled.div` `; type SwitchInfo = { - newInterval: string; + newInterval: SubscriptionInterval; to: string; from: string; impact: string; }; const MONTHLY_SWITCH_INFO: SwitchInfo = { - newInterval: 'year', + newInterval: SubscriptionInterval.Year, to: 'to yearly', from: 'from monthly to yearly', impact: 'You will be charged immediately for the full year.', }; const YEARLY_SWITCH_INFO: SwitchInfo = { - newInterval: 'month', + newInterval: SubscriptionInterval.Month, to: 'to monthly', from: 'from yearly to monthly', impact: 'Your credit balance will be used to pay the monthly bills.', @@ -68,10 +70,12 @@ const SWITCH_INFOS = { export const SettingsBilling = () => { const { enqueueSnackBar } = useSnackBar(); const onboardingStatus = useOnboardingStatus(); + const subscriptionStatus = useSubscriptionStatus(); const currentWorkspace = useRecoilValue(currentWorkspaceState); const setCurrentWorkspace = useSetRecoilState(currentWorkspaceState); const switchingInfo = - currentWorkspace?.currentBillingSubscription?.interval === 'year' + currentWorkspace?.currentBillingSubscription?.interval === + SubscriptionInterval.Year ? SWITCH_INFOS.year : SWITCH_INFOS.month; const [isSwitchingIntervalModalOpen, setIsSwitchingIntervalModalOpen] = @@ -94,14 +98,15 @@ export const SettingsBilling = () => { onboardingStatus !== OnboardingStatus.Completed; const displayPaymentFailInfo = - onboardingStatus === OnboardingStatus.PastDue || - onboardingStatus === OnboardingStatus.Unpaid; + subscriptionStatus === SubscriptionStatus.PastDue || + subscriptionStatus === SubscriptionStatus.Unpaid; const displaySubscriptionCanceledInfo = - onboardingStatus === OnboardingStatus.Canceled; + subscriptionStatus === SubscriptionStatus.Canceled; const displaySubscribeInfo = - onboardingStatus === OnboardingStatus.CompletedWithoutSubscription; + onboardingStatus === OnboardingStatus.Completed && + !isDefined(subscriptionStatus); const openBillingPortal = () => { if (isDefined(data) && isDefined(data.billingPortalSession.url)) { @@ -153,22 +158,20 @@ export const SettingsBilling = () => { /> )} {displaySubscriptionCanceledInfo && ( - <UndecoratedLink to={AppPath.PlanRequired}> - <Info - text={'Subscription canceled. Please start a new one'} - buttonTitle={'Subscribe'} - accent={'danger'} - /> - </UndecoratedLink> + <Info + text={'Subscription canceled. Please start a new one'} + buttonTitle={'Subscribe'} + accent={'danger'} + to={AppPath.PlanRequired} + /> )} {displaySubscribeInfo ? ( - <UndecoratedLink to={AppPath.PlanRequired}> - <Info - text={'Your workspace does not have an active subscription'} - buttonTitle={'Subscribe'} - accent={'danger'} - /> - </UndecoratedLink> + <Info + text={'Your workspace does not have an active subscription'} + buttonTitle={'Subscribe'} + accent={'danger'} + to={AppPath.PlanRequired} + /> ) : ( <> <Section> diff --git a/packages/twenty-front/src/pages/settings/accounts/SettingsAccounts.tsx b/packages/twenty-front/src/pages/settings/accounts/SettingsAccounts.tsx index 484a0a681742..0a46dfbe95d9 100644 --- a/packages/twenty-front/src/pages/settings/accounts/SettingsAccounts.tsx +++ b/packages/twenty-front/src/pages/settings/accounts/SettingsAccounts.tsx @@ -8,8 +8,8 @@ import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSi import { generateDepthOneRecordGqlFields } from '@/object-record/graphql/utils/generateDepthOneRecordGqlFields'; import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; import { SettingsAccountLoader } from '@/settings/accounts/components/SettingsAccountLoader'; +import { SettingsAccountsBlocklistSection } from '@/settings/accounts/components/SettingsAccountsBlocklistSection'; import { SettingsAccountsConnectedAccountsListCard } from '@/settings/accounts/components/SettingsAccountsConnectedAccountsListCard'; -import { SettingsAccountsEmailsBlocklistSection } from '@/settings/accounts/components/SettingsAccountsEmailsBlocklistSection'; import { SettingsAccountsSettingsSection } from '@/settings/accounts/components/SettingsAccountsSettingsSection'; import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer'; import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer'; @@ -55,7 +55,7 @@ export const SettingsAccounts = () => { loading={loading} /> </Section> - {isBlocklistEnabled && <SettingsAccountsEmailsBlocklistSection />} + {isBlocklistEnabled && <SettingsAccountsBlocklistSection />} <SettingsAccountsSettingsSection /> </> )} diff --git a/packages/twenty-front/src/pages/settings/accounts/SettingsAccountsCalendars.tsx b/packages/twenty-front/src/pages/settings/accounts/SettingsAccountsCalendars.tsx index 6ad0070f3699..6d3d1c3570e7 100644 --- a/packages/twenty-front/src/pages/settings/accounts/SettingsAccountsCalendars.tsx +++ b/packages/twenty-front/src/pages/settings/accounts/SettingsAccountsCalendars.tsx @@ -1,85 +1,14 @@ -import { addMinutes, endOfDay, min, startOfDay } from 'date-fns'; -import { useRecoilValue } from 'recoil'; -import { H2Title, IconSettings } from 'twenty-ui'; +import { IconSettings } from 'twenty-ui'; -import { CalendarChannel } from '@/accounts/types/CalendarChannel'; -import { ConnectedAccount } from '@/accounts/types/ConnectedAccount'; -import { CalendarMonthCard } from '@/activities/calendar/components/CalendarMonthCard'; -import { CalendarContext } from '@/activities/calendar/contexts/CalendarContext'; -import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; -import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; -import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; -import { SettingsAccountsCalendarChannelsListCard } from '@/settings/accounts/components/SettingsAccountsCalendarChannelsListCard'; -import { SettingsAccountsCalendarDisplaySettings } from '@/settings/accounts/components/SettingsAccountsCalendarDisplaySettings'; +import { SettingsAccountsCalendarChannelsContainer } from '@/settings/accounts/components/SettingsAccountsCalendarChannelsContainer'; import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer'; import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath'; import { SettingsPath } from '@/types/SettingsPath'; import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer'; import { Section } from '@/ui/layout/section/components/Section'; import { Breadcrumb } from '@/ui/navigation/bread-crumb/components/Breadcrumb'; -import { CalendarChannelVisibility } from '~/generated/graphql'; -import { TimelineCalendarEvent } from '~/generated-metadata/graphql'; export const SettingsAccountsCalendars = () => { - const calendarSettingsEnabled = false; - const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState); - const { records: accounts } = useFindManyRecords<ConnectedAccount>({ - objectNameSingular: CoreObjectNameSingular.ConnectedAccount, - filter: { - accountOwnerId: { - eq: currentWorkspaceMember?.id, - }, - }, - }); - - const { records: calendarChannels } = useFindManyRecords<CalendarChannel>({ - objectNameSingular: CoreObjectNameSingular.CalendarChannel, - filter: { - connectedAccountId: { - in: accounts.map((account) => account.id), - }, - }, - }); - - const exampleStartDate = new Date(); - const exampleEndDate = min([ - addMinutes(exampleStartDate, 30), - endOfDay(exampleStartDate), - ]); - const exampleDayTime = startOfDay(exampleStartDate).getTime(); - const exampleCalendarEvent: TimelineCalendarEvent = { - id: '', - participants: [ - { - firstName: currentWorkspaceMember?.name.firstName || '', - lastName: currentWorkspaceMember?.name.lastName || '', - displayName: currentWorkspaceMember - ? [ - currentWorkspaceMember.name.firstName, - currentWorkspaceMember.name.lastName, - ].join(' ') - : '', - avatarUrl: currentWorkspaceMember?.avatarUrl || '', - handle: '', - personId: '', - workspaceMemberId: currentWorkspaceMember?.id || '', - }, - ], - endsAt: exampleEndDate.toISOString(), - isFullDay: false, - startsAt: exampleStartDate.toISOString(), - conferenceSolution: '', - conferenceLink: { - label: '', - url: '', - }, - description: '', - isCanceled: false, - location: '', - title: 'Onboarding call', - visibility: CalendarChannelVisibility.ShareEverything, - }; - return ( <SubMenuTopBarContainer Icon={IconSettings} title="Settings"> <SettingsPageContainer> @@ -93,41 +22,8 @@ export const SettingsAccountsCalendars = () => { ]} /> <Section> - <H2Title - title="Calendar settings" - description="Sync your calendars and set your preferences" - /> - <SettingsAccountsCalendarChannelsListCard /> + <SettingsAccountsCalendarChannelsContainer /> </Section> - {!!calendarChannels.length && calendarSettingsEnabled && ( - <> - <Section> - <H2Title - title="Display" - description="Configure how we should display your events in your calendar" - /> - <SettingsAccountsCalendarDisplaySettings /> - </Section> - <Section> - <H2Title - title="Color code" - description="Events you participated in are displayed in red." - /> - <CalendarContext.Provider - value={{ - currentCalendarEvent: exampleCalendarEvent, - calendarEventsByDayTime: { - [exampleDayTime]: [exampleCalendarEvent], - }, - getNextCalendarEvent: () => undefined, - updateCurrentCalendarEvent: () => {}, - }} - > - <CalendarMonthCard dayTimes={[exampleDayTime]} /> - </CalendarContext.Provider> - </Section> - </> - )} </SettingsPageContainer> </SubMenuTopBarContainer> ); diff --git a/packages/twenty-front/src/pages/settings/accounts/SettingsAccountsCalendarsSettings.tsx b/packages/twenty-front/src/pages/settings/accounts/SettingsAccountsCalendarsSettings.tsx deleted file mode 100644 index 589b89acc52c..000000000000 --- a/packages/twenty-front/src/pages/settings/accounts/SettingsAccountsCalendarsSettings.tsx +++ /dev/null @@ -1,143 +0,0 @@ -import { useEffect } from 'react'; -import { useNavigate, useParams } from 'react-router-dom'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; -import { H2Title, IconRefresh, IconSettings, IconUser } from 'twenty-ui'; - -import { CalendarChannel } from '@/accounts/types/CalendarChannel'; -import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; -import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord'; -import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord'; -import { SettingsAccountsEventVisibilitySettingsCard } from '@/settings/accounts/components/SettingsAccountsCalendarVisibilitySettingsCard'; -import { SettingsAccountsCardMedia } from '@/settings/accounts/components/SettingsAccountsCardMedia'; -import { SettingsAccountsToggleSettingCard } from '@/settings/accounts/components/SettingsAccountsToggleSettingCard'; -import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer'; -import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath'; -import { AppPath } from '@/types/AppPath'; -import { SettingsPath } from '@/types/SettingsPath'; -import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer'; -import { Section } from '@/ui/layout/section/components/Section'; -import { Breadcrumb } from '@/ui/navigation/bread-crumb/components/Breadcrumb'; -import { CalendarChannelVisibility } from '~/generated/graphql'; - -const StyledCardMedia = styled(SettingsAccountsCardMedia)` - height: ${({ theme }) => theme.spacing(6)}; -`; - -export const SettingsAccountsCalendarsSettings = () => { - const theme = useTheme(); - const navigate = useNavigate(); - - const { accountUuid: calendarChannelId = '' } = useParams(); - - const { record: calendarChannel, loading } = - useFindOneRecord<CalendarChannel>({ - objectNameSingular: CoreObjectNameSingular.CalendarChannel, - objectRecordId: calendarChannelId, - }); - - const { updateOneRecord } = useUpdateOneRecord<CalendarChannel>({ - objectNameSingular: CoreObjectNameSingular.CalendarChannel, - }); - - const handleVisibilityChange = (value: CalendarChannelVisibility) => { - updateOneRecord({ - idToUpdate: calendarChannelId, - updateOneRecordInput: { - visibility: value, - }, - }); - }; - - const handleContactAutoCreationToggle = (value: boolean) => { - updateOneRecord({ - idToUpdate: calendarChannelId, - updateOneRecordInput: { - isContactAutoCreationEnabled: value, - }, - }); - }; - - const handleSyncEventsToggle = (value: boolean) => { - updateOneRecord({ - idToUpdate: calendarChannelId, - updateOneRecordInput: { - isSyncEnabled: value, - }, - }); - }; - - useEffect(() => { - if (!loading && !calendarChannel) navigate(AppPath.NotFound); - }, [loading, calendarChannel, navigate]); - - if (!calendarChannel) return null; - - return ( - <SubMenuTopBarContainer Icon={IconSettings} title="Settings"> - <SettingsPageContainer> - <Breadcrumb - links={[ - { - children: 'Accounts', - href: getSettingsPagePath(SettingsPath.Accounts), - }, - { - children: 'Calendars', - href: getSettingsPagePath(SettingsPath.AccountsCalendars), - }, - { children: calendarChannel?.handle || '' }, - ]} - /> - <Section> - <H2Title - title="Event visibility" - description="Define what will be visible to other users in your workspace" - /> - <SettingsAccountsEventVisibilitySettingsCard - value={calendarChannel.visibility} - onChange={handleVisibilityChange} - /> - </Section> - <Section> - <H2Title - title="Contact auto-creation" - description="Automatically create contacts for people you've participated in an event with." - /> - <SettingsAccountsToggleSettingCard - cardMedia={ - <StyledCardMedia> - <IconUser - size={theme.icon.size.sm} - stroke={theme.icon.stroke.lg} - /> - </StyledCardMedia> - } - title="Auto-creation" - value={!!calendarChannel.isContactAutoCreationEnabled} - onToggle={handleContactAutoCreationToggle} - /> - </Section> - <Section> - <H2Title - title="Synchronization" - description="Past and future calendar events will automatically be synced to this workspace" - /> - <SettingsAccountsToggleSettingCard - cardMedia={ - <StyledCardMedia> - <IconRefresh - size={theme.icon.size.sm} - stroke={theme.icon.stroke.lg} - /> - </StyledCardMedia> - } - title="Sync events" - value={!!calendarChannel.isSyncEnabled} - onToggle={handleSyncEventsToggle} - /> - </Section> - </SettingsPageContainer> - </SubMenuTopBarContainer> - ); -}; diff --git a/packages/twenty-front/src/pages/settings/accounts/SettingsAccountsEmails.tsx b/packages/twenty-front/src/pages/settings/accounts/SettingsAccountsEmails.tsx index d2827187f75c..b972ad215e87 100644 --- a/packages/twenty-front/src/pages/settings/accounts/SettingsAccountsEmails.tsx +++ b/packages/twenty-front/src/pages/settings/accounts/SettingsAccountsEmails.tsx @@ -1,6 +1,6 @@ -import { H2Title, IconSettings } from 'twenty-ui'; +import { IconSettings } from 'twenty-ui'; -import { SettingsAccountsMessageChannelsListCard } from '@/settings/accounts/components/SettingsAccountsMessageChannelsListCard'; +import { SettingsAccountsMessageChannelsContainer } from '@/settings/accounts/components/SettingsAccountsMessageChannelsContainer'; import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer'; import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer'; import { Section } from '@/ui/layout/section/components/Section'; @@ -16,11 +16,7 @@ export const SettingsAccountsEmails = () => ( ]} /> <Section> - <H2Title - title="Emails sync" - description="Sync your inboxes and set your privacy settings" - /> - <SettingsAccountsMessageChannelsListCard /> + <SettingsAccountsMessageChannelsContainer /> </Section> </SettingsPageContainer> </SubMenuTopBarContainer> diff --git a/packages/twenty-front/src/pages/settings/accounts/SettingsAccountsEmailsInboxSettings.tsx b/packages/twenty-front/src/pages/settings/accounts/SettingsAccountsEmailsInboxSettings.tsx deleted file mode 100644 index afef0c498d28..000000000000 --- a/packages/twenty-front/src/pages/settings/accounts/SettingsAccountsEmailsInboxSettings.tsx +++ /dev/null @@ -1,128 +0,0 @@ -import { useEffect } from 'react'; -import { useNavigate, useParams } from 'react-router-dom'; -import { useTheme } from '@emotion/react'; -import { H2Title, IconRefresh, IconSettings, IconUser } from 'twenty-ui'; - -import { MessageChannel } from '@/accounts/types/MessageChannel'; -import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; -import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord'; -import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord'; -import { SettingsAccountsCardMedia } from '@/settings/accounts/components/SettingsAccountsCardMedia'; -import { SettingsAccountsInboxVisibilitySettingsCard } from '@/settings/accounts/components/SettingsAccountsInboxVisibilitySettingsCard'; -import { SettingsAccountsToggleSettingCard } from '@/settings/accounts/components/SettingsAccountsToggleSettingCard'; -import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer'; -import { AppPath } from '@/types/AppPath'; -import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer'; -import { Section } from '@/ui/layout/section/components/Section'; -import { Breadcrumb } from '@/ui/navigation/bread-crumb/components/Breadcrumb'; -import { MessageChannelVisibility } from '~/generated/graphql'; - -export const SettingsAccountsEmailsInboxSettings = () => { - const theme = useTheme(); - const navigate = useNavigate(); - const { accountUuid: messageChannelId = '' } = useParams(); - - const { record: messageChannel, loading } = useFindOneRecord<MessageChannel>({ - objectNameSingular: CoreObjectNameSingular.MessageChannel, - objectRecordId: messageChannelId, - }); - - const { updateOneRecord } = useUpdateOneRecord<MessageChannel>({ - objectNameSingular: CoreObjectNameSingular.MessageChannel, - }); - - const handleVisibilityChange = (value: MessageChannelVisibility) => { - updateOneRecord({ - idToUpdate: messageChannelId, - updateOneRecordInput: { - visibility: value, - }, - }); - }; - - const handleContactAutoCreationToggle = (value: boolean) => { - updateOneRecord({ - idToUpdate: messageChannelId, - updateOneRecordInput: { - isContactAutoCreationEnabled: value, - }, - }); - }; - - const handleIsSyncEnabledToggle = (value: boolean) => { - updateOneRecord({ - idToUpdate: messageChannelId, - updateOneRecordInput: { - isSyncEnabled: value, - }, - }); - }; - - useEffect(() => { - if (!loading && !messageChannel) navigate(AppPath.NotFound); - }, [loading, messageChannel, navigate]); - - if (!messageChannel) return null; - - return ( - <SubMenuTopBarContainer Icon={IconSettings} title="Settings"> - <SettingsPageContainer> - <Breadcrumb - links={[ - { children: 'Accounts', href: '/settings/accounts' }, - { children: 'Emails', href: '/settings/accounts/emails' }, - { children: messageChannel.handle || '' }, - ]} - /> - <Section> - <H2Title - title="Email visibility" - description="Define what will be visible to other users in your workspace" - /> - <SettingsAccountsInboxVisibilitySettingsCard - value={messageChannel.visibility} - onChange={handleVisibilityChange} - /> - </Section> - <Section> - <H2Title - title="Contact auto-creation" - description="Automatically create contacts for people you’ve sent emails to" - /> - <SettingsAccountsToggleSettingCard - cardMedia={ - <SettingsAccountsCardMedia> - <IconUser - size={theme.icon.size.sm} - stroke={theme.icon.stroke.lg} - /> - </SettingsAccountsCardMedia> - } - title="Auto-creation" - value={!!messageChannel.isContactAutoCreationEnabled} - onToggle={handleContactAutoCreationToggle} - /> - </Section> - <Section> - <H2Title - title="Synchronization" - description="Past and future emails will automatically be synced to this workspace" - /> - <SettingsAccountsToggleSettingCard - cardMedia={ - <SettingsAccountsCardMedia> - <IconRefresh - size={theme.icon.size.sm} - stroke={theme.icon.stroke.lg} - /> - </SettingsAccountsCardMedia> - } - title="Sync emails" - value={!!messageChannel.isSyncEnabled} - onToggle={handleIsSyncEnabledToggle} - /> - </Section> - </SettingsPageContainer> - </SubMenuTopBarContainer> - ); -}; diff --git a/packages/twenty-front/src/pages/settings/accounts/__stories__/SettingsAccountsCalendars.stories.tsx b/packages/twenty-front/src/pages/settings/accounts/__stories__/SettingsAccountsCalendars.stories.tsx index d2134d2f4264..fc184ea50d93 100644 --- a/packages/twenty-front/src/pages/settings/accounts/__stories__/SettingsAccountsCalendars.stories.tsx +++ b/packages/twenty-front/src/pages/settings/accounts/__stories__/SettingsAccountsCalendars.stories.tsx @@ -1,23 +1,19 @@ import { Meta, StoryObj } from '@storybook/react'; -import { within } from '@storybook/test'; +import { HttpResponse, graphql } from 'msw'; +import { SettingsAccountsCalendars } from '~/pages/settings/accounts/SettingsAccountsCalendars'; -import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath'; -import { SettingsPath } from '@/types/SettingsPath'; import { PageDecorator, PageDecoratorArgs, } from '~/testing/decorators/PageDecorator'; import { graphqlMocks } from '~/testing/graphqlMocks'; -import { sleep } from '~/utils/sleep'; - -import { SettingsAccountsCalendars } from '../SettingsAccountsCalendars'; const meta: Meta<PageDecoratorArgs> = { title: 'Pages/Settings/Accounts/SettingsAccountsCalendars', component: SettingsAccountsCalendars, decorators: [PageDecorator], args: { - routePath: getSettingsPagePath(SettingsPath.AccountsCalendars), + routePath: '/settings/accounts/calendars', }, parameters: { layout: 'fullscreen', @@ -29,11 +25,120 @@ export default meta; export type Story = StoryObj<typeof SettingsAccountsCalendars>; -export const Default: Story = { - play: async ({ canvasElement }) => { - const canvas = within(canvasElement); - sleep(100); +export const NoConnectedAccount: Story = {}; - await canvas.findByText('Calendar settings'); +export const TwoConnectedAccounts: Story = { + parameters: { + msw: { + handlers: [ + ...graphqlMocks.handlers, + graphql.query('FindManyConnectedAccounts', () => { + return HttpResponse.json({ + data: { + connectedAccounts: { + __typename: 'ConnectedAccountConnection', + totalCount: 1, + pageInfo: { + __typename: 'PageInfo', + hasNextPage: false, + startCursor: '', + endCursor: '', + }, + edges: [ + { + __typename: 'ConnectedAccountEdge', + cursor: '', + node: { + __typename: 'ConnectedAccount', + accessToken: '', + refreshToken: '', + updatedAt: '2024-07-03T20:03:35.064Z', + createdAt: '2024-07-03T20:03:35.064Z', + id: '20202020-954c-4d76-9a87-e5f072d4b7ef', + provider: 'google', + accountOwnerId: '20202020-03f2-4d83-b0d5-2ec2bcee72d4', + lastSyncHistoryId: '', + handleAliases: '', + handle: 'test.test@gmail.com', + authFailedAt: null, + }, + }, + ], + }, + }, + }); + }), + graphql.query('FindManyCalendarChannels', () => { + return HttpResponse.json({ + data: { + calendarChannels: { + __typename: 'CalendarChannelConnection', + totalCount: 2, + pageInfo: { + __typename: 'PageInfo', + hasNextPage: false, + startCursor: '', + endCursor: '', + }, + edges: [ + { + __typename: 'CalendarChannelEdge', + cursor: '', + node: { + __typename: 'CalendarChannel', + handle: 'test.test@gmail.com', + excludeNonProfessionalEmails: true, + syncStageStartedAt: null, + id: '20202020-ef5a-4822-9e08-ce6e6a4dcb6f', + updatedAt: '2024-07-03T20:03:11.903Z', + createdAt: '2024-07-03T20:03:11.903Z', + connectedAccountId: + '20202020-954c-4d76-9a87-e5f072d4b7ef', + contactAutoCreationPolicy: 'SENT', + syncStage: 'PARTIAL_CALENDAR_EVENT_LIST_FETCH_PENDING', + type: 'email', + isContactAutoCreationEnabled: true, + syncCursor: '1562764', + excludeGroupEmails: true, + throttleFailureCount: 0, + isSyncEnabled: true, + visibility: 'SHARE_EVERYTHING', + syncStatus: 'COMPLETED', + syncedAt: '2024-07-04T16:25:04.960Z', + }, + }, + { + __typename: 'CalendarChannelEdge', + cursor: '', + node: { + __typename: 'CalendarChannel', + handle: 'test.test2@gmail.com', + excludeNonProfessionalEmails: true, + syncStageStartedAt: null, + id: '20202020-ef5a-4822-9e08-ce6e6a4dcb6a', + updatedAt: '2024-07-03T20:03:11.903Z', + createdAt: '2024-07-03T20:03:11.903Z', + connectedAccountId: + '20202020-954c-4d76-9a87-e5f072d4b7ef', + contactAutoCreationPolicy: 'SENT', + syncStage: 'PARTIAL_CALENDAR_EVENT_LIST_FETCH_PENDING', + type: 'email', + isContactAutoCreationEnabled: true, + syncCursor: '1562764', + excludeGroupEmails: true, + throttleFailureCount: 0, + isSyncEnabled: true, + visibility: 'SHARE_EVERYTHING', + syncStatus: 'COMPLETED', + syncedAt: '2024-07-04T16:25:04.960Z', + }, + }, + ], + }, + }, + }); + }), + ], + }, }, }; diff --git a/packages/twenty-front/src/pages/settings/accounts/__stories__/SettingsAccountsCalendarsSettings.stories.tsx b/packages/twenty-front/src/pages/settings/accounts/__stories__/SettingsAccountsCalendarsSettings.stories.tsx deleted file mode 100644 index 1e3ee5934d4d..000000000000 --- a/packages/twenty-front/src/pages/settings/accounts/__stories__/SettingsAccountsCalendarsSettings.stories.tsx +++ /dev/null @@ -1,61 +0,0 @@ -import { Meta, StoryObj } from '@storybook/react'; -import { within } from '@storybook/test'; -import { graphql, HttpResponse } from 'msw'; - -import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath'; -import { SettingsPath } from '@/types/SettingsPath'; -import { - PageDecorator, - PageDecoratorArgs, -} from '~/testing/decorators/PageDecorator'; -import { graphqlMocks } from '~/testing/graphqlMocks'; -import { mockedConnectedAccounts } from '~/testing/mock-data/accounts'; -import { sleep } from '~/utils/sleep'; - -import { SettingsAccountsCalendarsSettings } from '../SettingsAccountsCalendarsSettings'; - -const meta: Meta<PageDecoratorArgs> = { - title: 'Pages/Settings/Accounts/SettingsAccountsCalendarsSettings', - component: SettingsAccountsCalendarsSettings, - decorators: [PageDecorator], - args: { - routePath: getSettingsPagePath(SettingsPath.AccountsCalendarsSettings), - routeParams: { ':accountUuid': mockedConnectedAccounts[0].id }, - }, - parameters: { - layout: 'fullscreen', - msw: { - handlers: [ - ...graphqlMocks.handlers, - graphql.query('FindOneCalendarChannel', () => { - return HttpResponse.json({ - data: { - calendarChannel: { - edges: [], - pageInfo: { - hasNextPage: false, - hasPreviousPage: false, - startCursor: null, - endCursor: null, - }, - }, - }, - }); - }), - ], - }, - }, -}; - -export default meta; - -export type Story = StoryObj<typeof SettingsAccountsCalendarsSettings>; - -export const Default: Story = { - play: async ({ canvasElement }) => { - const canvas = within(canvasElement); - sleep(100); - - await canvas.findByText('Event visibility'); - }, -}; diff --git a/packages/twenty-front/src/pages/settings/accounts/__stories__/SettingsAccountsEmails.stories.tsx b/packages/twenty-front/src/pages/settings/accounts/__stories__/SettingsAccountsEmails.stories.tsx index 21bede0eb563..f0ebac280c23 100644 --- a/packages/twenty-front/src/pages/settings/accounts/__stories__/SettingsAccountsEmails.stories.tsx +++ b/packages/twenty-front/src/pages/settings/accounts/__stories__/SettingsAccountsEmails.stories.tsx @@ -1,4 +1,5 @@ import { Meta, StoryObj } from '@storybook/react'; +import { graphql, HttpResponse } from 'msw'; import { PageDecorator, @@ -25,4 +26,120 @@ export default meta; export type Story = StoryObj<typeof SettingsAccountsEmails>; -export const Default: Story = {}; +export const NoConnectedAccount: Story = {}; + +export const TwoConnectedAccounts: Story = { + parameters: { + msw: { + handlers: [ + ...graphqlMocks.handlers, + graphql.query('FindManyConnectedAccounts', () => { + return HttpResponse.json({ + data: { + connectedAccounts: { + __typename: 'ConnectedAccountConnection', + totalCount: 1, + pageInfo: { + __typename: 'PageInfo', + hasNextPage: false, + startCursor: '', + endCursor: '', + }, + edges: [ + { + __typename: 'ConnectedAccountEdge', + cursor: '', + node: { + __typename: 'ConnectedAccount', + accessToken: '', + refreshToken: '', + updatedAt: '2024-07-03T20:03:35.064Z', + createdAt: '2024-07-03T20:03:35.064Z', + id: '20202020-954c-4d76-9a87-e5f072d4b7ef', + provider: 'google', + accountOwnerId: '20202020-03f2-4d83-b0d5-2ec2bcee72d4', + lastSyncHistoryId: '', + handleAliases: '', + handle: 'test.test@gmail.com', + authFailedAt: null, + }, + }, + ], + }, + }, + }); + }), + graphql.query('FindManyMessageChannels', () => { + return HttpResponse.json({ + data: { + messageChannels: { + __typename: 'MessageChannelConnection', + totalCount: 2, + pageInfo: { + __typename: 'PageInfo', + hasNextPage: false, + startCursor: '', + endCursor: '', + }, + edges: [ + { + __typename: 'MessageChannelEdge', + cursor: '', + node: { + __typename: 'MessageChannel', + handle: 'test.test@gmail.com', + excludeNonProfessionalEmails: true, + syncStageStartedAt: null, + id: '20202020-ef5a-4822-9e08-ce6e6a4dcb6f', + updatedAt: '2024-07-03T20:03:11.903Z', + createdAt: '2024-07-03T20:03:11.903Z', + connectedAccountId: + '20202020-954c-4d76-9a87-e5f072d4b7ef', + contactAutoCreationPolicy: 'SENT', + syncStage: 'PARTIAL_MESSAGE_LIST_FETCH_PENDING', + type: 'email', + isContactAutoCreationEnabled: true, + syncCursor: '1562764', + excludeGroupEmails: true, + throttleFailureCount: 0, + isSyncEnabled: true, + visibility: 'SHARE_EVERYTHING', + syncStatus: 'COMPLETED', + syncedAt: '2024-07-04T16:25:04.960Z', + }, + }, + { + __typename: 'MessageChannelEdge', + cursor: '', + node: { + __typename: 'MessageChannel', + handle: 'test.test2@gmail.com', + excludeNonProfessionalEmails: true, + syncStageStartedAt: null, + id: '20202020-ef5a-4822-9e08-ce6e6a4dcb6a', + updatedAt: '2024-07-03T20:03:11.903Z', + createdAt: '2024-07-03T20:03:11.903Z', + connectedAccountId: + '20202020-954c-4d76-9a87-e5f072d4b7ef', + contactAutoCreationPolicy: 'SENT', + syncStage: 'PARTIAL_MESSAGE_LIST_FETCH_PENDING', + type: 'email', + isContactAutoCreationEnabled: true, + syncCursor: '1562764', + excludeGroupEmails: true, + throttleFailureCount: 0, + isSyncEnabled: true, + visibility: 'SHARE_EVERYTHING', + syncStatus: 'COMPLETED', + syncedAt: '2024-07-04T16:25:04.960Z', + }, + }, + ], + }, + }, + }); + }), + ], + }, + }, +}; diff --git a/packages/twenty-front/src/pages/settings/accounts/__stories__/SettingsAccountsEmailsInboxSettings.stories.tsx b/packages/twenty-front/src/pages/settings/accounts/__stories__/SettingsAccountsEmailsInboxSettings.stories.tsx deleted file mode 100644 index 6c23dd71c0ca..000000000000 --- a/packages/twenty-front/src/pages/settings/accounts/__stories__/SettingsAccountsEmailsInboxSettings.stories.tsx +++ /dev/null @@ -1,79 +0,0 @@ -import { Meta, StoryObj } from '@storybook/react'; -import { within } from '@storybook/test'; -import { graphql, HttpResponse } from 'msw'; - -import { MessageChannelVisibility } from '~/generated/graphql'; -import { SettingsAccountsEmailsInboxSettings } from '~/pages/settings/accounts/SettingsAccountsEmailsInboxSettings'; -import { - PageDecorator, - PageDecoratorArgs, -} from '~/testing/decorators/PageDecorator'; -import { graphqlMocks } from '~/testing/graphqlMocks'; - -const meta: Meta<PageDecoratorArgs> = { - title: 'Pages/Settings/Accounts/SettingsAccountsEmailsInboxSettings', - component: SettingsAccountsEmailsInboxSettings, - decorators: [PageDecorator], - args: { - routePath: '/settings/accounts/emails/:accountUuid', - routeParams: { ':accountUuid': '123' }, - }, - parameters: { - layout: 'fullscreen', - msw: { - handlers: [ - graphql.query('FindOneMessageChannel', () => { - return HttpResponse.json({ - data: { - messageChannel: { - id: '1', - visibility: MessageChannelVisibility.ShareEverything, - messageThreads: { edges: [] }, - createdAt: '2021-08-27T12:00:00Z', - type: 'email', - updatedAt: '2021-08-27T12:00:00Z', - targetUrl: 'https://example.com/webhook', - connectedAccountId: '1', - handle: 'handle', - connectedAccount: { - id: '1', - handle: 'handle', - updatedAt: '2021-08-27T12:00:00Z', - accessToken: 'accessToken', - messageChannels: { edges: [] }, - refreshToken: 'refreshToken', - __typename: 'ConnectedAccount', - accountOwner: { id: '1', __typename: 'WorkspaceMember' }, - provider: 'provider', - createdAt: '2021-08-27T12:00:00Z', - accountOwnerId: '1', - }, - __typename: 'MessageChannel', - }, - }, - }); - }), - graphqlMocks.handlers, - ], - }, - }, -}; - -export default meta; - -export type Story = StoryObj<typeof SettingsAccountsEmailsInboxSettings>; - -export const Default: Story = { - play: async ({ canvasElement }) => { - const canvas = within(canvasElement); - - await canvas.findByText('Email visibility'); - await canvas.findByText( - 'Define what will be visible to other users in your workspace', - ); - await canvas.findByText('Contact auto-creation'); - await canvas.findByText( - 'Automatically create contacts for people you’ve sent emails to', - ); - }, -}; diff --git a/packages/twenty-front/src/pages/settings/data-model/SettingsNewObject.tsx b/packages/twenty-front/src/pages/settings/data-model/SettingsNewObject.tsx index cfb6f203b04d..7adb8ee74f2c 100644 --- a/packages/twenty-front/src/pages/settings/data-model/SettingsNewObject.tsx +++ b/packages/twenty-front/src/pages/settings/data-model/SettingsNewObject.tsx @@ -1,6 +1,6 @@ +import { zodResolver } from '@hookform/resolvers/zod'; import { FormProvider, useForm } from 'react-hook-form'; import { useNavigate } from 'react-router-dom'; -import { zodResolver } from '@hookform/resolvers/zod'; import { H2Title, IconSettings } from 'twenty-ui'; import { z } from 'zod'; @@ -40,8 +40,8 @@ export const SettingsNewObject = () => { resolver: zodResolver(newObjectFormSchema), }); - const canSave = - formConfig.formState.isValid && !formConfig.formState.isSubmitting; + const { isValid, isSubmitting } = formConfig.formState; + const canSave = isValid && !isSubmitting; const handleSave = async ( formValues: SettingsDataModelNewObjectFormValues, @@ -84,6 +84,7 @@ export const SettingsNewObject = () => { /> <SaveAndCancelButtons isSaveDisabled={!canSave} + isCancelDisabled={isSubmitting} onCancel={() => navigate(settingsObjectsPagePath)} onSave={formConfig.handleSubmit(handleSave)} /> diff --git a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectEdit.tsx b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectEdit.tsx index e12103ee9f8e..82fdb67b8768 100644 --- a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectEdit.tsx +++ b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectEdit.tsx @@ -1,8 +1,8 @@ +import { zodResolver } from '@hookform/resolvers/zod'; +import pick from 'lodash.pick'; import { useEffect } from 'react'; import { FormProvider, useForm } from 'react-hook-form'; import { useNavigate, useParams } from 'react-router-dom'; -import { zodResolver } from '@hookform/resolvers/zod'; -import pick from 'lodash.pick'; import { H2Title, IconArchive, IconSettings } from 'twenty-ui'; import { z } from 'zod'; @@ -81,7 +81,12 @@ export const SettingsObjectEdit = () => { ), }); - navigate(`${settingsObjectsPagePath}/${getObjectSlug(formValues)}`); + navigate( + `${settingsObjectsPagePath}/${getObjectSlug({ + ...formValues, + namePlural: formValues.labelPlural, + })}`, + ); } catch (error) { enqueueSnackBar((error as Error).message, { variant: SnackBarVariant.Error, @@ -119,6 +124,7 @@ export const SettingsObjectEdit = () => { {activeObjectMetadataItem.isCustom && ( <SaveAndCancelButtons isSaveDisabled={!canSave} + isCancelDisabled={isSubmitting} onCancel={() => navigate(`${settingsObjectsPagePath}/${objectSlug}`) } diff --git a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectFieldEdit.tsx b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectFieldEdit.tsx index bb2ac5e637e4..fdc02bcdd33e 100644 --- a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectFieldEdit.tsx +++ b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectFieldEdit.tsx @@ -1,11 +1,11 @@ -import { useEffect } from 'react'; -import { FormProvider, useForm } from 'react-hook-form'; -import { useNavigate, useParams } from 'react-router-dom'; import { useApolloClient } from '@apollo/client'; import styled from '@emotion/styled'; import { zodResolver } from '@hookform/resolvers/zod'; import omit from 'lodash.omit'; import pick from 'lodash.pick'; +import { useEffect } from 'react'; +import { FormProvider, useForm } from 'react-hook-form'; +import { useNavigate, useParams } from 'react-router-dom'; import { H2Title, IconArchive, IconSettings } from 'twenty-ui'; import { z } from 'zod'; @@ -22,6 +22,7 @@ import { RecordFieldValueSelectorContextProvider } from '@/object-record/record- import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons/SaveAndCancelButtons'; import { SettingsHeaderContainer } from '@/settings/components/SettingsHeaderContainer'; import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer'; +import { FIELD_NAME_MAXIMUM_LENGTH } from '@/settings/data-model/constants/FieldNameMaximumLength'; import { SettingsDataModelFieldAboutForm } from '@/settings/data-model/fields/forms/components/SettingsDataModelFieldAboutForm'; import { SettingsDataModelFieldSettingsFormCard } from '@/settings/data-model/fields/forms/components/SettingsDataModelFieldSettingsFormCard'; import { SettingsDataModelFieldTypeSelect } from '@/settings/data-model/fields/forms/components/SettingsDataModelFieldTypeSelect'; @@ -103,10 +104,8 @@ export const SettingsObjectFieldEdit = () => { if (!activeObjectMetadataItem || !activeMetadataField) return null; - const canSave = - formConfig.formState.isValid && - formConfig.formState.isDirty && - !formConfig.formState.isSubmitting; + const { isDirty, isValid, isSubmitting } = formConfig.formState; + const canSave = isDirty && isValid && !isSubmitting; const isLabelIdentifier = isLabelIdentifierField({ fieldMetadataItem: activeMetadataField, @@ -189,6 +188,7 @@ export const SettingsObjectFieldEdit = () => { {shouldDisplaySaveAndCancel && ( <SaveAndCancelButtons isSaveDisabled={!canSave} + isCancelDisabled={isSubmitting} onCancel={() => navigate(`/settings/objects/${objectSlug}`)} onSave={formConfig.handleSubmit(handleSave)} /> @@ -202,6 +202,7 @@ export const SettingsObjectFieldEdit = () => { <SettingsDataModelFieldAboutForm disabled={!activeMetadataField.isCustom} fieldMetadataItem={activeMetadataField} + maxLength={FIELD_NAME_MAXIMUM_LENGTH} /> </Section> <Section> @@ -212,6 +213,7 @@ export const SettingsObjectFieldEdit = () => { <StyledSettingsObjectFieldTypeSelect disabled fieldMetadataItem={activeMetadataField} + excludedFieldTypes={[FieldMetadataType.Link]} /> <SettingsDataModelFieldSettingsFormCard disableCurrencyForm diff --git a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectNewField/SettingsObjectNewFieldStep2.tsx b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectNewField/SettingsObjectNewFieldStep2.tsx index da7fa13d2559..a2dca70beab8 100644 --- a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectNewField/SettingsObjectNewFieldStep2.tsx +++ b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectNewField/SettingsObjectNewFieldStep2.tsx @@ -1,10 +1,10 @@ -import { useEffect, useState } from 'react'; -import { FormProvider, useForm } from 'react-hook-form'; -import { useNavigate, useParams } from 'react-router-dom'; import { useApolloClient } from '@apollo/client'; import styled from '@emotion/styled'; import { zodResolver } from '@hookform/resolvers/zod'; import pick from 'lodash.pick'; +import { useEffect, useState } from 'react'; +import { FormProvider, useForm } from 'react-hook-form'; +import { useNavigate, useParams } from 'react-router-dom'; import { H2Title, IconSettings } from 'twenty-ui'; import { z } from 'zod'; @@ -17,6 +17,7 @@ import { RecordFieldValueSelectorContextProvider } from '@/object-record/record- import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons/SaveAndCancelButtons'; import { SettingsHeaderContainer } from '@/settings/components/SettingsHeaderContainer'; import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer'; +import { FIELD_NAME_MAXIMUM_LENGTH } from '@/settings/data-model/constants/FieldNameMaximumLength'; import { SettingsDataModelFieldAboutForm } from '@/settings/data-model/fields/forms/components/SettingsDataModelFieldAboutForm'; import { SettingsDataModelFieldSettingsFormCard } from '@/settings/data-model/fields/forms/components/SettingsDataModelFieldSettingsFormCard'; import { SettingsDataModelFieldTypeSelect } from '@/settings/data-model/fields/forms/components/SettingsDataModelFieldTypeSelect'; @@ -108,8 +109,8 @@ export const SettingsObjectNewFieldStep2 = () => { if (!activeObjectMetadataItem) return null; - const canSave = - formConfig.formState.isValid && !formConfig.formState.isSubmitting; + const { isValid, isSubmitting } = formConfig.formState; + const canSave = isValid && !isSubmitting; const handleSave = async ( formValues: SettingsDataModelNewFieldFormValues, @@ -133,26 +134,20 @@ export const SettingsObjectNewFieldStep2 = () => { objectMetadataId: relationFormValues.objectMetadataId, }, }); - - // TODO: fix optimistic update logic - // Forcing a refetch for now but it's not ideal - await apolloClient.refetchQueries({ - include: ['FindManyViews', 'CombinedFindManyRecords'], - }); } else { await createMetadataField({ ...formValues, objectMetadataId: activeObjectMetadataItem.id, }); - - // TODO: fix optimistic update logic - // Forcing a refetch for now but it's not ideal - await apolloClient.refetchQueries({ - include: ['FindManyViews', 'CombinedFindManyRecords'], - }); } navigate(`/settings/objects/${objectSlug}`); + + // TODO: fix optimistic update logic + // Forcing a refetch for now but it's not ideal + await apolloClient.refetchQueries({ + include: ['FindManyViews', 'CombinedFindManyRecords'], + }); } catch (error) { enqueueSnackBar((error as Error).message, { variant: SnackBarVariant.Error, @@ -164,9 +159,9 @@ export const SettingsObjectNewFieldStep2 = () => { [ // FieldMetadataType.Email, // FieldMetadataType.FullName, - // FieldMetadataType.Link, + FieldMetadataType.Link, FieldMetadataType.Numeric, - FieldMetadataType.Probability, + // FieldMetadataType.Probability, // FieldMetadataType.Uuid, // FieldMetadataType.Phone, ] as const @@ -192,6 +187,7 @@ export const SettingsObjectNewFieldStep2 = () => { {!activeObjectMetadataItem.isRemote && ( <SaveAndCancelButtons isSaveDisabled={!canSave} + isCancelDisabled={isSubmitting} onCancel={() => navigate(`/settings/objects/${objectSlug}`)} onSave={formConfig.handleSubmit(handleSave)} /> @@ -202,7 +198,9 @@ export const SettingsObjectNewFieldStep2 = () => { title="Name and description" description="The name and description of this field" /> - <SettingsDataModelFieldAboutForm /> + <SettingsDataModelFieldAboutForm + maxLength={FIELD_NAME_MAXIMUM_LENGTH} + /> </Section> <Section> <H2Title diff --git a/packages/twenty-front/src/pages/settings/data-model/__stories__/SettingsObjectDetail.stories.tsx b/packages/twenty-front/src/pages/settings/data-model/__stories__/SettingsObjectDetail.stories.tsx index 0e4b4eeac4a1..687cf19a2c9b 100644 --- a/packages/twenty-front/src/pages/settings/data-model/__stories__/SettingsObjectDetail.stories.tsx +++ b/packages/twenty-front/src/pages/settings/data-model/__stories__/SettingsObjectDetail.stories.tsx @@ -35,15 +35,13 @@ export const StandardObject: Story = { export const CustomObject: Story = { args: { - routeParams: { ':objectSlug': 'workspaces' }, + routeParams: { ':objectSlug': 'my-customs' }, }, }; export const ObjectDropdownMenu: Story = { - play: async ({ canvasElement }) => { - await sleep(100); - - const canvas = within(canvasElement); + play: async () => { + const canvas = within(document.body); const objectSummaryVerticalDotsIconButton = await canvas.findByRole( 'button', { @@ -59,10 +57,8 @@ export const ObjectDropdownMenu: Story = { }; export const FieldDropdownMenu: Story = { - play: async ({ canvasElement }) => { - await sleep(100); - - const canvas = within(canvasElement); + play: async () => { + const canvas = within(document.body); const [fieldVerticalDotsIconButton] = await canvas.findAllByRole('button', { name: 'Active Field Options', }); diff --git a/packages/twenty-front/src/pages/settings/developers/__stories__/api-keys/SettingsDevelopersApiKeysDetail.stories.tsx b/packages/twenty-front/src/pages/settings/developers/__stories__/api-keys/SettingsDevelopersApiKeysDetail.stories.tsx index cb5902051781..4428ce4e1bd5 100644 --- a/packages/twenty-front/src/pages/settings/developers/__stories__/api-keys/SettingsDevelopersApiKeysDetail.stories.tsx +++ b/packages/twenty-front/src/pages/settings/developers/__stories__/api-keys/SettingsDevelopersApiKeysDetail.stories.tsx @@ -1,6 +1,6 @@ import { Meta, StoryObj } from '@storybook/react'; -import { within } from '@storybook/test'; -import { graphql, HttpResponse } from 'msw'; +import { userEvent, within } from '@storybook/test'; +import { HttpResponse, graphql } from 'msw'; import { SettingsDevelopersApiKeyDetail } from '~/pages/settings/developers/api-keys/SettingsDevelopersApiKeyDetail'; import { @@ -8,6 +8,7 @@ import { PageDecoratorArgs, } from '~/testing/decorators/PageDecorator'; import { graphqlMocks } from '~/testing/graphqlMocks'; +import { sleep } from '~/utils/sleep'; const meta: Meta<PageDecoratorArgs> = { title: 'Pages/Settings/Developers/ApiKeys/SettingsDevelopersApiKeyDetail', @@ -50,6 +51,56 @@ export const Default: Story = { play: async ({ canvasElement }) => { const canvas = within(canvasElement); await canvas.findByText('Settings'); - await canvas.findByText('Regenerate an Api key'); + await canvas.findByText('sfsfdsf API Key'); + }, +}; + +export const RegenerateApiKey: Story = { + play: async ({ canvasElement, step }) => { + const canvas = within(canvasElement); + await canvas.findByText('Settings'); + + await userEvent.click(await canvas.findByText('Regenerate Key')); + + await canvas.findByText('Cancel'); + const confirmationInput = await canvas.findByPlaceholderText('yes'); + await userEvent.click(confirmationInput); + await userEvent.keyboard('y'); + await userEvent.keyboard('e'); + await userEvent.keyboard('s'); + + const confirmButton = await canvas.findByTestId( + 'confirmation-modal-confirm-button', + ); + + await step('Click on confirm button', async () => { + await sleep(1000); + await userEvent.click(confirmButton); + }); + }, +}; + +export const DeleteApiKey: Story = { + play: async ({ canvasElement, step }) => { + const canvas = within(canvasElement); + await canvas.findByText('Settings'); + + await userEvent.click(await canvas.findByText('Delete')); + + await canvas.findByText('Cancel'); + const confirmationInput = await canvas.findByPlaceholderText('yes'); + await userEvent.click(confirmationInput); + await userEvent.keyboard('y'); + await userEvent.keyboard('e'); + await userEvent.keyboard('s'); + + const confirmButton = await canvas.findByTestId( + 'confirmation-modal-confirm-button', + ); + + await step('Click on confirm button', async () => { + await sleep(1000); + await userEvent.click(confirmButton); + }); }, }; diff --git a/packages/twenty-front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeyDetail.tsx b/packages/twenty-front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeyDetail.tsx index 0a718cf7697f..2f3987e81b83 100644 --- a/packages/twenty-front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeyDetail.tsx +++ b/packages/twenty-front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeyDetail.tsx @@ -1,8 +1,8 @@ -import { useEffect, useState } from 'react'; -import { useNavigate, useParams } from 'react-router-dom'; import styled from '@emotion/styled'; import { isNonEmptyString } from '@sniptt/guards'; import { DateTime } from 'luxon'; +import { useEffect, useState } from 'react'; +import { useNavigate, useParams } from 'react-router-dom'; import { useRecoilState } from 'recoil'; import { H2Title, IconRepeat, IconSettings, IconTrash } from 'twenty-ui'; diff --git a/packages/twenty-front/src/pages/tasks/TasksEffect.tsx b/packages/twenty-front/src/pages/tasks/TasksEffect.tsx index c3d5e2daf743..9476c755f285 100644 --- a/packages/twenty-front/src/pages/tasks/TasksEffect.tsx +++ b/packages/twenty-front/src/pages/tasks/TasksEffect.tsx @@ -1,5 +1,6 @@ import { useEffect } from 'react'; import { useRecoilValue } from 'recoil'; +import { v4 } from 'uuid'; import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown'; @@ -29,6 +30,7 @@ export const TasksEffect = ({ filterDropdownId }: TasksEffectProps) => { useEffect(() => { if (isDefined(currentWorkspaceMember)) { setSelectedFilter({ + id: v4(), fieldMetadataId: 'assigneeId', value: JSON.stringify(currentWorkspaceMember.id), operand: ViewFilterOperand.Is, diff --git a/packages/twenty-front/src/testing/decorators/ChipGeneratorsDecorator.tsx b/packages/twenty-front/src/testing/decorators/ChipGeneratorsDecorator.tsx index 6f9ac5d305bd..283e7046e0ab 100644 --- a/packages/twenty-front/src/testing/decorators/ChipGeneratorsDecorator.tsx +++ b/packages/twenty-front/src/testing/decorators/ChipGeneratorsDecorator.tsx @@ -1,21 +1,21 @@ -import { useMemo } from 'react'; import { Decorator } from '@storybook/react'; +import { useMemo } from 'react'; import { PreComputedChipGeneratorsContext } from '@/object-metadata/context/PreComputedChipGeneratorsContext'; -import { getRecordChipGeneratorPerObjectPerField } from '@/object-record/utils/getRecordChipGeneratorPerObjectPerField'; +import { getRecordChipGenerators } from '@/object-record/utils/getRecordChipGenerators'; import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems'; export const ChipGeneratorsDecorator: Decorator = (Story) => { - const chipGeneratorPerObjectPerField = useMemo(() => { - return getRecordChipGeneratorPerObjectPerField( - generatedMockObjectMetadataItems, - ); - }, []); + const { chipGeneratorPerObjectPerField, identifierChipGeneratorPerObject } = + useMemo(() => { + return getRecordChipGenerators(generatedMockObjectMetadataItems); + }, []); return ( <PreComputedChipGeneratorsContext.Provider value={{ chipGeneratorPerObjectPerField, + identifierChipGeneratorPerObject, }} > <Story /> diff --git a/packages/twenty-front/src/testing/decorators/ObjectMetadataItemsDecorator.tsx b/packages/twenty-front/src/testing/decorators/ObjectMetadataItemsDecorator.tsx index 9c27a82e354f..c1582edbae07 100644 --- a/packages/twenty-front/src/testing/decorators/ObjectMetadataItemsDecorator.tsx +++ b/packages/twenty-front/src/testing/decorators/ObjectMetadataItemsDecorator.tsx @@ -1,14 +1,13 @@ -import { useEffect, useMemo } from 'react'; import { Decorator } from '@storybook/react'; +import { useEffect } from 'react'; import { useRecoilValue, useSetRecoilState } from 'recoil'; import { currentUserState } from '@/auth/states/currentUserState'; import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; import { ObjectMetadataItemsLoadEffect } from '@/object-metadata/components/ObjectMetadataItemsLoadEffect'; -import { PreComputedChipGeneratorsContext } from '@/object-metadata/context/PreComputedChipGeneratorsContext'; +import { PreComputedChipGeneratorsProvider } from '@/object-metadata/components/PreComputedChipGeneratorsProvider'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; -import { getRecordChipGeneratorPerObjectPerField } from '@/object-record/utils/getRecordChipGeneratorPerObjectPerField'; -import { mockedUsersData } from '~/testing/mock-data/users'; +import { mockedUserData } from '~/testing/mock-data/users'; import { mockWorkspaceMembers } from '~/testing/mock-data/workspace-members'; export const ObjectMetadataItemsDecorator: Decorator = (Story) => { @@ -20,23 +19,15 @@ export const ObjectMetadataItemsDecorator: Decorator = (Story) => { useEffect(() => { setCurrentWorkspaceMember(mockWorkspaceMembers[0]); - setCurrentUser(mockedUsersData[0]); + setCurrentUser(mockedUserData); }, [setCurrentUser, setCurrentWorkspaceMember]); - const chipGeneratorPerObjectPerField = useMemo(() => { - return getRecordChipGeneratorPerObjectPerField(objectMetadataItems); - }, [objectMetadataItems]); - return ( <> <ObjectMetadataItemsLoadEffect /> - <PreComputedChipGeneratorsContext.Provider - value={{ - chipGeneratorPerObjectPerField, - }} - > + <PreComputedChipGeneratorsProvider> {!!objectMetadataItems.length && <Story />} - </PreComputedChipGeneratorsContext.Provider> + </PreComputedChipGeneratorsProvider> </> ); }; diff --git a/packages/twenty-front/src/testing/decorators/PageDecorator.tsx b/packages/twenty-front/src/testing/decorators/PageDecorator.tsx index b6e842d26c52..19453453c664 100644 --- a/packages/twenty-front/src/testing/decorators/PageDecorator.tsx +++ b/packages/twenty-front/src/testing/decorators/PageDecorator.tsx @@ -1,3 +1,6 @@ +import { ApolloProvider } from '@apollo/client'; +import { loadDevMessages } from '@apollo/client/dev'; +import { Decorator } from '@storybook/react'; import { HelmetProvider } from 'react-helmet-async'; import { createMemoryRouter, @@ -6,9 +9,6 @@ import { Route, RouterProvider, } from 'react-router-dom'; -import { ApolloProvider } from '@apollo/client'; -import { loadDevMessages } from '@apollo/client/dev'; -import { Decorator } from '@storybook/react'; import { RecoilRoot } from 'recoil'; import { ClientConfigProviderEffect } from '@/client-config/components/ClientConfigProviderEffect'; @@ -21,6 +21,7 @@ import { DefaultLayout } from '~/modules/ui/layout/page/DefaultLayout'; import { UserProvider } from '~/modules/users/components/UserProvider'; import { mockedApolloClient } from '~/testing/mockedApolloClient'; +import { PrefetchDataProvider } from '@/prefetch/components/PrefetchDataProvider'; import { FullHeightStorybookLayout } from '../FullHeightStorybookLayout'; export type PageDecoratorArgs = { @@ -73,7 +74,9 @@ const Providers = () => { <HelmetProvider> <SnackBarProviderScope snackBarManagerScopeId="snack-bar-manager"> <ObjectMetadataItemsProvider> - <Outlet /> + <PrefetchDataProvider> + <Outlet /> + </PrefetchDataProvider> </ObjectMetadataItemsProvider> </SnackBarProviderScope> </HelmetProvider> diff --git a/packages/twenty-front/src/testing/decorators/RecordStoreDecorator.tsx b/packages/twenty-front/src/testing/decorators/RecordStoreDecorator.tsx index 96fcda4ab443..77705e775418 100644 --- a/packages/twenty-front/src/testing/decorators/RecordStoreDecorator.tsx +++ b/packages/twenty-front/src/testing/decorators/RecordStoreDecorator.tsx @@ -1,15 +1,15 @@ import { useEffect } from 'react'; import { Decorator } from '@storybook/react'; -import { useSetRecordInStore } from '@/object-record/record-store/hooks/useSetRecordInStore'; +import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore'; export const RecordStoreDecorator: Decorator = (Story, context) => { const { records } = context.parameters; - const { setRecords } = useSetRecordInStore(); + const { upsertRecords } = useUpsertRecordsInStore(); useEffect(() => { - setRecords(records); + upsertRecords(records); }); return <Story />; diff --git a/packages/twenty-front/src/testing/graphqlMocks.ts b/packages/twenty-front/src/testing/graphqlMocks.ts index c55061831824..696ba7eac5b4 100644 --- a/packages/twenty-front/src/testing/graphqlMocks.ts +++ b/packages/twenty-front/src/testing/graphqlMocks.ts @@ -15,7 +15,7 @@ import { mockedClientConfig } from '~/testing/mock-data/config'; import { mockedObjectMetadataItemsQueryResult } from '~/testing/mock-data/metadata'; import { getPeopleMock } from '~/testing/mock-data/people'; import { mockedRemoteTables } from '~/testing/mock-data/remote-tables'; -import { mockedUsersData } from '~/testing/mock-data/users'; +import { mockedUserData } from '~/testing/mock-data/users'; import { mockedViewsData } from '~/testing/mock-data/views'; import { mockWorkspaceMembers } from '~/testing/mock-data/workspace-members'; @@ -35,7 +35,7 @@ export const graphqlMocks = { graphql.query(getOperationName(GET_CURRENT_USER) ?? '', () => { return HttpResponse.json({ data: { - currentUser: mockedUsersData[0], + currentUser: mockedUserData, }, }); }), @@ -110,6 +110,57 @@ export const graphqlMocks = { }, }); }), + graphql.query('CombinedFindManyRecords', () => { + return HttpResponse.json({ + data: { + views: { + edges: mockedViewsData.map((view) => ({ + node: { + ...view, + viewFilters: { + edges: [], + totalCount: 0, + }, + viewSorts: { + edges: [], + totalCount: 0, + }, + viewFields: { + edges: mockedViewFieldsData + .filter((viewField) => viewField.viewId === view.id) + .map((viewField) => ({ + node: viewField, + cursor: null, + })), + totalCount: mockedViewFieldsData.filter( + (viewField) => viewField.viewId === view.id, + ).length, + }, + }, + cursor: null, + })), + pageInfo: { + hasNextPage: false, + hasPreviousPage: false, + startCursor: null, + endCursor: null, + totalCount: mockedViewsData.length, + }, + totalCount: mockedViewsData.length, + }, + }, + favorites: { + edges: [], + totalCount: 0, + pageInfo: { + hasNextPage: false, + hasPreviousPage: false, + startCursor: null, + endCursor: null, + }, + }, + }); + }), graphql.query('FindManyCompanies', ({ variables }) => { const mockedData = variables.limit ? companiesMock.slice(0, variables.limit) @@ -157,43 +208,44 @@ export const graphqlMocks = { graphql.query('FindDuplicateCompany', () => { return HttpResponse.json({ data: { - companyDuplicates: { - edges: [ - { - node: { - ...duplicateCompanyMock, - favorites: { - edges: [], - __typename: 'FavoriteConnection', - }, - attachments: { - edges: [], - __typename: 'AttachmentConnection', - }, - people: { - edges: [], - __typename: 'PersonConnection', - }, - opportunities: { - edges: [], - __typename: 'OpportunityConnection', - }, - activityTargets: { - edges: [], - __typename: 'ActivityTargetConnection', + companyDuplicates: [ + { + edges: [ + { + node: { + ...duplicateCompanyMock, + favorites: { + edges: [], + __typename: 'FavoriteConnection', + }, + attachments: { + edges: [], + __typename: 'AttachmentConnection', + }, + people: { + edges: [], + __typename: 'PersonConnection', + }, + opportunities: { + edges: [], + __typename: 'OpportunityConnection', + }, + activityTargets: { + edges: [], + __typename: 'ActivityTargetConnection', + }, }, + cursor: null, }, - cursor: null, + ], + pageInfo: { + hasNextPage: false, + hasPreviousPage: false, + startCursor: null, + endCursor: null, }, - ], - pageInfo: { - hasNextPage: false, - hasPreviousPage: false, - startCursor: null, - endCursor: null, }, - totalCount: 1, - }, + ], }, }); }), diff --git a/packages/twenty-front/src/testing/mock-data/companies.ts b/packages/twenty-front/src/testing/mock-data/companies.ts index a2fc79b6f370..41e7751cc802 100644 --- a/packages/twenty-front/src/testing/mock-data/companies.ts +++ b/packages/twenty-front/src/testing/mock-data/companies.ts @@ -47,7 +47,9 @@ export const companiesQueryResult = { id: '20202020-3ec3-4fe3-8997-b76aa0bfa408', employees: 100, createdAt: '2024-06-05T09:00:20.412Z', + updatedAt: '2024-06-05T09:00:20.412Z', name: 'Linkedin', + accountOwnerId: null, accountOwner: null, domainName: 'linkedin.com', address: '', @@ -58,6 +60,16 @@ export const companiesQueryResult = { label: '', url: '', }, + xLink: { + __typename: 'Link', + label: '', + url: '', + }, + annualRecurringRevenue: { + __typename: 'Currency', + amountMicros: null, + currencyCode: '', + }, previousEmployees: { __typename: 'Person', id: '20202020-2d40-4e49-8df4-9c6a049191de', @@ -132,13 +144,25 @@ export const companiesQueryResult = { id: '20202020-5d81-46d6-bf83-f7fd33ea6102', employees: null, createdAt: '2024-06-05T09:00:20.412Z', + updatedAt: '2024-06-05T09:00:20.412Z', name: 'Facebook', idealCustomerProfile: false, accountOwner: null, + accountOwnerId: null, domainName: 'facebook.com', address: '', previousEmployees: null, + annualRecurringRevenue: { + __typename: 'Currency', + amountMicros: null, + currencyCode: '', + }, position: 2, + xLink: { + __typename: 'Link', + label: '', + url: '', + }, linkedinLink: { __typename: 'Link', label: '', @@ -154,13 +178,25 @@ export const companiesQueryResult = { id: '20202020-0713-40a5-8216-82802401d33e', employees: null, createdAt: '2024-06-05T09:00:20.412Z', + updatedAt: '2024-06-05T09:00:20.412Z', name: 'Qonto', idealCustomerProfile: false, accountOwner: null, + accountOwnerId: null, domainName: 'qonto.com', address: '', previousEmployees: null, + annualRecurringRevenue: { + __typename: 'Currency', + amountMicros: null, + currencyCode: '', + }, position: 3, + xLink: { + __typename: 'Link', + label: '', + url: '', + }, linkedinLink: { __typename: 'Link', label: '', @@ -176,13 +212,25 @@ export const companiesQueryResult = { id: '20202020-ed89-413a-b31a-962986e67bb4', employees: null, createdAt: '2024-06-05T09:00:20.412Z', + updatedAt: '2024-06-05T09:00:20.412Z', name: 'Microsoft', idealCustomerProfile: true, accountOwner: null, + accountOwnerId: null, domainName: 'microsoft.com', address: '', previousEmployees: null, + annualRecurringRevenue: { + __typename: 'Currency', + amountMicros: null, + currencyCode: '', + }, position: 4, + xLink: { + __typename: 'Link', + label: '', + url: '', + }, linkedinLink: { __typename: 'Link', label: '', @@ -198,13 +246,25 @@ export const companiesQueryResult = { id: '20202020-171e-4bcc-9cf7-43448d6fb278', employees: null, createdAt: '2024-06-05T09:00:20.412Z', + updatedAt: '2024-06-05T09:00:20.412Z', name: 'Airbnb', idealCustomerProfile: true, accountOwner: null, + accountOwnerId: null, domainName: 'airbnb.com', address: '', previousEmployees: null, + annualRecurringRevenue: { + __typename: 'Currency', + amountMicros: null, + currencyCode: '', + }, position: 5, + xLink: { + __typename: 'Link', + label: '', + url: '', + }, linkedinLink: { __typename: 'Link', label: '', @@ -220,13 +280,25 @@ export const companiesQueryResult = { id: '20202020-c21e-4ec2-873b-de4264d89025', employees: null, createdAt: '2024-06-05T09:00:20.412Z', + updatedAt: '2024-06-05T09:00:20.412Z', name: 'Google', idealCustomerProfile: false, accountOwner: null, + accountOwnerId: null, domainName: 'google.com', address: '', previousEmployees: null, + annualRecurringRevenue: { + __typename: 'Currency', + amountMicros: null, + currencyCode: '', + }, position: 6, + xLink: { + __typename: 'Link', + label: '', + url: '', + }, linkedinLink: { __typename: 'Link', label: '', @@ -242,13 +314,25 @@ export const companiesQueryResult = { id: '20202020-707e-44dc-a1d2-30030bf1a944', employees: null, createdAt: '2024-06-05T09:00:20.412Z', + updatedAt: '2024-06-05T09:00:20.412Z', name: 'Netflix', idealCustomerProfile: true, accountOwner: null, + accountOwnerId: null, domainName: 'netflix.com', address: '', previousEmployees: null, + annualRecurringRevenue: { + __typename: 'Currency', + amountMicros: null, + currencyCode: '', + }, position: 7, + xLink: { + __typename: 'Link', + label: '', + url: '', + }, linkedinLink: { __typename: 'Link', label: '', @@ -264,13 +348,25 @@ export const companiesQueryResult = { id: '20202020-3f74-492d-a101-2a70f50a1645', employees: null, createdAt: '2024-06-05T09:00:20.412Z', + updatedAt: '2024-06-05T09:00:20.412Z', name: 'Libeo', idealCustomerProfile: false, accountOwner: null, + accountOwnerId: null, domainName: 'libeo.io', address: '', previousEmployees: null, + annualRecurringRevenue: { + __typename: 'Currency', + amountMicros: null, + currencyCode: '', + }, position: 8, + xLink: { + __typename: 'Link', + label: '', + url: '', + }, linkedinLink: { __typename: 'Link', label: '', @@ -286,13 +382,25 @@ export const companiesQueryResult = { id: '20202020-cfbf-4156-a790-e39854dcd4eb', employees: null, createdAt: '2024-06-05T09:00:20.412Z', + updatedAt: '2024-06-05T09:00:20.412Z', name: 'Claap', idealCustomerProfile: false, accountOwner: null, + accountOwnerId: null, domainName: 'claap.io', address: '', previousEmployees: null, + annualRecurringRevenue: { + __typename: 'Currency', + amountMicros: null, + currencyCode: '', + }, position: 9, + xLink: { + __typename: 'Link', + label: '', + url: '', + }, linkedinLink: { __typename: 'Link', label: '', @@ -308,13 +416,25 @@ export const companiesQueryResult = { id: '20202020-f86b-419f-b794-02319abe8637', employees: null, createdAt: '2024-06-05T09:00:20.412Z', + updatedAt: '2024-06-05T09:00:20.412Z', name: 'Hasura', idealCustomerProfile: false, accountOwner: null, + accountOwnerId: null, domainName: 'hasura.io', address: '', previousEmployees: null, + annualRecurringRevenue: { + __typename: 'Currency', + amountMicros: null, + currencyCode: '', + }, position: 10, + xLink: { + __typename: 'Link', + label: '', + url: '', + }, linkedinLink: { __typename: 'Link', label: '', @@ -330,13 +450,25 @@ export const companiesQueryResult = { id: '20202020-5518-4553-9433-42d8eb82834b', employees: null, createdAt: '2024-06-05T09:00:20.412Z', + updatedAt: '2024-06-05T09:00:20.412Z', name: 'Wework', idealCustomerProfile: false, accountOwner: null, + accountOwnerId: null, domainName: 'wework.com', address: '', previousEmployees: null, + annualRecurringRevenue: { + __typename: 'Currency', + amountMicros: null, + currencyCode: '', + }, position: 11, + xLink: { + __typename: 'Link', + label: '', + url: '', + }, linkedinLink: { __typename: 'Link', label: '', @@ -352,13 +484,25 @@ export const companiesQueryResult = { id: '20202020-f79e-40dd-bd06-c36e6abb4678', employees: null, createdAt: '2024-06-05T09:00:20.412Z', + updatedAt: '2024-06-05T09:00:20.412Z', name: 'Samsung', idealCustomerProfile: false, accountOwner: null, + accountOwnerId: null, domainName: 'samsung.com', address: '', previousEmployees: null, + annualRecurringRevenue: { + __typename: 'Currency', + amountMicros: null, + currencyCode: '', + }, position: 12, + xLink: { + __typename: 'Link', + label: '', + url: '', + }, linkedinLink: { __typename: 'Link', label: '', @@ -374,13 +518,25 @@ export const companiesQueryResult = { id: '20202020-1455-4c57-afaf-dd5dc086361d', employees: null, createdAt: '2024-06-05T09:00:20.412Z', + updatedAt: '2024-06-05T09:00:20.412Z', name: 'Algolia', idealCustomerProfile: false, accountOwner: null, + accountOwnerId: null, domainName: 'algolia.com', address: '', previousEmployees: null, + annualRecurringRevenue: { + __typename: 'Currency', + amountMicros: null, + currencyCode: '', + }, position: 13, + xLink: { + __typename: 'Link', + label: '', + url: '', + }, linkedinLink: { __typename: 'Link', label: '', diff --git a/packages/twenty-front/src/testing/mock-data/config.ts b/packages/twenty-front/src/testing/mock-data/config.ts index b3eb74af804c..a14ea35bf85e 100644 --- a/packages/twenty-front/src/testing/mock-data/config.ts +++ b/packages/twenty-front/src/testing/mock-data/config.ts @@ -34,8 +34,9 @@ export const mockedClientConfig: ClientConfig = { __typename: 'Billing', }, captcha: { - provider: CaptchaDriverType.GoogleRecatpcha, + provider: CaptchaDriverType.GoogleRecaptcha, siteKey: 'MOCKED_SITE_KEY', __typename: 'Captcha', }, + api: { mutationMaximumAffectedRecords: 100 }, }; diff --git a/packages/twenty-front/src/testing/mock-data/generated/standard-metadata-query-result.ts b/packages/twenty-front/src/testing/mock-data/generated/standard-metadata-query-result.ts index c31eaaa65788..b537a84c2b0d 100644 --- a/packages/twenty-front/src/testing/mock-data/generated/standard-metadata-query-result.ts +++ b/packages/twenty-front/src/testing/mock-data/generated/standard-metadata-query-result.ts @@ -1,10 +1,6 @@ -import { CurrencyCode } from '@/object-record/record-field/types/CurrencyCode'; import { - FieldMetadataType, - ObjectEdge, - ObjectMetadataItemsQuery, + ObjectMetadataItemsQuery } from '~/generated-metadata/graphql'; -import { CalendarChannelVisibility, MessageChannelVisibility } from "~/generated/graphql"; // This file is not designed to be manually edited. // It's an extract from the dev seeded environment metadata call @@ -2229,6 +2225,60 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery = "toRelationMetadata": null } }, + { + "__typename": "fieldEdge", + "node": { + "__typename": "field", + "id": "3715c0ac-c16f-4db3-b9be-e908b787929e", + "type": "RATING", + "name": "testRating", + "label": "Test rating", + "description": null, + "icon": "IconUsers", + "isCustom": true, + "isActive": true, + "isSystem": false, + "isNullable": true, + "createdAt": "2024-06-17T13:03:52.175Z", + "updatedAt": "2024-06-17T13:03:52.175Z", + "defaultValue": null, + "options": [ + { + "id": "9876aaeb-91ac-4e02-b521-356ff0c0a6f9", + "label": "1", + "value": "RATING_1", + "position": 0 + }, + { + "id": "4651d042-0804-465b-8265-5fae554de3a8", + "label": "2", + "value": "RATING_2", + "position": 1 + }, + { + "id": "a6942bdd-a8c8-44f9-87fc-b9a7f64ee5dd", + "label": "3", + "value": "RATING_3", + "position": 2 + }, + { + "id": "a838666f-cd2f-4feb-a72f-d3447b23ad42", + "label": "4", + "value": "RATING_4", + "position": 3 + }, + { + "id": "428f765e-4792-4cea-8270-9dba60f45fd9", + "label": "5", + "value": "RATING_5", + "position": 4 + } + ], + "relationDefinition": null, + "fromRelationMetadata": null, + "toRelationMetadata": null + } + }, { "__typename": "fieldEdge", "node": { @@ -5517,29 +5567,6 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery = "toRelationMetadata": null } }, - { - "__typename": "fieldEdge", - "node": { - "__typename": "field", - "id": "dd99cf8d-a10c-4d41-8469-6b5e03e5ae2e", - "type": "TEXT", - "name": "probability", - "label": "Probability", - "description": "Opportunity probability", - "icon": "IconProgressCheck", - "isCustom": false, - "isActive": true, - "isSystem": false, - "isNullable": false, - "createdAt": "2024-06-07T09:05:12.599Z", - "updatedAt": "2024-06-07T09:05:12.599Z", - "defaultValue": "'0'", - "options": null, - "relationDefinition": null, - "fromRelationMetadata": null, - "toRelationMetadata": null - } - }, { "__typename": "fieldEdge", "node": { diff --git a/packages/twenty-front/src/testing/mock-data/metadata.ts b/packages/twenty-front/src/testing/mock-data/metadata.ts index 94b5f910c24c..d6ec68da1d70 100644 --- a/packages/twenty-front/src/testing/mock-data/metadata.ts +++ b/packages/twenty-front/src/testing/mock-data/metadata.ts @@ -7,6 +7,7 @@ import { } from '~/generated-metadata/graphql'; import { mockedStandardObjectMetadataQueryResult } from '~/testing/mock-data/generated/standard-metadata-query-result'; +// TODO: replace with new mock const customObjectMetadataItemEdge: ObjectEdge = { __typename: 'objectEdge', node: { diff --git a/packages/twenty-front/src/testing/mock-data/people.ts b/packages/twenty-front/src/testing/mock-data/people.ts index e0aaa78486c3..89bff03b013e 100644 --- a/packages/twenty-front/src/testing/mock-data/people.ts +++ b/packages/twenty-front/src/testing/mock-data/people.ts @@ -1,3 +1,5 @@ +import { RecordGqlConnection } from '@/object-record/graphql/types/RecordGqlConnection'; + export const getPeopleMock = () => { const peopleMock = peopleQueryResult.people.edges.map((edge) => edge.node); @@ -22,7 +24,7 @@ export const mockedEmptyPersonData = { __typename: 'Person', }; -export const peopleQueryResult = { +export const peopleQueryResult: { people: RecordGqlConnection } = { people: { __typename: 'PersonConnection', totalCount: 15, diff --git a/packages/twenty-front/src/testing/mock-data/remote-servers.ts b/packages/twenty-front/src/testing/mock-data/remote-servers.ts index fee3c13cae5b..12948b099210 100644 --- a/packages/twenty-front/src/testing/mock-data/remote-servers.ts +++ b/packages/twenty-front/src/testing/mock-data/remote-servers.ts @@ -16,6 +16,7 @@ export const mockedRemoteServers = [ }, updatedAt: '2024-04-30T13:41:25.858Z', schema: 'public', + label: 'postgres DB', }, { __typename: 'RemoteServer', @@ -27,5 +28,6 @@ export const mockedRemoteServers = [ }, foreignDataWrapperType: 'stripe_fdw', updatedAt: '2024-04-30T13:41:25.858Z', + label: 'stripe DB', }, ]; diff --git a/packages/twenty-front/src/testing/mock-data/users.ts b/packages/twenty-front/src/testing/mock-data/users.ts index 92630930a647..d8067e6cca62 100644 --- a/packages/twenty-front/src/testing/mock-data/users.ts +++ b/packages/twenty-front/src/testing/mock-data/users.ts @@ -1,5 +1,11 @@ import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember'; -import { User, Workspace } from '~/generated/graphql'; +import { + OnboardingStatus, + SubscriptionInterval, + SubscriptionStatus, + User, + Workspace, +} from '~/generated/graphql'; type MockedUser = Pick< User, @@ -10,7 +16,7 @@ type MockedUser = Pick< | 'canImpersonate' | '__typename' | 'supportUserHash' - | 'onboardingStep' + | 'onboardingStatus' > & { workspaceMember: WorkspaceMember | null; locale: string; @@ -30,7 +36,6 @@ export const mockDefaultWorkspace: Workspace = { inviteHash: 'twenty.com-invite-hash', logo: workspaceLogoUrl, allowImpersonation: true, - subscriptionStatus: 'active', activationStatus: 'active', featureFlags: [ { @@ -58,9 +63,10 @@ export const mockDefaultWorkspace: Workspace = { currentBillingSubscription: { __typename: 'BillingSubscription', id: '7efbc3f7-6e5e-4128-957e-8d86808cdf6a', - interval: 'month', - status: 'active', + interval: SubscriptionInterval.Month, + status: SubscriptionStatus.Active, }, + workspaceMembersCount: 1, }; export const mockedWorkspaceMemberData: WorkspaceMember = { @@ -79,49 +85,26 @@ export const mockedWorkspaceMemberData: WorkspaceMember = { userEmail: 'charles@test.com', }; -export const mockedUsersData: Array<MockedUser> = [ - { - id: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6d', - __typename: 'User', - email: 'charles@test.com', - firstName: 'Charles', - lastName: 'Test', - canImpersonate: false, - supportUserHash: - 'a95afad9ff6f0b364e2a3fd3e246a1a852c22b6e55a3ca33745a86c201f9c10d', - workspaceMember: mockedWorkspaceMemberData, - defaultWorkspace: mockDefaultWorkspace, - locale: 'en', - workspaces: [{ workspace: mockDefaultWorkspace }], - onboardingStep: null, - }, - { - id: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6c', - __typename: 'User', - email: 'felix@test.com', - firstName: 'Felix', - lastName: 'Test', - canImpersonate: false, - supportUserHash: - '54ac3986035961724cdb9a7a30c70e6463a4b68f0ecd2014c727171a82144b74', - workspaceMember: { - ...mockedWorkspaceMemberData, - id: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6c', - name: { - firstName: 'Felix', - lastName: 'Test', - }, - userId: '81aeb270-d689-4515-bd5d-35dbe956da3b', - }, - defaultWorkspace: mockDefaultWorkspace, - locale: 'en', - workspaces: [{ workspace: mockDefaultWorkspace }], - onboardingStep: null, - }, -]; +export const mockedUserData: MockedUser = { + id: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6d', + __typename: 'User', + email: 'charles@test.com', + firstName: 'Charles', + lastName: 'Test', + canImpersonate: false, + supportUserHash: + 'a95afad9ff6f0b364e2a3fd3e246a1a852c22b6e55a3ca33745a86c201f9c10d', + workspaceMember: mockedWorkspaceMemberData, + defaultWorkspace: mockDefaultWorkspace, + locale: 'en', + workspaces: [{ workspace: mockDefaultWorkspace }], + onboardingStatus: OnboardingStatus.Completed, +}; -export const mockedOnboardingUsersData: Array<MockedUser> = [ - { +export const mockedOnboardingUserData = ( + onboardingStatus?: OnboardingStatus, +) => { + return { id: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6d', __typename: 'User', email: 'workspace-onboarding@test.com', @@ -130,35 +113,10 @@ export const mockedOnboardingUsersData: Array<MockedUser> = [ canImpersonate: false, supportUserHash: '4fb61d34ed3a4aeda2476d4b308b5162db9e1809b2b8277e6fdc6efc4a609254', - workspaceMember: { - ...mockedWorkspaceMemberData, - id: 'd454f075-c72f-4ebe-bac7-d28e75e74a23', - name: { - firstName: '', - lastName: '', - }, - - userId: '7f793378-b939-43b7-8642-292c9510754c', - }, - defaultWorkspace: mockDefaultWorkspace, - locale: 'en', - workspaces: [{ workspace: mockDefaultWorkspace }], - onboardingStep: null, - }, - { - id: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6d', - __typename: 'User', - email: 'profile-onboarding@test.com', - firstName: '', - lastName: '', - canImpersonate: false, workspaceMember: null, - defaultWorkspace: { - ...mockDefaultWorkspace, - activationStatus: 'inactive', - }, + defaultWorkspace: mockDefaultWorkspace, locale: 'en', workspaces: [{ workspace: mockDefaultWorkspace }], - onboardingStep: null, - }, -]; + onboardingStatus: onboardingStatus || null, + }; +}; diff --git a/packages/twenty-front/src/testing/mock-data/view-fields.ts b/packages/twenty-front/src/testing/mock-data/view-fields.ts index c644510c90f5..f8af8db65787 100644 --- a/packages/twenty-front/src/testing/mock-data/view-fields.ts +++ b/packages/twenty-front/src/testing/mock-data/view-fields.ts @@ -9,6 +9,9 @@ export const mockedViewFieldsData = [ position: 0, isVisible: true, size: 180, + createdAt: '2021-09-01T00:00:00.000Z', + updatedAt: '2021-09-01T00:00:00.000Z', + __typename: 'ViewField', }, { id: '2a96bbc8-d86d-439a-8e50-4b07ebd27750', @@ -17,6 +20,9 @@ export const mockedViewFieldsData = [ position: 1, isVisible: true, size: 100, + createdAt: '2021-09-01T00:00:00.000Z', + updatedAt: '2021-09-01T00:00:00.000Z', + __typename: 'ViewField', }, { id: '0c1b4c7b-6a3d-4fb0-bf2b-5d7c8fb844ed', @@ -25,6 +31,9 @@ export const mockedViewFieldsData = [ position: 2, isVisible: true, size: 150, + createdAt: '2021-09-01T00:00:00.000Z', + updatedAt: '2021-09-01T00:00:00.000Z', + __typename: 'ViewField', }, { id: 'cc7f9560-32b5-4b82-8fd9-b05fe77c8cf7', @@ -33,6 +42,9 @@ export const mockedViewFieldsData = [ position: 3, isVisible: true, size: 150, + createdAt: '2021-09-01T00:00:00.000Z', + updatedAt: '2021-09-01T00:00:00.000Z', + __typename: 'ViewField', }, { id: '3de4d078-3396-4480-be2d-6f3b1a228b0d', @@ -41,6 +53,9 @@ export const mockedViewFieldsData = [ position: 4, isVisible: true, size: 150, + createdAt: '2021-09-01T00:00:00.000Z', + updatedAt: '2021-09-01T00:00:00.000Z', + __typename: 'ViewField', }, { id: '4650c8fb-0f1e-4342-88dc-adedae1445f9', @@ -49,6 +64,9 @@ export const mockedViewFieldsData = [ position: 5, isVisible: true, size: 170, + createdAt: '2021-09-01T00:00:00.000Z', + updatedAt: '2021-09-01T00:00:00.000Z', + __typename: 'ViewField', }, { id: '727430bf-6ff8-4c85-9828-cbe72ac0fc27', @@ -57,6 +75,9 @@ export const mockedViewFieldsData = [ position: 6, isVisible: true, size: 170, + createdAt: '2021-09-01T00:00:00.000Z', + updatedAt: '2021-09-01T00:00:00.000Z', + __typename: 'ViewField', }, // People @@ -67,6 +88,9 @@ export const mockedViewFieldsData = [ position: 0, isVisible: true, size: 210, + createdAt: '2021-09-01T00:00:00.000Z', + updatedAt: '2021-09-01T00:00:00.000Z', + __typename: 'ViewField', }, { id: 'e1e24864-8601-4cd8-8a63-09c1285f2e39', @@ -75,6 +99,9 @@ export const mockedViewFieldsData = [ position: 1, isVisible: true, size: 150, + createdAt: '2021-09-01T00:00:00.000Z', + updatedAt: '2021-09-01T00:00:00.000Z', + __typename: 'ViewField', }, { id: '5a1df716-7211-445a-9f16-9783a00998a7', @@ -83,6 +110,9 @@ export const mockedViewFieldsData = [ position: 2, isVisible: true, size: 150, + createdAt: '2021-09-01T00:00:00.000Z', + updatedAt: '2021-09-01T00:00:00.000Z', + __typename: 'ViewField', }, { id: 'a6e1197a-7e84-4d92-ace2-367c0bc46c49', @@ -91,6 +121,9 @@ export const mockedViewFieldsData = [ position: 3, isVisible: true, size: 150, + createdAt: '2021-09-01T00:00:00.000Z', + updatedAt: '2021-09-01T00:00:00.000Z', + __typename: 'ViewField', }, { id: 'c9343097-d14b-4559-a5fa-626c1527d39f', @@ -99,6 +132,9 @@ export const mockedViewFieldsData = [ position: 4, isVisible: true, size: 150, + createdAt: '2021-09-01T00:00:00.000Z', + updatedAt: '2021-09-01T00:00:00.000Z', + __typename: 'ViewField', }, { id: 'a873e5f0-fed6-47e9-a712-6854eab3ec77', @@ -107,6 +143,9 @@ export const mockedViewFieldsData = [ position: 5, isVisible: true, size: 150, + createdAt: '2021-09-01T00:00:00.000Z', + updatedAt: '2021-09-01T00:00:00.000Z', + __typename: 'ViewField', }, { id: '66f134b8-5329-422f-b88e-83e6bb707eb5', @@ -115,6 +154,9 @@ export const mockedViewFieldsData = [ position: 6, isVisible: true, size: 150, + createdAt: '2021-09-01T00:00:00.000Z', + updatedAt: '2021-09-01T00:00:00.000Z', + __typename: 'ViewField', }, { id: '648faa24-cabb-482a-8578-ba3f09906017', @@ -123,6 +165,9 @@ export const mockedViewFieldsData = [ position: 7, isVisible: true, size: 150, + createdAt: '2021-09-01T00:00:00.000Z', + updatedAt: '2021-09-01T00:00:00.000Z', + __typename: 'ViewField', }, { id: '3a9e7f0d-a4ce-4ad5-aac7-3a24eb1a412d', @@ -131,6 +176,9 @@ export const mockedViewFieldsData = [ position: 8, isVisible: true, size: 150, + createdAt: '2021-09-01T00:00:00.000Z', + updatedAt: '2021-09-01T00:00:00.000Z', + __typename: 'ViewField', }, // Opportunities @@ -141,14 +189,9 @@ export const mockedViewFieldsData = [ position: 0, isVisible: true, size: 180, - }, - { - id: 'e5a731bb-82b9-4abe-ad22-1ddea94722f9', - fieldMetadataId: 'probability', - viewId: mockedViewsData[2].id, - position: 1, - isVisible: true, - size: 150, + createdAt: '2021-09-01T00:00:00.000Z', + updatedAt: '2021-09-01T00:00:00.000Z', + __typename: 'ViewField', }, { id: '3159acd8-463f-458d-bf9a-af8ac6f57dc0', @@ -157,6 +200,9 @@ export const mockedViewFieldsData = [ position: 2, isVisible: true, size: 100, + createdAt: '2021-09-01T00:00:00.000Z', + updatedAt: '2021-09-01T00:00:00.000Z', + __typename: 'ViewField', }, { id: 'afc0819d-b694-4e3c-a2e6-25261aa3ed2c', @@ -165,6 +211,9 @@ export const mockedViewFieldsData = [ position: 3, isVisible: true, size: 150, + createdAt: '2021-09-01T00:00:00.000Z', + updatedAt: '2021-09-01T00:00:00.000Z', + __typename: 'ViewField', }, { id: 'ec0507bb-aedc-4695-ba96-d81bdeb9db83', @@ -173,6 +222,9 @@ export const mockedViewFieldsData = [ position: 4, isVisible: true, size: 150, + createdAt: '2021-09-01T00:00:00.000Z', + updatedAt: '2021-09-01T00:00:00.000Z', + __typename: 'ViewField', }, { id: '3f1585f6-44f6-45c5-b840-bc05af5d0008', @@ -181,5 +233,8 @@ export const mockedViewFieldsData = [ position: 5, isVisible: true, size: 150, + createdAt: '2021-09-01T00:00:00.000Z', + updatedAt: '2021-09-01T00:00:00.000Z', + __typename: 'ViewField', }, ]; diff --git a/packages/twenty-front/src/testing/mock-data/views.ts b/packages/twenty-front/src/testing/mock-data/views.ts index c58e50846ec1..555e0a7c5d28 100644 --- a/packages/twenty-front/src/testing/mock-data/views.ts +++ b/packages/twenty-front/src/testing/mock-data/views.ts @@ -2,25 +2,58 @@ export const mockedViewsData = [ { id: '37a8a866-eb17-4e76-9382-03143a2f6a80', name: 'All companies', - objectMetadataId: 'company', + objectMetadataId: 'f9fd99a8-108f-4066-9675-cde753cf5de9', type: 'table', + icon: 'IconSkyline', + key: 'INDEX', + kanbanFieldMetadataId: null, + position: 0, + createdAt: '2021-09-01T00:00:00.000Z', + updatedAt: '2021-09-01T00:00:00.000Z', + isCompact: false, + + __typename: 'View', }, { id: '6095799e-b48f-4e00-b071-10818083593a', name: 'All people', objectMetadataId: 'person', type: 'table', + icon: 'IconPerson', + key: 'INDEX', + kanbanFieldMetadataId: null, + position: 0, + createdAt: '2021-09-01T00:00:00.000Z', + updatedAt: '2021-09-01T00:00:00.000Z', + isCompact: false, + __typename: 'View', }, { id: 'e26f66b7-f890-4a5c-b4d2-ec09987b5308', name: 'All opportunities', objectMetadataId: 'company', type: 'kanban', + icon: 'IconOpportunity', + key: 'INDEX', + kanbanFieldMetadataId: null, + position: 0, + createdAt: '2021-09-01T00:00:00.000Z', + updatedAt: '2021-09-01T00:00:00.000Z', + isCompact: false, + __typename: 'View', }, { id: '5c307222-1dd5-4ff3-ab06-8d990e9b3c74', name: 'All companies (v2)', - objectMetadataId: 'a3195559-cc20-4749-9565-572a2f506581', + objectMetadataId: 'f9fd99a8-108f-4066-9675-cde753cf5de9', type: 'table', + icon: 'IconSkyline', + key: 'INDEX', + kanbanFieldMetadataId: null, + position: 0, + createdAt: '2021-09-01T00:00:00.000Z', + updatedAt: '2021-09-01T00:00:00.000Z', + isCompact: false, + __typename: 'View', }, ]; diff --git a/packages/twenty-front/src/types/WithNarrowedStringLiteralProperty.ts b/packages/twenty-front/src/types/WithNarrowedStringLiteralProperty.ts new file mode 100644 index 000000000000..7e0ff52b4062 --- /dev/null +++ b/packages/twenty-front/src/types/WithNarrowedStringLiteralProperty.ts @@ -0,0 +1,7 @@ +export type WithNarrowedStringLiteralProperty< + T, + K extends keyof T, + Sub extends T[K], +> = Omit<T, K> & { + [P in K]: Extract<T[K], Sub>; +}; diff --git a/packages/twenty-front/src/utils/array/generateILikeFiltersForCompositeFields.ts b/packages/twenty-front/src/utils/array/generateILikeFiltersForCompositeFields.ts index 4d92976934b1..a5a2883e74e7 100644 --- a/packages/twenty-front/src/utils/array/generateILikeFiltersForCompositeFields.ts +++ b/packages/twenty-front/src/utils/array/generateILikeFiltersForCompositeFields.ts @@ -4,7 +4,31 @@ export const generateILikeFiltersForCompositeFields = ( filterString: string, baseFieldName: string, subFields: string[], + emptyCheck = false, ) => { + if (emptyCheck) { + return subFields.map((subField) => { + return { + or: [ + { + [baseFieldName]: { + [subField]: { + is: 'NULL', + }, + }, + }, + { + [baseFieldName]: { + [subField]: { + ilike: '', + }, + }, + }, + ], + }; + }); + } + return filterString .split(' ') .reduce((previousValue: RecordGqlOperationFilter[], currentValue) => { diff --git a/packages/twenty-front/src/utils/createApolloStoreFieldName.ts b/packages/twenty-front/src/utils/createApolloStoreFieldName.ts new file mode 100644 index 000000000000..7959a7f2a938 --- /dev/null +++ b/packages/twenty-front/src/utils/createApolloStoreFieldName.ts @@ -0,0 +1,9 @@ +export const createApolloStoreFieldName = ({ + fieldName, + fieldVariables, +}: { + fieldName: string; + fieldVariables: Record<string, any>; +}) => { + return `${fieldName}(${JSON.stringify(fieldVariables)})`; +}; diff --git a/packages/twenty-front/src/utils/createEventContext.ts b/packages/twenty-front/src/utils/createEventContext.ts new file mode 100644 index 000000000000..c69425003def --- /dev/null +++ b/packages/twenty-front/src/utils/createEventContext.ts @@ -0,0 +1,12 @@ +import { Context, createContext } from 'react'; + +type ObjectOfFunctions = { + [key: string]: (...args: any[]) => void; +}; + +export type EventContext<T extends ObjectOfFunctions> = + T extends ObjectOfFunctions ? T : never; + +export const createEventContext = <T extends ObjectOfFunctions>(): Context< + EventContext<T> +> => createContext<EventContext<T>>({} as EventContext<T>); diff --git a/packages/twenty-front/src/utils/format/__tests__/formatDate.test.ts b/packages/twenty-front/src/utils/format/__tests__/formatDate.test.ts index a80c11d3e7f5..60431e17b267 100644 --- a/packages/twenty-front/src/utils/format/__tests__/formatDate.test.ts +++ b/packages/twenty-front/src/utils/format/__tests__/formatDate.test.ts @@ -24,6 +24,7 @@ describe('formatToHumanReadableTime', () => { it('should format the date to a human-readable time', () => { const date = new Date('2022-01-01T12:30:00'); const result = formatToHumanReadableTime(date); - expect(result).toBe('12:30 PM'); + // it seems when running locally on MacOS the space is not the same + expect(['12:30 PM', '12:30 PM']).toContain(result); }); }); diff --git a/packages/twenty-front/src/utils/image/__tests__/getImageAbsoluteURIOrBase64.test.ts b/packages/twenty-front/src/utils/image/__tests__/getImageAbsoluteURIOrBase64.test.ts new file mode 100644 index 000000000000..226aa6a0e598 --- /dev/null +++ b/packages/twenty-front/src/utils/image/__tests__/getImageAbsoluteURIOrBase64.test.ts @@ -0,0 +1,27 @@ +import { getImageAbsoluteURIOrBase64 } from '../getImageAbsoluteURIOrBase64'; + +describe('getImageAbsoluteURIOrBase64', () => { + it('should return null if imageUrl is null', () => { + const imageUrl = null; + const result = getImageAbsoluteURIOrBase64(imageUrl); + expect(result).toBeNull(); + }); + + it('should return base64 encoded string if prefixed with data', () => { + const imageUrl = 'data:XXX'; + const result = getImageAbsoluteURIOrBase64(imageUrl); + expect(result).toBe(imageUrl); + }); + + it('should return absolute url if the imageUrl is an absolute url', () => { + const imageUrl = 'https://XXX'; + const result = getImageAbsoluteURIOrBase64(imageUrl); + expect(result).toBe(imageUrl); + }); + + it('should return fully formed url if imageUrl is a relative url', () => { + const imageUrl = 'XXX'; + const result = getImageAbsoluteURIOrBase64(imageUrl); + expect(result).toBe('http://localhost:3000/files/XXX'); + }); +}); diff --git a/packages/twenty-front/src/utils/isDeeplyEqual.ts b/packages/twenty-front/src/utils/isDeeplyEqual.ts index 1a887595abc0..62f10026352b 100644 --- a/packages/twenty-front/src/utils/isDeeplyEqual.ts +++ b/packages/twenty-front/src/utils/isDeeplyEqual.ts @@ -1,3 +1,4 @@ import deepEqual from 'deep-equal'; -export const isDeeplyEqual = <T>(a: T, b: T) => deepEqual(a, b); +export const isDeeplyEqual = <T>(a: T, b: T, options?: { strict: boolean }) => + deepEqual(a, b, options); diff --git a/packages/twenty-front/src/utils/recoil-effects.ts b/packages/twenty-front/src/utils/recoil-effects.ts index d7c0261b955f..7f20e24c5062 100644 --- a/packages/twenty-front/src/utils/recoil-effects.ts +++ b/packages/twenty-front/src/utils/recoil-effects.ts @@ -5,17 +5,17 @@ import { cookieStorage } from '~/utils/cookie-storage'; import { isDefined } from './isDefined'; export const localStorageEffect = - <T>(key: string): AtomEffect<T> => - ({ setSelf, onSet }) => { - const savedValue = localStorage.getItem(key); + <T>(key?: string): AtomEffect<T> => + ({ setSelf, onSet, node }) => { + const savedValue = localStorage.getItem(key ?? node.key); if (savedValue != null) { setSelf(JSON.parse(savedValue)); } onSet((newValue, _, isReset) => { isReset - ? localStorage.removeItem(key) - : localStorage.setItem(key, JSON.stringify(newValue)); + ? localStorage.removeItem(key ?? node.key) + : localStorage.setItem(key ?? node.key, JSON.stringify(newValue)); }); }; diff --git a/packages/twenty-front/src/utils/validation-schemas/__tests__/absoluteUrlSchema.test.ts b/packages/twenty-front/src/utils/validation-schemas/__tests__/absoluteUrlSchema.test.ts index d20f3bcf6393..ffb83cfc8ef5 100644 --- a/packages/twenty-front/src/utils/validation-schemas/__tests__/absoluteUrlSchema.test.ts +++ b/packages/twenty-front/src/utils/validation-schemas/__tests__/absoluteUrlSchema.test.ts @@ -28,7 +28,6 @@ describe('absoluteUrlSchema', () => { it('fails for invalid urls', () => { expect(absoluteUrlSchema.safeParse('?o').success).toBe(false); - expect(absoluteUrlSchema.safeParse('').success).toBe(false); expect(absoluteUrlSchema.safeParse('\\').success).toBe(false); }); }); diff --git a/packages/twenty-front/src/utils/validation-schemas/absoluteUrlSchema.ts b/packages/twenty-front/src/utils/validation-schemas/absoluteUrlSchema.ts index e0c376c7403f..a0deb4bfab25 100644 --- a/packages/twenty-front/src/utils/validation-schemas/absoluteUrlSchema.ts +++ b/packages/twenty-front/src/utils/validation-schemas/absoluteUrlSchema.ts @@ -8,4 +8,5 @@ export const absoluteUrlSchema = z .string() .transform((value) => `https://${value}`) .pipe(z.string().url()), - ); + ) + .or(z.literal('')); diff --git a/packages/twenty-front/vite.config.ts b/packages/twenty-front/vite.config.ts index 34055bdb14ba..705c2dcc51f5 100644 --- a/packages/twenty-front/vite.config.ts +++ b/packages/twenty-front/vite.config.ts @@ -63,6 +63,15 @@ export default defineConfig(({ command, mode }) => { '**/Chip.tsx', '**/Tag.tsx', '**/MultiSelectFieldDisplay.tsx', + '**/RatingInput.tsx', + '**/RecordTableCellContainer.tsx', + '**/RecordTableCellDisplayContainer.tsx', + '**/Avatar.tsx', + '**/RecordTableBodyDroppable.tsx', + '**/RecordTableCellBaseContainer.tsx', + '**/RecordTableCellTd.tsx', + '**/RecordTableTd.tsx', + '**/RecordTableHeaderDragDropColumn.tsx', ], babelOptions: { presets: ['@babel/preset-typescript', '@babel/preset-react'], diff --git a/packages/twenty-postgres/linux/Dockerfile b/packages/twenty-postgres/linux/Dockerfile index c8996796c3c7..871f87dff40c 100644 --- a/packages/twenty-postgres/linux/Dockerfile +++ b/packages/twenty-postgres/linux/Dockerfile @@ -3,7 +3,7 @@ ARG IMAGE_TAG='15.5.0-debian-11-r15' FROM bitnami/postgresql:${IMAGE_TAG} ARG PG_MAIN_VERSION=15 -ARG PG_GRAPHQL_VERSION=1.5.1 +ARG PG_GRAPHQL_VERSION=1.5.6 ARG WRAPPERS_VERSION=0.2.0 ARG TARGETARCH diff --git a/packages/twenty-postgres/linux/amd64/15/pg_graphql/1.5.6/pg_graphql--1.5.6.sql b/packages/twenty-postgres/linux/amd64/15/pg_graphql/1.5.6/pg_graphql--1.5.6.sql new file mode 100644 index 000000000000..b5489e7cd65c --- /dev/null +++ b/packages/twenty-postgres/linux/amd64/15/pg_graphql/1.5.6/pg_graphql--1.5.6.sql @@ -0,0 +1,116 @@ +/* +This file is auto generated by pgrx. + +The ordering of items is not stable, it is driven by a dependency graph. +*/ + +-- src/lib.rs:27 +-- pg_graphql::_internal_resolve +CREATE FUNCTION graphql."_internal_resolve"( + "query" TEXT, /* &str */ + "variables" jsonb DEFAULT '{}', /* core::option::Option<pgrx::datum::json::JsonB> */ + "operationName" TEXT DEFAULT null, /* core::option::Option<alloc::string::String> */ + "extensions" jsonb DEFAULT null /* core::option::Option<pgrx::datum::json::JsonB> */ +) RETURNS jsonb /* pgrx::datum::json::JsonB */ + +LANGUAGE c /* Rust */ +AS 'MODULE_PATHNAME', 'resolve_wrapper'; + +-- src/lib.rs:22 +create or replace function graphql.exception(message text) + returns text + language plpgsql +as $$ +begin + raise exception using errcode='22000', message=message; +end; +$$; + + +-- src/lib.rs:23 +-- requires: +-- resolve + +create or replace function graphql.resolve( + "query" text, + "variables" jsonb default '{}', + "operationName" text default null, + "extensions" jsonb default null +) + returns jsonb + language plpgsql +as $$ +declare + res jsonb; + message_text text; +begin + begin + select graphql._internal_resolve("query" := "query", + "variables" := "variables", + "operationName" := "operationName", + "extensions" := "extensions") into res; + return res; + exception + when others then + get stacked diagnostics message_text = message_text; + return + jsonb_build_object('data', null, + 'errors', jsonb_build_array(jsonb_build_object('message', message_text))); + end; +end; +$$; + + +-- src/lib.rs:21 +create function graphql.comment_directive(comment_ text) + returns jsonb + language sql + immutable +as $$ + /* + comment on column public.account.name is '@graphql.name: myField' + */ + select + coalesce( + ( + regexp_match( + comment_, + '@graphql\((.+?)\)' + ) + )[1]::jsonb, + jsonb_build_object() + ) +$$; + + +-- src/lib.rs:20 +-- Is updated every time the schema changes +create sequence if not exists graphql.seq_schema_version as int cycle; + +create or replace function graphql.increment_schema_version() + returns event_trigger + security definer + language plpgsql +as $$ +begin + perform nextval('graphql.seq_schema_version'); +end; +$$; + +create or replace function graphql.get_schema_version() + returns int + security definer + language sql +as $$ + select last_value from graphql.seq_schema_version; +$$; + +-- On DDL event, increment the schema version number +create event trigger graphql_watch_ddl + on ddl_command_end + execute procedure graphql.increment_schema_version(); + +create event trigger graphql_watch_drop + on sql_drop + execute procedure graphql.increment_schema_version(); + diff --git a/packages/twenty-postgres/linux/amd64/15/pg_graphql/1.5.6/pg_graphql.control b/packages/twenty-postgres/linux/amd64/15/pg_graphql/1.5.6/pg_graphql.control new file mode 100644 index 000000000000..56c20ea629f1 --- /dev/null +++ b/packages/twenty-postgres/linux/amd64/15/pg_graphql/1.5.6/pg_graphql.control @@ -0,0 +1,6 @@ +comment = 'pg_graphql: GraphQL support' +default_version = '1.5.6' +module_pathname = '$libdir/pg_graphql' +relocatable = false +superuser = true +schema = 'graphql' diff --git a/packages/twenty-postgres/linux/amd64/15/pg_graphql/1.5.6/pg_graphql.so b/packages/twenty-postgres/linux/amd64/15/pg_graphql/1.5.6/pg_graphql.so new file mode 100755 index 000000000000..9d1667369cb1 Binary files /dev/null and b/packages/twenty-postgres/linux/amd64/15/pg_graphql/1.5.6/pg_graphql.so differ diff --git a/packages/twenty-postgres/linux/arm64/15/pg_graphql/1.5.6/pg_graphql--1.5.6.sql b/packages/twenty-postgres/linux/arm64/15/pg_graphql/1.5.6/pg_graphql--1.5.6.sql new file mode 100644 index 000000000000..35a393c223bc --- /dev/null +++ b/packages/twenty-postgres/linux/arm64/15/pg_graphql/1.5.6/pg_graphql--1.5.6.sql @@ -0,0 +1,116 @@ +/* +This file is auto generated by pgrx. + +The ordering of items is not stable, it is driven by a dependency graph. +*/ + +-- src/lib.rs:27 +-- pg_graphql::_internal_resolve +CREATE FUNCTION graphql."_internal_resolve"( + "query" TEXT, /* &str */ + "variables" jsonb DEFAULT '{}', /* core::option::Option<pgrx::datum::json::JsonB> */ + "operationName" TEXT DEFAULT null, /* core::option::Option<alloc::string::String> */ + "extensions" jsonb DEFAULT null /* core::option::Option<pgrx::datum::json::JsonB> */ +) RETURNS jsonb /* pgrx::datum::json::JsonB */ + +LANGUAGE c /* Rust */ +AS 'MODULE_PATHNAME', 'resolve_wrapper'; + +-- src/lib.rs:21 +create function graphql.comment_directive(comment_ text) + returns jsonb + language sql + immutable +as $$ + /* + comment on column public.account.name is '@graphql.name: myField' + */ + select + coalesce( + ( + regexp_match( + comment_, + '@graphql\((.+?)\)' + ) + )[1]::jsonb, + jsonb_build_object() + ) +$$; + + +-- src/lib.rs:22 +create or replace function graphql.exception(message text) + returns text + language plpgsql +as $$ +begin + raise exception using errcode='22000', message=message; +end; +$$; + + +-- src/lib.rs:20 +-- Is updated every time the schema changes +create sequence if not exists graphql.seq_schema_version as int cycle; + +create or replace function graphql.increment_schema_version() + returns event_trigger + security definer + language plpgsql +as $$ +begin + perform nextval('graphql.seq_schema_version'); +end; +$$; + +create or replace function graphql.get_schema_version() + returns int + security definer + language sql +as $$ + select last_value from graphql.seq_schema_version; +$$; + +-- On DDL event, increment the schema version number +create event trigger graphql_watch_ddl + on ddl_command_end + execute procedure graphql.increment_schema_version(); + +create event trigger graphql_watch_drop + on sql_drop + execute procedure graphql.increment_schema_version(); + + +-- src/lib.rs:23 +-- requires: +-- resolve + +create or replace function graphql.resolve( + "query" text, + "variables" jsonb default '{}', + "operationName" text default null, + "extensions" jsonb default null +) + returns jsonb + language plpgsql +as $$ +declare + res jsonb; + message_text text; +begin + begin + select graphql._internal_resolve("query" := "query", + "variables" := "variables", + "operationName" := "operationName", + "extensions" := "extensions") into res; + return res; + exception + when others then + get stacked diagnostics message_text = message_text; + return + jsonb_build_object('data', null, + 'errors', jsonb_build_array(jsonb_build_object('message', message_text))); + end; +end; +$$; + diff --git a/packages/twenty-postgres/linux/arm64/15/pg_graphql/1.5.6/pg_graphql.control b/packages/twenty-postgres/linux/arm64/15/pg_graphql/1.5.6/pg_graphql.control new file mode 100644 index 000000000000..56c20ea629f1 --- /dev/null +++ b/packages/twenty-postgres/linux/arm64/15/pg_graphql/1.5.6/pg_graphql.control @@ -0,0 +1,6 @@ +comment = 'pg_graphql: GraphQL support' +default_version = '1.5.6' +module_pathname = '$libdir/pg_graphql' +relocatable = false +superuser = true +schema = 'graphql' diff --git a/packages/twenty-postgres/linux/arm64/15/pg_graphql/1.5.6/pg_graphql.so b/packages/twenty-postgres/linux/arm64/15/pg_graphql/1.5.6/pg_graphql.so new file mode 100755 index 000000000000..462b794534c9 Binary files /dev/null and b/packages/twenty-postgres/linux/arm64/15/pg_graphql/1.5.6/pg_graphql.so differ diff --git a/packages/twenty-postgres/linux/build-postgres-linux.sh b/packages/twenty-postgres/linux/build-postgres-linux.sh index 11744e774d7f..4b6e3b21831e 100755 --- a/packages/twenty-postgres/linux/build-postgres-linux.sh +++ b/packages/twenty-postgres/linux/build-postgres-linux.sh @@ -48,7 +48,7 @@ EOF echo_header $BLUE " DATABASE SETUP" PG_MAIN_VERSION=15 -PG_GRAPHQL_VERSION=1.5.1 +PG_GRAPHQL_VERSION=1.5.6 CARGO_PGRX_VERSION=0.11.2 TARGETARCH=$(dpkg --print-architecture) diff --git a/packages/twenty-postgres/linux/build_postgres.md b/packages/twenty-postgres/linux/build_postgres.md index 12c931125edc..c966b1ba5350 100644 --- a/packages/twenty-postgres/linux/build_postgres.md +++ b/packages/twenty-postgres/linux/build_postgres.md @@ -2,21 +2,23 @@ This doc explains how to build postgresql for Funnelmink Build .control, .so and .pg_graphql--version.sql -> docker buildx create --name mybuilder -> docker buildx use mybuilder +``` +docker buildx create --name mybuilder +docker buildx use mybuilder +``` Do the same for <PLATFORM> in ['amd64', 'arm64'] ('amd64' builds faster) -> cd packages/twenty-postgres -> docker buildx build --platform linux/<PLATFORM> --load -t twenty-bitnami-postgres-<PLATFORM> linux -> docker run --name twenty-bitnami-<PLATFORM> -v ~/Desktop/twenty/packages/twenty-postgres:/twenty <IMAGE_TAG> +``` +cd packages/twenty-postgres +docker buildx build --platform linux/<PLATFORM> --load -t twenty-bitnami-postgres-<PLATFORM> linux +docker run --name twenty-bitnami-<PLATFORM> -v ~/Desktop/twenty/packages/twenty-postgres:/twenty <IMAGE_TAG> +``` In another terminal -> docker exec -it <CONTAINER_TAG> sh -> sh twenty/linux/build-postgres-linux.sh -> cp opt/bitnami/postgresql/lib/pg_graphql.so twenty/linux/<PLATFORM>/15/pg_graphql/<PG_GRAPHQL_VERSION> -> cp opt/bitnami/postgresql/share/extension/pg_graphql.control twenty/linux/<PLATFORM>/15/pg_graphql/<PG_GRAPHQL_VERSION> -> cp opt/bitnami/postgresql/share/extension/pg_graphql--<PG_GRAPHQL_VERSION>.sql twenty/linux/<PLATFORM>/15/pg_graphql/<PG_GRAPHQL_VERSION> - -Then -> prod-server-build -> prod-server-run +``` +docker exec -it <CONTAINER_TAG> sh +sh twenty/linux/build-postgres-linux.sh +cp opt/bitnami/postgresql/lib/pg_graphql.so twenty/linux/<PLATFORM>/15/pg_graphql/<PG_GRAPHQL_VERSION> +cp opt/bitnami/postgresql/share/extension/pg_graphql.control twenty/linux/<PLATFORM>/15/pg_graphql/<PG_GRAPHQL_VERSION> +cp opt/bitnami/postgresql/share/extension/pg_graphql--<PG_GRAPHQL_VERSION>.sql twenty/linux/<PLATFORM>/15/pg_graphql/<PG_GRAPHQL_VERSION> +``` diff --git a/packages/twenty-postgres/linux/provision-postgres-linux.sh b/packages/twenty-postgres/linux/provision-postgres-linux.sh index 651224284e05..620d3e887fee 100755 --- a/packages/twenty-postgres/linux/provision-postgres-linux.sh +++ b/packages/twenty-postgres/linux/provision-postgres-linux.sh @@ -48,7 +48,7 @@ EOF echo_header $BLUE " DATABASE SETUP" PG_MAIN_VERSION=15 -PG_GRAPHQL_VERSION=1.5.1 +PG_GRAPHQL_VERSION=1.5.6 TARGETARCH=$(dpkg --print-architecture) # Install PostgresSQL diff --git a/packages/twenty-postgres/macos/arm/15/pg_graphql/1.5.6/pg_graphql--1.5.6.sql b/packages/twenty-postgres/macos/arm/15/pg_graphql/1.5.6/pg_graphql--1.5.6.sql new file mode 100644 index 000000000000..f7687883c020 --- /dev/null +++ b/packages/twenty-postgres/macos/arm/15/pg_graphql/1.5.6/pg_graphql--1.5.6.sql @@ -0,0 +1,116 @@ +/* +This file is auto generated by pgrx. + +The ordering of items is not stable, it is driven by a dependency graph. +*/ + +-- src/lib.rs:27 +-- pg_graphql::_internal_resolve +CREATE FUNCTION graphql."_internal_resolve"( + "query" TEXT, /* &str */ + "variables" jsonb DEFAULT '{}', /* core::option::Option<pgrx::datum::json::JsonB> */ + "operationName" TEXT DEFAULT null, /* core::option::Option<alloc::string::String> */ + "extensions" jsonb DEFAULT null /* core::option::Option<pgrx::datum::json::JsonB> */ +) RETURNS jsonb /* pgrx::datum::json::JsonB */ + +LANGUAGE c /* Rust */ +AS 'MODULE_PATHNAME', 'resolve_wrapper'; + +-- src/lib.rs:22 +create or replace function graphql.exception(message text) + returns text + language plpgsql +as $$ +begin + raise exception using errcode='22000', message=message; +end; +$$; + + +-- src/lib.rs:20 +-- Is updated every time the schema changes +create sequence if not exists graphql.seq_schema_version as int cycle; + +create or replace function graphql.increment_schema_version() + returns event_trigger + security definer + language plpgsql +as $$ +begin + perform nextval('graphql.seq_schema_version'); +end; +$$; + +create or replace function graphql.get_schema_version() + returns int + security definer + language sql +as $$ + select last_value from graphql.seq_schema_version; +$$; + +-- On DDL event, increment the schema version number +create event trigger graphql_watch_ddl + on ddl_command_end + execute procedure graphql.increment_schema_version(); + +create event trigger graphql_watch_drop + on sql_drop + execute procedure graphql.increment_schema_version(); + + +-- src/lib.rs:21 +create function graphql.comment_directive(comment_ text) + returns jsonb + language sql + immutable +as $$ + /* + comment on column public.account.name is '@graphql.name: myField' + */ + select + coalesce( + ( + regexp_match( + comment_, + '@graphql\((.+?)\)' + ) + )[1]::jsonb, + jsonb_build_object() + ) +$$; + + +-- src/lib.rs:23 +-- requires: +-- resolve + +create or replace function graphql.resolve( + "query" text, + "variables" jsonb default '{}', + "operationName" text default null, + "extensions" jsonb default null +) + returns jsonb + language plpgsql +as $$ +declare + res jsonb; + message_text text; +begin + begin + select graphql._internal_resolve("query" := "query", + "variables" := "variables", + "operationName" := "operationName", + "extensions" := "extensions") into res; + return res; + exception + when others then + get stacked diagnostics message_text = message_text; + return + jsonb_build_object('data', null, + 'errors', jsonb_build_array(jsonb_build_object('message', message_text))); + end; +end; +$$; + diff --git a/packages/twenty-postgres/macos/arm/15/pg_graphql/1.5.6/pg_graphql.control b/packages/twenty-postgres/macos/arm/15/pg_graphql/1.5.6/pg_graphql.control new file mode 100644 index 000000000000..56c20ea629f1 --- /dev/null +++ b/packages/twenty-postgres/macos/arm/15/pg_graphql/1.5.6/pg_graphql.control @@ -0,0 +1,6 @@ +comment = 'pg_graphql: GraphQL support' +default_version = '1.5.6' +module_pathname = '$libdir/pg_graphql' +relocatable = false +superuser = true +schema = 'graphql' diff --git a/packages/twenty-postgres/macos/arm/15/pg_graphql/1.5.6/pg_graphql.so b/packages/twenty-postgres/macos/arm/15/pg_graphql/1.5.6/pg_graphql.so new file mode 100755 index 000000000000..c87cdbd4c66f Binary files /dev/null and b/packages/twenty-postgres/macos/arm/15/pg_graphql/1.5.6/pg_graphql.so differ diff --git a/packages/twenty-postgres/macos/arm/build-postgres-macos-arm.sh b/packages/twenty-postgres/macos/arm/build-postgres-macos-arm.sh index a2738797f821..3decabfd7c5c 100755 --- a/packages/twenty-postgres/macos/arm/build-postgres-macos-arm.sh +++ b/packages/twenty-postgres/macos/arm/build-postgres-macos-arm.sh @@ -48,7 +48,7 @@ EOF echo_header $BLUE " DATABASE SETUP" PG_MAIN_VERSION=15 -PG_GRAPHQL_VERSION=1.5.1 +PG_GRAPHQL_VERSION=1.5.6 CARGO_PGRX_VERSION=0.11.2 current_directory=$(pwd) diff --git a/packages/twenty-postgres/macos/arm/provision-postgres-macos-arm.sh b/packages/twenty-postgres/macos/arm/provision-postgres-macos-arm.sh index 24e98760867b..201a4abb2ec0 100755 --- a/packages/twenty-postgres/macos/arm/provision-postgres-macos-arm.sh +++ b/packages/twenty-postgres/macos/arm/provision-postgres-macos-arm.sh @@ -1,7 +1,7 @@ #!/bin/bash PG_MAIN_VERSION=15 -PG_GRAPHQL_VERSION=1.5.1 +PG_GRAPHQL_VERSION=1.5.6 current_directory=$(pwd) diff --git a/packages/twenty-postgres/macos/intel/15/pg_graphql/1.5.6/pg_graphql--1.5.6.sql b/packages/twenty-postgres/macos/intel/15/pg_graphql/1.5.6/pg_graphql--1.5.6.sql new file mode 100644 index 000000000000..a24d69a1aef6 --- /dev/null +++ b/packages/twenty-postgres/macos/intel/15/pg_graphql/1.5.6/pg_graphql--1.5.6.sql @@ -0,0 +1,116 @@ +/* +This file is auto generated by pgrx. + +The ordering of items is not stable, it is driven by a dependency graph. +*/ + +-- src/lib.rs:27 +-- pg_graphql::_internal_resolve +CREATE FUNCTION graphql."_internal_resolve"( + "query" TEXT, /* &str */ + "variables" jsonb DEFAULT '{}', /* core::option::Option<pgrx::datum::json::JsonB> */ + "operationName" TEXT DEFAULT null, /* core::option::Option<alloc::string::String> */ + "extensions" jsonb DEFAULT null /* core::option::Option<pgrx::datum::json::JsonB> */ +) RETURNS jsonb /* pgrx::datum::json::JsonB */ + +LANGUAGE c /* Rust */ +AS 'MODULE_PATHNAME', 'resolve_wrapper'; + +-- src/lib.rs:20 +-- Is updated every time the schema changes +create sequence if not exists graphql.seq_schema_version as int cycle; + +create or replace function graphql.increment_schema_version() + returns event_trigger + security definer + language plpgsql +as $$ +begin + perform nextval('graphql.seq_schema_version'); +end; +$$; + +create or replace function graphql.get_schema_version() + returns int + security definer + language sql +as $$ + select last_value from graphql.seq_schema_version; +$$; + +-- On DDL event, increment the schema version number +create event trigger graphql_watch_ddl + on ddl_command_end + execute procedure graphql.increment_schema_version(); + +create event trigger graphql_watch_drop + on sql_drop + execute procedure graphql.increment_schema_version(); + + +-- src/lib.rs:22 +create or replace function graphql.exception(message text) + returns text + language plpgsql +as $$ +begin + raise exception using errcode='22000', message=message; +end; +$$; + + +-- src/lib.rs:21 +create function graphql.comment_directive(comment_ text) + returns jsonb + language sql + immutable +as $$ + /* + comment on column public.account.name is '@graphql.name: myField' + */ + select + coalesce( + ( + regexp_match( + comment_, + '@graphql\((.+?)\)' + ) + )[1]::jsonb, + jsonb_build_object() + ) +$$; + + +-- src/lib.rs:23 +-- requires: +-- resolve + +create or replace function graphql.resolve( + "query" text, + "variables" jsonb default '{}', + "operationName" text default null, + "extensions" jsonb default null +) + returns jsonb + language plpgsql +as $$ +declare + res jsonb; + message_text text; +begin + begin + select graphql._internal_resolve("query" := "query", + "variables" := "variables", + "operationName" := "operationName", + "extensions" := "extensions") into res; + return res; + exception + when others then + get stacked diagnostics message_text = message_text; + return + jsonb_build_object('data', null, + 'errors', jsonb_build_array(jsonb_build_object('message', message_text))); + end; +end; +$$; + diff --git a/packages/twenty-postgres/macos/intel/15/pg_graphql/1.5.6/pg_graphql.control b/packages/twenty-postgres/macos/intel/15/pg_graphql/1.5.6/pg_graphql.control new file mode 100644 index 000000000000..56c20ea629f1 --- /dev/null +++ b/packages/twenty-postgres/macos/intel/15/pg_graphql/1.5.6/pg_graphql.control @@ -0,0 +1,6 @@ +comment = 'pg_graphql: GraphQL support' +default_version = '1.5.6' +module_pathname = '$libdir/pg_graphql' +relocatable = false +superuser = true +schema = 'graphql' diff --git a/packages/twenty-postgres/macos/intel/15/pg_graphql/1.5.6/pg_graphql.so b/packages/twenty-postgres/macos/intel/15/pg_graphql/1.5.6/pg_graphql.so new file mode 100644 index 000000000000..c6f712ec040d Binary files /dev/null and b/packages/twenty-postgres/macos/intel/15/pg_graphql/1.5.6/pg_graphql.so differ diff --git a/packages/twenty-postgres/macos/intel/build-postgres-macos-intel.sh b/packages/twenty-postgres/macos/intel/build-postgres-macos-intel.sh index a5636eac08d2..944f64d72326 100755 --- a/packages/twenty-postgres/macos/intel/build-postgres-macos-intel.sh +++ b/packages/twenty-postgres/macos/intel/build-postgres-macos-intel.sh @@ -48,7 +48,7 @@ EOF echo_header $BLUE " DATABASE SETUP" PG_MAIN_VERSION=15 -PG_GRAPHQL_VERSION=1.5.1 +PG_GRAPHQL_VERSION=1.5.6 CARGO_PGRX_VERSION=0.11.2 current_directory=$(pwd) diff --git a/packages/twenty-postgres/macos/intel/provision-postgres-macos-intel.sh b/packages/twenty-postgres/macos/intel/provision-postgres-macos-intel.sh index c6a49fa430e7..72091af18798 100755 --- a/packages/twenty-postgres/macos/intel/provision-postgres-macos-intel.sh +++ b/packages/twenty-postgres/macos/intel/provision-postgres-macos-intel.sh @@ -1,7 +1,7 @@ #!/bin/bash PG_MAIN_VERSION=15 -PG_GRAPHQL_VERSION=1.5.1 +PG_GRAPHQL_VERSION=1.5.6 current_directory=$(pwd) diff --git a/packages/twenty-server/.env.example b/packages/twenty-server/.env.example index bfe76f8a49da..8b2c6cac2f93 100644 --- a/packages/twenty-server/.env.example +++ b/packages/twenty-server/.env.example @@ -70,6 +70,6 @@ SIGN_IN_PREFILLED=true # CAPTCHA_SECRET_KEY= # API_RATE_LIMITING_TTL= # API_RATE_LIMITING_LIMIT= -# MUTATION_MAXIMUM_RECORD_AFFECTED=100 +# MUTATION_MAXIMUM_AFFECTED_RECORDS=100 # CHROME_EXTENSION_ID=bggmipldbceihilonnbpgoeclgbkblkp -# PG_SSL_ALLOW_SELF_SIGNED=true +# PG_SSL_ALLOW_SELF_SIGNED=true \ No newline at end of file diff --git a/packages/twenty-server/.env.test b/packages/twenty-server/.env.test index 20bd13ac8ba3..fc51ab9e1e22 100644 --- a/packages/twenty-server/.env.test +++ b/packages/twenty-server/.env.test @@ -23,4 +23,4 @@ FILE_TOKEN_SECRET=secret_file_token # MESSAGING_PROVIDER_GMAIL_ENABLED=false # STORAGE_TYPE=local # STORAGE_LOCAL_PATH=.local-storage -# MUTATION_MAXIMUM_RECORD_AFFECTED=100 +# MUTATION_MAXIMUM_AFFECTED_RECORDS=100 diff --git a/packages/twenty-server/@types/express.d.ts b/packages/twenty-server/@types/express.d.ts index 9f5ffd96da42..09c6bfbfef80 100644 --- a/packages/twenty-server/@types/express.d.ts +++ b/packages/twenty-server/@types/express.d.ts @@ -5,6 +5,7 @@ declare module 'express-serve-static-core' { interface Request { user?: User; workspace?: Workspace; + workspaceId?: string; cacheVersion?: string | null; } } diff --git a/packages/twenty-server/package.json b/packages/twenty-server/package.json index b8d7cc58f722..c97dcfd3fb56 100644 --- a/packages/twenty-server/package.json +++ b/packages/twenty-server/package.json @@ -1,6 +1,6 @@ { "name": "twenty-server", - "version": "0.20.0", + "version": "0.22.0", "description": "", "author": "", "private": true, @@ -15,6 +15,8 @@ }, "dependencies": { "@graphql-yoga/nestjs": "patch:@graphql-yoga/nestjs@2.1.0#./patches/@graphql-yoga-nestjs-npm-2.1.0-cb509e6047.patch", + "@langchain/mistralai": "^0.0.24", + "@langchain/openai": "^0.1.3", "@nestjs/cache-manager": "^2.2.1", "@nestjs/devtools-integration": "^0.1.6", "@nestjs/graphql": "patch:@nestjs/graphql@12.1.1#./patches/@nestjs+graphql+12.1.1.patch", @@ -25,12 +27,16 @@ "graphql-middleware": "^6.1.35", "jsdom": "~22.1.0", "jwt-decode": "^4.0.0", + "langchain": "^0.2.6", + "langfuse-langchain": "^3.11.2", "lodash.differencewith": "^4.5.0", + "lodash.omitby": "^4.6.0", "lodash.uniq": "^4.5.0", "lodash.uniqby": "^4.7.0", "passport": "^0.7.0", "psl": "^1.9.0", - "tsconfig-paths": "^4.2.0" + "tsconfig-paths": "^4.2.0", + "zod-to-json-schema": "^3.23.1" }, "devDependencies": { "@nestjs/cli": "10.3.0", @@ -40,6 +46,7 @@ "@types/lodash.isequal": "^4.5.8", "@types/lodash.isobject": "^3.0.7", "@types/lodash.omit": "^4.5.9", + "@types/lodash.omitby": "^4.6.9", "@types/lodash.snakecase": "^4.1.7", "@types/lodash.uniq": "^4.5.9", "@types/lodash.uniqby": "^4.7.9", diff --git a/packages/twenty-server/scripts/render-worker.sh b/packages/twenty-server/scripts/render-worker.sh new file mode 100755 index 000000000000..1a34c6f7c3d7 --- /dev/null +++ b/packages/twenty-server/scripts/render-worker.sh @@ -0,0 +1,3 @@ +#!/bin/sh +export PG_DATABASE_URL=postgres://twenty:twenty@$PG_DATABASE_HOST:$PG_DATABASE_PORT/default +node dist/src/queue-worker/queue-worker diff --git a/packages/twenty-server/src/app.module.ts b/packages/twenty-server/src/app.module.ts index 95e8b31a0199..914b5b295f6c 100644 --- a/packages/twenty-server/src/app.module.ts +++ b/packages/twenty-server/src/app.module.ts @@ -21,9 +21,11 @@ import { GraphQLConfigModule } from 'src/engine/api/graphql/graphql-config/graph import { GraphQLConfigService } from 'src/engine/api/graphql/graphql-config/graphql-config.service'; import { WorkspaceCacheVersionModule } from 'src/engine/metadata-modules/workspace-cache-version/workspace-cache-version.module'; import { GraphQLHydrateRequestFromTokenMiddleware } from 'src/engine/middlewares/graphql-hydrate-request-from-token.middleware'; +import { MessageQueueModule } from 'src/engine/integrations/message-queue/message-queue.module'; +import { MessageQueueDriverType } from 'src/engine/integrations/message-queue/interfaces'; -import { CoreEngineModule } from './engine/core-modules/core-engine.module'; import { IntegrationsModule } from './engine/integrations/integrations.module'; +import { CoreEngineModule } from './engine/core-modules/core-engine.module'; @Module({ imports: [ @@ -72,6 +74,13 @@ export class AppModule { ); } + // Messaque Queue explorer only for sync driver + // Maybe we don't need to conditionaly register the explorer, because we're creating a jobs module + // that will expose classes that are only used in the queue worker + if (process.env.MESSAGE_QUEUE_TYPE === MessageQueueDriverType.Sync) { + modules.push(MessageQueueModule.registerExplorer()); + } + return modules; } diff --git a/packages/twenty-server/src/command/command.module.ts b/packages/twenty-server/src/command/command.module.ts index 86c629f92898..70fa379446f6 100644 --- a/packages/twenty-server/src/command/command.module.ts +++ b/packages/twenty-server/src/command/command.module.ts @@ -3,20 +3,15 @@ import { Module } from '@nestjs/common'; import { DatabaseCommandModule } from 'src/database/commands/database-command.module'; import { WorkspaceHealthCommandModule } from 'src/engine/workspace-manager/workspace-health/commands/workspace-health-command.module'; import { WorkspaceCleanerModule } from 'src/engine/workspace-manager/workspace-cleaner/workspace-cleaner.module'; -import { CalendarCronCommandsModule } from 'src/modules/calendar/crons/commands/calendar-cron-commands.module'; import { AppModule } from 'src/app.module'; import { WorkspaceMigrationRunnerCommandsModule } from 'src/engine/workspace-manager/workspace-migration-runner/commands/workspace-sync-metadata-commands.module'; import { WorkspaceSyncMetadataCommandsModule } from 'src/engine/workspace-manager/workspace-sync-metadata/commands/workspace-sync-metadata-commands.module'; -import { CalendarCommandsModule } from 'src/modules/calendar/commands/calendar-commands.module'; @Module({ imports: [ AppModule, WorkspaceSyncMetadataCommandsModule, DatabaseCommandModule, - // MessagingCronCommandsModule, - CalendarCronCommandsModule, - CalendarCommandsModule, WorkspaceCleanerModule, WorkspaceHealthCommandModule, WorkspaceMigrationRunnerCommandsModule, diff --git a/packages/twenty-server/src/database/commands/data-seed-demo-workspace/crons/start-data-seed-demo-workspace.cron.command.ts b/packages/twenty-server/src/database/commands/data-seed-demo-workspace/crons/start-data-seed-demo-workspace.cron.command.ts index e9a8df6d35f2..bdf120095b23 100644 --- a/packages/twenty-server/src/database/commands/data-seed-demo-workspace/crons/start-data-seed-demo-workspace.cron.command.ts +++ b/packages/twenty-server/src/database/commands/data-seed-demo-workspace/crons/start-data-seed-demo-workspace.cron.command.ts @@ -1,9 +1,8 @@ -import { Inject } from '@nestjs/common'; - import { Command, CommandRunner } from 'nest-commander'; import { dataSeedDemoWorkspaceCronPattern } from 'src/database/commands/data-seed-demo-workspace/crons/data-seed-demo-workspace-cron-pattern'; import { DataSeedDemoWorkspaceJob } from 'src/database/commands/data-seed-demo-workspace/jobs/data-seed-demo-workspace.job'; +import { InjectMessageQueue } from 'src/engine/integrations/message-queue/decorators/message-queue.decorator'; import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service'; @@ -13,7 +12,7 @@ import { MessageQueueService } from 'src/engine/integrations/message-queue/servi }) export class StartDataSeedDemoWorkspaceCronCommand extends CommandRunner { constructor( - @Inject(MessageQueue.cronQueue) + @InjectMessageQueue(MessageQueue.cronQueue) private readonly messageQueueService: MessageQueueService, ) { super(); diff --git a/packages/twenty-server/src/database/commands/data-seed-demo-workspace/crons/stop-data-seed-demo-workspace.cron.command.ts b/packages/twenty-server/src/database/commands/data-seed-demo-workspace/crons/stop-data-seed-demo-workspace.cron.command.ts index 84cd4a28df16..99dd1558bf7f 100644 --- a/packages/twenty-server/src/database/commands/data-seed-demo-workspace/crons/stop-data-seed-demo-workspace.cron.command.ts +++ b/packages/twenty-server/src/database/commands/data-seed-demo-workspace/crons/stop-data-seed-demo-workspace.cron.command.ts @@ -1,9 +1,8 @@ -import { Inject } from '@nestjs/common'; - import { Command, CommandRunner } from 'nest-commander'; import { dataSeedDemoWorkspaceCronPattern } from 'src/database/commands/data-seed-demo-workspace/crons/data-seed-demo-workspace-cron-pattern'; import { DataSeedDemoWorkspaceJob } from 'src/database/commands/data-seed-demo-workspace/jobs/data-seed-demo-workspace.job'; +import { InjectMessageQueue } from 'src/engine/integrations/message-queue/decorators/message-queue.decorator'; import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service'; @@ -13,7 +12,7 @@ import { MessageQueueService } from 'src/engine/integrations/message-queue/servi }) export class StopDataSeedDemoWorkspaceCronCommand extends CommandRunner { constructor( - @Inject(MessageQueue.cronQueue) + @InjectMessageQueue(MessageQueue.cronQueue) private readonly messageQueueService: MessageQueueService, ) { super(); diff --git a/packages/twenty-server/src/database/commands/data-seed-demo-workspace/jobs/data-seed-demo-workspace.job.ts b/packages/twenty-server/src/database/commands/data-seed-demo-workspace/jobs/data-seed-demo-workspace.job.ts index e7b963d62008..14655209c009 100644 --- a/packages/twenty-server/src/database/commands/data-seed-demo-workspace/jobs/data-seed-demo-workspace.job.ts +++ b/packages/twenty-server/src/database/commands/data-seed-demo-workspace/jobs/data-seed-demo-workspace.job.ts @@ -1,15 +1,15 @@ -import { Injectable } from '@nestjs/common'; - -import { MessageQueueJob } from 'src/engine/integrations/message-queue/interfaces/message-queue-job.interface'; - import { DataSeedDemoWorkspaceService } from 'src/database/commands/data-seed-demo-workspace/services/data-seed-demo-workspace.service'; +import { Processor } from 'src/engine/integrations/message-queue/decorators/processor.decorator'; +import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; +import { Process } from 'src/engine/integrations/message-queue/decorators/process.decorator'; -@Injectable() -export class DataSeedDemoWorkspaceJob implements MessageQueueJob<undefined> { +@Processor(MessageQueue.cronQueue) +export class DataSeedDemoWorkspaceJob { constructor( private readonly dataSeedDemoWorkspaceService: DataSeedDemoWorkspaceService, ) {} + @Process(DataSeedDemoWorkspaceJob.name) async handle(): Promise<void> { await this.dataSeedDemoWorkspaceService.seedDemo(); } diff --git a/packages/twenty-server/src/database/commands/database-command.module.ts b/packages/twenty-server/src/database/commands/database-command.module.ts index d829bcf75221..eaaaa8624a28 100644 --- a/packages/twenty-server/src/database/commands/database-command.module.ts +++ b/packages/twenty-server/src/database/commands/database-command.module.ts @@ -1,33 +1,39 @@ import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; -import { ConfirmationQuestion } from 'src/database/commands/questions/confirmation.question'; -import { WorkspaceManagerModule } from 'src/engine/workspace-manager/workspace-manager.module'; -import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module'; -import { TypeORMModule } from 'src/database/typeorm/typeorm.module'; -import { WorkspaceModule } from 'src/engine/core-modules/workspace/workspace.module'; -import { DataSeedWorkspaceCommand } from 'src/database/commands/data-seed-dev-workspace.command'; -import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; -import { WorkspaceSyncMetadataModule } from 'src/engine/workspace-manager/workspace-sync-metadata/workspace-sync-metadata.module'; -import { ObjectMetadataModule } from 'src/engine/metadata-modules/object-metadata/object-metadata.module'; import { StartDataSeedDemoWorkspaceCronCommand } from 'src/database/commands/data-seed-demo-workspace/crons/start-data-seed-demo-workspace.cron.command'; import { StopDataSeedDemoWorkspaceCronCommand } from 'src/database/commands/data-seed-demo-workspace/crons/stop-data-seed-demo-workspace.cron.command'; -import { WorkspaceAddTotalCountCommand } from 'src/database/commands/workspace-add-total-count.command'; import { DataSeedDemoWorkspaceCommand } from 'src/database/commands/data-seed-demo-workspace/data-seed-demo-workspace-command'; import { DataSeedDemoWorkspaceModule } from 'src/database/commands/data-seed-demo-workspace/data-seed-demo-workspace.module'; +import { DataSeedWorkspaceCommand } from 'src/database/commands/data-seed-dev-workspace.command'; +import { ConfirmationQuestion } from 'src/database/commands/questions/confirmation.question'; +import { UpdateMessageChannelVisibilityEnumCommand } from 'src/database/commands/upgrade-version/0-20/0-20-update-message-channel-visibility-enum.command'; +import { UpgradeTo0_22CommandModule } from 'src/database/commands/upgrade-version/0-22/0-22-upgrade-version.module'; +import { WorkspaceAddTotalCountCommand } from 'src/database/commands/workspace-add-total-count.command'; +import { TypeORMModule } from 'src/database/typeorm/typeorm.module'; +import { BillingSubscription } from 'src/engine/core-modules/billing/entities/billing-subscription.entity'; +import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity'; import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; -import { UpdateMessageChannelVisibilityEnumCommand } from 'src/database/commands/update-message-channel-visibility-enum.command'; +import { WorkspaceModule } from 'src/engine/core-modules/workspace/workspace.module'; +import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module'; import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; -import { WorkspaceCacheVersionModule } from 'src/engine/metadata-modules/workspace-cache-version/workspace-cache-version.module'; -import { UpdateMessageChannelSyncStatusEnumCommand } from 'src/database/commands/0-20-update-message-channel-sync-status-enum.command'; import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; +import { ObjectMetadataModule } from 'src/engine/metadata-modules/object-metadata/object-metadata.module'; +import { WorkspaceCacheVersionModule } from 'src/engine/metadata-modules/workspace-cache-version/workspace-cache-version.module'; +import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; +import { WorkspaceManagerModule } from 'src/engine/workspace-manager/workspace-manager.module'; +import { WorkspaceStatusModule } from 'src/engine/workspace-manager/workspace-status/workspace-manager.module'; +import { WorkspaceSyncMetadataModule } from 'src/engine/workspace-manager/workspace-sync-metadata/workspace-sync-metadata.module'; @Module({ imports: [ WorkspaceManagerModule, DataSourceModule, TypeORMModule, - TypeOrmModule.forFeature([Workspace], 'core'), + TypeOrmModule.forFeature( + [Workspace, BillingSubscription, FeatureFlagEntity], + 'core', + ), TypeOrmModule.forFeature( [FieldMetadataEntity, ObjectMetadataEntity], 'metadata', @@ -35,9 +41,12 @@ import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadat WorkspaceModule, WorkspaceDataSourceModule, WorkspaceSyncMetadataModule, + WorkspaceStatusModule, ObjectMetadataModule, DataSeedDemoWorkspaceModule, WorkspaceCacheVersionModule, + // Upgrades + UpgradeTo0_22CommandModule, ], providers: [ DataSeedWorkspaceCommand, @@ -47,7 +56,6 @@ import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadat StartDataSeedDemoWorkspaceCronCommand, StopDataSeedDemoWorkspaceCronCommand, UpdateMessageChannelVisibilityEnumCommand, - UpdateMessageChannelSyncStatusEnumCommand, ], }) export class DatabaseCommandModule {} diff --git a/packages/twenty-server/src/database/commands/update-message-channel-visibility-enum.command.ts b/packages/twenty-server/src/database/commands/upgrade-version/0-20/0-20-update-message-channel-visibility-enum.command.ts similarity index 100% rename from packages/twenty-server/src/database/commands/update-message-channel-visibility-enum.command.ts rename to packages/twenty-server/src/database/commands/upgrade-version/0-20/0-20-update-message-channel-visibility-enum.command.ts diff --git a/packages/twenty-server/src/database/commands/upgrade-version/0-22/0-22-add-new-address-field-to-views-with-deprecated-address.command.ts b/packages/twenty-server/src/database/commands/upgrade-version/0-22/0-22-add-new-address-field-to-views-with-deprecated-address.command.ts new file mode 100644 index 000000000000..4f4522b036e8 --- /dev/null +++ b/packages/twenty-server/src/database/commands/upgrade-version/0-22/0-22-add-new-address-field-to-views-with-deprecated-address.command.ts @@ -0,0 +1,180 @@ +import { Logger } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; + +import chalk from 'chalk'; +import isEmpty from 'lodash.isempty'; +import { Command, CommandRunner, Option } from 'nest-commander'; +import { Repository } from 'typeorm'; + +import { TypeORMService } from 'src/database/typeorm/typeorm.service'; +import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; +import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; +import { WorkspaceCacheVersionService } from 'src/engine/metadata-modules/workspace-cache-version/workspace-cache-version.service'; +import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager'; +import { WorkspaceStatusService } from 'src/engine/workspace-manager/workspace-status/services/workspace-status.service'; +import { COMPANY_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids'; +import { ViewFieldWorkspaceEntity } from 'src/modules/view/standard-objects/view-field.workspace-entity'; + +interface AddNewAddressFieldToViewsWithDeprecatedAddressFieldCommandOptions { + workspaceId?: string; +} + +@Command({ + name: 'migrate-0.22:add-new-address-field-to-views-with-deprecated-address-field', + description: 'Adding new field Address to views containing old address field', +}) +export class AddNewAddressFieldToViewsWithDeprecatedAddressFieldCommand extends CommandRunner { + private readonly logger = new Logger( + AddNewAddressFieldToViewsWithDeprecatedAddressFieldCommand.name, + ); + constructor( + @InjectRepository(FieldMetadataEntity, 'metadata') + private readonly fieldMetadataRepository: Repository<FieldMetadataEntity>, + private readonly typeORMService: TypeORMService, + private readonly dataSourceService: DataSourceService, + private readonly workspaceCacheVersionService: WorkspaceCacheVersionService, + private readonly twentyORMManager: TwentyORMManager, + private readonly workspaceStatusService: WorkspaceStatusService, + ) { + super(); + } + + @Option({ + flags: '-w, --workspace-id [workspace_id]', + description: 'workspace id. Command runs on all workspaces if not provided', + required: false, + }) + parseWorkspaceId(value: string): string { + return value; + } + + async run( + _passedParam: string[], + options: AddNewAddressFieldToViewsWithDeprecatedAddressFieldCommandOptions, + ): Promise<void> { + // This command can be generic-ified turning the below consts in options + const deprecatedFieldStandardId = + COMPANY_STANDARD_FIELD_IDS.address_deprecated; + const newFieldStandardId = COMPANY_STANDARD_FIELD_IDS.address; + + this.logger.log('running'); + let workspaceIds: string[] = []; + + if (options.workspaceId) { + workspaceIds = [options.workspaceId]; + } else { + const activeWorkspaceIds = + await this.workspaceStatusService.getActiveWorkspaceIds(); + + workspaceIds = activeWorkspaceIds; + } + + if (!workspaceIds.length) { + this.logger.log(chalk.yellow('No workspace found')); + + return; + } else { + this.logger.log( + chalk.green(`Running command on ${workspaceIds.length} workspaces`), + ); + } + + for (const workspaceId of workspaceIds) { + this.logger.log(`Running command for workspace ${workspaceId}`); + try { + const viewFieldRepository = + await this.twentyORMManager.getRepositoryForWorkspace( + workspaceId, + ViewFieldWorkspaceEntity, + ); + + const dataSourceMetadatas = + await this.dataSourceService.getDataSourcesMetadataFromWorkspaceId( + workspaceId, + ); + + for (const dataSourceMetadata of dataSourceMetadatas) { + const workspaceDataSource = + await this.typeORMService.connectToDataSource(dataSourceMetadata); + + if (workspaceDataSource) { + const newAddressField = await this.fieldMetadataRepository.findBy({ + workspaceId, + standardId: newFieldStandardId, + }); + + if (isEmpty(newAddressField)) { + this.logger.log( + `Error - missing new Address standard field of type Address, please run workspace-sync-metadata on your workspace (${workspaceId}) before running this command`, + ); + continue; + } + + const addressDeprecatedField = + await this.fieldMetadataRepository.findOneBy({ + workspaceId, + standardId: deprecatedFieldStandardId, + }); + + if (isEmpty(addressDeprecatedField)) { + continue; + } + + const viewsWithAddressDeprecatedField = + await viewFieldRepository.find({ + where: { + fieldMetadataId: addressDeprecatedField.id, + isVisible: true, + }, + }); + + for (const viewWithAddressDeprecatedField of viewsWithAddressDeprecatedField) { + const viewId = viewWithAddressDeprecatedField.viewId; + + const newAddressFieldInThisView = + await viewFieldRepository.findBy({ + fieldMetadataId: newAddressField[0].id, + viewId: viewWithAddressDeprecatedField.viewId as string, + isVisible: true, + }); + + if (!isEmpty(newAddressFieldInThisView)) { + continue; + } + + this.logger.log( + `Adding new address field to view ${viewId} for workspace ${workspaceId}...`, + ); + const newViewField = viewFieldRepository.create({ + viewId: viewWithAddressDeprecatedField.viewId, + fieldMetadataId: newAddressField[0].id, + position: viewWithAddressDeprecatedField.position - 0.5, + isVisible: true, + }); + + await viewFieldRepository.save(newViewField); + this.logger.log( + `New address field successfully added to view ${viewId} for workspace ${workspaceId}`, + ); + } + } + } + + await this.workspaceCacheVersionService.incrementVersion(workspaceId); + + this.logger.log( + chalk.green(`Running command on workspace ${workspaceId} done`), + ); + } catch (error) { + this.logger.log( + chalk.red( + `Running command on workspace ${workspaceId} failed with error: ${error}`, + ), + ); + continue; + } + + this.logger.log(chalk.green(`Command completed!`)); + } + } +} diff --git a/packages/twenty-server/src/database/commands/upgrade-version/0-22/0-22-fix-object-metadata-id-standard-id.command.ts b/packages/twenty-server/src/database/commands/upgrade-version/0-22/0-22-fix-object-metadata-id-standard-id.command.ts new file mode 100644 index 000000000000..213892637d95 --- /dev/null +++ b/packages/twenty-server/src/database/commands/upgrade-version/0-22/0-22-fix-object-metadata-id-standard-id.command.ts @@ -0,0 +1,101 @@ +import { Logger } from '@nestjs/common'; +import { InjectDataSource, InjectRepository } from '@nestjs/typeorm'; + +import chalk from 'chalk'; +import { Command, CommandRunner, Option } from 'nest-commander'; +import { DataSource, Repository } from 'typeorm'; + +import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; +import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; +import { WorkspaceCacheVersionService } from 'src/engine/metadata-modules/workspace-cache-version/workspace-cache-version.service'; +import { AUDIT_LOGS_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids'; + +interface FixObjectMetadataIdStandardIdCommandOptions { + workspaceId?: string; +} + +@Command({ + name: 'upgrade-0.22:fix-object-metadata-id-standard-id', + description: 'Fix object metadata id standard id', +}) +export class FixObjectMetadataIdStandardIdCommand extends CommandRunner { + private readonly logger = new Logger( + FixObjectMetadataIdStandardIdCommand.name, + ); + constructor( + @InjectRepository(Workspace, 'core') + private readonly workspaceRepository: Repository<Workspace>, + private readonly workspaceCacheVersionService: WorkspaceCacheVersionService, + @InjectDataSource('metadata') + private readonly metadataDataSource: DataSource, + ) { + super(); + } + + @Option({ + flags: '-w, --workspace-id [workspace_id]', + description: 'workspace id. Command runs on all workspaces if not provided', + required: false, + }) + parseWorkspaceId(value: string): string { + return value; + } + + async run( + _passedParam: string[], + options: FixObjectMetadataIdStandardIdCommandOptions, + ): Promise<void> { + const workspaceIds = options.workspaceId + ? [options.workspaceId] + : (await this.workspaceRepository.find()).map( + (workspace) => workspace.id, + ); + + if (!workspaceIds.length) { + this.logger.log(chalk.yellow('No workspace found')); + + return; + } + + this.logger.log( + chalk.green(`Running command on ${workspaceIds.length} workspaces`), + ); + + const metadataQueryRunner = this.metadataDataSource.createQueryRunner(); + + await metadataQueryRunner.connect(); + + const fieldMetadataRepository = + metadataQueryRunner.manager.getRepository(FieldMetadataEntity); + + for (const workspaceId of workspaceIds) { + try { + await metadataQueryRunner.startTransaction(); + + await fieldMetadataRepository.delete({ + workspaceId, + standardId: AUDIT_LOGS_STANDARD_FIELD_IDS.objectName, + name: 'objectMetadataId', + }); + + await metadataQueryRunner.commitTransaction(); + } catch (error) { + await metadataQueryRunner.rollbackTransaction(); + this.logger.log( + chalk.red(`Running command on workspace ${workspaceId} failed`), + ); + throw error; + } + + await this.workspaceCacheVersionService.incrementVersion(workspaceId); + + this.logger.log( + chalk.green(`Running command on workspace ${workspaceId} done`), + ); + } + + await metadataQueryRunner.release(); + + this.logger.log(chalk.green(`Command completed!`)); + } +} diff --git a/packages/twenty-server/src/database/commands/upgrade-version/0-22/0-22-update-boolean-fields-null-default-values-and-null-values.command.ts b/packages/twenty-server/src/database/commands/upgrade-version/0-22/0-22-update-boolean-fields-null-default-values-and-null-values.command.ts new file mode 100644 index 000000000000..3809600b515a --- /dev/null +++ b/packages/twenty-server/src/database/commands/upgrade-version/0-22/0-22-update-boolean-fields-null-default-values-and-null-values.command.ts @@ -0,0 +1,165 @@ +import { Logger } from '@nestjs/common'; +import { InjectDataSource, InjectRepository } from '@nestjs/typeorm'; + +import chalk from 'chalk'; +import { Command, CommandRunner, Option } from 'nest-commander'; +import { DataSource, IsNull, Repository } from 'typeorm'; + +import { TypeORMService } from 'src/database/typeorm/typeorm.service'; +import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; +import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; +import { + FieldMetadataEntity, + FieldMetadataType, +} from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; +import { WorkspaceCacheVersionService } from 'src/engine/metadata-modules/workspace-cache-version/workspace-cache-version.service'; +import { computeObjectTargetTable } from 'src/engine/utils/compute-object-target-table.util'; + +interface UpdateBooleanFieldsNullDefaultValuesAndNullValuesCommandOptions { + workspaceId?: string; +} + +@Command({ + name: 'upgrade-0.22:update-boolean-field-null-default-values-and-null-values', + description: + 'Update boolean fields null default values and null values to false', +}) +export class UpdateBooleanFieldsNullDefaultValuesAndNullValuesCommand extends CommandRunner { + private readonly logger = new Logger( + UpdateBooleanFieldsNullDefaultValuesAndNullValuesCommand.name, + ); + constructor( + @InjectRepository(Workspace, 'core') + private readonly workspaceRepository: Repository<Workspace>, + private readonly typeORMService: TypeORMService, + private readonly dataSourceService: DataSourceService, + private readonly workspaceCacheVersionService: WorkspaceCacheVersionService, + @InjectDataSource('metadata') + private readonly metadataDataSource: DataSource, + ) { + super(); + } + + @Option({ + flags: '-w, --workspace-id [workspace_id]', + description: 'workspace id. Command runs on all workspaces if not provided', + required: false, + }) + parseWorkspaceId(value: string): string { + return value; + } + + async run( + _passedParam: string[], + options: UpdateBooleanFieldsNullDefaultValuesAndNullValuesCommandOptions, + ): Promise<void> { + const workspaceIds = options.workspaceId + ? [options.workspaceId] + : (await this.workspaceRepository.find()).map( + (workspace) => workspace.id, + ); + + if (!workspaceIds.length) { + this.logger.log(chalk.yellow('No workspace found')); + + return; + } + + this.logger.log( + chalk.green(`Running command on ${workspaceIds.length} workspaces`), + ); + + for (const workspaceId of workspaceIds) { + const dataSourceMetadata = + await this.dataSourceService.getLastDataSourceMetadataFromWorkspaceId( + workspaceId, + ); + + if (!dataSourceMetadata) { + this.logger.log( + `Could not find dataSourceMetadata for workspace ${workspaceId}`, + ); + continue; + } + + const workspaceDataSource = + await this.typeORMService.connectToDataSource(dataSourceMetadata); + + if (!workspaceDataSource) { + throw new Error( + `Could not connect to dataSource for workspace ${workspaceId}`, + ); + } + + const workspaceQueryRunner = workspaceDataSource.createQueryRunner(); + const metadataQueryRunner = this.metadataDataSource.createQueryRunner(); + + await workspaceQueryRunner.connect(); + await metadataQueryRunner.connect(); + + await workspaceQueryRunner.startTransaction(); + await metadataQueryRunner.startTransaction(); + + try { + const fieldMetadataRepository = + metadataQueryRunner.manager.getRepository(FieldMetadataEntity); + + const booleanFieldsWithoutDefaultValue = + await fieldMetadataRepository.find({ + where: { + workspaceId, + type: FieldMetadataType.BOOLEAN, + defaultValue: IsNull(), + }, + relations: ['object'], + }); + + for (const booleanField of booleanFieldsWithoutDefaultValue) { + if (!booleanField.object) { + this.logger.log( + `Could not find objectMetadataItem for field ${booleanField.id}`, + ); + continue; + } + + // Could be done via a batch update but it's safer in this context to run it sequentially with the ALTER TABLE + await fieldMetadataRepository.update(booleanField.id, { + defaultValue: false, + }); + + const fieldName = booleanField.name; + const tableName = computeObjectTargetTable(booleanField.object); + + await workspaceQueryRunner.query( + `UPDATE "${dataSourceMetadata.schema}"."${tableName}" SET "${fieldName}" = 'false' WHERE "${fieldName}" IS NULL`, + ); + + await workspaceQueryRunner.query( + `ALTER TABLE "${dataSourceMetadata.schema}"."${tableName}" ALTER COLUMN "${fieldName}" SET DEFAULT false;`, + ); + } + + await workspaceQueryRunner.commitTransaction(); + await metadataQueryRunner.commitTransaction(); + } catch (error) { + await workspaceQueryRunner.rollbackTransaction(); + await metadataQueryRunner.rollbackTransaction(); + this.logger.log( + chalk.red(`Running command on workspace ${workspaceId} failed`), + ); + throw error; + } finally { + await workspaceQueryRunner.release(); + await metadataQueryRunner.release(); + } + + await this.workspaceCacheVersionService.incrementVersion(workspaceId); + + this.logger.log( + chalk.green(`Running command on workspace ${workspaceId} done`), + ); + } + + this.logger.log(chalk.green(`Command completed!`)); + } +} diff --git a/packages/twenty-server/src/database/commands/upgrade-version/0-22/0-22-update-message-channel-sync-stage-enum.command.ts b/packages/twenty-server/src/database/commands/upgrade-version/0-22/0-22-update-message-channel-sync-stage-enum.command.ts new file mode 100644 index 000000000000..e9de0891e37d --- /dev/null +++ b/packages/twenty-server/src/database/commands/upgrade-version/0-22/0-22-update-message-channel-sync-stage-enum.command.ts @@ -0,0 +1,233 @@ +import { Logger } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; + +import chalk from 'chalk'; +import { Command, CommandRunner, Option } from 'nest-commander'; +import { Repository } from 'typeorm'; +import { v4 } from 'uuid'; + +import { TypeORMService } from 'src/database/typeorm/typeorm.service'; +import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; +import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; +import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; +import { WorkspaceCacheVersionService } from 'src/engine/metadata-modules/workspace-cache-version/workspace-cache-version.service'; +import { WorkspaceStatusService } from 'src/engine/workspace-manager/workspace-status/services/workspace-status.service'; +import { MessageChannelSyncStage } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity'; + +interface UpdateMessageChannelSyncStageEnumCommandOptions { + workspaceId?: string; +} + +@Command({ + name: 'migrate-0.22:update-message-channel-sync-stage-enum', + description: 'Update messageChannel syncStage', +}) +export class UpdateMessageChannelSyncStageEnumCommand extends CommandRunner { + private readonly logger = new Logger( + UpdateMessageChannelSyncStageEnumCommand.name, + ); + constructor( + private readonly workspaceStatusService: WorkspaceStatusService, + @InjectRepository(FieldMetadataEntity, 'metadata') + private readonly fieldMetadataRepository: Repository<FieldMetadataEntity>, + @InjectRepository(ObjectMetadataEntity, 'metadata') + private readonly objectMetadataRepository: Repository<ObjectMetadataEntity>, + private readonly typeORMService: TypeORMService, + private readonly dataSourceService: DataSourceService, + private readonly workspaceCacheVersionService: WorkspaceCacheVersionService, + ) { + super(); + } + + @Option({ + flags: '-w, --workspace-id [workspace_id]', + description: 'workspace id. Command runs on all workspaces if not provided', + required: false, + }) + parseWorkspaceId(value: string): string { + return value; + } + + async run( + _passedParam: string[], + options: UpdateMessageChannelSyncStageEnumCommandOptions, + ): Promise<void> { + let workspaceIds: string[] = []; + + if (options.workspaceId) { + workspaceIds = [options.workspaceId]; + } else { + workspaceIds = await this.workspaceStatusService.getActiveWorkspaceIds(); + } + + if (!workspaceIds.length) { + this.logger.log(chalk.yellow('No workspace found')); + + return; + } else { + this.logger.log( + chalk.green(`Running command on ${workspaceIds.length} workspaces`), + ); + } + + for (const workspaceId of workspaceIds) { + try { + const dataSourceMetadatas = + await this.dataSourceService.getDataSourcesMetadataFromWorkspaceId( + workspaceId, + ); + + for (const dataSourceMetadata of dataSourceMetadatas) { + const workspaceDataSource = + await this.typeORMService.connectToDataSource(dataSourceMetadata); + + if (workspaceDataSource) { + const queryRunner = workspaceDataSource.createQueryRunner(); + + await queryRunner.connect(); + await queryRunner.startTransaction(); + + try { + await queryRunner.query( + `ALTER TYPE "${dataSourceMetadata.schema}"."messageChannel_syncStage_enum" RENAME TO "messageChannel_syncStage_enum_old"`, + ); + await queryRunner.query( + `CREATE TYPE "${dataSourceMetadata.schema}"."messageChannel_syncStage_enum" AS ENUM ( + 'FULL_MESSAGE_LIST_FETCH_PENDING', + 'PARTIAL_MESSAGE_LIST_FETCH_PENDING', + 'MESSAGE_LIST_FETCH_ONGOING', + 'MESSAGES_IMPORT_PENDING', + 'MESSAGES_IMPORT_ONGOING', + 'FAILED' + )`, + ); + + await queryRunner.query( + `ALTER TABLE "${dataSourceMetadata.schema}"."messageChannel" ALTER COLUMN "syncStage" DROP DEFAULT`, + ); + await queryRunner.query( + `ALTER TABLE "${dataSourceMetadata.schema}"."messageChannel" ALTER COLUMN "syncStage" TYPE text`, + ); + + await queryRunner.query( + `ALTER TABLE "${dataSourceMetadata.schema}"."messageChannel" ALTER COLUMN "syncStage" TYPE "${dataSourceMetadata.schema}"."messageChannel_syncStage_enum" USING "syncStage"::text::"${dataSourceMetadata.schema}"."messageChannel_syncStage_enum"`, + ); + + await queryRunner.query( + `ALTER TABLE "${dataSourceMetadata.schema}"."messageChannel" ALTER COLUMN "syncStage" SET DEFAULT 'FULL_MESSAGE_LIST_FETCH_PENDING'`, + ); + + await queryRunner.query( + `DROP TYPE "${dataSourceMetadata.schema}"."messageChannel_syncStage_enum_old"`, + ); + await queryRunner.commitTransaction(); + } catch (error) { + await queryRunner.rollbackTransaction(); + this.logger.log( + chalk.red(`Running command on workspace ${workspaceId} failed`), + ); + throw error; + } finally { + await queryRunner.release(); + } + } + } + + const messageChannelObjectMetadata = + await this.objectMetadataRepository.findOne({ + where: { nameSingular: 'messageChannel', workspaceId }, + }); + + if (!messageChannelObjectMetadata) { + this.logger.log( + chalk.yellow( + `Object metadata for messageChannel not found in workspace ${workspaceId}`, + ), + ); + + continue; + } + + const syncStageFieldMetadata = + await this.fieldMetadataRepository.findOne({ + where: { + name: 'syncStage', + workspaceId, + objectMetadataId: messageChannelObjectMetadata.id, + }, + }); + + if (!syncStageFieldMetadata) { + this.logger.log( + chalk.yellow( + `Field metadata for syncStage not found in workspace ${workspaceId}`, + ), + ); + + continue; + } + + const newOptions = [ + { + id: v4(), + value: MessageChannelSyncStage.FULL_MESSAGE_LIST_FETCH_PENDING, + label: 'Full messages list fetch pending', + position: 0, + color: 'blue', + }, + { + id: v4(), + value: MessageChannelSyncStage.PARTIAL_MESSAGE_LIST_FETCH_PENDING, + label: 'Partial messages list fetch pending', + position: 1, + color: 'blue', + }, + { + id: v4(), + value: MessageChannelSyncStage.MESSAGE_LIST_FETCH_ONGOING, + label: 'Messages list fetch ongoing', + position: 2, + color: 'orange', + }, + { + id: v4(), + value: MessageChannelSyncStage.MESSAGES_IMPORT_PENDING, + label: 'Messages import pending', + position: 3, + color: 'blue', + }, + { + id: v4(), + value: MessageChannelSyncStage.MESSAGES_IMPORT_ONGOING, + label: 'Messages import ongoing', + position: 4, + color: 'orange', + }, + { + id: v4(), + value: MessageChannelSyncStage.FAILED, + label: 'Failed', + position: 5, + color: 'red', + }, + ]; + + await this.fieldMetadataRepository.update(syncStageFieldMetadata.id, { + options: newOptions, + }); + + await this.workspaceCacheVersionService.incrementVersion(workspaceId); + + this.logger.log( + chalk.green(`Running command on workspace ${workspaceId} done`), + ); + } catch (error) { + this.logger.error( + `Migration failed for workspace ${workspaceId}: ${error.message}`, + ); + } + } + + this.logger.log(chalk.green(`Command completed!`)); + } +} diff --git a/packages/twenty-server/src/database/commands/0-20-update-message-channel-sync-status-enum.command.ts b/packages/twenty-server/src/database/commands/upgrade-version/0-22/0-22-update-message-channel-sync-status-enum.command.ts similarity index 91% rename from packages/twenty-server/src/database/commands/0-20-update-message-channel-sync-status-enum.command.ts rename to packages/twenty-server/src/database/commands/upgrade-version/0-22/0-22-update-message-channel-sync-status-enum.command.ts index 1a1e345ff232..d31a0fcd2e48 100644 --- a/packages/twenty-server/src/database/commands/0-20-update-message-channel-sync-status-enum.command.ts +++ b/packages/twenty-server/src/database/commands/upgrade-version/0-22/0-22-update-message-channel-sync-status-enum.command.ts @@ -1,17 +1,17 @@ -import { InjectRepository } from '@nestjs/typeorm'; import { Logger } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; +import chalk from 'chalk'; import { Command, CommandRunner, Option } from 'nest-commander'; import { Repository } from 'typeorm'; -import chalk from 'chalk'; import { v4 } from 'uuid'; -import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; -import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; import { TypeORMService } from 'src/database/typeorm/typeorm.service'; +import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; +import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; -import { WorkspaceCacheVersionService } from 'src/engine/metadata-modules/workspace-cache-version/workspace-cache-version.service'; import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; +import { WorkspaceCacheVersionService } from 'src/engine/metadata-modules/workspace-cache-version/workspace-cache-version.service'; import { MessageChannelSyncStatus } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity'; interface UpdateMessageChannelSyncStatusEnumCommandOptions { @@ -19,7 +19,7 @@ interface UpdateMessageChannelSyncStatusEnumCommandOptions { } @Command({ - name: 'migrate-0.20:update-message-channel-sync-status-enum', + name: 'migrate-0.22:update-message-channel-sync-status-enum', description: 'Update messageChannel syncStatus', }) export class UpdateMessageChannelSyncStatusEnumCommand extends CommandRunner { @@ -94,9 +94,7 @@ export class UpdateMessageChannelSyncStatusEnumCommand extends CommandRunner { `ALTER TYPE "${dataSourceMetadata.schema}"."messageChannel_syncStatus_enum" RENAME TO "messageChannel_syncStatus_enum_old"`, ); await queryRunner.query( - `CREATE TYPE "${dataSourceMetadata.schema}"."messageChannel_syncStatus_enum" AS ENUM ('PENDING', - 'SUCCEEDED', - 'FAILED', + `CREATE TYPE "${dataSourceMetadata.schema}"."messageChannel_syncStatus_enum" AS ENUM ( 'ONGOING', 'NOT_SYNCED', 'COMPLETED', @@ -166,27 +164,6 @@ export class UpdateMessageChannelSyncStatusEnumCommand extends CommandRunner { } const newOptions = [ - { - id: v4(), - value: MessageChannelSyncStatus.PENDING, - label: 'Pending', - position: 0, - color: 'blue', - }, - { - id: v4(), - value: MessageChannelSyncStatus.SUCCEEDED, - label: 'Succeeded', - position: 2, - color: 'green', - }, - { - id: v4(), - value: MessageChannelSyncStatus.FAILED, - label: 'Failed', - position: 3, - color: 'red', - }, { id: v4(), value: MessageChannelSyncStatus.ONGOING, diff --git a/packages/twenty-server/src/database/commands/upgrade-version/0-22/0-22-upgrade-version.command.ts b/packages/twenty-server/src/database/commands/upgrade-version/0-22/0-22-upgrade-version.command.ts new file mode 100644 index 000000000000..f42b3fd39cc9 --- /dev/null +++ b/packages/twenty-server/src/database/commands/upgrade-version/0-22/0-22-upgrade-version.command.ts @@ -0,0 +1,59 @@ +import { Command, CommandRunner, Option } from 'nest-commander'; + +import { AddNewAddressFieldToViewsWithDeprecatedAddressFieldCommand } from 'src/database/commands/upgrade-version/0-22/0-22-add-new-address-field-to-views-with-deprecated-address.command'; +import { FixObjectMetadataIdStandardIdCommand } from 'src/database/commands/upgrade-version/0-22/0-22-fix-object-metadata-id-standard-id.command'; +import { UpdateBooleanFieldsNullDefaultValuesAndNullValuesCommand } from 'src/database/commands/upgrade-version/0-22/0-22-update-boolean-fields-null-default-values-and-null-values.command'; +import { UpdateMessageChannelSyncStageEnumCommand } from 'src/database/commands/upgrade-version/0-22/0-22-update-message-channel-sync-stage-enum.command'; +import { UpdateMessageChannelSyncStatusEnumCommand } from 'src/database/commands/upgrade-version/0-22/0-22-update-message-channel-sync-status-enum.command'; + +interface UpdateBooleanFieldsNullDefaultValuesAndNullValuesCommandOptions { + workspaceId?: string; +} + +@Command({ + name: 'upgrade-0.22', + description: 'Upgrade to 0.22', +}) +export class UpgradeTo0_22Command extends CommandRunner { + constructor( + private readonly fixObjectMetadataIdStandardIdCommand: FixObjectMetadataIdStandardIdCommand, + private readonly updateBooleanFieldsNullDefaultValuesAndNullValuesCommand: UpdateBooleanFieldsNullDefaultValuesAndNullValuesCommand, + private readonly addNewAddressFieldToViewsWithDeprecatedAddressFieldCommand: AddNewAddressFieldToViewsWithDeprecatedAddressFieldCommand, + private readonly updateMessageChannelSyncStatusEnumCommand: UpdateMessageChannelSyncStatusEnumCommand, + private readonly updateMessageChannelSyncStageEnumCommand: UpdateMessageChannelSyncStageEnumCommand, + ) { + super(); + } + + @Option({ + flags: '-w, --workspace-id [workspace_id]', + description: 'workspace id. Command runs on all workspaces if not provided', + required: false, + }) + parseWorkspaceId(value: string): string { + return value; + } + + async run( + _passedParam: string[], + options: UpdateBooleanFieldsNullDefaultValuesAndNullValuesCommandOptions, + ): Promise<void> { + await this.fixObjectMetadataIdStandardIdCommand.run(_passedParam, options); + await this.updateBooleanFieldsNullDefaultValuesAndNullValuesCommand.run( + _passedParam, + options, + ); + await this.addNewAddressFieldToViewsWithDeprecatedAddressFieldCommand.run( + _passedParam, + options, + ); + await this.updateMessageChannelSyncStatusEnumCommand.run( + _passedParam, + options, + ); + await this.updateMessageChannelSyncStageEnumCommand.run( + _passedParam, + options, + ); + } +} diff --git a/packages/twenty-server/src/database/commands/upgrade-version/0-22/0-22-upgrade-version.module.ts b/packages/twenty-server/src/database/commands/upgrade-version/0-22/0-22-upgrade-version.module.ts new file mode 100644 index 000000000000..898f720bdb10 --- /dev/null +++ b/packages/twenty-server/src/database/commands/upgrade-version/0-22/0-22-upgrade-version.module.ts @@ -0,0 +1,56 @@ +import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; + +import { DataSeedDemoWorkspaceModule } from 'src/database/commands/data-seed-demo-workspace/data-seed-demo-workspace.module'; +import { AddNewAddressFieldToViewsWithDeprecatedAddressFieldCommand } from 'src/database/commands/upgrade-version/0-22/0-22-add-new-address-field-to-views-with-deprecated-address.command'; +import { FixObjectMetadataIdStandardIdCommand } from 'src/database/commands/upgrade-version/0-22/0-22-fix-object-metadata-id-standard-id.command'; +import { UpdateBooleanFieldsNullDefaultValuesAndNullValuesCommand } from 'src/database/commands/upgrade-version/0-22/0-22-update-boolean-fields-null-default-values-and-null-values.command'; +import { UpdateMessageChannelSyncStageEnumCommand } from 'src/database/commands/upgrade-version/0-22/0-22-update-message-channel-sync-stage-enum.command'; +import { UpdateMessageChannelSyncStatusEnumCommand } from 'src/database/commands/upgrade-version/0-22/0-22-update-message-channel-sync-status-enum.command'; +import { UpgradeTo0_22Command } from 'src/database/commands/upgrade-version/0-22/0-22-upgrade-version.command'; +import { TypeORMModule } from 'src/database/typeorm/typeorm.module'; +import { BillingSubscription } from 'src/engine/core-modules/billing/entities/billing-subscription.entity'; +import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity'; +import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; +import { WorkspaceModule } from 'src/engine/core-modules/workspace/workspace.module'; +import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module'; +import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; +import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; +import { ObjectMetadataModule } from 'src/engine/metadata-modules/object-metadata/object-metadata.module'; +import { WorkspaceCacheVersionModule } from 'src/engine/metadata-modules/workspace-cache-version/workspace-cache-version.module'; +import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; +import { WorkspaceManagerModule } from 'src/engine/workspace-manager/workspace-manager.module'; +import { WorkspaceStatusModule } from 'src/engine/workspace-manager/workspace-status/workspace-manager.module'; +import { WorkspaceSyncMetadataModule } from 'src/engine/workspace-manager/workspace-sync-metadata/workspace-sync-metadata.module'; + +@Module({ + imports: [ + WorkspaceManagerModule, + DataSourceModule, + TypeORMModule, + TypeOrmModule.forFeature( + [Workspace, BillingSubscription, FeatureFlagEntity], + 'core', + ), + TypeOrmModule.forFeature( + [FieldMetadataEntity, ObjectMetadataEntity], + 'metadata', + ), + WorkspaceModule, + WorkspaceDataSourceModule, + WorkspaceSyncMetadataModule, + WorkspaceStatusModule, + ObjectMetadataModule, + DataSeedDemoWorkspaceModule, + WorkspaceCacheVersionModule, + ], + providers: [ + FixObjectMetadataIdStandardIdCommand, + UpdateBooleanFieldsNullDefaultValuesAndNullValuesCommand, + UpdateMessageChannelSyncStatusEnumCommand, + UpdateMessageChannelSyncStageEnumCommand, + AddNewAddressFieldToViewsWithDeprecatedAddressFieldCommand, + UpgradeTo0_22Command, + ], +}) +export class UpgradeTo0_22CommandModule {} diff --git a/packages/twenty-server/src/database/typeorm-seeds/core/demo/workspaces.ts b/packages/twenty-server/src/database/typeorm-seeds/core/demo/workspaces.ts index adf4f886e9fa..8778e721a39d 100644 --- a/packages/twenty-server/src/database/typeorm-seeds/core/demo/workspaces.ts +++ b/packages/twenty-server/src/database/typeorm-seeds/core/demo/workspaces.ts @@ -16,7 +16,6 @@ export const seedWorkspaces = async ( 'domainName', 'inviteHash', 'logo', - 'subscriptionStatus', ]) .orIgnore() .values([ @@ -26,7 +25,6 @@ export const seedWorkspaces = async ( domainName: 'demo.dev', inviteHash: 'demo.dev-invite-hash', logo: 'data:image/png;base64,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', - subscriptionStatus: 'incomplete', }, ]) .execute(); diff --git a/packages/twenty-server/src/database/typeorm-seeds/core/feature-flags.ts b/packages/twenty-server/src/database/typeorm-seeds/core/feature-flags.ts index 3a36ad753ff7..a030ad88f8a8 100644 --- a/packages/twenty-server/src/database/typeorm-seeds/core/feature-flags.ts +++ b/packages/twenty-server/src/database/typeorm-seeds/core/feature-flags.ts @@ -41,7 +41,12 @@ export const seedFeatureFlags = async ( value: true, }, { - key: FeatureFlagKeys.IsContactCreationForSentAndReceivedEmailsEnabled, + key: FeatureFlagKeys.IsMessagingAliasFetchingEnabled, + workspaceId: workspaceId, + value: true, + }, + { + key: FeatureFlagKeys.IsGoogleCalendarSyncV2Enabled, workspaceId: workspaceId, value: true, }, diff --git a/packages/twenty-server/src/database/typeorm-seeds/core/workspaces.ts b/packages/twenty-server/src/database/typeorm-seeds/core/workspaces.ts index 58830c3c9d47..196746e8bb4d 100644 --- a/packages/twenty-server/src/database/typeorm-seeds/core/workspaces.ts +++ b/packages/twenty-server/src/database/typeorm-seeds/core/workspaces.ts @@ -15,12 +15,7 @@ export const seedWorkspaces = async ( const workspaces: { [key: string]: Pick< Workspace, - | 'id' - | 'displayName' - | 'domainName' - | 'inviteHash' - | 'logo' - | 'subscriptionStatus' + 'id' | 'displayName' | 'domainName' | 'inviteHash' | 'logo' >; } = { [SEED_APPLE_WORKSPACE_ID]: { @@ -29,7 +24,6 @@ export const seedWorkspaces = async ( domainName: 'apple.dev', inviteHash: 'apple.dev-invite-hash', logo: 'data:image/png;base64,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', - subscriptionStatus: 'incomplete', }, [SEED_TWENTY_WORKSPACE_ID]: { id: workspaceId, @@ -37,7 +31,6 @@ export const seedWorkspaces = async ( domainName: 'twenty.dev', inviteHash: 'twenty.dev-invite-hash', logo: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAeGVYSWZNTQAqAAAACAAEARIAAwAAAAEAAQAAARoABQAAAAEAAAA+ARsABQAAAAEAAABGh2kABAAAAAEAAABOAAAAAAAAAEgAAAABAAAASAAAAAEAA6ABAAMAAAABAAEAAKACAAQAAAABAAAAIKADAAQAAAABAAAAIAAAAABDGMxEAAAACXBIWXMAAAsTAAALEwEAmpwYAAAClGlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNi4wLjAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyIKICAgICAgICAgICAgeG1sbnM6ZXhpZj0iaHR0cDovL25zLmFkb2JlLmNvbS9leGlmLzEuMC8iPgogICAgICAgICA8dGlmZjpZUmVzb2x1dGlvbj43MjwvdGlmZjpZUmVzb2x1dGlvbj4KICAgICAgICAgPHRpZmY6WFJlc29sdXRpb24+NzI8L3RpZmY6WFJlc29sdXRpb24+CiAgICAgICAgIDx0aWZmOk9yaWVudGF0aW9uPjE8L3RpZmY6T3JpZW50YXRpb24+CiAgICAgICAgIDxleGlmOlBpeGVsWERpbWVuc2lvbj4xODA8L2V4aWY6UGl4ZWxYRGltZW5zaW9uPgogICAgICAgICA8ZXhpZjpDb2xvclNwYWNlPjE8L2V4aWY6Q29sb3JTcGFjZT4KICAgICAgICAgPGV4aWY6UGl4ZWxZRGltZW5zaW9uPjE4MDwvZXhpZjpQaXhlbFlEaW1lbnNpb24+CiAgICAgIDwvcmRmOkRlc2NyaXB0aW9uPgogICA8L3JkZjpSREY+CjwveDp4bXBtZXRhPgo1JQSrAAAFq0lEQVRYCe1WXWxURRQ+Z+b+dLfiQrEk/IViUEILlWQBrUWyREsoItGHLabRaMQUNdEH46tJH5AXTXwwQUXjAxEj3WgRIiiEUAUNNd1EjZRAJEAgIBZaWtrt7r135njmbrddCi1tDPqgJ7k7s/PzfedvzgzA//Jf9wDe1gHNJKASMFEOeH0KjL8+nUebcj9QeRdQqhMImlHflmN4ARECMWEH2Qkii/vjEw5vHL+TaCYr3kR2MkkS4EbMEQJDCKAAkYrhZl2kaCQD0zEH9+iBoMwivBu0dKQHLmV1ifBAoKJAaukJTw1SVvY65PdgYF/BQbja/hr2FeOZvlGorRkD088rYCwdIp55hRbJQbUSfFwhfKrkdi6304USUcnLBW+yI7wxy7Zc49YDYCXyrc+t+XgOcionAuzmuYtSwUkRiA7w/B+OvOX8ZIgLknc5op7ZTY9AVm1lgForKjEEyjA4fwYQc4p4TAsFGaEhxcDzhZarJUdYsC3mg0H+Miowe1lhSygEyf4srKEBg6U72aCth7ZZO004Qg/M6aUyNaAvWxFh0Z8KhA++AWQgwa1RRrDDBt2pMqIu63dP1MvXjQXVKXpUKjWbveCKHFaARwmL5MPGKzSoPN5rs6I6VNx4JgDLAokOs6oMrPr2YzwSJtoFxO45Z4MdAuEF8iDHVrrC56j4ZJQxigS2KyP6D3UMhHzbkAOfjl+TeCjsF/08+A7ViZz+yBZynsqFSjjoo8wbRDmLwA1yqt11ZHhmTEhDuVBhbcJrlLJLpcta5zDH5Pn4+rYjLejTOzrXWTUn1uKlZIvJ5rxUtdBdy9/X3614T71kRtrfwIPKF9V6QB2J2NLh5CXhGSzKuSRN4h4vEbJu73bMmFMhwuQbAjy7SDRAN7XaEelylvsmFExuQ69qPf64fM4QJA6TlWpAZfpG7jYnJ6AZfHZKzP/4hxRtb8a+o1usVUGf3iJ9RDbEc7R0dUafiqBYuecTvG6OZSqFnCUFIbYK88AL2/QeaeET0M/uz+nOypyoNqSGvG11/viE24pOzxBMiJd4hUrbtmF/3Wa6j7T+zSbh6Kz+PSrEQ6078KohT2/nwI6WpFFiSCr36W+qDxIt2U1LzFBVy3GnMHdTy4pUJVucfKHJz9a/SuV1L6rT65uI1jaq0089SzPMTBOT37S/eMBYaf4vbaWpi78INpp+cczN/2JJJA6H64vG5GMvZ+9dsyn4fsNmJn9anVmfpNlmnhW8yYiREBQhgMmJQpxNaeY6UTxd6BvytrbVQbypw+491bExNn3Zhlhs4WILovMcFNGgX53XKGsPfI7nDTnHnNP6Rrm1AmYNuzXRBvKGmBfvTbZISDWoB548sCab6fmgrLxmfiw2F4iLluQaQll1CS1Zs+8zPDcWuYEbW4FislH9guVLk0cbg2x2Z2l0HsRiCwLIak9yyUZfX5Ykavam8Mx45AZ2uA6M4hjzb5ItN25f9swvC8nXO20ohSnRCh8GNVhMzkXoKru/diLkhmR0Ao1JXJjo6ioPvcaF5U1blIErSz3pS5svHgRf9Ugha3fvwtO3s7yANykPFKxf2XhumtDuGhlwXcWYFB4Xm5zmWk/r96TwZH09ubdKuAJpcTspBbqqkqH1LjoLLIqWW8plt9vK5RtPBJT6+iv7R1Nk9u/nAjxBmVQIrl9M590fONNcrrya+rUIJJrrVnn0c8iZHnqX3QkFuNKHsCWceL5G0FoBZz2XCT565vINJb9mgvyTT0IDLJUlQUnQKkpSCxImBF4Ba3IemFQOwJB7XS17bLZX+o5gy7XN1wrfnj1GufiQl0x/IjIpBdLpeOjmXV/iMb4lP43y66ZEyRIvo9OOEPzEApiV5uv5zsrIs7pxVbCuYTk1PF9B4Vugmd8ed5Z7GH1EicLQP0heoCSMxzvspjjZ/wJ5QYm/3/4Fu4CabsKI91cAAAAASUVORK5CYII=', - subscriptionStatus: 'incomplete', }, }; @@ -50,7 +43,6 @@ export const seedWorkspaces = async ( 'domainName', 'inviteHash', 'logo', - 'subscriptionStatus', ]) .orIgnore() .values(workspaces[workspaceId]) diff --git a/packages/twenty-server/src/database/typeorm-seeds/workspace/calendar-channel.ts b/packages/twenty-server/src/database/typeorm-seeds/workspace/calendar-channel.ts index 1c217c07cf8e..14a4117ee3c9 100644 --- a/packages/twenty-server/src/database/typeorm-seeds/workspace/calendar-channel.ts +++ b/packages/twenty-server/src/database/typeorm-seeds/workspace/calendar-channel.ts @@ -1,7 +1,7 @@ import { EntityManager } from 'typeorm'; import { DEV_SEED_CONNECTED_ACCOUNT_IDS } from 'src/database/typeorm-seeds/workspace/connected-account'; -import { CalendarChannelVisibility } from 'src/modules/calendar/standard-objects/calendar-channel.workspace-entity'; +import { CalendarChannelVisibility } from 'src/modules/calendar/common/standard-objects/calendar-channel.workspace-entity'; const tableName = 'calendarChannel'; diff --git a/packages/twenty-server/src/database/typeorm-seeds/workspace/calendar-event-participants.ts b/packages/twenty-server/src/database/typeorm-seeds/workspace/calendar-event-participants.ts index 784ad55af836..4efc44406120 100644 --- a/packages/twenty-server/src/database/typeorm-seeds/workspace/calendar-event-participants.ts +++ b/packages/twenty-server/src/database/typeorm-seeds/workspace/calendar-event-participants.ts @@ -2,7 +2,7 @@ import { EntityManager } from 'typeorm'; import { DEV_SEED_PERSON_IDS } from 'src/database/typeorm-seeds/workspace/people'; import { DEV_SEED_WORKSPACE_MEMBER_IDS } from 'src/database/typeorm-seeds/workspace/workspace-members'; -import { CalendarEventParticipantResponseStatus } from 'src/modules/calendar/standard-objects/calendar-event-participant.workspace-entity'; +import { CalendarEventParticipantResponseStatus } from 'src/modules/calendar/common/standard-objects/calendar-event-participant.workspace-entity'; const tableName = 'calendarEventParticipant'; diff --git a/packages/twenty-server/src/database/typeorm-seeds/workspace/companies.ts b/packages/twenty-server/src/database/typeorm-seeds/workspace/companies.ts index 2762a29777c3..0d552b95e72e 100644 --- a/packages/twenty-server/src/database/typeorm-seeds/workspace/companies.ts +++ b/packages/twenty-server/src/database/typeorm-seeds/workspace/companies.ts @@ -29,7 +29,12 @@ export const seedCompanies = async ( 'id', 'name', 'domainName', - 'address', + 'addressAddressStreet1', + 'addressAddressStreet2', + 'addressAddressCity', + 'addressAddressState', + 'addressAddressPostcode', + 'addressAddressCountry', 'position', ]) .orIgnore() @@ -38,91 +43,156 @@ export const seedCompanies = async ( id: DEV_SEED_COMPANY_IDS.LINKEDIN, name: 'Linkedin', domainName: 'linkedin.com', - address: '', + addressAddressStreet1: 'Eutaw Street', + addressAddressStreet2: null, + addressAddressCity: 'Dublin', + addressAddressState: null, + addressAddressPostcode: null, + addressAddressCountry: 'Ireland', position: 1, }, { id: DEV_SEED_COMPANY_IDS.FACEBOOK, name: 'Facebook', domainName: 'facebook.com', - address: '', + addressAddressStreet1: null, + addressAddressStreet2: null, + addressAddressCity: null, + addressAddressState: null, + addressAddressPostcode: null, + addressAddressCountry: null, position: 2, }, { id: DEV_SEED_COMPANY_IDS.QONTO, name: 'Qonto', domainName: 'qonto.com', - address: '', + addressAddressStreet1: '18 rue de navarrin', + addressAddressStreet2: null, + addressAddressCity: 'Paris', + addressAddressState: null, + addressAddressPostcode: '75009', + addressAddressCountry: 'France', position: 3, }, { id: DEV_SEED_COMPANY_IDS.MICROSOFT, name: 'Microsoft', domainName: 'microsoft.com', - address: '', + addressAddressStreet1: null, + addressAddressStreet2: null, + addressAddressCity: null, + addressAddressState: null, + addressAddressPostcode: null, + addressAddressCountry: null, position: 4, }, { id: DEV_SEED_COMPANY_IDS.AIRBNB, name: 'Airbnb', domainName: 'airbnb.com', - address: '', + addressAddressStreet1: '888 Brannan St', + addressAddressStreet2: null, + addressAddressCity: 'San Francisco', + addressAddressState: 'CA', + addressAddressPostcode: '94103', + addressAddressCountry: 'United States', position: 5, }, { id: DEV_SEED_COMPANY_IDS.GOOGLE, name: 'Google', domainName: 'google.com', - address: '', + addressAddressStreet1: '760 Market St', + addressAddressStreet2: 'Floor 10', + addressAddressCity: 'San Francisco', + addressAddressState: null, + addressAddressPostcode: '94102', + addressAddressCountry: 'United States', position: 6, }, { id: DEV_SEED_COMPANY_IDS.NETFLIX, name: 'Netflix', domainName: 'netflix.com', - address: '', + addressAddressStreet1: '2300 Harrison St', + addressAddressStreet2: null, + addressAddressCity: 'San Francisco', + addressAddressState: 'CA', + addressAddressPostcode: '94110', + addressAddressCountry: 'United States', position: 7, }, { id: DEV_SEED_COMPANY_IDS.LIBEO, name: 'Libeo', domainName: 'libeo.io', - address: '', + addressAddressStreet1: null, + addressAddressStreet2: null, + addressAddressCity: null, + addressAddressState: null, + addressAddressPostcode: null, + addressAddressCountry: null, position: 8, }, { id: DEV_SEED_COMPANY_IDS.CLAAP, name: 'Claap', domainName: 'claap.io', - address: '', + addressAddressStreet1: null, + addressAddressStreet2: null, + addressAddressCity: null, + addressAddressState: null, + addressAddressPostcode: null, + addressAddressCountry: null, position: 9, }, { id: DEV_SEED_COMPANY_IDS.HASURA, name: 'Hasura', domainName: 'hasura.io', - address: '', + addressAddressStreet1: null, + addressAddressStreet2: null, + addressAddressCity: null, + addressAddressState: null, + addressAddressPostcode: null, + addressAddressCountry: null, position: 10, }, { id: DEV_SEED_COMPANY_IDS.WEWORK, name: 'Wework', domainName: 'wework.com', - address: '', + addressAddressStreet1: null, + addressAddressStreet2: null, + addressAddressCity: null, + addressAddressState: null, + addressAddressPostcode: null, + addressAddressCountry: null, position: 11, }, { id: DEV_SEED_COMPANY_IDS.SAMSUNG, name: 'Samsung', domainName: 'samsung.com', - address: '', + addressAddressStreet1: null, + addressAddressStreet2: null, + addressAddressCity: null, + addressAddressState: null, + addressAddressPostcode: null, + addressAddressCountry: null, position: 12, }, { id: DEV_SEED_COMPANY_IDS.ALGOLIA, name: 'Algolia', domainName: 'algolia.com', - address: '', + addressAddressStreet1: null, + addressAddressStreet2: null, + addressAddressCity: null, + addressAddressState: null, + addressAddressPostcode: null, + addressAddressCountry: null, position: 13, }, ]) diff --git a/packages/twenty-server/src/database/typeorm-seeds/workspace/opportunities.ts b/packages/twenty-server/src/database/typeorm-seeds/workspace/opportunities.ts index b314205ef7bb..b1c00b54dffc 100644 --- a/packages/twenty-server/src/database/typeorm-seeds/workspace/opportunities.ts +++ b/packages/twenty-server/src/database/typeorm-seeds/workspace/opportunities.ts @@ -1,7 +1,7 @@ import { EntityManager } from 'typeorm'; -import { DEV_SEED_PERSON_IDS } from 'src/database/typeorm-seeds/workspace/people'; import { DEV_SEED_COMPANY_IDS } from 'src/database/typeorm-seeds/workspace/companies'; +import { DEV_SEED_PERSON_IDS } from 'src/database/typeorm-seeds/workspace/people'; const tableName = 'opportunity'; @@ -25,7 +25,6 @@ export const seedOpportunity = async ( 'amountAmountMicros', 'amountCurrencyCode', 'closeDate', - 'probability', 'stage', 'position', 'pointOfContactId', @@ -39,7 +38,6 @@ export const seedOpportunity = async ( amountAmountMicros: 100000, amountCurrencyCode: 'USD', closeDate: new Date(), - probability: 0.5, stage: 'NEW', position: 1, pointOfContactId: DEV_SEED_PERSON_IDS.CHRISTOPH, @@ -51,7 +49,6 @@ export const seedOpportunity = async ( amountAmountMicros: 2000000, amountCurrencyCode: 'USD', closeDate: new Date(), - probability: 0.5, stage: 'MEETING', position: 2, pointOfContactId: DEV_SEED_PERSON_IDS.CHRISTOPHER_G, @@ -63,7 +60,6 @@ export const seedOpportunity = async ( amountAmountMicros: 300000, amountCurrencyCode: 'USD', closeDate: new Date(), - probability: 0.5, stage: 'PROPOSAL', position: 3, pointOfContactId: DEV_SEED_PERSON_IDS.NICHOLAS, @@ -75,7 +71,6 @@ export const seedOpportunity = async ( amountAmountMicros: 4000000, amountCurrencyCode: 'USD', closeDate: new Date(), - probability: 0.5, stage: 'PROPOSAL', position: 4, pointOfContactId: DEV_SEED_PERSON_IDS.MATTHEW, diff --git a/packages/twenty-server/src/database/typeorm/core/migrations/1719327438923-useEnumForSubscriptionStatusInterval.ts b/packages/twenty-server/src/database/typeorm/core/migrations/1719327438923-useEnumForSubscriptionStatusInterval.ts new file mode 100644 index 000000000000..c2894f0fd48a --- /dev/null +++ b/packages/twenty-server/src/database/typeorm/core/migrations/1719327438923-useEnumForSubscriptionStatusInterval.ts @@ -0,0 +1,61 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class UseEnumForSubscriptionStatusInterval1719327438923 + implements MigrationInterface +{ + name = 'UseEnumForSubscriptionStatusInterval1719327438923'; + + public async up(queryRunner: QueryRunner): Promise<void> { + await queryRunner.query( + `CREATE TYPE "core"."billingSubscription_status_enum" AS ENUM('active', 'canceled', 'incomplete', 'incomplete_expired', 'past_due', 'paused', 'trialing', 'unpaid')`, + ); + await queryRunner.query( + `ALTER TABLE "core"."billingSubscription" ALTER COLUMN "status" TYPE "core"."billingSubscription_status_enum" USING "status"::"core"."billingSubscription_status_enum"`, + ); + await queryRunner.query( + `ALTER TABLE "core"."billingSubscription" ALTER COLUMN "status" SET NOT NULL`, + ); + await queryRunner.query( + `CREATE TYPE "core"."billingSubscription_interval_enum" AS ENUM('day', 'month', 'week', 'year')`, + ); + await queryRunner.query( + `ALTER TABLE "core"."billingSubscription" ALTER COLUMN "interval" TYPE "core"."billingSubscription_interval_enum" USING "interval"::"core"."billingSubscription_interval_enum"`, + ); + await queryRunner.query( + `CREATE TYPE "core"."workspace_subscriptionstatus_enum" AS ENUM('active', 'canceled', 'incomplete', 'incomplete_expired', 'past_due', 'paused', 'trialing', 'unpaid')`, + ); + await queryRunner.query( + `ALTER TABLE "core"."workspace" ALTER COLUMN "subscriptionStatus" DROP DEFAULT`, + ); + await queryRunner.query( + `ALTER TABLE "core"."workspace" ALTER COLUMN "subscriptionStatus" TYPE "core"."workspace_subscriptionstatus_enum" USING "subscriptionStatus"::"core"."workspace_subscriptionstatus_enum"`, + ); + await queryRunner.query( + `ALTER TABLE "core"."workspace" ALTER COLUMN "subscriptionStatus" SET NOT NULL`, + ); + await queryRunner.query( + `ALTER TABLE "core"."workspace" ALTER COLUMN "subscriptionStatus" SET DEFAULT 'incomplete'::"core"."workspace_subscriptionstatus_enum"`, + ); + } + + public async down(queryRunner: QueryRunner): Promise<void> { + await queryRunner.query( + `ALTER TABLE "core"."workspace" ALTER COLUMN "subscriptionStatus" TYPE text`, + ); + await queryRunner.query( + `DROP TYPE "core"."workspace_subscriptionstatus_enum"`, + ); + await queryRunner.query( + `ALTER TABLE "core"."billingSubscription" ALTER COLUMN "interval" TYPE text`, + ); + await queryRunner.query( + `DROP TYPE "core"."billingSubscription_interval_enum"`, + ); + await queryRunner.query( + `ALTER TABLE "core"."billingSubscription" ALTER COLUMN "status" TYPE text`, + ); + await queryRunner.query( + `DROP TYPE "core"."billingSubscription_status_enum"`, + ); + } +} diff --git a/packages/twenty-server/src/database/typeorm/core/migrations/1719494707738-removeSubscriptionStatusFromCoreWorkspace.ts b/packages/twenty-server/src/database/typeorm/core/migrations/1719494707738-removeSubscriptionStatusFromCoreWorkspace.ts new file mode 100644 index 000000000000..85e64b408c4c --- /dev/null +++ b/packages/twenty-server/src/database/typeorm/core/migrations/1719494707738-removeSubscriptionStatusFromCoreWorkspace.ts @@ -0,0 +1,25 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class RemoveSubscriptionStatusFromCoreWorkspace1719494707738 + implements MigrationInterface +{ + name = 'RemoveSubscriptionStatusFromCoreWorkspace1719494707738'; + + public async up(queryRunner: QueryRunner): Promise<void> { + await queryRunner.query( + `ALTER TABLE "core"."workspace" DROP COLUMN "subscriptionStatus"`, + ); + await queryRunner.query( + `DROP TYPE "core"."workspace_subscriptionstatus_enum"`, + ); + } + + public async down(queryRunner: QueryRunner): Promise<void> { + await queryRunner.query( + `CREATE TYPE "core"."workspace_subscriptionstatus_enum" AS ENUM('active', 'canceled', 'incomplete', 'incomplete_expired', 'past_due', 'paused', 'trialing', 'unpaid')`, + ); + await queryRunner.query( + `ALTER TABLE "core"."workspace" ADD "subscriptionStatus" "core"."workspace_subscriptionstatus_enum" NOT NULL DEFAULT 'incomplete'`, + ); + } +} diff --git a/packages/twenty-server/src/database/typeorm/metadata/migrations/1718985664968-addIndexMetadataTable.ts b/packages/twenty-server/src/database/typeorm/metadata/migrations/1718985664968-addIndexMetadataTable.ts new file mode 100644 index 000000000000..c4d5afca948d --- /dev/null +++ b/packages/twenty-server/src/database/typeorm/metadata/migrations/1718985664968-addIndexMetadataTable.ts @@ -0,0 +1,28 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class AddIndexMetadataTable1718985664968 implements MigrationInterface { + name = 'AddIndexMetadataTable1718985664968'; + + public async up(queryRunner: QueryRunner): Promise<void> { + await queryRunner.query( + `CREATE TABLE "metadata"."indexMetadata" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "name" character varying NOT NULL, "workspaceId" character varying, "objectMetadataId" uuid NOT NULL, CONSTRAINT "PK_f73bb3c3678aee204e341f0ca4e" PRIMARY KEY ("id"))`, + ); + await queryRunner.query( + `CREATE TABLE "metadata"."indexFieldMetadata" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "indexMetadataId" uuid NOT NULL, "fieldMetadataId" uuid NOT NULL, "order" integer NOT NULL, CONSTRAINT "PK_5928f67e43eff7d95aa79fd96fd" PRIMARY KEY ("id"))`, + ); + await queryRunner.query( + `ALTER TABLE "metadata"."indexMetadata" ADD CONSTRAINT "FK_051487e9b745cb175950130b63f" FOREIGN KEY ("objectMetadataId") REFERENCES "metadata"."objectMetadata"("id") ON DELETE CASCADE ON UPDATE NO ACTION`, + ); + await queryRunner.query( + `ALTER TABLE "metadata"."indexFieldMetadata" ADD CONSTRAINT "FK_b20192c432612eb710801dd5664" FOREIGN KEY ("indexMetadataId") REFERENCES "metadata"."indexMetadata"("id") ON DELETE CASCADE ON UPDATE NO ACTION`, + ); + await queryRunner.query( + `ALTER TABLE "metadata"."indexFieldMetadata" ADD CONSTRAINT "FK_be0950612a54b58c72bd62d629e" FOREIGN KEY ("fieldMetadataId") REFERENCES "metadata"."fieldMetadata"("id") ON DELETE CASCADE ON UPDATE NO ACTION`, + ); + } + + public async down(queryRunner: QueryRunner): Promise<void> { + await queryRunner.query(`DROP TABLE "metadata"."indexFieldMetadata"`); + await queryRunner.query(`DROP TABLE "metadata"."indexMetadata"`); + } +} diff --git a/packages/twenty-server/src/database/typeorm/metadata/migrations/1720524654925-addDateColumnsToIndexMetadata.ts b/packages/twenty-server/src/database/typeorm/metadata/migrations/1720524654925-addDateColumnsToIndexMetadata.ts new file mode 100644 index 000000000000..6753c5c017ed --- /dev/null +++ b/packages/twenty-server/src/database/typeorm/metadata/migrations/1720524654925-addDateColumnsToIndexMetadata.ts @@ -0,0 +1,37 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class AddDateColumnsToIndexMetadata1720524654925 + implements MigrationInterface +{ + name = 'AddDateColumnsToIndexMetadata1720524654925'; + + public async up(queryRunner: QueryRunner): Promise<void> { + await queryRunner.query( + `ALTER TABLE "metadata"."indexMetadata" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now()`, + ); + await queryRunner.query( + `ALTER TABLE "metadata"."indexMetadata" ADD "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now()`, + ); + await queryRunner.query( + `ALTER TABLE "metadata"."indexFieldMetadata" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now()`, + ); + await queryRunner.query( + `ALTER TABLE "metadata"."indexFieldMetadata" ADD "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now()`, + ); + } + + public async down(queryRunner: QueryRunner): Promise<void> { + await queryRunner.query( + `ALTER TABLE "metadata"."indexFieldMetadata" DROP COLUMN "updatedAt"`, + ); + await queryRunner.query( + `ALTER TABLE "metadata"."indexFieldMetadata" DROP COLUMN "createdAt"`, + ); + await queryRunner.query( + `ALTER TABLE "metadata"."indexMetadata" DROP COLUMN "updatedAt"`, + ); + await queryRunner.query( + `ALTER TABLE "metadata"."indexMetadata" DROP COLUMN "createdAt"`, + ); + } +} diff --git a/packages/twenty-server/src/database/typeorm/typeorm.module.ts b/packages/twenty-server/src/database/typeorm/typeorm.module.ts index b24fe05bad94..bda843eae6f4 100644 --- a/packages/twenty-server/src/database/typeorm/typeorm.module.ts +++ b/packages/twenty-server/src/database/typeorm/typeorm.module.ts @@ -3,6 +3,7 @@ import { TypeOrmModule, TypeOrmModuleOptions } from '@nestjs/typeorm'; import { typeORMCoreModuleOptions } from 'src/database/typeorm/core/core.datasource'; import { EnvironmentModule } from 'src/engine/integrations/environment/environment.module'; +import { TwentyORMModule } from 'src/engine/twenty-orm/twenty-orm.module'; import { TypeORMService } from './typeorm.service'; @@ -28,6 +29,9 @@ const coreTypeORMFactory = async (): Promise<TypeOrmModuleOptions> => ({ useFactory: coreTypeORMFactory, name: 'core', }), + TwentyORMModule.register({ + workspaceEntities: ['dist/src/**/*.workspace-entity{.ts,.js}'], + }), EnvironmentModule, ], providers: [TypeORMService], diff --git a/packages/twenty-server/src/engine/api/__mocks__/object-metadata-item.mock.ts b/packages/twenty-server/src/engine/api/__mocks__/object-metadata-item.mock.ts index 8767507e5e57..d988d614a298 100644 --- a/packages/twenty-server/src/engine/api/__mocks__/object-metadata-item.mock.ts +++ b/packages/twenty-server/src/engine/api/__mocks__/object-metadata-item.mock.ts @@ -75,7 +75,7 @@ const fieldMultiSelectMock = { ], }; -const fieldRelationMock = { +export const fieldRelationMock = { name: 'fieldRelation', type: FieldMetadataType.RELATION, fromRelationMetadata: { @@ -145,13 +145,6 @@ const fieldNumericMock = { defaultValue: null, }; -const fieldProbabilityMock = { - name: 'fieldProbability', - type: FieldMetadataType.PROBABILITY, - isNullable: true, - defaultValue: null, -}; - const fieldFullNameMock = { name: 'fieldFullName', type: FieldMetadataType.FULL_NAME, @@ -206,7 +199,6 @@ export const fields = [ fieldBooleanMock, fieldNumberMock, fieldNumericMock, - fieldProbabilityMock, fieldLinkMock, fieldLinksMock, fieldCurrencyMock, diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-config/graphql-config.service.ts b/packages/twenty-server/src/engine/api/graphql/graphql-config/graphql-config.service.ts index b71ff69d4dd8..266dbf2ce48c 100644 --- a/packages/twenty-server/src/engine/api/graphql/graphql-config/graphql-config.service.ts +++ b/packages/twenty-server/src/engine/api/graphql/graphql-config/graphql-config.service.ts @@ -141,8 +141,10 @@ export class GraphQLConfigService // Create a new contextId for each request const contextId = ContextIdFactory.create(); - // Register the request in the contextId - this.moduleRef.registerRequestByContextId(context.req, contextId); + if (this.moduleRef.registerRequestByContextId) { + // Register the request in the contextId + this.moduleRef.registerRequestByContextId(context.req, contextId); + } // Resolve the WorkspaceSchemaFactory for the contextId const workspaceFactory = await this.moduleRef.resolve( diff --git a/packages/twenty-server/src/engine/api/graphql/metadata.module-factory.ts b/packages/twenty-server/src/engine/api/graphql/metadata.module-factory.ts index 5c28d63f3947..3d2e2b7e1584 100644 --- a/packages/twenty-server/src/engine/api/graphql/metadata.module-factory.ts +++ b/packages/twenty-server/src/engine/api/graphql/metadata.module-factory.ts @@ -1,15 +1,15 @@ import { YogaDriverConfig } from '@graphql-yoga/nestjs'; import GraphQLJSON from 'graphql-type-json'; -import { EnvironmentService } from 'src/engine/integrations/environment/environment.service'; -import { ExceptionHandlerService } from 'src/engine/integrations/exception-handler/exception-handler.service'; -import { useExceptionHandler } from 'src/engine/integrations/exception-handler/hooks/use-exception-handler.hook'; +import { useCachedMetadata } from 'src/engine/api/graphql/graphql-config/hooks/use-cached-metadata'; import { useThrottler } from 'src/engine/api/graphql/graphql-config/hooks/use-throttler'; import { MetadataGraphQLApiModule } from 'src/engine/api/graphql/metadata-graphql-api.module'; -import { renderApolloPlayground } from 'src/engine/utils/render-apollo-playground.util'; +import { useGraphQLErrorHandlerHook } from 'src/engine/core-modules/graphql/hooks/use-graphql-error-handler.hook'; import { DataloaderService } from 'src/engine/dataloaders/dataloader.service'; -import { useCachedMetadata } from 'src/engine/api/graphql/graphql-config/hooks/use-cached-metadata'; import { CacheStorageService } from 'src/engine/integrations/cache-storage/cache-storage.service'; +import { EnvironmentService } from 'src/engine/integrations/environment/environment.service'; +import { ExceptionHandlerService } from 'src/engine/integrations/exception-handler/exception-handler.service'; +import { renderApolloPlayground } from 'src/engine/utils/render-apollo-playground.util'; export const metadataModuleFactory = async ( environmentService: EnvironmentService, @@ -32,7 +32,7 @@ export const metadataModuleFactory = async ( return context.req.user?.id ?? context.req.ip ?? 'anonymous'; }, }), - useExceptionHandler({ + useGraphQLErrorHandlerHook({ exceptionHandlerService, }), useCachedMetadata({ diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/__tests__/args-string.factory.spec.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/__tests__/args-string.factory.spec.ts index 4cc9394e1adb..f4be0b8fb204 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/__tests__/args-string.factory.spec.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/__tests__/args-string.factory.spec.ts @@ -68,10 +68,7 @@ describe('ArgsStringFactory', () => { it('when orderBy is present, should return an array of objects', () => { const args = { - orderBy: { - id: 'AscNullsFirst', - name: 'AscNullsFirst', - }, + orderBy: [{ id: 'AscNullsFirst' }, { name: 'AscNullsFirst' }], }; argsAliasCreate.mockReturnValue(args); @@ -85,11 +82,11 @@ describe('ArgsStringFactory', () => { it('when orderBy is present with position criteria, should return position at the end of the list', () => { const args = { - orderBy: { - position: 'AscNullsFirst', - id: 'AscNullsFirst', - name: 'AscNullsFirst', - }, + orderBy: [ + { position: 'AscNullsFirst' }, + { id: 'AscNullsFirst' }, + { name: 'AscNullsFirst' }, + ], }; argsAliasCreate.mockReturnValue(args); @@ -103,11 +100,11 @@ describe('ArgsStringFactory', () => { it('when orderBy is present with position in the middle, should return position at the end of the list', () => { const args = { - orderBy: { - id: 'AscNullsFirst', - position: 'AscNullsFirst', - name: 'AscNullsFirst', - }, + orderBy: [ + { id: 'AscNullsFirst' }, + { position: 'AscNullsFirst' }, + { name: 'AscNullsFirst' }, + ], }; argsAliasCreate.mockReturnValue(args); diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/__tests__/find-duplicates-query.factory.spec.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/__tests__/find-duplicates-query.factory.spec.ts deleted file mode 100644 index b2423c9207f7..000000000000 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/__tests__/find-duplicates-query.factory.spec.ts +++ /dev/null @@ -1,206 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; - -import { RecordFilter } from 'src/engine/api/graphql/workspace-query-builder/interfaces/record.interface'; -import { FindDuplicatesResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; - -import { ArgsAliasFactory } from 'src/engine/api/graphql/workspace-query-builder/factories/args-alias.factory'; -import { FieldsStringFactory } from 'src/engine/api/graphql/workspace-query-builder/factories/fields-string.factory'; -import { FindDuplicatesQueryFactory } from 'src/engine/api/graphql/workspace-query-builder/factories/find-duplicates-query.factory'; -import { workspaceQueryBuilderOptionsMock } from 'src/engine/api/graphql/workspace-query-builder/__mocks__/workspace-query-builder-options.mock'; - -describe('FindDuplicatesQueryFactory', () => { - let service: FindDuplicatesQueryFactory; - const argAliasCreate = jest.fn(); - - beforeEach(async () => { - jest.resetAllMocks(); - - const module: TestingModule = await Test.createTestingModule({ - providers: [ - FindDuplicatesQueryFactory, - { - provide: FieldsStringFactory, - useValue: { - create: jest.fn().mockResolvedValue('fieldsString'), - // Mock implementation of FieldsStringFactory methods if needed - }, - }, - { - provide: ArgsAliasFactory, - useValue: { - create: argAliasCreate, - // Mock implementation of ArgsAliasFactory methods if needed - }, - }, - ], - }).compile(); - - service = module.get<FindDuplicatesQueryFactory>( - FindDuplicatesQueryFactory, - ); - }); - - it('should be defined', () => { - expect(service).toBeDefined(); - }); - - describe('create', () => { - it('should return (first: 0) as a filter when args are missing', async () => { - const args: FindDuplicatesResolverArgs<RecordFilter> = {}; - - const query = await service.create( - args, - workspaceQueryBuilderOptionsMock, - ); - - expect(query.trim()).toEqual(`query { - objectNameCollection(first: 0) { - fieldsString - } - }`); - }); - - it('should use firstName and lastName as a filter when both args are present', async () => { - argAliasCreate.mockReturnValue({ - nameFirstName: 'John', - nameLastName: 'Doe', - }); - - const args: FindDuplicatesResolverArgs<RecordFilter> = { - data: { - name: { - firstName: 'John', - lastName: 'Doe', - }, - } as unknown as RecordFilter, - }; - - const query = await service.create(args, { - ...workspaceQueryBuilderOptionsMock, - objectMetadataItem: { - ...workspaceQueryBuilderOptionsMock.objectMetadataItem, - nameSingular: 'person', - }, - }); - - expect(query.trim()).toEqual(`query { - personCollection(filter: {or:[{nameFirstName:{eq:"John"},nameLastName:{eq:"Doe"}}]}) { - fieldsString - } - }`); - }); - - it('should ignore an argument if the string length is less than 3', async () => { - argAliasCreate.mockReturnValue({ - linkedinLinkUrl: 'ab', - email: 'test@test.com', - }); - - const args: FindDuplicatesResolverArgs<RecordFilter> = { - data: { - linkedinLinkUrl: 'ab', - email: 'test@test.com', - } as unknown as RecordFilter, - }; - - const query = await service.create(args, { - ...workspaceQueryBuilderOptionsMock, - objectMetadataItem: { - ...workspaceQueryBuilderOptionsMock.objectMetadataItem, - nameSingular: 'person', - }, - }); - - expect(query.trim()).toEqual(`query { - personCollection(filter: {or:[{email:{eq:"test@test.com"}}]}) { - fieldsString - } - }`); - }); - - it('should return (first: 0) as a filter when only firstName is present', async () => { - argAliasCreate.mockReturnValue({ - nameFirstName: 'John', - }); - - const args: FindDuplicatesResolverArgs<RecordFilter> = { - data: { - name: { - firstName: 'John', - }, - } as unknown as RecordFilter, - }; - - const query = await service.create(args, { - ...workspaceQueryBuilderOptionsMock, - objectMetadataItem: { - ...workspaceQueryBuilderOptionsMock.objectMetadataItem, - nameSingular: 'person', - }, - }); - - expect(query.trim()).toEqual(`query { - personCollection(first: 0) { - fieldsString - } - }`); - }); - - it('should use "currentRecord" as query args when its present', async () => { - argAliasCreate.mockReturnValue({ - nameFirstName: 'John', - }); - - const args: FindDuplicatesResolverArgs<RecordFilter> = { - id: 'uuid', - }; - - const query = await service.create( - args, - { - ...workspaceQueryBuilderOptionsMock, - objectMetadataItem: { - ...workspaceQueryBuilderOptionsMock.objectMetadataItem, - nameSingular: 'person', - }, - }, - { - nameFirstName: 'Peter', - nameLastName: 'Parker', - }, - ); - - expect(query.trim()).toEqual(`query { - personCollection(filter: {id:{neq:"uuid"},or:[{nameFirstName:{eq:"Peter"},nameLastName:{eq:"Parker"}}]}) { - fieldsString - } - }`); - }); - }); - - describe('buildQueryForExistingRecord', () => { - it(`should include all the fields that exist for person inside "duplicateCriteriaCollection" constant`, async () => { - const query = service.buildQueryForExistingRecord('uuid', { - ...workspaceQueryBuilderOptionsMock, - objectMetadataItem: { - ...workspaceQueryBuilderOptionsMock.objectMetadataItem, - nameSingular: 'person', - }, - }); - - expect(query.trim()).toEqual(`query { - personCollection(filter: { id: { eq: "uuid" }}){ - edges { - node { - __typename - nameFirstName -nameLastName -linkedinLinkUrl -email - } - } - } - }`); - }); - }); -}); diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/args-string.factory.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/args-string.factory.ts index d28c124868a3..d4b8efd77ed6 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/args-string.factory.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/args-string.factory.ts @@ -36,11 +36,16 @@ export class ArgsStringFactory { typeof computedArgs[key] === 'object' && computedArgs[key] !== null ) { - // If it's an object (and not null), stringify it - argsString += `${key}: ${this.buildStringifiedObject( - key, - computedArgs[key], - )}, `; + if (key === 'orderBy') { + argsString += `${key}: ${this.buildStringifiedOrderBy( + computedArgs[key], + )}, `; + } else { + // If it's an object (and not null), stringify it + argsString += `${key}: ${stringifyWithoutKeyQuote( + computedArgs[key], + )}, `; + } } else { // For other types (number, boolean), add as is argsString += `${key}: ${computedArgs[key]}, `; @@ -55,22 +60,30 @@ export class ArgsStringFactory { return argsString; } - private buildStringifiedObject( - key: string, - obj: Record<string, any>, + private buildStringifiedOrderBy( + keyValuePairArray: Array<Record<string, any>>, ): string { - // PgGraphql is expecting the orderBy argument to be an array of objects - if (key === 'orderBy') { - const orderByString = Object.keys(obj) - .sort((_, b) => { - return b === 'position' ? -1 : 0; - }) - .map((orderByKey) => `{${orderByKey}: ${obj[orderByKey]}}`) - .join(', '); + if ( + keyValuePairArray.length !== 0 && + Object.keys(keyValuePairArray[0]).length === 0 + ) { + return `[]`; + } + // if position argument is present we want to put it at the very last + let orderByString = keyValuePairArray + .sort((_, obj) => (Object.hasOwnProperty.call(obj, 'position') ? -1 : 0)) + .map((obj) => { + const [key] = Object.keys(obj); + const value = obj[key]; + + return `{${key}: ${value}}`; + }) + .join(', '); - return `[${orderByString}]`; + if (orderByString.endsWith(', ')) { + orderByString = orderByString.slice(0, -2); } - return stringifyWithoutKeyQuote(obj); + return `[${orderByString}]`; } } diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/create-many-query.factory.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/create-many-query.factory.ts index b667472a3d3e..f44d1fbcb7c8 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/create-many-query.factory.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/create-many-query.factory.ts @@ -22,7 +22,7 @@ export class CreateManyQueryFactory { ) {} async create<Record extends IRecord = IRecord>( - args: CreateManyResolverArgs<Record>, + args: CreateManyResolverArgs<Partial<Record>>, options: WorkspaceQueryBuilderOptions, ) { const fieldsString = await this.fieldsStringFactory.create( diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/fields-string.factory.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/fields-string.factory.ts index e3ae2dfde33f..1acc3778d15f 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/fields-string.factory.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/fields-string.factory.ts @@ -6,6 +6,7 @@ import isEmpty from 'lodash.isempty'; import { FieldMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata.interface'; import { ObjectMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/object-metadata.interface'; +import { Record } from 'src/engine/api/graphql/workspace-query-builder/interfaces/record.interface'; import { isRelationFieldMetadataType } from 'src/engine/utils/is-relation-field-metadata-type.util'; @@ -26,7 +27,7 @@ export class FieldsStringFactory { fieldMetadataCollection: FieldMetadataInterface[], objectMetadataCollection: ObjectMetadataInterface[], ): Promise<string> { - const selectedFields: Record<string, any> = graphqlFields(info); + const selectedFields: Partial<Record> = graphqlFields(info); return this.createFieldsStringRecursive( info, @@ -38,7 +39,7 @@ export class FieldsStringFactory { async createFieldsStringRecursive( info: GraphQLResolveInfo, - selectedFields: Record<string, any>, + selectedFields: Partial<Record>, fieldMetadataCollection: FieldMetadataInterface[], objectMetadataCollection: ObjectMetadataInterface[], accumulator = '', diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/find-duplicates-query.factory.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/find-duplicates-query.factory.ts index 03655d4aeafe..5281dc7be5e7 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/find-duplicates-query.factory.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/find-duplicates-query.factory.ts @@ -3,15 +3,13 @@ import { Injectable, Logger } from '@nestjs/common'; import isEmpty from 'lodash.isempty'; import { WorkspaceQueryBuilderOptions } from 'src/engine/api/graphql/workspace-query-builder/interfaces/workspace-query-builder-options.interface'; -import { RecordFilter } from 'src/engine/api/graphql/workspace-query-builder/interfaces/record.interface'; +import { Record } from 'src/engine/api/graphql/workspace-query-builder/interfaces/record.interface'; import { FindDuplicatesResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; -import { ObjectMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/object-metadata.interface'; import { computeObjectTargetTable } from 'src/engine/utils/compute-object-target-table.util'; import { stringifyWithoutKeyQuote } from 'src/engine/api/graphql/workspace-query-builder/utils/stringify-without-key-quote.util'; import { ArgsAliasFactory } from 'src/engine/api/graphql/workspace-query-builder/factories/args-alias.factory'; -import { DUPLICATE_CRITERIA_COLLECTION } from 'src/engine/api/graphql/workspace-resolver-builder/constants/duplicate-criteria.constants'; -import { settings } from 'src/engine/constants/settings'; +import { DuplicateService } from 'src/engine/core-modules/duplicate/duplicate.service'; import { FieldsStringFactory } from './fields-string.factory'; @@ -22,12 +20,13 @@ export class FindDuplicatesQueryFactory { constructor( private readonly fieldsStringFactory: FieldsStringFactory, private readonly argsAliasFactory: ArgsAliasFactory, + private readonly duplicateService: DuplicateService, ) {} - async create<Filter extends RecordFilter = RecordFilter>( - args: FindDuplicatesResolverArgs<Filter>, + async create( + args: FindDuplicatesResolverArgs, options: WorkspaceQueryBuilderOptions, - currentRecord?: Record<string, unknown>, + existingRecords?: Record[], ) { const fieldsString = await this.fieldsStringFactory.create( options.info, @@ -35,121 +34,66 @@ export class FindDuplicatesQueryFactory { options.objectMetadataCollection, ); - const argsData = this.getFindDuplicateBy<Filter>( - args, - options, - currentRecord, - ); - - const duplicateCondition = this.buildDuplicateCondition( - options.objectMetadataItem, - argsData, - args.id, - ); - - const filters = stringifyWithoutKeyQuote(duplicateCondition); - - return ` - query { - ${computeObjectTargetTable(options.objectMetadataItem)}Collection${ - isEmpty(duplicateCondition?.or) - ? '(first: 0)' - : `(filter: ${filters})` - } { - ${fieldsString} - } - } - `; - } + if (existingRecords) { + const query = existingRecords.reduce((acc, record, index) => { + return ( + acc + this.buildQuery(fieldsString, options, undefined, record, index) + ); + }, ''); - getFindDuplicateBy<Filter extends RecordFilter = RecordFilter>( - args: FindDuplicatesResolverArgs<Filter>, - options: WorkspaceQueryBuilderOptions, - currentRecord?: Record<string, unknown>, - ) { - if (currentRecord) { - return currentRecord; + return `query { + ${query} + }`; } - return this.argsAliasFactory.create( - args.data ?? {}, - options.fieldMetadataCollection, - ); + const query = args.data?.reduce((acc, dataItem, index) => { + const argsData = this.argsAliasFactory.create( + dataItem ?? {}, + options.fieldMetadataCollection, + ); + + return ( + acc + + this.buildQuery( + fieldsString, + options, + argsData as Record, + undefined, + index, + ) + ); + }, ''); + + return `query { + ${query} + }`; } - buildQueryForExistingRecord( - id: string | number, + buildQuery( + fieldsString: string, options: WorkspaceQueryBuilderOptions, + data?: Record, + existingRecord?: Record, + index?: number, ) { - const idQueryField = typeof id === 'string' ? `"${id}"` : id; + const duplicateCondition = + this.duplicateService.buildDuplicateConditionForGraphQL( + options.objectMetadataItem, + data ?? existingRecord, + existingRecord?.id, + ); - return ` - query { - ${computeObjectTargetTable( - options.objectMetadataItem, - )}Collection(filter: { id: { eq: ${idQueryField} }}){ - edges { - node { - __typename - ${this.getApplicableDuplicateCriteriaCollection( - options.objectMetadataItem, - ) - .flatMap((dc) => dc.columnNames) - .join('\n')} - } - } - } - } - `; - } + const filters = stringifyWithoutKeyQuote(duplicateCondition); - private buildDuplicateCondition( - objectMetadataItem: ObjectMetadataInterface, - argsData?: Record<string, unknown>, - filteringByExistingRecordId?: string, - ) { - if (!argsData) { - return; + return `${computeObjectTargetTable( + options.objectMetadataItem, + )}Collection${index}: ${computeObjectTargetTable( + options.objectMetadataItem, + )}Collection${ + isEmpty(duplicateCondition?.or) ? '(first: 0)' : `(filter: ${filters})` + } { + ${fieldsString} } - - const criteriaCollection = - this.getApplicableDuplicateCriteriaCollection(objectMetadataItem); - - const criteriaWithMatchingArgs = criteriaCollection.filter((criteria) => - criteria.columnNames.every((columnName) => { - const value = argsData[columnName] as string | undefined; - - return ( - !!value && value.length >= settings.minLengthOfStringForDuplicateCheck - ); - }), - ); - - const filterCriteria = criteriaWithMatchingArgs.map((criteria) => - Object.fromEntries( - criteria.columnNames.map((columnName) => [ - columnName, - { eq: argsData[columnName] }, - ]), - ), - ); - - return { - // when filtering by an existing record, we need to filter that explicit record out - ...(filteringByExistingRecordId && { - id: { neq: filteringByExistingRecordId }, - }), - // keep condition as "or" to get results by more duplicate criteria - or: filterCriteria, - }; - } - - private getApplicableDuplicateCriteriaCollection( - objectMetadataItem: ObjectMetadataInterface, - ) { - return DUPLICATE_CRITERIA_COLLECTION.filter( - (duplicateCriteria) => - duplicateCriteria.objectName === objectMetadataItem.nameSingular, - ); + `; } } diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/update-many-query.factory.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/update-many-query.factory.ts index 936013110d3d..f55e512bac2d 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/update-many-query.factory.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/update-many-query.factory.ts @@ -28,7 +28,7 @@ export class UpdateManyQueryFactory { Record extends IRecord = IRecord, Filter extends RecordFilter = RecordFilter, >( - args: UpdateManyResolverArgs<Record, Filter>, + args: UpdateManyResolverArgs<Partial<Record>, Filter>, options: UpdateManyQueryFactoryOptions, ) { const fieldsString = await this.fieldsStringFactory.create( diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/update-one-query.factory.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/update-one-query.factory.ts index ba86a60fcdb7..57df907d95e6 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/update-one-query.factory.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/update-one-query.factory.ts @@ -20,7 +20,7 @@ export class UpdateOneQueryFactory { ) {} async create<Record extends IRecord = IRecord>( - args: UpdateOneResolverArgs<Record>, + args: UpdateOneResolverArgs<Partial<Record>>, options: WorkspaceQueryBuilderOptions, ) { const fieldsString = await this.fieldsStringFactory.create( @@ -35,6 +35,7 @@ export class UpdateOneQueryFactory { const argsData = { ...computedArgs.data, + id: undefined, // do not allow updating an existing object's id updatedAt: new Date().toISOString(), }; diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/interfaces/record.interface.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/interfaces/record.interface.ts index b9847baed1da..32ee60f567c6 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/interfaces/record.interface.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/interfaces/record.interface.ts @@ -16,9 +16,9 @@ export enum OrderByDirection { DescNullsLast = 'DescNullsLast', } -export type RecordOrderBy = { +export type RecordOrderBy = Array<{ [Property in keyof Record]?: OrderByDirection; -}; +}>; export interface RecordDuplicateCriteria { objectName: string; diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/workspace-query-builder.factory.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/workspace-query-builder.factory.ts index a563be43c4bd..fd49160eb5ab 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/workspace-query-builder.factory.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/workspace-query-builder.factory.ts @@ -64,37 +64,27 @@ export class WorkspaceQueryBuilderFactory { return this.findOneQueryFactory.create<Filter>(args, options); } - findDuplicates<Filter extends RecordFilter = RecordFilter>( - args: FindDuplicatesResolverArgs<Filter>, + findDuplicates( + args: FindDuplicatesResolverArgs, options: WorkspaceQueryBuilderOptions, - existingRecord?: Record<string, unknown>, + existingRecords?: IRecord[], ): Promise<string> { - return this.findDuplicatesQueryFactory.create<Filter>( + return this.findDuplicatesQueryFactory.create( args, options, - existingRecord, - ); - } - - findDuplicatesExistingRecord( - id: string | number, - options: WorkspaceQueryBuilderOptions, - ): string { - return this.findDuplicatesQueryFactory.buildQueryForExistingRecord( - id, - options, + existingRecords, ); } createMany<Record extends IRecord = IRecord>( - args: CreateManyResolverArgs<Record>, + args: CreateManyResolverArgs<Partial<Record>>, options: WorkspaceQueryBuilderOptions, ): Promise<string> { return this.createManyQueryFactory.create<Record>(args, options); } updateOne<Record extends IRecord = IRecord>( - initialArgs: UpdateOneResolverArgs<Record>, + initialArgs: UpdateOneResolverArgs<Partial<Record>>, options: WorkspaceQueryBuilderOptions, ): Promise<string> { return this.updateOneQueryFactory.create<Record>(initialArgs, options); @@ -111,7 +101,7 @@ export class WorkspaceQueryBuilderFactory { Record extends IRecord = IRecord, Filter extends RecordFilter = RecordFilter, >( - args: UpdateManyResolverArgs<Record, Filter>, + args: UpdateManyResolverArgs<Partial<Record>, Filter>, options: UpdateManyQueryFactoryOptions, ): Promise<string> { return this.updateManyQueryFactory.create(args, options); diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/workspace-query-builder.module.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/workspace-query-builder.module.ts index 46367dd98e71..0db5486c63e7 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/workspace-query-builder.module.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/workspace-query-builder.module.ts @@ -3,13 +3,14 @@ import { Module } from '@nestjs/common'; import { ObjectMetadataModule } from 'src/engine/metadata-modules/object-metadata/object-metadata.module'; import { FieldsStringFactory } from 'src/engine/api/graphql/workspace-query-builder/factories/fields-string.factory'; import { RecordPositionQueryFactory } from 'src/engine/api/graphql/workspace-query-builder/factories/record-position-query.factory'; +import { DuplicateModule } from 'src/engine/core-modules/duplicate/duplicate.module'; import { WorkspaceQueryBuilderFactory } from './workspace-query-builder.factory'; import { workspaceQueryBuilderFactories } from './factories/factories'; @Module({ - imports: [ObjectMetadataModule], + imports: [ObjectMetadataModule, DuplicateModule], providers: [...workspaceQueryBuilderFactories, WorkspaceQueryBuilderFactory], exports: [ WorkspaceQueryBuilderFactory, diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/commands/0-20-record-position-backfill.command.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/commands/0-20-record-position-backfill.command.ts index b5709a895481..ddc2f06a4dbf 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/commands/0-20-record-position-backfill.command.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/commands/0-20-record-position-backfill.command.ts @@ -1,11 +1,10 @@ -import { Inject } from '@nestjs/common'; - import { Command, CommandRunner, Option } from 'nest-commander'; import { RecordPositionBackfillJob, RecordPositionBackfillJobData, } from 'src/engine/api/graphql/workspace-query-runner/jobs/record-position-backfill.job'; +import { InjectMessageQueue } from 'src/engine/integrations/message-queue/decorators/message-queue.decorator'; import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service'; @@ -20,7 +19,7 @@ export type RecordPositionBackfillCommandOptions = { }) export class RecordPositionBackfillCommand extends CommandRunner { constructor( - @Inject(MessageQueue.recordPositionBackfillQueue) + @InjectMessageQueue(MessageQueue.recordPositionBackfillQueue) private readonly messageQueueService: MessageQueueService, ) { super(); diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/factories/__tests__/query-runner-args.factory.spec.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/factories/__tests__/query-runner-args.factory.spec.ts index 71e26b268146..962c8fcc9d95 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/factories/__tests__/query-runner-args.factory.spec.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/factories/__tests__/query-runner-args.factory.spec.ts @@ -152,8 +152,8 @@ describe('QueryRunnerArgsFactory', () => { } as WorkspaceQueryRunnerOptions; const args = { - id: '123', - data: { testNumber: '1', otherField: 'test' }, + ids: ['123'], + data: [{ testNumber: '1', otherField: 'test' }], }; const result = await factory.create( @@ -163,8 +163,8 @@ describe('QueryRunnerArgsFactory', () => { ); expect(result).toEqual({ - id: 123, - data: { testNumber: 1, otherField: 'test' }, + ids: [123], + data: [{ testNumber: 1, position: 2, otherField: 'test' }], }); }); }); diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/factories/query-runner-args.factory.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/factories/query-runner-args.factory.ts index 4a07ee358c5d..d8299e1cbfef 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/factories/query-runner-args.factory.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/factories/query-runner-args.factory.ts @@ -10,7 +10,10 @@ import { ResolverArgs, ResolverArgsType, } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; -import { RecordFilter } from 'src/engine/api/graphql/workspace-query-builder/interfaces/record.interface'; +import { + Record, + RecordFilter, +} from 'src/engine/api/graphql/workspace-query-builder/interfaces/record.interface'; import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; import { hasPositionField } from 'src/engine/metadata-modules/object-metadata/utils/has-position-field.util'; @@ -47,12 +50,12 @@ export class QueryRunnerArgsFactory { return { ...args, data: await Promise.all( - (args as CreateManyResolverArgs).data.map((arg, index) => + (args as CreateManyResolverArgs).data?.map((arg, index) => this.overrideDataByFieldMetadata(arg, options, fieldMetadataMap, { argIndex: index, shouldBackfillPosition, }), - ), + ) ?? [], ), } satisfies CreateManyResolverArgs; case ResolverArgsType.FindOne: @@ -75,25 +78,27 @@ export class QueryRunnerArgsFactory { case ResolverArgsType.FindDuplicates: return { ...args, - id: await this.overrideValueByFieldMetadata( - 'id', - (args as FindDuplicatesResolverArgs).id, - fieldMetadataMap, - ), - data: await this.overrideDataByFieldMetadata( - (args as FindDuplicatesResolverArgs).data, - options, - fieldMetadataMap, - { shouldBackfillPosition: false }, + ids: (await Promise.all( + (args as FindDuplicatesResolverArgs).ids?.map((id) => + this.overrideValueByFieldMetadata('id', id, fieldMetadataMap), + ) ?? [], + )) as string[], + data: await Promise.all( + (args as FindDuplicatesResolverArgs).data?.map((arg, index) => + this.overrideDataByFieldMetadata(arg, options, fieldMetadataMap, { + argIndex: index, + shouldBackfillPosition, + }), + ) ?? [], ), - }; + } satisfies FindDuplicatesResolverArgs; default: return args; } } private async overrideDataByFieldMetadata( - data: Record<string, any> | undefined, + data: Partial<Record> | undefined, options: WorkspaceQueryRunnerOptions, fieldMetadataMap: Map<string, FieldMetadataInterface>, argPositionBackfillInput: ArgPositionBackfillInput, @@ -199,14 +204,20 @@ export class QueryRunnerArgsFactory { if (!fieldMetadata) { return value; } + switch (fieldMetadata.type) { - case 'NUMBER': - return Object.fromEntries( - Object.entries(value).map(([filterKey, filterValue]) => [ - filterKey, - Number(filterValue), - ]), - ); + case 'NUMBER': { + if (value?.is === 'NULL') { + return value; + } else { + return Object.fromEntries( + Object.entries(value).map(([filterKey, filterValue]) => [ + filterKey, + Number(filterValue), + ]), + ); + } + } default: return value; } diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/jobs/call-webhook-jobs.job.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/jobs/call-webhook-jobs.job.ts index e3b7e68a1982..818be2a60d65 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/jobs/call-webhook-jobs.job.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/jobs/call-webhook-jobs.job.ts @@ -1,6 +1,5 @@ -import { Inject, Injectable, Logger } from '@nestjs/common'; +import { Logger } from '@nestjs/common'; -import { MessageQueueJob } from 'src/engine/integrations/message-queue/interfaces/message-queue-job.interface'; import { ObjectMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/object-metadata.interface'; import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; @@ -11,6 +10,9 @@ import { CallWebhookJob, CallWebhookJobData, } from 'src/engine/api/graphql/workspace-query-runner/jobs/call-webhook.job'; +import { InjectMessageQueue } from 'src/engine/integrations/message-queue/decorators/message-queue.decorator'; +import { Processor } from 'src/engine/integrations/message-queue/decorators/processor.decorator'; +import { Process } from 'src/engine/integrations/message-queue/decorators/process.decorator'; export enum CallWebhookJobsJobOperation { create = 'create', @@ -25,19 +27,18 @@ export type CallWebhookJobsJobData = { operation: CallWebhookJobsJobOperation; }; -@Injectable() -export class CallWebhookJobsJob - implements MessageQueueJob<CallWebhookJobsJobData> -{ +@Processor(MessageQueue.webhookQueue) +export class CallWebhookJobsJob { private readonly logger = new Logger(CallWebhookJobsJob.name); constructor( private readonly workspaceDataSourceService: WorkspaceDataSourceService, private readonly dataSourceService: DataSourceService, - @Inject(MessageQueue.webhookQueue) + @InjectMessageQueue(MessageQueue.webhookQueue) private readonly messageQueueService: MessageQueueService, ) {} + @Process(CallWebhookJobsJob.name) async handle(data: CallWebhookJobsJobData): Promise<void> { const dataSourceMetadata = await this.dataSourceService.getLastDataSourceMetadataFromWorkspaceIdOrFail( diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/jobs/call-webhook.job.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/jobs/call-webhook.job.ts index 5ce75b717f4b..d18686e96aba 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/jobs/call-webhook.job.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/jobs/call-webhook.job.ts @@ -1,7 +1,9 @@ -import { Injectable, Logger } from '@nestjs/common'; +import { Logger } from '@nestjs/common'; import { HttpService } from '@nestjs/axios'; -import { MessageQueueJob } from 'src/engine/integrations/message-queue/interfaces/message-queue-job.interface'; +import { Processor } from 'src/engine/integrations/message-queue/decorators/processor.decorator'; +import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; +import { Process } from 'src/engine/integrations/message-queue/decorators/process.decorator'; export type CallWebhookJobData = { targetUrl: string; @@ -13,12 +15,13 @@ export type CallWebhookJobData = { record: any; }; -@Injectable() -export class CallWebhookJob implements MessageQueueJob<CallWebhookJobData> { +@Processor(MessageQueue.webhookQueue) +export class CallWebhookJob { private readonly logger = new Logger(CallWebhookJob.name); constructor(private readonly httpService: HttpService) {} + @Process(CallWebhookJob.name) async handle(data: CallWebhookJobData): Promise<void> { try { await this.httpService.axiosRef.post(data.targetUrl, data); diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/jobs/record-position-backfill.job.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/jobs/record-position-backfill.job.ts index e0c589d9bdff..8619f1182814 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/jobs/record-position-backfill.job.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/jobs/record-position-backfill.job.ts @@ -1,22 +1,20 @@ -import { Injectable } from '@nestjs/common'; - -import { MessageQueueJob } from 'src/engine/integrations/message-queue/interfaces/message-queue-job.interface'; - import { RecordPositionBackfillService } from 'src/engine/api/graphql/workspace-query-runner/services/record-position-backfill-service'; +import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; +import { Processor } from 'src/engine/integrations/message-queue/decorators/processor.decorator'; +import { Process } from 'src/engine/integrations/message-queue/decorators/process.decorator'; export type RecordPositionBackfillJobData = { workspaceId: string; dryRun: boolean; }; -@Injectable() -export class RecordPositionBackfillJob - implements MessageQueueJob<RecordPositionBackfillJobData> -{ +@Processor(MessageQueue.recordPositionBackfillQueue) +export class RecordPositionBackfillJob { constructor( private readonly recordPositionBackfillService: RecordPositionBackfillService, ) {} + @Process(RecordPositionBackfillJob.name) async handle(data: RecordPositionBackfillJobData): Promise<void> { this.recordPositionBackfillService.backfill(data.workspaceId, data.dryRun); } diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/jobs/workspace-query-runner-job.module.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/jobs/workspace-query-runner-job.module.ts index fc4b7c6d52cb..8104cf075cf3 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/jobs/workspace-query-runner-job.module.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/jobs/workspace-query-runner-job.module.ts @@ -15,19 +15,6 @@ import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/works RecordPositionBackfillModule, HttpModule, ], - providers: [ - { - provide: CallWebhookJobsJob.name, - useClass: CallWebhookJobsJob, - }, - { - provide: CallWebhookJob.name, - useClass: CallWebhookJob, - }, - { - provide: RecordPositionBackfillJob.name, - useClass: RecordPositionBackfillJob, - }, - ], + providers: [CallWebhookJobsJob, CallWebhookJob, RecordPositionBackfillJob], }) export class WorkspaceQueryRunnerJobModule {} diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/listeners/entity-events-to-db.listener.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/listeners/entity-events-to-db.listener.ts index 755173ba63e1..d9a018f86ceb 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/listeners/entity-events-to-db.listener.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/listeners/entity-events-to-db.listener.ts @@ -1,19 +1,20 @@ -import { Inject, Injectable } from '@nestjs/common'; +import { Injectable } from '@nestjs/common'; import { OnEvent } from '@nestjs/event-emitter'; -import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; -import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service'; import { ObjectRecordCreateEvent } from 'src/engine/integrations/event-emitter/types/object-record-create.event'; -import { objectRecordChangedValues } from 'src/engine/integrations/event-emitter/utils/object-record-changed-values'; import { ObjectRecordUpdateEvent } from 'src/engine/integrations/event-emitter/types/object-record-update.event'; import { ObjectRecordBaseEvent } from 'src/engine/integrations/event-emitter/types/object-record.base.event'; -import { UpsertTimelineActivityFromInternalEvent } from 'src/modules/timeline/jobs/upsert-timeline-activity-from-internal-event.job'; +import { objectRecordChangedValues } from 'src/engine/integrations/event-emitter/utils/object-record-changed-values'; +import { InjectMessageQueue } from 'src/engine/integrations/message-queue/decorators/message-queue.decorator'; +import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; +import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service'; import { CreateAuditLogFromInternalEvent } from 'src/modules/timeline/jobs/create-audit-log-from-internal-event'; +import { UpsertTimelineActivityFromInternalEvent } from 'src/modules/timeline/jobs/upsert-timeline-activity-from-internal-event.job'; @Injectable() export class EntityEventsToDbListener { constructor( - @Inject(MessageQueue.entityEventsToDbQueue) + @InjectMessageQueue(MessageQueue.entityEventsToDbQueue) private readonly messageQueueService: MessageQueueService, ) {} @@ -40,7 +41,7 @@ export class EntityEventsToDbListener { // .... private async handle(payload: ObjectRecordBaseEvent) { - if (!payload.objectMetadata.isAuditLogged) { + if (!payload.objectMetadata?.isAuditLogged) { return; } diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-pre-query-hook/workspace-pre-query-hook.config.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-pre-query-hook/workspace-pre-query-hook.config.ts deleted file mode 100644 index 518e147241a1..000000000000 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-pre-query-hook/workspace-pre-query-hook.config.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-pre-query-hook/types/workspace-query-hook.type'; -import { CalendarEventFindManyPreQueryHook } from 'src/modules/calendar/query-hooks/calendar-event/calendar-event-find-many.pre-query.hook'; -import { CalendarEventFindOnePreQueryHook } from 'src/modules/calendar/query-hooks/calendar-event/calendar-event-find-one.pre-query-hook'; -import { BlocklistCreateManyPreQueryHook } from 'src/modules/connected-account/query-hooks/blocklist/blocklist-create-many.pre-query.hook'; -import { BlocklistUpdateManyPreQueryHook } from 'src/modules/connected-account/query-hooks/blocklist/blocklist-update-many.pre-query.hook'; -import { BlocklistUpdateOnePreQueryHook } from 'src/modules/connected-account/query-hooks/blocklist/blocklist-update-one.pre-query.hook'; -import { WorkspaceMemberDeleteOnePreQueryHook } from 'src/modules/workspace-member/query-hooks/workspace-member-delete-one.pre-query.hook'; -import { WorkspaceMemberDeleteManyPreQueryHook } from 'src/modules/workspace-member/query-hooks/workspace-member-delete-many.pre-query.hook'; -import { MessageFindManyPreQueryHook } from 'src/modules/messaging/common/query-hooks/message/message-find-many.pre-query.hook'; -import { MessageFindOnePreQueryHook } from 'src/modules/messaging/common/query-hooks/message/message-find-one.pre-query-hook'; - -// TODO: move to a decorator -export const workspacePreQueryHooks: WorkspaceQueryHook = { - message: { - findOne: [MessageFindOnePreQueryHook.name], - findMany: [MessageFindManyPreQueryHook.name], - }, - calendarEvent: { - findOne: [CalendarEventFindOnePreQueryHook.name], - findMany: [CalendarEventFindManyPreQueryHook.name], - }, - blocklist: { - createMany: [BlocklistCreateManyPreQueryHook.name], - updateMany: [BlocklistUpdateManyPreQueryHook.name], - updateOne: [BlocklistUpdateOnePreQueryHook.name], - }, - workspaceMember: { - deleteOne: [WorkspaceMemberDeleteOnePreQueryHook.name], - deleteMany: [WorkspaceMemberDeleteManyPreQueryHook.name], - }, -}; diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-pre-query-hook/workspace-pre-query-hook.module.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-pre-query-hook/workspace-pre-query-hook.module.ts deleted file mode 100644 index 8ea6b6a6e11b..000000000000 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-pre-query-hook/workspace-pre-query-hook.module.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Module } from '@nestjs/common'; - -import { WorkspacePreQueryHookService } from 'src/engine/api/graphql/workspace-query-runner/workspace-pre-query-hook/workspace-pre-query-hook.service'; -import { CalendarQueryHookModule } from 'src/modules/calendar/query-hooks/calendar-query-hook.module'; -import { ConnectedAccountQueryHookModule } from 'src/modules/connected-account/query-hooks/connected-account-query-hook.module'; -import { MessagingQueryHookModule } from 'src/modules/messaging/common/query-hooks/messaging-query-hook.module'; -import { WorkspaceMemberQueryHookModule } from 'src/modules/workspace-member/query-hooks/workspace-member-query-hook.module'; - -@Module({ - imports: [ - MessagingQueryHookModule, - CalendarQueryHookModule, - ConnectedAccountQueryHookModule, - WorkspaceMemberQueryHookModule, - ], - providers: [WorkspacePreQueryHookService], - exports: [WorkspacePreQueryHookService], -}) -export class WorkspacePreQueryHookModule {} diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-pre-query-hook/workspace-pre-query-hook.service.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-pre-query-hook/workspace-pre-query-hook.service.ts deleted file mode 100644 index 28681e0b965b..000000000000 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-pre-query-hook/workspace-pre-query-hook.service.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { ModuleRef } from '@nestjs/core'; - -import { WorkspacePreQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-pre-query-hook/interfaces/workspace-pre-query-hook.interface'; - -import { - ExecutePreHookMethod, - WorkspacePreQueryHookPayload, -} from 'src/engine/api/graphql/workspace-query-runner/workspace-pre-query-hook/types/workspace-query-hook.type'; -import { workspacePreQueryHooks } from 'src/engine/api/graphql/workspace-query-runner/workspace-pre-query-hook/workspace-pre-query-hook.config'; - -@Injectable() -export class WorkspacePreQueryHookService { - constructor(private readonly workspaceQueryHookModuleRef: ModuleRef) {} - - public async executePreHooks<T extends ExecutePreHookMethod>( - userId: string | undefined, - workspaceId: string, - objectName: string, - method: T, - payload: WorkspacePreQueryHookPayload<T>, - ): Promise<void> { - const hooks = workspacePreQueryHooks[objectName] || []; - - for (const hookName of Object.values(hooks[method] ?? [])) { - const hook: WorkspacePreQueryHook = - await this.workspaceQueryHookModuleRef.get(hookName, { - strict: false, - }); - - await hook.execute(userId, workspaceId, payload); - } - } -} diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator.ts new file mode 100644 index 000000000000..d87979418638 --- /dev/null +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator.ts @@ -0,0 +1,40 @@ +import { Scope, SetMetadata } from '@nestjs/common'; +import { SCOPE_OPTIONS_METADATA } from '@nestjs/common/constants'; + +import { WorkspaceResolverBuilderMethodNames } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; + +import { WORKSPACE_QUERY_HOOK_METADATA } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook.constants'; +import { WorkspaceQueryHookType } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/types/workspace-query-hook.type'; + +export type WorkspaceQueryHookKey = + `${string}.${WorkspaceResolverBuilderMethodNames}`; + +export interface WorkspaceQueryHookOptions { + key: WorkspaceQueryHookKey; + type?: WorkspaceQueryHookType; + scope?: Scope; +} + +export function WorkspaceQueryHook(key: WorkspaceQueryHookKey): ClassDecorator; +export function WorkspaceQueryHook( + options: WorkspaceQueryHookOptions, +): ClassDecorator; +export function WorkspaceQueryHook( + keyOrOptions: WorkspaceQueryHookKey | WorkspaceQueryHookOptions, +): ClassDecorator { + const options: WorkspaceQueryHookOptions = + keyOrOptions && typeof keyOrOptions === 'object' + ? keyOrOptions + : { key: keyOrOptions }; + + // Default to PreHook + if (!options.type) { + options.type = WorkspaceQueryHookType.PreHook; + } + + // eslint-disable-next-line @typescript-eslint/ban-types + return (target: Function) => { + SetMetadata(SCOPE_OPTIONS_METADATA, options)(target); + SetMetadata(WORKSPACE_QUERY_HOOK_METADATA, options)(target); + }; +} diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-pre-query-hook/interfaces/workspace-pre-query-hook.interface.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface.ts similarity index 84% rename from packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-pre-query-hook/interfaces/workspace-pre-query-hook.interface.ts rename to packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface.ts index 60a782e8c443..93c3964c83b5 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-pre-query-hook/interfaces/workspace-pre-query-hook.interface.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface.ts @@ -1,6 +1,6 @@ import { ResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; -export interface WorkspacePreQueryHook { +export interface WorkspaceQueryHookInstance { execute( userId: string | undefined, workspaceId: string, diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-hook/storage/workspace-query-hook.storage.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-hook/storage/workspace-query-hook.storage.ts new file mode 100644 index 000000000000..18b25d1d964d --- /dev/null +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-hook/storage/workspace-query-hook.storage.ts @@ -0,0 +1,59 @@ +// hook-registry.service.ts +import { Injectable } from '@nestjs/common'; +import { Module } from '@nestjs/core/injector/module'; + +import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface'; + +import { WorkspaceQueryHookKey } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator'; + +interface WorkspaceQueryHookData<T> { + instance: T; + host: Module; + isRequestScoped: boolean; +} + +@Injectable() +export class WorkspaceQueryHookStorage { + private preHookInstances = new Map< + WorkspaceQueryHookKey, + WorkspaceQueryHookData<WorkspaceQueryHookInstance>[] + >(); + private postHookInstances = new Map< + WorkspaceQueryHookKey, + WorkspaceQueryHookData<WorkspaceQueryHookInstance>[] + >(); + + registerWorkspaceQueryPreHookInstance( + key: WorkspaceQueryHookKey, + data: WorkspaceQueryHookData<WorkspaceQueryHookInstance>, + ) { + if (!this.preHookInstances.has(key)) { + this.preHookInstances.set(key, []); + } + + this.preHookInstances.get(key)?.push(data); + } + + getWorkspaceQueryPreHookInstances( + key: WorkspaceQueryHookKey, + ): WorkspaceQueryHookData<WorkspaceQueryHookInstance>[] | undefined { + return this.preHookInstances.get(key); + } + + registerWorkspaceQueryPostHookInstance( + key: WorkspaceQueryHookKey, + data: WorkspaceQueryHookData<WorkspaceQueryHookInstance>, + ) { + if (!this.postHookInstances.has(key)) { + this.postHookInstances.set(key, []); + } + + this.postHookInstances.get(key)?.push(data); + } + + getWorkspaceQueryPostHookInstances( + key: WorkspaceQueryHookKey, + ): WorkspaceQueryHookData<WorkspaceQueryHookInstance>[] | undefined { + return this.postHookInstances.get(key); + } +} diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-pre-query-hook/types/workspace-query-hook.type.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-hook/types/workspace-query-hook.type.ts similarity index 73% rename from packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-pre-query-hook/types/workspace-query-hook.type.ts rename to packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-hook/types/workspace-query-hook.type.ts index 84d75b1358b9..40ec1df6b4d4 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-pre-query-hook/types/workspace-query-hook.type.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-hook/types/workspace-query-hook.type.ts @@ -10,26 +10,10 @@ import { UpdateOneResolverArgs, } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; -export type ExecutePreHookMethod = - | 'createMany' - | 'createOne' - | 'deleteMany' - | 'deleteOne' - | 'findMany' - | 'findOne' - | 'findDuplicates' - | 'updateMany' - | 'updateOne'; - -export type ObjectName = string; - -export type HookName = string; - -export type WorkspaceQueryHook = { - [key in ObjectName]: { - [key in ExecutePreHookMethod]?: HookName[]; - }; -}; +export enum WorkspaceQueryHookType { + PreHook = 'PreHook', + PostHook = 'PostHook', +} export type WorkspacePreQueryHookPayload<T> = T extends 'createMany' ? CreateManyResolverArgs diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook-metadata.accessor.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook-metadata.accessor.ts new file mode 100644 index 000000000000..229e0b0bf3db --- /dev/null +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook-metadata.accessor.ts @@ -0,0 +1,25 @@ +/* eslint-disable @typescript-eslint/ban-types */ +import { Injectable, Type } from '@nestjs/common'; +import { Reflector } from '@nestjs/core'; + +import { WORKSPACE_QUERY_HOOK_METADATA } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook.constants'; +import { WorkspaceQueryHookOptions } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator'; + +@Injectable() +export class WorkspaceQueryHookMetadataAccessor { + constructor(private readonly reflector: Reflector) {} + + isWorkspaceQueryHook(target: Type<any> | Function): boolean { + if (!target) { + return false; + } + + return !!this.reflector.get(WORKSPACE_QUERY_HOOK_METADATA, target); + } + + getWorkspaceQueryHookMetadata( + target: Type<any> | Function, + ): WorkspaceQueryHookOptions | undefined { + return this.reflector.get(WORKSPACE_QUERY_HOOK_METADATA, target); + } +} diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook.constants.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook.constants.ts new file mode 100644 index 000000000000..ea1aadc49006 --- /dev/null +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook.constants.ts @@ -0,0 +1,3 @@ +export const WORKSPACE_QUERY_HOOK_METADATA = Symbol( + 'workspace-query-hook:query-hook-metadata', +); diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook.explorer.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook.explorer.ts new file mode 100644 index 000000000000..87bce8248bd1 --- /dev/null +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook.explorer.ts @@ -0,0 +1,139 @@ +import { Injectable, Logger, OnModuleInit } from '@nestjs/common'; +import { DiscoveryService, ModuleRef, createContextId } from '@nestjs/core'; +import { Module } from '@nestjs/core/injector/module'; +import { Injector } from '@nestjs/core/injector/injector'; + +import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface'; + +import { WorkspaceQueryHookMetadataAccessor } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook-metadata.accessor'; +import { WorkspaceQueryHookStorage } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/storage/workspace-query-hook.storage'; +import { WorkspaceQueryHookKey } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator'; +import { WorkspaceQueryHookType } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/types/workspace-query-hook.type'; + +@Injectable() +export class WorkspaceQueryHookExplorer implements OnModuleInit { + private readonly logger = new Logger('WorkspaceQueryHookModule'); + private readonly injector = new Injector(); + + constructor( + private readonly moduleRef: ModuleRef, + private readonly discoveryService: DiscoveryService, + private readonly metadataAccessor: WorkspaceQueryHookMetadataAccessor, + private readonly workspaceQueryHookStorage: WorkspaceQueryHookStorage, + ) {} + + onModuleInit() { + this.explore(); + } + + async explore() { + const hooks = this.discoveryService + .getProviders() + .filter((wrapper) => + this.metadataAccessor.isWorkspaceQueryHook( + !wrapper.metatype || wrapper.inject + ? wrapper.instance?.constructor + : wrapper.metatype, + ), + ); + + for (const hook of hooks) { + const { instance, metatype } = hook; + + const { key, type } = + this.metadataAccessor.getWorkspaceQueryHookMetadata( + instance.constructor || metatype, + ) ?? {}; + + if (!key || !type) { + this.logger.error( + `PreHook ${hook.name} is missing key or type metadata`, + ); + continue; + } + + if (!hook.host) { + this.logger.error(`PreHook ${hook.name} is missing host metadata`); + + continue; + } + + this.registerWorkspaceQueryHook( + key, + type, + instance, + hook.host, + !hook.isDependencyTreeStatic(), + ); + } + } + + async handleHook( + payload: Parameters<WorkspaceQueryHookInstance['execute']>, + instance: object, + host: Module, + isRequestScoped: boolean, + ) { + const methodName = 'execute'; + + if (isRequestScoped) { + const contextId = createContextId(); + + if (this.moduleRef.registerRequestByContextId) { + this.moduleRef.registerRequestByContextId( + { + req: { + workspaceId: payload?.[1], + }, + }, + contextId, + ); + } + + const contextInstance = await this.injector.loadPerContext( + instance, + host, + host.providers, + contextId, + ); + + await contextInstance[methodName].call(contextInstance, ...payload); + } else { + await instance[methodName].call(instance, ...payload); + } + } + + private registerWorkspaceQueryHook( + key: WorkspaceQueryHookKey, + type: WorkspaceQueryHookType, + instance: object, + host: Module, + isRequestScoped: boolean, + ) { + switch (type) { + case WorkspaceQueryHookType.PreHook: + this.workspaceQueryHookStorage.registerWorkspaceQueryPreHookInstance( + key, + { + instance: instance as WorkspaceQueryHookInstance, + host, + isRequestScoped, + }, + ); + break; + case WorkspaceQueryHookType.PostHook: + this.workspaceQueryHookStorage.registerWorkspaceQueryPostHookInstance( + key, + { + instance: instance as WorkspaceQueryHookInstance, + host, + isRequestScoped, + }, + ); + break; + default: + this.logger.error(`Unknown WorkspaceQueryHookType: ${type}`); + break; + } + } +} diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook.module.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook.module.ts new file mode 100644 index 000000000000..04e48b8c9da7 --- /dev/null +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook.module.ts @@ -0,0 +1,31 @@ +import { Module } from '@nestjs/common'; +import { DiscoveryModule } from '@nestjs/core'; + +import { WorkspaceQueryHookStorage } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/storage/workspace-query-hook.storage'; +import { WorkspaceQueryHookMetadataAccessor } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook-metadata.accessor'; +import { WorkspaceQueryHookExplorer } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook.explorer'; +import { WorkspaceQueryHookService } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook.service'; +import { BlocklistQueryHookModule } from 'src/modules/blocklist/query-hooks/blocklist-query-hook.module'; +import { CalendarQueryHookModule } from 'src/modules/calendar/common/query-hooks/calendar-query-hook.module'; +import { ConnectedAccountQueryHookModule } from 'src/modules/connected-account/query-hooks/connected-account-query-hook.module'; +import { MessagingQueryHookModule } from 'src/modules/messaging/common/query-hooks/messaging-query-hook.module'; +import { WorkspaceMemberQueryHookModule } from 'src/modules/workspace-member/query-hooks/workspace-member-query-hook.module'; + +@Module({ + imports: [ + MessagingQueryHookModule, + CalendarQueryHookModule, + ConnectedAccountQueryHookModule, + BlocklistQueryHookModule, + WorkspaceMemberQueryHookModule, + DiscoveryModule, + ], + providers: [ + WorkspaceQueryHookService, + WorkspaceQueryHookExplorer, + WorkspaceQueryHookMetadataAccessor, + WorkspaceQueryHookStorage, + ], + exports: [WorkspaceQueryHookService], +}) +export class WorkspaceQueryHookModule {} diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook.service.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook.service.ts new file mode 100644 index 000000000000..adfd90f4261d --- /dev/null +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook.service.ts @@ -0,0 +1,43 @@ +import { Injectable } from '@nestjs/common'; + +import { WorkspaceResolverBuilderMethodNames } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; + +import { WorkspaceQueryHookStorage } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/storage/workspace-query-hook.storage'; +import { WorkspaceQueryHookKey } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator'; +import { WorkspaceQueryHookExplorer } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook.explorer'; +import { WorkspacePreQueryHookPayload } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/types/workspace-query-hook.type'; + +@Injectable() +export class WorkspaceQueryHookService { + constructor( + private readonly workspaceQueryHookStorage: WorkspaceQueryHookStorage, + private readonly workspaceQueryHookExplorer: WorkspaceQueryHookExplorer, + ) {} + + public async executePreQueryHooks< + T extends WorkspaceResolverBuilderMethodNames, + >( + userId: string | undefined, + workspaceId: string, + objectName: string, + methodName: T, + payload: WorkspacePreQueryHookPayload<T>, + ): Promise<void> { + const key: WorkspaceQueryHookKey = `${objectName}.${methodName}`; + const preHookInstances = + this.workspaceQueryHookStorage.getWorkspaceQueryPreHookInstances(key); + + if (!preHookInstances) { + return; + } + + for (const preHookInstance of preHookInstances) { + await this.workspaceQueryHookExplorer.handleHook( + [userId, workspaceId, payload], + preHookInstance.instance, + preHookInstance.host, + preHookInstance.isRequestScoped, + ); + } + } +} diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-runner.module.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-runner.module.ts index f7358021b849..99c9b7a6e3ba 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-runner.module.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-runner.module.ts @@ -2,7 +2,7 @@ import { Module } from '@nestjs/common'; import { WorkspaceQueryBuilderModule } from 'src/engine/api/graphql/workspace-query-builder/workspace-query-builder.module'; import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; -import { WorkspacePreQueryHookModule } from 'src/engine/api/graphql/workspace-query-runner/workspace-pre-query-hook/workspace-pre-query-hook.module'; +import { WorkspaceQueryHookModule } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook.module'; import { workspaceQueryRunnerFactories } from 'src/engine/api/graphql/workspace-query-runner/factories'; import { AuthModule } from 'src/engine/core-modules/auth/auth.module'; import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; @@ -10,6 +10,7 @@ import { ObjectMetadataRepositoryModule } from 'src/engine/object-metadata-repos import { TelemetryListener } from 'src/engine/api/graphql/workspace-query-runner/listeners/telemetry.listener'; import { AnalyticsModule } from 'src/engine/core-modules/analytics/analytics.module'; import { RecordPositionBackfillCommand } from 'src/engine/api/graphql/workspace-query-runner/commands/0-20-record-position-backfill.command'; +import { DuplicateModule } from 'src/engine/core-modules/duplicate/duplicate.module'; import { WorkspaceQueryRunnerService } from './workspace-query-runner.service'; @@ -20,9 +21,10 @@ import { EntityEventsToDbListener } from './listeners/entity-events-to-db.listen AuthModule, WorkspaceQueryBuilderModule, WorkspaceDataSourceModule, - WorkspacePreQueryHookModule, + WorkspaceQueryHookModule, ObjectMetadataRepositoryModule.forFeature([WorkspaceMemberWorkspaceEntity]), AnalyticsModule, + DuplicateModule, ], providers: [ WorkspaceQueryRunnerService, diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-runner.service.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-runner.service.ts index a1cab54beeba..1ab7764f5549 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-runner.service.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-runner.service.ts @@ -1,6 +1,5 @@ import { BadRequestException, - Inject, Injectable, Logger, RequestTimeoutException, @@ -8,13 +7,14 @@ import { import { EventEmitter2 } from '@nestjs/event-emitter'; import isEmpty from 'lodash.isempty'; +import { DataSource } from 'typeorm'; -import { IConnection } from 'src/engine/api/graphql/workspace-query-runner/interfaces/connection.interface'; import { Record as IRecord, RecordFilter, RecordOrderBy, } from 'src/engine/api/graphql/workspace-query-builder/interfaces/record.interface'; +import { IConnection } from 'src/engine/api/graphql/workspace-query-runner/interfaces/connection.interface'; import { CreateManyResolverArgs, CreateOneResolverArgs, @@ -30,34 +30,36 @@ import { import { ObjectMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/object-metadata.interface'; import { WorkspaceQueryBuilderFactory } from 'src/engine/api/graphql/workspace-query-builder/workspace-query-builder.factory'; -import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; -import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service'; -import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; +import { QueryResultGettersFactory } from 'src/engine/api/graphql/workspace-query-runner/factories/query-result-getters.factory'; +import { QueryRunnerArgsFactory } from 'src/engine/api/graphql/workspace-query-runner/factories/query-runner-args.factory'; import { CallWebhookJobsJob, CallWebhookJobsJobData, CallWebhookJobsJobOperation, } from 'src/engine/api/graphql/workspace-query-runner/jobs/call-webhook-jobs.job'; +import { assertIsValidUuid } from 'src/engine/api/graphql/workspace-query-runner/utils/assert-is-valid-uuid.util'; import { parseResult } from 'src/engine/api/graphql/workspace-query-runner/utils/parse-result.util'; -import { computeObjectTargetTable } from 'src/engine/utils/compute-object-target-table.util'; -import { ObjectRecordDeleteEvent } from 'src/engine/integrations/event-emitter/types/object-record-delete.event'; +import { WorkspaceQueryHookService } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook.service'; +import { DuplicateService } from 'src/engine/core-modules/duplicate/duplicate.service'; +import { NotFoundError } from 'src/engine/core-modules/graphql/utils/graphql-errors.util'; +import { EnvironmentService } from 'src/engine/integrations/environment/environment.service'; import { ObjectRecordCreateEvent } from 'src/engine/integrations/event-emitter/types/object-record-create.event'; +import { ObjectRecordDeleteEvent } from 'src/engine/integrations/event-emitter/types/object-record-delete.event'; import { ObjectRecordUpdateEvent } from 'src/engine/integrations/event-emitter/types/object-record-update.event'; -import { WorkspacePreQueryHookService } from 'src/engine/api/graphql/workspace-query-runner/workspace-pre-query-hook/workspace-pre-query-hook.service'; -import { EnvironmentService } from 'src/engine/integrations/environment/environment.service'; -import { NotFoundError } from 'src/engine/utils/graphql-errors.util'; -import { QueryRunnerArgsFactory } from 'src/engine/api/graphql/workspace-query-runner/factories/query-runner-args.factory'; -import { QueryResultGettersFactory } from 'src/engine/api/graphql/workspace-query-runner/factories/query-result-getters.factory'; +import { InjectMessageQueue } from 'src/engine/integrations/message-queue/decorators/message-queue.decorator'; +import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; +import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service'; import { assertMutationNotOnRemoteObject } from 'src/engine/metadata-modules/object-metadata/utils/assert-mutation-not-on-remote-object.util'; -import { STANDARD_OBJECT_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-object-ids'; -import { assertIsValidUuid } from 'src/engine/api/graphql/workspace-query-runner/utils/assert-is-valid-uuid.util'; +import { computeObjectTargetTable } from 'src/engine/utils/compute-object-target-table.util'; import { isQueryTimeoutError } from 'src/engine/utils/query-timeout.util'; +import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; +import { STANDARD_OBJECT_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-object-ids'; -import { WorkspaceQueryRunnerOptions } from './interfaces/query-runner-option.interface'; import { PGGraphQLMutation, PGGraphQLResult, } from './interfaces/pg-graphql.interface'; +import { WorkspaceQueryRunnerOptions } from './interfaces/query-runner-option.interface'; import { PgGraphQLConfig, computePgGraphQLError, @@ -72,11 +74,12 @@ export class WorkspaceQueryRunnerService { private readonly workspaceDataSourceService: WorkspaceDataSourceService, private readonly queryRunnerArgsFactory: QueryRunnerArgsFactory, private readonly queryResultGettersFactory: QueryResultGettersFactory, - @Inject(MessageQueue.webhookQueue) + @InjectMessageQueue(MessageQueue.webhookQueue) private readonly messageQueueService: MessageQueueService, private readonly eventEmitter: EventEmitter2, - private readonly workspacePreQueryHookService: WorkspacePreQueryHookService, + private readonly workspaceQueryHookService: WorkspaceQueryHookService, private readonly environmentService: EnvironmentService, + private readonly duplicateService: DuplicateService, ) {} async findMany< @@ -101,7 +104,7 @@ export class WorkspaceQueryRunnerService { options, ); - await this.workspacePreQueryHookService.executePreHooks( + await this.workspaceQueryHookService.executePreQueryHooks( userId, workspaceId, objectMetadataItem.nameSingular, @@ -148,7 +151,7 @@ export class WorkspaceQueryRunnerService { options, ); - await this.workspacePreQueryHookService.executePreHooks( + await this.workspaceQueryHookService.executePreQueryHooks( userId, workspaceId, objectMetadataItem.nameSingular, @@ -167,16 +170,16 @@ export class WorkspaceQueryRunnerService { } async findDuplicates<TRecord extends IRecord = IRecord>( - args: FindDuplicatesResolverArgs<TRecord>, + args: FindDuplicatesResolverArgs<Partial<TRecord>>, options: WorkspaceQueryRunnerOptions, ): Promise<IConnection<TRecord> | undefined> { - if (!args.data && !args.id) { + if (!args.data && !args.ids) { throw new BadRequestException( 'You have to provide either "data" or "id" argument', ); } - if (!args.id && isEmpty(args.data)) { + if (!args.ids && isEmpty(args.data)) { throw new BadRequestException( 'The "data" condition can not be empty when ID input not provided', ); @@ -190,40 +193,27 @@ export class WorkspaceQueryRunnerService { ResolverArgsType.FindDuplicates, )) as FindDuplicatesResolverArgs<TRecord>; - let existingRecord: Record<string, unknown> | undefined; - - if (computedArgs.id) { - const existingRecordQuery = - this.workspaceQueryBuilderFactory.findDuplicatesExistingRecord( - computedArgs.id, - options, - ); - - const existingRecordResult = await this.execute( - existingRecordQuery, - workspaceId, - ); + let existingRecords: IRecord[] | undefined = undefined; - const parsedResult = await this.parseResult<Record<string, unknown>>( - existingRecordResult, + if (computedArgs.ids && computedArgs.ids.length > 0) { + existingRecords = await this.duplicateService.findExistingRecords( + computedArgs.ids, objectMetadataItem, - '', + workspaceId, ); - existingRecord = parsedResult?.edges?.[0]?.node; - - if (!existingRecord) { - throw new NotFoundError(`Object with id ${args.id} not found`); + if (!existingRecords || existingRecords.length === 0) { + throw new NotFoundError(`Object with id ${args.ids} not found`); } } const query = await this.workspaceQueryBuilderFactory.findDuplicates( computedArgs, options, - existingRecord, + existingRecords, ); - await this.workspacePreQueryHookService.executePreHooks( + await this.workspaceQueryHookService.executePreQueryHooks( userId, workspaceId, objectMetadataItem.nameSingular, @@ -237,17 +227,22 @@ export class WorkspaceQueryRunnerService { result, objectMetadataItem, '', + true, ); } async createMany<Record extends IRecord = IRecord>( - args: CreateManyResolverArgs<Record>, + args: CreateManyResolverArgs<Partial<Record>>, options: WorkspaceQueryRunnerOptions, ): Promise<Record[] | undefined> { const { workspaceId, userId, objectMetadataItem } = options; assertMutationNotOnRemoteObject(objectMetadataItem); + if (args.upsert) { + return await this.upsertMany(args, options); + } + args.data.forEach((record) => { if (record?.id) { assertIsValidUuid(record.id); @@ -260,7 +255,7 @@ export class WorkspaceQueryRunnerService { ResolverArgsType.CreateMany, )) as CreateManyResolverArgs<Record>; - await this.workspacePreQueryHookService.executePreHooks( + await this.workspaceQueryHookService.executePreQueryHooks( userId, workspaceId, objectMetadataItem.nameSingular, @@ -305,17 +300,73 @@ export class WorkspaceQueryRunnerService { return parsedResults; } + async upsertMany<Record extends IRecord = IRecord>( + args: CreateManyResolverArgs<Partial<Record>>, + options: WorkspaceQueryRunnerOptions, + ): Promise<Record[] | undefined> { + const ids = args.data + .map((item) => item.id) + .filter((id) => id !== undefined); + + const existingRecords = + ids.length > 0 + ? await this.duplicateService.findExistingRecords( + ids as string[], + options.objectMetadataItem, + options.workspaceId, + ) + : []; + + const existingRecordsMap = new Map( + existingRecords.map((record) => [record.id, record]), + ); + + const results: Record[] = []; + const recordsToCreate: Partial<Record>[] = []; + + for (const payload of args.data) { + if (payload.id && existingRecordsMap.has(payload.id)) { + const result = await this.updateOne( + { id: payload.id, data: payload }, + options, + ); + + if (result) { + results.push(result); + } + } else { + recordsToCreate.push(payload); + } + } + + if (recordsToCreate.length > 0) { + const createResults = await this.createMany( + { data: recordsToCreate } as CreateManyResolverArgs<Partial<Record>>, + options, + ); + + if (createResults) { + results.push(...createResults); + } + } + + return results; + } + async createOne<Record extends IRecord = IRecord>( - args: CreateOneResolverArgs<Record>, + args: CreateOneResolverArgs<Partial<Record>>, options: WorkspaceQueryRunnerOptions, ): Promise<Record | undefined> { - const results = await this.createMany({ data: [args.data] }, options); + const results = await this.createMany( + { data: [args.data], upsert: args.upsert }, + options, + ); return results?.[0]; } async updateOne<Record extends IRecord = IRecord>( - args: UpdateOneResolverArgs<Record>, + args: UpdateOneResolverArgs<Partial<Record>>, options: WorkspaceQueryRunnerOptions, ): Promise<Record | undefined> { const { workspaceId, userId, objectMetadataItem } = options; @@ -333,7 +384,7 @@ export class WorkspaceQueryRunnerService { options, ); - await this.workspacePreQueryHookService.executePreHooks( + await this.workspaceQueryHookService.executePreQueryHooks( userId, workspaceId, objectMetadataItem.nameSingular, @@ -373,7 +424,7 @@ export class WorkspaceQueryRunnerService { } async updateMany<Record extends IRecord = IRecord>( - args: UpdateManyResolverArgs<Record>, + args: UpdateManyResolverArgs<Partial<Record>>, options: WorkspaceQueryRunnerOptions, ): Promise<Record[] | undefined> { const { userId, workspaceId, objectMetadataItem } = options; @@ -382,14 +433,14 @@ export class WorkspaceQueryRunnerService { args.filter?.id?.in?.forEach((id) => assertIsValidUuid(id)); const maximumRecordAffected = this.environmentService.get( - 'MUTATION_MAXIMUM_RECORD_AFFECTED', + 'MUTATION_MAXIMUM_AFFECTED_RECORDS', ); const query = await this.workspaceQueryBuilderFactory.updateMany(args, { ...options, atMost: maximumRecordAffected, }); - await this.workspacePreQueryHookService.executePreHooks( + await this.workspaceQueryHookService.executePreQueryHooks( userId, workspaceId, objectMetadataItem.nameSingular, @@ -434,14 +485,14 @@ export class WorkspaceQueryRunnerService { assertMutationNotOnRemoteObject(objectMetadataItem); const maximumRecordAffected = this.environmentService.get( - 'MUTATION_MAXIMUM_RECORD_AFFECTED', + 'MUTATION_MAXIMUM_AFFECTED_RECORDS', ); const query = await this.workspaceQueryBuilderFactory.deleteMany(args, { ...options, atMost: maximumRecordAffected, }); - await this.workspacePreQueryHookService.executePreHooks( + await this.workspaceQueryHookService.executePreQueryHooks( userId, workspaceId, objectMetadataItem.nameSingular, @@ -509,7 +560,7 @@ export class WorkspaceQueryRunnerService { ); // TODO END - await this.workspacePreQueryHookService.executePreHooks( + await this.workspaceQueryHookService.executePreQueryHooks( userId, workspaceId, objectMetadataItem.nameSingular, @@ -570,15 +621,12 @@ export class WorkspaceQueryRunnerService { return sanitizedRecord; } - async execute( - query: string, + async executeSQL( + workspaceDataSource: DataSource, workspaceId: string, - ): Promise<PGGraphQLResult | undefined> { - const workspaceDataSource = - await this.workspaceDataSourceService.connectToWorkspaceDataSource( - workspaceId, - ); - + sqlQuery: string, + parameters?: any[], + ) { try { return await workspaceDataSource?.transaction( async (transactionManager) => { @@ -588,10 +636,7 @@ export class WorkspaceQueryRunnerService { )}; `); - const results = transactionManager.query<PGGraphQLResult>( - `SELECT graphql.resolve($1);`, - [query], - ); + const results = transactionManager.query(sqlQuery, parameters); return results; }, @@ -605,15 +650,42 @@ export class WorkspaceQueryRunnerService { } } + async execute( + query: string, + workspaceId: string, + ): Promise<PGGraphQLResult | undefined> { + const workspaceDataSource = + await this.workspaceDataSourceService.connectToWorkspaceDataSource( + workspaceId, + ); + + return this.executeSQL( + workspaceDataSource, + workspaceId, + `SELECT graphql.resolve($1);`, + [query], + ); + } + private async parseResult<Result>( graphqlResult: PGGraphQLResult | undefined, objectMetadataItem: ObjectMetadataInterface, command: string, + isMultiQuery = false, ): Promise<Result> { const entityKey = `${command}${computeObjectTargetTable( objectMetadataItem, )}Collection`; - const result = graphqlResult?.[0]?.resolve?.data?.[entityKey]; + const result = !isMultiQuery + ? graphqlResult?.[0]?.resolve?.data?.[entityKey] + : Object.keys(graphqlResult?.[0]?.resolve?.data).reduce( + (acc: IRecord[], dataItem, index) => { + acc.push(graphqlResult?.[0]?.resolve?.data[`${entityKey}${index}`]); + + return acc; + }, + [], + ); const errors = graphqlResult?.[0]?.resolve?.errors; if ( @@ -631,7 +703,7 @@ export class WorkspaceQueryRunnerService { errors, { atMost: this.environmentService.get( - 'MUTATION_MAXIMUM_RECORD_AFFECTED', + 'MUTATION_MAXIMUM_AFFECTED_RECORDS', ), } satisfies PgGraphQLConfig, ); diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface.ts b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface.ts index aa31be0bf763..a2db909472bc 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface.ts @@ -39,26 +39,36 @@ export interface FindOneResolverArgs<Filter = any> { filter?: Filter; } -export interface FindDuplicatesResolverArgs<Data extends Record = Record> { - id?: string; - data?: Data; +export interface FindDuplicatesResolverArgs< + Data extends Partial<Record> = Partial<Record>, +> { + ids?: string[]; + data?: Data[]; } -export interface CreateOneResolverArgs<Data extends Record = Record> { +export interface CreateOneResolverArgs< + Data extends Partial<Record> = Partial<Record>, +> { data: Data; + upsert?: boolean; } -export interface CreateManyResolverArgs<Data extends Record = Record> { +export interface CreateManyResolverArgs< + Data extends Partial<Record> = Partial<Record>, +> { data: Data[]; + upsert?: boolean; } -export interface UpdateOneResolverArgs<Data extends Record = Record> { +export interface UpdateOneResolverArgs< + Data extends Partial<Record> = Partial<Record>, +> { id: string; data: Data; } export interface UpdateManyResolverArgs< - Data extends Record = Record, + Data extends Partial<Record> = Partial<Record>, Filter = any, > { filter: Filter; diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/factories/root-type.factory.ts b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/factories/root-type.factory.ts index 66a031420ab8..780cf2985af7 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/factories/root-type.factory.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/factories/root-type.factory.ts @@ -102,9 +102,12 @@ export class RootTypeFactory { } const outputType = this.typeMapperService.mapToGqlType(objectType, { - isArray: ['updateMany', 'deleteMany', 'createMany'].includes( - methodName, - ), + isArray: [ + 'updateMany', + 'deleteMany', + 'createMany', + 'findDuplicates', + ].includes(methodName), }); fieldConfigMap[name] = { diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/services/type-mapper.service.ts b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/services/type-mapper.service.ts index cb04e530021f..531939cf4c7b 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/services/type-mapper.service.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/services/type-mapper.service.ts @@ -73,7 +73,6 @@ export class TypeMapperService { ), ], [FieldMetadataType.NUMERIC, BigFloatScalarType], - [FieldMetadataType.PROBABILITY, GraphQLFloat], [FieldMetadataType.POSITION, PositionScalarType], [FieldMetadataType.RAW_JSON, RawJSONScalar], ]); @@ -109,7 +108,6 @@ export class TypeMapperService { ), ], [FieldMetadataType.NUMERIC, BigFloatFilterType], - [FieldMetadataType.PROBABILITY, FloatFilterType], [FieldMetadataType.POSITION, FloatFilterType], [FieldMetadataType.RAW_JSON, RawJsonFilterType], ]); @@ -130,7 +128,6 @@ export class TypeMapperService { [FieldMetadataType.BOOLEAN, OrderByDirectionType], [FieldMetadataType.NUMBER, OrderByDirectionType], [FieldMetadataType.NUMERIC, OrderByDirectionType], - [FieldMetadataType.PROBABILITY, OrderByDirectionType], [FieldMetadataType.RATING, OrderByDirectionType], [FieldMetadataType.SELECT, OrderByDirectionType], [FieldMetadataType.MULTI_SELECT, OrderByDirectionType], diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/utils/__tests__/get-resolver-args.spec.ts b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/utils/__tests__/get-resolver-args.spec.ts index b66087fe89f2..26652d04a69a 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/utils/__tests__/get-resolver-args.spec.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/utils/__tests__/get-resolver-args.spec.ts @@ -1,4 +1,4 @@ -import { GraphQLID, GraphQLInt, GraphQLString } from 'graphql'; +import { GraphQLBoolean, GraphQLID, GraphQLInt, GraphQLString } from 'graphql'; import { WorkspaceResolverBuilderMethodNames } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; @@ -13,7 +13,11 @@ describe('getResolverArgs', () => { before: { type: GraphQLString, isNullable: true }, after: { type: GraphQLString, isNullable: true }, filter: { kind: InputTypeDefinitionKind.Filter, isNullable: true }, - orderBy: { kind: InputTypeDefinitionKind.OrderBy, isNullable: true }, + orderBy: { + kind: InputTypeDefinitionKind.OrderBy, + isNullable: true, + isArray: true, + }, limit: { type: GraphQLInt, isNullable: true }, }, findOne: { @@ -25,9 +29,19 @@ describe('getResolverArgs', () => { isNullable: false, isArray: true, }, + upsert: { + isArray: false, + isNullable: true, + type: GraphQLBoolean, + }, }, createOne: { data: { kind: InputTypeDefinitionKind.Create, isNullable: false }, + upsert: { + isArray: false, + isNullable: true, + type: GraphQLBoolean, + }, }, updateOne: { id: { type: GraphQLID, isNullable: false }, diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/utils/get-resolver-args.util.ts b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/utils/get-resolver-args.util.ts index 5eaa8f314ce1..609f268fd81f 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/utils/get-resolver-args.util.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/utils/get-resolver-args.util.ts @@ -1,4 +1,4 @@ -import { GraphQLString, GraphQLInt, GraphQLID } from 'graphql'; +import { GraphQLString, GraphQLInt, GraphQLID, GraphQLBoolean } from 'graphql'; import { WorkspaceResolverBuilderMethodNames } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; import { ArgMetadata } from 'src/engine/api/graphql/workspace-schema-builder/interfaces/param-metadata.interface'; @@ -38,6 +38,7 @@ export const getResolverArgs = ( orderBy: { kind: InputTypeDefinitionKind.OrderBy, isNullable: true, + isArray: true, }, }; case 'findOne': @@ -55,6 +56,11 @@ export const getResolverArgs = ( isNullable: false, isArray: true, }, + upsert: { + type: GraphQLBoolean, + isNullable: true, + isArray: false, + }, }; case 'createOne': return { @@ -62,6 +68,11 @@ export const getResolverArgs = ( kind: InputTypeDefinitionKind.Create, isNullable: false, }, + upsert: { + type: GraphQLBoolean, + isNullable: true, + isArray: false, + }, }; case 'updateOne': return { @@ -76,13 +87,15 @@ export const getResolverArgs = ( }; case 'findDuplicates': return { - id: { + ids: { type: GraphQLID, isNullable: true, + isArray: true, }, data: { kind: InputTypeDefinitionKind.Create, isNullable: true, + isArray: true, }, }; case 'deleteOne': diff --git a/packages/twenty-server/src/engine/api/rest/controllers/rest-api-core-batch.controller.ts b/packages/twenty-server/src/engine/api/rest/core/controllers/rest-api-core-batch.controller.ts similarity index 86% rename from packages/twenty-server/src/engine/api/rest/controllers/rest-api-core-batch.controller.ts rename to packages/twenty-server/src/engine/api/rest/core/controllers/rest-api-core-batch.controller.ts index 6f35ed834d29..e77ae4c8912f 100644 --- a/packages/twenty-server/src/engine/api/rest/controllers/rest-api-core-batch.controller.ts +++ b/packages/twenty-server/src/engine/api/rest/core/controllers/rest-api-core-batch.controller.ts @@ -2,7 +2,7 @@ import { Controller, Post, Req, Res } from '@nestjs/common'; import { Request, Response } from 'express'; -import { RestApiCoreService } from 'src/engine/api/rest/services/rest-api-core.service'; +import { RestApiCoreService } from 'src/engine/api/rest/core/rest-api-core.service'; import { cleanGraphQLResponse } from 'src/engine/api/rest/utils/clean-graphql-response.utils'; @Controller('rest/batch/*') diff --git a/packages/twenty-server/src/engine/api/rest/controllers/rest-api-core.controller.ts b/packages/twenty-server/src/engine/api/rest/core/controllers/rest-api-core.controller.ts similarity index 94% rename from packages/twenty-server/src/engine/api/rest/controllers/rest-api-core.controller.ts rename to packages/twenty-server/src/engine/api/rest/core/controllers/rest-api-core.controller.ts index fe2dfacaeaf0..5fd46c49a269 100644 --- a/packages/twenty-server/src/engine/api/rest/controllers/rest-api-core.controller.ts +++ b/packages/twenty-server/src/engine/api/rest/core/controllers/rest-api-core.controller.ts @@ -11,7 +11,7 @@ import { import { Request, Response } from 'express'; -import { RestApiCoreService } from 'src/engine/api/rest/services/rest-api-core.service'; +import { RestApiCoreService } from 'src/engine/api/rest/core/rest-api-core.service'; import { cleanGraphQLResponse } from 'src/engine/api/rest/utils/clean-graphql-response.utils'; @Controller('rest/*') diff --git a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/core-query-builder.factory.ts b/packages/twenty-server/src/engine/api/rest/core/query-builder/core-query-builder.factory.ts similarity index 76% rename from packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/core-query-builder.factory.ts rename to packages/twenty-server/src/engine/api/rest/core/query-builder/core-query-builder.factory.ts index d7f0d6d185da..bd2bda31d9cf 100644 --- a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/core-query-builder.factory.ts +++ b/packages/twenty-server/src/engine/api/rest/core/query-builder/core-query-builder.factory.ts @@ -2,24 +2,24 @@ import { BadRequestException, Injectable } from '@nestjs/common'; import { Request } from 'express'; -import { DeleteQueryFactory } from 'src/engine/api/rest/rest-api-core-query-builder/factories/delete-query.factory'; +import { DeleteQueryFactory } from 'src/engine/api/rest/core/query-builder/factories/delete-query.factory'; import { ObjectMetadataService } from 'src/engine/metadata-modules/object-metadata/object-metadata.service'; import { TokenService } from 'src/engine/core-modules/auth/services/token.service'; -import { CreateOneQueryFactory } from 'src/engine/api/rest/rest-api-core-query-builder/factories/create-one-query.factory'; -import { UpdateQueryFactory } from 'src/engine/api/rest/rest-api-core-query-builder/factories/update-query.factory'; -import { FindOneQueryFactory } from 'src/engine/api/rest/rest-api-core-query-builder/factories/find-one-query.factory'; -import { FindManyQueryFactory } from 'src/engine/api/rest/rest-api-core-query-builder/factories/find-many-query.factory'; -import { DeleteVariablesFactory } from 'src/engine/api/rest/rest-api-core-query-builder/factories/delete-variables.factory'; -import { CreateVariablesFactory } from 'src/engine/api/rest/rest-api-core-query-builder/factories/create-variables.factory'; -import { UpdateVariablesFactory } from 'src/engine/api/rest/rest-api-core-query-builder/factories/update-variables.factory'; -import { GetVariablesFactory } from 'src/engine/api/rest/rest-api-core-query-builder/factories/get-variables.factory'; -import { parseCorePath } from 'src/engine/api/rest/rest-api-core-query-builder/utils/path-parsers/parse-core-path.utils'; -import { computeDepth } from 'src/engine/api/rest/rest-api-core-query-builder/utils/compute-depth.utils'; +import { CreateOneQueryFactory } from 'src/engine/api/rest/core/query-builder/factories/create-one-query.factory'; +import { UpdateQueryFactory } from 'src/engine/api/rest/core/query-builder/factories/update-query.factory'; +import { FindOneQueryFactory } from 'src/engine/api/rest/core/query-builder/factories/find-one-query.factory'; +import { FindManyQueryFactory } from 'src/engine/api/rest/core/query-builder/factories/find-many-query.factory'; +import { DeleteVariablesFactory } from 'src/engine/api/rest/core/query-builder/factories/delete-variables.factory'; +import { CreateVariablesFactory } from 'src/engine/api/rest/core/query-builder/factories/create-variables.factory'; +import { UpdateVariablesFactory } from 'src/engine/api/rest/core/query-builder/factories/update-variables.factory'; +import { GetVariablesFactory } from 'src/engine/api/rest/core/query-builder/factories/get-variables.factory'; +import { parseCorePath } from 'src/engine/api/rest/core/query-builder/utils/path-parsers/parse-core-path.utils'; +import { computeDepth } from 'src/engine/api/rest/core/query-builder/utils/compute-depth.utils'; import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; -import { Query } from 'src/engine/api/rest/types/query.type'; +import { Query } from 'src/engine/api/rest/core/types/query.type'; import { EnvironmentService } from 'src/engine/integrations/environment/environment.service'; -import { CreateManyQueryFactory } from 'src/engine/api/rest/rest-api-core-query-builder/factories/create-many-query.factory'; -import { parseCoreBatchPath } from 'src/engine/api/rest/rest-api-core-query-builder/utils/path-parsers/parse-core-batch-path.utils'; +import { CreateManyQueryFactory } from 'src/engine/api/rest/core/query-builder/factories/create-many-query.factory'; +import { parseCoreBatchPath } from 'src/engine/api/rest/core/query-builder/utils/path-parsers/parse-core-batch-path.utils'; @Injectable() export class CoreQueryBuilderFactory { diff --git a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/core-query-builder.module.ts b/packages/twenty-server/src/engine/api/rest/core/query-builder/core-query-builder.module.ts similarity index 64% rename from packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/core-query-builder.module.ts rename to packages/twenty-server/src/engine/api/rest/core/query-builder/core-query-builder.module.ts index 8e91f11742d4..38b5ec398c34 100644 --- a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/core-query-builder.module.ts +++ b/packages/twenty-server/src/engine/api/rest/core/query-builder/core-query-builder.module.ts @@ -1,7 +1,7 @@ import { Module } from '@nestjs/common'; -import { CoreQueryBuilderFactory } from 'src/engine/api/rest/rest-api-core-query-builder/core-query-builder.factory'; -import { coreQueryBuilderFactories } from 'src/engine/api/rest/rest-api-core-query-builder/factories/factories'; +import { CoreQueryBuilderFactory } from 'src/engine/api/rest/core/query-builder/core-query-builder.factory'; +import { coreQueryBuilderFactories } from 'src/engine/api/rest/core/query-builder/factories/factories'; import { ObjectMetadataModule } from 'src/engine/metadata-modules/object-metadata/object-metadata.module'; import { AuthModule } from 'src/engine/core-modules/auth/auth.module'; diff --git a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/create-many-query.factory.ts b/packages/twenty-server/src/engine/api/rest/core/query-builder/factories/create-many-query.factory.ts similarity index 92% rename from packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/create-many-query.factory.ts rename to packages/twenty-server/src/engine/api/rest/core/query-builder/factories/create-many-query.factory.ts index 02c8714f44e6..b02bf194bbcc 100644 --- a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/create-many-query.factory.ts +++ b/packages/twenty-server/src/engine/api/rest/core/query-builder/factories/create-many-query.factory.ts @@ -1,7 +1,7 @@ import { Injectable } from '@nestjs/common'; import { capitalize } from 'src/utils/capitalize'; -import { mapFieldMetadataToGraphqlQuery } from 'src/engine/api/rest/rest-api-core-query-builder/utils/map-field-metadata-to-graphql-query.utils'; +import { mapFieldMetadataToGraphqlQuery } from 'src/engine/api/rest/core/query-builder/utils/map-field-metadata-to-graphql-query.utils'; @Injectable() export class CreateManyQueryFactory { diff --git a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/create-one-query.factory.ts b/packages/twenty-server/src/engine/api/rest/core/query-builder/factories/create-one-query.factory.ts similarity index 91% rename from packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/create-one-query.factory.ts rename to packages/twenty-server/src/engine/api/rest/core/query-builder/factories/create-one-query.factory.ts index a7135605eb41..e8078898935d 100644 --- a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/create-one-query.factory.ts +++ b/packages/twenty-server/src/engine/api/rest/core/query-builder/factories/create-one-query.factory.ts @@ -1,7 +1,7 @@ import { Injectable } from '@nestjs/common'; import { capitalize } from 'src/utils/capitalize'; -import { mapFieldMetadataToGraphqlQuery } from 'src/engine/api/rest/rest-api-core-query-builder/utils/map-field-metadata-to-graphql-query.utils'; +import { mapFieldMetadataToGraphqlQuery } from 'src/engine/api/rest/core/query-builder/utils/map-field-metadata-to-graphql-query.utils'; @Injectable() export class CreateOneQueryFactory { diff --git a/packages/twenty-server/src/engine/api/rest/core/query-builder/factories/create-variables.factory.ts b/packages/twenty-server/src/engine/api/rest/core/query-builder/factories/create-variables.factory.ts new file mode 100644 index 000000000000..cb907164a258 --- /dev/null +++ b/packages/twenty-server/src/engine/api/rest/core/query-builder/factories/create-variables.factory.ts @@ -0,0 +1,14 @@ +import { Injectable } from '@nestjs/common'; + +import { Request } from 'express'; + +import { QueryVariables } from 'src/engine/api/rest/core/types/query-variables.type'; + +@Injectable() +export class CreateVariablesFactory { + create(request: Request): QueryVariables { + return { + data: request.body, + }; + } +} diff --git a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/delete-query.factory.ts b/packages/twenty-server/src/engine/api/rest/core/query-builder/factories/delete-query.factory.ts similarity index 100% rename from packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/delete-query.factory.ts rename to packages/twenty-server/src/engine/api/rest/core/query-builder/factories/delete-query.factory.ts diff --git a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/delete-variables.factory.ts b/packages/twenty-server/src/engine/api/rest/core/query-builder/factories/delete-variables.factory.ts similarity index 67% rename from packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/delete-variables.factory.ts rename to packages/twenty-server/src/engine/api/rest/core/query-builder/factories/delete-variables.factory.ts index c41c2073c2df..a1a5a40bd221 100644 --- a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/delete-variables.factory.ts +++ b/packages/twenty-server/src/engine/api/rest/core/query-builder/factories/delete-variables.factory.ts @@ -1,6 +1,6 @@ import { Injectable } from '@nestjs/common'; -import { QueryVariables } from 'src/engine/api/rest/types/query-variables.type'; +import { QueryVariables } from 'src/engine/api/rest/core/types/query-variables.type'; @Injectable() export class DeleteVariablesFactory { diff --git a/packages/twenty-server/src/engine/api/rest/core/query-builder/factories/factories.ts b/packages/twenty-server/src/engine/api/rest/core/query-builder/factories/factories.ts new file mode 100644 index 000000000000..00faf41ca5e9 --- /dev/null +++ b/packages/twenty-server/src/engine/api/rest/core/query-builder/factories/factories.ts @@ -0,0 +1,25 @@ +import { DeleteQueryFactory } from 'src/engine/api/rest/core/query-builder/factories/delete-query.factory'; +import { CreateOneQueryFactory } from 'src/engine/api/rest/core/query-builder/factories/create-one-query.factory'; +import { UpdateQueryFactory } from 'src/engine/api/rest/core/query-builder/factories/update-query.factory'; +import { FindOneQueryFactory } from 'src/engine/api/rest/core/query-builder/factories/find-one-query.factory'; +import { FindManyQueryFactory } from 'src/engine/api/rest/core/query-builder/factories/find-many-query.factory'; +import { DeleteVariablesFactory } from 'src/engine/api/rest/core/query-builder/factories/delete-variables.factory'; +import { CreateVariablesFactory } from 'src/engine/api/rest/core/query-builder/factories/create-variables.factory'; +import { UpdateVariablesFactory } from 'src/engine/api/rest/core/query-builder/factories/update-variables.factory'; +import { GetVariablesFactory } from 'src/engine/api/rest/core/query-builder/factories/get-variables.factory'; +import { CreateManyQueryFactory } from 'src/engine/api/rest/core/query-builder/factories/create-many-query.factory'; +import { inputFactories } from 'src/engine/api/rest/input-factories/factories'; + +export const coreQueryBuilderFactories = [ + DeleteQueryFactory, + CreateOneQueryFactory, + CreateManyQueryFactory, + UpdateQueryFactory, + FindOneQueryFactory, + FindManyQueryFactory, + DeleteVariablesFactory, + CreateVariablesFactory, + UpdateVariablesFactory, + GetVariablesFactory, + ...inputFactories, +]; diff --git a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/find-many-query.factory.ts b/packages/twenty-server/src/engine/api/rest/core/query-builder/factories/find-many-query.factory.ts similarity index 78% rename from packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/find-many-query.factory.ts rename to packages/twenty-server/src/engine/api/rest/core/query-builder/factories/find-many-query.factory.ts index bd6bd1e458c1..401721162d83 100644 --- a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/find-many-query.factory.ts +++ b/packages/twenty-server/src/engine/api/rest/core/query-builder/factories/find-many-query.factory.ts @@ -1,7 +1,7 @@ import { Injectable } from '@nestjs/common'; import { capitalize } from 'src/utils/capitalize'; -import { mapFieldMetadataToGraphqlQuery } from 'src/engine/api/rest/rest-api-core-query-builder/utils/map-field-metadata-to-graphql-query.utils'; +import { mapFieldMetadataToGraphqlQuery } from 'src/engine/api/rest/core/query-builder/utils/map-field-metadata-to-graphql-query.utils'; @Injectable() export class FindManyQueryFactory { @@ -14,13 +14,19 @@ export class FindManyQueryFactory { return ` query FindMany${capitalize(objectNamePlural)}( $filter: ${objectNameSingular}FilterInput, - $orderBy: ${objectNameSingular}OrderByInput, + $orderBy: [${objectNameSingular}OrderByInput], $startingAfter: String, $endingBefore: String, - $limit: Int = 60 + $first: Int, + $last: Int ) { ${objectNamePlural}( - filter: $filter, orderBy: $orderBy, first: $limit, after: $startingAfter, before: $endingBefore + filter: $filter, + orderBy: $orderBy, + first: $first, + last: $last, + after: $startingAfter, + before: $endingBefore ) { edges { node { diff --git a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/find-one-query.factory.ts b/packages/twenty-server/src/engine/api/rest/core/query-builder/factories/find-one-query.factory.ts similarity index 91% rename from packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/find-one-query.factory.ts rename to packages/twenty-server/src/engine/api/rest/core/query-builder/factories/find-one-query.factory.ts index 9286080be123..cc2b498710bc 100644 --- a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/find-one-query.factory.ts +++ b/packages/twenty-server/src/engine/api/rest/core/query-builder/factories/find-one-query.factory.ts @@ -1,7 +1,7 @@ import { Injectable } from '@nestjs/common'; import { capitalize } from 'src/utils/capitalize'; -import { mapFieldMetadataToGraphqlQuery } from 'src/engine/api/rest/rest-api-core-query-builder/utils/map-field-metadata-to-graphql-query.utils'; +import { mapFieldMetadataToGraphqlQuery } from 'src/engine/api/rest/core/query-builder/utils/map-field-metadata-to-graphql-query.utils'; @Injectable() export class FindOneQueryFactory { diff --git a/packages/twenty-server/src/engine/api/rest/core/query-builder/factories/get-variables.factory.ts b/packages/twenty-server/src/engine/api/rest/core/query-builder/factories/get-variables.factory.ts new file mode 100644 index 000000000000..5af552d48f70 --- /dev/null +++ b/packages/twenty-server/src/engine/api/rest/core/query-builder/factories/get-variables.factory.ts @@ -0,0 +1,44 @@ +import { Injectable } from '@nestjs/common'; + +import { Request } from 'express'; + +import { LimitInputFactory } from 'src/engine/api/rest/input-factories/limit-input.factory'; +import { OrderByInputFactory } from 'src/engine/api/rest/input-factories/order-by-input.factory'; +import { FilterInputFactory } from 'src/engine/api/rest/input-factories/filter-input.factory'; +import { QueryVariables } from 'src/engine/api/rest/core/types/query-variables.type'; +import { EndingBeforeInputFactory } from 'src/engine/api/rest/input-factories/ending-before-input.factory'; +import { StartingAfterInputFactory } from 'src/engine/api/rest/input-factories/starting-after-input.factory'; + +@Injectable() +export class GetVariablesFactory { + constructor( + private readonly startingAfterInputFactory: StartingAfterInputFactory, + private readonly endingBeforeInputFactory: EndingBeforeInputFactory, + private readonly limitInputFactory: LimitInputFactory, + private readonly orderByInputFactory: OrderByInputFactory, + private readonly filterInputFactory: FilterInputFactory, + ) {} + + create( + id: string | undefined, + request: Request, + objectMetadata, + ): QueryVariables { + if (id) { + return { filter: { id: { eq: id } } }; + } + + const limit = this.limitInputFactory.create(request); + const endingBefore = this.endingBeforeInputFactory.create(request); + const startingAfter = this.startingAfterInputFactory.create(request); + + return { + filter: this.filterInputFactory.create(request, objectMetadata), + orderBy: this.orderByInputFactory.create(request, objectMetadata), + first: !endingBefore ? limit : undefined, + last: endingBefore ? limit : undefined, + startingAfter, + endingBefore, + }; + } +} diff --git a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/update-query.factory.ts b/packages/twenty-server/src/engine/api/rest/core/query-builder/factories/update-query.factory.ts similarity index 91% rename from packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/update-query.factory.ts rename to packages/twenty-server/src/engine/api/rest/core/query-builder/factories/update-query.factory.ts index ca7e9cd03d3d..f578b2d18e49 100644 --- a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/update-query.factory.ts +++ b/packages/twenty-server/src/engine/api/rest/core/query-builder/factories/update-query.factory.ts @@ -1,7 +1,7 @@ import { Injectable } from '@nestjs/common'; import { capitalize } from 'src/utils/capitalize'; -import { mapFieldMetadataToGraphqlQuery } from 'src/engine/api/rest/rest-api-core-query-builder/utils/map-field-metadata-to-graphql-query.utils'; +import { mapFieldMetadataToGraphqlQuery } from 'src/engine/api/rest/core/query-builder/utils/map-field-metadata-to-graphql-query.utils'; @Injectable() export class UpdateQueryFactory { diff --git a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/update-variables.factory.ts b/packages/twenty-server/src/engine/api/rest/core/query-builder/factories/update-variables.factory.ts similarity index 74% rename from packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/update-variables.factory.ts rename to packages/twenty-server/src/engine/api/rest/core/query-builder/factories/update-variables.factory.ts index 588288bf92d1..c911faa03a0b 100644 --- a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/update-variables.factory.ts +++ b/packages/twenty-server/src/engine/api/rest/core/query-builder/factories/update-variables.factory.ts @@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common'; import { Request } from 'express'; -import { QueryVariables } from 'src/engine/api/rest/types/query-variables.type'; +import { QueryVariables } from 'src/engine/api/rest/core/types/query-variables.type'; @Injectable() export class UpdateVariablesFactory { diff --git a/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/__tests__/check-fields.utils.spec.ts b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/__tests__/check-fields.utils.spec.ts new file mode 100644 index 000000000000..865eac4bc2b8 --- /dev/null +++ b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/__tests__/check-fields.utils.spec.ts @@ -0,0 +1,34 @@ +import { objectMetadataItemMock } from 'src/engine/api/__mocks__/object-metadata-item.mock'; +import { checkFields } from 'src/engine/api/rest/core/query-builder/utils/check-fields.utils'; +import { checkArrayFields } from 'src/engine/api/rest/core/query-builder/utils/check-order-by.utils'; + +describe('checkFields', () => { + it('should check field types', () => { + expect(() => + checkFields(objectMetadataItemMock, ['fieldNumber']), + ).not.toThrow(); + + expect(() => checkFields(objectMetadataItemMock, ['wrongField'])).toThrow(); + + expect(() => + checkFields(objectMetadataItemMock, ['fieldNumber', 'wrongField']), + ).toThrow(); + }); + + it('should check field types from array of fields', () => { + expect(() => + checkArrayFields(objectMetadataItemMock, [{ fieldNumber: undefined }]), + ).not.toThrow(); + + expect(() => + checkArrayFields(objectMetadataItemMock, [{ wrongField: undefined }]), + ).toThrow(); + + expect(() => + checkArrayFields(objectMetadataItemMock, [ + { fieldNumber: undefined }, + { wrongField: undefined }, + ]), + ).toThrow(); + }); +}); diff --git a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/utils/__tests__/compute-depth.utils.spec.ts b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/__tests__/compute-depth.utils.spec.ts similarity index 54% rename from packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/utils/__tests__/compute-depth.utils.spec.ts rename to packages/twenty-server/src/engine/api/rest/core/query-builder/utils/__tests__/compute-depth.utils.spec.ts index a6909574a6cc..7a2f51f18ad0 100644 --- a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/utils/__tests__/compute-depth.utils.spec.ts +++ b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/__tests__/compute-depth.utils.spec.ts @@ -1,12 +1,14 @@ -import { computeDepth } from 'src/engine/api/rest/rest-api-core-query-builder/utils/compute-depth.utils'; +import { computeDepth } from 'src/engine/api/rest/core/query-builder/utils/compute-depth.utils'; describe('computeDepth', () => { - it('should compute depth from query', () => { - const request: any = { - query: { depth: '1' }, - }; + [0, 1, 2].forEach((depth) => { + it('should compute depth from query', () => { + const request: any = { + query: { depth: `${depth}` }, + }; - expect(computeDepth(request)).toEqual(1); + expect(computeDepth(request)).toEqual(depth); + }); }); it('should return default depth if missing', () => { @@ -19,7 +21,7 @@ describe('computeDepth', () => { expect(() => computeDepth(request)).toThrow(); - request.query.depth = '0'; + request.query.depth = '-1'; expect(() => computeDepth(request)).toThrow(); }); diff --git a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/utils/__tests__/get-field-type.utils.spec.ts b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/__tests__/get-field-type.utils.spec.ts similarity index 78% rename from packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/utils/__tests__/get-field-type.utils.spec.ts rename to packages/twenty-server/src/engine/api/rest/core/query-builder/utils/__tests__/get-field-type.utils.spec.ts index 6c09709c205f..ec6854bc482f 100644 --- a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/utils/__tests__/get-field-type.utils.spec.ts +++ b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/__tests__/get-field-type.utils.spec.ts @@ -1,6 +1,6 @@ import { objectMetadataItemMock } from 'src/engine/api/__mocks__/object-metadata-item.mock'; import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; -import { getFieldType } from 'src/engine/api/rest/rest-api-core-query-builder/utils/get-field-type.utils'; +import { getFieldType } from 'src/engine/api/rest/core/query-builder/utils/get-field-type.utils'; describe('getFieldType', () => { it('should get field type', () => { diff --git a/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/__tests__/map-field-metadata-to-graphql-query.utils.spec.ts b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/__tests__/map-field-metadata-to-graphql-query.utils.spec.ts new file mode 100644 index 000000000000..473c6f8408d8 --- /dev/null +++ b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/__tests__/map-field-metadata-to-graphql-query.utils.spec.ts @@ -0,0 +1,59 @@ +import { + fieldCurrencyMock, + fieldLinkMock, + fieldNumberMock, + fieldTextMock, + objectMetadataItemMock, +} from 'src/engine/api/__mocks__/object-metadata-item.mock'; +import { mapFieldMetadataToGraphqlQuery } from 'src/engine/api/rest/core/query-builder/utils/map-field-metadata-to-graphql-query.utils'; +import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; +import { RelationMetadataType } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity'; + +describe('mapFieldMetadataToGraphqlQuery', () => { + it('should map properly', () => { + expect( + mapFieldMetadataToGraphqlQuery([objectMetadataItemMock], fieldNumberMock), + ).toEqual('fieldNumber'); + expect( + mapFieldMetadataToGraphqlQuery([objectMetadataItemMock], fieldTextMock), + ).toEqual('fieldText'); + expect( + mapFieldMetadataToGraphqlQuery([objectMetadataItemMock], fieldLinkMock), + ).toEqual(` + fieldLink + { + label + url + } + `); + expect( + mapFieldMetadataToGraphqlQuery( + [objectMetadataItemMock], + fieldCurrencyMock, + ), + ).toEqual(` + fieldCurrency + { + amountMicros + currencyCode + } + `); + }); + describe('should handle all field metadata types', () => { + Object.values(FieldMetadataType).forEach((fieldMetadataType) => { + it(`with field type ${fieldMetadataType}`, () => { + const field = { + type: fieldMetadataType, + name: 'toObjectMetadataName', + fromRelationMetadata: { + relationType: RelationMetadataType.ONE_TO_MANY, + }, + }; + + expect( + mapFieldMetadataToGraphqlQuery([objectMetadataItemMock], field), + ).toBeDefined(); + }); + }); + }); +}); diff --git a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/utils/check-fields.utils.ts b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/check-fields.utils.ts similarity index 100% rename from packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/utils/check-fields.utils.ts rename to packages/twenty-server/src/engine/api/rest/core/query-builder/utils/check-fields.utils.ts diff --git a/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/check-order-by.utils.ts b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/check-order-by.utils.ts new file mode 100644 index 000000000000..ce14a02bd276 --- /dev/null +++ b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/check-order-by.utils.ts @@ -0,0 +1,48 @@ +import { BadRequestException } from '@nestjs/common'; + +import { ObjectMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/object-metadata.interface'; +import { Record } from 'src/engine/api/graphql/workspace-query-builder/interfaces/record.interface'; + +import { compositeTypeDefintions } from 'src/engine/metadata-modules/field-metadata/composite-types'; +import { isCompositeFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/utils/is-composite-field-metadata-type.util'; +import { computeObjectTargetTable } from 'src/engine/utils/compute-object-target-table.util'; + +export const checkArrayFields = ( + objectMetadata: ObjectMetadataInterface, + fields: Array<Partial<Record>>, +): void => { + const fieldMetadataNames = objectMetadata.fields + .map((field) => { + if (isCompositeFieldMetadataType(field.type)) { + const compositeType = compositeTypeDefintions.get(field.type); + + if (!compositeType) { + throw new BadRequestException( + `Composite type '${field.type}' not found`, + ); + } + + return [ + field.name, + compositeType.properties.map( + (compositeProperty) => compositeProperty.name, + ), + ].flat(); + } + + return field.name; + }) + .flat(); + + for (const fieldObj of fields) { + for (const fieldName in fieldObj) { + if (!fieldMetadataNames.includes(fieldName)) { + throw new BadRequestException( + `field '${fieldName}' does not exist in '${computeObjectTargetTable( + objectMetadata, + )}' object`, + ); + } + } + } +}; diff --git a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/utils/compute-depth.utils.ts b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/compute-depth.utils.ts similarity index 93% rename from packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/utils/compute-depth.utils.ts rename to packages/twenty-server/src/engine/api/rest/core/query-builder/utils/compute-depth.utils.ts index 6fdee1b30d9f..ecd5060cfb45 100644 --- a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/utils/compute-depth.utils.ts +++ b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/compute-depth.utils.ts @@ -2,7 +2,7 @@ import { BadRequestException } from '@nestjs/common'; import { Request } from 'express'; -const ALLOWED_DEPTH_VALUES = [1, 2]; +const ALLOWED_DEPTH_VALUES = [0, 1, 2]; export const computeDepth = (request: Request): number | undefined => { if (!request.query.depth) { diff --git a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/__tests__/add-default-conjunction.utils.spec.ts b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/filter-utils/__tests__/add-default-conjunction.utils.spec.ts similarity index 81% rename from packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/__tests__/add-default-conjunction.utils.spec.ts rename to packages/twenty-server/src/engine/api/rest/core/query-builder/utils/filter-utils/__tests__/add-default-conjunction.utils.spec.ts index 8adda483599e..1b949c855194 100644 --- a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/__tests__/add-default-conjunction.utils.spec.ts +++ b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/filter-utils/__tests__/add-default-conjunction.utils.spec.ts @@ -1,4 +1,4 @@ -import { addDefaultConjunctionIfMissing } from 'src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/add-default-conjunction.utils'; +import { addDefaultConjunctionIfMissing } from 'src/engine/api/rest/core/query-builder/utils/filter-utils/add-default-conjunction.utils'; describe('addDefaultConjunctionIfMissing', () => { it('should add default conjunction if missing', () => { diff --git a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/__tests__/check-filter-enum-values.spec.ts b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/filter-utils/__tests__/check-filter-enum-values.spec.ts similarity index 84% rename from packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/__tests__/check-filter-enum-values.spec.ts rename to packages/twenty-server/src/engine/api/rest/core/query-builder/utils/filter-utils/__tests__/check-filter-enum-values.spec.ts index 4e4694c11019..8c24bce85846 100644 --- a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/__tests__/check-filter-enum-values.spec.ts +++ b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/filter-utils/__tests__/check-filter-enum-values.spec.ts @@ -1,4 +1,4 @@ -import { checkFilterEnumValues } from 'src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/check-filter-enum-values'; +import { checkFilterEnumValues } from 'src/engine/api/rest/core/query-builder/utils/filter-utils/check-filter-enum-values'; import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; import { fieldSelectMock, diff --git a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/__tests__/check-filter-query.utils.spec.ts b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/filter-utils/__tests__/check-filter-query.utils.spec.ts similarity index 86% rename from packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/__tests__/check-filter-query.utils.spec.ts rename to packages/twenty-server/src/engine/api/rest/core/query-builder/utils/filter-utils/__tests__/check-filter-query.utils.spec.ts index fc1f3e81870b..7cba92df6d0e 100644 --- a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/__tests__/check-filter-query.utils.spec.ts +++ b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/filter-utils/__tests__/check-filter-query.utils.spec.ts @@ -1,4 +1,4 @@ -import { checkFilterQuery } from 'src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/check-filter-query.utils'; +import { checkFilterQuery } from 'src/engine/api/rest/core/query-builder/utils/filter-utils/check-filter-query.utils'; describe('checkFilterQuery', () => { it('should check filter query', () => { diff --git a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/__tests__/format-field-values.utils.spec.ts b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/filter-utils/__tests__/format-field-values.utils.spec.ts similarity index 92% rename from packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/__tests__/format-field-values.utils.spec.ts rename to packages/twenty-server/src/engine/api/rest/core/query-builder/utils/filter-utils/__tests__/format-field-values.utils.spec.ts index eb94f88b310d..6787ccc3eec8 100644 --- a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/__tests__/format-field-values.utils.spec.ts +++ b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/filter-utils/__tests__/format-field-values.utils.spec.ts @@ -1,5 +1,5 @@ import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; -import { formatFieldValue } from 'src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/format-field-values.utils'; +import { formatFieldValue } from 'src/engine/api/rest/core/query-builder/utils/filter-utils/format-field-values.utils'; describe('formatFieldValue', () => { it('should format fieldNumber value', () => { diff --git a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/__tests__/parse-base-filter.utils.spec.ts b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/filter-utils/__tests__/parse-base-filter.utils.spec.ts similarity index 90% rename from packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/__tests__/parse-base-filter.utils.spec.ts rename to packages/twenty-server/src/engine/api/rest/core/query-builder/utils/filter-utils/__tests__/parse-base-filter.utils.spec.ts index c522b00bde8d..dc41296b7ac7 100644 --- a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/__tests__/parse-base-filter.utils.spec.ts +++ b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/filter-utils/__tests__/parse-base-filter.utils.spec.ts @@ -1,4 +1,4 @@ -import { parseBaseFilter } from 'src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/parse-base-filter.utils'; +import { parseBaseFilter } from 'src/engine/api/rest/core/query-builder/utils/filter-utils/parse-base-filter.utils'; describe('parseBaseFilter', () => { it('should parse simple filter string test 1', () => { diff --git a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/__tests__/parse-filter-content.utils.spec.ts b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/filter-utils/__tests__/parse-filter-content.utils.spec.ts similarity index 91% rename from packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/__tests__/parse-filter-content.utils.spec.ts rename to packages/twenty-server/src/engine/api/rest/core/query-builder/utils/filter-utils/__tests__/parse-filter-content.utils.spec.ts index ed0efea1c25b..884c672395d8 100644 --- a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/__tests__/parse-filter-content.utils.spec.ts +++ b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/filter-utils/__tests__/parse-filter-content.utils.spec.ts @@ -1,4 +1,4 @@ -import { parseFilterContent } from 'src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/parse-filter-content.utils'; +import { parseFilterContent } from 'src/engine/api/rest/core/query-builder/utils/filter-utils/parse-filter-content.utils'; describe('parseFilterContent', () => { it('should parse query filter test 1', () => { diff --git a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/__tests__/parse-filter.utils.spec.ts b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/filter-utils/__tests__/parse-filter.utils.spec.ts similarity index 94% rename from packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/__tests__/parse-filter.utils.spec.ts rename to packages/twenty-server/src/engine/api/rest/core/query-builder/utils/filter-utils/__tests__/parse-filter.utils.spec.ts index 3dfdd2b75b89..b92b09c96b31 100644 --- a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/__tests__/parse-filter.utils.spec.ts +++ b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/filter-utils/__tests__/parse-filter.utils.spec.ts @@ -1,5 +1,5 @@ import { objectMetadataItemMock } from 'src/engine/api/__mocks__/object-metadata-item.mock'; -import { parseFilter } from 'src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/parse-filter.utils'; +import { parseFilter } from 'src/engine/api/rest/core/query-builder/utils/filter-utils/parse-filter.utils'; describe('parseFilter', () => { it('should parse string filter test 1', () => { diff --git a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/add-default-conjunction.utils.ts b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/filter-utils/add-default-conjunction.utils.ts similarity index 67% rename from packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/add-default-conjunction.utils.ts rename to packages/twenty-server/src/engine/api/rest/core/query-builder/utils/filter-utils/add-default-conjunction.utils.ts index 03f66456e802..f30bf375d2e9 100644 --- a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/add-default-conjunction.utils.ts +++ b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/filter-utils/add-default-conjunction.utils.ts @@ -1,4 +1,4 @@ -import { Conjunctions } from 'src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/parse-filter.utils'; +import { Conjunctions } from 'src/engine/api/rest/core/query-builder/utils/filter-utils/parse-filter.utils'; export const DEFAULT_CONJUNCTION = Conjunctions.and; diff --git a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/check-filter-enum-values.ts b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/filter-utils/check-filter-enum-values.ts similarity index 100% rename from packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/check-filter-enum-values.ts rename to packages/twenty-server/src/engine/api/rest/core/query-builder/utils/filter-utils/check-filter-enum-values.ts diff --git a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/check-filter-query.utils.ts b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/filter-utils/check-filter-query.utils.ts similarity index 100% rename from packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/check-filter-query.utils.ts rename to packages/twenty-server/src/engine/api/rest/core/query-builder/utils/filter-utils/check-filter-query.utils.ts diff --git a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/format-field-values.utils.ts b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/filter-utils/format-field-values.utils.ts similarity index 93% rename from packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/format-field-values.utils.ts rename to packages/twenty-server/src/engine/api/rest/core/query-builder/utils/filter-utils/format-field-values.utils.ts index eeab31d6745e..79e351f94136 100644 --- a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/format-field-values.utils.ts +++ b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/filter-utils/format-field-values.utils.ts @@ -1,7 +1,7 @@ import { BadRequestException } from '@nestjs/common'; import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; -import { FieldValue } from 'src/engine/api/rest/types/field-value.type'; +import { FieldValue } from 'src/engine/api/rest/core/types/field-value.type'; export const formatFieldValue = ( value: string, diff --git a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/parse-base-filter.utils.ts b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/filter-utils/parse-base-filter.utils.ts similarity index 100% rename from packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/parse-base-filter.utils.ts rename to packages/twenty-server/src/engine/api/rest/core/query-builder/utils/filter-utils/parse-base-filter.utils.ts diff --git a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/parse-filter-content.utils.ts b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/filter-utils/parse-filter-content.utils.ts similarity index 100% rename from packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/parse-filter-content.utils.ts rename to packages/twenty-server/src/engine/api/rest/core/query-builder/utils/filter-utils/parse-filter-content.utils.ts diff --git a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/parse-filter.utils.ts b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/filter-utils/parse-filter.utils.ts similarity index 65% rename from packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/parse-filter.utils.ts rename to packages/twenty-server/src/engine/api/rest/core/query-builder/utils/filter-utils/parse-filter.utils.ts index ac8307d873c3..0f8a043b3bf6 100644 --- a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/parse-filter.utils.ts +++ b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/filter-utils/parse-filter.utils.ts @@ -2,13 +2,13 @@ import { BadRequestException } from '@nestjs/common'; import { ObjectMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/object-metadata.interface'; -import { parseFilterContent } from 'src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/parse-filter-content.utils'; -import { parseBaseFilter } from 'src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/parse-base-filter.utils'; -import { checkFields } from 'src/engine/api/rest/rest-api-core-query-builder/utils/check-fields.utils'; -import { formatFieldValue } from 'src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/format-field-values.utils'; -import { FieldValue } from 'src/engine/api/rest/types/field-value.type'; -import { checkFilterEnumValues } from 'src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/check-filter-enum-values'; -import { getFieldType } from 'src/engine/api/rest/rest-api-core-query-builder/utils/get-field-type.utils'; +import { parseFilterContent } from 'src/engine/api/rest/core/query-builder/utils/filter-utils/parse-filter-content.utils'; +import { parseBaseFilter } from 'src/engine/api/rest/core/query-builder/utils/filter-utils/parse-base-filter.utils'; +import { checkFields } from 'src/engine/api/rest/core/query-builder/utils/check-fields.utils'; +import { formatFieldValue } from 'src/engine/api/rest/core/query-builder/utils/filter-utils/format-field-values.utils'; +import { FieldValue } from 'src/engine/api/rest/core/types/field-value.type'; +import { checkFilterEnumValues } from 'src/engine/api/rest/core/query-builder/utils/filter-utils/check-filter-enum-values'; +import { getFieldType } from 'src/engine/api/rest/core/query-builder/utils/get-field-type.utils'; export enum Conjunctions { or = 'or', diff --git a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/utils/get-field-type.utils.ts b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/get-field-type.utils.ts similarity index 100% rename from packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/utils/get-field-type.utils.ts rename to packages/twenty-server/src/engine/api/rest/core/query-builder/utils/get-field-type.utils.ts diff --git a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/utils/map-field-metadata-to-graphql-query.utils.ts b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/map-field-metadata-to-graphql-query.utils.ts similarity index 94% rename from packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/utils/map-field-metadata-to-graphql-query.utils.ts rename to packages/twenty-server/src/engine/api/rest/core/query-builder/utils/map-field-metadata-to-graphql-query.utils.ts index c7112e0dfc5c..a34cc2123f36 100644 --- a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/utils/map-field-metadata-to-graphql-query.utils.ts +++ b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/map-field-metadata-to-graphql-query.utils.ts @@ -9,7 +9,7 @@ export const mapFieldMetadataToGraphqlQuery = ( field, maxDepthForRelations = DEFAULT_DEPTH_VALUE, ): string | undefined => { - if (maxDepthForRelations <= 0) { + if (maxDepthForRelations < 0) { return ''; } @@ -19,19 +19,23 @@ export const mapFieldMetadataToGraphqlQuery = ( FieldMetadataType.UUID, FieldMetadataType.TEXT, FieldMetadataType.PHONE, + FieldMetadataType.EMAIL, FieldMetadataType.DATE_TIME, FieldMetadataType.DATE, - FieldMetadataType.EMAIL, + FieldMetadataType.BOOLEAN, FieldMetadataType.NUMBER, - FieldMetadataType.SELECT, + FieldMetadataType.NUMERIC, FieldMetadataType.RATING, - FieldMetadataType.BOOLEAN, + FieldMetadataType.SELECT, + FieldMetadataType.MULTI_SELECT, FieldMetadataType.POSITION, + FieldMetadataType.RAW_JSON, ].includes(fieldType); if (fieldIsSimpleValue) { return field.name; } else if ( + maxDepthForRelations > 0 && fieldType === FieldMetadataType.RELATION && field.toRelationMetadata?.relationType === RelationMetadataType.ONE_TO_MANY ) { @@ -45,7 +49,6 @@ export const mapFieldMetadataToGraphqlQuery = ( { id ${(relationMetadataItem?.fields ?? []) - .filter((field) => field.type !== FieldMetadataType.RELATION) .map((field) => mapFieldMetadataToGraphqlQuery( objectMetadataItems, @@ -56,6 +59,7 @@ export const mapFieldMetadataToGraphqlQuery = ( .join('\n')} }`; } else if ( + maxDepthForRelations > 0 && fieldType === FieldMetadataType.RELATION && field.fromRelationMetadata?.relationType === RelationMetadataType.ONE_TO_MANY @@ -72,7 +76,6 @@ export const mapFieldMetadataToGraphqlQuery = ( node { id ${(relationMetadataItem?.fields ?? []) - .filter((field) => field.type !== FieldMetadataType.RELATION) .map((field) => mapFieldMetadataToGraphqlQuery( objectMetadataItems, diff --git a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/utils/path-parsers/__tests__/parse-core-batch-path.utils.spec.ts b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/path-parsers/__tests__/parse-core-batch-path.utils.spec.ts similarity index 65% rename from packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/utils/path-parsers/__tests__/parse-core-batch-path.utils.spec.ts rename to packages/twenty-server/src/engine/api/rest/core/query-builder/utils/path-parsers/__tests__/parse-core-batch-path.utils.spec.ts index 04131521108f..a66400eecb00 100644 --- a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/utils/path-parsers/__tests__/parse-core-batch-path.utils.spec.ts +++ b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/path-parsers/__tests__/parse-core-batch-path.utils.spec.ts @@ -1,4 +1,4 @@ -import { parseCoreBatchPath } from 'src/engine/api/rest/rest-api-core-query-builder/utils/path-parsers/parse-core-batch-path.utils'; +import { parseCoreBatchPath } from 'src/engine/api/rest/core/query-builder/utils/path-parsers/parse-core-batch-path.utils'; describe('parseCoreBatchPath', () => { it('should parse object from request path', () => { diff --git a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/utils/path-parsers/__tests__/parse-core-path.utils.spec.ts b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/path-parsers/__tests__/parse-core-path.utils.spec.ts similarity index 86% rename from packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/utils/path-parsers/__tests__/parse-core-path.utils.spec.ts rename to packages/twenty-server/src/engine/api/rest/core/query-builder/utils/path-parsers/__tests__/parse-core-path.utils.spec.ts index 0d20d453afc4..c5c9434160aa 100644 --- a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/utils/path-parsers/__tests__/parse-core-path.utils.spec.ts +++ b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/path-parsers/__tests__/parse-core-path.utils.spec.ts @@ -1,4 +1,4 @@ -import { parseCorePath } from 'src/engine/api/rest/rest-api-core-query-builder/utils/path-parsers/parse-core-path.utils'; +import { parseCorePath } from 'src/engine/api/rest/core/query-builder/utils/path-parsers/parse-core-path.utils'; describe('parseCorePath', () => { it('should parse object from request path', () => { diff --git a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/utils/path-parsers/parse-core-batch-path.utils.ts b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/path-parsers/parse-core-batch-path.utils.ts similarity index 100% rename from packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/utils/path-parsers/parse-core-batch-path.utils.ts rename to packages/twenty-server/src/engine/api/rest/core/query-builder/utils/path-parsers/parse-core-batch-path.utils.ts diff --git a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/utils/path-parsers/parse-core-path.utils.ts b/packages/twenty-server/src/engine/api/rest/core/query-builder/utils/path-parsers/parse-core-path.utils.ts similarity index 100% rename from packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/utils/path-parsers/parse-core-path.utils.ts rename to packages/twenty-server/src/engine/api/rest/core/query-builder/utils/path-parsers/parse-core-path.utils.ts diff --git a/packages/twenty-server/src/engine/api/rest/services/rest-api-core.service.ts b/packages/twenty-server/src/engine/api/rest/core/rest-api-core.service.ts similarity index 88% rename from packages/twenty-server/src/engine/api/rest/services/rest-api-core.service.ts rename to packages/twenty-server/src/engine/api/rest/core/rest-api-core.service.ts index 126c64e6a352..3b56c76e5148 100644 --- a/packages/twenty-server/src/engine/api/rest/services/rest-api-core.service.ts +++ b/packages/twenty-server/src/engine/api/rest/core/rest-api-core.service.ts @@ -2,11 +2,11 @@ import { Injectable } from '@nestjs/common'; import { Request } from 'express'; -import { CoreQueryBuilderFactory } from 'src/engine/api/rest/rest-api-core-query-builder/core-query-builder.factory'; +import { CoreQueryBuilderFactory } from 'src/engine/api/rest/core/query-builder/core-query-builder.factory'; import { GraphqlApiType, RestApiService, -} from 'src/engine/api/rest/services/rest-api.service'; +} from 'src/engine/api/rest/rest-api.service'; @Injectable() export class RestApiCoreService { diff --git a/packages/twenty-server/src/engine/api/rest/types/field-value.type.ts b/packages/twenty-server/src/engine/api/rest/core/types/field-value.type.ts similarity index 100% rename from packages/twenty-server/src/engine/api/rest/types/field-value.type.ts rename to packages/twenty-server/src/engine/api/rest/core/types/field-value.type.ts diff --git a/packages/twenty-server/src/engine/api/rest/types/query-variables.type.ts b/packages/twenty-server/src/engine/api/rest/core/types/query-variables.type.ts similarity index 83% rename from packages/twenty-server/src/engine/api/rest/types/query-variables.type.ts rename to packages/twenty-server/src/engine/api/rest/core/types/query-variables.type.ts index 6907aed8d5ec..97a23c657a48 100644 --- a/packages/twenty-server/src/engine/api/rest/types/query-variables.type.ts +++ b/packages/twenty-server/src/engine/api/rest/core/types/query-variables.type.ts @@ -3,7 +3,8 @@ export type QueryVariables = { data?: object | null; filter?: object; orderBy?: object; - limit?: number; + last?: number; + first?: number; startingAfter?: string; endingBefore?: string; input?: object; diff --git a/packages/twenty-server/src/engine/api/rest/core/types/query.type.ts b/packages/twenty-server/src/engine/api/rest/core/types/query.type.ts new file mode 100644 index 000000000000..92a9cf27ce53 --- /dev/null +++ b/packages/twenty-server/src/engine/api/rest/core/types/query.type.ts @@ -0,0 +1,6 @@ +import { QueryVariables } from 'src/engine/api/rest/core/types/query-variables.type'; + +export type Query = { + query: string; + variables: QueryVariables; +}; diff --git a/packages/twenty-server/src/engine/api/rest/errors/RestApiException.ts b/packages/twenty-server/src/engine/api/rest/errors/RestApiException.ts index 11a72c026232..2cc0b571b7ea 100644 --- a/packages/twenty-server/src/engine/api/rest/errors/RestApiException.ts +++ b/packages/twenty-server/src/engine/api/rest/errors/RestApiException.ts @@ -1,6 +1,6 @@ import { BadRequestException } from '@nestjs/common'; -import { BaseGraphQLError } from 'src/engine/utils/graphql-errors.util'; +import { BaseGraphQLError } from 'src/engine/core-modules/graphql/utils/graphql-errors.util'; const formatMessage = (message: BaseGraphQLError) => { if (message.extensions) { diff --git a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/__tests__/ending-before-input.factory.spec.ts b/packages/twenty-server/src/engine/api/rest/input-factories/__tests__/ending-before-input.factory.spec.ts similarity index 85% rename from packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/__tests__/ending-before-input.factory.spec.ts rename to packages/twenty-server/src/engine/api/rest/input-factories/__tests__/ending-before-input.factory.spec.ts index 2de86ff7f382..9bef0dbfdc98 100644 --- a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/__tests__/ending-before-input.factory.spec.ts +++ b/packages/twenty-server/src/engine/api/rest/input-factories/__tests__/ending-before-input.factory.spec.ts @@ -1,6 +1,6 @@ import { Test, TestingModule } from '@nestjs/testing'; -import { EndingBeforeInputFactory } from 'src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/ending-before-input.factory'; +import { EndingBeforeInputFactory } from 'src/engine/api/rest/input-factories/ending-before-input.factory'; describe('EndingBeforeInputFactory', () => { let service: EndingBeforeInputFactory; diff --git a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/__tests__/filter-input.factory.spec.ts b/packages/twenty-server/src/engine/api/rest/input-factories/__tests__/filter-input.factory.spec.ts similarity index 96% rename from packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/__tests__/filter-input.factory.spec.ts rename to packages/twenty-server/src/engine/api/rest/input-factories/__tests__/filter-input.factory.spec.ts index 12dd66750025..b6366ff7034d 100644 --- a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/__tests__/filter-input.factory.spec.ts +++ b/packages/twenty-server/src/engine/api/rest/input-factories/__tests__/filter-input.factory.spec.ts @@ -1,7 +1,7 @@ import { Test, TestingModule } from '@nestjs/testing'; import { objectMetadataItemMock } from 'src/engine/api/__mocks__/object-metadata-item.mock'; -import { FilterInputFactory } from 'src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-input.factory'; +import { FilterInputFactory } from 'src/engine/api/rest/input-factories/filter-input.factory'; describe('FilterInputFactory', () => { const objectMetadata = { objectMetadataItem: objectMetadataItemMock }; diff --git a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/__tests__/limit-input.factory.spec.ts b/packages/twenty-server/src/engine/api/rest/input-factories/__tests__/limit-input.factory.spec.ts similarity index 90% rename from packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/__tests__/limit-input.factory.spec.ts rename to packages/twenty-server/src/engine/api/rest/input-factories/__tests__/limit-input.factory.spec.ts index 16ed18507a0f..2104250f1cda 100644 --- a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/__tests__/limit-input.factory.spec.ts +++ b/packages/twenty-server/src/engine/api/rest/input-factories/__tests__/limit-input.factory.spec.ts @@ -1,6 +1,6 @@ import { Test, TestingModule } from '@nestjs/testing'; -import { LimitInputFactory } from 'src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/limit-input.factory'; +import { LimitInputFactory } from 'src/engine/api/rest/input-factories/limit-input.factory'; describe('LimitInputFactory', () => { let service: LimitInputFactory; diff --git a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/__tests__/order-by-input.factory.spec.ts b/packages/twenty-server/src/engine/api/rest/input-factories/__tests__/order-by-input.factory.spec.ts similarity index 72% rename from packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/__tests__/order-by-input.factory.spec.ts rename to packages/twenty-server/src/engine/api/rest/input-factories/__tests__/order-by-input.factory.spec.ts index ddd8b3eff533..63b3179ee68d 100644 --- a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/__tests__/order-by-input.factory.spec.ts +++ b/packages/twenty-server/src/engine/api/rest/input-factories/__tests__/order-by-input.factory.spec.ts @@ -3,7 +3,7 @@ import { Test, TestingModule } from '@nestjs/testing'; import { OrderByDirection } from 'src/engine/api/graphql/workspace-query-builder/interfaces/record.interface'; import { objectMetadataItemMock } from 'src/engine/api/__mocks__/object-metadata-item.mock'; -import { OrderByInputFactory } from 'src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/order-by-input.factory'; +import { OrderByInputFactory } from 'src/engine/api/rest/input-factories/order-by-input.factory'; describe('OrderByInputFactory', () => { const objectMetadata = { objectMetadataItem: objectMetadataItemMock }; @@ -26,7 +26,7 @@ describe('OrderByInputFactory', () => { it('should return default if order by missing', () => { const request: any = { query: {} }; - expect(service.create(request, objectMetadata)).toEqual({}); + expect(service.create(request, objectMetadata)).toEqual([{}]); }); it('should create order by parser properly', () => { @@ -36,10 +36,10 @@ describe('OrderByInputFactory', () => { }, }; - expect(service.create(request, objectMetadata)).toEqual({ - fieldNumber: OrderByDirection.AscNullsFirst, - fieldText: OrderByDirection.DescNullsLast, - }); + expect(service.create(request, objectMetadata)).toEqual([ + { fieldNumber: OrderByDirection.AscNullsFirst }, + { fieldText: OrderByDirection.DescNullsLast }, + ]); }); it('should choose default direction if missing', () => { @@ -49,9 +49,9 @@ describe('OrderByInputFactory', () => { }, }; - expect(service.create(request, objectMetadata)).toEqual({ - fieldNumber: OrderByDirection.AscNullsFirst, - }); + expect(service.create(request, objectMetadata)).toEqual([ + { fieldNumber: OrderByDirection.AscNullsFirst }, + ]); }); it('should handler complex fields', () => { @@ -61,9 +61,9 @@ describe('OrderByInputFactory', () => { }, }; - expect(service.create(request, objectMetadata)).toEqual({ - fieldCurrency: { amountMicros: OrderByDirection.AscNullsFirst }, - }); + expect(service.create(request, objectMetadata)).toEqual([ + { fieldCurrency: { amountMicros: OrderByDirection.AscNullsFirst } }, + ]); }); it('should handler complex fields with direction', () => { @@ -73,9 +73,9 @@ describe('OrderByInputFactory', () => { }, }; - expect(service.create(request, objectMetadata)).toEqual({ - fieldCurrency: { amountMicros: OrderByDirection.DescNullsLast }, - }); + expect(service.create(request, objectMetadata)).toEqual([ + { fieldCurrency: { amountMicros: OrderByDirection.DescNullsLast } }, + ]); }); it('should handler multiple complex fields with direction', () => { @@ -86,10 +86,10 @@ describe('OrderByInputFactory', () => { }, }; - expect(service.create(request, objectMetadata)).toEqual({ - fieldCurrency: { amountMicros: OrderByDirection.DescNullsLast }, - fieldLink: { label: OrderByDirection.AscNullsLast }, - }); + expect(service.create(request, objectMetadata)).toEqual([ + { fieldCurrency: { amountMicros: OrderByDirection.DescNullsLast } }, + { fieldLink: { label: OrderByDirection.AscNullsLast } }, + ]); }); it('should throw if direction invalid', () => { diff --git a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/__tests__/starting-before-input.factory.spec.ts b/packages/twenty-server/src/engine/api/rest/input-factories/__tests__/starting-before-input.factory.spec.ts similarity index 85% rename from packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/__tests__/starting-before-input.factory.spec.ts rename to packages/twenty-server/src/engine/api/rest/input-factories/__tests__/starting-before-input.factory.spec.ts index 484cd8da636e..814739584210 100644 --- a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/__tests__/starting-before-input.factory.spec.ts +++ b/packages/twenty-server/src/engine/api/rest/input-factories/__tests__/starting-before-input.factory.spec.ts @@ -1,6 +1,6 @@ import { Test, TestingModule } from '@nestjs/testing'; -import { StartingAfterInputFactory } from 'src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/starting-after-input.factory'; +import { StartingAfterInputFactory } from 'src/engine/api/rest/input-factories/starting-after-input.factory'; describe('StartingAfterInputFactory', () => { let service: StartingAfterInputFactory; diff --git a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/ending-before-input.factory.ts b/packages/twenty-server/src/engine/api/rest/input-factories/ending-before-input.factory.ts similarity index 100% rename from packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/ending-before-input.factory.ts rename to packages/twenty-server/src/engine/api/rest/input-factories/ending-before-input.factory.ts diff --git a/packages/twenty-server/src/engine/api/rest/input-factories/factories.ts b/packages/twenty-server/src/engine/api/rest/input-factories/factories.ts new file mode 100644 index 000000000000..bbe17eeca1ba --- /dev/null +++ b/packages/twenty-server/src/engine/api/rest/input-factories/factories.ts @@ -0,0 +1,13 @@ +import { StartingAfterInputFactory } from 'src/engine/api/rest/input-factories/starting-after-input.factory'; +import { EndingBeforeInputFactory } from 'src/engine/api/rest/input-factories/ending-before-input.factory'; +import { LimitInputFactory } from 'src/engine/api/rest/input-factories/limit-input.factory'; +import { OrderByInputFactory } from 'src/engine/api/rest/input-factories/order-by-input.factory'; +import { FilterInputFactory } from 'src/engine/api/rest/input-factories/filter-input.factory'; + +export const inputFactories = [ + StartingAfterInputFactory, + EndingBeforeInputFactory, + LimitInputFactory, + OrderByInputFactory, + FilterInputFactory, +]; diff --git a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-input.factory.ts b/packages/twenty-server/src/engine/api/rest/input-factories/filter-input.factory.ts similarity index 54% rename from packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-input.factory.ts rename to packages/twenty-server/src/engine/api/rest/input-factories/filter-input.factory.ts index 1041212dfbbb..93ed93d51eb4 100644 --- a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-input.factory.ts +++ b/packages/twenty-server/src/engine/api/rest/input-factories/filter-input.factory.ts @@ -2,10 +2,10 @@ import { Injectable } from '@nestjs/common'; import { Request } from 'express'; -import { addDefaultConjunctionIfMissing } from 'src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/add-default-conjunction.utils'; -import { checkFilterQuery } from 'src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/check-filter-query.utils'; -import { parseFilter } from 'src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/parse-filter.utils'; -import { FieldValue } from 'src/engine/api/rest/types/field-value.type'; +import { addDefaultConjunctionIfMissing } from 'src/engine/api/rest/core/query-builder/utils/filter-utils/add-default-conjunction.utils'; +import { checkFilterQuery } from 'src/engine/api/rest/core/query-builder/utils/filter-utils/check-filter-query.utils'; +import { parseFilter } from 'src/engine/api/rest/core/query-builder/utils/filter-utils/parse-filter.utils'; +import { FieldValue } from 'src/engine/api/rest/core/types/field-value.type'; @Injectable() export class FilterInputFactory { diff --git a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/limit-input.factory.ts b/packages/twenty-server/src/engine/api/rest/input-factories/limit-input.factory.ts similarity index 83% rename from packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/limit-input.factory.ts rename to packages/twenty-server/src/engine/api/rest/input-factories/limit-input.factory.ts index 26d958d3a390..d7ccaddc0904 100644 --- a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/limit-input.factory.ts +++ b/packages/twenty-server/src/engine/api/rest/input-factories/limit-input.factory.ts @@ -4,9 +4,9 @@ import { Request } from 'express'; @Injectable() export class LimitInputFactory { - create(request: Request): number { + create(request: Request, defaultLimit = 60): number { if (!request.query.limit) { - return 60; + return defaultLimit; } const limit = +request.query.limit; diff --git a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/order-by-input.factory.ts b/packages/twenty-server/src/engine/api/rest/input-factories/order-by-input.factory.ts similarity index 82% rename from packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/order-by-input.factory.ts rename to packages/twenty-server/src/engine/api/rest/input-factories/order-by-input.factory.ts index 2b44cd279a22..832de44c52f9 100644 --- a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/order-by-input.factory.ts +++ b/packages/twenty-server/src/engine/api/rest/input-factories/order-by-input.factory.ts @@ -7,7 +7,7 @@ import { RecordOrderBy, } from 'src/engine/api/graphql/workspace-query-builder/interfaces/record.interface'; -import { checkFields } from 'src/engine/api/rest/rest-api-core-query-builder/utils/check-fields.utils'; +import { checkArrayFields } from 'src/engine/api/rest/core/query-builder/utils/check-order-by.utils'; export const DEFAULT_ORDER_DIRECTION = OrderByDirection.AscNullsFirst; @@ -17,12 +17,12 @@ export class OrderByInputFactory { const orderByQuery = request.query.order_by; if (typeof orderByQuery !== 'string') { - return {}; + return [{}]; } //orderByQuery = field_1[AscNullsFirst],field_2[DescNullsLast],field_3 const orderByItems = orderByQuery.split(','); - let result = {}; + let result: Array<Record<string, OrderByDirection>> = []; let itemDirection = ''; let itemFields = ''; @@ -65,10 +65,14 @@ export class OrderByInputFactory { } }, itemDirection); - result = { ...result, ...fieldResult }; + const resultFields = Object.keys(fieldResult).map((key) => ({ + [key]: fieldResult[key], + })); + + result = [...result, ...resultFields]; } - checkFields(objectMetadata.objectMetadataItem, Object.keys(result)); + checkArrayFields(objectMetadata.objectMetadataItem, result); return result; } diff --git a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/starting-after-input.factory.ts b/packages/twenty-server/src/engine/api/rest/input-factories/starting-after-input.factory.ts similarity index 100% rename from packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/starting-after-input.factory.ts rename to packages/twenty-server/src/engine/api/rest/input-factories/starting-after-input.factory.ts diff --git a/packages/twenty-server/src/engine/api/rest/metadata/query-builder/factories/create-metadata-query.factory.ts b/packages/twenty-server/src/engine/api/rest/metadata/query-builder/factories/create-metadata-query.factory.ts new file mode 100644 index 000000000000..67333a146c3a --- /dev/null +++ b/packages/twenty-server/src/engine/api/rest/metadata/query-builder/factories/create-metadata-query.factory.ts @@ -0,0 +1,24 @@ +import { Injectable } from '@nestjs/common'; + +import { capitalize } from 'src/utils/capitalize'; +import { fetchMetadataFields } from 'src/engine/api/rest/metadata/query-builder/utils/fetch-metadata-fields.utils'; + +@Injectable() +export class CreateMetadataQueryFactory { + create(objectNameSingular: string, objectNamePlural: string): string { + const objectNameCapitalized = capitalize(objectNameSingular); + + const fields = fetchMetadataFields(objectNamePlural); + + return ` + mutation Create${objectNameCapitalized}($input: CreateOne${objectNameCapitalized}${ + objectNameSingular === 'field' ? 'Metadata' : '' + }Input!) { + createOne${objectNameCapitalized}(input: $input) { + id + ${fields} + } + } + `; + } +} diff --git a/packages/twenty-server/src/engine/api/rest/metadata/query-builder/factories/delete-metadata-query.factory.ts b/packages/twenty-server/src/engine/api/rest/metadata/query-builder/factories/delete-metadata-query.factory.ts new file mode 100644 index 000000000000..c1e09b05bdf9 --- /dev/null +++ b/packages/twenty-server/src/engine/api/rest/metadata/query-builder/factories/delete-metadata-query.factory.ts @@ -0,0 +1,18 @@ +import { Injectable } from '@nestjs/common'; + +import { capitalize } from 'src/utils/capitalize'; + +@Injectable() +export class DeleteMetadataQueryFactory { + create(objectNameSingular: string): string { + const objectNameCapitalized = capitalize(objectNameSingular); + + return ` + mutation Delete${objectNameCapitalized}($input: DeleteOne${objectNameCapitalized}Input!) { + deleteOne${objectNameCapitalized}(input: $input) { + id + } + } + `; + } +} diff --git a/packages/twenty-server/src/engine/api/rest/metadata/query-builder/factories/find-many-metadata-query.factory.ts b/packages/twenty-server/src/engine/api/rest/metadata/query-builder/factories/find-many-metadata-query.factory.ts new file mode 100644 index 000000000000..7434b2eb30b7 --- /dev/null +++ b/packages/twenty-server/src/engine/api/rest/metadata/query-builder/factories/find-many-metadata-query.factory.ts @@ -0,0 +1,33 @@ +import { Injectable } from '@nestjs/common'; + +import { capitalize } from 'src/utils/capitalize'; +import { fetchMetadataFields } from 'src/engine/api/rest/metadata/query-builder/utils/fetch-metadata-fields.utils'; + +@Injectable() +export class FindManyMetadataQueryFactory { + create(objectNamePlural): string { + const fields = fetchMetadataFields(objectNamePlural); + + return ` + query FindMany${capitalize(objectNamePlural)}( + $paging: CursorPaging! + ) { + ${objectNamePlural}( + paging: $paging + ) { + edges { + node { + id + ${fields} + } + } + pageInfo { + hasNextPage + startCursor + endCursor + } + } + } + `; + } +} diff --git a/packages/twenty-server/src/engine/api/rest/metadata/query-builder/factories/find-one-metadata-query.factory.ts b/packages/twenty-server/src/engine/api/rest/metadata/query-builder/factories/find-one-metadata-query.factory.ts new file mode 100644 index 000000000000..98078a29efa4 --- /dev/null +++ b/packages/twenty-server/src/engine/api/rest/metadata/query-builder/factories/find-one-metadata-query.factory.ts @@ -0,0 +1,22 @@ +import { Injectable } from '@nestjs/common'; + +import { capitalize } from 'src/utils/capitalize'; +import { fetchMetadataFields } from 'src/engine/api/rest/metadata/query-builder/utils/fetch-metadata-fields.utils'; + +@Injectable() +export class FindOneMetadataQueryFactory { + create(objectNameSingular: string, objectNamePlural: string): string { + const fields = fetchMetadataFields(objectNamePlural); + + return ` + query FindOne${capitalize(objectNameSingular)}( + $id: UUID!, + ) { + ${objectNameSingular}(id: $id) { + id + ${fields} + } + } + `; + } +} diff --git a/packages/twenty-server/src/engine/api/rest/metadata/query-builder/factories/get-metadata-variables.factory.ts b/packages/twenty-server/src/engine/api/rest/metadata/query-builder/factories/get-metadata-variables.factory.ts new file mode 100644 index 000000000000..61149853b0f9 --- /dev/null +++ b/packages/twenty-server/src/engine/api/rest/metadata/query-builder/factories/get-metadata-variables.factory.ts @@ -0,0 +1,42 @@ +import { BadRequestException, Injectable } from '@nestjs/common'; + +import { Request } from 'express'; + +import { LimitInputFactory } from 'src/engine/api/rest/input-factories/limit-input.factory'; +import { EndingBeforeInputFactory } from 'src/engine/api/rest/input-factories/ending-before-input.factory'; +import { StartingAfterInputFactory } from 'src/engine/api/rest/input-factories/starting-after-input.factory'; +import { MetadataQueryVariables } from 'src/engine/api/rest/metadata/types/metadata-query-variables.type'; + +@Injectable() +export class GetMetadataVariablesFactory { + constructor( + private readonly startingAfterInputFactory: StartingAfterInputFactory, + private readonly endingBeforeInputFactory: EndingBeforeInputFactory, + private readonly limitInputFactory: LimitInputFactory, + ) {} + + create(id: string | undefined, request: Request): MetadataQueryVariables { + if (id) { + return { id }; + } + + const limit = this.limitInputFactory.create(request, 1000); + const before = this.endingBeforeInputFactory.create(request); + const after = this.startingAfterInputFactory.create(request); + + if (before && after) { + throw new BadRequestException( + `Only one of 'endingBefore' and 'startingAfter' may be provided`, + ); + } + + return { + paging: { + first: !before ? limit : undefined, + last: before ? limit : undefined, + after, + before, + }, + }; + } +} diff --git a/packages/twenty-server/src/engine/api/rest/metadata/query-builder/factories/metadata-factories.ts b/packages/twenty-server/src/engine/api/rest/metadata/query-builder/factories/metadata-factories.ts new file mode 100644 index 000000000000..f8a7f485561c --- /dev/null +++ b/packages/twenty-server/src/engine/api/rest/metadata/query-builder/factories/metadata-factories.ts @@ -0,0 +1,17 @@ +import { FindOneMetadataQueryFactory } from 'src/engine/api/rest/metadata/query-builder/factories/find-one-metadata-query.factory'; +import { FindManyMetadataQueryFactory } from 'src/engine/api/rest/metadata/query-builder/factories/find-many-metadata-query.factory'; +import { GetMetadataVariablesFactory } from 'src/engine/api/rest/metadata/query-builder/factories/get-metadata-variables.factory'; +import { inputFactories } from 'src/engine/api/rest/input-factories/factories'; +import { CreateMetadataQueryFactory } from 'src/engine/api/rest/metadata/query-builder/factories/create-metadata-query.factory'; +import { UpdateMetadataQueryFactory } from 'src/engine/api/rest/metadata/query-builder/factories/update-metadata-query.factory'; +import { DeleteMetadataQueryFactory } from 'src/engine/api/rest/metadata/query-builder/factories/delete-metadata-query.factory'; + +export const metadataQueryBuilderFactories = [ + FindOneMetadataQueryFactory, + FindManyMetadataQueryFactory, + CreateMetadataQueryFactory, + DeleteMetadataQueryFactory, + UpdateMetadataQueryFactory, + GetMetadataVariablesFactory, + ...inputFactories, +]; diff --git a/packages/twenty-server/src/engine/api/rest/metadata/query-builder/factories/update-metadata-query.factory.ts b/packages/twenty-server/src/engine/api/rest/metadata/query-builder/factories/update-metadata-query.factory.ts new file mode 100644 index 000000000000..6be62fc48a9d --- /dev/null +++ b/packages/twenty-server/src/engine/api/rest/metadata/query-builder/factories/update-metadata-query.factory.ts @@ -0,0 +1,24 @@ +import { Injectable } from '@nestjs/common'; + +import { capitalize } from 'src/utils/capitalize'; +import { fetchMetadataFields } from 'src/engine/api/rest/metadata/query-builder/utils/fetch-metadata-fields.utils'; + +@Injectable() +export class UpdateMetadataQueryFactory { + create(objectNameSingular: string, objectNamePlural: string): string { + const objectNameCapitalized = capitalize(objectNameSingular); + + const fields = fetchMetadataFields(objectNamePlural); + + return ` + mutation Update${objectNameCapitalized}($input: UpdateOne${objectNameCapitalized}${ + objectNameSingular === 'field' ? 'Metadata' : '' + }Input!) { + updateOne${objectNameCapitalized}(input: $input) { + id + ${fields} + } + } + `; + } +} diff --git a/packages/twenty-server/src/engine/api/rest/metadata/query-builder/metadata-query-builder.factory.ts b/packages/twenty-server/src/engine/api/rest/metadata/query-builder/metadata-query-builder.factory.ts new file mode 100644 index 000000000000..ce9b38ce8265 --- /dev/null +++ b/packages/twenty-server/src/engine/api/rest/metadata/query-builder/metadata-query-builder.factory.ts @@ -0,0 +1,95 @@ +import { BadRequestException, Injectable } from '@nestjs/common'; + +import { Request } from 'express'; + +import { GetMetadataVariablesFactory } from 'src/engine/api/rest/metadata/query-builder/factories/get-metadata-variables.factory'; +import { FindOneMetadataQueryFactory } from 'src/engine/api/rest/metadata/query-builder/factories/find-one-metadata-query.factory'; +import { FindManyMetadataQueryFactory } from 'src/engine/api/rest/metadata/query-builder/factories/find-many-metadata-query.factory'; +import { parseMetadataPath } from 'src/engine/api/rest/metadata/query-builder/utils/parse-metadata-path.utils'; +import { CreateMetadataQueryFactory } from 'src/engine/api/rest/metadata/query-builder/factories/create-metadata-query.factory'; +import { UpdateMetadataQueryFactory } from 'src/engine/api/rest/metadata/query-builder/factories/update-metadata-query.factory'; +import { DeleteMetadataQueryFactory } from 'src/engine/api/rest/metadata/query-builder/factories/delete-metadata-query.factory'; +import { MetadataQuery } from 'src/engine/api/rest/metadata/types/metadata-query.type'; + +@Injectable() +export class MetadataQueryBuilderFactory { + constructor( + private readonly findOneQueryFactory: FindOneMetadataQueryFactory, + private readonly findManyQueryFactory: FindManyMetadataQueryFactory, + private readonly createQueryFactory: CreateMetadataQueryFactory, + private readonly updateQueryFactory: UpdateMetadataQueryFactory, + private readonly deleteQueryFactory: DeleteMetadataQueryFactory, + private readonly getMetadataVariablesFactory: GetMetadataVariablesFactory, + ) {} + + async get(request: Request): Promise<MetadataQuery> { + const { id, objectNameSingular, objectNamePlural } = + parseMetadataPath(request); + + return { + query: id + ? this.findOneQueryFactory.create(objectNameSingular, objectNamePlural) + : this.findManyQueryFactory.create(objectNamePlural), + variables: this.getMetadataVariablesFactory.create(id, request), + }; + } + + async create(request: Request): Promise<MetadataQuery> { + const { objectNameSingular, objectNamePlural } = parseMetadataPath(request); + + return { + query: this.createQueryFactory.create( + objectNameSingular, + objectNamePlural, + ), + variables: { + input: { + [objectNameSingular]: request.body, + }, + }, + }; + } + + async update(request: Request): Promise<MetadataQuery> { + const { objectNameSingular, objectNamePlural, id } = + parseMetadataPath(request); + + if (!id) { + throw new BadRequestException( + `update ${objectNameSingular} query invalid. Id missing. eg: /rest/metadata/${objectNameSingular}/0d4389ef-ea9c-4ae8-ada1-1cddc440fb56`, + ); + } + + return { + query: this.updateQueryFactory.create( + objectNameSingular, + objectNamePlural, + ), + variables: { + input: { + update: request.body, + id, + }, + }, + }; + } + + async delete(request: Request): Promise<MetadataQuery> { + const { objectNameSingular, id } = parseMetadataPath(request); + + if (!id) { + throw new BadRequestException( + `delete ${objectNameSingular} query invalid. Id missing. eg: /rest/metadata/${objectNameSingular}/0d4389ef-ea9c-4ae8-ada1-1cddc440fb56`, + ); + } + + return { + query: this.deleteQueryFactory.create(objectNameSingular), + variables: { + input: { + id, + }, + }, + }; + } +} diff --git a/packages/twenty-server/src/engine/api/rest/metadata/query-builder/metadata-query-builder.module.ts b/packages/twenty-server/src/engine/api/rest/metadata/query-builder/metadata-query-builder.module.ts new file mode 100644 index 000000000000..82bf0fb5674e --- /dev/null +++ b/packages/twenty-server/src/engine/api/rest/metadata/query-builder/metadata-query-builder.module.ts @@ -0,0 +1,12 @@ +import { Module } from '@nestjs/common'; + +import { AuthModule } from 'src/engine/core-modules/auth/auth.module'; +import { MetadataQueryBuilderFactory } from 'src/engine/api/rest/metadata/query-builder/metadata-query-builder.factory'; +import { metadataQueryBuilderFactories } from 'src/engine/api/rest/metadata/query-builder/factories/metadata-factories'; + +@Module({ + imports: [AuthModule], + providers: [...metadataQueryBuilderFactories, MetadataQueryBuilderFactory], + exports: [MetadataQueryBuilderFactory], +}) +export class MetadataQueryBuilderModule {} diff --git a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/utils/path-parsers/__tests__/parse-metadata-path.utils.spec.ts b/packages/twenty-server/src/engine/api/rest/metadata/query-builder/utils/__tests__/parse-metadata-path.utils.spec.ts similarity index 90% rename from packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/utils/path-parsers/__tests__/parse-metadata-path.utils.spec.ts rename to packages/twenty-server/src/engine/api/rest/metadata/query-builder/utils/__tests__/parse-metadata-path.utils.spec.ts index 28b1238c2468..ec6284da777d 100644 --- a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/utils/path-parsers/__tests__/parse-metadata-path.utils.spec.ts +++ b/packages/twenty-server/src/engine/api/rest/metadata/query-builder/utils/__tests__/parse-metadata-path.utils.spec.ts @@ -1,4 +1,4 @@ -import { parseMetadataPath } from 'src/engine/api/rest/rest-api-core-query-builder/utils/path-parsers/parse-metadata-path.utils'; +import { parseMetadataPath } from 'src/engine/api/rest/metadata/query-builder/utils/parse-metadata-path.utils'; describe('parseMetadataPath', () => { it('should parse object from request path with uuid', () => { diff --git a/packages/twenty-server/src/engine/api/rest/metadata/query-builder/utils/fetch-metadata-fields.utils.ts b/packages/twenty-server/src/engine/api/rest/metadata/query-builder/utils/fetch-metadata-fields.utils.ts new file mode 100644 index 000000000000..61899096d206 --- /dev/null +++ b/packages/twenty-server/src/engine/api/rest/metadata/query-builder/utils/fetch-metadata-fields.utils.ts @@ -0,0 +1,93 @@ +export const fetchMetadataFields = (objectNamePlural: string) => { + const fields = ` + type + name + label + description + icon + isCustom + isActive + isSystem + isNullable + createdAt + updatedAt + fromRelationMetadata { + id + relationType + toObjectMetadata { + id + dataSourceId + nameSingular + namePlural + isSystem + } + toFieldMetadataId + } + toRelationMetadata { + id + relationType + fromObjectMetadata { + id + dataSourceId + nameSingular + namePlural + isSystem + } + fromFieldMetadataId + } + defaultValue + options + `; + + switch (objectNamePlural) { + case 'objects': + return ` + dataSourceId + nameSingular + namePlural + labelSingular + labelPlural + description + icon + isCustom + isActive + isSystem + createdAt + updatedAt + labelIdentifierFieldMetadataId + imageIdentifierFieldMetadataId + fields(paging: { first: 1000 }) { + edges { + node { + id + ${fields} + } + } + } + `; + case 'fields': + return fields; + case 'relations': + return ` + relationType + fromObjectMetadata { + id + dataSourceId + nameSingular + namePlural + isSystem + } + fromObjectMetadataId + toObjectMetadata { + id + dataSourceId + nameSingular + namePlural + isSystem + } + toObjectMetadataId + fromFieldMetadataId + toFieldMetadataId + `; + } +}; diff --git a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/utils/path-parsers/parse-metadata-path.utils.ts b/packages/twenty-server/src/engine/api/rest/metadata/query-builder/utils/parse-metadata-path.utils.ts similarity index 100% rename from packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/utils/path-parsers/parse-metadata-path.utils.ts rename to packages/twenty-server/src/engine/api/rest/metadata/query-builder/utils/parse-metadata-path.utils.ts diff --git a/packages/twenty-server/src/engine/api/rest/controllers/rest-api-metadata.controller.ts b/packages/twenty-server/src/engine/api/rest/metadata/rest-api-metadata.controller.ts similarity index 76% rename from packages/twenty-server/src/engine/api/rest/controllers/rest-api-metadata.controller.ts rename to packages/twenty-server/src/engine/api/rest/metadata/rest-api-metadata.controller.ts index ac42dba52880..fc0154081f51 100644 --- a/packages/twenty-server/src/engine/api/rest/controllers/rest-api-metadata.controller.ts +++ b/packages/twenty-server/src/engine/api/rest/metadata/rest-api-metadata.controller.ts @@ -11,7 +11,7 @@ import { import { Request, Response } from 'express'; -import { RestApiMetadataService } from 'src/engine/api/rest/services/rest-api-metadata.service'; +import { RestApiMetadataService } from 'src/engine/api/rest/metadata/rest-api-metadata.service'; import { cleanGraphQLResponse } from 'src/engine/api/rest/utils/clean-graphql-response.utils'; @Controller('rest/metadata/*') @@ -24,28 +24,28 @@ export class RestApiMetadataController { async handleApiGet(@Req() request: Request, @Res() res: Response) { const result = await this.restApiMetadataService.get(request); - res.status(200).send(cleanGraphQLResponse(result.data)); + res.status(200).send(cleanGraphQLResponse(result.data.data)); } @Delete() async handleApiDelete(@Req() request: Request, @Res() res: Response) { const result = await this.restApiMetadataService.delete(request); - res.status(200).send(cleanGraphQLResponse(result.data)); + res.status(200).send(cleanGraphQLResponse(result.data.data)); } @Post() async handleApiPost(@Req() request: Request, @Res() res: Response) { const result = await this.restApiMetadataService.create(request); - res.status(201).send(cleanGraphQLResponse(result.data)); + res.status(201).send(cleanGraphQLResponse(result.data.data)); } @Patch() async handleApiPatch(@Req() request: Request, @Res() res: Response) { const result = await this.restApiMetadataService.update(request); - res.status(200).send(cleanGraphQLResponse(result.data)); + res.status(200).send(cleanGraphQLResponse(result.data.data)); } // This endpoint is not documented in the OpenAPI schema. @@ -55,6 +55,6 @@ export class RestApiMetadataController { async handleApiPut(@Req() request: Request, @Res() res: Response) { const result = await this.restApiMetadataService.update(request); - res.status(200).send(cleanGraphQLResponse(result.data)); + res.status(200).send(cleanGraphQLResponse(result.data.data)); } } diff --git a/packages/twenty-server/src/engine/api/rest/metadata/rest-api-metadata.service.ts b/packages/twenty-server/src/engine/api/rest/metadata/rest-api-metadata.service.ts new file mode 100644 index 000000000000..afd0e59efd77 --- /dev/null +++ b/packages/twenty-server/src/engine/api/rest/metadata/rest-api-metadata.service.ts @@ -0,0 +1,63 @@ +import { Injectable } from '@nestjs/common'; + +import { Request } from 'express'; + +import { TokenService } from 'src/engine/core-modules/auth/services/token.service'; +import { + GraphqlApiType, + RestApiService, +} from 'src/engine/api/rest/rest-api.service'; +import { MetadataQueryBuilderFactory } from 'src/engine/api/rest/metadata/query-builder/metadata-query-builder.factory'; + +@Injectable() +export class RestApiMetadataService { + constructor( + private readonly tokenService: TokenService, + private readonly metadataQueryBuilderFactory: MetadataQueryBuilderFactory, + private readonly restApiService: RestApiService, + ) {} + + async get(request: Request) { + await this.tokenService.validateToken(request); + const data = await this.metadataQueryBuilderFactory.get(request); + + return await this.restApiService.call( + GraphqlApiType.METADATA, + request, + data, + ); + } + + async create(request: Request) { + await this.tokenService.validateToken(request); + const data = await this.metadataQueryBuilderFactory.create(request); + + return await this.restApiService.call( + GraphqlApiType.METADATA, + request, + data, + ); + } + + async update(request: Request) { + await this.tokenService.validateToken(request); + const data = await this.metadataQueryBuilderFactory.update(request); + + return await this.restApiService.call( + GraphqlApiType.METADATA, + request, + data, + ); + } + + async delete(request: Request) { + await this.tokenService.validateToken(request); + const data = await this.metadataQueryBuilderFactory.delete(request); + + return await this.restApiService.call( + GraphqlApiType.METADATA, + request, + data, + ); + } +} diff --git a/packages/twenty-server/src/engine/api/rest/metadata/types/metadata-query-variables.type.ts b/packages/twenty-server/src/engine/api/rest/metadata/types/metadata-query-variables.type.ts new file mode 100644 index 000000000000..edc86f56fb1e --- /dev/null +++ b/packages/twenty-server/src/engine/api/rest/metadata/types/metadata-query-variables.type.ts @@ -0,0 +1,10 @@ +export type MetadataQueryVariables = { + id?: string; + input?: object; + paging?: { + first?: number; + last?: number; + after?: string; + before?: string; + }; +}; diff --git a/packages/twenty-server/src/engine/api/rest/metadata/types/metadata-query.type.ts b/packages/twenty-server/src/engine/api/rest/metadata/types/metadata-query.type.ts new file mode 100644 index 000000000000..6a3342482338 --- /dev/null +++ b/packages/twenty-server/src/engine/api/rest/metadata/types/metadata-query.type.ts @@ -0,0 +1,6 @@ +import { MetadataQueryVariables } from 'src/engine/api/rest/metadata/types/metadata-query-variables.type'; + +export type MetadataQuery = { + query: string; + variables: MetadataQueryVariables; +}; diff --git a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/__tests__/core-query-builder.factory.spec.ts b/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/__tests__/core-query-builder.factory.spec.ts deleted file mode 100644 index b64197417129..000000000000 --- a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/__tests__/core-query-builder.factory.spec.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; - -import { CoreQueryBuilderFactory } from 'src/engine/api/rest/rest-api-core-query-builder/core-query-builder.factory'; -import { DeleteQueryFactory } from 'src/engine/api/rest/rest-api-core-query-builder/factories/delete-query.factory'; -import { CreateOneQueryFactory } from 'src/engine/api/rest/rest-api-core-query-builder/factories/create-one-query.factory'; -import { CreateManyQueryFactory } from 'src/engine/api/rest/rest-api-core-query-builder/factories/create-many-query.factory'; -import { UpdateQueryFactory } from 'src/engine/api/rest/rest-api-core-query-builder/factories/update-query.factory'; -import { FindOneQueryFactory } from 'src/engine/api/rest/rest-api-core-query-builder/factories/find-one-query.factory'; -import { FindManyQueryFactory } from 'src/engine/api/rest/rest-api-core-query-builder/factories/find-many-query.factory'; -import { DeleteVariablesFactory } from 'src/engine/api/rest/rest-api-core-query-builder/factories/delete-variables.factory'; -import { CreateVariablesFactory } from 'src/engine/api/rest/rest-api-core-query-builder/factories/create-variables.factory'; -import { UpdateVariablesFactory } from 'src/engine/api/rest/rest-api-core-query-builder/factories/update-variables.factory'; -import { GetVariablesFactory } from 'src/engine/api/rest/rest-api-core-query-builder/factories/get-variables.factory'; -import { ObjectMetadataService } from 'src/engine/metadata-modules/object-metadata/object-metadata.service'; -import { TokenService } from 'src/engine/core-modules/auth/services/token.service'; -import { EnvironmentService } from 'src/engine/integrations/environment/environment.service'; - -describe('CoreQueryBuilderFactory', () => { - let service: CoreQueryBuilderFactory; - - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - providers: [ - CoreQueryBuilderFactory, - { provide: DeleteQueryFactory, useValue: {} }, - { provide: CreateOneQueryFactory, useValue: {} }, - { provide: CreateManyQueryFactory, useValue: {} }, - { provide: UpdateQueryFactory, useValue: {} }, - { provide: FindOneQueryFactory, useValue: {} }, - { provide: FindManyQueryFactory, useValue: {} }, - { provide: DeleteVariablesFactory, useValue: {} }, - { provide: CreateVariablesFactory, useValue: {} }, - { provide: UpdateVariablesFactory, useValue: {} }, - { provide: GetVariablesFactory, useValue: {} }, - { provide: ObjectMetadataService, useValue: {} }, - { provide: TokenService, useValue: {} }, - { provide: EnvironmentService, useValue: {} }, - ], - }).compile(); - - service = module.get<CoreQueryBuilderFactory>(CoreQueryBuilderFactory); - }); - it('should be defined', () => { - expect(service).toBeDefined(); - }); -}); diff --git a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/create-variables.factory.ts b/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/create-variables.factory.ts deleted file mode 100644 index eb4b20ef1c85..000000000000 --- a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/create-variables.factory.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Injectable } from '@nestjs/common'; - -import { Request } from 'express'; - -import { QueryVariables } from 'src/engine/api/rest/types/query-variables.type'; - -@Injectable() -export class CreateVariablesFactory { - create(request: Request): QueryVariables { - const data = Array.isArray(request.body) - ? request.body.map((recordData) => { - return { position: 'first', ...recordData }; - }) - : { position: 'first', ...request.body }; - - return { - data, - }; - } -} diff --git a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/factories.ts b/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/factories.ts deleted file mode 100644 index d583d2dfdf84..000000000000 --- a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/factories.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { DeleteQueryFactory } from 'src/engine/api/rest/rest-api-core-query-builder/factories/delete-query.factory'; -import { CreateOneQueryFactory } from 'src/engine/api/rest/rest-api-core-query-builder/factories/create-one-query.factory'; -import { UpdateQueryFactory } from 'src/engine/api/rest/rest-api-core-query-builder/factories/update-query.factory'; -import { FindOneQueryFactory } from 'src/engine/api/rest/rest-api-core-query-builder/factories/find-one-query.factory'; -import { FindManyQueryFactory } from 'src/engine/api/rest/rest-api-core-query-builder/factories/find-many-query.factory'; -import { DeleteVariablesFactory } from 'src/engine/api/rest/rest-api-core-query-builder/factories/delete-variables.factory'; -import { CreateVariablesFactory } from 'src/engine/api/rest/rest-api-core-query-builder/factories/create-variables.factory'; -import { UpdateVariablesFactory } from 'src/engine/api/rest/rest-api-core-query-builder/factories/update-variables.factory'; -import { GetVariablesFactory } from 'src/engine/api/rest/rest-api-core-query-builder/factories/get-variables.factory'; -import { LimitInputFactory } from 'src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/limit-input.factory'; -import { OrderByInputFactory } from 'src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/order-by-input.factory'; -import { FilterInputFactory } from 'src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-input.factory'; -import { CreateManyQueryFactory } from 'src/engine/api/rest/rest-api-core-query-builder/factories/create-many-query.factory'; -import { StartingAfterInputFactory } from 'src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/starting-after-input.factory'; -import { EndingBeforeInputFactory } from 'src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/ending-before-input.factory'; - -export const coreQueryBuilderFactories = [ - DeleteQueryFactory, - CreateOneQueryFactory, - CreateManyQueryFactory, - UpdateQueryFactory, - FindOneQueryFactory, - FindManyQueryFactory, - DeleteVariablesFactory, - CreateVariablesFactory, - UpdateVariablesFactory, - GetVariablesFactory, - StartingAfterInputFactory, - EndingBeforeInputFactory, - LimitInputFactory, - OrderByInputFactory, - FilterInputFactory, -]; diff --git a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/get-variables.factory.ts b/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/get-variables.factory.ts deleted file mode 100644 index 8703e67f7f2f..000000000000 --- a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/factories/get-variables.factory.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { Injectable } from '@nestjs/common'; - -import { Request } from 'express'; - -import { LimitInputFactory } from 'src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/limit-input.factory'; -import { OrderByInputFactory } from 'src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/order-by-input.factory'; -import { FilterInputFactory } from 'src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-input.factory'; -import { QueryVariables } from 'src/engine/api/rest/types/query-variables.type'; -import { EndingBeforeInputFactory } from 'src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/ending-before-input.factory'; -import { StartingAfterInputFactory } from 'src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/starting-after-input.factory'; - -@Injectable() -export class GetVariablesFactory { - constructor( - private readonly startingAfterInputFactory: StartingAfterInputFactory, - private readonly endingBeforeInputFactory: EndingBeforeInputFactory, - private readonly limitInputFactory: LimitInputFactory, - private readonly orderByInputFactory: OrderByInputFactory, - private readonly filterInputFactory: FilterInputFactory, - ) {} - - create( - id: string | undefined, - request: Request, - objectMetadata, - ): QueryVariables { - if (id) { - return { filter: { id: { eq: id } } }; - } - - return { - filter: this.filterInputFactory.create(request, objectMetadata), - orderBy: this.orderByInputFactory.create(request, objectMetadata), - limit: this.limitInputFactory.create(request), - startingAfter: this.startingAfterInputFactory.create(request), - endingBefore: this.endingBeforeInputFactory.create(request), - }; - } -} diff --git a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/utils/__tests__/check-fields.utils.spec.ts b/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/utils/__tests__/check-fields.utils.spec.ts deleted file mode 100644 index c54bf49bfcf6..000000000000 --- a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/utils/__tests__/check-fields.utils.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { objectMetadataItemMock } from 'src/engine/api/__mocks__/object-metadata-item.mock'; -import { checkFields } from 'src/engine/api/rest/rest-api-core-query-builder/utils/check-fields.utils'; - -describe('checkFields', () => { - it('should check field types', () => { - expect(() => - checkFields(objectMetadataItemMock, ['fieldNumber']), - ).not.toThrow(); - - expect(() => checkFields(objectMetadataItemMock, ['wrongField'])).toThrow(); - - expect(() => - checkFields(objectMetadataItemMock, ['fieldNumber', 'wrongField']), - ).toThrow(); - }); -}); diff --git a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/utils/__tests__/map-field-metadata-to-graphql-query.utils.spec.ts b/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/utils/__tests__/map-field-metadata-to-graphql-query.utils.spec.ts deleted file mode 100644 index 76dbe1b732ff..000000000000 --- a/packages/twenty-server/src/engine/api/rest/rest-api-core-query-builder/utils/__tests__/map-field-metadata-to-graphql-query.utils.spec.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { - fieldCurrencyMock, - fieldLinkMock, - fieldNumberMock, - fieldTextMock, - objectMetadataItemMock, -} from 'src/engine/api/__mocks__/object-metadata-item.mock'; -import { mapFieldMetadataToGraphqlQuery } from 'src/engine/api/rest/rest-api-core-query-builder/utils/map-field-metadata-to-graphql-query.utils'; - -describe('mapFieldMetadataToGraphqlQuery', () => { - it('should map properly', () => { - expect( - mapFieldMetadataToGraphqlQuery(objectMetadataItemMock, fieldNumberMock), - ).toEqual('fieldNumber'); - expect( - mapFieldMetadataToGraphqlQuery(objectMetadataItemMock, fieldTextMock), - ).toEqual('fieldText'); - expect( - mapFieldMetadataToGraphqlQuery(objectMetadataItemMock, fieldLinkMock), - ).toEqual(` - fieldLink - { - label - url - } - `); - expect( - mapFieldMetadataToGraphqlQuery(objectMetadataItemMock, fieldCurrencyMock), - ).toEqual(` - fieldCurrency - { - amountMicros - currencyCode - } - `); - }); -}); diff --git a/packages/twenty-server/src/engine/api/rest/rest-api.module.ts b/packages/twenty-server/src/engine/api/rest/rest-api.module.ts index 16141805d5e9..c459f3286264 100644 --- a/packages/twenty-server/src/engine/api/rest/rest-api.module.ts +++ b/packages/twenty-server/src/engine/api/rest/rest-api.module.ts @@ -1,23 +1,39 @@ import { Module } from '@nestjs/common'; import { HttpModule } from '@nestjs/axios'; -import { RestApiCoreController } from 'src/engine/api/rest/controllers/rest-api-core.controller'; -import { RestApiCoreService } from 'src/engine/api/rest/services/rest-api-core.service'; -import { CoreQueryBuilderModule } from 'src/engine/api/rest/rest-api-core-query-builder/core-query-builder.module'; +import { RestApiCoreController } from 'src/engine/api/rest/core/controllers/rest-api-core.controller'; +import { RestApiCoreService } from 'src/engine/api/rest/core/rest-api-core.service'; +import { CoreQueryBuilderModule } from 'src/engine/api/rest/core/query-builder/core-query-builder.module'; import { AuthModule } from 'src/engine/core-modules/auth/auth.module'; -import { RestApiMetadataController } from 'src/engine/api/rest/controllers/rest-api-metadata.controller'; -import { RestApiMetadataService } from 'src/engine/api/rest/services/rest-api-metadata.service'; -import { RestApiCoreBatchController } from 'src/engine/api/rest/controllers/rest-api-core-batch.controller'; -import { RestApiService } from 'src/engine/api/rest/services/rest-api.service'; +import { RestApiMetadataController } from 'src/engine/api/rest/metadata/rest-api-metadata.controller'; +import { RestApiMetadataService } from 'src/engine/api/rest/metadata/rest-api-metadata.service'; +import { RestApiCoreBatchController } from 'src/engine/api/rest/core/controllers/rest-api-core-batch.controller'; +import { RestApiService } from 'src/engine/api/rest/rest-api.service'; +import { EndingBeforeInputFactory } from 'src/engine/api/rest/input-factories/ending-before-input.factory'; +import { LimitInputFactory } from 'src/engine/api/rest/input-factories/limit-input.factory'; +import { StartingAfterInputFactory } from 'src/engine/api/rest/input-factories/starting-after-input.factory'; +import { MetadataQueryBuilderModule } from 'src/engine/api/rest/metadata/query-builder/metadata-query-builder.module'; @Module({ - imports: [CoreQueryBuilderModule, AuthModule, HttpModule], + imports: [ + CoreQueryBuilderModule, + MetadataQueryBuilderModule, + AuthModule, + HttpModule, + ], controllers: [ RestApiMetadataController, RestApiCoreBatchController, RestApiCoreController, ], - providers: [RestApiMetadataService, RestApiCoreService, RestApiService], + providers: [ + RestApiMetadataService, + RestApiCoreService, + RestApiService, + StartingAfterInputFactory, + EndingBeforeInputFactory, + LimitInputFactory, + ], exports: [RestApiMetadataService], }) export class RestApiModule {} diff --git a/packages/twenty-server/src/engine/api/rest/services/rest-api.service.ts b/packages/twenty-server/src/engine/api/rest/rest-api.service.ts similarity index 95% rename from packages/twenty-server/src/engine/api/rest/services/rest-api.service.ts rename to packages/twenty-server/src/engine/api/rest/rest-api.service.ts index 1107a259812d..d6b4d21640c3 100644 --- a/packages/twenty-server/src/engine/api/rest/services/rest-api.service.ts +++ b/packages/twenty-server/src/engine/api/rest/rest-api.service.ts @@ -4,7 +4,7 @@ import { HttpService } from '@nestjs/axios'; import { Request } from 'express'; import { AxiosResponse } from 'axios'; -import { Query } from 'src/engine/api/rest/types/query.type'; +import { Query } from 'src/engine/api/rest/core/types/query.type'; import { getServerUrl } from 'src/utils/get-server-url'; import { EnvironmentService } from 'src/engine/integrations/environment/environment.service'; import { RestApiException } from 'src/engine/api/rest/errors/RestApiException'; diff --git a/packages/twenty-server/src/engine/api/rest/services/__tests__/core.service.spec.ts b/packages/twenty-server/src/engine/api/rest/services/__tests__/core.service.spec.ts deleted file mode 100644 index 45fde1dfdc34..000000000000 --- a/packages/twenty-server/src/engine/api/rest/services/__tests__/core.service.spec.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; - -import { RestApiCoreService } from 'src/engine/api/rest/services/rest-api-core.service'; -import { CoreQueryBuilderFactory } from 'src/engine/api/rest/rest-api-core-query-builder/core-query-builder.factory'; -import { RestApiService } from 'src/engine/api/rest/services/rest-api.service'; - -describe('RestApiCoreService', () => { - let service: RestApiCoreService; - - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - providers: [ - RestApiCoreService, - { - provide: CoreQueryBuilderFactory, - useValue: {}, - }, - { - provide: RestApiService, - useValue: {}, - }, - ], - }).compile(); - - service = module.get<RestApiCoreService>(RestApiCoreService); - }); - it('should be defined', () => { - expect(service).toBeDefined(); - }); -}); diff --git a/packages/twenty-server/src/engine/api/rest/services/rest-api-metadata.service.ts b/packages/twenty-server/src/engine/api/rest/services/rest-api-metadata.service.ts deleted file mode 100644 index 007c67b2e5cc..000000000000 --- a/packages/twenty-server/src/engine/api/rest/services/rest-api-metadata.service.ts +++ /dev/null @@ -1,284 +0,0 @@ -import { BadRequestException, Injectable } from '@nestjs/common'; - -import { Query } from 'src/engine/api/rest/types/query.type'; -import { TokenService } from 'src/engine/core-modules/auth/services/token.service'; -import { capitalize } from 'src/utils/capitalize'; -import { parseMetadataPath } from 'src/engine/api/rest/rest-api-core-query-builder/utils/path-parsers/parse-metadata-path.utils'; -import { - GraphqlApiType, - RestApiService, -} from 'src/engine/api/rest/services/rest-api.service'; - -@Injectable() -export class RestApiMetadataService { - constructor( - private readonly tokenService: TokenService, - private readonly restApiService: RestApiService, - ) {} - - fetchMetadataFields(objectNamePlural: string) { - const fields = ` - type - name - label - description - icon - isCustom - isActive - isSystem - isNullable - createdAt - updatedAt - fromRelationMetadata { - id - relationType - toObjectMetadata { - id - dataSourceId - nameSingular - namePlural - isSystem - } - toFieldMetadataId - } - toRelationMetadata { - id - relationType - fromObjectMetadata { - id - dataSourceId - nameSingular - namePlural - isSystem - } - fromFieldMetadataId - } - defaultValue - options - `; - - switch (objectNamePlural) { - case 'objects': - return ` - dataSourceId - nameSingular - namePlural - labelSingular - labelPlural - description - icon - isCustom - isActive - isSystem - createdAt - updatedAt - labelIdentifierFieldMetadataId - imageIdentifierFieldMetadataId - fields(paging: { first: 1000 }) { - edges { - node { - id - ${fields} - } - } - } - `; - case 'fields': - return fields; - case 'relations': - return ` - relationType - fromObjectMetadata { - id - dataSourceId - nameSingular - namePlural - isSystem - } - fromObjectMetadataId - toObjectMetadata { - id - dataSourceId - nameSingular - namePlural - isSystem - } - toObjectMetadataId - fromFieldMetadataId - toFieldMetadataId - `; - } - } - - generateFindManyQuery(objectNameSingular: string, objectNamePlural: string) { - const fields = this.fetchMetadataFields(objectNamePlural); - - return ` - query FindMany${capitalize(objectNamePlural)}( - $filter: ${objectNameSingular}Filter, - ) { - ${objectNamePlural}( - filter: $filter, - paging: { first: 1000 } - ) { - edges { - node { - id - ${fields} - } - } - } - } - `; - } - - generateFindOneQuery(objectNameSingular: string, objectNamePlural: string) { - const fields = this.fetchMetadataFields(objectNamePlural); - - return ` - query FindOne${capitalize(objectNameSingular)}( - $id: UUID!, - ) { - ${objectNameSingular}(id: $id) { - id - ${fields} - } - } - `; - } - - async get(request) { - await this.tokenService.validateToken(request); - - const { objectNameSingular, objectNamePlural, id } = - parseMetadataPath(request); - - const query = id - ? this.generateFindOneQuery(objectNameSingular, objectNamePlural) - : this.generateFindManyQuery(objectNameSingular, objectNamePlural); - - const data: Query = { - query, - variables: id ? { id } : request.body, - }; - - return await this.restApiService.call( - GraphqlApiType.METADATA, - request, - data, - ); - } - - async create(request) { - await this.tokenService.validateToken(request); - - const { objectNameSingular: objectName, objectNamePlural } = - parseMetadataPath(request); - const objectNameCapitalized = capitalize(objectName); - - const fields = this.fetchMetadataFields(objectNamePlural); - - const query = ` - mutation Create${objectNameCapitalized}($input: CreateOne${objectNameCapitalized}Input!) { - createOne${objectNameCapitalized}(input: $input) { - id - ${fields} - } - } - `; - - const data: Query = { - query, - variables: { - input: { - [objectName]: request.body, - }, - }, - }; - - return await this.restApiService.call( - GraphqlApiType.METADATA, - request, - data, - ); - } - - async update(request) { - await this.tokenService.validateToken(request); - - const { - objectNameSingular: objectName, - objectNamePlural, - id, - } = parseMetadataPath(request); - const objectNameCapitalized = capitalize(objectName); - - if (!id) { - throw new BadRequestException( - `update ${objectName} query invalid. Id missing. eg: /rest/metadata/${objectName}/0d4389ef-ea9c-4ae8-ada1-1cddc440fb56`, - ); - } - const fields = this.fetchMetadataFields(objectNamePlural); - - const query = ` - mutation Update${objectNameCapitalized}($input: UpdateOne${objectNameCapitalized}Input!) { - updateOne${objectNameCapitalized}(input: $input) { - id - ${fields} - } - } - `; - - const data: Query = { - query, - variables: { - input: { - update: request.body, - id, - }, - }, - }; - - return await this.restApiService.call( - GraphqlApiType.METADATA, - request, - data, - ); - } - - async delete(request) { - await this.tokenService.validateToken(request); - - const { objectNameSingular: objectName, id } = parseMetadataPath(request); - const objectNameCapitalized = capitalize(objectName); - - if (!id) { - throw new BadRequestException( - `delete ${objectName} query invalid. Id missing. eg: /rest/metadata/${objectName}/0d4389ef-ea9c-4ae8-ada1-1cddc440fb56`, - ); - } - - const query = ` - mutation Delete${objectNameCapitalized}($input: DeleteOne${objectNameCapitalized}Input!) { - deleteOne${objectNameCapitalized}(input: $input) { - id - } - } - `; - - const data: Query = { - query, - variables: { - input: { - id, - }, - }, - }; - - return await this.restApiService.call( - GraphqlApiType.METADATA, - request, - data, - ); - } -} diff --git a/packages/twenty-server/src/engine/api/rest/types/query.type.ts b/packages/twenty-server/src/engine/api/rest/types/query.type.ts deleted file mode 100644 index 1af013c8a13c..000000000000 --- a/packages/twenty-server/src/engine/api/rest/types/query.type.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { QueryVariables } from 'src/engine/api/rest/types/query-variables.type'; - -export type Query = { - query: string; - variables: QueryVariables; -}; diff --git a/packages/twenty-server/src/engine/core-modules/ai-sql-query/ai-sql-query.module.ts b/packages/twenty-server/src/engine/core-modules/ai-sql-query/ai-sql-query.module.ts new file mode 100644 index 000000000000..f416a0898787 --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/ai-sql-query/ai-sql-query.module.ts @@ -0,0 +1,30 @@ +import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; + +import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; +import { UserModule } from 'src/engine/core-modules/user/user.module'; +import { AISQLQueryResolver } from 'src/engine/core-modules/ai-sql-query/ai-sql-query.resolver'; +import { AISQLQueryService } from 'src/engine/core-modules/ai-sql-query/ai-sql-query.service'; +import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity'; +import { WorkspaceQueryRunnerModule } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-runner.module'; +import { LLMChatModelModule } from 'src/engine/integrations/llm-chat-model/llm-chat-model.module'; +import { EnvironmentModule } from 'src/engine/integrations/environment/environment.module'; +import { LLMTracingModule } from 'src/engine/integrations/llm-tracing/llm-tracing.module'; +import { ObjectMetadataModule } from 'src/engine/metadata-modules/object-metadata/object-metadata.module'; +import { WorkspaceSyncMetadataModule } from 'src/engine/workspace-manager/workspace-sync-metadata/workspace-sync-metadata.module'; +@Module({ + imports: [ + WorkspaceDataSourceModule, + WorkspaceQueryRunnerModule, + UserModule, + TypeOrmModule.forFeature([FeatureFlagEntity], 'core'), + LLMChatModelModule, + LLMTracingModule, + EnvironmentModule, + ObjectMetadataModule, + WorkspaceSyncMetadataModule, + ], + exports: [], + providers: [AISQLQueryResolver, AISQLQueryService], +}) +export class AISQLQueryModule {} diff --git a/packages/twenty-server/src/engine/core-modules/ai-sql-query/ai-sql-query.prompt-templates.ts b/packages/twenty-server/src/engine/core-modules/ai-sql-query/ai-sql-query.prompt-templates.ts new file mode 100644 index 000000000000..3b100c0b7711 --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/ai-sql-query/ai-sql-query.prompt-templates.ts @@ -0,0 +1,14 @@ +import { PromptTemplate } from '@langchain/core/prompts'; + +export const sqlGenerationPromptTemplate = PromptTemplate.fromTemplate<{ + llmOutputJsonSchema: string; + sqlCreateTableStatements: string; + userQuestion: string; +}>(`Always respond following this JSON Schema: {llmOutputJsonSchema} + +Based on the table schema below, write a PostgreSQL query that would answer the user's question. All column names must be enclosed in double quotes. + +{sqlCreateTableStatements} + +Question: {userQuestion} +SQL Query:`); diff --git a/packages/twenty-server/src/engine/core-modules/ai-sql-query/ai-sql-query.resolver.ts b/packages/twenty-server/src/engine/core-modules/ai-sql-query/ai-sql-query.resolver.ts new file mode 100644 index 000000000000..6aa38399a91c --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/ai-sql-query/ai-sql-query.resolver.ts @@ -0,0 +1,64 @@ +import { Args, Query, Resolver, ArgsType, Field } from '@nestjs/graphql'; +import { ForbiddenException, UseGuards } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; + +import { Repository } from 'typeorm'; + +import { User } from 'src/engine/core-modules/user/user.entity'; +import { JwtAuthGuard } from 'src/engine/guards/jwt.auth.guard'; +import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; +import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator'; +import { + FeatureFlagEntity, + FeatureFlagKeys, +} from 'src/engine/core-modules/feature-flag/feature-flag.entity'; +import { AuthUser } from 'src/engine/decorators/auth/auth-user.decorator'; +import { AISQLQueryResult } from 'src/engine/core-modules/ai-sql-query/dtos/ai-sql-query-result.dto'; +import { AISQLQueryService } from 'src/engine/core-modules/ai-sql-query/ai-sql-query.service'; + +@ArgsType() +class GetAISQLQueryArgs { + @Field(() => String) + text: string; +} + +@UseGuards(JwtAuthGuard) +@Resolver(() => AISQLQueryResult) +export class AISQLQueryResolver { + constructor( + private readonly aiSqlQueryService: AISQLQueryService, + @InjectRepository(FeatureFlagEntity, 'core') + private readonly featureFlagRepository: Repository<FeatureFlagEntity>, + ) {} + + @Query(() => AISQLQueryResult) + async getAISQLQuery( + @AuthWorkspace() { id: workspaceId }: Workspace, + @AuthUser() user: User, + @Args() { text }: GetAISQLQueryArgs, + ) { + const isCopilotEnabledFeatureFlag = + await this.featureFlagRepository.findOneBy({ + workspaceId, + key: FeatureFlagKeys.IsCopilotEnabled, + value: true, + }); + + if (!isCopilotEnabledFeatureFlag?.value) { + throw new ForbiddenException( + `${FeatureFlagKeys.IsCopilotEnabled} feature flag is disabled`, + ); + } + + const traceMetadata = { + userId: user.id, + userEmail: user.email, + }; + + return this.aiSqlQueryService.generateAndExecute( + workspaceId, + text, + traceMetadata, + ); + } +} diff --git a/packages/twenty-server/src/engine/core-modules/ai-sql-query/ai-sql-query.service.ts b/packages/twenty-server/src/engine/core-modules/ai-sql-query/ai-sql-query.service.ts new file mode 100644 index 000000000000..465f9a0a481e --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/ai-sql-query/ai-sql-query.service.ts @@ -0,0 +1,250 @@ +import { Injectable, Logger } from '@nestjs/common'; + +import { RunnableSequence } from '@langchain/core/runnables'; +import { StructuredOutputParser } from '@langchain/core/output_parsers'; +import { DataSource, QueryFailedError } from 'typeorm'; +import { z } from 'zod'; +import { zodToJsonSchema } from 'zod-to-json-schema'; +import { PostgresConnectionOptions } from 'typeorm/driver/postgres/PostgresConnectionOptions'; +import groupBy from 'lodash.groupby'; + +import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; +import { WorkspaceQueryRunnerService } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-runner.service'; +import { LLMChatModelService } from 'src/engine/integrations/llm-chat-model/llm-chat-model.service'; +import { LLMTracingService } from 'src/engine/integrations/llm-tracing/llm-tracing.service'; +import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; +import { DEFAULT_LABEL_IDENTIFIER_FIELD_NAME } from 'src/engine/metadata-modules/object-metadata/object-metadata.constants'; +import { StandardObjectFactory } from 'src/engine/workspace-manager/workspace-sync-metadata/factories/standard-object.factory'; +import { AISQLQueryResult } from 'src/engine/core-modules/ai-sql-query/dtos/ai-sql-query-result.dto'; +import { sqlGenerationPromptTemplate } from 'src/engine/core-modules/ai-sql-query/ai-sql-query.prompt-templates'; + +@Injectable() +export class AISQLQueryService { + private readonly logger = new Logger(AISQLQueryService.name); + constructor( + private readonly workspaceDataSourceService: WorkspaceDataSourceService, + private readonly workspaceQueryRunnerService: WorkspaceQueryRunnerService, + private readonly llmChatModelService: LLMChatModelService, + private readonly llmTracingService: LLMTracingService, + private readonly standardObjectFactory: StandardObjectFactory, + ) {} + + private getLabelIdentifierName( + objectMetadata: ObjectMetadataEntity, + dataSourceId, + workspaceId, + workspaceFeatureFlagsMap, + ): string | undefined { + const customObjectLabelIdentifierFieldMetadata = objectMetadata.fields.find( + (fieldMetadata) => + fieldMetadata.id === objectMetadata.labelIdentifierFieldMetadataId, + ); + + /* const standardObjectMetadataCollection = this.standardObjectFactory.create( + standardObjectMetadataDefinitions, + { workspaceId, dataSourceId }, + workspaceFeatureFlagsMap, + ); + + const standardObjectLabelIdentifierFieldMetadata = + standardObjectMetadataCollection + .find( + (standardObjectMetadata) => + standardObjectMetadata.nameSingular === objectMetadata.nameSingular, + ) + ?.fields.find( + (field: PartialFieldMetadata) => + field.name === DEFAULT_LABEL_IDENTIFIER_FIELD_NAME, + ) as PartialFieldMetadata; */ + + const labelIdentifierFieldMetadata = + customObjectLabelIdentifierFieldMetadata; /*?? + standardObjectLabelIdentifierFieldMetadata*/ + + return ( + labelIdentifierFieldMetadata?.name ?? DEFAULT_LABEL_IDENTIFIER_FIELD_NAME + ); + } + + private async getColInfosByTableName(dataSource: DataSource) { + const { schema } = dataSource.options as PostgresConnectionOptions; + + // From LangChain sql_utils.ts + const sqlQuery = `SELECT + t.table_name, + c.* + FROM + information_schema.tables t + JOIN information_schema.columns c + ON t.table_name = c.table_name + WHERE + t.table_schema = '${schema}' + AND c.table_schema = '${schema}' + ORDER BY + t.table_name, + c.ordinal_position;`; + const colInfos = await dataSource.query< + { + table_name: string; + column_name: string; + data_type: string | undefined; + is_nullable: 'YES' | 'NO'; + }[] + >(sqlQuery); + + return groupBy(colInfos, (colInfo) => colInfo.table_name); + } + + private getCreateTableStatement(tableName: string, colInfos: any[]) { + return `${`CREATE TABLE ${tableName} (\n`} ${colInfos + .map( + (colInfo) => + `${colInfo.column_name} ${colInfo.data_type} ${ + colInfo.is_nullable === 'YES' ? '' : 'NOT NULL' + }`, + ) + .join(', ')});`; + } + + private getRelationDescriptions() { + // TODO - Construct sentences like the following: + // investorId: a foreign key referencing the person table, indicating the investor who owns this portfolio company. + return ''; + } + + private getTableDescription(tableName: string, colInfos: any[]) { + return [ + this.getCreateTableStatement(tableName, colInfos), + this.getRelationDescriptions(), + ].join('\n'); + } + + private async getWorkspaceSchemaDescription( + dataSource: DataSource, + ): Promise<string> { + const colInfoByTableName = await this.getColInfosByTableName(dataSource); + + return Object.entries(colInfoByTableName) + .map(([tableName, colInfos]) => + this.getTableDescription(tableName, colInfos), + ) + .join('\n\n'); + } + + private async generateWithDataSource( + workspaceId: string, + workspaceDataSource: DataSource, + userQuestion: string, + traceMetadata: Record<string, string> = {}, + ) { + const workspaceSchemaName = + this.workspaceDataSourceService.getSchemaName(workspaceId); + + workspaceDataSource.setOptions({ + schema: workspaceSchemaName, + }); + + const workspaceSchemaDescription = + await this.getWorkspaceSchemaDescription(workspaceDataSource); + + const llmOutputSchema = z.object({ + sqlQuery: z.string(), + }); + + const llmOutputJsonSchema = JSON.stringify( + zodToJsonSchema(llmOutputSchema), + ); + + const structuredOutputParser = + StructuredOutputParser.fromZodSchema(llmOutputSchema); + + const sqlQueryGeneratorChain = RunnableSequence.from([ + sqlGenerationPromptTemplate, + this.llmChatModelService.getJSONChatModel(), + structuredOutputParser, + ]); + + const metadata = { + workspaceId, + ...traceMetadata, + }; + const tracingCallbackHandler = + this.llmTracingService.getCallbackHandler(metadata); + + const { sqlQuery } = await sqlQueryGeneratorChain.invoke( + { + llmOutputJsonSchema, + sqlCreateTableStatements: workspaceSchemaDescription, + userQuestion, + }, + { + callbacks: [tracingCallbackHandler], + }, + ); + + return sqlQuery; + } + + async generate( + workspaceId: string, + userQuestion: string, + traceMetadata: Record<string, string> = {}, + ) { + const workspaceDataSource = + await this.workspaceDataSourceService.connectToWorkspaceDataSource( + workspaceId, + ); + + return this.generateWithDataSource( + workspaceId, + workspaceDataSource, + userQuestion, + traceMetadata, + ); + } + + async generateAndExecute( + workspaceId: string, + userQuestion: string, + traceMetadata: Record<string, string> = {}, + ): Promise<AISQLQueryResult> { + const workspaceDataSource = + await this.workspaceDataSourceService.connectToWorkspaceDataSource( + workspaceId, + ); + + const sqlQuery = await this.generateWithDataSource( + workspaceId, + workspaceDataSource, + userQuestion, + traceMetadata, + ); + + try { + const sqlQueryResult: Record<string, any>[] = + await this.workspaceQueryRunnerService.executeSQL( + workspaceDataSource, + workspaceId, + sqlQuery, + ); + + return { + sqlQuery, + sqlQueryResult: JSON.stringify(sqlQueryResult), + }; + } catch (error) { + if (error instanceof QueryFailedError) { + return { + sqlQuery, + queryFailedErrorMessage: error.message, + }; + } + + this.logger.error(error.message, error.stack); + + return { + sqlQuery, + }; + } + } +} diff --git a/packages/twenty-server/src/engine/core-modules/ai-sql-query/dtos/ai-sql-query-result.dto.ts b/packages/twenty-server/src/engine/core-modules/ai-sql-query/dtos/ai-sql-query-result.dto.ts new file mode 100644 index 000000000000..1046631f3253 --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/ai-sql-query/dtos/ai-sql-query-result.dto.ts @@ -0,0 +1,17 @@ +import { Field, ObjectType } from '@nestjs/graphql'; + +import { IsOptional } from 'class-validator'; + +@ObjectType('AISQLQueryResult') +export class AISQLQueryResult { + @Field(() => String) + sqlQuery: string; + + @Field(() => String, { nullable: true }) + @IsOptional() + sqlQueryResult?: string; + + @Field(() => String, { nullable: true }) + @IsOptional() + queryFailedErrorMessage?: string; +} diff --git a/packages/twenty-server/src/engine/core-modules/analytics/analytics.service.ts b/packages/twenty-server/src/engine/core-modules/analytics/analytics.service.ts index fd685851c584..73851f71ea5b 100644 --- a/packages/twenty-server/src/engine/core-modules/analytics/analytics.service.ts +++ b/packages/twenty-server/src/engine/core-modules/analytics/analytics.service.ts @@ -19,8 +19,8 @@ export class AnalyticsService { async create( createEventInput: CreateEventInput, - userId: string | undefined, - workspaceId: string | undefined, + userId: string | null | undefined, + workspaceId: string | null | undefined, workspaceDisplayName: string | undefined, workspaceDomainName: string | undefined, hostName: string | undefined, diff --git a/packages/twenty-server/src/engine/core-modules/auth/auth.module.ts b/packages/twenty-server/src/engine/core-modules/auth/auth.module.ts index 999d3175074f..5f60af70e3db 100644 --- a/packages/twenty-server/src/engine/core-modules/auth/auth.module.ts +++ b/packages/twenty-server/src/engine/core-modules/auth/auth.module.ts @@ -25,9 +25,12 @@ import { MicrosoftAuthController } from 'src/engine/core-modules/auth/controller import { AppTokenService } from 'src/engine/core-modules/app-token/services/app-token.service'; import { ObjectMetadataRepositoryModule } from 'src/engine/object-metadata-repository/object-metadata-repository.module'; import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; -import { CalendarChannelWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-channel.workspace-entity'; import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity'; import { OnboardingModule } from 'src/engine/core-modules/onboarding/onboarding.module'; +import { TwentyORMModule } from 'src/engine/twenty-orm/twenty-orm.module'; +import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; +import { WorkspaceModule } from 'src/engine/core-modules/workspace/workspace.module'; +import { CalendarChannelWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-channel.workspace-entity'; import { AuthResolver } from './auth.resolver'; @@ -60,11 +63,13 @@ const jwtModule = JwtModule.registerAsync({ ObjectMetadataRepositoryModule.forFeature([ ConnectedAccountWorkspaceEntity, MessageChannelWorkspaceEntity, - CalendarChannelWorkspaceEntity, ]), HttpModule, UserWorkspaceModule, + WorkspaceModule, OnboardingModule, + TwentyORMModule.forFeature([CalendarChannelWorkspaceEntity]), + WorkspaceDataSourceModule, ], controllers: [ GoogleAuthController, diff --git a/packages/twenty-server/src/engine/core-modules/auth/auth.resolver.ts b/packages/twenty-server/src/engine/core-modules/auth/auth.resolver.ts index 9ce29e324c0b..13ecbec165dc 100644 --- a/packages/twenty-server/src/engine/core-modules/auth/auth.resolver.ts +++ b/packages/twenty-server/src/engine/core-modules/auth/auth.resolver.ts @@ -82,9 +82,15 @@ export class AuthResolver { async findWorkspaceFromInviteHash( @Args() workspaceInviteHashValidInput: WorkspaceInviteHashValidInput, ) { - return await this.workspaceRepository.findOneBy({ + const workspace = await this.workspaceRepository.findOneBy({ inviteHash: workspaceInviteHashValidInput.inviteHash, }); + + if (!workspace) { + throw new BadRequestException('Workspace does not exist'); + } + + return workspace; } @UseGuards(CaptchaGuard) @@ -132,6 +138,7 @@ export class AuthResolver { } const transientToken = await this.tokenService.generateTransientToken( workspaceMember.id, + user.id, user.defaultWorkspace.id, ); diff --git a/packages/twenty-server/src/engine/core-modules/auth/controllers/google-apis-auth.controller.ts b/packages/twenty-server/src/engine/core-modules/auth/controllers/google-apis-auth.controller.ts index 0a36fe5d0132..0715d31220a3 100644 --- a/packages/twenty-server/src/engine/core-modules/auth/controllers/google-apis-auth.controller.ts +++ b/packages/twenty-server/src/engine/core-modules/auth/controllers/google-apis-auth.controller.ts @@ -9,16 +9,14 @@ import { import { Response } from 'express'; -import { GoogleAPIsProviderEnabledGuard } from 'src/engine/core-modules/auth/guards/google-apis-provider-enabled.guard'; -import { GoogleAPIsOauthGuard } from 'src/engine/core-modules/auth/guards/google-apis-oauth.guard'; -import { GoogleAPIsRequest } from 'src/engine/core-modules/auth/strategies/google-apis.auth.strategy'; +import { GoogleAPIsOauthRequestCodeGuard } from 'src/engine/core-modules/auth/guards/google-apis-oauth-request-code.guard'; import { GoogleAPIsService } from 'src/engine/core-modules/auth/services/google-apis.service'; import { TokenService } from 'src/engine/core-modules/auth/services/token.service'; import { EnvironmentService } from 'src/engine/integrations/environment/environment.service'; import { OnboardingService } from 'src/engine/core-modules/onboarding/onboarding.service'; -import { WorkspaceMemberRepository } from 'src/modules/workspace-member/repositories/workspace-member.repository'; -import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; -import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; +import { LoadServiceWithWorkspaceContext } from 'src/engine/twenty-orm/context/load-service-with-workspace.context'; +import { GoogleAPIsOauthExchangeCodeForTokenGuard } from 'src/engine/core-modules/auth/guards/google-apis-oauth-exchange-code-for-token.guard'; +import { GoogleAPIsRequest } from 'src/engine/core-modules/auth/types/google-api-request.type'; @Controller('auth/google-apis') export class GoogleAPIsAuthController { @@ -27,19 +25,18 @@ export class GoogleAPIsAuthController { private readonly tokenService: TokenService, private readonly environmentService: EnvironmentService, private readonly onboardingService: OnboardingService, - @InjectObjectMetadataRepository(WorkspaceMemberWorkspaceEntity) - private readonly workspaceMemberService: WorkspaceMemberRepository, + private readonly loadServiceWithWorkspaceContext: LoadServiceWithWorkspaceContext, ) {} @Get() - @UseGuards(GoogleAPIsProviderEnabledGuard, GoogleAPIsOauthGuard) + @UseGuards(GoogleAPIsOauthRequestCodeGuard) async googleAuth() { // As this method is protected by Google Auth guard, it will trigger Google SSO flow return; } @Get('get-access-token') - @UseGuards(GoogleAPIsProviderEnabledGuard, GoogleAPIsOauthGuard) + @UseGuards(GoogleAPIsOauthExchangeCodeForTokenGuard) async googleAuthGetAccessToken( @Req() req: GoogleAPIsRequest, @Res() res: Response, @@ -47,7 +44,7 @@ export class GoogleAPIsAuthController { const { user } = req; const { - email, + emails, accessToken, refreshToken, transientToken, @@ -56,7 +53,7 @@ export class GoogleAPIsAuthController { messageVisibility, } = user; - const { workspaceMemberId, workspaceId } = + const { workspaceMemberId, userId, workspaceId } = await this.tokenService.verifyTransientToken(transientToken); const demoWorkspaceIds = this.environmentService.get('DEMO_WORKSPACE_IDS'); @@ -71,8 +68,16 @@ export class GoogleAPIsAuthController { throw new Error('Workspace not found'); } - await this.googleAPIsService.refreshGoogleRefreshToken({ - handle: email, + const handle = emails[0].value; + + const googleAPIsServiceInstance = + await this.loadServiceWithWorkspaceContext.load( + this.googleAPIsService, + workspaceId, + ); + + await googleAPIsServiceInstance.refreshGoogleRefreshToken({ + handle, workspaceMemberId: workspaceMemberId, workspaceId: workspaceId, accessToken, @@ -81,12 +86,14 @@ export class GoogleAPIsAuthController { messageVisibility, }); - const userId = ( - await this.workspaceMemberService.find(workspaceMemberId, workspaceId) - )?.userId; - if (userId) { - await this.onboardingService.skipSyncEmailOnboardingStep( + const onboardingServiceInstance = + await this.loadServiceWithWorkspaceContext.load( + this.onboardingService, + workspaceId, + ); + + await onboardingServiceInstance.skipSyncEmailOnboardingStep( userId, workspaceId, ); diff --git a/packages/twenty-server/src/engine/core-modules/auth/guards/google-apis-oauth-exchange-code-for-token.guard.ts b/packages/twenty-server/src/engine/core-modules/auth/guards/google-apis-oauth-exchange-code-for-token.guard.ts new file mode 100644 index 000000000000..56780ecbcc20 --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/auth/guards/google-apis-oauth-exchange-code-for-token.guard.ts @@ -0,0 +1,74 @@ +import { + ExecutionContext, + Injectable, + NotFoundException, +} from '@nestjs/common'; +import { AuthGuard } from '@nestjs/passport'; +import { InjectRepository } from '@nestjs/typeorm'; + +import { Repository } from 'typeorm'; + +import { TokenService } from 'src/engine/core-modules/auth/services/token.service'; +import { + GoogleAPIScopeConfig, + GoogleAPIsOauthExchangeCodeForTokenStrategy, +} from 'src/engine/core-modules/auth/strategies/google-apis-oauth-exchange-code-for-token.auth.strategy'; +import { + FeatureFlagEntity, + FeatureFlagKeys, +} from 'src/engine/core-modules/feature-flag/feature-flag.entity'; +import { EnvironmentService } from 'src/engine/integrations/environment/environment.service'; +import { setRequestExtraParams } from 'src/engine/core-modules/auth/utils/google-apis-set-request-extra-params.util'; + +@Injectable() +export class GoogleAPIsOauthExchangeCodeForTokenGuard extends AuthGuard( + 'google-apis', +) { + constructor( + private readonly environmentService: EnvironmentService, + private readonly tokenService: TokenService, + @InjectRepository(FeatureFlagEntity, 'core') + private readonly featureFlagRepository: Repository<FeatureFlagEntity>, + ) { + super(); + } + + async canActivate(context: ExecutionContext) { + const request = context.switchToHttp().getRequest(); + const state = JSON.parse(request.query.state); + + if ( + !this.environmentService.get('MESSAGING_PROVIDER_GMAIL_ENABLED') && + !this.environmentService.get('CALENDAR_PROVIDER_GOOGLE_ENABLED') + ) { + throw new NotFoundException('Google apis auth is not enabled'); + } + + const { workspaceId } = await this.tokenService.verifyTransientToken( + state.transientToken, + ); + + const scopeConfig: GoogleAPIScopeConfig = { + isMessagingAliasFetchingEnabled: + !!(await this.featureFlagRepository.findOneBy({ + workspaceId, + key: FeatureFlagKeys.IsMessagingAliasFetchingEnabled, + value: true, + })), + }; + + new GoogleAPIsOauthExchangeCodeForTokenStrategy( + this.environmentService, + scopeConfig, + ); + + setRequestExtraParams(request, { + transientToken: state.transientToken, + redirectLocation: state.redirectLocation, + calendarVisibility: state.calendarVisibility, + messageVisibility: state.messageVisibility, + }); + + return (await super.canActivate(context)) as boolean; + } +} diff --git a/packages/twenty-server/src/engine/core-modules/auth/guards/google-apis-oauth-request-code.guard.ts b/packages/twenty-server/src/engine/core-modules/auth/guards/google-apis-oauth-request-code.guard.ts new file mode 100644 index 000000000000..d34ea86180b8 --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/auth/guards/google-apis-oauth-request-code.guard.ts @@ -0,0 +1,72 @@ +import { + ExecutionContext, + Injectable, + NotFoundException, +} from '@nestjs/common'; +import { AuthGuard } from '@nestjs/passport'; +import { InjectRepository } from '@nestjs/typeorm'; + +import { Repository } from 'typeorm'; + +import { TokenService } from 'src/engine/core-modules/auth/services/token.service'; +import { GoogleAPIScopeConfig } from 'src/engine/core-modules/auth/strategies/google-apis-oauth-exchange-code-for-token.auth.strategy'; +import { + FeatureFlagEntity, + FeatureFlagKeys, +} from 'src/engine/core-modules/feature-flag/feature-flag.entity'; +import { EnvironmentService } from 'src/engine/integrations/environment/environment.service'; +import { GoogleAPIsOauthRequestCodeStrategy } from 'src/engine/core-modules/auth/strategies/google-apis-oauth-request-code.auth.strategy'; +import { setRequestExtraParams } from 'src/engine/core-modules/auth/utils/google-apis-set-request-extra-params.util'; + +@Injectable() +export class GoogleAPIsOauthRequestCodeGuard extends AuthGuard('google-apis') { + constructor( + private readonly environmentService: EnvironmentService, + private readonly tokenService: TokenService, + @InjectRepository(FeatureFlagEntity, 'core') + private readonly featureFlagRepository: Repository<FeatureFlagEntity>, + ) { + super({ + prompt: 'select_account', + }); + } + + async canActivate(context: ExecutionContext) { + const request = context.switchToHttp().getRequest(); + + if ( + !this.environmentService.get('MESSAGING_PROVIDER_GMAIL_ENABLED') && + !this.environmentService.get('CALENDAR_PROVIDER_GOOGLE_ENABLED') + ) { + throw new NotFoundException('Google apis auth is not enabled'); + } + + const { workspaceId } = await this.tokenService.verifyTransientToken( + request.query.transientToken, + ); + + const scopeConfig: GoogleAPIScopeConfig = { + isMessagingAliasFetchingEnabled: + !!(await this.featureFlagRepository.findOneBy({ + workspaceId, + key: FeatureFlagKeys.IsMessagingAliasFetchingEnabled, + value: true, + })), + }; + + new GoogleAPIsOauthRequestCodeStrategy( + this.environmentService, + scopeConfig, + ); + setRequestExtraParams(request, { + transientToken: request.query.transientToken, + redirectLocation: request.query.redirectLocation, + calendarVisibility: request.query.calendarVisibility, + messageVisibility: request.query.messageVisibility, + }); + + const activate = (await super.canActivate(context)) as boolean; + + return activate; + } +} diff --git a/packages/twenty-server/src/engine/core-modules/auth/guards/google-apis-oauth.guard.ts b/packages/twenty-server/src/engine/core-modules/auth/guards/google-apis-oauth.guard.ts deleted file mode 100644 index a1214404fda4..000000000000 --- a/packages/twenty-server/src/engine/core-modules/auth/guards/google-apis-oauth.guard.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { ExecutionContext, Injectable } from '@nestjs/common'; -import { AuthGuard } from '@nestjs/passport'; - -@Injectable() -export class GoogleAPIsOauthGuard extends AuthGuard('google-apis') { - constructor() { - super({ - prompt: 'select_account', - }); - } - - async canActivate(context: ExecutionContext) { - const request = context.switchToHttp().getRequest(); - const transientToken = request.query.transientToken; - const redirectLocation = request.query.redirectLocation; - const calendarVisibility = request.query.calendarVisibility; - const messageVisibility = request.query.messageVisibility; - - if (transientToken && typeof transientToken === 'string') { - request.params.transientToken = transientToken; - } - - if (redirectLocation && typeof redirectLocation === 'string') { - request.params.redirectLocation = redirectLocation; - } - - if (calendarVisibility && typeof calendarVisibility === 'string') { - request.params.calendarVisibility = calendarVisibility; - } - - if (messageVisibility && typeof messageVisibility === 'string') { - request.params.messageVisibility = messageVisibility; - } - - const activate = (await super.canActivate(context)) as boolean; - - return activate; - } -} diff --git a/packages/twenty-server/src/engine/core-modules/auth/guards/google-apis-provider-enabled.guard.ts b/packages/twenty-server/src/engine/core-modules/auth/guards/google-apis-provider-enabled.guard.ts deleted file mode 100644 index bbd094be4803..000000000000 --- a/packages/twenty-server/src/engine/core-modules/auth/guards/google-apis-provider-enabled.guard.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { Injectable, CanActivate, NotFoundException } from '@nestjs/common'; -import { InjectRepository } from '@nestjs/typeorm'; - -import { Repository } from 'typeorm'; - -import { TokenService } from 'src/engine/core-modules/auth/services/token.service'; -import { - GoogleAPIScopeConfig, - GoogleAPIsStrategy, -} from 'src/engine/core-modules/auth/strategies/google-apis.auth.strategy'; -import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity'; -import { EnvironmentService } from 'src/engine/integrations/environment/environment.service'; - -@Injectable() -export class GoogleAPIsProviderEnabledGuard implements CanActivate { - constructor( - private readonly environmentService: EnvironmentService, - private readonly tokenService: TokenService, - @InjectRepository(FeatureFlagEntity, 'core') - private readonly featureFlagRepository: Repository<FeatureFlagEntity>, - ) {} - - async canActivate(): Promise<boolean> { - if ( - !this.environmentService.get('MESSAGING_PROVIDER_GMAIL_ENABLED') && - !this.environmentService.get('CALENDAR_PROVIDER_GOOGLE_ENABLED') - ) { - throw new NotFoundException('Google apis auth is not enabled'); - } - - const scopeConfig: GoogleAPIScopeConfig = { - isCalendarEnabled: !!this.environmentService.get( - 'MESSAGING_PROVIDER_GMAIL_ENABLED', - ), - }; - - new GoogleAPIsStrategy(this.environmentService, scopeConfig); - - return true; - } -} diff --git a/packages/twenty-server/src/engine/core-modules/auth/services/google-apis.service.ts b/packages/twenty-server/src/engine/core-modules/auth/services/google-apis.service.ts index ed4b58e59f9b..534ad1a6e1db 100644 --- a/packages/twenty-server/src/engine/core-modules/auth/services/google-apis.service.ts +++ b/packages/twenty-server/src/engine/core-modules/auth/services/google-apis.service.ts @@ -1,23 +1,12 @@ -import { Injectable, Inject } from '@nestjs/common'; +import { Injectable } from '@nestjs/common'; import { EntityManager } from 'typeorm'; import { v4 } from 'uuid'; -import { TypeORMService } from 'src/database/typeorm/typeorm.service'; import { EnvironmentService } from 'src/engine/integrations/environment/environment.service'; import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service'; -import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; -import { - GoogleCalendarSyncJobData, - GoogleCalendarSyncJob, -} from 'src/modules/calendar/jobs/google-calendar-sync.job'; -import { CalendarChannelRepository } from 'src/modules/calendar/repositories/calendar-channel.repository'; -import { - CalendarChannelWorkspaceEntity, - CalendarChannelVisibility, -} from 'src/modules/calendar/standard-objects/calendar-channel.workspace-entity'; import { ConnectedAccountRepository } from 'src/modules/connected-account/repositories/connected-account.repository'; import { ConnectedAccountWorkspaceEntity, @@ -34,23 +23,36 @@ import { MessagingMessageListFetchJob, MessagingMessageListFetchJobData, } from 'src/modules/messaging/message-import-manager/jobs/messaging-message-list-fetch.job'; +import { InjectMessageQueue } from 'src/engine/integrations/message-queue/decorators/message-queue.decorator'; +import { InjectWorkspaceRepository } from 'src/engine/twenty-orm/decorators/inject-workspace-repository.decorator'; +import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository'; +import { WorkspaceDataSource } from 'src/engine/twenty-orm/datasource/workspace.datasource'; +import { InjectWorkspaceDatasource } from 'src/engine/twenty-orm/decorators/inject-workspace-datasource.decorator'; +import { + CalendarChannelWorkspaceEntity, + CalendarChannelVisibility, +} from 'src/modules/calendar/common/standard-objects/calendar-channel.workspace-entity'; +import { + CalendarEventsImportJobData, + CalendarEventListFetchJob, +} from 'src/modules/calendar/calendar-event-import-manager/jobs/calendar-event-list-fetch.job'; @Injectable() export class GoogleAPIsService { constructor( - private readonly dataSourceService: DataSourceService, - private readonly typeORMService: TypeORMService, - @Inject(MessageQueue.messagingQueue) + @InjectWorkspaceDatasource() + private readonly workspaceDataSource: WorkspaceDataSource, + @InjectMessageQueue(MessageQueue.messagingQueue) private readonly messageQueueService: MessageQueueService, - @Inject(MessageQueue.calendarQueue) + @InjectMessageQueue(MessageQueue.calendarQueue) private readonly calendarQueueService: MessageQueueService, private readonly environmentService: EnvironmentService, @InjectObjectMetadataRepository(ConnectedAccountWorkspaceEntity) private readonly connectedAccountRepository: ConnectedAccountRepository, @InjectObjectMetadataRepository(MessageChannelWorkspaceEntity) private readonly messageChannelRepository: MessageChannelRepository, - @InjectObjectMetadataRepository(CalendarChannelWorkspaceEntity) - private readonly calendarChannelRepository: CalendarChannelRepository, + @InjectWorkspaceRepository(CalendarChannelWorkspaceEntity) + private readonly calendarChannelRepository: WorkspaceRepository<CalendarChannelWorkspaceEntity>, ) {} async refreshGoogleRefreshToken(input: { @@ -70,14 +72,6 @@ export class GoogleAPIsService { messageVisibility, } = input; - const dataSourceMetadata = - await this.dataSourceService.getLastDataSourceMetadataFromWorkspaceIdOrFail( - workspaceId, - ); - - const workspaceDataSource = - await this.typeORMService.connectToDataSource(dataSourceMetadata); - const isCalendarEnabled = this.environmentService.get( 'CALENDAR_PROVIDER_GOOGLE_ENABLED', ); @@ -92,65 +86,67 @@ export class GoogleAPIsService { const existingAccountId = connectedAccounts?.[0]?.id; const newOrExistingConnectedAccountId = existingAccountId ?? v4(); - await workspaceDataSource?.transaction(async (manager: EntityManager) => { - if (!existingAccountId) { - await this.connectedAccountRepository.create( - { - id: newOrExistingConnectedAccountId, - handle, - provider: ConnectedAccountProvider.GOOGLE, - accessToken: input.accessToken, - refreshToken: input.refreshToken, - accountOwnerId: workspaceMemberId, - }, - workspaceId, - manager, - ); - - await this.messageChannelRepository.create( - { - id: v4(), - connectedAccountId: newOrExistingConnectedAccountId, - type: MessageChannelType.EMAIL, - handle, - visibility: - messageVisibility || MessageChannelVisibility.SHARE_EVERYTHING, - syncStatus: MessageChannelSyncStatus.ONGOING, - }, - workspaceId, - manager, - ); + await this.workspaceDataSource.transaction( + async (manager: EntityManager) => { + if (!existingAccountId) { + await this.connectedAccountRepository.create( + { + id: newOrExistingConnectedAccountId, + handle, + provider: ConnectedAccountProvider.GOOGLE, + accessToken: input.accessToken, + refreshToken: input.refreshToken, + accountOwnerId: workspaceMemberId, + }, + workspaceId, + manager, + ); - if (isCalendarEnabled) { - await this.calendarChannelRepository.create( + await this.messageChannelRepository.create( { id: v4(), connectedAccountId: newOrExistingConnectedAccountId, + type: MessageChannelType.EMAIL, handle, visibility: - calendarVisibility || - CalendarChannelVisibility.SHARE_EVERYTHING, + messageVisibility || MessageChannelVisibility.SHARE_EVERYTHING, + syncStatus: MessageChannelSyncStatus.ONGOING, }, workspaceId, manager, ); - } - } else { - await this.connectedAccountRepository.updateAccessTokenAndRefreshToken( - input.accessToken, - input.refreshToken, - newOrExistingConnectedAccountId, - workspaceId, - manager, - ); - await this.messageChannelRepository.resetSync( - newOrExistingConnectedAccountId, - workspaceId, - manager, - ); - } - }); + if (isCalendarEnabled) { + await this.calendarChannelRepository.save( + { + id: v4(), + connectedAccountId: newOrExistingConnectedAccountId, + handle, + visibility: + calendarVisibility || + CalendarChannelVisibility.SHARE_EVERYTHING, + }, + {}, + manager, + ); + } + } else { + await this.connectedAccountRepository.updateAccessTokenAndRefreshToken( + input.accessToken, + input.refreshToken, + newOrExistingConnectedAccountId, + workspaceId, + manager, + ); + + await this.messageChannelRepository.resetSync( + newOrExistingConnectedAccountId, + workspaceId, + manager, + ); + } + }, + ); if (this.environmentService.get('MESSAGING_PROVIDER_GMAIL_ENABLED')) { const messageChannels = @@ -170,20 +166,22 @@ export class GoogleAPIsService { } } - if ( - this.environmentService.get('CALENDAR_PROVIDER_GOOGLE_ENABLED') && - isCalendarEnabled - ) { - await this.calendarQueueService.add<GoogleCalendarSyncJobData>( - GoogleCalendarSyncJob.name, - { - workspaceId, + if (isCalendarEnabled) { + const calendarChannels = await this.calendarChannelRepository.find({ + where: { connectedAccountId: newOrExistingConnectedAccountId, }, - { - retryLimit: 2, - }, - ); + }); + + for (const calendarChannel of calendarChannels) { + await this.calendarQueueService.add<CalendarEventsImportJobData>( + CalendarEventListFetchJob.name, + { + calendarChannelId: calendarChannel.id, + workspaceId, + }, + ); + } } } } diff --git a/packages/twenty-server/src/engine/core-modules/auth/services/sign-in-up.service.spec.ts b/packages/twenty-server/src/engine/core-modules/auth/services/sign-in-up.service.spec.ts index 370bfeee8985..b6b381ec0d1e 100644 --- a/packages/twenty-server/src/engine/core-modules/auth/services/sign-in-up.service.spec.ts +++ b/packages/twenty-server/src/engine/core-modules/auth/services/sign-in-up.service.spec.ts @@ -8,6 +8,7 @@ import { EnvironmentService } from 'src/engine/integrations/environment/environm import { SignInUpService } from 'src/engine/core-modules/auth/services/sign-in-up.service'; import { FileUploadService } from 'src/engine/core-modules/file/file-upload/services/file-upload.service'; import { UserWorkspaceService } from 'src/engine/core-modules/user-workspace/user-workspace.service'; +import { WorkspaceService } from 'src/engine/core-modules/workspace/services/workspace.service'; describe('SignInUpService', () => { let service: SignInUpService; @@ -40,6 +41,10 @@ describe('SignInUpService', () => { provide: HttpService, useValue: {}, }, + { + provide: WorkspaceService, + useValue: {}, + }, ], }).compile(); diff --git a/packages/twenty-server/src/engine/core-modules/auth/services/sign-in-up.service.ts b/packages/twenty-server/src/engine/core-modules/auth/services/sign-in-up.service.ts index 3397f2603365..4dafcf12666f 100644 --- a/packages/twenty-server/src/engine/core-modules/auth/services/sign-in-up.service.ts +++ b/packages/twenty-server/src/engine/core-modules/auth/services/sign-in-up.service.ts @@ -24,6 +24,7 @@ import { FileUploadService } from 'src/engine/core-modules/file/file-upload/serv import { EnvironmentService } from 'src/engine/integrations/environment/environment.service'; import { getImageBufferFromUrl } from 'src/utils/image'; import { UserWorkspaceService } from 'src/engine/core-modules/user-workspace/user-workspace.service'; +import { WorkspaceService } from 'src/engine/core-modules/workspace/services/workspace.service'; export type SignInUpServiceInput = { email: string; @@ -44,6 +45,7 @@ export class SignInUpService { @InjectRepository(User, 'core') private readonly userRepository: Repository<User>, private readonly userWorkspaceService: UserWorkspaceService, + private readonly workspaceService: WorkspaceService, private readonly httpService: HttpService, private readonly environmentService: EnvironmentService, ) {} @@ -142,10 +144,12 @@ export class SignInUpService { ForbiddenException, ); + const isWorkspaceActivated = + await this.workspaceService.isWorkspaceActivated(workspace.id); + assert( - !this.environmentService.get('IS_BILLING_ENABLED') || - workspace.subscriptionStatus !== 'incomplete', - 'Workspace subscription status is incomplete', + isWorkspaceActivated, + 'Workspace is not ready to welcome new members', ForbiddenException, ); @@ -199,7 +203,6 @@ export class SignInUpService { displayName: '', domainName: '', inviteHash: v4(), - subscriptionStatus: 'incomplete', }); const workspace = await this.workspaceRepository.save(workspaceToCreate); diff --git a/packages/twenty-server/src/engine/core-modules/auth/services/token.service.ts b/packages/twenty-server/src/engine/core-modules/auth/services/token.service.ts index c8a8a85dfe12..85bfcebc7974 100644 --- a/packages/twenty-server/src/engine/core-modules/auth/services/token.service.ts +++ b/packages/twenty-server/src/engine/core-modules/auth/services/token.service.ts @@ -147,6 +147,7 @@ export class TokenService { async generateTransientToken( workspaceMemberId: string, + userId: string, workspaceId: string, ): Promise<AuthToken> { const secret = this.environmentService.get('LOGIN_TOKEN_SECRET'); @@ -158,6 +159,7 @@ export class TokenService { const expiresAt = addMilliseconds(new Date().getTime(), ms(expiresIn)); const jwtPayload = { sub: workspaceMemberId, + userId, workspaceId, }; @@ -234,6 +236,7 @@ export class TokenService { async verifyTransientToken(transientToken: string): Promise<{ workspaceMemberId: string; + userId: string; workspaceId: string; }> { const transientTokenSecret = @@ -243,6 +246,7 @@ export class TokenService { return { workspaceMemberId: payload.sub, + userId: payload.userId, workspaceId: payload.workspaceId, }; } diff --git a/packages/twenty-server/src/engine/core-modules/auth/strategies/google-apis-oauth-common.auth.strategy.ts b/packages/twenty-server/src/engine/core-modules/auth/strategies/google-apis-oauth-common.auth.strategy.ts new file mode 100644 index 000000000000..99bd05cab01f --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/auth/strategies/google-apis-oauth-common.auth.strategy.ts @@ -0,0 +1,41 @@ +import { PassportStrategy } from '@nestjs/passport'; +import { Injectable } from '@nestjs/common'; + +import { Strategy } from 'passport-google-oauth20'; + +import { EnvironmentService } from 'src/engine/integrations/environment/environment.service'; + +export type GoogleAPIScopeConfig = { + isCalendarEnabled?: boolean; + isMessagingAliasFetchingEnabled?: boolean; +}; + +@Injectable() +export class GoogleAPIsOauthCommonStrategy extends PassportStrategy( + Strategy, + 'google-apis', +) { + constructor( + environmentService: EnvironmentService, + scopeConfig: GoogleAPIScopeConfig, + ) { + const scopes = [ + 'email', + 'profile', + 'https://www.googleapis.com/auth/gmail.readonly', + 'https://www.googleapis.com/auth/calendar.events', + ]; + + if (scopeConfig?.isMessagingAliasFetchingEnabled) { + scopes.push('https://www.googleapis.com/auth/profile.emails.read'); + } + + super({ + clientID: environmentService.get('AUTH_GOOGLE_CLIENT_ID'), + clientSecret: environmentService.get('AUTH_GOOGLE_CLIENT_SECRET'), + callbackURL: environmentService.get('AUTH_GOOGLE_APIS_CALLBACK_URL'), + scope: scopes, + passReqToCallback: true, + }); + } +} diff --git a/packages/twenty-server/src/engine/core-modules/auth/strategies/google-apis-oauth-exchange-code-for-token.auth.strategy.ts b/packages/twenty-server/src/engine/core-modules/auth/strategies/google-apis-oauth-exchange-code-for-token.auth.strategy.ts new file mode 100644 index 000000000000..047a7f55fa01 --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/auth/strategies/google-apis-oauth-exchange-code-for-token.auth.strategy.ts @@ -0,0 +1,52 @@ +import { Injectable } from '@nestjs/common'; + +import { VerifyCallback } from 'passport-google-oauth20'; + +import { GoogleAPIsOauthCommonStrategy } from 'src/engine/core-modules/auth/strategies/google-apis-oauth-common.auth.strategy'; +import { EnvironmentService } from 'src/engine/integrations/environment/environment.service'; +import { GoogleAPIsRequest } from 'src/engine/core-modules/auth/types/google-api-request.type'; + +export type GoogleAPIScopeConfig = { + isCalendarEnabled?: boolean; + isMessagingAliasFetchingEnabled?: boolean; +}; + +@Injectable() +export class GoogleAPIsOauthExchangeCodeForTokenStrategy extends GoogleAPIsOauthCommonStrategy { + constructor( + environmentService: EnvironmentService, + scopeConfig: GoogleAPIScopeConfig, + ) { + super(environmentService, scopeConfig); + } + + async validate( + request: GoogleAPIsRequest, + accessToken: string, + refreshToken: string, + profile: any, + done: VerifyCallback, + ): Promise<void> { + const { name, emails, photos } = profile; + + const state = + typeof request.query.state === 'string' + ? JSON.parse(request.query.state) + : undefined; + + const user: GoogleAPIsRequest['user'] = { + emails, + firstName: name.givenName, + lastName: name.familyName, + picture: photos?.[0]?.value, + accessToken, + refreshToken, + transientToken: state.transientToken, + redirectLocation: state.redirectLocation, + calendarVisibility: state.calendarVisibility, + messageVisibility: state.messageVisibility, + }; + + done(null, user); + } +} diff --git a/packages/twenty-server/src/engine/core-modules/auth/strategies/google-apis-oauth-request-code.auth.strategy.ts b/packages/twenty-server/src/engine/core-modules/auth/strategies/google-apis-oauth-request-code.auth.strategy.ts new file mode 100644 index 000000000000..128ba607cd45 --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/auth/strategies/google-apis-oauth-request-code.auth.strategy.ts @@ -0,0 +1,35 @@ +import { Injectable } from '@nestjs/common'; + +import { GoogleAPIsOauthCommonStrategy } from 'src/engine/core-modules/auth/strategies/google-apis-oauth-common.auth.strategy'; +import { EnvironmentService } from 'src/engine/integrations/environment/environment.service'; + +export type GoogleAPIScopeConfig = { + isCalendarEnabled?: boolean; + isMessagingAliasFetchingEnabled?: boolean; +}; + +@Injectable() +export class GoogleAPIsOauthRequestCodeStrategy extends GoogleAPIsOauthCommonStrategy { + constructor( + environmentService: EnvironmentService, + scopeConfig: GoogleAPIScopeConfig, + ) { + super(environmentService, scopeConfig); + } + + authenticate(req: any, options: any) { + options = { + ...options, + accessType: 'offline', + prompt: 'consent', + state: JSON.stringify({ + transientToken: req.params.transientToken, + redirectLocation: req.params.redirectLocation, + calendarVisibility: req.params.calendarVisibility, + messageVisibility: req.params.messageVisibility, + }), + }; + + return super.authenticate(req, options); + } +} diff --git a/packages/twenty-server/src/engine/core-modules/auth/strategies/google-apis.auth.strategy.ts b/packages/twenty-server/src/engine/core-modules/auth/strategies/google-apis.auth.strategy.ts deleted file mode 100644 index f4e55d5c4298..000000000000 --- a/packages/twenty-server/src/engine/core-modules/auth/strategies/google-apis.auth.strategy.ts +++ /dev/null @@ -1,110 +0,0 @@ -import { PassportStrategy } from '@nestjs/passport'; -import { Injectable } from '@nestjs/common'; - -import { Strategy, VerifyCallback } from 'passport-google-oauth20'; -import { Request } from 'express'; - -import { EnvironmentService } from 'src/engine/integrations/environment/environment.service'; -import { CalendarChannelVisibility } from 'src/modules/calendar/standard-objects/calendar-channel.workspace-entity'; -import { MessageChannelVisibility } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity'; - -export type GoogleAPIsRequest = Omit< - Request, - 'user' | 'workspace' | 'cacheVersion' -> & { - user: { - firstName?: string | null; - lastName?: string | null; - email: string; - picture: string | null; - workspaceInviteHash?: string; - accessToken: string; - refreshToken: string; - transientToken: string; - redirectLocation?: string; - calendarVisibility?: CalendarChannelVisibility; - messageVisibility?: MessageChannelVisibility; - }; -}; - -export type GoogleAPIScopeConfig = { - isCalendarEnabled?: boolean; -}; - -@Injectable() -export class GoogleAPIsStrategy extends PassportStrategy( - Strategy, - 'google-apis', -) { - constructor( - environmentService: EnvironmentService, - scopeConfig: GoogleAPIScopeConfig, - ) { - const scope = ['email', 'profile']; - - if (environmentService.get('MESSAGING_PROVIDER_GMAIL_ENABLED')) { - scope.push('https://www.googleapis.com/auth/gmail.readonly'); - } - - if ( - environmentService.get('CALENDAR_PROVIDER_GOOGLE_ENABLED') && - scopeConfig?.isCalendarEnabled - ) { - scope.push('https://www.googleapis.com/auth/calendar.events'); - } - - super({ - clientID: environmentService.get('AUTH_GOOGLE_CLIENT_ID'), - clientSecret: environmentService.get('AUTH_GOOGLE_CLIENT_SECRET'), - callbackURL: environmentService.get('AUTH_GOOGLE_APIS_CALLBACK_URL'), - scope, - passReqToCallback: true, - }); - } - - authenticate(req: any, options: any) { - options = { - ...options, - accessType: 'offline', - prompt: 'consent', - state: JSON.stringify({ - transientToken: req.params.transientToken, - redirectLocation: req.params.redirectLocation, - calendarVisibility: req.params.calendarVisibility, - messageVisibility: req.params.messageVisibility, - }), - }; - - return super.authenticate(req, options); - } - - async validate( - request: GoogleAPIsRequest, - accessToken: string, - refreshToken: string, - profile: any, - done: VerifyCallback, - ): Promise<void> { - const { name, emails, photos } = profile; - - const state = - typeof request.query.state === 'string' - ? JSON.parse(request.query.state) - : undefined; - - const user: GoogleAPIsRequest['user'] = { - email: emails[0].value, - firstName: name.givenName, - lastName: name.familyName, - picture: photos?.[0]?.value, - accessToken, - refreshToken, - transientToken: state.transientToken, - redirectLocation: state.redirectLocation, - calendarVisibility: state.calendarVisibility, - messageVisibility: state.messageVisibility, - }; - - done(null, user); - } -} diff --git a/packages/twenty-server/src/engine/core-modules/auth/types/google-api-request.type.ts b/packages/twenty-server/src/engine/core-modules/auth/types/google-api-request.type.ts new file mode 100644 index 000000000000..f8d5f609d4d1 --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/auth/types/google-api-request.type.ts @@ -0,0 +1,23 @@ +import { Request } from 'express'; + +import { CalendarChannelVisibility } from 'src/modules/calendar/common/standard-objects/calendar-channel.workspace-entity'; +import { MessageChannelVisibility } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity'; + +export type GoogleAPIsRequest = Omit< + Request, + 'user' | 'workspace' | 'cacheVersion' +> & { + user: { + firstName?: string | null; + lastName?: string | null; + emails: { value: string }[]; + picture: string | null; + workspaceInviteHash?: string; + accessToken: string; + refreshToken: string; + transientToken: string; + redirectLocation?: string; + calendarVisibility?: CalendarChannelVisibility; + messageVisibility?: MessageChannelVisibility; + }; +}; diff --git a/packages/twenty-server/src/engine/core-modules/auth/utils/__tests__/google-apis-set-request-extra-params.util.spec.ts b/packages/twenty-server/src/engine/core-modules/auth/utils/__tests__/google-apis-set-request-extra-params.util.spec.ts new file mode 100644 index 000000000000..052f4ff04d3a --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/auth/utils/__tests__/google-apis-set-request-extra-params.util.spec.ts @@ -0,0 +1,40 @@ +import { GoogleAPIsRequest } from 'src/engine/core-modules/auth/types/google-api-request.type'; +import { setRequestExtraParams } from 'src/engine/core-modules/auth/utils/google-apis-set-request-extra-params.util'; +import { CalendarChannelVisibility } from 'src/modules/calendar/common/standard-objects/calendar-channel.workspace-entity'; +import { MessageChannelVisibility } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity'; + +describe('googleApisSetRequestExtraParams', () => { + it('should set request extra params', () => { + const request = { + params: {}, + } as GoogleAPIsRequest; + + setRequestExtraParams(request, { + transientToken: 'abc', + redirectLocation: '/test', + calendarVisibility: CalendarChannelVisibility.SHARE_EVERYTHING, + messageVisibility: MessageChannelVisibility.SHARE_EVERYTHING, + }); + + expect(request.params).toEqual({ + transientToken: 'abc', + redirectLocation: '/test', + calendarVisibility: CalendarChannelVisibility.SHARE_EVERYTHING, + messageVisibility: MessageChannelVisibility.SHARE_EVERYTHING, + }); + }); + + it('should throw error if transientToken is not provided', () => { + const request = { + params: {}, + } as GoogleAPIsRequest; + + expect(() => { + setRequestExtraParams(request, { + redirectLocation: '/test', + calendarVisibility: CalendarChannelVisibility.SHARE_EVERYTHING, + messageVisibility: MessageChannelVisibility.SHARE_EVERYTHING, + }); + }).toThrow('transientToken is required'); + }); +}); diff --git a/packages/twenty-server/src/engine/core-modules/auth/utils/google-apis-set-request-extra-params.util.ts b/packages/twenty-server/src/engine/core-modules/auth/utils/google-apis-set-request-extra-params.util.ts new file mode 100644 index 000000000000..668426c23bc1 --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/auth/utils/google-apis-set-request-extra-params.util.ts @@ -0,0 +1,38 @@ +import { GoogleAPIsRequest } from 'src/engine/core-modules/auth/types/google-api-request.type'; + +type GoogleAPIsRequestExtraParams = { + transientToken?: string; + redirectLocation?: string; + calendarVisibility?: string; + messageVisibility?: string; +}; + +export const setRequestExtraParams = ( + request: GoogleAPIsRequest, + params: GoogleAPIsRequestExtraParams, +): void => { + const { + transientToken, + redirectLocation, + calendarVisibility, + messageVisibility, + } = params; + + if (!transientToken) { + throw new Error('transientToken is required'); + } + + request.params.transientToken = transientToken; + + if (redirectLocation) { + request.params.redirectLocation = redirectLocation; + } + + if (calendarVisibility) { + request.params.calendarVisibility = calendarVisibility; + } + + if (messageVisibility) { + request.params.messageVisibility = messageVisibility; + } +}; diff --git a/packages/twenty-server/src/engine/core-modules/billing/billing.controller.ts b/packages/twenty-server/src/engine/core-modules/billing/billing.controller.ts index 775604f7d295..4e71805b9c93 100644 --- a/packages/twenty-server/src/engine/core-modules/billing/billing.controller.ts +++ b/packages/twenty-server/src/engine/core-modules/billing/billing.controller.ts @@ -11,9 +11,9 @@ import { import { Response } from 'express'; import { - BillingService, + BillingWorkspaceService, WebhookEvent, -} from 'src/engine/core-modules/billing/billing.service'; +} from 'src/engine/core-modules/billing/billing.workspace-service'; import { StripeService } from 'src/engine/core-modules/billing/stripe/stripe.service'; @Controller('billing') @@ -22,7 +22,7 @@ export class BillingController { constructor( private readonly stripeService: StripeService, - private readonly billingService: BillingService, + private readonly billingWorkspaceService: BillingWorkspaceService, ) {} @Post('/webhooks') @@ -42,7 +42,7 @@ export class BillingController { ); if (event.type === WebhookEvent.SETUP_INTENT_SUCCEEDED) { - await this.billingService.handleUnpaidInvoices(event.data); + await this.billingWorkspaceService.handleUnpaidInvoices(event.data); } if ( @@ -58,7 +58,7 @@ export class BillingController { return; } - await this.billingService.upsertBillingSubscription( + await this.billingWorkspaceService.upsertBillingSubscription( workspaceId, event.data, ); diff --git a/packages/twenty-server/src/engine/core-modules/billing/billing.module.ts b/packages/twenty-server/src/engine/core-modules/billing/billing.module.ts index 4be921b78c04..a4462607a737 100644 --- a/packages/twenty-server/src/engine/core-modules/billing/billing.module.ts +++ b/packages/twenty-server/src/engine/core-modules/billing/billing.module.ts @@ -10,18 +10,30 @@ import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; import { BillingResolver } from 'src/engine/core-modules/billing/billing.resolver'; import { BillingWorkspaceMemberListener } from 'src/engine/core-modules/billing/listeners/billing-workspace-member.listener'; import { UserWorkspaceModule } from 'src/engine/core-modules/user-workspace/user-workspace.module'; +import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity'; +import { BillingWorkspaceService } from 'src/engine/core-modules/billing/billing.workspace-service'; @Module({ imports: [ StripeModule, UserWorkspaceModule, TypeOrmModule.forFeature( - [BillingSubscription, BillingSubscriptionItem, Workspace], + [ + BillingSubscription, + BillingSubscriptionItem, + Workspace, + FeatureFlagEntity, + ], 'core', ), ], controllers: [BillingController], - providers: [BillingService, BillingResolver, BillingWorkspaceMemberListener], - exports: [BillingService], + providers: [ + BillingService, + BillingWorkspaceService, + BillingResolver, + BillingWorkspaceMemberListener, + ], + exports: [BillingService, BillingWorkspaceService], }) export class BillingModule {} diff --git a/packages/twenty-server/src/engine/core-modules/billing/billing.resolver.ts b/packages/twenty-server/src/engine/core-modules/billing/billing.resolver.ts index 8766c4adc37e..40c90fbc2cea 100644 --- a/packages/twenty-server/src/engine/core-modules/billing/billing.resolver.ts +++ b/packages/twenty-server/src/engine/core-modules/billing/billing.resolver.ts @@ -3,8 +3,8 @@ import { UseGuards } from '@nestjs/common'; import { AvailableProduct, - BillingService, -} from 'src/engine/core-modules/billing/billing.service'; + BillingWorkspaceService, +} from 'src/engine/core-modules/billing/billing.workspace-service'; import { ProductInput } from 'src/engine/core-modules/billing/dto/product.input'; import { assert } from 'src/utils/assert'; import { ProductPricesEntity } from 'src/engine/core-modules/billing/dto/product-prices.entity'; @@ -18,11 +18,14 @@ import { UpdateBillingEntity } from 'src/engine/core-modules/billing/dto/update- @Resolver() export class BillingResolver { - constructor(private readonly billingService: BillingService) {} + constructor( + private readonly billingWorkspaceService: BillingWorkspaceService, + ) {} @Query(() => ProductPricesEntity) async getProductPrices(@Args() { product }: ProductInput) { - const stripeProductId = this.billingService.getProductStripeId(product); + const stripeProductId = + this.billingWorkspaceService.getProductStripeId(product); assert( stripeProductId, @@ -32,7 +35,7 @@ export class BillingResolver { ); const productPrices = - await this.billingService.getProductPrices(stripeProductId); + await this.billingWorkspaceService.getProductPrices(stripeProductId); return { totalNumberOfPrices: productPrices.length, @@ -47,7 +50,7 @@ export class BillingResolver { @Args() { returnUrlPath }: BillingSessionInput, ) { return { - url: await this.billingService.computeBillingPortalSessionURL( + url: await this.billingWorkspaceService.computeBillingPortalSessionURL( user.defaultWorkspaceId, returnUrlPath, ), @@ -60,7 +63,7 @@ export class BillingResolver { @AuthUser() user: User, @Args() { recurringInterval, successUrlPath }: CheckoutSessionInput, ) { - const stripeProductId = this.billingService.getProductStripeId( + const stripeProductId = this.billingWorkspaceService.getProductStripeId( AvailableProduct.BasePlan, ); @@ -70,7 +73,7 @@ export class BillingResolver { ); const productPrices = - await this.billingService.getProductPrices(stripeProductId); + await this.billingWorkspaceService.getProductPrices(stripeProductId); const stripePriceId = productPrices.filter( (price) => price.recurringInterval === recurringInterval, @@ -82,7 +85,7 @@ export class BillingResolver { ); return { - url: await this.billingService.computeCheckoutSessionURL( + url: await this.billingWorkspaceService.computeCheckoutSessionURL( user, stripePriceId, successUrlPath, @@ -93,7 +96,7 @@ export class BillingResolver { @Mutation(() => UpdateBillingEntity) @UseGuards(JwtAuthGuard) async updateBillingSubscription(@AuthUser() user: User) { - await this.billingService.updateBillingSubscription(user); + await this.billingWorkspaceService.updateBillingSubscription(user); return { success: true }; } diff --git a/packages/twenty-server/src/engine/core-modules/billing/billing.service.ts b/packages/twenty-server/src/engine/core-modules/billing/billing.service.ts index 8228788f4637..34cae6a376e4 100644 --- a/packages/twenty-server/src/engine/core-modules/billing/billing.service.ts +++ b/packages/twenty-server/src/engine/core-modules/billing/billing.service.ts @@ -1,308 +1,71 @@ import { Injectable, Logger } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; -import Stripe from 'stripe'; -import { Not, Repository } from 'typeorm'; +import { In, Repository } from 'typeorm'; import { EnvironmentService } from 'src/engine/integrations/environment/environment.service'; -import { StripeService } from 'src/engine/core-modules/billing/stripe/stripe.service'; -import { BillingSubscription } from 'src/engine/core-modules/billing/entities/billing-subscription.entity'; -import { BillingSubscriptionItem } from 'src/engine/core-modules/billing/entities/billing-subscription-item.entity'; +import { + BillingSubscription, + SubscriptionStatus, +} from 'src/engine/core-modules/billing/entities/billing-subscription.entity'; import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; -import { ProductPriceEntity } from 'src/engine/core-modules/billing/dto/product-price.entity'; -import { User } from 'src/engine/core-modules/user/user.entity'; -import { assert } from 'src/utils/assert'; -import { UserWorkspaceService } from 'src/engine/core-modules/user-workspace/user-workspace.service'; - -export enum AvailableProduct { - BasePlan = 'base-plan', -} - -export enum WebhookEvent { - CUSTOMER_SUBSCRIPTION_CREATED = 'customer.subscription.created', - CUSTOMER_SUBSCRIPTION_UPDATED = 'customer.subscription.updated', - CUSTOMER_SUBSCRIPTION_DELETED = 'customer.subscription.deleted', - SETUP_INTENT_SUCCEEDED = 'setup_intent.succeeded', -} +import { + FeatureFlagEntity, + FeatureFlagKeys, +} from 'src/engine/core-modules/feature-flag/feature-flag.entity'; @Injectable() export class BillingService { protected readonly logger = new Logger(BillingService.name); constructor( - private readonly stripeService: StripeService, - private readonly userWorkspaceService: UserWorkspaceService, private readonly environmentService: EnvironmentService, @InjectRepository(BillingSubscription, 'core') private readonly billingSubscriptionRepository: Repository<BillingSubscription>, - @InjectRepository(BillingSubscriptionItem, 'core') - private readonly billingSubscriptionItemRepository: Repository<BillingSubscriptionItem>, + @InjectRepository(FeatureFlagEntity, 'core') + private readonly featureFlagRepository: Repository<FeatureFlagEntity>, @InjectRepository(Workspace, 'core') private readonly workspaceRepository: Repository<Workspace>, ) {} - getProductStripeId(product: AvailableProduct) { - if (product === AvailableProduct.BasePlan) { - return this.environmentService.get('BILLING_STRIPE_BASE_PLAN_PRODUCT_ID'); - } - } - - async getProductPrices(stripeProductId: string) { - const productPrices = - await this.stripeService.getProductPrices(stripeProductId); - - return this.formatProductPrices(productPrices.data); - } - - formatProductPrices(prices: Stripe.Price[]) { - const result: Record<string, ProductPriceEntity> = {}; - - prices.forEach((item) => { - const interval = item.recurring?.interval; - - if (!interval || !item.unit_amount) { - return; - } - if ( - !result[interval] || - item.created > (result[interval]?.created || 0) - ) { - result[interval] = { - unitAmount: item.unit_amount, - recurringInterval: interval, - created: item.created, - stripePriceId: item.id, - }; - } - }); - - return Object.values(result).sort((a, b) => a.unitAmount - b.unitAmount); - } - - async getCurrentBillingSubscription(criteria: { - workspaceId?: string; - stripeCustomerId?: string; - }) { - const notCanceledSubscriptions = - await this.billingSubscriptionRepository.find({ - where: { ...criteria, status: Not('canceled') }, - relations: ['billingSubscriptionItems'], - }); - - assert( - notCanceledSubscriptions.length <= 1, - `More than on not canceled subscription for workspace ${criteria.workspaceId}`, - ); - - return notCanceledSubscriptions?.[0]; - } - - async getBillingSubscription(stripeSubscriptionId: string) { - return this.billingSubscriptionRepository.findOneOrFail({ - where: { stripeSubscriptionId }, - }); - } - - async getStripeCustomerId(workspaceId: string) { - const subscriptions = await this.billingSubscriptionRepository.find({ - where: { workspaceId }, - }); - - return subscriptions?.[0]?.stripeCustomerId; - } - - async getBillingSubscriptionItem( - workspaceId: string, - stripeProductId = this.environmentService.get( - 'BILLING_STRIPE_BASE_PLAN_PRODUCT_ID', - ), - ) { - const billingSubscription = await this.getCurrentBillingSubscription({ - workspaceId, - }); - - if (!billingSubscription) { - throw new Error( - `Cannot find billingSubscriptionItem for product ${stripeProductId} for workspace ${workspaceId}`, - ); - } - - const billingSubscriptionItem = - billingSubscription.billingSubscriptionItems.filter( - (billingSubscriptionItem) => - billingSubscriptionItem.stripeProductId === stripeProductId, - )?.[0]; - - if (!billingSubscriptionItem) { - throw new Error( - `Cannot find billingSubscriptionItem for product ${stripeProductId} for workspace ${workspaceId}`, + async getActiveSubscriptionWorkspaceIds() { + if (!this.environmentService.get('IS_BILLING_ENABLED')) { + return (await this.workspaceRepository.find({ select: ['id'] })).map( + (workspace) => workspace.id, ); } - return billingSubscriptionItem; - } - - async computeBillingPortalSessionURL( - workspaceId: string, - returnUrlPath?: string, - ) { - const stripeCustomerId = await this.getStripeCustomerId(workspaceId); - - if (!stripeCustomerId) { - return; - } - - const frontBaseUrl = this.environmentService.get('FRONT_BASE_URL'); - const returnUrl = returnUrlPath - ? frontBaseUrl + returnUrlPath - : frontBaseUrl; - - const session = await this.stripeService.createBillingPortalSession( - stripeCustomerId, - returnUrl, - ); - - assert(session.url, 'Error: missing billingPortal.session.url'); - - return session.url; - } - - async updateBillingSubscription(user: User) { - const billingSubscription = await this.getCurrentBillingSubscription({ - workspaceId: user.defaultWorkspaceId, - }); - const newInterval = - billingSubscription?.interval === 'year' ? 'month' : 'year'; - const billingSubscriptionItem = await this.getBillingSubscriptionItem( - user.defaultWorkspaceId, - ); - const stripeProductId = this.getProductStripeId(AvailableProduct.BasePlan); - - if (!stripeProductId) { - throw new Error('Stripe product id not found for basePlan'); - } - const productPrices = await this.getProductPrices(stripeProductId); - - const stripePriceId = productPrices.filter( - (price) => price.recurringInterval === newInterval, - )?.[0]?.stripePriceId; - - await this.stripeService.updateBillingSubscriptionItem( - billingSubscriptionItem, - stripePriceId, - ); - } - - async computeCheckoutSessionURL( - user: User, - priceId: string, - successUrlPath?: string, - ): Promise<string> { - const frontBaseUrl = this.environmentService.get('FRONT_BASE_URL'); - const successUrl = successUrlPath - ? frontBaseUrl + successUrlPath - : frontBaseUrl; - - const quantity = - (await this.userWorkspaceService.getWorkspaceMemberCount( - user.defaultWorkspaceId, - )) || 1; - - const stripeCustomerId = ( - await this.billingSubscriptionRepository.findOneBy({ - workspaceId: user.defaultWorkspaceId, - }) - )?.stripeCustomerId; - - const session = await this.stripeService.createCheckoutSession( - user, - priceId, - quantity, - successUrl, - frontBaseUrl, - stripeCustomerId, - ); - - assert(session.url, 'Error: missing checkout.session.url'); - - return session.url; - } - - async deleteSubscription(workspaceId: string) { - const subscriptionToCancel = await this.getCurrentBillingSubscription({ - workspaceId, - }); - - if (subscriptionToCancel) { - await this.stripeService.cancelSubscription( - subscriptionToCancel.stripeSubscriptionId, - ); - await this.billingSubscriptionRepository.delete(subscriptionToCancel.id); - } - } - - async handleUnpaidInvoices(data: Stripe.SetupIntentSucceededEvent.Data) { - const billingSubscription = await this.getCurrentBillingSubscription({ - stripeCustomerId: data.object.customer as string, - }); - - if (billingSubscription?.status === 'unpaid') { - await this.stripeService.collectLastInvoice( - billingSubscription.stripeSubscriptionId, - ); - } - } - - async upsertBillingSubscription( - workspaceId: string, - data: - | Stripe.CustomerSubscriptionUpdatedEvent.Data - | Stripe.CustomerSubscriptionCreatedEvent.Data - | Stripe.CustomerSubscriptionDeletedEvent.Data, - ) { - const workspace = this.workspaceRepository.find({ - where: { id: workspaceId }, + const activeSubscriptions = await this.billingSubscriptionRepository.find({ + where: { + status: In([ + SubscriptionStatus.Active, + SubscriptionStatus.Trialing, + SubscriptionStatus.PastDue, + ]), + }, + select: ['workspaceId'], }); - if (!workspace) { - return; - } - - await this.workspaceRepository.update(workspaceId, { - subscriptionStatus: data.object.status, + const freeAccessFeatureFlags = await this.featureFlagRepository.find({ + where: { + key: FeatureFlagKeys.IsFreeAccessEnabled, + value: true, + }, + select: ['workspaceId'], }); - await this.billingSubscriptionRepository.upsert( - { - workspaceId: workspaceId, - stripeCustomerId: data.object.customer as string, - stripeSubscriptionId: data.object.id, - status: data.object.status, - interval: data.object.items.data[0].plan.interval, - }, - { - conflictPaths: ['stripeSubscriptionId'], - skipUpdateIfNoValuesChanged: true, - }, + const activeWorkspaceIdsBasedOnSubscriptions = activeSubscriptions.map( + (subscription) => subscription.workspaceId, ); - const billingSubscription = await this.getBillingSubscription( - data.object.id, + const activeWorkspaceIdsBasedOnFeatureFlags = freeAccessFeatureFlags.map( + (featureFlag) => featureFlag.workspaceId, ); - await this.billingSubscriptionItemRepository.upsert( - data.object.items.data.map((item) => { - return { - billingSubscriptionId: billingSubscription.id, - stripeProductId: item.price.product as string, - stripePriceId: item.price.id, - stripeSubscriptionItemId: item.id, - quantity: item.quantity, - }; - }), - { - conflictPaths: ['billingSubscriptionId', 'stripeProductId'], - skipUpdateIfNoValuesChanged: true, - }, + return Array.from( + new Set([ + ...activeWorkspaceIdsBasedOnSubscriptions, + ...activeWorkspaceIdsBasedOnFeatureFlags, + ]), ); } } diff --git a/packages/twenty-server/src/engine/core-modules/billing/billing.workspace-service.ts b/packages/twenty-server/src/engine/core-modules/billing/billing.workspace-service.ts new file mode 100644 index 000000000000..d912751ea7e6 --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/billing/billing.workspace-service.ts @@ -0,0 +1,332 @@ +import { Injectable, Logger } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; + +import Stripe from 'stripe'; +import { Not, Repository } from 'typeorm'; + +import { EnvironmentService } from 'src/engine/integrations/environment/environment.service'; +import { StripeService } from 'src/engine/core-modules/billing/stripe/stripe.service'; +import { + BillingSubscription, + SubscriptionInterval, + SubscriptionStatus, +} from 'src/engine/core-modules/billing/entities/billing-subscription.entity'; +import { BillingSubscriptionItem } from 'src/engine/core-modules/billing/entities/billing-subscription-item.entity'; +import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; +import { ProductPriceEntity } from 'src/engine/core-modules/billing/dto/product-price.entity'; +import { User } from 'src/engine/core-modules/user/user.entity'; +import { assert } from 'src/utils/assert'; +import { UserWorkspaceService } from 'src/engine/core-modules/user-workspace/user-workspace.service'; +import { + FeatureFlagEntity, + FeatureFlagKeys, +} from 'src/engine/core-modules/feature-flag/feature-flag.entity'; +import { BillingService } from 'src/engine/core-modules/billing/billing.service'; + +export enum AvailableProduct { + BasePlan = 'base-plan', +} + +export enum WebhookEvent { + CUSTOMER_SUBSCRIPTION_CREATED = 'customer.subscription.created', + CUSTOMER_SUBSCRIPTION_UPDATED = 'customer.subscription.updated', + CUSTOMER_SUBSCRIPTION_DELETED = 'customer.subscription.deleted', + SETUP_INTENT_SUCCEEDED = 'setup_intent.succeeded', +} + +@Injectable() +export class BillingWorkspaceService { + protected readonly logger = new Logger(BillingService.name); + constructor( + private readonly stripeService: StripeService, + private readonly userWorkspaceService: UserWorkspaceService, + private readonly environmentService: EnvironmentService, + @InjectRepository(BillingSubscription, 'core') + private readonly billingSubscriptionRepository: Repository<BillingSubscription>, + @InjectRepository(FeatureFlagEntity, 'core') + private readonly featureFlagRepository: Repository<FeatureFlagEntity>, + @InjectRepository(BillingSubscriptionItem, 'core') + private readonly billingSubscriptionItemRepository: Repository<BillingSubscriptionItem>, + @InjectRepository(Workspace, 'core') + private readonly workspaceRepository: Repository<Workspace>, + ) {} + + async isBillingEnabledForWorkspace(workspaceId: string) { + const isFreeAccessEnabled = await this.featureFlagRepository.findOneBy({ + workspaceId, + key: FeatureFlagKeys.IsFreeAccessEnabled, + value: true, + }); + + return ( + !isFreeAccessEnabled && this.environmentService.get('IS_BILLING_ENABLED') + ); + } + + getProductStripeId(product: AvailableProduct) { + if (product === AvailableProduct.BasePlan) { + return this.environmentService.get('BILLING_STRIPE_BASE_PLAN_PRODUCT_ID'); + } + } + + async getProductPrices(stripeProductId: string) { + const productPrices = + await this.stripeService.getProductPrices(stripeProductId); + + return this.formatProductPrices(productPrices.data); + } + + formatProductPrices(prices: Stripe.Price[]) { + const result: Record<string, ProductPriceEntity> = {}; + + prices.forEach((item) => { + const interval = item.recurring?.interval; + + if (!interval || !item.unit_amount) { + return; + } + if ( + !result[interval] || + item.created > (result[interval]?.created || 0) + ) { + result[interval] = { + unitAmount: item.unit_amount, + recurringInterval: interval, + created: item.created, + stripePriceId: item.id, + }; + } + }); + + return Object.values(result).sort((a, b) => a.unitAmount - b.unitAmount); + } + + async getCurrentBillingSubscription(criteria: { + workspaceId?: string; + stripeCustomerId?: string; + }) { + const notCanceledSubscriptions = + await this.billingSubscriptionRepository.find({ + where: { ...criteria, status: Not(SubscriptionStatus.Canceled) }, + relations: ['billingSubscriptionItems'], + }); + + assert( + notCanceledSubscriptions.length <= 1, + `More than one not canceled subscription for workspace ${criteria.workspaceId}`, + ); + + return notCanceledSubscriptions?.[0]; + } + + async getBillingSubscription(stripeSubscriptionId: string) { + return this.billingSubscriptionRepository.findOneOrFail({ + where: { stripeSubscriptionId }, + }); + } + + async getStripeCustomerId(workspaceId: string) { + const subscriptions = await this.billingSubscriptionRepository.find({ + where: { workspaceId }, + }); + + return subscriptions?.[0]?.stripeCustomerId; + } + + async getBillingSubscriptionItem( + workspaceId: string, + stripeProductId = this.environmentService.get( + 'BILLING_STRIPE_BASE_PLAN_PRODUCT_ID', + ), + ) { + const billingSubscription = await this.getCurrentBillingSubscription({ + workspaceId, + }); + + if (!billingSubscription) { + throw new Error( + `Cannot find billingSubscriptionItem for product ${stripeProductId} for workspace ${workspaceId}`, + ); + } + + const billingSubscriptionItem = + billingSubscription.billingSubscriptionItems.filter( + (billingSubscriptionItem) => + billingSubscriptionItem.stripeProductId === stripeProductId, + )?.[0]; + + if (!billingSubscriptionItem) { + throw new Error( + `Cannot find billingSubscriptionItem for product ${stripeProductId} for workspace ${workspaceId}`, + ); + } + + return billingSubscriptionItem; + } + + async computeBillingPortalSessionURL( + workspaceId: string, + returnUrlPath?: string, + ) { + const stripeCustomerId = await this.getStripeCustomerId(workspaceId); + + if (!stripeCustomerId) { + return; + } + + const frontBaseUrl = this.environmentService.get('FRONT_BASE_URL'); + const returnUrl = returnUrlPath + ? frontBaseUrl + returnUrlPath + : frontBaseUrl; + + const session = await this.stripeService.createBillingPortalSession( + stripeCustomerId, + returnUrl, + ); + + assert(session.url, 'Error: missing billingPortal.session.url'); + + return session.url; + } + + async updateBillingSubscription(user: User) { + const billingSubscription = await this.getCurrentBillingSubscription({ + workspaceId: user.defaultWorkspaceId, + }); + const newInterval = + billingSubscription?.interval === SubscriptionInterval.Year + ? SubscriptionInterval.Month + : SubscriptionInterval.Year; + const billingSubscriptionItem = await this.getBillingSubscriptionItem( + user.defaultWorkspaceId, + ); + const stripeProductId = this.getProductStripeId(AvailableProduct.BasePlan); + + if (!stripeProductId) { + throw new Error('Stripe product id not found for basePlan'); + } + const productPrices = await this.getProductPrices(stripeProductId); + + const stripePriceId = productPrices.filter( + (price) => price.recurringInterval === newInterval, + )?.[0]?.stripePriceId; + + await this.stripeService.updateBillingSubscriptionItem( + billingSubscriptionItem, + stripePriceId, + ); + } + + async computeCheckoutSessionURL( + user: User, + priceId: string, + successUrlPath?: string, + ): Promise<string> { + const frontBaseUrl = this.environmentService.get('FRONT_BASE_URL'); + const successUrl = successUrlPath + ? frontBaseUrl + successUrlPath + : frontBaseUrl; + + const quantity = + (await this.userWorkspaceService.getWorkspaceMemberCount()) || 1; + + const stripeCustomerId = ( + await this.billingSubscriptionRepository.findOneBy({ + workspaceId: user.defaultWorkspaceId, + }) + )?.stripeCustomerId; + + const session = await this.stripeService.createCheckoutSession( + user, + priceId, + quantity, + successUrl, + frontBaseUrl, + stripeCustomerId, + ); + + assert(session.url, 'Error: missing checkout.session.url'); + + return session.url; + } + + async deleteSubscription(workspaceId: string) { + const subscriptionToCancel = await this.getCurrentBillingSubscription({ + workspaceId, + }); + + if (subscriptionToCancel) { + await this.stripeService.cancelSubscription( + subscriptionToCancel.stripeSubscriptionId, + ); + await this.billingSubscriptionRepository.delete(subscriptionToCancel.id); + } + } + + async handleUnpaidInvoices(data: Stripe.SetupIntentSucceededEvent.Data) { + const billingSubscription = await this.getCurrentBillingSubscription({ + stripeCustomerId: data.object.customer as string, + }); + + if (billingSubscription?.status === 'unpaid') { + await this.stripeService.collectLastInvoice( + billingSubscription.stripeSubscriptionId, + ); + } + } + + async upsertBillingSubscription( + workspaceId: string, + data: + | Stripe.CustomerSubscriptionUpdatedEvent.Data + | Stripe.CustomerSubscriptionCreatedEvent.Data + | Stripe.CustomerSubscriptionDeletedEvent.Data, + ) { + const workspace = this.workspaceRepository.find({ + where: { id: workspaceId }, + }); + + if (!workspace) { + return; + } + + await this.billingSubscriptionRepository.upsert( + { + workspaceId: workspaceId, + stripeCustomerId: data.object.customer as string, + stripeSubscriptionId: data.object.id, + status: data.object.status, + interval: data.object.items.data[0].plan.interval, + }, + { + conflictPaths: ['stripeSubscriptionId'], + skipUpdateIfNoValuesChanged: true, + }, + ); + + const billingSubscription = await this.getBillingSubscription( + data.object.id, + ); + + await this.billingSubscriptionItemRepository.upsert( + data.object.items.data.map((item) => { + return { + billingSubscriptionId: billingSubscription.id, + stripeProductId: item.price.product as string, + stripePriceId: item.price.id, + stripeSubscriptionItemId: item.id, + quantity: item.quantity, + }; + }), + { + conflictPaths: ['billingSubscriptionId', 'stripeProductId'], + skipUpdateIfNoValuesChanged: true, + }, + ); + + await this.featureFlagRepository.delete({ + workspaceId, + key: FeatureFlagKeys.IsFreeAccessEnabled, + }); + } +} diff --git a/packages/twenty-server/src/engine/core-modules/billing/dto/checkout-session.input.ts b/packages/twenty-server/src/engine/core-modules/billing/dto/checkout-session.input.ts index 778f0671ee6c..48738b85f8dd 100644 --- a/packages/twenty-server/src/engine/core-modules/billing/dto/checkout-session.input.ts +++ b/packages/twenty-server/src/engine/core-modules/billing/dto/checkout-session.input.ts @@ -3,9 +3,11 @@ import { ArgsType, Field } from '@nestjs/graphql'; import { IsNotEmpty, IsOptional, IsString } from 'class-validator'; import Stripe from 'stripe'; +import { SubscriptionInterval } from 'src/engine/core-modules/billing/entities/billing-subscription.entity'; + @ArgsType() export class CheckoutSessionInput { - @Field(() => String) + @Field(() => SubscriptionInterval) @IsString() @IsNotEmpty() recurringInterval: Stripe.Price.Recurring.Interval; diff --git a/packages/twenty-server/src/engine/core-modules/billing/dto/product-price.entity.ts b/packages/twenty-server/src/engine/core-modules/billing/dto/product-price.entity.ts index 69fc80011f3c..d8c2d6d434f3 100644 --- a/packages/twenty-server/src/engine/core-modules/billing/dto/product-price.entity.ts +++ b/packages/twenty-server/src/engine/core-modules/billing/dto/product-price.entity.ts @@ -2,9 +2,11 @@ import { Field, ObjectType } from '@nestjs/graphql'; import Stripe from 'stripe'; +import { SubscriptionInterval } from 'src/engine/core-modules/billing/entities/billing-subscription.entity'; + @ObjectType() export class ProductPriceEntity { - @Field(() => String) + @Field(() => SubscriptionInterval) recurringInterval: Stripe.Price.Recurring.Interval; @Field(() => Number) diff --git a/packages/twenty-server/src/engine/core-modules/billing/dto/product.input.ts b/packages/twenty-server/src/engine/core-modules/billing/dto/product.input.ts index 089d18ba0e05..1bab951e2eb1 100644 --- a/packages/twenty-server/src/engine/core-modules/billing/dto/product.input.ts +++ b/packages/twenty-server/src/engine/core-modules/billing/dto/product.input.ts @@ -2,7 +2,7 @@ import { ArgsType, Field } from '@nestjs/graphql'; import { IsNotEmpty, IsString } from 'class-validator'; -import { AvailableProduct } from 'src/engine/core-modules/billing/billing.service'; +import { AvailableProduct } from 'src/engine/core-modules/billing/billing.workspace-service'; @ArgsType() export class ProductInput { diff --git a/packages/twenty-server/src/engine/core-modules/billing/entities/billing-subscription.entity.ts b/packages/twenty-server/src/engine/core-modules/billing/entities/billing-subscription.entity.ts index 4da2b3ef5688..509d5250b265 100644 --- a/packages/twenty-server/src/engine/core-modules/billing/entities/billing-subscription.entity.ts +++ b/packages/twenty-server/src/engine/core-modules/billing/entities/billing-subscription.entity.ts @@ -1,4 +1,4 @@ -import { Field, ObjectType } from '@nestjs/graphql'; +import { Field, ObjectType, registerEnumType } from '@nestjs/graphql'; import { Column, @@ -18,6 +18,27 @@ import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; import { BillingSubscriptionItem } from 'src/engine/core-modules/billing/entities/billing-subscription-item.entity'; import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars'; +export enum SubscriptionStatus { + Active = 'active', + Canceled = 'canceled', + Incomplete = 'incomplete', + IncompleteExpired = 'incomplete_expired', + PastDue = 'past_due', + Paused = 'paused', + Trialing = 'trialing', + Unpaid = 'unpaid', +} + +export enum SubscriptionInterval { + Day = 'day', + Month = 'month', + Week = 'week', + Year = 'year', +} + +registerEnumType(SubscriptionStatus, { name: 'SubscriptionStatus' }); +registerEnumType(SubscriptionInterval, { name: 'SubscriptionInterval' }); + @Entity({ name: 'billingSubscription', schema: 'core' }) @ObjectType('BillingSubscription') export class BillingSubscription { @@ -49,12 +70,20 @@ export class BillingSubscription { @Column({ unique: true, nullable: false }) stripeSubscriptionId: string; - @Field(() => String) - @Column({ type: 'text', nullable: false }) + @Field(() => SubscriptionStatus) + @Column({ + type: 'enum', + enum: Object.values(SubscriptionStatus), + nullable: false, + }) status: Stripe.Subscription.Status; - @Field(() => String, { nullable: true }) - @Column({ type: 'text', nullable: true }) + @Field(() => SubscriptionInterval, { nullable: true }) + @Column({ + type: 'enum', + enum: Object.values(SubscriptionInterval), + nullable: true, + }) interval: Stripe.Price.Recurring.Interval; @OneToMany( diff --git a/packages/twenty-server/src/engine/core-modules/billing/jobs/update-subscription.job.ts b/packages/twenty-server/src/engine/core-modules/billing/jobs/update-subscription.job.ts index cf3ff0367a8d..9302c50f8d56 100644 --- a/packages/twenty-server/src/engine/core-modules/billing/jobs/update-subscription.job.ts +++ b/packages/twenty-server/src/engine/core-modules/billing/jobs/update-subscription.job.ts @@ -1,25 +1,30 @@ -import { Injectable, Logger } from '@nestjs/common'; +import { Logger, Scope } from '@nestjs/common'; -import { MessageQueueJob } from 'src/engine/integrations/message-queue/interfaces/message-queue-job.interface'; - -import { BillingService } from 'src/engine/core-modules/billing/billing.service'; +import { BillingWorkspaceService } from 'src/engine/core-modules/billing/billing.workspace-service'; import { UserWorkspaceService } from 'src/engine/core-modules/user-workspace/user-workspace.service'; import { StripeService } from 'src/engine/core-modules/billing/stripe/stripe.service'; +import { Processor } from 'src/engine/integrations/message-queue/decorators/processor.decorator'; +import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; +import { Process } from 'src/engine/integrations/message-queue/decorators/process.decorator'; export type UpdateSubscriptionJobData = { workspaceId: string }; -@Injectable() -export class UpdateSubscriptionJob - implements MessageQueueJob<UpdateSubscriptionJobData> -{ + +@Processor({ + queueName: MessageQueue.billingQueue, + scope: Scope.REQUEST, +}) +export class UpdateSubscriptionJob { protected readonly logger = new Logger(UpdateSubscriptionJob.name); + constructor( - private readonly billingService: BillingService, + private readonly billingWorkspaceService: BillingWorkspaceService, private readonly userWorkspaceService: UserWorkspaceService, private readonly stripeService: StripeService, ) {} + @Process(UpdateSubscriptionJob.name) async handle(data: UpdateSubscriptionJobData): Promise<void> { const workspaceMembersCount = - await this.userWorkspaceService.getWorkspaceMemberCount(data.workspaceId); + await this.userWorkspaceService.getWorkspaceMemberCount(); if (!workspaceMembersCount || workspaceMembersCount <= 0) { return; @@ -27,7 +32,9 @@ export class UpdateSubscriptionJob try { const billingSubscriptionItem = - await this.billingService.getBillingSubscriptionItem(data.workspaceId); + await this.billingWorkspaceService.getBillingSubscriptionItem( + data.workspaceId, + ); await this.stripeService.updateSubscriptionItem( billingSubscriptionItem.stripeSubscriptionItemId, diff --git a/packages/twenty-server/src/engine/core-modules/billing/listeners/billing-workspace-member.listener.ts b/packages/twenty-server/src/engine/core-modules/billing/listeners/billing-workspace-member.listener.ts index 77365b74aa8e..4fadaaf5ed7c 100644 --- a/packages/twenty-server/src/engine/core-modules/billing/listeners/billing-workspace-member.listener.ts +++ b/packages/twenty-server/src/engine/core-modules/billing/listeners/billing-workspace-member.listener.ts @@ -1,4 +1,4 @@ -import { Inject, Injectable } from '@nestjs/common'; +import { Injectable } from '@nestjs/common'; import { OnEvent } from '@nestjs/event-emitter'; import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; @@ -9,14 +9,15 @@ import { UpdateSubscriptionJob, UpdateSubscriptionJobData, } from 'src/engine/core-modules/billing/jobs/update-subscription.job'; -import { EnvironmentService } from 'src/engine/integrations/environment/environment.service'; +import { InjectMessageQueue } from 'src/engine/integrations/message-queue/decorators/message-queue.decorator'; +import { BillingWorkspaceService } from 'src/engine/core-modules/billing/billing.workspace-service'; @Injectable() export class BillingWorkspaceMemberListener { constructor( - @Inject(MessageQueue.billingQueue) + @InjectMessageQueue(MessageQueue.billingQueue) private readonly messageQueueService: MessageQueueService, - private readonly environmentService: EnvironmentService, + private readonly billingWorkspaceService: BillingWorkspaceService, ) {} @OnEvent('workspaceMember.created') @@ -24,7 +25,12 @@ export class BillingWorkspaceMemberListener { async handleCreateOrDeleteEvent( payload: ObjectRecordCreateEvent<WorkspaceMemberWorkspaceEntity>, ) { - if (!this.environmentService.get('IS_BILLING_ENABLED')) { + const isBillingEnabledForWorkspace = + await this.billingWorkspaceService.isBillingEnabledForWorkspace( + payload.workspaceId, + ); + + if (!isBillingEnabledForWorkspace) { return; } diff --git a/packages/twenty-server/src/engine/core-modules/calendar/dtos/timeline-calendar-event-participant.dto.ts b/packages/twenty-server/src/engine/core-modules/calendar/dtos/timeline-calendar-event-participant.dto.ts index 1d5d99720899..6e9a3189a285 100644 --- a/packages/twenty-server/src/engine/core-modules/calendar/dtos/timeline-calendar-event-participant.dto.ts +++ b/packages/twenty-server/src/engine/core-modules/calendar/dtos/timeline-calendar-event-participant.dto.ts @@ -5,10 +5,10 @@ import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/ @ObjectType('TimelineCalendarEventParticipant') export class TimelineCalendarEventParticipant { @Field(() => UUIDScalarType, { nullable: true }) - personId: string; + personId: string | null; @Field(() => UUIDScalarType, { nullable: true }) - workspaceMemberId: string; + workspaceMemberId: string | null; @Field() firstName: string; diff --git a/packages/twenty-server/src/engine/core-modules/calendar/dtos/timeline-calendar-event.dto.ts b/packages/twenty-server/src/engine/core-modules/calendar/dtos/timeline-calendar-event.dto.ts index 2c64d9226135..c9e579ccd30b 100644 --- a/packages/twenty-server/src/engine/core-modules/calendar/dtos/timeline-calendar-event.dto.ts +++ b/packages/twenty-server/src/engine/core-modules/calendar/dtos/timeline-calendar-event.dto.ts @@ -2,7 +2,7 @@ import { ObjectType, Field, registerEnumType } from '@nestjs/graphql'; import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars'; import { TimelineCalendarEventParticipant } from 'src/engine/core-modules/calendar/dtos/timeline-calendar-event-participant.dto'; -import { CalendarChannelVisibility } from 'src/modules/calendar/standard-objects/calendar-channel.workspace-entity'; +import { CalendarChannelVisibility } from 'src/modules/calendar/common/standard-objects/calendar-channel.workspace-entity'; registerEnumType(CalendarChannelVisibility, { name: 'CalendarChannelVisibility', diff --git a/packages/twenty-server/src/engine/core-modules/calendar/timeline-calendar-event.module.ts b/packages/twenty-server/src/engine/core-modules/calendar/timeline-calendar-event.module.ts index c8a7d442a073..47bdee1888d4 100644 --- a/packages/twenty-server/src/engine/core-modules/calendar/timeline-calendar-event.module.ts +++ b/packages/twenty-server/src/engine/core-modules/calendar/timeline-calendar-event.module.ts @@ -4,8 +4,8 @@ import { UserModule } from 'src/engine/core-modules/user/user.module'; import { TimelineCalendarEventResolver } from 'src/engine/core-modules/calendar/timeline-calendar-event.resolver'; import { TimelineCalendarEventService } from 'src/engine/core-modules/calendar/timeline-calendar-event.service'; import { TwentyORMModule } from 'src/engine/twenty-orm/twenty-orm.module'; -import { CalendarEventWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-event.workspace-entity'; import { PersonWorkspaceEntity } from 'src/modules/person/standard-objects/person.workspace-entity'; +import { CalendarEventWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-event.workspace-entity'; @Module({ imports: [ diff --git a/packages/twenty-server/src/engine/core-modules/calendar/timeline-calendar-event.service.ts b/packages/twenty-server/src/engine/core-modules/calendar/timeline-calendar-event.service.ts index 810869e2a74e..1ef6370abc2e 100644 --- a/packages/twenty-server/src/engine/core-modules/calendar/timeline-calendar-event.service.ts +++ b/packages/twenty-server/src/engine/core-modules/calendar/timeline-calendar-event.service.ts @@ -7,9 +7,9 @@ import { TIMELINE_CALENDAR_EVENTS_DEFAULT_PAGE_SIZE } from 'src/engine/core-modu import { TimelineCalendarEventsWithTotal } from 'src/engine/core-modules/calendar/dtos/timeline-calendar-events-with-total.dto'; import { InjectWorkspaceRepository } from 'src/engine/twenty-orm/decorators/inject-workspace-repository.decorator'; import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository'; -import { CalendarEventWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-event.workspace-entity'; import { PersonWorkspaceEntity } from 'src/modules/person/standard-objects/person.workspace-entity'; -import { CalendarChannelVisibility } from 'src/modules/calendar/standard-objects/calendar-channel.workspace-entity'; +import { CalendarChannelVisibility } from 'src/modules/calendar/common/standard-objects/calendar-channel.workspace-entity'; +import { CalendarEventWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-event.workspace-entity'; @Injectable() export class TimelineCalendarEventService { @@ -31,9 +31,7 @@ export class TimelineCalendarEventService { const calendarEventIds = await this.calendarEventRepository.find({ where: { calendarEventParticipants: { - person: { - id: Any(personIds), - }, + personId: Any(personIds), }, }, select: { @@ -81,19 +79,19 @@ export class TimelineCalendarEventService { const participants = event.calendarEventParticipants.map( (participant) => ({ calendarEventId: event.id, - personId: participant.person?.id, - workspaceMemberId: participant.workspaceMember?.id, + personId: participant.personId ?? null, + workspaceMemberId: participant.workspaceMemberId ?? null, firstName: - participant.person?.name.firstName || + participant.person?.name?.firstName || participant.workspaceMember?.name.firstName || '', lastName: - participant.person?.name.lastName || + participant.person?.name?.lastName || participant.workspaceMember?.name.lastName || '', displayName: - participant.person?.name.firstName || - participant.person?.name.lastName || + participant.person?.name?.firstName || + participant.person?.name?.lastName || participant.workspaceMember?.name.firstName || participant.workspaceMember?.name.lastName || '', @@ -135,9 +133,7 @@ export class TimelineCalendarEventService { ): Promise<TimelineCalendarEventsWithTotal> { const personIds = await this.personRepository.find({ where: { - company: { - id: companyId, - }, + companyId, }, select: { id: true, diff --git a/packages/twenty-server/src/engine/core-modules/client-config/client-config.entity.ts b/packages/twenty-server/src/engine/core-modules/client-config/client-config.entity.ts index 8252db6ba1af..478c89da0cd7 100644 --- a/packages/twenty-server/src/engine/core-modules/client-config/client-config.entity.ts +++ b/packages/twenty-server/src/engine/core-modules/client-config/client-config.entity.ts @@ -65,6 +65,12 @@ class Captcha { siteKey: string | undefined; } +@ObjectType() +class ApiConfig { + @Field(() => Number, { nullable: false }) + mutationMaximumAffectedRecords: number; +} + @ObjectType() export class ClientConfig { @Field(() => AuthProviders, { nullable: false }) @@ -96,4 +102,7 @@ export class ClientConfig { @Field(() => String, { nullable: true }) chromeExtensionId: string | undefined; + + @Field(() => ApiConfig) + api: ApiConfig; } diff --git a/packages/twenty-server/src/engine/core-modules/client-config/client-config.resolver.ts b/packages/twenty-server/src/engine/core-modules/client-config/client-config.resolver.ts index 4ce91428ca74..c8222a3418f8 100644 --- a/packages/twenty-server/src/engine/core-modules/client-config/client-config.resolver.ts +++ b/packages/twenty-server/src/engine/core-modules/client-config/client-config.resolver.ts @@ -46,6 +46,11 @@ export class ClientConfigResolver { siteKey: this.environmentService.get('CAPTCHA_SITE_KEY'), }, chromeExtensionId: this.environmentService.get('CHROME_EXTENSION_ID'), + api: { + mutationMaximumAffectedRecords: this.environmentService.get( + 'MUTATION_MAXIMUM_AFFECTED_RECORDS', + ), + }, }; return Promise.resolve(clientConfig); diff --git a/packages/twenty-server/src/engine/core-modules/core-engine.module.ts b/packages/twenty-server/src/engine/core-modules/core-engine.module.ts index 2df9de73b593..cb63a112ccab 100644 --- a/packages/twenty-server/src/engine/core-modules/core-engine.module.ts +++ b/packages/twenty-server/src/engine/core-modules/core-engine.module.ts @@ -10,7 +10,7 @@ import { TimelineMessagingModule } from 'src/engine/core-modules/messaging/timel import { TimelineCalendarEventModule } from 'src/engine/core-modules/calendar/timeline-calendar-event.module'; import { BillingModule } from 'src/engine/core-modules/billing/billing.module'; import { HealthModule } from 'src/engine/core-modules/health/health.module'; -import { TwentyORMModule } from 'src/engine/twenty-orm/twenty-orm.module'; +import { AISQLQueryModule } from 'src/engine/core-modules/ai-sql-query/ai-sql-query.module'; import { PostgresCredentialsModule } from 'src/engine/core-modules/postgres-credentials/postgres-credentials.module'; import { AnalyticsModule } from './analytics/analytics.module'; @@ -19,9 +19,6 @@ import { ClientConfigModule } from './client-config/client-config.module'; @Module({ imports: [ - TwentyORMModule.register({ - workspaceEntities: ['dist/src/**/*.workspace-entity{.ts,.js}'], - }), HealthModule, AnalyticsModule, AuthModule, @@ -35,6 +32,7 @@ import { ClientConfigModule } from './client-config/client-config.module'; TimelineCalendarEventModule, UserModule, WorkspaceModule, + AISQLQueryModule, PostgresCredentialsModule, ], exports: [ diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/constants/duplicate-criteria.constants.ts b/packages/twenty-server/src/engine/core-modules/duplicate/constants/duplicate-criteria.constants.ts similarity index 100% rename from packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/constants/duplicate-criteria.constants.ts rename to packages/twenty-server/src/engine/core-modules/duplicate/constants/duplicate-criteria.constants.ts diff --git a/packages/twenty-server/src/engine/core-modules/duplicate/duplicate.module.ts b/packages/twenty-server/src/engine/core-modules/duplicate/duplicate.module.ts new file mode 100644 index 000000000000..c32a4fa598cf --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/duplicate/duplicate.module.ts @@ -0,0 +1,11 @@ +import { Module } from '@nestjs/common'; + +import { DuplicateService } from 'src/engine/core-modules/duplicate/duplicate.service'; +import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; + +@Module({ + imports: [WorkspaceDataSourceModule], + exports: [DuplicateService], + providers: [DuplicateService], +}) +export class DuplicateModule {} diff --git a/packages/twenty-server/src/engine/core-modules/duplicate/duplicate.service.ts b/packages/twenty-server/src/engine/core-modules/duplicate/duplicate.service.ts new file mode 100644 index 000000000000..d7ed6f87bd85 --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/duplicate/duplicate.service.ts @@ -0,0 +1,173 @@ +import { Injectable } from '@nestjs/common'; + +import { ObjectMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/object-metadata.interface'; +import { + Record as IRecord, + Record, +} from 'src/engine/api/graphql/workspace-query-builder/interfaces/record.interface'; + +import { settings } from 'src/engine/constants/settings'; +import { computeObjectTargetTable } from 'src/engine/utils/compute-object-target-table.util'; +import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; +import { DUPLICATE_CRITERIA_COLLECTION } from 'src/engine/core-modules/duplicate/constants/duplicate-criteria.constants'; + +@Injectable() +export class DuplicateService { + constructor( + private readonly workspaceDataSourceService: WorkspaceDataSourceService, + ) {} + + async findExistingRecords( + recordIds: (string | number)[], + objectMetadata: ObjectMetadataInterface, + workspaceId: string, + ) { + const dataSourceSchema = + this.workspaceDataSourceService.getSchemaName(workspaceId); + + const results = await this.workspaceDataSourceService.executeRawQuery( + ` + SELECT + * + FROM + ${dataSourceSchema}."${computeObjectTargetTable( + objectMetadata, + )}" p + WHERE + p."id" IN (${recordIds + .map((_, index) => `$${index + 1}`) + .join(', ')}) + `, + recordIds, + workspaceId, + ); + + return results as IRecord[]; + } + + buildDuplicateConditionForGraphQL( + objectMetadata: ObjectMetadataInterface, + argsData?: Partial<Record>, + filteringByExistingRecordId?: string, + ) { + if (!argsData) { + return; + } + + const criteriaCollection = + this.getApplicableDuplicateCriteriaCollection(objectMetadata); + + const criteriaWithMatchingArgs = criteriaCollection.filter((criteria) => + criteria.columnNames.every((columnName) => { + const value = argsData[columnName] as string | undefined; + + return ( + !!value && value.length >= settings.minLengthOfStringForDuplicateCheck + ); + }), + ); + + const filterCriteria = criteriaWithMatchingArgs.map((criteria) => + Object.fromEntries( + criteria.columnNames.map((columnName) => [ + columnName, + { eq: argsData[columnName] }, + ]), + ), + ); + + return { + // when filtering by an existing record, we need to filter that explicit record out + ...(filteringByExistingRecordId && { + id: { neq: filteringByExistingRecordId }, + }), + // keep condition as "or" to get results by more duplicate criteria + or: filterCriteria, + }; + } + + private getApplicableDuplicateCriteriaCollection( + objectMetadataItem: ObjectMetadataInterface, + ) { + return DUPLICATE_CRITERIA_COLLECTION.filter( + (duplicateCriteria) => + duplicateCriteria.objectName === objectMetadataItem.nameSingular, + ); + } + + /** + * TODO: Remove this code by September 1st, 2024 if it isn't used + * It was build to be used by the upsertMany function, but it was not used. + * It's a re-implementation of the methods to findDuplicates, but done + * at the SQL layer instead of doing it at the GraphQL layer + * + async findDuplicate( + data: Partial<Record>, + objectMetadata: ObjectMetadataInterface, + workspaceId: string, + ) { + const dataSourceSchema = + this.workspaceDataSourceService.getSchemaName(workspaceId); + + const { duplicateWhereClause, duplicateWhereParameters } = + this.buildDuplicateConditionForUpsert(objectMetadata, data); + + const results = await this.workspaceDataSourceService.executeRawQuery( + ` + SELECT + * + FROM + ${dataSourceSchema}."${computeObjectTargetTable( + objectMetadata, + )}" p + WHERE + ${duplicateWhereClause} + `, + duplicateWhereParameters, + workspaceId, + ); + + return results.length > 0 ? results[0] : null; + } + + private buildDuplicateConditionForUpsert( + objectMetadata: ObjectMetadataInterface, + data: Partial<Record>, + ) { + const criteriaCollection = this.getApplicableDuplicateCriteriaCollection( + objectMetadata, + ).filter( + (duplicateCriteria) => duplicateCriteria.useAsUniqueKeyForUpsert === true, + ); + + const whereClauses: string[] = []; + const whereParameters: any[] = []; + let parameterIndex = 1; + + criteriaCollection.forEach((c) => { + const clauseParts: string[] = []; + + c.columnNames.forEach((column) => { + const dataKey = Object.keys(data).find( + (key) => key.toLowerCase() === column.toLowerCase(), + ); + + if (dataKey) { + clauseParts.push(`p."${column}" = $${parameterIndex}`); + whereParameters.push(data[dataKey]); + parameterIndex++; + } + }); + if (clauseParts.length > 0) { + whereClauses.push(`(${clauseParts.join(' AND ')})`); + } + }); + + const duplicateWhereClause = whereClauses.join(' OR '); + const duplicateWhereParameters = whereParameters; + + return { duplicateWhereClause, duplicateWhereParameters }; + } + * + */ +} diff --git a/packages/twenty-server/src/engine/core-modules/feature-flag/feature-flag.entity.ts b/packages/twenty-server/src/engine/core-modules/feature-flag/feature-flag.entity.ts index 954461abdc70..b064661900d4 100644 --- a/packages/twenty-server/src/engine/core-modules/feature-flag/feature-flag.entity.ts +++ b/packages/twenty-server/src/engine/core-modules/feature-flag/feature-flag.entity.ts @@ -1,19 +1,19 @@ import { Field, ObjectType } from '@nestjs/graphql'; +import { IDField } from '@ptc-org/nestjs-query-graphql'; import { - Entity, - Unique, - PrimaryGeneratedColumn, Column, CreateDateColumn, - UpdateDateColumn, + Entity, ManyToOne, + PrimaryGeneratedColumn, Relation, + Unique, + UpdateDateColumn, } from 'typeorm'; -import { IDField } from '@ptc-org/nestjs-query-graphql'; -import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars'; +import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; export enum FeatureFlagKeys { IsBlocklistEnabled = 'IS_BLOCKLIST_ENABLED', @@ -21,7 +21,10 @@ export enum FeatureFlagKeys { IsAirtableIntegrationEnabled = 'IS_AIRTABLE_INTEGRATION_ENABLED', IsPostgreSQLIntegrationEnabled = 'IS_POSTGRESQL_INTEGRATION_ENABLED', IsStripeIntegrationEnabled = 'IS_STRIPE_INTEGRATION_ENABLED', - IsContactCreationForSentAndReceivedEmailsEnabled = 'IS_CONTACT_CREATION_FOR_SENT_AND_RECEIVED_EMAILS_ENABLED', + IsCopilotEnabled = 'IS_COPILOT_ENABLED', + IsMessagingAliasFetchingEnabled = 'IS_MESSAGING_ALIAS_FETCHING_ENABLED', + IsGoogleCalendarSyncV2Enabled = 'IS_GOOGLE_CALENDAR_SYNC_V2_ENABLED', + IsFreeAccessEnabled = 'IS_FREE_ACCESS_ENABLED', } @Entity({ name: 'featureFlag', schema: 'core' }) diff --git a/packages/twenty-server/src/engine/core-modules/feature-flag/feature-flag.module.ts b/packages/twenty-server/src/engine/core-modules/feature-flag/feature-flag.module.ts index 0b0f9bbd25ad..a79d3a72901e 100644 --- a/packages/twenty-server/src/engine/core-modules/feature-flag/feature-flag.module.ts +++ b/packages/twenty-server/src/engine/core-modules/feature-flag/feature-flag.module.ts @@ -5,6 +5,7 @@ import { NestjsQueryTypeOrmModule } from '@ptc-org/nestjs-query-typeorm'; import { TypeORMModule } from 'src/database/typeorm/typeorm.module'; import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity'; +import { IsFeatureEnabledService } from 'src/engine/core-modules/feature-flag/services/is-feature-enabled.service'; @Module({ imports: [ @@ -17,7 +18,7 @@ import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature- resolvers: [], }), ], - exports: [], - providers: [], + exports: [IsFeatureEnabledService], + providers: [IsFeatureEnabledService], }) export class FeatureFlagModule {} diff --git a/packages/twenty-server/src/engine/core-modules/feature-flag/services/is-feature-enabled.service.ts b/packages/twenty-server/src/engine/core-modules/feature-flag/services/is-feature-enabled.service.ts new file mode 100644 index 000000000000..33e3bcc8655c --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/feature-flag/services/is-feature-enabled.service.ts @@ -0,0 +1,30 @@ +import { Injectable } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; + +import { Repository } from 'typeorm'; + +import { + FeatureFlagEntity, + FeatureFlagKeys, +} from 'src/engine/core-modules/feature-flag/feature-flag.entity'; + +@Injectable() +export class IsFeatureEnabledService { + constructor( + @InjectRepository(FeatureFlagEntity, 'core') + private readonly featureFlagRepository: Repository<FeatureFlagEntity>, + ) {} + + public async isFeatureEnabled( + key: FeatureFlagKeys, + workspaceId: string, + ): Promise<boolean> { + const featureFlag = await this.featureFlagRepository.findOneBy({ + workspaceId, + key, + value: true, + }); + + return !!featureFlag?.value; + } +} diff --git a/packages/twenty-server/src/engine/core-modules/graphql/engine-graphql.module.ts b/packages/twenty-server/src/engine/core-modules/graphql/engine-graphql.module.ts new file mode 100644 index 000000000000..ae592e22c802 --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/graphql/engine-graphql.module.ts @@ -0,0 +1,11 @@ +import { Module } from '@nestjs/common'; + +import { useGraphQLErrorHandlerHook } from 'src/engine/core-modules/graphql/hooks/use-graphql-error-handler.hook'; +import { ExceptionHandlerModule } from 'src/engine/integrations/exception-handler/exception-handler.module'; + +@Module({ + imports: [ExceptionHandlerModule], + exports: [useGraphQLErrorHandlerHook], + providers: [], +}) +export class EngineGraphQLModule {} diff --git a/packages/twenty-server/src/engine/core-modules/graphql/hooks/use-graphql-error-handler.hook.ts b/packages/twenty-server/src/engine/core-modules/graphql/hooks/use-graphql-error-handler.hook.ts new file mode 100644 index 000000000000..0f98cdcfdb42 --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/graphql/hooks/use-graphql-error-handler.hook.ts @@ -0,0 +1,133 @@ +import { + OnExecuteDoneHookResultOnNextHook, + Plugin, + getDocumentString, + handleStreamOrSingleExecutionResult, +} from '@envelop/core'; +import { GraphQLError, Kind, OperationDefinitionNode, print } from 'graphql'; + +import { GraphQLContext } from 'src/engine/api/graphql/graphql-config/interfaces/graphql-context.interface'; + +import { generateGraphQLErrorFromError } from 'src/engine/core-modules/graphql/utils/generate-graphql-error-from-error.util'; +import { BaseGraphQLError } from 'src/engine/core-modules/graphql/utils/graphql-errors.util'; +import { shouldCaptureException } from 'src/engine/core-modules/graphql/utils/should-capture-exception.util'; +import { ExceptionHandlerService } from 'src/engine/integrations/exception-handler/exception-handler.service'; + +type GraphQLErrorHandlerHookOptions = { + /** + * The exception handler service to use. + */ + exceptionHandlerService: ExceptionHandlerService; + /** + * The key of the event id in the error's extension. `null` to disable. + * @default exceptionEventId + */ + eventIdKey?: string | null; +}; + +export const useGraphQLErrorHandlerHook = < + PluginContext extends GraphQLContext, +>( + options: GraphQLErrorHandlerHookOptions, +): Plugin<PluginContext> => { + const eventIdKey = options.eventIdKey === null ? null : 'exceptionEventId'; + + function addEventId( + err: GraphQLError, + eventId: string | undefined | null, + ): GraphQLError { + if (eventIdKey !== null && eventId) { + err.extensions[eventIdKey] = eventId; + } + + return err; + } + + return { + async onExecute({ args }) { + const exceptionHandlerService = options.exceptionHandlerService; + const rootOperation = args.document.definitions.find( + (o) => o.kind === Kind.OPERATION_DEFINITION, + ) as OperationDefinitionNode; + const operationType = rootOperation.operation; + const user = args.contextValue.req.user; + const document = getDocumentString(args.document, print); + const opName = + args.operationName || + rootOperation.name?.value || + 'Anonymous Operation'; + + return { + onExecuteDone(payload) { + const handleResult: OnExecuteDoneHookResultOnNextHook<object> = ({ + result, + setResult, + }) => { + if (result.errors && result.errors.length > 0) { + const errorsToCapture = result.errors.reduce<BaseGraphQLError[]>( + (acc, error) => { + if (!(error instanceof BaseGraphQLError)) { + error = generateGraphQLErrorFromError(error); + } + + if (shouldCaptureException(error)) { + acc.push(error); + } + + return acc; + }, + [], + ); + + if (errorsToCapture.length > 0) { + const eventIds = exceptionHandlerService.captureExceptions( + errorsToCapture, + { + operation: { + name: opName, + type: operationType, + }, + document, + user, + }, + ); + + errorsToCapture.map((err, i) => addEventId(err, eventIds?.[i])); + } + + const nonCapturedErrors = result.errors.filter( + (error) => !errorsToCapture.includes(error), + ); + + setResult({ + ...result, + errors: [...nonCapturedErrors, ...errorsToCapture], + }); + } + }; + + return handleStreamOrSingleExecutionResult(payload, handleResult); + }, + }; + }, + onValidate: ({ context, validateFn, params: { documentAST, schema } }) => { + const errors = validateFn(schema, documentAST); + + if (Array.isArray(errors) && errors.length > 0) { + const headers = context.req.headers; + const currentSchemaVersion = context.req.cacheVersion; + + const requestSchemaVersion = headers['x-schema-version']; + + if ( + requestSchemaVersion && + requestSchemaVersion !== currentSchemaVersion + ) { + throw new GraphQLError( + `Schema version mismatch, please refresh the page.`, + ); + } + } + }, + }; +}; diff --git a/packages/twenty-server/src/engine/core-modules/graphql/utils/generate-graphql-error-from-error.util.ts b/packages/twenty-server/src/engine/core-modules/graphql/utils/generate-graphql-error-from-error.util.ts new file mode 100644 index 000000000000..35201e31bd73 --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/graphql/utils/generate-graphql-error-from-error.util.ts @@ -0,0 +1,18 @@ +import { + BaseGraphQLError, + ErrorCode, +} from 'src/engine/core-modules/graphql/utils/graphql-errors.util'; + +export const generateGraphQLErrorFromError = (error: Error) => { + const graphqlError = new BaseGraphQLError( + error.name, + ErrorCode.INTERNAL_SERVER_ERROR, + ); + + if (process.env.NODE_ENV === 'development') { + graphqlError.stack = error.stack; + graphqlError.extensions['response'] = error.message; + } + + return error; +}; diff --git a/packages/twenty-server/src/engine/utils/graphql-errors.util.ts b/packages/twenty-server/src/engine/core-modules/graphql/utils/graphql-errors.util.ts similarity index 68% rename from packages/twenty-server/src/engine/utils/graphql-errors.util.ts rename to packages/twenty-server/src/engine/core-modules/graphql/utils/graphql-errors.util.ts index d198a9e6ee73..613225796cb3 100644 --- a/packages/twenty-server/src/engine/utils/graphql-errors.util.ts +++ b/packages/twenty-server/src/engine/core-modules/graphql/utils/graphql-errors.util.ts @@ -15,7 +15,22 @@ declare module 'graphql' { } } -export class BaseGraphQLError extends Error implements GraphQLError { +export enum ErrorCode { + GRAPHQL_PARSE_FAILED = 'GRAPHQL_PARSE_FAILED', + GRAPHQL_VALIDATION_FAILED = 'GRAPHQL_VALIDATION_FAILED', + UNAUTHENTICATED = 'UNAUTHENTICATED', + FORBIDDEN = 'FORBIDDEN', + PERSISTED_QUERY_NOT_FOUND = 'PERSISTED_QUERY_NOT_FOUND', + PERSISTED_QUERY_NOT_SUPPORTED = 'PERSISTED_QUERY_NOT_SUPPORTED', + BAD_USER_INPUT = 'BAD_USER_INPUT', + NOT_FOUND = 'NOT_FOUND', + METHOD_NOT_ALLOWED = 'METHOD_NOT_ALLOWED', + CONFLICT = 'CONFLICT', + TIMEOUT = 'TIMEOUT', + INTERNAL_SERVER_ERROR = 'INTERNAL_SERVER_ERROR', +} + +export class BaseGraphQLError extends GraphQLError { public extensions: Record<string, any>; override readonly name!: string; readonly locations: ReadonlyArray<SourceLocation> | undefined; @@ -76,7 +91,7 @@ function toGraphQLError(error: BaseGraphQLError): GraphQLError { export class SyntaxError extends BaseGraphQLError { constructor(message: string) { - super(message, 'GRAPHQL_PARSE_FAILED'); + super(message, ErrorCode.GRAPHQL_PARSE_FAILED); Object.defineProperty(this, 'name', { value: 'SyntaxError' }); } @@ -84,23 +99,23 @@ export class SyntaxError extends BaseGraphQLError { export class ValidationError extends BaseGraphQLError { constructor(message: string) { - super(message, 'GRAPHQL_VALIDATION_FAILED'); + super(message, ErrorCode.GRAPHQL_VALIDATION_FAILED); Object.defineProperty(this, 'name', { value: 'ValidationError' }); } } export class AuthenticationError extends BaseGraphQLError { - constructor(message: string, extensions?: Record<string, any>) { - super(message, 'UNAUTHENTICATED', extensions); + constructor(message: string) { + super(message, ErrorCode.UNAUTHENTICATED); Object.defineProperty(this, 'name', { value: 'AuthenticationError' }); } } export class ForbiddenError extends BaseGraphQLError { - constructor(message: string, extensions?: Record<string, any>) { - super(message, 'FORBIDDEN', extensions); + constructor(message: string) { + super(message, ErrorCode.FORBIDDEN); Object.defineProperty(this, 'name', { value: 'ForbiddenError' }); } @@ -108,7 +123,7 @@ export class ForbiddenError extends BaseGraphQLError { export class PersistedQueryNotFoundError extends BaseGraphQLError { constructor() { - super('PersistedQueryNotFound', 'PERSISTED_QUERY_NOT_FOUND'); + super('PersistedQueryNotFound', ErrorCode.PERSISTED_QUERY_NOT_FOUND); Object.defineProperty(this, 'name', { value: 'PersistedQueryNotFoundError', @@ -118,7 +133,10 @@ export class PersistedQueryNotFoundError extends BaseGraphQLError { export class PersistedQueryNotSupportedError extends BaseGraphQLError { constructor() { - super('PersistedQueryNotSupported', 'PERSISTED_QUERY_NOT_SUPPORTED'); + super( + 'PersistedQueryNotSupported', + ErrorCode.PERSISTED_QUERY_NOT_SUPPORTED, + ); Object.defineProperty(this, 'name', { value: 'PersistedQueryNotSupportedError', @@ -127,41 +145,49 @@ export class PersistedQueryNotSupportedError extends BaseGraphQLError { } export class UserInputError extends BaseGraphQLError { - constructor(message: string, extensions?: Record<string, any>) { - super(message, 'BAD_USER_INPUT', extensions); + constructor(message: string) { + super(message, ErrorCode.BAD_USER_INPUT); Object.defineProperty(this, 'name', { value: 'UserInputError' }); } } export class NotFoundError extends BaseGraphQLError { - constructor(message: string, extensions?: Record<string, any>) { - super(message, 'NOT_FOUND', extensions); + constructor(message: string) { + super(message, ErrorCode.NOT_FOUND); Object.defineProperty(this, 'name', { value: 'NotFoundError' }); } } export class MethodNotAllowedError extends BaseGraphQLError { - constructor(message: string, extensions?: Record<string, any>) { - super(message, 'METHOD_NOT_ALLOWED', extensions); + constructor(message: string) { + super(message, ErrorCode.METHOD_NOT_ALLOWED); Object.defineProperty(this, 'name', { value: 'MethodNotAllowedError' }); } } export class ConflictError extends BaseGraphQLError { - constructor(message: string, extensions?: Record<string, any>) { - super(message, 'CONFLICT', extensions); + constructor(message: string) { + super(message, ErrorCode.CONFLICT); Object.defineProperty(this, 'name', { value: 'ConflictError' }); } } export class TimeoutError extends BaseGraphQLError { - constructor(message: string, extensions?: Record<string, any>) { - super(message, 'TIMEOUT', extensions); + constructor(message: string) { + super(message, ErrorCode.TIMEOUT); Object.defineProperty(this, 'name', { value: 'TimeoutError' }); } } + +export class InternalServerError extends BaseGraphQLError { + constructor(message: string) { + super(message, ErrorCode.INTERNAL_SERVER_ERROR); + + Object.defineProperty(this, 'name', { value: 'InternalServerError' }); + } +} diff --git a/packages/twenty-server/src/engine/core-modules/graphql/utils/should-capture-exception.util.ts b/packages/twenty-server/src/engine/core-modules/graphql/utils/should-capture-exception.util.ts new file mode 100644 index 000000000000..f801e9be71ae --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/graphql/utils/should-capture-exception.util.ts @@ -0,0 +1,26 @@ +import { + BaseGraphQLError, + ErrorCode, +} from 'src/engine/core-modules/graphql/utils/graphql-errors.util'; + +export const graphQLErrorCodesToFilter = [ + ErrorCode.GRAPHQL_VALIDATION_FAILED, + ErrorCode.UNAUTHENTICATED, + ErrorCode.FORBIDDEN, + ErrorCode.NOT_FOUND, + ErrorCode.METHOD_NOT_ALLOWED, + ErrorCode.TIMEOUT, + ErrorCode.CONFLICT, + ErrorCode.BAD_USER_INPUT, +]; + +export const shouldCaptureException = (exception: Error): boolean => { + if ( + exception instanceof BaseGraphQLError && + graphQLErrorCodesToFilter.includes(exception?.extensions?.code) + ) { + return true; + } + + return false; +}; diff --git a/packages/twenty-server/src/engine/core-modules/onboarding/enums/onboarding-status.enum.ts b/packages/twenty-server/src/engine/core-modules/onboarding/enums/onboarding-status.enum.ts new file mode 100644 index 000000000000..8370714f2b7f --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/onboarding/enums/onboarding-status.enum.ts @@ -0,0 +1,8 @@ +export enum OnboardingStatus { + PLAN_REQUIRED = 'PLAN_REQUIRED', + WORKSPACE_ACTIVATION = 'WORKSPACE_ACTIVATION', + PROFILE_CREATION = 'PROFILE_CREATION', + SYNC_EMAIL = 'SYNC_EMAIL', + INVITE_TEAM = 'INVITE_TEAM', + COMPLETED = 'COMPLETED', +} diff --git a/packages/twenty-server/src/engine/core-modules/onboarding/enums/onboarding-step.enum.ts b/packages/twenty-server/src/engine/core-modules/onboarding/enums/onboarding-step.enum.ts deleted file mode 100644 index 55087ce5aad0..000000000000 --- a/packages/twenty-server/src/engine/core-modules/onboarding/enums/onboarding-step.enum.ts +++ /dev/null @@ -1,4 +0,0 @@ -export enum OnboardingStep { - SYNC_EMAIL = 'SYNC_EMAIL', - INVITE_TEAM = 'INVITE_TEAM', -} diff --git a/packages/twenty-server/src/engine/core-modules/onboarding/onboarding.module.ts b/packages/twenty-server/src/engine/core-modules/onboarding/onboarding.module.ts index 65f0156d3dd0..a036cafee618 100644 --- a/packages/twenty-server/src/engine/core-modules/onboarding/onboarding.module.ts +++ b/packages/twenty-server/src/engine/core-modules/onboarding/onboarding.module.ts @@ -5,9 +5,19 @@ import { OnboardingResolver } from 'src/engine/core-modules/onboarding/onboardin import { KeyValuePairModule } from 'src/engine/core-modules/key-value-pair/key-value-pair.module'; import { UserWorkspaceModule } from 'src/engine/core-modules/user-workspace/user-workspace.module'; import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module'; +import { WorkspaceManagerModule } from 'src/engine/workspace-manager/workspace-manager.module'; +import { EnvironmentModule } from 'src/engine/integrations/environment/environment.module'; +import { BillingModule } from 'src/engine/core-modules/billing/billing.module'; @Module({ - imports: [DataSourceModule, UserWorkspaceModule, KeyValuePairModule], + imports: [ + DataSourceModule, + WorkspaceManagerModule, + UserWorkspaceModule, + KeyValuePairModule, + EnvironmentModule, + BillingModule, + ], exports: [OnboardingService], providers: [OnboardingService, OnboardingResolver], }) diff --git a/packages/twenty-server/src/engine/core-modules/onboarding/onboarding.service.ts b/packages/twenty-server/src/engine/core-modules/onboarding/onboarding.service.ts index 1709f3d789b9..f131e5bca20c 100644 --- a/packages/twenty-server/src/engine/core-modules/onboarding/onboarding.service.ts +++ b/packages/twenty-server/src/engine/core-modules/onboarding/onboarding.service.ts @@ -1,13 +1,20 @@ import { Injectable } from '@nestjs/common'; import { KeyValuePairService } from 'src/engine/core-modules/key-value-pair/key-value-pair.service'; -import { OnboardingStep } from 'src/engine/core-modules/onboarding/enums/onboarding-step.enum'; +import { OnboardingStatus } from 'src/engine/core-modules/onboarding/enums/onboarding-status.enum'; import { User } from 'src/engine/core-modules/user/user.entity'; import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; import { UserWorkspaceService } from 'src/engine/core-modules/user-workspace/user-workspace.service'; import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; import { ConnectedAccountRepository } from 'src/modules/connected-account/repositories/connected-account.repository'; +import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; +import { WorkspaceManagerService } from 'src/engine/workspace-manager/workspace-manager.service'; +import { InjectWorkspaceRepository } from 'src/engine/twenty-orm/decorators/inject-workspace-repository.decorator'; +import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository'; +import { SubscriptionStatus } from 'src/engine/core-modules/billing/entities/billing-subscription.entity'; +import { isDefined } from 'src/utils/is-defined'; +import { BillingWorkspaceService } from 'src/engine/core-modules/billing/billing.workspace-service'; enum OnboardingStepValues { SKIPPED = 'SKIPPED', @@ -26,29 +33,71 @@ type OnboardingKeyValueType = { @Injectable() export class OnboardingService { constructor( + private readonly billingWorkspaceService: BillingWorkspaceService, + private readonly workspaceManagerService: WorkspaceManagerService, private readonly userWorkspaceService: UserWorkspaceService, private readonly keyValuePairService: KeyValuePairService<OnboardingKeyValueType>, @InjectObjectMetadataRepository(ConnectedAccountWorkspaceEntity) private readonly connectedAccountRepository: ConnectedAccountRepository, + @InjectWorkspaceRepository(WorkspaceMemberWorkspaceEntity) + private readonly workspaceMemberRepository: WorkspaceRepository<WorkspaceMemberWorkspaceEntity>, ) {} - private async isSyncEmailOnboardingStep(user: User, workspace: Workspace) { + private async isSubscriptionIncompleteOnboardingStatus(user: User) { + const isBillingEnabledForWorkspace = + await this.billingWorkspaceService.isBillingEnabledForWorkspace( + user.defaultWorkspaceId, + ); + + if (!isBillingEnabledForWorkspace) { + return false; + } + + const currentBillingSubscription = + await this.billingWorkspaceService.getCurrentBillingSubscription({ + workspaceId: user.defaultWorkspaceId, + }); + + return ( + !isDefined(currentBillingSubscription) || + currentBillingSubscription?.status === SubscriptionStatus.Incomplete + ); + } + + private async isWorkspaceActivationOnboardingStatus(user: User) { + return !(await this.workspaceManagerService.doesDataSourceExist( + user.defaultWorkspaceId, + )); + } + + private async isProfileCreationOnboardingStatus(user: User) { + const workspaceMember = await this.workspaceMemberRepository.findOneBy({ + userId: user.id, + }); + + return ( + workspaceMember && + (!workspaceMember.name.firstName || !workspaceMember.name.lastName) + ); + } + + private async isSyncEmailOnboardingStatus(user: User) { const syncEmailValue = await this.keyValuePairService.get({ userId: user.id, - workspaceId: workspace.id, + workspaceId: user.defaultWorkspaceId, key: OnboardingStepKeys.SYNC_EMAIL_ONBOARDING_STEP, }); const isSyncEmailSkipped = syncEmailValue === OnboardingStepValues.SKIPPED; const connectedAccounts = await this.connectedAccountRepository.getAllByUserId( user.id, - workspace.id, + user.defaultWorkspaceId, ); return !isSyncEmailSkipped && !connectedAccounts?.length; } - private async isInviteTeamOnboardingStep(workspace: Workspace) { + private async isInviteTeamOnboardingStatus(workspace: Workspace) { const inviteTeamValue = await this.keyValuePairService.get({ workspaceId: workspace.id, key: OnboardingStepKeys.INVITE_TEAM_ONBOARDING_STEP, @@ -56,7 +105,7 @@ export class OnboardingService { const isInviteTeamSkipped = inviteTeamValue === OnboardingStepValues.SKIPPED; const workspaceMemberCount = - await this.userWorkspaceService.getWorkspaceMemberCount(workspace.id); + await this.userWorkspaceService.getWorkspaceMemberCount(); return ( !isInviteTeamSkipped && @@ -64,19 +113,28 @@ export class OnboardingService { ); } - async getOnboardingStep( - user: User, - workspace: Workspace, - ): Promise<OnboardingStep | null> { - if (await this.isSyncEmailOnboardingStep(user, workspace)) { - return OnboardingStep.SYNC_EMAIL; + async getOnboardingStatus(user: User) { + if (await this.isSubscriptionIncompleteOnboardingStatus(user)) { + return OnboardingStatus.PLAN_REQUIRED; + } + + if (await this.isWorkspaceActivationOnboardingStatus(user)) { + return OnboardingStatus.WORKSPACE_ACTIVATION; + } + + if (await this.isProfileCreationOnboardingStatus(user)) { + return OnboardingStatus.PROFILE_CREATION; + } + + if (await this.isSyncEmailOnboardingStatus(user)) { + return OnboardingStatus.SYNC_EMAIL; } - if (await this.isInviteTeamOnboardingStep(workspace)) { - return OnboardingStep.INVITE_TEAM; + if (await this.isInviteTeamOnboardingStatus(user.defaultWorkspace)) { + return OnboardingStatus.INVITE_TEAM; } - return null; + return OnboardingStatus.COMPLETED; } async skipInviteTeamOnboardingStep(workspaceId: string) { diff --git a/packages/twenty-server/src/engine/core-modules/open-api/open-api.service.ts b/packages/twenty-server/src/engine/core-modules/open-api/open-api.service.ts index c833377e1ae0..8a3738b2a695 100644 --- a/packages/twenty-server/src/engine/core-modules/open-api/open-api.service.ts +++ b/packages/twenty-server/src/engine/core-modules/open-api/open-api.service.ts @@ -133,9 +133,13 @@ export class OpenApiService { get: { tags: [item.namePlural], summary: `Find Many ${item.namePlural}`, - parameters: [{ $ref: '#/components/parameters/filter' }], + parameters: [ + { $ref: '#/components/parameters/limit' }, + { $ref: '#/components/parameters/startingAfter' }, + { $ref: '#/components/parameters/endingBefore' }, + ], responses: { - '200': getFindManyResponse200(item), + '200': getFindManyResponse200(item, true), '400': { $ref: '#/components/responses/400' }, '401': { $ref: '#/components/responses/401' }, }, @@ -158,7 +162,7 @@ export class OpenApiService { summary: `Find One ${item.nameSingular}`, parameters: [{ $ref: '#/components/parameters/idPath' }], responses: { - '200': getFindOneResponse200(item), + '200': getFindOneResponse200(item, true), '400': { $ref: '#/components/responses/400' }, '401': { $ref: '#/components/responses/401' }, }, @@ -174,18 +178,20 @@ export class OpenApiService { '401': { $ref: '#/components/responses/401' }, }, }, - patch: { - tags: [item.namePlural], - summary: `Update One ${item.namePlural}`, - operationId: `updateOne${capitalize(item.nameSingular)}`, - parameters: [{ $ref: '#/components/parameters/idPath' }], - requestBody: getRequestBody(capitalize(item.nameSingular)), - responses: { - '200': getUpdateOneResponse200(item, true), - '400': { $ref: '#/components/responses/400' }, - '401': { $ref: '#/components/responses/401' }, + ...(item.nameSingular !== 'relation' && { + patch: { + tags: [item.namePlural], + summary: `Update One ${item.nameSingular}`, + operationId: `updateOne${capitalize(item.nameSingular)}`, + parameters: [{ $ref: '#/components/parameters/idPath' }], + requestBody: getRequestBody(capitalize(item.nameSingular)), + responses: { + '200': getUpdateOneResponse200(item, true), + '400': { $ref: '#/components/responses/400' }, + '401': { $ref: '#/components/responses/401' }, + }, }, - }, + }), } as OpenAPIV3_1.PathItemObject; return path; @@ -194,7 +200,7 @@ export class OpenApiService { schema.components = { ...schema.components, // components.securitySchemes is defined in base Schema schemas: computeMetadataSchemaComponents(metadata), - parameters: computeParameterComponents(), + parameters: computeParameterComponents(true), responses: { '400': get400ErrorResponses(), '401': get401ErrorResponses(), diff --git a/packages/twenty-server/src/engine/core-modules/open-api/utils/__tests__/components.utils.spec.ts b/packages/twenty-server/src/engine/core-modules/open-api/utils/__tests__/components.utils.spec.ts index 8a953bc4540f..09d864377649 100644 --- a/packages/twenty-server/src/engine/core-modules/open-api/utils/__tests__/components.utils.spec.ts +++ b/packages/twenty-server/src/engine/core-modules/open-api/utils/__tests__/components.utils.spec.ts @@ -55,9 +55,6 @@ describe('computeSchemaComponents', () => { fieldNumeric: { type: 'number', }, - fieldProbability: { - type: 'number', - }, fieldLink: { properties: { label: { type: 'string' }, diff --git a/packages/twenty-server/src/engine/core-modules/open-api/utils/__tests__/parameters.utils.spec.ts b/packages/twenty-server/src/engine/core-modules/open-api/utils/__tests__/parameters.utils.spec.ts index 3fd99913c9c8..f91da6a750e6 100644 --- a/packages/twenty-server/src/engine/core-modules/open-api/utils/__tests__/parameters.utils.spec.ts +++ b/packages/twenty-server/src/engine/core-modules/open-api/utils/__tests__/parameters.utils.spec.ts @@ -9,10 +9,10 @@ import { computeOrderByParameters, computeStartingAfterParameters, } from 'src/engine/core-modules/open-api/utils/parameters.utils'; -import { DEFAULT_ORDER_DIRECTION } from 'src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/order-by-input.factory'; -import { FilterComparators } from 'src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/parse-base-filter.utils'; -import { Conjunctions } from 'src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/parse-filter.utils'; -import { DEFAULT_CONJUNCTION } from 'src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/add-default-conjunction.utils'; +import { DEFAULT_ORDER_DIRECTION } from 'src/engine/api/rest/input-factories/order-by-input.factory'; +import { FilterComparators } from 'src/engine/api/rest/core/query-builder/utils/filter-utils/parse-base-filter.utils'; +import { Conjunctions } from 'src/engine/api/rest/core/query-builder/utils/filter-utils/parse-filter.utils'; +import { DEFAULT_CONJUNCTION } from 'src/engine/api/rest/core/query-builder/utils/filter-utils/add-default-conjunction.utils'; describe('computeParameters', () => { describe('computeLimit', () => { @@ -68,7 +68,7 @@ describe('computeParameters', () => { required: false, schema: { type: 'integer', - enum: [1, 2], + enum: [0, 1, 2], }, }); }); diff --git a/packages/twenty-server/src/engine/core-modules/open-api/utils/components.utils.ts b/packages/twenty-server/src/engine/core-modules/open-api/utils/components.utils.ts index 62255806f168..6d65e82a26e6 100644 --- a/packages/twenty-server/src/engine/core-modules/open-api/utils/components.utils.ts +++ b/packages/twenty-server/src/engine/core-modules/open-api/utils/components.utils.ts @@ -35,7 +35,6 @@ const getFieldProperties = (type: FieldMetadataType): Property => { case FieldMetadataType.NUMBER: return { type: 'integer' }; case FieldMetadataType.NUMERIC: - case FieldMetadataType.PROBABILITY: case FieldMetadataType.RATING: case FieldMetadataType.POSITION: return { type: 'number' }; @@ -218,10 +217,9 @@ export const computeSchemaComponents = ( ); }; -export const computeParameterComponents = (): Record< - string, - OpenAPIV3_1.ParameterObject -> => { +export const computeParameterComponents = ( + fromMetadata = false, +): Record<string, OpenAPIV3_1.ParameterObject> => { return { idPath: computeIdPathParameter(), startingAfter: computeStartingAfterParameters(), @@ -229,7 +227,7 @@ export const computeParameterComponents = (): Record< filter: computeFilterParameters(), depth: computeDepthParameters(), orderBy: computeOrderByParameters(), - limit: computeLimitParameters(), + limit: computeLimitParameters(fromMetadata), }; }; diff --git a/packages/twenty-server/src/engine/core-modules/open-api/utils/parameters.utils.ts b/packages/twenty-server/src/engine/core-modules/open-api/utils/parameters.utils.ts index b07c297e0d8e..56034403a912 100644 --- a/packages/twenty-server/src/engine/core-modules/open-api/utils/parameters.utils.ts +++ b/packages/twenty-server/src/engine/core-modules/open-api/utils/parameters.utils.ts @@ -2,12 +2,14 @@ import { OpenAPIV3_1 } from 'openapi-types'; import { OrderByDirection } from 'src/engine/api/graphql/workspace-query-builder/interfaces/record.interface'; -import { FilterComparators } from 'src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/parse-base-filter.utils'; -import { Conjunctions } from 'src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/parse-filter.utils'; -import { DEFAULT_ORDER_DIRECTION } from 'src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/order-by-input.factory'; -import { DEFAULT_CONJUNCTION } from 'src/engine/api/rest/rest-api-core-query-builder/factories/input-factories/filter-utils/add-default-conjunction.utils'; +import { FilterComparators } from 'src/engine/api/rest/core/query-builder/utils/filter-utils/parse-base-filter.utils'; +import { Conjunctions } from 'src/engine/api/rest/core/query-builder/utils/filter-utils/parse-filter.utils'; +import { DEFAULT_ORDER_DIRECTION } from 'src/engine/api/rest/input-factories/order-by-input.factory'; +import { DEFAULT_CONJUNCTION } from 'src/engine/api/rest/core/query-builder/utils/filter-utils/add-default-conjunction.utils'; -export const computeLimitParameters = (): OpenAPIV3_1.ParameterObject => { +export const computeLimitParameters = ( + fromMetadata = false, +): OpenAPIV3_1.ParameterObject => { return { name: 'limit', in: 'query', @@ -16,8 +18,8 @@ export const computeLimitParameters = (): OpenAPIV3_1.ParameterObject => { schema: { type: 'integer', minimum: 0, - maximum: 60, - default: 60, + maximum: fromMetadata ? 1000 : 60, + default: fromMetadata ? 1000 : 60, }, }; }; @@ -57,7 +59,7 @@ export const computeDepthParameters = (): OpenAPIV3_1.ParameterObject => { required: false, schema: { type: 'integer', - enum: [1, 2], + enum: [0, 1, 2], }, }; }; diff --git a/packages/twenty-server/src/engine/core-modules/open-api/utils/path.utils.ts b/packages/twenty-server/src/engine/core-modules/open-api/utils/path.utils.ts index 37b1e217a415..fb73fb5ecb9e 100644 --- a/packages/twenty-server/src/engine/core-modules/open-api/utils/path.utils.ts +++ b/packages/twenty-server/src/engine/core-modules/open-api/utils/path.utils.ts @@ -105,7 +105,7 @@ export const computeSingleResultPath = ( }, patch: { tags: [item.namePlural], - summary: `Update One ${item.namePlural}`, + summary: `Update One ${item.nameSingular}`, operationId: `UpdateOne${capitalize(item.nameSingular)}`, parameters: [ { $ref: '#/components/parameters/idPath' }, diff --git a/packages/twenty-server/src/engine/core-modules/open-api/utils/responses.utils.ts b/packages/twenty-server/src/engine/core-modules/open-api/utils/responses.utils.ts index 7793a507f842..49264fee0e9f 100644 --- a/packages/twenty-server/src/engine/core-modules/open-api/utils/responses.utils.ts +++ b/packages/twenty-server/src/engine/core-modules/open-api/utils/responses.utils.ts @@ -3,6 +3,7 @@ import { capitalize } from 'src/utils/capitalize'; export const getFindManyResponse200 = ( item: Pick<ObjectMetadataEntity, 'nameSingular' | 'namePlural'>, + fromMetadata = false, ) => { return { description: 'Successful operation', @@ -19,7 +20,7 @@ export const getFindManyResponse200 = ( items: { $ref: `#/components/schemas/${capitalize( item.nameSingular, - )} with Relations`, + )}${!fromMetadata ? ' with Relations' : ''}`, }, }, }, @@ -32,9 +33,11 @@ export const getFindManyResponse200 = ( endCursor: { type: 'string' }, }, }, - totalCount: { - type: 'integer', - }, + ...(!fromMetadata && { + totalCount: { + type: 'integer', + }, + }), }, example: { data: { @@ -59,6 +62,7 @@ export const getFindManyResponse200 = ( export const getFindOneResponse200 = ( item: Pick<ObjectMetadataEntity, 'nameSingular'>, + fromMetadata = false, ) => { return { description: 'Successful operation', @@ -71,9 +75,9 @@ export const getFindOneResponse200 = ( type: 'object', properties: { [item.nameSingular]: { - $ref: `#/components/schemas/${capitalize( - item.nameSingular, - )} with Relations`, + $ref: `#/components/schemas/${capitalize(item.nameSingular)}${ + !fromMetadata ? ' with Relations' : '' + }`, }, }, }, diff --git a/packages/twenty-server/src/engine/core-modules/postgres-credentials/postgres-credentials.service.ts b/packages/twenty-server/src/engine/core-modules/postgres-credentials/postgres-credentials.service.ts index 6bdc67d43c99..790c36ab266e 100644 --- a/packages/twenty-server/src/engine/core-modules/postgres-credentials/postgres-credentials.service.ts +++ b/packages/twenty-server/src/engine/core-modules/postgres-credentials/postgres-credentials.service.ts @@ -1,5 +1,5 @@ -import { InjectRepository } from '@nestjs/typeorm'; import { BadRequestException } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; import { randomBytes } from 'crypto'; @@ -9,10 +9,10 @@ import { decryptText, encryptText, } from 'src/engine/core-modules/auth/auth.util'; -import { EnvironmentService } from 'src/engine/integrations/environment/environment.service'; -import { PostgresCredentials } from 'src/engine/core-modules/postgres-credentials/postgres-credentials.entity'; -import { NotFoundError } from 'src/engine/utils/graphql-errors.util'; +import { NotFoundError } from 'src/engine/core-modules/graphql/utils/graphql-errors.util'; import { PostgresCredentialsDTO } from 'src/engine/core-modules/postgres-credentials/dtos/postgres-credentials.dto'; +import { PostgresCredentials } from 'src/engine/core-modules/postgres-credentials/postgres-credentials.entity'; +import { EnvironmentService } from 'src/engine/integrations/environment/environment.service'; export class PostgresCredentialsService { constructor( diff --git a/packages/twenty-server/src/engine/core-modules/user-workspace/user-workspace.module.ts b/packages/twenty-server/src/engine/core-modules/user-workspace/user-workspace.module.ts index 09d3c621fc11..1fd86d27cbe2 100644 --- a/packages/twenty-server/src/engine/core-modules/user-workspace/user-workspace.module.ts +++ b/packages/twenty-server/src/engine/core-modules/user-workspace/user-workspace.module.ts @@ -9,6 +9,8 @@ import { UserWorkspaceService } from 'src/engine/core-modules/user-workspace/use import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module'; import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; import { User } from 'src/engine/core-modules/user/user.entity'; +import { TwentyORMModule } from 'src/engine/twenty-orm/twenty-orm.module'; +import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; @Module({ imports: [ @@ -21,6 +23,7 @@ import { User } from 'src/engine/core-modules/user/user.entity'; ], services: [UserWorkspaceService], }), + TwentyORMModule.forFeature([WorkspaceMemberWorkspaceEntity]), ], exports: [UserWorkspaceService], providers: [UserWorkspaceService], diff --git a/packages/twenty-server/src/engine/core-modules/user-workspace/user-workspace.service.ts b/packages/twenty-server/src/engine/core-modules/user-workspace/user-workspace.service.ts index bdeaa7535735..99c68f81ddd5 100644 --- a/packages/twenty-server/src/engine/core-modules/user-workspace/user-workspace.service.ts +++ b/packages/twenty-server/src/engine/core-modules/user-workspace/user-workspace.service.ts @@ -8,11 +8,12 @@ import { UserWorkspace } from 'src/engine/core-modules/user-workspace/user-works import { TypeORMService } from 'src/database/typeorm/typeorm.service'; import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; import { User } from 'src/engine/core-modules/user/user.entity'; -import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; import { ObjectRecordCreateEvent } from 'src/engine/integrations/event-emitter/types/object-record-create.event'; import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; import { assert } from 'src/utils/assert'; import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; +import { InjectWorkspaceRepository } from 'src/engine/twenty-orm/decorators/inject-workspace-repository.decorator'; +import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository'; export class UserWorkspaceService extends TypeOrmQueryService<UserWorkspace> { constructor( @@ -20,9 +21,10 @@ export class UserWorkspaceService extends TypeOrmQueryService<UserWorkspace> { private readonly userWorkspaceRepository: Repository<UserWorkspace>, @InjectRepository(User, 'core') private readonly userRepository: Repository<User>, + @InjectWorkspaceRepository(WorkspaceMemberWorkspaceEntity) + private readonly workspaceMemberRepository: WorkspaceRepository<WorkspaceMemberWorkspaceEntity>, private readonly dataSourceService: DataSourceService, private readonly typeORMService: TypeORMService, - private readonly workspaceDataSourceService: WorkspaceDataSourceService, private eventEmitter: EventEmitter2, ) { super(userWorkspaceRepository); @@ -99,23 +101,13 @@ export class UserWorkspaceService extends TypeOrmQueryService<UserWorkspace> { }); } - public async getWorkspaceMemberCount( - workspaceId: string, - ): Promise<number | undefined> { - try { - const dataSourceSchema = - this.workspaceDataSourceService.getSchemaName(workspaceId); - - return ( - await this.workspaceDataSourceService.executeRawQuery( - `SELECT * FROM ${dataSourceSchema}."workspaceMember"`, - [], - workspaceId, - ) - ).length; - } catch { + public async getWorkspaceMemberCount(): Promise<number | undefined> { + // TODO: to refactor, this could happen today for the first signup since the workspace does not exist yet + if (!this.workspaceMemberRepository) { return undefined; } + + return await this.workspaceMemberRepository.count(); } async checkUserWorkspaceExists( diff --git a/packages/twenty-server/src/engine/core-modules/user/services/user.service.ts b/packages/twenty-server/src/engine/core-modules/user/services/user.service.ts index 47b90a4197a7..853bafed4156 100644 --- a/packages/twenty-server/src/engine/core-modules/user/services/user.service.ts +++ b/packages/twenty-server/src/engine/core-modules/user/services/user.service.ts @@ -12,7 +12,6 @@ import { TypeORMService } from 'src/database/typeorm/typeorm.service'; import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity'; import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; import { ObjectRecordDeleteEvent } from 'src/engine/integrations/event-emitter/types/object-record-delete.event'; -import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record'; import { WorkspaceService } from 'src/engine/core-modules/workspace/services/workspace.service'; export class UserService extends TypeOrmQueryService<User> { @@ -113,8 +112,7 @@ export class UserService extends TypeOrmQueryService<User> { `SELECT * FROM ${dataSourceMetadata.schema}."workspaceMember"`, ); const workspaceMember = workspaceMembers.filter( - (member: ObjectRecord<WorkspaceMemberWorkspaceEntity>) => - member.userId === userId, + (member: WorkspaceMemberWorkspaceEntity) => member.userId === userId, )?.[0]; assert(workspaceMember, 'WorkspaceMember not found'); diff --git a/packages/twenty-server/src/engine/core-modules/user/user.entity.ts b/packages/twenty-server/src/engine/core-modules/user/user.entity.ts index 4a855db1035a..54c371481933 100644 --- a/packages/twenty-server/src/engine/core-modules/user/user.entity.ts +++ b/packages/twenty-server/src/engine/core-modules/user/user.entity.ts @@ -18,11 +18,11 @@ import { WorkspaceMember } from 'src/engine/core-modules/user/dtos/workspace-mem import { UserWorkspace } from 'src/engine/core-modules/user-workspace/user-workspace.entity'; import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars'; import { KeyValuePair } from 'src/engine/core-modules/key-value-pair/key-value-pair.entity'; -import { OnboardingStep } from 'src/engine/core-modules/onboarding/enums/onboarding-step.enum'; +import { OnboardingStatus } from 'src/engine/core-modules/onboarding/enums/onboarding-status.enum'; -registerEnumType(OnboardingStep, { - name: 'OnboardingStep', - description: 'Onboarding step', +registerEnumType(OnboardingStatus, { + name: 'OnboardingStatus', + description: 'Onboarding status', }); @Entity({ name: 'user', schema: 'core' }) @@ -119,6 +119,6 @@ export class User { @OneToMany(() => UserWorkspace, (userWorkspace) => userWorkspace.user) workspaces: Relation<UserWorkspace[]>; - @Field(() => OnboardingStep, { nullable: true }) - onboardingStep: OnboardingStep; + @Field(() => OnboardingStatus, { nullable: true }) + onboardingStatus: OnboardingStatus; } diff --git a/packages/twenty-server/src/engine/core-modules/user/user.resolver.ts b/packages/twenty-server/src/engine/core-modules/user/user.resolver.ts index ef596d19d0a5..93008f2502e1 100644 --- a/packages/twenty-server/src/engine/core-modules/user/user.resolver.ts +++ b/packages/twenty-server/src/engine/core-modules/user/user.resolver.ts @@ -27,8 +27,9 @@ import { DemoEnvGuard } from 'src/engine/guards/demo.env.guard'; import { JwtAuthGuard } from 'src/engine/guards/jwt.auth.guard'; import { User } from 'src/engine/core-modules/user/user.entity'; import { WorkspaceMember } from 'src/engine/core-modules/user/dtos/workspace-member.dto'; -import { OnboardingStep } from 'src/engine/core-modules/onboarding/enums/onboarding-step.enum'; +import { OnboardingStatus } from 'src/engine/core-modules/onboarding/enums/onboarding-status.enum'; import { OnboardingService } from 'src/engine/core-modules/onboarding/onboarding.service'; +import { LoadServiceWithWorkspaceContext } from 'src/engine/twenty-orm/context/load-service-with-workspace.context'; const getHMACKey = (email?: string, key?: string | null) => { if (!email || !key) return null; @@ -48,6 +49,7 @@ export class UserResolver { private readonly environmentService: EnvironmentService, private readonly fileUploadService: FileUploadService, private readonly onboardingService: OnboardingService, + private readonly loadServiceWithWorkspaceContext: LoadServiceWithWorkspaceContext, ) {} @Query(() => User) @@ -116,15 +118,13 @@ export class UserResolver { return this.userService.deleteUser(userId); } - @ResolveField(() => OnboardingStep) - async onboardingStep(@Parent() user: User): Promise<OnboardingStep | null> { - if (!user) { - return null; - } - - return this.onboardingService.getOnboardingStep( - user, - user.defaultWorkspace, + @ResolveField(() => OnboardingStatus) + async onboardingStatus(@Parent() user: User): Promise<OnboardingStatus> { + const contextInstance = await this.loadServiceWithWorkspaceContext.load( + this.onboardingService, + user.defaultWorkspaceId, ); + + return contextInstance.getOnboardingStatus(user); } } diff --git a/packages/twenty-server/src/engine/core-modules/workspace/handle-workspace-member-deleted.job.ts b/packages/twenty-server/src/engine/core-modules/workspace/handle-workspace-member-deleted.job.ts index 8ec5dad7ded7..7e3bce067751 100644 --- a/packages/twenty-server/src/engine/core-modules/workspace/handle-workspace-member-deleted.job.ts +++ b/packages/twenty-server/src/engine/core-modules/workspace/handle-workspace-member-deleted.job.ts @@ -1,19 +1,18 @@ -import { Injectable } from '@nestjs/common'; - -import { MessageQueueJob } from 'src/engine/integrations/message-queue/interfaces/message-queue-job.interface'; - import { WorkspaceService } from 'src/engine/core-modules/workspace/services/workspace.service'; +import { Processor } from 'src/engine/integrations/message-queue/decorators/processor.decorator'; +import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; +import { Process } from 'src/engine/integrations/message-queue/decorators/process.decorator'; export type HandleWorkspaceMemberDeletedJobData = { workspaceId: string; userId: string; }; -@Injectable() -export class HandleWorkspaceMemberDeletedJob - implements MessageQueueJob<HandleWorkspaceMemberDeletedJobData> -{ + +@Processor(MessageQueue.workspaceQueue) +export class HandleWorkspaceMemberDeletedJob { constructor(private readonly workspaceService: WorkspaceService) {} + @Process(HandleWorkspaceMemberDeletedJob.name) async handle(data: HandleWorkspaceMemberDeletedJobData): Promise<void> { const { workspaceId, userId } = data; diff --git a/packages/twenty-server/src/engine/core-modules/workspace/services/workspace.service.spec.ts b/packages/twenty-server/src/engine/core-modules/workspace/services/workspace.service.spec.ts index 87a10f16c6a2..696287311451 100644 --- a/packages/twenty-server/src/engine/core-modules/workspace/services/workspace.service.spec.ts +++ b/packages/twenty-server/src/engine/core-modules/workspace/services/workspace.service.spec.ts @@ -5,7 +5,7 @@ import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; import { WorkspaceManagerService } from 'src/engine/workspace-manager/workspace-manager.service'; import { UserWorkspace } from 'src/engine/core-modules/user-workspace/user-workspace.entity'; import { User } from 'src/engine/core-modules/user/user.entity'; -import { BillingService } from 'src/engine/core-modules/billing/billing.service'; +import { BillingWorkspaceService } from 'src/engine/core-modules/billing/billing.workspace-service'; import { UserWorkspaceService } from 'src/engine/core-modules/user-workspace/user-workspace.service'; import { UserService } from 'src/engine/core-modules/user/services/user.service'; import { EmailService } from 'src/engine/integrations/email/email.service'; @@ -46,7 +46,7 @@ describe('WorkspaceService', () => { useValue: {}, }, { - provide: BillingService, + provide: BillingWorkspaceService, useValue: {}, }, { diff --git a/packages/twenty-server/src/engine/core-modules/workspace/services/workspace.service.ts b/packages/twenty-server/src/engine/core-modules/workspace/services/workspace.service.ts index 185926b5afef..b546aedc62ea 100644 --- a/packages/twenty-server/src/engine/core-modules/workspace/services/workspace.service.ts +++ b/packages/twenty-server/src/engine/core-modules/workspace/services/workspace.service.ts @@ -1,24 +1,24 @@ -import { InjectRepository } from '@nestjs/typeorm'; import { BadRequestException } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; import assert from 'assert'; import { TypeOrmQueryService } from '@ptc-org/nestjs-query-typeorm'; -import { Repository } from 'typeorm'; -import { SendInviteLinkEmail } from 'twenty-emails'; import { render } from '@react-email/render'; +import { SendInviteLinkEmail } from 'twenty-emails'; +import { Repository } from 'typeorm'; -import { WorkspaceManagerService } from 'src/engine/workspace-manager/workspace-manager.service'; -import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; -import { User } from 'src/engine/core-modules/user/user.entity'; -import { ActivateWorkspaceInput } from 'src/engine/core-modules/workspace/dtos/activate-workspace-input'; +import { BillingWorkspaceService } from 'src/engine/core-modules/billing/billing.workspace-service'; +import { OnboardingService } from 'src/engine/core-modules/onboarding/onboarding.service'; import { UserWorkspace } from 'src/engine/core-modules/user-workspace/user-workspace.entity'; import { UserWorkspaceService } from 'src/engine/core-modules/user-workspace/user-workspace.service'; -import { BillingService } from 'src/engine/core-modules/billing/billing.service'; +import { User } from 'src/engine/core-modules/user/user.entity'; +import { ActivateWorkspaceInput } from 'src/engine/core-modules/workspace/dtos/activate-workspace-input'; import { SendInviteLink } from 'src/engine/core-modules/workspace/dtos/send-invite-link.entity'; +import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; import { EmailService } from 'src/engine/integrations/email/email.service'; import { EnvironmentService } from 'src/engine/integrations/environment/environment.service'; -import { OnboardingService } from 'src/engine/core-modules/onboarding/onboarding.service'; +import { WorkspaceManagerService } from 'src/engine/workspace-manager/workspace-manager.service'; export class WorkspaceService extends TypeOrmQueryService<Workspace> { constructor( @@ -30,7 +30,7 @@ export class WorkspaceService extends TypeOrmQueryService<Workspace> { private readonly userWorkspaceRepository: Repository<UserWorkspace>, private readonly workspaceManagerService: WorkspaceManagerService, private readonly userWorkspaceService: UserWorkspaceService, - private readonly billingService: BillingService, + private readonly billingWorkspaceService: BillingWorkspaceService, private readonly environmentService: EnvironmentService, private readonly emailService: EmailService, private readonly onboardingService: OnboardingService, @@ -64,7 +64,7 @@ export class WorkspaceService extends TypeOrmQueryService<Workspace> { assert(workspace, 'Workspace not found'); await this.userWorkspaceRepository.delete({ workspaceId: id }); - await this.billingService.deleteSubscription(workspace.id); + await this.billingWorkspaceService.deleteSubscription(workspace.id); await this.workspaceManagerService.delete(id); @@ -119,6 +119,7 @@ export class WorkspaceService extends TypeOrmQueryService<Workspace> { link: inviteLink, workspace: { name: workspace.displayName, logo: workspace.logo }, sender: { email: sender.email, firstName: sender.firstName }, + serverUrl: this.environmentService.get('SERVER_URL'), }; const emailTemplate = SendInviteLinkEmail(emailData); const html = render(emailTemplate, { diff --git a/packages/twenty-server/src/engine/core-modules/workspace/workspace-workspace-member.listener.ts b/packages/twenty-server/src/engine/core-modules/workspace/workspace-workspace-member.listener.ts index dbb717fcfd15..240b4eb1cf5f 100644 --- a/packages/twenty-server/src/engine/core-modules/workspace/workspace-workspace-member.listener.ts +++ b/packages/twenty-server/src/engine/core-modules/workspace/workspace-workspace-member.listener.ts @@ -1,4 +1,4 @@ -import { Inject, Injectable } from '@nestjs/common'; +import { Injectable } from '@nestjs/common'; import { OnEvent } from '@nestjs/event-emitter'; import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; @@ -9,11 +9,12 @@ import { HandleWorkspaceMemberDeletedJob, HandleWorkspaceMemberDeletedJobData, } from 'src/engine/core-modules/workspace/handle-workspace-member-deleted.job'; +import { InjectMessageQueue } from 'src/engine/integrations/message-queue/decorators/message-queue.decorator'; @Injectable() export class WorkspaceWorkspaceMemberListener { constructor( - @Inject(MessageQueue.workspaceQueue) + @InjectMessageQueue(MessageQueue.workspaceQueue) private readonly messageQueueService: MessageQueueService, ) {} diff --git a/packages/twenty-server/src/engine/core-modules/workspace/workspace.entity.ts b/packages/twenty-server/src/engine/core-modules/workspace/workspace.entity.ts index edc141b5580d..6b4d2b425343 100644 --- a/packages/twenty-server/src/engine/core-modules/workspace/workspace.entity.ts +++ b/packages/twenty-server/src/engine/core-modules/workspace/workspace.entity.ts @@ -10,7 +10,6 @@ import { Relation, UpdateDateColumn, } from 'typeorm'; -import Stripe from 'stripe'; import { User } from 'src/engine/core-modules/user/user.entity'; import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity'; @@ -85,12 +84,8 @@ export class Workspace { @OneToMany(() => FeatureFlagEntity, (featureFlag) => featureFlag.workspace) featureFlags: Relation<FeatureFlagEntity[]>; - @Field(() => String) - @Column({ type: 'text', default: 'incomplete' }) - subscriptionStatus: Stripe.Subscription.Status; - @Field({ nullable: true }) - currentBillingSubscription: BillingSubscription; + workspaceMembersCount: number; @Field() activationStatus: 'active' | 'inactive'; diff --git a/packages/twenty-server/src/engine/core-modules/workspace/workspace.module.ts b/packages/twenty-server/src/engine/core-modules/workspace/workspace.module.ts index 86f416fc4101..5e9668cabbd8 100644 --- a/packages/twenty-server/src/engine/core-modules/workspace/workspace.module.ts +++ b/packages/twenty-server/src/engine/core-modules/workspace/workspace.module.ts @@ -3,20 +3,20 @@ import { Module } from '@nestjs/common'; import { NestjsQueryGraphQLModule } from '@ptc-org/nestjs-query-graphql'; import { NestjsQueryTypeOrmModule } from '@ptc-org/nestjs-query-typeorm'; -import { WorkspaceManagerModule } from 'src/engine/workspace-manager/workspace-manager.module'; -import { WorkspaceResolver } from 'src/engine/core-modules/workspace/workspace.resolver'; import { TypeORMModule } from 'src/database/typeorm/typeorm.module'; +import { BillingModule } from 'src/engine/core-modules/billing/billing.module'; import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity'; +import { FileUploadModule } from 'src/engine/core-modules/file/file-upload/file-upload.module'; +import { OnboardingModule } from 'src/engine/core-modules/onboarding/onboarding.module'; import { UserWorkspace } from 'src/engine/core-modules/user-workspace/user-workspace.entity'; import { UserWorkspaceModule } from 'src/engine/core-modules/user-workspace/user-workspace.module'; -import { BillingModule } from 'src/engine/core-modules/billing/billing.module'; -import { FileUploadModule } from 'src/engine/core-modules/file/file-upload/file-upload.module'; -import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module'; +import { UserWorkspaceResolver } from 'src/engine/core-modules/user-workspace/user-workspace.resolver'; +import { User } from 'src/engine/core-modules/user/user.entity'; import { WorkspaceWorkspaceMemberListener } from 'src/engine/core-modules/workspace/workspace-workspace-member.listener'; +import { WorkspaceResolver } from 'src/engine/core-modules/workspace/workspace.resolver'; +import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module'; import { WorkspaceCacheVersionModule } from 'src/engine/metadata-modules/workspace-cache-version/workspace-cache-version.module'; -import { User } from 'src/engine/core-modules/user/user.entity'; -import { UserWorkspaceResolver } from 'src/engine/core-modules/user-workspace/user-workspace.resolver'; -import { OnboardingModule } from 'src/engine/core-modules/onboarding/onboarding.module'; +import { WorkspaceManagerModule } from 'src/engine/workspace-manager/workspace-manager.module'; import { workspaceAutoResolverOpts } from './workspace.auto-resolver-opts'; import { Workspace } from './workspace.entity'; diff --git a/packages/twenty-server/src/engine/core-modules/workspace/workspace.resolver.ts b/packages/twenty-server/src/engine/core-modules/workspace/workspace.resolver.ts index a30853ac2c54..5ead7800d66d 100644 --- a/packages/twenty-server/src/engine/core-modules/workspace/workspace.resolver.ts +++ b/packages/twenty-server/src/engine/core-modules/workspace/workspace.resolver.ts @@ -22,11 +22,12 @@ import { User } from 'src/engine/core-modules/user/user.entity'; import { AuthUser } from 'src/engine/decorators/auth/auth-user.decorator'; import { ActivateWorkspaceInput } from 'src/engine/core-modules/workspace/dtos/activate-workspace-input'; import { BillingSubscription } from 'src/engine/core-modules/billing/entities/billing-subscription.entity'; -import { BillingService } from 'src/engine/core-modules/billing/billing.service'; +import { BillingWorkspaceService } from 'src/engine/core-modules/billing/billing.workspace-service'; import { DemoEnvGuard } from 'src/engine/guards/demo.env.guard'; import { WorkspaceCacheVersionService } from 'src/engine/metadata-modules/workspace-cache-version/workspace-cache-version.service'; import { SendInviteLink } from 'src/engine/core-modules/workspace/dtos/send-invite-link.entity'; import { SendInviteLinkInput } from 'src/engine/core-modules/workspace/dtos/send-invite-link.input'; +import { UserWorkspaceService } from 'src/engine/core-modules/user-workspace/user-workspace.service'; import { Workspace } from './workspace.entity'; @@ -38,8 +39,9 @@ export class WorkspaceResolver { constructor( private readonly workspaceService: WorkspaceService, private readonly workspaceCacheVersionService: WorkspaceCacheVersionService, + private readonly userWorkspaceService: UserWorkspaceService, private readonly fileUploadService: FileUploadService, - private readonly billingService: BillingService, + private readonly billingWorkspaceService: BillingWorkspaceService, ) {} @Query(() => Workspace) @@ -116,15 +118,20 @@ export class WorkspaceResolver { return this.workspaceCacheVersionService.getVersion(workspace.id); } - @ResolveField(() => BillingSubscription) + @ResolveField(() => BillingSubscription, { nullable: true }) async currentBillingSubscription( @Parent() workspace: Workspace, ): Promise<BillingSubscription | null> { - return this.billingService.getCurrentBillingSubscription({ + return this.billingWorkspaceService.getCurrentBillingSubscription({ workspaceId: workspace.id, }); } + @ResolveField(() => Number) + async workspaceMembersCount(): Promise<number | undefined> { + return await this.userWorkspaceService.getWorkspaceMemberCount(); + } + @Mutation(() => SendInviteLink) async sendInviteLink( @Args() sendInviteLinkInput: SendInviteLinkInput, diff --git a/packages/twenty-server/src/engine/integrations/cache-storage/types/cache-storage-namespace.enum.ts b/packages/twenty-server/src/engine/integrations/cache-storage/types/cache-storage-namespace.enum.ts index 5ef0221bc969..e89fb00b0396 100644 --- a/packages/twenty-server/src/engine/integrations/cache-storage/types/cache-storage-namespace.enum.ts +++ b/packages/twenty-server/src/engine/integrations/cache-storage/types/cache-storage-namespace.enum.ts @@ -1,4 +1,5 @@ export enum CacheStorageNamespace { Messaging = 'messaging', + Calendar = 'calendar', WorkspaceSchema = 'workspaceSchema', } diff --git a/packages/twenty-server/src/engine/integrations/captcha/captcha.module.ts b/packages/twenty-server/src/engine/integrations/captcha/captcha.module.ts index 891bed2e5e12..506e51f42b2f 100644 --- a/packages/twenty-server/src/engine/integrations/captcha/captcha.module.ts +++ b/packages/twenty-server/src/engine/integrations/captcha/captcha.module.ts @@ -22,7 +22,7 @@ export class CaptchaModule { } switch (config.type) { - case CaptchaDriverType.GoogleRecatpcha: + case CaptchaDriverType.GoogleRecaptcha: return new GoogleRecaptchaDriver(config.options); case CaptchaDriverType.Turnstile: return new TurnstileDriver(config.options); diff --git a/packages/twenty-server/src/engine/integrations/captcha/interfaces/captcha.interface.ts b/packages/twenty-server/src/engine/integrations/captcha/interfaces/captcha.interface.ts index e7f0ca5620bd..f19e15fa2985 100644 --- a/packages/twenty-server/src/engine/integrations/captcha/interfaces/captcha.interface.ts +++ b/packages/twenty-server/src/engine/integrations/captcha/interfaces/captcha.interface.ts @@ -2,7 +2,7 @@ import { FactoryProvider, ModuleMetadata } from '@nestjs/common'; import { registerEnumType } from '@nestjs/graphql'; export enum CaptchaDriverType { - GoogleRecatpcha = 'google-recaptcha', + GoogleRecaptcha = 'google-recaptcha', Turnstile = 'turnstile', } @@ -15,8 +15,8 @@ export type CaptchaDriverOptions = { secretKey: string; }; -export interface GoogleRecatpchaDriverFactoryOptions { - type: CaptchaDriverType.GoogleRecatpcha; +export interface GoogleRecaptchaDriverFactoryOptions { + type: CaptchaDriverType.GoogleRecaptcha; options: CaptchaDriverOptions; } @@ -26,7 +26,7 @@ export interface TurnstileDriverFactoryOptions { } export type CaptchaModuleOptions = - | GoogleRecatpchaDriverFactoryOptions + | GoogleRecaptchaDriverFactoryOptions | TurnstileDriverFactoryOptions; export type CaptchaModuleAsyncOptions = { diff --git a/packages/twenty-server/src/engine/integrations/email/email-sender.job.ts b/packages/twenty-server/src/engine/integrations/email/email-sender.job.ts index 7b284d4b26c3..d97117d5063c 100644 --- a/packages/twenty-server/src/engine/integrations/email/email-sender.job.ts +++ b/packages/twenty-server/src/engine/integrations/email/email-sender.job.ts @@ -1,15 +1,15 @@ -import { Injectable } from '@nestjs/common'; - import { SendMailOptions } from 'nodemailer'; -import { MessageQueueJob } from 'src/engine/integrations/message-queue/interfaces/message-queue-job.interface'; - import { EmailSenderService } from 'src/engine/integrations/email/email-sender.service'; +import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; +import { Processor } from 'src/engine/integrations/message-queue/decorators/processor.decorator'; +import { Process } from 'src/engine/integrations/message-queue/decorators/process.decorator'; -@Injectable() -export class EmailSenderJob implements MessageQueueJob<SendMailOptions> { +@Processor(MessageQueue.emailQueue) +export class EmailSenderJob { constructor(private readonly emailSenderService: EmailSenderService) {} + @Process(EmailSenderJob.name) async handle(data: SendMailOptions): Promise<void> { await this.emailSenderService.send(data); } diff --git a/packages/twenty-server/src/engine/integrations/email/email.service.ts b/packages/twenty-server/src/engine/integrations/email/email.service.ts index a149c78023b2..79217adb8d1e 100644 --- a/packages/twenty-server/src/engine/integrations/email/email.service.ts +++ b/packages/twenty-server/src/engine/integrations/email/email.service.ts @@ -1,15 +1,16 @@ -import { Inject, Injectable } from '@nestjs/common'; +import { Injectable } from '@nestjs/common'; import { SendMailOptions } from 'nodemailer'; import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service'; import { EmailSenderJob } from 'src/engine/integrations/email/email-sender.job'; +import { InjectMessageQueue } from 'src/engine/integrations/message-queue/decorators/message-queue.decorator'; @Injectable() export class EmailService { constructor( - @Inject(MessageQueue.emailQueue) + @InjectMessageQueue(MessageQueue.emailQueue) private readonly messageQueueService: MessageQueueService, ) {} diff --git a/packages/twenty-server/src/engine/integrations/environment/environment-variables.ts b/packages/twenty-server/src/engine/integrations/environment/environment-variables.ts index 8d739dcea957..91dfabab3312 100644 --- a/packages/twenty-server/src/engine/integrations/environment/environment-variables.ts +++ b/packages/twenty-server/src/engine/integrations/environment/environment-variables.ts @@ -17,6 +17,8 @@ import { import { EmailDriver } from 'src/engine/integrations/email/interfaces/email.interface'; import { NodeEnvironment } from 'src/engine/integrations/environment/interfaces/node-environment.interface'; +import { LLMChatModelDriver } from 'src/engine/integrations/llm-chat-model/interfaces/llm-chat-model.interface'; +import { LLMTracingDriver } from 'src/engine/integrations/llm-tracing/interfaces/llm-tracing.interface'; import { assert } from 'src/utils/assert'; import { CastToStringArray } from 'src/engine/integrations/environment/decorators/cast-to-string-array.decorator'; @@ -220,6 +222,16 @@ export class EnvironmentVariables { @IsOptional() STORAGE_S3_ENDPOINT: string; + @ValidateIf((env) => env.STORAGE_TYPE === StorageDriverType.S3) + @IsString() + @IsOptional() + STORAGE_S3_ACCESS_KEY_ID: string; + + @ValidateIf((env) => env.STORAGE_TYPE === StorageDriverType.S3) + @IsString() + @IsOptional() + STORAGE_S3_SECRET_ACCESS_KEY: string; + @IsString() @ValidateIf((env) => env.STORAGE_TYPE === StorageDriverType.Local) STORAGE_LOCAL_PATH = '.local-storage'; @@ -324,7 +336,7 @@ export class EnvironmentVariables { @CastToPositiveNumber() @IsOptional() @IsNumber() - MUTATION_MAXIMUM_RECORD_AFFECTED = 100; + MUTATION_MAXIMUM_AFFECTED_RECORDS = 100; REDIS_HOST = '127.0.0.1'; @@ -359,6 +371,16 @@ export class EnvironmentVariables { OPENROUTER_API_KEY: string; + LLM_CHAT_MODEL_DRIVER: LLMChatModelDriver; + + OPENAI_API_KEY: string; + + LANGFUSE_SECRET_KEY: string; + + LANGFUSE_PUBLIC_KEY: string; + + LLM_TRACING_DRIVER: LLMTracingDriver = LLMTracingDriver.Console; + @CastToPositiveNumber() API_RATE_LIMITING_TTL = 100; @@ -376,6 +398,15 @@ export class EnvironmentVariables { AUTH_GOOGLE_APIS_CALLBACK_URL: string; CHROME_EXTENSION_ID: string; + + // --------------------------------------- + // Funnelmink + // --------------------------------------- + + @CastToBoolean() + @IsBoolean() + @IsOptional() + FUNNELMINK_PREFILL_NEW_WORKSPACES_WITH_FSM_OBJECTS = true; } export const validate = ( diff --git a/packages/twenty-server/src/engine/integrations/event-emitter/utils/__tests__/object-record-changed-values.spec.ts b/packages/twenty-server/src/engine/integrations/event-emitter/utils/__tests__/object-record-changed-values.spec.ts index 9da50ae4c899..9e4e51791a20 100644 --- a/packages/twenty-server/src/engine/integrations/event-emitter/utils/__tests__/object-record-changed-values.spec.ts +++ b/packages/twenty-server/src/engine/integrations/event-emitter/utils/__tests__/object-record-changed-values.spec.ts @@ -22,8 +22,16 @@ const mockObjectMetadata: ObjectMetadataInterface = { describe('objectRecordChangedValues', () => { it('detects changes in scalar values correctly', () => { - const oldRecord = { id: 1, name: 'Original Name', updatedAt: new Date() }; - const newRecord = { id: 1, name: 'Updated Name', updatedAt: new Date() }; + const oldRecord = { + id: '74316f58-29b0-4a6a-b8fa-d2b506d5516m', + name: 'Original Name', + updatedAt: new Date().toString(), + }; + const newRecord = { + id: '74316f58-29b0-4a6a-b8fa-d2b506d5516m', + name: 'Updated Name', + updatedAt: new Date().toString(), + }; const result = objectRecordChangedValues( oldRecord, @@ -38,8 +46,14 @@ describe('objectRecordChangedValues', () => { }); it('ignores changes to the updatedAt field', () => { - const oldRecord = { id: 1, updatedAt: new Date('2020-01-01') }; - const newRecord = { id: 1, updatedAt: new Date('2024-01-01') }; + const oldRecord = { + id: '74316f58-29b0-4a6a-b8fa-d2b506d5516d', + updatedAt: new Date('2020-01-01').toDateString(), + }; + const newRecord = { + id: '74316f58-29b0-4a6a-b8fa-d2b506d5516d', + updatedAt: new Date('2024-01-01').toDateString(), + }; const result = objectRecordChangedValues( oldRecord, @@ -51,8 +65,16 @@ it('ignores changes to the updatedAt field', () => { }); it('returns an empty object when there are no changes', () => { - const oldRecord = { id: 1, name: 'Name', value: 100 }; - const newRecord = { id: 1, name: 'Name', value: 100 }; + const oldRecord = { + id: '74316f58-29b0-4a6a-b8fa-d2b506d5516k', + name: 'Name', + value: 100, + }; + const newRecord = { + id: '74316f58-29b0-4a6a-b8fa-d2b506d5516k', + name: 'Name', + value: 100, + }; const result = objectRecordChangedValues( oldRecord, @@ -65,17 +87,17 @@ it('returns an empty object when there are no changes', () => { it('correctly handles a mix of changed, unchanged, and special case values', () => { const oldRecord = { - id: 1, + id: '74316f58-29b0-4a6a-b8fa-d2b506d5516l', name: 'Original', status: 'active', - updatedAt: new Date(2020, 1, 1), + updatedAt: new Date(2020, 1, 1).toDateString(), config: { theme: 'dark' }, }; const newRecord = { - id: 1, + id: '74316f58-29b0-4a6a-b8fa-d2b506d5516l', name: 'Updated', status: 'active', - updatedAt: new Date(2021, 1, 1), + updatedAt: new Date(2021, 1, 1).toDateString(), config: { theme: 'light' }, }; const expectedChanges = { diff --git a/packages/twenty-server/src/engine/integrations/event-emitter/utils/object-record-changed-properties.util.ts b/packages/twenty-server/src/engine/integrations/event-emitter/utils/object-record-changed-properties.util.ts index 53e2c7658be5..5d77c207623c 100644 --- a/packages/twenty-server/src/engine/integrations/event-emitter/utils/object-record-changed-properties.util.ts +++ b/packages/twenty-server/src/engine/integrations/event-emitter/utils/object-record-changed-properties.util.ts @@ -1,8 +1,14 @@ import deepEqual from 'deep-equal'; -export const objectRecordChangedProperties = ( - oldRecord: Record<string, any>, - newRecord: Record<string, any>, +import { Record } from 'src/engine/api/graphql/workspace-query-builder/interfaces/record.interface'; + +import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity'; + +export const objectRecordChangedProperties = < + PRecord extends Partial<Record | BaseWorkspaceEntity> = Partial<Record>, +>( + oldRecord: PRecord, + newRecord: PRecord, ) => { const changedProperties = Object.keys(newRecord).filter( (key) => !deepEqual(oldRecord[key], newRecord[key]), diff --git a/packages/twenty-server/src/engine/integrations/event-emitter/utils/object-record-changed-values.ts b/packages/twenty-server/src/engine/integrations/event-emitter/utils/object-record-changed-values.ts index ff300042d96a..062693cbd5d1 100644 --- a/packages/twenty-server/src/engine/integrations/event-emitter/utils/object-record-changed-values.ts +++ b/packages/twenty-server/src/engine/integrations/event-emitter/utils/object-record-changed-values.ts @@ -1,12 +1,13 @@ import deepEqual from 'deep-equal'; import { ObjectMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/object-metadata.interface'; +import { Record as IRecord } from 'src/engine/api/graphql/workspace-query-builder/interfaces/record.interface'; import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; export const objectRecordChangedValues = ( - oldRecord: Record<string, any>, - newRecord: Record<string, any>, + oldRecord: Partial<IRecord>, + newRecord: Partial<IRecord>, objectMetadata: ObjectMetadataInterface, ) => { const changedValues = Object.keys(newRecord).reduce( diff --git a/packages/twenty-server/src/engine/integrations/exception-handler/hooks/use-exception-handler.hook.ts b/packages/twenty-server/src/engine/integrations/exception-handler/hooks/use-exception-handler.hook.ts index cdfae3bf7608..bb4522796c34 100644 --- a/packages/twenty-server/src/engine/integrations/exception-handler/hooks/use-exception-handler.hook.ts +++ b/packages/twenty-server/src/engine/integrations/exception-handler/hooks/use-exception-handler.hook.ts @@ -1,10 +1,10 @@ -import { GraphQLError, Kind, OperationDefinitionNode, print } from 'graphql'; import { - getDocumentString, - handleStreamOrSingleExecutionResult, OnExecuteDoneHookResultOnNextHook, Plugin, + getDocumentString, + handleStreamOrSingleExecutionResult, } from '@envelop/core'; +import { GraphQLError, Kind, OperationDefinitionNode, print } from 'graphql'; import { GraphQLContext } from 'src/engine/api/graphql/graphql-config/interfaces/graphql-context.interface'; @@ -26,6 +26,9 @@ export type ExceptionHandlerPluginOptions = { eventIdKey?: string | null; }; +// This hook is deprecated. +// We should either handle exception in the context of graphql, controller or command +// @deprecated export const useExceptionHandler = <PluginContext extends GraphQLContext>( options: ExceptionHandlerPluginOptions, ): Plugin<PluginContext> => { diff --git a/packages/twenty-server/src/engine/integrations/file-storage/file-storage.module-factory.ts b/packages/twenty-server/src/engine/integrations/file-storage/file-storage.module-factory.ts index f846dc96df89..b1ab03642ef3 100644 --- a/packages/twenty-server/src/engine/integrations/file-storage/file-storage.module-factory.ts +++ b/packages/twenty-server/src/engine/integrations/file-storage/file-storage.module-factory.ts @@ -32,15 +32,24 @@ export const fileStorageModuleFactory = async ( const bucketName = environmentService.get('STORAGE_S3_NAME'); const endpoint = environmentService.get('STORAGE_S3_ENDPOINT'); const region = environmentService.get('STORAGE_S3_REGION'); + const accessKeyId = environmentService.get('STORAGE_S3_ACCESS_KEY_ID'); + const secretAccessKey = environmentService.get( + 'STORAGE_S3_SECRET_ACCESS_KEY', + ); return { type: StorageDriverType.S3, options: { bucketName: bucketName ?? '', endpoint: endpoint, - credentials: fromNodeProviderChain({ - clientConfig: { region }, - }), + credentials: accessKeyId + ? { + accessKeyId, + secretAccessKey, + } + : fromNodeProviderChain({ + clientConfig: { region }, + }), forcePathStyle: true, region: region ?? '', }, diff --git a/packages/twenty-server/src/engine/integrations/integrations.module.ts b/packages/twenty-server/src/engine/integrations/integrations.module.ts index df855478af6e..fb2f40051ec7 100644 --- a/packages/twenty-server/src/engine/integrations/integrations.module.ts +++ b/packages/twenty-server/src/engine/integrations/integrations.module.ts @@ -12,6 +12,10 @@ import { emailModuleFactory } from 'src/engine/integrations/email/email.module-f import { CacheStorageModule } from 'src/engine/integrations/cache-storage/cache-storage.module'; import { CaptchaModule } from 'src/engine/integrations/captcha/captcha.module'; import { captchaModuleFactory } from 'src/engine/integrations/captcha/captcha.module-factory'; +import { LLMChatModelModule } from 'src/engine/integrations/llm-chat-model/llm-chat-model.module'; +import { llmChatModelModuleFactory } from 'src/engine/integrations/llm-chat-model/llm-chat-model.module-factory'; +import { LLMTracingModule } from 'src/engine/integrations/llm-tracing/llm-tracing.module'; +import { llmTracingModuleFactory } from 'src/engine/integrations/llm-tracing/llm-tracing.module-factory'; import { EnvironmentModule } from './environment/environment.module'; import { EnvironmentService } from './environment/environment.service'; @@ -30,7 +34,7 @@ import { MessageQueueModule } from './message-queue/message-queue.module'; useFactory: loggerModuleFactory, inject: [EnvironmentService], }), - MessageQueueModule.forRoot({ + MessageQueueModule.registerAsync({ useFactory: messageQueueModuleFactory, inject: [EnvironmentService], }), @@ -50,6 +54,14 @@ import { MessageQueueModule } from './message-queue/message-queue.module'; wildcard: true, }), CacheStorageModule, + LLMChatModelModule.forRoot({ + useFactory: llmChatModelModuleFactory, + inject: [EnvironmentService], + }), + LLMTracingModule.forRoot({ + useFactory: llmTracingModuleFactory, + inject: [EnvironmentService], + }), ], exports: [], providers: [], diff --git a/packages/twenty-server/src/engine/integrations/llm-chat-model/drivers/interfaces/llm-prompt-template-driver.interface.ts b/packages/twenty-server/src/engine/integrations/llm-chat-model/drivers/interfaces/llm-prompt-template-driver.interface.ts new file mode 100644 index 000000000000..cef61eccd353 --- /dev/null +++ b/packages/twenty-server/src/engine/integrations/llm-chat-model/drivers/interfaces/llm-prompt-template-driver.interface.ts @@ -0,0 +1,5 @@ +import { BaseChatModel } from '@langchain/core/language_models/chat_models'; + +export interface LLMChatModelDriver { + getJSONChatModel(): BaseChatModel; +} diff --git a/packages/twenty-server/src/engine/integrations/llm-chat-model/drivers/openai.driver.ts b/packages/twenty-server/src/engine/integrations/llm-chat-model/drivers/openai.driver.ts new file mode 100644 index 000000000000..652a854ef831 --- /dev/null +++ b/packages/twenty-server/src/engine/integrations/llm-chat-model/drivers/openai.driver.ts @@ -0,0 +1,22 @@ +import { BaseChatModel } from '@langchain/core/language_models/chat_models'; +import { ChatOpenAI } from '@langchain/openai'; + +import { LLMChatModelDriver } from 'src/engine/integrations/llm-chat-model/drivers/interfaces/llm-prompt-template-driver.interface'; + +export class OpenAIDriver implements LLMChatModelDriver { + private chatModel: BaseChatModel; + + constructor() { + this.chatModel = new ChatOpenAI({ + model: 'gpt-4o', + }).bind({ + response_format: { + type: 'json_object', + }, + }) as unknown as BaseChatModel; + } + + getJSONChatModel() { + return this.chatModel; + } +} diff --git a/packages/twenty-server/src/engine/integrations/llm-chat-model/interfaces/llm-chat-model.interface.ts b/packages/twenty-server/src/engine/integrations/llm-chat-model/interfaces/llm-chat-model.interface.ts new file mode 100644 index 000000000000..5c6edbcd0237 --- /dev/null +++ b/packages/twenty-server/src/engine/integrations/llm-chat-model/interfaces/llm-chat-model.interface.ts @@ -0,0 +1,14 @@ +import { ModuleMetadata, FactoryProvider } from '@nestjs/common'; + +export enum LLMChatModelDriver { + OpenAI = 'openai', +} + +export interface LLMChatModelModuleOptions { + type: LLMChatModelDriver; +} + +export type LLMChatModelModuleAsyncOptions = { + useFactory: (...args: any[]) => LLMChatModelModuleOptions | undefined; +} & Pick<ModuleMetadata, 'imports'> & + Pick<FactoryProvider, 'inject'>; diff --git a/packages/twenty-server/src/engine/integrations/llm-chat-model/llm-chat-model.constants.ts b/packages/twenty-server/src/engine/integrations/llm-chat-model/llm-chat-model.constants.ts new file mode 100644 index 000000000000..e6c3ea7b0e5c --- /dev/null +++ b/packages/twenty-server/src/engine/integrations/llm-chat-model/llm-chat-model.constants.ts @@ -0,0 +1 @@ +export const LLM_CHAT_MODEL_DRIVER = Symbol('LLM_CHAT_MODEL_DRIVER'); diff --git a/packages/twenty-server/src/engine/integrations/llm-chat-model/llm-chat-model.module-factory.ts b/packages/twenty-server/src/engine/integrations/llm-chat-model/llm-chat-model.module-factory.ts new file mode 100644 index 000000000000..2d91f280ce54 --- /dev/null +++ b/packages/twenty-server/src/engine/integrations/llm-chat-model/llm-chat-model.module-factory.ts @@ -0,0 +1,17 @@ +import { LLMChatModelDriver } from 'src/engine/integrations/llm-chat-model/interfaces/llm-chat-model.interface'; + +import { EnvironmentService } from 'src/engine/integrations/environment/environment.service'; + +export const llmChatModelModuleFactory = ( + environmentService: EnvironmentService, +) => { + const driver = environmentService.get('LLM_CHAT_MODEL_DRIVER'); + + switch (driver) { + case LLMChatModelDriver.OpenAI: { + return { type: LLMChatModelDriver.OpenAI }; + } + default: + // `No LLM chat model driver (${driver})`); + } +}; diff --git a/packages/twenty-server/src/engine/integrations/llm-chat-model/llm-chat-model.module.ts b/packages/twenty-server/src/engine/integrations/llm-chat-model/llm-chat-model.module.ts new file mode 100644 index 000000000000..279993f72868 --- /dev/null +++ b/packages/twenty-server/src/engine/integrations/llm-chat-model/llm-chat-model.module.ts @@ -0,0 +1,35 @@ +import { DynamicModule, Global } from '@nestjs/common'; + +import { + LLMChatModelDriver, + LLMChatModelModuleAsyncOptions, +} from 'src/engine/integrations/llm-chat-model/interfaces/llm-chat-model.interface'; + +import { LLM_CHAT_MODEL_DRIVER } from 'src/engine/integrations/llm-chat-model/llm-chat-model.constants'; +import { OpenAIDriver } from 'src/engine/integrations/llm-chat-model/drivers/openai.driver'; +import { LLMChatModelService } from 'src/engine/integrations/llm-chat-model/llm-chat-model.service'; + +@Global() +export class LLMChatModelModule { + static forRoot(options: LLMChatModelModuleAsyncOptions): DynamicModule { + const provider = { + provide: LLM_CHAT_MODEL_DRIVER, + useFactory: (...args: any[]) => { + const config = options.useFactory(...args); + + switch (config?.type) { + case LLMChatModelDriver.OpenAI: { + return new OpenAIDriver(); + } + } + }, + inject: options.inject || [], + }; + + return { + module: LLMChatModelModule, + providers: [LLMChatModelService, provider], + exports: [LLMChatModelService], + }; + } +} diff --git a/packages/twenty-server/src/engine/integrations/llm-chat-model/llm-chat-model.service.ts b/packages/twenty-server/src/engine/integrations/llm-chat-model/llm-chat-model.service.ts new file mode 100644 index 000000000000..62beea8c6eca --- /dev/null +++ b/packages/twenty-server/src/engine/integrations/llm-chat-model/llm-chat-model.service.ts @@ -0,0 +1,16 @@ +import { Injectable, Inject } from '@nestjs/common'; + +import { LLMChatModelDriver } from 'src/engine/integrations/llm-chat-model/drivers/interfaces/llm-prompt-template-driver.interface'; + +import { LLM_CHAT_MODEL_DRIVER } from 'src/engine/integrations/llm-chat-model/llm-chat-model.constants'; + +@Injectable() +export class LLMChatModelService { + constructor( + @Inject(LLM_CHAT_MODEL_DRIVER) private driver: LLMChatModelDriver, + ) {} + + getJSONChatModel() { + return this.driver.getJSONChatModel(); + } +} diff --git a/packages/twenty-server/src/engine/integrations/llm-tracing/drivers/console.driver.ts b/packages/twenty-server/src/engine/integrations/llm-tracing/drivers/console.driver.ts new file mode 100644 index 000000000000..47e126324d97 --- /dev/null +++ b/packages/twenty-server/src/engine/integrations/llm-tracing/drivers/console.driver.ts @@ -0,0 +1,25 @@ +import { BaseCallbackHandler } from '@langchain/core/callbacks/base'; +import { ConsoleCallbackHandler } from '@langchain/core/tracers/console'; +import { Run } from '@langchain/core/tracers/base'; + +import { LLMTracingDriver } from 'src/engine/integrations/llm-tracing/drivers/interfaces/llm-tracing-driver.interface'; + +class WithMetadataConsoleCallbackHandler extends ConsoleCallbackHandler { + private metadata: Record<string, unknown>; + + constructor(metadata: Record<string, unknown>) { + super(); + this.metadata = metadata; + } + + onChainStart(run: Run) { + console.log(`Chain metadata: ${JSON.stringify(this.metadata)}`); + super.onChainStart(run); + } +} + +export class ConsoleDriver implements LLMTracingDriver { + getCallbackHandler(metadata: Record<string, unknown>): BaseCallbackHandler { + return new WithMetadataConsoleCallbackHandler(metadata); + } +} diff --git a/packages/twenty-server/src/engine/integrations/llm-tracing/drivers/interfaces/llm-tracing-driver.interface.ts b/packages/twenty-server/src/engine/integrations/llm-tracing/drivers/interfaces/llm-tracing-driver.interface.ts new file mode 100644 index 000000000000..fe1944a60c08 --- /dev/null +++ b/packages/twenty-server/src/engine/integrations/llm-tracing/drivers/interfaces/llm-tracing-driver.interface.ts @@ -0,0 +1,5 @@ +import { BaseCallbackHandler } from '@langchain/core/callbacks/base'; + +export interface LLMTracingDriver { + getCallbackHandler(metadata: Record<string, unknown>): BaseCallbackHandler; +} diff --git a/packages/twenty-server/src/engine/integrations/llm-tracing/drivers/langfuse.driver.ts b/packages/twenty-server/src/engine/integrations/llm-tracing/drivers/langfuse.driver.ts new file mode 100644 index 000000000000..b9b84aad0860 --- /dev/null +++ b/packages/twenty-server/src/engine/integrations/llm-tracing/drivers/langfuse.driver.ts @@ -0,0 +1,26 @@ +import { BaseCallbackHandler } from '@langchain/core/callbacks/base'; +import CallbackHandler from 'langfuse-langchain'; + +import { LLMTracingDriver } from 'src/engine/integrations/llm-tracing/drivers/interfaces/llm-tracing-driver.interface'; + +export interface LangfuseDriverOptions { + secretKey: string; + publicKey: string; +} + +export class LangfuseDriver implements LLMTracingDriver { + private options: LangfuseDriverOptions; + + constructor(options: LangfuseDriverOptions) { + this.options = options; + } + + getCallbackHandler(metadata: Record<string, unknown>): BaseCallbackHandler { + return new CallbackHandler({ + secretKey: this.options.secretKey, + publicKey: this.options.publicKey, + baseUrl: 'https://cloud.langfuse.com', + metadata: metadata, + }); + } +} diff --git a/packages/twenty-server/src/engine/integrations/llm-tracing/interfaces/llm-tracing.interface.ts b/packages/twenty-server/src/engine/integrations/llm-tracing/interfaces/llm-tracing.interface.ts new file mode 100644 index 000000000000..a97031499b10 --- /dev/null +++ b/packages/twenty-server/src/engine/integrations/llm-tracing/interfaces/llm-tracing.interface.ts @@ -0,0 +1,26 @@ +import { ModuleMetadata, FactoryProvider } from '@nestjs/common'; + +import { LangfuseDriverOptions } from 'src/engine/integrations/llm-tracing/drivers/langfuse.driver'; + +export enum LLMTracingDriver { + Langfuse = 'langfuse', + Console = 'console', +} + +export interface LangfuseDriverFactoryOptions { + type: LLMTracingDriver.Langfuse; + options: LangfuseDriverOptions; +} + +export interface ConsoleDriverFactoryOptions { + type: LLMTracingDriver.Console; +} + +export type LLMTracingModuleOptions = + | LangfuseDriverFactoryOptions + | ConsoleDriverFactoryOptions; + +export type LLMTracingModuleAsyncOptions = { + useFactory: (...args: any[]) => LLMTracingModuleOptions; +} & Pick<ModuleMetadata, 'imports'> & + Pick<FactoryProvider, 'inject'>; diff --git a/packages/twenty-server/src/engine/integrations/llm-tracing/llm-tracing.constants.ts b/packages/twenty-server/src/engine/integrations/llm-tracing/llm-tracing.constants.ts new file mode 100644 index 000000000000..92371f0e4e88 --- /dev/null +++ b/packages/twenty-server/src/engine/integrations/llm-tracing/llm-tracing.constants.ts @@ -0,0 +1 @@ +export const LLM_TRACING_DRIVER = Symbol('LLM_TRACING_DRIVER'); diff --git a/packages/twenty-server/src/engine/integrations/llm-tracing/llm-tracing.module-factory.ts b/packages/twenty-server/src/engine/integrations/llm-tracing/llm-tracing.module-factory.ts new file mode 100644 index 000000000000..754158e2a81e --- /dev/null +++ b/packages/twenty-server/src/engine/integrations/llm-tracing/llm-tracing.module-factory.ts @@ -0,0 +1,34 @@ +import { LLMTracingDriver } from 'src/engine/integrations/llm-tracing/interfaces/llm-tracing.interface'; + +import { EnvironmentService } from 'src/engine/integrations/environment/environment.service'; + +export const llmTracingModuleFactory = ( + environmentService: EnvironmentService, +) => { + const driver = environmentService.get('LLM_TRACING_DRIVER'); + + switch (driver) { + case LLMTracingDriver.Console: { + return { type: LLMTracingDriver.Console as const }; + } + case LLMTracingDriver.Langfuse: { + const secretKey = environmentService.get('LANGFUSE_SECRET_KEY'); + const publicKey = environmentService.get('LANGFUSE_PUBLIC_KEY'); + + if (!(secretKey && publicKey)) { + throw new Error( + `${driver} LLM tracing driver requires LANGFUSE_SECRET_KEY and LANGFUSE_PUBLIC_KEY to be defined, check your .env file`, + ); + } + + return { + type: LLMTracingDriver.Langfuse as const, + options: { secretKey, publicKey }, + }; + } + default: + throw new Error( + `Invalid LLM tracing driver (${driver}), check your .env file`, + ); + } +}; diff --git a/packages/twenty-server/src/engine/integrations/llm-tracing/llm-tracing.module.ts b/packages/twenty-server/src/engine/integrations/llm-tracing/llm-tracing.module.ts new file mode 100644 index 000000000000..9e9c452e95ba --- /dev/null +++ b/packages/twenty-server/src/engine/integrations/llm-tracing/llm-tracing.module.ts @@ -0,0 +1,39 @@ +import { Global, DynamicModule } from '@nestjs/common'; + +import { + LLMTracingModuleAsyncOptions, + LLMTracingDriver, +} from 'src/engine/integrations/llm-tracing/interfaces/llm-tracing.interface'; + +import { LangfuseDriver } from 'src/engine/integrations/llm-tracing/drivers/langfuse.driver'; +import { ConsoleDriver } from 'src/engine/integrations/llm-tracing/drivers/console.driver'; +import { LLMTracingService } from 'src/engine/integrations/llm-tracing/llm-tracing.service'; +import { LLM_TRACING_DRIVER } from 'src/engine/integrations/llm-tracing/llm-tracing.constants'; + +@Global() +export class LLMTracingModule { + static forRoot(options: LLMTracingModuleAsyncOptions): DynamicModule { + const provider = { + provide: LLM_TRACING_DRIVER, + useFactory: (...args: any[]) => { + const config = options.useFactory(...args); + + switch (config.type) { + case LLMTracingDriver.Langfuse: { + return new LangfuseDriver(config.options); + } + case LLMTracingDriver.Console: { + return new ConsoleDriver(); + } + } + }, + inject: options.inject || [], + }; + + return { + module: LLMTracingModule, + providers: [LLMTracingService, provider], + exports: [LLMTracingService], + }; + } +} diff --git a/packages/twenty-server/src/engine/integrations/llm-tracing/llm-tracing.service.ts b/packages/twenty-server/src/engine/integrations/llm-tracing/llm-tracing.service.ts new file mode 100644 index 000000000000..6ff2023902d1 --- /dev/null +++ b/packages/twenty-server/src/engine/integrations/llm-tracing/llm-tracing.service.ts @@ -0,0 +1,16 @@ +import { Injectable, Inject } from '@nestjs/common'; + +import { BaseCallbackHandler } from '@langchain/core/callbacks/base'; + +import { LLMTracingDriver } from 'src/engine/integrations/llm-tracing/drivers/interfaces/llm-tracing-driver.interface'; + +import { LLM_TRACING_DRIVER } from 'src/engine/integrations/llm-tracing/llm-tracing.constants'; + +@Injectable() +export class LLMTracingService { + constructor(@Inject(LLM_TRACING_DRIVER) private driver: LLMTracingDriver) {} + + getCallbackHandler(metadata: Record<string, unknown>): BaseCallbackHandler { + return this.driver.getCallbackHandler(metadata); + } +} diff --git a/packages/twenty-server/src/engine/integrations/message-queue/decorators/message-queue.decorator.ts b/packages/twenty-server/src/engine/integrations/message-queue/decorators/message-queue.decorator.ts index 69fa50ad5ef7..5a275d3d5b82 100644 --- a/packages/twenty-server/src/engine/integrations/message-queue/decorators/message-queue.decorator.ts +++ b/packages/twenty-server/src/engine/integrations/message-queue/decorators/message-queue.decorator.ts @@ -1,7 +1,8 @@ import { Inject } from '@nestjs/common'; import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; +import { getQueueToken } from 'src/engine/integrations/message-queue/utils/get-queue-token.util'; -export const InjectMessageQueue = (messageQueueName: MessageQueue) => { - return Inject(messageQueueName); +export const InjectMessageQueue = (queueName: MessageQueue) => { + return Inject(getQueueToken(queueName)); }; diff --git a/packages/twenty-server/src/engine/integrations/message-queue/decorators/process.decorator.ts b/packages/twenty-server/src/engine/integrations/message-queue/decorators/process.decorator.ts new file mode 100644 index 000000000000..214742cb0af0 --- /dev/null +++ b/packages/twenty-server/src/engine/integrations/message-queue/decorators/process.decorator.ts @@ -0,0 +1,21 @@ +import { SetMetadata } from '@nestjs/common'; +import { isString } from '@nestjs/common/utils/shared.utils'; + +import { PROCESS_METADATA } from 'src/engine/integrations/message-queue/message-queue.constants'; + +export interface MessageQueueProcessOptions { + jobName: string; + concurrency?: number; +} + +export function Process(jobName: string): MethodDecorator; +export function Process(options: MessageQueueProcessOptions): MethodDecorator; +export function Process( + nameOrOptions: string | MessageQueueProcessOptions, +): MethodDecorator { + const options = isString(nameOrOptions) + ? { jobName: nameOrOptions } + : nameOrOptions; + + return SetMetadata(PROCESS_METADATA, options || {}); +} diff --git a/packages/twenty-server/src/engine/integrations/message-queue/decorators/processor.decorator.ts b/packages/twenty-server/src/engine/integrations/message-queue/decorators/processor.decorator.ts new file mode 100644 index 000000000000..a244dc4d14ce --- /dev/null +++ b/packages/twenty-server/src/engine/integrations/message-queue/decorators/processor.decorator.ts @@ -0,0 +1,69 @@ +import { Scope, SetMetadata } from '@nestjs/common'; +import { SCOPE_OPTIONS_METADATA } from '@nestjs/common/constants'; + +import { MessageQueueWorkerOptions } from 'src/engine/integrations/message-queue/interfaces/message-queue-worker-options.interface'; + +import { + MessageQueue, + PROCESSOR_METADATA, + WORKER_METADATA, +} from 'src/engine/integrations/message-queue/message-queue.constants'; + +export interface MessageQueueProcessorOptions { + /** + * Specifies the name of the queue to subscribe to. + */ + queueName: MessageQueue; + /** + * Specifies the lifetime of an injected Processor. + */ + scope?: Scope; +} + +/** + * Represents a worker that is able to process jobs from the queue. + * @param queueName name of the queue to process + */ +export function Processor(queueName: string): ClassDecorator; +/** + * Represents a worker that is able to process jobs from the queue. + * @param queueName name of the queue to process + * @param workerOptions additional worker options + */ +export function Processor( + queueName: string, + workerOptions: MessageQueueWorkerOptions, +): ClassDecorator; +/** + * Represents a worker that is able to process jobs from the queue. + * @param processorOptions processor options + */ +export function Processor( + processorOptions: MessageQueueProcessorOptions, +): ClassDecorator; +/** + * Represents a worker that is able to process jobs from the queue. + * @param processorOptions processor options (Nest-specific) + * @param workerOptions additional Bull worker options + */ +export function Processor( + processorOptions: MessageQueueProcessorOptions, + workerOptions: MessageQueueWorkerOptions, +): ClassDecorator; +export function Processor( + queueNameOrOptions?: string | MessageQueueProcessorOptions, + maybeWorkerOptions?: MessageQueueWorkerOptions, +): ClassDecorator { + const options = + queueNameOrOptions && typeof queueNameOrOptions === 'object' + ? queueNameOrOptions + : { queueName: queueNameOrOptions }; + + // eslint-disable-next-line @typescript-eslint/ban-types + return (target: Function) => { + SetMetadata(SCOPE_OPTIONS_METADATA, options)(target); + SetMetadata(PROCESSOR_METADATA, options)(target); + maybeWorkerOptions && + SetMetadata(WORKER_METADATA, maybeWorkerOptions)(target); + }; +} diff --git a/packages/twenty-server/src/engine/integrations/message-queue/drivers/bullmq.driver.ts b/packages/twenty-server/src/engine/integrations/message-queue/drivers/bullmq.driver.ts index fc78eaabb064..c3324a500604 100644 --- a/packages/twenty-server/src/engine/integrations/message-queue/drivers/bullmq.driver.ts +++ b/packages/twenty-server/src/engine/integrations/message-queue/drivers/bullmq.driver.ts @@ -1,9 +1,14 @@ +import { OnModuleDestroy } from '@nestjs/common'; + +import omitBy from 'lodash.omitby'; import { JobsOptions, Queue, QueueOptions, Worker } from 'bullmq'; import { QueueCronJobOptions, QueueJobOptions, } from 'src/engine/integrations/message-queue/drivers/interfaces/job-options.interface'; +import { MessageQueueJob } from 'src/engine/integrations/message-queue/interfaces/message-queue-job.interface'; +import { MessageQueueWorkerOptions } from 'src/engine/integrations/message-queue/interfaces/message-queue-worker-options.interface'; import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; @@ -11,7 +16,7 @@ import { MessageQueueDriver } from './interfaces/message-queue-driver.interface' export type BullMQDriverOptions = QueueOptions; -export class BullMQDriver implements MessageQueueDriver { +export class BullMQDriver implements MessageQueueDriver, OnModuleDestroy { private queueMap: Record<MessageQueue, Queue> = {} as Record< MessageQueue, Queue @@ -27,7 +32,7 @@ export class BullMQDriver implements MessageQueueDriver { this.queueMap[queueName] = new Queue(queueName, this.options); } - async stop() { + async onModuleDestroy() { const workers = Object.values(this.workerMap); const queues = Object.values(this.queueMap); @@ -39,14 +44,22 @@ export class BullMQDriver implements MessageQueueDriver { async work<T>( queueName: MessageQueue, - handler: ({ data, id }: { data: T; id: string }) => Promise<void>, + handler: (job: MessageQueueJob<T>) => Promise<void>, + options?: MessageQueueWorkerOptions, ) { const worker = new Worker( queueName, async (job) => { - await handler(job as { data: T; id: string }); + // TODO: Correctly support for job.id + await handler({ data: job.data, id: job.id ?? '', name: job.name }); }, - this.options, + omitBy( + { + ...this.options, + concurrency: options?.concurrency, + }, + (value) => value === undefined, + ), ); this.workerMap[queueName] = worker; diff --git a/packages/twenty-server/src/engine/integrations/message-queue/drivers/interfaces/message-queue-driver.interface.ts b/packages/twenty-server/src/engine/integrations/message-queue/drivers/interfaces/message-queue-driver.interface.ts index cdd30913f439..1d53837d359a 100644 --- a/packages/twenty-server/src/engine/integrations/message-queue/drivers/interfaces/message-queue-driver.interface.ts +++ b/packages/twenty-server/src/engine/integrations/message-queue/drivers/interfaces/message-queue-driver.interface.ts @@ -3,6 +3,7 @@ import { QueueJobOptions, } from 'src/engine/integrations/message-queue/drivers/interfaces/job-options.interface'; import { MessageQueueJobData } from 'src/engine/integrations/message-queue/interfaces/message-queue-job.interface'; +import { MessageQueueWorkerOptions } from 'src/engine/integrations/message-queue/interfaces/message-queue-worker-options.interface'; import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; @@ -16,6 +17,7 @@ export interface MessageQueueDriver { work<T extends MessageQueueJobData>( queueName: MessageQueue, handler: ({ data, id }: { data: T; id: string }) => Promise<void> | void, + options?: MessageQueueWorkerOptions, ); addCron<T extends MessageQueueJobData | undefined>( queueName: MessageQueue, @@ -24,6 +26,5 @@ export interface MessageQueueDriver { options?: QueueCronJobOptions, ); removeCron(queueName: MessageQueue, jobName: string, pattern?: string); - stop?(): Promise<void>; register?(queueName: MessageQueue): void; } diff --git a/packages/twenty-server/src/engine/integrations/message-queue/drivers/pg-boss.driver.ts b/packages/twenty-server/src/engine/integrations/message-queue/drivers/pg-boss.driver.ts index 5210593c3ff0..98631bc88121 100644 --- a/packages/twenty-server/src/engine/integrations/message-queue/drivers/pg-boss.driver.ts +++ b/packages/twenty-server/src/engine/integrations/message-queue/drivers/pg-boss.driver.ts @@ -1,9 +1,13 @@ +import { OnModuleDestroy, OnModuleInit } from '@nestjs/common'; + import PgBoss from 'pg-boss'; import { QueueCronJobOptions, QueueJobOptions, } from 'src/engine/integrations/message-queue/drivers/interfaces/job-options.interface'; +import { MessageQueueJob } from 'src/engine/integrations/message-queue/interfaces/message-queue-job.interface'; +import { MessageQueueWorkerOptions } from 'src/engine/integrations/message-queue/interfaces/message-queue-worker-options.interface'; import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; @@ -13,26 +17,50 @@ export type PgBossDriverOptions = PgBoss.ConstructorOptions; const DEFAULT_PG_BOSS_CRON_PATTERN_WHEN_NOT_PROVIDED = '*/1 * * * *'; -export class PgBossDriver implements MessageQueueDriver { +export class PgBossDriver + implements MessageQueueDriver, OnModuleInit, OnModuleDestroy +{ private pgBoss: PgBoss; constructor(options: PgBossDriverOptions) { this.pgBoss = new PgBoss(options); } - async stop() { - await this.pgBoss.stop(); + async onModuleInit() { + await this.pgBoss.start(); } - async init(): Promise<void> { - await this.pgBoss.start(); + async onModuleDestroy() { + await this.pgBoss.stop(); } async work<T>( queueName: string, - handler: ({ data, id }: { data: T; id: string }) => Promise<void>, + handler: (job: MessageQueueJob<T>) => Promise<void>, + options?: MessageQueueWorkerOptions, ) { - return this.pgBoss.work(`${queueName}.*`, handler); + return this.pgBoss.work<T>( + `${queueName}.*`, + options?.concurrency + ? { + teamConcurrency: options.concurrency, + } + : {}, + async (job) => { + // PGBoss work with wildcard job name + const jobName = job.name.split('.')?.[1]; + + if (!jobName) { + throw new Error('Job name could not be splited from the job.'); + } + + await handler({ + data: job.data, + id: job.id, + name: jobName, + }); + }, + ); } async addCron<T>( diff --git a/packages/twenty-server/src/engine/integrations/message-queue/drivers/sync.driver.ts b/packages/twenty-server/src/engine/integrations/message-queue/drivers/sync.driver.ts index ca48a0236510..7d9d5cca3faa 100644 --- a/packages/twenty-server/src/engine/integrations/message-queue/drivers/sync.driver.ts +++ b/packages/twenty-server/src/engine/integrations/message-queue/drivers/sync.driver.ts @@ -1,57 +1,66 @@ -import { ModuleRef } from '@nestjs/core'; import { Logger } from '@nestjs/common'; -import { MessageQueueDriver } from 'src/engine/integrations/message-queue/drivers/interfaces/message-queue-driver.interface'; import { - MessageQueueCronJobData, - MessageQueueJob, MessageQueueJobData, + MessageQueueJob, } from 'src/engine/integrations/message-queue/interfaces/message-queue-job.interface'; import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; -import { getJobClassName } from 'src/engine/integrations/message-queue/utils/get-job-class-name.util'; + +import { MessageQueueDriver } from './interfaces/message-queue-driver.interface'; export class SyncDriver implements MessageQueueDriver { private readonly logger = new Logger(SyncDriver.name); - constructor(private readonly jobsModuleRef: ModuleRef) {} + private workersMap: { + [queueName: string]: (job: MessageQueueJob<any>) => Promise<void> | void; + } = {}; + + constructor() {} async add<T extends MessageQueueJobData>( - _queueName: MessageQueue, + queueName: MessageQueue, jobName: string, data: T, ): Promise<void> { - const jobClassName = getJobClassName(jobName); - const job: MessageQueueJob<MessageQueueJobData> = this.jobsModuleRef.get( - jobClassName, - { strict: false }, - ); - - await job.handle(data); + await this.processJob(queueName, { id: '', name: jobName, data }); } async addCron<T extends MessageQueueJobData | undefined>( - _queueName: MessageQueue, + queueName: MessageQueue, jobName: string, data: T, ): Promise<void> { this.logger.log(`Running cron job with SyncDriver`); - - const jobClassName = getJobClassName(jobName); - const job: MessageQueueCronJobData<MessageQueueJobData | undefined> = - this.jobsModuleRef.get(jobClassName, { - strict: true, - }); - - await job.handle(data); + await this.processJob(queueName, { + id: '', + name: jobName, + // TODO: Fix this type issue + data: data as any, + }); } - async removeCron(_queueName: MessageQueue, jobName: string) { - this.logger.log(`Removing '${jobName}' cron job with SyncDriver`); + async removeCron(queueName: MessageQueue) { + this.logger.log(`Removing '${queueName}' cron job with SyncDriver`); + } - return; + work<T extends MessageQueueJobData>( + queueName: MessageQueue, + handler: (job: MessageQueueJob<T>) => Promise<void> | void, + ) { + this.logger.log(`Registering handler for queue: ${queueName}`); + this.workersMap[queueName] = handler; } - work() { - return; + async processJob<T extends MessageQueueJobData>( + queueName: string, + job: MessageQueueJob<T>, + ) { + const worker = this.workersMap[queueName]; + + if (worker) { + await worker(job); + } else { + this.logger.error(`No handler found for job: ${queueName}`); + } } } diff --git a/packages/twenty-server/src/engine/integrations/message-queue/interfaces/index.ts b/packages/twenty-server/src/engine/integrations/message-queue/interfaces/index.ts index 300859d017d2..4fdb52388cd2 100644 --- a/packages/twenty-server/src/engine/integrations/message-queue/interfaces/index.ts +++ b/packages/twenty-server/src/engine/integrations/message-queue/interfaces/index.ts @@ -1 +1 @@ -export * from './message-queue.interface'; +export * from './message-queue-module-options.interface'; diff --git a/packages/twenty-server/src/engine/integrations/message-queue/interfaces/message-queue-job.interface.ts b/packages/twenty-server/src/engine/integrations/message-queue/interfaces/message-queue-job.interface.ts index 87423ffd2bee..8a1ced80ec50 100644 --- a/packages/twenty-server/src/engine/integrations/message-queue/interfaces/message-queue-job.interface.ts +++ b/packages/twenty-server/src/engine/integrations/message-queue/interfaces/message-queue-job.interface.ts @@ -1,5 +1,7 @@ -export interface MessageQueueJob<T extends MessageQueueJobData | undefined> { - handle(data: T): Promise<void> | void; +export interface MessageQueueJob<T = any> { + id: string; + name: string; + data: T; } export interface MessageQueueCronJobData< diff --git a/packages/twenty-server/src/engine/integrations/message-queue/interfaces/message-queue.interface.ts b/packages/twenty-server/src/engine/integrations/message-queue/interfaces/message-queue-module-options.interface.ts similarity index 72% rename from packages/twenty-server/src/engine/integrations/message-queue/interfaces/message-queue.interface.ts rename to packages/twenty-server/src/engine/integrations/message-queue/interfaces/message-queue-module-options.interface.ts index 568e0819fc8e..b98990385204 100644 --- a/packages/twenty-server/src/engine/integrations/message-queue/interfaces/message-queue.interface.ts +++ b/packages/twenty-server/src/engine/integrations/message-queue/interfaces/message-queue-module-options.interface.ts @@ -1,5 +1,3 @@ -import { FactoryProvider, ModuleMetadata } from '@nestjs/common'; - import { BullMQDriverOptions } from 'src/engine/integrations/message-queue/drivers/bullmq.driver'; import { PgBossDriverOptions } from 'src/engine/integrations/message-queue/drivers/pg-boss.driver'; @@ -28,10 +26,3 @@ export type MessageQueueModuleOptions = | PgBossDriverFactoryOptions | BullMQDriverFactoryOptions | SyncDriverFactoryOptions; - -export type MessageQueueModuleAsyncOptions = { - useFactory: ( - ...args: any[] - ) => MessageQueueModuleOptions | Promise<MessageQueueModuleOptions>; -} & Pick<ModuleMetadata, 'imports'> & - Pick<FactoryProvider, 'inject'>; diff --git a/packages/twenty-server/src/engine/integrations/message-queue/interfaces/message-queue-worker-options.interface.ts b/packages/twenty-server/src/engine/integrations/message-queue/interfaces/message-queue-worker-options.interface.ts new file mode 100644 index 000000000000..c4def7121eb0 --- /dev/null +++ b/packages/twenty-server/src/engine/integrations/message-queue/interfaces/message-queue-worker-options.interface.ts @@ -0,0 +1,3 @@ +export interface MessageQueueWorkerOptions { + concurrency?: number; +} diff --git a/packages/twenty-server/src/engine/integrations/message-queue/jobs.module.ts b/packages/twenty-server/src/engine/integrations/message-queue/jobs.module.ts index 5447402d603b..b8eee0bbbb90 100644 --- a/packages/twenty-server/src/engine/integrations/message-queue/jobs.module.ts +++ b/packages/twenty-server/src/engine/integrations/message-queue/jobs.module.ts @@ -11,21 +11,18 @@ import { StripeModule } from 'src/engine/core-modules/billing/stripe/stripe.modu import { UserWorkspaceModule } from 'src/engine/core-modules/user-workspace/user-workspace.module'; import { UserModule } from 'src/engine/core-modules/user/user.module'; import { HandleWorkspaceMemberDeletedJob } from 'src/engine/core-modules/workspace/handle-workspace-member-deleted.job'; +import { WorkspaceModule } from 'src/engine/core-modules/workspace/workspace.module'; import { EmailSenderJob } from 'src/engine/integrations/email/email-sender.job'; import { EmailModule } from 'src/engine/integrations/email/email.module'; import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module'; import { ObjectMetadataModule } from 'src/engine/metadata-modules/object-metadata/object-metadata.module'; import { CleanInactiveWorkspaceJob } from 'src/engine/workspace-manager/workspace-cleaner/crons/clean-inactive-workspace.job'; -import { CalendarEventParticipantModule } from 'src/modules/calendar/services/calendar-event-participant/calendar-event-participant.module'; -import { TimelineActivityModule } from 'src/modules/timeline/timeline-activity.module'; -import { WorkspaceModule } from 'src/engine/core-modules/workspace/workspace.module'; -import { CalendarMessagingParticipantJobModule } from 'src/modules/calendar-messaging-participant/jobs/calendar-messaging-participant-job.module'; -import { CalendarCronJobModule } from 'src/modules/calendar/crons/jobs/calendar-cron-job.module'; -import { CalendarJobModule } from 'src/modules/calendar/jobs/calendar-job.module'; -import { AutoCompaniesAndContactsCreationJobModule } from 'src/modules/connected-account/auto-companies-and-contacts-creation/jobs/auto-companies-and-contacts-creation-job.module'; +import { CalendarEventParticipantManagerModule } from 'src/modules/calendar/calendar-event-participant-manager/calendar-event-participant-manager.module'; import { CalendarModule } from 'src/modules/calendar/calendar.module'; +import { AutoCompaniesAndContactsCreationJobModule } from 'src/modules/contact-creation-manager/jobs/auto-companies-and-contacts-creation-job.module'; import { MessagingModule } from 'src/modules/messaging/messaging.module'; import { TimelineJobModule } from 'src/modules/timeline/jobs/timeline-job.module'; +import { TimelineActivityModule } from 'src/modules/timeline/timeline-activity.module'; @Module({ imports: [ @@ -39,33 +36,20 @@ import { TimelineJobModule } from 'src/modules/timeline/jobs/timeline-job.module UserWorkspaceModule, WorkspaceModule, MessagingModule, - CalendarEventParticipantModule, + CalendarModule, + CalendarEventParticipantManagerModule, TimelineActivityModule, StripeModule, - CalendarModule, - // JobsModules WorkspaceQueryRunnerJobModule, - CalendarMessagingParticipantJobModule, - CalendarCronJobModule, - CalendarJobModule, AutoCompaniesAndContactsCreationJobModule, TimelineJobModule, ], providers: [ - { - provide: CleanInactiveWorkspaceJob.name, - useClass: CleanInactiveWorkspaceJob, - }, - { provide: EmailSenderJob.name, useClass: EmailSenderJob }, - { - provide: DataSeedDemoWorkspaceJob.name, - useClass: DataSeedDemoWorkspaceJob, - }, - { provide: UpdateSubscriptionJob.name, useClass: UpdateSubscriptionJob }, - { - provide: HandleWorkspaceMemberDeletedJob.name, - useClass: HandleWorkspaceMemberDeletedJob, - }, + CleanInactiveWorkspaceJob, + EmailSenderJob, + DataSeedDemoWorkspaceJob, + UpdateSubscriptionJob, + HandleWorkspaceMemberDeletedJob, ], }) export class JobsModule { diff --git a/packages/twenty-server/src/engine/integrations/message-queue/message-queue-core.module.ts b/packages/twenty-server/src/engine/integrations/message-queue/message-queue-core.module.ts new file mode 100644 index 000000000000..c22b0abce39c --- /dev/null +++ b/packages/twenty-server/src/engine/integrations/message-queue/message-queue-core.module.ts @@ -0,0 +1,121 @@ +import { + DynamicModule, + Global, + Logger, + Module, + Provider, +} from '@nestjs/common'; + +import { MessageQueueDriver } from 'src/engine/integrations/message-queue/drivers/interfaces/message-queue-driver.interface'; + +import { MessageQueueDriverType } from 'src/engine/integrations/message-queue/interfaces'; +import { + MessageQueue, + QUEUE_DRIVER, +} from 'src/engine/integrations/message-queue/message-queue.constants'; +import { PgBossDriver } from 'src/engine/integrations/message-queue/drivers/pg-boss.driver'; +import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service'; +import { BullMQDriver } from 'src/engine/integrations/message-queue/drivers/bullmq.driver'; +import { SyncDriver } from 'src/engine/integrations/message-queue/drivers/sync.driver'; +import { getQueueToken } from 'src/engine/integrations/message-queue/utils/get-queue-token.util'; +import { + ASYNC_OPTIONS_TYPE, + ConfigurableModuleClass, + OPTIONS_TYPE, +} from 'src/engine/integrations/message-queue/message-queue.module-definition'; + +@Global() +@Module({}) +export class MessageQueueCoreModule extends ConfigurableModuleClass { + private static readonly logger = new Logger(MessageQueueCoreModule.name); + + static register(options: typeof OPTIONS_TYPE): DynamicModule { + const dynamicModule = super.register(options); + + const driverProvider: Provider = { + provide: QUEUE_DRIVER, + useFactory: () => { + return this.createDriver(options); + }, + }; + + const queueProviders = this.createQueueProviders(); + + return { + ...dynamicModule, + providers: [ + ...(dynamicModule.providers ?? []), + driverProvider, + ...queueProviders, + ], + exports: [ + ...(dynamicModule.exports ?? []), + ...Object.values(MessageQueue).map((queueName) => + getQueueToken(queueName), + ), + ], + }; + } + + static registerAsync(options: typeof ASYNC_OPTIONS_TYPE): DynamicModule { + const dynamicModule = super.registerAsync(options); + + const driverProvider: Provider = { + provide: QUEUE_DRIVER, + useFactory: async (...args: any[]) => { + const config = await options.useFactory!(...args); + + return this.createDriver(config); + }, + inject: options.inject || [], + }; + + const queueProviders = MessageQueueCoreModule.createQueueProviders(); + + return { + ...dynamicModule, + providers: [ + ...(dynamicModule.providers ?? []), + driverProvider, + ...queueProviders, + ], + exports: [ + ...(dynamicModule.exports ?? []), + ...Object.values(MessageQueue).map((queueName) => + getQueueToken(queueName), + ), + ], + }; + } + + static async createDriver({ type, options }: typeof OPTIONS_TYPE) { + switch (type) { + case MessageQueueDriverType.PgBoss: { + return new PgBossDriver(options); + } + case MessageQueueDriverType.BullMQ: { + return new BullMQDriver(options); + } + case MessageQueueDriverType.Sync: { + return new SyncDriver(); + } + default: { + this.logger.warn( + `Unsupported message queue driver type: ${type}. Using SyncDriver by default.`, + ); + + return new SyncDriver(); + } + } + } + + static createQueueProviders(): Provider[] { + return Object.values(MessageQueue).map((queueName) => ({ + provide: getQueueToken(queueName), + useFactory: (driver: MessageQueueDriver) => { + return new MessageQueueService(driver, queueName); + }, + inject: [QUEUE_DRIVER], + })); + } +} diff --git a/packages/twenty-server/src/engine/integrations/message-queue/message-queue-metadata.accessor.ts b/packages/twenty-server/src/engine/integrations/message-queue/message-queue-metadata.accessor.ts new file mode 100644 index 000000000000..e509e1fd8718 --- /dev/null +++ b/packages/twenty-server/src/engine/integrations/message-queue/message-queue-metadata.accessor.ts @@ -0,0 +1,54 @@ +/* eslint-disable @typescript-eslint/ban-types */ +import { Injectable, Type } from '@nestjs/common'; +import { Reflector } from '@nestjs/core'; + +import { MessageQueueWorkerOptions } from 'src/engine/integrations/message-queue/interfaces/message-queue-worker-options.interface'; + +import { MessageQueueProcessOptions } from 'src/engine/integrations/message-queue/decorators/process.decorator'; +import { MessageQueueProcessorOptions } from 'src/engine/integrations/message-queue/decorators/processor.decorator'; +import { + PROCESSOR_METADATA, + PROCESS_METADATA, + WORKER_METADATA, +} from 'src/engine/integrations/message-queue/message-queue.constants'; + +@Injectable() +export class MessageQueueMetadataAccessor { + constructor(private readonly reflector: Reflector) {} + + isProcessor(target: Type<any> | Function): boolean { + if (!target) { + return false; + } + + return !!this.reflector.get(PROCESSOR_METADATA, target); + } + + isProcess(target: Type<any> | Function): boolean { + if (!target) { + return false; + } + + return !!this.reflector.get(PROCESS_METADATA, target); + } + + getProcessorMetadata( + target: Type<any> | Function, + ): MessageQueueProcessorOptions | undefined { + return this.reflector.get(PROCESSOR_METADATA, target); + } + + getProcessMetadata( + target: Type<any> | Function, + ): MessageQueueProcessOptions | undefined { + const metadata = this.reflector.get(PROCESS_METADATA, target); + + return metadata; + } + + getWorkerOptionsMetadata( + target: Type<any> | Function, + ): MessageQueueWorkerOptions { + return this.reflector.get(WORKER_METADATA, target) ?? {}; + } +} diff --git a/packages/twenty-server/src/engine/integrations/message-queue/message-queue.constants.ts b/packages/twenty-server/src/engine/integrations/message-queue/message-queue.constants.ts index 7576b8693a01..e78cc50939bf 100644 --- a/packages/twenty-server/src/engine/integrations/message-queue/message-queue.constants.ts +++ b/packages/twenty-server/src/engine/integrations/message-queue/message-queue.constants.ts @@ -1,4 +1,7 @@ -export const QUEUE_DRIVER = Symbol('QUEUE_DRIVER'); +export const PROCESSOR_METADATA = Symbol('message-queue:processor_metadata'); +export const PROCESS_METADATA = Symbol('message-queue:process_metadata'); +export const WORKER_METADATA = Symbol('bullmq:worker_metadata'); +export const QUEUE_DRIVER = Symbol('message-queue:queue_driver'); export enum MessageQueue { taskAssignedQueue = 'task-assigned-queue', @@ -12,4 +15,5 @@ export enum MessageQueue { workspaceQueue = 'workspace-queue', recordPositionBackfillQueue = 'record-position-backfill-queue', entityEventsToDbQueue = 'entity-events-to-db-queue', + testQueue = 'test-queue', } diff --git a/packages/twenty-server/src/engine/integrations/message-queue/message-queue.explorer.ts b/packages/twenty-server/src/engine/integrations/message-queue/message-queue.explorer.ts new file mode 100644 index 000000000000..30e73f6bbc7b --- /dev/null +++ b/packages/twenty-server/src/engine/integrations/message-queue/message-queue.explorer.ts @@ -0,0 +1,216 @@ +import { Injectable, Logger, OnModuleInit } from '@nestjs/common'; +import { + DiscoveryService, + MetadataScanner, + ModuleRef, + createContextId, +} from '@nestjs/core'; +import { Module } from '@nestjs/core/injector/module'; +import { Injector } from '@nestjs/core/injector/injector'; +import { InstanceWrapper } from '@nestjs/core/injector/instance-wrapper'; + +import { MessageQueueWorkerOptions } from 'src/engine/integrations/message-queue/interfaces/message-queue-worker-options.interface'; +import { + MessageQueueJob, + MessageQueueJobData, +} from 'src/engine/integrations/message-queue/interfaces/message-queue-job.interface'; + +import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service'; +import { getQueueToken } from 'src/engine/integrations/message-queue/utils/get-queue-token.util'; +import { ExceptionHandlerService } from 'src/engine/integrations/exception-handler/exception-handler.service'; +import { shouldFilterException } from 'src/engine/utils/global-exception-handler.util'; + +import { MessageQueueMetadataAccessor } from './message-queue-metadata.accessor'; + +interface ProcessorGroup { + instance: object; + host: Module; + processMethodNames: string[]; + isRequestScoped: boolean; +} + +@Injectable() +export class MessageQueueExplorer implements OnModuleInit { + private readonly logger = new Logger('MessageQueueModule'); + private readonly injector = new Injector(); + + constructor( + private readonly moduleRef: ModuleRef, + private readonly discoveryService: DiscoveryService, + private readonly metadataAccessor: MessageQueueMetadataAccessor, + private readonly metadataScanner: MetadataScanner, + private readonly exceptionHandlerService: ExceptionHandlerService, + ) {} + + onModuleInit() { + this.explore(); + } + + explore() { + const processors = this.discoveryService + .getProviders() + .filter((wrapper) => + this.metadataAccessor.isProcessor( + !wrapper.metatype || wrapper.inject + ? wrapper.instance?.constructor + : wrapper.metatype, + ), + ); + + const groupedProcessors = this.groupProcessorsByQueueName(processors); + + for (const [queueName, processorGroupCollection] of Object.entries( + groupedProcessors, + )) { + const queueToken = getQueueToken(queueName); + const messageQueueService = this.getQueueService(queueToken); + + this.handleProcessorGroupCollection( + processorGroupCollection, + messageQueueService, + ); + } + } + + private groupProcessorsByQueueName(processors: InstanceWrapper[]) { + return processors.reduce( + (acc, wrapper) => { + const { instance, metatype } = wrapper; + const methodNames = this.metadataScanner.getAllMethodNames(instance); + const { queueName } = + this.metadataAccessor.getProcessorMetadata( + instance.constructor || metatype, + ) ?? {}; + + const processMethodNames = methodNames.filter((name) => + this.metadataAccessor.isProcess(instance[name]), + ); + + if (!queueName) { + this.logger.error( + `Processor ${wrapper.name} is missing queue name metadata`, + ); + + return acc; + } + + if (!wrapper.host) { + this.logger.error( + `Processor ${wrapper.name} is missing host metadata`, + ); + + return acc; + } + + if (!acc[queueName]) { + acc[queueName] = []; + } + + acc[queueName].push({ + instance, + host: wrapper.host, + processMethodNames, + isRequestScoped: !wrapper.isDependencyTreeStatic(), + }); + + return acc; + }, + {} as Record<string, ProcessorGroup[]>, + ); + } + + private getQueueService(queueToken: string): MessageQueueService { + try { + return this.moduleRef.get<MessageQueueService>(queueToken, { + strict: false, + }); + } catch (err) { + this.logger.error(`No queue found for token ${queueToken}`); + throw err; + } + } + + private async handleProcessorGroupCollection( + processorGroupCollection: ProcessorGroup[], + queue: MessageQueueService, + options?: MessageQueueWorkerOptions, + ) { + queue.work(async (job) => { + for (const processorGroup of processorGroupCollection) { + await this.handleProcessor(processorGroup, job); + } + }, options); + } + + private async handleProcessor( + { instance, host, processMethodNames, isRequestScoped }: ProcessorGroup, + job: MessageQueueJob<MessageQueueJobData>, + ) { + const filteredProcessMethodNames = processMethodNames.filter( + (processMethodName) => { + const metadata = this.metadataAccessor.getProcessMetadata( + instance[processMethodName], + ); + + return metadata && job.name === metadata.jobName; + }, + ); + + // Return early if no matching methods found + if (filteredProcessMethodNames.length === 0) { + return; + } + + if (isRequestScoped) { + const contextId = createContextId(); + + if (this.moduleRef.registerRequestByContextId) { + this.moduleRef.registerRequestByContextId( + { + // Add workspaceId to the request object + req: { + workspaceId: job.data?.workspaceId, + }, + }, + contextId, + ); + } + + const contextInstance = await this.injector.loadPerContext( + instance, + host, + host.providers, + contextId, + ); + + await this.invokeProcessMethods( + contextInstance, + filteredProcessMethodNames, + job, + ); + } else { + await this.invokeProcessMethods( + instance, + filteredProcessMethodNames, + job, + ); + } + } + + private async invokeProcessMethods( + instance: object, + processMethodNames: string[], + job: MessageQueueJob<MessageQueueJobData>, + ) { + for (const processMethodName of processMethodNames) { + try { + await instance[processMethodName].call(instance, job.data); + } catch (err) { + if (!shouldFilterException(err)) { + this.exceptionHandlerService.captureExceptions([err]); + } + throw err; + } + } + } +} diff --git a/packages/twenty-server/src/engine/integrations/message-queue/message-queue.module-definition.ts b/packages/twenty-server/src/engine/integrations/message-queue/message-queue.module-definition.ts new file mode 100644 index 000000000000..b7a437032f3e --- /dev/null +++ b/packages/twenty-server/src/engine/integrations/message-queue/message-queue.module-definition.ts @@ -0,0 +1,20 @@ +import { ConfigurableModuleBuilder } from '@nestjs/common'; + +import { MessageQueueModuleOptions } from 'src/engine/integrations/message-queue/interfaces'; + +export const { + ConfigurableModuleClass, + OPTIONS_TYPE, + ASYNC_OPTIONS_TYPE, + MODULE_OPTIONS_TOKEN, +} = new ConfigurableModuleBuilder<MessageQueueModuleOptions>() + .setExtras( + { + isGlobal: true, + }, + (definition, extras) => ({ + ...definition, + global: extras.isGlobal, + }), + ) + .build(); diff --git a/packages/twenty-server/src/engine/integrations/message-queue/message-queue.module.ts b/packages/twenty-server/src/engine/integrations/message-queue/message-queue.module.ts index 1f7cebba3e3b..ee7fb385b1fb 100644 --- a/packages/twenty-server/src/engine/integrations/message-queue/message-queue.module.ts +++ b/packages/twenty-server/src/engine/integrations/message-queue/message-queue.module.ts @@ -1,62 +1,36 @@ -import { DynamicModule, Global } from '@nestjs/common'; +import { DynamicModule, Global, Module } from '@nestjs/common'; +import { DiscoveryModule } from '@nestjs/core'; -import { MessageQueueDriver } from 'src/engine/integrations/message-queue/drivers/interfaces/message-queue-driver.interface'; - -import { - MessageQueueDriverType, - MessageQueueModuleAsyncOptions, -} from 'src/engine/integrations/message-queue/interfaces'; +import { MessageQueueCoreModule } from 'src/engine/integrations/message-queue/message-queue-core.module'; +import { MessageQueueMetadataAccessor } from 'src/engine/integrations/message-queue/message-queue-metadata.accessor'; +import { MessageQueueExplorer } from 'src/engine/integrations/message-queue/message-queue.explorer'; import { - MessageQueue, - QUEUE_DRIVER, -} from 'src/engine/integrations/message-queue/message-queue.constants'; -import { PgBossDriver } from 'src/engine/integrations/message-queue/drivers/pg-boss.driver'; -import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service'; -import { BullMQDriver } from 'src/engine/integrations/message-queue/drivers/bullmq.driver'; -import { SyncDriver } from 'src/engine/integrations/message-queue/drivers/sync.driver'; -import { JobsModule } from 'src/engine/integrations/message-queue/jobs.module'; + ASYNC_OPTIONS_TYPE, + OPTIONS_TYPE, +} from 'src/engine/integrations/message-queue/message-queue.module-definition'; @Global() +@Module({}) export class MessageQueueModule { - static forRoot(options: MessageQueueModuleAsyncOptions): DynamicModule { - const providers = [ - ...Object.values(MessageQueue).map((queue) => ({ - provide: queue, - useFactory: (driver: MessageQueueDriver) => { - return new MessageQueueService(driver, queue); - }, - inject: [QUEUE_DRIVER], - })), - { - provide: QUEUE_DRIVER, - useFactory: async (...args: any[]) => { - const config = await options.useFactory(...args); - - switch (config.type) { - case MessageQueueDriverType.PgBoss: { - const boss = new PgBossDriver(config.options); - - await boss.init(); + static register(options: typeof OPTIONS_TYPE): DynamicModule { + return { + module: MessageQueueModule, + imports: [MessageQueueCoreModule.register(options)], + }; + } - return boss; - } - case MessageQueueDriverType.BullMQ: { - return new BullMQDriver(config.options); - } - default: { - return new SyncDriver(JobsModule.moduleRef); - } - } - }, - inject: options.inject || [], - }, - ]; + static registerExplorer(): DynamicModule { + return { + module: MessageQueueModule, + imports: [DiscoveryModule], + providers: [MessageQueueExplorer, MessageQueueMetadataAccessor], + }; + } + static registerAsync(options: typeof ASYNC_OPTIONS_TYPE): DynamicModule { return { module: MessageQueueModule, - imports: [JobsModule, ...(options.imports || [])], - providers, - exports: Object.values(MessageQueue), + imports: [MessageQueueCoreModule.registerAsync(options)], }; } } diff --git a/packages/twenty-server/src/engine/integrations/message-queue/services/message-queue.service.ts b/packages/twenty-server/src/engine/integrations/message-queue/services/message-queue.service.ts index 87899696f907..6460e112d974 100644 --- a/packages/twenty-server/src/engine/integrations/message-queue/services/message-queue.service.ts +++ b/packages/twenty-server/src/engine/integrations/message-queue/services/message-queue.service.ts @@ -1,11 +1,15 @@ -import { Inject, Injectable, OnModuleDestroy } from '@nestjs/common'; +import { Inject, Injectable } from '@nestjs/common'; import { QueueCronJobOptions, QueueJobOptions, } from 'src/engine/integrations/message-queue/drivers/interfaces/job-options.interface'; import { MessageQueueDriver } from 'src/engine/integrations/message-queue/drivers/interfaces/message-queue-driver.interface'; -import { MessageQueueJobData } from 'src/engine/integrations/message-queue/interfaces/message-queue-job.interface'; +import { + MessageQueueJobData, + MessageQueueJob, +} from 'src/engine/integrations/message-queue/interfaces/message-queue-job.interface'; +import { MessageQueueWorkerOptions } from 'src/engine/integrations/message-queue/interfaces/message-queue-worker-options.interface'; import { MessageQueue, @@ -13,7 +17,7 @@ import { } from 'src/engine/integrations/message-queue/message-queue.constants'; @Injectable() -export class MessageQueueService implements OnModuleDestroy { +export class MessageQueueService { constructor( @Inject(QUEUE_DRIVER) protected driver: MessageQueueDriver, protected queueName: MessageQueue, @@ -23,12 +27,6 @@ export class MessageQueueService implements OnModuleDestroy { } } - async onModuleDestroy() { - if (typeof this.driver.stop === 'function') { - await this.driver.stop(); - } - } - add<T extends MessageQueueJobData>( jobName: string, data: T, @@ -50,8 +48,9 @@ export class MessageQueueService implements OnModuleDestroy { } work<T extends MessageQueueJobData>( - handler: ({ data, id }: { data: T; id: string }) => Promise<void> | void, + handler: (job: MessageQueueJob<T>) => Promise<void> | void, + options?: MessageQueueWorkerOptions, ) { - return this.driver.work(this.queueName, handler); + return this.driver.work(this.queueName, handler, options); } } diff --git a/packages/twenty-server/src/engine/integrations/message-queue/utils/get-queue-token.util.ts b/packages/twenty-server/src/engine/integrations/message-queue/utils/get-queue-token.util.ts new file mode 100644 index 000000000000..e73faea901a5 --- /dev/null +++ b/packages/twenty-server/src/engine/integrations/message-queue/utils/get-queue-token.util.ts @@ -0,0 +1,2 @@ +export const getQueueToken = (queueName: string) => + `MESSAGE_QUEUE_${queueName}`; diff --git a/packages/twenty-server/src/engine/metadata-modules/data-source/data-source.exception.ts b/packages/twenty-server/src/engine/metadata-modules/data-source/data-source.exception.ts new file mode 100644 index 000000000000..89672fa26ac0 --- /dev/null +++ b/packages/twenty-server/src/engine/metadata-modules/data-source/data-source.exception.ts @@ -0,0 +1,11 @@ +import { CustomException } from 'src/utils/custom-exception'; + +export class DataSourceException extends CustomException { + constructor(message: string, code: DataSourceExceptionCode) { + super(message, code); + } +} + +export enum DataSourceExceptionCode { + DATA_SOURCE_NOT_FOUND = 'DATA_SOURCE_NOT_FOUND', +} diff --git a/packages/twenty-server/src/engine/metadata-modules/data-source/data-source.service.ts b/packages/twenty-server/src/engine/metadata-modules/data-source/data-source.service.ts index 226b5a9ca830..6ca6eb83b207 100644 --- a/packages/twenty-server/src/engine/metadata-modules/data-source/data-source.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/data-source/data-source.service.ts @@ -3,6 +3,11 @@ import { InjectRepository } from '@nestjs/typeorm'; import { FindManyOptions, Repository } from 'typeorm'; +import { + DataSourceException, + DataSourceExceptionCode, +} from 'src/engine/metadata-modules/data-source/data-source.exception'; + import { DataSourceEntity } from './data-source.entity'; @Injectable() @@ -46,15 +51,31 @@ export class DataSourceService { }); } - async getLastDataSourceMetadataFromWorkspaceIdOrFail( + async getLastDataSourceMetadataFromWorkspaceId( workspaceId: string, - ): Promise<DataSourceEntity> { - return this.dataSourceMetadataRepository.findOneOrFail({ + ): Promise<DataSourceEntity | null> { + return this.dataSourceMetadataRepository.findOne({ where: { workspaceId }, order: { createdAt: 'DESC' }, }); } + async getLastDataSourceMetadataFromWorkspaceIdOrFail( + workspaceId: string, + ): Promise<DataSourceEntity> { + try { + return this.dataSourceMetadataRepository.findOneOrFail({ + where: { workspaceId }, + order: { createdAt: 'DESC' }, + }); + } catch (error) { + throw new DataSourceException( + `Data source not found for workspace ${workspaceId}: ${error}`, + DataSourceExceptionCode.DATA_SOURCE_NOT_FOUND, + ); + } + } + async delete(workspaceId: string): Promise<void> { await this.dataSourceMetadataRepository.delete({ workspaceId }); } diff --git a/packages/twenty-server/src/engine/metadata-modules/errors/InvalidStringException.ts b/packages/twenty-server/src/engine/metadata-modules/errors/InvalidStringException.ts deleted file mode 100644 index eabfb0140b5c..000000000000 --- a/packages/twenty-server/src/engine/metadata-modules/errors/InvalidStringException.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { BadRequestException } from '@nestjs/common'; - -export class InvalidStringException extends BadRequestException { - constructor(string: string) { - const message = `String "${string}" is not valid`; - - super(message); - } -} diff --git a/packages/twenty-server/src/engine/metadata-modules/field-metadata/composite-types/links.composite-type.ts b/packages/twenty-server/src/engine/metadata-modules/field-metadata/composite-types/links.composite-type.ts index 4adb14f757b6..2238e2175847 100644 --- a/packages/twenty-server/src/engine/metadata-modules/field-metadata/composite-types/links.composite-type.ts +++ b/packages/twenty-server/src/engine/metadata-modules/field-metadata/composite-types/links.composite-type.ts @@ -20,7 +20,7 @@ export const linksCompositeType: CompositeType = { { name: 'secondaryLinks', type: FieldMetadataType.RAW_JSON, - hidden: 'input', + hidden: false, isRequired: false, }, ], diff --git a/packages/twenty-server/src/engine/metadata-modules/field-metadata/field-metadata.entity.ts b/packages/twenty-server/src/engine/metadata-modules/field-metadata/field-metadata.entity.ts index dd24719ad690..5a80230f7865 100644 --- a/packages/twenty-server/src/engine/metadata-modules/field-metadata/field-metadata.entity.ts +++ b/packages/twenty-server/src/engine/metadata-modules/field-metadata/field-metadata.entity.ts @@ -9,6 +9,7 @@ import { CreateDateColumn, UpdateDateColumn, Relation, + OneToMany, } from 'typeorm'; import { FieldMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata.interface'; @@ -18,6 +19,7 @@ import { FieldMetadataSettings } from 'src/engine/metadata-modules/field-metadat import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { RelationMetadataEntity } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity'; +import { IndexFieldMetadataEntity } from 'src/engine/metadata-modules/index-field-metadata/index-field-metadata.entity'; export enum FieldMetadataType { UUID = 'UUID', @@ -29,7 +31,6 @@ export enum FieldMetadataType { BOOLEAN = 'BOOLEAN', NUMBER = 'NUMBER', NUMERIC = 'NUMERIC', - PROBABILITY = 'PROBABILITY', LINK = 'LINK', LINKS = 'LINKS', CURRENCY = 'CURRENCY', @@ -119,6 +120,16 @@ export class FieldMetadataEntity< ) toRelationMetadata: Relation<RelationMetadataEntity>; + @OneToMany( + () => IndexFieldMetadataEntity, + (indexFieldMetadata: IndexFieldMetadataEntity) => + indexFieldMetadata.fieldMetadata, + { + cascade: true, + }, + ) + indexFieldMetadatas: Relation<IndexFieldMetadataEntity>; + @CreateDateColumn({ type: 'timestamptz' }) createdAt: Date; diff --git a/packages/twenty-server/src/engine/metadata-modules/field-metadata/field-metadata.exception.ts b/packages/twenty-server/src/engine/metadata-modules/field-metadata/field-metadata.exception.ts new file mode 100644 index 000000000000..e9390c099edd --- /dev/null +++ b/packages/twenty-server/src/engine/metadata-modules/field-metadata/field-metadata.exception.ts @@ -0,0 +1,17 @@ +import { CustomException } from 'src/utils/custom-exception'; + +export class FieldMetadataException extends CustomException { + code: FieldMetadataExceptionCode; + constructor(message: string, code: FieldMetadataExceptionCode) { + super(message, code); + } +} + +export enum FieldMetadataExceptionCode { + FIELD_METADATA_NOT_FOUND = 'FIELD_METADATA_NOT_FOUND', + INVALID_FIELD_INPUT = 'INVALID_FIELD_INPUT', + FIELD_MUTATION_NOT_ALLOWED = 'FIELD_MUTATION_NOT_ALLOWED', + FIELD_ALREADY_EXISTS = 'FIELD_ALREADY_EXISTS', + OBJECT_METADATA_NOT_FOUND = 'OBJECT_METADATA_NOT_FOUND', + INTERNAL_SERVER_ERROR = 'INTERNAL_SERVER_ERROR', +} diff --git a/packages/twenty-server/src/engine/metadata-modules/field-metadata/field-metadata.module.ts b/packages/twenty-server/src/engine/metadata-modules/field-metadata/field-metadata.module.ts index bcf9159b9938..321bbc9d9677 100644 --- a/packages/twenty-server/src/engine/metadata-modules/field-metadata/field-metadata.module.ts +++ b/packages/twenty-server/src/engine/metadata-modules/field-metadata/field-metadata.module.ts @@ -1,26 +1,27 @@ import { Module } from '@nestjs/common'; +import { SortDirection } from '@ptc-org/nestjs-query-core'; import { NestjsQueryGraphQLModule, PagingStrategies, } from '@ptc-org/nestjs-query-graphql'; import { NestjsQueryTypeOrmModule } from '@ptc-org/nestjs-query-typeorm'; -import { SortDirection } from '@ptc-org/nestjs-query-core'; -import { WorkspaceMigrationRunnerModule } from 'src/engine/workspace-manager/workspace-migration-runner/workspace-migration-runner.module'; -import { WorkspaceMigrationModule } from 'src/engine/metadata-modules/workspace-migration/workspace-migration.module'; -import { ObjectMetadataModule } from 'src/engine/metadata-modules/object-metadata/object-metadata.module'; +import { TypeORMModule } from 'src/database/typeorm/typeorm.module'; import { JwtAuthGuard } from 'src/engine/guards/jwt.auth.guard'; import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module'; -import { TypeORMModule } from 'src/database/typeorm/typeorm.module'; -import { IsFieldMetadataDefaultValue } from 'src/engine/metadata-modules/field-metadata/validators/is-field-metadata-default-value.validator'; -import { FieldMetadataResolver } from 'src/engine/metadata-modules/field-metadata/field-metadata.resolver'; import { FieldMetadataDTO } from 'src/engine/metadata-modules/field-metadata/dtos/field-metadata.dto'; +import { FieldMetadataResolver } from 'src/engine/metadata-modules/field-metadata/field-metadata.resolver'; +import { FieldMetadataGraphqlApiExceptionInterceptor } from 'src/engine/metadata-modules/field-metadata/interceptors/field-metadata-graphql-api-exception.interceptor'; +import { IsFieldMetadataDefaultValue } from 'src/engine/metadata-modules/field-metadata/validators/is-field-metadata-default-value.validator'; import { IsFieldMetadataOptions } from 'src/engine/metadata-modules/field-metadata/validators/is-field-metadata-options.validator'; +import { ObjectMetadataModule } from 'src/engine/metadata-modules/object-metadata/object-metadata.module'; import { WorkspaceCacheVersionModule } from 'src/engine/metadata-modules/workspace-cache-version/workspace-cache-version.module'; +import { WorkspaceMigrationModule } from 'src/engine/metadata-modules/workspace-migration/workspace-migration.module'; +import { WorkspaceMigrationRunnerModule } from 'src/engine/workspace-manager/workspace-migration-runner/workspace-migration-runner.module'; -import { FieldMetadataService } from './field-metadata.service'; import { FieldMetadataEntity } from './field-metadata.entity'; +import { FieldMetadataService } from './field-metadata.service'; import { CreateFieldInput } from './dtos/create-field.input'; import { UpdateFieldInput } from './dtos/update-field.input'; @@ -61,6 +62,7 @@ import { UpdateFieldInput } from './dtos/update-field.input'; }, delete: { disabled: true }, guards: [JwtAuthGuard], + interceptors: [FieldMetadataGraphqlApiExceptionInterceptor], }, ], }), diff --git a/packages/twenty-server/src/engine/metadata-modules/field-metadata/field-metadata.resolver.ts b/packages/twenty-server/src/engine/metadata-modules/field-metadata/field-metadata.resolver.ts index b4bc92e00fa8..f92b8144b53e 100644 --- a/packages/twenty-server/src/engine/metadata-modules/field-metadata/field-metadata.resolver.ts +++ b/packages/twenty-server/src/engine/metadata-modules/field-metadata/field-metadata.resolver.ts @@ -23,6 +23,7 @@ import { RelationDefinitionDTO } from 'src/engine/metadata-modules/field-metadat import { UpdateOneFieldMetadataInput } from 'src/engine/metadata-modules/field-metadata/dtos/update-field.input'; import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; import { FieldMetadataService } from 'src/engine/metadata-modules/field-metadata/field-metadata.service'; +import { fieldMetadataGraphqlApiExceptionHandler } from 'src/engine/metadata-modules/field-metadata/utils/field-metadata-graphql-api-exception-handler.util'; @UseGuards(JwtAuthGuard) @Resolver(() => FieldMetadataDTO) @@ -30,25 +31,33 @@ export class FieldMetadataResolver { constructor(private readonly fieldMetadataService: FieldMetadataService) {} @Mutation(() => FieldMetadataDTO) - createOneField( + async createOneField( @Args('input') input: CreateOneFieldMetadataInput, @AuthWorkspace() { id: workspaceId }: Workspace, ) { - return this.fieldMetadataService.createOne({ - ...input.field, - workspaceId, - }); + try { + return await this.fieldMetadataService.createOne({ + ...input.field, + workspaceId, + }); + } catch (error) { + fieldMetadataGraphqlApiExceptionHandler(error); + } } @Mutation(() => FieldMetadataDTO) - updateOneField( + async updateOneField( @Args('input') input: UpdateOneFieldMetadataInput, @AuthWorkspace() { id: workspaceId }: Workspace, ) { - return this.fieldMetadataService.updateOne(input.id, { - ...input.update, - workspaceId, - }); + try { + return await this.fieldMetadataService.updateOne(input.id, { + ...input.update, + workspaceId, + }); + } catch (error) { + fieldMetadataGraphqlApiExceptionHandler(error); + } } @Mutation(() => FieldMetadataDTO) @@ -85,27 +94,32 @@ export class FieldMetadataResolver { ); } - return this.fieldMetadataService.deleteOneField(input, workspaceId); + try { + return await this.fieldMetadataService.deleteOneField(input, workspaceId); + } catch (error) { + fieldMetadataGraphqlApiExceptionHandler(error); + } } @ResolveField(() => RelationDefinitionDTO, { nullable: true }) async relationDefinition( @Parent() fieldMetadata: FieldMetadataDTO, @Context() context: { loaders: IDataloaders }, - ): Promise<RelationDefinitionDTO | null> { + ): Promise<RelationDefinitionDTO | null | undefined> { if (fieldMetadata.type !== FieldMetadataType.RELATION) { return null; } - const relationMetadataItem = - await context.loaders.relationMetadataLoader.load(fieldMetadata.id); + try { + const relationMetadataItem = + await context.loaders.relationMetadataLoader.load(fieldMetadata.id); - const relationDefinition = - await this.fieldMetadataService.getRelationDefinitionFromRelationMetadata( + return await this.fieldMetadataService.getRelationDefinitionFromRelationMetadata( fieldMetadata, relationMetadataItem, ); - - return relationDefinition; + } catch (error) { + fieldMetadataGraphqlApiExceptionHandler(error); + } } } diff --git a/packages/twenty-server/src/engine/metadata-modules/field-metadata/field-metadata.service.ts b/packages/twenty-server/src/engine/metadata-modules/field-metadata/field-metadata.service.ts index 8098b4f26957..fe817577320f 100644 --- a/packages/twenty-server/src/engine/metadata-modules/field-metadata/field-metadata.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/field-metadata/field-metadata.service.ts @@ -1,56 +1,60 @@ -import { - BadRequestException, - ConflictException, - Injectable, - NotFoundException, -} from '@nestjs/common'; +import { Injectable } from '@nestjs/common'; import { InjectDataSource, InjectRepository } from '@nestjs/typeorm'; -import { v4 as uuidV4 } from 'uuid'; -import { DataSource, FindOneOptions, Repository } from 'typeorm'; import { TypeOrmQueryService } from '@ptc-org/nestjs-query-typeorm'; +import { DataSource, FindOneOptions, Repository } from 'typeorm'; +import { v4 as uuidV4 } from 'uuid'; -import { WorkspaceMigrationRunnerService } from 'src/engine/workspace-manager/workspace-migration-runner/workspace-migration-runner.service'; -import { WorkspaceMigrationService } from 'src/engine/metadata-modules/workspace-migration/workspace-migration.service'; -import { ObjectMetadataService } from 'src/engine/metadata-modules/object-metadata/object-metadata.service'; -import { CreateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/create-field.input'; -import { - WorkspaceMigrationColumnActionType, - WorkspaceMigrationColumnDrop, - WorkspaceMigrationTableAction, - WorkspaceMigrationTableActionType, -} from 'src/engine/metadata-modules/workspace-migration/workspace-migration.entity'; import { TypeORMService } from 'src/database/typeorm/typeorm.service'; import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; -import { UpdateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/update-field.input'; -import { WorkspaceMigrationFactory } from 'src/engine/metadata-modules/workspace-migration/workspace-migration.factory'; -import { computeObjectTargetTable } from 'src/engine/utils/compute-object-target-table.util'; -import { generateMigrationName } from 'src/engine/metadata-modules/workspace-migration/utils/generate-migration-name.util'; -import { generateNullable } from 'src/engine/metadata-modules/field-metadata/utils/generate-nullable'; +import { CreateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/create-field.input'; +import { DeleteOneFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/delete-field.input'; import { FieldMetadataDTO } from 'src/engine/metadata-modules/field-metadata/dtos/field-metadata.dto'; import { RelationDefinitionDTO, RelationDefinitionType, } from 'src/engine/metadata-modules/field-metadata/dtos/relation-definition.dto'; +import { UpdateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/update-field.input'; +import { + FieldMetadataException, + FieldMetadataExceptionCode, +} from 'src/engine/metadata-modules/field-metadata/field-metadata.exception'; +import { assertDoesNotNullifyDefaultValueForNonNullableField } from 'src/engine/metadata-modules/field-metadata/utils/assert-does-not-nullify-default-value-for-non-nullable-field.util'; +import { computeColumnName } from 'src/engine/metadata-modules/field-metadata/utils/compute-column-name.util'; +import { generateNullable } from 'src/engine/metadata-modules/field-metadata/utils/generate-nullable'; +import { ObjectMetadataService } from 'src/engine/metadata-modules/object-metadata/object-metadata.service'; +import { assertMutationNotOnRemoteObject } from 'src/engine/metadata-modules/object-metadata/utils/assert-mutation-not-on-remote-object.util'; import { RelationMetadataEntity, RelationMetadataType, } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity'; -import { DeleteOneFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/delete-field.input'; -import { computeColumnName } from 'src/engine/metadata-modules/field-metadata/utils/compute-column-name.util'; -import { assertMutationNotOnRemoteObject } from 'src/engine/metadata-modules/object-metadata/utils/assert-mutation-not-on-remote-object.util'; -import { InvalidStringException } from 'src/engine/metadata-modules/errors/InvalidStringException'; -import { validateMetadataName } from 'src/engine/metadata-modules/utils/validate-metadata-name.utils'; +import { exceedsDatabaseIdentifierMaximumLength } from 'src/engine/metadata-modules/utils/validate-database-identifier-length.utils'; +import { + InvalidStringException, + NameTooLongException, + validateMetadataNameOrThrow, +} from 'src/engine/metadata-modules/utils/validate-metadata-name.utils'; import { WorkspaceCacheVersionService } from 'src/engine/metadata-modules/workspace-cache-version/workspace-cache-version.service'; +import { generateMigrationName } from 'src/engine/metadata-modules/workspace-migration/utils/generate-migration-name.util'; +import { + WorkspaceMigrationColumnActionType, + WorkspaceMigrationColumnDrop, + WorkspaceMigrationTableAction, + WorkspaceMigrationTableActionType, +} from 'src/engine/metadata-modules/workspace-migration/workspace-migration.entity'; +import { WorkspaceMigrationFactory } from 'src/engine/metadata-modules/workspace-migration/workspace-migration.factory'; +import { WorkspaceMigrationService } from 'src/engine/metadata-modules/workspace-migration/workspace-migration.service'; +import { computeObjectTargetTable } from 'src/engine/utils/compute-object-target-table.util'; +import { WorkspaceMigrationRunnerService } from 'src/engine/workspace-manager/workspace-migration-runner/workspace-migration-runner.service'; import { FieldMetadataEntity, FieldMetadataType, } from './field-metadata.entity'; -import { isEnumFieldMetadataType } from './utils/is-enum-field-metadata-type.util'; -import { generateRatingOptions } from './utils/generate-rating-optionts.util'; import { generateDefaultValue } from './utils/generate-default-value'; +import { generateRatingOptions } from './utils/generate-rating-optionts.util'; +import { isEnumFieldMetadataType } from './utils/is-enum-field-metadata-type.util'; @Injectable() export class FieldMetadataService extends TypeOrmQueryService<FieldMetadataEntity> { @@ -94,7 +98,10 @@ export class FieldMetadataService extends TypeOrmQueryService<FieldMetadataEntit ); if (!objectMetadata) { - throw new NotFoundException('Object does not exist'); + throw new FieldMetadataException( + 'Object metadata does not exist', + FieldMetadataExceptionCode.INVALID_FIELD_INPUT, + ); } if (!fieldMetadataInput.isRemoteCreation) { @@ -107,7 +114,10 @@ export class FieldMetadataService extends TypeOrmQueryService<FieldMetadataEntit !fieldMetadataInput.options && fieldMetadataInput.type !== FieldMetadataType.RATING ) { - throw new BadRequestException('Options are required for enum fields'); + throw new FieldMetadataException( + 'Options are required for enum fields', + FieldMetadataExceptionCode.INVALID_FIELD_INPUT, + ); } } @@ -116,6 +126,13 @@ export class FieldMetadataService extends TypeOrmQueryService<FieldMetadataEntit fieldMetadataInput.options = generateRatingOptions(); } + if (fieldMetadataInput.type === FieldMetadataType.LINK) { + throw new FieldMetadataException( + '"Link" field types are being deprecated, please use Links type instead', + FieldMetadataExceptionCode.INVALID_FIELD_INPUT, + ); + } + this.validateFieldMetadataInput<CreateFieldInput>(fieldMetadataInput); const fieldAlreadyExists = await fieldMetadataRepository.findOne({ @@ -127,7 +144,10 @@ export class FieldMetadataService extends TypeOrmQueryService<FieldMetadataEntit }); if (fieldAlreadyExists) { - throw new ConflictException('Field already exists'); + throw new FieldMetadataException( + 'Field already exists', + FieldMetadataExceptionCode.FIELD_ALREADY_EXISTS, + ); } const createdFieldMetadata = await fieldMetadataRepository.save({ @@ -183,7 +203,10 @@ export class FieldMetadataService extends TypeOrmQueryService<FieldMetadataEntit const workspaceQueryRunner = workspaceDataSource?.createQueryRunner(); if (!workspaceQueryRunner) { - throw new Error('Could not create workspace query runner'); + throw new FieldMetadataException( + 'Could not create workspace query runner', + FieldMetadataExceptionCode.INTERNAL_SERVER_ERROR, + ); } await workspaceQueryRunner.connect(); @@ -263,7 +286,10 @@ export class FieldMetadataService extends TypeOrmQueryService<FieldMetadataEntit }); if (!existingFieldMetadata) { - throw new NotFoundException('Field does not exist'); + throw new FieldMetadataException( + 'Field does not exist', + FieldMetadataExceptionCode.FIELD_METADATA_NOT_FOUND, + ); } const objectMetadata = @@ -277,25 +303,37 @@ export class FieldMetadataService extends TypeOrmQueryService<FieldMetadataEntit ); if (!objectMetadata) { - throw new NotFoundException('Object does not exist'); + throw new FieldMetadataException( + 'Object metadata does not exist', + FieldMetadataExceptionCode.OBJECT_METADATA_NOT_FOUND, + ); } assertMutationNotOnRemoteObject(objectMetadata); + assertDoesNotNullifyDefaultValueForNonNullableField({ + isNullable: existingFieldMetadata.isNullable, + defaultValueFromUpdate: fieldMetadataInput.defaultValue, + }); + if ( objectMetadata.labelIdentifierFieldMetadataId === existingFieldMetadata.id && fieldMetadataInput.isActive === false ) { - throw new BadRequestException( + throw new FieldMetadataException( 'Cannot deactivate label identifier field', + FieldMetadataExceptionCode.FIELD_MUTATION_NOT_ALLOWED, ); } if (fieldMetadataInput.options) { for (const option of fieldMetadataInput.options) { if (!option.id) { - throw new BadRequestException('Option id is required'); + throw new FieldMetadataException( + 'Option id is required', + FieldMetadataExceptionCode.INVALID_FIELD_INPUT, + ); } } } @@ -325,10 +363,18 @@ export class FieldMetadataService extends TypeOrmQueryService<FieldMetadataEntit ? updatableFieldInput.defaultValue : null, }); - const updatedFieldMetadata = await fieldMetadataRepository.findOneOrFail({ + + const updatedFieldMetadata = await fieldMetadataRepository.findOne({ where: { id }, }); + if (!updatedFieldMetadata) { + throw new FieldMetadataException( + 'Field does not exist', + FieldMetadataExceptionCode.FIELD_METADATA_NOT_FOUND, + ); + } + if ( fieldMetadataInput.name || updatableFieldInput.options || @@ -392,7 +438,10 @@ export class FieldMetadataService extends TypeOrmQueryService<FieldMetadataEntit }); if (!fieldMetadata) { - throw new NotFoundException('Field does not exist'); + throw new FieldMetadataException( + 'Field does not exist', + FieldMetadataExceptionCode.FIELD_METADATA_NOT_FOUND, + ); } const objectMetadata = @@ -403,7 +452,10 @@ export class FieldMetadataService extends TypeOrmQueryService<FieldMetadataEntit }); if (!objectMetadata) { - throw new NotFoundException('Object does not exist'); + throw new FieldMetadataException( + 'Object metadata does not exist', + FieldMetadataExceptionCode.OBJECT_METADATA_NOT_FOUND, + ); } await fieldMetadataRepository.delete(fieldMetadata.id); @@ -454,7 +506,10 @@ export class FieldMetadataService extends TypeOrmQueryService<FieldMetadataEntit }); if (!fieldMetadata) { - throw new NotFoundException('Field does not exist'); + throw new FieldMetadataException( + 'Field does not exist', + FieldMetadataExceptionCode.FIELD_METADATA_NOT_FOUND, + ); } return fieldMetadata; @@ -517,9 +572,12 @@ export class FieldMetadataService extends TypeOrmQueryService<FieldMetadataEntit relationMetadata.relationType === RelationMetadataType.MANY_TO_MANY || relationMetadata.relationType === RelationMetadataType.MANY_TO_ONE ) { - throw new Error(` + throw new FieldMetadataException( + ` Relation type ${relationMetadata.relationType} not supported - `); + `, + FieldMetadataExceptionCode.INVALID_FIELD_INPUT, + ); } if (isRelationFromSource) { @@ -558,11 +616,17 @@ export class FieldMetadataService extends TypeOrmQueryService<FieldMetadataEntit >(fieldMetadataInput: T): T { if (fieldMetadataInput.name) { try { - validateMetadataName(fieldMetadataInput.name); + validateMetadataNameOrThrow(fieldMetadataInput.name); } catch (error) { if (error instanceof InvalidStringException) { - throw new BadRequestException( + throw new FieldMetadataException( `Characters used in name "${fieldMetadataInput.name}" are not supported`, + FieldMetadataExceptionCode.INVALID_FIELD_INPUT, + ); + } else if (error instanceof NameTooLongException) { + throw new FieldMetadataException( + `Name "${fieldMetadataInput.name}" exceeds 63 characters`, + FieldMetadataExceptionCode.INVALID_FIELD_INPUT, ); } else { throw error; @@ -570,6 +634,17 @@ export class FieldMetadataService extends TypeOrmQueryService<FieldMetadataEntit } } + if (fieldMetadataInput.options) { + for (const option of fieldMetadataInput.options) { + if (exceedsDatabaseIdentifierMaximumLength(option.value)) { + throw new FieldMetadataException( + `Option value "${option.value}" exceeds 63 characters`, + FieldMetadataExceptionCode.INVALID_FIELD_INPUT, + ); + } + } + } + return fieldMetadataInput; } } diff --git a/packages/twenty-server/src/engine/metadata-modules/field-metadata/interceptors/field-metadata-graphql-api-exception.interceptor.ts b/packages/twenty-server/src/engine/metadata-modules/field-metadata/interceptors/field-metadata-graphql-api-exception.interceptor.ts new file mode 100644 index 000000000000..4c2696e0d32f --- /dev/null +++ b/packages/twenty-server/src/engine/metadata-modules/field-metadata/interceptors/field-metadata-graphql-api-exception.interceptor.ts @@ -0,0 +1,15 @@ +import { CallHandler, ExecutionContext, NestInterceptor } from '@nestjs/common'; + +import { Observable, catchError } from 'rxjs'; + +import { fieldMetadataGraphqlApiExceptionHandler } from 'src/engine/metadata-modules/field-metadata/utils/field-metadata-graphql-api-exception-handler.util'; + +export class FieldMetadataGraphqlApiExceptionInterceptor + implements NestInterceptor +{ + intercept(_: ExecutionContext, next: CallHandler): Observable<any> { + return next + .handle() + .pipe(catchError((err) => fieldMetadataGraphqlApiExceptionHandler(err))); + } +} diff --git a/packages/twenty-server/src/engine/metadata-modules/field-metadata/interfaces/field-metadata-default-value.interface.ts b/packages/twenty-server/src/engine/metadata-modules/field-metadata/interfaces/field-metadata-default-value.interface.ts index c78af0480a45..f3e24005c7ef 100644 --- a/packages/twenty-server/src/engine/metadata-modules/field-metadata/interfaces/field-metadata-default-value.interface.ts +++ b/packages/twenty-server/src/engine/metadata-modules/field-metadata/interfaces/field-metadata-default-value.interface.ts @@ -35,7 +35,6 @@ type FieldMetadataDefaultValueMapping = { [FieldMetadataType.NUMBER]: FieldMetadataDefaultValueNumber; [FieldMetadataType.POSITION]: FieldMetadataDefaultValueNumber; [FieldMetadataType.NUMERIC]: FieldMetadataDefaultValueString; - [FieldMetadataType.PROBABILITY]: FieldMetadataDefaultValueNumber; [FieldMetadataType.LINK]: FieldMetadataDefaultValueLink; [FieldMetadataType.LINKS]: FieldMetadataDefaultValueLinks; [FieldMetadataType.CURRENCY]: FieldMetadataDefaultValueCurrency; diff --git a/packages/twenty-server/src/engine/metadata-modules/field-metadata/utils/__tests__/assert-does-not-nullify-default-value-for-non-nullable-field.spec.ts b/packages/twenty-server/src/engine/metadata-modules/field-metadata/utils/__tests__/assert-does-not-nullify-default-value-for-non-nullable-field.spec.ts new file mode 100644 index 000000000000..04ecc103340d --- /dev/null +++ b/packages/twenty-server/src/engine/metadata-modules/field-metadata/utils/__tests__/assert-does-not-nullify-default-value-for-non-nullable-field.spec.ts @@ -0,0 +1,38 @@ +import { assertDoesNotNullifyDefaultValueForNonNullableField } from 'src/engine/metadata-modules/field-metadata/utils/assert-does-not-nullify-default-value-for-non-nullable-field.util'; + +describe('assertDoesNotNullifyDefaultValueForNonNullableField', () => { + it('should not throw if default value is set to null and field is nullable', () => { + expect(() => + assertDoesNotNullifyDefaultValueForNonNullableField({ + isNullable: true, + defaultValueFromUpdate: null, + }), + ).not.toThrow(); + }); + + it('should not throw if default value is undefined and field is non nullable', () => { + expect(() => + assertDoesNotNullifyDefaultValueForNonNullableField({ + isNullable: false, + }), + ).not.toThrow(); + }); + + it('should not throw if default value is not set to null and field is non nullable', () => { + expect(() => + assertDoesNotNullifyDefaultValueForNonNullableField({ + isNullable: false, + defaultValueFromUpdate: 'new default value', + }), + ).not.toThrow(); + }); + + it('should throw if default value is set to null and field is non nullable', () => { + expect(() => + assertDoesNotNullifyDefaultValueForNonNullableField({ + isNullable: false, + defaultValueFromUpdate: null, + }), + ).toThrow(); + }); +}); diff --git a/packages/twenty-server/src/engine/metadata-modules/field-metadata/utils/__tests__/serialize-default-value.spec.ts b/packages/twenty-server/src/engine/metadata-modules/field-metadata/utils/__tests__/serialize-default-value.spec.ts index 61e46ec6a8c5..476104f1bba3 100644 --- a/packages/twenty-server/src/engine/metadata-modules/field-metadata/utils/__tests__/serialize-default-value.spec.ts +++ b/packages/twenty-server/src/engine/metadata-modules/field-metadata/utils/__tests__/serialize-default-value.spec.ts @@ -1,5 +1,4 @@ -import { BadRequestException } from '@nestjs/common'; - +import { FieldMetadataException } from 'src/engine/metadata-modules/field-metadata/field-metadata.exception'; import { serializeDefaultValue } from 'src/engine/metadata-modules/field-metadata/utils/serialize-default-value'; describe('serializeDefaultValue', () => { @@ -15,8 +14,10 @@ describe('serializeDefaultValue', () => { expect(serializeDefaultValue('now')).toBe('now()'); }); - it('should throw BadRequestException for invalid dynamic default value type', () => { - expect(() => serializeDefaultValue('invalid')).toThrow(BadRequestException); + it('should throw FieldMetadataException for invalid dynamic default value type', () => { + expect(() => serializeDefaultValue('invalid')).toThrow( + FieldMetadataException, + ); }); it('should handle string static default value', () => { diff --git a/packages/twenty-server/src/engine/metadata-modules/field-metadata/utils/__tests__/validate-default-value-based-on-type.spec.ts b/packages/twenty-server/src/engine/metadata-modules/field-metadata/utils/__tests__/validate-default-value-based-on-type.spec.ts index 757303d4c1ea..3695a072ec9c 100644 --- a/packages/twenty-server/src/engine/metadata-modules/field-metadata/utils/__tests__/validate-default-value-based-on-type.spec.ts +++ b/packages/twenty-server/src/engine/metadata-modules/field-metadata/utils/__tests__/validate-default-value-based-on-type.spec.ts @@ -78,18 +78,6 @@ describe('validateDefaultValueForType', () => { ).toBe(false); }); - it('should validate number default value for PROBABILITY type', () => { - expect( - validateDefaultValueForType(FieldMetadataType.PROBABILITY, 0.5).isValid, - ).toBe(true); - }); - - it('should return false for invalid number default value for PROBABILITY type', () => { - expect( - validateDefaultValueForType(FieldMetadataType.PROBABILITY, '50%').isValid, - ).toBe(false); - }); - it('should validate boolean default value for BOOLEAN type', () => { expect( validateDefaultValueForType(FieldMetadataType.BOOLEAN, true).isValid, diff --git a/packages/twenty-server/src/engine/metadata-modules/field-metadata/utils/assert-does-not-nullify-default-value-for-non-nullable-field.util.ts b/packages/twenty-server/src/engine/metadata-modules/field-metadata/utils/assert-does-not-nullify-default-value-for-non-nullable-field.util.ts new file mode 100644 index 000000000000..7fcd625b82de --- /dev/null +++ b/packages/twenty-server/src/engine/metadata-modules/field-metadata/utils/assert-does-not-nullify-default-value-for-non-nullable-field.util.ts @@ -0,0 +1,19 @@ +import { + FieldMetadataException, + FieldMetadataExceptionCode, +} from 'src/engine/metadata-modules/field-metadata/field-metadata.exception'; + +export const assertDoesNotNullifyDefaultValueForNonNullableField = ({ + isNullable, + defaultValueFromUpdate, +}: { + isNullable: boolean; + defaultValueFromUpdate?: any; +}) => { + if (!isNullable && defaultValueFromUpdate === null) { + throw new FieldMetadataException( + 'Default value cannot be nullified for non-nullable field', + FieldMetadataExceptionCode.INVALID_FIELD_INPUT, + ); + } +}; diff --git a/packages/twenty-server/src/engine/metadata-modules/field-metadata/utils/compute-column-name.util.ts b/packages/twenty-server/src/engine/metadata-modules/field-metadata/utils/compute-column-name.util.ts index c1f358ad44b7..116eb94f165f 100644 --- a/packages/twenty-server/src/engine/metadata-modules/field-metadata/utils/compute-column-name.util.ts +++ b/packages/twenty-server/src/engine/metadata-modules/field-metadata/utils/compute-column-name.util.ts @@ -4,6 +4,10 @@ import { CompositeProperty } from 'src/engine/metadata-modules/field-metadata/in import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; import { isCompositeFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/utils/is-composite-field-metadata-type.util'; import { pascalCase } from 'src/utils/pascal-case'; +import { + FieldMetadataException, + FieldMetadataExceptionCode, +} from 'src/engine/metadata-modules/field-metadata/field-metadata.exception'; type ComputeColumnNameOptions = { isForeignKey?: boolean }; @@ -29,8 +33,9 @@ export function computeColumnName<T extends FieldMetadataType | 'default'>( } if (isCompositeFieldMetadataType(fieldMetadataOrFieldName.type)) { - throw new Error( - `Cannot compute column name for composite field metadata type: ${fieldMetadataOrFieldName.type}`, + throw new FieldMetadataException( + `Cannot compute composite column name for non-composite field metadata type: ${fieldMetadataOrFieldName.type}`, + FieldMetadataExceptionCode.INVALID_FIELD_INPUT, ); } @@ -61,8 +66,9 @@ export function computeCompositeColumnName< } if (!isCompositeFieldMetadataType(fieldMetadataOrFieldName.type)) { - throw new Error( + throw new FieldMetadataException( `Cannot compute composite column name for non-composite field metadata type: ${fieldMetadataOrFieldName.type}`, + FieldMetadataExceptionCode.INVALID_FIELD_INPUT, ); } diff --git a/packages/twenty-server/src/engine/metadata-modules/field-metadata/utils/field-metadata-graphql-api-exception-handler.util.ts b/packages/twenty-server/src/engine/metadata-modules/field-metadata/utils/field-metadata-graphql-api-exception-handler.util.ts new file mode 100644 index 000000000000..5ff6bf16169a --- /dev/null +++ b/packages/twenty-server/src/engine/metadata-modules/field-metadata/utils/field-metadata-graphql-api-exception-handler.util.ts @@ -0,0 +1,32 @@ +import { + ConflictError, + ForbiddenError, + InternalServerError, + NotFoundError, + UserInputError, +} from 'src/engine/core-modules/graphql/utils/graphql-errors.util'; +import { + FieldMetadataException, + FieldMetadataExceptionCode, +} from 'src/engine/metadata-modules/field-metadata/field-metadata.exception'; + +export const fieldMetadataGraphqlApiExceptionHandler = (error: Error) => { + if (error instanceof FieldMetadataException) { + switch (error.code) { + case FieldMetadataExceptionCode.FIELD_METADATA_NOT_FOUND: + throw new NotFoundError(error.message); + case FieldMetadataExceptionCode.INVALID_FIELD_INPUT: + throw new UserInputError(error.message); + case FieldMetadataExceptionCode.FIELD_MUTATION_NOT_ALLOWED: + throw new ForbiddenError(error.message); + case FieldMetadataExceptionCode.FIELD_ALREADY_EXISTS: + throw new ConflictError(error.message); + case FieldMetadataExceptionCode.OBJECT_METADATA_NOT_FOUND: + case FieldMetadataExceptionCode.INTERNAL_SERVER_ERROR: + default: + throw new InternalServerError(error.message); + } + } + + throw error; +}; diff --git a/packages/twenty-server/src/engine/metadata-modules/field-metadata/utils/serialize-default-value.ts b/packages/twenty-server/src/engine/metadata-modules/field-metadata/utils/serialize-default-value.ts index 2f93da1b8cc9..7445e0fed2ec 100644 --- a/packages/twenty-server/src/engine/metadata-modules/field-metadata/utils/serialize-default-value.ts +++ b/packages/twenty-server/src/engine/metadata-modules/field-metadata/utils/serialize-default-value.ts @@ -1,7 +1,9 @@ -import { BadRequestException } from '@nestjs/common'; - import { FieldMetadataDefaultSerializableValue } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata-default-value.interface'; +import { + FieldMetadataException, + FieldMetadataExceptionCode, +} from 'src/engine/metadata-modules/field-metadata/field-metadata.exception'; import { isFunctionDefaultValue } from 'src/engine/metadata-modules/field-metadata/utils/is-function-default-value.util'; import { serializeFunctionDefaultValue } from 'src/engine/metadata-modules/field-metadata/utils/serialize-function-default-value.util'; @@ -18,7 +20,10 @@ export const serializeDefaultValue = ( serializeFunctionDefaultValue(defaultValue); if (!serializedTypeDefaultValue) { - throw new BadRequestException('Invalid default value'); + throw new FieldMetadataException( + 'Invalid default value', + FieldMetadataExceptionCode.INVALID_FIELD_INPUT, + ); } return serializedTypeDefaultValue; @@ -51,5 +56,8 @@ export const serializeDefaultValue = ( return `'${JSON.stringify(defaultValue)}'`; } - throw new BadRequestException(`Invalid default value "${defaultValue}"`); + throw new FieldMetadataException( + `Invalid default value "${defaultValue}"`, + FieldMetadataExceptionCode.INVALID_FIELD_INPUT, + ); }; diff --git a/packages/twenty-server/src/engine/metadata-modules/field-metadata/utils/validate-default-value-for-type.util.ts b/packages/twenty-server/src/engine/metadata-modules/field-metadata/utils/validate-default-value-for-type.util.ts index bb7ec90f8658..776c49db65e3 100644 --- a/packages/twenty-server/src/engine/metadata-modules/field-metadata/utils/validate-default-value-for-type.util.ts +++ b/packages/twenty-server/src/engine/metadata-modules/field-metadata/utils/validate-default-value-for-type.util.ts @@ -41,7 +41,6 @@ export const defaultValueValidatorsMap = { [FieldMetadataType.BOOLEAN]: [FieldMetadataDefaultValueBoolean], [FieldMetadataType.NUMBER]: [FieldMetadataDefaultValueNumber], [FieldMetadataType.NUMERIC]: [FieldMetadataDefaultValueString], - [FieldMetadataType.PROBABILITY]: [FieldMetadataDefaultValueNumber], [FieldMetadataType.LINK]: [FieldMetadataDefaultValueLink], [FieldMetadataType.CURRENCY]: [FieldMetadataDefaultValueCurrency], [FieldMetadataType.FULL_NAME]: [FieldMetadataDefaultValueFullName], diff --git a/packages/twenty-server/src/engine/metadata-modules/field-metadata/utils/validate-options-for-type.util.ts b/packages/twenty-server/src/engine/metadata-modules/field-metadata/utils/validate-options-for-type.util.ts index 7e119d594638..aecb4eefe9fd 100644 --- a/packages/twenty-server/src/engine/metadata-modules/field-metadata/utils/validate-options-for-type.util.ts +++ b/packages/twenty-server/src/engine/metadata-modules/field-metadata/utils/validate-options-for-type.util.ts @@ -8,6 +8,10 @@ import { FieldMetadataComplexOption, FieldMetadataDefaultOption, } from 'src/engine/metadata-modules/field-metadata/dtos/options.input'; +import { + FieldMetadataException, + FieldMetadataExceptionCode, +} from 'src/engine/metadata-modules/field-metadata/field-metadata.exception'; import { isEnumFieldMetadataType } from './is-enum-field-metadata-type.util'; @@ -24,7 +28,10 @@ export const validateOptionsForType = ( if (options === null) return true; if (!Array.isArray(options)) { - throw new Error('Options must be an array'); + throw new FieldMetadataException( + 'Options must be an array', + FieldMetadataExceptionCode.INVALID_FIELD_INPUT, + ); } if (!isEnumFieldMetadataType(type)) { @@ -39,7 +46,10 @@ export const validateOptionsForType = ( // Check if all options are unique if (new Set(values).size !== options.length) { - throw new Error('Options must be unique'); + throw new FieldMetadataException( + 'Options must be unique', + FieldMetadataExceptionCode.INVALID_FIELD_INPUT, + ); } const validators = optionsValidatorsMap[type]; diff --git a/packages/twenty-server/src/engine/metadata-modules/index-field-metadata/index-field-metadata.entity.ts b/packages/twenty-server/src/engine/metadata-modules/index-field-metadata/index-field-metadata.entity.ts new file mode 100644 index 000000000000..036bee830ca0 --- /dev/null +++ b/packages/twenty-server/src/engine/metadata-modules/index-field-metadata/index-field-metadata.entity.ts @@ -0,0 +1,54 @@ +import { + Column, + CreateDateColumn, + Entity, + JoinColumn, + ManyToOne, + PrimaryGeneratedColumn, + Relation, + UpdateDateColumn, +} from 'typeorm'; + +import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; +import { IndexMetadataEntity } from 'src/engine/metadata-modules/index-metadata/index-metadata.entity'; + +@Entity('indexFieldMetadata') +export class IndexFieldMetadataEntity { + @PrimaryGeneratedColumn('uuid') + id: string; + + @Column({ nullable: false }) + indexMetadataId: string; + + @ManyToOne( + () => IndexMetadataEntity, + (indexMetadata) => indexMetadata.indexFieldMetadatas, + { + onDelete: 'CASCADE', + }, + ) + @JoinColumn() + indexMetadata: Relation<IndexMetadataEntity>; + + @Column({ nullable: false }) + fieldMetadataId: string; + + @ManyToOne( + () => FieldMetadataEntity, + (fieldMetadata) => fieldMetadata.indexFieldMetadatas, + { + onDelete: 'CASCADE', + }, + ) + @JoinColumn() + fieldMetadata: Relation<FieldMetadataEntity>; + + @Column({ nullable: false }) + order: number; + + @CreateDateColumn({ type: 'timestamptz' }) + createdAt: Date; + + @UpdateDateColumn({ type: 'timestamptz' }) + updatedAt: Date; +} diff --git a/packages/twenty-server/src/engine/metadata-modules/index-field-metadata/index-field-metadata.module.ts b/packages/twenty-server/src/engine/metadata-modules/index-field-metadata/index-field-metadata.module.ts new file mode 100644 index 000000000000..937851df1ed9 --- /dev/null +++ b/packages/twenty-server/src/engine/metadata-modules/index-field-metadata/index-field-metadata.module.ts @@ -0,0 +1,11 @@ +import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; + +import { IndexFieldMetadataEntity } from 'src/engine/metadata-modules/index-field-metadata/index-field-metadata.entity'; + +@Module({ + imports: [TypeOrmModule.forFeature([IndexFieldMetadataEntity], 'metadata')], + providers: [], + exports: [], +}) +export class IndexFieldMetadataModule {} diff --git a/packages/twenty-server/src/engine/metadata-modules/index-metadata/index-metadata.entity.ts b/packages/twenty-server/src/engine/metadata-modules/index-metadata/index-metadata.entity.ts new file mode 100644 index 000000000000..74b15a10d089 --- /dev/null +++ b/packages/twenty-server/src/engine/metadata-modules/index-metadata/index-metadata.entity.ts @@ -0,0 +1,51 @@ +import { + Column, + CreateDateColumn, + Entity, + JoinColumn, + ManyToOne, + OneToMany, + PrimaryGeneratedColumn, + Relation, + UpdateDateColumn, +} from 'typeorm'; + +import { IndexFieldMetadataEntity } from 'src/engine/metadata-modules/index-field-metadata/index-field-metadata.entity'; +import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; + +@Entity('indexMetadata') +export class IndexMetadataEntity { + @PrimaryGeneratedColumn('uuid') + id: string; + + @Column({ nullable: false }) + name: string; + + @Column({ nullable: true }) + workspaceId: string; + + @Column({ nullable: false, type: 'uuid' }) + objectMetadataId: string; + + @ManyToOne(() => ObjectMetadataEntity, (object) => object.indexes, { + onDelete: 'CASCADE', + }) + @JoinColumn() + objectMetadata: Relation<ObjectMetadataEntity>; + + @OneToMany( + () => IndexFieldMetadataEntity, + (indexFieldMetadata: IndexFieldMetadataEntity) => + indexFieldMetadata.indexMetadata, + { + cascade: true, + }, + ) + indexFieldMetadatas: Relation<IndexFieldMetadataEntity[]>; + + @CreateDateColumn({ type: 'timestamptz' }) + createdAt: Date; + + @UpdateDateColumn({ type: 'timestamptz' }) + updatedAt: Date; +} diff --git a/packages/twenty-server/src/engine/metadata-modules/index-metadata/index-metadata.module.ts b/packages/twenty-server/src/engine/metadata-modules/index-metadata/index-metadata.module.ts new file mode 100644 index 000000000000..01cb4a3e6a92 --- /dev/null +++ b/packages/twenty-server/src/engine/metadata-modules/index-metadata/index-metadata.module.ts @@ -0,0 +1,11 @@ +import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; + +import { IndexMetadataEntity } from 'src/engine/metadata-modules/index-metadata/index-metadata.entity'; + +@Module({ + imports: [TypeOrmModule.forFeature([IndexMetadataEntity], 'metadata')], + providers: [], + exports: [], +}) +export class IndexMetadataModule {} diff --git a/packages/twenty-server/src/engine/metadata-modules/index-metadata/utils/generate-deterministic-index-name.ts b/packages/twenty-server/src/engine/metadata-modules/index-metadata/utils/generate-deterministic-index-name.ts new file mode 100644 index 000000000000..ebf84d17d2da --- /dev/null +++ b/packages/twenty-server/src/engine/metadata-modules/index-metadata/utils/generate-deterministic-index-name.ts @@ -0,0 +1,11 @@ +import { createHash } from 'crypto'; + +export const generateDeterministicIndexName = (columns: string[]): string => { + const hash = createHash('sha256'); + + columns.forEach((column) => { + hash.update(column); + }); + + return hash.digest('hex').slice(0, 27); +}; diff --git a/packages/twenty-server/src/engine/metadata-modules/object-metadata/interceptors/object-metadata-graphql-api-exception.interceptor.ts b/packages/twenty-server/src/engine/metadata-modules/object-metadata/interceptors/object-metadata-graphql-api-exception.interceptor.ts new file mode 100644 index 000000000000..117fb32f3790 --- /dev/null +++ b/packages/twenty-server/src/engine/metadata-modules/object-metadata/interceptors/object-metadata-graphql-api-exception.interceptor.ts @@ -0,0 +1,15 @@ +import { CallHandler, ExecutionContext, NestInterceptor } from '@nestjs/common'; + +import { Observable, catchError } from 'rxjs'; + +import { objectMetadataGraphqlApiExceptionHandler } from 'src/engine/metadata-modules/object-metadata/utils/object-metadata-graphql-api-exception-handler.util'; + +export class ObjectMetadataGraphqlApiExceptionInterceptor + implements NestInterceptor +{ + intercept(_: ExecutionContext, next: CallHandler): Observable<any> { + return next + .handle() + .pipe(catchError((err) => objectMetadataGraphqlApiExceptionHandler(err))); + } +} diff --git a/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.constants.ts b/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.constants.ts new file mode 100644 index 000000000000..856d01f5db38 --- /dev/null +++ b/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.constants.ts @@ -0,0 +1 @@ +export const DEFAULT_LABEL_IDENTIFIER_FIELD_NAME = 'name'; diff --git a/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.entity.ts b/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.entity.ts index d4cf45c14165..cc64c231b704 100644 --- a/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.entity.ts +++ b/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.entity.ts @@ -15,6 +15,7 @@ import { ObjectMetadataInterface } from 'src/engine/metadata-modules/field-metad import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; import { RelationMetadataEntity } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity'; import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity'; +import { IndexMetadataEntity } from 'src/engine/metadata-modules/index-metadata/index-metadata.entity'; @Entity('objectMetadata') @Unique('IndexOnNameSingularAndWorkspaceIdUnique', [ @@ -82,6 +83,11 @@ export class ObjectMetadataEntity implements ObjectMetadataInterface { }) fields: Relation<FieldMetadataEntity[]>; + @OneToMany(() => FieldMetadataEntity, (field) => field.object, { + cascade: true, + }) + indexes: Relation<IndexMetadataEntity[]>; + @OneToMany( () => RelationMetadataEntity, (relation: RelationMetadataEntity) => relation.fromObjectMetadata, diff --git a/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.exception.ts b/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.exception.ts new file mode 100644 index 000000000000..2d489b1320ef --- /dev/null +++ b/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.exception.ts @@ -0,0 +1,15 @@ +import { CustomException } from 'src/utils/custom-exception'; + +export class ObjectMetadataException extends CustomException { + code: ObjectMetadataExceptionCode; + constructor(message: string, code: ObjectMetadataExceptionCode) { + super(message, code); + } +} + +export enum ObjectMetadataExceptionCode { + OBJECT_METADATA_NOT_FOUND = 'OBJECT_METADATA_NOT_FOUND', + INVALID_OBJECT_INPUT = 'INVALID_OBJECT_INPUT', + OBJECT_MUTATION_NOT_ALLOWED = 'OBJECT_MUTATION_NOT_ALLOWED', + OBJECT_ALREADY_EXISTS = 'OBJECT_ALREADY_EXISTS', +} diff --git a/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.module.ts b/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.module.ts index 9974403628bd..efd5aeccb44b 100644 --- a/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.module.ts +++ b/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.module.ts @@ -1,33 +1,34 @@ import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; +import { SortDirection } from '@ptc-org/nestjs-query-core'; import { NestjsQueryGraphQLModule, PagingStrategies, } from '@ptc-org/nestjs-query-graphql'; import { NestjsQueryTypeOrmModule } from '@ptc-org/nestjs-query-typeorm'; -import { SortDirection } from '@ptc-org/nestjs-query-core'; -import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module'; -import { WorkspaceMigrationRunnerModule } from 'src/engine/workspace-manager/workspace-migration-runner/workspace-migration-runner.module'; -import { WorkspaceMigrationModule } from 'src/engine/metadata-modules/workspace-migration/workspace-migration.module'; -import { JwtAuthGuard } from 'src/engine/guards/jwt.auth.guard'; import { TypeORMModule } from 'src/database/typeorm/typeorm.module'; -import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; -import { RelationMetadataEntity } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity'; -import { ObjectMetadataResolver } from 'src/engine/metadata-modules/object-metadata/object-metadata.resolver'; -import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module'; import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity'; -import { WorkspaceCacheVersionModule } from 'src/engine/metadata-modules/workspace-cache-version/workspace-cache-version.module'; +import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module'; +import { JwtAuthGuard } from 'src/engine/guards/jwt.auth.guard'; +import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module'; +import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; import { BeforeUpdateOneObject } from 'src/engine/metadata-modules/object-metadata/hooks/before-update-one-object.hook'; +import { ObjectMetadataGraphqlApiExceptionInterceptor } from 'src/engine/metadata-modules/object-metadata/interceptors/object-metadata-graphql-api-exception.interceptor'; +import { ObjectMetadataResolver } from 'src/engine/metadata-modules/object-metadata/object-metadata.resolver'; +import { RelationMetadataEntity } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity'; import { RemoteTableRelationsModule } from 'src/engine/metadata-modules/remote-server/remote-table/remote-table-relations/remote-table-relations.module'; +import { WorkspaceCacheVersionModule } from 'src/engine/metadata-modules/workspace-cache-version/workspace-cache-version.module'; +import { WorkspaceMigrationModule } from 'src/engine/metadata-modules/workspace-migration/workspace-migration.module'; +import { WorkspaceMigrationRunnerModule } from 'src/engine/workspace-manager/workspace-migration-runner/workspace-migration-runner.module'; -import { ObjectMetadataService } from './object-metadata.service'; import { ObjectMetadataEntity } from './object-metadata.entity'; +import { ObjectMetadataService } from './object-metadata.service'; import { CreateObjectInput } from './dtos/create-object.input'; -import { UpdateObjectPayload } from './dtos/update-object.input'; import { ObjectMetadataDTO } from './dtos/object-metadata.dto'; +import { UpdateObjectPayload } from './dtos/update-object.input'; @Module({ imports: [ @@ -64,6 +65,7 @@ import { ObjectMetadataDTO } from './dtos/object-metadata.dto'; update: { disabled: true }, delete: { disabled: true }, guards: [JwtAuthGuard], + interceptors: [ObjectMetadataGraphqlApiExceptionInterceptor], }, ], }), diff --git a/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.resolver.ts b/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.resolver.ts index ccb1b2a60643..9ae44b1fe996 100644 --- a/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.resolver.ts +++ b/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.resolver.ts @@ -12,6 +12,7 @@ import { UpdateOneObjectInput, } from 'src/engine/metadata-modules/object-metadata/dtos/update-object.input'; import { BeforeUpdateOneObject } from 'src/engine/metadata-modules/object-metadata/hooks/before-update-one-object.hook'; +import { objectMetadataGraphqlApiExceptionHandler } from 'src/engine/metadata-modules/object-metadata/utils/object-metadata-graphql-api-exception-handler.util'; @UseGuards(JwtAuthGuard) @Resolver(() => ObjectMetadataDTO) @@ -22,11 +23,18 @@ export class ObjectMetadataResolver { ) {} @Mutation(() => ObjectMetadataDTO) - deleteOneObject( + async deleteOneObject( @Args('input') input: DeleteOneObjectInput, @AuthWorkspace() { id: workspaceId }: Workspace, ) { - return this.objectMetadataService.deleteOneObject(input, workspaceId); + try { + return await this.objectMetadataService.deleteOneObject( + input, + workspaceId, + ); + } catch (error) { + objectMetadataGraphqlApiExceptionHandler(error); + } } @Mutation(() => ObjectMetadataDTO) @@ -34,8 +42,15 @@ export class ObjectMetadataResolver { @Args('input') input: UpdateOneObjectInput, @AuthWorkspace() { id: workspaceId }: Workspace, ) { - await this.beforeUpdateOneObject.run(input, workspaceId); + try { + await this.beforeUpdateOneObject.run(input, workspaceId); - return this.objectMetadataService.updateOneObject(input, workspaceId); + return await this.objectMetadataService.updateOneObject( + input, + workspaceId, + ); + } catch (error) { + objectMetadataGraphqlApiExceptionHandler(error); + } } } diff --git a/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.service.ts b/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.service.ts index 878a12192a13..c1e1d8111009 100644 --- a/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.service.ts @@ -1,9 +1,4 @@ -import { - BadRequestException, - ConflictException, - Injectable, - NotFoundException, -} from '@nestjs/common'; +import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import console from 'console'; @@ -56,6 +51,10 @@ import { mapUdtNameToFieldType } from 'src/engine/metadata-modules/remote-server import { WorkspaceCacheVersionService } from 'src/engine/metadata-modules/workspace-cache-version/workspace-cache-version.service'; import { UpdateOneObjectInput } from 'src/engine/metadata-modules/object-metadata/dtos/update-object.input'; import { RemoteTableRelationsService } from 'src/engine/metadata-modules/remote-server/remote-table/remote-table-relations/remote-table-relations.service'; +import { + ObjectMetadataException, + ObjectMetadataExceptionCode, +} from 'src/engine/metadata-modules/object-metadata/object-metadata.exception'; import { ObjectMetadataEntity } from './object-metadata.entity'; @@ -121,7 +120,10 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt }); if (!objectMetadata) { - throw new NotFoundException('Object does not exist'); + throw new ObjectMetadataException( + 'Object does not exist', + ObjectMetadataExceptionCode.OBJECT_METADATA_NOT_FOUND, + ); } // DELETE RELATIONS @@ -159,8 +161,9 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt objectMetadataInput.nameSingular.toLowerCase() === objectMetadataInput.namePlural.toLowerCase() ) { - throw new BadRequestException( + throw new ObjectMetadataException( 'The singular and plural name cannot be the same for an object', + ObjectMetadataExceptionCode.INVALID_OBJECT_INPUT, ); } @@ -186,7 +189,10 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt }); if (objectAlreadyExists) { - throw new ConflictException('Object already exists'); + throw new ObjectMetadataException( + 'Object already exists', + ObjectMetadataExceptionCode.OBJECT_ALREADY_EXISTS, + ); } const isCustom = !objectMetadataInput.isRemote; @@ -372,18 +378,25 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt workspaceId: string, options: FindOneOptions<ObjectMetadataEntity>, ): Promise<ObjectMetadataEntity> { - return this.objectMetadataRepository.findOneOrFail({ - relations: [ - 'fields', - 'fields.fromRelationMetadata', - 'fields.toRelationMetadata', - ], - ...options, - where: { - ...options.where, - workspaceId, - }, - }); + try { + return this.objectMetadataRepository.findOneOrFail({ + relations: [ + 'fields', + 'fields.fromRelationMetadata', + 'fields.toRelationMetadata', + ], + ...options, + where: { + ...options.where, + workspaceId, + }, + }); + } catch (error) { + throw new ObjectMetadataException( + 'Object does not exist', + ObjectMetadataExceptionCode.OBJECT_METADATA_NOT_FOUND, + ); + } } public async findManyWithinWorkspace( diff --git a/packages/twenty-server/src/engine/metadata-modules/object-metadata/utils/assert-mutation-not-on-remote-object.util.ts b/packages/twenty-server/src/engine/metadata-modules/object-metadata/utils/assert-mutation-not-on-remote-object.util.ts index 1bfcf6973ceb..0db389d95fef 100644 --- a/packages/twenty-server/src/engine/metadata-modules/object-metadata/utils/assert-mutation-not-on-remote-object.util.ts +++ b/packages/twenty-server/src/engine/metadata-modules/object-metadata/utils/assert-mutation-not-on-remote-object.util.ts @@ -1,11 +1,17 @@ -import { BadRequestException } from '@nestjs/common'; - import { ObjectMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/object-metadata.interface'; +import { + ObjectMetadataException, + ObjectMetadataExceptionCode, +} from 'src/engine/metadata-modules/object-metadata/object-metadata.exception'; + export const assertMutationNotOnRemoteObject = ( objectMetadataItem: ObjectMetadataInterface, ) => { if (objectMetadataItem.isRemote) { - throw new BadRequestException('Remote objects are read-only'); + throw new ObjectMetadataException( + 'Remote objects are read-only', + ObjectMetadataExceptionCode.OBJECT_MUTATION_NOT_ALLOWED, + ); } }; diff --git a/packages/twenty-server/src/engine/metadata-modules/object-metadata/utils/object-metadata-graphql-api-exception-handler.util.ts b/packages/twenty-server/src/engine/metadata-modules/object-metadata/utils/object-metadata-graphql-api-exception-handler.util.ts new file mode 100644 index 000000000000..ef00ed60f9fa --- /dev/null +++ b/packages/twenty-server/src/engine/metadata-modules/object-metadata/utils/object-metadata-graphql-api-exception-handler.util.ts @@ -0,0 +1,30 @@ +import { + ConflictError, + ForbiddenError, + InternalServerError, + NotFoundError, + UserInputError, +} from 'src/engine/core-modules/graphql/utils/graphql-errors.util'; +import { + ObjectMetadataException, + ObjectMetadataExceptionCode, +} from 'src/engine/metadata-modules/object-metadata/object-metadata.exception'; + +export const objectMetadataGraphqlApiExceptionHandler = (error: Error) => { + if (error instanceof ObjectMetadataException) { + switch (error.code) { + case ObjectMetadataExceptionCode.OBJECT_METADATA_NOT_FOUND: + throw new NotFoundError(error.message); + case ObjectMetadataExceptionCode.INVALID_OBJECT_INPUT: + throw new UserInputError(error.message); + case ObjectMetadataExceptionCode.OBJECT_MUTATION_NOT_ALLOWED: + throw new ForbiddenError(error.message); + case ObjectMetadataExceptionCode.OBJECT_ALREADY_EXISTS: + throw new ConflictError(error.message); + default: + throw new InternalServerError(error.message); + } + } + + throw error; +}; diff --git a/packages/twenty-server/src/engine/metadata-modules/object-metadata/utils/validate-object-metadata-input.util.ts b/packages/twenty-server/src/engine/metadata-modules/object-metadata/utils/validate-object-metadata-input.util.ts index 42d1c1b00545..a8a07ccc3353 100644 --- a/packages/twenty-server/src/engine/metadata-modules/object-metadata/utils/validate-object-metadata-input.util.ts +++ b/packages/twenty-server/src/engine/metadata-modules/object-metadata/utils/validate-object-metadata-input.util.ts @@ -1,9 +1,14 @@ -import { BadRequestException, ForbiddenException } from '@nestjs/common'; - -import { InvalidStringException } from 'src/engine/metadata-modules/errors/InvalidStringException'; import { CreateObjectInput } from 'src/engine/metadata-modules/object-metadata/dtos/create-object.input'; import { UpdateObjectPayload } from 'src/engine/metadata-modules/object-metadata/dtos/update-object.input'; -import { validateMetadataName } from 'src/engine/metadata-modules/utils/validate-metadata-name.utils'; +import { + ObjectMetadataException, + ObjectMetadataExceptionCode, +} from 'src/engine/metadata-modules/object-metadata/object-metadata.exception'; +import { exceedsDatabaseIdentifierMaximumLength } from 'src/engine/metadata-modules/utils/validate-database-identifier-length.utils'; +import { + validateMetadataNameOrThrow, + InvalidStringException, +} from 'src/engine/metadata-modules/utils/validate-metadata-name.utils'; import { camelCase } from 'src/utils/camel-case'; const coreObjectNames = [ @@ -50,12 +55,18 @@ export const validateObjectMetadataInputOrThrow = < validateNameIsNotReservedKeywordOrThrow(objectMetadataInput.nameSingular); validateNameIsNotReservedKeywordOrThrow(objectMetadataInput.namePlural); + + validateNameIsNotTooLongThrow(objectMetadataInput.nameSingular); + validateNameIsNotTooLongThrow(objectMetadataInput.namePlural); }; const validateNameIsNotReservedKeywordOrThrow = (name?: string) => { if (name) { if (reservedKeywords.includes(name)) { - throw new ForbiddenException(`The name "${name}" is not available`); + throw new ObjectMetadataException( + `The name "${name}" is not available`, + ObjectMetadataExceptionCode.INVALID_OBJECT_INPUT, + ); } } }; @@ -63,7 +74,21 @@ const validateNameIsNotReservedKeywordOrThrow = (name?: string) => { const validateNameCamelCasedOrThrow = (name?: string) => { if (name) { if (name !== camelCase(name)) { - throw new ForbiddenException(`Name should be in camelCase: ${name}`); + throw new ObjectMetadataException( + `Name should be in camelCase: ${name}`, + ObjectMetadataExceptionCode.INVALID_OBJECT_INPUT, + ); + } + } +}; + +const validateNameIsNotTooLongThrow = (name?: string) => { + if (name) { + if (exceedsDatabaseIdentifierMaximumLength(name)) { + throw new ObjectMetadataException( + `Name exceeds 63 characters: ${name}`, + ObjectMetadataExceptionCode.INVALID_OBJECT_INPUT, + ); } } }; @@ -71,12 +96,13 @@ const validateNameCamelCasedOrThrow = (name?: string) => { const validateNameCharactersOrThrow = (name?: string) => { try { if (name) { - validateMetadataName(name); + validateMetadataNameOrThrow(name); } } catch (error) { if (error instanceof InvalidStringException) { - throw new BadRequestException( + throw new ObjectMetadataException( `Characters used in name "${name}" are not supported`, + ObjectMetadataExceptionCode.INVALID_OBJECT_INPUT, ); } else { throw error; diff --git a/packages/twenty-server/src/engine/metadata-modules/relation-metadata/interceptors/relation-metadata-graphql-api-exception.interceptor.ts b/packages/twenty-server/src/engine/metadata-modules/relation-metadata/interceptors/relation-metadata-graphql-api-exception.interceptor.ts new file mode 100644 index 000000000000..04139a44a4e1 --- /dev/null +++ b/packages/twenty-server/src/engine/metadata-modules/relation-metadata/interceptors/relation-metadata-graphql-api-exception.interceptor.ts @@ -0,0 +1,17 @@ +import { CallHandler, ExecutionContext, NestInterceptor } from '@nestjs/common'; + +import { Observable, catchError } from 'rxjs'; + +import { relationMetadataGraphqlApiExceptionHandler } from 'src/engine/metadata-modules/relation-metadata/utils/relation-metadata-graphql-api-exception-handler.util'; + +export class RelationMetadataGraphqlApiExceptionInterceptor + implements NestInterceptor +{ + intercept(_: ExecutionContext, next: CallHandler): Observable<any> { + return next + .handle() + .pipe( + catchError((err) => relationMetadataGraphqlApiExceptionHandler(err)), + ); + } +} diff --git a/packages/twenty-server/src/engine/metadata-modules/relation-metadata/relation-metadata.exception.ts b/packages/twenty-server/src/engine/metadata-modules/relation-metadata/relation-metadata.exception.ts new file mode 100644 index 000000000000..4ce48e8b8d65 --- /dev/null +++ b/packages/twenty-server/src/engine/metadata-modules/relation-metadata/relation-metadata.exception.ts @@ -0,0 +1,15 @@ +import { CustomException } from 'src/utils/custom-exception'; + +export class RelationMetadataException extends CustomException { + code: RelationMetadataExceptionCode; + constructor(message: string, code: RelationMetadataExceptionCode) { + super(message, code); + } +} + +export enum RelationMetadataExceptionCode { + RELATION_METADATA_NOT_FOUND = 'RELATION_METADATA_NOT_FOUND', + INVALID_RELATION_INPUT = 'INVALID_RELATION_INPUT', + RELATION_ALREADY_EXISTS = 'RELATION_ALREADY_EXISTS', + FOREIGN_KEY_NOT_FOUND = 'FOREIGN_KEY_NOT_FOUND', +} diff --git a/packages/twenty-server/src/engine/metadata-modules/relation-metadata/relation-metadata.module.ts b/packages/twenty-server/src/engine/metadata-modules/relation-metadata/relation-metadata.module.ts index a5fc287a5ed4..f706eb898d57 100644 --- a/packages/twenty-server/src/engine/metadata-modules/relation-metadata/relation-metadata.module.ts +++ b/packages/twenty-server/src/engine/metadata-modules/relation-metadata/relation-metadata.module.ts @@ -7,16 +7,17 @@ import { import { NestjsQueryTypeOrmModule } from '@ptc-org/nestjs-query-typeorm'; import { JwtAuthGuard } from 'src/engine/guards/jwt.auth.guard'; +import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; 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 { RelationMetadataGraphqlApiExceptionInterceptor } from 'src/engine/metadata-modules/relation-metadata/interceptors/relation-metadata-graphql-api-exception.interceptor'; +import { RelationMetadataResolver } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.resolver'; +import { WorkspaceCacheVersionModule } from 'src/engine/metadata-modules/workspace-cache-version/workspace-cache-version.module'; import { WorkspaceMigrationModule } from 'src/engine/metadata-modules/workspace-migration/workspace-migration.module'; import { WorkspaceMigrationRunnerModule } from 'src/engine/workspace-manager/workspace-migration-runner/workspace-migration-runner.module'; -import { WorkspaceCacheVersionModule } from 'src/engine/metadata-modules/workspace-cache-version/workspace-cache-version.module'; -import { RelationMetadataResolver } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.resolver'; -import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; -import { RelationMetadataService } from './relation-metadata.service'; import { RelationMetadataEntity } from './relation-metadata.entity'; +import { RelationMetadataService } from './relation-metadata.service'; import { CreateRelationInput } from './dtos/create-relation.input'; import { RelationMetadataDTO } from './dtos/relation-metadata.dto'; @@ -47,6 +48,7 @@ import { RelationMetadataDTO } from './dtos/relation-metadata.dto'; update: { disabled: true }, delete: { disabled: true }, guards: [JwtAuthGuard], + interceptors: [RelationMetadataGraphqlApiExceptionInterceptor], }, ], }), diff --git a/packages/twenty-server/src/engine/metadata-modules/relation-metadata/relation-metadata.resolver.ts b/packages/twenty-server/src/engine/metadata-modules/relation-metadata/relation-metadata.resolver.ts index c7eb414987b5..332f783e454d 100644 --- a/packages/twenty-server/src/engine/metadata-modules/relation-metadata/relation-metadata.resolver.ts +++ b/packages/twenty-server/src/engine/metadata-modules/relation-metadata/relation-metadata.resolver.ts @@ -7,6 +7,7 @@ import { RelationMetadataService } from 'src/engine/metadata-modules/relation-me import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; import { RelationMetadataDTO } from 'src/engine/metadata-modules/relation-metadata/dtos/relation-metadata.dto'; import { DeleteOneRelationInput } from 'src/engine/metadata-modules/relation-metadata/dtos/delete-relation.input'; +import { relationMetadataGraphqlApiExceptionHandler } from 'src/engine/metadata-modules/relation-metadata/utils/relation-metadata-graphql-api-exception-handler.util'; @UseGuards(JwtAuthGuard) @Resolver() @@ -16,13 +17,17 @@ export class RelationMetadataResolver { ) {} @Mutation(() => RelationMetadataDTO) - deleteOneRelation( + async deleteOneRelation( @Args('input') input: DeleteOneRelationInput, @AuthWorkspace() { id: workspaceId }: Workspace, ) { - return this.relationMetadataService.deleteOneRelation( - input.id, - workspaceId, - ); + try { + return await this.relationMetadataService.deleteOneRelation( + input.id, + workspaceId, + ); + } catch (error) { + relationMetadataGraphqlApiExceptionHandler(error); + } } } diff --git a/packages/twenty-server/src/engine/metadata-modules/relation-metadata/relation-metadata.service.ts b/packages/twenty-server/src/engine/metadata-modules/relation-metadata/relation-metadata.service.ts index 8915b60ab4bf..b287f9e6fa90 100644 --- a/packages/twenty-server/src/engine/metadata-modules/relation-metadata/relation-metadata.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/relation-metadata/relation-metadata.service.ts @@ -1,9 +1,4 @@ -import { - BadRequestException, - ConflictException, - Injectable, - NotFoundException, -} from '@nestjs/common'; +import { Injectable, NotFoundException } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { TypeOrmQueryService } from '@ptc-org/nestjs-query-typeorm'; @@ -28,9 +23,15 @@ import { import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { computeObjectTargetTable } from 'src/engine/utils/compute-object-target-table.util'; import { generateMigrationName } from 'src/engine/metadata-modules/workspace-migration/utils/generate-migration-name.util'; -import { InvalidStringException } from 'src/engine/metadata-modules/errors/InvalidStringException'; -import { validateMetadataName } from 'src/engine/metadata-modules/utils/validate-metadata-name.utils'; +import { + validateMetadataNameOrThrow, + InvalidStringException, +} from 'src/engine/metadata-modules/utils/validate-metadata-name.utils'; import { WorkspaceCacheVersionService } from 'src/engine/metadata-modules/workspace-cache-version/workspace-cache-version.service'; +import { + RelationMetadataException, + RelationMetadataExceptionCode, +} from 'src/engine/metadata-modules/relation-metadata/relation-metadata.exception'; import { RelationMetadataEntity, @@ -62,12 +63,13 @@ export class RelationMetadataService extends TypeOrmQueryService<RelationMetadat ); try { - validateMetadataName(relationMetadataInput.fromName); - validateMetadataName(relationMetadataInput.toName); + validateMetadataNameOrThrow(relationMetadataInput.fromName); + validateMetadataNameOrThrow(relationMetadataInput.toName); } catch (error) { if (error instanceof InvalidStringException) { - throw new BadRequestException( + throw new RelationMetadataException( `Characters used in name "${relationMetadataInput.fromName}" or "${relationMetadataInput.toName}" are not supported`, + RelationMetadataExceptionCode.INVALID_RELATION_INPUT, ); } else { throw error; @@ -132,8 +134,9 @@ export class RelationMetadataService extends TypeOrmQueryService<RelationMetadat if ( relationMetadataInput.relationType === RelationMetadataType.MANY_TO_MANY ) { - throw new BadRequestException( + throw new RelationMetadataException( 'Many to many relations are not supported yet', + RelationMetadataExceptionCode.INVALID_RELATION_INPUT, ); } @@ -142,8 +145,9 @@ export class RelationMetadataService extends TypeOrmQueryService<RelationMetadat undefined || objectMetadataMap[relationMetadataInput.toObjectMetadataId] === undefined ) { - throw new NotFoundException( + throw new RelationMetadataException( 'Can\t find an existing object matching with fromObjectMetadataId or toObjectMetadataId', + RelationMetadataExceptionCode.RELATION_METADATA_NOT_FOUND, ); } @@ -177,12 +181,13 @@ export class RelationMetadataService extends TypeOrmQueryService<RelationMetadat ); if (fieldAlreadyExists) { - throw new ConflictException( + throw new RelationMetadataException( `Field on ${ objectMetadataMap[ relationMetadataInput[`${relationDirection}ObjectMetadataId`] ].nameSingular } already exists`, + RelationMetadataExceptionCode.RELATION_ALREADY_EXISTS, ); } } @@ -335,7 +340,10 @@ export class RelationMetadataService extends TypeOrmQueryService<RelationMetadat }); if (!relationMetadata) { - throw new NotFoundException('Relation does not exist'); + throw new RelationMetadataException( + 'Relation does not exist', + RelationMetadataExceptionCode.RELATION_METADATA_NOT_FOUND, + ); } const foreignKeyFieldMetadataName = `${camelCase( @@ -351,8 +359,9 @@ export class RelationMetadataService extends TypeOrmQueryService<RelationMetadat }); if (!foreignKeyFieldMetadata) { - throw new NotFoundException( + throw new RelationMetadataException( `Foreign key fieldMetadata not found (${foreignKeyFieldMetadataName}) for relation ${relationMetadata.id}`, + RelationMetadataExceptionCode.FOREIGN_KEY_NOT_FOUND, ); } @@ -420,6 +429,7 @@ export class RelationMetadataService extends TypeOrmQueryService<RelationMetadat return ( foundRelationMetadataItem ?? + // TODO: return a relation metadata not found exception new NotFoundException( `RelationMetadata with fieldMetadataId ${fieldMetadataId} not found`, ) diff --git a/packages/twenty-server/src/engine/metadata-modules/relation-metadata/utils/relation-metadata-graphql-api-exception-handler.util.ts b/packages/twenty-server/src/engine/metadata-modules/relation-metadata/utils/relation-metadata-graphql-api-exception-handler.util.ts new file mode 100644 index 000000000000..4367e4035127 --- /dev/null +++ b/packages/twenty-server/src/engine/metadata-modules/relation-metadata/utils/relation-metadata-graphql-api-exception-handler.util.ts @@ -0,0 +1,28 @@ +import { + ConflictError, + InternalServerError, + NotFoundError, + UserInputError, +} from 'src/engine/core-modules/graphql/utils/graphql-errors.util'; +import { + RelationMetadataException, + RelationMetadataExceptionCode, +} from 'src/engine/metadata-modules/relation-metadata/relation-metadata.exception'; + +export const relationMetadataGraphqlApiExceptionHandler = (error: Error) => { + if (error instanceof RelationMetadataException) { + switch (error.code) { + case RelationMetadataExceptionCode.RELATION_METADATA_NOT_FOUND: + throw new NotFoundError(error.message); + case RelationMetadataExceptionCode.INVALID_RELATION_INPUT: + throw new UserInputError(error.message); + case RelationMetadataExceptionCode.RELATION_ALREADY_EXISTS: + throw new ConflictError(error.message); + case RelationMetadataExceptionCode.FOREIGN_KEY_NOT_FOUND: + default: + throw new InternalServerError(error.message); + } + } + + throw error; +}; diff --git a/packages/twenty-server/src/engine/metadata-modules/remote-server/remote-server.exception.ts b/packages/twenty-server/src/engine/metadata-modules/remote-server/remote-server.exception.ts new file mode 100644 index 000000000000..6aa035234bf9 --- /dev/null +++ b/packages/twenty-server/src/engine/metadata-modules/remote-server/remote-server.exception.ts @@ -0,0 +1,16 @@ +import { CustomException } from 'src/utils/custom-exception'; + +export class RemoteServerException extends CustomException { + code: RemoteServerExceptionCode; + constructor(message: string, code: RemoteServerExceptionCode) { + super(message, code); + } +} + +export enum RemoteServerExceptionCode { + REMOTE_SERVER_NOT_FOUND = 'REMOTE_SERVER_NOT_FOUND', + REMOTE_SERVER_ALREADY_EXISTS = 'REMOTE_SERVER_ALREADY_EXISTS', + REMOTE_SERVER_MUTATION_NOT_ALLOWED = 'REMOTE_SERVER_MUTATION_NOT_ALLOWED', + REMOTE_SERVER_CONNECTION_ERROR = 'REMOTE_SERVER_CONNECTION_ERROR', + INVALID_REMOTE_SERVER_INPUT = 'INVALID_REMOTE_SERVER_INPUT', +} diff --git a/packages/twenty-server/src/engine/metadata-modules/remote-server/remote-server.resolver.ts b/packages/twenty-server/src/engine/metadata-modules/remote-server/remote-server.resolver.ts index 04d44a190d8c..262326669ea0 100644 --- a/packages/twenty-server/src/engine/metadata-modules/remote-server/remote-server.resolver.ts +++ b/packages/twenty-server/src/engine/metadata-modules/remote-server/remote-server.resolver.ts @@ -11,6 +11,7 @@ import { RemoteServerDTO } from 'src/engine/metadata-modules/remote-server/dtos/ import { UpdateRemoteServerInput } from 'src/engine/metadata-modules/remote-server/dtos/update-remote-server.input'; import { RemoteServerType } from 'src/engine/metadata-modules/remote-server/remote-server.entity'; import { RemoteServerService } from 'src/engine/metadata-modules/remote-server/remote-server.service'; +import { remoteServerGraphqlApiExceptionHandler } from 'src/engine/metadata-modules/remote-server/utils/remote-server-graphql-api-exception-handler.util'; @UseGuards(JwtAuthGuard) @Resolver() @@ -24,7 +25,14 @@ export class RemoteServerResolver { @Args('input') input: CreateRemoteServerInput<RemoteServerType>, @AuthWorkspace() { id: workspaceId }: Workspace, ) { - return this.remoteServerService.createOneRemoteServer(input, workspaceId); + try { + return await this.remoteServerService.createOneRemoteServer( + input, + workspaceId, + ); + } catch (error) { + remoteServerGraphqlApiExceptionHandler(error); + } } @Mutation(() => RemoteServerDTO) @@ -32,7 +40,14 @@ export class RemoteServerResolver { @Args('input') input: UpdateRemoteServerInput<RemoteServerType>, @AuthWorkspace() { id: workspaceId }: Workspace, ) { - return this.remoteServerService.updateOneRemoteServer(input, workspaceId); + try { + return await this.remoteServerService.updateOneRemoteServer( + input, + workspaceId, + ); + } catch (error) { + remoteServerGraphqlApiExceptionHandler(error); + } } @Mutation(() => RemoteServerDTO) @@ -40,7 +55,14 @@ export class RemoteServerResolver { @Args('input') { id }: RemoteServerIdInput, @AuthWorkspace() { id: workspaceId }: Workspace, ) { - return this.remoteServerService.deleteOneRemoteServer(id, workspaceId); + try { + return await this.remoteServerService.deleteOneRemoteServer( + id, + workspaceId, + ); + } catch (error) { + remoteServerGraphqlApiExceptionHandler(error); + } } @Query(() => RemoteServerDTO) @@ -48,7 +70,14 @@ export class RemoteServerResolver { @Args('input') { id }: RemoteServerIdInput, @AuthWorkspace() { id: workspaceId }: Workspace, ) { - return this.remoteServerService.findOneByIdWithinWorkspace(id, workspaceId); + try { + return await this.remoteServerService.findOneByIdWithinWorkspace( + id, + workspaceId, + ); + } catch (error) { + remoteServerGraphqlApiExceptionHandler(error); + } } @Query(() => [RemoteServerDTO]) @@ -57,9 +86,13 @@ export class RemoteServerResolver { { foreignDataWrapperType }: RemoteServerTypeInput<RemoteServerType>, @AuthWorkspace() { id: workspaceId }: Workspace, ) { - return this.remoteServerService.findManyByTypeWithinWorkspace( - foreignDataWrapperType, - workspaceId, - ); + try { + return await this.remoteServerService.findManyByTypeWithinWorkspace( + foreignDataWrapperType, + workspaceId, + ); + } catch (error) { + remoteServerGraphqlApiExceptionHandler(error); + } } } diff --git a/packages/twenty-server/src/engine/metadata-modules/remote-server/remote-server.service.ts b/packages/twenty-server/src/engine/metadata-modules/remote-server/remote-server.service.ts index b7ad3a2e7fdc..d1c241827882 100644 --- a/packages/twenty-server/src/engine/metadata-modules/remote-server/remote-server.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/remote-server/remote-server.service.ts @@ -1,8 +1,4 @@ -import { - ForbiddenException, - Injectable, - NotFoundException, -} from '@nestjs/common'; +import { Injectable } from '@nestjs/common'; import { InjectDataSource, InjectRepository } from '@nestjs/typeorm'; import isEmpty from 'lodash.isempty'; @@ -27,6 +23,10 @@ import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/work import { buildUpdateRemoteServerRawQuery } from 'src/engine/metadata-modules/remote-server/utils/build-update-remote-server-raw-query.utils'; import { validateRemoteServerType } from 'src/engine/metadata-modules/remote-server/utils/validate-remote-server-type.util'; import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity'; +import { + RemoteServerException, + RemoteServerExceptionCode, +} from 'src/engine/metadata-modules/remote-server/remote-server.exception'; @Injectable() export class RemoteServerService<T extends RemoteServerType> { @@ -122,7 +122,10 @@ export class RemoteServerService<T extends RemoteServerType> { ); if (!remoteServer) { - throw new NotFoundException('Remote server does not exist'); + throw new RemoteServerException( + 'Remote server does not exist', + RemoteServerExceptionCode.REMOTE_SERVER_NOT_FOUND, + ); } const currentRemoteTablesForServer = @@ -132,8 +135,9 @@ export class RemoteServerService<T extends RemoteServerType> { }); if (currentRemoteTablesForServer.length > 0) { - throw new ForbiddenException( + throw new RemoteServerException( 'Cannot update remote server with synchronized tables', + RemoteServerExceptionCode.REMOTE_SERVER_MUTATION_NOT_ALLOWED, ); } @@ -207,7 +211,10 @@ export class RemoteServerService<T extends RemoteServerType> { }); if (!remoteServer) { - throw new NotFoundException('Remote server does not exist'); + throw new RemoteServerException( + 'Remote server does not exist', + RemoteServerExceptionCode.REMOTE_SERVER_NOT_FOUND, + ); } await this.remoteTableService.unsyncAll(workspaceId, remoteServer); diff --git a/packages/twenty-server/src/engine/metadata-modules/remote-server/remote-table/distant-table/distant-table.exception.ts b/packages/twenty-server/src/engine/metadata-modules/remote-server/remote-table/distant-table/distant-table.exception.ts new file mode 100644 index 000000000000..609da7a6fc65 --- /dev/null +++ b/packages/twenty-server/src/engine/metadata-modules/remote-server/remote-table/distant-table/distant-table.exception.ts @@ -0,0 +1,13 @@ +import { CustomException } from 'src/utils/custom-exception'; + +export class DistantTableException extends CustomException { + code: DistantTableExceptionCode; + constructor(message: string, code: DistantTableExceptionCode) { + super(message, code); + } +} + +export enum DistantTableExceptionCode { + INTERNAL_SERVER_ERROR = 'INTERNAL_SERVER_ERROR', + TIMEOUT_ERROR = 'TIMEOUT_ERROR', +} diff --git a/packages/twenty-server/src/engine/metadata-modules/remote-server/remote-table/distant-table/distant-table.service.ts b/packages/twenty-server/src/engine/metadata-modules/remote-server/remote-table/distant-table/distant-table.service.ts index d0e5fdadeb3d..337ab25be7b4 100644 --- a/packages/twenty-server/src/engine/metadata-modules/remote-server/remote-table/distant-table/distant-table.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/remote-server/remote-table/distant-table/distant-table.service.ts @@ -1,8 +1,4 @@ -import { - BadRequestException, - Injectable, - RequestTimeoutException, -} from '@nestjs/common'; +import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { EntityManager, Repository } from 'typeorm'; @@ -17,6 +13,10 @@ import { DistantTables } from 'src/engine/metadata-modules/remote-server/remote- import { STRIPE_DISTANT_TABLES } from 'src/engine/metadata-modules/remote-server/remote-table/distant-table/utils/stripe-distant-tables.util'; import { PostgresTableSchemaColumn } from 'src/engine/metadata-modules/remote-server/types/postgres-table-schema-column'; import { isQueryTimeoutError } from 'src/engine/utils/query-timeout.util'; +import { + DistantTableException, + DistantTableExceptionCode, +} from 'src/engine/metadata-modules/remote-server/remote-table/distant-table/distant-table.exception'; @Injectable() export class DistantTableService { @@ -64,7 +64,10 @@ export class DistantTableService { tableName?: string, ): Promise<DistantTables> { if (!remoteServer.schema) { - throw new BadRequestException('Remote server schema is not defined'); + throw new DistantTableException( + 'Remote server schema is not defined', + DistantTableExceptionCode.INTERNAL_SERVER_ERROR, + ); } const tmpSchemaId = v4(); @@ -116,8 +119,9 @@ export class DistantTableService { return distantTables; } catch (error) { if (isQueryTimeoutError(error)) { - throw new RequestTimeoutException( + throw new DistantTableException( `Could not find distant tables: ${error.message}`, + DistantTableExceptionCode.TIMEOUT_ERROR, ); } @@ -132,8 +136,9 @@ export class DistantTableService { case RemoteServerType.STRIPE_FDW: return STRIPE_DISTANT_TABLES; default: - throw new BadRequestException( + throw new DistantTableException( `Type ${remoteServer.foreignDataWrapperType} does not have a static schema.`, + DistantTableExceptionCode.INTERNAL_SERVER_ERROR, ); } } diff --git a/packages/twenty-server/src/engine/metadata-modules/remote-server/remote-table/foreign-table/foreign-table.exception.ts b/packages/twenty-server/src/engine/metadata-modules/remote-server/remote-table/foreign-table/foreign-table.exception.ts new file mode 100644 index 000000000000..3f3305823784 --- /dev/null +++ b/packages/twenty-server/src/engine/metadata-modules/remote-server/remote-table/foreign-table/foreign-table.exception.ts @@ -0,0 +1,13 @@ +import { CustomException } from 'src/utils/custom-exception'; + +export class ForeignTableException extends CustomException { + code: ForeignTableExceptionCode; + constructor(message: string, code: ForeignTableExceptionCode) { + super(message, code); + } +} + +export enum ForeignTableExceptionCode { + FOREIGN_TABLE_MUTATION_NOT_ALLOWED = 'FOREIGN_TABLE_MUTATION_NOT_ALLOWED', + INVALID_FOREIGN_TABLE_INPUT = 'INVALID_FOREIGN_TABLE_INPUT', +} diff --git a/packages/twenty-server/src/engine/metadata-modules/remote-server/remote-table/foreign-table/foreign-table.service.ts b/packages/twenty-server/src/engine/metadata-modules/remote-server/remote-table/foreign-table/foreign-table.service.ts index c5951b69b173..4f1f2d1cdc64 100644 --- a/packages/twenty-server/src/engine/metadata-modules/remote-server/remote-table/foreign-table/foreign-table.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/remote-server/remote-table/foreign-table/foreign-table.service.ts @@ -1,10 +1,14 @@ -import { BadRequestException, Injectable } from '@nestjs/common'; +import { Injectable } from '@nestjs/common'; import { RemoteServerEntity, RemoteServerType, } from 'src/engine/metadata-modules/remote-server/remote-server.entity'; import { RemoteTableStatus } from 'src/engine/metadata-modules/remote-server/remote-table/dtos/remote-table.dto'; +import { + ForeignTableException, + ForeignTableExceptionCode, +} from 'src/engine/metadata-modules/remote-server/remote-table/foreign-table/foreign-table.exception'; import { getForeignTableColumnName } from 'src/engine/metadata-modules/remote-server/remote-table/foreign-table/utils/get-foreign-table-column-name.util'; import { PostgresTableSchemaColumn } from 'src/engine/metadata-modules/remote-server/types/postgres-table-schema-column'; import { WorkspaceCacheVersionService } from 'src/engine/metadata-modules/workspace-cache-version/workspace-cache-version.service'; @@ -90,8 +94,9 @@ export class ForeignTableService { } catch (exception) { this.workspaceMigrationService.deleteById(workspaceMigration.id); - throw new BadRequestException( + throw new ForeignTableException( 'Could not create foreign table. The table may already exists or a column type may not be supported.', + ForeignTableExceptionCode.INVALID_FOREIGN_TABLE_INPUT, ); } } @@ -130,7 +135,10 @@ export class ForeignTableService { } catch (exception) { this.workspaceMigrationService.deleteById(workspaceMigration.id); - throw new BadRequestException('Could not alter foreign table.'); + throw new ForeignTableException( + 'Could not alter foreign table.', + ForeignTableExceptionCode.FOREIGN_TABLE_MUTATION_NOT_ALLOWED, + ); } } @@ -167,7 +175,10 @@ export class ForeignTableService { case RemoteServerType.STRIPE_FDW: return { object: distantTableName }; default: - throw new BadRequestException('Foreign data wrapper not supported'); + throw new ForeignTableException( + 'Foreign data wrapper not supported', + ForeignTableExceptionCode.INVALID_FOREIGN_TABLE_INPUT, + ); } } } diff --git a/packages/twenty-server/src/engine/metadata-modules/remote-server/remote-table/remote-table.exception.ts b/packages/twenty-server/src/engine/metadata-modules/remote-server/remote-table/remote-table.exception.ts new file mode 100644 index 000000000000..32e99227c5a3 --- /dev/null +++ b/packages/twenty-server/src/engine/metadata-modules/remote-server/remote-table/remote-table.exception.ts @@ -0,0 +1,17 @@ +import { CustomException } from 'src/utils/custom-exception'; + +export class RemoteTableException extends CustomException { + code: RemoteTableExceptionCode; + constructor(message: string, code: RemoteTableExceptionCode) { + super(message, code); + } +} + +export enum RemoteTableExceptionCode { + REMOTE_TABLE_NOT_FOUND = 'REMOTE_TABLE_NOT_FOUND', + INVALID_REMOTE_TABLE_INPUT = 'INVALID_REMOTE_TABLE_INPUT', + REMOTE_TABLE_ALREADY_EXISTS = 'REMOTE_TABLE_ALREADY_EXISTS', + NO_FOREIGN_TABLES_FOUND = 'NO_FOREIGN_TABLES_FOUND', + NO_OBJECT_METADATA_FOUND = 'NO_OBJECT_METADATA_FOUND', + NO_FIELD_METADATA_FOUND = 'NO_FIELD_METADATA_FOUND', +} diff --git a/packages/twenty-server/src/engine/metadata-modules/remote-server/remote-table/remote-table.resolver.ts b/packages/twenty-server/src/engine/metadata-modules/remote-server/remote-table/remote-table.resolver.ts index 37abfc748688..7698f25d094f 100644 --- a/packages/twenty-server/src/engine/metadata-modules/remote-server/remote-table/remote-table.resolver.ts +++ b/packages/twenty-server/src/engine/metadata-modules/remote-server/remote-table/remote-table.resolver.ts @@ -8,6 +8,7 @@ import { FindManyRemoteTablesInput } from 'src/engine/metadata-modules/remote-se import { RemoteTableInput } from 'src/engine/metadata-modules/remote-server/remote-table/dtos/remote-table-input'; import { RemoteTableDTO } from 'src/engine/metadata-modules/remote-server/remote-table/dtos/remote-table.dto'; import { RemoteTableService } from 'src/engine/metadata-modules/remote-server/remote-table/remote-table.service'; +import { remoteTableGraphqlApiExceptionHandler } from 'src/engine/metadata-modules/remote-server/remote-table/utils/remote-table-graphql-api-exception-handler.util'; @UseGuards(JwtAuthGuard) @Resolver() @@ -19,11 +20,15 @@ export class RemoteTableResolver { @Args('input') input: FindManyRemoteTablesInput, @AuthWorkspace() { id: workspaceId }: Workspace, ) { - return this.remoteTableService.findDistantTablesWithStatus( - input.id, - workspaceId, - input.shouldFetchPendingSchemaUpdates, - ); + try { + return await this.remoteTableService.findDistantTablesWithStatus( + input.id, + workspaceId, + input.shouldFetchPendingSchemaUpdates, + ); + } catch (error) { + remoteTableGraphqlApiExceptionHandler(error); + } } @Mutation(() => RemoteTableDTO) @@ -31,7 +36,11 @@ export class RemoteTableResolver { @Args('input') input: RemoteTableInput, @AuthWorkspace() { id: workspaceId }: Workspace, ) { - return this.remoteTableService.syncRemoteTable(input, workspaceId); + try { + return await this.remoteTableService.syncRemoteTable(input, workspaceId); + } catch (error) { + remoteTableGraphqlApiExceptionHandler(error); + } } @Mutation(() => RemoteTableDTO) @@ -39,7 +48,14 @@ export class RemoteTableResolver { @Args('input') input: RemoteTableInput, @AuthWorkspace() { id: workspaceId }: Workspace, ) { - return this.remoteTableService.unsyncRemoteTable(input, workspaceId); + try { + return await this.remoteTableService.unsyncRemoteTable( + input, + workspaceId, + ); + } catch (error) { + remoteTableGraphqlApiExceptionHandler(error); + } } @Mutation(() => RemoteTableDTO) @@ -47,9 +63,13 @@ export class RemoteTableResolver { @Args('input') input: RemoteTableInput, @AuthWorkspace() { id: workspaceId }: Workspace, ) { - return this.remoteTableService.syncRemoteTableSchemaChanges( - input, - workspaceId, - ); + try { + return await this.remoteTableService.syncRemoteTableSchemaChanges( + input, + workspaceId, + ); + } catch (error) { + remoteTableGraphqlApiExceptionHandler(error); + } } } diff --git a/packages/twenty-server/src/engine/metadata-modules/remote-server/remote-table/remote-table.service.ts b/packages/twenty-server/src/engine/metadata-modules/remote-server/remote-table/remote-table.service.ts index 732108af8330..9102839eddac 100644 --- a/packages/twenty-server/src/engine/metadata-modules/remote-server/remote-table/remote-table.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/remote-server/remote-table/remote-table.service.ts @@ -1,4 +1,4 @@ -import { BadRequestException, Logger, NotFoundException } from '@nestjs/common'; +import { Logger } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; @@ -40,6 +40,10 @@ import { } from 'src/engine/metadata-modules/workspace-migration/workspace-migration.entity'; import { CreateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/create-field.input'; import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; +import { + RemoteTableException, + RemoteTableExceptionCode, +} from 'src/engine/metadata-modules/remote-server/remote-table/remote-table.exception'; export class RemoteTableService { private readonly logger = new Logger(RemoteTableService.name); @@ -74,7 +78,10 @@ export class RemoteTableService { }); if (!remoteServer) { - throw new NotFoundException('Remote server does not exist'); + throw new RemoteTableException( + 'Remote server does not exist', + RemoteTableExceptionCode.INVALID_REMOTE_TABLE_INPUT, + ); } const currentRemoteTables = await this.findRemoteTablesByServerId({ @@ -148,7 +155,10 @@ export class RemoteTableService { }); if (!remoteServer) { - throw new NotFoundException('Remote server does not exist'); + throw new RemoteTableException( + 'Remote server does not exist', + RemoteTableExceptionCode.INVALID_REMOTE_TABLE_INPUT, + ); } const currentRemoteTableWithSameDistantName = @@ -161,7 +171,10 @@ export class RemoteTableService { }); if (currentRemoteTableWithSameDistantName) { - throw new BadRequestException('Remote table already exists'); + throw new RemoteTableException( + 'Remote server does not exist', + RemoteTableExceptionCode.REMOTE_TABLE_ALREADY_EXISTS, + ); } const dataSourceMetatada = @@ -200,7 +213,10 @@ export class RemoteTableService { ); if (!distantTableColumns) { - throw new BadRequestException('Table not found'); + throw new RemoteTableException( + 'Remote server does not exist', + RemoteTableExceptionCode.REMOTE_TABLE_NOT_FOUND, + ); } // We only support remote tables with an id column for now. @@ -209,7 +225,10 @@ export class RemoteTableService { ); if (!distantTableIdColumn) { - throw new BadRequestException('Remote table must have an id column'); + throw new RemoteTableException( + 'Remote server does not exist', + RemoteTableExceptionCode.INVALID_REMOTE_TABLE_INPUT, + ); } await this.foreignTableService.createForeignTable( @@ -250,7 +269,10 @@ export class RemoteTableService { }); if (!remoteServer) { - throw new NotFoundException('Remote server does not exist'); + throw new RemoteTableException( + 'Remote server does not exist', + RemoteTableExceptionCode.INVALID_REMOTE_TABLE_INPUT, + ); } const remoteTable = await this.remoteTableRepository.findOne({ @@ -262,7 +284,10 @@ export class RemoteTableService { }); if (!remoteTable) { - throw new NotFoundException('Remote table does not exist'); + throw new RemoteTableException( + 'Remote table does not exist', + RemoteTableExceptionCode.REMOTE_TABLE_NOT_FOUND, + ); } await this.unsyncOne(workspaceId, remoteTable, remoteServer); @@ -302,7 +327,10 @@ export class RemoteTableService { }); if (!remoteServer) { - throw new NotFoundException('Remote server does not exist'); + throw new RemoteTableException( + 'Remote server does not exist', + RemoteTableExceptionCode.INVALID_REMOTE_TABLE_INPUT, + ); } const remoteTable = await this.remoteTableRepository.findOne({ @@ -314,7 +342,10 @@ export class RemoteTableService { }); if (!remoteTable) { - throw new NotFoundException('Remote table does not exist'); + throw new RemoteTableException( + 'Remote table does not exist', + RemoteTableExceptionCode.REMOTE_TABLE_NOT_FOUND, + ); } const distantTableColumns = @@ -379,7 +410,10 @@ export class RemoteTableService { ); if (!currentForeignTableNames.includes(remoteTable.localTableName)) { - throw new NotFoundException('Foreign table does not exist'); + throw new RemoteTableException( + 'Foreign table does not exist', + RemoteTableExceptionCode.NO_FOREIGN_TABLES_FOUND, + ); } const objectMetadata = @@ -507,8 +541,9 @@ export class RemoteTableService { }); if (!objectMetadata) { - throw new NotFoundException( + throw new RemoteTableException( `Cannot find associated object for table ${foreignTableName}`, + RemoteTableExceptionCode.NO_OBJECT_METADATA_FOUND, ); } for (const columnUpdate of columnsUpdates) { @@ -547,8 +582,9 @@ export class RemoteTableService { }); if (!fieldMetadataToDelete) { - throw new NotFoundException( + throw new RemoteTableException( `Cannot find associated field metadata for column ${columnName}`, + RemoteTableExceptionCode.NO_FIELD_METADATA_FOUND, ); } diff --git a/packages/twenty-server/src/engine/metadata-modules/remote-server/remote-table/utils/get-remote-table-local-name.util.ts b/packages/twenty-server/src/engine/metadata-modules/remote-server/remote-table/utils/get-remote-table-local-name.util.ts index 92008e169d00..1df79156fafc 100644 --- a/packages/twenty-server/src/engine/metadata-modules/remote-server/remote-table/utils/get-remote-table-local-name.util.ts +++ b/packages/twenty-server/src/engine/metadata-modules/remote-server/remote-table/utils/get-remote-table-local-name.util.ts @@ -1,9 +1,11 @@ -import { BadRequestException } from '@nestjs/common/exceptions'; - import { singular } from 'pluralize'; import { DataSource } from 'typeorm'; import { camelCase } from 'src/utils/camel-case'; +import { + RemoteTableException, + RemoteTableExceptionCode, +} from 'src/engine/metadata-modules/remote-server/remote-table/remote-table.exception'; const MAX_SUFFIX = 10; @@ -55,5 +57,8 @@ export const getRemoteTableLocalName = async ( } } - throw new BadRequestException('Table name is already taken.'); + throw new RemoteTableException( + 'Table name is already taken', + RemoteTableExceptionCode.INVALID_REMOTE_TABLE_INPUT, + ); }; diff --git a/packages/twenty-server/src/engine/metadata-modules/remote-server/remote-table/utils/remote-table-graphql-api-exception-handler.util.ts b/packages/twenty-server/src/engine/metadata-modules/remote-server/remote-table/utils/remote-table-graphql-api-exception-handler.util.ts new file mode 100644 index 000000000000..13e2c976a623 --- /dev/null +++ b/packages/twenty-server/src/engine/metadata-modules/remote-server/remote-table/utils/remote-table-graphql-api-exception-handler.util.ts @@ -0,0 +1,30 @@ +import { + ConflictError, + InternalServerError, + NotFoundError, + UserInputError, +} from 'src/engine/core-modules/graphql/utils/graphql-errors.util'; +import { + RemoteTableException, + RemoteTableExceptionCode, +} from 'src/engine/metadata-modules/remote-server/remote-table/remote-table.exception'; + +export const remoteTableGraphqlApiExceptionHandler = (error: Error) => { + if (error instanceof RemoteTableException) { + switch (error.code) { + case RemoteTableExceptionCode.REMOTE_TABLE_NOT_FOUND: + case RemoteTableExceptionCode.NO_OBJECT_METADATA_FOUND: + case RemoteTableExceptionCode.NO_FOREIGN_TABLES_FOUND: + case RemoteTableExceptionCode.NO_FIELD_METADATA_FOUND: + throw new NotFoundError(error.message); + case RemoteTableExceptionCode.INVALID_REMOTE_TABLE_INPUT: + throw new UserInputError(error.message); + case RemoteTableExceptionCode.REMOTE_TABLE_ALREADY_EXISTS: + throw new ConflictError(error.message); + default: + throw new InternalServerError(error.message); + } + } + + throw error; +}; diff --git a/packages/twenty-server/src/engine/metadata-modules/remote-server/utils/build-update-remote-server-raw-query.utils.ts b/packages/twenty-server/src/engine/metadata-modules/remote-server/utils/build-update-remote-server-raw-query.utils.ts index fff4778db0fa..3e23e9b55cb5 100644 --- a/packages/twenty-server/src/engine/metadata-modules/remote-server/utils/build-update-remote-server-raw-query.utils.ts +++ b/packages/twenty-server/src/engine/metadata-modules/remote-server/utils/build-update-remote-server-raw-query.utils.ts @@ -1,10 +1,12 @@ -import { BadRequestException } from '@nestjs/common'; - import { ForeignDataWrapperOptions, RemoteServerEntity, RemoteServerType, } from 'src/engine/metadata-modules/remote-server/remote-server.entity'; +import { + RemoteServerException, + RemoteServerExceptionCode, +} from 'src/engine/metadata-modules/remote-server/remote-server.exception'; import { UserMappingOptions } from 'src/engine/metadata-modules/remote-server/types/user-mapping-options'; export type DeepPartial<T> = { @@ -49,7 +51,10 @@ export const buildUpdateRemoteServerRawQuery = ( } if (options.length < 1) { - throw new BadRequestException('No fields to update'); + throw new RemoteServerException( + 'No fields to update', + RemoteServerExceptionCode.INVALID_REMOTE_SERVER_INPUT, + ); } const rawQuery = `UPDATE metadata."remoteServer" SET ${options.join( diff --git a/packages/twenty-server/src/engine/metadata-modules/remote-server/utils/remote-server-graphql-api-exception-handler.util.ts b/packages/twenty-server/src/engine/metadata-modules/remote-server/utils/remote-server-graphql-api-exception-handler.util.ts new file mode 100644 index 000000000000..e289d02af499 --- /dev/null +++ b/packages/twenty-server/src/engine/metadata-modules/remote-server/utils/remote-server-graphql-api-exception-handler.util.ts @@ -0,0 +1,30 @@ +import { + ConflictError, + ForbiddenError, + InternalServerError, + NotFoundError, + UserInputError, +} from 'src/engine/core-modules/graphql/utils/graphql-errors.util'; +import { + RemoteServerException, + RemoteServerExceptionCode, +} from 'src/engine/metadata-modules/remote-server/remote-server.exception'; + +export const remoteServerGraphqlApiExceptionHandler = (error: any) => { + if (error instanceof RemoteServerException) { + switch (error.code) { + case RemoteServerExceptionCode.REMOTE_SERVER_NOT_FOUND: + throw new NotFoundError(error.message); + case RemoteServerExceptionCode.INVALID_REMOTE_SERVER_INPUT: + throw new UserInputError(error.message); + case RemoteServerExceptionCode.REMOTE_SERVER_MUTATION_NOT_ALLOWED: + throw new ForbiddenError(error.message); + case RemoteServerExceptionCode.REMOTE_SERVER_ALREADY_EXISTS: + throw new ConflictError(error.message); + default: + throw new InternalServerError(error.message); + } + } + + throw error; +}; diff --git a/packages/twenty-server/src/engine/metadata-modules/remote-server/utils/validate-remote-server-input.utils.ts b/packages/twenty-server/src/engine/metadata-modules/remote-server/utils/validate-remote-server-input.utils.ts index 99de7fa95d52..38cfecdcf4ac 100644 --- a/packages/twenty-server/src/engine/metadata-modules/remote-server/utils/validate-remote-server-input.utils.ts +++ b/packages/twenty-server/src/engine/metadata-modules/remote-server/utils/validate-remote-server-input.utils.ts @@ -1,7 +1,10 @@ -import { BadRequestException } from '@nestjs/common'; - import { isDefined } from 'class-validator'; +import { + RemoteServerException, + RemoteServerExceptionCode, +} from 'src/engine/metadata-modules/remote-server/remote-server.exception'; + const INPUT_REGEX = /^([A-Za-z0-9\-_.@]+)$/; export const validateObjectAgainstInjections = (input: object) => { @@ -21,6 +24,9 @@ export const validateObjectAgainstInjections = (input: object) => { export const validateStringAgainstInjections = (input: string) => { if (!INPUT_REGEX.test(input)) { - throw new BadRequestException('Invalid remote server input'); + throw new RemoteServerException( + 'Invalid remote server input', + RemoteServerExceptionCode.INVALID_REMOTE_SERVER_INPUT, + ); } }; diff --git a/packages/twenty-server/src/engine/metadata-modules/remote-server/utils/validate-remote-server-type.util.ts b/packages/twenty-server/src/engine/metadata-modules/remote-server/utils/validate-remote-server-type.util.ts index 7a158e6a7a36..333353970c8d 100644 --- a/packages/twenty-server/src/engine/metadata-modules/remote-server/utils/validate-remote-server-type.util.ts +++ b/packages/twenty-server/src/engine/metadata-modules/remote-server/utils/validate-remote-server-type.util.ts @@ -1,5 +1,3 @@ -import { BadRequestException } from '@nestjs/common'; - import { Repository } from 'typeorm'; import { @@ -7,6 +5,10 @@ import { FeatureFlagKeys, } from 'src/engine/core-modules/feature-flag/feature-flag.entity'; import { RemoteServerType } from 'src/engine/metadata-modules/remote-server/remote-server.entity'; +import { + RemoteServerException, + RemoteServerExceptionCode, +} from 'src/engine/metadata-modules/remote-server/remote-server.exception'; export const validateRemoteServerType = async ( remoteServerType: RemoteServerType, @@ -24,7 +26,10 @@ export const validateRemoteServerType = async ( const featureFlagEnabled = featureFlag && featureFlag.value; if (!featureFlagEnabled) { - throw new BadRequestException(`Type ${remoteServerType} is not supported.`); + throw new RemoteServerException( + `Type ${remoteServerType} is not supported.`, + RemoteServerExceptionCode.INVALID_REMOTE_SERVER_INPUT, + ); } }; @@ -35,8 +40,9 @@ const getFeatureFlagKey = (remoteServerType: RemoteServerType) => { case RemoteServerType.STRIPE_FDW: return FeatureFlagKeys.IsStripeIntegrationEnabled; default: - throw new BadRequestException( + throw new RemoteServerException( `Type ${remoteServerType} is not supported.`, + RemoteServerExceptionCode.INVALID_REMOTE_SERVER_INPUT, ); } }; diff --git a/packages/twenty-server/src/engine/metadata-modules/utils/__tests__/validate-metadata-name.spec.ts b/packages/twenty-server/src/engine/metadata-modules/utils/__tests__/validate-metadata-name.spec.ts index d2e03eac6fef..445620dd4236 100644 --- a/packages/twenty-server/src/engine/metadata-modules/utils/__tests__/validate-metadata-name.spec.ts +++ b/packages/twenty-server/src/engine/metadata-modules/utils/__tests__/validate-metadata-name.spec.ts @@ -1,32 +1,57 @@ -import { InvalidStringException } from 'src/engine/metadata-modules/errors/InvalidStringException'; -import { validateMetadataName } from 'src/engine/metadata-modules/utils/validate-metadata-name.utils'; +import { + validateMetadataNameOrThrow, + InvalidStringException, + NameTooLongException, +} from 'src/engine/metadata-modules/utils/validate-metadata-name.utils'; -describe('validateMetadataName', () => { +describe('validateMetadataNameOrThrow', () => { it('does not throw if string is valid', () => { const input = 'testName'; - expect(validateMetadataName(input)).not.toThrow; + expect(validateMetadataNameOrThrow(input)).not.toThrow; }); it('throws error if string has spaces', () => { const input = 'name with spaces'; - expect(() => validateMetadataName(input)).toThrow(InvalidStringException); + expect(() => validateMetadataNameOrThrow(input)).toThrow( + InvalidStringException, + ); }); it('throws error if string starts with capital letter', () => { const input = 'StringStartingWithCapitalLetter'; - expect(() => validateMetadataName(input)).toThrow(InvalidStringException); + expect(() => validateMetadataNameOrThrow(input)).toThrow( + InvalidStringException, + ); }); it('throws error if string has non latin characters', () => { const input = 'בְרִבְרִ'; - expect(() => validateMetadataName(input)).toThrow(InvalidStringException); + expect(() => validateMetadataNameOrThrow(input)).toThrow( + InvalidStringException, + ); }); it('throws error if starts with digits', () => { const input = '123string'; - expect(() => validateMetadataName(input)).toThrow(InvalidStringException); + expect(() => validateMetadataNameOrThrow(input)).toThrow( + InvalidStringException, + ); + }); + it('does not throw if string is less than 63 characters', () => { + const inputWith63Characters = + 'thisIsAstringWithSixtyThreeCharacters11111111111111111111111111'; + + expect(validateMetadataNameOrThrow(inputWith63Characters)).not.toThrow; + }); + it('throws error if string is above 63 characters', () => { + const inputWith64Characters = + 'thisIsAstringWithSixtyFourCharacters1111111111111111111111111111'; + + expect(() => validateMetadataNameOrThrow(inputWith64Characters)).toThrow( + NameTooLongException, + ); }); }); diff --git a/packages/twenty-server/src/engine/metadata-modules/utils/metadata.constants.ts b/packages/twenty-server/src/engine/metadata-modules/utils/metadata.constants.ts new file mode 100644 index 000000000000..ce2dabd729b6 --- /dev/null +++ b/packages/twenty-server/src/engine/metadata-modules/utils/metadata.constants.ts @@ -0,0 +1 @@ +export const IDENTIFIER_MAX_CHAR_LENGTH = 63; diff --git a/packages/twenty-server/src/engine/metadata-modules/utils/validate-database-identifier-length.utils.ts b/packages/twenty-server/src/engine/metadata-modules/utils/validate-database-identifier-length.utils.ts new file mode 100644 index 000000000000..dff01b4f33b3 --- /dev/null +++ b/packages/twenty-server/src/engine/metadata-modules/utils/validate-database-identifier-length.utils.ts @@ -0,0 +1,5 @@ +import { IDENTIFIER_MAX_CHAR_LENGTH } from 'src/engine/metadata-modules/utils/metadata.constants'; + +export const exceedsDatabaseIdentifierMaximumLength = (string: string) => { + return string.length > IDENTIFIER_MAX_CHAR_LENGTH; +}; diff --git a/packages/twenty-server/src/engine/metadata-modules/utils/validate-metadata-name.utils.ts b/packages/twenty-server/src/engine/metadata-modules/utils/validate-metadata-name.utils.ts index 16e8bfd56c9c..72835eead45e 100644 --- a/packages/twenty-server/src/engine/metadata-modules/utils/validate-metadata-name.utils.ts +++ b/packages/twenty-server/src/engine/metadata-modules/utils/validate-metadata-name.utils.ts @@ -1,9 +1,28 @@ -import { InvalidStringException } from 'src/engine/metadata-modules/errors/InvalidStringException'; +import { exceedsDatabaseIdentifierMaximumLength } from 'src/engine/metadata-modules/utils/validate-database-identifier-length.utils'; const VALID_STRING_PATTERN = /^[a-z][a-zA-Z0-9]*$/; -export const validateMetadataName = (string: string) => { - if (!string.match(VALID_STRING_PATTERN)) { - throw new InvalidStringException(string); +export const validateMetadataNameOrThrow = (name: string) => { + if (!name.match(VALID_STRING_PATTERN)) { + throw new InvalidStringException(name); + } + if (exceedsDatabaseIdentifierMaximumLength(name)) { + throw new NameTooLongException(name); } }; + +export class InvalidStringException extends Error { + constructor(string: string) { + const message = `String "${string}" is not valid`; + + super(message); + } +} + +export class NameTooLongException extends Error { + constructor(string: string) { + const message = `String "${string}" exceeds 63 characters limit`; + + super(message); + } +} diff --git a/packages/twenty-server/src/engine/metadata-modules/workspace-migration/factories/basic-column-action.factory.ts b/packages/twenty-server/src/engine/metadata-modules/workspace-migration/factories/basic-column-action.factory.ts index 093b3cba9cd8..93e38a5966f6 100644 --- a/packages/twenty-server/src/engine/metadata-modules/workspace-migration/factories/basic-column-action.factory.ts +++ b/packages/twenty-server/src/engine/metadata-modules/workspace-migration/factories/basic-column-action.factory.ts @@ -13,6 +13,10 @@ import { serializeDefaultValue } from 'src/engine/metadata-modules/field-metadat import { fieldMetadataTypeToColumnType } from 'src/engine/metadata-modules/workspace-migration/utils/field-metadata-type-to-column-type.util'; import { ColumnActionAbstractFactory } from 'src/engine/metadata-modules/workspace-migration/factories/column-action-abstract.factory'; import { computeColumnName } from 'src/engine/metadata-modules/field-metadata/utils/compute-column-name.util'; +import { + WorkspaceMigrationException, + WorkspaceMigrationExceptionCode, +} from 'src/engine/metadata-modules/workspace-migration/workspace-migration.exception'; export type BasicFieldMetadataType = | FieldMetadataType.UUID @@ -21,7 +25,6 @@ export type BasicFieldMetadataType = | FieldMetadataType.EMAIL | FieldMetadataType.NUMERIC | FieldMetadataType.NUMBER - | FieldMetadataType.PROBABILITY | FieldMetadataType.BOOLEAN | FieldMetadataType.POSITION | FieldMetadataType.DATE_TIME @@ -66,8 +69,9 @@ export class BasicColumnActionFactory extends ColumnActionAbstractFactory<BasicF this.logger.error( `Column name not found for current or altered field metadata, can be due to a missing or an invalid target column map. Current column name: ${currentColumnName}, Altered column name: ${alteredColumnName}.`, ); - throw new Error( + throw new WorkspaceMigrationException( `Column name not found for current or altered field metadata`, + WorkspaceMigrationExceptionCode.INVALID_FIELD_METADATA, ); } diff --git a/packages/twenty-server/src/engine/metadata-modules/workspace-migration/factories/column-action-abstract.factory.ts b/packages/twenty-server/src/engine/metadata-modules/workspace-migration/factories/column-action-abstract.factory.ts index a56d3a8fdb28..0e600aa6f618 100644 --- a/packages/twenty-server/src/engine/metadata-modules/workspace-migration/factories/column-action-abstract.factory.ts +++ b/packages/twenty-server/src/engine/metadata-modules/workspace-migration/factories/column-action-abstract.factory.ts @@ -12,6 +12,10 @@ import { WorkspaceMigrationColumnAlter, } from 'src/engine/metadata-modules/workspace-migration/workspace-migration.entity'; import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; +import { + WorkspaceMigrationException, + WorkspaceMigrationExceptionCode, +} from 'src/engine/metadata-modules/workspace-migration/workspace-migration.exception'; export class ColumnActionAbstractFactory< T extends FieldMetadataType | 'default', @@ -32,7 +36,10 @@ export class ColumnActionAbstractFactory< return this.handleCreateAction(alteredFieldMetadata, options); case WorkspaceMigrationColumnActionType.ALTER: { if (!currentFieldMetadata) { - throw new Error('current field metadata is required for alter'); + throw new WorkspaceMigrationException( + 'current field metadata is required for alter', + WorkspaceMigrationExceptionCode.INVALID_FIELD_METADATA, + ); } return this.handleAlterAction( @@ -43,8 +50,10 @@ export class ColumnActionAbstractFactory< } default: { this.logger.error(`Invalid action: ${action}`); - - throw new Error('[AbstractFactory]: invalid action'); + throw new WorkspaceMigrationException( + '[AbstractFactory]: invalid action', + WorkspaceMigrationExceptionCode.INVALID_ACTION, + ); } } } @@ -53,7 +62,10 @@ export class ColumnActionAbstractFactory< _fieldMetadata: FieldMetadataInterface<T>, _options?: WorkspaceColumnActionOptions, ): WorkspaceMigrationColumnCreate[] { - throw new Error('handleCreateAction method not implemented.'); + throw new WorkspaceMigrationException( + 'handleCreateAction method not implemented.', + WorkspaceMigrationExceptionCode.INVALID_ACTION, + ); } protected handleAlterAction( @@ -61,6 +73,9 @@ export class ColumnActionAbstractFactory< _alteredFieldMetadata: FieldMetadataInterface<T>, _options?: WorkspaceColumnActionOptions, ): WorkspaceMigrationColumnAlter[] { - throw new Error('handleAlterAction method not implemented.'); + throw new WorkspaceMigrationException( + 'handleAlterAction method not implemented.', + WorkspaceMigrationExceptionCode.INVALID_ACTION, + ); } } diff --git a/packages/twenty-server/src/engine/metadata-modules/workspace-migration/factories/composite-column-action.factory.ts b/packages/twenty-server/src/engine/metadata-modules/workspace-migration/factories/composite-column-action.factory.ts index 5947ba2c9723..a74bdd4e17d3 100644 --- a/packages/twenty-server/src/engine/metadata-modules/workspace-migration/factories/composite-column-action.factory.ts +++ b/packages/twenty-server/src/engine/metadata-modules/workspace-migration/factories/composite-column-action.factory.ts @@ -13,6 +13,10 @@ import { fieldMetadataTypeToColumnType } from 'src/engine/metadata-modules/works import { ColumnActionAbstractFactory } from 'src/engine/metadata-modules/workspace-migration/factories/column-action-abstract.factory'; import { computeCompositeColumnName } from 'src/engine/metadata-modules/field-metadata/utils/compute-column-name.util'; import { compositeTypeDefintions } from 'src/engine/metadata-modules/field-metadata/composite-types'; +import { + WorkspaceMigrationException, + WorkspaceMigrationExceptionCode, +} from 'src/engine/metadata-modules/workspace-migration/workspace-migration.exception'; export type CompositeFieldMetadataType = | FieldMetadataType.ADDRESS @@ -34,8 +38,9 @@ export class CompositeColumnActionFactory extends ColumnActionAbstractFactory<Co this.logger.error( `Composite type not found for field metadata type: ${fieldMetadata.type}`, ); - throw new Error( + throw new WorkspaceMigrationException( `Composite type not found for field metadata type: ${fieldMetadata.type}`, + WorkspaceMigrationExceptionCode.INVALID_FIELD_METADATA, ); } @@ -74,8 +79,9 @@ export class CompositeColumnActionFactory extends ColumnActionAbstractFactory<Co this.logger.error( `Composite type not found for field metadata type: ${currentFieldMetadata.type} or ${alteredFieldMetadata.type}`, ); - throw new Error( + throw new WorkspaceMigrationException( `Composite type not found for field metadata type: ${currentFieldMetadata.type} or ${alteredFieldMetadata.type}`, + WorkspaceMigrationExceptionCode.INVALID_FIELD_METADATA, ); } @@ -91,8 +97,9 @@ export class CompositeColumnActionFactory extends ColumnActionAbstractFactory<Co this.logger.error( `Current property not found for altered property: ${alteredProperty.name}`, ); - throw new Error( + throw new WorkspaceMigrationException( `Current property not found for altered property: ${alteredProperty.name}`, + WorkspaceMigrationExceptionCode.INVALID_FIELD_METADATA, ); } diff --git a/packages/twenty-server/src/engine/metadata-modules/workspace-migration/factories/enum-column-action.factory.ts b/packages/twenty-server/src/engine/metadata-modules/workspace-migration/factories/enum-column-action.factory.ts index 1007f41e6297..939cc95b8901 100644 --- a/packages/twenty-server/src/engine/metadata-modules/workspace-migration/factories/enum-column-action.factory.ts +++ b/packages/twenty-server/src/engine/metadata-modules/workspace-migration/factories/enum-column-action.factory.ts @@ -13,6 +13,10 @@ import { serializeDefaultValue } from 'src/engine/metadata-modules/field-metadat import { fieldMetadataTypeToColumnType } from 'src/engine/metadata-modules/workspace-migration/utils/field-metadata-type-to-column-type.util'; import { ColumnActionAbstractFactory } from 'src/engine/metadata-modules/workspace-migration/factories/column-action-abstract.factory'; import { computeColumnName } from 'src/engine/metadata-modules/field-metadata/utils/compute-column-name.util'; +import { + WorkspaceMigrationException, + WorkspaceMigrationExceptionCode, +} from 'src/engine/metadata-modules/workspace-migration/workspace-migration.exception'; export type EnumFieldMetadataType = | FieldMetadataType.RATING @@ -82,8 +86,9 @@ export class EnumColumnActionFactory extends ColumnActionAbstractFactory<EnumFie this.logger.error( `Column name not found for current or altered field metadata, can be due to a missing or an invalid target column map. Current column name: ${currentColumnName}, Altered column name: ${alteredColumnName}.`, ); - throw new Error( + throw new WorkspaceMigrationException( `Column name not found for current or altered field metadata`, + WorkspaceMigrationExceptionCode.INVALID_FIELD_METADATA, ); } diff --git a/packages/twenty-server/src/engine/metadata-modules/workspace-migration/utils/field-metadata-type-to-column-type.util.ts b/packages/twenty-server/src/engine/metadata-modules/workspace-migration/utils/field-metadata-type-to-column-type.util.ts index f3999fd7f9f1..5c4f64213b27 100644 --- a/packages/twenty-server/src/engine/metadata-modules/workspace-migration/utils/field-metadata-type-to-column-type.util.ts +++ b/packages/twenty-server/src/engine/metadata-modules/workspace-migration/utils/field-metadata-type-to-column-type.util.ts @@ -1,4 +1,8 @@ import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; +import { + WorkspaceMigrationException, + WorkspaceMigrationExceptionCode, +} from 'src/engine/metadata-modules/workspace-migration/workspace-migration.exception'; export const fieldMetadataTypeToColumnType = <Type extends FieldMetadataType>( fieldMetadataType: Type, @@ -18,7 +22,6 @@ export const fieldMetadataTypeToColumnType = <Type extends FieldMetadataType>( case FieldMetadataType.NUMERIC: return 'numeric'; case FieldMetadataType.NUMBER: - case FieldMetadataType.PROBABILITY: case FieldMetadataType.POSITION: return 'float'; case FieldMetadataType.BOOLEAN: @@ -34,6 +37,9 @@ export const fieldMetadataTypeToColumnType = <Type extends FieldMetadataType>( case FieldMetadataType.RAW_JSON: return 'jsonb'; default: - throw new Error(`Cannot convert ${fieldMetadataType} to column type.`); + throw new WorkspaceMigrationException( + `Cannot convert ${fieldMetadataType} to column type.`, + WorkspaceMigrationExceptionCode.INVALID_FIELD_METADATA, + ); } }; diff --git a/packages/twenty-server/src/engine/metadata-modules/workspace-migration/workspace-migration.entity.ts b/packages/twenty-server/src/engine/metadata-modules/workspace-migration/workspace-migration.entity.ts index 8116e0b3dc9e..12084f80f1aa 100644 --- a/packages/twenty-server/src/engine/metadata-modules/workspace-migration/workspace-migration.entity.ts +++ b/packages/twenty-server/src/engine/metadata-modules/workspace-migration/workspace-migration.entity.ts @@ -18,6 +18,11 @@ export enum WorkspaceMigrationColumnActionType { export type WorkspaceMigrationRenamedEnum = { from: string; to: string }; export type WorkspaceMigrationEnum = string | WorkspaceMigrationRenamedEnum; +export enum WorkspaceMigrationIndexActionType { + CREATE = 'CREATE', + DROP = 'DROP', +} + export interface WorkspaceMigrationColumnDefinition { columnName: string; columnType: string; @@ -27,6 +32,12 @@ export interface WorkspaceMigrationColumnDefinition { defaultValue?: any; } +export interface WorkspaceMigrationIndexAction { + action: WorkspaceMigrationIndexActionType; + name: string; + columns: string[]; +} + export interface WorkspaceMigrationColumnCreate extends WorkspaceMigrationColumnDefinition { action: WorkspaceMigrationColumnActionType.CREATE; @@ -105,6 +116,7 @@ export enum WorkspaceMigrationTableActionType { CREATE_FOREIGN_TABLE = 'create_foreign_table', DROP_FOREIGN_TABLE = 'drop_foreign_table', ALTER_FOREIGN_TABLE = 'alter_foreign_table', + ALTER_INDEXES = 'alter_indexes', } export type WorkspaceMigrationTableAction = { @@ -113,6 +125,7 @@ export type WorkspaceMigrationTableAction = { action: WorkspaceMigrationTableActionType; columns?: WorkspaceMigrationColumnAction[]; foreignTable?: WorkspaceMigrationForeignTable; + indexes?: WorkspaceMigrationIndexAction[]; }; @Entity('workspaceMigration') diff --git a/packages/twenty-server/src/engine/metadata-modules/workspace-migration/workspace-migration.exception.ts b/packages/twenty-server/src/engine/metadata-modules/workspace-migration/workspace-migration.exception.ts new file mode 100644 index 000000000000..6340aeaa20af --- /dev/null +++ b/packages/twenty-server/src/engine/metadata-modules/workspace-migration/workspace-migration.exception.ts @@ -0,0 +1,14 @@ +import { CustomException } from 'src/utils/custom-exception'; + +export class WorkspaceMigrationException extends CustomException { + code: WorkspaceMigrationExceptionCode; + constructor(message: string, code: WorkspaceMigrationExceptionCode) { + super(message, code); + } +} + +export enum WorkspaceMigrationExceptionCode { + NO_FACTORY_FOUND = 'NO_FACTORY_FOUND', + INVALID_ACTION = 'INVALID_ACTION', + INVALID_FIELD_METADATA = 'INVALID_FIELD_METADATA', +} diff --git a/packages/twenty-server/src/engine/metadata-modules/workspace-migration/workspace-migration.factory.ts b/packages/twenty-server/src/engine/metadata-modules/workspace-migration/workspace-migration.factory.ts index 6b3697294f86..02dcfe59ac27 100644 --- a/packages/twenty-server/src/engine/metadata-modules/workspace-migration/workspace-migration.factory.ts +++ b/packages/twenty-server/src/engine/metadata-modules/workspace-migration/workspace-migration.factory.ts @@ -12,6 +12,10 @@ import { import { BasicColumnActionFactory } from 'src/engine/metadata-modules/workspace-migration/factories/basic-column-action.factory'; import { EnumColumnActionFactory } from 'src/engine/metadata-modules/workspace-migration/factories/enum-column-action.factory'; import { CompositeColumnActionFactory } from 'src/engine/metadata-modules/workspace-migration/factories/composite-column-action.factory'; +import { + WorkspaceMigrationException, + WorkspaceMigrationExceptionCode, +} from 'src/engine/metadata-modules/workspace-migration/workspace-migration.exception'; @Injectable() export class WorkspaceMigrationFactory { @@ -68,10 +72,6 @@ export class WorkspaceMigrationFactory { [FieldMetadataType.NUMBER, { factory: this.basicColumnActionFactory }], [FieldMetadataType.POSITION, { factory: this.basicColumnActionFactory }], [FieldMetadataType.RAW_JSON, { factory: this.basicColumnActionFactory }], - [ - FieldMetadataType.PROBABILITY, - { factory: this.basicColumnActionFactory }, - ], [FieldMetadataType.BOOLEAN, { factory: this.basicColumnActionFactory }], [FieldMetadataType.DATE_TIME, { factory: this.basicColumnActionFactory }], [FieldMetadataType.DATE, { factory: this.basicColumnActionFactory }], @@ -131,7 +131,10 @@ export class WorkspaceMigrationFactory { undefinedOrAlteredFieldMetadata, ); - throw new Error(`No field metadata provided for action ${action}`); + throw new WorkspaceMigrationException( + `No field metadata provided for action ${action}`, + WorkspaceMigrationExceptionCode.INVALID_ACTION, + ); } const columnActions = this.createColumnAction( @@ -161,7 +164,10 @@ export class WorkspaceMigrationFactory { }, ); - throw new Error(`No factory found for type ${alteredFieldMetadata.type}`); + throw new WorkspaceMigrationException( + `No factory found for type ${alteredFieldMetadata.type}`, + WorkspaceMigrationExceptionCode.NO_FACTORY_FOUND, + ); } return factory.create( diff --git a/packages/twenty-server/src/engine/middlewares/graphql-hydrate-request-from-token.middleware.ts b/packages/twenty-server/src/engine/middlewares/graphql-hydrate-request-from-token.middleware.ts index b9d3d2cd5078..cbe7f3092963 100644 --- a/packages/twenty-server/src/engine/middlewares/graphql-hydrate-request-from-token.middleware.ts +++ b/packages/twenty-server/src/engine/middlewares/graphql-hydrate-request-from-token.middleware.ts @@ -55,6 +55,7 @@ export class GraphQLHydrateRequestFromTokenMiddleware req.user = data.user; req.workspace = data.workspace; + req.workspaceId = data.workspace.id; req.cacheVersion = cacheVersion; } catch (error) { res.writeHead(200, { 'Content-Type': 'application/json' }); diff --git a/packages/twenty-server/src/engine/object-metadata-repository/metadata-to-repository.mapping.ts b/packages/twenty-server/src/engine/object-metadata-repository/metadata-to-repository.mapping.ts index 17b4d0e8028c..1ead430c1a88 100644 --- a/packages/twenty-server/src/engine/object-metadata-repository/metadata-to-repository.mapping.ts +++ b/packages/twenty-server/src/engine/object-metadata-repository/metadata-to-repository.mapping.ts @@ -1,30 +1,19 @@ -import { CalendarChannelEventAssociationRepository } from 'src/modules/calendar/repositories/calendar-channel-event-association.repository'; -import { CalendarChannelRepository } from 'src/modules/calendar/repositories/calendar-channel.repository'; -import { CalendarEventParticipantRepository } from 'src/modules/calendar/repositories/calendar-event-participant.repository'; -import { CalendarEventRepository } from 'src/modules/calendar/repositories/calendar-event.repository'; +import { BlocklistRepository } from 'src/modules/blocklist/repositories/blocklist.repository'; import { CompanyRepository } from 'src/modules/company/repositories/company.repository'; -import { BlocklistRepository } from 'src/modules/connected-account/repositories/blocklist.repository'; import { ConnectedAccountRepository } from 'src/modules/connected-account/repositories/connected-account.repository'; -import { AuditLogRepository } from 'src/modules/timeline/repositiories/audit-log.repository'; -import { TimelineActivityRepository } from 'src/modules/timeline/repositiories/timeline-activity.repository'; -import { WorkspaceMemberRepository } from 'src/modules/workspace-member/repositories/workspace-member.repository'; -import { AttachmentRepository } from 'src/modules/attachment/repositories/attachment.repository'; -import { CommentRepository } from 'src/modules/activity/repositories/comment.repository'; import { MessageChannelMessageAssociationRepository } from 'src/modules/messaging/common/repositories/message-channel-message-association.repository'; import { MessageChannelRepository } from 'src/modules/messaging/common/repositories/message-channel.repository'; import { MessageParticipantRepository } from 'src/modules/messaging/common/repositories/message-participant.repository'; import { MessageThreadRepository } from 'src/modules/messaging/common/repositories/message-thread.repository'; import { MessageRepository } from 'src/modules/messaging/common/repositories/message.repository'; import { PersonRepository } from 'src/modules/person/repositories/person.repository'; +import { AuditLogRepository } from 'src/modules/timeline/repositiories/audit-log.repository'; +import { TimelineActivityRepository } from 'src/modules/timeline/repositiories/timeline-activity.repository'; +import { WorkspaceMemberRepository } from 'src/modules/workspace-member/repositories/workspace-member.repository'; export const metadataToRepositoryMapping = { AuditLogWorkspaceEntity: AuditLogRepository, BlocklistWorkspaceEntity: BlocklistRepository, - CalendarChannelEventAssociationWorkspaceEntity: - CalendarChannelEventAssociationRepository, - CalendarChannelWorkspaceEntity: CalendarChannelRepository, - CalendarEventParticipantWorkspaceEntity: CalendarEventParticipantRepository, - CalendarEventWorkspaceEntity: CalendarEventRepository, CompanyWorkspaceEntity: CompanyRepository, ConnectedAccountWorkspaceEntity: ConnectedAccountRepository, MessageChannelMessageAssociationWorkspaceEntity: @@ -36,6 +25,4 @@ export const metadataToRepositoryMapping = { PersonWorkspaceEntity: PersonRepository, TimelineActivityWorkspaceEntity: TimelineActivityRepository, WorkspaceMemberWorkspaceEntity: WorkspaceMemberRepository, - AttachmentWorkspaceEntity: AttachmentRepository, - CommentWorkspaceEntity: CommentRepository, }; diff --git a/packages/twenty-server/src/engine/twenty-orm/context/load-service-with-workspace.context.ts b/packages/twenty-server/src/engine/twenty-orm/context/load-service-with-workspace.context.ts new file mode 100644 index 000000000000..02af97805044 --- /dev/null +++ b/packages/twenty-server/src/engine/twenty-orm/context/load-service-with-workspace.context.ts @@ -0,0 +1,39 @@ +import { Inject, Type } from '@nestjs/common'; +import { ModuleRef, createContextId } from '@nestjs/core'; +import { Injector } from '@nestjs/core/injector/injector'; + +export class LoadServiceWithWorkspaceContext { + private readonly injector = new Injector(); + + constructor( + @Inject(ModuleRef) + private readonly moduleRef: ModuleRef, + ) {} + + async load<T>(service: T, workspaceId: string): Promise<T> { + const modules = this.moduleRef['container'].getModules(); + const host = [...modules.values()].find((module) => + module.providers.has((service as Type<T>).constructor), + ); + + if (!host) { + throw new Error('Host module not found for the service'); + } + + const contextId = createContextId(); + + if (this.moduleRef.registerRequestByContextId) { + this.moduleRef.registerRequestByContextId( + { req: { workspaceId } }, + contextId, + ); + } + + return this.injector.loadPerContext( + service, + host, + new Map(host.providers), + contextId, + ); + } +} diff --git a/packages/twenty-server/src/engine/twenty-orm/custom.workspace-entity.ts b/packages/twenty-server/src/engine/twenty-orm/custom.workspace-entity.ts index ee7740f065ee..56f9238d249f 100644 --- a/packages/twenty-server/src/engine/twenty-orm/custom.workspace-entity.ts +++ b/packages/twenty-server/src/engine/twenty-orm/custom.workspace-entity.ts @@ -36,7 +36,7 @@ export class CustomWorkspaceEntity extends BaseWorkspaceEntity { }) @WorkspaceIsNullable() @WorkspaceIsSystem() - position: number; + position: number | null; @WorkspaceRelation({ standardId: CUSTOM_OBJECT_STANDARD_FIELD_IDS.activityTargets, diff --git a/packages/twenty-server/src/engine/twenty-orm/datasource/workspace.datasource.ts b/packages/twenty-server/src/engine/twenty-orm/datasource/workspace.datasource.ts index ab51a2492706..71ca2190903c 100644 --- a/packages/twenty-server/src/engine/twenty-orm/datasource/workspace.datasource.ts +++ b/packages/twenty-server/src/engine/twenty-orm/datasource/workspace.datasource.ts @@ -6,8 +6,8 @@ import { QueryRunner, } from 'typeorm'; -import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository'; import { WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/entity.manager'; +import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository'; export class WorkspaceDataSource extends DataSource { readonly manager: WorkspaceEntityManager; diff --git a/packages/twenty-server/src/engine/twenty-orm/decorators/workspace-field.decorator.ts b/packages/twenty-server/src/engine/twenty-orm/decorators/workspace-field.decorator.ts index 60a228d90d5d..cfbb7a96407d 100644 --- a/packages/twenty-server/src/engine/twenty-orm/decorators/workspace-field.decorator.ts +++ b/packages/twenty-server/src/engine/twenty-orm/decorators/workspace-field.decorator.ts @@ -46,6 +46,13 @@ export function WorkspaceField<T extends FieldMetadataType>( object, propertyKey.toString(), ); + const isDeprecated = + TypedReflect.getMetadata( + 'workspace:is-deprecated-field-metadata-args', + object, + propertyKey.toString(), + ) ?? false; + const defaultValue = (options.defaultValue ?? generateDefaultValue( options.type, @@ -65,6 +72,7 @@ export function WorkspaceField<T extends FieldMetadataType>( isNullable, isSystem, gate, + isDeprecated, }); }; } diff --git a/packages/twenty-server/src/engine/twenty-orm/decorators/workspace-index.decorator.ts b/packages/twenty-server/src/engine/twenty-orm/decorators/workspace-index.decorator.ts new file mode 100644 index 000000000000..0ba01f8e037a --- /dev/null +++ b/packages/twenty-server/src/engine/twenty-orm/decorators/workspace-index.decorator.ts @@ -0,0 +1,43 @@ +import { generateDeterministicIndexName } from 'src/engine/metadata-modules/index-metadata/utils/generate-deterministic-index-name'; +import { metadataArgsStorage } from 'src/engine/twenty-orm/storage/metadata-args.storage'; +import { convertClassNameToObjectMetadataName } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/convert-class-to-object-metadata-name.util'; + +export interface WorkspaceIndexOptions { + columns?: string[]; +} + +export function WorkspaceIndex(): PropertyDecorator; +export function WorkspaceIndex(columns: string[]): ClassDecorator; +export function WorkspaceIndex( + columns?: string[], +): PropertyDecorator | ClassDecorator { + return (target: any, propertyKey: string | symbol) => { + if (propertyKey === undefined && columns === undefined) { + throw new Error('Class level WorkspaceIndex should be used with columns'); + } + + // TODO: handle composite field metadata types + + if (Array.isArray(columns) && columns.length > 0) { + metadataArgsStorage.addIndexes({ + name: `IDX_${generateDeterministicIndexName([ + convertClassNameToObjectMetadataName(target.name), + ...columns, + ])}`, + columns, + target: target, + }); + + return; + } + + metadataArgsStorage.addIndexes({ + name: `IDX_${generateDeterministicIndexName([ + convertClassNameToObjectMetadataName(target.constructor.name), + propertyKey.toString(), + ])}`, + columns: [propertyKey.toString()], + target: target.constructor, + }); + }; +} diff --git a/packages/twenty-server/src/engine/twenty-orm/decorators/workspace-is-deprecated.decorator.ts b/packages/twenty-server/src/engine/twenty-orm/decorators/workspace-is-deprecated.decorator.ts new file mode 100644 index 000000000000..a9bbb192e6e2 --- /dev/null +++ b/packages/twenty-server/src/engine/twenty-orm/decorators/workspace-is-deprecated.decorator.ts @@ -0,0 +1,12 @@ +import { TypedReflect } from 'src/utils/typed-reflect'; + +export function WorkspaceIsDeprecated(): PropertyDecorator { + return (object, propertyKey) => { + TypedReflect.defineMetadata( + 'workspace:is-deprecated-field-metadata-args', + true, + object, + propertyKey.toString(), + ); + }; +} diff --git a/packages/twenty-server/src/engine/twenty-orm/decorators/workspace-join-column.decorator.ts b/packages/twenty-server/src/engine/twenty-orm/decorators/workspace-join-column.decorator.ts new file mode 100644 index 000000000000..98dc6eedb10c --- /dev/null +++ b/packages/twenty-server/src/engine/twenty-orm/decorators/workspace-join-column.decorator.ts @@ -0,0 +1,17 @@ +import { WorkspaceIndex } from 'src/engine/twenty-orm/decorators/workspace-index.decorator'; +import { metadataArgsStorage } from 'src/engine/twenty-orm/storage/metadata-args.storage'; + +export function WorkspaceJoinColumn( + relationPropertyKey: string, +): PropertyDecorator { + return (object, propertyKey) => { + metadataArgsStorage.addJoinColumns({ + target: object.constructor, + relationName: relationPropertyKey, + joinColumn: propertyKey.toString(), + }); + + // Register index for join column + WorkspaceIndex()(object, propertyKey); + }; +} diff --git a/packages/twenty-server/src/engine/twenty-orm/decorators/workspace-relation.decorator.ts b/packages/twenty-server/src/engine/twenty-orm/decorators/workspace-relation.decorator.ts index e20877f00eab..2ead553d039b 100644 --- a/packages/twenty-server/src/engine/twenty-orm/decorators/workspace-relation.decorator.ts +++ b/packages/twenty-server/src/engine/twenty-orm/decorators/workspace-relation.decorator.ts @@ -8,35 +8,19 @@ import { metadataArgsStorage } from 'src/engine/twenty-orm/storage/metadata-args import { TypedReflect } from 'src/utils/typed-reflect'; import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; -interface WorkspaceBaseRelationOptions<TType, TClass> { +interface WorkspaceRelationOptions<TClass> { standardId: string; label: string | ((objectMetadata: ObjectMetadataEntity) => string); description?: string | ((objectMetadata: ObjectMetadataEntity) => string); icon?: string; - type: TType; + type: RelationMetadataType; inverseSideTarget: () => ObjectType<TClass>; inverseSideFieldKey?: keyof TClass; onDelete?: RelationOnDeleteAction; } -export interface WorkspaceManyToOneRelationOptions<TClass> - extends WorkspaceBaseRelationOptions< - RelationMetadataType.MANY_TO_ONE | RelationMetadataType.ONE_TO_ONE, - TClass - > { - joinColumn?: string; -} - -export interface WorkspaceOtherRelationOptions<TClass> - extends WorkspaceBaseRelationOptions< - RelationMetadataType.ONE_TO_MANY | RelationMetadataType.MANY_TO_MANY, - TClass - > {} - export function WorkspaceRelation<TClass extends object>( - options: - | WorkspaceManyToOneRelationOptions<TClass> - | WorkspaceOtherRelationOptions<TClass>, + options: WorkspaceRelationOptions<TClass>, ): PropertyDecorator { return (object, propertyKey) => { const isPrimary = @@ -63,14 +47,6 @@ export function WorkspaceRelation<TClass extends object>( propertyKey.toString(), ); - let joinColumn: string | undefined; - - if ('joinColumn' in options) { - joinColumn = options.joinColumn - ? options.joinColumn - : `${propertyKey.toString()}Id`; - } - metadataArgsStorage.addRelations({ target: object.constructor, standardId: options.standardId, @@ -82,7 +58,6 @@ export function WorkspaceRelation<TClass extends object>( inverseSideTarget: options.inverseSideTarget, inverseSideFieldKey: options.inverseSideFieldKey as string | undefined, onDelete: options.onDelete, - joinColumn, isPrimary, isNullable, isSystem, diff --git a/packages/twenty-server/src/engine/twenty-orm/factories/entity-schema-column.factory.ts b/packages/twenty-server/src/engine/twenty-orm/factories/entity-schema-column.factory.ts index 68b537d8634b..83106f92fa68 100644 --- a/packages/twenty-server/src/engine/twenty-orm/factories/entity-schema-column.factory.ts +++ b/packages/twenty-server/src/engine/twenty-orm/factories/entity-schema-column.factory.ts @@ -4,6 +4,7 @@ import { ColumnType, EntitySchemaColumnOptions } from 'typeorm'; import { WorkspaceFieldMetadataArgs } from 'src/engine/twenty-orm/interfaces/workspace-field-metadata-args.interface'; import { WorkspaceRelationMetadataArgs } from 'src/engine/twenty-orm/interfaces/workspace-relation-metadata-args.interface'; +import { WorkspaceJoinColumnsMetadataArgs } from 'src/engine/twenty-orm/interfaces/workspace-join-columns-metadata-args.interface'; import { fieldMetadataTypeToColumnType } from 'src/engine/metadata-modules/workspace-migration/utils/field-metadata-type-to-column-type.util'; import { isEnumFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/utils/is-enum-field-metadata-type.util'; @@ -12,6 +13,7 @@ import { computeCompositeColumnName } from 'src/engine/metadata-modules/field-me import { isCompositeFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/utils/is-composite-field-metadata-type.util'; import { compositeTypeDefintions } from 'src/engine/metadata-modules/field-metadata/composite-types'; import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; +import { getJoinColumn } from 'src/engine/twenty-orm/utils/get-join-column.util'; type EntitySchemaColumnMap = { [key: string]: EntitySchemaColumnOptions; @@ -22,6 +24,7 @@ export class EntitySchemaColumnFactory { create( fieldMetadataArgsCollection: WorkspaceFieldMetadataArgs[], relationMetadataArgsCollection: WorkspaceRelationMetadataArgs[], + joinColumnsMetadataArgsCollection: WorkspaceJoinColumnsMetadataArgs[], ): EntitySchemaColumnMap { let entitySchemaColumnMap: EntitySchemaColumnMap = {}; @@ -56,9 +59,14 @@ export class EntitySchemaColumnFactory { }; for (const relationMetadataArgs of relationMetadataArgsCollection) { - if (relationMetadataArgs.joinColumn) { - entitySchemaColumnMap[relationMetadataArgs.joinColumn] = { - name: relationMetadataArgs.joinColumn, + const joinColumn = getJoinColumn( + joinColumnsMetadataArgsCollection, + relationMetadataArgs, + ); + + if (joinColumn) { + entitySchemaColumnMap[joinColumn] = { + name: joinColumn, type: 'uuid', nullable: relationMetadataArgs.isNullable, }; diff --git a/packages/twenty-server/src/engine/twenty-orm/factories/entity-schema-relation.factory.ts b/packages/twenty-server/src/engine/twenty-orm/factories/entity-schema-relation.factory.ts index d194879214f3..bc83b460b26a 100644 --- a/packages/twenty-server/src/engine/twenty-orm/factories/entity-schema-relation.factory.ts +++ b/packages/twenty-server/src/engine/twenty-orm/factories/entity-schema-relation.factory.ts @@ -4,9 +4,11 @@ import { EntitySchemaRelationOptions } from 'typeorm'; import { RelationType } from 'typeorm/metadata/types/RelationTypes'; import { WorkspaceRelationMetadataArgs } from 'src/engine/twenty-orm/interfaces/workspace-relation-metadata-args.interface'; +import { WorkspaceJoinColumnsMetadataArgs } from 'src/engine/twenty-orm/interfaces/workspace-join-columns-metadata-args.interface'; import { convertClassNameToObjectMetadataName } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/convert-class-to-object-metadata-name.util'; import { RelationMetadataType } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity'; +import { getJoinColumn } from 'src/engine/twenty-orm/utils/get-join-column.util'; type EntitySchemaRelationMap = { [key: string]: EntitySchemaRelationOptions; @@ -18,6 +20,7 @@ export class EntitySchemaRelationFactory { // eslint-disable-next-line @typescript-eslint/ban-types target: Function, relationMetadataArgsCollection: WorkspaceRelationMetadataArgs[], + joinColumnsMetadataArgsCollection: WorkspaceJoinColumnsMetadataArgs[], ): EntitySchemaRelationMap { const entitySchemaRelationMap: EntitySchemaRelationMap = {}; @@ -27,16 +30,19 @@ export class EntitySchemaRelationFactory { const oppositeObjectName = convertClassNameToObjectMetadataName( oppositeTarget.name, ); - const relationType = this.getRelationType(relationMetadataArgs); + const joinColumn = getJoinColumn( + joinColumnsMetadataArgsCollection, + relationMetadataArgs, + ); entitySchemaRelationMap[relationMetadataArgs.name] = { type: relationType, target: oppositeObjectName, inverseSide: relationMetadataArgs.inverseSideFieldKey ?? objectName, - joinColumn: relationMetadataArgs.joinColumn + joinColumn: joinColumn ? { - name: relationMetadataArgs.joinColumn, + name: joinColumn, } : undefined, }; diff --git a/packages/twenty-server/src/engine/twenty-orm/factories/entity-schema.factory.ts b/packages/twenty-server/src/engine/twenty-orm/factories/entity-schema.factory.ts index 326f5558a01a..75f63dcb221d 100644 --- a/packages/twenty-server/src/engine/twenty-orm/factories/entity-schema.factory.ts +++ b/packages/twenty-server/src/engine/twenty-orm/factories/entity-schema.factory.ts @@ -23,17 +23,21 @@ export class EntitySchemaFactory { const fieldMetadataArgsCollection = metadataArgsStorage.filterFields(target); + const joinColumnsMetadataArgsCollection = + metadataArgsStorage.filterJoinColumns(target); const relationMetadataArgsCollection = metadataArgsStorage.filterRelations(target); const columns = this.entitySchemaColumnFactory.create( fieldMetadataArgsCollection, relationMetadataArgsCollection, + joinColumnsMetadataArgsCollection, ); const relations = this.entitySchemaRelationFactory.create( target, relationMetadataArgsCollection, + joinColumnsMetadataArgsCollection, ); const entitySchema = new EntitySchema({ diff --git a/packages/twenty-server/src/engine/twenty-orm/factories/scoped-workspace-datasource.factory.ts b/packages/twenty-server/src/engine/twenty-orm/factories/scoped-workspace-datasource.factory.ts index 0c21b6e74b6d..096be2194307 100644 --- a/packages/twenty-server/src/engine/twenty-orm/factories/scoped-workspace-datasource.factory.ts +++ b/packages/twenty-server/src/engine/twenty-orm/factories/scoped-workspace-datasource.factory.ts @@ -1,25 +1,27 @@ -import { Inject, Injectable, Scope } from '@nestjs/common'; +import { Inject, Injectable, Optional, Scope } from '@nestjs/common'; import { REQUEST } from '@nestjs/core'; import { EntitySchema } from 'typeorm'; -import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; import { WorkspaceDatasourceFactory } from 'src/engine/twenty-orm/factories/workspace-datasource.factory'; @Injectable({ scope: Scope.REQUEST }) export class ScopedWorkspaceDatasourceFactory { constructor( - @Inject(REQUEST) private readonly request: Request, + @Optional() + @Inject(REQUEST) + private readonly request: Request | null, private readonly workspaceDataSourceFactory: WorkspaceDatasourceFactory, ) {} public async create(entities: EntitySchema[]) { - const workspace: Workspace | undefined = this.request['req']?.['workspace']; + const workspaceId: string | undefined = + this.request?.['req']?.['workspaceId']; - if (!workspace) { + if (!workspaceId) { return null; } - return this.workspaceDataSourceFactory.create(entities, workspace.id); + return this.workspaceDataSourceFactory.create(entities, workspaceId); } } diff --git a/packages/twenty-server/src/engine/twenty-orm/factories/workspace-datasource.factory.ts b/packages/twenty-server/src/engine/twenty-orm/factories/workspace-datasource.factory.ts index 27aead734ab4..2c733961a265 100644 --- a/packages/twenty-server/src/engine/twenty-orm/factories/workspace-datasource.factory.ts +++ b/packages/twenty-server/src/engine/twenty-orm/factories/workspace-datasource.factory.ts @@ -14,7 +14,10 @@ export class WorkspaceDatasourceFactory { private readonly environmentService: EnvironmentService, ) {} - public async create(entities: EntitySchema[], workspaceId: string) { + public async create( + entities: EntitySchema[], + workspaceId: string, + ): Promise<WorkspaceDataSource | null> { const storedWorkspaceDataSource = DataSourceStorage.getDataSource(workspaceId); @@ -23,19 +26,22 @@ export class WorkspaceDatasourceFactory { } const dataSourceMetadata = - await this.dataSourceService.getLastDataSourceMetadataFromWorkspaceIdOrFail( + await this.dataSourceService.getLastDataSourceMetadataFromWorkspaceId( workspaceId, ); + if (!dataSourceMetadata) { + return null; + } + const workspaceDataSource = new WorkspaceDataSource({ url: dataSourceMetadata.url ?? this.environmentService.get('PG_DATABASE_URL'), type: 'postgres', - // logging: this.environmentService.get('DEBUG_MODE') - // ? ['query', 'error'] - // : ['error'], - logging: 'all', + logging: this.environmentService.get('DEBUG_MODE') + ? ['query', 'error'] + : ['error'], schema: dataSourceMetadata.schema, entities, ssl: this.environmentService.get('PG_SSL_ALLOW_SELF_SIGNED') diff --git a/packages/twenty-server/src/engine/twenty-orm/interfaces/workspace-field-metadata-args.interface.ts b/packages/twenty-server/src/engine/twenty-orm/interfaces/workspace-field-metadata-args.interface.ts index cad77a674e52..0574fb7922cf 100644 --- a/packages/twenty-server/src/engine/twenty-orm/interfaces/workspace-field-metadata-args.interface.ts +++ b/packages/twenty-server/src/engine/twenty-orm/interfaces/workspace-field-metadata-args.interface.ts @@ -73,4 +73,9 @@ export interface WorkspaceFieldMetadataArgs { * Field gate. */ readonly gate?: Gate; + + /** + * Is deprecated field. + */ + readonly isDeprecated?: boolean; } diff --git a/packages/twenty-server/src/engine/twenty-orm/interfaces/workspace-index-metadata-args.interface.ts b/packages/twenty-server/src/engine/twenty-orm/interfaces/workspace-index-metadata-args.interface.ts new file mode 100644 index 000000000000..add4c89e7476 --- /dev/null +++ b/packages/twenty-server/src/engine/twenty-orm/interfaces/workspace-index-metadata-args.interface.ts @@ -0,0 +1,17 @@ +export interface WorkspaceIndexMetadataArgs { + /** + * Class to which index is applied. + */ + // eslint-disable-next-line @typescript-eslint/ban-types + readonly target: Function; + + /* + * Index name. + */ + name: string; + + /* + * Index columns. + */ + columns: string[]; +} diff --git a/packages/twenty-server/src/engine/twenty-orm/interfaces/workspace-join-columns-metadata-args.interface.ts b/packages/twenty-server/src/engine/twenty-orm/interfaces/workspace-join-columns-metadata-args.interface.ts new file mode 100644 index 000000000000..481f4a77ea2d --- /dev/null +++ b/packages/twenty-server/src/engine/twenty-orm/interfaces/workspace-join-columns-metadata-args.interface.ts @@ -0,0 +1,17 @@ +export interface WorkspaceJoinColumnsMetadataArgs { + /** + * Class to which relation is applied. + */ + // eslint-disable-next-line @typescript-eslint/ban-types + readonly target: Function; + + /** + * Relation name. + */ + readonly relationName: string; + + /** + * Relation label. + */ + readonly joinColumn: string; +} diff --git a/packages/twenty-server/src/engine/twenty-orm/interfaces/workspace-relation-metadata-args.interface.ts b/packages/twenty-server/src/engine/twenty-orm/interfaces/workspace-relation-metadata-args.interface.ts index 911e9d78e8ed..861b1e7d44d4 100644 --- a/packages/twenty-server/src/engine/twenty-orm/interfaces/workspace-relation-metadata-args.interface.ts +++ b/packages/twenty-server/src/engine/twenty-orm/interfaces/workspace-relation-metadata-args.interface.ts @@ -62,11 +62,6 @@ export interface WorkspaceRelationMetadataArgs { */ readonly onDelete?: RelationOnDeleteAction; - /** - * Relation join column. - */ - readonly joinColumn?: string; - /** * Is primary field. */ diff --git a/packages/twenty-server/src/engine/twenty-orm/repository/workspace.repository.ts b/packages/twenty-server/src/engine/twenty-orm/repository/workspace.repository.ts index f03123e0734f..0f336768589d 100644 --- a/packages/twenty-server/src/engine/twenty-orm/repository/workspace.repository.ts +++ b/packages/twenty-server/src/engine/twenty-orm/repository/workspace.repository.ts @@ -1,6 +1,7 @@ import { DeepPartial, DeleteResult, + EntityManager, FindManyOptions, FindOneOptions, FindOptionsWhere, @@ -29,9 +30,13 @@ export class WorkspaceRepository< /** * FIND METHODS */ - override async find(options?: FindManyOptions<Entity>): Promise<Entity[]> { + override async find( + options?: FindManyOptions<Entity>, + entityManager?: EntityManager, + ): Promise<Entity[]> { + const manager = entityManager || this.manager; const computedOptions = this.transformOptions(options); - const result = await super.find(computedOptions); + const result = await manager.find(this.target, computedOptions); const formattedResult = this.formatResult(result); return formattedResult; @@ -39,9 +44,11 @@ export class WorkspaceRepository< override async findBy( where: FindOptionsWhere<Entity> | FindOptionsWhere<Entity>[], + entityManager?: EntityManager, ): Promise<Entity[]> { + const manager = entityManager || this.manager; const computedOptions = this.transformOptions({ where }); - const result = await super.findBy(computedOptions.where); + const result = await manager.findBy(this.target, computedOptions.where); const formattedResult = this.formatResult(result); return formattedResult; @@ -49,9 +56,11 @@ export class WorkspaceRepository< override async findAndCount( options?: FindManyOptions<Entity>, + entityManager?: EntityManager, ): Promise<[Entity[], number]> { + const manager = entityManager || this.manager; const computedOptions = this.transformOptions(options); - const result = await super.findAndCount(computedOptions); + const result = await manager.findAndCount(this.target, computedOptions); const formattedResult = this.formatResult(result); return formattedResult; @@ -59,9 +68,14 @@ export class WorkspaceRepository< override async findAndCountBy( where: FindOptionsWhere<Entity> | FindOptionsWhere<Entity>[], + entityManager?: EntityManager, ): Promise<[Entity[], number]> { + const manager = entityManager || this.manager; const computedOptions = this.transformOptions({ where }); - const result = await super.findAndCountBy(computedOptions.where); + const result = await manager.findAndCountBy( + this.target, + computedOptions.where, + ); const formattedResult = this.formatResult(result); return formattedResult; @@ -69,9 +83,11 @@ export class WorkspaceRepository< override async findOne( options: FindOneOptions<Entity>, + entityManager?: EntityManager, ): Promise<Entity | null> { + const manager = entityManager || this.manager; const computedOptions = this.transformOptions(options); - const result = await super.findOne(computedOptions); + const result = await manager.findOne(this.target, computedOptions); const formattedResult = this.formatResult(result); return formattedResult; @@ -79,9 +95,11 @@ export class WorkspaceRepository< override async findOneBy( where: FindOptionsWhere<Entity> | FindOptionsWhere<Entity>[], + entityManager?: EntityManager, ): Promise<Entity | null> { + const manager = entityManager || this.manager; const computedOptions = this.transformOptions({ where }); - const result = await super.findOneBy(computedOptions.where); + const result = await manager.findOneBy(this.target, computedOptions.where); const formattedResult = this.formatResult(result); return formattedResult; @@ -89,9 +107,11 @@ export class WorkspaceRepository< override async findOneOrFail( options: FindOneOptions<Entity>, + entityManager?: EntityManager, ): Promise<Entity> { + const manager = entityManager || this.manager; const computedOptions = this.transformOptions(options); - const result = await super.findOneOrFail(computedOptions); + const result = await manager.findOneOrFail(this.target, computedOptions); const formattedResult = this.formatResult(result); return formattedResult; @@ -99,9 +119,14 @@ export class WorkspaceRepository< override async findOneByOrFail( where: FindOptionsWhere<Entity> | FindOptionsWhere<Entity>[], + entityManager?: EntityManager, ): Promise<Entity> { + const manager = entityManager || this.manager; const computedOptions = this.transformOptions({ where }); - const result = await super.findOneByOrFail(computedOptions.where); + const result = await manager.findOneByOrFail( + this.target, + computedOptions.where, + ); const formattedResult = this.formatResult(result); return formattedResult; @@ -113,29 +138,40 @@ export class WorkspaceRepository< override save<T extends DeepPartial<Entity>>( entities: T[], options: SaveOptions & { reload: false }, + entityManager?: EntityManager, ): Promise<T[]>; override save<T extends DeepPartial<Entity>>( entities: T[], options?: SaveOptions, + entityManager?: EntityManager, ): Promise<(T & Entity)[]>; override save<T extends DeepPartial<Entity>>( entity: T, options: SaveOptions & { reload: false }, + entityManager?: EntityManager, ): Promise<T>; override save<T extends DeepPartial<Entity>>( entity: T, options?: SaveOptions, + entityManager?: EntityManager, ): Promise<T & Entity>; override async save<T extends DeepPartial<Entity>>( entityOrEntities: T | T[], options?: SaveOptions, + entityManager?: EntityManager, ): Promise<T | T[]> { + const manager = entityManager || this.manager; const formattedEntityOrEntities = this.formatData(entityOrEntities); - const result = await super.save(formattedEntityOrEntities as any, options); + const result = await manager.save( + this.target, + formattedEntityOrEntities as any, + options, + ); + const formattedResult = this.formatResult(result); return formattedResult; @@ -147,15 +183,27 @@ export class WorkspaceRepository< override remove( entities: Entity[], options?: RemoveOptions, + entityManager?: EntityManager, ): Promise<Entity[]>; - override remove(entity: Entity, options?: RemoveOptions): Promise<Entity>; + override remove( + entity: Entity, + options?: RemoveOptions, + entityManager?: EntityManager, + ): Promise<Entity>; override async remove( entityOrEntities: Entity | Entity[], + options?: RemoveOptions, + entityManager?: EntityManager, ): Promise<Entity | Entity[]> { + const manager = entityManager || this.manager; const formattedEntityOrEntities = this.formatData(entityOrEntities); - const result = await super.remove(formattedEntityOrEntities as any); + const result = await manager.remove( + this.target, + formattedEntityOrEntities, + options, + ); const formattedResult = this.formatResult(result); return formattedResult; @@ -172,40 +220,50 @@ export class WorkspaceRepository< | ObjectId | ObjectId[] | FindOptionsWhere<Entity>, + entityManager?: EntityManager, ): Promise<DeleteResult> { + const manager = entityManager || this.manager; + if (typeof criteria === 'object' && 'where' in criteria) { criteria = this.transformOptions(criteria); } - return this.delete(criteria); + return manager.delete(this.target, criteria); } override softRemove<T extends DeepPartial<Entity>>( entities: T[], options: SaveOptions & { reload: false }, + entityManager?: EntityManager, ): Promise<T[]>; override softRemove<T extends DeepPartial<Entity>>( entities: T[], options?: SaveOptions, + entityManager?: EntityManager, ): Promise<(T & Entity)[]>; override softRemove<T extends DeepPartial<Entity>>( entity: T, options: SaveOptions & { reload: false }, + entityManager?: EntityManager, ): Promise<T>; override softRemove<T extends DeepPartial<Entity>>( entity: T, options?: SaveOptions, + entityManager?: EntityManager, ): Promise<T & Entity>; override async softRemove<T extends DeepPartial<Entity>>( entityOrEntities: T | T[], options?: SaveOptions, + entityManager?: EntityManager, ): Promise<T | T[]> { + const manager = entityManager || this.manager; const formattedEntityOrEntities = this.formatData(entityOrEntities); - const result = await super.softRemove( + const result = await manager.softRemove( + this.target, formattedEntityOrEntities as any, options, ); @@ -225,12 +283,15 @@ export class WorkspaceRepository< | ObjectId | ObjectId[] | FindOptionsWhere<Entity>, + entityManager?: EntityManager, ): Promise<UpdateResult> { + const manager = entityManager || this.manager; + if (typeof criteria === 'object' && 'where' in criteria) { criteria = this.transformOptions(criteria); } - return this.softDelete(criteria); + return manager.softDelete(this.target, criteria); } /** @@ -239,29 +300,36 @@ export class WorkspaceRepository< override recover<T extends DeepPartial<Entity>>( entities: T[], options: SaveOptions & { reload: false }, + entityManager?: EntityManager, ): Promise<T[]>; override recover<T extends DeepPartial<Entity>>( entities: T[], options?: SaveOptions, + entityManager?: EntityManager, ): Promise<(T & Entity)[]>; override recover<T extends DeepPartial<Entity>>( entity: T, options: SaveOptions & { reload: false }, + entityManager?: EntityManager, ): Promise<T>; override recover<T extends DeepPartial<Entity>>( entity: T, options?: SaveOptions, + entityManager?: EntityManager, ): Promise<T & Entity>; override async recover<T extends DeepPartial<Entity>>( entityOrEntities: T | T[], options?: SaveOptions, + entityManager?: EntityManager, ): Promise<T | T[]> { + const manager = entityManager || this.manager; const formattedEntityOrEntities = this.formatData(entityOrEntities); - const result = await super.recover( + const result = await manager.recover( + this.target, formattedEntityOrEntities as any, options, ); @@ -281,12 +349,15 @@ export class WorkspaceRepository< | ObjectId | ObjectId[] | FindOptionsWhere<Entity>, + entityManager?: EntityManager, ): Promise<UpdateResult> { + const manager = entityManager || this.manager; + if (typeof criteria === 'object' && 'where' in criteria) { criteria = this.transformOptions(criteria); } - return this.restore(criteria); + return manager.restore(this.target, criteria); } /** @@ -294,9 +365,11 @@ export class WorkspaceRepository< */ override async insert( entity: QueryDeepPartialEntity<Entity> | QueryDeepPartialEntity<Entity>[], + entityManager?: EntityManager, ): Promise<InsertResult> { + const manager = entityManager || this.manager; const formatedEntity = this.formatData(entity); - const result = await super.insert(formatedEntity); + const result = await manager.insert(this.target, formatedEntity); const formattedResult = this.formatResult(result); return formattedResult; @@ -317,12 +390,15 @@ export class WorkspaceRepository< | ObjectId[] | FindOptionsWhere<Entity>, partialEntity: QueryDeepPartialEntity<Entity>, + entityManager?: EntityManager, ): Promise<UpdateResult> { + const manager = entityManager || this.manager; + if (typeof criteria === 'object' && 'where' in criteria) { criteria = this.transformOptions(criteria); } - return this.update(criteria, partialEntity); + return manager.update(this.target, criteria, partialEntity); } override upsert( @@ -330,50 +406,63 @@ export class WorkspaceRepository< | QueryDeepPartialEntity<Entity> | QueryDeepPartialEntity<Entity>[], conflictPathsOrOptions: string[] | UpsertOptions<Entity>, + entityManager?: EntityManager, ): Promise<InsertResult> { + const manager = entityManager || this.manager; + const formattedEntityOrEntities = this.formatData(entityOrEntities); - return this.upsert(formattedEntityOrEntities, conflictPathsOrOptions); + return manager.upsert( + this.target, + formattedEntityOrEntities, + conflictPathsOrOptions, + ); } /** * EXIST METHODS */ - override exist(options?: FindManyOptions<Entity>): Promise<boolean> { - const computedOptions = this.transformOptions(options); - - return super.exist(computedOptions); - } - - override exists(options?: FindManyOptions<Entity>): Promise<boolean> { + override exists( + options?: FindManyOptions<Entity>, + entityManager?: EntityManager, + ): Promise<boolean> { + const manager = entityManager || this.manager; const computedOptions = this.transformOptions(options); - return super.exists(computedOptions); + return manager.exists(this.target, computedOptions); } override existsBy( where: FindOptionsWhere<Entity> | FindOptionsWhere<Entity>[], + entityManager?: EntityManager, ): Promise<boolean> { + const manager = entityManager || this.manager; const computedOptions = this.transformOptions({ where }); - return super.existsBy(computedOptions.where); + return manager.existsBy(this.target, computedOptions.where); } /** * COUNT METHODS */ - override count(options?: FindManyOptions<Entity>): Promise<number> { + override count( + options?: FindManyOptions<Entity>, + entityManager?: EntityManager, + ): Promise<number> { + const manager = entityManager || this.manager; const computedOptions = this.transformOptions(options); - return super.count(computedOptions); + return manager.count(this.target, computedOptions); } override countBy( where: FindOptionsWhere<Entity> | FindOptionsWhere<Entity>[], + entityManager?: EntityManager, ): Promise<number> { + const manager = entityManager || this.manager; const computedOptions = this.transformOptions({ where }); - return super.countBy(computedOptions.where); + return manager.countBy(this.target, computedOptions.where); } /** @@ -382,57 +471,79 @@ export class WorkspaceRepository< override sum( columnName: PickKeysByType<Entity, number>, where?: FindOptionsWhere<Entity> | FindOptionsWhere<Entity>[], + entityManager?: EntityManager, ): Promise<number | null> { + const manager = entityManager || this.manager; const computedOptions = this.transformOptions({ where }); - return super.sum(columnName, computedOptions.where); + return manager.sum(this.target, columnName, computedOptions.where); } override average( columnName: PickKeysByType<Entity, number>, where?: FindOptionsWhere<Entity> | FindOptionsWhere<Entity>[], + entityManager?: EntityManager, ): Promise<number | null> { + const manager = entityManager || this.manager; const computedOptions = this.transformOptions({ where }); - return super.average(columnName, computedOptions.where); + return manager.average(this.target, columnName, computedOptions.where); } override minimum( columnName: PickKeysByType<Entity, number>, where?: FindOptionsWhere<Entity> | FindOptionsWhere<Entity>[], + entityManager?: EntityManager, ): Promise<number | null> { + const manager = entityManager || this.manager; const computedOptions = this.transformOptions({ where }); - return super.minimum(columnName, computedOptions.where); + return manager.minimum(this.target, columnName, computedOptions.where); } override maximum( columnName: PickKeysByType<Entity, number>, where?: FindOptionsWhere<Entity> | FindOptionsWhere<Entity>[], + entityManager?: EntityManager, ): Promise<number | null> { + const manager = entityManager || this.manager; const computedOptions = this.transformOptions({ where }); - return super.maximum(columnName, computedOptions.where); + return manager.maximum(this.target, columnName, computedOptions.where); } override increment( conditions: FindOptionsWhere<Entity>, propertyPath: string, value: number | string, + entityManager?: EntityManager, ): Promise<UpdateResult> { + const manager = entityManager || this.manager; const computedConditions = this.transformOptions({ where: conditions }); - return this.increment(computedConditions.where, propertyPath, value); + return manager.increment( + this.target, + computedConditions.where, + propertyPath, + value, + ); } override decrement( conditions: FindOptionsWhere<Entity>, propertyPath: string, value: number | string, + entityManager?: EntityManager, ): Promise<UpdateResult> { + const manager = entityManager || this.manager; const computedConditions = this.transformOptions({ where: conditions }); - return this.decrement(computedConditions.where, propertyPath, value); + return manager.decrement( + this.target, + computedConditions.where, + propertyPath, + value, + ); } /** diff --git a/packages/twenty-server/src/engine/twenty-orm/storage/metadata-args.storage.ts b/packages/twenty-server/src/engine/twenty-orm/storage/metadata-args.storage.ts index 9fb114be94f2..77b038b335c7 100644 --- a/packages/twenty-server/src/engine/twenty-orm/storage/metadata-args.storage.ts +++ b/packages/twenty-server/src/engine/twenty-orm/storage/metadata-args.storage.ts @@ -5,6 +5,8 @@ import { WorkspaceFieldMetadataArgs } from 'src/engine/twenty-orm/interfaces/wor import { WorkspaceEntityMetadataArgs } from 'src/engine/twenty-orm/interfaces/workspace-entity-metadata-args.interface'; import { WorkspaceRelationMetadataArgs } from 'src/engine/twenty-orm/interfaces/workspace-relation-metadata-args.interface'; import { WorkspaceExtendedEntityMetadataArgs } from 'src/engine/twenty-orm/interfaces/workspace-extended-entity-metadata-args.interface'; +import { WorkspaceIndexMetadataArgs } from 'src/engine/twenty-orm/interfaces/workspace-index-metadata-args.interface'; +import { WorkspaceJoinColumnsMetadataArgs } from 'src/engine/twenty-orm/interfaces/workspace-join-columns-metadata-args.interface'; export class MetadataArgsStorage { private readonly entities: WorkspaceEntityMetadataArgs[] = []; @@ -13,6 +15,8 @@ export class MetadataArgsStorage { private readonly relations: WorkspaceRelationMetadataArgs[] = []; private readonly dynamicRelations: WorkspaceDynamicRelationMetadataArgs[] = []; + private readonly indexes: WorkspaceIndexMetadataArgs[] = []; + private readonly joinColumns: WorkspaceJoinColumnsMetadataArgs[] = []; addEntities(...entities: WorkspaceEntityMetadataArgs[]): void { this.entities.push(...entities); @@ -32,12 +36,20 @@ export class MetadataArgsStorage { this.relations.push(...relations); } + addIndexes(...indexes: WorkspaceIndexMetadataArgs[]): void { + this.indexes.push(...indexes); + } + addDynamicRelations( ...dynamicRelations: WorkspaceDynamicRelationMetadataArgs[] ): void { this.dynamicRelations.push(...dynamicRelations); } + addJoinColumns(...joinColumns: WorkspaceJoinColumnsMetadataArgs[]): void { + this.joinColumns.push(...joinColumns); + } + filterEntities( target: Function | string, ): WorkspaceEntityMetadataArgs | undefined; @@ -93,6 +105,16 @@ export class MetadataArgsStorage { return this.filterByTarget(this.relations, target); } + filterIndexes(target: Function | string): WorkspaceIndexMetadataArgs[]; + + filterIndexes(target: (Function | string)[]): WorkspaceIndexMetadataArgs[]; + + filterIndexes( + target: (Function | string) | (Function | string)[], + ): WorkspaceIndexMetadataArgs[] { + return this.filterByTarget(this.indexes, target); + } + filterDynamicRelations( target: Function | string, ): WorkspaceDynamicRelationMetadataArgs[]; @@ -107,6 +129,20 @@ export class MetadataArgsStorage { return this.filterByTarget(this.dynamicRelations, target); } + filterJoinColumns( + target: Function | string, + ): WorkspaceJoinColumnsMetadataArgs[]; + + filterJoinColumns( + target: (Function | string)[], + ): WorkspaceJoinColumnsMetadataArgs[]; + + filterJoinColumns( + target: (Function | string) | (Function | string)[], + ): WorkspaceJoinColumnsMetadataArgs[] { + return this.filterByTarget(this.joinColumns, target); + } + protected filterByTarget<T extends { target: Function | string }>( array: T[], target: (Function | string) | (Function | string)[], diff --git a/packages/twenty-server/src/engine/twenty-orm/twenty-orm-core.module.ts b/packages/twenty-server/src/engine/twenty-orm/twenty-orm-core.module.ts index befe7c28a717..efed8ca7bcae 100644 --- a/packages/twenty-server/src/engine/twenty-orm/twenty-orm-core.module.ts +++ b/packages/twenty-server/src/engine/twenty-orm/twenty-orm-core.module.ts @@ -7,10 +7,6 @@ import { Provider, Type, } from '@nestjs/common'; -import { - ConfigurableModuleClass, - MODULE_OPTIONS_TOKEN, -} from '@nestjs/common/cache/cache.module-definition'; import { importClassesFromDirectories } from 'typeorm/util/DirectoryExportedClassesLoader'; import { Logger as TypeORMLogger } from 'typeorm/logger/Logger'; @@ -30,12 +26,25 @@ import { ScopedWorkspaceDatasourceFactory } from 'src/engine/twenty-orm/factorie import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity'; import { splitClassesAndStrings } from 'src/engine/twenty-orm/utils/split-classes-and-strings.util'; import { CustomWorkspaceEntity } from 'src/engine/twenty-orm/custom.workspace-entity'; +import { + ConfigurableModuleClass, + MODULE_OPTIONS_TOKEN, +} from 'src/engine/twenty-orm/twenty-orm.module-definition'; +import { LoadServiceWithWorkspaceContext } from 'src/engine/twenty-orm/context/load-service-with-workspace.context'; @Global() @Module({ imports: [DataSourceModule], - providers: [...entitySchemaFactories, TwentyORMManager], - exports: [EntitySchemaFactory, TwentyORMManager], + providers: [ + ...entitySchemaFactories, + TwentyORMManager, + LoadServiceWithWorkspaceContext, + ], + exports: [ + EntitySchemaFactory, + TwentyORMManager, + LoadServiceWithWorkspaceContext, + ], }) export class TwentyORMCoreModule extends ConfigurableModuleClass @@ -46,7 +55,6 @@ export class TwentyORMCoreModule static register(options: TwentyORMOptions): DynamicModule { const dynamicModule = super.register(options); - console.log('register', options); const providers: Provider[] = [ { provide: TWENTY_ORM_WORKSPACE_DATASOURCE, diff --git a/packages/twenty-server/src/engine/twenty-orm/twenty-orm.manager.ts b/packages/twenty-server/src/engine/twenty-orm/twenty-orm.manager.ts index caaa4c21646d..668379a0aa51 100644 --- a/packages/twenty-server/src/engine/twenty-orm/twenty-orm.manager.ts +++ b/packages/twenty-server/src/engine/twenty-orm/twenty-orm.manager.ts @@ -1,19 +1,46 @@ -import { Injectable, Type } from '@nestjs/common'; +import { Injectable, Optional, Type } from '@nestjs/common'; import { ObjectLiteral } from 'typeorm'; -import { EntitySchemaFactory } from 'src/engine/twenty-orm/factories/entity-schema.factory'; -import { InjectWorkspaceDatasource } from 'src/engine/twenty-orm/decorators/inject-workspace-datasource.decorator'; import { WorkspaceDataSource } from 'src/engine/twenty-orm/datasource/workspace.datasource'; -import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository'; +import { EntitySchemaFactory } from 'src/engine/twenty-orm/factories/entity-schema.factory'; import { WorkspaceDatasourceFactory } from 'src/engine/twenty-orm/factories/workspace-datasource.factory'; -import { ObjectLiteralStorage } from 'src/engine/twenty-orm/storage/object-literal.storage'; +import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository'; +import { ActivityTargetWorkspaceEntity } from 'src/modules/activity/standard-objects/activity-target.workspace-entity'; +import { ActivityWorkspaceEntity } from 'src/modules/activity/standard-objects/activity.workspace-entity'; +import { CommentWorkspaceEntity } from 'src/modules/activity/standard-objects/comment.workspace-entity'; +import { ApiKeyWorkspaceEntity } from 'src/modules/api-key/standard-objects/api-key.workspace-entity'; +import { AttachmentWorkspaceEntity } from 'src/modules/attachment/standard-objects/attachment.workspace-entity'; +import { BlocklistWorkspaceEntity } from 'src/modules/blocklist/standard-objects/blocklist.workspace-entity'; +import { CalendarChannelEventAssociationWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-channel-event-association.workspace-entity'; +import { CalendarChannelWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-channel.workspace-entity'; +import { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-event-participant.workspace-entity'; +import { CalendarEventWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-event.workspace-entity'; +import { CompanyWorkspaceEntity } from 'src/modules/company/standard-objects/company.workspace-entity'; +import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; +import { FavoriteWorkspaceEntity } from 'src/modules/favorite/standard-objects/favorite.workspace-entity'; +import { MessageChannelMessageAssociationWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel-message-association.workspace-entity'; +import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity'; +import { MessageParticipantWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-participant.workspace-entity'; +import { MessageThreadWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-thread.workspace-entity'; +import { MessageWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message.workspace-entity'; +import { OpportunityWorkspaceEntity } from 'src/modules/opportunity/standard-objects/opportunity.workspace-entity'; +import { PersonWorkspaceEntity } from 'src/modules/person/standard-objects/person.workspace-entity'; +import { AuditLogWorkspaceEntity } from 'src/modules/timeline/standard-objects/audit-log.workspace-entity'; +import { BehavioralEventWorkspaceEntity } from 'src/modules/timeline/standard-objects/behavioral-event.workspace-entity'; +import { TimelineActivityWorkspaceEntity } from 'src/modules/timeline/standard-objects/timeline-activity.workspace-entity'; +import { ViewFieldWorkspaceEntity } from 'src/modules/view/standard-objects/view-field.workspace-entity'; +import { ViewFilterWorkspaceEntity } from 'src/modules/view/standard-objects/view-filter.workspace-entity'; +import { ViewSortWorkspaceEntity } from 'src/modules/view/standard-objects/view-sort.workspace-entity'; +import { ViewWorkspaceEntity } from 'src/modules/view/standard-objects/view.workspace-entity'; +import { WebhookWorkspaceEntity } from 'src/modules/webhook/standard-objects/webhook.workspace-entity'; +import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; @Injectable() export class TwentyORMManager { constructor( - @InjectWorkspaceDatasource() - private readonly workspaceDataSource: WorkspaceDataSource, + @Optional() + private readonly workspaceDataSource: WorkspaceDataSource | null, private readonly entitySchemaFactory: EntitySchemaFactory, private readonly workspaceDataSourceFactory: WorkspaceDatasourceFactory, ) {} @@ -23,6 +50,10 @@ export class TwentyORMManager { ): WorkspaceRepository<T> { const entitySchema = this.entitySchemaFactory.create(entityClass); + if (!this.workspaceDataSource) { + throw new Error('Workspace data source not found'); + } + return this.workspaceDataSource.getRepository<T>(entitySchema); } @@ -30,11 +61,52 @@ export class TwentyORMManager { workspaceId: string, entityClass: Type<T>, ): Promise<WorkspaceRepository<T>> { - const entities = ObjectLiteralStorage.getAllEntitySchemas(); + // TODO: This is a temporary solution to get all workspace entities + const workspaceEntities = [ + ActivityTargetWorkspaceEntity, + ActivityWorkspaceEntity, + ApiKeyWorkspaceEntity, + AttachmentWorkspaceEntity, + BlocklistWorkspaceEntity, + BehavioralEventWorkspaceEntity, + CalendarChannelEventAssociationWorkspaceEntity, + CalendarChannelWorkspaceEntity, + CalendarEventParticipantWorkspaceEntity, + CalendarEventWorkspaceEntity, + CommentWorkspaceEntity, + CompanyWorkspaceEntity, + ConnectedAccountWorkspaceEntity, + FavoriteWorkspaceEntity, + AuditLogWorkspaceEntity, + MessageChannelMessageAssociationWorkspaceEntity, + MessageChannelWorkspaceEntity, + MessageParticipantWorkspaceEntity, + MessageThreadWorkspaceEntity, + MessageWorkspaceEntity, + OpportunityWorkspaceEntity, + PersonWorkspaceEntity, + TimelineActivityWorkspaceEntity, + ViewFieldWorkspaceEntity, + ViewFilterWorkspaceEntity, + ViewSortWorkspaceEntity, + ViewWorkspaceEntity, + WebhookWorkspaceEntity, + WorkspaceMemberWorkspaceEntity, + ]; + + const entities = workspaceEntities.map((workspaceEntity) => + this.entitySchemaFactory.create(workspaceEntity as any), + ); + const workspaceDataSource = await this.workspaceDataSourceFactory.create( entities, workspaceId, ); + + if (!workspaceDataSource) { + throw new Error('Workspace data source not found'); + } + const entitySchema = this.entitySchemaFactory.create(entityClass); return workspaceDataSource.getRepository<T>(entitySchema); diff --git a/packages/twenty-server/src/engine/twenty-orm/twenty-orm.module.ts b/packages/twenty-server/src/engine/twenty-orm/twenty-orm.module.ts index 3cf38e38c3f0..cd94d01298c4 100644 --- a/packages/twenty-server/src/engine/twenty-orm/twenty-orm.module.ts +++ b/packages/twenty-server/src/engine/twenty-orm/twenty-orm.module.ts @@ -1,5 +1,4 @@ import { DynamicModule, Global, Module } from '@nestjs/common'; -import { ConfigurableModuleClass } from '@nestjs/common/cache/cache.module-definition'; import { EntityClassOrSchema } from '@nestjs/typeorm/dist/interfaces/entity-class-or-schema.type'; import { @@ -12,7 +11,7 @@ import { TwentyORMCoreModule } from 'src/engine/twenty-orm/twenty-orm-core.modul @Global() @Module({}) -export class TwentyORMModule extends ConfigurableModuleClass { +export class TwentyORMModule { static register(options: TwentyORMOptions): DynamicModule { return { module: TwentyORMModule, diff --git a/packages/twenty-server/src/engine/twenty-orm/utils/get-join-column.util.ts b/packages/twenty-server/src/engine/twenty-orm/utils/get-join-column.util.ts new file mode 100644 index 000000000000..a328b5a3f6b4 --- /dev/null +++ b/packages/twenty-server/src/engine/twenty-orm/utils/get-join-column.util.ts @@ -0,0 +1,87 @@ +import { WorkspaceJoinColumnsMetadataArgs } from 'src/engine/twenty-orm/interfaces/workspace-join-columns-metadata-args.interface'; +import { WorkspaceRelationMetadataArgs } from 'src/engine/twenty-orm/interfaces/workspace-relation-metadata-args.interface'; + +import { RelationMetadataType } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity'; +import { metadataArgsStorage } from 'src/engine/twenty-orm/storage/metadata-args.storage'; + +export const getJoinColumn = ( + joinColumnsMetadataArgsCollection: WorkspaceJoinColumnsMetadataArgs[], + relationMetadataArgs: WorkspaceRelationMetadataArgs, + opposite = false, +): string | null => { + if ( + relationMetadataArgs.type === RelationMetadataType.ONE_TO_MANY || + relationMetadataArgs.type === RelationMetadataType.MANY_TO_MANY + ) { + return null; + } + + const inverseSideTarget = relationMetadataArgs.inverseSideTarget(); + const inverseSideJoinColumnsMetadataArgsCollection = + metadataArgsStorage.filterJoinColumns(inverseSideTarget); + const filteredJoinColumnsMetadataArgsCollection = + joinColumnsMetadataArgsCollection.filter( + (joinColumnsMetadataArgs) => + joinColumnsMetadataArgs.relationName === relationMetadataArgs.name, + ); + const oppositeFilteredJoinColumnsMetadataArgsCollection = + inverseSideJoinColumnsMetadataArgsCollection.filter( + (joinColumnsMetadataArgs) => + joinColumnsMetadataArgs.relationName === relationMetadataArgs.name, + ); + + if ( + filteredJoinColumnsMetadataArgsCollection.length > 0 && + oppositeFilteredJoinColumnsMetadataArgsCollection.length > 0 + ) { + throw new Error( + `Join column for ${relationMetadataArgs.name} relation is present on both sides`, + ); + } + + // If we're in a ONE_TO_ONE relation and there are no join columns, we need to find the join column on the inverse side + if ( + relationMetadataArgs.type === RelationMetadataType.ONE_TO_ONE && + filteredJoinColumnsMetadataArgsCollection.length === 0 && + !opposite + ) { + const inverseSideRelationMetadataArgsCollection = + metadataArgsStorage.filterRelations(inverseSideTarget); + const inverseSideRelationMetadataArgs = + inverseSideRelationMetadataArgsCollection.find( + (inverseSideRelationMetadataArgs) => + inverseSideRelationMetadataArgs.inverseSideFieldKey === + relationMetadataArgs.name, + ); + + if (!inverseSideRelationMetadataArgs) { + throw new Error( + `Inverse side join column of relation ${relationMetadataArgs.name} is missing`, + ); + } + + return getJoinColumn( + inverseSideJoinColumnsMetadataArgsCollection, + inverseSideRelationMetadataArgs, + // Avoid infinite recursion + true, + ); + } + + // Check if there are multiple join columns for the relation + if (filteredJoinColumnsMetadataArgsCollection.length > 1) { + throw new Error( + `Multiple join columns found for relation ${relationMetadataArgs.name}`, + ); + } + + const joinColumnsMetadataArgs = filteredJoinColumnsMetadataArgsCollection[0]; + + if (!joinColumnsMetadataArgs) { + throw new Error( + `Join column is missing for relation ${relationMetadataArgs.name}`, + ); + } + + return joinColumnsMetadataArgs.joinColumn; +}; diff --git a/packages/twenty-server/src/engine/utils/global-exception-handler.util.ts b/packages/twenty-server/src/engine/utils/global-exception-handler.util.ts index 326f991bb401..7bb281278a9b 100644 --- a/packages/twenty-server/src/engine/utils/global-exception-handler.util.ts +++ b/packages/twenty-server/src/engine/utils/global-exception-handler.util.ts @@ -7,13 +7,14 @@ import { ExceptionHandlerUser } from 'src/engine/integrations/exception-handler/ import { AuthenticationError, BaseGraphQLError, - ForbiddenError, - ValidationError, - NotFoundError, ConflictError, + ErrorCode, + ForbiddenError, MethodNotAllowedError, + NotFoundError, TimeoutError, -} from 'src/engine/utils/graphql-errors.util'; + ValidationError, +} from 'src/engine/core-modules/graphql/utils/graphql-errors.util'; import { ExceptionHandlerService } from 'src/engine/integrations/exception-handler/exception-handler.service'; const graphQLPredefinedExceptions = { @@ -26,6 +27,17 @@ const graphQLPredefinedExceptions = { 409: ConflictError, }; +export const graphQLErrorCodesToFilter = [ + ErrorCode.GRAPHQL_VALIDATION_FAILED, + ErrorCode.UNAUTHENTICATED, + ErrorCode.FORBIDDEN, + ErrorCode.NOT_FOUND, + ErrorCode.METHOD_NOT_ALLOWED, + ErrorCode.TIMEOUT, + ErrorCode.CONFLICT, + ErrorCode.BAD_USER_INPUT, +]; + export const handleExceptionAndConvertToGraphQLError = ( exception: Error, exceptionHandlerService: ExceptionHandlerService, @@ -43,6 +55,14 @@ export const shouldFilterException = (exception: Error): boolean => { ) { return true; } + + if ( + exception instanceof BaseGraphQLError && + graphQLErrorCodesToFilter.includes(exception?.extensions?.code) + ) { + return true; + } + if (exception instanceof HttpException && exception.getStatus() < 500) { return true; } @@ -50,7 +70,7 @@ export const shouldFilterException = (exception: Error): boolean => { return false; }; -export const handleException = ( +const handleException = ( exception: Error, exceptionHandlerService: ExceptionHandlerService, user?: ExceptionHandlerUser, @@ -68,11 +88,14 @@ export const convertExceptionToGraphQLError = ( if (exception instanceof HttpException) { return convertHttpExceptionToGraphql(exception); } + if (exception instanceof BaseGraphQLError) { + return exception; + } return convertExceptionToGraphql(exception); }; -export const convertHttpExceptionToGraphql = (exception: HttpException) => { +const convertHttpExceptionToGraphql = (exception: HttpException) => { const status = exception.getStatus(); let error: BaseGraphQLError; @@ -97,7 +120,10 @@ export const convertHttpExceptionToGraphql = (exception: HttpException) => { }; export const convertExceptionToGraphql = (exception: Error) => { - const error = new BaseGraphQLError(exception.name, 'INTERNAL_SERVER_ERROR'); + const error = new BaseGraphQLError( + exception.name, + ErrorCode.INTERNAL_SERVER_ERROR, + ); error.stack = exception.stack; error.extensions['response'] = exception.message; diff --git a/packages/twenty-server/src/engine/workspace-manager/demo-objects-prefill-data/companies-demo.json.ts b/packages/twenty-server/src/engine/workspace-manager/demo-objects-prefill-data/companies-demo.json.ts index 32a29ab1609a..258d4d6730f0 100644 --- a/packages/twenty-server/src/engine/workspace-manager/demo-objects-prefill-data/companies-demo.json.ts +++ b/packages/twenty-server/src/engine/workspace-manager/demo-objects-prefill-data/companies-demo.json.ts @@ -2,532 +2,532 @@ export const companiesDemo = [ { name: 'Google', domainName: 'goo.gle', - address: 'Mountain View', + addressAddressCity: 'Mountain View', employees: 284571, linkedinLinkUrl: 'https://linkedin.com/company/google', }, { name: 'Microsoft', domainName: 'microsoft.com', - address: 'Redmond', + addressAddressCity: 'Redmond', employees: 226067, linkedinLinkUrl: 'https://linkedin.com/company/microsoft', }, { name: 'Meta', domainName: 'metacareers.com', - address: 'Menlo Park', + addressAddressCity: 'Menlo Park', employees: 119511, linkedinLinkUrl: 'https://linkedin.com/company/meta', }, { name: 'SLB', domainName: 'slb.com', - address: 'Houston', + addressAddressCity: 'Houston', employees: 113151, linkedinLinkUrl: 'https://linkedin.com/company/slbglobal', }, { name: 'Cisco', domainName: 'cisco.com', - address: 'San Jose', + addressAddressCity: 'San Jose', employees: 99625, linkedinLinkUrl: 'https://linkedin.com/company/cisco', }, { name: 'Uber', domainName: 'uber.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 90545, linkedinLinkUrl: 'https://linkedin.com/company/uber-com', }, { name: 'Salesforce', domainName: 'salesforce.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 71322, linkedinLinkUrl: 'https://linkedin.com/company/salesforce', }, { name: 'Amdocs', domainName: 'amdocs.com', - address: 'Chesterfield', + addressAddressCity: 'Chesterfield', employees: 35731, linkedinLinkUrl: 'https://linkedin.com/company/amdocs', }, { name: 'VMware', domainName: 'vmware.com', - address: 'Palo Alto', + addressAddressCity: 'Palo Alto', employees: 34759, linkedinLinkUrl: 'https://linkedin.com/company/vmware', }, { name: 'GlobalLogic', domainName: 'globallogic.com', - address: 'Santa Clara', + addressAddressCity: 'Santa Clara', employees: 24461, linkedinLinkUrl: 'https://linkedin.com/company/globallogic', }, { name: 'ServiceNow', domainName: 'servicenow.com', - address: 'Santa Clara', + addressAddressCity: 'Santa Clara', employees: 24104, linkedinLinkUrl: 'https://linkedin.com/company/servicenow', }, { name: 'SS&C Technologies', domainName: 'ssctech.com', - address: 'Windsor', + addressAddressCity: 'Windsor', employees: 20311, linkedinLinkUrl: 'https://linkedin.com/company/ss-c-technologies', }, { name: 'Workday', domainName: 'workday.com', - address: 'Pleasanton', + addressAddressCity: 'Pleasanton', employees: 20036, linkedinLinkUrl: 'https://linkedin.com/company/workday', }, { name: 'Red Hat', domainName: 'redhat.com', - address: 'Raleigh', + addressAddressCity: 'Raleigh', employees: 19945, linkedinLinkUrl: 'https://linkedin.com/company/red-hat', }, { name: 'NetSuite', domainName: 'netsuite.com', - address: 'Austin', + addressAddressCity: 'Austin', employees: 19269, linkedinLinkUrl: 'https://linkedin.com/company/netsuite', }, { name: 'Synopsys Inc', domainName: 'synopsys.com', - address: 'Sunnyvale', + addressAddressCity: 'Sunnyvale', employees: 18061, linkedinLinkUrl: 'https://linkedin.com/company/synopsys', }, { name: 'Siemens Digital Industries Software', domainName: 'sw.siemens.com', - address: 'Plano', + addressAddressCity: 'Plano', employees: 17262, linkedinLinkUrl: 'https://linkedin.com/company/siemenssoftware', }, { name: 'SAS', domainName: 'sas.com', - address: 'Cary', + addressAddressCity: 'Cary', employees: 16287, linkedinLinkUrl: 'https://linkedin.com/company/sas', }, { name: 'Intuit', domainName: 'intuit.com', - address: 'Mountain View', + addressAddressCity: 'Mountain View', employees: 15851, linkedinLinkUrl: 'https://linkedin.com/company/intuit', }, { name: 'Broadcom Software', domainName: 'broadcom.com', - address: 'San Jose', + addressAddressCity: 'San Jose', employees: 15127, linkedinLinkUrl: 'https://linkedin.com/company/broadcomsoftware', }, { name: 'Autodesk', domainName: 'autodesk.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 14593, linkedinLinkUrl: 'https://linkedin.com/company/autodesk', }, { name: 'Epic', domainName: 'epic.com', - address: 'Verona', + addressAddressCity: 'Verona', employees: 13765, linkedinLinkUrl: 'https://linkedin.com/company/epic1979', }, { name: 'Bosch USA', domainName: 'bosch.us', - address: 'Farmington', + addressAddressCity: 'Farmington', employees: 13754, linkedinLinkUrl: 'https://linkedin.com/company/boschusa', }, { name: 'Cloud Software Group', domainName: 'cloudsoftwaregroup.com', - address: 'Fort Lauderdale', + addressAddressCity: 'Fort Lauderdale', employees: 13111, linkedinLinkUrl: 'https://linkedin.com/company/cloudsoftwaregroup', }, { name: 'Pitney Bowes', domainName: 'pitneybowes.com', - address: 'Stamford', + addressAddressCity: 'Stamford', employees: 12306, linkedinLinkUrl: 'https://linkedin.com/company/pitney-bowes', }, { name: 'Juniper Networks', domainName: 'juniper.net', - address: 'Sunnyvale', + addressAddressCity: 'Sunnyvale', employees: 11928, linkedinLinkUrl: 'https://linkedin.com/company/juniper-networks', }, { name: 'Chegg Inc.', domainName: 'chegg.com', - address: 'Santa Clara', + addressAddressCity: 'Santa Clara', employees: 10790, linkedinLinkUrl: 'https://linkedin.com/company/chegg-inc-', }, { name: 'Teradata', domainName: 'teradata.com', - address: 'San Diego', + addressAddressCity: 'San Diego', employees: 10748, linkedinLinkUrl: 'https://linkedin.com/company/teradata', }, { name: 'NICE', domainName: 'nice.com', - address: 'Hoboken', + addressAddressCity: 'Hoboken', employees: 10258, linkedinLinkUrl: 'https://linkedin.com/company/nice-systems', }, { name: 'Cadence Design Systems', domainName: 'cadence.com', - address: 'San Jose', + addressAddressCity: 'San Jose', employees: 9377, linkedinLinkUrl: 'https://linkedin.com/company/cadence-design-systems', }, { name: 'Cox Automotive Inc.', domainName: 'coxautoinc.com', - address: 'Atlanta', + addressAddressCity: 'Atlanta', employees: 9331, linkedinLinkUrl: 'https://linkedin.com/company/cox-automotive-inc-', }, { name: 'Trimble Inc.', domainName: 'trimble.com', - address: 'Broomfield', + addressAddressCity: 'Broomfield', employees: 9311, linkedinLinkUrl: 'https://linkedin.com/company/trimble', }, { name: '[24]7.ai', domainName: '247.ai', - address: 'San Jose', + addressAddressCity: 'San Jose', employees: 9170, linkedinLinkUrl: 'https://linkedin.com/company/24-7-ai', }, { name: 'Akamai Technologies', domainName: 'akamai.com', - address: 'Cambridge', + addressAddressCity: 'Cambridge', employees: 9168, linkedinLinkUrl: 'https://linkedin.com/company/akamai-technologies', }, { name: 'Splunk', domainName: 'splunk.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 8891, linkedinLinkUrl: 'https://linkedin.com/company/splunk', }, { name: 'Okta', domainName: 'okta.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 8860, linkedinLinkUrl: 'https://linkedin.com/company/okta-inc-', }, { name: 'Ceridian', domainName: 'ceridian.com', - address: 'Minneapolis', + addressAddressCity: 'Minneapolis', employees: 8813, linkedinLinkUrl: 'https://linkedin.com/company/ceridian', }, { name: 'RealPage, Inc.', domainName: 'realpage.com', - address: 'Richardson', + addressAddressCity: 'Richardson', employees: 8227, linkedinLinkUrl: 'https://linkedin.com/company/realpage', }, { name: 'Freelance', domainName: 'jobicy.com', - address: 'Ny', + addressAddressCity: 'Ny', employees: 8180, linkedinLinkUrl: 'https://linkedin.com/company/pro-freelance', }, { name: 'Stripe', domainName: 'stripe.com', - address: 'South San Francisco', + addressAddressCity: 'South San Francisco', employees: 8145, linkedinLinkUrl: 'https://linkedin.com/company/stripe', }, { name: 'Shutterfly', domainName: 'shutterflyinc.com', - address: 'San Jose', + addressAddressCity: 'San Jose', employees: 8070, linkedinLinkUrl: 'https://linkedin.com/company/shutterfly', }, { name: 'Unity', domainName: 'unity.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 8063, linkedinLinkUrl: 'https://linkedin.com/company/unity', }, { name: 'Veeva Systems', domainName: 'veeva.com', - address: 'Pleasanton', + addressAddressCity: 'Pleasanton', employees: 7831, linkedinLinkUrl: 'https://linkedin.com/company/veeva-systems', }, { name: 'Nuance Communications', domainName: 'nuance.com', - address: 'Burlington', + addressAddressCity: 'Burlington', employees: 7761, linkedinLinkUrl: 'https://linkedin.com/company/nuance-communications', }, { name: 'Freshworks', domainName: 'freshworks.com', - address: 'San Mateo', + addressAddressCity: 'San Mateo', employees: 7687, linkedinLinkUrl: 'https://linkedin.com/company/freshworks-inc', }, { name: 'Seal Software, a DocuSign Company', domainName: 'seal-software.com', - address: 'Walnut Creek', + addressAddressCity: 'Walnut Creek', employees: 7586, linkedinLinkUrl: 'https://linkedin.com/company/seal-software-group', }, { name: 'DocuSign', domainName: 'docusign.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 7557, linkedinLinkUrl: 'https://linkedin.com/company/docusign', }, { name: 'Nutanix', domainName: 'nutanix.com', - address: 'San Jose', + addressAddressCity: 'San Jose', employees: 7454, linkedinLinkUrl: 'https://linkedin.com/company/nutanix', }, { name: 'Genesys', domainName: 'genesys.com', - address: 'Menlo Park', + addressAddressCity: 'Menlo Park', employees: 7371, linkedinLinkUrl: 'https://linkedin.com/company/genesys', }, { name: 'SAP Concur', domainName: 'concur.com', - address: 'Bellevue', + addressAddressCity: 'Bellevue', employees: 7305, linkedinLinkUrl: 'https://linkedin.com/company/sapconcur', }, { name: 'Square', domainName: 'squareup.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 7233, linkedinLinkUrl: 'https://linkedin.com/company/joinsquare', }, { name: 'Snap Inc.', domainName: 'snap.com', - address: 'Santa Monica', + addressAddressCity: 'Santa Monica', employees: 7219, linkedinLinkUrl: 'https://linkedin.com/company/snap-inc-co', }, { name: 'MathWorks', domainName: 'mathworks.com', - address: 'Natick', + addressAddressCity: 'Natick', employees: 7188, linkedinLinkUrl: 'https://linkedin.com/company/the-mathworks_2', }, { name: 'PTC', domainName: 'ptc.co', - address: 'Boston', + addressAddressCity: 'Boston', employees: 7119, linkedinLinkUrl: 'https://linkedin.com/company/ptcinc', }, { name: 'Ansys', domainName: 'ansys.com', - address: 'Canonsburg', + addressAddressCity: 'Canonsburg', employees: 7112, linkedinLinkUrl: 'https://linkedin.com/company/ansys-inc', }, { name: 'Aricent', domainName: 'altran.com', - address: 'Santa Clara', + addressAddressCity: 'Santa Clara', employees: 7016, linkedinLinkUrl: 'https://linkedin.com/company/aricent', }, { name: 'Databricks', domainName: 'databricks.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 6927, linkedinLinkUrl: 'https://linkedin.com/company/databricks', }, { name: 'Shipt', domainName: 'shipt.com', - address: 'Birmingham', + addressAddressCity: 'Birmingham', employees: 6902, linkedinLinkUrl: 'https://linkedin.com/company/shipt', }, { name: 'CSG', domainName: 'csgi.com', - address: 'Englewood', + addressAddressCity: 'Englewood', employees: 6849, linkedinLinkUrl: 'https://linkedin.com/company/csg-', }, { name: 'Twilio', domainName: 'twilio.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 6721, linkedinLinkUrl: 'https://linkedin.com/company/twilio-inc-', }, { name: 'Veritas Technologies LLC', domainName: 'veritas.com', - address: 'Santa Clara', + addressAddressCity: 'Santa Clara', employees: 6718, linkedinLinkUrl: 'https://linkedin.com/company/veritas-technologies-llc', }, { name: 'Citrix', domainName: 'citrix.com', - address: 'Fort Lauderdale', + addressAddressCity: 'Fort Lauderdale', employees: 6528, linkedinLinkUrl: 'https://linkedin.com/company/citrix', }, { name: 'Tyler Technologies', domainName: 'tylertech.com', - address: 'Plano', + addressAddressCity: 'Plano', employees: 6496, linkedinLinkUrl: 'https://linkedin.com/company/tyler-technologies', }, { name: 'Esri', domainName: 'esri.com', - address: 'Redlands', + addressAddressCity: 'Redlands', employees: 6463, linkedinLinkUrl: 'https://linkedin.com/company/esri', }, { name: 'Paycom', domainName: 'paycom.com', - address: 'Oklahoma City', + addressAddressCity: 'Oklahoma City', employees: 6378, linkedinLinkUrl: 'https://linkedin.com/company/paycom', }, { name: 'Roblox', domainName: 'roblox.com', - address: 'San Mateo', + addressAddressCity: 'San Mateo', employees: 6297, linkedinLinkUrl: 'https://linkedin.com/company/roblox', }, { name: 'Zendesk', domainName: 'zendesk.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 6255, linkedinLinkUrl: 'https://linkedin.com/company/zendesk', }, { name: 'Newfold Digital', domainName: 'newfold.com', - address: 'Jacksonville', + addressAddressCity: 'Jacksonville', employees: 6213, linkedinLinkUrl: 'https://linkedin.com/company/newfold', }, { name: 'Informatica', domainName: 'informatica.com', - address: 'Redwood City', + addressAddressCity: 'Redwood City', employees: 5850, linkedinLinkUrl: 'https://linkedin.com/company/informatica', }, { name: 'Caf\u00e9', domainName: 'at.cafe', - address: 'New York', + addressAddressCity: 'New York', employees: 5795, linkedinLinkUrl: 'https://linkedin.com/company/get-cafe', }, { name: 'Mavenir', domainName: 'mavenir.com', - address: 'Richardson', + addressAddressCity: 'Richardson', employees: 5763, linkedinLinkUrl: 'https://linkedin.com/company/mavenir', }, { name: 'Allscripts', domainName: 'allscripts.com', - address: 'Chicago', + addressAddressCity: 'Chicago', employees: 5719, linkedinLinkUrl: 'https://linkedin.com/company/allscripts', }, { name: 'Yardi', domainName: 'yardi.com', - address: 'Goleta', + addressAddressCity: 'Goleta', employees: 5583, linkedinLinkUrl: 'https://linkedin.com/company/yardi', }, { name: 'Datadog', domainName: 'datadoghq.com', - address: 'New York', + addressAddressCity: 'New York', employees: 5470, linkedinLinkUrl: 'https://linkedin.com/company/datadog', }, { name: 'Epicor', domainName: 'epicor.com', - address: 'Austin', + addressAddressCity: 'Austin', employees: 5310, linkedinLinkUrl: 'https://linkedin.com/company/epicor-software-corp', }, { name: 'Hexagon Asset Lifecycle Intelligence', domainName: 'hexagonppm.com', - address: 'Madison', + addressAddressCity: 'Madison', employees: 5262, linkedinLinkUrl: 'https://linkedin.com/company/hexagonassetlifecycleintelligence', @@ -535,105 +535,105 @@ export const companiesDemo = [ { name: 'Blue Yonder', domainName: 'blueyonder.com', - address: 'Scottsdale', + addressAddressCity: 'Scottsdale', employees: 5205, linkedinLinkUrl: 'https://linkedin.com/company/blueyonder', }, { name: 'MongoDB', domainName: 'mongodb.com', - address: 'New York', + addressAddressCity: 'New York', employees: 5182, linkedinLinkUrl: 'https://linkedin.com/company/mongodbinc', }, { name: 'uTest', domainName: 'utest.com', - address: 'Framingham', + addressAddressCity: 'Framingham', employees: 5125, linkedinLinkUrl: 'https://linkedin.com/company/utest', }, { name: 'Paylocity', domainName: 'paylocity.com', - address: 'Schaumburg', + addressAddressCity: 'Schaumburg', employees: 5095, linkedinLinkUrl: 'https://linkedin.com/company/paylocity', }, { name: 'IAC', domainName: 'iac.com', - address: 'New York', + addressAddressCity: 'New York', employees: 5040, linkedinLinkUrl: 'https://linkedin.com/company/iac', }, { name: 'Toast', domainName: 'toasttab.com', - address: 'Boston', + addressAddressCity: 'Boston', employees: 5008, linkedinLinkUrl: 'https://linkedin.com/company/toast-inc', }, { name: 'Bentley Systems', domainName: 'bentley.com', - address: 'Exton', + addressAddressCity: 'Exton', employees: 4862, linkedinLinkUrl: 'https://linkedin.com/company/bentley-systems', }, { name: 'Owner.com', domainName: 'owner.com', - address: 'Palo Alto', + addressAddressCity: 'Palo Alto', employees: 4677, linkedinLinkUrl: 'https://linkedin.com/company/profitboss', }, { name: 'eClinicalWorks', domainName: 'eclinicalworks.com', - address: 'Westborough', + addressAddressCity: 'Westborough', employees: 4661, linkedinLinkUrl: 'https://linkedin.com/company/eclinicalworks', }, { name: 'Altimetrik', domainName: 'altimetrik.com', - address: 'Southfield', + addressAddressCity: 'Southfield', employees: 4629, linkedinLinkUrl: 'https://linkedin.com/company/altimetrik', }, { name: 'CA Technologies', domainName: 'ca.com', - address: 'San Jose', + addressAddressCity: 'San Jose', employees: 4616, linkedinLinkUrl: 'https://linkedin.com/company/ca-technologies', }, { name: 'Dynatrace', domainName: 'dynatrace.com', - address: 'Waltham', + addressAddressCity: 'Waltham', employees: 4502, linkedinLinkUrl: 'https://linkedin.com/company/dynatrace', }, { name: 'Sprinklr', domainName: 'sprinklr.com', - address: 'New York', + addressAddressCity: 'New York', employees: 4495, linkedinLinkUrl: 'https://linkedin.com/company/sprinklr', }, { name: 'UiPath', domainName: 'uipath.com', - address: 'New York', + addressAddressCity: 'New York', employees: 4484, linkedinLinkUrl: 'https://linkedin.com/company/uipath', }, { name: 'The Reynolds and Reynolds Company', domainName: 'reyrey.com', - address: 'Dayton', + addressAddressCity: 'Dayton', employees: 4473, linkedinLinkUrl: 'https://linkedin.com/company/the-reynolds-and-reynolds-company', @@ -641,679 +641,679 @@ export const companiesDemo = [ { name: 'Stealth', domainName: 'stealthstartup.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 4472, linkedinLinkUrl: 'https://linkedin.com/company/stealthstartup', }, { name: 'WEX', domainName: 'wexinc.com', - address: 'Portland', + addressAddressCity: 'Portland', employees: 4377, linkedinLinkUrl: 'https://linkedin.com/company/wexinc', }, { name: 'HighRadius', domainName: 'highradius.com', - address: 'Houston', + addressAddressCity: 'Houston', employees: 4316, linkedinLinkUrl: 'https://linkedin.com/company/highradius', }, { name: 'Avalara', domainName: 'avalara.com', - address: 'Seattle', + addressAddressCity: 'Seattle', employees: 4311, linkedinLinkUrl: 'https://linkedin.com/company/avalara', }, { name: 'Manhattan Associates', domainName: 'manh.com', - address: 'Atlanta', + addressAddressCity: 'Atlanta', employees: 4236, linkedinLinkUrl: 'https://linkedin.com/company/manhattan-associates', }, { name: 'Aspen Technology', domainName: 'aspentech.com', - address: 'Bedford', + addressAddressCity: 'Bedford', employees: 4194, linkedinLinkUrl: 'https://linkedin.com/company/aspen-technology', }, { name: 'Hyland', domainName: 'hyland.com', - address: 'Westlake', + addressAddressCity: 'Westlake', employees: 4166, linkedinLinkUrl: 'https://linkedin.com/company/hyland-software', }, { name: 'Palantir Technologies', domainName: 'palantir.com', - address: 'Denver', + addressAddressCity: 'Denver', employees: 4104, linkedinLinkUrl: 'https://linkedin.com/company/palantir-technologies', }, { name: 'Market America, Inc.', domainName: 'marketamerica.com', - address: 'Greensboro', + addressAddressCity: 'Greensboro', employees: 4091, linkedinLinkUrl: 'https://linkedin.com/company/market-america-inc-', }, { name: 'Procore Technologies', domainName: 'procore.com', - address: 'Carpinteria', + addressAddressCity: 'Carpinteria', employees: 4010, linkedinLinkUrl: 'https://linkedin.com/company/procore-technologies', }, { name: 'ZoomInfo', domainName: 'zoominfo.com', - address: 'Vancouver', + addressAddressCity: 'Vancouver', employees: 3875, linkedinLinkUrl: 'https://linkedin.com/company/zoominfo', }, { name: 'TIBCO', domainName: 'tibco.com', - address: 'Palo Alto', + addressAddressCity: 'Palo Alto', employees: 3871, linkedinLinkUrl: 'https://linkedin.com/company/tibco', }, { name: 'GE Digital', domainName: 'ge.com', - address: 'San Ramon', + addressAddressCity: 'San Ramon', employees: 3849, linkedinLinkUrl: 'https://linkedin.com/company/ge-digital', }, { name: 'RMS', domainName: 'rms.com', - address: 'Newark', + addressAddressCity: 'Newark', employees: 3844, linkedinLinkUrl: 'https://linkedin.com/company/rms', }, { name: 'Tableau', domainName: 'tableau.com', - address: 'Seattle', + addressAddressCity: 'Seattle', employees: 3838, linkedinLinkUrl: 'https://linkedin.com/company/tableau-software', }, { name: 'Extreme Networks', domainName: 'extremenetworks.com', - address: 'Morrisville', + addressAddressCity: 'Morrisville', employees: 3799, linkedinLinkUrl: 'https://linkedin.com/company/extreme-networks', }, { name: 'Smartsheet', domainName: 'smartsheet.com', - address: 'Bellevue', + addressAddressCity: 'Bellevue', employees: 3798, linkedinLinkUrl: 'https://linkedin.com/company/smartsheet-com', }, { name: 'Quest Software', domainName: 'quest.com', - address: 'Aliso Viejo', + addressAddressCity: 'Aliso Viejo', employees: 3795, linkedinLinkUrl: 'https://linkedin.com/company/quest-software', }, { name: 'Motive', domainName: 'gomotive.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 3788, linkedinLinkUrl: 'https://linkedin.com/company/motive-inc', }, { name: 'Retired Life', domainName: 'swde.com', - address: 'San Jose', + addressAddressCity: 'San Jose', employees: 3774, linkedinLinkUrl: 'https://linkedin.com/company/retired-life', }, { name: 'Dropbox', domainName: 'dropbox.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 3751, linkedinLinkUrl: 'https://linkedin.com/company/dropbox', }, { name: 'Deltek', domainName: 'deltek.com', - address: 'Herndon', + addressAddressCity: 'Herndon', employees: 3727, linkedinLinkUrl: 'https://linkedin.com/company/deltek', }, { name: 'e2open', domainName: 'e2open.com', - address: 'Austin', + addressAddressCity: 'Austin', employees: 3694, linkedinLinkUrl: 'https://linkedin.com/company/e2open', }, { name: 'Altair', domainName: 'altair.com', - address: 'Troy', + addressAddressCity: 'Troy', employees: 3596, linkedinLinkUrl: 'https://linkedin.com/company/altair-engineering', }, { name: 'Gopuff', domainName: 'gopuff.com', - address: 'Philadelphia', + addressAddressCity: 'Philadelphia', employees: 3574, linkedinLinkUrl: 'https://linkedin.com/company/gopuff', }, { name: 'FICO', domainName: 'fico.com', - address: 'Bozeman', + addressAddressCity: 'Bozeman', employees: 3511, linkedinLinkUrl: 'https://linkedin.com/company/fico', }, { name: 'Elastic', domainName: 'elastic.co', - address: 'Mountain View', + addressAddressCity: 'Mountain View', employees: 3489, linkedinLinkUrl: 'https://linkedin.com/company/elastic-co', }, { name: 'Blackbaud', domainName: 'blackbaud.com', - address: 'Charleston', + addressAddressCity: 'Charleston', employees: 3478, linkedinLinkUrl: 'https://linkedin.com/company/blackbaud', }, { name: 'MicroStrategy', domainName: 'microstrategy.com', - address: 'Vienna', + addressAddressCity: 'Vienna', employees: 3469, linkedinLinkUrl: 'https://linkedin.com/company/microstrategy', }, { name: 'Discord', domainName: 'discord.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 3467, linkedinLinkUrl: 'https://linkedin.com/company/discord', }, { name: 'Inovalon', domainName: 'inovalon.com', - address: 'Bowie', + addressAddressCity: 'Bowie', employees: 3459, linkedinLinkUrl: 'https://linkedin.com/company/inovalon', }, { name: 'Progress', domainName: 'progress.com', - address: 'Burlington', + addressAddressCity: 'Burlington', employees: 3428, linkedinLinkUrl: 'https://linkedin.com/company/progress-software', }, { name: 'Rubrik', domainName: 'rbrk.co', - address: 'Palo Alto', + addressAddressCity: 'Palo Alto', employees: 3370, linkedinLinkUrl: 'https://linkedin.com/company/rubrik-inc', }, { name: 'Axtria - Ingenious Insights', domainName: 'axtria.com', - address: 'Berkeley Heights', + addressAddressCity: 'Berkeley Heights', employees: 3367, linkedinLinkUrl: 'https://linkedin.com/company/axtria', }, { name: 'Audible', domainName: 'audible.com', - address: 'Newark', + addressAddressCity: 'Newark', employees: 3192, linkedinLinkUrl: 'https://linkedin.com/company/audible', }, { name: 'Kaseya', domainName: 'kaseya.com', - address: 'Miami', + addressAddressCity: 'Miami', employees: 3191, linkedinLinkUrl: 'https://linkedin.com/company/kaseya', }, { name: 'MRI Software', domainName: 'mrisoftware.com', - address: 'Solon', + addressAddressCity: 'Solon', employees: 3107, linkedinLinkUrl: 'https://linkedin.com/company/mri-software-llc', }, { name: 'CyberArk', domainName: 'cyberark.com', - address: 'Newton Center', + addressAddressCity: 'Newton Center', employees: 3099, linkedinLinkUrl: 'https://linkedin.com/company/cyber-ark-software', }, { name: 'Cornerstone OnDemand', domainName: 'cornerstoneondemand.com', - address: 'Santa Monica', + addressAddressCity: 'Santa Monica', employees: 3089, linkedinLinkUrl: 'https://linkedin.com/company/cornerstone-ondemand', }, { name: 'Reddit, Inc.', domainName: 'redditinc.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 3061, linkedinLinkUrl: 'https://linkedin.com/company/reddit-com', }, { name: 'Ivanti', domainName: 'ivanti.com', - address: 'South Jordan', + addressAddressCity: 'South Jordan', employees: 3056, linkedinLinkUrl: 'https://linkedin.com/company/ivanti', }, { name: 'Cloudera', domainName: 'cloudera.com', - address: 'Santa Clara', + addressAddressCity: 'Santa Clara', employees: 3007, linkedinLinkUrl: 'https://linkedin.com/company/cloudera', }, { name: 'Medidata Solutions', domainName: 'medidata.com', - address: 'New York', + addressAddressCity: 'New York', employees: 3001, linkedinLinkUrl: 'https://linkedin.com/company/medidata-solutions', }, { name: 'Commvault', domainName: 'commvault.com', - address: 'Eatontown', + addressAddressCity: 'Eatontown', employees: 2974, linkedinLinkUrl: 'https://linkedin.com/company/commvault', }, { name: 'ConnectWise', domainName: 'connectwise.com', - address: 'Tampa', + addressAddressCity: 'Tampa', employees: 2937, linkedinLinkUrl: 'https://linkedin.com/company/connectwise', }, { name: 'BILL', domainName: 'bill.com', - address: 'Alviso', + addressAddressCity: 'Alviso', employees: 2932, linkedinLinkUrl: 'https://linkedin.com/company/bill', }, { name: 'Alteryx', domainName: 'alteryx.com', - address: 'Irvine', + addressAddressCity: 'Irvine', employees: 2916, linkedinLinkUrl: 'https://linkedin.com/company/alteryx', }, { name: 'MNC Software', domainName: 'mncsoftware.com', - address: 'San Diego', + addressAddressCity: 'San Diego', employees: 2912, linkedinLinkUrl: 'https://linkedin.com/company/mnc-software', }, { name: 'Celonis', domainName: 'celonis.com', - address: 'New York', + addressAddressCity: 'New York', employees: 2906, linkedinLinkUrl: 'https://linkedin.com/company/celonis', }, { name: 'Attachmate', domainName: 'microfocus.com', - address: 'Seattle', + addressAddressCity: 'Seattle', employees: 2889, linkedinLinkUrl: 'https://linkedin.com/company/attachmate', }, { name: 'NETSCOUT', domainName: 'netscout.com', - address: 'Westford', + addressAddressCity: 'Westford', employees: 2853, linkedinLinkUrl: 'https://linkedin.com/company/netscout', }, { name: 'Confluent', domainName: 'confluent.io', - address: 'Mountain View', + addressAddressCity: 'Mountain View', employees: 2844, linkedinLinkUrl: 'https://linkedin.com/company/confluent', }, { name: 'Samsara', domainName: 'samsara.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 2824, linkedinLinkUrl: 'https://linkedin.com/company/samsara', }, { name: 'Chetu, Inc.', domainName: 'chetu.com', - address: 'Fort Lauderdale', + addressAddressCity: 'Fort Lauderdale', employees: 2809, linkedinLinkUrl: 'https://linkedin.com/company/chetu-inc-', }, { name: 'Kronos Incorporated', domainName: 'ukg.com', - address: 'Lowell', + addressAddressCity: 'Lowell', employees: 2808, linkedinLinkUrl: 'https://linkedin.com/company/kronos', }, { name: 'Qlik', domainName: 'qlik.com', - address: 'King Of Prussia', + addressAddressCity: 'King Of Prussia', employees: 2779, linkedinLinkUrl: 'https://linkedin.com/company/qlik', }, { name: 'Vertafore', domainName: 'vertafore.com', - address: 'Denver', + addressAddressCity: 'Denver', employees: 2768, linkedinLinkUrl: 'https://linkedin.com/company/vertafore', }, { name: 'Asana', domainName: 'asana.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 2753, linkedinLinkUrl: 'https://linkedin.com/company/asana', }, { name: 'Jamf', domainName: 'jamf.com', - address: 'Minneapolis', + addressAddressCity: 'Minneapolis', employees: 2721, linkedinLinkUrl: 'https://linkedin.com/company/jamf-software', }, { name: 'Paycor', domainName: 'paycor.com', - address: 'Cincinnati', + addressAddressCity: 'Cincinnati', employees: 2719, linkedinLinkUrl: 'https://linkedin.com/company/paycor', }, { name: 'Hudl', domainName: 'hudl.com', - address: 'Lincoln', + addressAddressCity: 'Lincoln', employees: 2709, linkedinLinkUrl: 'https://linkedin.com/company/hudl', }, { name: 'Precisely', domainName: 'precisely.com', - address: 'Burlington', + addressAddressCity: 'Burlington', employees: 2662, linkedinLinkUrl: 'https://linkedin.com/company/preciselydata', }, { name: 'New Relic', domainName: 'newrelic.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 2636, linkedinLinkUrl: 'https://linkedin.com/company/new-relic-inc-', }, { name: 'Aptean', domainName: 'aptean.com', - address: 'Alpharetta', + addressAddressCity: 'Alpharetta', employees: 2617, linkedinLinkUrl: 'https://linkedin.com/company/aptean', }, { name: 'o9 Solutions, Inc.', domainName: 'o9solutions.com', - address: 'Dallas', + addressAddressCity: 'Dallas', employees: 2612, linkedinLinkUrl: 'https://linkedin.com/company/o9solutions', }, { name: 'SpotOn', domainName: 'spoton.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 2608, linkedinLinkUrl: 'https://linkedin.com/company/spoton', }, { name: 'Automation Anywhere', domainName: 'automationanywhere.com', - address: 'San Jose', + addressAddressCity: 'San Jose', employees: 2588, linkedinLinkUrl: 'https://linkedin.com/company/automation-anywhere', }, { name: 'Tekion Corp', domainName: 'tekion.com', - address: 'Pleasanton', + addressAddressCity: 'Pleasanton', employees: 2579, linkedinLinkUrl: 'https://linkedin.com/company/tekion', }, { name: 'Aurora', domainName: 'aurora.tech', - address: 'Mountain View', + addressAddressCity: 'Mountain View', employees: 2557, linkedinLinkUrl: 'https://linkedin.com/company/aurora-inc.', }, { name: 'SolarWinds', domainName: 'solarwinds.com', - address: 'Austin', + addressAddressCity: 'Austin', employees: 2529, linkedinLinkUrl: 'https://linkedin.com/company/solarwinds', }, { name: 'GoTo', domainName: 'goto.com', - address: 'Boston', + addressAddressCity: 'Boston', employees: 2505, linkedinLinkUrl: 'https://linkedin.com/company/goto', }, { name: 'PROS', domainName: 'pros.com', - address: 'Houston', + addressAddressCity: 'Houston', employees: 2479, linkedinLinkUrl: 'https://linkedin.com/company/pros', }, { name: 'Miro', domainName: 'miro.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 2445, linkedinLinkUrl: 'https://linkedin.com/company/mirohq', }, { name: 'Kofax', domainName: 'kofax.com', - address: 'Irvine', + addressAddressCity: 'Irvine', employees: 2442, linkedinLinkUrl: 'https://linkedin.com/company/kofax', }, { name: 'Accolite Digital', domainName: 'accolite.com', - address: 'Addison', + addressAddressCity: 'Addison', employees: 2438, linkedinLinkUrl: 'https://linkedin.com/company/accolitedigital', }, { name: 'HashiCorp', domainName: 'hashicorp.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 2436, linkedinLinkUrl: 'https://linkedin.com/company/hashicorp', }, { name: 'Pluralsight', domainName: 'pluralsight.com', - address: 'Draper', + addressAddressCity: 'Draper', employees: 2433, linkedinLinkUrl: 'https://linkedin.com/company/pluralsight', }, { name: 'Bottomline Technologies', domainName: 'bottomline.com', - address: 'Portsmouth', + addressAddressCity: 'Portsmouth', employees: 2407, linkedinLinkUrl: 'https://linkedin.com/company/bottomline-technologies', }, { name: 'Anaplan', domainName: 'anaplan.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 2401, linkedinLinkUrl: 'https://linkedin.com/company/anaplan', }, { name: 'OneTrust', domainName: 'onetrust.com', - address: 'Atlanta', + addressAddressCity: 'Atlanta', employees: 2383, linkedinLinkUrl: 'https://linkedin.com/company/onetrust', }, { name: 'Medallia', domainName: 'medallia.com', - address: 'Pleasanton', + addressAddressCity: 'Pleasanton', employees: 2381, linkedinLinkUrl: 'https://linkedin.com/company/medallia-inc.', }, { name: 'SailPoint', domainName: 'sailpoint.com', - address: 'Austin', + addressAddressCity: 'Austin', employees: 2366, linkedinLinkUrl: 'https://linkedin.com/company/sailpoint-technologies', }, { name: 'Appian Corporation', domainName: 'appian.com', - address: 'Mc Lean', + addressAddressCity: 'Mc Lean', employees: 2345, linkedinLinkUrl: 'https://linkedin.com/company/appian-corporation', }, { name: 'Dealertrack', domainName: 'dealertrack.com', - address: 'New Hyde Park', + addressAddressCity: 'New Hyde Park', employees: 2335, linkedinLinkUrl: 'https://linkedin.com/company/dealertrack', }, { name: 'impact.com', domainName: 'impact.com', - address: 'Santa Barbara', + addressAddressCity: 'Santa Barbara', employees: 2327, linkedinLinkUrl: 'https://linkedin.com/company/impactdotcom', }, { name: 'Inhabit\u00ae', domainName: 'inhabitiq.com', - address: 'Knoxville', + addressAddressCity: 'Knoxville', employees: 2286, linkedinLinkUrl: 'https://linkedin.com/company/inhabit-iq', }, { name: 'SymphonyAI', domainName: 'symphonyai.com', - address: 'Palo Alto', + addressAddressCity: 'Palo Alto', employees: 2282, linkedinLinkUrl: 'https://linkedin.com/company/symphonyai', }, { name: 'CCC Intelligent Solutions', domainName: 'cccis.com', - address: 'Chicago', + addressAddressCity: 'Chicago', employees: 2282, linkedinLinkUrl: 'https://linkedin.com/company/ccc-intelligent-solutions', }, { name: 'Toshiba Global Commerce Solutions', domainName: 'toshiba.com', - address: 'Durham', + addressAddressCity: 'Durham', employees: 2281, linkedinLinkUrl: 'https://linkedin.com/company/toshibacommerce', }, { name: 'Vertex Inc.', domainName: 'vertexinc.com', - address: 'King Of Prussia', + addressAddressCity: 'King Of Prussia', employees: 2265, linkedinLinkUrl: 'https://linkedin.com/company/vertex-inc.', }, { name: 'PRO Unlimited', domainName: 'magnitglobal.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 2264, linkedinLinkUrl: 'https://linkedin.com/company/prounlimited', }, { name: 'Five9', domainName: 'five9.com', - address: 'San Ramon', + addressAddressCity: 'San Ramon', employees: 2253, linkedinLinkUrl: 'https://linkedin.com/company/five9', }, { name: 'Cohesity', domainName: 'cohesity.com', - address: 'San Jose', + addressAddressCity: 'San Jose', employees: 2252, linkedinLinkUrl: 'https://linkedin.com/company/cohesity', }, { name: 'Wind River', domainName: 'windriver.com', - address: 'Alameda', + addressAddressCity: 'Alameda', employees: 2244, linkedinLinkUrl: 'https://linkedin.com/company/wind-river', }, { name: 'Icertis', domainName: 'icertis.com', - address: 'Bellevue', + addressAddressCity: 'Bellevue', employees: 2233, linkedinLinkUrl: 'https://linkedin.com/company/icertis', }, { name: 'Navan', domainName: 'navan.com', - address: 'Palo Alto', + addressAddressCity: 'Palo Alto', employees: 2221, linkedinLinkUrl: 'https://linkedin.com/company/navan', }, { name: 'Diligent', domainName: 'diligent.com', - address: 'New York', + addressAddressCity: 'New York', employees: 2215, linkedinLinkUrl: 'https://linkedin.com/company/diligent-board-member-services', @@ -1321,35 +1321,35 @@ export const companiesDemo = [ { name: 'Applied Systems', domainName: 'appliedsystems.com', - address: 'University Park', + addressAddressCity: 'University Park', employees: 2198, linkedinLinkUrl: 'https://linkedin.com/company/applied-systems', }, { name: 'Forcepoint', domainName: 'forcepoint.com', - address: 'Austin', + addressAddressCity: 'Austin', employees: 2196, linkedinLinkUrl: 'https://linkedin.com/company/forcepoint', }, { name: 'Compuware', domainName: 'bmc.com', - address: 'Detroit', + addressAddressCity: 'Detroit', employees: 2183, linkedinLinkUrl: 'https://linkedin.com/company/compuware', }, { name: 'Netsmart', domainName: 'ntst.com', - address: 'Leawood', + addressAddressCity: 'Leawood', employees: 2177, linkedinLinkUrl: 'https://linkedin.com/company/netsmart', }, { name: 'The Apache Software Foundation', domainName: 'apache.org', - address: 'Wilmington', + addressAddressCity: 'Wilmington', employees: 2177, linkedinLinkUrl: 'https://linkedin.com/company/the-apache-software-foundation', @@ -1357,938 +1357,938 @@ export const companiesDemo = [ { name: 'ArisGlobal', domainName: 'arisglobal.com', - address: 'Miami', + addressAddressCity: 'Miami', employees: 2168, linkedinLinkUrl: 'https://linkedin.com/company/aris-global', }, { name: 'WORKING BY MY SELF', domainName: 'fcutechnologies.com', - address: 'Fort Lauderdale', + addressAddressCity: 'Fort Lauderdale', employees: 2148, linkedinLinkUrl: 'https://linkedin.com/company/working-by-my-self', }, { name: 'Varonis', domainName: 'varonis.com', - address: 'New York', + addressAddressCity: 'New York', employees: 2140, linkedinLinkUrl: 'https://linkedin.com/company/varonis', }, { name: 'Fever', domainName: 'feverup.com', - address: 'New York', + addressAddressCity: 'New York', employees: 2125, linkedinLinkUrl: 'https://linkedin.com/company/fever-up', }, { name: 'Agilysys', domainName: 'agilysys.com', - address: 'Alpharetta', + addressAddressCity: 'Alpharetta', employees: 2081, linkedinLinkUrl: 'https://linkedin.com/company/agilysys', }, { name: 'OutSystems', domainName: 'outsystems.com', - address: 'Boston', + addressAddressCity: 'Boston', employees: 2057, linkedinLinkUrl: 'https://linkedin.com/company/outsystems', }, { name: 'Entrata', domainName: 'entrata.com', - address: 'Lehi', + addressAddressCity: 'Lehi', employees: 2045, linkedinLinkUrl: 'https://linkedin.com/company/entratasoftware', }, { name: 'Verkada', domainName: 'verkada.com', - address: 'San Mateo', + addressAddressCity: 'San Mateo', employees: 2044, linkedinLinkUrl: 'https://linkedin.com/company/verkada', }, { name: 'Majesco', domainName: 'majesco.com', - address: 'Morristown', + addressAddressCity: 'Morristown', employees: 2021, linkedinLinkUrl: 'https://linkedin.com/company/majesco', }, { name: 'Boomi', domainName: 'boomi.com', - address: 'Wayne', + addressAddressCity: 'Wayne', employees: 2009, linkedinLinkUrl: 'https://linkedin.com/company/boomi-inc', }, { name: 'PDI Technologies', domainName: 'pditechnologies.com', - address: 'Alpharetta', + addressAddressCity: 'Alpharetta', employees: 2005, linkedinLinkUrl: 'https://linkedin.com/company/pdi-technologies', }, { name: 'ServiceTitan', domainName: 'servicetitan.com', - address: 'Glendale', + addressAddressCity: 'Glendale', employees: 1997, linkedinLinkUrl: 'https://linkedin.com/company/servicetitan', }, { name: 'Sitecore', domainName: 'sitecore.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 1943, linkedinLinkUrl: 'https://linkedin.com/company/sitecore', }, { name: 'SAP SuccessFactors', domainName: 'sap.com', - address: 'South San Francisco', + addressAddressCity: 'South San Francisco', employees: 1941, linkedinLinkUrl: 'https://linkedin.com/company/successfactors', }, { name: 'Postman', domainName: 'postman.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 1928, linkedinLinkUrl: 'https://linkedin.com/company/postman-platform', }, { name: 'Scale AI', domainName: 'scale.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 1906, linkedinLinkUrl: 'https://linkedin.com/company/scaleai', }, { name: 'Duck Creek Technologies', domainName: 'duckcreek.com', - address: 'Boston', + addressAddressCity: 'Boston', employees: 1894, linkedinLinkUrl: 'https://linkedin.com/company/duck-creek-technologies', }, { name: 'MICROS Systems Inc', domainName: 'oracle.com', - address: 'Columbia', + addressAddressCity: 'Columbia', employees: 1882, linkedinLinkUrl: 'https://linkedin.com/company/micros-systems-inc', }, { name: 'Riverbed Technology', domainName: 'riverbed.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 1874, linkedinLinkUrl: 'https://linkedin.com/company/riverbed-technology', }, { name: 'Fast Enterprises, LLC', domainName: 'fastenterprises.com', - address: 'Englewood', + addressAddressCity: 'Englewood', employees: 1833, linkedinLinkUrl: 'https://linkedin.com/company/fast-enterprises', }, { name: 'Alvaria, Inc.', domainName: 'alvaria.com', - address: 'Westford', + addressAddressCity: 'Westford', employees: 1830, linkedinLinkUrl: 'https://linkedin.com/company/alvaria-inc', }, { name: 'BlackLine', domainName: 'blackline.com', - address: 'Woodland Hills', + addressAddressCity: 'Woodland Hills', employees: 1826, linkedinLinkUrl: 'https://linkedin.com/company/blackline', }, { name: '3Pillar Global', domainName: '3pillarglobal.com', - address: 'Fairfax', + addressAddressCity: 'Fairfax', employees: 1824, linkedinLinkUrl: 'https://linkedin.com/company/3pillar-global', }, { name: 'Saama', domainName: 'saama.com', - address: 'Campbell', + addressAddressCity: 'Campbell', employees: 1809, linkedinLinkUrl: 'https://linkedin.com/company/saama-technologies', }, { name: 'Ancestry', domainName: 'ancestry.com', - address: 'Lehi', + addressAddressCity: 'Lehi', employees: 1794, linkedinLinkUrl: 'https://linkedin.com/company/ancestry.com', }, { name: 'insightsoftware', domainName: 'insightsoftware.com', - address: 'Raleigh', + addressAddressCity: 'Raleigh', employees: 1788, linkedinLinkUrl: 'https://linkedin.com/company/outcomes-by-insightsoftware', }, { name: 'Ebix', domainName: 'ebix.com', - address: 'Duluth', + addressAddressCity: 'Duluth', employees: 1757, linkedinLinkUrl: 'https://linkedin.com/company/ebix', }, { name: 'Zuora', domainName: 'zuora.com', - address: 'Redwood City', + addressAddressCity: 'Redwood City', employees: 1746, linkedinLinkUrl: 'https://linkedin.com/company/zuora', }, { name: 'IntelyCare', domainName: 'intelycare.com', - address: 'Quincy', + addressAddressCity: 'Quincy', employees: 1731, linkedinLinkUrl: 'https://linkedin.com/company/intelycare', }, { name: 'Axway', domainName: 'axway.com', - address: 'Scottsdale', + addressAddressCity: 'Scottsdale', employees: 1731, linkedinLinkUrl: 'https://linkedin.com/company/axway', }, { name: 'Community Brands', domainName: 'communitybrands.com', - address: 'Saint Petersburg', + addressAddressCity: 'Saint Petersburg', employees: 1731, linkedinLinkUrl: 'https://linkedin.com/company/communitybrands', }, { name: 'InterSystems', domainName: 'intersystems.com', - address: 'Cambridge', + addressAddressCity: 'Cambridge', employees: 1730, linkedinLinkUrl: 'https://linkedin.com/company/intersystems', }, { name: 'Mozilla', domainName: 'mozilla.org', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 1721, linkedinLinkUrl: 'https://linkedin.com/company/mozilla-corporation', }, { name: 'Semrush', domainName: 'semrush.com', - address: 'Boston', + addressAddressCity: 'Boston', employees: 1706, linkedinLinkUrl: 'https://linkedin.com/company/semrush', }, { name: 'Avid', domainName: 'avid.com', - address: 'Burlington', + addressAddressCity: 'Burlington', employees: 1705, linkedinLinkUrl: 'https://linkedin.com/company/avid-technology', }, { name: 'Conga', domainName: 'conga.com', - address: 'Broomfield', + addressAddressCity: 'Broomfield', employees: 1695, linkedinLinkUrl: 'https://linkedin.com/company/conga', }, { name: 'InfoBeans', domainName: 'infobeans.com', - address: 'Danville', + addressAddressCity: 'Danville', employees: 1691, linkedinLinkUrl: 'https://linkedin.com/company/infobeans', }, { name: 'AppFolio, Inc.', domainName: 'appfolioinc.com', - address: 'Goleta', + addressAddressCity: 'Goleta', employees: 1688, linkedinLinkUrl: 'https://linkedin.com/company/appfolio-inc', }, { name: 'Sovos', domainName: 'sovos.com', - address: 'Wilmington', + addressAddressCity: 'Wilmington', employees: 1684, linkedinLinkUrl: 'https://linkedin.com/company/sovos', }, { name: 'nCino, Inc.', domainName: 'ncino.com', - address: 'Wilmington', + addressAddressCity: 'Wilmington', employees: 1680, linkedinLinkUrl: 'https://linkedin.com/company/ncino-inc-', }, { name: 'Vistex', domainName: 'vistex.com', - address: 'Hoffman Estates', + addressAddressCity: 'Hoffman Estates', employees: 1677, linkedinLinkUrl: 'https://linkedin.com/company/vistex', }, { name: 'Taboola', domainName: 'taboola.com', - address: 'New York', + addressAddressCity: 'New York', employees: 1677, linkedinLinkUrl: 'https://linkedin.com/company/taboola', }, { name: 'EverCommerce', domainName: 'evercommerce.com', - address: 'Denver', + addressAddressCity: 'Denver', employees: 1673, linkedinLinkUrl: 'https://linkedin.com/company/evercommerce', }, { name: 'Virgin Pulse', domainName: 'virginpulse.com', - address: 'Providence', + addressAddressCity: 'Providence', employees: 1666, linkedinLinkUrl: 'https://linkedin.com/company/virgin-pulse', }, { name: 'Houzz', domainName: 'houzz.com', - address: 'Palo Alto', + addressAddressCity: 'Palo Alto', employees: 1641, linkedinLinkUrl: 'https://linkedin.com/company/houzz', }, { name: 'AvidXchange, Inc.', domainName: 'avidxchange.com', - address: 'Charlotte', + addressAddressCity: 'Charlotte', employees: 1639, linkedinLinkUrl: 'https://linkedin.com/company/avidxchange-inc-', }, { name: 'Planview, Inc.', domainName: 'planview.com', - address: 'Austin', + addressAddressCity: 'Austin', employees: 1634, linkedinLinkUrl: 'https://linkedin.com/company/planview', }, { name: 'HackerRank', domainName: 'hackerrank.com', - address: 'Mountain View', + addressAddressCity: 'Mountain View', employees: 1632, linkedinLinkUrl: 'https://linkedin.com/company/hackerrank', }, { name: 'Clearwater Analytics', domainName: 'clearwateranalytics.com', - address: 'Boise', + addressAddressCity: 'Boise', employees: 1615, linkedinLinkUrl: 'https://linkedin.com/company/clearwateranalytics', }, { name: 'Outreach', domainName: 'outreach.io', - address: 'Seattle', + addressAddressCity: 'Seattle', employees: 1612, linkedinLinkUrl: 'https://linkedin.com/company/outreach-saas', }, { name: 'Everbridge', domainName: 'everbridge.com', - address: 'Burlington', + addressAddressCity: 'Burlington', employees: 1607, linkedinLinkUrl: 'https://linkedin.com/company/everbridge', }, { name: 'Zycus', domainName: 'zycus.com', - address: 'Princeton', + addressAddressCity: 'Princeton', employees: 1604, linkedinLinkUrl: 'https://linkedin.com/company/zycus', }, { name: 'Bullhorn', domainName: 'bullhorn.com', - address: 'Boston', + addressAddressCity: 'Boston', employees: 1604, linkedinLinkUrl: 'https://linkedin.com/company/bullhorn', }, { name: 'LivePerson', domainName: 'liveperson.com', - address: 'New York', + addressAddressCity: 'New York', employees: 1603, linkedinLinkUrl: 'https://linkedin.com/company/liveperson', }, { name: 'Relativity', domainName: 'relativity.com', - address: 'Chicago', + addressAddressCity: 'Chicago', employees: 1601, linkedinLinkUrl: 'https://linkedin.com/company/relativityhq', }, { name: 'HealthEdge', domainName: 'healthedge.com', - address: 'Burlington', + addressAddressCity: 'Burlington', employees: 1600, linkedinLinkUrl: 'https://linkedin.com/company/healthedge', }, { name: 'QAD', domainName: 'qad.com', - address: 'Santa Barbara', + addressAddressCity: 'Santa Barbara', employees: 1598, linkedinLinkUrl: 'https://linkedin.com/company/qad', }, { name: 'Braze', domainName: 'braze.com', - address: 'New York', + addressAddressCity: 'New York', employees: 1598, linkedinLinkUrl: 'https://linkedin.com/company/braze-', }, { name: 'Exadel', domainName: 'exadel.com', - address: 'Walnut Creek', + addressAddressCity: 'Walnut Creek', employees: 1592, linkedinLinkUrl: 'https://linkedin.com/company/exadel', }, { name: 'Phenom', domainName: 'phenom.com', - address: 'Ambler', + addressAddressCity: 'Ambler', employees: 1592, linkedinLinkUrl: 'https://linkedin.com/company/phenomtxm', }, { name: 'Bazaarvoice', domainName: 'bazaarvoice.com', - address: 'Austin', + addressAddressCity: 'Austin', employees: 1587, linkedinLinkUrl: 'https://linkedin.com/company/bazaarvoice', }, { name: 'AppDynamics', domainName: 'appdynamics.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 1553, linkedinLinkUrl: 'https://linkedin.com/company/appdynamics', }, { name: 'Mitchell International', domainName: 'mitchell.com', - address: 'San Diego', + addressAddressCity: 'San Diego', employees: 1548, linkedinLinkUrl: 'https://linkedin.com/company/mitchell-international', }, { name: 'Talkdesk', domainName: 'talkdesk.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 1491, linkedinLinkUrl: 'https://linkedin.com/company/talkdesk', }, { name: 'Hughes Systique Corporation (HSC)', domainName: 'hsc.com', - address: 'Rockville', + addressAddressCity: 'Rockville', employees: 1481, linkedinLinkUrl: 'https://linkedin.com/company/hsc', }, { name: 'Avature', domainName: 'avature.net', - address: 'New York', + addressAddressCity: 'New York', employees: 1478, linkedinLinkUrl: 'https://linkedin.com/company/avature', }, { name: 'Anyone Home Inc', domainName: 'anyonehome.com', - address: 'Lake Forest', + addressAddressCity: 'Lake Forest', employees: 1476, linkedinLinkUrl: 'https://linkedin.com/company/anyone-home-inc', }, { name: 'Engineer.ai', domainName: 'builder.ai', - address: 'Venice', + addressAddressCity: 'Venice', employees: 1474, linkedinLinkUrl: 'https://linkedin.com/company/engineer.ai', }, { name: 'Apptio', domainName: 'apptio.com', - address: 'Bellevue', + addressAddressCity: 'Bellevue', employees: 1467, linkedinLinkUrl: 'https://linkedin.com/company/apptio', }, { name: 'KMS Technology, Inc.', domainName: 'kms-technology.com', - address: 'Atlanta', + addressAddressCity: 'Atlanta', employees: 1464, linkedinLinkUrl: 'https://linkedin.com/company/kms-technology', }, { name: 'JFrog', domainName: 'jfrog.com', - address: 'Sunnyvale', + addressAddressCity: 'Sunnyvale', employees: 1459, linkedinLinkUrl: 'https://linkedin.com/company/jfrog-ltd', }, { name: 'ASG Technologies', domainName: 'asg.com', - address: 'Naples', + addressAddressCity: 'Naples', employees: 1459, linkedinLinkUrl: 'https://linkedin.com/company/asg', }, { name: 'Seismic', domainName: 'seismic.com', - address: 'San Diego', + addressAddressCity: 'San Diego', employees: 1457, linkedinLinkUrl: 'https://linkedin.com/company/seismic', }, { name: 'ModMed', domainName: 'modmed.com', - address: 'Boca Raton', + addressAddressCity: 'Boca Raton', employees: 1452, linkedinLinkUrl: 'https://linkedin.com/company/modernizing-medicine', }, { name: 'ACV Auctions', domainName: 'acvauctions.com', - address: 'Buffalo', + addressAddressCity: 'Buffalo', employees: 1450, linkedinLinkUrl: 'https://linkedin.com/company/acv-auctions', }, { name: 'Cerence Inc.', domainName: 'cerence.com', - address: 'Burlington', + addressAddressCity: 'Burlington', employees: 1448, linkedinLinkUrl: 'https://linkedin.com/company/cerence', }, { name: 'Via', domainName: 'ridewithvia.com', - address: 'New York', + addressAddressCity: 'New York', employees: 1446, linkedinLinkUrl: 'https://linkedin.com/company/ridewithvia', }, { name: 'Kingsoft', domainName: 'ksosoft.com', - address: 'Palo Alto', + addressAddressCity: 'Palo Alto', employees: 1445, linkedinLinkUrl: 'https://linkedin.com/company/kingsoft', }, { name: 'Model N', domainName: 'modeln.com', - address: 'San Mateo', + addressAddressCity: 'San Mateo', employees: 1445, linkedinLinkUrl: 'https://linkedin.com/company/modeln', }, { name: 'ThoughtSpot', domainName: 'thoughtspot.com', - address: 'Mountain View', + addressAddressCity: 'Mountain View', employees: 1436, linkedinLinkUrl: 'https://linkedin.com/company/thoughtspot', }, { name: 'SSS', domainName: 'getebs.com', - address: 'Littleton', + addressAddressCity: 'Littleton', employees: 1431, linkedinLinkUrl: 'https://linkedin.com/company/employee-based-software', }, { name: 'BeyondTrust', domainName: 'beyondtrust.com', - address: 'Duluth', + addressAddressCity: 'Duluth', employees: 1428, linkedinLinkUrl: 'https://linkedin.com/company/beyondtrust', }, { name: 'MetricStream', domainName: 'metricstream.com', - address: 'Alviso', + addressAddressCity: 'Alviso', employees: 1426, linkedinLinkUrl: 'https://linkedin.com/company/metricstream', }, { name: 'LogMeIn', domainName: 'logmeininc.com', - address: 'Boston', + addressAddressCity: 'Boston', employees: 1425, linkedinLinkUrl: 'https://linkedin.com/company/logmein', }, { name: 'Khoros', domainName: 'khoros.com', - address: 'Austin', + addressAddressCity: 'Austin', employees: 1424, linkedinLinkUrl: 'https://linkedin.com/company/khoros', }, { name: 'Sprout Social, Inc.', domainName: 'sproutsocial.com', - address: 'Chicago', + addressAddressCity: 'Chicago', employees: 1416, linkedinLinkUrl: 'https://linkedin.com/company/sprout-social-inc-', }, { name: 'Odessa', domainName: 'odessainc.com', - address: 'Philadelphia', + addressAddressCity: 'Philadelphia', employees: 1415, linkedinLinkUrl: 'https://linkedin.com/company/odessa-inc-', }, { name: 'Enverus', domainName: 'enverus.com', - address: 'Austin', + addressAddressCity: 'Austin', employees: 1404, linkedinLinkUrl: 'https://linkedin.com/company/enverus-energy', }, { name: 'AvePoint', domainName: 'avepoint.com', - address: 'Jersey City', + addressAddressCity: 'Jersey City', employees: 1404, linkedinLinkUrl: 'https://linkedin.com/company/avepoint', }, { name: 'Gong', domainName: 'gong.io', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 1398, linkedinLinkUrl: 'https://linkedin.com/company/gong-io', }, { name: 'Syncfusion', domainName: 'syncfusion.com', - address: 'Morrisville', + addressAddressCity: 'Morrisville', employees: 1397, linkedinLinkUrl: 'https://linkedin.com/company/syncfusion', }, { name: 'Ping Identity', domainName: 'pingidentity.com', - address: 'Denver', + addressAddressCity: 'Denver', employees: 1388, linkedinLinkUrl: 'https://linkedin.com/company/ping-identity', }, { name: 'WellSky', domainName: 'wellsky.com', - address: 'Overland Park', + addressAddressCity: 'Overland Park', employees: 1387, linkedinLinkUrl: 'https://linkedin.com/company/wellsky', }, { name: 'Tricentis', domainName: 'tricentis.com', - address: 'Austin', + addressAddressCity: 'Austin', employees: 1383, linkedinLinkUrl: 'https://linkedin.com/company/tricentis', }, { name: 'Taskrabbit', domainName: 'taskrabbit.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 1383, linkedinLinkUrl: 'https://linkedin.com/company/taskrabbit', }, { name: 'Syniti', domainName: 'syniti.com', - address: 'Needham Heights', + addressAddressCity: 'Needham Heights', employees: 1372, linkedinLinkUrl: 'https://linkedin.com/company/synitidata', }, { name: 'BigCommerce', domainName: 'bigcommerce.com', - address: 'Austin', + addressAddressCity: 'Austin', employees: 1360, linkedinLinkUrl: 'https://linkedin.com/company/bigcommerce', }, { name: 'OEC', domainName: 'oeconnection.com', - address: 'Richfield', + addressAddressCity: 'Richfield', employees: 1357, linkedinLinkUrl: 'https://linkedin.com/company/oeconnection', }, { name: 'Calsoft', domainName: 'calsoftinc.com', - address: 'San Jose', + addressAddressCity: 'San Jose', employees: 1357, linkedinLinkUrl: 'https://linkedin.com/company/calsoft', }, { name: 'Taller', domainName: 'tallertechnologies.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 1351, linkedinLinkUrl: 'https://linkedin.com/company/taller-technologies', }, { name: 'Planet', domainName: 'planet.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 1348, linkedinLinkUrl: 'https://linkedin.com/company/planet-labs', }, { name: '6sense', domainName: '6sense.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 1346, linkedinLinkUrl: 'https://linkedin.com/company/6sense', }, { name: 'Vitech Systems Group', domainName: 'vitechinc.com', - address: 'New York', + addressAddressCity: 'New York', employees: 1345, linkedinLinkUrl: 'https://linkedin.com/company/vitech-systems-group', }, { name: 'Smarsh', domainName: 'smarsh.com', - address: 'Portland', + addressAddressCity: 'Portland', employees: 1344, linkedinLinkUrl: 'https://linkedin.com/company/smarsh', }, { name: 'NICE Actimize', domainName: 'niceactimize.com', - address: 'Hoboken', + addressAddressCity: 'Hoboken', employees: 1343, linkedinLinkUrl: 'https://linkedin.com/company/actimize', }, { name: 'Dataiku', domainName: 'dataiku.com', - address: 'New York', + addressAddressCity: 'New York', employees: 1340, linkedinLinkUrl: 'https://linkedin.com/company/dataiku', }, { name: 'Liferay', domainName: 'liferay.com', - address: 'Diamond Bar', + addressAddressCity: 'Diamond Bar', employees: 1329, linkedinLinkUrl: 'https://linkedin.com/company/liferay-inc-', }, { name: 'Gainsight', domainName: 'gainsight.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 1328, linkedinLinkUrl: 'https://linkedin.com/company/gainsight', }, { name: 'Infotech', domainName: 'infotechinc.com', - address: 'Gainesville', + addressAddressCity: 'Gainesville', employees: 1322, linkedinLinkUrl: 'https://linkedin.com/company/infotech-inc', }, { name: 'JAGGAER', domainName: 'jaggaer.com', - address: 'Morrisville', + addressAddressCity: 'Morrisville', employees: 1317, linkedinLinkUrl: 'https://linkedin.com/company/jaggaer', }, { name: 'Checkr, Inc.', domainName: 'checkr.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 1304, linkedinLinkUrl: 'https://linkedin.com/company/checkr-com', }, { name: 'CARFAX', domainName: 'carfax.com', - address: 'Centreville', + addressAddressCity: 'Centreville', employees: 1296, linkedinLinkUrl: 'https://linkedin.com/company/carfax', }, { name: 'Lucid Software', domainName: 'lucid.co', - address: 'South Jordan', + addressAddressCity: 'South Jordan', employees: 1295, linkedinLinkUrl: 'https://linkedin.com/company/lucidsoftware', }, { name: 'Domo', domainName: 'domo.com', - address: 'American Fork', + addressAddressCity: 'American Fork', employees: 1293, linkedinLinkUrl: 'https://linkedin.com/company/domotalk', }, { name: 'Podium', domainName: 'podium.com', - address: 'Lehi', + addressAddressCity: 'Lehi', employees: 1292, linkedinLinkUrl: 'https://linkedin.com/company/podium', }, { name: 'Mendix', domainName: 'mendix.com', - address: 'Boston', + addressAddressCity: 'Boston', employees: 1290, linkedinLinkUrl: 'https://linkedin.com/company/mendix', }, { name: 'EDB', domainName: 'edbpostgres.com', - address: 'Bedford', + addressAddressCity: 'Bedford', employees: 1289, linkedinLinkUrl: 'https://linkedin.com/company/edbpostgres', }, { name: 'OneStream Software', domainName: 'onestreamsoftware.com', - address: 'Birmingham', + addressAddressCity: 'Birmingham', employees: 1288, linkedinLinkUrl: 'https://linkedin.com/company/onestream-software', }, { name: 'Rent.', domainName: 'rent.com', - address: 'Atlanta', + addressAddressCity: 'Atlanta', employees: 1285, linkedinLinkUrl: 'https://linkedin.com/company/rentsolutions', }, { name: 'Waystar', domainName: 'waystar.com', - address: 'Louisville', + addressAddressCity: 'Louisville', employees: 1273, linkedinLinkUrl: 'https://linkedin.com/company/waystar', }, { name: '2020', domainName: '2020spaces.com', - address: 'Westford', + addressAddressCity: 'Westford', employees: 1267, linkedinLinkUrl: 'https://linkedin.com/company/2020spaces', }, { name: 'isolved', domainName: 'isolvedhcm.com', - address: 'Charlotte', + addressAddressCity: 'Charlotte', employees: 1261, linkedinLinkUrl: 'https://linkedin.com/company/isolved', }, { name: 'Art Technology Group', domainName: 'atg.com', - address: 'Cambridge', + addressAddressCity: 'Cambridge', employees: 1259, linkedinLinkUrl: 'https://linkedin.com/company/atg', }, { name: 'CAST', domainName: 'castsoftware.com', - address: 'New York', + addressAddressCity: 'New York', employees: 1259, linkedinLinkUrl: 'https://linkedin.com/company/cast', }, { name: 'OCLC', domainName: 'oc.lc', - address: 'Dublin', + addressAddressCity: 'Dublin', employees: 1258, linkedinLinkUrl: 'https://linkedin.com/company/oclc', }, { name: 'Mediaocean', domainName: 'mediaocean.com', - address: 'New York', + addressAddressCity: 'New York', employees: 1255, linkedinLinkUrl: 'https://linkedin.com/company/mediaocean', }, { name: 'Bandwidth Inc.', domainName: 'bandwidth.com', - address: 'Raleigh', + addressAddressCity: 'Raleigh', employees: 1252, linkedinLinkUrl: 'https://linkedin.com/company/bandwidth-inc', }, { name: 'Hexagon Safety, Infrastructure & Geospatial', domainName: 'hexagonsafetyinfrastructure.com', - address: 'Madison', + addressAddressCity: 'Madison', employees: 1252, linkedinLinkUrl: 'https://linkedin.com/company/hexagon-geospatial', }, { name: 'Wish', domainName: 'wish.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 1248, linkedinLinkUrl: 'https://linkedin.com/company/wishshopping', }, { name: 'Sagitec Solutions', domainName: 'sagitec.com', - address: 'Saint Paul', + addressAddressCity: 'Saint Paul', employees: 1244, linkedinLinkUrl: 'https://linkedin.com/company/sagitec-solutions', }, { name: 'Zinnia ', domainName: 'zinnia.com', - address: 'Greenwich', + addressAddressCity: 'Greenwich', employees: 1243, linkedinLinkUrl: 'https://linkedin.com/company/zinniatm', }, { name: 'CureMD', domainName: 'curemd.com', - address: 'New York', + addressAddressCity: 'New York', employees: 1243, linkedinLinkUrl: 'https://linkedin.com/company/curemd', }, { name: 'Druva', domainName: 'druva.com', - address: 'Santa Clara', + addressAddressCity: 'Santa Clara', employees: 1238, linkedinLinkUrl: 'https://linkedin.com/company/druva', }, { name: 'Restaurant365', domainName: 'restaurant365.com', - address: 'Irvine', + addressAddressCity: 'Irvine', employees: 1234, linkedinLinkUrl: 'https://linkedin.com/company/restaurant365-cloud-erp-for-restaurants', @@ -2296,364 +2296,364 @@ export const companiesDemo = [ { name: 'Lawson Software', domainName: 'lawson.com', - address: 'New York', + addressAddressCity: 'New York', employees: 1231, linkedinLinkUrl: 'https://linkedin.com/company/lawson-software', }, { name: 'AlphaSense', domainName: 'alpha-sense.com', - address: 'New York', + addressAddressCity: 'New York', employees: 1223, linkedinLinkUrl: 'https://linkedin.com/company/alphasense', }, { name: 'ECI Software Solutions', domainName: 'ecisolutions.com', - address: 'Fort Worth', + addressAddressCity: 'Fort Worth', employees: 1223, linkedinLinkUrl: 'https://linkedin.com/company/eci-software--solutions', }, { name: 'Wrike', domainName: 'wrike.com', - address: 'San Diego', + addressAddressCity: 'San Diego', employees: 1210, linkedinLinkUrl: 'https://linkedin.com/company/wrike', }, { name: 'Syndigo', domainName: 'syndigo.com', - address: 'Chicago', + addressAddressCity: 'Chicago', employees: 1208, linkedinLinkUrl: 'https://linkedin.com/company/syndigo', }, { name: 'Gigamon', domainName: 'gigamon.com', - address: 'Santa Clara', + addressAddressCity: 'Santa Clara', employees: 1196, linkedinLinkUrl: 'https://linkedin.com/company/gigamon', }, { name: 'Fastly', domainName: 'fastly.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 1188, linkedinLinkUrl: 'https://linkedin.com/company/fastly', }, { name: 'Cantaloupe Inc', domainName: 'cantaloupe.com', - address: 'Malvern', + addressAddressCity: 'Malvern', employees: 1187, linkedinLinkUrl: 'https://linkedin.com/company/cantaloupeinc', }, { name: 'EagleView', domainName: 'eagleview.com', - address: 'Bellevue', + addressAddressCity: 'Bellevue', employees: 1184, linkedinLinkUrl: 'https://linkedin.com/company/eagleview-technologies-inc', }, { name: 'Litera', domainName: 'litera.com', - address: 'Chicago', + addressAddressCity: 'Chicago', employees: 1183, linkedinLinkUrl: 'https://linkedin.com/company/literamicrosystems', }, { name: 'Collibra', domainName: 'collibra.com', - address: 'New York', + addressAddressCity: 'New York', employees: 1183, linkedinLinkUrl: 'https://linkedin.com/company/collibra', }, { name: 'Picsart', domainName: 'picsart.com', - address: 'Miami Beach', + addressAddressCity: 'Miami Beach', employees: 1180, linkedinLinkUrl: 'https://linkedin.com/company/picsart-photo-studio', }, { name: 'CalAmp', domainName: 'calamp.com', - address: 'Irvine', + addressAddressCity: 'Irvine', employees: 1180, linkedinLinkUrl: 'https://linkedin.com/company/calamp-corp', }, { name: 'ESS', domainName: 'ess-home.com', - address: 'Tempe', + addressAddressCity: 'Tempe', employees: 1178, linkedinLinkUrl: 'https://linkedin.com/company/ess', }, { name: 'Grafana Labs', domainName: 'grafana.com', - address: 'New York', + addressAddressCity: 'New York', employees: 1178, linkedinLinkUrl: 'https://linkedin.com/company/grafana-labs', }, { name: 'Fivetran', domainName: '5tran.co', - address: 'Oakland', + addressAddressCity: 'Oakland', employees: 1176, linkedinLinkUrl: 'https://linkedin.com/company/fivetran', }, { name: 'CentralSquare Technologies', domainName: 'centralsquare.com', - address: 'Lake Mary', + addressAddressCity: 'Lake Mary', employees: 1175, linkedinLinkUrl: 'https://linkedin.com/company/centralsqtech', }, { name: 'StubHub', domainName: 'stubhub.com', - address: 'New York', + addressAddressCity: 'New York', employees: 1164, linkedinLinkUrl: 'https://linkedin.com/company/stubhub', }, { name: 'EIS Ltd', domainName: 'eisgroup.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 1154, linkedinLinkUrl: 'https://linkedin.com/company/eisgroupltd', }, { name: 'Tebra', domainName: 'tebra.com', - address: 'Corona Del Mar', + addressAddressCity: 'Corona Del Mar', employees: 1151, linkedinLinkUrl: 'https://linkedin.com/company/tebra', }, { name: 'Benefitfocus', domainName: 'benefitfocus.com', - address: 'Charleston', + addressAddressCity: 'Charleston', employees: 1148, linkedinLinkUrl: 'https://linkedin.com/company/benefitfocus', }, { name: 'NISC', domainName: 'nisc.coop', - address: 'Lake Saint Louis', + addressAddressCity: 'Lake Saint Louis', employees: 1140, linkedinLinkUrl: 'https://linkedin.com/company/nisc', }, { name: 'Dell Compellent', domainName: 'dell.com', - address: 'Eden Prairie', + addressAddressCity: 'Eden Prairie', employees: 1138, linkedinLinkUrl: 'https://linkedin.com/company/dell-compellent', }, { name: 'Radancy', domainName: 'radancy.com', - address: 'New York', + addressAddressCity: 'New York', employees: 1137, linkedinLinkUrl: 'https://linkedin.com/company/radancy', }, { name: 'Granicus', domainName: 'granicus.com', - address: 'Denver', + addressAddressCity: 'Denver', employees: 1134, linkedinLinkUrl: 'https://linkedin.com/company/granicusinc', }, { name: 'ACTIVE Network', domainName: 'activenetwork.com', - address: 'Plano', + addressAddressCity: 'Plano', employees: 1134, linkedinLinkUrl: 'https://linkedin.com/company/the-active-network', }, { name: 'Acquia', domainName: 'acquia.com', - address: 'Boston', + addressAddressCity: 'Boston', employees: 1134, linkedinLinkUrl: 'https://linkedin.com/company/acquia', }, { name: 'WalkMe\u2122', domainName: 'walkme.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 1127, linkedinLinkUrl: 'https://linkedin.com/company/walkme', }, { name: 'Outbrain', domainName: 'outbrain.com', - address: 'New York', + addressAddressCity: 'New York', employees: 1123, linkedinLinkUrl: 'https://linkedin.com/company/outbrain', }, { name: 'WillowTree', domainName: 'willowtreeapps.com', - address: 'Charlottesville', + addressAddressCity: 'Charlottesville', employees: 1117, linkedinLinkUrl: 'https://linkedin.com/company/willowtreeapps', }, { name: 'LogicMonitor', domainName: 'logicmonitor.com', - address: 'Santa Barbara', + addressAddressCity: 'Santa Barbara', employees: 1113, linkedinLinkUrl: 'https://linkedin.com/company/logicmonitor', }, { name: 'Jellysmack', domainName: 'jellysmack.com', - address: 'New York', + addressAddressCity: 'New York', employees: 1109, linkedinLinkUrl: 'https://linkedin.com/company/jellysmack', }, { name: 'Henry Schein One', domainName: 'henryscheinone.com', - address: 'American Fork', + addressAddressCity: 'American Fork', employees: 1108, linkedinLinkUrl: 'https://linkedin.com/company/henry-schein-one', }, { name: 'Prometheus Group', domainName: 'prometheusgroup.com', - address: 'Raleigh', + addressAddressCity: 'Raleigh', employees: 1102, linkedinLinkUrl: 'https://linkedin.com/company/prometheusgroup', }, { name: 'Atlas', domainName: 'atlashxm.com', - address: 'Chicago', + addressAddressCity: 'Chicago', employees: 1101, linkedinLinkUrl: 'https://linkedin.com/company/atlashxm', }, { name: 'Dialpad', domainName: 'dialpad.com', - address: 'San Ramon', + addressAddressCity: 'San Ramon', employees: 1101, linkedinLinkUrl: 'https://linkedin.com/company/dialpad', }, { name: 'Accruent', domainName: 'accruent.com', - address: 'Austin', + addressAddressCity: 'Austin', employees: 1098, linkedinLinkUrl: 'https://linkedin.com/company/accruent', }, { name: 'Charles River Development', domainName: 'crd.com', - address: 'Burlington', + addressAddressCity: 'Burlington', employees: 1090, linkedinLinkUrl: 'https://linkedin.com/company/charles-river-development', }, { name: 'Flexera', domainName: 'flexera.com', - address: 'Itasca', + addressAddressCity: 'Itasca', employees: 1089, linkedinLinkUrl: 'https://linkedin.com/company/flexera', }, { name: 'Quotient Technology Inc.', domainName: 'quotient.com', - address: 'Salt Lake City', + addressAddressCity: 'Salt Lake City', employees: 1087, linkedinLinkUrl: 'https://linkedin.com/company/quotient-technology', }, { name: 'Sage Intacct, Inc.', domainName: 'sageintacct.com', - address: 'San Jose', + addressAddressCity: 'San Jose', employees: 1087, linkedinLinkUrl: 'https://linkedin.com/company/sageintacct', }, { name: 'Plaid', domainName: 'plaid.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 1081, linkedinLinkUrl: 'https://linkedin.com/company/plaid-', }, { name: 'C3 AI', domainName: 'c3.ai', - address: 'Redwood City', + addressAddressCity: 'Redwood City', employees: 1077, linkedinLinkUrl: 'https://linkedin.com/company/c3-ai', }, { name: 'Upland Software', domainName: 'uplandsoftware.com', - address: 'Austin', + addressAddressCity: 'Austin', employees: 1072, linkedinLinkUrl: 'https://linkedin.com/company/upland-software', }, { name: 'Zapier', domainName: 'zapier.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 1066, linkedinLinkUrl: 'https://linkedin.com/company/zapier', }, { name: 'WSO2', domainName: 'wso2.com', - address: 'Santa Clara', + addressAddressCity: 'Santa Clara', employees: 1065, linkedinLinkUrl: 'https://linkedin.com/company/wso2', }, { name: 'Auctane', domainName: 'auctane.com', - address: 'Austin', + addressAddressCity: 'Austin', employees: 1055, linkedinLinkUrl: 'https://linkedin.com/company/auctane', }, { name: 'Salesloft', domainName: 'salesloft.com', - address: 'Atlanta', + addressAddressCity: 'Atlanta', employees: 1055, linkedinLinkUrl: 'https://linkedin.com/company/salesloft', }, { name: 'RLDatix', domainName: 'rldatix.com', - address: 'Chicago', + addressAddressCity: 'Chicago', employees: 1048, linkedinLinkUrl: 'https://linkedin.com/company/rldatix', }, { name: 'SS&C Blue Prism', domainName: 'blueprism.com', - address: 'Windsor', + addressAddressCity: 'Windsor', employees: 1048, linkedinLinkUrl: 'https://linkedin.com/company/blue-prism-limited', }, { name: 'Waitr', domainName: 'waitrapp.com', - address: 'Lafayette', + addressAddressCity: 'Lafayette', employees: 1043, linkedinLinkUrl: 'https://linkedin.com/company/waitr-inc-', }, { name: 'Software Engineering Institute | Carnegie Mellon University', domainName: 'sei.cmu.edu', - address: 'Pittsburgh', + addressAddressCity: 'Pittsburgh', employees: 1043, linkedinLinkUrl: 'https://linkedin.com/company/software-engineering-institute', @@ -2661,7 +2661,7 @@ export const companiesDemo = [ { name: 'Downey Unified School District', domainName: 'dusd.net', - address: 'Downey', + addressAddressCity: 'Downey', employees: 1038, linkedinLinkUrl: 'https://linkedin.com/company/downey-unified-school-district', @@ -2669,1225 +2669,1225 @@ export const companiesDemo = [ { name: 'Private Access, Inc.', domainName: 'privateaccess.com', - address: 'Irvine', + addressAddressCity: 'Irvine', employees: 1037, linkedinLinkUrl: 'https://linkedin.com/company/private-access-inc.', }, { name: 'iManage', domainName: 'imanage.com', - address: 'Chicago', + addressAddressCity: 'Chicago', employees: 1036, linkedinLinkUrl: 'https://linkedin.com/company/imanage', }, { name: 'QASource', domainName: 'qasource.com', - address: 'Pleasanton', + addressAddressCity: 'Pleasanton', employees: 1032, linkedinLinkUrl: 'https://linkedin.com/company/qasource', }, { name: 'Azuga, Inc.', domainName: 'azuga.com', - address: 'San Jose', + addressAddressCity: 'San Jose', employees: 1026, linkedinLinkUrl: 'https://linkedin.com/company/azuga-inc-', }, { name: 'Talent Systems, LLC', domainName: 'talentsystems.com', - address: 'Los Angeles', + addressAddressCity: 'Los Angeles', employees: 1022, linkedinLinkUrl: 'https://linkedin.com/company/talent-systems-llc', }, { name: 'Datasite', domainName: 'datasite.com', - address: 'Minneapolis', + addressAddressCity: 'Minneapolis', employees: 1021, linkedinLinkUrl: 'https://linkedin.com/company/datasiteglobal', }, { name: 'AVASOFT', domainName: 'avasoft.com', - address: 'Blue Bell', + addressAddressCity: 'Blue Bell', employees: 1017, linkedinLinkUrl: 'https://linkedin.com/company/avasoft', }, { name: 'DataRobot', domainName: 'datarobot.com', - address: 'Boston', + addressAddressCity: 'Boston', employees: 1015, linkedinLinkUrl: 'https://linkedin.com/company/datarobot', }, { name: 'Technisys', domainName: 'technisys.com', - address: 'Miami', + addressAddressCity: 'Miami', employees: 1014, linkedinLinkUrl: 'https://linkedin.com/company/technisys', }, { name: 'project44', domainName: 'project44.com', - address: 'Chicago', + addressAddressCity: 'Chicago', employees: 1013, linkedinLinkUrl: 'https://linkedin.com/company/project-44', }, { name: 'Imprivata', domainName: 'imprivata.com', - address: 'Waltham', + addressAddressCity: 'Waltham', employees: 1013, linkedinLinkUrl: 'https://linkedin.com/company/imprivata', }, { name: 'Webflow', domainName: 'webflow.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 1011, linkedinLinkUrl: 'https://linkedin.com/company/webflow-inc-', }, { name: 'Blend', domainName: 'blend.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 1011, linkedinLinkUrl: 'https://linkedin.com/company/blend-', }, { name: 'Egnyte', domainName: 'egnyte.com', - address: 'Mountain View', + addressAddressCity: 'Mountain View', employees: 1009, linkedinLinkUrl: 'https://linkedin.com/company/egnyte', }, { name: 'SS&C Eze', domainName: 'ezesoft.com', - address: 'Windsor', + addressAddressCity: 'Windsor', employees: 1008, linkedinLinkUrl: 'https://linkedin.com/company/ezesoftware', }, { name: 'Tipalti', domainName: 'tipalti.com', - address: 'San Mateo', + addressAddressCity: 'San Mateo', employees: 1007, linkedinLinkUrl: 'https://linkedin.com/company/tipalti', }, { name: 'Altium\u00ae', domainName: 'altium.com', - address: 'La Jolla', + addressAddressCity: 'La Jolla', employees: 1005, linkedinLinkUrl: 'https://linkedin.com/company/altium', }, { name: 'airSlate', domainName: 'airslate.com', - address: 'Brookline', + addressAddressCity: 'Brookline', employees: 1001, linkedinLinkUrl: 'https://linkedin.com/company/airslate', }, { name: 'Arbisoft', domainName: 'arbisoft.com', - address: 'Mckinney', + addressAddressCity: 'Mckinney', employees: 996, linkedinLinkUrl: 'https://linkedin.com/company/arbisoft', }, { name: 'Airtable', domainName: 'airtable.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 989, linkedinLinkUrl: 'https://linkedin.com/company/airtable', }, { name: 'Birdeye', domainName: 'birdeye.com', - address: 'Palo Alto', + addressAddressCity: 'Palo Alto', employees: 988, linkedinLinkUrl: 'https://linkedin.com/company/birdeye', }, { name: 'Ultimate Software', domainName: 'ultimatesoftware.com', - address: 'Fort Lauderdale', + addressAddressCity: 'Fort Lauderdale', employees: 988, linkedinLinkUrl: 'https://linkedin.com/company/ultimate-software', }, { name: 'Homecare Homebase', domainName: 'hchb.com', - address: 'Dallas', + addressAddressCity: 'Dallas', employees: 987, linkedinLinkUrl: 'https://linkedin.com/company/homecare-homebase', }, { name: 'DISCO', domainName: 'csdisco.com', - address: 'Austin', + addressAddressCity: 'Austin', employees: 984, linkedinLinkUrl: 'https://linkedin.com/company/cs-disco-llc', }, { name: 'Highspot', domainName: 'highspot.com', - address: 'Seattle', + addressAddressCity: 'Seattle', employees: 982, linkedinLinkUrl: 'https://linkedin.com/company/highspot', }, { name: 'Sagent', domainName: 'sagent.com', - address: 'King Of Prussia', + addressAddressCity: 'King Of Prussia', employees: 981, linkedinLinkUrl: 'https://linkedin.com/company/sagent-lending-technologies', }, { name: 'Apollo.io', domainName: 'apollo.io', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 981, linkedinLinkUrl: 'https://linkedin.com/company/apolloio', }, { name: 'PAS', domainName: 'pas.com', - address: 'Houston', + addressAddressCity: 'Houston', employees: 981, linkedinLinkUrl: 'https://linkedin.com/company/pas', }, { name: 'Wikimedia Foundation', domainName: 'wikimediafoundation.org', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 981, linkedinLinkUrl: 'https://linkedin.com/company/wikimedia-foundation', }, { name: 'Nintex', domainName: 'nintex.com', - address: 'Bellevue', + addressAddressCity: 'Bellevue', employees: 978, linkedinLinkUrl: 'https://linkedin.com/company/nintex', }, { name: 'RUCKUS Networks', domainName: 'commscope.com', - address: 'Sunnyvale', + addressAddressCity: 'Sunnyvale', employees: 978, linkedinLinkUrl: 'https://linkedin.com/company/ruckus-networks', }, { name: 'ForgeRock', domainName: 'forgerock.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 977, linkedinLinkUrl: 'https://linkedin.com/company/forgerock', }, { name: 'Trading Technologies', domainName: 'tradingtechnologies.com', - address: 'Chicago', + addressAddressCity: 'Chicago', employees: 975, linkedinLinkUrl: 'https://linkedin.com/company/trading-technologies', }, { name: 'KANINI', domainName: 'kanini.com', - address: 'Nashville', + addressAddressCity: 'Nashville', employees: 972, linkedinLinkUrl: 'https://linkedin.com/company/kanini', }, { name: 'Dealer.com', domainName: 'dealer.com', - address: 'Burlington', + addressAddressCity: 'Burlington', employees: 962, linkedinLinkUrl: 'https://linkedin.com/company/dealer-com', }, { name: 'WS', domainName: 'ws-inc.com', - address: 'Pinehurst', + addressAddressCity: 'Pinehurst', employees: 960, linkedinLinkUrl: 'https://linkedin.com/company/wbem-solutions', }, { name: 'Kyriba', domainName: 'kyriba.com', - address: 'San Diego', + addressAddressCity: 'San Diego', employees: 960, linkedinLinkUrl: 'https://linkedin.com/company/kyriba', }, { name: 'Demandbase', domainName: 'demandbase.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 958, linkedinLinkUrl: 'https://linkedin.com/company/demandbase', }, { name: 'Sumo Logic', domainName: 'sumologic.com', - address: 'Redwood City', + addressAddressCity: 'Redwood City', employees: 954, linkedinLinkUrl: 'https://linkedin.com/company/sumo-logic', }, { name: 'Edifecs', domainName: 'edifecs.com', - address: 'Bellevue', + addressAddressCity: 'Bellevue', employees: 949, linkedinLinkUrl: 'https://linkedin.com/company/edifecs', }, { name: 'ibi | Information Builders', domainName: 'ibi.com', - address: 'Fort Lauderdale', + addressAddressCity: 'Fort Lauderdale', employees: 948, linkedinLinkUrl: 'https://linkedin.com/company/information-builders', }, { name: 'Emburse', domainName: 'emburse.com', - address: 'Los Angeles', + addressAddressCity: 'Los Angeles', employees: 941, linkedinLinkUrl: 'https://linkedin.com/company/emburse', }, { name: 'ConstructConnect', domainName: 'constructconnect.com', - address: 'Cincinnati', + addressAddressCity: 'Cincinnati', employees: 940, linkedinLinkUrl: 'https://linkedin.com/company/constructconnect', }, { name: 'Perforce Software', domainName: 'perforce.com', - address: 'Minneapolis', + addressAddressCity: 'Minneapolis', employees: 939, linkedinLinkUrl: 'https://linkedin.com/company/perforce', }, { name: 'Insurity', domainName: 'insurity.com', - address: 'Hartford', + addressAddressCity: 'Hartford', employees: 938, linkedinLinkUrl: 'https://linkedin.com/company/insurity', }, { name: 'webOS', domainName: 'developer.lge.com', - address: 'Santa Clara', + addressAddressCity: 'Santa Clara', employees: 936, linkedinLinkUrl: 'https://linkedin.com/company/webos', }, { name: 'Zenoti', domainName: 'zenoti.com', - address: 'Bellevue', + addressAddressCity: 'Bellevue', employees: 934, linkedinLinkUrl: 'https://linkedin.com/company/zenoti', }, { name: 'Intapp', domainName: 'intapp.com', - address: 'Palo Alto', + addressAddressCity: 'Palo Alto', employees: 930, linkedinLinkUrl: 'https://linkedin.com/company/intapp', }, { name: 'OATI', domainName: 'oati.com', - address: 'Minneapolis', + addressAddressCity: 'Minneapolis', employees: 930, linkedinLinkUrl: 'https://linkedin.com/company/oati', }, { name: 'Frontline Education', domainName: 'frontlineeducation.com', - address: 'Malvern', + addressAddressCity: 'Malvern', employees: 926, linkedinLinkUrl: 'https://linkedin.com/company/frontline-education', }, { name: 'Aspect Software', domainName: 'aspect.com', - address: 'Westford', + addressAddressCity: 'Westford', employees: 920, linkedinLinkUrl: 'https://linkedin.com/company/aspect-software', }, { name: 'GreyOrange', domainName: 'greyorange.com', - address: 'Roswell', + addressAddressCity: 'Roswell', employees: 919, linkedinLinkUrl: 'https://linkedin.com/company/gogreyorange', }, { name: 'Sirion', domainName: 'sirionlabs.com', - address: 'Bellevue', + addressAddressCity: 'Bellevue', employees: 918, linkedinLinkUrl: 'https://linkedin.com/company/sirionlabs', }, { name: 'In Time Tec', domainName: 'intimetec.com', - address: 'Meridian', + addressAddressCity: 'Meridian', employees: 917, linkedinLinkUrl: 'https://linkedin.com/company/in-time-tec', }, { name: 'Operative', domainName: 'operative.com', - address: 'New York', + addressAddressCity: 'New York', employees: 910, linkedinLinkUrl: 'https://linkedin.com/company/operative', }, { name: 'Kore.ai', domainName: 'kore.ai', - address: 'Orlando', + addressAddressCity: 'Orlando', employees: 908, linkedinLinkUrl: 'https://linkedin.com/company/kore-inc', }, { name: 'Redis', domainName: 'redis.com', - address: 'Mountain View', + addressAddressCity: 'Mountain View', employees: 908, linkedinLinkUrl: 'https://linkedin.com/company/redisinc', }, { name: 'Addepar', domainName: 'addepar.com', - address: 'Mountain View', + addressAddressCity: 'Mountain View', employees: 907, linkedinLinkUrl: 'https://linkedin.com/company/addepar', }, { name: 'TCP Software', domainName: 'tcpsoftware.com', - address: 'Austin', + addressAddressCity: 'Austin', employees: 902, linkedinLinkUrl: 'https://linkedin.com/company/tcpsoftware', }, { name: 'TraceLink', domainName: 'tracelink.com', - address: 'Wilmington', + addressAddressCity: 'Wilmington', employees: 897, linkedinLinkUrl: 'https://linkedin.com/company/tracelink', }, { name: 'Benchling', domainName: 'benchling.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 895, linkedinLinkUrl: 'https://linkedin.com/company/benchling', }, { name: 'Housecall Pro', domainName: 'housecallpro.com', - address: 'Denver', + addressAddressCity: 'Denver', employees: 894, linkedinLinkUrl: 'https://linkedin.com/company/housecallpro', }, { name: 'Turnitin', domainName: 'turnitin.com', - address: 'Oakland', + addressAddressCity: 'Oakland', employees: 885, linkedinLinkUrl: 'https://linkedin.com/company/turnitin', }, { name: 'Schr\u00f6dinger', domainName: 'schrodinger.com', - address: 'New York', + addressAddressCity: 'New York', employees: 885, linkedinLinkUrl: 'https://linkedin.com/company/schr-dinger', }, { name: 'eGain Corporation', domainName: 'egain.com', - address: 'Sunnyvale', + addressAddressCity: 'Sunnyvale', employees: 879, linkedinLinkUrl: 'https://linkedin.com/company/egain-corporation', }, { name: 'Brightly', domainName: 'brightlysoftware.com', - address: 'Cary', + addressAddressCity: 'Cary', employees: 878, linkedinLinkUrl: 'https://linkedin.com/company/brightlysoftware', }, { name: 'Snap-on Business Solutions', domainName: 'snapon.com', - address: 'Richfield', + addressAddressCity: 'Richfield', employees: 876, linkedinLinkUrl: 'https://linkedin.com/company/snap-on-business-solutions', }, { name: 'ACS Technologies', domainName: 'acstechnologies.com', - address: 'Florence', + addressAddressCity: 'Florence', employees: 874, linkedinLinkUrl: 'https://linkedin.com/company/acs-technologies', }, { name: 'Uniphore', domainName: 'uniphore.com', - address: 'Palo Alto', + addressAddressCity: 'Palo Alto', employees: 872, linkedinLinkUrl: 'https://linkedin.com/company/uniphore', }, { name: 'Folio3 Software', domainName: 'folio3.com', - address: 'Belmont', + addressAddressCity: 'Belmont', employees: 872, linkedinLinkUrl: 'https://linkedin.com/company/folio3', }, { name: 'MHC', domainName: 'mhcautomation.com', - address: 'Burnsville', + addressAddressCity: 'Burnsville', employees: 871, linkedinLinkUrl: 'https://linkedin.com/company/mhcautomation', }, { name: 'Xactly Corp', domainName: 'xactlycorp.com', - address: 'Los Gatos', + addressAddressCity: 'Los Gatos', employees: 865, linkedinLinkUrl: 'https://linkedin.com/company/xactly-corporation', }, { name: 'Weave', domainName: 'getweave.com', - address: 'Lehi', + addressAddressCity: 'Lehi', employees: 864, linkedinLinkUrl: 'https://linkedin.com/company/getweave', }, { name: 'Microworkers', domainName: 'microworkers.com', - address: 'Frisco', + addressAddressCity: 'Frisco', employees: 862, linkedinLinkUrl: 'https://linkedin.com/company/microworkers.com', }, { name: 'Trilogy', domainName: 'trilogy.com', - address: 'Austin', + addressAddressCity: 'Austin', employees: 861, linkedinLinkUrl: 'https://linkedin.com/company/trilogy', }, { name: 'Akvelon, Inc.', domainName: 'akvelon.com', - address: 'Bellevue', + addressAddressCity: 'Bellevue', employees: 860, linkedinLinkUrl: 'https://linkedin.com/company/akvelon', }, { name: 'iPipeline', domainName: 'ipipeline.com', - address: 'Exton', + addressAddressCity: 'Exton', employees: 856, linkedinLinkUrl: 'https://linkedin.com/company/ipipeline', }, { name: 'Salary.com', domainName: 'salary.com', - address: 'Wellesley Hills', + addressAddressCity: 'Wellesley Hills', employees: 854, linkedinLinkUrl: 'https://linkedin.com/company/salarydotcom', }, { name: 'PandaDoc', domainName: 'pandadoc.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 851, linkedinLinkUrl: 'https://linkedin.com/company/pandadoc', }, { name: 'MSC Software', domainName: 'mscsoftware.com', - address: 'Newport Beach', + addressAddressCity: 'Newport Beach', employees: 849, linkedinLinkUrl: 'https://linkedin.com/company/msc-software', }, { name: 'Harness', domainName: 'harness.io', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 848, linkedinLinkUrl: 'https://linkedin.com/company/harnessinc', }, { name: 'ActiveCampaign', domainName: 'activecampaign.com', - address: 'Chicago', + addressAddressCity: 'Chicago', employees: 848, linkedinLinkUrl: 'https://linkedin.com/company/activecampaign-inc-', }, { name: 'Doximity', domainName: 'doximity.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 848, linkedinLinkUrl: 'https://linkedin.com/company/doximity', }, { name: 'Couchbase', domainName: 'couchbase.com', - address: 'Santa Clara', + addressAddressCity: 'Santa Clara', employees: 847, linkedinLinkUrl: 'https://linkedin.com/company/couchbase', }, { name: 'Lytx, Inc.', domainName: 'lytx.com', - address: 'San Diego', + addressAddressCity: 'San Diego', employees: 845, linkedinLinkUrl: 'https://linkedin.com/company/lytxinc', }, { name: 'Pendo.io', domainName: 'pendo.io', - address: 'Raleigh', + addressAddressCity: 'Raleigh', employees: 844, linkedinLinkUrl: 'https://linkedin.com/company/pendo-io', }, { name: 'Workato', domainName: 'workato.com', - address: 'Mountain View', + addressAddressCity: 'Mountain View', employees: 842, linkedinLinkUrl: 'https://linkedin.com/company/workato', }, { name: 'Saviynt', domainName: 'saviynt.com', - address: 'El Segundo', + addressAddressCity: 'El Segundo', employees: 842, linkedinLinkUrl: 'https://linkedin.com/company/saviynt', }, { name: 'SmartBear', domainName: 'smartbear.com', - address: 'Somerville', + addressAddressCity: 'Somerville', employees: 838, linkedinLinkUrl: 'https://linkedin.com/company/smartbear', }, { name: 'Rovi Corporation (now TiVo)', domainName: 'tivo.com', - address: 'San Carlos', + addressAddressCity: 'San Carlos', employees: 837, linkedinLinkUrl: 'https://linkedin.com/company/rovi', }, { name: 'Handshake', domainName: 'joinhandshake.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 833, linkedinLinkUrl: 'https://linkedin.com/company/team-handshake', }, { name: 'Navitaire, an Amadeus company', domainName: 'navitaire.com', - address: 'Minneapolis', + addressAddressCity: 'Minneapolis', employees: 829, linkedinLinkUrl: 'https://linkedin.com/company/navitaire', }, { name: 'OneSpan', domainName: 'onespan.com', - address: 'Chicago', + addressAddressCity: 'Chicago', employees: 826, linkedinLinkUrl: 'https://linkedin.com/company/onespan', }, { name: 'Bitsight', domainName: 'bitsight.com', - address: 'Boston', + addressAddressCity: 'Boston', employees: 824, linkedinLinkUrl: 'https://linkedin.com/company/bitsight', }, { name: 'ID.me', domainName: 'id.me', - address: 'Mc Lean', + addressAddressCity: 'Mc Lean', employees: 823, linkedinLinkUrl: 'https://linkedin.com/company/id.me', }, { name: 'SymphonyAI Retail CPG', domainName: 'symphonyretailai.com', - address: 'Frisco', + addressAddressCity: 'Frisco', employees: 823, linkedinLinkUrl: 'https://linkedin.com/company/symphonyretailcpg', }, { name: 'Unilog', domainName: 'unilogcorp.com', - address: 'Wayne', + addressAddressCity: 'Wayne', employees: 823, linkedinLinkUrl: 'https://linkedin.com/company/unilog-inc', }, { name: 'Teletrac Navman', domainName: 'teletracnavman.com', - address: 'Irvine', + addressAddressCity: 'Irvine', employees: 821, linkedinLinkUrl: 'https://linkedin.com/company/teletrac', }, { name: 'Buildertrend', domainName: 'buildertrend.com', - address: 'Omaha', + addressAddressCity: 'Omaha', employees: 819, linkedinLinkUrl: 'https://linkedin.com/company/buildertrend', }, { name: 'Tecsys Inc.', domainName: 'tecsys.com', - address: 'Chicago', + addressAddressCity: 'Chicago', employees: 816, linkedinLinkUrl: 'https://linkedin.com/company/tecsys-inc', }, { name: 'ThousandEyes (part of Cisco)', domainName: 'thousandeyes.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 816, linkedinLinkUrl: 'https://linkedin.com/company/thousandeyes', }, { name: 'Greenhouse Software', domainName: 'greenhouse.io', - address: 'New York', + addressAddressCity: 'New York', employees: 814, linkedinLinkUrl: 'https://linkedin.com/company/greenhouse-inc-', }, { name: 'Exiger', domainName: 'exiger.com', - address: 'New York', + addressAddressCity: 'New York', employees: 811, linkedinLinkUrl: 'https://linkedin.com/company/exiger', }, { name: 'MBO Partners', domainName: 'mbopartners.com', - address: 'Ashburn', + addressAddressCity: 'Ashburn', employees: 808, linkedinLinkUrl: 'https://linkedin.com/company/mbo-partners', }, { name: 'Neo4j', domainName: 'neo4j.com', - address: 'San Mateo', + addressAddressCity: 'San Mateo', employees: 808, linkedinLinkUrl: 'https://linkedin.com/company/neo4j', }, { name: 'VTS', domainName: 'vts.com', - address: 'New York', + addressAddressCity: 'New York', employees: 805, linkedinLinkUrl: 'https://linkedin.com/company/we-are-vts', }, { name: 'Slice', domainName: 'slicelife.com', - address: 'New York', + addressAddressCity: 'New York', employees: 805, linkedinLinkUrl: 'https://linkedin.com/company/slice', }, { name: 'Amplitude', domainName: 'amplitude.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 803, linkedinLinkUrl: 'https://linkedin.com/company/amplitude-analytics', }, { name: 'Daxko', domainName: 'daxko.com', - address: 'Birmingham', + addressAddressCity: 'Birmingham', employees: 802, linkedinLinkUrl: 'https://linkedin.com/company/daxko', }, { name: 'AppLovin', domainName: 'applovin.com', - address: 'Palo Alto', + addressAddressCity: 'Palo Alto', employees: 802, linkedinLinkUrl: 'https://linkedin.com/company/applovin', }, { name: 'Xometry', domainName: 'xometry.com', - address: 'Rockville', + addressAddressCity: 'Rockville', employees: 801, linkedinLinkUrl: 'https://linkedin.com/company/xometry', }, { name: 'Quickbase', domainName: 'quickbase.com', - address: 'Boston', + addressAddressCity: 'Boston', employees: 796, linkedinLinkUrl: 'https://linkedin.com/company/quickbase', }, { name: 'Agora', domainName: 'agora.io', - address: 'Santa Clara', + addressAddressCity: 'Santa Clara', employees: 793, linkedinLinkUrl: 'https://linkedin.com/company/agora-lab-inc', }, { name: 'InMoment', domainName: 'inmoment.com', - address: 'South Jordan', + addressAddressCity: 'South Jordan', employees: 793, linkedinLinkUrl: 'https://linkedin.com/company/weareinmoment', }, { name: 'PatientPoint\u00ae', domainName: 'patientpoint.com', - address: 'Cincinnati', + addressAddressCity: 'Cincinnati', employees: 789, linkedinLinkUrl: 'https://linkedin.com/company/patientpoint', }, { name: 'HHAeXchange', domainName: 'hhaexchange.com', - address: 'New York', + addressAddressCity: 'New York', employees: 788, linkedinLinkUrl: 'https://linkedin.com/company/hhaexchange', }, { name: 'NinjaOne', domainName: 'ninjaone.com', - address: 'Austin', + addressAddressCity: 'Austin', employees: 787, linkedinLinkUrl: 'https://linkedin.com/company/ninjaone', }, { name: 'Zywave', domainName: 'zywave.com', - address: 'Milwaukee', + addressAddressCity: 'Milwaukee', employees: 785, linkedinLinkUrl: 'https://linkedin.com/company/zywave', }, { name: 'Adobe Marketo', domainName: 'marketo.com', - address: 'San Jose', + addressAddressCity: 'San Jose', employees: 784, linkedinLinkUrl: 'https://linkedin.com/company/adobemarketoengage', }, { name: 'MasterControl', domainName: 'mastercontrol.com', - address: 'Salt Lake City', + addressAddressCity: 'Salt Lake City', employees: 783, linkedinLinkUrl: 'https://linkedin.com/company/mastercontrol', }, { name: 'Jumio Corporation', domainName: 'jumio.com', - address: 'Sunnyvale', + addressAddressCity: 'Sunnyvale', employees: 779, linkedinLinkUrl: 'https://linkedin.com/company/jumio-corporation', }, { name: 'CRMNEXT', domainName: 'crmnext.com', - address: 'Raleigh', + addressAddressCity: 'Raleigh', employees: 778, linkedinLinkUrl: 'https://linkedin.com/company/crmnext', }, { name: 'ChannelAdvisor', domainName: 'channeladvisor.com', - address: 'Morrisville', + addressAddressCity: 'Morrisville', employees: 777, linkedinLinkUrl: 'https://linkedin.com/company/channeladvisor', }, { name: 'SumTotal Systems, LLC', domainName: 'sumtotalsystems.com', - address: 'Gainesville', + addressAddressCity: 'Gainesville', employees: 776, linkedinLinkUrl: 'https://linkedin.com/company/sumtotal-systems', }, { name: 'Payscale', domainName: 'payscale.com', - address: 'Seattle', + addressAddressCity: 'Seattle', employees: 775, linkedinLinkUrl: 'https://linkedin.com/company/payscale', }, { name: 'Riskonnect, Inc.', domainName: 'riskonnect.com', - address: 'Kennesaw', + addressAddressCity: 'Kennesaw', employees: 775, linkedinLinkUrl: 'https://linkedin.com/company/riskonnect-inc', }, { name: 'Riskified', domainName: 'riskified.com', - address: 'New York', + addressAddressCity: 'New York', employees: 770, linkedinLinkUrl: 'https://linkedin.com/company/riskified', }, { name: 'Shopkeeper', domainName: 'shopkeeper.com', - address: 'Pompano Beach', + addressAddressCity: 'Pompano Beach', employees: 770, linkedinLinkUrl: 'https://linkedin.com/company/shopkeeperapp', }, { name: 'Stack Overflow', domainName: 'stackoverflow.com', - address: 'New York', + addressAddressCity: 'New York', employees: 768, linkedinLinkUrl: 'https://linkedin.com/company/stack-overflow', }, { name: 'Netwrix Corporation', domainName: 'netwrix.com', - address: 'Frisco', + addressAddressCity: 'Frisco', employees: 768, linkedinLinkUrl: 'https://linkedin.com/company/netwrix-corporation', }, { name: 'Securonix', domainName: 'securonix.com', - address: 'Addison', + addressAddressCity: 'Addison', employees: 767, linkedinLinkUrl: 'https://linkedin.com/company/securonix', }, { name: 'Draup', domainName: 'draup.com', - address: 'Spring', + addressAddressCity: 'Spring', employees: 766, linkedinLinkUrl: 'https://linkedin.com/company/draupplatform', }, { name: 'eQ Technologic', domainName: '1eq.com', - address: 'Costa Mesa', + addressAddressCity: 'Costa Mesa', employees: 766, linkedinLinkUrl: 'https://linkedin.com/company/eq-technologic', }, { name: 'Mindtickle', domainName: 'mindtickle.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 765, linkedinLinkUrl: 'https://linkedin.com/company/mindtickle', }, { name: 'Omnitracs', domainName: 'omnitracs.com', - address: 'Roanoke', + addressAddressCity: 'Roanoke', employees: 764, linkedinLinkUrl: 'https://linkedin.com/company/omnitracs', }, { name: 'Programmer', domainName: 'gregoryleroy.com', - address: 'Austin', + addressAddressCity: 'Austin', employees: 762, linkedinLinkUrl: 'https://linkedin.com/company/programmer', }, { name: 'Navis', domainName: 'navis.com', - address: 'Alpharetta', + addressAddressCity: 'Alpharetta', employees: 761, linkedinLinkUrl: 'https://linkedin.com/company/navis', }, { name: 'AuditBoard', domainName: 'auditboard.com', - address: 'Cerritos', + addressAddressCity: 'Cerritos', employees: 759, linkedinLinkUrl: 'https://linkedin.com/company/auditboard', }, { name: 'Algolia', domainName: 'algolia.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 759, linkedinLinkUrl: 'https://linkedin.com/company/algolia', }, { name: 'YML', domainName: 'yml.co', - address: 'Redwood City', + addressAddressCity: 'Redwood City', employees: 754, linkedinLinkUrl: 'https://linkedin.com/company/ymlco', }, { name: 'Bolt', domainName: 'bolt.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 750, linkedinLinkUrl: 'https://linkedin.com/company/bolt-com', }, { name: 'Dandy', domainName: 'meetdandy.com', - address: 'New York', + addressAddressCity: 'New York', employees: 745, linkedinLinkUrl: 'https://linkedin.com/company/dandyofficial', }, { name: 'Diverse Lynx', domainName: 'diverselynx.com', - address: 'Princeton', + addressAddressCity: 'Princeton', employees: 743, linkedinLinkUrl: 'https://linkedin.com/company/diverselynx', }, { name: 'JMP', domainName: 'jmp.com', - address: 'Cary', + addressAddressCity: 'Cary', employees: 741, linkedinLinkUrl: 'https://linkedin.com/company/jmp', }, { name: 'ON24', domainName: 'on24.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 741, linkedinLinkUrl: 'https://linkedin.com/company/on24', }, { name: 'LabVantage Solutions, Inc', domainName: 'labvantage.com', - address: 'Somerset', + addressAddressCity: 'Somerset', employees: 740, linkedinLinkUrl: 'https://linkedin.com/company/labvantage', }, { name: 'Exabeam', domainName: 'exabeam.com', - address: 'San Mateo', + addressAddressCity: 'San Mateo', employees: 739, linkedinLinkUrl: 'https://linkedin.com/company/exabeam', }, { name: 'Iterable', domainName: 'iterable.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 739, linkedinLinkUrl: 'https://linkedin.com/company/iterable', }, { name: 'Clari', domainName: 'clari.com', - address: 'Sunnyvale', + addressAddressCity: 'Sunnyvale', employees: 737, linkedinLinkUrl: 'https://linkedin.com/company/clari', }, { name: 'Komodo Health', domainName: 'komodohealth.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 737, linkedinLinkUrl: 'https://linkedin.com/company/komodo-health', }, { name: 'Alation', domainName: 'alation.com', - address: 'Redwood City', + addressAddressCity: 'Redwood City', employees: 736, linkedinLinkUrl: 'https://linkedin.com/company/alation', }, { name: 'Celigo', domainName: 'celigo.com', - address: 'Redwood City', + addressAddressCity: 'Redwood City', employees: 733, linkedinLinkUrl: 'https://linkedin.com/company/celigo-inc', }, { name: 'Aptos Retail', domainName: 'aptos.com', - address: 'Alpharetta', + addressAddressCity: 'Alpharetta', employees: 733, linkedinLinkUrl: 'https://linkedin.com/company/aptos-retail', }, { name: 'WorkForce Software', domainName: 'workforcesoftware.com', - address: 'Livonia', + addressAddressCity: 'Livonia', employees: 721, linkedinLinkUrl: 'https://linkedin.com/company/workforce-software', }, { name: 'HPE Security - Data Security', domainName: 'voltage.com', - address: 'Sunnyvale', + addressAddressCity: 'Sunnyvale', employees: 713, linkedinLinkUrl: 'https://linkedin.com/company/hpe-security-data-security', }, { name: 'DDN Storage', domainName: 'ddn.com', - address: 'Chatsworth', + addressAddressCity: 'Chatsworth', employees: 712, linkedinLinkUrl: 'https://linkedin.com/company/ddn-storage', }, { name: 'KPA', domainName: 'kpa.io', - address: 'Broomfield', + addressAddressCity: 'Broomfield', employees: 709, linkedinLinkUrl: 'https://linkedin.com/company/kpa-llc', }, { name: 'Lohika', domainName: 'lohika.com', - address: 'San Mateo', + addressAddressCity: 'San Mateo', employees: 705, linkedinLinkUrl: 'https://linkedin.com/company/lohika', }, { name: 'Qualifacts', domainName: 'qualifacts.com', - address: 'Nashville', + addressAddressCity: 'Nashville', employees: 705, linkedinLinkUrl: 'https://linkedin.com/company/qualifacts', }, { name: 'Centric Software', domainName: 'centricsoftware.com', - address: 'Campbell', + addressAddressCity: 'Campbell', employees: 705, linkedinLinkUrl: 'https://linkedin.com/company/centric-software', }, { name: 'Omdena', domainName: 'omdena.com', - address: 'New York', + addressAddressCity: 'New York', employees: 704, linkedinLinkUrl: 'https://linkedin.com/company/omdena', }, { name: 'AccountantsWorld', domainName: 'accountantsworld.com', - address: 'Hauppauge', + addressAddressCity: 'Hauppauge', employees: 704, linkedinLinkUrl: 'https://linkedin.com/company/accountantsworld', }, { name: 'Aderant', domainName: 'aderant.com', - address: 'Atlanta', + addressAddressCity: 'Atlanta', employees: 704, linkedinLinkUrl: 'https://linkedin.com/company/aderant', }, { name: 'Python Software Foundation', domainName: 'python.org', - address: 'Beaverton', + addressAddressCity: 'Beaverton', employees: 704, linkedinLinkUrl: 'https://linkedin.com/company/python-software-foundation', }, { name: 'OpenGov Inc.', domainName: 'opengov.com', - address: 'San Jose', + addressAddressCity: 'San Jose', employees: 703, linkedinLinkUrl: 'https://linkedin.com/company/opengov-inc', }, { name: 'Denodo', domainName: 'denodo.com', - address: 'Palo Alto', + addressAddressCity: 'Palo Alto', employees: 702, linkedinLinkUrl: 'https://linkedin.com/company/denodo-technologies', }, { name: 'NEOGOV', domainName: 'neogov.com', - address: 'El Segundo', + addressAddressCity: 'El Segundo', employees: 698, linkedinLinkUrl: 'https://linkedin.com/company/neogov', }, { name: 'VertexOne', domainName: 'vertexone.net', - address: 'Dallas', + addressAddressCity: 'Dallas', employees: 696, linkedinLinkUrl: 'https://linkedin.com/company/vertex-one', }, { name: 'The Linux Foundation', domainName: 'linuxfoundation.org', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 694, linkedinLinkUrl: 'https://linkedin.com/company/the-linux-foundation', }, { name: 'Reputation', domainName: 'reputation.com', - address: 'San Ramon', + addressAddressCity: 'San Ramon', employees: 694, linkedinLinkUrl: 'https://linkedin.com/company/reputation-com', }, { name: 'Relevantz ', domainName: 'relevantz.com', - address: 'Alpharetta', + addressAddressCity: 'Alpharetta', employees: 691, linkedinLinkUrl: 'https://linkedin.com/company/relevantz', }, { name: 'M-Files', domainName: 'm-files.com', - address: 'Austin', + addressAddressCity: 'Austin', employees: 691, linkedinLinkUrl: 'https://linkedin.com/company/m-files-corporation', }, { name: 'Homebase', domainName: 'joinhomebase.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 688, linkedinLinkUrl: 'https://linkedin.com/company/homebase-app', }, { name: 'Calypso Technology', domainName: 'calypso.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 688, linkedinLinkUrl: 'https://linkedin.com/company/calypso-technology', }, { name: 'Viewpoint', domainName: 'viewpoint.com', - address: 'Broomfield', + addressAddressCity: 'Broomfield', employees: 686, linkedinLinkUrl: 'https://linkedin.com/company/viewpoint-construction-software', @@ -3895,315 +3895,315 @@ export const companiesDemo = [ { name: 'Devo', domainName: 'devo.com', - address: 'Cambridge', + addressAddressCity: 'Cambridge', employees: 685, linkedinLinkUrl: 'https://linkedin.com/company/devoinc', }, { name: 'WebPT', domainName: 'webpt.com', - address: 'Phoenix', + addressAddressCity: 'Phoenix', employees: 685, linkedinLinkUrl: 'https://linkedin.com/company/webpt', }, { name: 'MatrixCare', domainName: 'matrixcare.com', - address: 'Minneapolis', + addressAddressCity: 'Minneapolis', employees: 683, linkedinLinkUrl: 'https://linkedin.com/company/matrixcare', }, { name: 'Sisense', domainName: 'sisense.com', - address: 'New York', + addressAddressCity: 'New York', employees: 683, linkedinLinkUrl: 'https://linkedin.com/company/sisense', }, { name: 'Calendly', domainName: 'calendly.com', - address: 'Atlanta', + addressAddressCity: 'Atlanta', employees: 681, linkedinLinkUrl: 'https://linkedin.com/company/calendly', }, { name: 'Placer.ai', domainName: 'placer.io', - address: 'Los Altos', + addressAddressCity: 'Los Altos', employees: 677, linkedinLinkUrl: 'https://linkedin.com/company/placer', }, { name: 'MResult', domainName: 'mresult.com', - address: 'Mystic', + addressAddressCity: 'Mystic', employees: 674, linkedinLinkUrl: 'https://linkedin.com/company/mresult', }, { name: 'Coherent Solutions', domainName: 'coherentsolutions.com', - address: 'Minneapolis', + addressAddressCity: 'Minneapolis', employees: 672, linkedinLinkUrl: 'https://linkedin.com/company/coherent-solutions', }, { name: 'Mirantis', domainName: 'mirantis.com', - address: 'Campbell', + addressAddressCity: 'Campbell', employees: 671, linkedinLinkUrl: 'https://linkedin.com/company/mirantis', }, { name: 'Simplify Healthcare', domainName: 'simplifyhealthcare.com', - address: 'Aurora', + addressAddressCity: 'Aurora', employees: 671, linkedinLinkUrl: 'https://linkedin.com/company/simplifyhealthcare', }, { name: 'JumpCloud', domainName: 'jumpcloud.com', - address: 'Louisville', + addressAddressCity: 'Louisville', employees: 671, linkedinLinkUrl: 'https://linkedin.com/company/jumpcloud', }, { name: 'ASAP', domainName: 'asap.com', - address: 'Lafayette', + addressAddressCity: 'Lafayette', employees: 667, linkedinLinkUrl: 'https://linkedin.com/company/asap', }, { name: 'Xoxoday', domainName: 'xoxoday.com', - address: 'Redwood City', + addressAddressCity: 'Redwood City', employees: 666, linkedinLinkUrl: 'https://linkedin.com/company/xoxoday', }, { name: 'DataStax', domainName: 'datastax.com', - address: 'Santa Clara', + addressAddressCity: 'Santa Clara', employees: 666, linkedinLinkUrl: 'https://linkedin.com/company/datastax', }, { name: 'Foursquare', domainName: 'foursquare.com', - address: 'New York', + addressAddressCity: 'New York', employees: 665, linkedinLinkUrl: 'https://linkedin.com/company/foursquare', }, { name: 'LastPass', domainName: 'lastpass.com', - address: 'Boston', + addressAddressCity: 'Boston', employees: 664, linkedinLinkUrl: 'https://linkedin.com/company/lastpass', }, { name: 'SOCi, Inc.', domainName: 'meetsoci.com', - address: 'San Diego', + addressAddressCity: 'San Diego', employees: 664, linkedinLinkUrl: 'https://linkedin.com/company/soci-inc-', }, { name: 'Stratus Technologies', domainName: 'stratus.com', - address: 'Maynard', + addressAddressCity: 'Maynard', employees: 662, linkedinLinkUrl: 'https://linkedin.com/company/stratus-technologies', }, { name: 'AdvancedMD', domainName: 'advancedmd.com', - address: 'South Jordan', + addressAddressCity: 'South Jordan', employees: 661, linkedinLinkUrl: 'https://linkedin.com/company/advancedmd', }, { name: 'Matterport', domainName: 'matterport.com', - address: 'Sunnyvale', + addressAddressCity: 'Sunnyvale', employees: 660, linkedinLinkUrl: 'https://linkedin.com/company/matterport', }, { name: 'Samsung Research America (SRA)', domainName: 'sra.samsung.com', - address: 'Mountain View', + addressAddressCity: 'Mountain View', employees: 658, linkedinLinkUrl: 'https://linkedin.com/company/sra-samsungreasearchamerica', }, { name: 'Creatio', domainName: 'creatio.com', - address: 'Boston', + addressAddressCity: 'Boston', employees: 657, linkedinLinkUrl: 'https://linkedin.com/company/creatioglobal', }, { name: 'Branch', domainName: 'branch.io', - address: 'Palo Alto', + addressAddressCity: 'Palo Alto', employees: 657, linkedinLinkUrl: 'https://linkedin.com/company/branch-metrics', }, { name: 'Versa Networks', domainName: 'versa-networks.com', - address: 'Alviso', + addressAddressCity: 'Alviso', employees: 655, linkedinLinkUrl: 'https://linkedin.com/company/versa-networks', }, { name: 'Mitek Systems', domainName: 'miteksystems.com', - address: 'San Diego', + addressAddressCity: 'San Diego', employees: 653, linkedinLinkUrl: 'https://linkedin.com/company/miteksystems', }, { name: 'PDF Solutions', domainName: 'pdf.com', - address: 'Santa Clara', + addressAddressCity: 'Santa Clara', employees: 653, linkedinLinkUrl: 'https://linkedin.com/company/pdf-solutions', }, { name: 'ESO', domainName: 'eso.com', - address: 'Austin', + addressAddressCity: 'Austin', employees: 652, linkedinLinkUrl: 'https://linkedin.com/company/eso-solutions', }, { name: 'Mural', domainName: 'mural.co', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 650, linkedinLinkUrl: 'https://linkedin.com/company/mural.co', }, { name: 'FourKites, Inc.', domainName: 'fourkites.com', - address: 'Chicago', + addressAddressCity: 'Chicago', employees: 650, linkedinLinkUrl: 'https://linkedin.com/company/fourkites-inc', }, { name: 'Aras Corporation', domainName: 'aras.com', - address: 'Andover', + addressAddressCity: 'Andover', employees: 648, linkedinLinkUrl: 'https://linkedin.com/company/aras-corporation', }, { name: 'Delphix', domainName: 'delphix.com', - address: 'Redwood City', + addressAddressCity: 'Redwood City', employees: 648, linkedinLinkUrl: 'https://linkedin.com/company/delphix', }, { name: 'Wolfram', domainName: 'wolfram.com', - address: 'Champaign', + addressAddressCity: 'Champaign', employees: 644, linkedinLinkUrl: 'https://linkedin.com/company/wolfram-research', }, { name: 'Eightfold', domainName: 'eightfold.ai', - address: 'Santa Clara', + addressAddressCity: 'Santa Clara', employees: 643, linkedinLinkUrl: 'https://linkedin.com/company/eightfoldai', }, { name: 'Quark Software Inc.', domainName: 'quark.com', - address: 'Grand Rapids', + addressAddressCity: 'Grand Rapids', employees: 641, linkedinLinkUrl: 'https://linkedin.com/company/quark', }, { name: 'connectRN', domainName: 'connectrn.com', - address: 'Waltham', + addressAddressCity: 'Waltham', employees: 640, linkedinLinkUrl: 'https://linkedin.com/company/connectrn', }, { name: 'RSI', domainName: 'rsidelivers.com', - address: 'Pembroke', + addressAddressCity: 'Pembroke', employees: 638, linkedinLinkUrl: 'https://linkedin.com/company/revenue-solutions-inc-', }, { name: 'Macrosoft', domainName: 'macrosoftinc.com', - address: 'Parsippany', + addressAddressCity: 'Parsippany', employees: 638, linkedinLinkUrl: 'https://linkedin.com/company/macrosoft', }, { name: 'Paradox', domainName: 'paradox.ai', - address: 'Scottsdale', + addressAddressCity: 'Scottsdale', employees: 637, linkedinLinkUrl: 'https://linkedin.com/company/paradoxolivia', }, { name: 'SmartRecruiters', domainName: 'smartrecruiters.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 637, linkedinLinkUrl: 'https://linkedin.com/company/smartrecruiters', }, { name: 'Tealium', domainName: 'tealium.com', - address: 'San Diego', + addressAddressCity: 'San Diego', employees: 635, linkedinLinkUrl: 'https://linkedin.com/company/tealium', }, { name: 'Securiti', domainName: 'securiti.ai', - address: 'San Jose', + addressAddressCity: 'San Jose', employees: 634, linkedinLinkUrl: 'https://linkedin.com/company/securitiai', }, { name: 'Lattice', domainName: 'lattice.com', - address: 'San Francisco', + addressAddressCity: 'San Francisco', employees: 634, linkedinLinkUrl: 'https://linkedin.com/company/lattice-hq', }, { name: 'TuSimple', domainName: 'tusimple.com', - address: 'San Diego', + addressAddressCity: 'San Diego', employees: 633, linkedinLinkUrl: 'https://linkedin.com/company/tusimple', }, { name: 'Ceipal', domainName: 'ceipal.com', - address: 'Rochester', + addressAddressCity: 'Rochester', employees: 633, linkedinLinkUrl: 'https://linkedin.com/company/ceipal', }, { name: 'RSD', domainName: 'rocketsoftware.com', - address: 'Waltham', + addressAddressCity: 'Waltham', employees: 633, linkedinLinkUrl: 'https://linkedin.com/company/rsd', }, diff --git a/packages/twenty-server/src/engine/workspace-manager/demo-objects-prefill-data/company.ts b/packages/twenty-server/src/engine/workspace-manager/demo-objects-prefill-data/company.ts index 49834df3933a..7476368f9ae3 100644 --- a/packages/twenty-server/src/engine/workspace-manager/demo-objects-prefill-data/company.ts +++ b/packages/twenty-server/src/engine/workspace-manager/demo-objects-prefill-data/company.ts @@ -12,7 +12,7 @@ export const companyPrefillDemoData = async ( .into(`${schemaName}.company`, [ 'name', 'domainName', - 'address', + 'addressAddressCity', 'employees', 'linkedinLinkUrl', 'position', diff --git a/packages/twenty-server/src/engine/workspace-manager/demo-objects-prefill-data/opportunity.ts b/packages/twenty-server/src/engine/workspace-manager/demo-objects-prefill-data/opportunity.ts index e2d53abfb311..23c51142980f 100644 --- a/packages/twenty-server/src/engine/workspace-manager/demo-objects-prefill-data/opportunity.ts +++ b/packages/twenty-server/src/engine/workspace-manager/demo-objects-prefill-data/opportunity.ts @@ -3,12 +3,6 @@ import { v4 } from 'uuid'; const tableName = 'opportunity'; -const getRandomProbability = () => { - const firstDigit = Math.floor(Math.random() * 9) + 1; - - return firstDigit / 10; -}; - const getRandomStage = () => { const stages = ['NEW', 'SCREENING', 'MEETING', 'PROPOSAL', 'CUSTOMER']; @@ -28,7 +22,6 @@ const generateOpportunities = (companies) => { amountCurrencyCode: 'USD', closeDate: new Date(), stage: getRandomStage(), - probability: getRandomProbability(), pointOfContactId: company.personId, companyId: company.id, })); @@ -56,7 +49,6 @@ export const opportunityPrefillDemoData = async ( 'amountCurrencyCode', 'closeDate', 'stage', - 'probability', 'pointOfContactId', 'companyId', 'position', diff --git a/packages/twenty-server/src/engine/workspace-manager/demo-objects-prefill-data/people-demo.json.ts b/packages/twenty-server/src/engine/workspace-manager/demo-objects-prefill-data/people-demo.json.ts index 2bd808d0bc65..0af53c10f23f 100644 --- a/packages/twenty-server/src/engine/workspace-manager/demo-objects-prefill-data/people-demo.json.ts +++ b/packages/twenty-server/src/engine/workspace-manager/demo-objects-prefill-data/people-demo.json.ts @@ -5,7 +5,7 @@ export const peopleDemo = [ city: 'West Justin', email: 'mark.young@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDkjRTsUhO1WY9gTQBWvL+CwQGZiWI+VF6msmXXrh1JVkt/7q4yT+NSaNoN14i1CSSSUqoPzSMMj6Cu3svhjZ5Z7i4eXd0GMYrKVWKdjeFCcldI83fUb2M+YL92Y8gbuvtitK18SrsVLyNt+cF1HGPXFdnefDGxCFo7iVWHIPpXG6v4PurHe8TiREGSehqVWi3uXLDzSvY2ldZFDowZTyCDkGlHWuZ8O3Tx3TWbsNrglVz0IrpwOa2TuczVgxzVbUHKWEzDrjH51bxVa+tnutPnijGXKErk45HND2BbnS+D4Y10yFl4MpLfXmu5jDRxqD+FeZwadK2haaqRzGTygQyMRsOM9O5rW8J3+rSOLaXzyjZw03Ue3PSvPkt5HrQeiidlOrmM9hXKayA0LqpBJBzWX4in1m7uJ1R7kQQgkiE/ex2A7moNPtZEQqY5UOMtvYkH3PvS5dLluTvynn0k3la/G8Y+64Xp2zXcBa5pdIeTxLJKSFhin5JB5OcgV1SrXfBpo8qpFp6kWOamtgjTokg+Rjtb6HimYoHBqmrqxnF2aZ2mhIn9npa3AG+MbGB6cVejW2i1FIk8tFUEtjAzXP6VcNIDIx5z82Kh1G702/KmW4igdSQrliGHqMivOad2j2YyTimjZsRDPcTRybGySRnnPNR6rFDbwssagZHasDS7qw052FrcRzKz8sH5zn0NXtSmMwIJ7ZNJq2g2zGgt9kMs38ErliDzls8EU0VFbyXbm5SZv3KOBEMDgY5/U1IOtd1GNo37nmYipzSsug3FAB7Cp0hLnjoOp9K3tA0yO4u9zAOsS72z39BWjdtDCxnWFteJDJKsbbNuTxzj1q6LeW5t0e1uIEYDA3rlcfSu2+xBbIxqByu9/f0Fed6haSw3s6W5aNlwVAPDAjP881zVo2fMd2GqNLlJnha2UvczW8j/AOwOKrh/tJG05zyTWUVup5dsuOvI9a3rG1WCMDHzGueWh03cnqVtB0hrrxhqNtKjfZpbdZc54DdOPfirF/oc1hJtlDAH7rDkNXXeGLRcXF5gbpMRqf8AZH/166O7sYLi38qeMOh4INdlNPkR5tZr2jsf/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-1.png', linkedinUrl: '/in/mark-young-7edccf6aca', jobTitle: 'Surveyor, minerals', }, @@ -15,7 +15,7 @@ export const peopleDemo = [ city: 'Larryview', email: 'gabriel.robinson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDYxSGn4ppFeedpDLIkMTSyuqRqMszHAArh9W+IiRO8WmQCTHAmkzg+4WtXxb52oPaaJbEb7lt8mf4UX1/H+VSQ/DfTnSM75Nw+8SetXHlWsg5Zy+E4Sbx1r7uHF2UA6hY1A/lWlY/EvUI5R9ut4Z4u+wbW/wAK7lvh7ohj2tA5OOofFY958PNKRGEfmrnoS2cVftKb6C9jUXU19F8R6drsebaULL3hcgMPw71sha8OvdOufD+qsI5CHhbcjqeR71694W1ga7okdyceeh8uYAdGH+IwamcLarYUZNuz3NQiozUtMIqCjHtLfzvFN5OwyY444k9uNx/nXWR5VQMflXDatJcWt5O8L3C+ZggW6gsSFHrWn4avdSnJhvHYgR71dxhvofeiS6m9OWljqHyAc1l3p+T3Ncpq82tG9cxT3TQryUiIG7noKt2M96xEUq3AGM4mwSPoR1pculyubWxxviaMzXLvICHBOa2vhgHWXU0yfKIRsehyR/KmeMLUH7PIp+ZsqfetP4c2E1quovcRmJnMYVGPzY55x261qneFjllFqdzqe1MJp1MPNZjJLeKGUsJAMg01bqxgW6ZZoU2DB5xiqM0rQyuQTjbmspnsLucyNHK8nGfLiJBx2zSSuzpjsrHR2NzYXbbA8cmQCGXkH8atXEUMKkqAD7VzcN5DE3lRwzruOMNERj3zWvI58sbm+bbmhqxVzDv7WO6uomkbHlPvB7Vq6RFi9adhhli8tiBgNz1rJubgwytMFDiMbivrXRWqMkILDDt8zD09qaRnKSSfmITTcZp2KMUznKGpRuIfOQZ2feH+zSrb+eqtHOIiRk7e9aAAPWuNvZruGdn08iWAudq+nPai3U0hNo6tlS3gJ8wMcck1jXF/sUgNuJ6eprCiuNWvHMbI0frkYxWvp+luh3zHLUmki02x9psimjmu5EjTcCzOcAD3NdQrJIoeNlZTyGU5BrldbsTfWT2SNtaUbd390dzWtopitYF09CAsSgRj2rWEG4ORjVlaaR//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-2.png', linkedinUrl: '/in/gabriel-robinson-3157ccba23', jobTitle: 'Armed forces logistics/support/administrative officer', }, @@ -25,7 +25,7 @@ export const peopleDemo = [ city: 'Victoriamouth', email: 'kimberly.gordon@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0ygkAEkgAdzTQ1ecfFXxUdO01dHtJNt1dD94VPKR/4np+dNsEa+r/ABN8PaXO9uksl3KnDfZwCoPpknFUtP8Aivo9yZftkE1oqjKsfm3e3HevKfD3hW/12QeREVjB5lYcV6Ba/CmB4dt1eSFyONgwKydVJm0aMpK6R1Fh8R/DeoXIt1u2hdjhTOm1T+PSurGGGQQR7V4xq3wture3aWyuRKV58thg/ga1vhr4ruY7tvDerORLGMW5kPzcdU9/aqjNS2JnTlHc9SxRSbx60hcVZmRzSiGCSQjOxS2PXFfNOq3s2t+Jrm4unLSzTbfZRnGBX0ffRSXFhcQxNskeNlRvQ44r5t0K1ceJoYLhW3RynzARkkqef5VM3ZFQV3Y918NWkNjpMEMShQq+ldIpGztXnl7qa21sGkhupEcfLHECD+ODU2kXMtrJ5oNzHC20lJZN2M9Pxrht1PSv0O4m5XpXkXxDsF07VrDW7YeVIko3leOQcg11XiPUJVlfd9r8mMgMkB+b9DXNeJIv7W0CWKEzqIiH/wBIySCP8RVw0kmRV1i0eq6fcfa7CGc4yy846ZqzWdoabNGtQAQDGCAwwRxWjniu1Hmja821Hw5BYeKJr+LdliXOf9rP/wBevRmbapJrynxX46W38QraWqx3Nu22ORj2bPOD34rKsm46G9CSjLU7GzjSaIAELj15FLeva2boLiaNEBBJYADOePxqGxQ4Uq3ymjUdWW3cQLp0ly/XO35f/r1xLseoknsWppbK51LENwjF1G4DnntWT4rsnfw5fQ2oLzeUSqrgZqSx1FJJzA+lPa5AKsF4/OpZdRS11qxs3AdrpmByfuqB1/PFXFPmSM6toxdzo9GWSPRrJJs+asKB8+uBmrtNXgClzXeeQYHiZJ5rKKFHaOB5AJ2U4O30z6E14XfWE1v4iXzYJFV5x5IK4DDcMYr6LliNwjRr90jBNYl54ehu44i0amaB98RI6HpXnVsdCM1GOqO6jhm43loZQmazYBs7D0NX4xY36fv5OPY4xU01kssIVh2wcjpWM+jurnypcCoTOw1HisrJWMUpOf7zZNcdqVtqd34qtNRSGQW8OFUdwufvfQ5rT1O3mt9KnMJzMVO0mui0ND/Z9vOh3AoCM+hqvbRptc3UxqxlNaG5ayb4xzxgYqYmoo2UDptJp+RXoRnGSumeKLT1R//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-3.png', linkedinUrl: '/in/kimberly-gordon-4a10fde4c9', jobTitle: 'Engineer, manufacturing systems', }, @@ -35,7 +35,7 @@ export const peopleDemo = [ city: 'Franciscoland', email: 'cindy.baker@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0FnA+lYt94msbKQozF3XqE5rnvEXimYQulqdsZO0bfvOa4yW8khHm3b/vD0B4C+w9/esJVdbI3jS6yO9uvH8VthRb5kPIXfkj8AKgg+IkJlAuYGVCcFlOcfUV5bdXb3cvl2zne5wdvCj8epp0PhXVbyUi3XMY6seA1PmfVhyJ7I9+t7yK6hSaGQOjjIIqcmvLtFuNY8IRiTUiZtPICyBTkxf7VehWOp2+owia3mWSM9GBq1JMzlFx3NEGnA1EDTwaog8QlmmUSSSsfOPRF/gH9Kw2WYlpZnk57Zzmp5dQMsZKARxAElm5J/xpmlW39u6ksGXKLhmye1cq01Ozd2Nfw1oMuoz+eyBYB6dDXptpawwQhUI49Kw7hzptmtva2ckvGOF+Vfc1h6U13c3qu0JhMuSPL+UgA45FT8WpurR907HUrcXNtJG6hkZSrA9wa5rwLPJp9xdafI29IZzHgDlR2J/SneKbu/tLi0soQ584ZLK238M9qt+CLeCW/vdQKujvtTy5OoOAcmtKdzCvY71adj3qHdTgxrc5D512l42UqQh+6uOgrW8DCa01cpJGQkueSOmKyY7+GG6VpnY7+MgZI967jw/DEZzIAQR8uD2BrlnKysd1OKbvfY76F45U2lQcjvVdlsbW5jRI0Esh9hTYUby8qecVnT3VijyR3IeWXGWCoWwPSs43ex1NIt6otjexxFpIyyNgYOcVFZWoN0zxfLyCWXrx/kVzzS2XnmOG2ltw33QU2jNdN4cnjnSZAf3kbbGBrWC96xz4jSJuqTtGetSocim7eKVQRXSeefLsm3zPmOHznPWvUbBZYIYrqIFgyDeBTbbwBaXGyaXKRqCx2H5j14J6dq3rezSygMIbcqHaCRya5arvax2UNG7k1rqqzRAJIAw6g9avRJ5kRQSqMjnPeucu7BXUzQna464rNkubizheWS4YIilj7AVlHc6WzfvLeKxgkmkmDIil2z6DmjwfHIzR3TEk3BYn2OSa4OHWNQ1p/KlRhZnBkMaknbnvXq3hDTpbfS0adNqhiYgVwSvqRXRGLuctWopI36cop4f/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-4.png', linkedinUrl: '/in/cindy-baker-788ab17f8b', jobTitle: 'Learning disability nurse', }, @@ -45,7 +45,7 @@ export const peopleDemo = [ city: 'South Kaitlin', email: 'anthony.may@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDo8UU/FNb5VLdcDPFUI5rxP4utfDqiIxtNdOm5EH3R6FjXkuq+IdT1dj9suXkQtuEecIPwrauY7jxh4qYOwVSSMjoqCupj+G2nFlZmlK+maxnVSdmbwoykro8qLng/KT60sbETKQTz3r1tvh3o4wRDIMf7VZupeB7NYWFtmOTsTyKj20TT6tM47RvEWo6LdNJazFR/HG/IcV7ZpGqW+taXDfWxykg5Xurdwa8BvbSWxu5El5KNg46V6B8J72VrnULNv9V5ayge+cH+dbRZzSVj07FGKXFLirJOA8OWKJ4h1aUIExKEC+neu5AYACuS1OyEWq6hIEnZJJVO2E4Odg71b8OXM7ho5BOsW0svnHLD2NcNRe82enQfupG/LuUEE4rKuyCAB1rC1N7uWeSV1uJYkGdsUmC3PTHerFkJXwgimQY6SHP61HLpc05tbHn3iOLGpOJPkYtg5rf+Fkbrrl/vHS2GCOn3hUHje0DS2zgfO2UOBW98NNOmsZr03OFkkiQohOSFycn+VdVOSsjgqwd3Y76lFGKUVuc5TeOP7XIGAJbDfpj+lVnaCNp8PGoVcHtVi8ys6N6rj8qxLibSZXJn2E4wcAknHbj+VcNRe+z1aDvTVty/p/2e4LJ8pcANxggiprmOOBSw6joBWZY3dhG+22ZAT0AG0/lWhdN8hYnPHSoehoc3e2MNzewXM7N+4LMAOh4rd8PQMbiW4dcFU8sEjGRnIrHubhrYSXKqG8oFtvr7V11hCYLGIMgSRlDSAf3iOa2oxblfsc1eajBrqybtS0lLmus88gvYmktm8sZdeQPX2rJigWeBShWMjg44reFc1qmf7Qm+yMVC43gdC2MnFc9aH2jrw1Vr3ScxJCCxKsfXFVJbsyqRnrVMpeyth43I9cjFOjh8s7m4x2rnZ1czZFPcGxRJiqs3moArDIJLAYruWyOowe4qjpHh5ZXjvb5AQh3RRHsezH+g/Gs/W/E9npPiN7OZnZDGhkK8+U/P9MZrrowcY6nDiSlLQ//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-5.png', linkedinUrl: '/in/anthony-may-2020930433', jobTitle: 'Optometrist', }, @@ -55,7 +55,7 @@ export const peopleDemo = [ city: 'New Margaretshire', email: 'vicki.meyer@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDXwK57xH4vsfD48oD7RenpAp+77se386veI9U/sbQLq9UgSqu2LP8AePA/x/CvEZZ5ru6aed3klc5d2PJNKTsOKudbJ47127lypjt4uyRp/U5qgde1CS7Mj3lysrHcH37a6Hw34U/tSFJZcxQHpgferrpPAWjXESpJFJuAxvDYNc7qK51Kg7HI6f47u7Z0XUEW5g6NIgw49+ODXcWV/a6narc2cyyxN3HY+hHY1zN/8MoIlZrC5kjbsrjI/OuZ8PX114X8U/YrxCI7giJxnjOflYf571pCpd2M6lJxVz1OgAGilFbGBxHxQncafp9uM7HlZ2P0GB/M1yfh3T4b27jWRdwDdD0Ndz4/0+TU7G1itmTz4maQI38Qx6/41zfhZGsprhpLaWR4/lwgGQfoTXPVlvY6aMHdNo9S04J5CKuBtAGB0Fa4B2cCuBudUlgg+S2uXDZwqLg8f1p2i6jfQNvn89YXIO2VskZ6D61zW0udt9bHcTD5eRXl/wAQrOPyYLxFHnRSj5vbPeug8UavewyNDbmdVRQz+WuW59MVzd60mp6a1swmUghn83kjHPH4Zq4KzTIqNOLR3MT+ZBG/B3KG49xUgqG2Km0h8tWRNg2q4wQMdxUwNdx5hV1CINhxkMVKbh2zWH9lS1vJPL53kFj3JxjmunkQSRlTx6H0rlzd3E+r3sN1CsXkuEjZf4xjO6uStBp83Q78PVTiovdHR2K+emBtB6nPIo1D7PaKDPLEuPmOQFUfjUdirLgg8kcUXusabHmK6gknI5wsJbn8qxjqdTXYkma1m1CExzws7xcjrmqd/ZxmVI8oAWydqjBqpbajo/23ZawPDIR/y0jK5+mavENJejcMgDJ9qpJ8yRFSyg2y30FANIaQGu88ksAVkavaqblHVQJGTkjvg8fzrVnllgjR47Z5gWwSpA2j1NZ26a61HdKAAF2qB2rnrzSjy9Tpw1OTlzdBljebERZDgqcH6VrrAlyo+cYPQ45FY1/YuoLoufUCsg3OowHZCHYdhXIjvudDd2kdsTIXDY6E0WisymZxy/T6Vz00t5KD9qkIVRkiuphZHhRoyChUYPtXTRSbucuKm7JdxGpt4D//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-6.png', linkedinUrl: '/in/vicki-meyer-f2e0fdfbd9', jobTitle: 'Farm manager', }, @@ -65,7 +65,7 @@ export const peopleDemo = [ city: 'Clayton', email: 'billy.mckinney@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-7.png', linkedinUrl: '/in/billy-mckinney-709e41f9ba', jobTitle: 'Therapist, nutritional', }, @@ -75,7 +75,7 @@ export const peopleDemo = [ city: 'New Markborough', email: 'andrew.king@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-8.png', linkedinUrl: '/in/andrew-king-9eee067c59', jobTitle: 'Paramedic', }, @@ -85,7 +85,7 @@ export const peopleDemo = [ city: 'West Aaronchester', email: 'todd.jones@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1GsjxL4gt/Dejy304DsOIot2N7emf1rXrwL4ja/c6j4pu7dpSLezkMUSdQMY3H6k1JSItS8V6v4hu911dERE5W3iJCD8P8cms2e5iEmwsy8dckVR08SvlliYknGR1NaTaJc3A8qO1ZpeuCtZtq5ootrQis9cvtEnjuNPvHiUHOwSkg/UdDXq/hX4k2+uTR215HHBMx2l9+FLdsZrgLT4cXt0m+5l8vA6LzWLrGkzeHrlYtrbP4ZPU0KabsOVOSV2fS1Fcp8PvEL+IPDMbzZ+0Wx8mRv72Bwfyrq60MhR1r5s8QwH/AIS/UYXxlryTOf8AeNfSQrxHxDopu/Gv2+PIt765OARhlYHB/DgmplJLcqEHLVHWaDoVhHp8H7keZsALd62rfSrW3JaMDJ6561h6nPfWSLFZxuFIxuUdPxrO8PX2tXeoRpdyS+U7chwMgfh0rks3qeimlodrJGscZG4D2rhvG8aPpLiRNwBHOOlP8SanrNvfzpZE+VDg/KMlvpVMSXWr6dcW16Dnyz94dDTirWZM3dOJsfBlj/YGopj5VuQQfqo4/SvSq4H4VQraaLdW55meUTMR0wRtA/8AHT+dd9XWndHntNOzDNcPq2ng6iZJMhYZQ0Kjpkk5P6121Zur2IubWSVXKOi7sYBDY5qKkXJaGtGai2n1M22eOaIRkfNjB4yDR/otteRx5RTkFmOB9BVW1kCjP5VnapqWkEL9sIJVshghYq31HSuSKu7Hf0L7LbT6tOm+NgxyOh5qvqUUMMbJGoBIxwMYrJ0670pJ3awlDsWAYtkNkfWtSSN768hgU4aRgMkZxVWd7CbVtTZ8G2UdnpBKDkttz7D/APXXRd6gtbdLS1jgT7qDGfU+tTV1xVlY82cuaTaCmTqGt5VPQoRz9KjvL22sIDNdTpDGP4nOP/11xGu+JLfXp7XSrN5VtpZMzv8AdMigE7R3wSOap7XJjq7DftJtn2swAPQmrnkyTW4EUiJxwSKiu7BLiEKQOOhPasO6XUrGXy0DFO3PSuBHp3aNSW2khBaZ0kI7irvhq4t5taAmlUTGNjEpP3j3x9BXLr9tuWKzttTuFPJqhrVydK1nR7q3fbNbOz7B3Bx1/Ktaes0ZVm3Bs9rpO9Yen+L9F1CKJheRwyyYHlSnBBPb0kcB/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-9.png', linkedinUrl: '/in/todd-jones-d1cae42f61', jobTitle: 'Media planner', }, @@ -95,7 +95,7 @@ export const peopleDemo = [ city: 'New Cassiechester', email: 'gregory.perez@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDu65zxT4vsfDMAEmJruQfu4AcH6n0H8637iUW9tLOQSI0LkDvgZr501W5bU9QuL64PmSzzFtqjuTwPoBxUXLSNjWfHWtazbeVJKI4ucxwApu+p71zaalM8bxTO6oR8uT3r0bSvhukumRy3EzrcOAwVeAvtVSX4WOzMWvst2BWsVWgb/V522OS0/wAV6pod0j2l7INp5QnKEe4Nez+DvFa+J9Od5EWO6hbEir0IPQiuEk+GUKwAtcvvHXA4rLjN54H1+1mt3aSyc4dc4yO4P86uNSMnZESozirs90opI3WWJJEOVYBgfUGnVZkVNXDHRb4IcN9nkwfT5TXgumRBtTt+cqrAqPU179qE8VvYSvNkoV2kAZJzwB+teU+GfDUlh4rEF6oJiVpFI5UjsRWdSaRtSpylZ20PS7dsQqCDu2jOKJD82c1zOvfbdzCI3RQKTtg45A7msbw9LqD38cby3XlyDcRK+4geh9K41DS56HPrY7W4UshBOBXA+NY1OmkkZ2sDn0qx4s1DUobl7WAzbEALGI8n6VlTxXV1ot5DLJLKwUYEgGQcjoe9aQjazMqsrpxPWdC83/hH9O8//W/Zo9312ir9VtMlSfSbSWMEK0K4B+mKtV2HnNWditfRia0ZSM4wwHuDmubt4JGvIL24Ym6Curg9ACQQB7YFdWORWRqUJjnicMNhBGMdPxrnrwfxI7MNVSXs36k21biMqo/3gRxVONbO1neONUDjG5uBgnoKlimCRPz82M1zl/d6bPC0czRkqxO4qWIb146VzRV9DtbRZvoreTVnVtjB8YOQcGq97bxRI0YH3hjFY8ctotyzQXCyvgA8nP4ZresrdtT1CGJmKg/Mx9AK05XexlKSSbZ11jCtvp9tCv3UjUD8qsUdAAO1Ga7bWPLbu7jRWNe6hZ3l3JYQzBrq3/1seDlM9K1mbYASPl7n0rHms7a31OfUkQBrhFSdv93O0/kcflWda/I7GtC3tFcoSyOmYywVjxzSshFkYkZIuODipb6yhvD87FSB8rjtXP3tvfW4+SQOo6GuONmeg24i3UXlr+8dHI74rofCts5je+kGA42R+47muIC3M0hM7YA6gHrXQ+EvEYjt57O7zthmYROOgTPT8810UknI5a8nync5pM1DDcxXCb4pM//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-10.png', linkedinUrl: '/in/gregory-perez-5ca5d506c0', jobTitle: 'Special effects artist', }, @@ -105,7 +105,7 @@ export const peopleDemo = [ city: 'Gordonhaven', email: 'vanessa.farmer@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD02kpTWV4i1iLQdBu9SlK/uUyik/eY8AfnWZRDrvijTPD8QN5OPNIysKHLt+FcFffFi4SYta29ssWeFkYlj/KvMp7jUvEmqu+6Se5mfJJPLH09hXVWPwq1WZFeW4hiyMlQSSKiUkt3Y2hTb2VzbHxju3ulCafGqA8qW6j613nhvxnYeIV8vH2a7/54uwO7/dPf+deTX/wt1e2RpILlZiOeBg1iRzXNlGfNXbc277ZFzgsPUehHtSU09mDptfEj6YorkfAPin/hI9IaOZ915bYVyerqejfXsa6+tE7mLVhK8f8AjXqMhl03So2whUzuPU9B/WvYTXg/xqYr4utf+vNcf99NTA0PhtoKQWQ1KT5pZuEyPur/APXr1W2UiMZwa8yVpNL8MWEaW0k7tAoCA4UHGST0rT8KvfRT2yEOsNyA5ViTsz2OTwa4JJybkz1YWilA9AA4PT8a8i+J3hqW2l/tm1UGBuJwv8J7H6Vu+NXvIr6NYopZk3AfKTgc46CphDNf6bfaVcWzI3lMuVOUk44I561UPd94ma5rxOI+FV9NaeM4IA2UuUeJx6jG4H9K9+FfNvw+kkg8e6ZGOHScoQfTBBr6TrsR50grzr4oeFBq8dpqqAFrVTHIP9gnIP4HP516LUF9H51jPHsLkocKO57UO9tAi0pK5yumCCazijkRThQACParBls7LUbVHeOJS3GSBk+gFZ2mTJPAk0WQrZGCMYIOCPzFNv8AVrCG5SOW1e6lU8hUzj8a81J3seykmtDfhuLDUJ5o0lilAc4I5wQeQaluDBbR7UTnHasjTNY067LRR272sobo6Fcn2Per93jl2ICqpJJ7Vb00Iatucr4Z8IRf8JG+osgRorp5Q4/iU8gfgc16XWB4Svk1XSTqEUBigmciHd95kHGT9Tmt+u2mmo6nmVpKUtNkFFLio5poreMyTSLGg6sxwKsyOOntZdMup45MbZZXlRgeCGYn8OtOhtY7k7jLtx0I6ioJtaOv3c+2AR29vK0MbE/M+OpPpz0FVXSeLPlHkcEV59W3tHY9Sg2qaudBHax20eTKJB6nrWZrkV7q+mTafprKs9z+68wnAVSfmP5ZqKxt7m53/aThR0AJ5q7Jqi6JqGlo0Y8q5uPszN/dLKSD+YFVTs5IK0nys6TTLFNN022sozlII1jBxjOBH//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-11.png', linkedinUrl: '/in/vanessa-farmer-c79ab76e62', jobTitle: 'Engineer, land', }, @@ -115,7 +115,7 @@ export const peopleDemo = [ city: 'North Amy', email: 'elizabeth.chung@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-12.png', linkedinUrl: '/in/elizabeth-chung-72c8e6d73e', jobTitle: 'Race relations officer', }, @@ -125,7 +125,7 @@ export const peopleDemo = [ city: 'North Kristopher', email: 'melissa.huerta@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDGbOaTFTslCxjqegrK5pYqyzJbqGkPU4UdyaV5o4bFrq6lWCPouTy1czc6hLcXrssgVUJ+fso9qL3TzdWq3DOzuo6SN09ABUNtstRSRcOvyRNlRuifkbweK27S+W4UDaVJGRnofoayZ7OKZYGAChwjsPwwau2CNY3E9nId0RG+JvQ4qbvoyuVdUahOcjoR2phU5rJbVFW9Eg/1eQrj0rdUAgEcg9K0UrmbjYQrWR4k1EadppRf9dPlVx2Hc1uhK5Hx5G+2xIHBLDP5cUAjEtIzJ5Y+8uQcDuTXolp4fEUMTSruLL82a5Dw9EF024mMBnPnCNB2BwOa7HwtJe3F1FbTeb9nlBP7wEFf19qwnc7KSWlzn7+1n065TPMYBUZ/u56VVvbsi1jZScxN69RXQeJbaUaizSQTTRx8qFGcjpwM9ap6joxurImO2aGWJd3C43r3yMnke1SnbUcopuyOYNyv+sYfLIMNjof/AK9dlokv2jS4zu3bcrn+VedvmK5aPPy545xkV3fgvD6XOucskvI/Ct0jkkbYFYnjG1afQhIi5aGQP9ByP61vgU9okmieKRdyOpVh6g1RBgfDzyH0N4Z1DZmY8/hXa2MllaakEZ0iVIyR2yTWBbadDY7I7VBHGOgA70t7f6SsqrdRyySJxmNSSPxFcsk+dnpUbOmrHSW0lpfgJvhlOMq2QwIzTr2SC2iKhccY6cVl6fqejSwrDaRG3fd8qtGUOfx61cvow4BY5wOlS9NDRnlur+H5n1OZoosQvlhjoo6/hzWz4EtpEs7q4P8AqpHCp/tY71Bqet3GpazJ4dsbdY2ZtklwW5K4ycDtxmuwtbaKzto7eBdscY2gV00+a2p59ZxvaJCBTgMU4LTghPQZrQxGkFkO3r2qO3txcc+f5TjqatRITLtIIx1rFtp2ubdZ/uu2c49c1jXha0jqwtR6pHRx232eH57hJB645qKSRp2A3Zz1NZNu1xNMI3PBrZijCjaB+Nc7Opu5ymiaEI9dvtWnkRpGldY0U52jpk++O1dLTvD/AIdE2r61d72W2dYwPQSYJJH4Y/OnSW7xOyt2PX1ruirxTPMnpNo//9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-13.png', linkedinUrl: '/in/melissa-huerta-65292000ee', jobTitle: 'Museum/gallery exhibitions officer', }, @@ -135,7 +135,7 @@ export const peopleDemo = [ city: 'West Oliviaburgh', email: 'debbie.johnson@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-14.png', linkedinUrl: '/in/debbie-johnson-6108ee5a49', jobTitle: 'Wellsite geologist', }, @@ -145,7 +145,7 @@ export const peopleDemo = [ city: 'Barretttown', email: 'kathy.mcclain@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1Cop54raB555FjijUs7ucBQO5NSmvLvjJrklrplro8Em03RLzAdSo6D8/5UAZ/ib4uyyPJaeH4dqfd+1yDLH3Ve31Neevr2ry3X2hr+7MwOd5lYkGtLQPCM+oRrPO5ihPIHdq7m28D6bHBjyi+R95jWbqxRvGhOSucNb+PPEVlLuj1a5+bBIdt4/XNez+CfGkHi6wkbYIbyDAmiByDn+Jfb+VcHfeB9OMJCxsrDowNckn2zwX4itL+BiVjkByONy91P1FONRS2JnRlDVn0jSiobO7hvrKC7gbdDOiyIfYjNWKsyA14d8VmN347t7VsFIrdMD6kmvcu1eS+OrFD8RbO4UqwkgCyAclWXJGfwxUydlcuEeaVi3pkGLWJEH3QBXQJG/lgA81xl/fCw+SW2mkVhkFRwPp70zw/LdPego8ohkwdsjE4z/WuPlduY9HmV+U628hZkKg4OOa4HxhamTTnBTLJ8wq/wCIbq5+3OpMogh+8Iidx/Cs/wC0DUrOe3WCRNsZB3HOcj+dVBNe8TUaacT034dXL3XgLSnf7yRmP/vliB+ldTXL/DoIvgTTI1UqyKyuD/e3En+ddTXYeaxRXAeLbV01xpyPlKq2cD02/wCNd+Kx/EOmPqNqDGUBjBJyMkjrgflUVI3WhrRmoy1Oatfs93aiOVFP1GRVeW40+zu4oN6QJuGCRjee+KrWu5OAeOool1IyN5MWnSXG3qSuFPrgnrXEk27Hp6bjZZrGfWJkMscqOeg6j3xSX0FtaxFIUUZ7iqX2kQXG19NeDd3VQfzx0qaKCXUNQhtg2DI4UEjOM1VndIltJO53nhG2+zeG7ZcY3lnx9TW5VXTYZbfTLaCcqZY4wrFemQKt12pWVjy5O8mxBRx3oqK5ie4tpYIzh5EZFPuQcUyTzK/f7JqFxED8qysBj0zU0Rs7iIme4dVx0Xg1Vh0ydbVYbsETqNsmezjr+tZd5ZXlux2jevrXA7XPVV0kak4soEJgkY/7zZqCy1iPR7tNRmilligy7JHjceCOM1l20NzPJgoF9SeTWhJAEi2ev61SdncUk5Jo9N0LXrLX9Kg1C0YrHMDhZOGBBwRWqOehzXCeHbM2XhyFSu1ftbMgHHyk/wD6662F2HBJPvW6e5//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-15.png', linkedinUrl: '/in/kathy-mcclain-cf5890c5b5', jobTitle: 'Surveyor, building control', }, @@ -155,7 +155,7 @@ export const peopleDemo = [ city: 'Cassidyburgh', email: 'michael.elliott@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-16.png', linkedinUrl: '/in/michael-elliott-d5e13ac5c8', jobTitle: 'Ergonomist', }, @@ -165,7 +165,7 @@ export const peopleDemo = [ city: 'Wareport', email: 'kimberly.edwards@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwCi3WmYqQjrUU0iwQvNIcKoz9falsMPTJxnp71GdSsbeURzTgN6AZrCQahrV8I7MGSdjwo+7GvqT2rqf+FY3Vza+bLfD7SecjpWDqm8aTG/a7d498T709cEfzpA6yrujbIpi+EPEejxHyHhuo/4oySGx7E1gy38lndsjq8Lq2CHGCPZh0/GpVV3HKlob5Bpyqc1DZXSX0HmJjIOGHoatKvNdCd0YWswwOa57xXcyQ2kEEZx5rEk/T/9ddCa5jxajFrA44LMv48UpbDjudn8O9GFjo/2iTDTzneT6DsK9Ch4jAyK8/vbo6NpltbR2ktzIYwBGhIAwOSSKt+FZL15VL280EU2CVdicZ+vQ+1cLv8AEeirJcp2rkbCMgetcB4+8PxX2nPeRjbcwjOcffXuDUviyW6guBJHbXF0inAWNiB19qfY3UmoRvZXFrLbsF2sjHcrZHUGjX4gdn7p5p4YvXt9WFrIcpKpH4jkf1ruF6157ZxNZ+LEtmHMVwVGfTJr0KMZNdsdjz57jSKhvNMXUbVN0YIgkEu7JyD0AH1z+lWD1q9pbIZmikOEYZ69xyKVS/K7FUbc6udTZSQyQhWRTxjkVFe6tZafe26SEqrNhQFJycZ/AcVStCTgoQVPIIPWq134ihhuPIW0edhkE7DgeoziuFXeh6SSNXTNTs9QlmVWJUORhlIwfxqzeywQL8qDpWHY+IYLmVrZrOWB8gA+UQp+hxVq6jaQjJ470SutB2Ryp0C2fU73UjCrzmVWUOD8qkfeHvnP5VLGK1Zr22bTv9HlWRpAVJA6DPSsxOtddG9rs4MRy3SQ0rSplHDKcEdDT9tKE5rc5i9YXIRDF93YR+vNai2kVyAwm2HsR1FZcEAfI7sP5UxvNgAwWx9a4Kuk2elRk+RG0tvHbAnzg5Pc9azb66d4JY4m52nB9KgjWW5bbk4+tTSQeVbFcck4qFq0XNuzZlxRCG2hhUYWNAoqRI+amM//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-17.png', linkedinUrl: '/in/kimberly-edwards-00862e876a', jobTitle: 'Exercise physiologist', }, @@ -175,7 +175,7 @@ export const peopleDemo = [ city: 'Jefferyport', email: 'regina.williams@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-18.png', linkedinUrl: '/in/regina-williams-9d91d1682f', jobTitle: 'Clinical scientist, histocompatibility and immunogenetics', }, @@ -185,7 +185,7 @@ export const peopleDemo = [ city: 'Ericaland', email: 'john.guerrero@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0+ori4gtLd57iVIoYxl5HbCqPc1NXinxW8RXGpa2fD1vIUtbYr5oH/LSQjPPsMj8aG7Alc1PEfxhiglmttCtRNt4+1y52/VU7/jXJxfFPxU0u5rsbc97dNv8AKr2mfDZZrdHuLpkmYdF6Ctb/AIVTbeVlb+Uyds4xWPt4nQsPMm8PfGBZLj7Pr0EcangXFuDgH/aX/CvVIpY54klhdZI3AZWU5BHqK8em+FCAFhdAEDsK6LwDLeaFqUvhu9mEsDoZrN8Y6feX+uKqNWLdiJ0pRV2ehYoxTqMVqYi1886vmb4i6iSNx+3OOfY4r6AvLuKws5ruckRRKWYgZ4rxqbThL8QZ7yNW+zXTtcRlsc8DP6msqsklY2pQbd+h2VmwJCc8VtxAFfv59q8+1WW8H7qEzDjKiM45A7mqmhX+spdwpPLMRNjhzkqM9D6VxKOlz0XLWx6bIuUILYrmrkmLxHpEgHK3iru9myDWP4t1HVbS9a3tWl+RFYmM8nPp60uhyTLdWkt9LJst7lZZGlI4xnoauCs1IyqO6cT1mkoDB0VhyGGRS13nmkF/aLfafcWr/dlQrXm5R4bkSTD5wzIi44UY5/UV6fXM+KNIQ276hExDIwZkAGDk4Jz+Nc9enzK6OrD1VG8X1M+3+z3KbWRckYORkGo57e1tplSNUDAZJ4GOarWkoA6/NVC/urO+/dTYyrbjhSxB/CuOKvod9zo72Gzn1BPMMbbkA7HBFVrixhnmSzVdokYKeO2awrOW1trh2MxlkYAZfIPXjGa6rRo3utWWQEDyhubI/lWii3JIznLljc6vAAwOgooNFegeUFUtXXfo16p7wt/KrtYviO7nt7OOOHaFmLJIxGcDaeB9ambtFtlwTckkcIJzHgMcHtVyFPNj2JMsYA4NQz2u+McZIFZpWeGXCqSO3PSvOVj1HdGvLF5URDXCzH/arr/DNk9vYfaZv9ZOAQPRe3+NcLBbSsd0zZOM4HavQ9AvFvtGgcDBjzEw9Cp2/wBK6KFnI5sS5cppUUUV1nCf/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-19.png', linkedinUrl: '/in/john-guerrero-f5c763a584', jobTitle: 'Wellsite geologist', }, @@ -195,7 +195,7 @@ export const peopleDemo = [ city: 'Jamesborough', email: 'david.bailey@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDGpMgAknAHWnY4rnfFt5Lb2cUMTlRMSHI6kelZFiaj4qit5lisoxO2fmdvuj6etU9Q1vUJIA0jxwIeQIm5NYdlGXm2jJHTLdquHThcs23eiqOhHWk2Wo3LNl4tu7dl81lnj6EMMEfjXS22v2t2iEsEZh90n+XrXNReDtYuosrAyR9i4x/9es+Sxn09PKuMqY5MN6p7j2o5k9gcJLdHooIIBHINFV9MkE2mW7Bw52AEg98VYIqiB/FcT4nnmm1k2+BiMDZj3Ga7gCuN1+3KeJ4XwdsqqB9elJjRseG/Bz3IE8smGYfL6D3rutG8KxaY7TTETyHpleB/U1nAjT7Rf9HeWRkLABioAA7Y71raFf3KeWJjLslUMFkfcVB7HPQ1yttq7O+KitLGq8I2sVj49TXmvjvR45YJLmLIkU5YDuK7HxFqErpN5fmmKAZZYmwW9sd+tc7eIt5YzgQvFKkfzguWDAjjr3oire8hzs1ynH+D5G+1TwbSAEyea68rXM+Drbabm4brwg/nXUmuo84UVFcaamoqg482FxKmRnOOoqYDNSwu0EyyL2okroqEkpJs6Ow8u4tYtyhmxxmpbwRwzwqWWPcwyTxiqukYMasvHzYx6Ut7qEa3XlywvIw5wF4rjtrY9SNpLQltkjl1G5UOjgdCKraxbwx2rpEu13GMAdc0lrfRvd7YYmiY9inFM1d8spJOQwH9adnewpNRWpzlnpselxG2jk8xVY/PjGamOKkIySfWoyK7FseXJ3d0SDFSKM01IndtqqWJ7Cr8WlzMh+YK5XIHpQ2kSlcWyma3VzyUzzjtWvbPDcxjlWDdSe1VNNgCyyK5LBhg5q1BpMUkrIWKP1GDjIribvK56UE4pILow2qMQVAXuK5+7naebnIAGRn3rXvtMSKVY9zOxbPJzgVmT2pmvJCpIwBj39qqMkpXJqJzjZFMnFMY1eewdckMD7GoZLK4QkNE35n/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-20.png', linkedinUrl: '/in/david-bailey-a321ec2517', jobTitle: 'Radiographer, therapeutic', }, @@ -205,7 +205,7 @@ export const peopleDemo = [ city: 'Calvinton', email: 'emily.davidson@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-21.png', linkedinUrl: '/in/emily-davidson-4cfca34af8', jobTitle: 'Health visitor', }, @@ -215,7 +215,7 @@ export const peopleDemo = [ city: 'South Veronica', email: 'michelle.jackson@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-22.png', linkedinUrl: '/in/michelle-jackson-bcb3423e3e', jobTitle: 'Social research officer, government', }, @@ -225,7 +225,7 @@ export const peopleDemo = [ city: 'North Nicole', email: 'ryan.romero@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDsyOKTFPIpvTk1mUJis278QaRYuUudRt0cdV35I/AVzOoXuqeLbmWy0iY2mmRsUkuv4piOoX/Z/nTrb4W2gjDXN9K+R2AFS5paFqnJ6nU2WrafqQzZ3kMx9EcZ/LrV3FcBcfD2KyInsNQnhmQ5Vx2rd8P63PLN/ZerFFv1GY5F4WdR3HuO4ojOMtglTlHVnQ4pwFGKUCqIHGsDxhfNYeHLgodsk5ECn03df0zXQVynjy3abSrPBOBdKCPqpFDBbkugLHDpttDEuAqjoK6HcpQBZgT6V5/q9xNbYtoRPtCdIuM496q+HJNSmv4YSbgRyHJ3tnb9fQ1x20ud99bHoN0n7sgP83pXDa+Xt41nQlJ4JBJG46g5qv4iudRi1GaFGnZIuT5bYyPamRSvfWkttN5v+rOBLyQcZ604q1pCk73iekafdLf6db3ajAmjD49MirQFYXg0u/hKwZ+u1sfTccVu11nCKK5zxMZWlhhbBtm2sFA5MgbIP4AGujqhq0BltwyxNI652qoBPNTUTcdDSk0palG2ktruExyIu0dSec1Tn1rTdHvIl8lkjDfLtT7xHUk9hUVq4hzuOPb0qhPf3l4pxbQpCuQrzvtB+gH8zXIlc7rliLU9P1PU5RzhzyCh49896lvre1tlKxqMkdRWIt5PZuW+yxlSQN0B3KPr/jVuSRp2UKCzMeAO9NrUTfc6HwisiabKh/1KyYiH90Y5H510FZ+j27W2nqjqysSTtYYIrQrrhflVzhqNOTsFKKKxPEHiC20mzlRZkN4RtjjBBKk9CR6VdjM5rXJTZ6ncIeEZyQfTNRm40yWALcFpDjOFOKgso59T0KGW9mae4kQmSRuSTk1gXWnT2pLg71z26iuLRyZ3K6ijblu9PjiYW+YwOxNXfDDrc61bg42Jlhk9SBxXK29o0kgZ149Kk10zWmkJcW7mOWGZHUqcEYP/ANeqjbmQptuLPZqWsjw/rlvrOmW8yzxm4MY82MMNz//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-23.png', linkedinUrl: '/in/ryan-romero-36790b1367', jobTitle: 'Forest/woodland manager', }, @@ -235,7 +235,7 @@ export const peopleDemo = [ city: 'Spencemouth', email: 'victor.lewis@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwCuabTyKacAEk4ArMsCwVSzMAoGSSeBWFe+KrSBtlsjXLeo4X8+9M2SeIrlizsunRttRFOPNI6sfb0Fbdr4QsEYSrEd3uc1lKtGLsbQw8pq5yv/AAmsiN+8sUx7OR/St3Tdds9TAEb7JT/yzY8/h61pXnhXT5U3NbLkeneuX1DwzboC1qpilU5Qg8ZpKvFjlhprU6jrTgtZPh+/lvLZorjP2iHhif4h61s4rYwsIwqhqhZdMuNpwxQgfjxWgwqnfKHspRx0pXsNK4miQrFaxRgcgCuttw2wfLke1edX0chuViaa6WIJlI7YYZiOpJrT8Nz3ltcrD51w0TEFVnOSK4nDTmuejGevLY7K53eWcDArlr4jJ45FUvEDXV9fMpluhDHkkQPjOP5ms6xiYXXyS3QTGXiueT04INNQVr3Bzd+WxLo2BqzNghnVgR+tdIBXP6evlaxI5BEag5fsCegrowK6ou6OGcWmRvUZVHim3gcIWXPrinuaaMZ56EEHFEldWCnLlkmWtLtba8gUyKNwHWnCfT4dSSMSRxbQcZGM+9YVvPcWySqjEFUJVfXFMtbC41eQi7byZIxkb2GCPbANcqpu7TO9VNFyq5sWtxYXN3KDLHIGJGV5249al1C1t7aL90FDEda5y906fSZ8WcnmM/VYz8v45AqS4upTaxIZA0mznB7U3T10F7TT3kS6cqnzjkHc+MYz2HNbgSs3RYw1puAGN55z1I4rWxxW9ONrnJWmpWSKTU3FSEUqRs7AKpY+grUwM+8QIFkYfJuwSO2ae3kNGN8zxkDJZGxkZ4rS1DTJl0iaR0HGDt74zzXFXFpqcbCO3cPEfuqecD05rKpy81mb0ublujoHmtIYx5bSSMxxuZsn/wCtXMi7kluZYYlBJO3I6KKWWw1aZAsrCNT/AAIMZ/GtbStFWyi8xwWlIwB1qOeMFpuXyTm9dEaXhxnbTpk2/JbzGIHv0B5/E1r5zV7TNJ+w6SsEigSyEvIPc/5A/CnnTCw/dHn0NbrZXxOx/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-24.png', linkedinUrl: '/in/victor-lewis-71ac9f14ee', jobTitle: 'Surgeon', }, @@ -245,7 +245,7 @@ export const peopleDemo = [ city: 'Jacksonhaven', email: 'christopher.powell@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD02ilxVHWtSTR9Fu9Qdd3kxlgo7noB+ZFZGhleKvGFl4YtDuxPesP3Vup5Pu3oK85T4k6/cSmT7XDGCP8AVrCoUfnk/rVfSPDuoa/NPeX06vLI5Yu67uT6ZrZX4dvGCRNHk9DsAx+VYSq9DpjQdrmOPiTr/m+V9tKsxwrGJSM+nTFdp4O+IB1q8XS9RjVL05CyIMByOxHY/wA6wv8AhWlqULSXDlzydvArL1DwZ/Zf+l2t1KJYjuBU4YAehoVVIJUJHtxpuK4/4feILnV7K6s76XzbqzYDeerIehP5V2Vbp3Vzmas7C1znjptvhO5U/dd0Vvcbh/hXSVzvjfy38NT27Z8yUr5f1BB/lmlLZjgm5KxlaJCsdlEEGBtBrb4IGCTXF6tNdWqCK3S4IVMr5PHQU3w5e6nPcxwztMFkG4GXqv1rh5dLnqKX2Ts5cBcZxWBqjDy3/i4P41g67e6kbmVIzOY4skiE8t9B3pLG7ublFjlSdMDOJevT1p8ulwctbFr4ckf8JhqJj4RrUbx7hhj+depV5n4AMNh4l1BJQd9y3lwkDjjLH+lem12U3eJ5tVNS1CsXxRbNcaWGUbjG2QPqMVtVHcwC5tpISxXeMZA6VU1eLQqcuWSZylq0N1bhJFUj3pkcllbaisatHGFyeSBk1VMT2V7Nbs2djEZ6ZrKvbrTbptkqOZFyAyRMdvryBXAk72PWi01dGlavZ3N1JG7I4Zjgg571JfRwWsJWJAMjtWDZ3OnWsxS3V0LnpJGVJNXb6VnOMk0NW0C+hb8JWmdbSTHA3SnPrgj+or0Gs3RdHi0q1GCzTOo3s3b2HtWlXbTi4xszy69RTldC0opKgvb61061e5u5kiiUdWOM+w9TWhicn4vUWmoR3AyBKnzH3HH8sVmiD7VCuLnyjjgr6Vg6Pq+peItW1i41CVpIPNVIEP3Y1wTgD8RTrmzv7cn7LKMD+A9vpXFUtzs9Ki2qaNZ7f7MhzP5h9TVTTZPtmtWcAO4NOu4+2axhFqVyzLcSbV7gHk1JqdlMmiXKWhZbjyyUKnByOeDUqykXJuSZ7YaSvPPhb4vuta0x7DV5997AAySSMA0iHsfUjH616HXeeUf/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-25.png', linkedinUrl: '/in/christopher-powell-2e521c68f3', jobTitle: 'Hydrogeologist', }, @@ -255,7 +255,7 @@ export const peopleDemo = [ city: 'South Jacqueline', email: 'jack.george@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-26.png', linkedinUrl: '/in/jack-george-1b6352407c', jobTitle: 'Engineer, site', }, @@ -265,7 +265,7 @@ export const peopleDemo = [ city: 'Markchester', email: 'manuel.lara@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-27.png', linkedinUrl: '/in/manuel-lara-f896ffc5d1', jobTitle: 'Government social research officer', }, @@ -275,7 +275,7 @@ export const peopleDemo = [ city: 'Brianfurt', email: 'john.gonzalez@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-28.png', linkedinUrl: '/in/john-gonzalez-1077ebc9e6', jobTitle: 'Horticultural therapist', }, @@ -285,7 +285,7 @@ export const peopleDemo = [ city: 'North Christian', email: 'theodore.gonzalez@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-29.png', linkedinUrl: '/in/theodore-gonzalez-b0caf15fb1', jobTitle: 'Administrator', }, @@ -295,7 +295,7 @@ export const peopleDemo = [ city: 'North Jacob', email: 'christine.bishop@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDLOabzU5TFZmq3X2dBEpwzDLH0WlKXKrhFXdiU3aB9ifMfXtTLi+FuuSyk1z6Xh83joO+eldBY6ddX9qTbqWd+Ayr0/E1zOb3Z0RgtkRQ6w7ttkiVM/d54IrRVxIm4Cqlz4L1ZbZZAmWTkndyagtrw2rCCcYJ9eoPcGqjV1CVLQ0tpPNPRTmrcFv5qK6nKsMirSWfNbnMVyihSx4AGSa891bUDcXMjg/6xjj2UdK7PxBefZNGmK8PJ8g/GvOYA11drEpyzt5aD37msqmrsa011Oi8L6DLr16AQRaxkGRv7x9K9psLCK0t0jjjVVUYGBXDWaxaDoscHkSyllztjzk+vTvW1o15JEUz5qRybTtdicZrnlrqdsLR0OpkXdGRivK/iDpTWc0V9CMJI218dm7Gur8R6i8aN8s7qh+7CSCfyrF1UDVNAubeOGSORUJIkbIDAZB/z70kuoS10KHhXUDcWLROfmiP6GukEgrzrwtd7L4qrArIuOD3FdokjetdkNjgmtTl/G1wI47eEH+8+P5VgeELM3GuxzNzHbnv3NXPGbO2ttkHCxgLWb4X1qHR9XkNyZDBMoTCgEbsjBP61ErtOxpCyaue56fFFJCvAyO9LeNb2s8XmyIi7h8zEDknj8ajsVwqlTkEcVHearGkwiaxknYeqcfge9ca10PRSvsXYntLi/lCSo/Y45wah1SGGG1mIAztOfyqC01KF5DH9ilgY9CU4/OotfvobHT5bm6mSJFUhS/Qtg4HvTs72FJcu545pRa18QyQj5Qsx49K9DR8mvN9GDy6i88hJkZ9xPqSa9HhBIFdsN2eZU2RxnjC6jk1byccqu0n9a46Rcbj6133iPwrf3WsSy2VvNMrnJGzG09xzWba+BtTuJVNxGIkzzzk4qOdRepai5LQ9T0yVrewt0YnHlqQfwrViEE4y7ZB7elQQ2gFnGgHCqBimGwf70ZIFcdzvWhdlEFumVcYryT4la697qkOkxZEVviSQ/wB5yOPyB/WvTzZmNQ0hLHrzXiHiOUz+Kr+YjrMV/Lj+la0dZXMa7fLY2fDlkHnEhHGCfx7V3EMRAHFYHg6MSW69znn8q7SKAY6V00tKu9j/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-30.png', linkedinUrl: '/in/christine-bishop-c6ec520c6c', jobTitle: 'Geneticist, molecular', }, @@ -305,7 +305,7 @@ export const peopleDemo = [ city: 'Cooperport', email: 'alejandro.moran@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-31.png', linkedinUrl: '/in/alejandro-moran-03db39c63a', jobTitle: 'Applications developer', }, @@ -315,7 +315,7 @@ export const peopleDemo = [ city: 'Carmenchester', email: 'john.cook@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD17FQXd5bWFq9zdzxwQIMtJI2AKsV4f8TNWn1zxGdLiLG2tn8lIweGl/iYj2zj8KG7Dirs2NY+LxkkeHQrRXAOBPNzn3Cjp+JrlJfiF4qmJkN3cIM5BjwoGPbFdxoPgvTtL05I3gEsrDLuw6mtE+G9MRSn2Vdp5IrndY6lhzirP4v6vbmFbqC2nUff3IUZh9QcA/hXsOl6la6vp0N9aSB4pVDDB5B7g+4rzfUPA+lSEyLGR3wKzdJvLnwV4jtzCzPpN2winib/AJZnsw+n8s1cKqbsZ1KDirns1GKUdKK2OccOteFRWpPiyWWT5/Lunz9dxr2+7uobGzlup22xRKWY+gry630/d4rmkwyxTzNOinupyRWVVq1jejFvXodnA/yhTSTHJ61iatf3NpG0dtFNJLtLARr6etY2jalqt7eRQXQdVcBzkcqPQ+hrltodyetjqpxlcZIrkPEiL9ikyM45pPEesajZ3bwW0buqgbjGMn8KrzTzX+l3UcysJFiPDLgg4z+NNLqKb0aPV9Fne60KwnkGHe3Qt9cCr1Z3h6WObw9p7RNlRAiH6gYP6g1pV2rY8x6Mg1CzTUNPntJM7ZUKnFcTbpI9400wKtC5SJduONuCc9//AK1d/XP61Y+W4uoyioWG4c5yayrQv7yOnD1eVOD6lQKlwrbRj1GOtV4TaR3DxRBA643NwBk9qlRwtuwH3iOK567udKdDC7B5I3J3KhYh/XI6VzJXO1MsTpA+rOsmwh/unrz6VHe28ccbqqjJUjisiJrFJ28mXdIQBl8gnHpn3rat4JdSvYreMgM/dugp8rvYTkktTsvDlr9k0C1i3Zypf/vok/1rUplvCtvbxwr92NAo/AU+u1KyseXJ80mx1efar4pvpvGreHDbw/YXhM0c4B3HbwR1x1/nW5qfie0ZJbawm8ybHLqPlA74Pc1xmoNIzW+p26hruyJJTu8Z+8v+fSicW4uwU2lJXNaWWSJvKZtpI4J9KkeMPY+WJBCAOCtRym013Top4nJVuVYdVPpXNaudU0plRn8yFhhJB/I1xLU9G7RqXEAiUguJO4J5NdJ4OtHdpL+QfKB5cfue5/pXCWiXco33DYU9h1NdV4C8TwOL7TbudIjDdFLfccbhjkZ+ufzrWkk5GNeT5Tv6SkrpOI//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-32.png', linkedinUrl: '/in/john-cook-ced58e0bb5', jobTitle: 'Chief Marketing Officer', }, @@ -325,7 +325,7 @@ export const peopleDemo = [ city: 'Claudiaborough', email: 'leslie.calderon@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-33.png', linkedinUrl: '/in/leslie-calderon-79bad778f2', jobTitle: 'Teacher, music', }, @@ -335,7 +335,7 @@ export const peopleDemo = [ city: 'Gibsontown', email: 'barbara.young@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-34.png', linkedinUrl: '/in/barbara-young-d2423e1be3', jobTitle: 'Television floor manager', }, @@ -345,7 +345,7 @@ export const peopleDemo = [ city: 'Alyssastad', email: 'maria.thomas@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-35.png', linkedinUrl: '/in/maria-thomas-833d46722e', jobTitle: 'Investment banker, operational', }, @@ -355,7 +355,7 @@ export const peopleDemo = [ city: 'North Christopher', email: 'paul.villegas@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-36.png', linkedinUrl: '/in/paul-villegas-dda25fb766', jobTitle: 'Veterinary surgeon', }, @@ -365,7 +365,7 @@ export const peopleDemo = [ city: 'Williamsland', email: 'bradley.turner@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDRC8UoWpAvFYniq/uNO0gG1YpPNIIlcdVznkflWJsZHiPxh/Z909jYIr3CffkYZCn0A7much8UatuaSa8cqf7uB+HtWx4b8E/2w8t9qE0ojkY7VU8t6sTXWr8NtFBVtkpPU5fOazdaCdjWOHqSVzzpPFOowbpra7k25y0cvze3euq8N+LRqqCG8RYpxxuB4Y/TtW7eeAtElj4tShAxlWIrhte8JHS42n06Vx5fJjPPHtSVaEtByw84q56Jto2Vz/g3VZtS0lkuSxnt22kt/EpGQa6XHFamI8LXL+M2CxWGRx5pP6f/AF66oDiue8VWjXQsMH5RMVf2DcA/0pSdkOKbdkdFoMax6dAoGAVBrfJOB3HtXCawt3G3lRm8MaplI7QYYkdyf6VL4UfVBKEuJLoxPhh57AlfQH3rhtpc9NPXlOuuDtXB4rjte2/Z375BzVLxPPq1zeyx2z3AhgGW8g8n8Ky7L7W7+S0ly0e3547kDcv0PcU+XS4OevLYp+Dbgr4mlt41AjaFvyyCK9EA4rz/AME2nk+J78yYxGjJGT3y3QfgK9DxxXcnc8xqzAdKr3dustuX2gyArzjsDu/pU4HFKSRG4Cg7lK1FSN46F0ZqMrs1LRY54hnGfeq9xeWNteRwtNFEScDJxuPfHrVW1uPKtd+clUz9cCufuJJ9XOZIJhGuQpWDI68nJ61yRV9D0r9jU0+7tbjVbqNZY5AWOMHNO1ZLeCNiiKGK9RXKLIdF1BpIoZEidhkNFjHvkcVp6reedAzAnlQx9s0SjbQObvuQeH7ZRdeZ33s+SPXiuozxWdpNnJbWy+bt3lQBjsOtaBHFddOLS1POrSUpaCgcUoFCmsvxDeNb6ZLFBJtuJEIUqeV461qYkd5ex2M7xu/7onG7OQCeoPpVy4uLSey8qSZk+UEeWcdOlcx4L0+S48J4uhkyyM4B5OM45/KlvfD+pwI0lpMph7KT0+lcUuXnaPQhzKCZqXF1ZWts0aTbiF4Lc8VzKaxA0sbTygWqurzvjIC56VRlsL1v+PiQNuONo6H61YvdFcaLNCMCV0OMjjPWhcqYnzyTPRra6t72BZ7aZJYn5V0OQae3SvNPAuovpTx21y4S2mB3ZPCN2P8ASvSt6ugZGDKehByDXc1YAAAAA8+5/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-37.png', linkedinUrl: '/in/bradley-turner-eb4dd1bbce', jobTitle: 'Financial controller', }, @@ -375,7 +375,7 @@ export const peopleDemo = [ city: 'Whitemouth', email: 'matthew.alexander@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0zFGKdiigBpIVSScAck15X4n+LywebbaDbh5FbabmYZX/AICvf8fyrpPiXqFxZ+F/s1pL5c99KLZcfeYHqB6cd/SvO7b4eM6oonGCBuPvWc6ijua06Up7HKXvirXNTdmvNTvZA2cgylVI9ABgYqpZ6pqOmy+dYXNzbt1zE5WvUIvhrpwUeZJIz9dwOKlPgvS4ItvlswHXmsnXibrCyKfhr4vXMYit9Zg+0pkK1xHxIo9SOjfpXrOm6lZavZJeWFwk8D9GX17g+h9q+cfEOgf2ZflIZco3KnH863Phh4hu9F8Tw2E8h+xXziN16jefuN+fH41tGV1c5pwcXZnvtFLRVkHG+OrY3F3ojbciOWV/x2jH8zTbZAqKB+VP+I4mXQ7eWFpAVnxiIfMcg9PyrkvC02o3Pmx3ZkVBEWVpPvDnGDXHXXvXPRwkrRsdi544Yn6Vn3chVSq/jXFXkusxaiAJbt03YARwBWxaT3s37uZZOO7jn8+9YOOlzpUruxzHiQmQuXYr820/SuZ0m4ez1qymjBLQ3CMGPswrt/Ftmr2KyqfnDY+tYFp4fuXuYJ7qRIoRKmUKncy5B7dPbNdNKaUdTiq05OdkfR9LRRXScRh+J2T7NbxyDKs5/l/9euYilsbSCYCaNGZtpBOB+ddL4uiLaN56/wDLBw5+h4P8xXlc0unXVyZbiYKv/PIAnOO+B3rkrRbmelhZL2em52tsLK+Z1OxmQ9eCDT52htUIjUdK5+w1WzQR28AUc5UKCMVevJgrFR1xnmsGraHVdGZqMKXJjjk5+cNVqG0muX8hMyJcONqN1BBGMe3WqU7N54UMN3bPrXR+DIbm/wBduLqbC29nEqIqjhpGzk59lH/j1aU48zSMZ1FBOR39FFFd55JBe2y3tjPbMcCVCmfTI615fBpd0gSISJbyxZSRD3I616vXJeLfD0s6y6rY3KxTohaSJwdsmB1GOhxWVWHMro6MPV9nKzOfuPKs7X96UkY+nPPrWLLqY+ZijZPQnvXO3eq3kkzJKWUjjC/41Z0uG5uHDFCEHdufyrl5EtWdjqOTsjY0+KWd2uZhtGMIp/nXceBtWglFzpSQus0B815ONrbun44H6VzKJshVMZP0rrfDmjjRkd2X/TLtxJP/ALIAwq/gMk+5rShdNJn/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-38.png', linkedinUrl: '/in/matthew-alexander-57352bb034', jobTitle: 'Engineer, electrical', }, @@ -385,7 +385,7 @@ export const peopleDemo = [ city: 'Josephberg', email: 'nancy.green@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-39.png', linkedinUrl: '/in/nancy-green-08c0a785dc', jobTitle: 'Horticulturist, amenity', }, @@ -395,7 +395,7 @@ export const peopleDemo = [ city: 'Lake Jamesside', email: 'cindy.martin@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDtjTDTGmPYVH5jk9K4DrJSwUEkgCs29u5hGzxoyRIMlimd1Ravqy6bGhK7mY4VepY+wpIrPV9ZjUXESwQNz5Z64pXd7IpRurswLnxD58qkxNLECdqDv7mpU1G5nTcLNoV7HeM/yrbOipp7OVjRl/hUjpWHfSjd5eNj/wAI/wAKmUujLUCBNaltpt0Ry6nLJnOfwrtNK1GDVLJbmA8HhlPVW9DXm80yq4MgB57npW94VuFj1WWOMkLNHyp/vDofyzShKzsKcbo7ArSbakIpMVZmYLae174sjlk5jt4tyr/tE11iHAwGrkPEN1PpyzzwWclySiIFQkYJJ5yKPC13qF0nl3SSIWjLjec49s0We5tCzVjqp4t6lTgg1xviLSXMRcKTjkHoRVHV77WLXUV8pLqdC3RW2qBnFathf3GoZjmtZoyMqQx3KfcHuKmUXa5orXscEJJN7JIC6dCO9aGhXX2TWLXnKF8cnoDx/WpPFOlPYXiT24PznkDp+NWNH0tv7S06aU5kMgcxleg+vcg4yKnqiXF6+R6NSUtFaHONGzeUZQQ4wc+1MWeythON6IwXaO1E6kpkdRWJqN1pCyeRcxPI+3DbUJz7GjU6KSTRuW8kNyrKSu9eo4IIqO5uY7dTtQfhWdZX2mPEIrIBGHO0qVP5Gn3CM5+aspOysbqKuZ10TdFndc4+6Pen6PAw1e2gz5nko0rsTnaOij88/lVHXr6XTLIT2+wsGC4YcHP+f0re8PWJt7VruVt91d4eV/5ADsBTpK7uZ1p2jyrqavajFPVSxAAyfQVOtnIxAJCk9j1rdRb2OJtIqbcgj1rKe2O4o8/lMD271vG2K9DurI151hNhDtVpZ5iv0UAk03B2uXTq8srdyDYlvH80oc9c4xUEl2ZBtXkmq1zZyswMROB1BNWre3Cbc8nvXKzuuYPii1efTrdMgKZhvYnpwa6/SVdNMgSQ5ZUAz61Tu7Fb60a3JKl/usOoPrW3bWqYWMEoqAIpA9K0u5//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-40.png', linkedinUrl: '/in/cindy-martin-cef98190f9', jobTitle: 'Geographical information systems officer', }, @@ -405,7 +405,7 @@ export const peopleDemo = [ city: 'New Tracy', email: 'lori.martin@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDcxUF1eW1lF5lzMkS9AWPX6Umo38OmWL3U5+Vegzyx7CvJdS16fU9VaZmUknAzyEHoBXl6vY9BLuemf8JHYGN5FZiqjrtxn86p2/jLTpyUJ2uOi5HP51yNrb3usJ9ns0eYj70khwin6VZPwy1Kf52u4lOOwPWoi/5nY2dJ/ZVzuLPWLO7YIH2SHorcZrRxXl134e1fQrUtNiWNDkSJnj6963/B3iptTnawuXzKBmMnqcdR71S18zOUeU7Gl4NKRRigk8z+Impu+qJYlyIYUB2r3Zup/LFctpmmz6jcosW2KPPU9frWt49V4/Fly0o6ohj+mMf0o8Hwy3GqDjEaLub8Olav3YXQQXNJI9N0Syt9LsI4IiAF+8zdzW9FMkg/dsjY67TmuWubiWziyljLdORkADj9al0Wa4Y+bJbG2XGSmRx7VxW6npX6HQXcSTQukiAowwQe9eO3Wnt4c8b27QELBLMrR5PQE4I/Cu/8SXzxgkRzSRKAdsQya43xUV1LTre6hSRXhfYVcfMrf5Fa0bp+TMa6TXmj1Db60mKS18w2cBlH70xrv+uOakIqzjOT8T6DZ6tevJcwgGKFcSgnd16Dt39KzdC0ptLa6BU/PJ8h/wBmu3vrdpArjoCN1ZEzIt08Xmq7bQxx1Hp/Ks5SlqnsdtOMXFSSNmwuA6hSoz6modauGt7c7YZZDgkiJcsfYe9MswOMdSKjvdTngYrHayzMB14C/metYpanVo9iva38c95BC9vLG/l/OJBwD6emaq+IrKG5s3gjVY2dlO7tww5py6xNPcItzaGFjwGGCP0JqyyGa/hQ4PzDr9auzUkRNLlaZuhcKAOwxSEVIaaRW55Y8AMuCMg9Qa8306yfS9c1qxYEtFcCSNiclo3GRXpKdOtZGuwxLc2kyovmvlGbHJUcgH9fzol8LRdL40U7K6Xb8zbSprViaJ/m35B96xp9Mll3PCMkdRVV7XUYo8qmR6Zrm03PQTNm+ihjUsrDipNKjWbddMA3O1D6etYjWt38qztgEZIBzW/o20aeAp6O2R6c1pBK5hiJPlL5pp6U40h6VqcR/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-41.png', linkedinUrl: '/in/lori-martin-119def9345', jobTitle: 'Logistics and distribution manager', }, @@ -415,7 +415,7 @@ export const peopleDemo = [ city: 'North Joeborough', email: 'kathryn.cruz@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-42.png', linkedinUrl: '/in/kathryn-cruz-602e728f69', jobTitle: 'Designer, graphic', }, @@ -425,7 +425,7 @@ export const peopleDemo = [ city: 'Lake Jeffrey', email: 'robert.terry@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-43.png', linkedinUrl: '/in/robert-terry-8967a9c9ba', jobTitle: 'Sub', }, @@ -435,7 +435,7 @@ export const peopleDemo = [ city: 'New Hannahland', email: 'andrea.walker@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-44.png', linkedinUrl: '/in/andrea-walker-1047d1ba76', jobTitle: 'Financial adviser', }, @@ -445,7 +445,7 @@ export const peopleDemo = [ city: 'Tylermouth', email: 'steve.campos@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD07FJTjWD4w1SbSPDtxc26EycKGzgJnuaAE13xXpuhB1nk3TKuREvU+g9q8o1T4gaw7PIt68UUvTygMr9D29KrafpGpeJLh5PMiMB/ibJrej+GAl2tPcqMDogwDWTqI3jRk1c5+18falayQpFfz7Mjl33fzrsvCvxCd7po9VuTPDIMrNtA2H0wO1Zt18LLQJ+7mkHc1zOr+HrvQLRvIzJCGyfVfekqivoN0ZJXZ9BRSxTxLNC6yRuMqynIIp4ry34Rapczve2Mjny1QSbCehzjIr1PFap3MGrCmuF+JOphbO10lM77hvMc9gq//X/lXd1wPxPhI0+wukQlllMZYDpuHH6iiWw47lPwzapa6ZDFGO2Sa6yIoVGHyfrXm2qG6gSKCOS4AWMYW3HJIHOan8Ly6lJepBLJcbG5zMckVxW6noJ/ZPQJ3UKQXwfTNc5rBja1lVlDKQcg965rxA+pHUHRHudkeceS2M49KTTHuXYRu1zsxlknHIp20uPm1sM8C6gmn+OLe2t4gVugYnOeg5P6ECva68Q8I2ckHxIgOP3ccrAsTxyDj8ea9vrrhsefNWYZrA8Y2kl34ek8snMLiQr/AH8dv1rdqO4hFxbSwnHzqRzTkrqwoO0kzibFoJo9siKc/wB7mlW80+z1SOMvHGozjtk4qlNby2V9JbuRvQnOD1rPuLi2uj5clrM5XI3LETj8a4knex6is1oa9ld2F5dyIXjkR2OGHOCD0PpUupC3to9sMajjtWBbXVrbPsS2mjLEZ3xEfrV+7Jb+Kk+wDfDGnNN4jimYZAl84N6YBGP5fnXpuawPDGmG0sxcybd8yArgcqvX9a3q66cWo6nn1pqUtAopKK0MTk/F9kY2S/jON2I3Hv2Nc8kS3EYV5zGO2K7HxVLGmj+W4JaWQBPqOf5Zrz65SWJtyFsda5KqSmd1CT5DS8tLdDtmL+5qtuMsiRgltzDP51nwmacnOcZ5zWtBbmNAejCs2zXVnpwAUADgAYFLmuf8LLqU7Xkl1KzwAqsW5s84yfp1FbxznHpXbGXMrnnSi4uzP//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-45.png', linkedinUrl: '/in/steve-campos-1225440c77', jobTitle: 'Osteopath', }, @@ -455,7 +455,7 @@ export const peopleDemo = [ city: 'New Annafort', email: 'allison.morgan@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDpjgCkGDS7cimkbQeaZJk6z4hs9HjHmtl24VR1NcXrXiya6iVIH8tDy7Z/Ks3xIJ9W18W8AyWcRRg+ua7a1+Gtp/ZqQSzM0hwXbHesZT7nRCn2PPY7m3lIL3KSufRsH9eKuHCICjnPYP8Ayrqbr4U2oRmjuZS/bgYrjL/T5tGaaxuXLBMNG3cVKaexbi1uKt7cRXCzQO9vOh4ZD/h2r0nwV4nk1qGa1vdovYMEkDHmL649fWvJBKA43EFD/Fir9hqsmlX0V1C3zI2cr0PsfrVRbRnJJo9pUMBWV4hv2sdNdlOHbhTW2AMVQ1axjvrB4ZVDIeTkdK1ltoYx31PPPBSf2h4rDy/M0KPIo9zgZ/WvX4QVUAmvG9Nxpeuaj9mt5bjEB2pExVhlh3rvPDNzqM6xxXCyfPGZAJH3FfYnHWuWSO6m9DrM5BxXnnxA8My3sYv7QZmjBDx/31/xqfVbzV7fV4o1+1yo7YAjcIgGeMnFa1pdSX6tFJFcRsvylZfmH1DdxSV1qW1fRnhbSeVmMjDA9D2+tMWdmcZQEe54rovHOjvp2ttcRriOXkYrnlb92T5eCoya2TurnLJOLsfRgHFGwspGOo709RmpdoArY5zh/DlgbfxNdT3UWGmiZCpHAO4cflXbWkcEEkpiCKQu0DgVXuYt2HH3l6Vk3b6YzlLu7MTEfOAxBI/CuWpG0jvoPmidGsUFx99V3rwQwplxNFbxn5QMVm2l1pqRKlndq7D1k3MfbnmlukabgnA71m2bWRzGu2A1qQZj3bT8ozjJrz7xbpyaRNDbJIplkXc6Acgdv1z+Vdv401O40fSzcWMxim3BVYAHr9a4XwvpkvibxGpv7p2lkbcXbksRzV0ovcwrTVrHu6nFO3GmgZ4FW49MuZRnYFH+0cV2HCVc5rEnsS9yyGRUOchiOorq00xf4pC3+7wKwdbgYa0LfkQrAroB3OSGJP5VjWS5bnRh5SjLQhhs0tl3N5LN/fC81DPfFiURt59qqyWs0kpjWUgehPUVowWSQoo2jdXI3dnbfqzkfF2j3Gq2lnbRMilpssztgDg1q+CfBLeH7qW8u545nK7YQo+76n61qXmn/b4/spj8wyHbtFdXp3h9LDSbazEjM8SbTIf4j3P510UNTgAAOTEaH//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-46.png', linkedinUrl: '/in/allison-morgan-6486ee71fe', jobTitle: 'Microbiologist', }, @@ -465,7 +465,7 @@ export const peopleDemo = [ city: 'Samanthabury', email: 'tamara.melendez@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwCwzgmmHkihonB6VXvJvstpLOR/q1zUFblXUNRFuwhgAaU/e77a5nUdXVw0Ubs859TwKdpqXuraj9ktz++l+aR+u0V6PpXw/wBMtoAJYvOmI+aRuua5nO71OyNPTQ8itpZS+4S/vM9COD9K2odQkZQrL5cvUHoT+NddqvgFYJWmsiQOpjI4/CuQ1BXsy8Ui9D1xyDU6Nj5XFGvpmuLI/wBnujtbOAx459/8a3hGTXlpndpSS/I4z616F4TvW1PT2jZt0sBCk+qnpW8JPZnNOK3RuEAmsbxUTHoExXqSB/X+lX/ONVNYje70i4iVN7bchR3Iq5bER3Qz4Z6eBaz3z/NLK20ewAr0+MEIOK8s0QvpWiLEz3DZZsLbr8xPXrn8K6bw/rFydsUsd04ZS6+ZgsB71yNdT0IvSx1cmdvSvOvHuhefbNfW6/vEH7xR3HrV7VdRu5/9IzeNCORDbsASPqO9Q/2pLIoVYriTPytDNgEZHrRbqNu+h407Mkh54zXZ/Da4b+3ZoudskByPTBGDWX4n0S4t7/zo7URRzE4jV95B/IV0PgfSLjTb97mcDLQY4/hJI4P4VvFq6OWcXZm8akT09aQofSlCkGtjmNbQLdVsti7QwY5DDPetiKFIriZ5GQME9hxWTo2csAeQc1avbzSTOVuWzIF2nbnOPQ1xtWlY9Sl78U0S2durqwiEfHOCOmf6UlxAsJLlVyBxgYGabp97poXyrNo1YdEHBx9KdeksDk8AVDLtY5+S0W7u0ZwSFJPHpVlgqyMQOTjcfU4rm9b8R3mmarbWNmsf+kY3MR8w5xx9ea6EJj1/Gt6MOpyYiorcqBk9qYUFTkcVGxVF3MwUDuTXScZYsnMEu4d60xZw3gD7lViMZHWuP1bxFHpttI0KeZIqk5PQVpeHvt1xoFpc3M5FzKN8hA45JI49uK5qySfMdmGnJaHQC1gshuGzJ/i71Ru7kyjy4zknkn0p76deSNiabK+1TxWSQRkCsGzqvc4DVYtLbxPAl9eJbSKFKl8888AHoOa7f7Kp+lef+Nba2uNVgfJNxESSB0xxjNdH4X1vzLeOwvGCyouI3Y/fHp9RXX//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-47.png', linkedinUrl: '/in/tamara-melendez-33bb698d07', jobTitle: 'Accounting technician', }, @@ -475,7 +475,7 @@ export const peopleDemo = [ city: 'Port Howard', email: 'larry.robertson@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-48.png', linkedinUrl: '/in/larry-robertson-6829bf55c6', jobTitle: 'Production assistant, television', }, @@ -485,7 +485,7 @@ export const peopleDemo = [ city: 'Rachelmouth', email: 'lisa.cook@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-49.png', linkedinUrl: '/in/lisa-cook-87669acc77', jobTitle: 'Clinical cytogeneticist', }, @@ -495,7 +495,7 @@ export const peopleDemo = [ city: 'Marvinborough', email: 'kirsten.moore@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-50.png', linkedinUrl: '/in/kirsten-moore-91e3033de9', jobTitle: 'Media buyer', }, @@ -505,7 +505,7 @@ export const peopleDemo = [ city: 'Mcbridemouth', email: 'amanda.frye@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwBdtBwqlmIVR1JqUJmsDxbeNbad5ER/eSEcDsKbYLUr6p4ktYWMMLFvV1GazZdUneyaa2ug7vwM9Qa51TNcMFiJaZmCqgA5PvXVad8ONXndJ5niQt1G4msnJdWaxi3sihbardSbUuZwjZ5IbP8AI1tWetSW0qxXCl4mPEinOKS8+FVzFEXgu1LjnG3+tc00F9YCa2u3KSQMCrk9vT3FKMk3oxyg0tUejoVlUMjBlPINSKnFcLo+vSae5jlGUY8qSePdTXoEDJLGsiHKsMg1qncxasSKleV+JNTebV7sOdoVym0HsDXrJIRGc9FBJxXhWry+dqc82CvmOXwR0B6UMEdn4D0P+0LkalLwkbfInqfU17NaxlIgO9eW6Sk+l+FbQRrOXlTdthO05PPJrb8M3Or/AGu3hnllaOf5v3pyyexrinq2z0adklE7/BZTxXk3xG0C5hvjqcQJt3QCTH8BHf6Vu+K7rV7bUUS0e52bsHymxU3lXWp6Vd6fciff5TL+9IYMcdQ1OOmoprm908Y+0yriJfLYMevUCvXPDj+boVqQ2/CY3DvivHnikhlkj24YNyD6ivWfAjeb4aQnGfMbgds11o4GdCorzbxd4cuH8URzRxAw3bAKw6BsdPrx+tekrUV9F5to5WISSoC0QP8AeA4pvYS31J9DSFtOhgkVSVjCkEegrQt47eLVoUjVVC8k8CuZ8O3c93psU86COfcySoBjaykjGO1Wb290p5Y2uLnZMmQGQnKk/SvPs72PWjZpNHVvFazTskoQtklScHNR3Iit4yFA6dhWNpd9ozIUtp4zKz5Y5wxY960L11iikmkYeXGhck+gGap9hPQ8v8T+HPLgeWBQ1zfXQWKPvkkljnsK7bR7EabpVvaADMaAMR3PeuU8KXuo+JtROpalJuhtAVtlChVBbjPucCu6QcV2U00tTzaslKWhAvSnUAU8QyFd2ML6mtEm9jNuxTnRbfMkYC72y2B1PrRDbvc4aOWNGA6kVUZbltduo5ZT5CIgiixxyMlvrnj8KbJDPFJ+4fZ6g9K4a1lUZ6OHbUEzcjtGSL9+8Uh7ECqOtwy6ppE1lHL5azbUdx/dyMj8s0WtndOC1zNlOwXjNJ4hguP7Bmeyby57fbMnvtOcH6jIqYyXMmyqnNKLDTNLtdJtRb2ilYwc8nJrQHSi3t5Lmxt7qMDbLGG2k8g45FDxvHw6lT71aPMuf//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-51.png', linkedinUrl: '/in/amanda-frye-1f5377943e', jobTitle: 'Metallurgist', }, @@ -515,7 +515,7 @@ export const peopleDemo = [ city: 'New Troy', email: 'jennifer.chambers@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-52.png', linkedinUrl: '/in/jennifer-chambers-ca724f5258', jobTitle: 'Agricultural engineer', }, @@ -525,7 +525,7 @@ export const peopleDemo = [ city: 'South Alexandra', email: 'rodney.roberts@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDRIz1pu0Zqby8d6QLz0rnOgz769t9Oh824fGfuqOrH2rkNU8W3CyFY3MK/whOSfqah8QXEusa69pB84Q7EC+g6n86i/wCEG1W5T7yrg9zmqTjHcXJKWyKN7q8sxWR53yEG3JOR+HatPS/Fl9bKPLl89E++jcnFRz/D3U4bcYkEjDqBWdJ4Z1GwhaRVYnHO09qOeD6h7Kouh6bpniKx1IxRFvKnkHCN0J9jW4sPFeAR3EkDYaUhgcrjqDXufhfU/wC2fD9vdM26UDy5eMfMOv58H8aHGwlK5Jtz1pGGFJPQAmrAjXFJ5ecggYPapKPPfCcAuL65vD80hwoHoCSf8K9Ftrdwgxg5rzqW1udJutUjtzIF+04j8oc42gj+dbPhfUNYuZltbjcQULhn6j2PpWFRe85HXRlaKidhcRuqYGOe1c7qGY4yu3nBzXPavfa5JfsEa4KIcERnr9Kv2M125+zzLIwHd+fyPeocdLmilrY8+1nasjMqJuV+uOo9D+Nek/CpxLoF4oBytxzkf7IriPEtg8OtFYFLeYoYADvXpfwysGtvDlwZCpke5YnGeMKODXZGScUefODjJs1QM08LSqvHSngEVIGVJFbC/nikUZmw5z64x/SrGnNZ2styfMjXbGVXoOfp2qjr0bRzQXC9MFTj86xpptMvMlw27G1jEGJIHY4rCSfOztpNOCsdBbCzupGjLxOxG4FSGB9qbeG2s1YIoyf4qyLPUdLs4zbW0QiZiMAqVNJeSEltxJI61nJW0NU7me1pHdX5mLMsmNqsD93nOa9E8NwG30Zdww0rtIeMZzxn9K84Ed9d3draadIUluZhGzhQdqdWPtgA161GgRFRfuqABXTRi/iOPEVFbkRkgY7UoU+lSLgClyK0OcoanZNeWMkcf+s6pn1rj4El27ftLW0i/KQOPwr0Ec9BmuY8W2iJFbXCqI5ZmYZA64A61NSGnMbUalnymS7Lbw/PcLMx7kfrWbNcSSgqGLEnrWXN9p8zax4z1FaWnQOSrOeB0Fcz7nYm2Wk1G80I2s1kkbzSyLBiRc53H/GvVLdy6K3fvXF6Ppv27UIZHXMdsfMJI/i/h/xrs7cSJPHsIIZxuBGeO9dmHi3TucGJaVSyP//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-53.png', linkedinUrl: '/in/rodney-roberts-4b08e437c4', jobTitle: 'Recycling officer', }, @@ -535,7 +535,7 @@ export const peopleDemo = [ city: 'North Erinton', email: 'lindsay.wagner@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDQa6Uj7wqFrjPesliR3pqMxbqaokv3F1FBGXmcInqaxbzxlY2SkQq08vZRwPzrl9e1Ge+1T7JGSyq21UHJJrRtvAtzPbiWWZVlb+EcgVnKokawpOWwrePdTdgqQQx+zAkmuh0jxMbtdt1GEf8AvL0rlLnwfqlsCyyK4HTmjTlmt5wssRAAw64zis3U6pmipW0kj0czc+xqWKYZ61z9jeblWMtuQj5W9K0E35IrWE+YxnDlZRcVn6rdmw02adR84GF+prVljwKwvE8LyaHJtxhWDN9Kt7ELczvB+niW4kvpPmccLn1PU16TaxssILV5/oZih0CKWZJHEjttSM4z2/pXQ6FcyPLHGvnLG/ISVtxFcFRXbZ6dGyikdOIQw5x9DXIeJtJuIJRf2i5XGHVal143FvdHdHczoOkccm0da1dOm8yP7M1vLEvTDHcp+h71K0Vy5e9ocRp98Q5wMLnlf7prr7C7W4g35+YHDVw2uo+jeJZVC4ibkD610fhzLxzSg5jfBHsa6afxJ9ziqrRrsbckWeoqjqmmG90u4t4+HdeM1ueSWxxTxEVHSumxy3Oc8MRx/wBjW0TphkUqQR0IJzWva/ZotTG50TaM4J5/KopYzBdFgAobnjvVKW7sTcnzIzK4BB2LnFedKL5mj16TvBWOh+0Wl6R5UkcvBKuhBB5xVuIQwEFhnHpWDaX+nAqsUfkOT91k2k/41svHuiHI5qGrGmhy/iTTYdR1KK5kTMa/K2Op5FJ4dtUtNRv7FeYoeh9CSePyxVnVddh07VItPW3knu5EzGqYAycjBPbpVrR7CSztnadla5mcyzMvTcew9h0rooRk3d7HHiZwUbLdmxGntRIpFS5KCnJZ3d1zFCxX+90H512nnmZeWzyQb4xlk5x7VkRxRyLhzg+orsJtOubPT7i4JUvFEzhBzkgVx20yR71PJ59q48QkpXO/CylaxrW9tGINodXXHcVP5hChM5PasW3F2X2k4U+lasUYRwuSfU1zOx1XbMBtEubzxY1+4CQxOu1ieSFHQD6110cINS6Hpcmq314qELDHEB5nXEhPA/IfrUzWVxZXDQTgB154PBHqK76LTgmjza6aAAAAAJtM/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-54.png', linkedinUrl: '/in/lindsay-wagner-0562c96aa1', jobTitle: 'Psychotherapist, child', }, @@ -545,7 +545,7 @@ export const peopleDemo = [ city: 'East Patricia', email: 'mary.haynes@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-55.png', linkedinUrl: '/in/mary-haynes-a41c2d1798', jobTitle: 'Arts development officer', }, @@ -555,7 +555,7 @@ export const peopleDemo = [ city: 'New Kaylee', email: 'david.phelps@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-56.png', linkedinUrl: '/in/david-phelps-0dbf8cb8d9', jobTitle: 'IT technical support officer', }, @@ -565,7 +565,7 @@ export const peopleDemo = [ city: 'East Bruce', email: 'patricia.smith@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDkDOrDrWfvzcNUhqsDiY0AWw4VC5BIHb1pHMwhedyqxKOAQQazp57i5vUtLdjuJA+XrXcaR8Nri+iWW7unTjp/jWE6iTszop0m1dI88uJJLg+cwIUHgHpWnpsU6fvSSy4z0yP513Oq/DthbKkUmFjBxtHX61xV8t1o+YZDtcfdK1KmpaFOm46sry37i4yPkdT95ePzrrtGv7fUIShIE6DJHqPUV5xPctJIS3Oehq5pGoPaXkUytjY2Tz1HcflWi0M3ZmzVUn98asdKgAy7fWtTE3Ph9pi3viS5uJlybdcrn1J/wr2uCNRGAGBJ7A1474dtXtxelRJMzhMeS2Mdec12Ph68v5YXEolj2xlh5xyy+xrgqx95s9Ki1ypHXXACLtD7ie3XFeceOfDbX9v59uuJo8nbj7wpby81AXhlZ76ZAQNkA45Na0d7NcKIZElyvGHHP51FmtUaOz91nhFwjxMyEFSDyD2qONtpzmu68b6MElS8ih27ztcep7ViWvhWZrOe4uDJDtB2Ar3xkZ9uO1dcaicbs4nRlz2RoEVAg5P1q2y8VAik5+tbnMd58PSkkF9FKFYfKBnsOa7WFIILK62bMthQo4yK8x8I3bWurGDOFuF2/iOR/WuuvxYSjY1/5J/5aDcQf/rGuGsmps9PDNOmjWt7W3mLKyKGTjB6j60s0kNpCVWNR9KzrSewgtylteLLKxzuMm4n2qK6EjkhjmsWb2Rk30a3r4lXcgcNj1xUF/apDClkrbZ79wgUc7R/Ew+i96mu2MYJRypXncO2K5fwpcXer6zd6neyyTPGpjiLdFBPQfhWtGHMzCtV5IvuyMxZQ0yKLC9K0ng2qRVcJtFd55Yy3LQXEc0fDowYH6V3tvCdTs0uIXQbhyGwea5Cx0671CXy7WB5W74HA+p7V19n4eudI0m6vLq72iOMuIo+Rn61jWhzK63OnD1XTl5CpYxWQMsiRGU/xYBNUrm9Zt2Dkn0pLnzpQpDllYZqOK0JYZHFcPU9ByuVpIme0lJzllIpPDMNmllJ9lDbAwB3LjBx0rYFpJdFLe3XMjnA9veujt/DdtZadHZQKQA24t3LE5Jrow7erOTFWwAAAAAADRH/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-57.png', linkedinUrl: '/in/patricia-smith-5277401ff1', jobTitle: 'Scientist, biomedical', }, @@ -575,7 +575,7 @@ export const peopleDemo = [ city: 'Port Crystalbury', email: 'rachel.morse@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-58.png', linkedinUrl: '/in/rachel-morse-86b5f8b59c', jobTitle: 'Patent attorney', }, @@ -585,7 +585,7 @@ export const peopleDemo = [ city: 'Mcdowellside', email: 'rhonda.nelson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDW3ACoJpAKjEvqarySEmpAnADkFshO5qvPeQW6sVRi38Kjq3+FSTqwthbxSHzpANoHQk10+l+Gra2tdsq+dKy4eRu/sPauWdRt2R106StdnnE2oo8h8yeCIkcRoMkfU9/wqpdxhF379w7HH+FeqT+FdKMbAWUXPU45rhPEegw6XGVgG1SeB1B9uazNXDQ5YaksTA+YwYHjg8V13h7XUvf9HmkXz+qnoWFcKZDFn5XPqoNVvtrwzrNCjxyKwbdnmtItp6GMoprU9I8096a7ZHNRl6QPXUcxo6Qpm1S0VsnazFR+BNd+jbVAzzivMTdy28TNAsrTkbU8o4Iz/Sug8K3+pXltdw36SBoc7ZXHLc1yVY2lc7qDvCx1shJXjmsXWIYbm3eKeFXBHRhXI351u0uZriKS6lSMbthkPz5PRRmtXT7++1NAtxazRkccnI/A1DWlzXrY8z1uFbO7kiVTwfut1H41iCchjhg2ezc16D4+0gtbQ3aL+8jOCa4e30uWYl0gIbBJ3HA4GT/Kri1bUxlF81kd/uyKZnBpp5GBTAeetdhwm54bEcmrqJACNjYB+ldeyRW8ZSFVAZui4/lXn+m3H2TUIZR0DYP0PFdHdDRnuQb68KOpyyhiOfw6VyVr8x6GF1jY6SGG0uowzKjY65FRXc0Fmp8tVAA4xVG2u9OeNYbC5jcjsr5P496qXUckrkO3APNYSl0OhRRm37jUQ8brmNjzms3VIYNF0C8mkwsZQhE45b+HHvWnejERihba54DDqPevLvEt5e6jr5tJ7hnhgPyoBgBj1OPWnBXZE5cqudkORTQnNPCkcU4e/WvRPKGKh3ciuvsLWPUraOd5zE4G1tvciuWAJAJqWG5ntt3luyg84BrOrDmWhvQq+zlc7Ux29jFtUoCerAc1jXmpRICqtuJ7Cs2JLm6tVa5lcSPkjnjGeKt6foyg75Tkg9K86W56MWmrjrSB5I2uJRg4+UeleQa8Xh8V3SnI3tnPtivdpYx5BRRgYrz3xJ4WN/dJdQYE8ZI5H3hV05WepnVi5LQ//9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-59.png', linkedinUrl: '/in/rhonda-nelson-0f7ce0e497', jobTitle: 'Environmental manager', }, @@ -595,7 +595,7 @@ export const peopleDemo = [ city: 'North Vanessaport', email: 'lauren.carroll@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0Qzop2461SuSWJAYbKW4kKxOwTcQOAO9Zkl08VtLOUZiik7B1NNszvrYz9b1eDREEk+W3dAvWuEv/AIjXtzLtsk8hFPAb5iRQ0V9461aTa5SCM4OOiL/U10lp4I0qwjx5bSvj70hzWUqqR0QouRxF5461uR8LOkK99iD+tdD4d+IEMu231N9shOBMB8p+v+Na1x4L0eeIh7bk9wTXDeIPCTaVG09o7vEvJU9RSVRNlSoSij2G3McoDA53dCOhp4tX8/dGQo7471538OPEEkxk0u4kLBV3QlzyD3UV6dZKQh3EEnvWqOaUdRzzAITWFr9+tpot3IDhjGVBHqeBWpOp8kgda5nxRamTQLokZ+XNKTGtWQ+DLZbPRAYgF83kn1rodwOBuzXJXjPZaHZW62ckv+jqTg4AwuTz61H4XlupJFRxIkTDeFZidvtzXLLXU9GFlZHYSkBOo/OsPWFMllMoXcSpwPWsHxDLO07yBJJY4xkIrEZ5x0FTaVczz/upLZotoHfIpW0uU3d2PPrKd7LXo3jOzbIDkcY55r3iykdiHDEoea8av9Mmm8YyQ28ed7g+gGa9lsQLe3SM/wAKhc/SumLT1PPqRsWZG+TcMms26IuYJLbkbxtJ9M1tfZmCDB4qtPaYXgDce9XJXRCuncoERyWohkUfINpB9qpxNaxSuqlE2g9e5qxdowuZGGfmOeawr290vOzynldcqXjXJHrzXFrex6sbNJotW4gldo22tkkgjnIzU9wIrZMRqv4Vj2V/p6MYoYmgZjkKyYyavTEuwyal6aFaFG3tTNe7dgPnMCxPbGMY/KutjjfaQcCs7SLf948p2su0bGHvnP8ASthR8jA966aUWtWcFeak0l0NUE1XunZRkDj2p5Y9jioGLFtoySew710HOZ17C8luZl7cMPasiazjuIwGlVCvAxwa6a63xQtBJHtkZM7T1A965a/tXwXjYhvT1rjrWUtDvw7ly6kBtktlI3hvemxsWkUE8bhmq0NvcuzGT5Vqz5flgeorG+pu9UdctssCKiLwBgcU50+TB4xVWzvpLpo4tu6RuBirMqTK22VGQ+4xXfGSkro8ycUAAABxdmf/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-60.png', linkedinUrl: '/in/lauren-carroll-319b96609a', jobTitle: 'Statistician', }, @@ -605,7 +605,7 @@ export const peopleDemo = [ city: 'South Rachelmouth', email: 'shannon.martinez@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDP1vV4dHsjIxBmcERJ6n1+leb3WpX2oS+bNLISf7zYH4CrGvXcuo61dO5O1HKKD0VVOMf1qrAsodTtZs9MisWzaMSeG0LwNIwVse5GPpTUR13q3zA9j/Suz0jwdLqcSSTOYkIBwBXTL4H01IlT59453Vl7WKN1QkzzHR/Ed3pkwQs01sPvRMfu+49K9Asb6DUbRLm2bdG3r1B9DVfVPh9YtExgZ0fHWsfwokmnX19pEx+ZG8xfcdP8KuFRS0RlUpSgrs6oCnBaAKeBWxieQTuGl8tNw5+cnrXT+GIIZLyD93uI4HfmrmreDPMM11YOd5lbcj4788YrU8EafHFaPOw/ebtoJ7etck6i5dDthSkp2kdxagbQAACOMCrjKdoyK525vZrRgkcMzluAFGBn3JrM0nUdaurzLGVIGzhJMErzjnuKwUdLnU5K9jq51JiNcLNaAeMUuVGD9nYN78j/ABrV8VajqVoiW9oCS4G51PIBOKo6PGzRvK6uH+6Sz7t2D1B9DWtGPvJmGIknFo0AKcKXFKK7DzyzHEJZOYw3U49DxzUMES2x2xLtXcSR7k03UDdCwd7J9kyEMDjORnkflS2uchJHLHP3j1NcNaHKz06FXnjrujeg8u5jIYc47jrTfLtrVtqqBI/YVFErKMqe1Qz3OmMjreTRFz94FufpWUddDfQS+hSR4JJFUggqc1RlEYk2xjCgdKqNNp4nWO0uN4H3I8/d+lSxAlSx6k1vRj75z4mVqbTH0CloFdh5o+4u4rY+Qys0ske5VA4we+aIYWa1jdfvBRXSzaRHdweXgLMgPlv6e30rKgge3XyZVKunBBrjxPMpJ9DvwnLytLcrw3hyEc4I4OasvbpPHj5OnBPUVUvNONwC0Rw47Vjz/wBo2g2tJhR+dYR3Oq9ixcWoguFCEF+xzmp1UKoUdAKh07Nza/aGbe+5lY+mDVkiu6lCyu+p52Iq88rdhtFLRjitjnP/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-61.png', linkedinUrl: '/in/shannon-martinez-5f73530423', jobTitle: 'Designer, blown glass/stained glass', }, @@ -615,7 +615,7 @@ export const peopleDemo = [ city: 'New John', email: 'daniel.williams@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDpM0pYKCSQAOpNNrm/HV+9j4ZlaMnfI4QAHrmkM57X/iNcLcS2mlxqka7kM7DLH3XtXn11dyzys07mR253sc4Nb/h7wtLrUTTTSGJCflAGcmuhT4YtI/z3abT3EfP86zdSKdmbRozaujzxXMalvN3MPzx7Vd0rWLrSLpbm0lKk8MCa74/DOyRRm4lZh1zXNa94PbT4Xlt5twjGdhGOKSqxbG6E0rnqOh61DrmmR3cY2t0kTOdprRrzH4X6hJHe3emTEgSp5yA+o4P6fyr02tTAWuM+JEvl6PZnHH2jn/vk12OawPGenrqHhq4U53RfvVx6j/8AXSew4q7KvhNEGlwMFxlAQK7CKTagzXn5mvdLtbaO1V8CJdoSPdkgc5rU0LWtWupI4ruAIW5Bxg/QiuJr7R6UJK3KdTO5K1yHiXH2GUgbiVOfpSa1rOrrcyR2sfyRg7iACT9PWqFtLd3uVn83hcssiAdfpQl1CUl8JzvgJt/jSPaCAIpOc9sV69Xm/gPSmtvENzcsAUUPEh9Oa9HJrti7o86UWnqNFRXkQuLKeFuQ6Ff0qUdKUjIptXEnZ3MvSngubCJJACQoxmrUaQrqcaxhBtHOOOawCf7NnulGSsJZgg9Oo/nWFdXt/qE6TIqwMvTqCQfeuLld2j0ozTimkdnbxwSXsyShSSTgnvTdQEVvCyxqFyOa4uzvL3TriQ4EoY56En6mtnUr4PaqzZG5N5GegocdbDc1bVGl4ajURFwo53NkD1Y1vGqOjwLBpNsAoBMSsfU5GauNXXBWVjzqk+aVxRThUsdm7jJOBTLqB4Ywyk4zgmqIOU8Y/wCh24vY2+dlMciDqy/3vw/rWPBqTXmmR+RceVc7cbiuRity/gNzcJK3zFQy8+hx/hXMXugNFPiyuDbq/QEZUH+lc02nI66XMo3Rpi/S0sGaa6EtwARwvFYEFxLq8kUabii/6xu2B2H1qRfDl3v2XN2rr0KR9x/SultLFLW1EaKoAGOBUtpbGnvTepe0PXxdCS1uYfIkgCgH+Fl7H9K3uoyKx9G08S3ARgMZyfp6V1KWgG75MjP410wba1OKaSkAAAAAACWh/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-62.png', linkedinUrl: '/in/daniel-williams-f8d496db83', jobTitle: 'Nature conservation officer', }, @@ -625,7 +625,7 @@ export const peopleDemo = [ city: 'Arthurfurt', email: 'willie.cannon@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1WkpaSkBzni/xjZ+E7FZJAs13J/qrbftLDuSewryPWviZr+pxsy3S2UO7Kw2x2k/VuuKb4ljv/FHjzUfJdWSKQxKx5VUXgY/KmH4e6g74DQuD6LjFS6kU7NmkaUpK6Rmw+MdftMT2+s3CAkcGcv8Aoa7PQfi/d/a4k1WGGW2bCM8Q2up/veh+lZLfDKZLchrlcjnG2uc1Twne6TE0zKJYx129alVYt2uU6M0r2PpWzvLfULSO6tZVlgkGUdehFWAK8i+EevTLeSaLMx8iWMywhuqsPvD8R/KvXq1MRKAOaKUUgPINOtfs2pagSmH+1yKfwJrrLZZPLBArldXu7qO5mltYmSWeWSQhRnDZPHP0qTw/rOtyzR21zbgO67g+cce47GuGau3I9Km7JQZ1Ny03lFccGuV1395ZvGFLZHIxUWpa94gE8yQ2y+XGMs6jLEZxx6063vJ7phHcxOrKMkuuP1qWn8RfMneJl/Dq0MXj+3Kk4EUpI/4DXuNeQ+HEl0zWbi/t1VpgwiVWP8BYbiBXr5rtpzUtjz6lNw1fUZSiilrQyODuobb+1L22ugAfNJXI7HkVLpP9nx6jiOSFFjU4BIB+uPSmeNrMxX8F4vyrIu0t/tD/AOtXOQhtRBLWMrkDGQQpx7c5xXDKD5mj06c04I6ALp89yyyNFKj9WQhtpz39Kh1KOztIdsAHTGay4pn052hi05o0kOG2bTj645qC6mTzTl8qOgzWck1oaJrc3PDNs13eQAKpWOTcWxzgcmvQzWR4Ygji8P2jKqhnTcxA5OSTWvXdShyo82tU55eggoqtd39vZLmV/mPRRyTWFc+JJ2QmCJIl/vN8xrSxkauuwWdxotyt82yBULl+6kdCPevLD9mUlLiaVCv9xsE1vXss+pRyJPKzGRCo3Hpn+VYOqWX2q2DIBux0rnxGjR14a7TsLNc2Fpat9nnkZiOd5yfzrLtBJeTg5IQH86bbWMccgZixPTa3OK2bK28s/dxXM2lsdSTe5e8B6rd6d4k1LTrt2+xvtkjyeFzkZHpyK9SVgwBBBB7ivKrKHN/cXGOirGD+v9a2bW/uLOXEcrqp5wDkflXfTu4Js86qAACSm0j/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-63.png', linkedinUrl: '/in/willie-cannon-44b80be6a1', jobTitle: 'Engineer, electronics', }, @@ -635,7 +635,7 @@ export const peopleDemo = [ city: 'South Kellietown', email: 'donna.cole@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-64.png', linkedinUrl: '/in/donna-cole-2daf2f491d', jobTitle: 'Land/geomatics surveyor', }, @@ -645,7 +645,7 @@ export const peopleDemo = [ city: 'Estradaborough', email: 'morgan.cook@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDjDTafimORGpdzhR1NIoRmCKWZgqjqScVXXUbdn2oxbHcDisPUbxry4wocxA4RB3q9aaLqkkYKQhEPZjzUSmkXGDZfGu2ySeWAWI9Kuw30M5AVirHsaypvCd+IvMGPM67VrNUzWkjRXKlD61KqX2KdNrdHYqeasxHmsLS77zl8qRvnH3Se4rZiatU7q5m1ZlDFU9UYJpsxzzjj61cNY/iFytgij+KQfyoewluN8LWAubpp3XIQ7VHvXpFrat5G4qMCvP8ARZBaaPHKbczNJIwVc4H1P5V1Wg3shaIIskaykHY77gP8K4aqbbZ6FFpJI6RLbKkhBjHeuS8XaEstsbmHh1GWHtV3xHM1pMH8hp2OMLu4Az6VYs5Gu4XhltPJYAg7eUbjtUJOK5kXJqXus8uinks5Bz905HtXaW0oliSRejDIrj9QgEN9cWjkhomIU47V02iEtpkOeSMg/nXdBnnzQ+s3WrSS5tFMY3NGc4rTxzTguRg1bIRZ8KpBJo1ukijgHg+uTW3CkSatDHuSMDnk4zXPaPcBlZVTYyNyPX3rQe9iN6N1u00ijspOK8+SfM0enTacVY6WNra6IG6OQZO1lIYHmrF4sVvb54zjtWZYalbSfuRaPDIT/wA8iAfxq5eAMmXbgVnK60NUcRqtjGLPUbmVAVZDJvIwQw4AB75qj4aYtZMCcjOR7Vna7r11qsCwhBDapK6bVP39uME/n0rQ8MROtq5IwrYxXbRTW559aSlsX9tPRaf5eO1KqEmug5zLvPO02+W/jGbdUxMuexPb3roLD7NdhZS52sMhuhqE2guUNuy7hINpAqpbRGISwKzfuZCm7uQO9cuIilqdeGk9jroltraDKzZGO9V5ZWuVIXOwDr61Fp2mAgSSyGQYyMnitF0URYUYFcTep2o8WCeTqcsci5AlYMPXBr0XTIo57OOSEDYew7Uk3hGLV9QTZmOZnALDuO+R9K0NJ0K70G4ntpo2e2L5SRRuGOnPpXdTqp6nBUpNaH//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-65.png', linkedinUrl: '/in/morgan-cook-82f95695fe', jobTitle: 'Research officer, political party', }, @@ -655,7 +655,7 @@ export const peopleDemo = [ city: 'Colemanville', email: 'elizabeth.smith@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDJnmhjhZpCFVRkk1xt1qklxcsI28uPPA74961/EshTT1RDjzJAGPsAT/SuN+0MGKxjn+8aweprBJam1G0LMu+YjJ7g4/OugtZZLAobZY3Vh86mYfOPoe9ZXh7Rr7VXG3Ij/vMK7mH4ewTqn2q8fb2VOgrNtHRGDaucNcTtZ6gbu1Ro1LYdSOma3ElS5ijnfAYjGB3rt38B6edONspds87icnNcX4g0qXSXt4pW/d7tqyEUc1mJ07p3FIDrjHNTwRrIMHimyYSTjvT0kweBW5xMwPFeRp8RX7vmYb8qwtBs0vdYjjKbo15I9a7nUNOh1CxNo4bdK4CMp+6eTn36Vl+EtHex1a6ilKs0aDDLyDnuKxctzrpwdk3sd5p0aRoqRIBgdFGK37eMsgB4NcRqN1cWo8uGF2ZuM7iBWfpF7rKzReZJMqTchGOdgz3Has1HS5031seqRuQNoOO3NcV8R4fM0LplllTafqcVB4t1HVrBooLPzNxQMxjPJzxgVBcQXl14fZdQVxsuIyGLFt2DTS2ZMtmjJTAjiUnJVADmnSTKg4qRkRVzVVolJyDXStrHnPU0kDRyZYnYePpVuxskswvlgEleXA+93qi0pdQp4HrRYQ3Meuibz3a1lhK+UTwrgjkD3Fc8o31OqhVt7jOpheK4j2SRqc+tEkFvAUjijy7ckgdKhiXGCKrarfaWkSx3lwFfIJCsd36Vmrs7NDp7q2tpzCJgjboxhiAcEdqyPEM0f9ivCihQrrj8+1Q6bqGj3SNFbXRkuFI+Zs59h+tV9aIkmhhPUAuR9elXFe9YyqvlgznSPlwagYmNsnpWw9vGV55PtWXcJlyvT0rdM81mpFGncA1pRRRMikLyO9S6D4cu76dJ5BttUbJLfx47Ct7UtBVEkns0ALN5kqDufUf4Vk4Stc6oOPMrnPedsBQnB9aj+xC6I+dFYdGI5qSWMNyRnNReTLxs5X1rJM7E7FuK2FpEzyTxuBzkDpWRLI93dyTMfvHAHoO1dNp+nCSIqCVJX746g9qh0/RTq+nNf2KKk0btHPbZ4DqcEqfQ9cVpDfzOfEXkrmD5TR8tR/ZxmG8HBrRmt2G5HQq6HBU8EU61R2BXzP/Z', + 'https://twentyhq.github.io/placeholder-images/people/image-66.png', linkedinUrl: '/in/elizabeth-smith-205530e011', jobTitle: 'Prison officer', }, @@ -665,7 +665,7 @@ export const peopleDemo = [ city: 'East Jared', email: 'nathaniel.johnson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDpKwfFusy6Po++3A8+VtiE/wAPqa3M1w3xAkMlxYWwY4wzkfpSY0cbNez3jsZZZJWY5bj9arywXUv+pBKgcjv7GvRfDWkwW9vEpiVnbliR1Ndja+HtNHzraRKxHJArndZJnXHDtq9zw+OBgHUQush2lSB901L9vvIUhWXdDMjZVhwTivcpdItF5W1iOO+2uQ8VaFBeWMoESrIo3IwHQikq12N4ayvct+FNUm1LSi86kMrYBPcVu9a4HwLeTQ6hPpsg+RohKp7gjAIrvM10rY5HuNBriPGyldWsJSOPLI/EH/69dqDXPeJrQXElpM3SNwPzPP8ASpm7IqnG7NDR1AVOOQM11dq2EA6j2rgrt76zYG33nIJVUAJP51paHqurtJAl4oCy8jIwy56A1xOPU9GMuh17uzDA6VzfiD5bSQoMkKePWq2v6pq0MsgtBlI/vADJP0/Oqlmb65kYXG/7uWVwPTtStpcpvoY3g4CbWr+cAY8pQD6ZPNdrXO+GNPWyW6lXrJKw/AHiugzXdB3R5lSLi9RoNUdUh862P+z835c1cFKyCRCrdDTnHmVhU58srjtOMNzbxiQBiB0NSSoi6nbxxqAR8xxWVpxeNjg8oSGH0pJrhJ71ZluRBKnTDgE+2K4ba2PUi01c3UhilvpVkUbs5GaW8MUFu20AHBrFt7oRTvI9ws0jnPMgJBq5qMu+2LE4yuealq2hTaILEFbOMZGGG7gepqzmqmm3MF3p8M9vKJIyuAw9uMVarvpx5Y2PKqz55XInkSGNpJGVEUZZmOABXMaz470y0s5UsJ/tF0VIjKL8qn1JNcVrOqazrDv53mmEciJFIUfh3rmyehrRIzPRPCGr3K6YJZ5WkbzHBdjkk5zz+ddbHCLlVkEcRZhxuGc1514Lv4BPJplywQTnMZbpu9PxrtLUX1rcfZI2QlT8oc4z9DXFUVps9CjP3VY3I7VYFMjxRhvoKxtdvpX0i88pslYm5H0OBVi6XUpMRTNGhf8AhRsn8+1Ynim/ttJ0k2MRU3My4C+g7samKvLQupPRtnOeCtbn0udLc5eCYfNHnoQM5HvXqFteQ3UIkjYEGvFrB9mo2uP+ei/zrv7XUorCBLiWZI1PyNu/ixUAHfY8w//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-67.png', linkedinUrl: '/in/nathaniel-johnson-847d2defe7', jobTitle: 'Geochemist', }, @@ -675,7 +675,7 @@ export const peopleDemo = [ city: 'Barkerchester', email: 'rebecca.elliott@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-68.png', linkedinUrl: '/in/rebecca-elliott-033486b7fa', jobTitle: 'Fine artist', }, @@ -685,7 +685,7 @@ export const peopleDemo = [ city: 'Vargasshire', email: 'kristina.olson@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-69.png', linkedinUrl: '/in/kristina-olson-be254bb623', jobTitle: 'Warden/ranger', }, @@ -695,7 +695,7 @@ export const peopleDemo = [ city: 'Palmerfurt', email: 'robert.henderson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDFzVS+v4NNtzPcMQOiqOrH0FW8Vxfi2WSTU44GOI40DL+PX+Vc0VdnRJ2RR1HWLrVrk72eOHPyRKeAPf1NMisQUJLfQ+n1rQ0rwvf3wSRIiA3KsWxW7/wgmtPnoVPXDDkVTlFaAqcnrY5SFPsbFmYc8D3+tXbbU5reRJYJGePnzEZs4ArqB8O7iaIvczhX9K5TVvD1xodwDK2+BjtLL/WmpxegSpTirnXo4kjV1PysMinAGszQL0XljtxgwnZj27Vp5GcHNQ9GNO6LRFcj4miX+2YGZT80QyfxNdgaztd0cyvpt2TlS4QjHYnI/kaSdmPlclodVoMKrZxZwCEGB+FdHGxVMFa42WN7eEF1uXJBZUhOOAPX1rS0W6u4mQSNOIpACFmYMyegNYNdTtUvsm3MWAOBXD+MlX+z5G2hsDLCtvXbu6lMoiaby4eWEJAZvYfnXPXVp9qtbjb9oDBMSLM27ORxzTiraim7pxOe8LoBYSyqMb5MflW2c5qvpNibPRLQ54kBP45qwx285Ardu7OPlcdGXiMir0rLNoONgLW7q5bPK4IH8jVOgSyRQyqpG11IYEZyKhq5dOXKzqLExz2ibwCQOM0t2FW7hjUAMT0FZ+lyERRspyCOlNvLq2uLgCeRUZOeM5FZWOxNNF6CIf2pcxsByN2DVTWfKhspgigEqeKrRzwQ3G62mWRz2LHP60zWZHltpCpCyEALnoCemadtQlJJHC+O70x3en2UTBHtoPn8s4GTgfyUVyv2q4ZeZpCP941v6r4X16a6kupgt1JIcsyH+lZL6PqMK/vLGcAf7BrqhZKx51RuUmz04AAEsQAOpNZU+srJefY7KLzzg73B+Va72+8MQy6TPbquXdCu4+pHFeN2l1LpGpEupBUmOVD6dCKap6XJ51fyO/t7o2G1ZCQjAMjds9xW2qx3ESkModhw1UbaK21jR0eJ1dcfK39DVW30u+YGO0vVQp/yzlXOPp7VyLzO9NrVGtJFFbIzu6lwOuK5W61A32oW1pCWZPM8yV16DHQVY1HT9QJFvc3qNvPKxDBx9a57WJjpV5C1owjdF2hR0I9xVximzOrN2uzthNkYNRsN3Nc5pniq3ndYrxfJc8bxyv8A9auwitSyZ7UpJn//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-70.png', linkedinUrl: '/in/robert-henderson-39d03b4d6f', jobTitle: 'Video editor', }, @@ -705,7 +705,7 @@ export const peopleDemo = [ city: 'East Travisberg', email: 'kendra.knox@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD07ArB8R6u1hFHa22ftU/8QGdi+tb9cfrMvm6xOePkAjB+gz/MmlJ2QRV2ZT25kO+V2kfqSxzz61kX9qj7i/zpjAUjitiaaNIyC2MdqxLu8UIw2nr/AAqTWJskc3dRyxSExj5fSut8AeJHs7+PSLgs0F05EWT/AKt/b2P865u4lySQM59RUFpKYblLhMLLC4kTHXIOacXYUlc9/NNpI5FmhSVejqGH4jNOrcwJK8k8WeJobTV7qG2PmTNKRheg5x1r07VL06dps92sfmGMZC+vOK8Qn024ufH7faowBNOZsKPlx97j86yqSS0N6VNtc3TY7XTNGW4tEmuZHaZlBZQcAVJcaNbr/C3/AH2aqatdXFnDtgjnd8EjyzgL9aqaJfatdTiG5kY7sMd+DtB7ZGOa5tbXOxKN7WH3egwSHcobHcE1yWt2zaQpuIfnCnlT6V0PiXVr+K4e1tFYFASzLjP0Fc3eJJd6TdBhN5yp8xkYHPfjFVG+5FS2qSPctCuWvPD+nXDx+W0lujFM5xwK0KwPA0s8vgjSWuFCuIdnHdVJAP5AV0FdaOBjZ4kngkhkGUdSpFeeXGlGz1Np5RmaNyA2P4SK9GIrB8Tac13YCaFik8Dq4YfxKDyp9QRms6tPm1RvQq8mj2ZRjWKeLBUE9w3Q1AsdtFM0UCLvGNxA70QL8hKnjGRVC8udKVfLmlJkRt2UzkN68Vxq70PR0exTuYo11yZJAMNyM1Q1aOIxtDEvLjbgDrTPNtHvj5c7SOccv1/Ct/wxZLfa75kiB0hXf8w4DZGK0UW5JGc5KMW2drpVn9g0iztMYMMKoR745/WrlFFdp5bdwpjoJEZGGQwwQe9BcKCWIAHUmsjUr17u3a2spHR2/wCWqnb05wD74xmk3YaV2YBcwD0Q8E+lPltlubc4dVGOGxzUwiDRGNx9QapT6Y3kn7POy4521563PVTsY17bfZpCd4ZvWut8DR5sbmfj5pNvvwP/AK9chNE6sTLJvIqrYtdw6mLm2lkiER+8rEbie3v2zW1N2lcwr3lE9iork7bxdICBd2ykH+KM4/Q1vWupW16mYJAT3U8EfhXA00f/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-71.png', linkedinUrl: '/in/kendra-knox-8b8db240fa', jobTitle: 'Conservation officer, nature', }, @@ -715,7 +715,7 @@ export const peopleDemo = [ city: 'Woodburgh', email: 'donna.jacobs@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDpQKMUuOK57xV4ptvDtqFI8y8lUmKPsP8Aab2rzEm3ZHoN21Zd1fX9O0SINezhWb7sajLt9B/WuVk+JcIl/d6fmL1aUbvyArhIodT8T6mxQPc3EhyxzwB7+grqLX4V6pcYaS5ghPoMmt+SEfiZmnOXwo6yy8c6JdhAbgwuwyVkU8fiOK6KKWOeNZInV0YZDKcg15ldfDLU7KMyxzxyypk7cEZH1qt4Y8T3Wg6wumXwYWskmwq/WFicZHtUuCfwsq8o/Gj1jFGBilpcVkWLivC/F2pPrXim6eP5kR/IiA7heM/icn8a9ylDGB9rbW2nB9DjrXz9o0bT+ILaLO4mcAn1561tRW7MqmtketeBvDaaLp/myEPdTAFz2UdgK7lBhBgj8DXFalJPbwCOO2lnL4AAJCr7k1D4XW9W6Eklq9vG/XLHjnvmsmm/eZ2xtG0UdvP9zmvI/iXpCxzQarD8shYJJjv6Gun8YveCQiNJZYY8ZVCeenpXM+I3kufCMxaGWJ4XUSRud2OcZB9OaqmrNMitZxaPQtIuvt2j2d0WDGWFWJHc45q7XM/D8yN4PtBJ2Zgv0zn+tdPUyVnYyTurilQylT0Iwa8rtvB8mieJIJUcSxpIze4HQE/n+lergVzHiXU7DSr6FbwvG1yAIpNuVJBxgnt1FUm1ohxUW/eOg06dJYQjAcUzVr+006JTK6xpn5mI/IcVWsgQOD2qvqevQ2Y2fY5rlx1CxkgH61mtXY7FYuW+pWF/qM0UUqv8oJBHeszxdbQT6Bd2yJ88iYXA754qGx1q1luHhFg9ox9UwCevWrcwM88akM244IHanqmTJK2pa0HTxpmhWVmBzHEob69T+taGKcBgADoKQ03qchIBXFfE3SnvfDovYyxNkd5QDqCRk/hXarWJ4g8Q2ul+VYGAXl3d/IttkAbSOSx7Crhe90RLYoWF6VgiLNgMisCe4IrVEFteruM20Hpg9KyXtsWke1AAowAOgHpWcy3SHESnHpWXW53RdjfmtILMMwn8z3Y5NWNKXzlafqM7V/rXOxwTTEGZiQOSua2/DOqQXsF1aoAstpMY3XPbqD/n0qkr6mdWWht4pCKdSGg5z//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-72.png', linkedinUrl: '/in/donna-jacobs-75f4cb3e8a', jobTitle: 'Wellsite geologist', }, @@ -725,7 +725,7 @@ export const peopleDemo = [ city: 'North Andrea', email: 'michael.martinez@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-73.png', linkedinUrl: '/in/michael-martinez-37a2df073b', jobTitle: 'Scientist, water quality', }, @@ -735,7 +735,7 @@ export const peopleDemo = [ city: 'Wendyfurt', email: 'natalie.hansen@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDiW5NMPFPcc0w5NZljCyopZjgDqTVUXzzAm2AwvJZ+mKqahKZ7kWy/cTkk9zXd6D8PjcWcUmoOI9/zeUg5A9z61nUqKKNadJzOLOoyhgTPwOqquamF/NEFkEokQ+q4xXqX/CvdKWE+XE2SOuelcV4l8JPosLTW7sydwRWPtU2b+waVyvaanG5VWOxj0z0NbMMwc7Tgj3riIAZIcj51HBHQrW7aXLJtQnJAHPqK1T6GLXVETcfSoi2OlTP3qBlrYxGeHbNdQ8Z20ZGVjbeR67R/jXudrEURcgGvDdFQ2euSyeSZvMhfYoJBzkelel+D7nUHnktLmOVYQCVZ88Ee56iuKum5XO/DNKJ2oH7vqoHpmsvVbSC8tZIJkDK4wRXJa1BfWupmaK2lmGQeHPzZOPWug097i5hHmW0sDf3WOR+FYuNlc3T1seM63YHRtXljjY+XkgZ4NR213lQeu3+VdZ8StOWGWG92ko/yPj17GuEtmMb8HdG3eumD5opnJUXLNo6JzyaiPJp7jmmYrqOM6TwPHE+tyeaAcQnGfcivRYmtrUSnfFHgBQCQK8r8OXJtNbgbOA/yH8f/AK9djdX+gi/J1CVC4ABic5B+o9ea4q6fOelhbOnY62P7PckEhSVODnmpJ7iK3jIQDp1rJsdQ0u8jRNNmiwOgQ9vpUk8fmfLk471zydtDosjB1izj1u3aGcHy87hjr+Fef+IfDseh6ULiaUpKzBY4gOSSBn8ua9Jv5ZrcFrZULxgsAw4wK8S1rWr7W9Sae+m8zaSqKOFQegFbYeLb8jDETjFbas9JkTTpeloufpiqF1pVu/8AqCY367TyKsR3ci4ZQpH0qVZUlO5l2nuRWilJHK4pnNkSW0wJBV0bI+or0DTIDq9vFeRPEhYfNuXPPeud1FI5IB+6DOejegqtpOo39hJ5Vsdysc7D0q6kXOPMtx0Kvsp2uemxW4tYxkJu/vAVXnu1jUjILHoK5ttZvpgYzIoIO1to7+la+l2DPtmnJOfXrXFJWep3c99SdrVmsZpHHzOpH4V4da+HL3UPElxptuPmjkYO7DhVz1NfQtwVEIQYyeAKq2ukW8W7yUCvKd0jgcmuvBxbbfQ48XJWS6n/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-74.png', linkedinUrl: '/in/natalie-hansen-eba76059eb', jobTitle: 'Designer, furniture', }, @@ -745,7 +745,7 @@ export const peopleDemo = [ city: 'New Stephanie', email: 'katie.russo@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-75.png', linkedinUrl: '/in/katie-russo-2a475932df', jobTitle: 'Tourism officer', }, @@ -755,7 +755,7 @@ export const peopleDemo = [ city: 'Jefferyton', email: 'danielle.park@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-76.png', linkedinUrl: '/in/danielle-park-fadefa41f3', jobTitle: 'Transport planner', }, @@ -765,7 +765,7 @@ export const peopleDemo = [ city: 'East Gabrielborough', email: 'nicholas.guzman@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDn2yTTec1MVpu2vOuerYQHaCzEADqT0FZtx4is4W2xbp2B5KfdH41m3QvfEepnT9Py0KdccAnuSfSuhsfhdeMgNxexAHqsan+dapQj8TMW5y+BGcPFFnmMGOUb++BgVppNHOm+KRXX1U5pb34WyxwH7PeE45wRXKzx6h4Z1FRcJ8h4OOjD0+tFoS+FhepD41odQc0q5plvNHdQJNEcowyKmVazNUSEVU1K5Fnp802QCFwv1PSrrCsPxWHGkLjoZRn9aIq8khzdotnTeAdNjt9KWYDMs53Me9egwoRGApB9hXmsbS2XhyxRFuCWhB/c9c4zWn4ZbUlu4YnmlMMuHPmH5lz2NZyjduTNIOyUTtp1YIR0+tefeN7WOfR51YAsBuBPajxNPqJ1BgjXLwof+WGc/gM1HIsl5aTW0gm3BCpEnP40Rja0gk7pxOW8Kzg2kltnJjO4fQ10YFcb4UEiarKrAgbSvT0NdqFraqrSMKLvAdjmkkslv42tnCncDjcM4Ip+Klgbyp45MZ2sCRWRsvM6PRmt302CCRRlUC4PPapZtR07S9SgjkYRjkjC9SBz7VmW06md5FyFLEgGobjUXu3wlnLMoyOBtH4E9f5VCi27GqfY0dNv9P1K5mCSLINxHK9DnpzRrAt7eB9gAOO1YttqL2Mzr9lkjDtyrJlR/wACHT8abrd2DbSSMcKqktTcbOwm7LXcy7LTIbSNZVj2vICTkfjn9auAc04TG4iik8spuQHaeo470AVTv1M9Og2nCjaavWWjahqBH2e2dlP8Z4X86aTZN0tyq0jRxFxnA647VazZ3Voqy3bruAI8s1bvtEutMvxHMVMEkKFCB1bnfz9cVzt3pDRTt5UmzdyKTSUrMqLbjdGjcTWVpbFIbonA/j7VkJML+VEILQq2Wz0Y1U/si4kmxLIGyeMVfuraSzsD9l4lQZX3Ip6JifM0Xzim1q3Hh7UUtop/I3bo1Z1TqrYG4Y+tZnlurEMCCOoNNxaepMZJrQ//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-77.png', linkedinUrl: '/in/nicholas-guzman-41594d6dc9', jobTitle: 'Scientist, research (medical)', }, @@ -775,7 +775,7 @@ export const peopleDemo = [ city: 'Port Jenniferstad', email: 'brandi.dodson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDqDimEe1PxWfrl6dO0ee5j/wBYAFX6k4q27K4kruxS1bWUscwwqJbk8Beyn3rn7rVrxIDNfXMcQ67QQMVziaoiyOVkd5mOC6fMxPoCat2/h+fUiJLiDf3WLdwP95v8K45VG3q7I7oUklorsni8dPb7tjGVR0Lr2rp9D8VRajEvmjarfdkHT8awF8C31/EwnMcUf8Eag8VmWuj3Xh5bi2eTnqueRTjV7MmVF9UerAZHr70oQVzngvVH1GwnilJ3wPtIJ6A/0rqAorqi7q5ySXK7DCDXnfxB1Sc3qaZGSqBFY+5bv+AFek7a8x+Jdvt1i1kCHMkGMjuQx4/Woq/CXS+IveDvBKXVvFfXTZjblIx3Hqa9Ji0+G3iEccShRwAK5vJ0zQ7S2W2mlcWy/cJATC/zqTwvfXlzKkUwmEZ+YCU5I9jXA9dT046aHSiHGQABXB+PNPkFqb2D78fLAdxWh4jvL4XMiQ+e0UYLbYmxux296roX1HTZbaS0lt3eP+M5zkfzoWmoPXQ5fwTfiPVIjux548tx69wf6V6YDxXkPhCzll8TQwMpXY/mfTGa9h2cV30tjzK247bWP4i0ZdSit5toL27E/wDASOf5Ct0LT9uB0q5x5otEQlyyTFt/Knt1yAeO9RI1tDeBQVUDueMmoYVaNiM4HU1SvL3RGKmd42lTIVhyUJ4PI6V5lnse1Gz2LcBglupFJVsscEc5p98kcEfygY9qybS80iIkWjxqztnHQsT3q5dM0pUdqT7Dem5haBpDwarPeBhgu/GP4W5/Q5rqsU22thDFjADNy2Km2cV6VKLjGzPHrzU53Ww4DinUAU9I2kYKilmPYCtDIpXZ8shhxkYNVpLU3EYKlBgcHpVmbzH1G5tZFUJAVQepJUE/zFUbu2ngTMD5/wBk15tVrnbR62H5owVxotRACW2FsdetOtmM15Eh6ZyfwFVIYLubLTtsUdgetSSXDadG90se8RDLL3I7496mDXMmyqvNKLsdBtoIp5BXGRjIyPcU9M8c/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-78.png', linkedinUrl: '/in/brandi-dodson-428d92f283', jobTitle: 'Therapist, drama', }, @@ -785,7 +785,7 @@ export const peopleDemo = [ city: 'New Charlesfurt', email: 'sara.kane@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-79.png', linkedinUrl: '/in/sara-kane-778b92a3ff', jobTitle: 'Associate Professor', }, @@ -795,7 +795,7 @@ export const peopleDemo = [ city: 'Port Kurt', email: 'allison.howard@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1DFctrfi+Gzma0ssSzDhn6hT6D1p/jbW30rSfIt3CXNzlQ5P3FHU/rivKEuuqxuVB+9IRy1YVJtaI1pwvqzuodQuL5i80/wBSzdKL+eCGNSNQ8tz0OFKk/l/WuZtrv9wILCAT3bcFnG7b/QfQCr6+CdTvU865uwHYcopwv0xWDOhRL1l4yms7hIZmBAYBh1BHqK9DtrmO7gSaMgqwrgLPwNb28StdSM7Dt6Cp7LWP7B1SOxlci2kbCFjnFawqa2M6lJ2ud7ikxTlIKg+tFdBzHj/xT1I3HiaKwVsx20Q3hf7x55/SuOtS95dLChIBOOD/AFr0XxxoUd74odhGwM0SZdOMHByT+CiuY8K6RH/bjhm3rHyGxgHnAxXNNq7OuEXZHa+HtGgsbZdiYcjlu9dOiMErnri5uLIbIIpHLcZA4H41m6bf6zLejzPPWFmwVkHK8/U1jbqdN0tDs2DMhGcV5546RvtFh5WRKJeMdxxWz4nutUgcQWofAALFDyc9hUOmaU2pa1pRuldPJEkjKxzuxj+fFVCOqIqy91ndaP5n9lQeZ128fTtV40gAAAAwB2oNdp5xy/jTNvbQ3uD5YbZLt67SDzWFb2kUDW9xbbSjR4DIchh1rvNStYr2wnt51DRupz/SvGfDcc1v4inQSO1sqMEG47R8wzgdK56sdbnXQnpynp1tcRzx7GUHjnI4NJKIIAERV3tzhRjAqpaplcqaivbrSjCUvrhFPf5iCPyrnV9jrsjSuo4muk8wKdyZGeeRU2lpHLftLt5iUqv49f5Vz1vc6fLlLa6E7g8NuyRXU6PbmOESkcupJ/P/AOtWtJe+Y4h2hY06Q0tIa6zzzJ8QR3FzbwWFvJ5ZupNjyeigEkfjjFc01po0N9Ha2F1BLcQqRLHEd20H1I6dOlXvG/ihNKs3srWT/TnAO4Y/dD1+uOlcr4DkslhuIUiVLh5PMdu7/wD6qzqxtHmNaLvJI3xObJ9jNhc8E1KYjOmUeMccFhT7u1SbhxVKTS5kAMUzKlcaPQTsWILRnuooDJHuZvvDgCu1jRY0VFGFUYFcFcWY+ySwl2+dCu/PIJHWovDHxC3WKW2ro7Tw/I868lscZIrpoa37nJibtpnolIaqWWqWWox77S5jlHoDyPqOtWzXQcp//9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-80.png', linkedinUrl: '/in/allison-howard-5cc9c06425', jobTitle: 'Hydrographic surveyor', }, @@ -805,7 +805,7 @@ export const peopleDemo = [ city: 'Lake William', email: 'jonathan.drake@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDfCVVv7610yze6u5lihQZLHv7D1NXscV47471Qat4hktw5EFnmJV9X7n8/5VzxV2bN2Rpal8SJpJmTTrdYoBx5snLH6DoP1rnn8V6vNcxzm/uN6tnCnAH5cV1vh34eQ3WnQ3GoTNvkAYImAFFdG/wu0dlxulyeh3cUvbQTsaLD1GrnEWPxC1G3usXjx3MJAOCoVh+I/wAK7/Rdesdbh3W8gEoHzxMfmX/61YF38JoFj3RXbBh7VyqWN/4O8QW8hYtHuyP9tehB96alCWi3JdOcFeWx69so2CnQss0KSoco6hlPseaftpCHY4rwaOFptYfzMPm4LN7/ADf1r3okKpZiAAMkmvJYtLNv40bMLPazzNLA0ZBDryeKpSSuCi5WPT9OP7iJSNuFHHpxW0rDyx84OPeuG1C4lnjCC2uQoIGFIX8Sc9KztFkvYLlSkdzBA7cxyybu+K41DS56HPrY9HkOU5JFefePY0bTo5WA3JIMNjpmpvE1xqH2iSJWuxHFtysBwxrNvY7i68O39vJ5zsseV88jcGz61cI2akRVldOJ2Hh/e3h3T2f7xgX+VaWKraTD5GjWMROSkCA/kKtkVucQ10EkTIejAg1y9xaML63lwqiBikYxzjbgnP1xXUjpWfqlsWiEoIARgTxz+dROLeqNaM0rxfUdabJ49pUBgME02ZIILhUd4wBhmLEDB7VBaS7GAz16VQ1S/wBNuEK3kYYI2f8AVlyD6+1YJXdjtubNytrNqfyyxtvAHBzziqmp20RtZIVGGII4HUkYrF0+40pJpGtCWckKS6kHI6YJrex9ouo17kgn+dPladiZNW1NKzh+z2UEO7dsQLn14qUinAYGKCOK6bHnt3dxijiqmq3Fvb2TC4kCeb+7TP8AEx6CrqKW4UZNU/EGim/0uI8mS2uEuMDvt6j8iavl0ZKeqOb+0PFIELBT2J7ir0cU0tsBE6o4HDk1U1CyFzCMdRyDWQ8l/aEKoZ1xgNnOK41ZnoXcWb0kEsUZNw6yv2Oa0NHHmySzEg4+UDP5muXtBd3Mh88lVPVc9a6HQUk+1agR/q1Mar9dvP8AMVrTV5GNaTcbs36DTeQORRsraxyn/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-81.png', linkedinUrl: '/in/jonathan-drake-5ef0430b02', jobTitle: 'Learning disability nurse', }, @@ -815,7 +815,7 @@ export const peopleDemo = [ city: 'South Shelly', email: 'samantha.williams@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-82.png', linkedinUrl: '/in/samantha-williams-8b316b4a9d', jobTitle: 'Technical brewer', }, @@ -825,7 +825,7 @@ export const peopleDemo = [ city: 'North Lori', email: 'katherine.mooney@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-83.png', linkedinUrl: '/in/katherine-mooney-ef2c2c12dd', jobTitle: 'Accountant, chartered', }, @@ -835,7 +835,7 @@ export const peopleDemo = [ city: 'Roberttown', email: 'luis.lloyd@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDGApcU7FL0GTQMgubq3soTNcyrGg4yaxbnxVaombeJ5M/xP8oFZmpPL4h1hYbVXdEG1FBwPdj6Vr23w21S4iAZoAuc/eOR+lZSqRjuzWFKUtkV4fFpZvntk2D+6/NbVlqlpfoDFIAx/hY8/wD16gl+Ft7Gn7q7jPtgiuc1Xw/qXhyNhKv7pj99MkZ9/SpVaLdkypUJJXaO2IphWsbw3rB1G3MExJniH3j/ABD1+tbmOa2RgGKo6xO1to91Kv3gmB+PH9a0MVn66o/sO8JGQEzgfUUMCPwLYQxRvMSCzkAt9K9Ts0KRA8Ee1eTaJZrJ4dt3kjmlVnbCRnGTmuu8Mrc20sSRxTRW84yVlbJU/wCRXnVVdtnq0dIpHZO21CTtUepOK53X47e50ycEJKhQ5xyKzvEVvI9x50trNdIp4EbY79uamtbJRGwitpLcciRGOQfes7aXNOtjy3TZFsNZtgjfIZNpHseK7nHNcELOT/hJjAqnEd2M8dBur0LbXpw2PJnuMxSMiyI0bgFWGCD6U4UYqiDS8MRQw2n2GQA+U7DgdeetbUt1a22p28MssUIKllBOMmuctHK3G5euBU95qumG5Vb5Qz/dUeXuIrzJRak0z2Kck4po6bTbm01BGaKWKVQTtKkEdcUak6RQMqdSMVl6Zq+nSgraMvLYI27Wz/WptRbMbtnoOpqGraFnOw6UsEE9y+PMkmModeMhs/KfXsaKINTl1GyQtbmCJWIRSclwOAx9M+lBFejQi4x1PLxE1KXu7IhFLTRTZZooE3zSKi+rHFbGBIGaPLqMkc1oW0Zv41ljuBE5HUAGuJ1bxNG0ElvZBiSOZc46dcCra3V3GqS2km1ZRkDtmuPER95NHdhajSaO+jgW0hzJMsj92P8Anis29v8AzIZWB3RxqXbHfAzisi1ttYvQPtbLsPQA9a1762js9FuFkxjyyGP4VyuyZ1OTlqZmn6hDqNhHcwAhGH3T1HtVgmuS0Of+ybaONyWj2gP7e9dNDcw3Kb4JUkH+yc4r1E7nkNWP/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-84.png', linkedinUrl: '/in/luis-lloyd-ee56c3462c', jobTitle: 'Producer, television/film/video', }, @@ -845,7 +845,7 @@ export const peopleDemo = [ city: 'Matthewchester', email: 'travis.serrano@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDrKUUlKzBEZ2OFUEn6VianOeKfGdn4ZVYjE1xeOu5YVOAB6se1eeXHxE8R30ryQypbRj7scaDA/E8mszXLqfxJ4oup7aIku2EXqdo4GasxeFdZgh4ttwcYxupOcY7sqNOUtUiKLxv4kim+0LqMzbW+ZHwR9MV2ml/FWGeSJL+z8sdJJYjnbx1xXLxeAtZkgMriOLJxszk1m6t4XvdGTzeNmPmINJVYPS5TozSu0e66dqVnq9mt1YzrNCTjcvY+hB6VORXingHWW03xRbweeyW12fLkUn5S3Y4+vevbSKszGgVS1x2i8P6jIn3ltpCP++TWgBSS28dzBJBKu6ORSjA9wRg0gPJ/A9lEfMn25csAT+H/ANevSreAHBaIDFeb6XZ3FnYzRwNJkXciI0ffBwCc/Suq8OahqztHBdgkSZIaQYYfUVw1Y3k2epRlaKjY6aRTtIWMY9elcx4it0lsJVKZypyDTdcu9XeVzE0wijGSsOMsM9B6mmWwuJ1Ky+cML8yy4/mKz5bamt7+6eZaZDHB4p01YF3ZuY8An1YZFfQTCvH9F0QN42SZwRb212HG0ZySeB9K9jcV6MZKSPInBxepGtPFMWpBTJOWs7K3t727s3+Yec0gz/tHP9a0oI4v7TWNSi7Ez2FVNbgNvqEN1FkGXhvcj/61Zj3On3FxuuCROAVBQHI9siuCcWptHr0ZKUE0dBapBPIysELdRnnNN1Tyba2YKACRxWfYXOmQZitgsbE/dKlT+tGqtmNyzHj1rNq2hoV9Dso2uEZEwZJd0jZ+9j/9Vdg1Z2hWiw6ZBLt+eRdxJ9Cc1ovXfRg4x1PKxFRTlZdCNelOFNXpTLi7t7OEzXM8cMQ6vIwArUwI9TsTf2LRIQso+aMnswrlbFhKpEkxjdeHx1BFM1v4hWq289tpSvLIUIFwflVeOoHU/pXOad5l7ptrKJmRnQB3B7+prmxCWjO3CSeqO0leK1gLmcP7msa6uZL4gKSYxyT60LpKRojT3Mk8h6KTxVi6aKwsZHchQB1rkb10O7zZW8EeMrq81GbS9TkjKK5it32hSCP4T68V6C1eFRnLGaEeWS5cEdc5613GmfEMIBDqluxIAHnxc59yv+FemnpqNJa3R//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-85.png', linkedinUrl: '/in/travis-serrano-789399815b', jobTitle: 'Therapist, art', }, @@ -855,7 +855,7 @@ export const peopleDemo = [ city: 'Hayesstad', email: 'amy.newton@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDqc5pKKOaBDgwqC6ujFCXHCgfePFZmua3DpVs7sA7jopPU1xkUfiTxa5lkl8q0zwuMAiuWpVd+WJ1UqN1eRrXHjG48x0tIWlUfeYc/lU1tq010UnVwx67VHzfkabb6OmnIYiRuH3W9azbtlCtKq7ZU5baeo9R7isnNvqa+zS6Ha2OrpKVSQAbuA3bNa+ARXCWl0k0KzZ4biQD1/vCur0i6M9u0btmSLgn1HY1vSq3fKznq07aotYqOZxDC8h/hBNS4qlqr+XYOc4rabtFsyirtI4N4m1/X4oHy0aEvIPXn/wDVXoEEK28KxoAABjArzGw1CS3ur94IDNMyBVAJGMsBk10XhO81G4keO78zbhipcHgj61wRi7XPSur2OjvbITRtkqPcnpXF6nC9rc7+p/i9GHf/ABpmuPqX2+SeITSRoNwXOQ3OOBThJcanARJa+VNH/Eo+VqHHS4Xu7FTS7pUmlt84XPA9jXRaVqRgngkP8R8qT+lcPK7W2ooyjGcqw9DWvp9yZRJHnryPYijVaozavoz1IZxWJ4ml2afjoDnP5VvAcVi+I7fz7Aj0rsrfw2cdH40ch8P/ACJrnUhMoMh2qAfTJNdpKbKwjmBeKPCcADHWvNPDEr2Hi0RdEnVkP1HI/lXZ6leaGJPLvVaWXHzBVJ/A4/lXJ6HoxVzWsfs91AdwQsvUHBqrqU8FvGQABxjpiqdpqGlFVisCsZB4QDafyNQalG0+c5HrUyfQtI4nVJEGpIcY38gnofan2jmO4JU/Kc/ge4qLV76whvGgnDNIVHl4XIz6e1Z+nTyfbXDnMZwG/wAaq3u3MZNcx9A1n6shazbA71pYqKeISRlT3rumuaLR58HaSZ4zqDPp2sR3Kqd0cgcAd8dq7WEQalbrNFd7Fb+71+hrL16zWPUN8ke5A2SK5Xw88sHiY2jFzFMrEruOA3UH+lefDb0PS5mmd/5UdouTIjn121Svr4NHsRg7n0qtJYTtdNE0rFDyoz1FXINPSI9OQM5pM0PMPEKMNaVP4wN1W7Zwol9SAP0Fa2t6Obm+a6KtlDxtHWqFhol9dJJOi/uQ3Unqe4Fa8ycUjncWpNn/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-86.png', linkedinUrl: '/in/amy-newton-ff6b79dfce', jobTitle: 'Exhibition designer', }, @@ -865,7 +865,7 @@ export const peopleDemo = [ city: 'Parkerland', email: 'jonathan.hawkins@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDnwaq32p2umx77h+T91ByT+FN1K7FjYSznG4DCg9z2riHabUJTI+53buf89K4acObV7HZOdtFubT+Lbln/AHMMcY7BgWNRnxHqe45kQD1CjFTaX4Qv9QG+KMCPONxOB/8AXro0+GreXuN8RLjoF4+lW5UkCp1WrmZYa+bmTybpURuzqeDWoWyMg5BqrefDye3hE1vdbplGSCODWVok1xFez2NwCrpzt9COuKhqMtYlWlHSSN7dQDzTaUVBRi+Ji7LbRr3LMf0H9ar+HLcT6lErxZ77ccfU1p67Z3FxbxTW8Ekvlsd4QZIUjrirPhHaonkMTtIpC5C8j25rTmtTJjG9RXO9tXhhiAZ1QDjk4FaCSRyj91Ij4/usDXJXO2UAyWskmAflfgD/APXSaJcCHE32RYA3JQZDAZ6GsFDS518+tjqbr5YyTgD3rzfXoFt9etpo8DzX2kiuj8T3odp4ZBIUjjDbVzlgT7Vy7WyPPAq+YqxSZ2sSwBweh9OR+VXCNtTOrK/uls0gpCc8jvRmgyN7Rgjxsu4K65AJ9TjH9ajtrZbO+uvlGZJd5x05AqlZ3P2a4DHJQ/eFWYNTg1C8uHhjeNVfaQ4xkjrj2qJJm8JJpdzqoYo7hASMNjGar3gtrRR5jAbeSzdB+VPtTjYQeSM1VvtThhYqylmJzhUJP51MddDYZMtleX9uY5kd2jxwM/nWXrNtHbxARkKwbJAXrRHqFu16pijaKb0K4B/Gma1Nvbk8ntV2s7Gc/hdzHJpAaDQKs5ScD5qkiQq0jxD5x85Hr2P8hVe4nS1geaQ/Koz9aPDd5cX8z3E8axxk7Y1HoO5okny3HB+9Y6LT9USSJAWw6nBB61r+XHLHgsCD0rnpNFE052OVwe3pUr6RqMCgQ3o2joHHT8ay0OlSaJ7q2htTv+UsvesK8uPtMxbqO1V9Ue9ignae48xYlJ2qMAkCoradbm2SVf4hyPQ1oo9TGpUvoPNKyP/Z', + 'https://twentyhq.github.io/placeholder-images/people/image-87.png', linkedinUrl: '/in/jonathan-hawkins-c68fe4ecec', jobTitle: 'Surveyor, land/geomatics', }, @@ -875,7 +875,7 @@ export const peopleDemo = [ city: 'East Micheal', email: 'patricia.anthony@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0ukFLSEhQSegpAZ2s67Y6DZG5vplReirnlz6AV5XrnxQ1C5O2yK2kRJAKjcxHv6VmeNdVn8T+MGsbUlo4m8qNfp1P55rodL+HFmtmBPI7zMPmbPGfasZ1EjenSctjk5fEus3K4fWLx0btyo/Tmm2er6nZXAmtdQnjk658wkH8DWzq3w+uNOiaeykeTaclTzkVy0mYpVzkKxww/ums+bm1TNHDl0aPXfDXxBivXis9VVYbhuFmH3GPv6f56V3eOK+bDIY5dpbJxkY/i9x717N8P/EB1rRmt5m3XNphST/EvY/0reEujMJx6o6ysrxLevp3hvUbuP78UDMp9Djg1q1Q1uxOp6Ff2K43TwPGufUg4/WrM0eLfDmzF3qV3fP88iAKCfckk/pXr1vGVVRmvGPDEVxp9pq9u8M/2iGdYyiNtIbkckeld74TutSkeCC4ZysiFx5hyy+xrhqxvJs9KjK0UjtPK3JjAI9DXlHjnQP7OuzdRR4tpjzx9xq2PEU2qw6igia7dCwUpHKVHX0Fa62zajbSWF3HNtIKne25W9waUfd1Kn72h4jJKwBjYncp4PrXbfC3UJE8XRRqTtnidJF+gzn9K4vXdNuNM1m4tCCSjY+o7H8q6D4bmeHx3pgVTl2cMB6bTk11Lozhd1dH0JRRRWpicJa6Kuma7rIuEyl7cCeNuzKV6fgc1sadFbw3cjKUQImOuKteIoS1rFOo+aN8fga5aW90xJ2Fw5LkbWC9x6GuKrFqZ6eHfNTVjqTHbXLgMFMijI6HIqaQpbx5wOO1Y2n32kSIkVjJGjA/Kg+U/lWjOm8cnisnpobaHJatocOsamt464lVSi4HUZ71S8KafHN8Up5IQPK0+3/eFBwZCMH+Z/Ko/GHiC/0m9s7PTZI0kuyULMuSvIAI9Otd34Q8MQeGdKaNXaa6uG825nbq7H+grpowd7s4sRUVuVG9S4oorqOMr31sbuylhBwzL8p9D2riI7CV5mUuIpVOGBHOa6jWPE+k6GALy5Hmn7sMfzOfw7fjXnVj4huvEcmoagXMbi5KRqvRUAGB71z146cx1YWo1LlOzt7RYIgZPLZv72KSa9Lny4zub27ViWcd/drsnucR442cZFa1tbx264H51yNnZe5iWtnY3XxOso71yZYbQy28ZXKu2Tnn26/hXpgrxPXL7Pi77bbuVltUEaOOxBz/AFr0nQfGGn6uiQvMsN6FG+N/lDH/AGT3rvpJ8iPNrP32f//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-88.png', linkedinUrl: '/in/patricia-anthony-64ce02febc', jobTitle: 'Paediatric nurse', }, @@ -885,7 +885,7 @@ export const peopleDemo = [ city: 'Knightport', email: 'matthew.gomez@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDucUoFOxVHWNQXSdJuL1l3GNflX+83YfnQBleJvGWneGVEcoae7Zcpbx9fYk9hXnt18TPEc5MkMUFuh+7Gke4j6k5q5pHhO41+6uNQ1GcmSViQxGSx9foPSujh+GVrsG67k357AYrB1lex0xw8mrnF23xO8RW0jG4EMozyksQGP++cV6L4U8Y2XiaJoxthvU+/DuzuHqvqKpXXw4014+ZJNx+8cZzXJ6r4ObRs3elzOs8PzHBwWHtQqyvYJYeSVz10imlaxfCXiBfEGkq78XUICzL79j+NbxWtzmHAVzHj5FPh2PcxGLmM4Hfr1rqgK5zxmi3Olx2m0ljKknHoDg/zqZtKN2XCLlKyJNDjC2MPABKA/SugTOwCuO1GS4tcJDDdP8vyC3IHQdyal8OXmpyyolz56xv8wM2Cw9Aa4Uup6f8AdOpn4GK5LXSFiYqM8HP0qDXNR1c3E62wmMMP3vKwWb2H51Rhkubk7XFwoVcsk4GR9COtFuoX6EHwzQnWNTZBiIxLke+4/wD169KIrgfAXladqF9FIrA3c+yIjoNu48/nXoJFdsGmjzakXGWogrL1qEPEG2kkgg49Ota2KiuIPPhKZwT0OKKkeaNgpT5JpsqWRjuIVDYzild7eK9jiR0XBzycZNZ1mxjOzP3eD+FU7y+0aeVVu5IQ6ZCkgkqT15HSuFLoeotdUXbBoJtQuoiyN8xIwc0mq+VBA4RQDjFY9nd6RZXB+wTRFmbkcgk/j1qbWZi0LH1GfpQ1bQZH4ct0k1CDaDgM0p+oz/8AWrtjWPoGkGwt0lkk3SPGOMY255NbBrtpRcY6nm15qctOg7FBKopZiAoGST2FchqvxL8OaYSkdw97L022y5H/AH0cCuD8UfEO81+1NnbQmytW++A+Xf2J7D2rVIwOrtfEkV9LLfInl200riM/RiOfrjP41vCI3MCtDIiOQMHAORXnngqRLzR57CTG6OQsoPcHn+ea2G/tWwxHavvQdEbqPpXBPSbPTpS9xNHRPa+QfMldGZR1xWH/AGhDd6ra28kiiKSdQ7E4GM8D8elZV1farc/ubhWTd2HGaytfia10SQ52yZUgjsciiKvJBOTcWe49KSvENP8Aixr1iyfbVgvoejBl2P8Agw/qK7vS/ih4dv1UTyy2Uh6iZMqPw//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-89.png', linkedinUrl: '/in/matthew-gomez-68cc301b54', jobTitle: 'Site engineer', }, @@ -895,7 +895,7 @@ export const peopleDemo = [ city: 'West Patrickshire', email: 'jonathan.schultz@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDocUBafis3W9SGlaXLcAAyfdjU92PSgCvrXibTNCAW6kLTMMrDGMuR6+341xd58TL8S4gsoIU7B8ufx5FVdF8Jal4hd9RurlovMcnzHGWc+tdAnwvtRlpr2aRz32isJV4J2udEcPOSukZ1l8Tpg6/bbOKSMnBMRKsPwOa7nStYsdZtzNZSh9v3kPDL9RXAan8MWjDPa3hOOcMuK5xYNX8J3i3kUjDa2CVPBHoR6VUasJbMmdCcdWj3ArSbar6VqEWraZb30PCSrnHoe4/OreK1MRwHFcn43DPHYR4ypkZj9QP/AK9deK57xXD5ltbMmC8TlmXvtI25H4kVMnZalwi27I0dBjSPTreMDovFb0hY4AUfhXCarCHMeGvNgQ7I7f5TwOSTTfDV1fpKsbTXRtyQQLg5Iz0Fedy6XPU5teU62+VhERjGR3rzzxNGPssodAdw5FWvEV5qF7PLEtzdJDFksLdfmIFYMcMgZ0Ml0wKHck/Jqowt7xM5392x1Xw7cnw/LD/BDOQn0IB/nXWkVy3w8jWLQpYif33m73X0BAx/I11pFegndHmSTTsxAKqaharcQnI5xgkeg5/mBVwCldC8ZUEAkYyRmpqR5otFUp8k02QWtvHPa5ZgG6jPSqizabbXSxyTQxZYhCeNxHUimrvSN0VsFAR+IqrJdvLbCOTS32AYG4p0/OvNV3oeuu6KME1pc6vOkU0TBnI4OTn3qDWLeCDcqqN2OoqjPdLa3ZFvphhLEY2YOPripZFk1C/jtycO7BT7Zq7O9iJNJO5v+ErdItMklUYZ32kemBx/Ot01BYWYsLNLcNu25y2MZNTmvQgrRSPKqS5ptoUCn8AZqk2oIB+7Rm7ZPAp8czsw34x6ChyQlFnLW+pXV5Fd3TxnK3MsRRBjAVsD9BWi91pl1Yj7SxYHoobHPvUiW62eqXdoygJOxuIj67vvD8/51m6noNvcKdhMUhP3gcV5s3abuerT+BWM6/uLG2DC2z7c5pPCuo26+IIYrkZlnRvJYno3f9Kx7jT5Le4MPmmTHU1RcyR+ILGSFirQZfI7HitqVuZGNa/Iz2c001wyeOLm0lCXtukqZxvj+U/4V0una/p+pr+5mCv/AHJPlP8A9eu2559j/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-90.png', linkedinUrl: '/in/jonathan-schultz-3c0c1ecc59', jobTitle: 'Sports therapist', }, @@ -905,7 +905,7 @@ export const peopleDemo = [ city: 'Longchester', email: 'matthew.cummings@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0uvFPjHqks2uW+mLc5toIRI8S8YdieT+GK9qzXzv8RiW8eaqoPzF0xx/sigEcqUUj5RzUZjLPwAMdcHNdha+Br66t4pQRlwDyOlNuvAGrx/MBFKB6cGs+eJt7KXY5F1UL8uVYc9eKhR2VsjqOleh6b8PLmWHfdP5ZI4BHIrG8QeEX0i3NxHJ5ir97jFHtI3sDpStc978K6rBrPhmwvIJTIDEqOW6h1GGB981r1518G5JX8IXCv/q0u2CHH+yua9ErUxYCvAvGVtJN8Sb+NRuaSZduOcgqK95k3GF9hw+04+uK8sawibxNZTYLSrCyyuR95wPX15rKc+XQ2pUudXOmsAIrWJO6gA/lVwnI6CuT1K91OybFrHv4JA2Zzj15pNJ8R6ndzrBcWIjdgDkHp9R61zcrtc7VJXsdSxbBxiuO8Xo39k3AQZO3Jx6Vb1rxBqFnI8FtZGSRV3EscD6e5rKtptQ1AzJfIqgp8wC+o6ZoStqKTT90674Wxxw+BrZUILmSRpB6Enj9MV2ma57wdara6BGFwA5yAO2AB/Sugrsi7q5581yyaFrgNXNva+Ikt4pY2mjLM6K3zKrAYz+VUfE/xNlt72aw0iNFMbFGncbjnvtHT8TXI+HJZbrVtQ1S4lZ5GYbiTk46k1FVLluzShJqVkenxpHcRFXUEe9V/JtILkJAg3qwLEDpUEE+yJjuyACetYjalJJIJLaRICDn5m+99RXMkd90bc8cEmqSLOoyx+Uke1Q6gkNtCwjAHB6VgSaleNqDPcvDKmAFEbDIPrVrV71U02ad2wFjLc/Si2thOSsd54bv9Pu9Jt47K8gnZE+dY3BIPfI61sgGvla0vZ7SZLi3meKVCGV0OCDXv3gPXpdc8PreXTDz9xidx3Ze/wCRBrt0SPMd5O54hq0fl61fRs2WSdxnPua0vCV8lrq3kTkCK4Gwk9M9qoeIpYpvEuoSQxNFG0zEK3HPc/icms8gjkUSjzRsxxk4Suj0ya4k0tmhcsIjwkh5/A1eEi3VmpimjR9vytjI/KuO03xfG8C2erqWCjCzgZOP9od/rUzSQ5zYagBEeykMPyPSuXlcXqdsaiesToJitvCTPPEz45IXFcP4m1SaW2itwxCSDcQepA6fhVq6vo7c+Ze3LS4+7HnlvwFczd3Ml/dPcScbjwOwHYVpTjd3Mq1RtWK8Z+U17N8JpgfDF1EV5W5J54yCo/wrxwqF6V7L8PL5rbTodG1HCTLF9pg5+9C3I59RzxWlR2QAGNJXZ//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-91.png', linkedinUrl: '/in/matthew-cummings-27d772de78', jobTitle: 'Designer, interior/spatial', }, @@ -915,7 +915,7 @@ export const peopleDemo = [ city: 'New Ashley', email: 'joshua.richards@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwC7gE4pCgqdU46VXlcQxvI/CoCSakZz+veIU0qRbeFBJcN1z0T/ABNcLe63NczyM8jM5G0s3Suj0/Rp/FWpT3TsUjD8Mf6Vvx/Cy3KktcsSSDwKh1EbKlJq55qLgRHeoMnIyzHG36Ctyx1m+tlFxbS7kH3kK8fjXWt8KLbnFy5bryKy7jwFeaWWayPmccrnGR70vaIfsZHQ6NqkOs2XnxgB1O2RfQ/4VfZB6V5fo2oz6LfqrIy4l2yL6g16sQCMjoRkVomYtWLCoNvNYviWJjoV0EOMgZ+mRmtnBIqnqkIl0u6iJGXiYDJxzjj9aHsEVd2RB4Pgji0qPyhhWJP612MQ+Uc5rzhZb/TtHs4bbzQ3kA4hTJzjJznitbw1qWrXdwtveKwyNwZlwfoa433PQjtY7bkDOfwrOvpNsTEDLAE1ymt6nrUF48VuZfLTJPlqCTj0z3q3peoXlztiuUuFJGcTR7cfjR0uV1scJrNssl60iplmbJA9c16NDGwt41bqFAP5VyeraRcSeJWjtMCMlZWz0A7/AP6q7OGSOaBJYjlGGQcYrqhJPQ4akGteg0Anp0pksIkRkbkEYNWig28dajIxVtXVjOLs00LpsUUtkiSqMqACD7VYs/sq6gfL8tERSOwyaxt0qTSgNwCWx696o3Hk3b5IlimC43rEw/DIFcSTvY9NNNXR1Cmzml2SmNi2cHg1LNDBAuYx+VcxavBZQtHDbyfNyT5DDJ9elbBkdoo8nkjJpPQZTEZa8knjJEoIBPYr3H61ehjCQqijAA6VWtYneSR92ULYAxWgo2100oW1Zx16qklFEWcgYoK04YUdaCa2OUzNRikjX7RGOAMOPb1oVY7uFWNwYzgYK1o3gaPSri4KEou0Z7ZJArl7uOeDMtueMZ29q5qqSkduHlLl9DeUpbQbFm8w+pqu1wz/ALqNsk9T6CsOy+3Xr4wVB+8R6V0NvZxW42pye596ydjbVvUt2LxmIojA+WdrY7HrzVo4NV/DWly3R1ucfcaZFi+qoM/qcVPLFLbvtlUq3v3rth8KZ59TAAAADSbR/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-92.png', linkedinUrl: '/in/joshua-richards-ec2044ed2a', jobTitle: 'Civil engineer, consulting', }, @@ -925,7 +925,7 @@ export const peopleDemo = [ city: 'Reginaville', email: 'ryan.johnson@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-93.png', linkedinUrl: '/in/ryan-johnson-7dda846caa', jobTitle: 'Office manager', }, @@ -935,7 +935,7 @@ export const peopleDemo = [ city: 'Lake Mandy', email: 'teresa.terrell@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-94.png', linkedinUrl: '/in/teresa-terrell-fe92ba9d84', jobTitle: "Barrister's clerk", }, @@ -945,7 +945,7 @@ export const peopleDemo = [ city: 'North Haley', email: 'jacob.jenkins@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-95.png', linkedinUrl: '/in/jacob-jenkins-b378edc103', jobTitle: 'Lecturer, higher education', }, @@ -955,7 +955,7 @@ export const peopleDemo = [ city: 'Lake Deborah', email: 'michael.myers@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDqM0uaizQ8qxRtI5wigkn0ApCEur23soDNcyrGg7nufQetc7qHjVLWMvBakgd5DyfwFc09xqXi7xAxskLQxHCL2UetdG3gee4jEdzMAuOR6Vzzra6HVToXV2Zi/EosI2+wqVDfvMOQce1dbpur2er2wmtJQw/iU/eX2IrmLz4c2saHyJpFOOpANcdOuo+EtUjuEY/I33h0kXuDRGtd2HPDtK57LmjNV7W5S6tYriM/JKgdfoRmps8V0HIGay/EJf8AsO5WMZZwE/MgVp1V1Jd9mV6ksoH50p6RZUFeSRf8JaRb6To0UaIBI43O2OWNbExAb5Rmuc1mKSNVAN0yqnCwHGMD1qj4Yku55ykst0sQw+Jm3Eeg9q4H3PVjodDefKpLcZHevO/F8Uc2mzBgDgHB9DU3iO7u77UZ4AbjyIOohbDNj0/OsiaEz2ssMP2hVWM745jnkjjBot1HJ9DrvCzFvC+mk/8APBRWxWL4WkD+GdPwRlYgrAdiK2c13rY8iW4KwI60GIXIKAAsBuX2IrIUOR94/nUtrM1ndLNgsBkFc4zmlNXi0VTlyzTO3CRXNqgwCcd6o/6LFIYYjGrZwc4GTUdtc/6CZATtEe/iucvryO9gR1SFSuSjHOQT15xxXF5Hqw12KsCxHXrpGZGyxI/wpuuC2tbV9iBWIxxXPTSf2bqsk1qyujEHG75s/j1qxqFw+pXEMPKtLgEH+H/PNTy62Kk7K7Nzw9bi20eFF6Nl/wAzWtzVGyQWttHApLBBjJq35gxXoRVkkePN3k2V1j46VBcgCKRQwWRkbZz3xUWqal9kcQx43Eck9vpWJO7uU3SN5mCwJ5/OplPoXGm3qX/B+qzp4eaKbcyQSGEsexwCQfzNdP8Aa4bvTxGJFicLjp0ArgvDfiC00u6utP1GJlgum3OGXoT39xWhqsQgt0u9L1S3a0kHyea3Tnpn/GuWUWpHbTqK2hLq0kNtFI8kkfmIM/WuG/4SOWPWrSaEhcsC5IyAvQj8s1lavqd1PctDK6sAcHyzkH8apySoVUIpDEAHPYVpCnZ3ZnWrc2h7Paaxpt7j7PdxMx6KTg/ka0K8NhnIbIJGB0zXqHhTWDf6f5EzZniHUn7y9jW6lrZnHI46XR//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-96.png', linkedinUrl: '/in/michael-myers-5d468b5c78', jobTitle: 'Psychologist, clinical', }, @@ -965,7 +965,7 @@ export const peopleDemo = [ city: 'Daltonstad', email: 'jennifer.phillips@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-97.png', linkedinUrl: '/in/jennifer-phillips-83c06e63a9', jobTitle: 'Immunologist', }, @@ -975,7 +975,7 @@ export const peopleDemo = [ city: 'Batesside', email: 'alison.ortega@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-98.png', linkedinUrl: '/in/alison-ortega-0b7bad2804', jobTitle: 'Professor Emeritus', }, @@ -985,7 +985,7 @@ export const peopleDemo = [ city: 'Jamesstad', email: 'gregory.little@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-99.png', linkedinUrl: '/in/gregory-little-bf88b7a274', jobTitle: 'Ship broker', }, @@ -995,7 +995,7 @@ export const peopleDemo = [ city: 'New Melanieberg', email: 'barry.finley@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwCUmjPFB60CuE7BskiQxtJK6oijLMxwAKwLzxzpNpxEJbn1Ma4A/E1geLdUuNUuzptmS0KMAVQZMj/1Apln8P8AWrxEeeNIVPOGb5q0SjFXkyPek7RRpp8RrV7oIbGRYO77wW/L/wCvXQ6brlhq6E2k2XX70bDDD8K4u7+HGrQBnjaJwOgBwa5qaC/0W7UyCSCVT8rDj9ar3J/CxNTh8SPZ80lZPh3Wota09ZAcTxgLMp7Njr9DWxjNZO6ZotVcDWfrl6dP0a5uVXcyrge2eM1omsXxWrnw9MqjhmUP7Lmhbg9if4c6DF9kOq3MYeeQ4iz2HevQGjOR8gx7VxtjHHY+GrCOdbl8wAiO3yDnGSc1f8PXbSLlTcpGOdkxyawn7zcmddP3Uoo2boFVOVAGO9cJ4s02G9sJQyAsAWBHUVp6xOt4zyXCXU6rkiOJscDt9ay4kt5HJgW4hAX54ZeaSjb3kVJ83us4XwVdtY+I1g3ZS4zGR79Qf8+teqCvLNOtWh8dwpGpwtycDHbmvVQK66ju0zggrJobStDHcRmCVQySfKQfejGTTlOGUnsc1mWjqbKzgbT0R8K6AKfwGKqNNZRSNGSyfIWU+WcEdOvQVPBILlHliJVWycN2qlcXF6IziBI414XzG6/lXMlrY9CNnsUNOe2uLgqW4fJDbCMHPfI/WpNTt4LeFgoXcR1FVVubs3W1oFKk8uhxj8DUmogtGQxyw4OPWh9hs5vT7KNdRlnGPNaQNkdcAYxW6KrWShoVk2kZyBn69atCt4p21OKo03oIBR3rp7PwdfXGGnZLdO+eW/Ktu28IadFtLo8x7lz/AEFbKDZz86RyOnNIsbDnyycZ98dPyrQkuLXygrLuPb2rotf0mOLR4pbOBVNpL5xRBjcuCrfoc/hXNXWnx3EImiIwwyCK560eSR2YefNAyr6eMf6rg5rNuJS0R5OB1NaEmmlW+eUkemKINGl1q4+wW6lY/wDlvJ2RO/4ntWUdXZG0nZXZBjEELhcJIm5cjt0poPNd9PoFrNAkHkgCNQkeONoHbNc1qegy6e+9dzwk4zjlT6Gu2UE82M0z/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-100.png', linkedinUrl: '/in/barry-finley-72ad288ea6', jobTitle: 'Network engineer', }, @@ -1005,7 +1005,7 @@ export const peopleDemo = [ city: 'Port Jeremy', email: 'brian.evans@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDXA4rgvFfjhrO4bT9JZfOQ4luCAQp/ur7+9dlrF01hol7dJ9+KFmX644rw6ztnvbhYuS0j4J/rSbsNK4+6vb3Um868uJZyDj5myaiaT7kbH90PunvzXp1l4N0trVEaA5xgvuINX08AaRtx5UjAj+Js1j7eJ0fVZnkUU01jcBkkZGHzAq2P1rv/AAd4vuLueOwv/wB5uO2OUnn159a0Jvhtp4hx5ku8HOR6elc3qOif8I1qtpeW5ZoEYbwRkj3/ACzVRqxbsiJUJxV2ep7aNoxRG6yRq6nKsAQfan4rUxMvxJGZfDOoIO8JP5c15docWdRhCp85bivWtRKNYSwOpInUxAD3GK4bwzpb2mrXEVwo86GPr1HPcVlUmkmjelTbafQ7qy27dvetNS20dwK4XVFuxI2PtbBQWWOAgDgdz61Joj6nBeRiSe5MUihisjhtuex44NcnJpe53c+trHayg474rhvGaj+z5DjIyAfzxVrxXd6kshitXm2oAW8o4Jz6etYf2S4a2uY5ZZ3AZN6ytux8wOQR2xVQja0iakrpxSO8skMdjboRgrEox+FWKZGweNWXoQCM07Ndx5hWuRmLcBkqcjPrWHGyRa067WDNCmSxyScmui2gjBrC1WER6lDJu5MZAOPeuetD7R10KunIzoUiiuIxlQT6VVuVggk8uNVDjlu2Kis7xkRmIwQuSB3xXP3l2NVYrII40U5GVJbNc8Y3O250ksMT6iA+070GOc81He28MaBFUAlgCK5mF5LLUPNFwkqlcbWJ3D6ZroGkNzPCegODVcuqREpWi2zRU4UUuaYKUmu48ocOlYOtSwXk3kW1xG9xCPmVWzsPYH0zzUHiHxfaaQkltA3m320gBeVjPbd/hXM+CJI2lvGd8zyyB2z3/wAnNRWTUGzWhrURsWerFSyygxypwyk9vb2rdW6jntQI5xFIVwGAyPyrB1XRmkl8yPufWqTWWs2ieXFGZFYYDZ6Vyrlep2XlE6KeRLa3ZJbgTzYONwxT9G33J+0H/VKNqH1Pc/0rnItN1Cd8X0gVOpROpH1otvGv9lXMun3Np5kcLlY2jIBC9hjvWtKKctDGvOXLqd7SGsKy8X6NfYAuhC5/gmG39elbKypIgdHVlPQqcg0AV02OQ//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-1.png', linkedinUrl: '/in/brian-evans-7848e0a7de', jobTitle: 'Information officer', }, @@ -1015,7 +1015,7 @@ export const peopleDemo = [ city: 'Parsonsberg', email: 'troy.davidson@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-2.png', linkedinUrl: '/in/troy-davidson-20a1718421', jobTitle: 'Civil Service fast streamer', }, @@ -1025,7 +1025,7 @@ export const peopleDemo = [ city: 'South Stevenbury', email: 'aaron.schroeder@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDvKSnUx8hGK9ccUhlfUL2LTrGa6mICRIWPPXFeZXfxE1OS7JgWONB91VG4H61j+INV1bWNTe2lEud5UQdvpirWnfDrULgiW4kFup6KBzWE6qR0Qot9BIvH2pSXrHzwhIOEK/LWjZ/Eu4ULHcRqZEb5sdxVk/DKzEXz3ErSDkNXMap4Qk0iQz+fuQd8cmoVVdzR0JLoes6F4o07XkItpCsy8tE/DAevvW1ivnTTtWn0vWIbqE8xODz3HpX0Fpt9DqWnxXUBykgz9D3FdEZXOWUbFvtVTULyOwsZrmXO2Nc8d6uVh+Lo5JfCt+kSlnMfb0yMn8qb2JW5x/g22i1HW7/V2UM7vtX2zya9D29B1ryzRoZNP8OMVNzulmbaLfqcAc10nha5u3YxztOIwhcGY5P0NcE1d3PUp6JI6mcbVPzYrm9Ztoru3eGQZVgRxWJrcl7cXTSKLqSOPkLCxGRmprSeSRRH5dwhHJWU5/Wo5dLml9bHmGoQtZ3skOQQCdueteo/CbUnutMvLKRifs7qVHsc/wBRXnXi6Awa4+eFb5lP1/8Ar11vwgMh1W+QDCeUGJ/Gu2nsmedVVm0evUyaITQPE2cOCDin0orYwOX8P2IsrD7DcL+9ilcHPf5jg/lirF3e2FmLlXlRHWPOOOnrVm/Qx33mDoyg/lWJeXljPJ/x5zTlBgskWQfbJrz5R95o9ak+aCaLejz2t2nyvGxIDAqcgg07UPJgQlUA+lZVrqVtEfLjgkibPR4yP16VPfkupLHms32NTkNQ01dR1eOSSMOioAR3yTxiuk+HlnFa6lqqoATFti3D8Tj9f0rnrvWXs71tPs7N57+dMxMPup7nv/jXovhiy+xaNbKFK74w8m4clzySfc811UIvdnDiZxtyrc2RTqQUtdRwmfq0LtbebGMtHyR6jvWYFtpol8yU4AyAK1NYvhYWSkxl2ncQouccnqfwGTXN3enTNG0lu+1hzt7GuOvbmO/CuXLqTXLxQoSsmR/tVkXF0ZBtVtzE5JqA2V5KcStkegq2lkYlPHSudnVuJ4e8NNc62+rSthSAijHUD37HP8q79ECIFBJx3Y5Ncpous3EF7baabQSRSFsSqeU6k5rrc130WnBWPKkpu5//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-3.png', linkedinUrl: '/in/aaron-schroeder-c0b91178c9', jobTitle: 'Editorial assistant', }, @@ -1035,7 +1035,7 @@ export const peopleDemo = [ city: 'South Jenniferhaven', email: 'mary.anderson@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-4.png', linkedinUrl: '/in/mary-anderson-17e7aeb95e', jobTitle: 'Quality manager', }, @@ -1045,7 +1045,7 @@ export const peopleDemo = [ city: 'West Jeremystad', email: 'david.obrien@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0EimnCgkkADqT2qTFcr8Rbh7bwVelGZWkKRgr7nn9KGwOJ8Y/Ey9+3y2OhSLDDCSpuQAWkI64z0Ga83mumuJmnnd5pZDl3dskn3rrPCvhAa0klzcyFUztUKOT610LfDO1jQ4uGZj0yKxdVJ2Z0RoSaujyp5GRs+o4GK3PC3ia58Patb3KO7W6sPMhz8rKeuB612cvw4s1iz5r7hXM634TktIi8DGTZ26cUlVi2DoTSue6aNrmneILL7Xp04kjzhlIwyH0I7VoYrwr4UX09t42FoCRFcxOrqTwcDcD9eP1r3jFbpmDCuW+I6g+Br/chbBTGOx3DmuqrN8Roknhy/jdN6vEUI+vFJ6K4RV2kjivBSCLQbfA+8M5rp23EjnIri2l1HS9HsorCMviBTkLnnGepqx4f1rVdQuRFdwiNgpbj+R964Wup6UXa0TorkME54rltZybWUKMsVNU9W17WVu5VtolZIxjOMk9uKjtr28vcJcRsrAZOVxS5XuNyT0MP4fKz/EbT9gxjzC3t8jZr3814l4bjl03xLe6hahfNSTykUjPDEbv04r249TXbCSZ59SDjqxKjuovPtJYv76EVLS1bV9CE7O5yNlFD9n+zEAiP5Pm54FSQxW8d0ywoo2qdxAxzS6sotdTlYAKrKHwBjtz/Kuavbq3u1UxXIhcZAIcjPrntXA4tSaPUjJSimWrOGCW6ljlC7snkjrzRqMcNshEagcdqwrS4h0+VtlyJyzcEvzVu/uDKu8njGaTWoXVibwzYG91mB0IAWUytx2GP8AK9OrL8PWMVnodmFiRZGhVnYKASTzyfxrUNdtOHKjz6tTnfoLRRSPIkaF3YKijJZjgAVoZGN4msmuNOa4iOJYR0/vA9RXKkrPahftIgKjjC8/StnUPFFrqMo0/TJllDBjNKBxgY4XPXJI5rC1DTWlR3jcpJjII6GuSs0pnbh+bkuUZ2SFTmVZCB1xiszzWueFJZP4j6+1N/s27lf8A0mTcM9Mda1Etlij27QKxbNtW9T0jR9Qs9R06N7OZZEjAjcDgowHII7Gr5rxi28Uy+F/EIMCCSKZALqInG7Gdp9iAa9L0fxZpGtqBbXSpN3hlO1wf6/hXfB80UzzpAnHlk0f/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-5.png', linkedinUrl: '/in/david-obrien-5393bdf2d9', jobTitle: 'Air cabin crew', }, @@ -1055,7 +1055,7 @@ export const peopleDemo = [ city: 'South Daniel', email: 'colin.miller@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0TFGKXFU9V1CHSdKub6dgscKFjnuew/OkMzPE3i3TPC9urXjM88gzFbxjLP8A4D3Necal8XtSlciws4beP/b+dv8ACsmw06/8batNqWo3EmzO3f8A+yqOgArq7T4eaRCd0iySk/3mrGVaMXY3hh5TVzJtPi7qsQVbi2tJsdTtKk/ka7bQPiJpOsKsdyy2VyxwEdsq30P+NYlz4C0eRQVtym30PWuU8QeEFsYTcaaWDJyU9R7Uo14vQcsNKKue7DBAIIIPcUYrhPhp4qbWNPbTLvAvLVQQ2f8AWJ6/UV32K3OcMVw/xTMv/CLwJHna90oce2Dj9cV3IrkviNE0nhdccKLhNxx0ByP5kUnsNbmJ4etY7TTbaKMcBAT9T3ro1+6MHJrhtQj/AHMSyfagnljbHb9ePeneH5biK6WIfaPKY/KsjYOa4HG/vHqRlZ8p2rtgHJx+NYmo4MbYGTg1z+ti4ubuQ7rny0b7sJ5460llLInyq12VAyUnHNHLpcHPWxmeFJX0z4hWAgHyzSGJvdWH+fyr3avFNDtDcfEyyCqVjSXzW3DjABP88V7Ziu6m7xPMqK0gFc342tWn0iNwxHlSZIB4P1rpRVPVbRr3TpYUUM+MqCe9E1eLQ6bSmmzjre38yP5cMf8AaFRLJaxagiyPDGVzt56nHJqKK7e3tZC42vEG3L3yOMVgOJ9ZCytFINo+QiI/ic1wpO9j001bQ3oZbeW9lWN4pFdyOvQ1ZmtVhXcygegFckPO0maR0iYRMRuDRH881tXmpM9hG6ZMkijC+me9Di7hzLruQaXC11rv7vO83EYUg9NpBOfavWj1rifBmjzhItQmCiMlmXnlj0z/ADrtq66MWlqefXmpNJCClFFLWxgea+M4hpeqSktsgvFLBvQnhh/X8apme3fTUjMrxgKACvcCtPxNdHV9cvNOeNTDbIirxnJOSf1FcVfwahar5SLIyDgFfSuOdnNo76bkoJm891BDp5VXMpYbdx9DXP2V1LcbbYMS6nbuHZR3NVYvtV2RCFZFHB4wfeuh0/SxZWjAKAWFS2oofvTfket2EUMOn28duVMKxqEKnIIx1zU9effDrXUttDGnajcKjQsRCzngqSeM16Arq6hkYMp69z//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-6.png', linkedinUrl: '/in/colin-miller-fdfec5eb0f', jobTitle: 'Museum/gallery conservator', }, @@ -1065,7 +1065,7 @@ export const peopleDemo = [ city: 'West Kathy', email: 'jesus.johnson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDPzSg00CsXxJdvBaRQRkhp22nHUis27FJXIdQ8U+Xdm3sY1lKnDSMeCfQCse41O8uJ/Me5aTA+6g2ge2K6DRPBZ1CJZ2f7MD0AySfc10K/DK1Z98l25P8Asrgn8a55Vo3OqOHla555Z3zWdyswuWAkGCVPIz61tw+IfJnEVwxljJ4kHUe9dPJ8N9MWMhpJC3XOa5PXvCNzYwGS0kLqnO09ce1EasW7IJUJJXZ0aSpKgeNgykZBFLmud8K3ssiz2U6lWi+Zcjt3FdDjmt0zmasyTiuf19o1v7Iv1wcH05Fb9ZGt6a1zLY3IwVEnltzyM9Dj0zSm0kOmm5aHd6PGBbRBeyjFbwJCAc1x149zaQ+VBFO525XyuOg/zxUnh681Z5I47ky+U/OZPvLnoDXnKOlz1k+h01wD5ZA4+tcrrjmOA8E4BJqLXb7Vpp51t/M8iDO4xcs2OwHfrVGKSe5URypMpC5YSnPaqUeopPocpo9w03ieRlY+WVbcB0Jx1rrO9c9oWntaaxfytxGWKIAM5Oc/lXRAc13xaa0PLnFp6iZ4q7bxpdaZLF0dHDg49Of6VRIqezuDazF9u5WUqy5xkGlVjzRsgozUJ3Z1lk8VzbRhwCwUdaJHt4b2OIPHGep5xk1mabL+5jwei/yqvfT2N64WdPnXIDCNiRn3A4rz0uh7Caaui3ZGCXUbmMsjZYkc5zTdU8m1t3ES4ZgR9Kxrd7GwuGNrkOzfxKyk/nU+qz7reUknI/SqasyW9ChaIsUMjDJ8xs5Pr3/CpB1p0cbJbxqQBhegpD1rtpRcY6nmV5qUlboMpKftpVjOa2Ocel0bOPeSQmevpWyZIbm2XfPtDKDlTWBHKLi9ktgFaJUAY/7RJ4/DFMj0a9KE202CpIKk9K8+qkqjPUoSfImbErQWsTFZASO7HNc7Jfi8O1XzGDvkbsKguLTUtzR3Cnb3+bg1YGnNHp0keAJJEI+mRUaLUttyNmRkdAyMCpGQR3FUznNZWjSTtplvb3CkIpEbTKw+VuwI9OnNbZtpIhhm3e/rXo3PKQAAAAAAasf/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-7.png', linkedinUrl: '/in/jesus-johnson-8a2b7bb431', jobTitle: 'Radio broadcast assistant', }, @@ -1075,7 +1075,7 @@ export const peopleDemo = [ city: 'Desireemouth', email: 'brooke.henderson@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-8.png', linkedinUrl: '/in/brooke-henderson-98aee4e9a6', jobTitle: 'Market researcher', }, @@ -1085,7 +1085,7 @@ export const peopleDemo = [ city: 'Lynchstad', email: 'meredith.gregory@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-9.png', linkedinUrl: '/in/meredith-gregory-a3f977f6ef', jobTitle: 'Environmental manager', }, @@ -1095,7 +1095,7 @@ export const peopleDemo = [ city: 'Lewisfurt', email: 'crystal.vaughn@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0TbRin4rJ8Q6umi6TLccNMQREhP3jjP6DmpKE1fX9O0aPN1cIsh+7EDlj+Feb618QtbuZH/s/FjbD7uFDOfck/wBK47UNRvdZ1JiTumkOQqitnT/Amr3sQaUrGD3YZNQ52NY029il/wAJ5r8TZk1OaRTkFWPFamieP9ZjulmknaeDPzxv3H1q+nwuyhM92zt/u4rmb7w9JockkcjFk5wfT0pKaeg3TktWe26N4k0vXExaXKmYDLRNww/CtfbXzPZX81jfxTw70mjbckit0NfSWnzm70+3uGwWkjVjjpkjmrTMmrFuuN+Jc8EHhRhJGjyvIEi3D7pPUj3xXZ15t8XmK6fpfPHmvx6nAxTewR3MbwB4eTa9/LhnZ/lGOgFenIoCADB9q85tppNM0KyhH2jfJCH2wDnPUn9a2PDM9/PdqtxNO0JUsPOHI46GuR9z0IWSSOtl4BAP4VxvijS1v7VyrbZQOD61X1u41JrpzFJc+QmcCDqQP60yyu5rgiIpcKccrMOaPMb3seUzwmOaRG4ZTgivfPhzqUmp+DrbzR89uTBnPUDofyP6V414mtBZ6669FfkH2Ney/DW3jt/BVtsxl5HZseucfyArpg7nBUVnY62uf8X+Hotf0nBH+kW2ZIT6nuPxxXQUvarsZp2OR0kW8tlEkka5CAYIqSXUNPsr7yWdI8ISoA6+tVvIlg1CZShj+YkKewqpcanbSsYP7MluQowW2gD8CevNcSvex6ySa0LOjXllfb1V0kB5B6g89D71Yv1gtkJRFGOmKy7XVLfzDELGa3Ynj5MjP1FTajudQG9KT00HY5HUNO/tDU455EDRgbGHc88Yr1Pwzp/9meHbO17qm4/jzXC6RLDd+I49H2P5zp5jPj5Qnf3zxj8a9PACgADAHAFdFFPdnDiJLZBS0lFbnKYfiK3dIlvYv4Btkx6djWRDHZXUQMkhHsK6LX5/s+hXkm3diInFefXds4BkhZgeuAa5aySlc78NJuNuxvTfZ7NMpISOgBNZtzdNKu1Wyx71k25mm5kDH61qw22xMsOT0rE6Cz4Ls7VvEuoXhuEa6SJYlh7qvc139cN4a082Wp3WosxJnKoi46KByfxJ/Su3zkZHSu2m/Ve+z//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-10.png', linkedinUrl: '/in/crystal-vaughn-2886394a50', jobTitle: 'Operations geologist', }, @@ -1105,7 +1105,7 @@ export const peopleDemo = [ city: 'South Hollyfurt', email: 'william.greene@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDrNtKFqTbTZHSCJ5ZWCRopZmPQAdTVCEOFUsxAAGST0FYd34s0m2cokslyw4It4y4/Pp+tQxCTxI4nn3pp5P7m36bx/ef1z2HatqDw5ZKPlhA/pXNPEJOyOunhXJXkYUPjfRXkCTvPak9DPEQv5jNdDFJHcRLLDIkkbDKuhyD+NUL3wtYSqfMh3D0rnlik8MXDT6cHNrnM1oTkMO5X0b+dEMQm7MKmFcVeJ2JWm7afbzRXlrFcwNvilUMrDuDT9tdJyE+2sHxg+3QGiBI8+VIjjuCckfkK6PHFc94ui8ywtAOcXceR7HI/rUTfusuCvJFrSYwlsigdhW8M7RjmuE1S5urUFIxdsGGUW2GGOPepfC93qz3CRXUtwY3+YedgsvscV5yWlz1r68p2E4+U56VymrhVBYDPBrP8S6hrBvpY7V7jyYvvLDjLfTNU7We6uPlkef5R86TqNw/EdaOXqDl0NTwFcNLp93bEkrDNlAewYZx+YNdZtrkPASLFNq6swBa4AUE9cZ6V2hWvRg7xR5NRWkyQCsPXLdVWW5c5G1eCem05zW6BVLVbQ3lhLGF3FkYAfUVNWPNEuhPknqLZiC5gCsBkDrTHmsbTUYYTLFESeMkDcfauX8Pa4FsyLkkPCpJ9wKpajdy65OH3LCkX3AELHPfJArhUXex6ildXR0tk9rd6ldRiSOTDHlTnB9DRqkMFvC+xQGIOSBXG2V7caHfyFdksMhHysCrA+2e1aeu60ptEK8GXGc/wjvmhx1sJzstSXQbfzp7crjIuTJkHtk5/lXcGud8K6dNBZw3Ey7d0eUGf7xzn8q6M9K7aMeVannYialJW6IUUtIKoa/Hdv4b1J7EN9oS3Zo9pwSRzgVsc55vrWdJ8Q3doj7FkYlGPTa3+Brp4yJNGijtrlYZ1UKMr1x/jWWdFbU9BhS6w9wEB356N9awZZtZsl8gI0iYwGVfSvOclJ3R6kYypo6W9ljttKkNzLHNO4K4Xt75NcZZTT6xrFppfm5WWUAsBnC+v5U2abU7xVhWEoAuGMnI/KrNpaTeGrFtRjG65jIk5HYc4/nVxtF6kTcp7Hs6II0VFGFUAD6UpqOCcXFtFMOA6BsfU7jzj/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-11.png', linkedinUrl: '/in/william-greene-da956010f3', jobTitle: 'Surveyor, commercial/residential', }, @@ -1115,7 +1115,7 @@ export const peopleDemo = [ city: 'West Darrellshire', email: 'aaron.griffin@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-12.png', linkedinUrl: '/in/aaron-griffin-361a228e01', jobTitle: 'Engineer, maintenance (IT)', }, @@ -1125,7 +1125,7 @@ export const peopleDemo = [ city: 'East Shane', email: 'steven.smith@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-13.png', linkedinUrl: '/in/steven-smith-6e762c7e90', jobTitle: 'Psychologist, forensic', }, @@ -1135,7 +1135,7 @@ export const peopleDemo = [ city: 'East James', email: 'mark.faulkner@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-14.png', linkedinUrl: '/in/mark-faulkner-5b751ca394', jobTitle: 'Nurse, adult', }, @@ -1145,7 +1145,7 @@ export const peopleDemo = [ city: 'South Victoria', email: 'jeffrey.hunt@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-15.png', linkedinUrl: '/in/jeffrey-hunt-c364e07096', jobTitle: 'Dramatherapist', }, @@ -1155,7 +1155,7 @@ export const peopleDemo = [ city: 'Popehaven', email: 'tara.mathis@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0vFFOrnvGXiRPDPh+W7BX7S/7u3Vu7nv9AOaYh+u+LNK8Pssd3Kz3DDKwQjc59z6D61ytx8T2jO5dMCpno8vzY/AV5TLqM91dPcXErvLIdzyOcsxrY0/R9U1OBvs8BJzgHJ/mazczWNO53H/C3bUThGsJAvqXArs9B8S2GvwlrZ9si/fjb7y15Svww1GS3aSaaINjIVck/nWVbXl54W1KFgxW4i+9k9eeQfUGkqibHKk0j6ExRiqul38OqaXb3sBzFMgYe3qPwPFW62MBa8O+LWqi98Tx2KtmKyjCkdt7cn9MV7jXzP4juW1TxvqT4Pz3bIo+jYH8qmWxUdzb8E+EZ9YvBe3KFbSI5Gf4zXs1nYRWkKpFGoUdgK5S6LaZp8drDDLIBHgLHwBgc/jUnhk3y3MQlacQyAPtkYnbntXG3fU9CK5dEdg6/KQBXlnxL0B2j/tW3x8mBKv6Z/lXQ+K5rtbljE1w0MY5WEkE847fWs+8WW90C/tHhljlWEnDNuDcZyPehaahJXViP4P6+0sd3ok75KDz4M+nRh/I/nXqleCfCyORvGcbpnckLn/EfrXvddkdjz5bhXkniDwgtr4wlvIgAk9yk6gjjnlhn6qfzr1usfxE8Frpsl9OjMsCknYMnH0pVE3HQqk0pakdo0M8IDKrcdxmkuZLe0nhV3SNSw5JAGc8AVQ0a4jurSK5gYmKVA6Z9DS3+q6WZFjnhNw6HO1Yy201xa7HpJX2LsD215d3CI8cgDdsHB9Ki1FIYbd1CgfKRgCqtnqmmhysEZgdiMK6bSaj1u9itLOW8uNxihXcyr1PsKH2Bq25R8CaANMvvPKDcYnBYDjO7j8wP0r0AVk+HnFxo9vdiPyzcKJNpOSAegrVrtppqOp5tVpz0FqveWyXlnNbuMrIhU/jVikqzM860C1vtEspdPvSA0EpCMP7p5H8zW4sKXaZMwX0IqbVbhbjWZLMIP3UKlm9SxPH4Y/Wsie1mjUGIkewNcFSymz0qLfKmaRgW3Q/vQ49TXN+K7W91bTrexs8kzTqHPbAz19s4rWtbOV499w5bPRaLiaez1bS3hP7szMki+o2E/0pQa5lcdVtxZ02h2ktjodlazY82KFVbHqBWjSA5GR0or0DzT//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-16.png', linkedinUrl: '/in/tara-mathis-1d1d3c04ed', jobTitle: 'Surveyor, minerals', }, @@ -1165,7 +1165,7 @@ export const peopleDemo = [ city: 'Brandonburgh', email: 'anna.davis@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-17.png', linkedinUrl: '/in/anna-davis-ec88f7642f', jobTitle: 'Programme researcher, broadcasting/film/video', }, @@ -1175,7 +1175,7 @@ export const peopleDemo = [ city: 'Port Alyssaland', email: 'kevin.johnson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDvMVg+JvFVn4Zt0Mo8y4lz5cQPX3PoK32ZUUsxwoGSfQV8+eI7u41zxDc3vmbY3fEZ/wBgcL+n86TdhpXNbVviPrl5HJHHIlqP+mI5OfrmuVjupLiR5ZmJbHU9T71t6f4VvNTby7ZMAfelkXitO6+HV+IvmmRZQvACkZHvWbqI2VKT2RlaJ451XRp/JinElv3ikG4Z9q9h8OeJ7DxJZq9vIFuVUebAT8yn+o968Tm8H6nByUXg9qk8M3U/h3xZp810rKnm7W56huD/ADqlNPYiUJLdH0FilxRRVmZHeIZLGdF6tGwH5V4BZxiTUIkkbMbOMg96+gLy6jsrKa6myY4lLMAMk15VZ+HhD4zjjkQiCR3njUjHy9cfh0rKpJLQ3pQk1foekacFWxiRVCgIOQOnFR3iKMkPurC1zV7zTo2itIZ5GA3ExJn9a5/T9c1m+vY7WZMNJg524IB9cdDXNZ2udqaTsdFfWzeQX4+lefeKIgLQSBfnRwQfQ1teIdavNOumtEjZmQ87RuxWXK5vLcfaASElRpBtwdoYZqoqzTIqNNOJ7BpguP7KtPtbK1x5S+YVGATirdRwSJNbRSxghHRWUHsCMipK7DzhtxClzbSQSLlHUqQa5iCzkiuXubp2kuPMOwkn5V6YA7V1grM1a3wqzKzAg8qDwawrQv7x1Yery3g+owmC9tWjlCgdORnNUrD+zY7uaG2ijDR4DSd8ntTD80TbWxkE/SsSeTT3sWt1trmQq2RIkTct65rnWp2aFfW4oT4hlLBSjng9cGqgtVkuUgjGTIwTj3NUJXj+2BS024jGZUIzXReG7AX2qhpGYLABJ8p6nIxVKLbsTOSim2d5HGsUSRIMKihQPYcU6ikrtPLJkUsQBWXdXTTM0LW8kRjfBL4+bjqPauhhtWQZzyaq39sHJEq9P4h1FRUi5RsjSlJRldnDXri3kZCxRH4DelEkay2Ri+1hEA4x1NWNajEabZUDI3fsa42/RoWX7NcMYj/AT92uO1nZnenpdE95GkcgjSXzCfzrvPDmlPpthumH+kTYZx/dHYV5kt6LGWO7lUyLCwkZfUA5xXrtnqNtfwpLBIDvUNtPUZ9q3opPU5sRJ7FikpaDXQcp/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-18.png', linkedinUrl: '/in/kevin-johnson-c2a28b524a', jobTitle: 'Fast food restaurant manager', }, @@ -1185,7 +1185,7 @@ export const peopleDemo = [ city: 'New Sarahberg', email: 'sergio.glenn@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-19.png', linkedinUrl: '/in/sergio-glenn-5cdb7d803d', jobTitle: 'Surgeon', }, @@ -1195,7 +1195,7 @@ export const peopleDemo = [ city: 'Logantown', email: 'nicole.allen@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDuu1cf4l8e2uh3q2NvB9ruh/rAHwsfsT6+1XvGviH/AIR3QHmiP+lTHyoPY45b8B/SvDra5kmuvM2eZIxyWY9/UmspO2xtGN9zs/E3jSbUpY4VZ4bfAJjRup9z3rAj1R5pPLhlcAdCWxzV/SfDF74hleV1Cp0D9BWpL8K7wJ5kd4u4fwgYrFtPc6VCS2RnWniPXNJuBNFdmXH3keQuhHoc/wBK9G8O+OLDXWjtpB9mvWH+rY/Kx/2T/SvO7zwhq1rAVkJlwOCpOa5WUzWN0oIlimjIYMOCCOhpwkTUh3R9Kmisrwzqh1rw3Y37kGWSPEmP7w4P8s1q4rc5ji/ihZLP4XW5x81vMCPo3B/pXkVhA13dRw7ggJ5wO1e9eK7FtS8Lajaou6RoiUH+0OR/KvFvCNm9z4jSN1ICZL5HpWc+5rT1sj2LRbWK1sIY4hhQoGK2x92uHvtTudOjMUMVzJJ1VYV6fUmptAvdZkuES68zy3AbdIQSoPbjvXLy9T0OZXsdXPErJ8wHPrXmvjvSoTaNeIgEkR7dx6Vv+JtS1a1meKyjdxGMsyDJ/CsG7uLnUtKu7adZvNWFiVkUZzjIII61UU9yKjTVjY+E0jP4YuVbOFujt/FRXe1yPw0tGtfBduX25mkeQYPYnHPvxXXV2LY857le+iFxYTwtnDxlTg+1efwaUthrL3sarGkoMaoB0wRz+PNej9a5DXJo7XWYLDyWAdDKknb3WsasXudGGml7rN6y8m5h/eIv41VvbqztpViEkceCMliACfQepqpatJ5ZCHtmq09/pzgQ3VlNKy/9O5P9K5lroej6Gi09pLq7x+ZHIrqOhzg1BqsVvHCyRooLDHFY8dxpdvdbbeGWORuMvGwJ/E1feKW9u4YA2CxHJ7VVnexErKLubnh6yTT9BtLePlQpb8zmtKkRFjjWNRhVAUUtdqVkeTJ3bYhYKM1h6xZrdAXLDMkQO0+gNbbRZ+9VPUAsdjNnuuB9TSnZrUdO6kjmrS78tgrnBXgg9xWwsKXK580DI4PcVi3NmXUSAdetZzTXdsdq7wB2rh0vc9NNo37i0Fvl/NDY71PoSfabmS5JBWL5R9T/APW/nXNGe7uMK5bJ7V03hlljhngJ+fcG+oxitaaXMY15PkdjcB//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-20.png', linkedinUrl: '/in/nicole-allen-d6ccf222ff', jobTitle: 'Fine artist', }, @@ -1205,7 +1205,7 @@ export const peopleDemo = [ city: 'Gonzaleztown', email: 'christopher.jones@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDm35NIFqQrUkSqqNI3bge5qW7K4JXdkWLe0G0POQqYzjPJqD+1tPgvkiaGNucfNlsfjWbPqUty0xjXe4IVQOQD6niom8J6nqUCzMRG5zyetYuprqdEaLa0Rt3Ws28uz/VOijG5SAPy61YRIr2JWtGLE9VJ6elc9D4FvhOolmLjHIUnk1alt59Is5ohu2vjnkH6f4UlUV9GVKhK12i1PC8UjI4KsOCCOlRqpBp9nq8erRRJIi/aCNu8cDjufyqwYSrYI5rdO5zNWIyvNYmuSszxWyEgnj/69b5Wue1uOSO8WVR95cAnoPWpnsOG50vhzS47bTYiwXcfmZm9a6q3CGMbJVYD+6a4vUl8u1gidJpAsWdkY5JxkmpPDC3TajHAEMcEgyc8FfTPvXE1fU9aErWidruiQ5eVEJ7Fuv51n6ikbROrBXRhg965LxKLn+05E8l5YkOfl5Yj2rQ0p5VcW/lyrGwyUcdD6/40raXG5a2OVuI3s52FuwUB9y9s57V1cEn26BLnaF8xQcD6da5TW5PsuqzWci45wrHtn/IrsNLtjFp8EZbdtQYOMZFdsOjPKqaNoiZBmq95YLeRxAgBUJYue3t+OatkGp7YI5KSEgZDDnHI5oq35XYrD29olI1Y4LW6TDovyjBJqnBqel6ZqSrlU2glQB97HelUnyCUPB5yPT1qhJcQXcXlR2Ms0eNoYKAPwJIzXDFXZ6y2sjQh1HSdUuXjVxIC5Ukr91vQ1oSwW9mVCAsccHPFYMd7HbQ+VJp8sCEhQdoI/wC+h0/Gtd3LRR5OeMiiSswv3Oc1DSI7rVTeXG1d42xORkbwO4rThYiJAwCttGQOxxQ9zbPeSQFwZIgGK4yVz0NNBLHNdNC+7ODFuKiktxhXNJ5fNWVQUpQZrpOIjMjKgT+EjB+lSNbWs8W2WYgDkCknQbEGM5rB1SO6trg4B2kZU57Vw1ElNnqUJv2abOgSG3gi2Rz+Yp7E1EZySI1OccCubsppnnWMswDcEjtXTx2ItXABzxUM1u5Fa3sRFPcznmSdwSfYAAD/AD61aVAKckqzLIyZwkrRNkdGGMj8iKUGvQg/iZ//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-21.png', linkedinUrl: '/in/christopher-jones-7b60309d81', jobTitle: 'Visual merchandiser', }, @@ -1215,7 +1215,7 @@ export const peopleDemo = [ city: 'West Ericville', email: 'brandon.sanchez@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDxxsmljQs4FOxUkTGMqQO/J9qTdkNK7Na006Foh5zAknj5sVuW9xaaXFukUFO3lnJH4VyUUdzqVx5UJY88BR3rpYPAOuGAOJVGecEniuWevxM64J/ZQatf2MrRy+TGVPL+pHqPWs+50i3nt1utOdmX+JD2rWk+HuqGPBkD4GSM8ZrLS1utAM8NyMZXK5PBPpRGVvhYSg38SOfkRlY5yD3zUfetO9ZLi3WdU2kcPjv71m45rpi7q5ySVnYkbIqKZsHYD0H61bdQRVGZSkhwPvHNEhxPT/BOkwRafDOEDTONxY16NboPKHP4V5pE89jo9skfn7jECFi6k4zWj4eu9Xe6ht5ZJTHNg5kOSvsfSvPkm7yPUi7JRPQQAATXD+N9Phm0u4kIxInzAgVX8TX+q2980Fu1wY0PPk9TQ4u73TLm2mFxvERH73nnHY0krWY3rdHmVl5bho5JThgdxqqfvkDpng0+0R/PyVztBJz9DQE5r0InlyJzxmrWm2CajNImcSLGWXjOcdqhK5BqXT7iSx1CK4j5KHkeo7inNNrQINKSvseraU0UkCRyIpwoHParsUlrbavbqzJGgOSSQMmsPSbhbm3juIwVD5OD2qS9vdLlkQXRUumcHaSVJ/lXmpO9j1001dHSCWyuL2ZN8Um5jggg4PoaivpIYI2jVeSMDFZOnX+jJG0dvtEjEEkjaxPrz1p2rXC2ltNeOcrDGXwT146UNa2BtJXPPNd0pdIt4VbBmnZnbHZc8fzrCAywrS1jVZ9XvPPmREwoVY06KPSqCj5q9GCajqeTUknLTYfg1PbwlmACkn0AqzDYz3EixQxPJIxwFRck/hXpngXwLeWlzNeaxbeUHhMUUZPzDcMMSO3HH41ZBgaIHttPCOrJhiQGGMVrRQeeoxMsZHRsc0f2JcaNLLY3chkkDsRIf41J+Uj8P1zVZ0kibCflXmzfvs9SnpBWNIW4jiIkmSU+uKwfFPnT6OUj3sm9S+0fwjnn2zitGCGVz+8OAewqaW3kbUdLhiUkyXITjsO+fUYzmnBpTQqt5RZ5aY/mpQnIOK7Lxb4I1LR9Ruri3s5H07eWSRBkIp7HuMdK5hIiSCvQPMP/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-22.png', linkedinUrl: '/in/brandon-sanchez-f78c3a4268', jobTitle: 'Radio producer', }, @@ -1225,7 +1225,7 @@ export const peopleDemo = [ city: 'Kathleenhaven', email: 'cindy.schmidt@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-23.png', linkedinUrl: '/in/cindy-schmidt-19ce5324d9', jobTitle: 'Production assistant, television', }, @@ -1235,7 +1235,7 @@ export const peopleDemo = [ city: 'Stephensonville', email: 'john.gillespie@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDuQTjjFNYn1FMV+PQ0hcAEsBgck1BRma/r9l4fsPtV6x+Y7Y40+859q84vfiZqs90wsYYILfqoK73I9z0/Si8tL74g+IpJwwi0+3JiiPoM9fcnr+VdBD8KdOEf/H3cFzzkkY/KodWMXZmkaM5K6OMHxC8QoxLXbjJ6NEpA/Su98J+O7bXQlrdBYb3Hb7rn29D7UTfDLSpoAjSz7wc5yK5DVvh/Po6S3tldkmL5sYwQPUUlWg9Cnh5x1PXt3pTt2a4/wL4hm1ewltbx993akBmP8anoT78V1uPSrMROe/OKzPEEjx+Hr9o8h/JYDB6VqscL7Vma0BJol4m4LviKgkZ5NDdhxTbsjG8FwLb6FBgYL5Y12cfKjaa8/uo3j0y1Aku0QRABLYAMxA9as+H7m7jmiTzrtkkOQs5BYVxtXvI9GDtaNjuGyAcnArB1vBspgo3HYcj8K5/XZ755jL9ovfKVziO2IBHODmpbGSdJdoa6kUj5o5wNwP1HFLl0uVza2Oc8AHZ4ruAoIV7cgj1wRivUgMjqa4Lwrpslr4lvb1/khMrwRxrzgnnJ9sV3vIrsUkzzpxcdx5UYHpUU8KTwvEwBVhirKoNuTTHXqPWqaurERdmmZunQwm3WN8ZQbQfpUsJtIdSVGeNCMkAnBPrVRlaCeQAngk/1rKmuIr0gypJuUEArEePx/wAK4Unex60Wmro3YPss9y4V42BY4KkHB71LdRwwI2FXOOSK5qG6j09mWBSA5GQ8ZBJ+ta9xL5kQLHHy5NKStoO4zSLUASS4/wBZKz49+mfyrWwcVFZ2/lW8YOc7RnPare3iuynDlWp5tapzy0JRgLmkjBnmWKMZZzgCuni0SyiwWRpT6uf6Vdjghh/1USJ/uqBWpgeaauyxalcQoQTAdjjOT7E/WqTQm6t12XQhcAYYDPFdT4k0dLbVZNSRP3V4FSY46SKMAn6jA/D3rj73TZlYyW0pU+nauKppN3PSov3E4k4VLaPa1wksmOTgVEsm/wCYthFPLHpVS30y4kk3zSdetaMlg975WkWo/e3R2Z/ur/Ex+gqLq+hbu03I30DfYbOeQAPMhLYHBIOM/iMU7ORXWrplrHYQ2nkq0UKBEDegGKoXXh9GBe1bY39xjj//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-24.png', linkedinUrl: '/in/john-gillespie-fa4d7d67f3', jobTitle: 'Television/film/video producer', }, @@ -1245,7 +1245,7 @@ export const peopleDemo = [ city: 'East Mercedesbury', email: 'andrew.lyons@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-25.png', linkedinUrl: '/in/andrew-lyons-02809c0ff1', jobTitle: 'Accountant, chartered public finance', }, @@ -1255,7 +1255,7 @@ export const peopleDemo = [ city: 'East Amandamouth', email: 'joseph.willis@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0M1Xu7qGxtZLm4cLGgyT/AEqzivOfilqzWqWFihI3lpXI/If1pSdlccVd2Oe8R+Lb6+1AzK721up2xorHjHc47mufnvJp42uBP52fvrn5h7jNdB4e8H3Gu2n2ueVlVzhQvAIrqLf4Z6TC2+QzMxHZsVzOa6nXGk7aHlT3s5eIkll/vHqprotO8b3theIyzvMq4BSTJH59q7i+8A6RPbmMROpBzuB5zXAeJPCJ0aBp4GZo05bjn8aamhSpSSPZNA1228Q6al3ANjdHjJyUPpWpivCvh54hfS/E1vbNJi2u28p0J4BP3T+f8692xXRF3RzSVmOxXjPjuRrrxtPbzNwiqEB7DaMfqTXtGOK8s8d6JNceN7OdQvlXMaISDyCDjkVNTYqkryO18NwrBo1siDgIMVrtuJ5Fc1qT3Flb7bbzyVTKrAoJAA96k8OajeXUai687kbsy4yPY4rj8z0V2NifKg8VzOtxpJbyBlDAg5HrRrmp373Eot/N8uEZbyupx6Dueaow3E14PnWdeMlZ0wf8KLdQv0PKZwsOrp9kGJUmUx7fXPFfSqbvLXf97Az9a8DsNIlk+IsFukbGP7WjEjsoOT+lfQGK7Kex51TcdWB4hsRNNa3AHzJIpzjoASf610GOKguYTNAyjG7BxmipHmjYdGfLO7IIlWSLP51ADD5oWMrweccVFGXELc9BWVNd2kkgWS3n3oCoYQMCB9a4lqemvImsjEb+ZHI3MTj3qTUQkKEAAEisVbi0hvvLtopUkc5w0Z5/Gr2qFmTLHnHT0oemgGX4bsll8RtIyk/vRKGx02rjFeh1i+H9Ma0gE8hUtIg2gD7oPNbddlKLUdTza81KWnQdSYp2KR2CLn9PWtTExbt1t7mSM8BuRn3pZESWPBbHGQaxtBml1iLUmu8uwvZUGewBAFPurXUbZcQHzYx0U9RXBKykz06bfKiW4WOE7gRuHf1rKuLnz5FQuArEbmJwFX3qKRNTuSRNH5aj3qrrNsbfw/e5+80D/wAjU6XKbbPTFVQo24244x6UprmfBdxPFotrp162Z4oVKknkjHI/CumNABXonlH/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-26.png', linkedinUrl: '/in/joseph-willis-242605ba96', jobTitle: 'Accommodation manager', }, @@ -1265,7 +1265,7 @@ export const peopleDemo = [ city: 'Sabrinahaven', email: 'charles.stanton@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDtQvFOC4pwFcH488TXtrNHo+kuy3D4M0ifeUHooPYmm3YErmtr/jnSPD85tpWe4uR96OHHyezE8A+1c2/xWfcrJpSCMnjdLk/yqtpHw/S5Ky3l1IZHO58DPJ9z1rqIPhxo5w0gdyPXA/lXO6/Y6Vhn1KmmfEjT7yYR3lu1oT/EW3Afpmuwgmhu4Fmt5UljboyHINcre/DbRnGUSRCOmGzWboz3HhDWVspWMmlXLYEh6xt2J/z/ACqoVU3YmdBxVzvytNK1NimkVsc5IBXkxuPtHi28nwDvuG/IHA/SvW1FeT6bb58UXidFimlwPXDVlV+E2or3jv8ATFURrjtW2hO0Y5rh57mW1VlZLt+PljthyferejzXsMq7muBC+CVnbcVz2/8ArVyWtqehfodXMTg5GK5DxTBHLaNlQeOam8QX15HMywm48uMZPkKCx/CsWaSa9s5133B/dNuWdcMpxkU13FLax1/h+4ku9Bs5pclymCT3xxn9K0SKzfC4J8MWDMckx5/U1qMK7lseW9yK/iebT544yVZkIBBwa4Z7Q2erR3GMeZHtJ9Twa9DA4ri/ENq1rPBwQPNJVscEEVjWi9zqw81ZxZ0NqI50UsFzj0qpql5Z2TIssqRrkcnp1qtYSu0YKt823IFQy3PmyeXLbTuV44i/rXKldnenpoXkvLKfVmiSdJNyAkDtSanHFFbyKqgFh1rMVo7eYeVBKjdBmLj9Km1N2aFQfvEDIptaie2pseHrX7JpfkjOFc459hWmwqGwjaKxiVvvYyfx5qZq7oK0UeVUac20SCsXxVCZdGwvDCVSPrzW0MYrk/EdzqktxELfy30zfib5fmVh0IPoTRP4WKn8aMSw1HBMZYrNFnKHrjvXQRXUMsfz5O4dVrD1XRXlUXcAxIBzjvWVFdX1ou1onx/uk4ri0Z6WsdDsZJYLdOGO7qCTVbRi2paspB/dW/7yQ+p/hH58/hXMyXOo3aYC7VPGQuOK7HwZai30+4PdpAD+A/8Ar1pTiuYxrSfIdJTTTjTDAABXWcB//9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-27.png', linkedinUrl: '/in/charles-stanton-89aca5d45a', jobTitle: 'Music tutor', }, @@ -1275,7 +1275,7 @@ export const peopleDemo = [ city: 'Lake Barbarachester', email: 'gary.hall@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-28.png', linkedinUrl: '/in/gary-hall-1ec55a0077', jobTitle: 'Theme park manager', }, @@ -1285,7 +1285,7 @@ export const peopleDemo = [ city: 'New Seanstad', email: 'steven.martin@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDKJB71A4FPyB1AqNmXPSkBUvLmOzgLuQT2XPWuduteuREwRQpY8ADpW3Y6O/iHxLJbsCttHzI5PYdh9a7iT4eaRKVkAZSABtHSsZ1VF2OiFFyV0eNNqN2yHzJi7v8Aw5wBTrO7meUAzlXB+Qg16dcfDHT2YlJJASc4NY2ofD+OFd9tIfMTkA9zU+3iU8NMo6dqwuz9nlIE6j/vqr+0k1w1zNc2WoENEUlRs8cc13VtIJreKbH30DY+tdCOZqxZfpVfI3DNWnHFQFctzQI3PB6qRdShNrPMQx+ldpk7QA2fpXnkMNzaaUfIMxaWeR/3OAevGSfpV7w1eapdTC3n837hbMvUexxXBNatnq0nokdlJlR94fSsi9fBx1Pc1yeq3+rC8ZVNy0cZwRDj5ufetSynnkHlSLKcf89QMj8e4qHHS5fNrY898SxJNqDSr97JyK3tNUtptsT/AHBTNf0F9Q8RLBAwRZIw7NjOK0lt0gjSFN2Ix5Z3dcjiu2nNNJHn1acleXQa+cVAcip2PHFQPkmtTnOv0Uxy6dFE6/eGc/jWnZx28E0xQqNq4zwMmub0S5ZrUx55jOB9Dz/jT72XTpwAl6IpAMMRJgnnnNcE01No9ak04JmwkEE0hRgFfGRkA5FJN5NqNo5esSxuNPtE2286sc8YfJ/Wr9wwbBJ5PNQ9DS5TmhWV2IXErYCyDquDms65lD3DY6Z/OrV5JNvQROQhB347+lVFh5rpoQt7zOHE1b+4iEioWXFacdlLKpZRhB1Y8Ch9LwoZ3684HFdRxlOxumtZGZejLg1tpGlxZo0c0cYxkYHWs1LdPss8ioANjBCepGOtO02KPUdGtJUZo3ESqWHYgY5rlxEbNSO3CzesS6YY4oyXMLt6gVAbh5jtVsnpmqLWdyJCs0+U/wBnjNSGVLGJ5ccKOB61z+h1N9xJpJ28R2thEcxfZmklGOhzgc/Wp1GHwRTdEikXzL+fmec5PsOwq+I1nmkKjDA8+ld9OLUEmVNtH//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-29.png', linkedinUrl: '/in/steven-martin-82c1e4ee0a', jobTitle: 'Artist', }, @@ -1295,7 +1295,7 @@ export const peopleDemo = [ city: 'Colemanton', email: 'jennifer.mcgee@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0DxR4w03wtah7ty9w4Jjt4z8ze59B714rrPxH13WLh2F5LaW54WCA4AHueprmNV1e61S9mu7uVpbiZssxOfw+lUVJOMnr60Dsb0OrXbgg3koYkN5m85J9+a0IfG2v2kqB9TugU6HzCwx9Dwab4f8ACk2rorE+XET1A613H/CvNNez8su+4j72e9ZOqloaxoyauanhL4oW2pOllq5SG4OAk44WQ+hH8J/SvSAcjivAL/4bXNnE8tlcGVlG7b0Jr1zwZrkWs+HbWQOxnjXypVf7wdeDmrhNS2InBx3OkpRTc0uaszPjd3GeOlaWh2wur+JNu4k9OtULiymgPzAMpOAy9DXongTS4UsPtJUec5xuPXFY1J2jdG9Km5TszuNKQQ2yQogGBjiteM5HLjP1rkb+/ezbyzazyqeMKML+JrLszNdXizWtrc2YfO4Fz2PcZ4rltdXO29nY9EYMQQG5ql4OsWg1bWOdsYuVkVB6sgJ/XNc54jmvoGs7cLKyS43GNsdfU+ldn4OVRpDTm3khklf5lk5PAwK2orW5z4h6HThjinBqhBFOBrqOM8Cj0yDUI4ZgmbXylICjJOc8/hWvo0Z0u3WJOUVjXCeFNdvbS5SwVg9u5JVH/hPtXoNoxljCy7RJj5sdM1wVE46HpU5Rn7yOjhuYrj5XQHPXNTObSy2RoibpT7AcVjQqwYAGn3d9pqRGK9IZ8Z24ycVnG7NnY2JJLC9hi85onZDjAIOPpW9pMga3dV+6rYWvP7CbRZFe3tYjFKw3KCMYPtXdaeptrKJM87cn6muiinzHLiWuSxrBsU4PVUSmnCSuo4TxVfBtva3Md5aK6tH1jLZFXL/zbRUuoQWA4Zfau0GmptOwsPYtkVj6haFAwx16iuSom9TspSS0Mq01uOeIbWAPcHqK0lha7TMUqK+c7u9cpcaT/pG+I7c1p6amy7htZbuRHkG5dvXAOKyS10Olya3Oq0/TbmSREmlR1LAnaoGMV1uB0wQKpaTpkFlCZI5pZmcfekxke2K0MdjXXTi4rU4a1TnkN2jPWnqM9qXatOAHAB61qYn/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-30.png', linkedinUrl: '/in/jennifer-mcgee-f4f8b04f40', jobTitle: 'Special effects artist', }, @@ -1305,7 +1305,7 @@ export const peopleDemo = [ city: 'Thompsonhaven', email: 'bonnie.warren@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-31.png', linkedinUrl: '/in/bonnie-warren-c433803c71', jobTitle: 'Lobbyist', }, @@ -1315,7 +1315,7 @@ export const peopleDemo = [ city: 'Gloriahaven', email: 'gregory.martinez@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-32.png', linkedinUrl: '/in/gregory-martinez-81489f760c', jobTitle: 'Secretary, company', }, @@ -1325,7 +1325,7 @@ export const peopleDemo = [ city: 'Gregorymouth', email: 'bradley.randall@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1mijikqiRskiRRtJI6oiAszMcAAdSa4PWPito1kWj06OS/lHAZfkj/M8n8BUfxP1Gea2tvD9nJse6/eXLA/diBwAfqf5VyGn+DNNXBmeWVv8AewKyqVVDc2p0pT1RrQ/GC7NwPN0u38knosrBvzNdn4e8eaN4inFtC0lvdn7sE4ALf7pHBrkG8EaPcRErBtYDqGORXHa54ZudDZL/AE24lYo27r8yHsQRURrpuxcsPJK59D0tYXhHXP8AhIPDVpft/riuyYejjg/4/jW5XQcwUZpuaAaAPKPF8jv41vT12JFGMem3P8zU1grsmRjI65rK8ZXkkviLUWthJG3nrFk4zlVAJ9hWHoF5q0mpQwSSMVdj97+tcVWPM2zvoy5UkekxhjGcMckdq5/XJSLeTKn5evvXM6tPrUOoSxxXEwiQ52q3JGcYArbspJ7mL7PdpIPl4L4P61ly2szXmveJ0vwl3LoWoRknYt3lQewKj/CvQa85+H7TabKlgsatDctJJK+clWUDA/T9a9ErvhJSWh59SDi9RaTFTmIdVNREYqyDy/xnHbQ+KJAyqRNGrsB/eIxz+VUtFgtodYiYBVjTkk4GTXR/EXSonsY9TSPE6SKkjg9VwcfrXnfnWU2N8pjdVKhlJyD74riqwfMzvozXIjsby0tp7pllWPLZYNwQcGq080ECrDEAXPAx2rLsrnSbaAwW7J5jnJbcdxP0NXtFtDfa5AhG7e43Z9Byax5Xexs5JK51Xg+yUXU92IynyBfQbvX8h+tdfUcFtDaxCKCJIox0VBgU/oa76cOSNjzas+eVy0CQKZIQF3MQAO5rnbrxDNLlbVBGP7zcn/CsS6uZp2ZZZ5JX255PC+mKh1orYpUm9zn/AIheK7x9fs9Fs5ALCUMZSoz5hHv6CuSjuLiJiIZYo+ed4zW14is1lit7uMZksnIb3Rhg/lwa5jUISW3L6dRWTnd3N4LlWht75pIsTzQyDGdwFTjX73w5ajU7VY2kUhAsi5DA8YrA0pdsmZSzAdjXZaTpP9tTxyzRj7DbyBzn+OQcqPoDyazvaRo9Y6nqWn3bXthDPInlyMo3p/dbHIqzWPG8kTYV9shAYjtj3q7HegsElUq3TNdcKqejjlTfQ//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-33.png', linkedinUrl: '/in/bradley-randall-00c2f788ab', jobTitle: 'Product manager', }, @@ -1335,7 +1335,7 @@ export const peopleDemo = [ city: 'South Eileen', email: 'brian.steele@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-34.png', linkedinUrl: '/in/brian-steele-fe89252d69', jobTitle: 'Sound technician, broadcasting/film/video', }, @@ -1345,7 +1345,7 @@ export const peopleDemo = [ city: 'New Jenny', email: 'ann.mercer@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-35.png', linkedinUrl: '/in/ann-mercer-e7eedca5ab', jobTitle: 'Editorial assistant', }, @@ -1355,7 +1355,7 @@ export const peopleDemo = [ city: 'New Benjaminmouth', email: 'billy.fuentes@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDvHOKq3V1DaW0lxO4SKNSzMewqV3zXAfErUpYLK2sopdom3NIo7gdKlsaRga/491C8nnS2l+z2w+4qfeI9Sa4yTUJWm8wn52/iJrtPBPgBvEVu19eysluW2oBxu967S6+F+hxwtFFu3EffJzWbqxTN40JSVzxNb0xOxDEg9q7Lwt8RrzTpPIvma6tSAAGPzR/Q/wBK2p/hZYIjH7TKTXI+IfBkmjWj3VvN5kaH5gw5ApqrFuwpUJxV2e6W9xHd20VxCQ0cqh1I7g1OtcN8LL97vwo0MjEtbTsgB7KQCP5mu5BqzErdq8u+I6MfENrxlWtxnP8AvGvTdxxXIeJtKOrazp0piwkc62xbd13YY/4VE5KO5pSg5Xt0Ov8ADkEdrotpDGpVBGCRWhNtJ+Rs/jXG+If7Rt5X+zPdLGifL5A6Af1rP8Nanrd3ex2tzJI8R+bMijcPQGuO2lz0VvY7W5QBDk8npzXEeLoml0W6jUEnbnHriofEmratFfNBbPIsUY+YxjJP0BosGnu4mS4knbcnKzD1FVFW1Jm76DPhFLmx1WPHSVG/MH/CvSa4D4aWsmnwXMDoo+0Zm3d8KdoH867/ABXYmnsedKLi9Rqw+1Ur/T1kkguSSBA4YKBwWyOfyBFbaximXNss0DLznGRg45qakOaNi6NTklcrTJBeWp87aADjGM5qHTLWzEjGCNUjRiCw7nHNY9zeskcuH+VBk4HNY09/b3NujQzi3kUYV1cjr1z2P41xRTPSTRoTxQtfyrMg+ZjgkUl1DFbqNtc59s+zyu/2lbkkcktg/gK1RK135UfOZMAD61VncTkrO5seErNkimlK/Lwq4/M/0/Oul8o+lTW9rBZwiGCMIg5wO59alyK7Yx5VY8ypPnlcZjjNRXU5ttPu7oLuFvE0pHrirkFnPcqSq7UA+8f6Vpx6Tbmxmt5AWFxGUkJ7gjkfrVMhb6nlN1I9zH5yhVjuPmyO2e1TXEcstgphnijZQBg81p3GhNo9immSgFYI9iPjiRR0P19feuL1G1vIZSbaY4HRWrz7+9Z7npp2Scdi3cIYbcm4MTse4xWVPrM2m2n9o2uxmtmUrvGQeelVY7e6uZCLmcgHghe9ac+ni7sDp0CD97hAOwHc1aaTREm5J3PStJ1RNV0y3vFG3zUDFfQ1e3iuPh22dhHaqSsfCq69Ux0NbNncThikxzx8pPcfWu6xwAAAAAAAA4n/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-36.png', linkedinUrl: '/in/billy-fuentes-2b9e1e559f', jobTitle: 'Energy manager', }, @@ -1365,7 +1365,7 @@ export const peopleDemo = [ city: 'Bennettberg', email: 'kelsey.palmer@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-37.png', linkedinUrl: '/in/kelsey-palmer-25e5d90ac8', jobTitle: 'Medical secretary', }, @@ -1375,7 +1375,7 @@ export const peopleDemo = [ city: 'Castroshire', email: 'ryan.holmes@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDvCoxXPeKvES6BYqYwrXMpwiseg7k10ZGa8F8XXcuo+Ib9nLP+9McY7YBwABSbsOKuXtV8ZXupxLBcSsIwCdqDG70NYy67cwxFfM2qfuex4ya9B8N+B9MTTIWvIvOmdcs7nofQVsS/D7QnjKrCQSODnpXP7ZXOlUJWPJ08RypdwO0zFgwDEHpjgGvWvDfiqPWWMEgxIqjDf3vWqKfDPR44vnDM/r7Vg63or+HtTgv9Od0VR93PG4c/r/SnGsm7ImVCSjdnqWKXFNt2aW2ikddrMgYj0JFS4roOYdXgepqIvGl8MZVLtxj8eK996DNeRX2jm58Z2+qGPZb3827y/wC6w6/njNZ1JJKzNqUHLVHcac37qNcH7o49K24wdg56Vw2tRXYYLE1yIwPuwcEn3zVHw9LqsN/EvmXfkzYJW4bLLz39K4VHS56F9bHpRyVPOK4zxq7Jp6gf89FGcZ68f1qr4su9XivRb2zXIRQu425wcn0qubO5bSnjuJbh1WaNj5/JHzDOD6VUVqmTO7TSPRLGN49Ptkc5ZYlBPqcCp8U2J98EbkbSyg4Hbin16CPMe4A8VxOuW/2C7W7cfLHcJg4+6hyP612orI8T2C33h+8ULmRYiyEHuOf6VnUhzI1o1ORtdwt3hu49hCk45yM5qI21vBdJHEih8gkgdK5/R9TWO23O2QsZfPsBWLfeIhrG02sbxlW3CXzdhz9M8/jXEot6HoKSPRrq3t5b7bMqksAVJHcVXuIo2ZIAB8zgdOOD/wDWrgdO1y+t5ZG1H96Mja/mAlCOg4rv9NcXV4XxkIgbn1PT+tWoNySInUUY3NfGBgdKKWiu48wQVT1PULWygKXEm1pUO1ccnt/OteCwlmwSNi+prE8X+GBeNYaigZxZBg8Y7g4IY+uCP1pTuotl00nJJnnt3bS6eXeLiJwQOPu56irkckjaWn2JbeORE2hZRWldQCa3Axn/AArnrrTrgYFlcDbyCr9V9q4Izvueg04u6NCaaVdJk+1LC8jDAVMGuj8KXUDJc2rOftqFWlQ9lIG3Ht/Wuc0nTHikBuZPNYY/3c1s6BpBl8dG+gDCMWzLcc8MTgL+PH6VrSkueyMqyco3Z1tFXX05iMxt+BqrLbzQ8uhx6tljhP/Z', + 'https://twentyhq.github.io/placeholder-images/people/image-38.png', linkedinUrl: '/in/ryan-holmes-0c335917d6', jobTitle: 'Armed forces operational officer', }, @@ -1385,7 +1385,7 @@ export const peopleDemo = [ city: 'New Sara', email: 'larry.castro@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDtMUHCqSeAOTTsVj+JtVOj6NLcKpLH5R2x71k2WkchrPj263TQ2UaRqGKh2HJHT8K4u+12d5hIJWYZCuC2cVc0vSLnxHfzTyOYYM8lep9hXVxfDmyfDPM7ZGDnvWTmk9TeNJtXR5216VLS28oVmGSuOT+NavhzxHNY3jTh/LlX8mHoRXdp8OtKjAIRsgdc9axNZ8CwxwSS2jkSoMgHpS9pHYr2MtzuPDHie18R2zBCFuov9ZF3+o9q39teCaDey6Lr2n30r+WgmCyKP7p4P6V79wRkd62RztWIq53xzGH8JXf7sOQUx7fMK6LFZniSAXHhrUIywX9yWBPYjkfyoYLc4zwlEBp0ewdSd3512kQO0YbPtXnNjJeWvhy38nzVZwxPljnqa1/DVzq0t9DBcuxjcFgXHzL7GuSUd2d8JaJHa5JXG6sfVn2Wz7Rk4PFc3rl3q8N+wgkmMSH7sZ5PPYVdsJL2dPKnWTAHVxS5dLlc2tjzLV38298iIEkvwB3zX0PYxtFp9tG5yyxIp+oArxMaFJJ4luJgxSC2mDswXccZBwBXunBUEdDyK64NPY4Jxa1ZDUN7EJ7CeIjIaMjHrxU1OFNq5Cdnc4jSWjjtRbToCykjBGRjNaVo1tDqYBaOPCHHaodasFs7xZYydsuT9PasW6u9NaQfapAsnKqRnIP4VyuLTsejCSkro6S3NpdSspMch6gjBzzReyRW8RVFwcYGOKydLv8ASSixWbR53fwjBzVu9A3FieAKhroXdFbTtOEk5kjyGnfEozw3Hp7YFdxkAYHas7StPS1tY3OWlZckk9M84FaFdVOHKtTgrVFNpLoNoApQKMVqYmV4ih8zS2kH34mBH48VycMVxKMxbM57112vXEMWmSRvIBJKMRr3Yg5riZzcW53QZIbnFc9X4jrw7aia0UE0cRMwTPqKY7tM2M5A6mqdpFqV0CZcRReucmtSO1EUAUDn3rFnRdyOvjA8pMdNo/lQay7bWFU29vNDKGb5fMUAoCB35yK1Mgiu2LUldHmyi4uzP//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-39.png', linkedinUrl: '/in/larry-castro-631a1061ce', jobTitle: 'Call centre manager', }, @@ -1395,7 +1395,7 @@ export const peopleDemo = [ city: 'Spencerstad', email: 'elizabeth.gonzalez@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-40.png', linkedinUrl: '/in/elizabeth-gonzalez-7717b4d0bd', jobTitle: 'Automotive engineer', }, @@ -1405,7 +1405,7 @@ export const peopleDemo = [ city: 'South Erintown', email: 'christopher.matthews@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwCGaVJB8tVJ7iK2iMkzbVHpyT9BTizoeF4rm9Tmkv7l0G5iG8uKJR745rNsIq7N1tXtY7VpQrHupC5P61StvGMv2gjeoi6eje2K2NJ8FQvaKLq4YTEdAeB+FXP+FY2DTCX7QxJHTHFYqomdfsJJHPJ4ospZ1injCF2wZF/nitYxRykeVIJFIyGWrl18NNPSdZo5HKr/AA571lz2d3pGtpEkwNlMBhGXoR2qlNXsROi0rk5g2Co49yPntVh5VZyOgpjJk8Hg1ocosrnGNuMVzOm4/tYSMwbEpb6eldYyr5TSvnYo3HA5rn7LS5LXXI0kO6KVzJGxGDx2IqKkktDpowb97pc7ezYyMMHmt+BS8Qw2PUVwmpSXkChLZpVJ6eUBuP49hVTRNQ14XUS3LzbJTwJByoz39K5VHS56DlrY9IZHCY34HpXG+JJTG0WfviT5PqaqeKNU1u1vTaWSyHYFLMgyTn0qBoLy802M3jSM0U6sSwG4jPIFUlZpkT1TijWhghckvjPvTzaRtwv86fHCM8AjPODUv2V1Hy5NdaZ5TWow2yKvGCD2NZl1H5FxDcNlnaXaCT91SMdK3Gh3IACM1U1OzP2LfzkMp68VlUjfU68PU5bxfUuWckFxGEdBnGMkZpZYIobhFjVR0YsMDvWVaSGM4OSMcGq+o3dlqUapKVUodwJkwc1zxV9DvujqLuKCXU8NsYOoIbg8+lVJzFJKtqFAGcn8Oa5uxmhtJ5HlufPlfC58zO3B4xW/Yxie6d3HKj9apRblYznNRi31J5ogmGGKs2y5T5hT/JUNubn61ZRkC8CutI8uxkjnmnXKM1hIGUhcZBPep7DTLu/n8qBc4+8x6KPetbV/C832aKeB2mkiiEckYH3sfxAevtSmnyuxpTtzK5w5/ckDO30NSIhaHbG8aMBgFhU81uGGCPbms6eKSLiMg+m7tXGmj0rNPQleEhNsksU0mOAvFaen74IixO4nkn0rLtI2MpZ1UZ64HWun0bTUv9QTehKRIS5BI4IIx+P9K0g/esY1k5RuyONzcNtDYHrV6O3ULjdk1oz+EWUl7Ocj/Yk/xFU4LSVHdJCu5DtODnmunVbnElcAAAAAAADY/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-41.png', linkedinUrl: '/in/christopher-matthews-28232e7783', jobTitle: 'Surveyor, building', }, @@ -1415,7 +1415,7 @@ export const peopleDemo = [ city: 'Parkerview', email: 'rodney.briggs@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDvc0maCazNdvm0/R7i5Tqi8E9BUtlI5zxL45XTLj7PZ7XZfvseQPauE1XxlqF4G8ycsGyAqdB9Kg0zS5vEerTSNIVhViXk67iewruNP+HemAh3aR2POSawlUSep0QoyaujzkazOyqHkYJ0K/1rWsPGWrJdo6XLlUYBUY/Ltr0D/hWujysCIyD1Pzday9f+HlsLB3sT5cyA4z0b60vaIv2Mjr9D8QWuu27PCGSVAPMjbtn0PcVrCvE/BOtyeH9XC3nMcv7qQf3Bng/hXtYYMoIIIIyCK3TucslYaxrk/iHKY/B9wA23fIi/Xnp+ldSa53xvZfbvCl2oQM8WJVycYIPJ/LNDBbnL+DoFTS4igHJJOK9BswuwYPIrzCF7ux0WzSEyKWj3YjXLE9a2fDGo6vd30Vvcq6AjIZxzj3ria1bPSg9FE9DR1IHzc+xqlqkpW1fHOFJxXE65qGt2WotFbea0ado8fNz29619Kvb25URXUU6Hbk+avP5ik1oVfU8r1fL3zmN9pDk8dxXuGh7/AOwNP3klvs6ZJ+leUatoUr+JbtIUPkxfOxAzhTzxXsFpGIbKCIHOyNVz9BXVTaZwVYtai5qtqMX2jTLqEDJeJlx68VY7UmK0aMk7O5ymhGCewhjlQEhApB7EcVp2UtpBrSoWjjVFOB0zXNzSLo+q38JLFIm8xR1JDAH+tYdzdT6pcC4jWONlQhctg59Ca4uV81j04zTimj01J7G4lCs0UoYnDAg8+lWLjyIIwIlx9K880rUjpFrJBNbIVds7xwc1v6pqojsEZDiSVfrjNJroU2twsIBd3l5dIxyZTEw7OoUDH511KnCgDsK5fwdbymynndiYmlIjU+3U/n/Kumwa6aULK5w16nNaK6C54oFLxRxWxznF+PNOlSJNXgXIRfLnHtn5T+uKzUvp2tYnsni80gZHoK6/xLceTZRWskO5bxWwSOMLjNebXWmX+nsfsDho25VW6gema5qluY7KDko3Ove/eHSGecxSzMCojBzk1yyedqlxb20YfzQAGA6J2zUVlZa3fyeWyeUnQsxz+Vd3oeiR6ZAehkPViOTWfwmzbmbemQxWunQQxgBUXAAqySOoqbQtOuLpyWGLRScserH0FWtS0yeO5eSGEtCRn5e34V1Qd4pnBUjyyaP/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-42.png', linkedinUrl: '/in/rodney-briggs-634d20e650', jobTitle: 'Clinical cytogeneticist', }, @@ -1425,7 +1425,7 @@ export const peopleDemo = [ city: 'Haynesborough', email: 'donald.khan@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDoFj3fe4pjkRtgc1K7DbwcU2PKZmO0kfd3dPrUPQErstR2byIGf92p7nr+VTpZWq8Mzk+ucVlLq0krsk3GOh7VMknmHh2H0qOY1UUaMmmbgTbyBv8AZbg/nWZKTGWR1KsvUHtWnbzmNRuJ+uKdf2631v5igGZBwR/EPSnzEyiYazc1oWci4681nRwEvnHFWo4tp46UJmRCzhsD0qtql/Dp6I0spGPlVF5Lk9gO9TeWxbAHWuB06+udd8ak3CsoilZI4242KvX8aUnobUld2OqjtNT1Aq4ZbONugA3SY9yeBVpfCqPhp7y5lP8AtTkZ/Kp76ae3TbDHI7AEhYxyT+NZ+kXOqT3K/aFlRGPSQ8rz6VzNt6noxhFaWNFfDzQDNveXEZHpMSPyOagfWLzw6RLqBE9kWAeVVw6Z4zjoah8Q3OqWl2UslkdUAbKdW9gO9Z+vNd3nhK8llSUSRoGZJE2kcj04pxbuTUjGz0OoSSN/nhYNG/zKw6EHoatxpuXrWJosy3Gj2csa4VoVOPQ45rXjJAyDXSmeY9ynPA8kDIp2kjANZTWsS69b36KqhXaDnqxI5P5iujYArXP6rfQpdCwWN/tIUThscYzgHP14rKrF3udmHqLlcH6nTR+XMuCoPrkVUu57S0lRXeKIZAyxAySeAPeo7K5Bt9zcMq5YVkXuoWt1xM0SIp/iGSD/AErCOp3K3Q6VprKe82CSJztHGckVU1uKJtLu4MD54inTjkVg2F1aQyv9nngmJ4bB+YemK2551JhLjO5lOKbvcmVrakWnwx2NnDbqBtjXA+laCbWXK1UERaTjp6VehTamDXTG+x5NSXNNtB5RIBFUdR0oTyJcH5XETRZ+pBH6rWlE/RcZJ6Cor1rpLxYHhVYDGHD55LZIIx7D+dVU+Fl0VeaOTiuJbZpYCcOqkOGP61sxvJPZK1qYw+0YBxiq+r6Sbv8AewgLOBhW7H2Nc2NXvbBmhkt2Dqdp4ODXIrHoJuLOtk8yGyMl2kbvjgLg1Vt919dwsCdkQ3MffGAP1JrKsbnUNSfmIohONzD+VdCiDTIrZIoXeNpQsjA5Zd3G4+vPWqi1zakVuaUXY1YYVXkinSqAMrSyLNBxJGR79qh8zJxXXY86x//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-43.png', linkedinUrl: '/in/donald-khan-5aae10186f', jobTitle: 'Surveyor, rural practice', }, @@ -1435,7 +1435,7 @@ export const peopleDemo = [ city: 'South Katherine', email: 'spencer.lee@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDoglYfijX4/D+nrIFV7iU7Y0Jx/wACPsK6MJxXiXjC9uL7xNfLuyEkMaZ/hVeOPTmsDewy41bUNRuZXuZ2kXAbHYfQVlm6LTOoc+WwxhskD3zXZ+HfBT3Olfa52dWf7qgcn3q1J8Mry6O8yeTGeVQjms+eNzo9jOyOCa7a28vL8DptODXqPhXxVFqMMFnd5W4K4SQ9JP8A69Ul+GKQxFppt7AZxiuO1rS9R8PXEcysfLEmUI7Ec01NN2RMqUoq7PaSlNKU3Trn7fplrd7SPOiVyPQkVY21ZiWwvFeFamw/4TS/DgbftjBs+gaveR0ryfxBoTT+IrfUighF9NhkBzhgcZ/ECplJLRmlOEpXa6Hoek7UtYlXptBGPSt0SHyx82QPauWu7m706NVtIHlOMLtFUdL1vXrm6jFzaeXHLwARgoM45FcqT3PRutjrrksY+OnrXnHjthFpZkGMhwRkVs+Itb1m0u2tLS0aUpjcw561h61Fc6pocsdwhWRZFByO+4fpVRWqZFR3i4o63wtGw8K6YWBDGBSc1qlaTTj5ml2rbVXMS/KvQcdKmZa6TzmrOxMBWBqmnKzTTOgYrtMZx9zBzkV0C1HeW6TWsgZckKSPrSnDmRdGr7NvsyrY3EUsYikAPbNSTR28MipEqBzydo7ZrIsyHYENjPamX9xY4w+opbTBs7/OCnPYY7j2rlSex6Sa3NGeOFtXmjmUEHDLke1Z2pJFI6W0aZ3MPlFZ0Vwkl2zS6nHeTZAyjg7SPYVr6XELjU2kcZ8pc/j/AJzVKN5WJnNRjc24ohDAkY6IoWgipTUZrqseVckUcVzHjbXb3SbCJdMKG5d13hlz8hOD/P8ASs3VPGNzM5h0+Pyk7yH7x+npXP3Nw9ypaR2YtwWY5Oa0URHV5a1YZYANhgT69xVm5tpLu0Ux2sMzjtIBg+9c/p/iCC5t/sOoFUmxtV2+7J/gamN/eWR8q2nXA4CzHGPx71w8ri7M9SFRP3o7Fr7FJbAyy28EJzyEA/Mmr/hXVbS5uL+034u4XXeGP3lIBBH51gG+uLje93KoiTk4Py/nXGC4Fzq89zGxUTSNtYccYwP5VtRV5XOfFTvFHu5NNNeSaJ4p1DSJJQ0huYuhjkY4B9Qe1el6TqkWrafHdRDG4fMhPKnuascaP//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-44.png', linkedinUrl: '/in/spencer-lee-030eb9cd9d', jobTitle: 'Multimedia programmer', }, @@ -1445,7 +1445,7 @@ export const peopleDemo = [ city: 'Powellshire', email: 'katherine.parker@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDvKKKxPFfiKLwzocl8yh5SfLhjJ+85/oOpqhFLxh4ztvDFuI0VZr+Ufu4SeFH95vb+deVar4o1rWl3Xt/IIxyIof3aD8B1/GsW5u7rW9UmvLyYySyHcz9PwHoBU1lY3OosYrWB5D0HpWUpGkYjtP8AEOo6LeC5sruVWB5Vm3K3sRXTWfxU1xZA8kVrMin54ypUkexzVS2+HGrTjzJmSPPbrWXq3h650O6G8bo271KqLZMt0pLVo920DXLXxDpUd/anAbh4yfmRu4NaeK+cfD3iS78Mayt1bMzQFsTQ54kXuPr6Gvom0uor2zhuoG3RTIHQ+oIzWydzFqxLXjHxa1SS58Q22l5/cW0fmFR3Zv8A6wFe0V4P8ULSSy8az3DnctzGjx+wA24/MUS2BFLw54X1LxDIDbIIrZW2tK3T3A9a9l0Hwxa6HaLFGm9/4nYck1ynhmE2fg/Ty0NxI8iM4WJ9gByTnPrXS+G725uUxIbgJjIE5yR7ZrhqSbPRpRUfU2pUwhAXFcL4401r3SJTBgyx/MoHf1Fa2uS3EryOVuZYolJ8qJ9oOPpyTVG023abVtJrdgPmVmyCCP51CVveNG7+6eIE5Jz+Ir3v4X3xvfBUEbNl7aR4T9M5H6GvFdesGstbuoVU7Q5YfQ816b8GZ5DYanbEfu1kSQH0JBB/kK74O+p5klbQ9Pryr4vaFczNa61Chkhhj8qUD+DnIP05r1amSxrJGyOoZWGCpGQRVtEo53wjGknhjTkcDIgTj8M1qSNBFcrEjRpgEntzVeC1Fk/kxII4x9xRwAPQVVuL6waTE9pJKygjPlEkA9cGvNkmpNHrU/eimizpskNy0qFlY5yOcgjNLqCx20RKgDjtWfZ6lZJceXb27xMx4HlEVLqjl1OT0FS9NCmrHl3i3TWK3OpFgEKhDn1rsfg/aGHw7d3JHM0+M+yj/wCvXnfiHVr3WNTfSYcNbJPtjRF+Z26c+vOcV7f4W0b+wfDtpYHHmIu6Qju55Nd1FNLU82vJOWhtUuKzNV8QaVoq5v7yOJiMrH1dvoo5rhNX+LIBMWkWOSP+WtyeP++R/jW5gegas0VvZNdSyrEsX8THAOeMVQRbe8T53KkcHnBFeNav4p1jXdi3t4zR+YpWJRtQHPoK9clsFu4gQxVmXh1ODXFiUlJM7sLJ2aG3JtrEbw+T7nk1l3F014dqk7TyTThokiSnzpnlPbcc1PLbrbW7YHIHWua51N3Oc+GGn6Tc6xqdzJETqdpM23c2V2kkbgPXt+Neq186QazcaV4jl1LTpNj+cW46OM8g+oNeveHPH2ma9H5czLZXgOPJkfhvdW7/AE616ky3Z//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-45.png', linkedinUrl: '/in/katherine-parker-87afc741ec', jobTitle: 'Arts development officer', }, @@ -1455,7 +1455,7 @@ export const peopleDemo = [ city: 'South Jasonberg', email: 'amanda.jackson@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-46.png', linkedinUrl: '/in/amanda-jackson-31a0288c40', jobTitle: 'Engineer, energy', }, @@ -1465,7 +1465,7 @@ export const peopleDemo = [ city: 'South Paul', email: 'kimberly.lloyd@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0FnA+lYt94msbKQozF3XqE5rnvEXimYQulqdsZO0bfvOa4yW8khHm3b/vD0B4C+w9/esJVdbI3jS6yO9uvH8VthRb5kPIXfkj8AKgg+IkJlAuYGVCcFlOcfUV5bdXb3cvl2zne5wdvCj8epp0PhXVbyUi3XMY6seA1PmfVhyJ7I9+t7yK6hSaGQOjjIIqcmvLtFuNY8IRiTUiZtPICyBTkxf7VehWOp2+owia3mWSM9GBq1JMzlFx3NEGnA1EDTwaog8QlmmUSSSsfOPRF/gH9Kw2WYlpZnk57Zzmp5dQMsZKARxAElm5J/xpmlW39u6ksGXKLhmye1cq01Ozd2Nfw1oMuoz+eyBYB6dDXptpawwQhUI49Kw7hzptmtva2ckvGOF+Vfc1h6U13c3qu0JhMuSPL+UgA45FT8WpurR907HUrcXNtJG6hkZSrA9wa5rwLPJp9xdafI29IZzHgDlR2J/SneKbu/tLi0soQ584ZLK238M9qt+CLeCW/vdQKujvtTy5OoOAcmtKdzCvY71adj3qHdTgxrc5D512l42UqQh+6uOgrW8DCa01cpJGQkueSOmKyY7+GG6VpnY7+MgZI967jw/DEZzIAQR8uD2BrlnKysd1OKbvfY76F45U2lQcjvVdlsbW5jRI0Esh9hTYUby8qecVnT3VijyR3IeWXGWCoWwPSs43ex1NIt6otjexxFpIyyNgYOcVFZWoN0zxfLyCWXrx/kVzzS2XnmOG2ltw33QU2jNdN4cnjnSZAf3kbbGBrWC96xz4jSJuqTtGetSocim7eKVQRXSeefLsm3zPmOHznPWvUbBZYIYrqIFgyDeBTbbwBaXGyaXKRqCx2H5j14J6dq3rezSygMIbcqHaCRya5arvax2UNG7k1rqqzRAJIAw6g9avRJ5kRQSqMjnPeucu7BXUzQna464rNkubizheWS4YIilj7AVlHc6WzfvLeKxgkmkmDIil2z6DmjwfHIzR3TEk3BYn2OSa4OHWNQ1p/KlRhZnBkMaknbnvXq3hDTpbfS0adNqhiYgVwSvqRXRGLuctWopI36cop4f/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-47.png', linkedinUrl: '/in/kimberly-lloyd-851cd20ebf', jobTitle: 'Armed forces operational officer', }, @@ -1475,7 +1475,7 @@ export const peopleDemo = [ city: 'Port David', email: 'eric.hunter@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1ykJCqSxAAGST0FFeb/FLxFLBZjRbGVlmlG64Kddh6L+Pf2obsCVyTXvivY2kr22kW7XkgOPOfiL8O7fpXH3PxY8RuxCG2iX/AGIRx+easeH/AAPbSWUU+ouzTOAdoOAtb58E6GoyIGOep3VzuujpWHbMHTPjJqVtcxx6paw3MJPzNGux/wDD9K9c0fWbHXbBLywmWSJhyAeVPoR2Nea3PgfRmQt5R47ZrJ0u8m8A68l1AGl0m5xHcR9SnPDD6VUKyk7EToSirnt9KKYjrJGrqcqwDA+xp1bmAleJeKCZviFemT+GZQR9AAK9sHNeO6oYr7xpLexxn7LPJkHHO5Bhs/lWVWSSNaUW3c6K0fKhc8Cr+5COHyfrXCa2JnIZGutmCVSHjp6n1qpob6it4iNNc+S5BxKc4z0FcXLpc9Dm1segT7fLIL44rj/ETqlm4cbkPB9qo+I7jUDcyRwy3Cxx/e8kc1UtknltLiCR533Rk4m6g4qoxtaRM5XvE9v8PyCXw7prqSQbaPr/ALorRzWL4TKjwppqqSQkIQk9yOD+ua2c13rY81qzsIDXm2tae1lq8u3iFHJRf97Jz+tej1heJNKF5avdCUo8KZ244YDn8KzrQ5o6G1CpyS16nM23l3EZVgB9RkVEotIL1Y8xqqkEliOWPpVVZSg+XpgnNZN1eWmors8ssUJ2uIySD3ORXBFN6HotpGxN9lk1mTDIyv6HPNQ36QRKVRQrEYyK5uOS30+8LIxYNgMzgg/hmuhsYTrGrWtoxISU8sOoXqf0q+V3SIclZtnpOgwC20CxiHOIVOfc8/1rRqG3hS1to4IgQkahVyc8CpM16CVlY8uTu2xa4b4mXFzFolr9nV3DXaIyp1bIOP1xXYkszcscVT1PTV1PTpbY4DZDxk9nU5H6iom7qyLgrO7PNJJWtW2yvsU9Gx0qwUiazCpOIQBgbRU+o2+8NG6bWGVZWHQ+lcjfpeQsViYBcYHqB7VwRs99z0neOq2NW5SKOJi86zH/AGqv+ENTjtvEkSyLuZoGKn0UEA49+a5Wzt5pWxcNuHfFbfh2E3PjXeo/d2toc+244FawtzGNS7i2z11NRtX/AOWoX/eGKsghhkEEeorlnhyyv2GBj3q1DJNF8yuRjtmurn7nAAAAAcXIf//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-48.png', linkedinUrl: '/in/eric-hunter-a131354d18', jobTitle: 'Call centre manager', }, @@ -1485,7 +1485,7 @@ export const peopleDemo = [ city: 'Port Davidberg', email: 'ashley.taylor@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0csDQpApAuacEyazKBpVRSzMAB1JqhPqe4bYGVf8Aaf8AwrhfHXiq4tNW/s+yVSYQNxboWNZ9h4X8T6/tubm8Nqh5ABOa5atWTfLHQ6adJWuzqdR8TXMUpgsJVnuRglFBPB74qe21PVEQSXrklu4Hy/8A1qwRoOr+HpmmeRLuPv8ALzj1pW8QLBtL58qQ7WVjnBrndSadrm3s49jtLbVgGVZmB3dMf09a14nSaMPGwZT0IryVtUK3AQOTExyhPY/411PhzxBGl0IJnAWTgntu9fb3rajXd7SMalFWvE68LTJH8pHcjhQTU/QUwqGHPSu05Txrw/bHxT47mvblcpbs0pjPds4FexwIEQKMdO1eUx20nhzXdfWOGZyzp5Qt2wxDEkfTFdP4V1G/1CJluUmj2xF8zfe69DXC00z0YWaOtngWRCpAbNeb+LNBktY5biCMNE3348fqKn1W+1i3v/NigublAQNqSbQRW5BdyalD5U1vNGehWQZ/I9xUtX1NPI8Wa+aFMoxeMHBBHIq/Y60XmQ5w4754an+MNEbRNVaVYy1rcdh/C1c0scqJJPHE/kpjcW7Z4q+RSRg207H1S3NNApRS12nCYU1okevXU8kYIuYowD/u5B/pQ2o6bp8NxvmjiIwGJIAH1Par2qRbrdXHVW6+xrmbi70j7Rta0nnkThjFEW/M/jXJUT52elh/egjds5bS6VyrRkr6HII9aS4u0gUqsYH0rNt9R0+YCCzR4pB0Voyh/HNPniLNg9e9YSbWhvyoxdXthqe1pQAsTbt1cX4qs0sfDiDyUS4uJPKjCjBYHB6fhiu41i/i0q0e5kiaSOIbmVeuAK4bQnvviN44tZWg8rTrJhIUznauc8nuSQK0owcmY1qijF92e8AU4LS9KWu88sr3cDTWsiJ94r8v1rl47aFsedK0brwVHHPuK7CuI8T6/pH9rWmmwAPfTswMsZ4XaM4PrWNandcy6HTh6vI+XuaMkkEEQHm7gO57Vny6kjfKjBmPpWYtpJLnzGZlPQZq/a6eIyOK4jvuY3iyCY+Eb+QDL7Bke2Rmr/wi8MPo+kz6lcPG017jYsbhgiD1I4zn+VW/EXkp4dvY5iAksTR/mMVifDLVIdFVdElkxbynKOe0nfP1rrwy0WcOK3R//9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-49.png', linkedinUrl: '/in/ashley-taylor-4aa9cb790c', jobTitle: 'Arts administrator', }, @@ -1495,7 +1495,7 @@ export const peopleDemo = [ city: 'South Anna', email: 'michael.ayers@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwBmKcBSgU24mjtLZ55jhEGTSuOxDe39tp8PmXD4z91R1b6CuW1TxVcIoMG1B/dHJ/E1gzXs+s6o80nKsTgE4AA7CoL61lZg207VHYYArGU22bxppK5oJ471RAU2QsT/ABFeldHpfiv7R5SXkarvOPMTgA+4riLXRbu7O5ITgZOMdhVu2geGCVJSVIByrDuKHO2zGqV90eokZpm3NYPhTVDc25sp3BmjGY8nO5PY+1dHt5rVO6MGrOwKK5nxzdm3062twcCaU7sdSAP8SK6pVrifiFDM0lg4X9woYFvQ/wD6hSlsVDcwtF069umWW2hZwOPlXOPwrsNH8N6rJd5urR0tx13r1qt4eg+yeHYZTFPI8xYoI3K498+vFdd4bv74mNZ5JzFIMqJz8y/WuSV9z0KdlZFeLQ5tNncCDzICdykdu2K4zxXaS2jOzRkb+/tXbeIbq7maRopLhYIQcpC2C+P/ANfrWJJCmoafIv2aaJ0XLLIxYMCPcnBpJW1Kk7+6cHoc0ltrFk6sQPOUdexODXrRXBryOyB/tiytiCCJlX/x6vYWXrXXDY86puIoqhr+lHV9HltlwJDhkz6jtWioqUVTVyE7FXw3HGmlxWksYVohgo3Y1pyeWNQiiUouFLYzisqKN7e/LBy3mHPP8qbdajp5vfJuo3eVcgBVOR+NcTTUrHrU5KUU0amnmG4lmU7CwP1BqDWmht7N1QBeOwqlZ6jYfa/s1qrRuT90pj9ai15sQzMxyEFLrYbskcvovhjzNYS+mcgRt5ipjk85H613JFZ+gpd/2VFJfLGtzINzCMcAdh+VaJrtgrLU8upJSlpsMFPBqMU8VRmRXYxAZRwY/mzTYraHUVWX5TIR97vWf4i1F7ax8m1ljFw7AMpwTs7/AE4pIbe6ULJaXAjV+oYZANctaylc7sK2omo1rHp+Zfl3AYzWNe3CzzIJWAgDgyMxwOTzVw6fezvi7ulYddsdZviIW62hsYnUORjA5x7msk9ToldpnRxTwTR7oJY5EHGUYEfpQxrjNFvhozNF5e+F8FiDgg+vvXTQapZXR/dzrn+63yn9a7IzUjzJU5RZ/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-50.png', linkedinUrl: '/in/michael-ayers-a7a9c15b39', jobTitle: 'Community pharmacist', }, @@ -1505,7 +1505,7 @@ export const peopleDemo = [ city: 'Port Rhondaton', email: 'stephen.fisher@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0zFBIUEkgAckmlrl/G2r/AGDS1tIz+9uvlODyF7/n0pN2VxpXdjN1vx/FBcGHTNsix/flZeD7CuUuPFF1qd2WluSJB90k8L9AKXTNHfUA4ZQAGwTjPPoK24fAdsyncWyRjNYSqdzpjRb2MWDxB5FyFmkk81OkgPI+ldTpPjF7SbyNSZpYW5Sbqy/X1FZT+Boy2WkkLL0JrG1qxe0TDPlk4PbFKM+wSpNLU9ljkSaJZY2Do4yrDoRTq4r4da097psmnTn97bcp/uE/4/zrta6E7o5mrMWvO/G5DeJrdc4224OT2GSeP0r0SvPfiDazf2vY3CAFJIjDx1Bzn8uRUz2Kh8Rc0GBYbRFUcjqa6eJvlGea4S7ubyyURWvm7guR5a5JwKv6DqOqSyRxXRYh+dzLtIrjt1PRTXwnVyEHtXP6vHEUdmjU5Ug8dRVTWtQ1NJXW38zbHkkoM5x1+tVLO6uLwlZxMuVyVlXGPpTt1BvoJ4QQQ+Litvt8poG3j/P4V6PXmngq3lh8YTbgdpjcA+1el11w2POqKzCsLxVZi40+OVRmSJxj6Hr/ACrcqO5gFzayQkgbxgEjOD605K6sEJcskznNOEM8C7wMgdaeZbYahHFGyDaeeQM1mrbz2l3JbbslCR6ZqlM8VxN5Uun3TOgwHVAOPY5riSd7HppppNG9DNavcvFIyEs5AOcjNOvxFDGdowcVgW/l28xiisLlN55Zo8/iSK07lJH2KSSTgY96GrOw3tqWPCloqz3FwynfjAJ9Cc/0rqKqadYjT7cx797E5JxirZrsgrRszzKslKV0JS0yWWOCNpJXVEUZLMcAVy+pePNNtHMVorXcnqp2p+ferMx/id47S9hmVwJJFO5B1wO/64qrDJBPCpL9R1BrlZdYn1nxSl1NtVXhaIIucAAgjr+NXZtNuSSbSfy27qe/vXJVSUzvoSfIjonMFvHkSYA7k1kX2urYWx1AL5kdsyuwP8XI4quml3xVftVwHB/hFQeJI4Y/D8tscfvcIPc5B/pUK3MrFzb5Wem2d5Df2cV1bvvilXcpqavGtK8Ralo3yWsx8rOTE4ypP0rtNI8fWd5iO/jNrIeN4+ZDJ5p//9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-51.png', linkedinUrl: '/in/stephen-fisher-696b8604f2', jobTitle: 'Equities trader', }, @@ -1515,7 +1515,7 @@ export const peopleDemo = [ city: 'Calderonshire', email: 'kara.james@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDXwK57xH4vsfD48oD7RenpAp+77se386veI9U/sbQLq9UgSqu2LP8AePA/x/CvEZZ5ru6aed3klc5d2PJNKTsOKudbJ47127lypjt4uyRp/U5qgde1CS7Mj3lysrHcH37a6Hw34U/tSFJZcxQHpgferrpPAWjXESpJFJuAxvDYNc7qK51Kg7HI6f47u7Z0XUEW5g6NIgw49+ODXcWV/a6narc2cyyxN3HY+hHY1zN/8MoIlZrC5kjbsrjI/OuZ8PX114X8U/YrxCI7giJxnjOflYf571pCpd2M6lJxVz1OgAGilFbGBxHxQncafp9uM7HlZ2P0GB/M1yfh3T4b27jWRdwDdD0Ndz4/0+TU7G1itmTz4maQI38Qx6/41zfhZGsprhpLaWR4/lwgGQfoTXPVlvY6aMHdNo9S04J5CKuBtAGB0Fa4B2cCuBudUlgg+S2uXDZwqLg8f1p2i6jfQNvn89YXIO2VskZ6D61zW0udt9bHcTD5eRXl/wAQrOPyYLxFHnRSj5vbPeug8UavewyNDbmdVRQz+WuW59MVzd60mp6a1swmUghn83kjHPH4Zq4KzTIqNOLR3MT+ZBG/B3KG49xUgqG2Km0h8tWRNg2q4wQMdxUwNdx5hV1CINhxkMVKbh2zWH9lS1vJPL53kFj3JxjmunkQSRlTx6H0rlzd3E+r3sN1CsXkuEjZf4xjO6uStBp83Q78PVTiovdHR2K+emBtB6nPIo1D7PaKDPLEuPmOQFUfjUdirLgg8kcUXusabHmK6gknI5wsJbn8qxjqdTXYkma1m1CExzws7xcjrmqd/ZxmVI8oAWydqjBqpbajo/23ZawPDIR/y0jK5+mavENJejcMgDJ9qpJ8yRFSyg2y30FANIaQGu88ksAVkavaqblHVQJGTkjvg8fzrVnllgjR47Z5gWwSpA2j1NZ26a61HdKAAF2qB2rnrzSjy9Tpw1OTlzdBljebERZDgqcH6VrrAlyo+cYPQ45FY1/YuoLoufUCsg3OowHZCHYdhXIjvudDd2kdsTIXDY6E0WisymZxy/T6Vz00t5KD9qkIVRkiuphZHhRoyChUYPtXTRSbucuKm7JdxGpt4D//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-52.png', linkedinUrl: '/in/kara-james-5cf607e6c1', jobTitle: 'Maintenance engineer', }, @@ -1525,7 +1525,7 @@ export const peopleDemo = [ city: 'South Toddview', email: 'gary.lamb@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1Oql/qNnpdq1zfXMdvCv8cjY/Aepq5ivB/Geqy6z4hvBcSMYYHaKCLkBccZ/E80noCNzVPixcy3LLplvHFbqSA8g3s/vjoBWA3xO1vzmD3UoJ6BUUBT+XSrmmfDtbiySSa5ZZXG7A7VG/w0mWYMdQVsdmWsvaxN/YT7Gjo/xYvLeRI9VhS5hYcSphHB9+1eqaZqdpq9kl3ZzJLGw/hOdp9D714zN8N967jchDnkLU+kz3vgfWoBHLvsZmAkBBxjoc/wCNEasW7ClRlFXaPa8UYpQQQCOh5orYxHd68JmtFvdVkuiBzOzbR03FjXteqX66Xps14yGQRgYQdWJOAP1rzOxsGj1eT7QQfvzJgY6np+FZVJJaGtKm5a9DorYt5KKeGCjOKmk6Z3AmuV1h7tpNkT3KoBwIeOfUmsjQ73UpL1IpJbny3P8Ay2IJA/pXLy6XO9S1sd4yll+9iuW13BTY3I3cN6GqfiW+1KG7e3t2kARQxMdVrFbq4triG4mmcmPIEvVW68Gko2tIU5XvE9psQ40+2Ehy4iTcfU4FWKqaVdR32lW1xFnYyADPtx/Srdd62PMaadmU9ZhNxo9zGoy2zcB9Dn+lcHaRtCiNIS1wcl3Jz1OePbpXpFcZrtgun3qOkhZJQSFI+7g/rWFaP2jrw9RJcjITGLgEcqOh6c1ViWziuZEiVSyY3PwOTT3mb7M+3rjNc9d3FhLAY3Dko3LrGx+b1yKwSudd7I178WzX6tIV2vhSRg4Pai4to4SEXkkYB7VzcM1kZ22zPJIQFJkBH5ZrobKKS+vre2ycuwGcdB60nHWwOStdnoemQJbaVaQxDCLEuB+FWaFUIioOigAUGu9KyseU3d3HVyni6eJpre2Unz0UuR/snj+YrctdTW6uJlTAjix9WzWL4ltPNUXyLukiTY+OpTOc/gc/nU1E+V2NKNlNXOYaVhGY92CeCakeEi32xyrGAMA4qnOA7B1PWqFxcOhw5ZT2xyK5Ed92i5LbEKTJIsldT4M053d9SlHyjKRe57n+lcHBLJMxJdivvXV+EPEP2LS7wzq8ltFMSNoyVBOOPbjP41dJXmY4iT5PU9CoNUrDV7DU41e1uFYn+E84T//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-53.png', linkedinUrl: '/in/gary-lamb-c0f66f8f75', jobTitle: 'General practice doctor', }, @@ -1535,7 +1535,7 @@ export const peopleDemo = [ city: 'Laurahaven', email: 'james.griffin@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-54.png', linkedinUrl: '/in/james-griffin-8a5e63d24f', jobTitle: 'Public relations officer', }, @@ -1545,7 +1545,7 @@ export const peopleDemo = [ city: 'New Brandonton', email: 'wanda.chambers@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDs/EviCDw7pbXUo3yt8sUWeXb/AArxu81K71i9e61CeVnc5EaHhR6Cun+J0rnxFbRAb9luCqk8KSTk/jx+VcOb57aTcxQueijp+Nc1Rtux0U0krmtb3EFqd5juY8dJDyR+FNvrlblDLG6m4OM+j+hFX9C0G/8AEDCfzmjj6ema7C0+G9pEmZJ3Zz+VSjRxPNrHVpvMMMqGVyfutwFruvCHin7FcDSrw5hkP7kg8oe457Vc1L4c2byedA7LJ3wa4m90qXQfENsXBCls+YemO+aalZicND24HPfinYqKFkeCN4nDxsoKsO4x1qVTW5zHjXxLllHiq5KkrlEUD2x1rmtBsUudWjhl+ZRgsvrXofxM8PzXeoW9zBuZpIyD6Dbk/wBa57wFpeb26uJcEqdo781jJ2udEIt2PTtLt4ra2SKFAiAcBRWymdtcVfavNp6GKOG6kkIO0RKBj8TUWl6rrguo0uAzRSgEFsEqD6kd/as1orm71djuXyy1wfxBtBPpSbR++85VQjrk8YrR8T6rqunkQ2UTOxUMWXt9Kx5Fu9Rt7RJhcLLHexZMjBgxz1BHFUld3JlojttEsH07RrS0kbc8UYU1ogUZJGcYzSjpXQjiKOvWQvtImiI5Azn0Hf8ASuOtbBdMuS0KBUYLkeuO9ehSIssbRuAysCpB7g15zpumXWk3up2dxJNJDHPi281icRYyAM9qyrR6nRQqfZZ1du8F3HiWNT659aW4FtARDGi7yNxx2FZ9sjoPlPbP1pl5caROnk3cm585OASf0rGOuh1WRsXK27SQmcKwdQBnnmkjggmuY4TGNsbeYPQEdKxYH08gxR3DSP8AwF859sZrf0mMlZJH+9wtaRV5JGdX3YM0MClC5pcUorpOAZNKIYWc9un1rgrKbWbrWtUh1WbzIoiv2U7QMqcnt+X4V1lyZJgSx+gHSqDx7nEgH7xRg+4p1aTcNNx0ppT1M2O7Fu3lyMVwe/pWgoSZAfNAHY45FVLq0S4XPb+VUoNPuEm2Cf8AdfyrgW56NzYNuqDasvmFjgetb1pCYLdUbl+rfWuB19Lm10+2ntXfzI7qM4z94ZwR+tdzBcObdJH5GBk+ldNGN7s5cRN6IuGikByAR0PekzUAAAAGpzn/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-55.png', linkedinUrl: '/in/wanda-chambers-8ea5f97b07', jobTitle: 'Advertising account planner', }, @@ -1555,7 +1555,7 @@ export const peopleDemo = [ city: 'New Meganberg', email: 'lisa.kline@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-56.png', linkedinUrl: '/in/lisa-kline-513a938279', jobTitle: 'Actuary', }, @@ -1565,7 +1565,7 @@ export const peopleDemo = [ city: 'South Ronald', email: 'jason.roberts@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-57.png', linkedinUrl: '/in/jason-roberts-a33d0ea932', jobTitle: 'Tourism officer', }, @@ -1575,7 +1575,7 @@ export const peopleDemo = [ city: 'Port Kevinbury', email: 'john.mcpherson@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-58.png', linkedinUrl: '/in/john-mcpherson-0d3f263d26', jobTitle: 'Editor, magazine features', }, @@ -1585,7 +1585,7 @@ export const peopleDemo = [ city: 'Brandonchester', email: 'karen.rhodes@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-59.png', linkedinUrl: '/in/karen-rhodes-239af63ac9', jobTitle: 'Commercial art gallery manager', }, @@ -1595,7 +1595,7 @@ export const peopleDemo = [ city: 'Meganhaven', email: 'kathy.sparks@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-60.png', linkedinUrl: '/in/kathy-sparks-3dcdea4c5a', jobTitle: 'Engineer, production', }, @@ -1605,7 +1605,7 @@ export const peopleDemo = [ city: 'East Bryanshire', email: 'richard.murphy@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0w1g+KvFVj4T0v7XdnfK/ywQKfmlb+g9TW9mvnv4jX1zrfxAurZmzDaEW0Q/ujjcfxJNIZn65488QeIp5GmupYLcnCW1uSqKPQkcn8a54QSEZaNs9eleu6R4e0y1tIkFtGxI5LDJJroToenXMAV7WIjGB8tcrxSvax1rCO17niGleJdW8O3om029liwQTESTG/qCvSvefBPja18X6bk7IdRhH7+3B6ejLnsf0rnbzwPpBiP8Aogz65NcuLFvB/iSx1bThtiEojmj7FGOD/n6VcK8ZOxE8NKEbnuJpKcaZ3rUwJc18965bt/wsXVMZLteNgY/GvfrlpFtZjD/rQjFPrjivHGiNx4j+3XLh7l4v3zYx8wAAP5VFSfLoaUqblqdFpx3KE7jvXRQpIsQHB9MVwF2reaVeG7kUDKrbkAn8T3qXSbrU7e6SOD7YIZAG2XJBZQfcdD7GuLk0uehz68p3NzHM0RUfL9a4DxWrvYTx9SAOh96u+IbzVGleI/aFiQZcW5G8+wrMgtcxyL5dyANrMs5DE4IOAR+VOEbWkKcm7xPZLdWS0hVzlljUE++KUnmiORpbeORl2syhivoSOlNJw1d55hJmvNfEFt9h1GRBj75Ycc4IyK9J71ma/YJe6PcAIplVNyNjnjnGampDmRpSqcj9TlbMw3tssciDdjhu1XIo7eGcQRKrFMM7gBQCa5m3d4WRkYlDyBU9xe6PehBc796HqhbIPrxXCot6Hpcy3Oi1GKCTUG8wKY5MAtwQDVZoLaK6t7eNA26VQQO4zWDFPpEEpZJpJJnG3dIzc/TPFb3hm2+164JJRvEKluex6CnGD5kiZzSg2dywxwKhfrUzGoJOlegzyiXFcP8AErxHeaNpKR6bP5czMDKVGWCdPwzWhqfi8IxjsIw2Ossg4/AVwmpzvqUkzTtvaT7xPeqsBSN3LbAbs7Tgg+hrXtZo7mISrefZ2XgMo5FV1tlu7RS3LAYYe9Zc2l3Mcn7h2UH0rzr62e56ava6N2cokZle9+0nszgA/lXZ+A3s59HknglMlwZCs+eqkHAH0rzi3sJdy+a7OR3PrUGkvLZ3l+iuyAzkjBx7/wBa2o2czDENuJ7o3Wq8zbRXnll4i1O1YbbppEHVJfmH+NdDb+KY5wFubcoe7IescZ//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-61.png', linkedinUrl: '/in/richard-murphy-66d2f794a5', jobTitle: 'Osteopath', }, @@ -1615,7 +1615,7 @@ export const peopleDemo = [ city: 'Gardnerhaven', email: 'nicole.peterson@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-62.png', linkedinUrl: '/in/nicole-peterson-2d8cc71386', jobTitle: 'Production engineer', }, @@ -1625,7 +1625,7 @@ export const peopleDemo = [ city: 'Port Peter', email: 'bryan.ward@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDvaKXFJUFmL4j8QwaBZCRgHuJMiGL+8e5PsK8zvvEmsa5cZacrCOkKcJ+Pr+NdB46tZ7vxRYQwvudkAVMcIMnLH9f0p1p4KliYyRzoC3YLisp1EnZm1Ok5K6ORNxPLuinVkU8FFPT6etOt7rUrAGS2klOw5DDOfzr0ex8HWcK7rn97J6dhWpJpNlFC6RwIN3U4rN1V0NVh31OF0/4oXFuGXUrcTbcAFPkb8e1ej6Zqdpq9il3ZTLLE3dT0PofevHtX8P8A2bUpg6Dy5Mjd+v8AStL4e30um+IPsSyk2V0SoTHAYDgj34xW8XdXOaUbOx6zRilNHSqIOa1K13eJPNK5PkLg/ia1IU2IOawfGM0hgtrq2kuI+GX90vzN6cH8ap+GtTv7uN47nd8se7ewwce4rjqx95s9HDy91ROyUcH5uarXLEIVXk964LU9R1pLrAubjyCRgQIDn05rX07VL0OsNzHLIOn3fmH17VHLpc05ruwzWIknh2lgDuw30rH0DTjB4m09TGcGTfnPTHOf0rb1SGe9kiCIIFc4Jc5JP0H+NLo1idM1uxuL13l8wtEjqMIrEcDHXp3reE0rJnNOlKTdjt6BRQK6DkMjVYlMkUZVShVsZ7HNVdNgt4I7h98fPGM46Vd16Mm2jkXqrY49xXF3l1pWfKmuSgJ+aNQSGx2+tcdVPnZ6OHa9mjpFt7aW4+zfuwyKNpHp6VdWCK2U4GTjFYdjfaa0EcNofL5+TMZXn8a2m+VBuPzY5FZvQ20KznEgZgDg5o0ix/08Mo/c587yyc7W5/nmq1yzSFljcqwGQw7V0ml2xgsYy/MsgDOfc1pRhzP0Ma1Xki+7LGKMU6iu080gu7YXVrJDnBYcH0PauT+wzq23csTrwwNbet+KNJ8Pp/ptyPOYZSBPmkb8O31NcgviBvETXF8im2WIxoEByQrbhknvkgCsa1O65l0OnDVeSXL3Oijj2W+JnRvU1XmvCx2qQze1Yoe+dwhfcnTj0rRhtfJAYnk9jXGzuvcnt4SqtuO53rd0bUjdG7s5mBubOUxtjuvY/wBPwqtp8C21pJq11gW8ALKD/GR3+grzeTV7u3vpb63naGeR2csp9TnHvXZh4NLmfU4MVNMAAkorof/Z', + 'https://twentyhq.github.io/placeholder-images/people/image-63.png', linkedinUrl: '/in/bryan-ward-9146d84428', jobTitle: 'Interior and spatial designer', }, @@ -1635,7 +1635,7 @@ export const peopleDemo = [ city: 'North Ryanport', email: 'rebecca.howell@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-64.png', linkedinUrl: '/in/rebecca-howell-b51b44e75e', jobTitle: 'Engineer, electronics', }, @@ -1645,7 +1645,7 @@ export const peopleDemo = [ city: 'Port Nicoleshire', email: 'lori.bean@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-65.png', linkedinUrl: '/in/lori-bean-adcfd993d8', jobTitle: 'Designer, blown glass/stained glass', }, @@ -1655,7 +1655,7 @@ export const peopleDemo = [ city: 'South Mary', email: 'kevin.eaton@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0KgsqgsxAA6k0ZrmPHc8sPhubyiMnqO5xzxSGcx4p+JDx3D2ukcbDgynByfYV55qeuanq07T3FwXkc8qTgAewqrDZzX1wwiHJJyT2roovBFzMif6SBkZPy9KylUit2axpylsjk5ZZA2Q7b84bnrnvWnpmtX+lOHsbqS3Z+TsPWrD+FZ1vXTzCUV9u4jiq95pclsGQ8jnB9MU+eLB05Lc9F8F/EWS81JrLWrhV8z7krcAN6e2a9Pr5YZ5HYb8gjgsa+jfCWqx6x4XsbqMnIjET7jk7l4Ofyz+NWjJmvXE/Ey1upfD/AJ0Cl4YmDygfw46Hr7+9drWd4gsH1Tw/fWcf+sliIXnHPUUwPHfCVujwGQKCxk79q9EtoyqZK8AV5/BZSaXarH50+4E/6gDO78a39C1G+aeOCaR5VkG4bwAw9jXDNXbZ6NKVkonQPp8ExYtCPm6msy50O0EEqyIJU5ZezL+NZ2qahqCTCSO6uPK/55wgZxmrdpfTFgGM0nGGSRRn8xU2aVynJN2PM9WgjhlZk3D5yvX8q9l+FaIvgmMoSS08hbPrnH8gK831vRri68QS20ES/vgHRCc4HevVPh9prab4ThikKlzI5+Xtz0/SuyEkzgqQauzpKUYIwRwabSitDM83itlivbq1Z/M8qVlDeoFXdOt4xqjkbRsTv70niKE2fiOWRFws0YkwO56H+VYPnpJdtI06xykbSAx/WuGUXzNHpU5JwVjqUtYJZiOFbqv9anktooIicZbHWsG1u7a2XZC8R54AODn6VtyP5kKkk8rnFQ1Y00MeCzMmqTXe0F0VUjb05yf8K9AsIBa2EMIGNq8j371zHh2wuZtUe5YqLGNcBCMl5M9foB/Ouv7V1UYte8zir1E/dRHS0UZAGTW5zHPeLtNlubBby2UtNbAkqOrJ3x9Ov51x1rH9oUSRugZwDkjNeiahqqWdlcTIhkMSFsdjXlitPbP5sWAsjfMvZTXNWSTudeHlKx1CQJDCN2wsRzximtcFgI0OWPH0qjBZ384zJJGFbk7a1Le0SBMgdO5rnbR06yOk8O7BpgQMN+9sjPNaprhIrS4nuzHasVmk+6R613NvZzQW0cTyGV0UKznuccmuujPmjbscNenyyv0AAAAAAAAdz//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-66.png', linkedinUrl: '/in/kevin-eaton-16b640da6b', jobTitle: 'Higher education lecturer', }, @@ -1665,7 +1665,7 @@ export const peopleDemo = [ city: 'West Spencerville', email: 'nicholas.wright@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDoyKYaeTTTXIzqGs6xo0kjBVUEknoBXCap8Ro4zImmW4kwcJLJ0b3C1reKrme6a30OzZlnu/mlcfwRj/Gksvhlp4dJXuJHOACD3NUnFbhySlscC/i/WTKz/wBpTAFfmw2OfQf/AFqvaV8QdWgljFxcJLGnVJACWHu3XNegSfDPQmQjZJu9d1YGofDTT4YHMMzh/wCHIyM1TqQ6i9jPodNoXiKx8QQM9s22VfvxE8j39xWqVrwuze/0DU1nhkxJA+MDuO4PtXuNjdR39hBdxfcmQOAe2e1ElYSd9xxFMIqQ0h5qCjmo0Mniy+kYfMkccaH0GM/zNdhbD5Bh88V594lmurTVrhrRplaVY+YlySQpp3hXUNa1C4Nvc71Kxlw7Lgn61El1N6ctOU9ClJ5xJj2rD1KZghXBJx+dcRqWo+IkvZFSWYxLztiA+bnt71p6Ze3spENxFPyM5lGSPxpOOly1LWxxuuR+Zcs+OS3PavUvCSsvhTTwef3Zx9MnFcL4h0l7jWkSDGZY8kt0Hua9E8NNE+gW8UW7NuPIfcuPmXrxWykmkjllBpt9C0SDQBQATinEYoEZVzHbyXzxTIp3qDzUmlvp9o1zskijwu1eQPqao+IFaN4LgZAwVbH5j+tcvILXU5PNVLgrjawhiYhh6E96y5Xc6oP3VY7SNtNurj7NMYnZhuVhhgaddfZbGPbCqAj0rlbG7sdNQWqW7x7343RMhB+prVveuC2T3qZK2hd7lJolurpnJZJMbUdTjbznP6V1+kQ/Z9PUN96Ri7HHUmud0m2a71OMB8RrlpB/eHp+eK7DbgYxgVpTj1OetPTlKqAinEUDAFOrUwM/VbF7/TpYYyBJjKE+orjUhWYKs13JbSR/Kyrx+BFehg81yPjqwiR7aRE8u6kRmJHBYDGM1Mo6XNKc2nYrtJFBb7EuhL67utVWvDMwjRwxPeuUji1CVyryDaDzjiuk0q28kBnOWrF2RunKRsw6i2iqJlh83dhCM4PPpXZAyLGhmQxuyhihPTI6VQ8NaCNRnivruMfZoWDxKw++46H6D+ddbqOnm6VTHgOvr3FdNKDcLs5a8lz6H//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-67.png', linkedinUrl: '/in/nicholas-wright-6c27afa8b3', jobTitle: 'Environmental manager', }, @@ -1675,7 +1675,7 @@ export const peopleDemo = [ city: 'West Sarahshire', email: 'kevin.paul@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-68.png', linkedinUrl: '/in/kevin-paul-12c8e885e9', jobTitle: 'Health and safety inspector', }, @@ -1685,7 +1685,7 @@ export const peopleDemo = [ city: 'Stevensshire', email: 'joshua.black@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-69.png', linkedinUrl: '/in/joshua-black-08413d2634', jobTitle: 'Banker', }, @@ -1695,7 +1695,7 @@ export const peopleDemo = [ city: 'Kington', email: 'scott.bruce@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDgaiuJxbxGRufQetTY4rJ1B2lvEiTOUGT+NQaEE1xcXLkMSEbBCj8qbJJtjW1I+Q8se1dToXhGfUoVmmnEZblSBmt+P4bl2y93EVPX90cn9ah1YpmioTaueZRxvBKJFcCJ+oBq0LprKbzFJa3fjb/hXo138NLMJ+4uZFO3ByM1xniHwrcaVH5iMZUU4PqB9KFVi3YHRnFXJYpVmjDocqeQacazNFmLRvCwKleQD6VqEVZmLWbOBHfk/wB5c8flWpT30gXVtBegnAn8pl9jjH86mTsVGLex6B4djRbGEYwdowPbFdNE2FAxXG3UM9uiCLzzkfIsJC9B6mtDQL/Uf3QuTKUlGQJQNyexxXJbqegnb3ToZnJUgDNcV4t2rYyttz8pJxWl4gv9R2y/ZTJsh++IgNzdOBn61iNay3KTl/PDBP3glfcDkdvzppdQk7+6ef6Z+9vZpgPlK8fnWqRUVjpz2VjG7n/Wltv0BxUxrsuec01uFbugMJ7O+tGwcBZlB6/KecfkKwQakguZbSYTQOVcAjPqD1FTKN1YqnLllc9UsWjntkDgE470+4CrdwxooDE5IFZekTCS3jkU8EAj8qS9urW4uV851VkOQMnI/LpXGlrY9JNNGjaoGv7pHA4Oee9V9ZMUNjLsAU7T0qna3VvBcMbeVHLHJG75v161Fr1wBaysT0XpTtrYUmkjl9ZwkttCAoEUCj5emetZZqaeeS4lMsrbnPU1Ca7IqysebOXNJsZRxgk9KrTXkcZIHzH26VUmu5pFO3Cr3HcirUWyGztPDGqSJYhpD+7EjKD/AHcHj9K66NY7uJWDKGI4YCuA8GXlvJLJplywUTHdET3buK6k6ZcwHZBcmIg8K33TXFUXLN3O+jK8E0ackUVsjOXUsOrEVx/iLVN0UQB/dPJhm9Titi40u7kKpcXKy7uqp0x71z3jBYreC2txjduyB7AU6dnNCrSfK2yhmmk1hGaSFgY3I9u1WodRc8SKD7iuzlODmP/Z', + 'https://twentyhq.github.io/placeholder-images/people/image-70.png', linkedinUrl: '/in/scott-bruce-f345ae71e4', jobTitle: 'Educational psychologist', }, @@ -1705,7 +1705,7 @@ export const peopleDemo = [ city: 'Brownfort', email: 'ebony.nixon@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-71.png', linkedinUrl: '/in/ebony-nixon-6ce991d391', jobTitle: 'Arboriculturist', }, @@ -1715,7 +1715,7 @@ export const peopleDemo = [ city: 'Kathrynton', email: 'jesse.hartman@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0jFGKWszxHef2f4a1K7BwY7dyCD0OMD9TQBx/if4p2OkyyWmlwrfXMbFXctiND9epryTUvEmqazefaL27kkkyQMNtCqew9BU/hrw++u3rEyGOBPvuByxPYV6DbfDLTHi2vJI2TntxWUqsYuzNoUZSV0eTfafKmdonkB6hw3OfrXaeGviZqujW/kz5vbdcbY52O4f7rf0Oa7WP4a6LCfMEBbHqeK53xZ4Gtls5LmyykkS7tueCB1qfbxvYt4eSVz1Hw94isPEumreWLtjgSRuMMjeh/wAa18V4N8K9dfSvFa6bPkQ3y+WMno45U/j0/Gveq3RzBXK/EeGWbwFqQiOCqqzD1UMM11VZ3iFI5PDepJKcI1s4J/CgEeU+BYQumKVXG9ya9It4z5QIbPtXmNslxY6LaJE0qsY+sQ5J655rX8Patqst1DBcmRhIMqWUBvxrinG7cj0qcrJRO/PzJ9/Fc94iLf2ZcLGCzeWeBWDq+o61Fcu1vNKIVJ+WNASwBxj61bsL64eTZcLOWPVZFGR/So5epfMtjzrw0jnx9o6xDkXiH8M8/wBa+ka8S0/TTZ+Pn1RwEtbCXzmQDLMCDgD869tBDKCOhGRXdCSaPNqQcXcKralCtxpd3Cy7leF1IHfg1Zo6iqJTs7nm+mQAwLC3DKAMEZAxWhYQwxa1H5hjXywSCSByetR6lb/2frM0cYIQncv0Iz/jWFLJBqNzvcyJIuQGjjYkfiK4Wnex6cWmk0dR5EL3TxoYmR2LrjB571M0EVvH93msGwvLLS4zGkLqHcEl42U59ea17yUsAFPBGSfSoaa0K0KGn2f2rUbh1ypeUI/feuAMV6D0GB0rmvCdsht57lssTKQmTwOOtdITXZRjZX7nBiKnM1HsKKKKWtjA5vxdpzzWX26AfvLdTvA6lP8A61chatFe2qf6YYeMgp1xXdeINXtrGwngZ1a5kibZF1J46n0ryua0Ygy2szRb+fl6ZrmrJXudVCUraHXSSQ2tgUW489iMfMP51RW8e8dIIW3Z+8R/CKwLexvLhiZZSNvBwetdLpdutrGCRzWDsjdOUnqO8OXs9t46v7NCxtxZxMUPTOSAfrzXoCuHRXGcEZ5rkNEhR724vsD98RGreqrn+pNdVZuvlYJ4Utk/Qmu2lfkRxVrc7sf/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-72.png', linkedinUrl: '/in/jesse-hartman-f27f702502', jobTitle: 'Chiropractor', }, @@ -1725,7 +1725,7 @@ export const peopleDemo = [ city: 'South Matthewton', email: 'julie.whitney@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0k0lLTScVRJT1XVbTR7F7u8lEcS+vUn0Feda78UyY3i0uIRgHKyy8lhjsv1qH4h3769r1noOmgzywlmkCHgNx1Pt/Wm2PwsMih9Qu8sR9yMcD8TWU6ijobQpSkro58fEzxHCzE38ZLHG0Qqf6V0+i/Ftkkit9atAVPDXEPUehKf4VPN8LNK8kgPLvA++G71wviHwfdaGrSxuZYB3J5FTGqmypUZJXPftO1K01ayjvLGdZoJPusv8AIjsatV84eEfFtz4Y1ZJxue0f/XQluG9x719F21xHd2sNzCcxTIsiH1BGRWydzBqw+q955n2Ofyv9Z5bbPrjip6QjIpiPLvhxpSxxXWoTZNzJIUJbqoB5/WvSUwV4INeXJejTNDVZreaeWaebCR57Ocnj6V0PhM3CuFdZEt3XzAHOSMjp/wDWrgmtWz0qeyR1k7oq/M6rn3rm9ajSW0dCobcD75rnvEy3D3pufs0txGvQK2OKWxvLieU2z2bwlAOV5U/j0NLl0uW3rY8t1mBYbxxEu1cn5RXu/wAM9SfUfA1l5pzJbk25+i/d/QivI/HNj9m1RZY14mXcR7969P8AhIm3wQGwRuuZDk9+grrpu6PPqqzaO6pCcAnGcc0tFamRzul2lq9mqPEpG5mAccjLE/1qG91ay024ki8qTCx5BRDt6464xUzAx30yRn5dxPHb1rKn1+881orLTWlVeN7gAfXk9K86zbaPXik0rFzRLu3voSrxyKCAf3sZUj2INWb77NbRnYqjHTFZNprV7NOYbjTnjOfvoQVH1weKffKZM7m6UmrOwzmNXsIdWu4nuI2eGHcWC9SCR+ld94OtzaaNJbqiLCk7eTsUAFTg9B7k1ytk0baktptYyuP3YAyCc45/OvQbG2FnZRwA52jkjua6KKd79DkxDio26snpKWiuo4jK1aJkjFwg4T7+PT1qgbewuYwZpOnIArdu0D2ky+qH+VcHqFhcqjS2zHAGcZNcddJSud2Gk3G3Y1ZzZ2UeIpOPrWLdakhGyM7iT0FYwhvbh2DggA81q2WlNGvmOOe1YXOk3PCdkr3E946guoEak9u5/p+VdgK5zwpIvl3UPRg4YD2xj+ldHXfS+BHm1gAAAAA+Nn//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-73.png', linkedinUrl: '/in/julie-whitney-527c01e206', jobTitle: 'Leisure centre manager', }, @@ -1735,7 +1735,7 @@ export const peopleDemo = [ city: 'North Andrewbury', email: 'barbara.diaz@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-74.png', linkedinUrl: '/in/barbara-diaz-5f4a19157d', jobTitle: 'Press photographer', }, @@ -1745,7 +1745,7 @@ export const peopleDemo = [ city: 'East Wandaport', email: 'jordan.montoya@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-75.png', linkedinUrl: '/in/jordan-montoya-f49fb6a720', jobTitle: 'Broadcast engineer', }, @@ -1755,7 +1755,7 @@ export const peopleDemo = [ city: 'Ashleyburgh', email: 'jorge.hanson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDX20YpwHFcZ4+8StpVoun2rlbq4UlmXqie3uay3NWamreL9J0iXyJJGnnAyYoBuI+p6Cuff4mwLeBBpsnk9y0g3fljFcDpWmX2q3AjtLdpGzyew+tdfD8L9VmhLTXMUbdsZJ+lKU4x3Y4wnLVI6XTfHmj6hMIZDJaOfumfG0/iD/OumUq6hlIIPII7149qPgTXtODMIxNGO6H+lafgXxJNYX40a/crA2Qm/wDgb0+hppqXwsHGUfiR6htpNtPHNLigAA4rwvxDevrHii9kydplMSeyrwP5V7uBmvD47VT40ntpQwzduDx23Gi9k2K12ker+FdMttN0WCONFVioZ2PeulSeB0xFcRuw4IVgcVxWpT4gRTa3EkI+URo20H6ntVHQ1xeRyx2j2cbkfIWz16D1rhtdczPSvZqKO/vFHksCVHoCeteReOdHjt7pdQtSY5SwDY459RXQeIyr3sv2pLqeJH2hIOo+vpWTqCC80q6gBuCqodon+8rDpzV0/dakTV95OJ2fhnU/7X0C1uz/AKwrsk/3hwf8fxrXxXLfDqLb4TiY9Xldj+eP6V1mK62cAKOK4+50sjVobo5kuIXZ5ZHOTtYkKv4V2S9KztTYQqpMTHzHA3joOvWsaydro6MPJJtPqWrERXFttKgHjmqd5eadpt7GLqWOJNwAyMl2P+AqWz+ReOcjIFUL3W7Z2Ma2ctwyE52RE4PfnFc0ddDsAXWnahrMwtriJw2MqOoOKh1i1t4bWVI0Acqenf2qjDqdnHdN5di1o7YADx7d344HNT3cxnkXPUkZHWm007A/M0vCtq1n4dtYWjCFQ3A+p5rYIqO2Qx20SHqqgGpTXattTzJWu7CheKoateW9tbCGaTY8+UiGPvMOcVsJCHYgtjA5qpq+iDVtMWNAv2m2lE8WT/EvUfiMj8actnYUfiVzmo71o8qXAYdMntVpoPtNqUFykIxwy9R9KoanYG6txLCdsqDv/I1yU2qXVrIYpfNjK8DAyK4Iq+x6TlynTywLbBi1ws7D+NutXNCX7XeNKekIz+J6f1rjILme8kxvkI6kngV0fheeWHV7rr9kWBVYjn58k/yrWEff1MqsnyNna0HpTVdXUMrAg9DSnpXUcAAAAAAAABwn/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-76.png', linkedinUrl: '/in/jorge-hanson-c899de111f', jobTitle: 'General practice doctor', }, @@ -1765,7 +1765,7 @@ export const peopleDemo = [ city: 'Port Shawn', email: 'anna.robbins@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwC9qeoQaXYvdTngcKo6sewFeZ3+tX2qTs8rkJnhBwqitrxnepNqi2zsWSBRiMd2PJJ/SuX37pBuJAPRVHNTKWtiox0uWEhL4zKqE/7XNOEU0cpKkyY654z/AI1u6R4Zub8q0j/Z4DztQcn6nvXUR+CNO8kKruG7nPX8KydRJm6oyaucfZapLa8x7lVCGCn9R7+tdtDcrNGrr0YA1aTwnpyWyxGMv6kmqAjWxu5bJVOzAeMe3TFXCrd2IqUnFXLyLuq1HFxmq8PY4q0pIHFbHOeTeKHkTX75FGWMmT3wMDFP8K2a3F8rMu9gcnjgV03ibw9Bf3N3PnyJ1dVV9/EnA6g/lxVvwhpiWunMWTEhcgnvxXNOas7HZCm01c6KFAIwAOnpV+KN8DOBWBd3MkMgTy5NrELkHAz7msyyur1dUcILlIUfa3mHg89RyeK5+XqdV7aHdIh2kHiud1WIya1aPH/Cj7iOmMio/E0t3HAoi3lQgcqjYL89BUunW7C0hd4vLdhyK0or3kY137jLUceBU6jApEQipgvtXaeeYeoyRS6nbwTMF8zJi3dHYDp9f/r1atw0THgD5iSB61xvji/MRsVQZmjfzl9iOn9a6Pw5dPd6PbTTtmWVdzH3zzXJVjZ3R3UZ3ik+h0CeVcLtZR05BHWq1xFBAVVUHmPkhQKljUgD17VSvp9PmBS8kTOMFd3OPSsUdSNOFEkggMgG7aQM80shBdQB0FUbK406TEdpICR93kn+dWmYmVjWtGPvnPiXaFh4qVVpqc1MBXWcB5x4utkZVuVQyuAVVQMgtkYH8619DhuF0S3M0IgmGWMQOdoJ6VlfES4bSrvTLWNsoq+ccHqQcD+tdJZ3CT2kU0ZBjkUMp+tc1ZtJPuddCOrJkvkGAzAMOxp4t45xnKHHQkc1FJpi3Kbo2AB6gjODSQaU8WQ87n02nFc51p2LbLFZIu54+SNp6ZNTRknnr71yfjNRbW2nBWbcJz1OeNprW8O6g11ZiT7zJ8sif3senvXVSsoc5yV7znym6lWF6UwhWiEkXzcZwO4qsuqWq5DSgEcEHqK3Wuy04uzP/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-77.png', linkedinUrl: '/in/anna-robbins-8ddf20e83c', jobTitle: 'Nurse, mental health', }, @@ -1775,7 +1775,7 @@ export const peopleDemo = [ city: 'East Eric', email: 'steve.keller@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDodlNkaOGJpZXVI0GWZjgAe5qxtryv4keIXmvjosD7beHBnx/G/UA+w4/H6VkaGlqvxBQvJFo8SSBOtxNwv/AR1P41yN3448QifcL5lGcgIigfy6VW0bSb/Vz5FlE7burAYFdPD8KdTLD7Rd+Wp7AZqXUinqzSNKUloinY/EjWHIic2zsP78eN/tkHivQ9C8QWevWpeHMc6cSwP95D/Ue9cPd/C2eK2Lx3JZl6EiuaS+v/AA1rscrK6SQsMrn769x7g0RnGT0CVKUVeSPcStJspLO5hv7GC7gYNFMgdSPQ1NtqjMsBa+eb1H1nxNc5OGnumyfTLGvolRXi8WjtbfFNrMkGP7SZFI6EHLf/AFqJOybHBczSPVfDulWmk2UUFvGFUAZbuTXQTFDtYMGPsa8/1xbsu8YScoqFsrnsOgGRyao+F5tSa7igzOFlwcSEnaD6gk4NcHLpc9S+tj0S4AMZAOCfWvNvH+lw3GltNsHmwndvA7dxVnxbc38N1JbgzssQywiJ5HoAOtVEiafSbyFhLnyG+V2J/hz371UVa0iamqcTb+H7eZ4NtDnIDOo9sMa6bbXLfDKKVPBkXmjAMzlPpx/XNdcVrtPMJlFcje6Kttr9vdwRBVgdmd8cnzCe/tXYL0qrf25mtn27cgZ5HpWdWDktDXD1FGVnsxU+z39sYpo1x3JqCMadY3Agt9kYUgu5IGSe1VYHPQHrWVqV5pMsXkzQTyujZDJAzYb1zXElfQ9PQ2bpLK71aZJCjrIcoRzg1Tv7SC2t5Y405KkZrEsLywS6dUaXedo3SoVJx0wTW3KHuZkRT8zEAVXK72FJpLUueHdO/s3RIbfOcZb860mFOiiEMCRL0UYpSK74qyseTOV5NjgOKXjpUtvZ3FwMomF9TxVuGwFvOkk0gKqfmGOBVEHDPcIkjbXUxMSY3HQirRtUurYL9pEePukdR9KLjTIbeJrDGUjz5fuhJwfyrmrj7RYzGNJG2dhnpXnNe8erGTSTRttaJApUzCVvVhzV3Rgk12zFgWjXgfXjP+fWubhead/nY7e/vW54csZJdYu74MRBBbCH2Lls/oAPzrSl8aM68m4M6YimkUoP084//9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-78.png', linkedinUrl: '/in/steve-keller-377272ac44', jobTitle: 'Industrial buyer', }, @@ -1785,7 +1785,7 @@ export const peopleDemo = [ city: 'New Georgeport', email: 'brianna.moreno@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDvNgxUbJU5FVb66isbKe7mOIoULsfYCtXoZGVrut2OhWyy3j43nCIoyzfSuWfxzLdZaxtFSMfxzHP5gdK4e/vr/wAa+IWeNSWPCID8saV1um/DydYwXvQhI+YR8D/69cdWu9k7HbRw6erVyceP/Jt2+0RJ5wOCF6D/ABrasPFVndwxPKDGH4z1GazZfhramIhLiTfjq3Nc5c6Nf6DbTReYZY+vFZrESWzNXhk+h6l8rYIOQeQakRK4XwV4pN3Kum3bjOP3LNwf9016Cq4Fd8JqauefODg7MuGuT+It99j8H3KKuXuWWAe2eSfyFdYa89+LJkXw/ZFM7ftXzf8AfJxRP4WEPiRjeBtOS3sTIgzJKcs2Otej2q/ux6+leaW17LpWh2iwwyvJJEAAhxzjPJrW8Manql1eQ29yJFST5hvOSPY15U023I9iDSSid8SdvB/CsDW40NrJuUElT1HWuc8S3+rQ3xFoJWjTsjEbhmrVlqN1fRC3ubaaORRzuO4H8ahrS5d9bHmwuhZa2JICV2SBguenNfQVvh7dGXkMoIPrxXz3qtjNF4nmt442f95woGeOtfQ9quLSHAx+7Xj04r0sOeXiCwa5/wAa2S3vhqWNsYV1ckjoAa6PFV7+2F1YTwYBLoQATjntW01eLSMKbUZps4jSGt2gSOSNWAUAZq8l1ZWerRLI6RAAlR3Jx6Vni0msrny5Y/Lf+6Ogqtc6lYmcpLbSXDqCMohOPxryLPmse7GzSsb+n3ljfSOFkjlUk4ZcHv0NPv57a3jIjULx2rLsNV0+TEMds9szHo0ZGfxpb2HfJuY8Cod1oXoZK2C3FzPMYgXnXasg+8hA4/OvTI12xIp6hQD+VYGh6S7Ik90gUBtyoDnd6E10gwK9LDU5RTcup5OLqxnaMeg7ikNKaaSAOTXUcZy3ifbHeQOOGZOv0NZMNnBccvMVPt1FaGvTx3uprFEwdI49pYdM5rEmgkgBwTXlV2nUbR7OGuqauayWkFnGSk+8H1FVZJDPPHCGyGYAn6mqUEF1cNgghT6VoQW4tZoWbHyyKSfxrFW5tTaV7M7lUCjAGAOKDxTsjsaacV7Z4B//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-79.png', linkedinUrl: '/in/brianna-moreno-dae63a4f83', jobTitle: 'General practice doctor', }, @@ -1795,7 +1795,7 @@ export const peopleDemo = [ city: 'South Stephanie', email: 'shawn.krause@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-80.png', linkedinUrl: '/in/shawn-krause-f42275b298', jobTitle: 'Insurance broker', }, @@ -1805,7 +1805,7 @@ export const peopleDemo = [ city: 'New Jorgeland', email: 'michael.pierce@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-81.png', linkedinUrl: '/in/michael-pierce-b01914124c', jobTitle: 'Engineer, broadcasting (operations)', }, @@ -1815,7 +1815,7 @@ export const peopleDemo = [ city: 'Butlerchester', email: 'elizabeth.leon@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-82.png', linkedinUrl: '/in/elizabeth-leon-7618636547', jobTitle: 'Clinical embryologist', }, @@ -1825,7 +1825,7 @@ export const peopleDemo = [ city: 'North Jamesburgh', email: 'carl.wagner@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDrwOKUCjHFLikMx/EfiC18Oaabuf53Y7YogcFz/hXlOq+ONY1WRgb37JEQR5MBKjB9T1NaHiI3PjHxbLawSbbS0Plq2OAB1PuSc1dh+GUTAlr1jnp8vSspVYx0bNYUZzV0jh0vbyynieK4kEy8o6yEbfpXTaL8Q9U0672Xkxv7c9UlOHH0b/Gr8vwvAUkXzbvpWJqPgW/t42dHjfaOOeTSVaD6lOhUXQ9h0bWLPXNPS7tG+U8MjfeQ+hq+Vrwjwdq97ofiK2LZEMriKZSeqk4/TrXvWK2MCPtSlSykA4JGAaB0pwoA848H2qxwzsQC7TMCfXH+TXdRZWMf0rgLyza3SdLcztE11MUWBsE/Me9afhibUd6xTvN5TrlTN94exrz6kbtyPTpStFRsdc+dhHQe9YepDMLKvJINYOv/ANqy3MjB7o26DJWBsbuemKk00XIxCVnCYztlOf1qeXS5blraxwF5G328lCFbdyO4Oa+gUGI1z6CvIdQ0aS48UhocCIbZZCR2B5x7nFetWtyl7aRXMQISRdwB6iu6nJNWPOqQcXfoOFOFNHSnCtDIworaBZriB1BxKxAI9Tn+tIJrOC/EIkij2KTgnBP4UupAw6luH/LRQf6VjyzW93IwksZJ8ZG4Jx+Z6150o++0etSfNBNbmrY3NlfFkWSOXPIKkMOvSp7lIbaMlFAJFZNrdwwN5SWMlvuI48sY/MVavZMoeealrWxbM2KLdNJIgIl4O4Ht6H1612lrH5NnDFjBVACKwfD9mk5lnckhHAA7E4zXSGuyjC3vM8/EVE7RXQjHSloGMUvFbnMZus2ctzbeZAu6aPkL/eHcVgwPbTw7bhmGOqnj8DXVXd/a2EYkupljUnauerH0ArgL2FtVkeeNjA0jlhg+/FcteK+I7MNOXwmy8tpbRfu5OMfxHtWVLfNcfu4Mtk8n0qpFoN6pJurkMg7DvWja2SwLhQa53ZbHVqy/4d1+2g1L+w5I3WZx5qy5G1s8Y9jxXXGvJb10GpNdRDEigIHHXg5/nXXad40tjDFFqCyJNt5kAyG9+Old9O/KjzavxuwAAAAAAAAAAf/Z', + 'https://twentyhq.github.io/placeholder-images/people/image-83.png', linkedinUrl: '/in/carl-wagner-c6d92ca2ac', jobTitle: 'Programmer, multimedia', }, @@ -1835,7 +1835,7 @@ export const peopleDemo = [ city: 'Montgomeryborough', email: 'erica.taylor@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-84.png', linkedinUrl: '/in/erica-taylor-99a8f528f9', jobTitle: 'Catering manager', }, @@ -1845,7 +1845,7 @@ export const peopleDemo = [ city: 'Kramerville', email: 'sandy.gomez@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDuVOByMVla7rttodos0/zO5wkYPLGrOo38WnafPeTn93ChZsdT7fjXiGva3feItSE8h4HypEv3Yx6f/XqZSsOMbnWX3xDvbwFNNtRbdQWk+Yn6dhVCPxtr0dk0DXa+crffKjdjPr071Z0HwXcXESyXExiRucKMGujPw909oyUkk8wjBJPFc7ra7nUqDtsYel/E6WGMR6rbiZgeJIcAke49a9G07UbXUbZZ7aQMjfpXCXvwztY0EltPIsq92wRWRo2p3fhDWPsV4d9tK3zew/vD/CrhWTdjOdFpXPXiAORRt3DOKghl3qCDlTyPpVlGAFbnOcZ8QJCPCFwFYrukRTtHUZ6V5x4bt0l1FA43EMMDsP8A69ep+LbM3XhW/jVGd9gKKvUkEYArz/wRYONTYzIQ6Ju2kYINYVnY6KCuenWWBGq+laqKSnGDXJ38zW0Zj+zzTswztQHH/wCuk0BbiCYMIpIY5OWViTj2PNcdup6F+h1kqnYcjAxXm/xBtEawW4C4kiYEMPeug8Vz3R/dxCV405YRZyfyrmtb3XPhi4AilieIrvSQ57jnP41Ud0yJ7NHZ6VK0mmWkoOQ8KHP4CtIMzqRk1gaWHtdNs7cZIWJRk/SuitlIjBY9a7Yu55j3KepxJPbRq3KrIrkeuKwLaDZeNfEDzJlwQvYA8fjiuhlIeEEcg9q5+71RYddtNLa1cebGzrP/AAnHb61jXpu/Mjrw9WPJyM6W0eKZPmAJ9xUWpTW9pGA7xxDqzMQoHaobYbG479KivNSsN4juYHmZedoiLfr0rlWrsd1l0LKTW0l+YxLHJuQEgc4NVdZt4Li1ktAoBkGOlQQ32m+eVghaGQjjfGVz+NSSb3uMkckdfSmk3JRJm1GLcixaQxCKKPO4xqBzVqSURgAcVS3iD2JpqTtLJtI613RfQ8hu7uWx9wHr9az720SZYpmGZIX3KR2zwf0NabKCAvGKJvKjtJN2BlSB7mtJ25XcIX5kZkNyYj5bnBU5B9a0EWKdSWcFT+lVjaCZAeORVKSwuUOImK15V+p7CL9xDBbIWRwRUUMmcykVFHp8qBWuJC7dcdhUlspaTZjPUhfWtqDXPdmGK5nDQaBJc3HK4TtVh9kMig8ZpyyDzSAMAdc0yRVmct6V3K3Q8w//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-85.png', linkedinUrl: '/in/sandy-gomez-fe6cfbd6f8', jobTitle: 'Event organiser', }, @@ -1855,7 +1855,7 @@ export const peopleDemo = [ city: 'Cheyenneton', email: 'tracy.gray@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDGbOaTFTslCxjqegrK5pYqyzJbqGkPU4UdyaV5o4bFrq6lWCPouTy1czc6hLcXrssgVUJ+fso9qL3TzdWq3DOzuo6SN09ABUNtstRSRcOvyRNlRuifkbweK27S+W4UDaVJGRnofoayZ7OKZYGAChwjsPwwau2CNY3E9nId0RG+JvQ4qbvoyuVdUahOcjoR2phU5rJbVFW9Eg/1eQrj0rdUAgEcg9K0UrmbjYQrWR4k1EadppRf9dPlVx2Hc1uhK5Hx5G+2xIHBLDP5cUAjEtIzJ5Y+8uQcDuTXolp4fEUMTSruLL82a5Dw9EF024mMBnPnCNB2BwOa7HwtJe3F1FbTeb9nlBP7wEFf19qwnc7KSWlzn7+1n065TPMYBUZ/u56VVvbsi1jZScxN69RXQeJbaUaizSQTTRx8qFGcjpwM9ap6joxurImO2aGWJd3C43r3yMnke1SnbUcopuyOYNyv+sYfLIMNjof/AK9dlokv2jS4zu3bcrn+VedvmK5aPPy545xkV3fgvD6XOucskvI/Ct0jkkbYFYnjG1afQhIi5aGQP9ByP61vgU9okmieKRdyOpVh6g1RBgfDzyH0N4Z1DZmY8/hXa2MllaakEZ0iVIyR2yTWBbadDY7I7VBHGOgA70t7f6SsqrdRyySJxmNSSPxFcsk+dnpUbOmrHSW0lpfgJvhlOMq2QwIzTr2SC2iKhccY6cVl6fqejSwrDaRG3fd8qtGUOfx61cvow4BY5wOlS9NDRnlur+H5n1OZoosQvlhjoo6/hzWz4EtpEs7q4P8AqpHCp/tY71Bqet3GpazJ4dsbdY2ZtklwW5K4ycDtxmuwtbaKzto7eBdscY2gV00+a2p59ZxvaJCBTgMU4LTghPQZrQxGkFkO3r2qO3txcc+f5TjqatRITLtIIx1rFtp2ubdZ/uu2c49c1jXha0jqwtR6pHRx232eH57hJB645qKSRp2A3Zz1NZNu1xNMI3PBrZijCjaB+Nc7Opu5ymiaEI9dvtWnkRpGldY0U52jpk++O1dLTvD/AIdE2r61d72W2dYwPQSYJJH4Y/OnSW7xOyt2PX1ruirxek2j/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-86.png', linkedinUrl: '/in/tracy-gray-e7455e5048', jobTitle: 'Charity officer', }, @@ -1865,7 +1865,7 @@ export const peopleDemo = [ city: 'South Martha', email: 'amy.davies@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-87.png', linkedinUrl: '/in/amy-davies-6d15292b3d', jobTitle: 'Trading standards officer', }, @@ -1875,7 +1875,7 @@ export const peopleDemo = [ city: 'Vaughnmouth', email: 'mary.wood@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-88.png', linkedinUrl: '/in/mary-wood-ac63c86744', jobTitle: 'Nutritional therapist', }, @@ -1885,7 +1885,7 @@ export const peopleDemo = [ city: 'Onealshire', email: 'james.green@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-89.png', linkedinUrl: '/in/james-green-0c06ff4286', jobTitle: 'Journalist, broadcasting', }, @@ -1895,7 +1895,7 @@ export const peopleDemo = [ city: 'East Jesseburgh', email: 'rebecca.petersen@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-90.png', linkedinUrl: '/in/rebecca-petersen-3213856af4', jobTitle: 'Licensed conveyancer', }, @@ -1905,7 +1905,7 @@ export const peopleDemo = [ city: 'Sherylport', email: 'hunter.pierce@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDvDQKU1U1PUYNJ0y4v7k4ihQsfUnsB7k8Vym43VNY0/RbU3Oo3UcEfbceWPoAOT+FcJd/F+zErJYaXLOoOA8soTPvjBrAj0HUvHN/Jq2p3RhSRsRIBnYvYD0H862B8K7bcmy+kK/xblGafPTTs2UqVSSukT2nxetXlCXelSxDuUlDY/AgV3Oka3p2u2n2jT7lZU6MvRkPoR2rhLr4V6cy5jup1P4GsEaFqvgjUF1XTpVnRDh0bup45Hejnpy0TB0qkdWj2jFGKrabfQ6pp0F7AcxyoGHse4/A8VaoJCuK+JrMdBtbcMQktyN4HcKCf54rt65LxskN2thb71aSK5VpE7hWBGaL21BJvRDPDsQh0u3TGCFHFdNEp2jv9K8+1QTCbZi6ZQu5Eg4OQOTmr/h2bVI5ooZJZ2hkwwE5yy57H/Cubl05juUteWx2b5CntXL+IAv2SXjd8pzVLxLcak1w6RSTiGIEsID8zfT1qjYec8nlubkDblo5znqOx/mKOXTmBy15Tofh+7NoEsZPyxzttHoCAf55rqq5XwIi29jdwM37xrh3VT/cGBn866wiuq99Thas7DRXM+JLdFuRPzvZR2/u101VNR0/7fAEDBXGcEjsamcboulNRldmVarBdwqrqpIHUinvPY2l9DE0sUXzAfMQNx9qy7MvDIUzhlJBHuKjub1bmTy206SbA5YgKPwJ61zJXdjuvpoasc9jc380RlikyxHynOD7+lJqEdvaW77FAJHWsuzu4LWUxjTpYN3G4AOD9SOlTX4a5ZYUyWdgo+poas7CvpqXvDFvsZpAekeDxjknNdHVPTbH7BblCwZyeSOntVyuqCtGxw1ZKUrobT1FRvIkaF3ZUVeSzHAFc1rvi21ispINOm8y4b5d6j5VHc57mtErmTZh6hrNtcand3NmGNuspRjjHzLwT9M1ct77TLmAGdgw7qTXO6FCpS7gP3mlL/gQP8DVhtD85yEO1vY4rknZTaZ3U2+RNG5Pe6dawMLdgi9hmoNC1WGTXbQTkiNyVjJ7vjj+tZC6GYCBLIXc9s9BVfVohA1gsZ2sJsgjrwpohZzQqjfI7nrpptcjY+N7dY4otRR1k+6ZUGQT6kdRXTWl/aX0e+1uI5R32nmf/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-91.png', linkedinUrl: '/in/hunter-pierce-6873b9e186', jobTitle: 'Product manager', }, @@ -1915,7 +1915,7 @@ export const peopleDemo = [ city: 'West Zachary', email: 'christian.bailey@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDt6wfE3izT/DFsrXB824f/AFduhG4+59B71uswRGdvuqCT9K8JKt4n8UtNckuJpiWz/CmeAPwrNuyuXFXdi9qHjDxL4gic27vbWjcbYF2jHu3U1zcmnX9uPO3SEnksc9frXtlhYW8FulukKLGowFA4rW/s6CWLy3t42QjoVFcn1nXY7/qatueN+HvHmtaVchLgSXlpjaYpCSV/3T1r17SNXs9bsEvLN9yNwVPVD6EVSm8O6dH88VlCrDoQtcpLFJ4b8UW99ZEx2lxIqXUIPykN3x7VrCupOxjUwzhG9z0aloNJW5zDbobrKcesbD9K8b8NITfxBCNzMMY64r2K8leG1d41DN0ANcNpejwabr00cfMYQuhPUEnkVhWml7p0UKTfvdLnV2mCSK1VyIwBzXH30lxGxQR3DLjIEOATxnv3puh3GpLcoP8ASRBJ8224bLKPf0rj5dLno82tjrZwdp6gVwvitSLYleSWUcfUCtDxNd6lveGDzfLjXLmI/MfYVhLFK9vIWW4JQozJM24kgg1UI2akRUd04o9JRSsaqeoABopEYvEjMMMVBIHY0V6J5Ikql4WUdSOK52dTDeISB/q+o7jNdKOlZOsRRw+VPgDLFG/H/wDVWFendcx04ary+4+pdhhiu4huAz6GmTJbwMYolXf1bHaqdrKyqrKcjGap3txYXfyXBGVOQSG6/hXFFX0PSvoaNzFH/aWJNuJFHX1qvdJBHLDEkY+aQZFZCtawXXmLdGWUjA3uT+Wa04I/tGowh8nHzH8v/wBVXGPvJGdSSUG2bxNNzSmmE16R45KvSuT8QarNdaq2k20atBBEJrmXqVOQAB6feFUdW8fgI8WnQMCRgTycY9wP8apeAr6NvEzW11+8S+jaNtx+83UZ/wA9aUo3i0VB8skzTtb9rf8AdzNjHc9xW8jx3EX+u2gjqOar6x4akspBu3PA3+rlx19j71jHTLxTi3mK46ZPFea1Z2Z6sZXV1sat2kMEbOZd23u1W9BjElu16XDGXhcdgP61y0ltdFmFxMHVRkntWfeatqnhy7SK2uCsUsST7CoIyw963w6Tlc58VJ8tj040w1wth8QjkJqFqG/6aQH/ANlP+NdPY+INL1EAW92m/wDuP+A//9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-92.png', linkedinUrl: '/in/christian-bailey-b3f28cc8db', jobTitle: 'Community education officer', }, @@ -1925,7 +1925,7 @@ export const peopleDemo = [ city: 'Port Scott', email: 'william.mitchell@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-93.png', linkedinUrl: '/in/william-mitchell-90c3f0b311', jobTitle: 'Insurance account manager', }, @@ -1935,7 +1935,7 @@ export const peopleDemo = [ city: 'New Jonathon', email: 'brent.gray@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDttlU9Sv7bS7Rrm6fag4AHVj6CtLZXjnivVrjWfEc8Ub/6PA5hhVepI4P6iolKyLjG7L174smvLpy1y1vED8iIMAD3Ydfxpv2mKeES3WqmVj9xI5ME/ic0/Tfh3LcBJbibD9884roB8NdNK5Jcy9QRwK5pTv1OuNJpbHD/ANtSR3Bitrq5tpVOAGk6/j0Ndz4L8RvrVtNb3JDXVufmbGNy+49QeKV/htpRh+cy+Zj7wbpXOjTZfA+si9gnMltcKY5C6/dPUZ/KqhNJkVKUrXPS8U0rVXSNQTVNOjukA+bIODkZFXStdJyluTcInK/eCkj61474fjSTVGaRQ0m/OT1ya9mO0IS5AUDJJ7CvK/DmnyjxKyToUxKzBD6DOPw6VlW2NqKuz0i0jCxBeKuheK53Uw6g5W6k4JCQHHQetVfD8l15qki8SF+ds77iv19K5baXO6+tjq5F4rk/E8MT2UiyAFD1z60vii8vEldIftBijUFvI+8fpWRdxSy6HdkNc8R/Mk+CwPHIIoS1uKT0aNPwPBJD4eAfARpWMYHYcf1zXSEVQ8OQ+V4dsVJz+7zn6nNaRFdy2PNe467jM1nLEDjcpFYwtYn1SO+TCtHuhwB1HvXQYyKzbuIwvEVUbd2N2efpWVaDfvI6MPUSTgy/GokXPH41VvLi1tcCWWOIZALMQBknp9akil2R59s4rJu9SsHJS4dCVPTaWINYJXOtFzz7aXVXjSWN22gkA5xUGrQxvbSQ/d8wbcgetUbe805Z2+yyx78AEHg/hmr7757iMDknnmlZ3sN2S1LljCILGKIYwo4x6VK1SKu1QPQYprCu1KyseXJ80myWWWOCB5pWCRopZmPYDqa5CPx1o+u6hHpdiJ3eQnbKyhV4BPHOf0qz4v1jybcabAcyzj94f7q+n1NcB4G0dbfxzK0rYWBGMK+7dfyyaVTSLKpK80elx3BRjFKQrjse9W2UPFtyFbHHFJeael0OR83Y9xWNeNqlkMRx+ag75wR9a5NjvTL00CqMuEZh3Iqhp/iXSx4gk024uliuwimNX4Vs+h9enFNiS/uVVroqiNzsXrivLPG1rLH4vllljxFLsEUi+ygY/SrpWczOu24Hv9MYVwvw81qeZH066lZ8JvhLnJGOo//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-94.png', linkedinUrl: '/in/brent-gray-19b7fd459b', jobTitle: 'Careers information officer', }, @@ -1945,7 +1945,7 @@ export const peopleDemo = [ city: 'Port Tara', email: 'melissa.myers@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwCjWDrHim10tmgiH2i5HVQcKv1P9Kn8T6sdH03dF/x8TErH/s+przNmY5Zslm5JPUmoSKbN9/E+qXbszXHlKBwsfAH9TVqx8ZajBGyyrHOo6O4wR9cVnaPpFzqQ2W0eCfvO3QfSuttPAQEeZ5iXx/COD9aidWEdGzWFGpNXSHad4rsr8iOYi3mPTcflb6H/ABrZLVxus+C5tOjaW2kMidWUitHwtq32yxFtM/8ApEPy4PVlHempRkrxFKEoO0jog1OBNRinr1oFY4DxxcyS68YmGEgQBeeuec1kaZCtzcJE46kdBXS+K9BurrxDI1tFuMsYkAA5boDVfwhY/wDE3ZbiMhlXPzDpRKajFjp03Ka8zv8ARrKC0tQiIF7/AOTXVW9uRBkx5rnnJtPLZbT7QWwED/cBPGTn+tR6Y161/Fey24hEu4qv3SMHHIHr24rzlG6cmeq5WaijX1SzMlu4EXGPSvHLvzNG8YM1shO4j92O+7qK9R8UXd3dXMVihOxpFVtrYGW9eeB6muMi0pr3xOt/HB9nt4I1BU8hm5Hy+3Ga3w65Xfuc2KfMrdjoV6A4qVACabtxT0rpOMluopBqtrdJ8yCOSJk9zgg/XIqtcWMNtqDTRQlMrgjOeMmr1wHktZljz5hQ7cHBzjj9awtKOopb+Xqk7S3K8Nkg49uPauavF/EdmHmvgO80QQXNuFkweOAe9PuYrW1YhIlWZz91Byay7JWiWNo2BDdqmubywnUw3iq7fxKeo9sVyxu9Dsa6kV7ZiS5heaMBZU5z7VQnjjimZIsbAABUFxcWqXKLbO5VeERiePpSRsTGGJ5bmt6MXznPiZLkt1YxutKnWkbk05BzXYecb9npNxeW88luu6SMZVOm/wBQD61zdskl1dXDyoUZm5Q9V7Y+tex2mmpYIqxDCqMYrL1vw1Feym/s0C3WP3ijpKP/AIqor05Sh7pthqkYz9483W6eykEMrFSDlT2NbMO24QSJKkZxkMajvrFJQUli3KPvKRyKxbizigj/ANGu5QpOPLJyP1rz1JXPTadiS+hc3Sgz+Zx94enelPHA6VN4Tt/7UuNThnJ2W5jxIOq5B/Titm78J3sZLQbZV64zg130o+7c83EVOaduxzpGTTl61JJbvFI0cilHU4KkYIodanOf/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-95.png', linkedinUrl: '/in/melissa-myers-0802db2cf0', jobTitle: 'Arboriculturist', }, @@ -1955,7 +1955,7 @@ export const peopleDemo = [ city: 'East Natasha', email: 'brittney.nguyen@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDh5OTVnT8GdaqOTVvTE8y5VAcFv5U3oI6OK1EyZJ2oOpxmqY1Ozt7hrexgZ5R96Rxjj61rW6rfRSwKrYC4QA/ePbp2qa2+HxKBriRiG5KjtXLKrc6oUTnJ9aYTLHkoG525yBV6z1KzuYMFCpBwWxgHFdK/gazeErs46gntWXqNrBp6bJYRuAxuxjIpKoOVIqSoqEA/xcg+tXrJV21mm6he3ETjaU+6fQVasnbB5rohK6OaUbM4l60dCVGnmkccInH1NZ7rkVd0giN585+6GA+n/wCunU+FhD4kej+ENM2wi9mYmRicL2A7V2LdABzXHRu1po1rGbeWTfED8gyRxnjpzVzw291JIN/nrbMMgTfeU+lcVj0kdDKSE7D8a5vW4Ip4GEiZBHWqWsi4mvJZiLh4IwSEh6tj8aZazz3YWI28sYAziQYPTvyRR5jfY4nUcwyNFGQB0B9u1bujEGzjDdQoBrntbtZo9YkgUMQHygAzwf8A69b+mxyQ26LIuHA+auikcFZHHluKv6GFk1aGEttEp2Z+vSsticU63kkhnSVDh0YMp9xW0ldWM4vlkme66Y0M+nQxuoOFAwRkU6W7srS7WF5o4jtJVTxn6CsrRL+HVIFuIHznAcYxhsDIqe+1HTlfZJaPdMMg7IS2PXmuHW9j1oJS+ENJubS+8wJLHKMnkHI4OMVPevDaISqBR7dKo2mp2MjmOG2ltnJ4VoSv64puoq0n3jwOopPTQdrPU5u4tBdX/muisrIVbI+76HNDRujtjnnqDmkj1XzrtrURR7RKU3A5JA46dqnaORtrYxgcEdDW1G6u2cVdqVkjmf8AhGNQVDJMIoUUZJd+n5VQkto7cklt2O5GBXcasDKm4nEY5Vf6muG107LeNScLLKise4XPP6V0KRzOJ1Hg2/e3m2Z/c3QYx47lOpHtz1ruQltdRB3lwO204rPaCCLUNOvIkRYGt2tcqOEOQw/Agfyp+oaSWYvDM0LN3B4z9K5Kz9+53Yd2gieQQ2kfyykg+prKluGunKoxK5yzVWXS7wO32mfcPY9a0PsogttqgDjmsbm7Z47Hc3X9r3E5DqrTOR6j5jXd6Tq1w0QiZlcsMqWHX2NZuuWkFpejG3zLidpQoHSPYo5+rAn8aSxK5MXTbypru5tEebwAAAABy6s//9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-96.png', linkedinUrl: '/in/brittney-nguyen-c1eb8b312b', jobTitle: 'Logistics and distribution manager', }, @@ -1965,7 +1965,7 @@ export const peopleDemo = [ city: 'North Kariside', email: 'jacob.franklin@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDgqcKTFUNU1D7FCFTmZxx7D1rhSu7I727K7Lk91Dapulbk9FHJNVf7ZUci3cj1z0+tVND8Pajr85MEJfuzyHj867GL4V37jeLmCJ8YwgJqnyR0bJSqSV0jDh1KGXapyhbp3Bq4Riprj4aanbQ+clzGZUbcF5wayLe5ninltLqNkeLjnsP8KHyv4SlzR+JGgrFTwanWUk1VDdDT0PNRcqxD2rHnSG81dIX7kJ14HNbOKyI7Ur4ijVs4lkBU/U81UN2RU2R7Jolpb2dokUKrGoA6cV0kWPKG0hj7GuI1S0lMSgRTSRAZxHyenYZHP1o8O2d7a3asiSRwOAzeb94A9AcHrXPbqdl+h2F2hERzge5rynxzbQxH7YiASAbCfY10fiuO/u7iRA05tYcbhApZmPsMj1rl9etHOiTqBLmPbkSdeo/KrpqzTM6rvFoyLBzJZRORjK9PSranmq1pEYLWKM5G1e9WFNW9zKOwV0dvpUd1pdlcxfNLEfM5PAC9QPcmubzWnpWuT6ZHLEI1mikB+Rz90+oqZJ9DSEktz0vSpo5LdUcAjHel1W/s7ERrJNDCpIBLEKCewrI0mRWhiYHqo4p99f2M37qa1ebYf+fcvg/XGKyXY6FrsWLe9srnWbmGKeKZCoJAOcGsnxOkDQfZokCmQ4OPSq9tLptldv8AY7SSBn4LPCy7voTVDWbsrchidxBIwaqz5rEyslqc9cKqTOqsWAOMnqajHJpz8nJPNNUc1qczd2IKco5puKmjidklZEZ/LjaQhepAGcUCOphnaC1gfJWORQd3oa21/wBMtgPtYjJHDDtWbY2jXGhRxSrtfYOOu01iXtnqFkpMW7Z6qciufqdKulc2r1UsYXY3hkYDqx5rlp3adtxJP1pkSz3EypIzN3OacJC19Nb7PuqHU+o6H9f51rFamdSV1qVXXBqe1RWY5GTTnh706GMhsitDB3P/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-97.png', linkedinUrl: '/in/jacob-franklin-fe55bfc993', jobTitle: 'Freight forwarder', }, @@ -1975,7 +1975,7 @@ export const peopleDemo = [ city: 'West Jamesburgh', email: 'kathy.burgess@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDv8cVm3esWlsSm/wAxx1C9vxrnfGHiVraVdMs3xIwzM47D0/xribzWimIIiS3Q4PJPpXDObvZHXCnpdnd33jJrZT5NkHI9XrKh+IN80oMtnGsROAVyefesXS7qW8mVMNKehVB19h7V0kfhC4uCzOkcMMg5jHUfjWftGaqkn0N7R/Etrqr+Q6Nb3PZJBw3up71tEV5Vq3hzWtDAuoJ/tMMJ3YBIdR7V3XhfX4vEOkrOp/fRnZKvofX8a1hPmMqlNxNnFOxRSirMjwG/1VnnnupG3SMSck9T/wDrrNsllvblIIyTLIeTVG+mzDu/h3Cus8Aad9okmvH5I4FZNcsLnTH3pqJ6N4V0e20uxVVxv6u5711cc0LIBHKjeytmuJu7u4s8BLN5skDJGVX39KzNEe9utVkn+wtAA5BOMdDjPHFYJO1zr0Wh6FdIskbbioGOc9K4DwhEdL8f6tp0ZxA6CRVHTsR/Orvjae+gFvHBE8kbFc4zjJ9fameDbV7vxNcam0PkCO0SMxn+8f8A9VaU1rcxrtcp32KO1OxRiuk4D5git2u40hVSWLgnAzx3Nek+HLQ6VZqkbB037tw7j1rz611JtEvY7ryvMVWIK5wfwNehaDrSavE0vkeSJDlVJzx61z1ua3kd9Dlv5nc2V8s6eW8YORyas3MtrYxDaFBc4yeAKxbRGBGDxVm81KxtYTHejzGPOwRlz+VYLXQ62kT/AGuw1GOALPFKeRlDuB+hq5pkUMc05jQKzY3e+OBXL2eraVcztDaQSQyMMjKba2vD9z595djOdh2fka1p6TObEq0DoKKKK6zzj5kvo1ms89wxz+tdT4PUvoELocPGxH61zka5URkfMSeP5V3Pg/TTaacYZB7muapL3bHbRj79zoLPUQECyfKw61srHHdx4Eq46/NXPy2rh8AZFAWaHGGK/jXOjruaV+I9JtZLmeZSkY3Zz+lN8DSNO007f8tCSfqea8u1/XL7U72S1klItY5mVEAxnbjk+vevVvAUarpKEev59q6IRtJXOSvU5kzsMUVz/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-98.png', linkedinUrl: '/in/kathy-burgess-99f2ff488c', jobTitle: 'Learning disability nurse', }, @@ -1985,7 +1985,7 @@ export const peopleDemo = [ city: 'South Jenniferstad', email: 'nicole.smith@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDiSSe9RySLEjO7YVRkmn+tZGtuywooOFJ5HcmpLM+91CS9fAysYPC1UOcqME/Q1pWOjvOquzbQe1dBa+GLUxkurN+NS6kVoUqUnqcbHK0MwKMdwOcjgiup0rUjexFXP71OvuPWm3vh23wdu5G6A5rMsoX07W44mOVcFQfWhTUglTlHc6tCT3q5Cc8VnAlTVmF+RzVCM/HBrJ1lMxQv6SY/Otaq11D59u6nOAQeBn6Um7ajSvoS6cpaNVAJI7Cur05JYocYG4eo5rko/MjkRFhkYNwuxsZNWbW/1i3uEQLKYZOUWXG4VzNPc601pE2tSikZQdmT1OBXLXcOdTtGIwVkx+hrQv73V5ZXVVdBGMSbCNx7YAqvEshkLGP5kbG533Z9SD+dELp3YqlmuVFs7c8kVJERuHNVWPNPTtXUcZGaEx84PQqaDVi3tmcgsML1JPYUmroadncl0uW2eN4rlQR057Vct/Ie7WK1jRRGwJdiAT71zVtdRXAjuY8qrk/KT71qApdSIpsppQvCskZ/Q1yuLvY7oSVkzS1JY/7RkMyo0bthsEHn1qlKInfy4Qqoik/X2qtLGttK5azuIsjBeQf1qxosaXk00aNukXG5e4B6URjZ6iqS0aRUkUg06MHIro/+Ec3Hc7SBT/dANSDw9bqOJZP0rpUkzjcWinougyX94wkBVUXcdwq/rOjRWGn3Mhmd5zbzCKMAAZ8s811emosl9cTKeGQVieIJ9mvRxOP3QgYHPQbuM1LbckikkoNnlljZyR6ZCn8SjJrU03UZ7UF4L7yHAwVdcg1ozaY1szxjGM5XHQj2rHvNLMkm4DB9M1jzatM6FFpJxLV5eTX0gee8Nw56Kq4FO0iEw6mkxbZHOTBIc4wTjYf++sD8arWdo0APHJrobLTTc6VcZH8LMPqOR/KjnswcHJand6VZTx28bT3CyIwHzBa130iJ4mOBvx1AxmsTR74xpCkzAxTjIPo3/wBfrXWQH5QOo7H2p3aZFlIAAAAAAI3P/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-99.png', linkedinUrl: '/in/nicole-smith-8aec41062c', jobTitle: 'Legal secretary', }, @@ -1995,7 +1995,7 @@ export const peopleDemo = [ city: 'Barrstad', email: 'troy.decker@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDs8UYp2KMViaDelYGqeMdO01mRQ1wyfeKEBV/Gn+I7u6Aj06ybZPcKfn746YH+Pashfh281pFFNfFscttWplNI0jTctSknxP3XaD+zQLYtgtv5FdBpXjTStUJVn+yyZwFlIw30IrIuvh3Zqh/fy8DjgYFcnrPhZ7C3ke1lZioyQR/KkqkWU6MlqeyYpQOK85+Hniu4urhdHvpfM/d/uGYcgjqpPfj+Vek4qzETFKBSgU4CgDMjijk1+SRhl4owq57A1uE/KFUcH0rldTkuLe8vZbdmz+7XCLls4PAqLw7e6pceY2otIIwjMpdQrDtgiuea1bOyl8KRvXzbAyHr6VxuuMEhcgZ4JNZ+o3OvXV1JLBLM0KtwqEAkZpyG5mVlmDkLkNv6/wD1xU8vUtyvocdpsz2/ie0a2GXS6TZjvlule8kV4lpFoLPxlbzS8WcE/myP/dA6V7eCGUMpypGQfUV1I4pJoaBTgKQCnCmQVoIFTULkuQVm2sPbAwf5VDqtzaWtvcI80cbCPOOnB71PcN5UiSt9wAg/zrjLy+/tm7MzqixR5TbsLHGec4H0rnlH3jtpSvFWNjw/JDPbvtZG6HKnIII4NV9X8qNWEYGT1rndJ1SXSZTA6K6ZIDA/MR70niTUmKeTCSHc8n0FS4u9i3JWKdjGbm7nEaErNIYskcdMcfjXrMaeVCkec7FC5+grjPAWlbrAX86/LvJhz39Sa7Yit4RtqclWd7IaKcKQVUvtUtNPjZp5RuVS2xeWxWhkO1KFpdOnCMqyBCyMxwARzzXNJN9q0KA2k0cLbRwD19envUd1r9zrFpNDFGIYJoyoHViCO5qCHSTd6HbT2l0YN8CiQbdyhgAD9ORWVWyszei2rlfU54YNPk3NE8rAjCiuN3Sapflo9+HOXYnhR6fWug1Dw7qKRYmuInibvGCCf8KltbCLS7JmYKuBk+gFZXSWhq05PUl8EeKLmPxBcaBclPsaMFtztwUYjOM9wa9LNeCRTM17JdREq7SBww4PHT+VdppnxHuE/d6hbLMAxXzIztYj6dDXUlojklu7H//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-100.png', linkedinUrl: '/in/troy-decker-bd98e78a69', jobTitle: 'Surveyor, minerals', }, @@ -2005,7 +2005,7 @@ export const peopleDemo = [ city: 'Myershaven', email: 'corey.thompson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDv8UYorP17VU0PQ7vUXUN5KZVT3Y8Afmago5/xl47tvDaPZ2qi41RlyqfwxZ6Fv8K8uPirXtUuGN1qM5yeUVyqr+C8CsYx6jr2pT3JLSzTuWdvUk10Nn4C16SEPHDHnsHNKU4rdlxpylqkZaapqFheNPZ3c8bg8ujkE/X1rvPC/wAUC8sdhraZYnAu14/76X+orIX4b6/dBiY4ocjld+QaydV8K3Hh+4Se6BZEXJx69qlVIvS5TpTSu0e9q6yIrowZWGQQcgilxXnPwr8QS6hHeaZMSwgxJET2BOCK9IqzIXFcJ8WTKPCkKozBGuVD47jBIz+Nd5iuR+JO9/CbQLEGEsq/N/dI5/oaV7FJX0RzPgvTYotNhlCDe3OSK9JtE3Qg5zjsK8xuJ7nToo4rZ5UUIAoiTJOBWz4a1rVbu7htZkYMT95l2nHviuKSb949KDSSiehhwsZ+bGRXOeJraC40e5E0fmfIccc1ga7rmsWd68EQYbOuyMMSB6Va0rUru+CRzrNgjLCWLaf8PwqbaXKur2OP+Gjpa+MjDGcrPbupA7YwR/KvY6848IaONO8aXtwIt0YleCPH8G75s/kMV6URXdGSktDzZwcXqLWdr9ml7otzG6byql1HuP8AJrTxSOiyIyMMqwwR7U2rqxMZWaZxmjrBcQLHOillHfmtK0NrHrkUYKRpHz1AyayZrb7Dq80KZVQ3y5PbqKqSstzdgyWs25RgOoAOPbmuHlfNY9aMk4qx1TPZSXBSby5AzEBwQcc96luXt7WELCgUY5IrBtJra2iaCLTJ1EhG5gob8Tg1bmO4BdxI7e9Q10Kb7lnR7WMXDXAXDSMXb3PTP+fSts1Fa2q20CqB82Bk5zzUtdtOHKrHmVqinK6JThevFZmqarHZQMI2DTkfKo5x7msecBchc7gM9azr8lJkG4YIzmtbmVjEs9d1HWoHu9QRFljkaIbE25CnGfzzW1aSWlymJ2Y98A1TggSOeSPjbIS6/U9R/WmS2JSUhcjPQg1w1Pjdz0KXwKxurLZWsR8lzjHc9KrRX8cNzb3E+RAJkX6kkAfqarWelln3SsWA7GtIaWNUuoLVEzFBIk0zdgFOQPqSB+GamGs1Yqb91tnWmmmqqXe2Qxvzt6kVZV1cZUgr0DzD/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-1.png', linkedinUrl: '/in/corey-thompson-f8d368eaf4', jobTitle: 'Structural engineer', }, @@ -2015,7 +2015,7 @@ export const peopleDemo = [ city: 'Cooperview', email: 'angela.webster@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-2.png', linkedinUrl: '/in/angela-webster-0702bee349', jobTitle: 'Chartered public finance accountant', }, @@ -2025,7 +2025,7 @@ export const peopleDemo = [ city: 'Reneebury', email: 'jenna.smith@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDvcV5X8T/FMizf2DZSlQFDXTqfXon9T+FemaneLp2l3V4wLCCJnwO+B0r5mvb6W+u7i7nYtJK5d29SaljQB/KHA47knk1PbCO5mChmC9WUjrU2haQ2sXSxqBjPzMa9Hs/AtnAobzXLdx2rOVSMdDaFKUldHlkbxJcsGYpzxkHFXkuprS4jlikaKRSGSRG/UGu81bwBazxZt3KMB07V5/eWkmlTyWk5yFPy5ojNS2CVOUNz27wT4mHiLST55AvrfCzgDG70YfX+ddOBXhXw61f+zfFsEbZMV2PIYehP3T+f8693rRGTMLxw0qeCNYMX3/s5/LIz+ma+cD90RjqTX1NqNoL7TLq04/fRMgz0yRxXg174OuNL1yztLlAW3LuZTwff9aUpW3HGLlsdV4S0qKxsE2p+9YZY9669FbbjFcnf3E2noFS3uGVuA0b7QPxqHQ9X1OW5SJvOaOTp5uCyj3Irhab949GLS907MhmUgVwfjnQ1ltmvFXEsSkn/AGhV/wASatqVlcCO380BRk+XjJ/OnWTTanYzx3UM4XYQXlk3buO1OKcbSFNqV4nA+Cws/jHSFZWx9pU8e3P9K+jq8u+G/hKLzo9amDBoSwjUjgk8Zr1Gu6LujzpKzsSEYNcl4xtoozDfMhyBtd+ygHj9a6881na1bm50i5iWPzGZOFxnPPp3pSipKzHCbi7o5eCSO4g8uRFI6HPNEENtFfRRQx8hgSQKpshtpmXJ+U88Y/Sopbyzd0Zb8W8q5zhup9xXBZ3seommrm5eQ20t68c6DJO4EjOagm2BTBCi8jHTArPt7y0kDeZfieZjx8/Q+wrc0O28+98xhlY1yc04xvJImcuWLZs6XbC102GPGGI3txjk/wCcVcxTsUYrvSsrI8xtt3Y+op7iC1gae4mSGJBlnkYAD8TSs7dl49TWdqemx6xYSWd0N0Uq8AjjIOR+oFNiSOT1y5huNQnuLaUSQvgh16HgVmC3NzhleEHGMsM8VrT2hhkaGRNjrwVxx+HtWHcWcscn7tmUE/w157k+Zs9OC5UrF2O2Ma4Z4yT/AHRXZeGri1eyeCORTcI2ZV7jPT9K5CzthEFJZmJ7tWt4bsDJ4mur+MFY0t1gdgeGbOR+Q/nV0Ze+Z4hXhc7I0VCJGWZonGSBnPtUPPP/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-3.png', linkedinUrl: '/in/jenna-smith-74d6913e06', jobTitle: 'Colour technologist', }, @@ -2035,7 +2035,7 @@ export const peopleDemo = [ city: 'Eileenmouth', email: 'johnny.lee@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD02kpaKgoK43xX8RdN8OStZQJ9t1AdYlbCR/7zf0H6V180qwQvK5+VBk155aeDNLmlmubi38+aeVpGeQ5OSc4qJ1FDc0p0nU2OJv8A4k+K7xi8d/FaoTwkEY4/E5P60tn8UPE1lnzbuK6H/TeIH9Rg16enhXRwgC6dbnHqmar3XhfSJYyG0+AD2XFZ+3XY3+qvuZvh/wCLGnag8cGrQ/YZWO3zlbdFn37r+tehKyuodGDKwyGByCK8D8a+FrXS5FnsgUif7yZyAa6b4SeJZWkm8PXkjMFXzbUsc4A+8v07j8a1jJSV0c84ODsz1qiiiqIMzXtx09VUn5pFz7jrVe2TYi1k/EPzv7PsgLmeGBpiHWD77tj5fw61Q8JzXbxNDLJM1uI9yPMMOO2DXLXWtzvwztGx1+5VXlwD9agndSuO59K4DWNOkj1F7gW1zORyAk5UtzjgZ61saXDdAjAuYx0Mczbh+BrJpWubpu9jM8T2/wBo3+aDsHYjrXI+GwLLxzpLwAk/aAuPUNkH9DXoPiNf+JTIW6g9fSua8N6PPD4m07ULhAlpE+4SPwScHGB9TWtKaS1OevTcnpqeyUUUV1HCZOt+XKYIZACOWwfyrJgvtPtrdibmJCXK4PbHar3ihTFFb3YBIRijAe/I/lXEW1zYDUGkLsbgtuZVXP8AKuWom5s9HDtezVjt7aW0uzhdrHPXqD9KtSrDAp2Yz7VzltqEczLDGz8HIzGVK/0rSeYmTbnnuTWT00N7mXqypcBYJORI4FWHAjs3LHep5wBnp0A/WqV/ITdIIyNw6Z6Vf0GefVNZuFkt1S2s0XJzndI3QfQDn8RRCLk0iZ1FBOTOvooorvPJKGtWb32j3EEfMpXcg/2hyB/SuLsbWR9hSQRjGWQCvRB1rgPFem6hory6pZsstkz5aMnDRk/zGayqwb1R0YeryOzNS4kSGDywVPHJ75rMmvxEpJdSPXNcgmtahqI3QW0yhv4q19M0e5lkSS8Ukjpl81zSikdak2aNrG1w8l04OPupn+ddj4diRNIR1UBpGZmI7nOP5AVjywrHbeWo7dq1PD0d5HbHfGBa9UJ+8SeuParw92f/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-4.png', linkedinUrl: '/in/johnny-lee-37995fae9a', jobTitle: 'Sports development officer', }, @@ -2045,7 +2045,7 @@ export const peopleDemo = [ city: 'Port Mackenzieshire', email: 'curtis.cross@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDm8EmkkkEEZdunp61JtOaytWm2zpEVzxWcnZGkVdjpdRZ95jfABxjpx9ayzq8q6kkbDaA3Y7ga1rPR72+ciBFWHGVX/Peo7rwdq8037u2YseOcYH41jzK+pvyStoVpb5xIxMuFU5C5A7Y4q5pGqPOFSWQHj5d3UgVftfhvezoJLyf58dBWXrnhu70KOOeNC8EfDGhSVwdOVrs2W55B4pFWqGiXX2y2fClQhAwTmtRVrdO5ztagRisXVwftsGOAeD71u4qC70RrxrO6V+BIEdcdATgH86mbsi6abeh3+hQRRadbYRQdg5xWyIlOCQD+FcvqF3eaevlWUDuVXI2rnpUehaxq95dxw3cPl7+c4xgehrk8zvVtjrHTavFcv4mC/wBlzKwByvOelQa5rWq2t5JDaQeYsYySBkn6Uy3urjUlMN5AyEr8wZcdRR5g+xwuhhjc3DDGz0981uAc1DpmlvZ2cksjZLudoA4Cg45PrVpVFdcGmjz6kWnqMNbOm5uNKZFxmCYSNz2HI/XNZLDin2l3NZSO0WCHXaysOCKJx5lYdKfJK7PQIDDOgVlHTvTVFtDfxomxMHJPArPsJx5aMTxtz+lU765srxgJAQ6E7WWNmKk+4rkXY9Fa7Gogt5dQmVyjEsdp4NF6sUCMFUA47CsOxns7OVxE2XdgT5ilST+PWr+pTDymc9lzQ1rYb03MW+QW9hFEON7FgM9B/wDrNZyc1Pc3El0ymQj5V2gAYGKZGuDXXCPLGx5tWfPK6IqAKXaRV3TNMn1O68qFCQoy7DsP8aszNDe8VlDIAdhQZI7GtJZEuLNF8/yjt4KimWVtJ/ZyRyoFYrkoDnHtmqNxplzESbZxsP8ACe1cV1dnoxuki45EUJQyiVh3YVm3EpuInK/cQcn1NEGn3coZrh9q9MDvVq4tHTTpI4VXcqZCnoSOaSaTQSvJMwziheDVu7027t7eC6e2eOOWJHI67CRypNUQxzXcAAAAAAHnH//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-5.png', linkedinUrl: '/in/curtis-cross-8df12d4c6d', jobTitle: 'Broadcast journalist', }, @@ -2055,7 +2055,7 @@ export const peopleDemo = [ city: 'Hansonfurt', email: 'paula.perez@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDJnmhjhZpCFVRkk1xt1qklxcsI28uPPA74961/EshTT1RDjzJAGPsAT/SuN+0MGKxjn+8aweprBJam1G0LMu+YjJ7g4/OugtZZLAobZY3Vh86mYfOPoe9ZXh7Rr7VXG3Ij/vMK7mH4ewTqn2q8fb2VOgrNtHRGDaucNcTtZ6gbu1Ro1LYdSOma3ElS5ijnfAYjGB3rt38B6edONspds87icnNcX4g0qXSXt4pW/d7tqyEUc1mJ07p3FIDrjHNTwRrIMHimyYSTjvT0kweBW5xMwPFeRp8RX7vmYb8qwtBs0vdYjjKbo15I9a7nUNOh1CxNo4bdK4CMp+6eTn36Vl+EtHex1a6ilKs0aDDLyDnuKxctzrpwdk3sd5p0aRoqRIBgdFGK37eMsgB4NcRqN1cWo8uGF2ZuM7iBWfpF7rKzReZJMqTchGOdgz3Has1HS5031seqRuQNoOO3NcV8R4fM0LplllTafqcVB4t1HVrBooLPzNxQMxjPJzxgVBcQXl14fZdQVxsuIyGLFt2DTS2ZMtmjJTAjiUnJVADmnSTKg4qRkRVzVVolJyDXStrHnPU0kDRyZYnYePpVuxskswvlgEleXA+93qi0pdQp4HrRYQ3Meuibz3a1lhK+UTwrgjkD3Fc8o31OqhVt7jOpheK4j2SRqc+tEkFvAUjijy7ckgdKhiXGCKrarfaWkSx3lwFfIJCsd36Vmrs7NDp7q2tpzCJgjboxhiAcEdqyPEM0f9ivCihQrrj8+1Q6bqGj3SNFbXRkuFI+Zs59h+tV9aIkmhhPUAuR9elXFe9YyqvlgznSPlwagYmNsnpWw9vGV55PtWXcJlyvT0rdM81mpFGncA1pRRRMikLyO9S6D4cu76dJ5BttUbJLfx47Ct7UtBVEkns0ALN5kqDufUf4Vk4Stc6oOPMrnPedsBQnB9aj+xC6I+dFYdGI5qSWMNyRnNReTLxs5X1rJM7E7FuK2FpEzyTxuBzkDpWRLI93dyTMfvHAHoO1dNp+nCSIqCVJX746g9qh0/RTq+nNf2KKk0btHPbZ4DqcEqfQ9cVpDfzOfEXkrmD5TR8tR/ZxmG8HBrRmt2G5HQq6HBU8EU61R2BXzP/Z', + 'https://twentyhq.github.io/placeholder-images/people/image-6.png', linkedinUrl: '/in/paula-perez-a4abb3240e', jobTitle: 'Bonds trader', }, @@ -2065,7 +2065,7 @@ export const peopleDemo = [ city: 'East Marybury', email: 'stephen.berger@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-7.png', linkedinUrl: '/in/stephen-berger-fcf9446666', jobTitle: 'Production engineer', }, @@ -2075,7 +2075,7 @@ export const peopleDemo = [ city: 'South Michael', email: 'candace.michael@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD02lpKTNIYpri/F3xCs/DT/ZbdFu788lN2Fj/3j/Sk+IPiW70Kyt4rI7Zbliu8DJX/APXXDWvw8utVzeX91ieX5yuMnJ9feolNR3NIU3PYL34o+IbwDyGhtIx1NvFuJ/Fs1paV8TNXQqLlYbtO+5djfp/hWdP8Mry2G+2uSzj2rDlsJ7CcwXimOReRJj+dZe0vszX2TW6PbNE8WaZreI45PJuD/wAsZDgn6HvW7ivm6a+e3mG1yChBWRTjH/1q9o8C+Jz4g0sx3B/0y3ADn++vZq1jO+jMZwtqjqKSikqyDzzxZF/aXjuxtHGY7O38/b6sT/8AWFdJYIUQEkVyvjeOK38UtcSCZhLZIu2IkEneQP5VJ4Rkuri4EH+krCVLD7QckfjXJVV5XO7DtKNjt4ypXOQK57xV4ah1y0zGyx3IHyt2b2NYGuQT2mpeY9vd3Q6hVmKjGfSug0qSSQKn2S4gGMbXOQaz2V0bbuzPF76wudNuHt5xhkJGDyK6P4e6s1h4ptFBPlznyHXPTd0/XFbvxI0oGGK/iX94PlfA+96VyPhDTr2fxNpsyQyCA3KZl2naCDnGfwreDurnLOPK7H0LSUUV0HKc/rcVu2pxtLGGdoduT6ZPFU7TUdNsGuTJKkWwAHjhR71e8SwMVt7hf4SUb6HmuXj1LS4L4s6eZMG52jPTtXJUT52elh7OmrHXR3FpdsMGN1wMMOQatvJBDH8gHA7Vhwarpl75cMGYnJO0GMpzV1omxtzkVi9NDayM3UoF1NhHJjy1cOc9OKZpNhGLy0XyRAYZCAEPDqRkf41JfXKWKGRo98aZL49MdaPB93Prsz6q8Rhs418q2QnJYn7zH9B+Jq6UXKSM6s1CL7s62ilpa7jyynqdq15p8sSf6zGU+orj7TT3lfcsoiP8Q967yuW8T2wtZI7u3yjSkhxngkd6xrR+0jpw1TlfKXEt/Kh2uyk9cioXuwo25yfauci1K8lYRc4Petq0tWUB36n1rjZ23Ket201xot1GgJmmXYoHvXSeGtM/snQbazwMoOcdzVO4Z4FE0ah3j+YIe/tXQIJVijM0flyMgZkznaSOldOHtqcmKvdH/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-8.png', linkedinUrl: '/in/candace-michael-a468f60b3c', jobTitle: 'Surveyor, building control', }, @@ -2085,7 +2085,7 @@ export const peopleDemo = [ city: 'Diazshire', email: 'jessica.lawrence@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1Cop54raB555FjijUs7ucBQO5NSmvLvjJrklrplro8Em03RLzAdSo6D8/5UAZ/ib4uyyPJaeH4dqfd+1yDLH3Ve31Neevr2ry3X2hr+7MwOd5lYkGtLQPCM+oRrPO5ihPIHdq7m28D6bHBjyi+R95jWbqxRvGhOSucNb+PPEVlLuj1a5+bBIdt4/XNez+CfGkHi6wkbYIbyDAmiByDn+Jfb+VcHfeB9OMJCxsrDowNckn2zwX4itL+BiVjkByONy91P1FONRS2JnRlDVn0jSiobO7hvrKC7gbdDOiyIfYjNWKsyA14d8VmN347t7VsFIrdMD6kmvcu1eS+OrFD8RbO4UqwkgCyAclWXJGfwxUydlcuEeaVi3pkGLWJEH3QBXQJG/lgA81xl/fCw+SW2mkVhkFRwPp70zw/LdPego8ohkwdsjE4z/WuPlduY9HmV+U628hZkKg4OOa4HxhamTTnBTLJ8wq/wCIbq5+3OpMogh+8Iidx/Cs/wC0DUrOe3WCRNsZB3HOcj+dVBNe8TUaacT034dXL3XgLSnf7yRmP/vliB+ldTXL/DoIvgTTI1UqyKyuD/e3En+ddTXYeaxRXAeLbV01xpyPlKq2cD02/wCNd+Kx/EOmPqNqDGUBjBJyMkjrgflUVI3WhrRmoy1Oatfs93aiOVFP1GRVeW40+zu4oN6QJuGCRjee+KrWu5OAeOool1IyN5MWnSXG3qSuFPrgnrXEk27Hp6bjZZrGfWJkMscqOeg6j3xSX0FtaxFIUUZ7iqX2kQXG19NeDd3VQfzx0qaKCXUNQhtg2DI4UEjOM1VndIltJO53nhG2+zeG7ZcY3lnx9TW5VXTYZbfTLaCcqZY4wrFemQKt12pWVjy5O8mxBRx3oqK5ie4tpYIzh5EZFPuQcUyTzK/f7JqFxED8qysBj0zU0Rs7iIme4dVx0Xg1Vh0ydbVYbsETqNsmezjr+tZd5ZXlux2jevrXA7XPVV0kak4soEJgkY/7zZqCy1iPR7tNRmilligy7JHjceCOM1l20NzPJgoF9SeTWhJAEi2ev61SdncUk5Jo9N0LXrLX9Kg1C0YrHMDhZOGBBwRWqOehzXCeHbM2XhyFSu1ftbMgHHyk/wD6662F2HBJPvXZzHnunuf/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-9.png', linkedinUrl: '/in/jessica-lawrence-61fd28400c', jobTitle: 'Regulatory affairs officer', }, @@ -2095,7 +2095,7 @@ export const peopleDemo = [ city: 'Garrettfurt', email: 'victoria.west@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDzyVTmqzA1flFRRQ+bKFzgdz6Um7ajSuSadpst7IAOF7nFddpnhfT1YGeUSH0dwo/Suc/tRIh5UMoiiXgleWb2FaVnbXF2EeCA4/vOBn9c5rhqVZvbRHZTortcua/pGnW8W63KgjvE+R+RrEk0ESaf9qs5i5/iQ9fwrYj8J3ivI/2vPmdUC8U3R1n0+a7sJmG7G6PP3W9jRGrJLcqVBdUcVICrYPWmDNb+u28UkguoU2EnEiehrHEftXZCXMrnHKLi7MvsKq3FwLeMqPvOMZ9BV1hgnNY2sZSQMO4wKmp8Nh0/iNjwzpIvSLqfLfMdi9sV6XZW6xQgDAx2FebW889hoNqsUTtJInUNtA79a1fCt9qU13BDOzlJTkbiSVrinFvU9GnJK0T0GPAJOQK5jxNb+XGbxOCg+YeorD8VXd/BevHAZSE7K5APPYDrVqzuL29s5LO6icHYQGJyDx61PJZXLcrvlKaGDUdNkkik3MVOcjnNYgWn+HZGt7ia2cEFWII7GnuoWRwOgYiuuhpdHn1ujJZfmNU7m1Wd4t3HzBcn34q8y80+NVJGQCM9DW048ysZQlyu50GmRwtaJbyIPlUDntWhYC1tdZhDFY0X5snjNYml3gv4vtKqUO9kZS2cEH1p95e2ElwolSR5I8gMiElfxrzbO9j14tNKx0qpZ3kzqxjc5JVxg55pbo29tGVRRnGBgVkabf6TGnlQI0EjHOHQqSfWrd6wVWmbkRoWx68UmnexWiVznLq0S3SSdhtcyEoe5BGT+orGbLMT3JrQvb5762hd0Ebc/IvQVnkV30I2jc8vET5pWWyLDUqHBrvX+GV0lwqyahF5Z6lEJP5VqJ8PNOjsLiBZZHuJVxHO+MxntgdK1cjGx51o1uLOK5w7ESSFznsTWtFbx3H35tmOhqxLYfYpXtnQq0fyMD1zWfLE8T/u686crybPVppxijTSCKCIqJt/4Vl67LM2npGjlfMkCkj06/4Vbggk2BpTnPOBTbiA3VxZ2mxi1zIY4iOz7SRn24ohZzVxVW+RtHPsMoq9QowKgK4NWZVZGKsCCDgg9qiIya9FJJWRlN3d2f/Z', + 'https://twentyhq.github.io/placeholder-images/people/image-10.png', linkedinUrl: '/in/victoria-west-4514ebe192', jobTitle: 'Therapist, sports', }, @@ -2105,7 +2105,7 @@ export const peopleDemo = [ city: 'New Brian', email: 'matthew.matthews@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDoGprMqKWYgAdSeAKVuVrkvHGoyWtpbW8TYaZyXA7qP/r0SdlcIq7sZWv6415dSosh+zxnCKvQ47nFcfczm5uyCN23kuTjj0zW3YWsmpSlGQhDwAvVifWuig+GTSWgZpsO3OMZxXNzq+p1Km2tDkYrWJUUhowDyPnrTVw0GyJwSOmOfw962h8PLi1Vh5+8Ecgjg1iX9pJp0u0EsyjBU9vQ1PMmxuDSL3hnxLLZXv2G6bfbOwVfWIn+leigV4S1y4nEythgf1r2XQL5tS0K0u3+86c+5Bxn9K6Kb6HPUXUv54rhPHdlM1zaX68wqhjb/ZOcj867gmsvXbYXujXUJySE3jHqOac/hFT+JFrwvolrHplnN5f7zaHJPqRXWqvAHauOvbjUdOgiSyErRiMbPLQHoO+TUuga3qmoTCC4tikhXduK4/8A1GuLzPRXY6t1wp6YPrXI6z4bgvZ/O3+WTw2B1FRav4g1a2umigtmYICWITdnHpz1qay1K9vwqTwSISM/PHto8wfY8k160Wy1CWFOzFST6+teo+EIzF4VsAQQShbn3JrE1bQoNQ8W4nDLb7FZ2A4J7Cuws1aOziRwoZVAwgwB9BXTSld2OStBpX8xKYhCyqWGVzyPbvUlRkcmtnqc6dnc2bb7PLb+WQpReBn0qS0WBbwrAgAQckDvWTbttB5wByRVe4vLWTBhvBBLggEsRn69q4WrSaPUg1KKZrqkD3BSZRuJOMjrT7kQ2sf7tQM+lYFrc2FuGBvPPkZupckg+2elaFy25VJbg881L7DZWhEbyvv+b0XH5GrQXimWqjysjuTU+BXZShyq/c8+vUcny9iqKYR8xqQCmykRRvK33VXJrUxILqX7NGjjOXkWMAdyxwKseW93AuyZYmAxkj9Ko3ayT2ST7cvEUuAo/wBkg4/IVcu7QXEaXFvKUDjO5e49cVyYhWkmduGk+Ww5YWgjIkmRz64qoha5m2KxKDqaqrY3TykT3YZP9njNakEUdpASOABkk1g2b3b3M/S5ZY9Y1eFzmJZkKe2UUmtdJVkXcjBge4NY9ijCO5uH+/cSl8e3AH6Cm21wRdTCJXZA3JHQH1r0KatBXPOqACpZzdj/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-11.png', linkedinUrl: '/in/matthew-matthews-42bbc7a5f8', jobTitle: 'Pathologist', }, @@ -2115,7 +2115,7 @@ export const peopleDemo = [ city: 'Powellfort', email: 'megan.lopez@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDUzTJJY4InllYJGilmY9ABS1x/xGvXttAjt0k2m4l2sAeSoGf54rMs5PxR4xuNYvGhs5HhsU4ABwZPc/4VzL4yOTz6Vp6PoN5qvMUeI/7zV19t8OozFma4cuf7oodSMdCo0py1SPOiArYJ4xXUeHfHV9pHl29xm5sl42t95B7H+lblx4AtwnyuwIri9V0i40qYpJGQh6N2NEZxlsEqUoas9xt7qK8to7iBw8UihlYdwaecVxfw1u2n0S4tmYkwTcewYZ/mDXaYoZKHV5z8To/9J0193G112/iOa9Grj/Hmkm9Swul5EMmxlx1DEf4UXsNK+iJ/DkCx6bAFXB2g4rroUITDCuLnP2SNcJcOzglFjfYBgevrWjoN/qYkRJ5naKQAhJMFkz0ya5HH7R3xlb3TeuU+Q4H4muD8Y2/maZJgA7Pmra8QajqDPIkEjrHDndsI3N7D86w3jN5ZXK7ZldEO/fJuByP51UFb3hVHdOJB8LSv/EzUn5v3Zx7c16LiuS8AaQLDS5Lh1/fTkAn0UdB+tdgRXTucFraMaKiuovPt3jxng8CnSOQQi/ebpVth5MAihiaSVvvY4z+JoauhxdndGRpywTWoilQMR6jNTTxRRXUMUKjOQTtFRTw/ZNSljXjD4IHbvVS8vbdJwGLiVeQUByK47a2PTi1JJk8EMcmpXUcijO7OG71X1aGGO2MMCAFuMAdaitbyFrpgjOZH5y+cmrttB9v1FUYjozfkP8cVSWtiZvliyxpsbR2SKVwcZNXccVFpsd1bgR3kfI/5aL0b6+lSXpe1YSL80TfpXWtjzW23cemLjWppCBtViFA6ADpV6M8ysOvSoEhFvq88fqW/nU6JslbP3TzQCMHWoZWuodShUtb3cKkkfwyLwR+X8qpwQwXS7pJCpGeR1FdhpMcSzTaVdrut5yZIs9j6A9j3rJ1rwm9vcg2ku4SZ8tOdzEDJHpmsJ03fmR1UqySszAuIILXcyOSe7HqateHAZLy9u2yFggIHPQn/ACKy5o5LcM0iyMynADg9a6bRrD7P4Mu7hwwnnOSSMZUnH86mmryHWl7pqploIz7A064tkmheMr8rCnWyg2ERPXbirMYDID6iuhHKz//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-12.png', linkedinUrl: '/in/megan-lopez-936955bbda', jobTitle: 'Ophthalmologist', }, @@ -2125,7 +2125,7 @@ export const peopleDemo = [ city: 'Michelleside', email: 'kim.campbell@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-13.png', linkedinUrl: '/in/kim-campbell-7d447d5ec6', jobTitle: 'Recruitment consultant', }, @@ -2135,7 +2135,7 @@ export const peopleDemo = [ city: 'Jamesberg', email: 'william.ryan@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-14.png', linkedinUrl: '/in/william-ryan-a5c6cbc922', jobTitle: 'Ergonomist', }, @@ -2145,7 +2145,7 @@ export const peopleDemo = [ city: 'Castillostad', email: 'lauren.walker@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDtTiijNITgcVQjivG/jb+wx9g08q18w+djz5Q9ceteO3s0t9clmdpGY5Z2OSx9zW3LYXGs+K7u2VnMrTOWY9QAeSa7GP4d2wsfLMpMuM7iOhrKU0jaNNvY81hhKnBHNW0Ow4YFT2Irr7j4byQRl4Lpi4H92uUvYJrQvBONzqcehqVJMpwaRXacqewcHgg4P4GvYfh34pk13TZLK9k331pjLN1kTsT7jofwrxIvkHafqCK6TwHqJsPF9i+7CSt5Dj2bj+eKuLszOSuj3btQOTSYNKK0MzyvwjAZPEGuXUikS/aGTGPu/MTXoC7sDvWD4rtW02U32nW58+6IEpR9oBGcMfzqv4c1TU7/ADFdwlXCFlYd8etclSLu2d1GS5UjqCSR/wDWrk/E/ha31WEzIxiugPlYd/Y1V1TWtetbp/JjJROSEXqM449a09OvrzUQUmtplKnBZsEfmKizSuaNpux47cwSWl1JDOu2RDg1Y0RXbxBpypklriPG3r94V23jTQDczwzW6jzPuuaTQfD8dpd6STteY3qMzBcMjA5wD6YB/KtlNOxzuk9fI9YHSlFIBS4roOUo6ksbNGJVBRgV5qtYwwwyTNCoARMcDHJq/qEBns3UfeA3L9RXJTz2hJWW9aBiMNgnJ/wrlqq0vU7sO1KFuxvm2tbziRV3p1DCllkhs4SsagYHYcVmWd1pqx7Le9EshPVpMsfz5qe4haT7zHHesW+h0WRlyAzzF3IUHpnjFN8N3MOr+Jy1oQ9rp8RJk/vyMNox9BmpbiJZUlUKCoQgZ9af8ONEl0nQpprmMpPcyltp7KOB/jWtGN5XOevNqNu52A6UuKUClrrOEbXLahpyQXpDzNGjfMhH8q6vgVT1CS2KCKWFZmPRCOnv7VE4cyNaVR05XOejhgt0J85ZCf4mAzUD33nN5UbliTjjtUd9BAbx0RAiDAYDoDin2sUducIAxFcUlZnepcyuXDB5dvjuetM0yHVIdb3x3LHTfK+eJjkb/QenrV6C3kuRk8Ie/r9K27Cw3usSj5Ry30rahCV+Y54rzjblP//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-15.png', linkedinUrl: '/in/lauren-walker-74bbb465a8', jobTitle: 'Nature conservation officer', }, @@ -2155,7 +2155,7 @@ export const peopleDemo = [ city: 'Garciaport', email: 'jordan.castro@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDp6BS4pQKRRR1fV7TRNNlvrt8RxjhR1c9gPevL9Q+Jut37sunxw2cXbA3v+Z4/IUzxHPd+LfFk1tCStrbMY0DHKjHBbHua07P4YzMok+1RnPUbcVnKoluaQpSlqjmF8X+JBP5n9rXIycgFh/LpXTaN8T7uCdIdXRJ4mYAyxrtdB9Bwa6GD4YWRiBmuJGbrgDiqurfDe1+yv9mkAcKdu5e9R7aJp9WkdnZ39nqUPnWVzFcRjgtGwOPr6VPivFfCd/ceG/EEYllZbd5PKuFJ+XGcZ/A4r20itk7nO1ZjMUvRSQMkDIoFO4VSWICgZJPQUAeWeErYMZZmHzvKSx969OsQVi55wK8vtBcWdgoiMuXd9piAJb5j611HhnUdXe9htL1TslXKu4wQPQj1rimrts9Kk7JRO7ic9qqagQLd2X7wBNctrl1rlpdYt3leEDOIsZYegz3q9p1xeTKqTRToQMkSqM/mKhrS5d9bHkniCItcyuMht+5gOxr2vTJHn0mzlkJLvAjMT3JUV5r4n0O4uPFDW2nRg+eocA8KPXPpXqFgUfTrcxsrKIwuV6cDFdlKSasefVg07iiiePzbWWMDJZCv5ilFSLWhktDi/DywSWa28yDfHxg9jWvZ3FpHrzJJNFGY4iQpOKw7iN9K1y8DtuBJmXaMZB5xWaiS6hqLXDKRKAQqrGWAPua4nHWx6sJc0U0ei2t3Y3wUrJFKGOFZSGGfTNXLhIoYzs6kVxcF3dafbMrRyvGWB5hI2nPXNbt7qsUdspyC5TOPfFQ10KbtuZ1vEJtdupo3/fW8SgAjgknOD+VdBaxLDbhVGASW/M5rm/CwkuJ76RsbWYb2xyT6V1OMCumjBr3jixFVNciIl6U8UwU8V0HKcj46s7iO0XVrVd3kIVmX/Y7N+B/nWPZXkN9aoVumjlK/Ns6Cu51uaCDRLs3DhUaMoM9yeAPzrxxrC6t7gpZSYDHIjP8AIVz1UrnTQlJI9In1S2tdFaKOVp5mUqS3fiuSl1m4uvKhgcPJjbtHWqllpWtX7eVITAvdhyce3pXZ6H4bjsgCUHy9/esdIm/vSNrw1Zm005o3OZN2XPqxGT/Otdq5p49WbXbWGwldYWYtPjBUKOuc+vT8a6MEkc8H0rqpO8UcdQBWi4zZ/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-16.png', linkedinUrl: '/in/jordan-castro-5db609defa', jobTitle: 'Research officer, trade union', }, @@ -2165,7 +2165,7 @@ export const peopleDemo = [ city: 'Joshuaport', email: 'scott.williams@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0fFGKdisfxNr0HhvQ59RmUuVwscY/jc9BQBDr/i7RvDSgajdbZWXckKLudh9P8cV59f8AxluG3f2dpMSIG4e4kJJH0GMfnXDpYaz4u1Se6Ie4lZsvIW+VfQZrfh+GWqSoolmhjGOQCTWUqkV1NY0ZS1SNWH4yaismJ9GtmXIzslZTj9a9L0LxLpfiO2E1hcKz4+eFuHQ+4/rXjl58NtViQCOeNwvI55Nc/bNqHhTxDbXDxslxDIJBzw4B5GfccU41E9glSlHdH01ijFVdK1O21nS7fULRt0E6blz1HqD7g8VcrQyCvKvjFqErNp2kKQsLg3EnqxBwo/nXq+K8p+L1qsup6GwQ73Eibh3GVwP1NKWw47mr4RsYbHRLZECgsu4+5PeukGT0wfpXL31uLazVWiuJgqDbDCcdB3NTeHmMJH7qWJXAYq7liM9j715zV/ePXi7e6b8gODkAfWuC8c6bBc6czlAXQ7gfStPxDO91JNlZ3jh52wthj9KzZ4hd6ZMim4H7oh45zkjI4INVFWsyJu94k/wZuZXg1S0EjmCFlYI3RWOen5V6pXmPwWjX+ztYkK/vTPGGb1G04/rXp5Fd62PLe4orjPG2mvqVzbHAb7M6SRL+Pz/oP0rtBWbq1kbgxzIjOyAjC9R7/wA/zqKqbjoa4dxU/eKFugkiXoTjvVO9nt7SeJZCw3uF+RCf5dB7mp7JikA3ZDAYwaz7u/VHKmOSVgeQicfnXAlrY9Va7EVrLb3GpTCNiRnA3KR7/jT9SijSBsKASOcVVS7WW6wsckMhPAZeD+NT3wkmIRVLOxChR1JqrO5MtFqTfD7TV0mC6t4wQjBXfn+PnP6fyrtDWT4dsDZWLl4mjeV87W6gdv61rmu6nflVzy6zXO+XYKWijIAJJAAGST2qzE5W7k8q/nBOAZGwe3WkLJNEUY4J6EU9vI1NZ5YWEkMrF43HcdiKovpV8q5gmV1HQOORXmytzM9eDaihZQkQwG5A6ml0N/tOuQA8hNzk+4HFUp9OvjGWuJUX/ZStHw7GlvrCISATEwGT1PFXTtzoiq3yM7CkNKaSAAK7zzD/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-17.png', linkedinUrl: '/in/scott-williams-0c2a344935', jobTitle: 'Bonds trader', }, @@ -2175,7 +2175,7 @@ export const peopleDemo = [ city: 'Webbfurt', email: 'peter.thompson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDrcUmOaeFrmfHOqz6T4fP2Ztk1w/lBu4GDnHvUjMTxH8SBp9/JY6VBFO8RKyzy52BvQAda4XVfEura4u27upHGf9Wh2p+QrofC/gy1vrdbm+Z38zO1AcAD/GuqT4d6dE6tC7gd1bnIrN1op2NlQk1c8mj1bUbGZLiG8uPMTgMJD+Rr0vwn8Qor9Y7LVpFS4JCrNjAb03e9XD8ONKVGL72JOcA8Vy3iTwZDZWzXFiXEkXzHnqKSrRbsDoSSuerkZ5pu32rnvAuryatoRS5kL3Ns/lsSOduPl/z7V05WtTEeK4L4nEiDTAfub3J/IV34WuQ8fWv2y0soguWjmDk/7JO3+opSdkOCbehJ4eUJp0AIwSoI9q6dN20d/pXCaib62cJbvOibPlWFRk4Hqan8NX+rPdxQ3M0jRvyPMA3L7HFcfLpzHoKWvKdnJu2ntXLeIziylwM/KcgVS8RXmrG9lS2mlWOEZIixk/T161W05ru4bbO85XblkmA4z6EUuXS43K/ui/DQMbnVmH+qPl4wOM/NXoOK474f25s0vY9mRNKzhvQKcf1NdmQK7Yu6POnFp6gDWP4jgaaxyo5Xk/hz/StgdKZNAtxE0bZAIxkUTjdWHTlyyuZtoILu3UMoJx3FLFbwx6nGkSKNp+YrWTayvZmRGJ3RZGPXFZ896l5Mr+fHBKvQh8EZ/wA9640nex6KkrXR0It4ZdQlSVRlmOCe9JqMcVpbkIoBx2rnLS7S0uHb7THM7tk5fnPtWreytcqijrJgAfXihx1sHNoXPDdusUBfbg7eOfXk1tk023s47SPZGCfUmnke1dkI8qsefUlzSuhF6U9eTTAcDFI1zHFwTk+gqzI5fxKfsmoNIowsiAsQPwP8qhU/abf91NHDIAMMRnj6Ukrz32rX32hyyiTYiHoi4GB+uazW0+9tywt2U7D9w+nbFccmudnoU7qKZrvtgt/3rxSyY5O2qNteqbqO4kY/Z4GDuwGenp9KgOmahIQLl1Af+FOp/GtP7CiWhhCjbtwRUuSTuVZy3Ossr+21O1W5s5lliboy1Ntyea5fwtaNo+mqqsXWR2bDdcE8fpXRC5Vzwdp9DXctVc85qzsf/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-18.png', linkedinUrl: '/in/peter-thompson-341acf2282', jobTitle: 'Waste management officer', }, @@ -2185,7 +2185,7 @@ export const peopleDemo = [ city: 'Seanside', email: 'jill.williams@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDb1/XbTw/ppurjLMfliiX70jeg/qa8f1fxFquvz/6TdbYs5EUXCL7D1Puat+OtUfUvE9yDITb2v7iJe3H3j+f8q5qOVWJ3EhB2BrFs1ii7K1naw4bLs3RVHJ/Gs7bvkJjUr7ZzirZj3Tcj5iOg6AelTC1lO2CGAuz/AMKilexVrjdJ1u4srxXjnaGUH5GRuPx9a9l8L+KBrsDQ3MaxXsQG4Kflcf3hXmifD7UpLNLhkChvmAHUVf0qeTw3rsErt8iKUmRupB9P89qSmr6A4O2p69jFPU1FHIssSSIcq6hgfY1KBWpkfOuukjWL0SAmQzuW596oE7FGcbuy+ldl4m8IX0V/qN5H+9w7SbR/ChPGfWofAugG/wBTlnvIwUgHyqw43Vi5JXN1B6eZh6PpV/rOox2ttC7v1LY4UepNezaH4PTTo4i675VHzOajnuG0WPbbW0pZuiwIo7d2PFN0nWNdNxC9w58mYbgrBSUGcYbAGDWbfMrnRGKjodqLeNoPLEfavKfihp0Vo9vdRrhp2MZGPTnNdv4m1nU9PSCKwiDSysMvjhQa4/xXaahrOn6YjpNJci8KAMVKscfeBGMrxQt0TLZnXeHBInhvTlmGJRAu4HscVqBqjjUrEgPUKAcUvIFdKOJmdqdqt3EVwf3hVXxxlQen61nWmmR6Ze3EkKbY5SpK+hAxWpeq0tnMiOyOUO1lOCD2IrnvC15eX2mmTUZmkuPNeKQsMcqcdO3GKwqxs7nXRqXiovodrbCG4jw6gj3qO8ht4doVFDHnAHJqO0RkwAaiv7nTpCY7m6CSDg7Xww/Ks0dKSNBI45Y4WlQEFeCw71DqEUUn2cgYMUm5cfQj+tVbSWydfJhuzKR9zc+TViVsyKp6hauC96xlX92DFXkc0pUdqTvUojyK6TzyisZkXHrVWHTIoHmgiG3JEn446/pV6VZhbsLdlWYjClhkA1FaQTLOzzE7z1JHWsaz0sb0Frcjt7ooRG52up71aazS6G5lTPY45qO/sFnlVvuk8ZFSQaXdRx5N18o9qwV7nXzW1HR2SWgzhAfUDmmEs8hc96iu5Xs5LZHfcjvtdm7Z6H88VZdTGcNxW9K2rObESbepIE+XNODkCq6ynJ//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-19.png', linkedinUrl: '/in/jill-williams-15b1d79aa6', jobTitle: 'Pathologist', }, @@ -2195,7 +2195,7 @@ export const peopleDemo = [ city: 'North Kimberly', email: 'joyce.diaz@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-20.png', linkedinUrl: '/in/joyce-diaz-c25c3d067c', jobTitle: 'Loss adjuster, chartered', }, @@ -2205,7 +2205,7 @@ export const peopleDemo = [ city: 'South Andrewchester', email: 'robert.owens@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDu3IFRnNOkzmo5JVhieSRtsaKWZj2A60hlHVtZstDsjd383lx5woAyzn0A7mvNdU+J+r3UrJpUCWkXZmXfIfz4FXpbCTxlevqF9M8dqGKW0Q/hX1/GtWx+H2mxNuaSWTPY4qJVEjWNCUlc4uH4ieKbSXdLdxzr/dkhXB/IA133hfx5a66VtrqMWt4eFGfkk+h7H2NPb4e6M6nMch/4F0rD1jwJZ2dq09g0qTRDcvzdcVPtkU8PJHo2CaUDmsHwjq82p6UVuj/pVudkmerccGug5J6VqYD344NYPi12j8MXpUkblCHHoWANdJOo6Cub8XFDoE1u2fMmx5YHcqQx/QUm7DiruyMbREC2MKgcbRXU2y5iGDnFcHqLTW+2KOW4jQL8i26bmJAq74evtTknjtp2lKNghplAb6HFckl1PQi/sncKTjGcVk6sc2kgUc4Nc9r91qcV80UUt0IlBOIMc+wz3qzptxPcKiyfaxxkrcoAceoIqbaXK62IvBZI1W/Cj5WQdfY//XNdyOnSuN8NwpY61ePIdqTP5UfHVs5x+ldkPpXZBpo8+pFp6juWOc1keIoTLp4kVNzxtlfxGK2V4HIqK6hFxbvFnbuGM4zinJXTQqcuWSZzen+RcKFlUE47inJLax6vHGGjjVe2QCfWqTRSWd3JDnJQnnpmqbXFvNJtmgmZhxlYjn8DXHZ3aPTi00rHQrc2UtyyO8UmWK5BBwfQ+lWrpIIYf3YA47VzsFzbQxtEttMN3VjCcn3zWlLkwqGfIxmplpoP1HabbebcRsTlA3mYPZh3H510WKqadY/Z4UcsS5XpjpmrxGB0rrpQcVqefXqKctOgoBIoCY604sO1N3fnWpgc/wCI7QJsvEOCTscfyNYsUazqC0xQjoR1rrNY0+a+04iJcyxsJFX+9jII/ImuFubedP3tu+PUHpXNWjyyuduHk3H0NuJUgTIm8w+pqGW4DKxByiAs34Vk2lrezSfvZlUH+7zXS6VpDahILWND5A4mkPTHcfU1ileVkbt2V5bG/azmezgmKFDLGsm09sjOKmJBFaF1axnYAu0AYGPSqclrInT5qxxPKuf/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-21.png', linkedinUrl: '/in/robert-owens-39e8664408', jobTitle: 'Land/geomatics surveyor', }, @@ -2215,7 +2215,7 @@ export const peopleDemo = [ city: 'Chadport', email: 'christine.fernandez@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-22.png', linkedinUrl: '/in/christine-fernandez-4bde5f26e0', jobTitle: 'Theme park manager', }, @@ -2225,7 +2225,7 @@ export const peopleDemo = [ city: 'East Robert', email: 'gary.jones@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-23.png', linkedinUrl: '/in/gary-jones-a993bf28c1', jobTitle: 'Community education officer', }, @@ -2235,7 +2235,7 @@ export const peopleDemo = [ city: 'South Stevenfort', email: 'ronald.brown@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDtpyccVXZyRjpVrAcZJqhcHY+BUsAZljBZmAA5JPasK98YWVtGWt8TYOC+cKP8azvFl3PcvFo1mCZZhulwcYXsDWdb/D29uIAs9/GFP8KgnFRKajuawpSlqkacXj+SS7RBFD5bDgBuSe/Wt3TfFljqEzQk+VKpwwJ4zXPxfC9QuIb0iTrllFULvwDfackt1Beb5kGenX2pe1RboS7Hp8cgdcqQRViLFeTeGvFU+nyrbyvvjDYkSQ42DPJFeqWs0c8SSxuHRhlWHQitU7mDViAgqnXmqxVc5fk1Y3kjkVH5Rl+lAjjbd1vNdu7hMMS20Y9P8iuwtIxsHz8+ma8+v/O07U9VSCR0RJlQeWuWPyg4H51f8LXmp3V3FbzmTaylwZOoHvjpXHUXvNno0X7qR3oAxw+D6Cs+/lKRMBXC6zLrSaoUhe4eLIUhZNoIre029upQLe4ikwvAZufyPcVm1oa9bHHaraRR37XUcAcSgh+cY+ldn8P9Wa8trix2bUtwCmScgHPHPvXOeJ7dbW84yEdTIO+PXj8q0Phsrvrt5lWQfZQ20jGct1xXXSldI4K0bNneug29KSDpgCpXO4YHehItgrY5zl57WKDWr0TKGE8glXPuoH8wadaX2naZfTea6owj6DqB61L4hRlvIp9p27Nu6ubFxbXs5kNu8xHG1I84wehPrXFOL52enRd6aS3Or067sdVTfbyCRcZVwCPw5qaSeGDO1Bu9TWNY6vFC0dr9leIE8boipB+vQ1bvGQ5IPSspaGy13M+6jFzKZtqvIikRq44JPQVueFNLgguri/ETxysgi2M2do4JHvyAfxrl9T1N9LtJLsRCVYxyu7HPQYP1rtfCpnl0GG5uQqy3BMpVRgKD0H5Vvh4tyuc2JmlBx6svLGBTitPGBRxXYeeZerWjXWnSrGMyKNyj1IrjYIvMQKbgw47LXoxxiuC8UWzRarP5PysQr7enUVz14r4jqw02nykxKQwhROJfciqs14WG0HJ7YrmmuLvcVCNn0zW7pljPtWWcBc9AK5GktTsUmzZ0vTYLuWGO7QSIG8wqehI5H612idMDpXK29tPcjybZyk8nyxsOx9fpXXtaGz8qPeXOwAk9SQOTXXhH/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-24.png', linkedinUrl: '/in/ronald-brown-921558ef53', jobTitle: 'Arts administrator', }, @@ -2245,7 +2245,7 @@ export const peopleDemo = [ city: 'North Noah', email: 'curtis.oliver@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-25.png', linkedinUrl: '/in/curtis-oliver-1f7c8563a6', jobTitle: 'Oncologist', }, @@ -2255,7 +2255,7 @@ export const peopleDemo = [ city: 'Kylebury', email: 'stacy.vasquez@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDLOabzU5TFZmq3X2dBEpwzDLH0WlKXKrhFXdiU3aB9ifMfXtTLi+FuuSyk1z6Xh83joO+eldBY6ddX9qTbqWd+Ayr0/E1zOb3Z0RgtkRQ6w7ttkiVM/d54IrRVxIm4Cqlz4L1ZbZZAmWTkndyagtrw2rCCcYJ9eoPcGqjV1CVLQ0tpPNPRTmrcFv5qK6nKsMirSWfNbnMVyihSx4AGSa891bUDcXMjg/6xjj2UdK7PxBefZNGmK8PJ8g/GvOYA11drEpyzt5aD37msqmrsa011Oi8L6DLr16AQRaxkGRv7x9K9psLCK0t0jjjVVUYGBXDWaxaDoscHkSyllztjzk+vTvW1o15JEUz5qRybTtdicZrnlrqdsLR0OpkXdGRivK/iDpTWc0V9CMJI218dm7Gur8R6i8aN8s7qh+7CSCfyrF1UDVNAubeOGSORUJIkbIDAZB/z70kuoS10KHhXUDcWLROfmiP6GukEgrzrwtd7L4qrArIuOD3FdokjetdkNjgmtTl/G1wI47eEH+8+P5VgeELM3GuxzNzHbnv3NXPGbO2ttkHCxgLWb4X1qHR9XkNyZDBMoTCgEbsjBP61ErtOxpCyaue56fFFJCvAyO9LeNb2s8XmyIi7h8zEDknj8ajsVwqlTkEcVHearGkwiaxknYeqcfge9ca10PRSvsXYntLi/lCSo/Y45wah1SGGG1mIAztOfyqC01KF5DH9ilgY9CU4/OotfvobHT5bm6mSJFUhS/Qtg4HvTs72FJcu545pRa18QyQj5Qsx49K9DR8mvN9GDy6i88hJkZ9xPqSa9HhBIFdsN2eZU2RxnjC6jk1byccqu0n9a46Rcbj6133iPwrf3WsSy2VvNMrnJGzG09xzWba+BtTuJVNxGIkzzzk4qOdRepai5LQ9T0yVrewt0YnHlqQfwrViEE4y7ZB7elQQ2gFnGgHCqBimGwf70ZIFcdzvWhdlEFumVcYryT4la697qkOkxZEVviSQ/wB5yOPyB/WvTzZmNQ0hLHrzXiHiOUz+Kr+YjrMV/Lj+la0dZXMa7fLY2fDlkHnEhHGCfx7V3EMRAHFYHg6MSW69znn8q7SKAY6V00tKu9j/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-26.png', linkedinUrl: '/in/stacy-vasquez-72e5c629d2', jobTitle: 'Engineer, biomedical', }, @@ -2265,7 +2265,7 @@ export const peopleDemo = [ city: 'West Jennifer', email: 'susan.hancock@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-27.png', linkedinUrl: '/in/susan-hancock-00b3694621', jobTitle: 'Charity fundraiser', }, @@ -2275,7 +2275,7 @@ export const peopleDemo = [ city: 'West Heather', email: 'amy.conner@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-28.png', linkedinUrl: '/in/amy-conner-65d26933e9', jobTitle: 'Web designer', }, @@ -2285,7 +2285,7 @@ export const peopleDemo = [ city: 'New Kelli', email: 'keith.stein@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-29.png', linkedinUrl: '/in/keith-stein-dae7ba0be7', jobTitle: 'Airline pilot', }, @@ -2295,7 +2295,7 @@ export const peopleDemo = [ city: 'Kristyshire', email: 'kristen.lane@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-30.png', linkedinUrl: '/in/kristen-lane-7988cdb7fc', jobTitle: 'Immigration officer', }, @@ -2305,7 +2305,7 @@ export const peopleDemo = [ city: 'Lake Eric', email: 'leroy.bright@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwBwwagvrpLO0aZ+3QepqwFrlvFIuHu4UHCbTt9M+tTN2VyoK7sZeoak13I0jEndkAZ4XpgU+wsFktjJkIwBO4YJFZc4k87yZ2ChTgtjr/jWnpu+3cmKWbyyv3FiyD9K5mzpSHyxSy2TXKtFJOvygjgFe+QP/wBVZuk3SreIiqEYsQQe30rbtvC+s30pmSBreKRs4J2k++O1SXvhpdO3ieMEICQ3cH1o5kVyPcW21WSz1QRyHEZOGUjj6iutXEiBh35ryr7TK9woI3bTjr2r1DTZEl0+FkOV2gfT2ram3sc9VLcmFcV45uWa4trQKVAG8P654rtgvFZevaSup6eVBAkT5gcdeOlXJaEQepiaP4dbU7O2uLdkbAIIfJ5Bxmu+0Dw29lEBMFY5ySF6muX0BtR0rw5ZGzg81n3Hb26k9a6fQPEOp39zHbXOntbyMCevGK4pLqehBnVxRLGnCjH0rmfEuji7trhhJtDqSRjnIHY1Fq3iTWLS4eK203ztgyTnr249amtb+91NAl3ZyQMVydy8Gk9rldbHh9/H5Ny0CZZxkMe9ek+FrV4dAgMhyz5YjPT2rBbwu994ivIt6okL43Y5OD0+uK7WztUs7OO3QkrGMZPeuqk02cVaLiteo3jFN3YpQOOlIRWxgamhi1S3Nrt+RScBucZOa17SOP8AtZFiUDapJwK5i2JScEHFWZr2BrjfFqC204BHLYz9a4ZxtJo9OlLnin1OjSKCWQrMo3gnGRRdmK3iITrismyu9Pjj2/bVnlLZy0u4g+2atXTLnJbPFQ+xo9DLR7KGOZt8b3LOWKg5KsRjJ9OMVXV8iqdvYC2u72YnL3E5cn0AGAPyH61aAxXbShyo82tUc3bsR5zSGjGKQ8DmtTEdgnocGrVvA90APPWN14+Zc1ky6nDEGWIiWbIUKDxknAyauyxSlQysVfGCV9a5q6s0dmFk1c2ordreM+bPHIcfeAxTIT58hbOUXv6msvTbO8uJT9plYxDsOM10MUKxqURcKK5WdTbe5hz/ACzuPc1EGBqz4g8iK1Vd7LdFg0ew4OO+fase3uGkT5xyOCR0NehRbnG9Wuf/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-31.png', linkedinUrl: '/in/leroy-bright-5ce647996d', jobTitle: 'Chief Marketing Officer', }, @@ -2315,7 +2315,7 @@ export const peopleDemo = [ city: 'South Jason', email: 'bradley.patterson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDzljSDrTiua6Tw3oVvdgXl7saEN8sTPtD46kn0qW0ldlJNuyMzTdC1LVmAsrSSX/aAwv5nitVfAmr/APLU20THgKZck/lXfW15EhG2dIY4+AkPCKPTNZ1xfSx3DzQIhhQkFgMbvwIyaxdY2VFnA3vhzVdPQvcWUgQfxr8w/MVjtkda9Ih1q/ivYjbxMLVx86yZOPUc9qxPFNhZXCve2ChJUP7+EDHH94VUaqehMqUonIg04U0CnrWpmaGm2YvNQigYkIxy2OuBXYa5p7Lp1vZ2C9SAWU/dHeuV0slNTgIIHOM12NtcSNPDaD5jI+Gb0x1rCqzakrs17HR4hDG91JkAActgVdeytGOISjEdQDmsvVAxVg0FxOiLnZCOf8Kq6Db3LXasbeSCAgEh8ZXPY4rjt1PRT6G7Np0AhJIVeO5rjriz8nXFmxuTaQ6dmqfxVc3kWrSQgz/ZYwG/dIXYj6cVnT3hjt1miLnyyuQ4weuDkfjVRVmmTU1TRgazaw2upyJb58lgHUH+HPb8Kogc1qa6Cb2MnqYV/rWaBzXoR2PLe5f08j+0LfcCQHBwO+K7fTLCW11COWYZJHmYznZkDAP51wtrL9mvIZ8f6twx/A16tFHHD83mB/tDmUHjkEAD9MVzYi6aOzCqLi+6Ni3aKRDnA9c1latqwsj+5spp13BAIl+8e/PYCr6IFiJXk44FY8+qXLxuljZSSxocb3IRWPcjPWudK51ryM9dag1DXHWS3kjAUDLLwecU3XbG2NpOiDDyLwarSX063GbuwMKkbQ6MHA+uCfzqW6czMiE5Jx0oejG1pZnD6gWe7JYYIVR+lVAKuaiSdQuM9pCPyqqK9COyPInbmdiU81veFI3k1ku0jNsgIRS3A5HSsUJXZ+GtBvbZbPVmT/RrhHGR/D6Z+vb6VNVe4y6L99HQLdP9zOOxPpU8scUkJSSfCYxgelVr63lZS8ABcDp6iuRvr+4icq5kTHYdq4Eensbl1BBCp8ubcvoa5vVdQIiVYnIcn7y8YxVZLua6crvZlx1qteriRU/urWtKKczGvJqDaKL5ZixJJJySe9NC1MVoCQAFdx5p/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-32.png', linkedinUrl: '/in/bradley-patterson-590ba76c7d', jobTitle: 'Public house manager', }, @@ -2325,7 +2325,7 @@ export const peopleDemo = [ city: 'Dawnport', email: 'sarah.mcdaniel@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDse1Np1NNc5sRXNxHawNLJ90frXD614nlur5LS0yD2A7/WtLxVeIJ44GlAwOFU/MSfasaP4e3c9mbmS4CSFt4jbJx7GspTu7G8KelyHbKshmmuZWmP3g+OPoQapzahtkxG+x89JBwaZf6Zfac2WDumOSp6VkyXMchCSZG7+M4yDWS11NGuU6fTPEN/p13vDGSLq9u7ZGPVTXo+nahb6pZLc27ZQ8EHqp9DXjVnLKpKdGXlWxkGuo8Laz9hv1SQbIpyEkXsrdj/AE/GtISadmZTimro9Appp1JjNamJw1sraj47S3nTJty02PXHT9T+ld5IWC7epPYVx2u2v2PxA93BDJNLPaNhEJUhgy85H1qXwzf39xBLDdJKjoGKmRs8A461zShY7qcr2Nm7slkRgyqQR0rzLxF4be0meWLiFjnH92tLUrnWP7VBT7TIhYA/OQvJ/lWtbebqMDQzwyL1HzHcPwNJJx1Ldpe6zzaK7ktHEcu5lH3TnBx6VpW2oJcNgEgjgknnFZuuae+nanJASfLJ3Jnpg1UtXaGUsRkitrJq5y6p2PoqgUAUYrQwHRpEZtzoCwUqpPYHr/Kqc8cNvHL5KorNxxgZqywOMisLVBpIj2XlyyOfvAMefasKqdztwzvGxo2kVvcxHeq7kOCCKiu5IbYEIoHGKoWF3YRpss7hZCeT8+SaW4xITk5rF9josjlNd0xdTlWXbl0BCj+97Vy2pad9lvLayhBa5mPCLyfQAevJNdnr1zJaWUlxbvseJSQcA/zrC+F0L6p4tuL6+czTwwmQM/J3EgZ/Kt6MWzmrzUdLanr4pcUo6UtbnGNxmsrULFpt211QjkEjrWvU6aL/AGkq+buSIchxwfwpSg5LTc0pVfZyucWtv9kBOE3nuOTVae+2DaDl26AVfmsUaW4iaWQtE5U5PbsaoWejzXF6RAu7aeXPRa4+V3t1O7nTVzM1a2nvNLls4IzLdXA2qvofU+gFb/grw3H4YhkjeUTXVwo8xwMDI7D2rYg0z7KoWDazEfvJGHzH6egq7HYuoyDg464rspU3BanBVgAqKctD/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-33.png', linkedinUrl: '/in/sarah-mcdaniel-a2c7767c1e', jobTitle: 'Media planner', }, @@ -2335,7 +2335,7 @@ export const peopleDemo = [ city: 'Port Pamelafurt', email: 'brandon.boyd@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-34.png', linkedinUrl: '/in/brandon-boyd-4e2e998802', jobTitle: 'Surveyor, insurance', }, @@ -2345,7 +2345,7 @@ export const peopleDemo = [ city: 'Matthewport', email: 'carolyn.villarreal@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwCn3ommitbd7id9sSDJNSFBng1yvijVwJTpyoSqYLn1PoKUpWVyoxu7CXviG8vS4tGNtbD+PHzEf0rAudR378O7PtBLMfwxWho2katrlwEtY8xjgluABXXw/CqUxs11MgcjgLWDnd6m6p6aHmqagxZAzkZPJFdNonisW5NveOzQk/K5bJX8+1alz8KbmOPdHcIxHOCK5bWNDu9HXdLbqVHBempq+gOm7anoisk8ayxOrxsMqynINSxrXEeBryc30lswPkOpbGeFb19q70ACt4u6OdqzKqAZya4/xFZxjxCGbdtlQOT9OMV2ABFc94msbme5spIlLI7CJsdjnP8AjU1Ni6fxHpHg/TIbDQ4BEo3uNzH610jkkjPNchqN1Pptstvbw3cjCPK+RgBcD1P8qTw3qGq3kqw3fmhWG4NIBkZ7HHeuPpc712OnnztI6cVxnii2jm02ZGQN8pJFJ4h1PV0uZYrXzjFEPmMWMnHpmqVvdT3f7uaO5RguWExBz+Ip+YPsefeF7hrbxOiQgtHKCjD29f0r0fJrjfDmlvD4kvZmwqRl0UEdee30rtY0yK64bHnzTTIeMVPb2q3qPEP9apV4+M9CM/pUGKktpmtrlJlGdpzjPX2pzjzRaCnLlkmdxbPDc26hwDn1qPzbWG7ESMiBTySQMmqFhJvhWQcKwzgdqr3t7pUoVJrWaVlzhxAx254JBx/KuFX2PUST1RJaPbzX88bsrBmOCOQaj1VYLaJljUDI7Vm217plvOyW1vNE7HPzxMCT6k06/dphuY/hQ73sJ6IzLe3W3jZsfM7lx+PX+VWkfFMIJIGelPVa7aceVWZ5tWanK6IsetOAFP2UoQ5rQzL1hO8cTpn5Bz+Fahjt723BeYhe2OtUNOhYOGI4YEfWi/0hzE727sjKc4BrgrWVQ9HDyfIhlzDDaKfLlJ+tZu4yuvJK5606DTrhxvuJC3OADVl7baoUZH0qIySaZc02mVioBp4FBhkWNHbBDZGR6g4NKleindXR5h5jTTsz/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-35.png', linkedinUrl: '/in/carolyn-villarreal-3f2ca6cc5f', jobTitle: 'Engineer, automotive', }, @@ -2355,7 +2355,7 @@ export const peopleDemo = [ city: 'South Carriechester', email: 'harry.garrett@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-36.png', linkedinUrl: '/in/harry-garrett-5faf263278', jobTitle: 'Pharmacist, hospital', }, @@ -2365,7 +2365,7 @@ export const peopleDemo = [ city: 'East Jason', email: 'richard.lee@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-37.png', linkedinUrl: '/in/richard-lee-8f9dff7c18', jobTitle: 'Financial trader', }, @@ -2375,7 +2375,7 @@ export const peopleDemo = [ city: 'New Karen', email: 'kristen.landry@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDbIpMU6jFZGgAVm3PiLSbOfyJr2ISf3Qc4rh/Hniy5W8fSNPl8uNFHnyKeWJ/hz2ArntJ0HVrlPNgtzhujvx+NDairscYuTskep3fjLQ7CQRzXYLkAhUUtx+FX9O13TtWH+h3CucZKngj8DXld34I1jYHCx5A5Cscmsm1e90y9McwkjkTkENgj8alTUloynSlH4lY94IoAri/DHixpZUstRkyzcRzMevsfeu3Aqk7ktWIcVS1q+TS9Fu718YijJAPc9h+dXxXn3xS1No7G10tM/vm82Q+w6D8/5ULcRxeiWsmta21zcHcA3mPn+InoK9g0y3KxAkDgcCvJtAmitLGSaRHkDSbFjQ43HHrXa+H7uSO6t0jMohuMNsdy22uTEpyd+x6GEaikurO6ijVuSB+Nee+P9EmilOp28W6EqFfH8P8A9atfxXmyulnFtJcg9F3naPwrQtLoXtu9q9mYTtwy4yjgj8s1hTvD30b1Ep+4zx1J2QDBOBj6ivYfBmtf2zowEjZuIP3cnv6H8a8g1OBrDVrq3IwEcqAfTtXV/DnUY7bWTbO+FuEKrn16gfoa9Bd0eXJPVPoeogV578WLcnT9PnCrhZGQnHPIyB+hr0QVh+MNDl17QHtYNomVw6bvaqW5Bwfg+3t5dHh3orksxOfXNdVaS21prUSSRuQFONi8A+/pXKeGI/sVvJaOcXEEzLMh/hbOP6Vux3t2t84j2oF/ibvXDVTc2j18Ok4RSOxtrmO+iUvbSx5JG2ZMEH0rReOGKAE4z6AdKxdNvr+RVS5t1kiJ4lRun1B/pWrcpuiIzgYrkl7uh0W11PGfHFsW157iNcKyjd7nmsTSLprTUYJkO1o5FYE9sGu68R3+iQz3EV5MROmCsSqSTx19D+NcBYobzUAq4QSv+C5NenQk3CzR5WJilO6e59CipB0poWnDitjlPLvFatoPjA3jx4sr6Mb2UdHHf6/41u6TJCHJkAYEZ5710+r6HZ+INPayu0LKTuVl+8hHcVwsOAh8okxgkDPXFc2Iitztwk3qju47uwhgBVlXjpVaa+M6FYckHv6Vl6TYGUh5GDKa3TAka7VFefK1z0UeHeL/AJvFdyCc7cL+n/162vh7on9pakzMP3ceCxx1Ga6a38BJ4g8ZyyPkwGN5Zx6YGFx9Tiuy8O+HrTw/YG3tN5DMWZnOWJr1KU1KCR5FVYOM2z//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-38.png', linkedinUrl: '/in/kristen-landry-106c6fc0b5', jobTitle: 'Facilities manager', }, @@ -2385,7 +2385,7 @@ export const peopleDemo = [ city: 'East Ronaldmouth', email: 'joshua.burgess@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDtDTTTzTagswfFPiSDwzpf2p082aQ7IYs43N7+wrx7Udc1rxFcD7TcsQxysQ+VF+grv9U05fE/jKdbrcbPTwIkQHgseSf8+gq6/wAP7Dz/AD7eRoyT908gVLqJOxpGlKSueSTWMsDHJJYdSKt6Pr2o+HrkT2szKpI3IRlWHoRXrs/grSZgC6PuAwSG61j6t4M0xbGVYY2DBSV570vbIp4eSOj8NeJbTxJZebD8k6AebCeq+/uK3MV4v4Emm0/xnbW+5tsu6Jx2IwSP1Ar2rFaGIEUmOaeRxQBSA5Wzg8nWNT4+Z7pmP5Ct5AxUck1x+snUWeWaGWSORpjuECjkgADOeg4pfDOqavcyLb3QYtgsC4wfxrmkrvmO6DsuVnXur881kaiW8iRVGW2muZ1nUtdS6eKKWUQoMkRINxGccVp6ZJdyKEuGnOBn98oB/Mdam2lyua7sc54ft2/4TewBH8bE/UKa9axXA21kItVvL1WKTfMsLDsdvOPf/wCvXdWjSPYwPNjzWjUvj1xzXRCd9DkqU3FcxJ2pcUCnAVoYmNIsaX88UoGH+YZHWiyhgW9fyEA2qckDGTS69EVEM68EEqT+tc6+oyMpNncLG4GCC4yfwzXNKNpWO+nJOCfU3EgtprjbKFDnkZHWnXccVtFx17VztpeC3GJ5/Pl3ff8AMDEf4VqXMhcKS3GM1D00LuhtjbteSqpUtHvzwOnvXW4446VznhXVUuXvtP2bXtZBz/eDAGukrppxsrnFVm5O3YaBTZJUiGXYCopZmBKJwR1NZzLneSST3JrZQuYNjtUuDdabMsMbHCl19WxzxXMxxvPboYEgztDDzB1B5rpLZjsRz09PasG+sEhuDau7Rd4JFOMp6fh0rKvG1pI6cNN3aI/IWOLdNHb7z/dAp0MhuGyWzGvU9qzWsrhJsTSs8Z4yOlXYreTUJBYW37tMfvHH8K/41y/E7I6m7ayLnhO3KC/1McG6uWZM91ACj+VdRb30c4IPyODtKk96qpCltAkMShIolCqB6CqyxF5zJnGeoH869FQtFI82UgAAAAvJs//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-39.png', linkedinUrl: '/in/joshua-burgess-3596563692', jobTitle: 'IT technical support officer', }, @@ -2395,7 +2395,7 @@ export const peopleDemo = [ city: 'North Carmen', email: 'alicia.stevens@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1rtXJ6943s9Nke2tgLi4Xhtp+VT7mo/G/iYaRYG1hmCXMw5OeVX1HvXitxqh8w/OVXPccmsqlRp8sTanTTXNI7a+8X6ndSM8l4Yk7JGMD/GqK/EDWrKRRHJvTH/LRRmud09LzWrhbO2Qop5L9WrutP+GFuyLJezytJ2AOKz52t2a+zTWiNnw58S7XUJore/CwySNtDjO0n0OelegKwYZFeNa18NpIQ1xp1z8w58txwfbNdN8PfFEt1A+jai5+3WvC7/vMnTn3HT8q1p1L6GNSny6noOaTNMEgNG+tjE+atU1K81fWJtRu2Zi5+UH+Ef0qvoWmN4g1j7NG21M8v1qpqt1c3AJhiKRZwSo/nXd/CjSCI7q+bk5CLx+JNcN7RudyV5cp33hzwtYaFbjyV3Sn70jdTW6xUdGri/EOs31qJI49MnlTH3iCR9AKwtHXVP7RVczxrIA5USFlUHsQehpLa5rbWx6RcDdGfmrzbVX/ALF+IWlagmQJzskUcZ7E/kR+VafjPUNU0ye2trUTEyAHfH27dazNLtD4h8R6QtyJV+yiVpRM24vjHQ/U1cFqZVLWZ64r8Cl3ZquqhFCrwAMCnc11nCfPnh+zfUJrm2MfmTKm6IZ6kkAj+teneHLY6JG1uDuQtuzjocc15Cb+98PazBfQbBLH0VuQQRyD7V6j4Z1+TXrT7TNAsIkwUAOfY8/UVwSTtc9SEl8L3R3DS293BtkjQg+oqkpsLS5EMSRq7Asx4GAKrqrhcK3OKzrm70fypbe7SSdifnCws+T9cVKuzSyNPUzY3jQb5IpMjaRnOKzbiyjN/aSWjmFrbdyvcHHH6Vhwy6UkpSFZ4yeI/MiKhfYVv6LKks7xyMDMoBIrWC95GNf3Yu50UMztEpbG7HOKl3nFQAoD1p/mKO9dZ5p8vXM7XV7JIxJAJ/KvV/BthPB4TtztKyjLqD1AJyAfwrrNN8NW9hZpBBawmNRySgy31q1JBFZqCsYQMduAOK8mWLT921kerCjZ3vqYtvrCzAwO/lyDgg8EVoPBb3VqIWuNqAYrF1fToLp92CsnYjiud+zXkUpjNw5UdOa1jrqNux009rY6dDJKLssirli5zgCsrwvNLqF9cXwBXLgoe4XOAPyFcjbG58SeJjpSXwht45Dw/R9vb3JINeqeHfDi6NHIXkDl2yFUYC10Rg7nLVqp3NrBJpcHHSn5XNKMHJ6V0nIf/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-40.png', linkedinUrl: '/in/alicia-stevens-428bceb969', jobTitle: 'Chiropodist', }, @@ -2405,7 +2405,7 @@ export const peopleDemo = [ city: 'Codyville', email: 'jason.torres@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDs80tJSivOOwZcXENpbyXFxIsUMa7ndjgAVwOr/FGKP5NJtfMH/PacYB9wvU/jineOHutf1a28M2JwAPPuWPQDtn+f4ii1+Fdv8ryXskrYw2VwPwq1KEfjYKE5/Cjmj8TPERiZRcWyt1DeSPyrb0P4reYUi1e19jPbjp9V/wAK2rj4Y6M8ZwJlbGMhq5XVvhsba2kktLwkqCwRh1/GqVWjLQHQrR1PVLO9tdRtEurOZJoXHyup4qevFvAWvz6Hra2l0zfZLphG69Qj9A2P88V7VipnHldhRd0R0UUVAzkfDqGfW9Xv5uZZLgxjPZV4AruoQfLAxn6VwF3YENcF5bpYZbqRwlsMSMT9eg4rW8PTTwqsayXflk8LdcuPyrOcU25HXSdoqNjqpSVQ5wBXP6uc2kpQbm2nAFZOuQyzy+Y8moToOQltIF7/AKmk0+FoZMI13sHWOc5I+hqeRWvcvmd7WPM71GM5aMAOHB6d817xES0MbHqVBP5V5Tquj3N54oaG1i/dsyyOxOMLxmvV4Hjmt0kiOY2Hy9q6ZSUkjh5HFsZQKSipEV7JEM08UhywckZ9+RU4ntY75o2miVkTIUkA/XFUrjMN4HBPzj+VZMt7a3V0FkR5JOcKseQB7mseVuTR3QkuRWOhsJrS5YiOWN93IKHIp96sMEbbVGcdRWFaX6xzeTAjLk/deMjp6HvWlencjc9KmStoWmZNjEDqM84yXCqvtjnP866W2i8m1jjxjA6ViaHBJNcSuWXyF+8Mcs3bn06/pXRYrWEepy1pp+6ipSgUYp2K0MCrfW7T2x8v/WLyvv7VmQRiaFSsohkHHv8AQiulS1kIBYbc9K5bxBp8q6vOIJnifCuAOjAj/EGpqRsuY2oTd+VFx/LtojmZXc9SetZk1+bthBbvuJ+8w7CqK6Tc3Sb57/cpP3EGDWxY6fDYxhY0LSNx6kmudtdDpXM9xujJcya+LSGZ1hhQSTKOhByB+JP8q6ocHFO0jSf7Ot5JJMG5nO6Q+nov4VMYMyE812xg1BXOCck5tgAAAAAAAACP/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-41.png', linkedinUrl: '/in/jason-torres-8250efe63e', jobTitle: 'QuickActions analyst', }, @@ -2415,7 +2415,7 @@ export const peopleDemo = [ city: 'Thomasview', email: 'michael.ortiz@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-42.png', linkedinUrl: '/in/michael-ortiz-4c03016b05', jobTitle: 'Sound technician, broadcasting/film/video', }, @@ -2425,7 +2425,7 @@ export const peopleDemo = [ city: 'Lake Justin', email: 'deanna.williams@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDqsVG7KilmIAHepscVhatfCK5VT91OAP7zH/CsJOyNoq7NaKVCS2FCjks3asrU9bWNti3CAkZG1NzY9ehwPc4FMW+RY9sxBc/cj/xHc/yqO4/sywQz3n+kSk5Eac4P06Z+tYOTe5uopFaK/vGXzEaWaP8AvrHtI9+OorV0vWEuhtLAsPvexrnppdR1pilpHJbQHg/MdxqdLS30i3Kl2F2wyHc56VcZWQpQO4jAbkY5qYIKwfDeoNeJJFJxInOK6IDit4u6OeSs7Ge5CRs5OABkmvPr6882drgP8zNw5GcfQV6E8QmheNvuupU/Q15TfJc6fPsA3EN5SDg8/wCPc1jVWxtS6liC4me4Bijdt38bfzrpbTR7m6RfNUpF1IxjNQTWcml2yutvJcTuOZO0fHb3p3hy/wBVubuOO4eUxyDIDj7oPTPpUKOlzdWTsdRaWS28eEAGK5XxpCf7PeVciSM5BFJ4q1TVLK6MNqZAqDLFBkn2FVEe61TSbuC5jdXERw7EkNx7k81XL1BvoS+AbmS8u4ZN3/LJvM/DivSAOK84+F9m0QuGk371XHtgn/61ek4raGxyVNzPWuY1rRpJtWt5oYx5W4yyNxweOPxxXUAVn63Ldw6c0tmAZFOSD6Y//VSkroqnLlZejMU8HlOgZSOQRxTIYba3uBFCiqQQzHgYqDTX+0WkMueXQE/Wqmrahp9ugSS1ubiQNndFEx2npnNYrsdi12JryG3n1CWOVVYMcqeDmql3FFFC8MSYypHA4qnpt7YyyOqQXUUmR808ZG78cVa1KO4ltZjbKXmwMKOp9cUNO9gei1NDwhYQ2Ojgq2WckZ9h/k1vVx2j6k9vBHFKhQqMEHsa6eC7SVQQwroh8KPPqNuTuRgU4wpKhSRAyMMEEdRWtFpyjtk1heKW+zJHaDcFnjkZypwdq7SwB/3Sfyp2uIiSBbODyoW3JH8oOc4HpUckUc8OGn2qOmOtXzDDHCqQIqxY+UKOMdqzL63V4A0f3x1xXM3qdsXZFYwLApCzlwT3600B/tUAWUo+CwBHDYxn8ef50LFsiGfvnrRJn+1NKiH3nmY/8B2HP86FuOburs3brRV1Oz4dYboj76jIb61xN3/bPh6UpdLmPPyuPun6V6ZEnlxJ6rS3tlb6naPbXSBo3GPp7iulMwAAAAOOSP/Z', + 'https://twentyhq.github.io/placeholder-images/people/image-43.png', linkedinUrl: '/in/deanna-williams-08b67a9a7c', jobTitle: 'Research officer, political party', }, @@ -2435,7 +2435,7 @@ export const peopleDemo = [ city: 'North Brandy', email: 'kevin.ray@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-44.png', linkedinUrl: '/in/kevin-ray-dbea2dd52d', jobTitle: 'Naval architect', }, @@ -2445,7 +2445,7 @@ export const peopleDemo = [ city: 'Rebeccaberg', email: 'tony.walters@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwC6EpGAAJJwBU+2uW8aajJa2MdlAcSXOckddo6j8aQzL1nxlIkrRaYiuo484jOT7CsqTxJq8kSp5jOzj5goxW74X8GDVbIXUwMSNwgB/U12WnfDWxt5VkM8jgcgZ6Vi6qvY3jQk1c8xj8TahausiysEBGY26e/FdlpOv2+qxr/BIeMdia6G6+GWjzO0mJATyee9cX4p8JSeHbf+0dKd2SMgvHn9aaqK9glQklc6rbTglZnhzUzq+kpO4AlU7JAPUVsBa1MCQDiuL8Z25m1TTwfuhSfrzXbDpWHrNkL3VdPwQyI4jkA6qWIIz+FTN2RcIuT0Or0eJYbGCMKAAg4H0rdhI2fKc1xWsyXkPy263GAPlEHBJHvUPhubWXvIkuXuPJl+bMuMr7H0NcaXU9BPod8zYQjd+Fcx4m2HSLoMu5ShBrJ8U3+sWt7JFaec0SAFvJA3H6U6wku7yF4bgXAXYQyzgZ5HYjrTt1B9jn/A/wDx6XaLyiyDBx14/wDrV1m2sXwpZtZ6WY5MCRnL4x/D0HP4Gt4iuyLujzpJp2Y0DimvFkwuq4VXDufUggD/AD7U8CiQuLeRFxhh37VFSPMtC6M1GWvU2rcxTrsdR9T3qOa4srS8hiMkcfzDliBk+gqjbXAHOe2fyrnb/Wba+nWOVtqg/Ltj3HP+92rkjq7HoXVjsUuLG61CaPzI5MnjBBwfQ0t95VvG4QAHbXD6XqVvYXcsSSrIGK+YrKVZT2IPeul1K5zEcHOV6/Wqa6Cb0uV4YhBbRKPTjPUDr/MmpO1GS4XcACABx0pcV1042jZnn1ZqU7ocF4qnq2qWui6dJe3ZYRJxhRksfQVbnuILSLzJ5kjT1Y1wXinUl1oSW0ZP2RRx23H1rRRuZG8980ESsdwjlUNGfQEdPrWxHvnsI/sssUThQAH6YqpLZxahpEQjAZCg2j2xXPFNQ04NDCSyDs3JX9a89NM9PWL0OqKyQ2j/AGt4ZZeRtUcVkWuoC4ntY5ZwI9wXn+JwOF/TP5VmW8WqXw2TFkiJ5wcE1H4x057Pw3by2mI/sc6ykD8Qf51pFrmRnUcpRbO4ApcVydp4zijt4WvoHCsoBlj559xXRWWp2eoQiS1uEcHt0I/CuxpoAAAAADguf//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-45.png', linkedinUrl: '/in/tony-walters-2bfeca8dd4', jobTitle: 'Purchasing manager', }, @@ -2455,7 +2455,7 @@ export const peopleDemo = [ city: 'Batesville', email: 'andrew.roberts@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwCwoqrqurWmiWJurtiBnaiqMs59BV9Fryfxnqsup67NCGJt7VzHGo4Ge5+ua5IRuzrk7Im1HxzqmoyGO2K2kOekf3j9W/wxWcdRv4p1cXziY87xMSfxpmm6RcXRLRQlgpwQBkVv23gfWLwho4I0A/iZR/SrcorQlQnJXGWfjbV7CULdTJPHjpIB/wChCux0XxJa60pQKYbgDmNjnPuD3Fc3J8NNQe3d3lTeAcLzg1zlpLc+HtYty6sGgb5lYcMvcCp92W25TjOHxbHrhFMxTo5EnhSWM5R1DKfUHmlArMonQc14wIVfW5hLzm4f/wBCNe0p615YmlMvjNllQiKW4MqcYyMk/pVxdricW7HpWhadaW0CeTAit9K6iI7Ix8oA9hXDXYvbVB5TT/MMqsQHp6nvVrQbrVoZo3uJZmimAOybGU+o7Gue3U7eb7NjrJj8pwPxrzjx7DD9jE5iDNG2QR1B6f1roPE1/qW2VLVnVYcFjFgs2ewH41yWs2c82iXh3TFwQHErbgWyORVQWqZNSV4uNje8NfN4Z05s5/citPHNM023jttJtIYlKokSgA/SpiOa0Zy7aEg6Vga3bxrdWl6sZDxS+WWz2bP9cVvrVLWLcTaZKwHKbX/I/wCGaTRUJW0Zr6e0N1bRq4DYXuKdfCKJ40RQrE5OKyNJlIVcGmajeWl4/l3Ekce0/wAR5FZJdDsTVjX8pP7XnjkUYZAwBqhrKW3lLb+WNjONyjvWdbXEFvfM8V4tw7YBy+WFW5R9p1GNWzgEsfy/+uKLa2FKSSuy7wqAAcAYqI8GpXqu55rY4rk61W1fULfTNKmnutxjI2YUZJJ4pLzUILEYc7pD0Rev/wBauS1vUZNTxFKqrEAcIP61pGDZlKaResr5rJjFK+0qA8bH+Idx9a6NUiu7dHWVFkI+ViM1gwWkGsaYpBG9Rj3BHaorew1WD9xb3MZK9El4xXMt9dz0E2tVsa80MdnG8zzI7qD2wBRombiOS+L7t52L7AdT+J/lWLNp19cPsvplKA5ZI+h9iag0e6uNM1G7jB3wyMHCHgDtj9K0gk2Y15StdnZO+KrOcmktrlL9SYgQw+8p6ipRbue1W4s5AAAAAOdNH//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-46.png', linkedinUrl: '/in/andrew-roberts-41c13e9f43', jobTitle: 'Physiotherapist', }, @@ -2465,7 +2465,7 @@ export const peopleDemo = [ city: 'Stephanieport', email: 'lucas.fisher@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-47.png', linkedinUrl: '/in/lucas-fisher-7a563c63b5', jobTitle: 'Materials engineer', }, @@ -2475,7 +2475,7 @@ export const peopleDemo = [ city: 'South Ashleystad', email: 'sarah.bates@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-48.png', linkedinUrl: '/in/sarah-bates-477cbbc18f', jobTitle: 'Educational psychologist', }, @@ -2485,7 +2485,7 @@ export const peopleDemo = [ city: 'West Dana', email: 'jon.osborne@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0q/vbfTbOS7uX2RRjJP8ASvEvE3i691y+fa3l2658qLccD3OOprqPixezJcafZ8mFkZ8A/wAWcZP4dK8/ttMkvZIYUUkseR3/ADrnnLWx0U49R9vKZ5hvlUL/AHwcc/Q1PM89nJ8oZlfq6jcpHuOxrXt/BU92SJAREvAB4rTg8APGQTfygj+EHisudG6oyOWTxLeafciOGZkI+aNgcjPpXsfhvXYtU0yJpJV8/wC6w75xmuPT4f2XDzMXk+tJp+mtpXi2ygyRaTt8v+yw7Z/z1qo1FeyIqUWo3Z6dRS0V0HKeV/E5idfiLc+XaqIx7ljWR4TBF4kjHc7d/QV13j/TBrN/DBGpE0EG/fnggt0I/A81j+D7Jbdbrev7yNtp+tctSS1R20qclyt9Tr0OV4FTLg9DzXKatqN3CzJCs5wM7YUyaz9L1DVnuUikeba4B/eAZA98dDWKjpc6+bWx3jKGHzHArn9ZnNtLaygZKXCFffmqHibVb/TpY4YElZnXdmIZpdGNzqF5bR3zSbUnjc71A53DGPWqitUzOo9Gj03OecUtJRXceWcz4q0x7kpLEcCQqkvuAen6ms+2hhglkeKPyzIQWHviu1eNZY2RxlWGDXIT27WV5LE0hb5iQT6dv0rkrQs+ZHoYetzRUHui0sUc0ZLqMehqo5tI52ghVd6ruY9MUs0jiFtp5xmsGaaxmhZLhXYZOSYmOffpWMVc67o3btrXNu8xRlI2noce9WrOOL+0IIkUbdwbj25/pXHxy2KHZ5jSMRgblbge2RXV+Gone/3OSRHGcH68VpFe8kZVZWg7nV0UUV2nkjhXM65EWvpCvXAP6VuXt79jjUrH5rsQAgbHHc59Kxrl2nneR+CemPSsK8klY6sLFuV+hil2YFS2OxqXY0sWxXVRjgntUN7ZuzbkJBPpWBdXN9bzeUEckdxXMjt5mjbmtTAhLTrJn8xXU+HrJ7ax82UYkmwcHqF7Vw1pDdSDfO2T/Cvv712vh/xDDrGnrJLthuFJSRCeAynBxW9FJyucuJlLl8jbpBS5yMiiuk4AAAAAAADiP//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-49.png', linkedinUrl: '/in/jon-osborne-e72d657289', jobTitle: 'Geologist, engineering', }, @@ -2495,7 +2495,7 @@ export const peopleDemo = [ city: 'West Michealland', email: 'lisa.green@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-50.png', linkedinUrl: '/in/lisa-green-e3c92b78e0', jobTitle: 'Art therapist', }, @@ -2505,7 +2505,7 @@ export const peopleDemo = [ city: 'Michelleville', email: 'george.allen@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwC+BThSgVR1q+XTNGurtv8AlnGdo9WPAH51JZyHirxy0EjWGjt++VsST4yB7L7+9cLO95f3Jknkkmkblmc5NdX4O8NR3ym9vULhySiHp9TXoNp4N0qCQSrZqGx3JIrGVZJ2OiGGlJXPDHiKk/Lz29q2dG8T6joTqIX862z80EnT8O4r2Gbwrpj5Y2MWcY6VxviLwpapDLLbJ5MigkbehpKunoOWFkldM6jRtWg1vTI723BVWJDI3VWHUVeIrz/4c3MiXt7YN90oJR7EHB/nXoWK3OYUCsDxtEZPCl2AOQUP/jwroRWfrsP2jRLuDbnfGR+XP9KluyuyoxcnZFfwvbLDplqoX5tg4rroi3Rh+lcHKl3bRoYpJ1+TciwgdhznP8q1fDuo6mxjW7lcrJhgJFAYexxXFbTmPTTt7p0zlx24rntajE1u6rjcQeKra3eanLLL9nuJVhhUlliAy2Owz3qlYx3E+GLXKsF3MkuDkEZ6jvRbS4OWtjnPBMZHiq6yNpWBgR77hXopFcnoNi0GvalqKhcMwiAz64J/pXXmuyEk0edUpuLu+o0UyfPkPhAzbTgH6GlU06nJXVhU5cskxNMaG4sogyhjgEZqV4lOpRJGoJUZYCsnSpDayTRtnMLMAPbPH6VFdXImvBJ5scTqDwGOefXFcVtbHqxkmk0bNjHHJcyqwG/OQD3qW8WOKFwBtJFYFpcG2mIililJPA3YP61f1C78y3GTtZlPHpSfYG7FHSASs3yLse4Yhu5xgf0rZNZ2ixgaZDJjltzZ9iTWgTXZTjZHm16nO0l0IQalWmQwvLIEQZY1qwaaqYMh3HuO1W3YxSucjrk5024S5XOyVcPxwCOh/Hp+FXLW5hv7NXV1jmKjnGcVra7o5uTbXSKZIkRopYgMjB5DY/DFcumhXNtcMtjcoqN91ZQTj2BrkqW5jvotqKsbZkhsrbe7o0wHPygGuYvL6S/lEcJP3fmI/gHf8auXWg38hAuLlApP3Yuv51pWPh2T7K1vZQZZh8znoPcmo9DRtvfYl02QNYRiMZjRFAZemMVazmtXStEj0uwW3GGbJeRuzN/hTr6xQWzShcMBnIrrjLTU8+QAAAAJX0P/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-51.png', linkedinUrl: '/in/george-allen-9de1c6f0d2', jobTitle: 'Retail merchandiser', }, @@ -2515,7 +2515,7 @@ export const peopleDemo = [ city: 'Hoffmanberg', email: 'rhonda.smith@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-52.png', linkedinUrl: '/in/rhonda-smith-7c802edf30', jobTitle: 'Therapist, nutritional', }, @@ -2525,7 +2525,7 @@ export const peopleDemo = [ city: 'East Gabrielberg', email: 'kyle.day@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-53.png', linkedinUrl: '/in/kyle-day-bedc45ac4c', jobTitle: 'Dispensing optician', }, @@ -2535,7 +2535,7 @@ export const peopleDemo = [ city: 'Pamelabury', email: 'valerie.smith@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0k1l6vr+maFbmbUbuOBeyk5ZvYDqaq+M9dPh3wzc38ZXz+I4d3Tee/wCHJr531HVbnVb03F7dy3Dkk7m5NQbt2PVb/wCK4ku86ZbKbZP4pzhpPwHSsyL4q6pBO7yrazJziPBUfnXO6D4Ku9e2ybBbwHo5GCa760+EWmpbEyXErsR34BrN1Yp2NFSm1cv+GPiPaazIttfxpaXD8IwbMbH0yehrtwQeleO6n8L7rT4pJLC6Ljr5bDg1c+GXim+GqP4d1N3bareTv6oV6rn0xVRmpbCcZR+I9WpwoxSgVQjyD416n/pGmaWGyqq07oOuTwufwzXnfh3Tl1LWIY5OIt2WA710fxbUp47mJJw0EZ57cdqb8OrL7TqMsp6Rrn86mo7RbFCPNUSPXdNEFtDHt2xxoMZJwBW3Fd2sqYiuonI7K2cV5nq95Os5gFrJIuCeRkcDoM8Ams/w3bXbahHIls0KudxxwVGehxXGo6XPQcveser3RDxnLhePWvJ9fibQ/H+napboBJOdpUd26frmtTx39rt9Qjg2zyQqisfLBJOfQAiud1KOa7bRlgV1kjvPLCv2bg+vt61pSVmmZVndWPdIzvjViMEgHHpTxUcAPkRkjkqCcetSius5Tzjx7oUF5ri3MyIY3tMOxUEgITwP++lrK8KWC6RNKyxFEmCOqnqB6Guy8eqbfRU1UDcLJw0qYzvib5WH6g/hXO2+q6XqN26afdRz7Ywx2dAD0+n0rmrJpvszqo8rS7o7CJLG/t9k8KFT/eFV7mXStHTyovJt4wC8krkKAPTNZsDyYABwagvNS0toTbXEElzKpyUSIsc1zRTeh02Ni9m0bV5bYNLHIHjwOefYioJdC0+e6s7dY8CKYSgqcZwD/jWBZX+krOwezngLggPKmNuewPaum0F5Jb8ebyVU7TWkYtTRnUVoO50oUKAB0FKBS4oFd5wHH/EnVrfTPB11HPGZWvB5CIDjkjqfpivGPAs5g1+aJT/rISR74x/9evaviHoa634VmQECWAiWMn26j8RXj2haPLp+q6TeFwTdLKQuedq5GSPyrOpsxxvzpno8V3vUBWw3Q+1XhZG8h8uORB6bh0PrWHJCc7uR9KiF3LFxvcD1FcVtdD0Lm4NHuLYl57mOUAflRmaK4truF3LR7toiBOOQDkDqMdvasmG4uLiXmR9o65Navg2GSS+1JhudFvSVGfu/KM4/StIb3ZnVba1O9jbzIkcjaWUEj0p4plrKzfJNGQf4STyRVkxDqK64yUjimnEAAAAAAAAAA//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-54.png', linkedinUrl: '/in/valerie-smith-71a58f5833', jobTitle: 'Diagnostic radiographer', }, @@ -2545,7 +2545,7 @@ export const peopleDemo = [ city: 'South Brycefort', email: 'matthew.nelson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwB2KTFPxQBWpA3GBknAHc1j3XivSLMlftBncHBWEbv16VzPijWZ9Wv/AOybFXMcblWx/wAtGH9BUFv4IvJUUyyxx+wyTWNSqo7m1OjKeyOg/wCE/wBN/wCfS6z2GF/xrV07xHpupgCOYRSn/lnKQpP09a5j/hAx5fN05Yf7NYeo+HdQ06N22+bEvJI7VnHERb0ZrLDTirtHq5FAFcB4S8UvDIljqEpMBGI3fkoewz6fyr0ECuhO5ytWE201w2xtv3sHH1qYDimshZGVeCQQKoRwfhSy+We6kG+4kkILHrjPP6129vCduTziuCt5WtNHSNkmeQs/yxHGcEjJP4Vv6A91BdRQyO3kuocZOcZ5x/8AWry66b1PXw0kkkdSkZKHgAVm6hApiIwCfSsXxGLlLhXiWSWPOcByP5VbtZZSoheGSJlA4LblPHY1z8unMdLlrynnGrWQhv2aLCqxJ47V6roFyb3QbKdjljGAx9SOD/KuD8VwBL47ejrux6Guw8Dq3/CLW+4k/O//AKEa9TDy5kePiI8smjfVadtCgt6DNKtKeQR6iug5zl9Pgha1jjePnGTn35/rUi31raakI2ilYBTjy0yB+NVwHtn27iduQfwot9Qn3nybYuecliF/LNeRJNtnuU7WSRtafcQ364lglRs9Jo8Eexq9cxQwRAg4OO3QVlwarMxCT2ciZPUYZf0PFWbv54jk9q55KzsdCsc7caZBqGoCa6UtCi7TjpkngnHaul0S1S00mGBIljCZGF6Hk8/jWPaXNst6LWR8TTD92p6N2P8AOuljGyNUHYYr0MGpXb6HmY1w5UlvcaBTsUKKdxXeecYmuWroguolyq8Pjt71n2qWJw0pJ74z0rqLuMS6fcJ6xn+VeeXMM0jjyTgmuHEQV79z0MLUfLbsdeZLGGIeU/AHPNUpr3zh5cR3E9/SsnT9JuJpNtw+5R1weK3ItPjthhBXnysmehFykVtOsZX1/wC0eWfJih2iTj72c4rpwD3rI0idxdTwMBsI3qe+eh/pW1xivWwzXs0/as//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-55.png', linkedinUrl: '/in/matthew-nelson-a288db243c', jobTitle: 'Surveyor, insurance', }, @@ -2555,7 +2555,7 @@ export const peopleDemo = [ city: 'Jessicaberg', email: 'terri.ramos@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-56.png', linkedinUrl: '/in/terri-ramos-eb86c1f353', jobTitle: 'Tour manager', }, @@ -2565,7 +2565,7 @@ export const peopleDemo = [ city: 'Mathewsburgh', email: 'brian.bell@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-57.png', linkedinUrl: '/in/brian-bell-50b9b8cc1c', jobTitle: 'Engineer, electrical', }, @@ -2575,7 +2575,7 @@ export const peopleDemo = [ city: 'West Jeffrey', email: 'troy.stuart@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-58.png', linkedinUrl: '/in/troy-stuart-f056c7bfcb', jobTitle: 'Corporate investment banker', }, @@ -2585,7 +2585,7 @@ export const peopleDemo = [ city: 'Valenciaside', email: 'beth.shea@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-59.png', linkedinUrl: '/in/beth-shea-2f51929bb5', jobTitle: 'Forensic psychologist', }, @@ -2595,7 +2595,7 @@ export const peopleDemo = [ city: 'Baileystad', email: 'erin.barrera@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDXwKQ7VBYkADkk0gzXMePdVk03w+Y422vdEx574xzimJHPeJvH9w8z2ejsIo1JVrjGWf8A3fQe9cXNcXEm6Wa4eV26s7Emqyhm7Ese1atv4e1G6j8xLd2J6Z6VDkluaRg3sjJWd4zwSAeuD1rpPDvii60OdGVzLZsf3kBP6j0NN/4QvUmt3kdAGA6CsUwPbblddrDgikpKWw5QlHdHvtrdQX9pFdWzh4ZV3KRUoUZrzH4barLFqc2mOxMMyGRVzwrDuPqP5V6bmtE7mTVgArzD4nXTNrNna87Y4N4HuxP+Ar1EV5b8TLGf+37a5UEpNAEU+hUnI/UUPYI7h4S8Im7Ed/efcbBSPuR716fb2McMaKIwAPauWkH2GygTbes3lAKts23BA9av+HtSv7h0hlaZkPIM4G4D0JFebNuXvM9emlD3UbslspUgRjmvJvG2jTWN01wkZ8iQ5yB90+hru9f1DUYpSkLXCxIMsLcDc3tk1SSNdSspIWju1yhDi5O7Oe+elOD5feCrFT90808N30tj4i0+eMZPmhCPUHgj8jXu5UV4p4X0qaTxfaR+XujiufmP+7n/AAr22vQieTJWGCs/XNJh1awEcg+aJvMQ+9aIpSAykHkHim1dWFF2aZU0xopbdFcDcB0IzUzGJNQjjUKvcngCqscYt7gqM47VWvbzTJpkFyrM6E4IU5X8a8tppuJ7kGpRTRqQ+VJdSo208nB6g0zUxHBbsFxnHAFZ1le6XE7JbDY7tn5lIJNS6rI3kSSKpdlQlUH8R7CizvYHZK7Knh/R4bWWW7CYd3ZvxYDP+feugIqjottd22kwR30he5ILSEnOCTnH4dKvmvSpx5Y2Z41WfPJtDMUopkkiR53Nz6VFazG8ZyoKxICS3eqclexnZ7kGpyxxvCisPPYEhR1Kjqf1FUo1husM8xRhxkcEU1187U7a4Y5JjdPpyDj9KlubFH3Dlc8hh2rzq0k53PWwyapoUxw26kiYt7t1qpd6smmpHdzxs8KMARnHXjNTW+nrGfmZpGJ4JPSk1a0in06aKWMSKy42EdfT9azjK0kzWonKLTOgjmSeFJYzlHUMp9jSnFQ2FibWyt7YN/qYVQk+oFSKylym4BgcEHrXqxd1c8VqAAAAAAs7H//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-60.png', linkedinUrl: '/in/erin-barrera-74010827a9', jobTitle: 'Youth worker', }, @@ -2605,7 +2605,7 @@ export const peopleDemo = [ city: 'West Darrylmouth', email: 'danielle.maynard@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDz5qFHfNS7M024K20IZiAT90H+ZpVJ8qKhDmZraXYWsxBnYnvis/WdRit5TBbeUjL2AyR9ao/2jIkLurFVb5R2Ln/D2qQ6C01vC1kjvO/MssnT6AVyXd7yZ1KOloom0y6gvSYJIwJOu4HmllQoxAPAqFtBv9Oxeo26SMgkDoR6fSq91qK+d5sYIVj8yHt9K0hNp6O6InT01VmWSKADmlUh1DKcgjIIp4Wuo5RLuYW6rkcsf0FZbyG4laSRsY9s1a17KSRN/Aqk8etZFtm7v4LYcmSQAj05rmqK8rnTT+Gxu6Rol5reoRkRkWyHr2r1KHSY7eAKMA47Vzl5PJpVkLa2tZJCV52cAYH86j8PNqDXsUcrSiOQBmDMTtB7HPQ1zO7VzshaLsb95pqyW8iDGWUjivMdS0mWzmbzo22N1PvXYeLry7tbww24mZFxnyyR/KsfWZnuvDV3GyyJPAAWDNu7jkGqgmtSalndGHp7kNJASfl5XPpWgBWLpc7TXUe45JQg1vBa7aex589yh4lVvIhcdMlT9eMVS8LQ51u2cjIR8t+H/wBc1ua3a+fpjABiQc/KM4rK8PavBpF41vdwsfOkXbIv8JPHPtWdVPWxrRaurns1s8Fxb7GRffI4qCaeysp1jBSNeNzsQMkngCo7Zflyp461UutQ02QeVLaS3Lq2fliJAP16VwpX0PT06E8rWd3qsyBo3VuR3wazPENrbx6TeRIvLQsBge1RwXdglwVSCWBzjBlUgnHvTdb1G3s7Jrm7J8sfLgDJJPQCqs72JlZJ3PNNBjc37cECMEH610+KoaTZtEj3DqQ8x3EVo7a9GGx5Ety3E5BrkNas7hr8SNbOFEoJkA4PI712ttayzyrFFGzuxwFUZNdC/he7t0gN2EEcoO5euCD09PelUaSux0027IWJ2ijVCccdasmGGeHDz7R2AqSe1DIBWTNC8LkEECvNR6uxLNbxQqQkm8e9cj4ja51DUYNPiG23jXzJXI6k5AH5D9a6pYiYxI3c9KyblfNlndQT5bBX46ZGQfof6VvRSczDESagZ4QKoUdAMUmKnIrcecf/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-61.png', linkedinUrl: '/in/danielle-maynard-ba9f453d8e', jobTitle: 'Location manager', }, @@ -2615,7 +2615,7 @@ export const peopleDemo = [ city: 'Colinville', email: 'sarah.oneal@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-62.png', linkedinUrl: '/in/sarah-oneal-814e3f10b5', jobTitle: 'Programmer, multimedia', }, @@ -2625,7 +2625,7 @@ export const peopleDemo = [ city: 'North Paul', email: 'carrie.taylor@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-63.png', linkedinUrl: '/in/carrie-taylor-33e1df2a16', jobTitle: 'Archaeologist', }, @@ -2635,7 +2635,7 @@ export const peopleDemo = [ city: 'Annashire', email: 'andrea.smith@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwCL5nfC81at4xJII418z+856Cs1mklk8tMrCv8ArGHVj/dFaEDYG0uIkHLHOcf4muSrWbdkdFOlZXZa1HUIrCDyo1knmI4ih6D6ntXLz6pqYQvcRrasv+rIl3ZHoR1/Gt5NSgkuWSNS0cQ+WMHG5vc1UXwnf6tcvc3Mqxq5yFUdvxrKM9Tb2d0U9N1qO8ARmXzV4btirzyZNIfDEukl9gE0Tc7ejA+xrOivBHdG2lYnJ+Vm4P0NbU6mtjKrSaVzXtW/eCtePGKw4pArVoxT5Wuk5jCndozt+9KfmCA8J7mqM90qHy/P5PJA5JPvjtSX8M/3AwBblsHt6n1qLwxYnUNXdv8Alint1NeZY9JLWx0vhbSJHJuJEYAnI3dT7mu4VNihelcjqupXumRNFa2MsoxjeOg/DjmsfTJdca9jLSzIkqhymchAfUE8GrjHS5d1flO+uojJGxyB9a8w8QwGPXbcJw8gyR9DXQeLtQ1jT57WysgxaUAtKP4c8VzwM93qFpJPDIrpG+5mbOcHrn0qlHqRUkrWNAN81X4X+XrWay7WwfrVuBsiu480dPYSXSSQqB5pPGf7pNWtHsf7KlchQFOOB2qPVndLSS6tpCkydGH8qdol3cXVlFLdMD5qAgAYA7EV50otNo9SnUUkjrUmt7uDy3jBB6hulMWKztJBHFGPMcZ4HYVRgiKnC/hUd5NpBieK7vVSXo21yHHsMc0K7NrIuarbQXD2zShWUrjnqDXO6o1uksZjQDYpUAVDFNp6yNHb37TPj92HJyPbnrUUwMpZj1xzWkF7yuYV3aDXUqE73LHqatW4psVuD1q/BAAOK7Tyxs8QmQRyg+UOWwOtXrbTfJsPKTI2ElfYHnFdbpuiI2mol5CsgZt21hnHpTrvRwhZrdjz1Rv8a5qlKXQ66NWKepxsV+VfyWfY/TmrT2pmhwk0aHH38c1X1awgecpOrRt69CK5iVtQt7gwm5LRA/Kc81zpanbz21Nm6ga2z5t0JT2PepZEyPTAwK5i11eVtal06RQ8O5Q79WUjDV2t3p86L5oTcnXctddKPVnDiKjkzMWPack1chwKrhWY4FX7e2+XJNbnKf/Z', + 'https://twentyhq.github.io/placeholder-images/people/image-64.png', linkedinUrl: '/in/andrea-smith-63bc9b52c2', jobTitle: 'Mechanical engineer', }, @@ -2645,7 +2645,7 @@ export const peopleDemo = [ city: 'East Barbarafort', email: 'adam.cowan@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDvQOKMU4CjFdHMY2EC1Xlv7WE4aQFvReawNd8RQQXUlmJQqxYEhzyzH+EDqaxb2W7v4ohaR3EO19zMGC7h6VjUrqLsa06Mp7I7D+3LQE70lRR/EVH9DVu2vLW8XdbzI/GcDqPwrHtp4WU/aNMlJK4JVg36Zqr5Nkrma3kaGSM8gfKyfUehqI4i5csO47o6gikxUNlObm2VyQWHBI6H3qwRXQpXMGgpHkWKJ5W+6ilj9AM0tVdT3DR74p977PJj67TWdykjxzS7ltRvrjUHTMk8rMuewzmu8sYJTErnBHsa82tB5NlaRs8yJ5QP7kZcnGa6HQLi+tNbgtBcTS2s2CDMuGA68815tVczbPWoS5Ukd5AsgO7IA96qa2oe0kmQYuIlJR16/Q+o9qwPFMLx6mpEly0RBIELc/QDNaGlIysESSdoSo3JcphhmsrWXMjZu75Wiz4D1BdQhvXjYoqlQ9uf+WcnOSPY8Guvrg/BsAsvEusqCFhcqig92BJwPwru816lOScVY8epBxlqGazfENqt74d1C3ZygaBssO2Of6VoA0yeIXFtLC33ZEKH8Rim9UTF2aZ5hocFrcDy5URtijbkVd02505vE6IJ4kSPITjjI4rJntLjS9QntmZRJGuMjof8g1Hplu0lyc2avjP32AwPUV5zjq7nrwldJI7ue802USK7xzrG+12UZCc9TWhLBbxWitGwJK54PSsAG4itiptHaNlwdpDDHuO9XoYglnHGrNsUZGTyB6VjJWNr9yTTLI+cjjGGn+0bsdDgrj8sfnXR4qhp0JS3Rjj7vAHvV/Nejh4OMdTysVUU5q3QhVwRT9wquv1pWkVBljWpznHePLFUlt7+Ph5Mxv74HB/KsbS3tHYJMxxjkg4rT8Zaqbi8j05UwkQEpY9STkD9K5Vbed7sJCQHPQmuOrbmZ30LqKZ6FBNbQwiOKTIx3PaojMZcpEfkHU+grK03Q7s83c4IPZK3/suyEQQoWZvlVVGSxrlbV9DrV3ub6AKgHoMU7cKs2+g6hDpwa5lWW6LZCKANq+nuaqSxSwttljZD7ivWi7o8aQAAAACSsz//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-65.png', linkedinUrl: '/in/adam-cowan-a8cb02d136', jobTitle: 'Sports development officer', }, @@ -2655,7 +2655,7 @@ export const peopleDemo = [ city: 'Annaton', email: 'bryan.johnson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1uvNfE3jxp78abpErJEpIluEPLf7p7D3710XxC1STS/CF08T7HmIh3A8gHrj3wCPxrw61ujG4OxQp7ev19azqStojSnG+p0N/PGbJpZ7pkDc/eOW9zjJ/lXHXMazOJVljkjB+9wGX8K7AQ3WryQQWSgbR8zEfKPwrZHw2muyHu7wjI+7GgFc6kdPI2cRpepT+ajxzeTeQHckiEg49c17R4L8Zw+IrcWtwQmoxrlgPuygdWH9RXIXPw6trYLLbySLKg6g1yE0+o+D/ABDbXygho3Bz/DIO4/KtITsyJ0ny3Z9F0UyGVZ4I5l+7IgcfQjNPrpOQ4n4qRCTwtC7EhY7pSfTkMOa8q8P2cep3o8x8knao9q9s8ZQSXukJY+Sj29xJsnZv4FwSCPQ5ArznwhokVpr0se9ZRDHlHXo2TjP6Guaq1do66MHyqXQ7vStLs7KJVhjAYDGa1zjHXkVyeqapqdkWisrR5DgkFVzWRpXiDxBdXUSXNpsEvIJXBUZ7+lZLa503u7Hd3CbkPOM+tefeN4AumMSoZgwK8d81c8Ta1rNhM1vaWzSuihiRz17Ad6z7dr7UYhHqaEBJonYkcHDqTjH40Ja3Jm9Gj1PRxKNEsBOpWUW8e9T2O0Zq7SnqaQV3HmkF9bfa7OWDuw4z61x/2WOzvIjGoVo4/L47jOefxzXcVh+IYY0SK5CKHLbGbHUY71jVhdcx00KtvcIY5IbqIqyj3zUPk2sEhjiUeYRliB0FV7c4X7wAxmqN7Lpk0RV9REMoPLrNtYn0Pt7VzLU7tDQvoYZNU2zqCrqCMjuKbbxRHVLe3hiDAOGI7YHNc7DNCLpvN1NbuXhRtkB2/QV1XhmIyXs87c7E259yf/rVUFeSRnVlywbOnooortPMFY7VJrh/+EqGvXc2l/YmieBj5rbs7WBxjpXZMxcjAIX371hXekQ2GpT38EQC3bBpSB0fGMn64rOrfl0NqKXNqYLStbzeQ7Yz0J7irM1q9zBtiWJWA4LKKn1Cwhu0KyD6N3BrnrtdTs/khYvGP4ie1ci3O9NofLaPaFnk8rd6qoFd5oNn9j0uPcwaSX94xByOen6V535VxPZzNK252RsemcV0/gPUZf8AhEdPF2H3GPKk84HpW1G12znxMm0jr6KakiSDKJxH/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-66.png', linkedinUrl: '/in/bryan-johnson-ec29fc1f9a', jobTitle: 'Clinical molecular geneticist', }, @@ -2665,7 +2665,7 @@ export const peopleDemo = [ city: 'Dennischester', email: 'richard.jackson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwC0SDWbrGt2ui2ZnuDuY8Rxjq5/z3rQIryrXriXVtauHbJjRjHF6ACpGlcsT+LNX1NivmGCBjjZCMcemTzVRbm5c43TRshyrZI//XXb+Fvhy97aR3F65hDDKhfvEe9dhD8NNMjj2mSdvqeKxdVJnRGhJo8wi8a6nZuFmVLlF4ZWG1vqCK7XTtUg1TT47qA/K3BUnlT6GpNa+FllcDzLe4eKRR3GQa47StPu/DPiY6fKyvBcD5WHGSMkf1qo1E9CJ0ZRV2dujcintioFPFSE5FaMxQE5rzfSYEN3tfBAmJ+vNekxAtMqhQxPQHoTWXYeHobHxh5YUPDkzKDzg+n4VlUmlob0qbkuY9B0kbLSIEYO0cVsb/kHGa4/UZr62yIFmIIyoiUFs49Sag0S88QmdTOzGGRc7ZQNyDPfHSuVLqd/kdfOcxnjtXlXjaLOu6Q8fDfaMfh3rrvE+qaxbDyLKBnbgs6gNjPoK5q4sZ557S5vHlkMErY8wAfNtPIx2q6a95MzrP3GiyOlLmjFGK7TzR4fa6uvVSDW3MoFzBKApO1sMB2ODWOI6fDdi31NbVwcmHzAT0AJ4rGtG6udOHnZ8vc7azaG5g2uFPqCOtNuBDb/ACoih2BOFFUrTBRWRuvNVdRubS5BSSdUYHr5u1v0Ncq7HerGhKqfa18xQVeMH5h3FY2vPGY1ijAABz9OKg+2H7QqyXy3G1dqjeCR+VV7pvMuGBP3eK0pr30ZV5JU2URyo+lOA4pAMAVIorsPML0Fq833Rhf7x6VLqGjG5msNStiWa3RoZ0A++h6H8D/Ot0QBRgLwOOKHD25DoOPSlKPMrMuLcXdGLFdfYmELvs5yjHoRWhsW4hBHlAkYVsVJcW9vfQsjRjd3UjpXM3Vlf2Mm23klSMdBjcB9K4pQlB6nfTqqWxeurf7Ly8iu3QEDFJaQJIgLAl/4g3rWHuuX13TbUmSZ5GeSQgcIqqeT+JFdZb2zIxI+56HtW9GP2jDEzbdijd6fH5LGIYkXnA6Gsy2ZZlzGQ3O0gdQfSugm+WVR6g/0qhpdlEdUecIAyjDEd8dM1ucAAAAAAHKz/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-67.png', linkedinUrl: '/in/richard-jackson-a17e46e0d7', jobTitle: 'Engineer, water', }, @@ -2675,7 +2675,7 @@ export const peopleDemo = [ city: 'Williamtown', email: 'kelly.jackson@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-68.png', linkedinUrl: '/in/kelly-jackson-8b32bfb505', jobTitle: 'Pension scheme manager', }, @@ -2685,7 +2685,7 @@ export const peopleDemo = [ city: 'Samanthafort', email: 'jack.ingram@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDss03PNRBjWdr19JY6NcTQnEuMKfr/APWrNstK5T1fxfb6d+7t186bJBP8K49axpPHuoTI7xBLeNO4UH9W4rjorG7vQXijaRckOWGeasnw9qEii3jty2cHbuxj3xWLn5nRGl5GqPHusm48+K5jmABDQ4wPqBXZ6F4stdYtVJYJPwGQnr9PWuBj+H2uyxo7rFEQ2QAeQPwrPvLC/wDC9zG827Jc4daan2YpUna7R7XvB6UhNY+gammpaLbXKsCxXa+P7w61p7+K1uYWIx0ri/Fl1O+sRafk+RJECB6kk5NdiCa5fxZFIbiymjTOd0ZfH3fSonsXT3On8M6RaWWlRxhN24ZJPfNbYtLZCCsIz6gVzV3Jc2VtHHB9pO2MbRCoPQe9TaFdanI6LdPIVfDZkABHscVy+Z6KdtDfkwg+6PbNch4v0+G+0yWOUDP3lP8AdI6GrOvX2pee62xk2RcnywCT9M1Qbzr2zmifzgTGdyyqM5I7EUW6hLsYXw9DW0t/ZiRmjUhgD0B6Gu7PSuO8CWZhtrydsl2cISfYZ/rXXluK647HnS3BFqO8s1u7ZojnJIK4GcHNSIamU4IYdRRJXTQU5csk2X7R45YlyATjoabc3NraXUKSyJFvOBnjJ9Kgs12nOeRUN3qEEhCtbyykZyViJH5muRLoenGz2FtJ7e5v7lY5Ekw2OOeaTUjHFC2AA2McCqlveQLKVit5YWPQNHgH8aW83TSoufmyOKGtbDlZblfTbWO0tikeeTk56k1cxSqm1QCcmmMcV1xVkkeXUlzSbRIicdKfjYpY8AcmkdliXLH6D1rNvL53haNQFU8HnmqbSJSbG6Zr8OpQz3MCOkUchibd1BHfitdZbWe3Uu+UI42msXwxZ21q17bAAfaJTNz3yBn+VaNxocE/yxMYJO+04Brik/eZ6NPSKCeSC3RiknAHc1mNrFtaXEEl05SOVjGjEcFsd6lPh9reTE9w03oCeBWL4tsRcW1rGrBBHKGx6iiL95BU1izrCd3I5B9KYy8VzdnrFzbQKrBZYkAXB4OPrW3Z6lb3YHWNj0Dd/wAa7FJM89wAAAAAAEWj/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-69.png', linkedinUrl: '/in/jack-ingram-e68114f5c7', jobTitle: 'Pharmacist, community', }, @@ -2695,7 +2695,7 @@ export const peopleDemo = [ city: 'Port Michelle', email: 'rhonda.jenkins@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwCi3WmYqQjrUU0iwQvNIcKoz9falsMPTJxnp71GdSsbeURzTgN6AZrCQahrV8I7MGSdjwo+7GvqT2rqf+FY3Vza+bLfD7SecjpWDqm8aTG/a7d498T709cEfzpA6yrujbIpi+EPEejxHyHhuo/4oySGx7E1gy38lndsjq8Lq2CHGCPZh0/GpVV3HKlob5Bpyqc1DZXSX0HmJjIOGHoatKvNdCd0YWswwOa57xXcyQ2kEEZx5rEk/T/9ddCa5jxajFrA44LMv48UpbDjudn8O9GFjo/2iTDTzneT6DsK9Ch4jAyK8/vbo6NpltbR2ktzIYwBGhIAwOSSKt+FZL15VL280EU2CVdicZ+vQ+1cLv8AEeirJcp2rkbCMgetcB4+8PxX2nPeRjbcwjOcffXuDUviyW6guBJHbXF0inAWNiB19qfY3UmoRvZXFrLbsF2sjHcrZHUGjX4gdn7p5p4YvXt9WFrIcpKpH4jkf1ruF6157ZxNZ+LEtmHMVwVGfTJr0KMZNdsdjz57jSKhvNMXUbVN0YIgkEu7JyD0AH1z+lWD1q9pbIZmikOEYZ69xyKVS/K7FUbc6udTZSQyQhWRTxjkVFe6tZafe26SEqrNhQFJycZ/AcVStCTgoQVPIIPWq134ihhuPIW0edhkE7DgeoziuFXeh6SSNXTNTs9QlmVWJUORhlIwfxqzeywQL8qDpWHY+IYLmVrZrOWB8gA+UQp+hxVq6jaQjJ470SutB2Ryp0C2fU73UjCrzmVWUOD8qkfeHvnP5VLGK1Zr22bTv9HlWRpAVJA6DPSsxOtddG9rs4MRy3SQ0rSplHDKcEdDT9tKE5rc5i9YXIRDF93YR+vNai2kVyAwm2HsR1FZcEAfI7sP5UxvNgAwWx9a4Kuk2elRk+RG0tvHbAnzg5Pc9azb66d4JY4m52nB9KgjWW5bbk4+tTSQeVbFcck4qFq0XNuzZlxRCG2hhUYWNAoqRI+amM//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-70.png', linkedinUrl: '/in/rhonda-jenkins-f071128f22', jobTitle: 'Aeronautical engineer', }, @@ -2705,7 +2705,7 @@ export const peopleDemo = [ city: 'Youngborough', email: 'jacqueline.johnson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDpgFxQcU78K5Px74hk0TR1jtHCXdy2xW7ouOW+vam3YSVy5rXi3TNFJjkmElz/AM8Y+W/H0rFj+I0Ujqo0+UqTgnIB/AVzHhjwZd6+BdySFIWbJkfkse+K9GsvhlYeWrvcTM45DcCsJV0nZHRGg2rsq6Z4x0zUn8olreYnASYY3fQ9K3SVIyOhrmde+GcEvmTWdw8UvXaeVJrG8NarfaVrA0DVi2W/495GOQfbP8qqFVS0JqUXHU7tgKFHtRigA1sYF3BryTxo0Go+Po7Td5ioqI4B+63Uj+VeuCvGEt5Lj4nSiRSPMumbp25OazqOyNKavI9h0aKKGyjhhQKiAAKO1dFHxCNrc+lefahqUmmL5JtLqYMOkQP+Sab4eOqnUFy1wtrIQxWZslQeg+tcNup6W+h3F5nyzzyRXlPxAj8iCG/i+W5tZVdG/GtzxXfapDqLxQ/aDbQ/eMAyxrl/El22qeH7ldkwaEAsJOvUd6qC95Mip8LR3Wm3qajp0F0nAkQMR6EirYFcz4IuPN0JI8HMYA6e3/1q6cV3rY81qzLK1x1zpC2muHUEVSyMzu5PJLHp+ArswfauY8WazDokHmXEBdJ2WMFeoPr+FZVouS0N8PNRbTOm0++hu4AkkaH/AHhmk1HU7DT5Y0kljhjyMs3GST0Fc/YBxyjcdRVy51nTtgguLKedhyAIM/iCf6Vwq70PStfYtxajp99rVzEk0cyMoJHXBrL8RLavaSWcMSgSgrhRVSDUtJtpGjt7S4gduAXiILVXlzNqMSyNnfIEH9apJ81iZtRWpraHYpZaVBDEAQAeQOvNagjbuKIwAoVAAoGAB2FSc16KVlY8mTu2yVRWD4y0Yaz4dmjCbpYT50X+8P8A62a6ILUdzOIIioQs7A444pSkktQjFydkcdFM1uQhYqrAEGtH7LY6hF+9vHj+h5FE9h5lmOOVFc1c288TEDcB7V5vU9ZaGtcWdnpytJHdO/puPJqvZwm8ube4CtiKTO4cYz1/rWQkEk8mGLEDk5rovD16geSxlQLxujcd+eQa2pNKWphXbcdDpRgDjpS8mlCgDB//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-71.png', linkedinUrl: '/in/jacqueline-johnson-dda681b600', jobTitle: 'Water quality scientist', }, @@ -2715,7 +2715,7 @@ export const peopleDemo = [ city: 'South Matthew', email: 'casey.oneill@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1CkZ1jRndgqKCWYnAAHelrzn4wa1NY6FbaZBIY2vnbzSpwTGvUfiSPyoAx/EvxglaWaz0GFECttF5IdxI9VXH6muCn8Z+IbuQiXWLtt3BxMVGPw6VseF/Af8Aatot1eO0KScoi9SPU11ifCnTimDNKc9DWDrRTsdEcPNq559pfj3X9JkHkancsgOSkjeYp/Bq9o8J/EDT/EaQ285FtqLL/qj91z/sn+h5ri5PhHCisyXb57ZFcr4g8Kal4d8u6il8yMOBlOGU9j/9emq0W7ImVCaV2fR1AFY/hbUm1fwxp97I26WSECU/7Y4b9RWxWxgFeN/GJWk8Q6YuDtFsf1c5r2WvL/iSkWpa1p6RxsXtJBFMx9H2kVM5JIuEXJ6F/QgE0+3QjDBBx6cV1Vv9wc5rgL97qA7IfPxjKrAPmOKs6He6x58cMxkKPggygbgPQ47159vtHqKX2TunYlMZ4rjvGQU6Pcjbuwmf1pniC+1eGZ47fzdicnyQCT7DNU4lnu7aaKcXHzxncs4HBI7YoS+0KT3ib/wv8z/hDhu+4biQx/Tj+ua7SuU+HarD4Qtrb5vMjyXyOhYkjH4Yrq69GLujy5Jp2YlcX4v04tfRzgYjfa7EdSydP6V2lV72xh1CDyZtwXOQVOCKmpDmjZF0p8krs5awME8SrIoJx3qaRoI7yKNCihSMngVliNrW7eHPMblcfSql3faXLOkd2rNKpJGxCSp9c156TvY9RNNXOkMls9/JHIyMrtgHg81FqCwwwskagZGOKwrC90hLh4YAyyvgEyIQW/GtaOBr/UIoNx5bkjsKfK72CUkldmz4YtRbaa3+0+B9BwK2qjhiWCFIkGFUYFPr0IR5YpHk1Jc83IKKKiuZhBCzE/NjCj1NUScT4icwa7cY4B2nPvgVBFGblQ0c4jYDg1Qs7O4iW4huXLyiWTJY5ONxx+mKieCdAfIYqw7dq82TvNnq07xijZaI28bPLOsh6ZrX8K4nluZzyVCqp+uc/wAq5KK0upUDXD8Z+6K2vDeqNZ6//ZrjEVxCZFb0ZSP6GtKLXtEZ17uDO5ooBBGQceaf/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-72.png', linkedinUrl: '/in/casey-oneill-ab8f249833', jobTitle: 'Local government officer', }, @@ -2725,7 +2725,7 @@ export const peopleDemo = [ city: 'Lake Christopher', email: 'kathleen.francis@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-73.png', linkedinUrl: '/in/kathleen-francis-097093196c', jobTitle: 'Paediatric nurse', }, @@ -2735,7 +2735,7 @@ export const peopleDemo = [ city: 'East Diane', email: 'gary.woods@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-74.png', linkedinUrl: '/in/gary-woods-4b0cba46d6', jobTitle: 'Multimedia specialist', }, @@ -2745,7 +2745,7 @@ export const peopleDemo = [ city: 'West Michael', email: 'rachel.harris@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1RiFUsSAAMkk9K8l8Z/FJ/OfTvDjjA4kvAM59k9vf8q3/AIq6xPp/h+Kygcx/bWZZXB6RqBkfjkD6ZrwnzS0m1B14A/xrOT6I0jHqzWn13XJ28yfUJ3b1aQ0238R6xZfNaX1xGFbdhZDwauaN4Tu9ZkBLskPdumfpXZQfDuxiCZlkLfxZPWsnVjHQ3VCUlexzeg/EnWdKvkkuriW7ticSRSPnj1Ge9e56NrdlrthHeWUm6N1zgjBHtXjuq/DmEBpbSdw3Xaw4qD4c3mpaJ43j0ne3lzkrJEehwM7h78VcKsZbEVKMoas95xRS0Vqc54r8aL4trdnZh/lit97D0LMf6AVwGg2ou7+OPaWBYDnvXqfxN8KjVtcW6imYTNa7lTbxlCep98iue8AaPsuriW4jIki+UZHQ1hUmkn3OulSk3FvZnoGm28draxxRoFwB0q2yniuf1W/mtVMcNrJKWHUttUfU1h6DeajNdKX82NJfm2lidoz3B6Vxct1c7+az5Ttp0ZoyK4TVsaZ4z0HU0U+YLgI+3uM4/kTV/wAXalqNpLHb2u/DY3FM55qjp9m+sazokMsTp5d9iQlywYAFsg+h21rRi1JMyxDTg0e1g5AI7jNLTVAVQo7DFLXeeUc94t0972xV4/vKdjn/AGCRn+Vc5a26WcrlE27iMj6DFegSqHRlIyCMEV5xDPdf8JDq1ncZMVu6LCduMqRnP51yYinrzI9DC1tFTZtjbPHgqD7EVXEVtbzbEQeYRuOBjAqRMopxWdfXOkmJlvpkLN95c5J9sCuVanfoT3sUMtzFvKNuXHY81c0K1hfWIgqD9wDIPY4x/U1zCXmlyT4tpiz4wu4nI+ma7LwlEWW4uXX5jhAf1P8AStaUX7RIwxDSpO509FJRXoHjiGuX1qzCSpOBhpCa6WeVYIHlfO1VJIHU1y93fy6g670WNF5VQc/mawxE0o26nThoSc+ZbGcLnB8tmAPTmknskuIioCezHgipprJLjrjcOlZkttcxlszbUWuBb3PUTK72C2z5LIx/vE9K9C0i2+w6dHG+N5G5vqa4AW+9D5rFwRgg+ldH4fvZrPTLGO4czRbAuT1z2NdFCS5tTlxalJI62iqseowv1DKffmrCyxuMq6n8a7VJPZnmuAAAAAAAItH/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-75.png', linkedinUrl: '/in/rachel-harris-93dfc3611e', jobTitle: 'Medical laboratory scientific officer', }, @@ -2755,7 +2755,7 @@ export const peopleDemo = [ city: 'North Douglas', email: 'charlene.rose@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-76.png', linkedinUrl: '/in/charlene-rose-98947b0547', jobTitle: 'Solicitor', }, @@ -2765,7 +2765,7 @@ export const peopleDemo = [ city: 'Hudsonmouth', email: 'donna.saunders@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDkDOrDrWfvzcNUhqsDiY0AWw4VC5BIHb1pHMwhedyqxKOAQQazp57i5vUtLdjuJA+XrXcaR8Nri+iWW7unTjp/jWE6iTszop0m1dI88uJJLg+cwIUHgHpWnpsU6fvSSy4z0yP513Oq/DthbKkUmFjBxtHX61xV8t1o+YZDtcfdK1KmpaFOm46sry37i4yPkdT95ePzrrtGv7fUIShIE6DJHqPUV5xPctJIS3Oehq5pGoPaXkUytjY2Tz1HcflWi0M3ZmzVUn98asdKgAy7fWtTE3Ph9pi3viS5uJlybdcrn1J/wr2uCNRGAGBJ7A1474dtXtxelRJMzhMeS2Mdec12Ph68v5YXEolj2xlh5xyy+xrgqx95s9Ki1ypHXXACLtD7ie3XFeceOfDbX9v59uuJo8nbj7wpby81AXhlZ76ZAQNkA45Na0d7NcKIZElyvGHHP51FmtUaOz91nhFwjxMyEFSDyD2qONtpzmu68b6MElS8ih27ztcep7ViWvhWZrOe4uDJDtB2Ar3xkZ9uO1dcaicbs4nRlz2RoEVAg5P1q2y8VAik5+tbnMd58PSkkF9FKFYfKBnsOa7WFIILK62bMthQo4yK8x8I3bWurGDOFuF2/iOR/WuuvxYSjY1/5J/5aDcQf/rGuGsmps9PDNOmjWt7W3mLKyKGTjB6j60s0kNpCVWNR9KzrSewgtylteLLKxzuMm4n2qK6EjkhjmsWb2Rk30a3r4lXcgcNj1xUF/apDClkrbZ79wgUc7R/Ew+i96mu2MYJRypXncO2K5fwpcXer6zd6neyyTPGpjiLdFBPQfhWtGHMzCtV5IvuyMxZQ0yKLC9K0ng2qRVcJtFd55Yy3LQXEc0fDowYH6V3tvCdTs0uIXQbhyGwea5Cx0671CXy7WB5W74HA+p7V19n4eudI0m6vLq72iOMuIo+Rn61jWhzK63OnD1XTl5CpYxWQMsiRGU/xYBNUrm9Zt2Dkn0pLnzpQpDllYZqOK0JYZHFcPU9ByuVpIme0lJzllIpPDMNmllJ9lDbAwB3LjBx0rYFpJdFLe3XMjnA9veujt/DdtZadHZQKQA24t3LE5Jrow7erOTFWwAAAAAADRH/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-77.png', linkedinUrl: '/in/donna-saunders-4f712712f8', jobTitle: 'Actor', }, @@ -2775,7 +2775,7 @@ export const peopleDemo = [ city: 'Lake Jennifer', email: 'thomas.singh@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-78.png', linkedinUrl: '/in/thomas-singh-640bdc36f3', jobTitle: 'Press sub', }, @@ -2785,7 +2785,7 @@ export const peopleDemo = [ city: 'Jordanton', email: 'ryan.morales@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-79.png', linkedinUrl: '/in/ryan-morales-081c6966a9', jobTitle: 'Food technologist', }, @@ -2795,7 +2795,7 @@ export const peopleDemo = [ city: 'South Philipbury', email: 'christy.hall@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwC6WGajdqb3zSE56VACh/zpJJUiIDnkjIGOTUV1OllaPcS8heg9TS6H4Nvdbxqeo3Mlukx3JFHwQvbntUSnbQ1p03LUSfWNOs03NIC+MgA1FB4kiuk8tInMn04H4116eA9HiUfuN79SzHJNcnrvhWbTJjc6fcMgznYVGPpWbqM2VFCf2xF53ly4BPcVfiKyJuRgV9RXC316HPIG8HDoRxn1FXNH1z7I2xiTGTyCaqM2tzOVNPY6t14qDcVNSu/FRdTWpgOSxTVry0tJfuGUOV9QuTXokBSNAoYceleYy30enTG4e2knCxMoSMnJLFR1rovCUslwh/0ee2iZC+2Vicc471y1L81zvopch10l1EvBlQH3bFZupbZLZgdrBulcfraXVjqBu7fSjeyH5tzscAZxwPWtKyvb28cpPp5gdTglOUb6VD1VzZKzseb+KEjgu5Bs8tweo71iQ3SzxEcLMvOR3r0Px5oouNMa6UYmi5z6ivIopGRzjhgeOetaU/eic9Vcsj2RyRT4ypFOaPIpiRNniuo4zf8AD1pbStPLMoYkBBnsOp/pVy51XS9Nilj81IcOFc9l+tZeju6NJFyAfmqR9TsPtbGLT2uHU7WlWMnp7gVx1L87R6eGjeCsdFZXFrdRMSVbYcZHINJd3cMIyirx6VkWupWt1iCCGSGRedrRlf8A61NuFdyQTWMpNaGygr6mZq8/263mh27hIMYrlrfwtY273AWItOE3KsihlPqK6i5eK1UsTgDkn0rnvEvi3TtM02a2sZFlv5MqAvOwnq5PbjoKULvRBLlj7z6G6Yi3FSxoE4xU/lgDNMI969M8Ykt38qfcBwQQa0UsbaYBzMEJH3R0rNi61n2z38OqzWryq9v5W+Jv4wc4IPqK5sRH7aOzC1LPkOmmaG2j2h8/Ssu5vljjPIyaz5XnLYYn606KwaUgtkj3rz3K7PRUbFS4kaWCSVh8gU9e9ea+H9MXXfE7Jcuy7maQ7RnOOcV63f2gFm0SjqMVg+C/DbWt9dalMu0BmijGOvqa68N1DjxfRn//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-80.png', linkedinUrl: '/in/christy-hall-916136bbc9', jobTitle: 'Pension scheme manager', }, @@ -2805,7 +2805,7 @@ export const peopleDemo = [ city: 'Dustintown', email: 'joshua.hawkins@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-81.png', linkedinUrl: '/in/joshua-hawkins-9a0340bb4e', jobTitle: 'Occupational psychologist', }, @@ -2815,7 +2815,7 @@ export const peopleDemo = [ city: 'West Timside', email: 'jasmine.stanley@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-82.png', linkedinUrl: '/in/jasmine-stanley-94eeb75ca5', jobTitle: 'Nutritional therapist', }, @@ -2825,7 +2825,7 @@ export const peopleDemo = [ city: 'Jessicafurt', email: 'morgan.thomas@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDvTTc80E8UwtxVEiTXMdtGXkOFFcH4i+JdvaRtDpcZmmIwHYfKp+neqvjvXbiaSPTrf5Uc8EfeY5xx+NN0r4XS3NgZdQn2zSLnA6pWc6iiawpOWxxr6/qeoz77yaWXd/tHH6cVL9tnjBmt5po2HB8pipH8q6O7+Gk1hE7RTs6Lz8oww965XVrS6smAYh1wPnHeoU1I0dOUVqjp9B+Imoaawi1LfeW/95+JF/Hv+NesaXqNrq9hHe2cgkhkHB7g9wR2NfMjzurYycDse1dz8NPE7aZrI0+Z/wDQ7xgmD/BJ/Cfx6H6itYsxkj2PHFNxTz0puKsg83OnjUvirIp/1NggkC++M/zb9K9OhZQgUMM45rg9bji07xFf35t7qZp7eFNltwxb5u/0Aq/4aa7nkZH+0JGIi4W4O4rnsTXDW+K56OH+Cx1kwQ5AbOe1ee+MPDMrxT3NiFJkX97C3RsdGHoafqEl/a6krvaXt4ucARzbFA7VqW13NdyGMwTxgcbZeR9Qe9ZJ21Ru1fRng1zvVykgwy/Kc/1qOC4e2lWSM4ZWDA+hByK9F+IPhmKOI6lbJtfOJVHQ+/1rz620y+u4JpoLaSSKHmR1HC12QmpRuedUpuMrH1CelApxFJitznKziB7h0ljVsqMk1Sl1jS9PjuY/NjiIwGPZR70/UlZJo3XOGGDj2rIlvtLNxldOluZEwC8cW7p7159RP2jR6+HXNTVje0+8sdQUgSI4UAh05DA0t3dRWwPlogx3rIh1iykAt4bWW3kJztaIrzRdKzZBPOOaxlpob2MvVj/aaNAwyrEE/nVL7DDDZXCGFViRg0bp3weRj1P61cupFtoicE46gdTUeiajD4j1dYrNZPsNoBJIzjG58/KoH6n6VpTi5uyMqlSNNOT3PQNtG2pdtJivTPGM/UoJJLNjCCZF5AHf1FYUdlazKrtctGcfdQ4/SutxXI+KoEinSS3ISVlJdV789a5cRTv7524Ss4vkLEjW9rEFEu73NZd1q0SqQGBz+tcy89xLJsYvj61pWljvAOPxriaO/muJcyTT2FzMFO7yyI198cVueANEk0vQwJhiaU72FQpCYwuFyAQcHvXU6NeW99Z+bApQoxjeNuqMOoP+eldeFa1xad0f/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-83.png', linkedinUrl: '/in/morgan-thomas-a18e91a104', jobTitle: 'Clinical research associate', }, @@ -2835,7 +2835,7 @@ export const peopleDemo = [ city: 'Carlosview', email: 'laura.gomez@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDj3dUUuzYUck1lzarJvDKfLj7D+I1ZvpFdXiPADYPufasR41hlDy/Mo5xUSl0RpGGl2bcN9MIWlCq7gZUE8fmadDrSTQvII/KuI+WQ/wAVY8EF1rFx5cRKgDiNBgL6ZNbkHgLUQgdp1yf4f/r1k5Jbmqi5bIjg1iC8yEj2tnlSf5VYfg1Hq/gu5h2XEG0FV5TtnvWfpVwS88E7fvV7Nx0rSE0yJ02tzQalTg03OCR3pyitTEwLwzfaGHO0EknHWqUbStIIEkJdyMA81o3Em6O4DFjsAA/GovC9p9s1xOuEGcVz3srnTa8kj0DwtoSWMO5l3SN8zsfWuwESbOGH0zXIanNdW48mO2ZlIwXIyB+HSsHS4L77bHIFmjEh3Y3EFRnHIrC11dnVezsj0O5g8yBgeOO9eV+JII7HX43PyrIMsB3NdJ4tfUY9QttPj80K6qWZSQOa5TVl3X1gJI2UBSGySf4sZqqa1uZ1XdWNMlJNjxbtjKD83WnqCDTtgLcdMcZqRUrsWxwPc5FpZZLny3QKrnG1a3vCcDWOps7IQhGD+dZGuJbQXUj20o8zqAvRTn9a6LwndSX1s0k4Td90bVx0rmqXUTrpNOR6PFcQXcHlsikEY56VEtva2rhI41Mjgk4HQCsu3Rox16dKdd3el3dm0V1crGw4JEm1vpxzWCOvQ1NWtre8ntXOxwY8HocEVwHjfyor/TxCmCqurAd14rZtZrGHKxXgkYDCZc5A7D3rn729Nx4oaJ8ELGI8eh6/1q4J8xlWaUSa3GYYgOSFwTVpUp0cXtVpIfau5Kysec3d3MJ/B9xfSXU1tGk0UYMzxqTvIzyAOlW/DtkY9OMkcRiV2LopOSBXrXhfRUs3mkY/v2AwP9n/APXSa74bR1ku9PiAlHMkK9H9x7/zrGtBtaG9GaUtTz+O+LDZuCuOCD2qb7O80eIzCGA4ZhWdqAhfcWQhweo4IrOS6uRgCXIzgetci8jtvY1ZoWtI3kupYdijJYDAFZl3pIh1RJpECyMwkYjPzg8ipLpTJB5btu3ctn0xXQyWT6l4N03UlBWe0UK/+1H0/wAD+ddFGzepz4hvQzEAxuyMVchiJFUlHlyZP3HOGH9a6nw5OltN9nuUWa1kP3XGcOo4rH//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-84.png', linkedinUrl: '/in/laura-gomez-7ee145bfc4', jobTitle: 'Bookseller', }, @@ -2845,7 +2845,7 @@ export const peopleDemo = [ city: 'Rileychester', email: 'anne.montgomery@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1HFMNOrE8W3hsfCuozrJ5bLCQGBxgnj+tMRi+JvHtppZks9OK3V6vDEHKxH39T7V5hqPiO+1C7Xz7xxO5wMkHn+lZtpFHt3eWXI5wxwCfp1NXH8KaxqKmRLTy0PIz8tYSld6nRGGmhTg1iY30W+Z0IGfMDEFT7YrsvCPj6ayu0tNSleSzc4DudxQ+ueuK5aLwLqqoztGuV55frWVqFrcWk25kMbLwyEcCmmr6CcXbVH05G6SorowZWGQR0IqVeK8v+Fvih7uNtIuZC2xd0Oew7gH0r1AVqncxasBrivihfrZ+DJ0OC1w6xKvcnOePyrtTXnnxasJbvQ7GaJC/kXBJAPqv/wBah7Cjuc94F8NvJHHqN2Q+R8iY6e5r0Vk2IBgYHauAE2oWHhKw+y28slxJH/C21V9yan8I32tXN5FFfs5jcFgWOdvXg1ySi3eR3xaVkdkyEqQE61xHjLQ4bqzklCFZl5GOM1U8V3+ux6l5Vi83krz8jY3c47dasaXf394DaX8EiPHkb925W+hoUWlzA5JvlOO8BXT2njTTojII/wB9sJY4BB4xX0d0NfOdrohbxDd79yJHLtRwM4JbivomJXWGNZG3uFAZvU4610xaZxzi1uPrP1uzF9pU0JUN/EAe5FaFIelW1dWIi7O5yWkiNbBLK4Qb0XaQeRVuGK1trxEjEa7fmYgBR9KpSGM6vcwxN88ZG4egPT+RrL1q/wBIjYW8yT3Fyuc+QCShI7kfyrhs72PSjaSTRorb211O8MwQtkspIBBGe1Q6gbe0i8uNRuxxgYrK0i+0vzPLgjngnJ3fv1IZvxq5eKHn3tzik007FGdo+mRHWxLcOEinkBKnuRz/AIV6f5yZ4YH8a8Q0uO+1Od7j+1I5XhdlEMh27Rk9PXgfpXUahFr1irSlZki/vA5Arqpq2jOGtJPY9LzUF5OLezllJwEUmrO3jNZOvPFHYN9oYrBn58d/b861b0MVueaRa5LH4rRjEwW8zFuHQEcjnvj+tdO1tDeRYkuFiGc5A5zXJ6h4gTWryxgsLOOCC2vUVZWOS3944HA/Wuj1Cx84Aq5jdhwQeM1yTXKzupSugFrDYowjuRIp7kDP41V84zkqhyO5qpBpt205S4lzH3xxmtNYUgUqgwuKzbNDybSRdDWJPKjLtHMd2Pqa930bUjcacDcYb5QGB5rx14vsfjxfIbBnG5wOxOT/AEzXq9iq+W0YwA6hgK609EzhcdbH/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-85.png', linkedinUrl: '/in/anne-montgomery-10245f347a', jobTitle: 'Arts development officer', }, @@ -2855,7 +2855,7 @@ export const peopleDemo = [ city: 'Nicolefurt', email: 'tiffany.peterson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDpRj0ppwKXPy1zniHxEmkxMM4bkA9z9Kluw0rmvd6laWK7riZIx23HFZZ8X6YwkMVwq7BkluAa8o1DU7jULhridmcseAT0qxZaBrF3H5kVpMYz03LjNS5WLUb7Ho8HjmxeQpISATw7AAGtqz1e2vgDGy89MMCDXjV/4c1a1XzmtZlXuPSobHXLjTJ4jG7FQfmUng/WhO+wONtz3kEU/GRXJ+HfFFtqWyMny2bgKWzz9a60H5apMhqxER8prxHxRqL3esXGxy0Acooz0ANereJryWz0V2hYrI52Ar16HOPyrxe8Mcm7LHlup9c80m9SktDrfh74eS+uX1G5XfHGdsasM5Pc162I0VFG1R6V5tpt1HpWhwwlJpEAwI41OXPrV7SLi4EomgimVXYfuZXPU1yTTk3I7qbUUonW38SvCQQDXjfirQmsrp7mPBhYnI/u11eqXMk0rXF1HNKqOVEMLE7SD36Vn6hi5tJFghk2N8jRScYPqDVU1y6k1LSVjjdNv5LGcMvtznp717l4f1AappMNyoIDL0PX3r5/PySEHnaSCK9f+H+pR3OkJADteLjHrXUcXQueOxnQVXO0tKAp98GvGrtWa78sHIU4HbmvZvGlzFHpQVgCysGHPevGpZwl+JGU7Q4LD8eam+pSWiue36XawXOmwEExyeWoJB9qC9hpt4v2ids8hM5OTjnH4VB4au7a/wBOSe0l3xAlc4xyPap9Q1aWMmK203zAmcyykKvvjPWuBJt2PUSTtYzbeO2vb6Z4JmG5jnaSOfeo9RtoreNmYszgHBJzTrXVJHlZZLEROTndFgrVbWblIrSW4mJ2IpJx1q3e9iXZJ3PK75fLv5c8kuW4rq/AmqR2V9JHNlYZR1AzgiuX1K5W61N5VQpHgbQ3XFafhcy/2knlqGBYKwI6A8Zrt6HmO3M7HpXjnS/tHkyxOQXO0r7+v1rybUbPyZmy3fnnmvf9YszdafIiAGXadh9DXh+u2EsVxKDGd27ex5OOvU0rWY07xNP4e6vNbXdxp5OYZF8wD+6wwD/n2r0jzNOmhPnuW/2c14/4UlMPii2x0bch/EV6ZqGmLODInyuBziuWukpnZh23AfdTWVsn7p8L6E1x3i+8aXRmVMiNnUf71a62TBsOCfrWT4tty+mBEH3SDSg1zIqpfkZwaYOK6Tw8+yXEYPnsQIyOB+J7VzkYweeK6HwwjPq0UasgLNgB225/Hsa7WecAAAAAAefE/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-86.png', linkedinUrl: '/in/tiffany-peterson-fed8500c17', jobTitle: 'Multimedia specialist', }, @@ -2865,7 +2865,7 @@ export const peopleDemo = [ city: 'North Kelsey', email: 'ian.martinez@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-87.png', linkedinUrl: '/in/ian-martinez-03c2967428', jobTitle: 'Phytotherapist', }, @@ -2875,7 +2875,7 @@ export const peopleDemo = [ city: 'Lake Daniel', email: 'shelly.rodriguez@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDpgFxQcU78K5Px74hk0TR1jtHCXdy2xW7ouOW+vam3YSVy5rXi3TNFJjkmElz/AM8Y+W/H0rFj+I0Ujqo0+UqTgnIB/AVzHhjwZd6+BdySFIWbJkfkse+K9GsvhlYeWrvcTM45DcCsJV0nZHRGg2rsq6Z4x0zUn8olreYnASYY3fQ9K3SVIyOhrmde+GcEvmTWdw8UvXaeVJrG8NarfaVrA0DVi2W/495GOQfbP8qqFVS0JqUXHU7tgKFHtRigA1sYF3BryTxo0Go+Po7Td5ioqI4B+63Uj+VeuCvGEt5Lj4nSiRSPMumbp25OazqOyNKavI9h0aKKGyjhhQKiAAKO1dFHxCNrc+lefahqUmmL5JtLqYMOkQP+Sab4eOqnUFy1wtrIQxWZslQeg+tcNup6W+h3F5nyzzyRXlPxAj8iCG/i+W5tZVdG/GtzxXfapDqLxQ/aDbQ/eMAyxrl/El22qeH7ldkwaEAsJOvUd6qC95Mip8LR3Wm3qajp0F0nAkQMR6EirYFcz4IuPN0JI8HMYA6e3/1q6cV3rY81qzLK1x1zpC2muHUEVSyMzu5PJLHp+ArswfauY8WazDokHmXEBdJ2WMFeoPr+FZVouS0N8PNRbTOm0++hu4AkkaH/AHhmk1HU7DT5Y0kljhjyMs3GST0Fc/YBxyjcdRVy51nTtgguLKedhyAIM/iCf6Vwq70PStfYtxajp99rVzEk0cyMoJHXBrL8RLavaSWcMSgSgrhRVSDUtJtpGjt7S4gduAXiILVXlzNqMSyNnfIEH9apJ81iZtRWpraHYpZaVBDEAQAeQOvNagjbuKIwAoVAAoGAB2FSc16KVlY8mTu2yVRWD4y0Yaz4dmjCbpYT50X+8P8A62a6ILUdzOIIioQs7A444pSkktQjFydkcdFM1uQhYqrAEGtH7LY6hF+9vHj+h5FE9h5lmOOVFc1c288TEDcB7V5vU9ZaGtcWdnpytJHdO/puPJqvZwm8ube4CtiKTO4cYz1/rWQkEk8mGLEDk5rovD16geSxlQLxujcd+eQa2pNKWphXbcdDpRgDjpS8mlCgDB//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-88.png', linkedinUrl: '/in/shelly-rodriguez-42e2b8178f', jobTitle: 'Conservation officer, nature', }, @@ -2885,7 +2885,7 @@ export const peopleDemo = [ city: 'East Michael', email: 'philip.santos@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-89.png', linkedinUrl: '/in/philip-santos-0c763b15db', jobTitle: 'Field trials officer', }, @@ -2895,7 +2895,7 @@ export const peopleDemo = [ city: 'Jeremyburgh', email: 'michael.foley@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDWPPamY55xj2pw4ycVQ1fUo9K0ye9kXcI14X+8egH51zHX0K+sa9YaJCHupPnb7kacs34envXG3PxIundhZ2cSKOhkJZv6U/SvCV54nlbVdUnKmc7gBzhe2PQV1tv8OdIgj+dHlJ/iY80c8VuCpzlqtDmdL+IscmE1K3KtnmWIcflXaW9zDdW6TwSLJG4yrL0NYt/8OtKeEmJHQ+oNYWnvc+D9YispZTLpl0+FY9Y3o5oy2DklD4jvRg9qegApoHGc1IuTz2pDsByRXJeOWY6faWgIxPON30A/+vXXEYHqa57xHai7vdKHB2T/ADjuAccn24p3tqFrqyNzR41jsYY1HCIBxW18xXCOD7VyN9evZlo1W5YFc4gTLH8ag0W81O6vliLzeSxDHzuoHpx3rC2lzpvrY664RihXdjNcF4yt9+lzcfMmHBx0Iq7ruoahb37QqZzEnJ8gZJ+lQSS/2pYzQsJsmJhtmXDAkVUdNRT1TRsaPcG60aynfJZ4VLe5xWgMAcCsnwzG6eHbJHIZlTH056VrgfnWpzkgX3FUL633FZQo+VgWbHOB0/WtHGRnNQTq5t5ETHzDnNKSuh05WZbtTbXFttlAHbmqR1PTLW/SHfHAu7CZHL464qtFkqQpI4zVCfUomAgWwkmC8Z8s4P44rCKvodRflv8ATptTk/exyqxwQPvLnv8ASpL+G2gj/dAcjtWAt7DDPsNi0G4f3CV/E4q+waQqozzjAJ9apqzE3oXtOgENoqAEck/Srmwg02FHRAGxkDtUv862SOWTuyRwMcDFROywwyzODsjQu59AOtWI4ZJm2RIXY9gK1YNCL280N10nQxMo7A9atK5k5WOE+0gfMj4jY5Un0q4IvOgHl3axYHBHUU2Tw/PpkH9m3WS8Q2q/98Dowrm72K+sZsIS69sGuXZnanomjckj8pTvuRK3rjmqcmpiwMM7RmRPMCH2zxn8KzrQXVzITICPUk1oS6ZNqNzZWtsBlJlkkz0CDrn8/wA6qPxImbbi2dSD605RnpWpc6dEsAYAjGMY9Krvps0A3Y3r1yO1dDicAAAAAHIpH//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-90.png', linkedinUrl: '/in/michael-foley-a0535b3102', jobTitle: 'Exhibition designer', }, @@ -2905,7 +2905,7 @@ export const peopleDemo = [ city: 'Port Caseymouth', email: 'david.raymond@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDscgCmk5qPd70m6gZT1PXNN0aMSX91HDkEqpPzN9BXlerfE3Wbi+32LC0tlYhFVQSw7Fs96ztVS78V+LL2VCoRZCgY9FUcD+Va9v8AD1mClr/PcjZUSqRjuaRpTlqkYa+O/EQvo7yTUpH2HAjY/IR6EV6n4Q8Z2fiKDyZNtveqf9WW4f3X/CuOb4ZJsO29Yt1AK8VzepeG9S8PsJQ52K2d6dV9DSVWLejHKjOKu0fQIIHU09WTvWD4e1M6roFneOR5jxjfj+8OD+orS3VoZEYNUtYllh0W+lgJEqQOyEdQQDU4eklKvBIr/dKEH6YoBHlvhGPbp+8g7nckn1rvbQN5YPtXARPNYaZbJbltxU8qmSeT61p6JrmpyzxwTREF+jEbeK4ppttnp0pKKUTvIGJB9/5VheKmQaROCuflrJ1rWdX0+5MNumAOSQm4mrVrcT6pZSwXiyb2jOfMj29RxUKNtSpSTvEl+Gs8r+GnWRQI0nYRnuc8n9a7LeB2rl/BkX2Pw1BAVwwZiffJz/Wt/wA2u9O6PLaadmJn2pwPbAqIbqeoY0xHGtDFZX8tpKqlVb5c+h5FTQ+QdShjhAVVYFmFP8UWxiv4rgDiRMZ9x/kVhcTTLmGXIzgpj/GuKUbSaPVpS5op9TsrxrP7UY7lUIdiEY4PPpmkk8hUWKActxxWBbmGO3MclrP85BaQgE59etaVjFvulG4kD3qOW7sXKSim2bFvGtvbpEi4CjGKk3c9KQmjNd6VlY8mUuZtkm6gyrGNzsAPeqE2pwIf9TdKv95ox/LOarRXVtfEmG4WU91OQR+BrKVZLZFxpN7mbr+sR6kiW8CNtjcku3GT06VjwtbsQk5YD0BxW3faX5spmgH7wDDJ/e9x71iXVkzOPlII4K9DXO5czuztpxSjZGjA1oqEQFyD2Jyc1q2CtAyuRyR0rM060jgIZUwf9o11djpkt0iOymNOu49SPaou09C5Wt7wsENzcW/neTgbiMK2cgd6acqcMCCOxFdRFEsMCgKAqjCj0FQXDWYXE7Rj/eIrojXa3OGVNN6H/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-91.png', linkedinUrl: '/in/david-raymond-1e1178af61', jobTitle: 'Psychologist, occupational', }, @@ -2915,7 +2915,7 @@ export const peopleDemo = [ city: 'Spencerberg', email: 'amanda.booker@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-92.png', linkedinUrl: '/in/amanda-booker-6781b9995d', jobTitle: 'Network engineer', }, @@ -2925,7 +2925,7 @@ export const peopleDemo = [ city: 'Lake Alexandra', email: 'emily.jenkins@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-93.png', linkedinUrl: '/in/emily-jenkins-54d2700826', jobTitle: 'Technical brewer', }, @@ -2935,7 +2935,7 @@ export const peopleDemo = [ city: 'Donnaside', email: 'timothy.larsen@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-94.png', linkedinUrl: '/in/timothy-larsen-fb5366ba23', jobTitle: 'Geneticist, molecular', }, @@ -2945,7 +2945,7 @@ export const peopleDemo = [ city: 'Campbellville', email: 'ashley.barrett@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-95.png', linkedinUrl: '/in/ashley-barrett-014f05cf8c', jobTitle: 'Writer', }, @@ -2955,7 +2955,7 @@ export const peopleDemo = [ city: 'Patriciafort', email: 'sandra.adkins@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-96.png', linkedinUrl: '/in/sandra-adkins-8cbb8957df', jobTitle: 'Chief Marketing Officer', }, @@ -2965,7 +2965,7 @@ export const peopleDemo = [ city: 'North Rebecca', email: 'kelly.johnson@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-97.png', linkedinUrl: '/in/kelly-johnson-c74ca2d4f3', jobTitle: 'Farm manager', }, @@ -2975,7 +2975,7 @@ export const peopleDemo = [ city: 'Anthonymouth', email: 'patricia.rodriguez@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-98.png', linkedinUrl: '/in/patricia-rodriguez-e83155aa16', jobTitle: 'QuickActions analyst', }, @@ -2985,7 +2985,7 @@ export const peopleDemo = [ city: 'West Keith', email: 'dawn.scott@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDtdtJtqTHFVb+8jsLOS4k6L0Hdj2FZN2V2Uk3oSSSRwxmSR1RB1LHArIn8VaJbhjJfR5XsOp+lcRrfiO7uZhDFELi6kPyx/wAKe2O9NsvCWr3rC41FLZe4Reorn9v9x0xw9zsU8aaO5GXlRD/GycfpW5BPBdwrNbypLG3RkORXmN54Z1eygZIfKnj67TwazNG1678O6kpwwjJxJC3RvUex9DRCtfcJ0LI9kK0BaS0uIr20iuYG3RSqGU+xqXFdBzEnFef/ABG1V7Q29uh6Lvx6sTgfyP6139eX/EuIt4h0xRyZIun0b/69RVV4mlL4jX8G6BFa2K30/wC8u5vmZ27Z7V1rIMcY/CuY1e7k0rT4rW2s2uJfLxz91QBz+NQeFJbqaQCeAwq4DnBOBn69/auBxbXMenFpe6dPMuU7D1zXn/jTSkkt2u0G2SPlsDqKu+KLu6WZ/KjeaOPnaufX2qgLuXUtPuLaa2MMyxkFRyrDHBFOMWveFNp+6bnwy1R7vRZ7GU5ktZOP91uf55/Ou4ry74TSbr7UkI+YRID+Zr1IivQjseXPcUCuY8S6UL7UrSeYKVi2+QMc7s5bJ9MDpXUDpVa/EIg86chVj53EdM8VFZNw0NKEkp6kcTJNHggE+4qjdXtpYyojBl3MFyqk5b8BxUtoRJEJIjlWGVPrVS71YwArDZPMVPLsAq574J61wJX0PUSvsU7G5tbu/uEXlC3G5e/WjUo7e3UhIwGx1FV49W8y4O+yaFj3XDL+JFR6lOAjTSnbGilmPWhpp2G/Mb4H00afqM7QL+7mRjNkchgfl/DBrujWR4et0jsftCZAn5AIxgDj/Gtc9K9Ckny6nk12nP3Rw6VFPEs0LRtnDDtU1LitTI5e0na3ku7cjakU7KvsDyP51dJtXiO98r6ZqS7WFtUkhRR5hiVpTj1yB+PFZWqaaYoFmjYhT1HvXm1VabPUoyvBXI7treLlGOPQmua8RXTHSm8oEgyJn3GQT/KtOO1MkZd2LHOOarak62ohd41e3Rx5yHuh4P5Zz+FTC3Mi6l+V2O40aVLjTYpYhtSRQ4HpnmtDHFU9Lhjgso44mBjVRtI9KunpXpLY8gAAAAPJe5//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-99.png', linkedinUrl: '/in/dawn-scott-c95e0080c3', jobTitle: 'Sports therapist', }, @@ -2995,7 +2995,7 @@ export const peopleDemo = [ city: 'Thomasfurt', email: 'timothy.jones@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0LFFLRSGZPiLxBb+G9Ka+uEaQZ2qikAscZx+leLax8Qde1eaeSO7ltrfkLBDwAPc9TXWfE+7k1LVLDw/EmX/12fqMD+Rqjo3w4tzCrXsrMf7q1lOqo6M3p0ZTV0ebvLuIlY/MTk5zV3TNXurCZrq2u5YLggjcjEN+PrXqepfDzS7uJBDF5DRjGV71yXiPwbHplkJrdZJSv3sdh61mq0XoaSw046nQ+A/iPLPef2Zr9yXMrBYLlwBz6MR6+terYr5OfIk+TI5/Kvffhp4il13w60N1IZLuyYRO56up+6T79R+FdCZytHZ0UUoFMR5U0VxP8SdWmvFy8YCwjsIv4cfUV21tGVUe3pXL+NontvEpngMqvLZpkx9SQ7AU7wzealKUiunYh0LAvwy47GuGtH3mz08NL3Ejq5d2w4NYuoP8pHf0rmtTudZ+2NLHLcPGpwEjP3ucdKvQPd3B2SBwy8fMB/MVk46XNubWx5v4jhiXVpTtEfUsBxXT/Bu7ceKL22BzHJalm9Mqwx/M1keM7Rm1KHYhZpF5Cjk4NbPws0uez8XrJNG0YNtJhSMH+Hr7c1205LlR51WD5me00oooFbHOYWvW0Ju4J5VB3oYjkehz/U1SghhhFw6lFwgAAwOta/iGHfpLSj70LCT8Oh/Q1wE88N/IXebYu3aUGfm+uK4q0XznpYWSdOy3R1VlFbXG4EIXXGRwabfNDbRnywAcYrG0u+gtVEUZjOP7pwfyNSancAhwDkisGraHTdGGtul7ryM0YcxRnr0BJFdj4UtEa7ub1VG2Nfs6NnOTnLflhR+dcAlrqV/ex2ulzyRXFzKEaVB9xOrE+wFes6DpCaHottp6Pv8AKX5nxjexOS34k11UIa8xw4ir7vIupfpRSUCuo4gmiW4t5IX+7IpU/jXnIsZ4pntWlWKaFirZHX/9fWvRmkSJdzsAK43xd5c11bywBopmQ5kH8QGMAj8awrpWudOFlJSsupSl8qytyWaORyOc1z99fm4by4jvkkI+72pzWN5er+8nGzOGC8Grljo0VmzPt+YD1rkukdvvSZb8LX1joN+7Xrsu+LarBCeSQT0r0kMGUMpyCMg15xZ6Kb/UEupVxb253f7zdh/jXY2d7JFEI3Xcg4XHUCumhD//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-100.png', linkedinUrl: '/in/timothy-jones-eb531fbe5d', jobTitle: 'Manufacturing engineer', }, @@ -3005,7 +3005,7 @@ export const peopleDemo = [ city: 'Port Christineshire', email: 'william.walker@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-1.png', linkedinUrl: '/in/william-walker-492bb70711', jobTitle: 'Water engineer', }, @@ -3015,7 +3015,7 @@ export const peopleDemo = [ city: 'Port Tyler', email: 'jesus.santana@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwCsTXJanrMt1dSQwSotuh25B+8a6DW3MWiXbqSDsxke5xXCJC7yRoNoXOMCs5voaQXU2LGGeXe+cRL1coME++TUc15JJcG1nEYjYfLtbK5HP4Gtm00R9Qto4grLgYRA2EjH0HU1dPw9ll2HzUX1JWufmVzp9nKxxct/NaXUkUM37tyDyOK37PUpbUI0oRoGHLL2Na8vw6SILIJMsvPNc7r2kT2UiOX/AHR4Ygc1Smr6EypSSuzq0kWVA6HKsMg0+qmllG023KHKhAKuYrpRykGrxmXSLpAOSlc5pMEJkVGAIBAHrXYvGrxuhXcCpBGcZ4rAsNLW1177PI2dvzqPXPOTWNWVtDejBtX8ztdMSOOIBEUMOuBW2jHaCcfhXE38l9bKywiYjbkCIDninaLe6yssS3EjNHMAQHADJ6A+9cvLpc7+bWx2MrEqVx271xviZESA71DKeoPNT+JdS1WF5YrMECPBYpyxJ9B3rAljvZ7G6W5kdmVed2MZ4PBpxj1JnLRxJ9GjMemIu3HzMR+daGKit08u2iQjBVACPwqYGu5bHly0bJdxUgjtTLyBPOgvQuHLMNw7g9j9KkHNNmVtiNvYIpyU7HPesq0Lq6N8PU5Xyvqbtr5NzCocAkDv3pJ4oYp1VFCvwTjtWfZsyKpU8Yzj6VHeXFjd4FxNGjBsjL4Oa5FqejoaVxBE2rOsgB3qCM+tVb1IBtt1UAMfmGKzoZba3uXZbpZ5DhT+83EVLcuzTbsnPSqUW5JEzkoxbZVbkk+tKKXFFd55BMpqOW9thKbQyAz5Hyd/X+VWYbZmGTwvXNU20VBrUupctJOFHPRcDH+FZ1ZWizWjG80PjnNpN5Ttgj7pPcGtAwLPECvlhiMAlc1Fe2SXMSkjJXrVYWGoqALaZPL7bjmuJM9PVDpbRbYl28vcO4AFVobhblpGEgdkbaw9DSGK6a4ZbiVX28sF6Z9KraZp/lajfzhm2SlWKk8BunH4Yrak1znPiLuBdJpuamNsxyAQSO1RNE6feBHvXXc4AAAAAADgsf/Z', + 'https://twentyhq.github.io/placeholder-images/people/image-2.png', linkedinUrl: '/in/jesus-santana-fc2b873356', jobTitle: 'Designer, industrial/product', }, @@ -3025,7 +3025,7 @@ export const peopleDemo = [ city: 'West Christopher', email: 'maurice.carpenter@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwCsKyte1tNFtkIQSTSH5UJ7dzWuBzzXnviy5M2uSxjH7tQgz+dccFdnZN2RQvr+41a6El1I21vugH5V9qqea8U4fBZFI/wroPD3habWRu5jjPQ46+9dDN8NL6TaEmDKOm4Vq6kU7EKlJq55+L6a32EPuGOR2BzXQ6DrssUhfJaJTmWIeh4yK6M/C+Ux5LKWA5+tc5r+g3eixI4UrEvDOBS9pGWg/ZTjqdxbXUV9bLPA25D+lTqlcr4InMsd2khJYEMB7etdcorKWjsWtVchBrgPEdt/xU0xIyZFUj2GK9AUc1z3iLShcXkN2m8Mm1G9GyTj8qIOzHKLkjrPDNusFhDGgAKqK7K2B2DPJHpXnUtzdWkUbxJMuRgJEATkepPFW9I1rXo7uKO6R2ScjYJAARntx3rNx6m6kvhPRJGzDyMfWuL8aQpLoVyhXI27uB05qLXta1uCVktIpAqNhlRA7fz96qi5v7qyuYrpJGJjKlZVAIJGOCCRRbqDtZo43wT5jXd9I4xtVU+vP/1q7NTzWTomlLp1mG81pJJgrMSuB07VqitJO7uYKLirMj3YplxAL2BE/wCeTeYR6+lOIoGQeCR9KmxcXZmrpn71TEByDnJxj9QauTRCPUrVZHQAMG7DBrMscrOGB69RU17PpV7PGt8hZozkYRiVPrkVnrex0R1WhuyRpLfy+W8Zyeeh5qC9QCPY2M54Axgn8qqafd6Rb70tgiyORuJUqWI4B560/U5SkZkVsOMbfrSe9gdktTL1JIbaZLaBQqRKBgfnVRTzRIzySM7sWZjkk96RRWqRzSd3cTvTlHNGw5qK5kaGBgn+tZSE+uODVJXdkQ2krkskjRP8pxjBzWlb5uVUm7MZI4K9RWBosF62mKL6fzrphucnoD6D6UssdyMiHcrdOOlZPc6INpJnWbFt4W3XXnf7T9azL2bdHE0jABjhMnGaj0zSLx4hJezEg9EHp71N4l0VdU0aSHzDC8Y3ROP4WHSkmlIcryRQPWkB5qx9hl8pF3BpAg3e5xyahMMkZ+ZSPet3Fo5VNAAAAAAAAADP/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-3.png', linkedinUrl: '/in/maurice-carpenter-2f52cbbda1', jobTitle: 'Surveyor, insurance', }, @@ -3035,7 +3035,7 @@ export const peopleDemo = [ city: 'East Sarahtown', email: 'robert.barnes@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-4.png', linkedinUrl: '/in/robert-barnes-b7ef473c08', jobTitle: 'Ecologist', }, @@ -3045,7 +3045,7 @@ export const peopleDemo = [ city: 'South Tyler', email: 'matthew.aguilar@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDtMUCnYqrqN9DpmnzXk5xHEu4+57AfU1xHUF/qFnpdo11fXCQQL1Zz+g9TXF3nxW0uIt9ks57hVP3mYJn6Dk1hx6Prfji7bUL6dY4ckQxn7qD2H9e9bdr8KkyrS3Ks3smMVXNBaMfs5vVIXT/ippVy6reWs9qGON+Q6j69D+ldvbXNve26XFtMk0LjKuhyDXBX3wm8zcYblVycncvSo9PtdV8C3UUYb7XpsrYkRTjYfWhuL2DkmtWei4pcUiMJEV1OVYZB9RTsVIh2K5T4gkjQoU52POA2Poa60da5fxwsU+mwweZiVJVl2DuvK/1prRhZvYk8MxiLS4EHXYCBXWRt+7HevPNUivYVjithP5e3CiE45A9al8L3OufaoI7mScwS8jzh8y9eDWPL9o7E/snfO3yY6VyniYqlozccEEZ+tZnim91xbiVbRpvJh+95Iyzc9AKrxx3tzpt1Dcmc4iPE2CQ3Xg0JbSFJ7xOn8OTtc6FbuwxjKj6A4FauKzfDhT+xYIVbLxKBIPQnn+tamK2ORq2jAVi+ILRZVWQA72XbnGehzW3imXFuLiEpkA9iRSkroqEuWV2Z2nTxXFskcgGcdxmp5Ht7e9t4y0aAkEkkCsezBgk8sn5kbafwqLUbzTL2VUugrPGcjCFip/DpWKWtjsTujdge3uL24j3xuNx5BBqDVPJigeNQMsMcCsfTrzS7SR1tSqyO3IYFWJ/HrV2dWurqONT8zHqelDWtgbVtS/o8IitnI7kD8hir560yKPyolTPQc4p1bJWVjjnLmk2SBeayfE2rS6Nok1xbBGusYhV+QT9KlvvEGnaexR5vMm/55x8n/AVw+sam+qXrTtkJ0RM/dFapGQzSdbuLuwg1C8f5rld7sBtAbPoK6SKNLu1VlufKyPlZOuK5fSPKjR9NlACPloT+pWrH9m3EBKwXLRD+Huv/ANauWWknc7ab91NHRNbxW8DFp1lIH3n60uhX0E+qtC7/AL/yt8Y9RnBP8q56GxupTi5uDIM5IHSsya8ksfHFtND/AMsLbJXsQW6flVQSciarfKermkxWBYeMNOu5PJn3W0w6h+V/MVvo6SIHRlZT0KnINbNWOQAAAAAA5bn/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-5.png', linkedinUrl: '/in/matthew-aguilar-c9fde35926', jobTitle: 'Biomedical scientist', }, @@ -3055,7 +3055,7 @@ export const peopleDemo = [ city: 'West Dannyport', email: 'anthony.stanley@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDuPNjReRx0JqrMkUmA7/QVOoULkDiqOpTWtnZy3twxWKBS7YqGy7C3urWOkWvm3dzHCnbceW9gOprlLn4oaekhWCymkjH8bsFz6cVxaWur+NNauLiOJx83ysxwkS9h9cVtp8J5ZIWea+PmnoAOKh1EtDRUpNXSN7TviXo97OkUkUlvu43uQVB+vYe9dUt0JoxJAUkQjIZTkH6GvJL34Y6haRF4btHI/hINV/DPia98J6h9l1ESGzY4dCPu/wC0tCknsxOEo7o9iSSRzllGPepgGbocDvTUZJ4kkQ5jdQyn1B5FSoFHFXcgYOc7n47YrmfHbj/hHTbKctPIqn6Dn+grpTnH3ePauX8aRn7NYttO3zmH47eP5VEmVFamt4Z06Gw0m3gjGDtBY9ye5NdC+VUAAGuNv7qS1t440e5UhBxbpubgfpTNF1C9mmRZJboxk5ImAyPSuZdzv8jp75T5RB44rzfxhp0N3YsWQFkO4EdRWprWo3zXLLHPOscZwREu4kCqBZryGRHlkkUqQRKm1lPvTWmoparlOi8C3i3XhO2TezPAWhbd7Hj9CK6IYUccmuL+G3zaVfoeMXHr/siu0KEH2rpOElWIjvxWRrlubiNIXVTAPmHHPmZG3H61rr8yjJxUdxEkgBK5wcjjPNTUTcdC6MkprmIreKGSD95gE8g1QudRt7SWMvDK0bMVVkj446k+lTKpNuw3YYJ39ay5X1BowDaRCIDgyS44+gFckddD0VrsV9Pu7e61OfG5VZiPmTj/APVS6pDHGW2KB7is547z7YXFuqk/xRSZH4g1dut8gVTyzAA49TTejE9ncm8H2wtTNFE37jYGYf8ATTJya6o5x2qlpFl9lswWj2u5yykdPQVo7QRnHNdUE0tTz6sk56ESDOW5+lSiNcZJpqjaPenbqsyMi/3W07EH92/P0NQvf2rwBJEWTI9e9ad6gZoVZfvg9uo4rn7/AEdlBaIGuOdlNnoUruCKt3eQR7liQJx1ptlJ9q1G1QA7fNXk9+arx2Em87gRjuasCQ6aVuVUMYjvwe+KlNcyLknys7hsA0qqznCqT9BWfb61El0Fng3hs7SGxyO1b9vqFpOBscJ//9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-6.png', linkedinUrl: '/in/anthony-stanley-3854ad13be', jobTitle: 'Designer, interior/spatial', }, @@ -3065,7 +3065,7 @@ export const peopleDemo = [ city: 'Jeffreyport', email: 'brian.garza@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-7.png', linkedinUrl: '/in/brian-garza-66afe09a9a', jobTitle: 'Medical illustrator', }, @@ -3075,7 +3075,7 @@ export const peopleDemo = [ city: 'East Benjamin', email: 'lisa.oconnor@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-8.png', linkedinUrl: '/in/lisa-oconnor-ec7fe69b0a', jobTitle: 'Systems analyst', }, @@ -3085,7 +3085,7 @@ export const peopleDemo = [ city: 'Frazierchester', email: 'william.wilson@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-9.png', linkedinUrl: '/in/william-wilson-fdb80928cc', jobTitle: 'Radio broadcast assistant', }, @@ -3095,7 +3095,7 @@ export const peopleDemo = [ city: 'Allenport', email: 'joanna.alvarez@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0LNGabmmyZMbAHacdfSpGcj488Zjw3ZCC1Cvfz5EeeiD+8a8an1O8vpHur25kkmPQls//AKquyWt34t8aXSI5f9637xiSFQHAr0nTvh5pVvEvmq0zjqzGsp1Yx0ZtToynqjxiYTeYGl+8eeT0qxA7gEZ99w717PqngTSruIgW4U46jrXluv8Ah+Xw7cOV3NC3AJ7UoVoy0KnQlBXOn8FfEO4sb2HTdUmM1lIQiSufmhPbnuv16V7IGBHHSvk5mzz3719BfDjWG1jwdbGRy89qTbyE9Tj7p/Ij8q2MDq81n67Ncw+H9RktBm4W3cxj32mr2aCAwKkZBGCKQHkvwvtF/s25uguZJJcFu+AP/r16fGCEHNecWkU3hq21GytIriVEvpERkIXAwCMk1t+F9V1LUH8q6idW2lgXGDj3xXDVi3JyPRoySionXOSEODmuX8S6VBqlhLBMmSw+U9we1Z+r6xrFreuI/NMSAnbEACQPQnqat2OqtqqKhguUYDkTKM/mKjlaXMaNp+6eHX1o9jfS28oIZGx0xXqXwXeZZNXTJ8jbGcdt3P8ASsfxl4fe88QRCAAecoyemCK9E8D6HbaNZXfloVkeQIx3Ehgo4P6mu2NVSS7nBOk43fRHT0opAKXbWhiZlxBbLdyK8YxP85z3PT+gp1lFCt0/koAsanOB1NLq0LNAsi9UP6GsOS6hUFPOmhcDDMikiuGqmps9Kg+aCNdUtbhvLmVd/Ubh1FJcvb2cGIkAHTisyzubAL5Mc8jTHo0uSx/E0+5jOcyNkDtWT7G1rFKC3E9y0sgUg8DPv2rq7OEW9qkY7DmvOr+2nufFGlSRqxSFwwwON2R/QfrXpgUAV10YWXMcOIqN+6OHSlFLxjrVa4vYoBgfO3oK2bSOdJvYmkjWWNkYfKwwa5iexENwYZpmjI+6y9xU9zql1O7LE3lIOPl6k/Wse1ElxqV+Z2L/AHFQtzgAf/XrmrSTVzroRlFmj+6tYs+dvJ6k1UErXcm1CSg6n1pGsN0mXYlfQmr0aLBHhAM4/KuW51+pmPc6ra6jCmmLAyu+JjKmdgx1/pXY205nhBYYccMKxrO3IbKKSznJY960ATE+U3NjqRXVTm4qzOOrBSd0AAAAAAAAAAH/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-10.png', linkedinUrl: '/in/joanna-alvarez-9f444908cb', jobTitle: 'Data processing manager', }, @@ -3105,7 +3105,7 @@ export const peopleDemo = [ city: 'New Charles', email: 'denise.hill@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-11.png', linkedinUrl: '/in/denise-hill-3e8506c956', jobTitle: 'Trade union research officer', }, @@ -3115,7 +3115,7 @@ export const peopleDemo = [ city: 'Wilsonshire', email: 'marie.frey@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDjDTafimORGpdzhR1NIoRmCKWZgqjqScVXXUbdn2oxbHcDisPUbxry4wocxA4RB3q9aaLqkkYKQhEPZjzUSmkXGDZfGu2ySeWAWI9Kuw30M5AVirHsaypvCd+IvMGPM67VrNUzWkjRXKlD61KqX2KdNrdHYqeasxHmsLS77zl8qRvnH3Se4rZiatU7q5m1ZlDFU9UYJpsxzzjj61cNY/iFytgij+KQfyoewluN8LWAubpp3XIQ7VHvXpFrat5G4qMCvP8ARZBaaPHKbczNJIwVc4H1P5V1Wg3shaIIskaykHY77gP8K4aqbbZ6FFpJI6RLbKkhBjHeuS8XaEstsbmHh1GWHtV3xHM1pMH8hp2OMLu4Az6VYs5Gu4XhltPJYAg7eUbjtUJOK5kXJqXus8uinks5Bz905HtXaW0oliSRejDIrj9QgEN9cWjkhomIU47V02iEtpkOeSMg/nXdBnnzQ+s3WrSS5tFMY3NGc4rTxzTguRg1bIRZ8KpBJo1ukijgHg+uTW3CkSatDHuSMDnk4zXPaPcBlZVTYyNyPX3rQe9iN6N1u00ijspOK8+SfM0enTacVY6WNra6IG6OQZO1lIYHmrF4sVvb54zjtWZYalbSfuRaPDIT/wA8iAfxq5eAMmXbgVnK60NUcRqtjGLPUbmVAVZDJvIwQw4AB75qj4aYtZMCcjOR7Vna7r11qsCwhBDapK6bVP39uME/n0rQ8MROtq5IwrYxXbRTW559aSlsX9tPRaf5eO1KqEmug5zLvPO02+W/jGbdUxMuexPb3roLD7NdhZS52sMhuhqE2guUNuy7hINpAqpbRGISwKzfuZCm7uQO9cuIilqdeGk9jroltraDKzZGO9V5ZWuVIXOwDr61Fp2mAgSSyGQYyMnitF0URYUYFcTep2o8WCeTqcsci5AlYMPXBr0XTIo57OOSEDYew7Uk3hGLV9QTZmOZnALDuO+R9K0NJ0K70G4ntpo2e2L5SRRuGOnPpXdTqp6nBUpNaH//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-12.png', linkedinUrl: '/in/marie-frey-6f12dc710b', jobTitle: 'Lecturer, higher education', }, @@ -3125,7 +3125,7 @@ export const peopleDemo = [ city: 'South Alejandra', email: 'sarah.anderson@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-13.png', linkedinUrl: '/in/sarah-anderson-fe0d0f83d5', jobTitle: 'Pensions consultant', }, @@ -3135,7 +3135,7 @@ export const peopleDemo = [ city: 'East Cliffordmouth', email: 'mary.garcia@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-14.png', linkedinUrl: '/in/mary-garcia-ed7168a5f9', jobTitle: 'Optometrist', }, @@ -3145,7 +3145,7 @@ export const peopleDemo = [ city: 'Kristyton', email: 'richard.massey@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDHWNmbAzUrT21mB5kisf4uensB3P6VU1fUzpo2QY84rkH0rjmu5r29UO/tgd6wnJvRG0Irdnot3q9smkvLbkGJsqoYYJPt2rBguUkX92kg2NuKL/Ea0NM06eez+zSLmNuSMVoJ4OkRfMhBB7+lcvMjrVJlzT9WhubUWtwAofgLImQD/T61R1fR7iwbzGUGJuhU5Aq3aaLLZyLOyOrEHJ25B9s/0rK1LX7zT7lreUFoJPlaJ14I9R6VdOo4uxnUpXRUwaeuc9aXAIDKcqwyD6ilUc123ucRj+K0MOsBjnDRgqPXt/jVHR9N/wBPR5OTuGK3vGNsbr7OYWDTIp3IOoXPB/Oq/heEvczM+SY1GAfWuab3sddOLuro7jTATgKMY4NddpoVgIy3NecS38lqxSJJ5HPPlxdT+Jp2n6xrltdxJPb3MSyjIEvOB7nHBrnStqdbd9D1dYIZEIkReM4zzXC+PrGJ9ISQRqHhlBU49eoqfX9c1LSnijtYJp5JIg26KPd/k1R1CS81bQJFuI5opIpELCVME89sdetW9SLWOUs1YWUQbrj9KnUc1YeJVO1BhRwPpUYQ5rtirKx5snd3LWpxNHDLcQRl52RVUbc9D1x+NQabaQ28s00LlhNg4x09a2Nm8YPXtWXZXJubcXOzYJCfl7jBwc/iDXLVi079zvo1FKKT3R0WmRWk0n7+JCf9oZp3iC7s7QxxCWKFVQsS5wAKz4CS6sCcgZwKpXlzZXdwVn3OyNjiFmP8qwSvodJ2dnqely2tr51xE4KYKnBP1/WrWpJbPYyxxqBGEL8Hjjn+lc3p15o8Ia3SGYK6so82ErweozV/UmNjo7oGLb1Eak+h/wDrVolqkZ1HypvqcmwzUYXmpsUgXmu48o1EU7his+S2SzLRxj5A7Nj03Hd/U10+kaet3I+8fIFIDejHoaxtR0y/025MV+RIZPuTquFk/wAD7VhX+E6cN8ZWjlKFGHbg/StO1snmKukyr2Dd1rEYsjbG/OnxXbROAJWDDtjrXKkdt2js4rN4EJmufOyON1YOt3nnukCnKx8n61Y0+O8nR5p3cQqpOMYLVlmLv610Uo3dzlxFR2sVttAHNR//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-15.png', linkedinUrl: '/in/richard-massey-af5c02d5ad', jobTitle: 'Armed forces operational officer', }, @@ -3155,7 +3155,7 @@ export const peopleDemo = [ city: 'Lindahaven', email: 'megan.rodriguez@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-16.png', linkedinUrl: '/in/megan-rodriguez-377a7d26f7', jobTitle: 'Editor, magazine features', }, @@ -3165,7 +3165,7 @@ export const peopleDemo = [ city: 'Jeffreyfurt', email: 'sandra.conway@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-17.png', linkedinUrl: '/in/sandra-conway-49f0ce34eb', jobTitle: 'Press sub', }, @@ -3175,7 +3175,7 @@ export const peopleDemo = [ city: 'Rebeccafort', email: 'rachael.dalton@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-18.png', linkedinUrl: '/in/rachael-dalton-6bab20a6a3', jobTitle: 'Catering manager', }, @@ -3185,7 +3185,7 @@ export const peopleDemo = [ city: 'East Gabrielashire', email: 'katherine.little@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-19.png', linkedinUrl: '/in/katherine-little-d826db995d', jobTitle: 'Production assistant, radio', }, @@ -3195,7 +3195,7 @@ export const peopleDemo = [ city: 'Aprilfort', email: 'faith.cross@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-20.png', linkedinUrl: '/in/faith-cross-029912b4f5', jobTitle: 'Pensions consultant', }, @@ -3205,7 +3205,7 @@ export const peopleDemo = [ city: 'Amandastad', email: 'amy.farmer@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwCzNhI/lAJ71ntODlRgfSpZJSV5PHeqOEhLSbPl6kk0PuTa7JndEjy7EZ6VTubyK0VXcMzMeFA5NZl7qpSUKqGSdjhIxzitWLw5qd/bi4uNkb7cKPSueVVt6bHVCirDLbV47m6KNBtz1GcEVoXFpclklhcNb/xKByKyJrC+tVU3cCymI/eXg49Qa0oNU8gQ/PvifgE9VPoahVGmVKirEyKF+UDgdBSMrDLBSalZ0JEkQGxuoz0NTiRRGSV6CuqLUldHJKLTsVGwyc1z+t3xtmWJGycbj7elbjOgh3N2HWuE8RXGb6TZxuCgVNT4bF0viudf4Q0YNi/uF3yv93vgV6JDH+6AI4rhvtQ0rTLaEW8s0jxgBUYqBgc81o+Hb26mmjjdJo0k52yNuxn3rk8z0FbY6SWyjmjYFRzXn2u6c+m3JO3EMjfka3vEl1c207BEnlRATsjcqD+VVxI2t6XJaz2ctu6pwGJIOR2NK2lweuhz9ldFkMBYjPKn3rVFwRGEz25rk9OuGLSQn/XwN8wPUgHrW4qsOQxOa6KDtdHHXWzLVwgKAHgDtXLvYxXfiJI5fuOvyc/xdR/Ku6NuHTLKMYrnNVSCK7gnVWX7NKrsyddoPIFaVU3HQzpNKWp3lisMsYDopI6Zp73Fpa6lAjuka54ycFjjOBVHTbiO8hS5tpA8UnII4qG51S2FyY3tJZ3XIJEZ/Q4riV9j1Ek9jdtrqxvpZAjpINxGRzgg8g1NdeTBHhVGMdqx7TVbRx5YtJoGJGCYjg/jir9xnbuc4VVJJPYUO+wWscDrWmQWq3eoogWfzRzjs3T9aZEzFQQeABVjUdWtvEKw2mnq5gSTzJHYY3EdMD8TT7e1JbZjjua6KCd22cWJktEjoREQuCCRWLrdm01nMYYzv25+tdgQqqBikj057l9/lNg8cjAroaujlWjOD8E6hIFutPcYEREiH0z1H5/zrsYoYp+Xb6etZVrpNtDrd1d26FA4MTKOjEHlsdq0/s5C7lyMda4J25j0qTfKrl9IYoo8BwRWXr0jtoV4IyRmMrn61ctrV5Bkk4+tLe2guLN4MEqeoHU4qVuXJtpnE+ErDZbyyBc44BrqobAOd2zBrUsrC3ttPhNtEFtnG5Tjqe4PvVqO3Y/S/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-21.png', linkedinUrl: '/in/amy-farmer-e9024737cf', jobTitle: 'Printmaker', }, @@ -3215,7 +3215,7 @@ export const peopleDemo = [ city: 'South Andrew', email: 'stanley.todd@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0KvMPid4ouoLgaHYzGJTGGuSvVs9Fz24/nXp4rw3xo/23x1qAZMMjCNQP4sKAK5zZK5yU0E+SUBLEYPHaqyEKyxsSOfmyK9f0rwnp7WERmTdK4G4+9W9Q+HmkypuiG2Qj73rUqujZ4dniRvrpiynLbsDb6Yrd8L+JJfD2qR3eSVUnfGT94HtXfP4D02KINgl1H3s1yWv+Gre3TzIDtYHvzxTVaMnYToSirnu9rcx3lpDcxHMcyCRT7EZFS1g+C5PN8G6W2/diHbn6EjH6VvUzIcOleH+MY5ovibMo+YSvG6lfQqBj9DXt4rzbWtOjPiizfyXPkzOXkJyAGzgfnUylY0pQ5r+RuWB3xgDOQB0rRl3gLk8Vw+tJrMZCWTSIgyy7OMkDp71Q0bXPEclxHbXKsxfGCy/Mv1rnUNLnZza2O6uI3MR+YKPTpXA+K2b7K6qeik5HtUfiLX9bF1NYW6MJIl+Yjr+FY1tHeuZlu3aQ7CDuOR0qowt7xM53909h8B2zWngrTYmxuMZc4OfvMT/WuhNYXgy1+y+FLNT1fdIfxJx+mK3TXRvqcUlZtCisLXtPd4JZoIyxIDtjsV5rdFKVDKVPQjBolFSVmEJuDujkYmhv7XyZADxzkUltYWtlcrHCimUkMxA96oxj7HeSxM3COVP4VUvdSheNZLK9EM4YnPmD5z6EGuRJ7Hopq1yLVrSC48RXKSqPmbcCR1qq2mpPexWFjGDLIfXgDuaypL24bUnkvL2Od8gDYwwDV/S55Yr6S5RsMF25+tWo62ZEpWWh6ta28dnZQW0ZykSBAfXAqQ1wkGuXkTZLlhWiPEMzKBxmunQ4XGRv2017eANFbiOL+/Jx+lZ3i3V7vRPD91c2aCW5XYkZAzlmYDgfjXWNhnVR930rkNeYy5jxkAeZj1IbP8hWjVkRDWSONBvpbFbm83Lcv80oJyc++KJIJ7m2URfZDgcCUZBH0rZvBGIdy4KHn6isC8tIWt2ktbkxuOSprgTbdz0l7uxlXdvLEWaUWyEcYiUAVJoOqiXUZ9ImVfLUhkfHzAkCssedNKS5JAP51f0eyA1zzyMMVAJ/M1tT+KxhWbcbnUT2M8H3lDL2ZTkVFESrYINdBZMrA5PTt7GrEui29yDJGTFJ6AZX8q3cOxzqr3P/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-22.png', linkedinUrl: '/in/stanley-todd-d92752ad42', jobTitle: 'Psychologist, forensic', }, @@ -3225,7 +3225,7 @@ export const peopleDemo = [ city: 'Tonyastad', email: 'bradley.miller@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-23.png', linkedinUrl: '/in/bradley-miller-4b0d674c5d', jobTitle: 'Hospital doctor', }, @@ -3235,7 +3235,7 @@ export const peopleDemo = [ city: 'North Dawnport', email: 'sharon.rhodes@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDn2ahfmOBUferUEeFL9SO1TJ8quxpXdkTQ2zMOcAe9LPdWdoCpLNJxt2kFT6062S612f7DpxRJc/Mdudq+pPQV2em/DO0ijEt5KZJTzx0rldSU9jrVKMVqcrp2oWGoAxJDJFKON3UE06bET+XINrdsnrXSXnw4tY2MtlPNC/XKt3rhvE1tqWlN/pA3rnHmAcN+HY1KlOLG4RcS4xw1SxSYNY+maiLpAjNlu2a0lODXXGXMjklHlZnD71F7MUsDCnDykgkHnHtTtvNYmrTPHqCop5IBHsKmrqrFUviPWfhzo0el6CspX9/cHzJG9B2H5fzrvFkULjdk155c3DWOk2kJiuGRrdWPkgk8LzjGOfxqx4XW+e6SNxOLWQbgZcgjI6HJPNYJs7OW521xKuwjcPzrk/ENpDe2csU0YZHGB/jWJ4lN4bt5DHcy20f/ADxySQD2AIosJppW8nyZUCgfeBB5HcZP6VMtVcpRtoeZFjp+pvC2QyN8r9j6GuugYSRq46MARXGeJN1rrV5CR80cpK/7p5rq9Dl+0aRbyDn5cflW9M46gzHPFULjS5LrVYZgrMhXDbfatXy6u6dIsF5E78JnDfQ8GtJq60M6bSkrnpenPbT2EUciKVCADP0qvd6zYaXexxsCFIbYFXqcc1Uswv3YXDRDhSDnIqC91dRi2XSbm4XkFtmB78muRN7HpRjd6FjRtRs9QEigkqSeHQjHPTmp7xre3HyIo+lY9pq4kkNu2mXFsxPBCZX657VNdRlshmJx1pPTQpxs9Tz3xDoT6nr08yLtzEHUkcMR1FW/DtoYNIjVu7MQMdBmtNdc06TU5dNiEkl6hIf5MKigev49qtRxDAVQAB0FdFJPdnFXcdkZv2elEGK1vswpptq3OUn0i6MMZhY4Gcg/zroTBbXcSl5iMcjB5rnrWDEqkDPPT1qzc2ksPzRs2z0z0rlqxSlc7aE3y27GkYYLVSUmLZ9azZ5S52Iclj+VU0MkjYJb8a0ILYrgkc1kb3OK0jQrx/Fmoak6mO3ErqpPV+35V2EVrip7Gzn3XrNIzxeeoiDHp8uWA9s4/WteHTldAQxyeoNdkF7qZ51T4mf/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-24.png', linkedinUrl: '/in/sharon-rhodes-708695e723', jobTitle: 'Lighting technician, broadcasting/film/video', }, @@ -3245,7 +3245,7 @@ export const peopleDemo = [ city: 'Marquezhaven', email: 'emily.young@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDqOtFLjFAFebc7bFTUtVstHtDc306xR9BnksfQDvXn2p/FK5kRo9Mso4ucCWU7jj1A6Vk+Jr+78U+KDZW/zQ28jJEvYYOC36VqWvw/UorXFxucjkKOK2SjFXkR70vhMCXx34lZEVtR2BSfmVFBP14rR0z4l6nagLfxR3iZ5bGx8fhx+lbMvw/sWj4eQPjgg9K5LWvB13pm6SM+bH696tOnLQThUjqet6Nrlhr9kLiykyBw8bcMh9CKvkV4L4d1iXQtbguQWEYYLMo/iTuK98V0kRXRgysAVI7g1lUhysqEuZEm6kYjY3OBg8+lGKNoYbSMg8GsyzzDwlaK8t1eFR5jzMoPoM138UZ2g5rz9nhsYbiAQzTA3ExREYrwGPJP4VueHJ5t0cJDiN13gMxO32NXNX94um7JI6Z1IU84FZWoKskJUgHNYevSyNM7+U8ojGQocjIz0GKdp9z56CMW0lvIACRnKnI/nS5dLl82tjzjV4vJ1CUKMDca9l8GXTXfg/TpG+8sflnPfaSP6V5n4ztRHqKOowZE5wOpzXovgO3ktvB9qsilWZnbBGMAsa1m7wTORK02jpw3FKGNMz707PvWJocvFaW63M0DJnZK5Gfck/1p4ubKzvJEJ2ER5GFpNRDw6zKUH3wGH5f/AFqzvt0plbba78HlnOPyppXZ0R1SsatlNa3nyspJPILIR+BzVidIYIztUA+1Z0F/IzbHtHTP8S8rVi7BaPk9qmWhRgy2yXepRXEiq3lZKhhXYaNbm304A9HcsB6CuXs5d2sQ2KxF3lXJbcAEUHn8a7YAIoVeFAwBVamM5LZCcUCjFNzg0WMrmdrNjLPGtxbqWkjGCo6ke1ZVi9sf9Z+I9K62JufeuBuFSfU52iG2NpW2j8aHY0hJ7G3NcW0a5RhiqM12ZEKR8k9TSrpgZAwP1zU62qRRkgcAVDZqiPRdLSTUn1CXJ8tBGg9CDkmumLVz2kPOl0Y15jkY5X0461vjWZ//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-25.png', linkedinUrl: '/in/emily-young-721fb2a8e0', jobTitle: 'Bonds trader', }, @@ -3255,7 +3255,7 @@ export const peopleDemo = [ city: 'Benjaminborough', email: 'victoria.harris@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-26.png', linkedinUrl: '/in/victoria-harris-6f291283ab', jobTitle: 'Hospital pharmacist', }, @@ -3265,7 +3265,7 @@ export const peopleDemo = [ city: 'Lake Marilyn', email: 'andrew.massey@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDtKTvRVa9vIbC0mu7h9kMKF3b0ArmNhNT1jT9FtvtGoXKQRZwC3Un2A5Ncufir4eEjqEvGRSQHEQw305zXBXEOqeP9ekvJMw2qnZEXHCL6AetdLZfDKwQKZ5ZpvY4UU3OMdyo05y1SOgsfiV4dvp0hM0tuz8Bp0Cr+eTXVhldQ6kMrDIIOQRXmF98MrQAvaTzRHrtOGFZ2j6rqvgfVYrO+kkk0yZtvJyq+49PpS5oy2Y5U5R3R7BigUyORZYlkRgysMqQcging0ECdq88+KdzKtrp9nHIQs0haRAfvKuMZ9smvQq8/+IsSPqejFlJyXTP1K8ULce5o+F7SK20u3Q4DBec11cakjI+Ye1cNewRxjdNFcTjblIoSV6D271qaEy2pQos0QbBMbyFjz6571ja6udqdtDopvlX5iBn1rivFttDdaZNwr7efXBFXNeMd2JJZVuJhESfKjfB49MVmQW8Mjv5SSxKU/eRSNuzkdc+tFrag3f3Sf4ca/Ne28+k3DbzajMLnrszjB+nFd6K82+GMIS/1Z9hyoRN2Pc8V6QDW73OEK5vxHZresjOQPIYOue5HNdHnis+9tXuYT5eCTuHPuMVMloaU2lLUbYQwywIWGWx1pL97e1vLZZMqGYAlVJx9cdKh0p2WBCfvAYx71DeSSz3HzRSyFecqAq/metZJdDsTvsWbD7PcXtyE+YbjtLLjPr1pmpW8UULuo2tg5qnDJNHdM8cUsbHnDDK/mOlTahI9zGEA+eTAx7mlJdAvbcZ4U05bCzkYMC0p3MQPXn+tdGKo2MD28BVwAzMTgVdBraO2pxVGnLQbnilj+6Ks/YXPDEAe1OGnkrsVyCQQD6ccVfKzO5ycl0LO+uI2+VfMO09vpVyO6gkh2PyGGSarJYPL5tveAmYMQxPXNU20O6jfEMxxnoSRXOmm9Tus0i/PewQxlI8DjrTNLZb7URg5WFd59z0ArNn0KYuFmmLdyAa0/D6+VqM1rEnBi3A/Q/8A16cbcxE2+Vs3H6ilFJIjhgSpscp//9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-27.png', linkedinUrl: '/in/andrew-massey-0f7983ac40', jobTitle: 'Podiatrist', }, @@ -3275,7 +3275,7 @@ export const peopleDemo = [ city: 'Lake Jennifer', email: 'heather.mack@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-28.png', linkedinUrl: '/in/heather-mack-fc2f7ee6fd', jobTitle: "Politician's assistant", }, @@ -3285,7 +3285,7 @@ export const peopleDemo = [ city: 'South Jacquelinefort', email: 'michelle.richards@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDuAeK5vxL4z07w2DFNuluim5YlOPpk9q6DGB14r588b6kNU8XX80JzAGEan1AGM/nSbGkP1rxjqmu3xlkleONuI4ImIVR/U+9UJ5NqDeUJ/wB7NUbdliJIQFuwNbFj4b1XWIxIiEqe/QVnJpas1jFvREek+I7/AMPT+baShQ33kIypr1fwp8QLXWnFreGO2uSPkJb5ZPYZ6H2rg/8AhXN8sLmSdMheBjvXK3dtPo10scmVdGz7EURqJ6JhOlKOskfTZJpDx1rn/B+pLqXhq1l84SPt5XdlkGeAfwre7e1aXMrGfrUssOiXjwDMoiYLg9CRjNfOMjGWZgxPmFuWPXNfTrKJIyvYjBFfP0uiTR+NHsXQ83JyR6buv5VMnbUuCu7HS6F4CS4hjmuHJyASK9JtLCGxs0hgQBFGOBXM6jqd5pCeTbQzONuV8mPJ/Enj8Kj0TWPEF9eJDdwqkb4bdtwQPQ+9cDcpLmZ6SUYvlSOoukIickYyK8r8e2qG3SYr86tXSeJte1e1vZLWztmfy/mZwN2PauT1y7uNR0m4WZXMkQDNvQAg59qulFppkVpJxcTb+EIka6vX2s0axAFs8A56Y9a9WP5Vwvwu0y40/wAPzTXCsguZA8Sn+5jr+Nd033c4rtPOY1CdvFchrmjIusjUlADLhjj+I9OfwrrYz8vBrn/FVjqVzDay6dLt8qUGdP78fGf5frUVYuUdDSjNQldmnYvb3VuEkVTx3GRTZZLOG4FvD5aYILHgDJrKsslcq+E61HeXmk3MaxXFpLMyEsrCBjg+oNeetdD1tNx8ogbxDcROUdJBkHINZHiOC1+zPbQRKPMG3CjrVJZNMsr9mt1ufNfADSRtz9Ce1aOj2n9p68pnyyQjeRnuOn61rGL5kjKpJKLudbpFiumaXbWqs5EaAfOc446fSrrHGRnA+tBVu360jHqMA13HlAikJnFcN418bX+g3LW1hbwSIiDzmkUsRn0AI9vzroNU8TWmmboVzPcAcxqeF+p7V5pq8st5ez3Uyrum+ZlA45obBI6e3uzFaRSliIpUDhh0GRWwn2W9s/nuii44KHmuO0TxHaxWws9QCpGnyxuRkY9DTtZs1VDPplwYieTGG+U/SvPcHGVmepConG6NHUktbMF453b03HJp3grxTp41q40udXS6lYbJSflfjO32PX61x8LTSkm4kLbfXtWJD5qavNdKxUrIGjYHoQciuijGzObETbR9IMAeec1C5IBA/OvPNL+JjiYRarbKU6ebBwQfdT/Su0s9UtNUthPZzrLGeuOo+o4DtXScZ//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-29.png', linkedinUrl: '/in/michelle-richards-5d0d907e8c', jobTitle: 'Geochemist', }, @@ -3295,7 +3295,7 @@ export const peopleDemo = [ city: 'Christineburgh', email: 'billy.jacobs@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-30.png', linkedinUrl: '/in/billy-jacobs-e9d18903f6', jobTitle: 'Pensions consultant', }, @@ -3305,7 +3305,7 @@ export const peopleDemo = [ city: 'New Micheleside', email: 'michael.white@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0JulRZ5qywGKqt1oBFDW9WXR9Kluygd14RCcbia8g8S+K9V1WL95KY1H/ACzjGAK7/wAWJJf6pp+mxqDvyzMRnaO5/Ifyp83gTTLoq3llCAARnrWM6lnY3p0nJXR4slyDGRKZGPUnrk0mZ2IkRWKjpkdK90Hg3R4o9otIzxgkjk1Vfw7p1vA6RW6gY9Kn2xp9X8zzjQ/iBqugII0nFxGCC0EuSuPbuD9K9n8NeJLPxPpa3tp8rA7ZYmPMbf4ehrxLxHof2K/YQSbYs5Ubeh9KseB9bk0jXYXTckckgimjPRlY4z9QTmtoyurnPKNnY96lYEcVWNSM2KiPNUyEY0lvu8SPK3OLcBfYZ5/lWwoNYHiSS7tY0ubPf5hGzCLknn+VV/D1/ql5Cy3ylHEZkDHjvjBHY1yVV7zZ30H7qR0kxxkA5NZF2xwQOtctfaj4hN03ltI8KkfLGACcntWpZ3F7N+7uI3yvGWHP5jrWdtLmt9bHJeIiQWD5D7uP8a5jSJWTWINv+sE6bT2J3Diu+8U2KT2sZ/5absCsrw/4S+wa1ZXl452faUIj2ZUHtk5/lW8JK2pzVKcnLQ9dI4po4qUDK1GeuK6DkIpdhwrAHPHNVJRDDBL5ZRSTjAwKs3IAiLf3ea5e/OlXZ2NOcKfnVATu+uK5Kq989DDaw0N2zjtbhXUBS6HB6Uk/lW4wBzWZpt3ZQgQ2rLkdFxg/kauXLDJzyayZuZV1HHNIrSLkK+4fWrOnWbSX8ZAIjZhKUbnaRnn27VVnLPMFRsFec9a0vC8FzJc6je3DOVLiGAHgBQMsQPdj19q1px5mYVKnJFs6L2FMZTmnjgUhOTXWeeRSR742XOMjGaxfsbGMKX8kpwQp6mt8CsHxK1rZWn22a4eEl1jG3kMSQBkVlUhzK6OihV5HZjH226curH+9WVdakqg/MCzH8TVLULXVNwKsZICcErwRSWejGF1lmYk9QCc1yabnZdsvWymOBppjyRk+gFJ4L8T3N9f3FheMghJP2MBcHaD0J7kjmsHxHrayOdNtGyBxM47f7NYcVw1nLFNHIY3jYMrL1BHSuuhB25m6H//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-31.png', linkedinUrl: '/in/michael-white-6548d80612', jobTitle: 'Metallurgist', }, @@ -3315,7 +3315,7 @@ export const peopleDemo = [ city: 'North Brookeville', email: 'jose.frazier@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0rtUbyLGhd2CqoySTwBTia86+IHiJ4XbTIyVHV8dT9ahuxSVy5qHxChW7NvZRjYM5nkOPyH+NZ9140nCnE5WQDOQQQaxdE8IXGswrMziKM9HZeSPautt/hxpkcBSR3dj/ABdKyc0bqkzK/wCE4mZ4XW4xwAFPrXcaNrkGrW2QwEyD94vp7j2rlb34Z2E0f7ueVSOetclqVnqng2dJLd3aHdweT+BpqeopUmlc9qzxntS5rN0W+GoaTb3HAd0DOo/hJHIrRFaGIyZ/Lhd8Z2qWx64FeMKf7ev5ZJyCZJQZDjtnOK9oZQ6lTyCMGvHtOPk+JTZSoyETFyCp6Dp/jUTehdNXZ6VYIsdvFGowqqMYrUUpt4bPtmuD1q8m8oLG9ysZU7Vt1+Y461V0C41P7WiSTXPkuR/r+oz0Fc6Wlzu62PRWdMY3YrnvEMEU+nyxygFcZyfrWD4ludRiu3jgnuBGoBPkLls+lO0ueeeCSG5a5eJk+YTrhhkU/MT7FvwJK1vfahp5dpEwsyMf4QeMf59K7ivP/AG/+1btXU5EWwtjrgjrXoHeumOxwS3F2kVwt7YfY/EDsAXYu0jOx6BugFd9WD4hQQxLdBSQzqj47ZOAfpU1Y3WhrQmk7PqVoEhmiywH0Iqo9xp8F/GjtFGqOCCTgs3oPpSjcU2qcHFZ81xazRCJ7GeUAkBxDn6kH/CuWJ32RqS3enT6i2ySKTzCAcEEg9s1PPbQRx4VcE9652CWxtI2j+yTR5wN7xEZ9Of8a2FMj+WvLEjj3pvcT0Rd8MWjQR3U5JxNJwPTGa3qhsoXitUSRQr9SM5qwRiuuCsjzajvJ2HAVFc28dzbSQSrlHXaRU2az/EOk3ep+HL2C0Yx3ZTdATx8w5H59Ksg5SSQwyGNjgZxmreLSaLY8xVSMbQaqy2ZlsUV/vhRk++Oa5m8+1W1wYyGA7EHiuBWuendo65YrWCPbHMWHoxq5oai4vNxOUiGR7ntXIabDcXB3O52d+a0rl7iy1HSDbSNGWuPLwOjgjkH8AT+FXC3MjOq24s9CpcCkIKnBBFJmuw4D//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-32.png', linkedinUrl: '/in/jose-frazier-c989680d85', jobTitle: 'Conservation officer, historic buildings', }, @@ -3325,7 +3325,7 @@ export const peopleDemo = [ city: 'South Hannahchester', email: 'michael.barrett@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDiTmgUpFFIoUU17iGPh5AD6dabHa3Go3IgjJjhB/eOOp9hXW2Pg6wEa7odx6klic1hUxEYOx0UsNKornILewMcbyPqKl3hhkHI9a7G88Jac8JxbAHHBU4rkL/RptMdntSzx/xRtyfwNTDExk7MuphJwV1qMzR3qOKQSpuAP0PapMc10nISYppp5FNA+boeKARu6LChKhF44rubdNsY4B+leYNM8W2LfcKjJkC3XLk1teHr7UluY7dZJWjc8ef95a8yUb3kexCVrRsdpOp2HGAK5HVsCTJ685qprd9qEt88e+5EcZ/5d+TVGGeW5Pls85UDJFwmGFJQ0uNz15bGe6hbp9gAjPIx60uKjQN58g2kqvGe1S4r0YO8TyaitJjzU1kiSXao/wB1gf5VCadC/lTo/wDdINOSvFoUHaSZ0uj29nc26mfaNverUer6VaakiM3khR8uUxkeuen4VzVmz7mMbMRgkLnrzVm3e91GXD2sUZiAGHP3vpwa89Qu3dnre00XKjVt9V0q6upM5mjZjuYIflHrnoak1dLKG2/0cJyOo9KxL1b60kVIoYiz8Hyzwo79QKLsbIF3v8wTkDoPaiULbApt6NFeKOFdOeViGdiQox0yaqAc1ZMwawhgVcFeS2etV8c120YtR1POxE1KWnQMUYp2KekbOwVQST0AFamBB9oa0IkHTdmt+GSymjR3uCocAna2Kx9Uspre5gtpIyqPAJWJ/vEkY/IVkppt4ZtkblfpXFU5ednoUXJQR1t3cafZQtIspZh6nJNcu93NeMchghbLbqlXSLpZAs8m9j0ArRbTHSJYYF3zuQBgdT2rO8UzW0pIQoNoI6Y4qMrzXX3XhqSLQ7dVUNcxKS4XoSTkgfj0rlp4JIZNkiMjejDFehF3RwAeXJWZ/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-33.png', linkedinUrl: '/in/michael-barrett-9a6fdee03b', jobTitle: 'Sound technician, broadcasting/film/video', }, @@ -3335,7 +3335,7 @@ export const peopleDemo = [ city: 'Taylorfurt', email: 'lisa.allen@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-34.png', linkedinUrl: '/in/lisa-allen-65f7418d40', jobTitle: 'Contracting civil engineer', }, @@ -3345,7 +3345,7 @@ export const peopleDemo = [ city: 'Coletown', email: 'kristopher.berg@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-35.png', linkedinUrl: '/in/kristopher-berg-66eb2e31cf', jobTitle: 'Community pharmacist', }, @@ -3355,7 +3355,7 @@ export const peopleDemo = [ city: 'South Aaron', email: 'regina.allen@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-36.png', linkedinUrl: '/in/regina-allen-f1f56a375b', jobTitle: 'Civil Service administrator', }, @@ -3365,7 +3365,7 @@ export const peopleDemo = [ city: 'Bakerfort', email: 'angela.williams@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-37.png', linkedinUrl: '/in/angela-williams-00ba2b783f', jobTitle: 'Designer, furniture', }, @@ -3375,7 +3375,7 @@ export const peopleDemo = [ city: 'South Sherrychester', email: 'aaron.watts@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDh802SRYkLuwVR1J7U+sfV5HaVIFPGMlfU+9eXCPM7HqTlyq4kmtSSFltogF6Bzyfyo33RKvJcck4xnH6V0vh/wPNf20dxNOkAcBgFTLYrqoPhtp5y0s0ssjD7zAdfWtXOnHREKlVlqzzmO+uImaOZ1LAA/N3q8sobAPD4yVzyK668+GVm0Z/0mbeOhwK4bVbG60DVVjnJkRuEkA4I9D71PuT+Hcdp0/i2LtIc04cgGkNZGouOKyyiS6xtY8llU/StWo10t11yxlfGy4KkY+verpuzIqRbSsep6PGEt1XuuK6GIERjIzXDXqXMUWE+0txuVYOCcD1q34fm1CKRDJLdGKUBts7ZKZ7H0rJR0udXNrY6m4GENedeN40FqZiATGcjI71teKLq+cSpE0/lR8P9n+83sB+NcprFk/8AYt2Q1ySoAkSZ93ORyDVQjqmRUldONjEtSWtY2PUipTSIpSNVIwQBkUUPczWw6unslhvtDhk2E3Fk2QR2Gf8AAmuXFXbC/msDIIipWVdrqwyCKTKi7Hp2myRXFuu/BwBwadfywW8kaZSPJGSTjvxWPpT5ijZG4NSX99pznZdmNmU9CucVKXQ6E7l6NoZdVuI96NwDwc1R1mK2khFsRhZGAbHp3qpa3enRzlbN0DE8gdTVDX71oOVwXbKjPbjrTasxNpLU5W5cPcSMoABYkAdhUNK1JVHPcUU6QiG2ad8+WrBSR2zTo4nc4VSatPArWrwMAVdcN71cI3euxnOVlpubGnX7W1tE7HEMihg3ofeukEQu4ldJFBI+Vqw9Fhhu9I+z8FoVCsp61LaaPcFnis9ReADny2XOPpWezsdEZNK6Lc0K2ivK8ylgOp7Vx+o3pvLgsCSi8DP61rXlndJdPHcXZnEYycDAzXNWgeW08wggszHB+pq1Hmu0RUqaq4rHmm0rKRQBStbcm9z/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-38.png', linkedinUrl: '/in/aaron-watts-423d6e63d0', jobTitle: 'Commissioning editor', }, @@ -3385,7 +3385,7 @@ export const peopleDemo = [ city: 'Lake Jennifer', email: 'angela.callahan@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-39.png', linkedinUrl: '/in/angela-callahan-c21517a078', jobTitle: 'Merchant navy officer', }, @@ -3395,7 +3395,7 @@ export const peopleDemo = [ city: 'Lake Samantha', email: 'walter.mclaughlin@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD2D6Uh+hpeO2aQk0xEU00VvA800ixxRqWd3OAo9Sa8w1b42aZbztFpdhLeBWIMsjeWre46n88VneKpr7xr4nurFbqaDRLF/JKK2BNID8x96bH8PNGUKQsgP+9ms5VEnY3hQlJXG2/xxuBKxudGgMXO0JMQw/Eg5rvfCnj/AEfxTGkcUn2e+Iy1tIef+Ano1cfN4E0OWEI1sQ3XcG5NYeo+C00+JrrSpZYbqL50IbuOePQ0lVTKeGkke8CgVwvw08Wz+IdLltNRYnUbTAdm6yIejfXsa7v8q1OYOax/FF5Np/hfU7u2bbPFbsUYdj61sc1ieLjGvhPVBKwUNbuq57sRwPzoY1qzznw3GI9LgOSWfLsSeSSckmumT7oOa4y7Rra1hgD3IVYhtW3HzEgcnNWPD93dPOkMsk7J1BnA3D64rifc9WGlonWHI71UumAjYYycVzOsyXf2xgst15ac4gYDOO1WNOkkkAXddKMZMdwPmH0Pel0uNvWxS+H87WnxIWGPIjuI5UYfQbh+or3CvHfDdvDa/EZbuV1ihiUkEjqzrtA/M17FxXXB3R5lWLUg4rI8T2gvPD15EeSqeYPqvNa46VBeRSTWc0URVZHQqpYcZI71TV1YmLtJM86sxFNCCwHTvUUM9p/aOwPGm0HA6E++PSqKNLaRSxy8NBuVhnuDisQI984kmW6LAfKEj4H+NcSWtj1k9FY6qC5s5Lry2ZHDEruUg4PofSrtxBHCAUxXFo0thu8lZgucsJIj/OulluWa3Q/xMoOPShod+5FplkdR1Z4FUlZpVUsB90Lg9fz/ACr1fGBXI+DdJdIRqMjDD7vLUdeuCT+VddiumlGyuediKnM0l0E5pDml56CkZZCp2D5scZ9a2sc55d42txp+qXBXhbhfNGemT1H5gn8azo3jvLZVW5eGQAHclX7gXd8rLqUhmn5V9w6HPT8K5i4tL7T5iIlcxdigzj8K4205M9KKlCKubrzx29oI1l86Q8ZbvUSzGRVQEklRwO31rFsopry4wyTHjnd8o/xrp4LQQxBQMVLsilzS3PStIiFvpFpEBjbEv8qu5rk/Bwu3lvGbcbVNqqC2Rv5Jx6cY/OuqOR2rsi4z/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-40.png', linkedinUrl: '/in/walter-mclaughlin-7ec17dd691', jobTitle: 'Lecturer, further education', }, @@ -3405,7 +3405,7 @@ export const peopleDemo = [ city: 'East Debbiefurt', email: 'brian.ellis@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-41.png', linkedinUrl: '/in/brian-ellis-bc4c380ff5', jobTitle: 'Corporate investment banker', }, @@ -3415,7 +3415,7 @@ export const peopleDemo = [ city: 'East Robert', email: 'joshua.watson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDsscUYp2KAKkYmKwdS8Y6LpjNG9z50y9Y4BuIP16D86q+ML+7Mcek6e5jmuBmaUf8ALOPpx7muZtvBVuiBmlmYY5HFZVK0YOzN6VCVRXRsRfE3S2l2y2dzEv8AeGGx+FdNpeu6ZrSbrG6SRhyYz8rj8DzXA3XhO1EbbHlQ+uc1z8mmT6XMLizndZYuVOcH8DUxxEZFTws4nt+BTStc54O8U/8ACQ2bx3AVL2EDeB/GP7wH866UitzmHYoApaUCgDjLz59fumbG7eFHPYDFaqqwjUKoYH0Nc94jjU3k8jJM8bTcovBJwP8AA1BoVxJEyqokSEjKqxywNedUjeTkerRlaKibWooyRtkqg9zXIX5AYDg56kGpNUY30jyzRzyxofux1mmLy3fYjqq8FCc/lSULalSnfQv+EZWt/G1sAwEcqun5qSP1Ar1givHfDjpbeKrS7uT5VrC5Jc88kEAfma9lIrvpu6PMqxakIKWgU4CrMzk2tFF9PbM5ADcE81EHsLeZ42uEDKhI3DBPbIFW9cheHUllU8SqPzFZD3kdwCDYyzIuRnywQfzrzJRam4ns05KUFJFLTWtLud0jnjbcCy7OR15BpupxwW0TKi4JHJzTBfRwXIjis2gJJwu3AFUtSJy+W5BxQ07hfQj0y0a+1CG1VSRNIFY49xz+QNevkADA6CuX8IaHFb2FtqTljPKhIU4woJ6/lXUmu6jBxV31PNr1FJpLoIBTq4q9+I9hECLK1mnI/if5F/xrlr/x/rl23lxSx2yN/wA8V5A+pzWpgd94uu7e1sbdXY/aZZgkCjqxPX8Kw4BDcW376Z4SOqg459K4VL+eXVLK4uZZJik6kl2LHGeetdlqenJdoHidkY8h1NcOJsppno4RvkaKd/Ja2SM6Sl2zj5utc/cXDXPOTt5Zie5PapbnTZQx2u8mOCXPGap3SPa2jsx7ZJqIpPY0nJ7s7b4Z+Kn1Ozk0m9kzcQFvIY9XjB+79R/L6V6Aa+a7KeWymSaCRo5I23K6nBBrt9K+KGp2reXqMMd5GP4h8j/pwfyr0rEAAAAAAHlH/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-42.png', linkedinUrl: '/in/joshua-watson-5613c41859', jobTitle: 'Scientist, clinical (histocompatibility and immunogenetics)', }, @@ -3425,7 +3425,7 @@ export const peopleDemo = [ city: 'North Donna', email: 'monica.molina@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwCdetITkCnKOaTHArnNRCyqhZjgDuaYhSZDI0ixxqM5Y9qztUmZ5FgjUOTyRnGKu2mk3F1bG3ifMb8SOen4VlOetkbU6d9TJS6v7u7Y2iH7OjYxgc+9aN4JktA5wGPXPFaEvhU2wU21zIhUduhrOumnt7aZZeYwMMP61k22zXktqZEevS2smyeMsmeSOoroYZY7mJZImDIw4IrjfOiaYpIvydm7itDS7n+z7soJQ0EhGQe3vWkJtaMylDqjqQOajkZYopHcgKoJyegqUdajmjWWN42XKnqK2MkYOiQya5rR83d5SLuIB4PYV6RbW6woFXGB6V5mLr+yRfrDbSzvvRE8skYzk9RXW+HJr5lEN05YND5oLHJXPY+9c0o9TupvodK6fKea5LxFZMYWdQSjDDqP51ma3camt2JYlupFz91HIGPoKuW91c3J+zSW8ylcAnO5T+NLlaVy7pvlOIZBBlg6uoPUc/mKrPOJGBQ4I6AYwa0vFemmyvo5oxtSbKtjs3UViW/lFd2CGJ5HYmrSurnPLR2PUh1pCP50oHNHrW5yk+h2kMf2vzVV/Nk3ZI7Y4/rWjJcWdrBP+9jiIwuCcYrMtWYSYBqO4vdJeZvNt5JmU4OxCQSPX1rnlH3rHo0XzQTW5u2UltcqVJRmXrjkGlu3htlJRVGB2rLs9W06T/R7ZGjfOdvlFcGl1BJHO0t061k+xr1OY1uI6qjIzbQHDBvTFc7qWniw05ZpAAzkBOMdRnNb2raiuj25ufKEojOSmcZFcy9/d+NdYTaq21tH91Sc4z1J9TWlNN+hhVlFb7no6jmk9frT1HNJjkjvmurqcA1GZCWXrVuGyhu0DF1Q4596rhGALY4FZC3kza3d2qyFTHEjqB75z/SpqU3bnN8PWtLlOmZIbGHG5cewxWTe6mqo21tzN6VmzpqE2Du3oe+as2eltu3zdq5GdlzkvGJddEBckGWUA/TrVfwNbJLqUSMdgGXH+3jtXW6xpKap5du4+RWDn2AqXSLS3sdSll8pURhjzPQ+ldVGDlTuu5xYiSjUAAAAAC3kf//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-43.png', linkedinUrl: '/in/monica-molina-2213f0ccce', jobTitle: 'Press sub', }, @@ -3435,7 +3435,7 @@ export const peopleDemo = [ city: 'Cunninghamstad', email: 'justin.castro@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0PcRSFw3WjNJn6UAUtU1az0eze6vZhFEozz1PsB3NeV33xR1aW6ke1EVtbKSAhQMxHqSe9ZfxB1GfWfG01nalpFtwIUQHjcPvfrmq9r4F1KcK8zoik5Kg5NTKaW7NIwlLZFqP4oa1FceYbwyJ/deNcfoM10+g/FNZtqatCNpP+vhHT6r/AIVyN54BuwC8bqf9kdq5y602+0skTAoo6EUlOL2Y5U5R3R9KWV/bajbLc2c8c8LdHQ5H/wBarQJ9K8L+G3iGaz8TQ2LS/wCjXp2Ovbdj5T9c8V7mM1RmwJIrP1u9fTtDvr2Jd0kEDuoI7gcVoVFdW0d3ZzW8o3RyxsjD1BGKYjw7wfE17e3OpTZeeRzuJ9TyTXosKsEGe3pXAaRG+n6ZIiebuNxIoMYGeDgc/hWzoGo391cJDKX9f3gwa4qibbZ6NJpRSOrCtjOOtc74isIp7CbcmWCkjiqeq6hqNvevGsk/lpziLGSPbPU1ftLo3SBJBODjlZl5/PvUWtqaN30PJbeV7DUo5oWIeKQPGw7EHNfUdu/m28UjAqzoGI9Mivnx/D8kviiSKIBYY513PjIUEjH86+hQu0YyOK7oyT2PNnFx3HY5oAp2KBVEHAXGmW+nanc2YX5HczJkcAMc4/PNLp8UEeoEjaqIOpwMmrviu18u/huUDfvVwTnuP/rVzD3FszsSk3mAbS8YPH4964Zp87R6dJ3gjckitpbgJIFDsCVbg5pZkhtotqjnHWsm2ubCKPykjaJicgspBz9auv8AOF3Hp3rNroaEWlaULjVwy5HnMDKPULjH06frXotYXha0nh0957ldrTOTGhHKp2/PrW6a7aUOVann1qim7LZEnFNZgKjlZhyD16AVWlLs+zrjqa1uY2M/xNPbHSgr5aRpAsRTs3qfbGa4gBSxVpShHTArs9egzpLShc+VKrn2HT+tcpd2olTepKn1Fcdd2md2G+EapjSPAl3jHORinoxkT5eQBwfWqlvZNuzLIXGeh6Vo7HkCWtouZ5j5cYHqe/4daxvqb+p1vhnVpNa0OK8kiWMlmUBOhAOMj8q2MCpdL0iHTtMtrCNcJEgQYHU+v50slq0fTn2r0Vux5b30P//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-44.png', linkedinUrl: '/in/justin-castro-43678bde89', jobTitle: 'Plant breeder/geneticist', }, @@ -3445,7 +3445,7 @@ export const peopleDemo = [ city: 'Port Angela', email: 'austin.dixon@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDpAKgvr600y0e7vZkhgTqzfy9zVlRmvIvE+oz+JtZkt1ci0t5THCg6E9Cx/wA9Kkrc0NV+KMzytFpFqiRg4E04yT/wHtWMfiF4iLf8fUYwc/6lcH26Vv6b4M0oRrHPGZWxyxOK3k8E6IYtoteT3yc1g8RFHSsLNowtG+JRaUQavCgyf9bEMY+o/wAK763uIbu3SeCRZInGVZehrkrjwHo6xkrC2R33dKr+HpLnQNbGltKZbC4b91u6o1VCrGTsiJ0JQV2dwaKUikrUxHXL+VZTyf3I2b8hXjekIyybwPmJyCa9h1G5gtNPle4J2MNmAMkk8V5jpNpJaXiQ3KYKZbKnIYdiKipJJWNacG2n0Ow0/DN8xA9TW7GcxjawOPQ1xV2uVVPLmeNv4VO3J9zTdFMkEgdIZrdD1WSQsTzXHy6XO9T1sdpOD5ZycA+tcXrj7Li3aNhnzlAb0OaseJJZpvNjKSyRRjlFOGNY9vZmQIirLEqyxsRI27aQwzj8KqnGzTJqyunE9NYUzFSnBGR3qM12nmkOqW4udNkUjO35wPpXGXCATiRQS5B6+me1d+Bkc9K5bXrBbJoJVfKOzKFI+7361hWg37yOmhUSXIyex8u5iUOvzDipbzyImWIlA33iTgAVQsnPyFT1pt9dafcZjuYxJtOSNhbBrmS1O6+hoypbtqWC0Z8xB3zyKqXltA9xDbgbQ8gDEVm2sunQ3W6AsZPu5fOfwJrVtYmudYiPUJ85+g/yKaj7yRM5JRbZ0h4GKjNSNUZrvPKJl6Vxvi7WYJrwaTEjtNb7ZZZQflTcOF+veqviL4j2lrFLa6Rme5xgXGP3an29f5Vy3gq7S+1q6s7+Rna/XPmsctvHIOfXrTlFuLHCVpJm9Y6n5SBJGwyHjPcVuRqtxGCkwUEcEc4rD1PQ7mxuPKmXryj/AMLj1FU4odRTAiDY+vArgasz0Yy0udDcQpbKztMJNvc1taDbuLdruUYebG0Hsv8A9euFnS6Zdk0u45+6DxmtvSfiHpZtILfUPMgnRAjyBMoSOMjHIH4VtRjd3MMTN2sdo1RmobTUbPUIvNs7qKdPWNgcfU4z/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-45.png', linkedinUrl: '/in/austin-dixon-791d6f8fa6', jobTitle: 'Dealer', }, @@ -3455,7 +3455,7 @@ export const peopleDemo = [ city: 'Christopherchester', email: 'mitchell.massey@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDnI3JXrTLy/jsYfMkJJJwqjqxoiUq201y2o3/2u+kkbOyP5IxUGhotqtxcSBnAwfuxqeB7k1iX11NPM8Q2kD+4KnGJIclyowflX+tOg0K8viBbR5/pU3S1Y0m9ER6ZrVzayCJp2CLgDJ/xrp7bVluS0MmElx8vo3/16xpfBupIrFkVdozWdc3Cxssf3Co4YetCaew3GUdzs4GJWrSGsTQ9RW+typOZY/v+/vW1HTYkU9SY29hczDqsZNcBhSq7s8nJr0m8g+1Wk0AGTIpUD37VxOm6VPPrdnaNgky4bByPeldD5Wx9pYXEyArGwUD5QB+v/wBevVvC+gyWWmxyyqA7jOD1pl/prQQCCG3dlYBcRgDn3NU/DI1Brpd63UcbnnznJIHuD0rmlJyVzspwUHY6G90/90xPRhgivJvFGgS2aPJtOFYkHsRXa+L5dTa4eK3M/lRD5jA3J/Dv1rFltJ7rTbqF3uCREdyTnJBxxg0Q93UKqUrxscf4WlZdXRV6OjKfyzXeKK4bwnbu2sByDiNGP58V3a9a6mcUdhCxXkdRzWuukQSXllqUKLGsKqFCj724HOfoTWK/Q1o6dqtwsMFmFQxeb8xPUA+n41lUi2ro3ozSdmdzbSLNDsYDpjkZqOR7eGZYk2KeCzcAe1QW/wB3g9qytW1PSFCRXSmaQPkBYyxDf0rmWuh3aF5hBJrU8TFGRuR0PNU9Yht4beRIkAZhjgd6x7C70tNQlW1MgnyAwmyG9utWdSlLsDnoe/rTtrYTaSuc5Z6bHpkZjUhn/ib39KtL1omkMkjOepNIvJrsSdtTzW1fQjP3TS2/GG6BeSfQVYjtJZn2xoWY9hWofC80uj6jA0gFxLbMqqv8J6jJ9eKqxFy/BdmPapbGRkH1FWpLN7mD91IkbD7pPNVvsMd3pcO3sgwe44rFnbUrJtkfmMo6V56ep6ibRdls3tnMs8qSMOhAwBWXcXaTTmMOCwG7Hr71Cz3t5JsmLKvcVRaFh4kiZP8AVrbkMPbdW1LWeplXk3BssyNzT17UrQkXbQy527dySDuPerK2DsAUYEdcdK6rHAAAAAABwXP/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-46.png', linkedinUrl: '/in/mitchell-massey-22fdbe6b77', jobTitle: 'Phytotherapist', }, @@ -3465,7 +3465,7 @@ export const peopleDemo = [ city: 'Glennview', email: 'eric.reid@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0+kpaRslTg4PamI5zxPr0emR+QtwIpHU8jr+FeZtrZ1W8Np57/Pks7Hn6VY8aCS01uWGYtMXVQrE8k+3p/wDXqCz8AardSxugECsMlmbJFc8pa6nTCGmhEbvT7d1tYpN6LyN45B9Kp/a3tXWYwx+ezbS4OCR2rsovhRiPdNeFpM5JC9a57VPCOoaPM8m0TRIMg9gKlsrlY1tcuQqT28xgmQ/KVIBr0nwh4sTXrZIblkTUFU70HAcD+Ja8QubpZfkWIBv4lB4+oqbR9Yk0vVrS8R2UQuGIHG4dx+VVFuLIkk0fSFUtWuXs9MnnjBLouQPWr1UNZs3v9IurWIjzJEIXJxz9a3exgtzynTJZdf8AHFub0bmDbiudw+UZH8q9gtoVVBjGRXlsulT+G7+F9rC4e3do0tvmKkFRyx6k55OK6fwpe6rfxSLqCMm1Cys3B4OMGuVppnbB3R2LlegP5GsbWolnspY2UHepGK4/U7nxDBfqYHuZIs/dUgDrj0rbtLm9uB5NxDMpXj5sEH3BHWpexaWtjxbWLRbO9k3FhkkGsppiHAA+UHgMK7b4hWDWuopKF/dzcke9cXJDlA6rg+h71rF3RzzVnY+qaSloroOYz7q0hfUYLqQAlIniUH3IJ/lSGaztoZVWWKMscYJxU9/GWtiw6oc1y15daC9z9nuTvmT5mjAzn3I/GuapfmO7D2cDqLX7NcbgdpKnB7027mhgXKgDHpWRp2qaROBBp80YccbF4I9cipboFmIPNYydtDZJXOZ13TY9akiabiOJixHqMVyfiLR4tL0gSBNsskgSIH7xBwTx+ddvqV3/AGfC9xtVkhUuynuAK5Lw5Z6l8Q/ECanehYdMtGGY0PHrtHqTxk1VNNszqTjFO57PRS0V2nnjXXejL6jFc22nzytuijh3rlW3qCa6WuZ1DUlfWbi0sJf9IgjV5l7EnOPx45rKqtOY6MPNxlbuWYrZ7VMyRRq3qAKqXV2FyMgsfSsa51jUZJRC0ZX3q9ZWTsRLKST71yN3Z2XKWtWVxd6DdQwoZJ5l2Ko9TxWx4E8O3PhzRWt7t0Mrtu2p0XjpnvVbxBEjaFeI8nlhomUMDggkcfrWd8O9Smth/ZN3dSTll3I8rknd3Az29vaujDq6bOTEAAAAMQ9Uf//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-47.png', linkedinUrl: '/in/eric-reid-4a1a08817b', jobTitle: 'TEFL teacher', }, @@ -3475,7 +3475,7 @@ export const peopleDemo = [ city: 'Hernandezview', email: 'andrea.park@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDuT0opTWXrmrxaLpkt5LgkcIpP3m7Csm7Gi1L1xdwWkfmTypGvqx6/SsweKdMMuwS/jXmb3WqeJ7nETyTyueFyQoHrx0FdHp3wxvCqy3t8FzztUc/nWLqM3VK51sPibSpyAtxwejkYX861AyuoZSCDyCO9eb6p4L1uwiJsLxJIV6R7cMPxrO8OeKb7RNVWz1F3Ns7bHR/+WZPcelONS7JlSaPWP4qdTVIZQw6Gn1qZB2rx/wCI+tvf60mmW75jgbYfQv3P4dK9gOdpx17V88xBr7xmIiSd12VPP+0c0pFR3PXvB+jwaRpMYUAyv80kh7mur89NoAkUn6155rV9LbL5S208qAZwgOB/TNV/Cy3cmoJmGWGKTBbdnj0z71yNNq56CsnY9CuJFK4LgfjXmXj3Tk+z/bFUCSM/Nx95TVnxdLdwahIgSeWGM9IwST+ArOlmfUNFu4GSVXSI/K/PI5pJWakE2mnE7XwJrK6v4diVn3T237qTPU+h/KunxXlXwpaVL664PkyJjPbcD0r1btXYtjznuNPSvHrHR4rXxDHfBAG853wP7ucZPvk17HiuD1CSw0zVL6C5njibcJIt3GQ/JA/4F/Ooq3toa0Lc1mdHaXsV3b7HRMd8iqV3rOnaZcxqwCRbgOByzVWsozj5TxUV9qsez7PBpcl0VzlsAL74J6/hXKldnoehNBq+n6lqk6ggq5wVI6GjU0tIEMaRgblIyKybfUIY2Mc2mPalsAHGR+Y6U+5lB+aZwqAckngCpa6D2H+ALI2aTKUIXeGBzxzXe1jaHaiC3Ur0cBuPTt+lbPau6F+XU8upbndh/avJ/ijEk15GyKDKijcR1xmvWcCuR8Q2Vrd3UtqLSSZ54yWmBVRHj36n6VUtFciOrsjKhuGhVEZiAwBB/CtN7e0u4MNdFF7CqtxYBrZFIyVAGa56USRSlDuGDxzXFuemnY3mt7e1jYx3Bce9ZshnnliWBQw35fI6gAnH4/0qvDluSSfrW14dvbF9Tk0m4ytzKomiY9DjIwPenTV5kVpNQZ2dmuLWLjHyjj04qfHFKihVAHalxXaecf/Z', + 'https://twentyhq.github.io/placeholder-images/people/image-48.png', linkedinUrl: '/in/andrea-park-80bc0bf8a0', jobTitle: 'Brewing technologist', }, @@ -3485,7 +3485,7 @@ export const peopleDemo = [ city: 'Port Emilyport', email: 'wendy.page@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDvcUuKWigRT1LUrTSbNrq8kCRrwPVj6D3riZ/HOoXe97K2it7cdJJTliPX0rB8a64NT8TPbxZlhtv3Uf8AdDfxH8+PwqBIhNbqiqZ5T0z91fwrGdR3sjop07q7J5/iBqNnMGW7FxzypT5a0bX4nzXLrstkB/iUnArHbwjc3RBkkCJjsOv+ArOvdBk0a6ilQB4jw/FQqnS5cqL3set6F4ntNbzEFMNyo5jY5z9D3rdIrweG9udJ1WG9tiSI2B257en5V7dpuoW+qafFeWsgkikGQR2PcH3FbwldHPONnoWqzPEOoHS9BvLpTiRYzsP+0RxWnWJ4ttFu/DV6G3ExxNIoB6kDpVMlbnkmg6PcarcbjynVsn19a9G0/QEtAGbDMB0HQVw2gOItEaWRJ3lmlbasbbegrr/DN1cs0ccrytEy7180/Mvsa4prqelTatY6L7OAh+UAY71zXiG0DWTOuCQc8d6r62001xJMomdYxkIshG4DtgHk0WEpvYBGbaS3bAJBPB471PLZXK5rux5xeTM0rncRjgivQvhRdyMNRtSxMY2yAH+E9D+f9K4LXLc2uqzRAYblgD/EK9B+Etsq6fqNwf8AWGVY/wDgIGf6100+jOGrpdHo9QXkBubKeAEAyRsgJ9xipxRWxgcB4dsEtdNFndR4nikdXU/3s1rhrW2nn8yVIykecH0qfV4/K1ZJFGN6ZOO5FZUmo6e1wTLG0si8HaucVwyXvNHq0nzQTRoWBt7yPerRuTggqchh61LdLHbxHGBgdhVO11CxdvLhO2TrtK4NOvgXRtzHgVD0NDg9Z0aXWdWheMhRtwST2zXVfDKOW3h1a2PzQRTqqvjq2MN/Ss1L6GLU4rDynkvLkYtwBxkdcnt9a9D0rS7fSLBbW2XCglmYnJdjyWJ9Sa6qCe7OHEuK0W5cFFAoroOQy9dtpZbVZ4QWkiySB1I71h2kEVwuSygnvjrXZZA5JxXA6pOkut3H2KbYm8KcDjdgZxXNWgviOzDVH8JrNHHbLwVx7CqF5d708tPmduuO1Rf2deyj97OSKtwWUcEWTyT6965mdd7mLa6NJd+JLaeMnzLdBt+pOcn8q9LxjivMr3TP7Tuxl2jCODuU4OAOmfeus0nVRa2yW1zuKoMK/XA966qM1y2Zw4gApvmuj//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-49.png', linkedinUrl: '/in/wendy-page-7d996e5a2f', jobTitle: 'Chief Executive Officer', }, @@ -3495,7 +3495,7 @@ export const peopleDemo = [ city: 'East Brett', email: 'vanessa.carpenter@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0PHFefeLfiVHo17Jp+mRxz3EfEkrnKIfTjqRV/wCI3iVtD0RoLV2S8uOFZcfKueTXgsrF32gHJOScdSalspI7t/id4gkKyF4NoP8AcAzVfUvH+vysrrePC3QJCAB+PrWn4U8Cx6hDHdXzEIcFY8YrvJfB2kGBYjZpgd8c1hKsk9Dojh5NXZ57o/xR1e3Ig1MiaBnGZ1UB0HcccGvWtE1qy13TUurO4EwHyvxgq3oRXn+ufDvTnhZ7VDBIOcqa5PwXrN54W8WfYJmIhlcRyKWwp9Dz9auFVT2M6lKUNz3zFKBTInEiZH0qQVqZHg/xL1wat4hUQRny7dfLRuzHqSPz4rndDtzdanCJju+cYUVY8Q27xa7dW6zC5KtxKpyDWp4CsFm1kmQHMSlvbPasZytFs2pxvJI9f0hAtsiKANoxxWo44ADAn61yGoTzRAwJBLIrKSSDgcDPqMmsjwz9pa+3hZokk+Yh2OQPcE1xpaXO9vWx3F7GzQkZwcV434+sVguYrtRhmby2x3rsvGV1eLM0MbSmKIZYRE7j+ANcf4khafRY3jidDBKPMDtnsRnv61pSVpJmdZ3i0epeBdaXW9DR/mEsAEUgY5OcDB/Ec11VeT/CN3+03ygHaUUNzwCCa9YFdq2POe54PaPEnjaSGRE2XG9VXtu6j9RXXWWkppd9vjHLxgOfU5rnPF3h26sL69v5YvICPm1lU8sQRg59ccmpfCXifUNc1GeHUGjYRRrtZVwScnJNctaD3R3UKi+FnqFr5N3a+XJGp4796hY2Nk5jQRR4G53JCgVWt9yJ8p7ZqtdX+lSRNBPCbhlOSBEW5/lXPHXQ6rEt/HaTaqNzRusifXmuY8Y2KNpRt7OAM5kTKA43c9KsLdWC3f7pJEYjC+YCCfYVZ+wXGqq/lyIrx9Vb+IH8RVwi+dIzrNRg7lP4aafLaX19LJGI2YBGTd90ZJ/HmvTBWHonh+PSVZllZ3bA3bQvHp7/AI1uV6CPLbuZPiLQzr2mm1DxxsTnc6bv68VyVv4Et/DUyzx3DSzzgo+RgYHOcV6jJplybd/KeMTYym4ZH41yVzHdNfN9r3CRMrtIxtrDESSjbudGGi3K/Yy4pmQbS2COKtNB9ogKiVFGOCeopt1ZlySvWsqVp4m2EE/pXEmegR3VoYZcGUSOTwcc12ek6WlnZRiaNGnPzMSM4Pp+FcK0siSpKy7gjBtvrg9K9HsLldS02C/twWhmXPuD3B/GurD2bb6nJi3Ky7EppKCaSgAAAOs4T//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-50.png', linkedinUrl: '/in/vanessa-carpenter-a0b8dc7720', jobTitle: 'Chiropractor', }, @@ -3505,7 +3505,7 @@ export const peopleDemo = [ city: 'Kennethfort', email: 'lisa.bailey@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-51.png', linkedinUrl: '/in/lisa-bailey-f737183c93', jobTitle: 'Agricultural engineer', }, @@ -3515,7 +3515,7 @@ export const peopleDemo = [ city: 'Port Kimberly', email: 'jason.wagner@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0ailx70n40xFe9vrXTrVrm8njghXq8jYFeVa/8Ubya+I0SQQ2cfG9owWc9zz0FVPifd3uo+L4dIgDyKiJsi7bm5J/+v7VPp3w1j8lXu7nMrAErGMKP8azlNI1hTctjmT4519b17o61db2/hDYX6Y6VdsviH4gDq41eSQ55WRAw/lXYy/DrR5I9ojYHHJzXJ638P8A+zo2ngnbYO3pU+0TNPYyR6N4f+IemaqYLW7f7NeSHb8w/ds3oD2J9DXY18rzSTWknkybmHvXvPw51+TW/DQW4cvc2hETMTksuPlJ/Dj8K0jLoYyR11JiloqiTywFNU+ImsXuAxgxBGfQKMH9Qa7CEgAc5NcZr8X9l+J9Y+zecnntG2IV53FST/jVrwxc3t1N5dw0pQIWBlHzfjXJUXvNndRfupHYE56H8qp3wSS1eORA4I5BrjdVfUYb12ilunjXkKj4z9BWvp97cSqscscynHSTB/UVnbS5rfWx5j4lt4UvP3eVUHG0/wAq3/hXrDW3iqOyDbYbpGRlz1IBI/lTPH+m+XcRXEY4kHzYHeofhvpVzB4w067ubVzbOX8uQ9m2nBx+ddMJaI46kXdnvWaKSitjA5fWLWBdbmkkAJnRGOfYY/pVKG90+zNyWljjKqAfQD1rT8UwsTbTr2yh/n/jXKfabFp8+RJK6nlkQnp2zXJNPnZ6FHWCsdBbS2V25AaN+AQy8girMqwwplQvtisi21CzlZYkhkiYngNGVq/KhHBNZPQ30MbULVL+WJ5cbIWLYYZB4q/4fijGtWe9VjmWKQBVHDAY5+nP61S1S+j0y3kupIi8MYJYKefan/Dx7vWr6/1+8gaONlEFoD0CZy2PXnHPtWlKLbRhWmoxa6s9AFFFFdh55R1mze902SOL/Wr8yD1I7VxVvbJJ96YxMOCo45969ErjPGlskNxb3MBWOSQN5mOpx3IrGrDTmOjD1LPlHiMRw4MocetQNc7sjduPtWDbfbppfLlLFD6HrW5bWYiIzjNcjOxO5l+JbGa70Ca3iUvLMyrgf7wrt/DOny6T4ds7K4x5sUeGx0zWLMOFAznPGOtaOhNeWcKWt/eSXbuTtlk6jngV/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-52.png', linkedinUrl: '/in/jason-wagner-6eafd392ce', jobTitle: 'Surveyor, quantity', }, @@ -3525,7 +3525,7 @@ export const peopleDemo = [ city: 'West Tammy', email: 'judith.moore@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDpj8q00EkEmkk3FOOtU7/UItL06a7uDhIlz9T2FAjI8Q+Io9M/0eEh7puduM7R6muW+3XV0xlnuFJHIDP/AErnEuL7WtTfyF3TTuWLEZxnv9K7/S/h6stsJL2dnlPORxisJzOqnT7HIahfC+ij3IY2jbawB4YVoaVdXME6Ism0fwgjCkV2Fz8PbV7cIjOSBxzXLrpM2halHBL88DEg7v8APWs+e+hr7NrU7K0v1ciNvlfFakEikV55d3/2e7QRtmPPyt6e1dlo14l7ZiRSNw4YehrenNvRnNVhbVFx5iBXAfEq9kNrYWwJCO7Ow9cAY/nXfSqdnAzXEfEC2Emj29wVO6GbAPsQf8BVy2M47j/h/pYWwa6ZAZZG646AV6ZbJiEDcCR715hpFxdWvhWwEAm82VGYbMDnJPJNbvhPU9Wv7lbe7VwSMguMEj3rjkup6FNqyR30ePXpXL+M9La+0qZ4RtnQbl461ia7qGu217JHbyy+XGNwVMDIHYHua09H1G+vo0hu7e6jJGf3wznPof6VFrK5fWx5Ab+TzGWTIOec9iK7bwJf+bLdQEnlQ4/D/wDXXP8AjHQ307xDMsafu5h5igfrW78O4FT7YWU+ZtGM9hk8V0Qs2mjkqJpM9HEII6Vn6tosOr6ZPZyfL5g+Vv7rDofzrbUAU5lU10nKct4ftBDpMFhdxgSwgowPrk1t6clvDqW1dqBFPJwMmqV9AYLzzEz8/JrLnudIkuC0t0VlUYLIT+uK4ZJqTR6lNqUU0dQ0FtdSBZETzMZBIByKmPkWicAZHT0rBsrnQ4IVjsp1R92QCSDn8avTFpMA5weayd0a2Ri6npp1XUobgYEkf3NwyDznmk0OyCPfXaDCzzERjtsXgH8Tk1ka/wCIL628TWuiWmxY7lVDuFy4ySMA9q7qG2WKNUVQqqAAoHAHpXVh4faZxYmomuRFkoRRipgRWbqet6dpS5u7pEbGQg5Y/gK6jjE1OCSS2Mkf348n8O9YMVuk6qwuPLOOq1zPjbx4bvRJbPT4pIVnBDSOcMy+mB0zV2JZZtLtpY2KSmJM4PU4Fc1eNnc7MNN2sdXFCkMGGmWXj7xHNRfamnk8mNwxHUjtXNWsN/cNsmmcR98cZrehe10ixeV2CqoySa5HudfNc55Ly1i+KLRS2KzNHEg+0M5/c5HBx0zzXo5xnArzay23N/c34T97dPuZvQAYA/Ku3sb9JUWJ32zAAEMMZr0aatFJnmVHeTYAAAAAAAAAj//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-53.png', linkedinUrl: '/in/judith-moore-e8bdfc83e3', jobTitle: 'Translator', }, @@ -3535,7 +3535,7 @@ export const peopleDemo = [ city: 'Andrewfort', email: 'steven.moore@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1mikqO4mFvbSzkZEaFyPXAzQBx3i/x+mgXTWFnbi5u1UGRiTtjJ5AIHU456ivLb/XtY1R5Lu5uZ7jOMREkKp9l6Ct2w0W61zW7q7vGZBI/mS8feZucD6V0R+HdtNJvjupkB/hB4rnlVV7HTCg2rnmEWqXSkyv8kyj5lHTjpitzT/iFrOh3kRR3nszy9vNkqP909RXoy+B9JijXfB5jIuCxPWs7VvDFlPaskKLHIB8rAdPSp9si/qzsdloHiCy8Racl3aPgkfPE33kPuK1a8D0jUbzwnriyAMpVtssanKyLnmvelYOisOhAIrpjK6OSSsxar30fnafcx9N8TD9DU5qK6kMNnPIqhmSNmCnocCmwSu7HDeHxm13Y6sc11UAxGOc1wTte2GmwC0aQswYjylySck1o+G9R1i6kWK+jKblLBnXafoRXnSWtz1YPRROvkJ2EZrFv2+Qhaw9W1LXY55VgiZokGT5a5Zh7U+wvLy6ASeKZCBnEq4Yf41NupV+hy+t232jVIZoj86EAkD14r2mBSlvEp6hAD+VeYXNgZNXBjYqpYM2BknHOBXo2mX39o6fFdGPy2fIZD/CQcEV2UZJ6Hn16bXvdC4aawDKVPIIwaU0lbnOcvawxQvLauq5jcgDHHWrcPki8KoUAjQk9BzUOrWy2+oq8YIEo3Hnv3rFu5NNml2yySpKBjfGrZx6ZArzpRak4nsU2pxTRu2ht5nMblS2Mjoc0XZhtlIjUZIrJ02XSLdfIsx5TE52shUk/jVq9YBCSeal6aFMzo4xJKxK5YHcGHUGu3s4fs9nFFjBC8/XvWB4asoriOS6kUsVk2pk8cDrj8a6auyhCy5mefiavN7i6BSUtBIAJJwB3NbnKZut23nae8odY3gBkDMcDAHOTXNwBbyIOJ9hx1HFHi/xLYTaXc6ZazebJIAkjJ90DPIz3P0rn0Waayt54Jmi3ou4r9K5cRFJpndhJuzR1Hli2hJaYP7msa5vDdN5UT5JPJ9BVVNN1GRcXF6Xj9hjNaFtZJBGTj6muVnVdswrTX7vw/4/jR5ZP7Nltl82POV+8Rux6ivXVdZEV0YMjDKsDwR614RrVz9r1qaVRhYx5a/QVsaJ49vtFtorSSGO5tlOFDttZR6A16NJ/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-54.png', linkedinUrl: '/in/steven-moore-a4d5be1e3c', jobTitle: 'Accountant, chartered certified', }, @@ -3545,7 +3545,7 @@ export const peopleDemo = [ city: 'Robinsonberg', email: 'darren.castillo@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDPZaZtqyyUwJTEQ4wCScAdzWZc+IdNtSQZS7Dsg6/jVW+N9rt21hp8beSPvNnAb6+1A+G2q3CjeIUHu5JrKVWMXa5tChOSukTQ+J7B8bxImfYEfpWxHIk0YkicMh6EVzs3wy1SFAY50I7rk1Wni1nwxCvmDfGO4OR9DSjWi3a45YecVdo6phSKtM028i1O0WaMFSQCynqpq2I8GtjAnIqteMEtJDkjIxke9XytUdTjI0+VsfdwT9M0nsUtzQ8LadDZWKlASzksxPWuujPyjGDXn17JcW9lbxxyXCDygwFuuWY4zV3wxcaq93FFdTyvC3zgygbhx0OP5V5jV7yPZi7WidnPwhBwMjvXJ67FFNaypKoKMpBrJ8QXesSX0iwzXH2eM8iDGSPoaS3kuJh5bvOwC/Ms6jcPx70uXS43LXlsYvhzFrqUlrksHU4J746f1rqttcloyMvil7djkxFgPpg12nl16UHdHjVFaVh2KR4PtELw8YcYbIzx3/SpccU6P5ZFPbNOavFodOSjNNmlp4glto0ZASFAGRTJdR07TdTSOZgnykjC8cdfYVWtpBHK+3opOPpVKW8e9Pz2czoMgN8qj8N3WvMSu7HtdNC1pF7Z308wRw4JOMqR36c1LqkcECnyxhyDz6VkJfGzmIWzmiDMP4Qy/XIqfUpmeInncRRJWYJ99zH0602XUlyoAmkmB3DqU6Efoa6DFUtMjVrdJAvQnn1OcVoBK7qEWo3Z5eKnFySj0GgcUuKcMYpR1rc5SpckxAMD8rcGrBexlhVJ8vkAgA8CnX8EkcFozRHy5y4DH/Zx/PJ/KsSXSJi7mNzjqBXn1rKoz1cO5OkmX7i6s7eMiBtgx3OeKxbi9M67YmznqfSoH066MmHyR69quNZ/Z7bHAastEbJSZ0dtEIrWJMfdQD9KeRRZWl6ugafeXcbK88e5jjpydufqMU4V6kdjxpJpu5//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-55.png', linkedinUrl: '/in/darren-castillo-8ed7a1702b', jobTitle: 'Advertising copywriter', }, @@ -3555,7 +3555,7 @@ export const peopleDemo = [ city: 'Andrewstad', email: 'regina.quinn@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-56.png', linkedinUrl: '/in/regina-quinn-3983eab37e', jobTitle: 'Materials engineer', }, @@ -3565,7 +3565,7 @@ export const peopleDemo = [ city: 'Lake Wendyland', email: 'michelle.delgado@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-57.png', linkedinUrl: '/in/michelle-delgado-53f8093373', jobTitle: 'Soil scientist', }, @@ -3575,7 +3575,7 @@ export const peopleDemo = [ city: 'North Briannastad', email: 'miguel.rose@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDvMUYpaKgoZNLHBC80rqkaDczMcAD1rzrW/ieYpHg0i0ViOk9x0P0Uf1rR+J99PaeHFiiOEuH2SH2615/p/g/W7y3WVYQqSLkb2weamUlHcuEHLYZP4r165uxcLrkplX/lmjbFH4DipbHx7q+npLINRlkd8MyzfvAPpnpWxbfCmTy/Mnux55HRRxn61nXnw3vbZGMbpJgZwe9Z+1h3NfYT7HXeG/iTFd5GsvBChHyTopAz6MOcfWu+gmhuoEnglSWJxlXQ5BFfMtyr2crRN8p6OhXoa9D+F/iR7O6Oj3r4huWzbkn7sn938f51qmYtHrRpKWimScT4201tV1vQrSUk2rSMxTPBZeefw/rXVQwhFGBWZ4ttPO06K5VpVa2csPK++cjHH6Vl+F7vULmN4bnz1UKxVpvvcHHNcmITud+Fa5Tq9hGTkVTugAh7nriuI1SHVk1NCpu5U3BcCXA5PXFb2ni8xskEu0dA5z+RrBx0udPNrY838UIrXkkuxeSd3qK5+y8yDUrO4t33TJOjKMd88f0rufH2nLG0M0SgPJlWA71zOhaPfjW9Iee1kSCS6jUOeOMjGR1A44zXZSknFHBWi1Jn0FRRRWxzEVyV8oBhkE4rHl1DTrBJfMnjhO4KS3AH1rXvFJtnI6rzXJzX+mre7jE8ko4JjiLZ/EVyV03I9HCaw03OjtntrxSwKsQcZ6g0TyRwKdo5rPs9RtbgrFACpA+6yFCB9DU0oDZ5rnfY6dDHvbKK9u7e4nfAgYvjHB4qxaW6y6jZCZQXWQlWUY3jAbJ+mKjnlZJd6oGVeWUnHFN8D3dzr0l5rVwgSIMbe1jHQKOWbPcnj8q1oxcpLyMa1RQg+7OvpaMUtdx5Y1lDoVPQjBrnXsyshjafymQ4+Xv710lU7/Tbe8UuxKShTtcNj86zq0+Zabm9Ct7N67GWziNADIpxzmqEupDBSMh29qyvsl5POQzF4enDVrW2mxwKGHX0rhasehzXE+zu1jKZGw7qQWx04rZ8LNpC6DBb6LcLPawDZuHUt1Ofc5zVS4IjgJ7AfnWb4NgOkTjTITvjYNLKfRs5z+uKfQ//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-58.png', linkedinUrl: '/in/miguel-rose-31034cf613', jobTitle: 'Therapeutic radiographer', }, @@ -3585,7 +3585,7 @@ export const peopleDemo = [ city: 'Carolynville', email: 'gary.mason@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDtccUU4ioppY7eF5pWCxopZmPQAUwOc8SeNbHw/IbZUNxebN3lqRhfTcf6V5zqXjW/1KRZLmVl2HiCIlU/EZ5NaGj+Gn8UazPqV+7eQZWJ2nBfngfQDFd7bfD3QkCSLagEe9YSrJOx0Qw8pK54zJq8jrlXdSh3AAnHWu98MfEpG22uqcqoAEoHzDtyO9ddeeC9ElBP9nxqQOq8Vx+u+BtOa0f7HH5M4OVYHqfekq6KeFklc9HtLqC/tUubWQSRP0YVOBXkvgDxJNpmqRaJe7lhmcqCxzh+368V65it0zlGGsPxfn/hFNQxnlADj03DNbprN8QQfaPDt/EDhmgbb9QMj+VDGtzG8KENpNuyrjcM/rXXKMRrtbPtmvLbs6lZabY21o04/wBHDYgHzE4ycn+lX/B17rd1drbXkk/llSwaUcj2NcDjuz1Iy2id9ccIQWx7Zrl9WlKqcZ4BIrlvEN94gbU7iK2kn8mLJPldwPT3pul6hqM0gt7szsrDJ85cFaXLpcbnrynLXH77X7by0yzTLwPqK+g8V4b/AGf9l8eQSbglnHMk0sh4CKME17kCGUMpyCMg+td0GmjzKkWnqRVV1K3W6sZI2GRwwB9R0q1SMCUIGPxpyV00KEuWSZl6XFbXmmRLMF+4ASafay6bb3m2Foo0QHuBuNc1LeT2S3kGf3kDPlR3GcjH51y92dQ114Z4Y/KVY8BhGwwPTIHNcSg27HqKasrand2cmnXN3JHM8UgkY4IIPfv6VNqFrZ2UebeNQa8xsZr3w/JLutZGR25zE2T79K6G/wBakayt5VPzyrnBPQUnB3sHtFbXRkMEH2zUbp8b0yIXUjtt6j3ya9ThjENvHEOiIFH4DFcP4E0oz2f9oyuChmbC7fvEcZz6Z/lXd110oON2zgr1FJJIjpKcBS4rUwPP/HNjc2N1/asCFrWZRHcbf4T0yfYjH5U2eZ7nS4hbXYgmUAENkAge4rb8XaoIZrDSfKV1v2cSZGflVc4rz3VrPVNMhKWY8+2AIw33lHYZ74rnqJc1jroyko3RuyXL2WnFppo5pnBVQhP0yc1w/wBsuJiLUN5kxwoweFA7k0JPqN1EUlby0xtz3x7VuaHoqR4k2YHbPf3NTpBFPmqtdj0rwdNZR6Ba6fDcxPcQJ+9jDDcpJJ5H410BryLT7aXS/Fk2rRNnCqoHr/eH6CvV7a6iu7dJomBVhnGensa6op8ikck1aTR//9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-59.png', linkedinUrl: '/in/gary-mason-549d3828f5', jobTitle: 'Theatre director', }, @@ -3595,7 +3595,7 @@ export const peopleDemo = [ city: 'New Craigburgh', email: 'david.young@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0CkxS0UgErk/EHxB0fQ98Mb/bbtTgxQkYU/7TdB+prT8Uaw2jaM8kKeZdTN5NvH/edun4Dr+Fef6f8OLWaFWvLqV52+ZyvC5qJ1FDc1p0pT2Ibn4w6g0n+i6baRp6SOzn8xitLSPi4k06xatp6xKxx5tu27H/AAE/41df4b6G0WBHIGHcNWBffDWBQxt7xlI5G5azWIiavCzPVtP1Gz1W1FzY3CTxHjch6H0I7GrWK+cLa91Xwjq26K4lilRuQCdrD3HQive/Dmtw+ItDg1GJdpcbZEz91x1Fbp3OZqxqUUtJQI5HxJm48SWUJGUt4GlA/wBpjtz+Sn860bVVWMYIOK5n4kLLDdW88bzKrw7CIfvMQxwP1rN8EjUPO8q4Mq27xmQGQ5I+tcleN3c78NK0Uj0BpUUcuAfc1QvZF2cd+9edeIdP1H+1BII5po88HzCO9bOnC+jPlOs2xcja7bh9VNYuGl7nRzu9rHI+LGe5u3JHIJXHtXWfB27kA1OxLExAJMoPY8g/0/KsDxnaMt5bPHw0g5/Cuj+ENm6Pq9w6OufLjUsuM9ScfpXZSfuo8+urSZ6fQKKUVqYHP6/5L38EUyAjyyQT9awn1nTNLe4jclXVQAqLng+gHWtvxbERDbXI/gYo2PQ8/wBK4O41/ToLnM8Eksvbauce3SuOrFubPSw8l7NWOz0y7s9Ti3xncB0LKR/On3ckFuDsUbj3rB0rxBDdBEhhmUEnAliK4/Grd829jzWElZ2OhNGRdWyXl6k5CuYFYqrfdJNdJ4WhmOpm4G9Ea32zxs2cODxjt61z9rN/xM4o/KaQyuEQL/ePTivQtNsBZQnc26V+Xb+grelBuSfRHNWqRjBrqy5RRS12HnGfrdo17pFxFGMybdyD1I5xXAW9lLKqtBcLAQOQR1FenivJvFk0+n6zeNb8L5pyo6c81jWjezOrDVHG6Npl+zW21pg7HnOayL3URHDy25z0A6muY/tG/vsqMqo4JzzWxp2kzSlJJSdueOeTXM4Jas6edy2Os8GWnm6i08qgvHHuHsScfyzXdYrhtA1FNM1VbeSIlLthEHH8DAEjPtXcmuuj8BxV1aZ//9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-60.png', linkedinUrl: '/in/david-young-ad2e589cdb', jobTitle: 'Medical illustrator', }, @@ -3605,7 +3605,7 @@ export const peopleDemo = [ city: 'Alexshire', email: 'jennifer.lewis@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1rFGKWkpDA8VzuoeMtKsZGQO0xTO9ohlV/Gua+JviqeyMOg6aWN1cDdLs+8F7L+NcppPg7V7gCW9uPJjbkp1b6HHFY1KvKbU6Tkdk3xJFxdmPT7IyJ2MrbSfwrZ07xpa3Uqw3kD2krdCxyp/GuFuPA1wN8tveqCTnyymRWDdveaZKIpo9rL12klGH07Vj7dt6M2eHSWqPflKuoZWDKeQR3pa848F+KT5i2szkwOcDJ+4a9IrphNTRzTg4uwU1mCKXY4VRk0tZ+uXAtNDvZycBIWP6VTdiUjyzREOu+MtU124G4rJ5cKnnb7/gOK7lCoXG7NeSaPqbWvh+7lSOaSSW7KosbFeSAc5FdH4Ovbu8fyp1mVWUuPNYtj8686rFu7Z6lJxskdyzLjhgDXK+J9MF7ZyYJWUDKMPWsLxPLfLdM8CTyheQA7BcD0A71NpGoXNynkXFtJEwHBDEq3Hv3qFFpcxo2m+U5zQ7ySDUBGxAJyCR0yO/5/zr3vQL8ajo0E2csBtb6ivnO8kaz8Rzx4IG/cPY4r1/4X6n9rsLi3JzjDgfzrrpu0l5nBVV4vyPQK5rx55n/CHX4i67OfpnmulqrqFql7p1xbSDKyxspH1FdDV0c6dmeTfDyG3PhjbIgd5JnZ8jpzj+ldG1xY2Usq7ljIjzwO3c1zfhnbBazWkfEsM7bxjGQeh/Sr17qWnKwSSJ5ZF4LKpJHtmvNndyZ69KK5UamnTWt5Hw6SKQCGU5BFPu/IhQ7UAx6Vk2OqWbt5cMbxuTwGQirl4C6cmsnpoa2PM/EcW/XDMBhWwpb0POK6X4YXz2XiaO3b7sqlCP5GsXWb7S4p545ZA12DhUweOmP/19q1fhhaS3fiOCYqSsYZ2OOgPQV2QvZHBVtdnulFFFdpwHhur3Z8N+PbnzQUt5HZHOOik5Vvp0rpVtYrlQwlUZHBB6itXx/wCFU1aOPUUCiSIAS54yv+c/pXCeFXItLq18xyLa4KoWPRSMgVw1qdtT0cNVex1S26Wy8MDn0qC5n/dkLyTTEV2O1zn8akMQBxXI0djdzyDWxv8AFE4PBVx/KvdPhhZQ2uiSnA+0O4ZvXbjj+tcFqPhG2vtaW4JdXkYEgHg4/wDrCt7Q9R1HRr9mW1keEKFLRneMeuOvb3rthVXvI//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-61.png', linkedinUrl: '/in/jennifer-lewis-008f8dc7e6', jobTitle: 'Teaching laboratory technician', }, @@ -3615,7 +3615,7 @@ export const peopleDemo = [ city: 'East Taylor', email: 'amanda.carson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDiW5NMPFPcc0w5NZljCyopZjgDqTVUXzzAm2AwvJZ+mKqahKZ7kWy/cTkk9zXd6D8PjcWcUmoOI9/zeUg5A9z61nUqKKNadJzOLOoyhgTPwOqquamF/NEFkEokQ+q4xXqX/CvdKWE+XE2SOuelcV4l8JPosLTW7sydwRWPtU2b+waVyvaanG5VWOxj0z0NbMMwc7Tgj3riIAZIcj51HBHQrW7aXLJtQnJAHPqK1T6GLXVETcfSoi2OlTP3qBlrYxGeHbNdQ8Z20ZGVjbeR67R/jXudrEURcgGvDdFQ2euSyeSZvMhfYoJBzkelel+D7nUHnktLmOVYQCVZ88Ee56iuKum5XO/DNKJ2oH7vqoHpmsvVbSC8tZIJkDK4wRXJa1BfWupmaK2lmGQeHPzZOPWug097i5hHmW0sDf3WOR+FYuNlc3T1seM63YHRtXljjY+XkgZ4NR213lQeu3+VdZ8StOWGWG92ko/yPj17GuEtmMb8HdG3eumD5opnJUXLNo6JzyaiPJp7jmmYrqOM6TwPHE+tyeaAcQnGfcivRYmtrUSnfFHgBQCQK8r8OXJtNbgbOA/yH8f/AK9djdX+gi/J1CVC4ABic5B+o9ea4q6fOelhbOnY62P7PckEhSVODnmpJ7iK3jIQDp1rJsdQ0u8jRNNmiwOgQ9vpUk8fmfLk471zydtDosjB1izj1u3aGcHy87hjr+Fef+IfDseh6ULiaUpKzBY4gOSSBn8ua9Jv5ZrcFrZULxgsAw4wK8S1rWr7W9Sae+m8zaSqKOFQegFbYeLb8jDETjFbas9JkTTpeloufpiqF1pVu/8AqCY367TyKsR3ci4ZQpH0qVZUlO5l2nuRWilJHK4pnNkSW0wJBV0bI+or0DTIDq9vFeRPEhYfNuXPPeud1FI5IB+6DOejegqtpOo39hJ5Vsdysc7D0q6kXOPMtx0Kvsp2uemxW4tYxkJu/vAVXnu1jUjILHoK5ttZvpgYzIoIO1to7+la+l2DPtmnJOfXrXFJWep3c99SdrVmsZpHHzOpH4V4da+HL3UPElxptuPmjkYO7DhVz1NfQtwVEIQYyeAKq2ukW8W7yUCvKd0jgcmuvBxbbfQ48XIAABWS6n//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-62.png', linkedinUrl: '/in/amanda-carson-8e728fa39a', jobTitle: 'Product/process development scientist', }, @@ -3625,7 +3625,7 @@ export const peopleDemo = [ city: 'Port Matthewtown', email: 'jeffrey.valentine@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0zFQ3N1DZ27zzuEjUck1LnA5ryfxbrF7PI4GXLv8Auog2Nq5wOlRKVhxjc6u/8bwwwSPbpjbwC/X8q4qXxu13eGaa7kVwf3Y3EBfw/CtTS/ApurWJr2ZwzDLKDn9TWu3w60YJh4mZz/EWNc7qq51Kg7EFl41uHkRi8c8GM9QCR9frXVaRrlrq6MImAlXloyeR7/SuHufh3a28X7iWXCkkLu4rn9KudQ8M+MLczl2tnO3cvQoex/SqhVu7EVKLSue10GmxyLLEsiHKsAQfanGug5irqbsmlXbIcMsLkH8DXmGkwNcyfaLlACZAyA/pXqkzRrBI0xURBTvLdMd6810S3k/tjyJifk3MozwQDwRWNVpG9GLbO7tXAC44wBVqSRSOHya4nW5LhA6iG6mVVyEh4x/9es3w+uof2gsZNykbgOweQttHoa5OXS5331segzY2YY4zXD6+kKv+8xtJIB9Caq+MbvU4tQe1i+0GGMBiYfvHP/66yZGll0+WMtcboyrET8kHcOc96qMdmTUlo0etaKnlaLZJknEK8n6VeJqC3UJbRKOgRQPyqQmu88wivIBdWM1uTgSIVrklg26iLwAKUHkquOSuOv55rsgeKwdUtmt2R1VfKLcnuK568G/eR1YaoknFlyOOK7g+bA9feqbTadYu6K8UYXAZmIAyewpkbHymKsRgZxWJf6hpDRCO4UyMhPIiLHPc5xXLFXO65e1C506fWQrSxuJFAYA9D2qpq1naRW0kCdHUjPpWIs+jJdZgBEjDG50K7voTWlFDcX16kMQ3tjOCccVXK7ik0lqd3axiCzgiBJCRquT3wMVKaavCgH07UpPFegeQ9x4rD1jVtMaX+ymu4xfMQVg53Eev5VsTTx21u80hAVBmvN71k/tyDVJU3Txsx3d8NwRUzTcXYqnZSTZr/aXtpBDIwXPRj3FXJEaW3KxyqnGA3pVa5S31K0BVwysOGHUGsC9s9UtIQbW5EqD+FuCK89PU9TVbF27tnhJeacSEdCe1bfhSylCyX84I8wbYs/3e5rz6aTUXcrdSYwMkA9q9N8N65p2raJZyWkyLmML5TMAwIGMYrpoxvK5y4io7W7m1QelFQ3V3DZ2zzzuFjQZYAANdJxH/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-63.png', linkedinUrl: '/in/jeffrey-valentine-ccb2756410', jobTitle: 'Surveyor, hydrographic', }, @@ -3635,7 +3635,7 @@ export const peopleDemo = [ city: 'North Rodney', email: 'helen.gordon@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwCq1M5zUxWmhOc9q8c9UEBPRSx7AdTU08X2eza4nhHyjhTk4/SotPXz5SZT1/hzjArSn8OTalGNgMI9d56fSrRNm9jlrXUpXud5VWjJHy7eBW3cybIlmSALn72BVtPDK2DFlkLMOjbapao7CDacxuOuO9Ddw5HEbFcxXH3G+bupqQLmuTS6liugwOWU5BHQiutgdZ4ElXo6g1DVhp3FK0h+VGb0UmpSKaULxuo4JUikiuhJ4Q0793NdynfJI2AT2ArtUysYHb2rhIFuLfQoxFDJIzOw+Q8D36itXw7cahIFjufMCldymTqvsa05eppBqyR0E24KePzrmtWsROjdj2qprdzqbys0YnaFP4Y/4v1p1q9zOBHLFIrr3Y8Glyu1ym09DkJIY4pXi43A8+xro9JQjTY1I+6SP1rF1awlGth4hkS4DCuk02IJYRKGD4H3h35pSMOVpsU0LxS44pBUjN/SGjWxWFwMDoParMkkMcrqGRAqE+lZOnyFxt6FOPwpNQvNH3hL1/nwVyoOR6jI+lUtTohZpWL2mSRXEbqSpK9jzkUX0sduh2KAelZ+m3mkopjsGRR2UcGpL0E5JPah6aDsjGMDSTCUE7wc57AVfiRY4wqjAHaseC8uZPEZs4yv2WOHfJ8vOecc/lW0BSZjOSeiK3akp+2muVRcswUepOKDMmtZjBLuHQjBrSSBbqNWWQIfWuYl1q0hkEaMZpCwXCdAfrVzSLl9Usp3VjHLDO8RweMDBH86v2ckuZlU6y5uVGs1slr87OGPriqdzM03yqcknJPpULWuoO+JyNg9DVyG1CJk9ahm97mJZX1hHrl1YqrresAzFhwwAGADWxnJrmL7TS/i2K4t2ZZ3QR4HqTwfyrr1tJQW3IVC8kn/ABrSUPdTe80z/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-64.png', linkedinUrl: '/in/helen-gordon-71ec22bf50', jobTitle: 'Engineer, communications', }, @@ -3645,7 +3645,7 @@ export const peopleDemo = [ city: 'Danielleport', email: 'cameron.lopez@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-65.png', linkedinUrl: '/in/cameron-lopez-e66f1d22d8', jobTitle: 'Engineer, production', }, @@ -3655,7 +3655,7 @@ export const peopleDemo = [ city: 'Coleview', email: 'troy.gray@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDlDUc00dvGZJXCqO9TEVzfiCYm6WIliFXIAqC0ixca4zEJaxgEn70np7CqsurzuyxeaVkz1HarWj+HNR1SAXCpHGjcKWJGR9K1T8O7+UBjPDuHQ85rN1Ip2bNVSm1dI56z1nUI7gmaUSAjhX6fpW7a6kly/luAsnbB4NLP8O9QaNWa5j3rxgegrDmtL7QLsLcJuKDKPnIxQpxezFKnKKu0dMRTlBzUVrcJd2yTp0YflVhRzWhmNK1zF3bPcatNkHl8Z9q6srk4FU4LBv8AhJlikjdQzKTkYz/nFRN2RVOPMztdHt0t7CBMYwoAFbKb8A4/Kue1KIpHnZPJhSVjhOOnvTdFkmt5o1ZplSRQxV5N23PY+9cXLpc9NSs+U6Zstk7fxriPGtnHLYH5RuB4PvWj4jvbkybbc3BVCARA+1jn04qjfWskukXiPJK4RPuy4LKw9COopxVmmTUd04nP6LD5ekwjnPOfzrQVeabbQtBaxI4wdoPPvVhRzXctjzHuNRgkyMegYE/nXSyQxzS27Agm1IHTkll/lzXMEZrf0u+FxbCCRSZY+Q/qtY14tq6OnDTSvF9ToYoE2iTgnpg96z71okuFRmjjYsF5woyew9TWla8RqTyRWRqF/ZxS4uF8xt2dqoWI+p7VypX0O4sokY1Jk8yNyQMYOefSnalBEbdgQBvGGAFUbG9sri5YWw2SDGVdCh/DNXdSnWDE0m7aCMgU7O9hNq2pzGpbBeuqdBgVVXrTp5DNcSSf3mJpinmu+Kskjy5y5pNjQM1qaOpW7BIO1gVJxUWm6bNqF2tvEPdmPRR611mo+GpVvrbVLRi0CRCOaEdsAAMB9OtTV+Bjo/GhkMjxHy2IGOalKxvHjHPYj0pZrQXMYIODjg1RGman0hlRlHTJrgR6exYkiWFQcAkdCaxNcvDLsiHT7xIrQeyvkwLlx8x6Kc1kTQPfajdQQIS9siMV9VOcEfiDWtKzmYV2+RmbtoC4NSyRvE2x1ZSOxGJx55//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-66.png', linkedinUrl: '/in/troy-gray-756cd40db4', jobTitle: 'Health and safety inspector', }, @@ -3665,7 +3665,7 @@ export const peopleDemo = [ city: 'Lake Brooke', email: 'tonya.payne@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-67.png', linkedinUrl: '/in/tonya-payne-5e0b7eec25', jobTitle: 'Training and development officer', }, @@ -3675,7 +3675,7 @@ export const peopleDemo = [ city: 'Jacobberg', email: 'april.williams@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDz5qFHfNS7M024K20IZiAT90H+ZpVJ8qKhDmZraXYWsxBnYnvis/WdRit5TBbeUjL2AyR9ao/2jIkLurFVb5R2Ln/D2qQ6C01vC1kjvO/MssnT6AVyXd7yZ1KOloom0y6gvSYJIwJOu4HmllQoxAPAqFtBv9Oxeo26SMgkDoR6fSq91qK+d5sYIVj8yHt9K0hNp6O6InT01VmWSKADmlUh1DKcgjIIp4Wuo5RLuYW6rkcsf0FZbyG4laSRsY9s1a17KSRN/Aqk8etZFtm7v4LYcmSQAj05rmqK8rnTT+Gxu6Rol5reoRkRkWyHr2r1KHSY7eAKMA47Vzl5PJpVkLa2tZJCV52cAYH86j8PNqDXsUcrSiOQBmDMTtB7HPQ1zO7VzshaLsb95pqyW8iDGWUjivMdS0mWzmbzo22N1PvXYeLry7tbww24mZFxnyyR/KsfWZnuvDV3GyyJPAAWDNu7jkGqgmtSalndGHp7kNJASfl5XPpWgBWLpc7TXUe45JQg1vBa7aex589yh4lVvIhcdMlT9eMVS8LQ51u2cjIR8t+H/wBc1ua3a+fpjABiQc/KM4rK8PavBpF41vdwsfOkXbIv8JPHPtWdVPWxrRaurns1s8Fxb7GRffI4qCaeysp1jBSNeNzsQMkngCo7Zflyp461UutQ02QeVLaS3Lq2fliJAP16VwpX0PT06E8rWd3qsyBo3VuR3wazPENrbx6TeRIvLQsBge1RwXdglwVSCWBzjBlUgnHvTdb1G3s7Jrm7J8sfLgDJJPQCqs72JlZJ3PNNBjc37cECMEH610+KoaTZtEj3DqQ8x3EVo7a9GGx5Ety3E5BrkNas7hr8SNbOFEoJkA4PI712ttayzyrFFGzuxwFUZNdC/he7t0gN2EEcoO5euCD09PelUaSux0027IWJ2ijVCccdasmGGeHDz7R2AqSe1DIBWTNC8LkEECvNR6uxLNbxQqQkm8e9cj4ja51DUYNPiG23jXzJXI6k5AH5D9a6pYiYxI3c9KyblfNlndQT5bBX46ZGQfof6VvRSczDESagZ4QKoUdAMUmKnIrcecf/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-68.png', linkedinUrl: '/in/april-williams-f4fa095134', jobTitle: 'Tourist information centre manager', }, @@ -3685,7 +3685,7 @@ export const peopleDemo = [ city: 'New Jonathanview', email: 'gregory.baker@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-69.png', linkedinUrl: '/in/gregory-baker-58cbfbde95', jobTitle: 'Pharmacist, community', }, @@ -3695,7 +3695,7 @@ export const peopleDemo = [ city: 'Loganborough', email: 'bobby.cummings@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDMwazdZ1Q6dGsca7p5B8ueij1rYCVx3iaQ/wBsLHyAkY/HNYtmiRmm9kkfdMzyckZY/rUF3fNFKFHlsgxlNnX6V0Oj+GW1BEkeTYDyBiugk8C3N0pQPEFIwSRmp5lc19nJo4ieVhaNKpVkyDtbkr6VY0zV3QRtEuHDHzI/7w9a7y0+GsUAAkmaQEYJxisvWfDH9kNG8Kjy9+GfHKijmQ/Zu1y5G6zRLImQGHQ9qXbVXRnL6eFdtzoxUn1q/tqzBjgtcb4kAj15S/IdEx7Cu1A4rn9dtPtV9azFQPLlEfX7wOD/AI1MnYuEW9joNHQLEgUYwBgV2VkSVycV5zcy31nj7KJNxBKhcc8e9aWja5rUc9tDeRj9/gg4wVB7H3rLle51qS+E9EWUkcdKwPEjKunTEqGCqSQfSsrxDrer6fcPFZxbyo+YAZ6+nrTYm1C7huIb0PnyjuJAwcjsRTs9wbWxg6HEq2JZTne5atErUkVlHY2VtDGqhfLByDncTyT+tBFarVHHNOLsxoHFUNQh37ZDyI/mx78c1oLRJEsiFWGc0SVxwnyu5bsDb3EYSZQ31qSaGNNWtI4VA+YE4rH09yrLzz0xUl7PbT6hEZL37PJEc/Kxz7ZxWKR2p3R2slrbTXjrOils5Ukc0y/EUEDIgAJ4rH0y5tCSDeJPOxBOZPmB9s/0q3q0mIyQecjFPyCTSV2Zl+VFwI06RjH49aqGnkd6Ya2SsrHBKXNJsatQX2pWelxLNezCKNm2gkE8/hRc3cFjD5k8gVew7n6VxviDU11R1TysQp0Vu/ua0hByIckjoRcbGWVT+7c7kbFbtpC94EkWREbs2M1y+mahbanZm2YhJgPuHv7irtgLuGQRRyqpJwN/T865WmnZndGS3R2PktbQ/vWjkYc7sAGqN3ctOy8/J1HvUIs71pQlzKpB5Kx+lZHiT7Ra67pUkDYQq8bL2xgH+lVBXkkTVk3Fs1SaYTWedXhWXy5UZD/e6iriyLIu5GDD1BzW8oOO5xoAAAAknsf/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-70.png', linkedinUrl: '/in/bobby-cummings-18e64e1c24', jobTitle: 'Mechanical engineer', }, @@ -3705,7 +3705,7 @@ export const peopleDemo = [ city: 'Villegasberg', email: 'melissa.jackson@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-71.png', linkedinUrl: '/in/melissa-jackson-36c2e59b76', jobTitle: 'Pharmacologist', }, @@ -3715,7 +3715,7 @@ export const peopleDemo = [ city: 'Bestfort', email: 'lance.norman@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-72.png', linkedinUrl: '/in/lance-norman-7b07c0a723', jobTitle: 'Furniture conservator/restorer', }, @@ -3725,7 +3725,7 @@ export const peopleDemo = [ city: 'Tinaview', email: 'amy.roberts@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDn2ahfmOBUferUEeFL9SO1TJ8quxpXdkTQ2zMOcAe9LPdWdoCpLNJxt2kFT6062S612f7DpxRJc/Mdudq+pPQV2em/DO0ijEt5KZJTzx0rldSU9jrVKMVqcrp2oWGoAxJDJFKON3UE06bET+XINrdsnrXSXnw4tY2MtlPNC/XKt3rhvE1tqWlN/pA3rnHmAcN+HY1KlOLG4RcS4xw1SxSYNY+maiLpAjNlu2a0lODXXGXMjklHlZnD71F7MUsDCnDykgkHnHtTtvNYmrTPHqCop5IBHsKmrqrFUviPWfhzo0el6CspX9/cHzJG9B2H5fzrvFkULjdk155c3DWOk2kJiuGRrdWPkgk8LzjGOfxqx4XW+e6SNxOLWQbgZcgjI6HJPNYJs7OW521xKuwjcPzrk/ENpDe2csU0YZHGB/jWJ4lN4bt5DHcy20f/ADxySQD2AIosJppW8nyZUCgfeBB5HcZP6VMtVcpRtoeZFjp+pvC2QyN8r9j6GuugYSRq46MARXGeJN1rrV5CR80cpK/7p5rq9Dl+0aRbyDn5cflW9M46gzHPFULjS5LrVYZgrMhXDbfatXy6u6dIsF5E78JnDfQ8GtJq60M6bSkrnpenPbT2EUciKVCADP0qvd6zYaXexxsCFIbYFXqcc1Uswv3YXDRDhSDnIqC91dRi2XSbm4XkFtmB78muRN7HpRjd6FjRtRs9QEigkqSeHQjHPTmp7xre3HyIo+lY9pq4kkNu2mXFsxPBCZX657VNdRlshmJx1pPTQpxs9Tz3xDoT6nr08yLtzEHUkcMR1FW/DtoYNIjVu7MQMdBmtNdc06TU5dNiEkl6hIf5MKigev49qtRxDAVQAB0FdFJPdnFXcdkZv2elEGK1vswpptq3OUn0i6MMZhY4Gcg/zroTBbXcSl5iMcjB5rnrWDEqkDPPT1qzc2ksPzRs2z0z0rlqxSlc7aE3y27GkYYLVSUmLZ9azZ5S52Iclj+VU0MkjYJb8a0ILYrgkc1kb3OK0jQrx/Fmoak6mO3ErqpPV+35V2EVrip7Gzn3XrNIzxeeoiDHp8uWA9s4/WteHTldAQxyeoNdkF7qZ51T4mf/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-73.png', linkedinUrl: '/in/amy-roberts-b98996c9ef', jobTitle: 'Cytogeneticist', }, @@ -3735,7 +3735,7 @@ export const peopleDemo = [ city: 'Rossmouth', email: 'kaitlyn.kelly@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-74.png', linkedinUrl: '/in/kaitlyn-kelly-e6d2be7a00', jobTitle: 'Commercial/residential surveyor', }, @@ -3745,7 +3745,7 @@ export const peopleDemo = [ city: 'Mitchellland', email: 'alan.perez@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-75.png', linkedinUrl: '/in/alan-perez-6a584f8e83', jobTitle: 'Advertising copywriter', }, @@ -3755,7 +3755,7 @@ export const peopleDemo = [ city: 'Evanmouth', email: 'kaylee.garrett@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDqOtFLjFAFebc7bFTUtVstHtDc306xR9BnksfQDvXn2p/FK5kRo9Mso4ucCWU7jj1A6Vk+Jr+78U+KDZW/zQ28jJEvYYOC36VqWvw/UorXFxucjkKOK2SjFXkR70vhMCXx34lZEVtR2BSfmVFBP14rR0z4l6nagLfxR3iZ5bGx8fhx+lbMvw/sWj4eQPjgg9K5LWvB13pm6SM+bH696tOnLQThUjqet6Nrlhr9kLiykyBw8bcMh9CKvkV4L4d1iXQtbguQWEYYLMo/iTuK98V0kRXRgysAVI7g1lUhysqEuZEm6kYjY3OBg8+lGKNoYbSMg8GsyzzDwlaK8t1eFR5jzMoPoM138UZ2g5rz9nhsYbiAQzTA3ExREYrwGPJP4VueHJ5t0cJDiN13gMxO32NXNX94um7JI6Z1IU84FZWoKskJUgHNYevSyNM7+U8ojGQocjIz0GKdp9z56CMW0lvIACRnKnI/nS5dLl82tjzjV4vJ1CUKMDca9l8GXTXfg/TpG+8sflnPfaSP6V5n4ztRHqKOowZE5wOpzXovgO3ktvB9qsilWZnbBGMAsa1m7wTORK02jpw3FKGNMz707PvWJocvFaW63M0DJnZK5Gfck/1p4ubKzvJEJ2ER5GFpNRDw6zKUH3wGH5f/AFqzvt0plbba78HlnOPyppXZ0R1SsatlNa3nyspJPILIR+BzVidIYIztUA+1Z0F/IzbHtHTP8S8rVi7BaPk9qmWhRgy2yXepRXEiq3lZKhhXYaNbm304A9HcsB6CuXs5d2sQ2KxF3lXJbcAEUHn8a7YAIoVeFAwBVamM5LZCcUCjFNzg0WMrmdrNjLPGtxbqWkjGCo6ke1ZVi9sf9Z+I9K62JufeuBuFSfU52iG2NpW2j8aHY0hJ7G3NcW0a5RhiqM12ZEKR8k9TSrpgZAwP1zU62qRRkgcAVDZqiPRdLSTUn1CXJ8tBGg9CDkmumLVz2kPOl0Y15jkY5X0461vjWZ//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-76.png', linkedinUrl: '/in/kaylee-garrett-5c56311f4e', jobTitle: 'Chief Operating Officer', }, @@ -3765,7 +3765,7 @@ export const peopleDemo = [ city: 'Lake Melissamouth', email: 'deanna.ball@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-77.png', linkedinUrl: '/in/deanna-ball-cac5d9cf3c', jobTitle: 'Nurse, learning disability', }, @@ -3775,7 +3775,7 @@ export const peopleDemo = [ city: 'West Timothy', email: 'michele.crawford@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwCL5nfC81at4xJII418z+856Cs1mklk8tMrCv8ArGHVj/dFaEDYG0uIkHLHOcf4muSrWbdkdFOlZXZa1HUIrCDyo1knmI4ih6D6ntXLz6pqYQvcRrasv+rIl3ZHoR1/Gt5NSgkuWSNS0cQ+WMHG5vc1UXwnf6tcvc3Mqxq5yFUdvxrKM9Tb2d0U9N1qO8ARmXzV4btirzyZNIfDEukl9gE0Tc7ejA+xrOivBHdG2lYnJ+Vm4P0NbU6mtjKrSaVzXtW/eCtePGKw4pArVoxT5Wuk5jCndozt+9KfmCA8J7mqM90qHy/P5PJA5JPvjtSX8M/3AwBblsHt6n1qLwxYnUNXdv8Alint1NeZY9JLWx0vhbSJHJuJEYAnI3dT7mu4VNihelcjqupXumRNFa2MsoxjeOg/DjmsfTJdca9jLSzIkqhymchAfUE8GrjHS5d1flO+uojJGxyB9a8w8QwGPXbcJw8gyR9DXQeLtQ1jT57WysgxaUAtKP4c8VzwM93qFpJPDIrpG+5mbOcHrn0qlHqRUkrWNAN81X4X+XrWay7WwfrVuBsiu480dPYSXSSQqB5pPGf7pNWtHsf7KlchQFOOB2qPVndLSS6tpCkydGH8qdol3cXVlFLdMD5qAgAYA7EV50otNo9SnUUkjrUmt7uDy3jBB6hulMWKztJBHFGPMcZ4HYVRgiKnC/hUd5NpBieK7vVSXo21yHHsMc0K7NrIuarbQXD2zShWUrjnqDXO6o1uksZjQDYpUAVDFNp6yNHb37TPj92HJyPbnrUUwMpZj1xzWkF7yuYV3aDXUqE73LHqatW4psVuD1q/BAAOK7Tyxs8QmQRyg+UOWwOtXrbTfJsPKTI2ElfYHnFdbpuiI2mol5CsgZt21hnHpTrvRwhZrdjz1Rv8a5qlKXQ66NWKepxsV+VfyWfY/TmrT2pmhwk0aHH38c1X1awgecpOrRt69CK5iVtQt7gwm5LRA/Kc81zpanbz21Nm6ga2z5t0JT2PepZEyPTAwK5i11eVtal06RQ8O5Q79WUjDV2t3p86L5oTcnXctddKPVnDiKjkzMWPack1chwKrhWY4FX7e2+XJAAANbnKf//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-78.png', linkedinUrl: '/in/michele-crawford-21fd4da56c', jobTitle: 'Education officer, environmental', }, @@ -3785,7 +3785,7 @@ export const peopleDemo = [ city: 'Gomezshire', email: 'tommy.brown@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1KilqG8uorKynup22xQo0jn0AGTQBheKvF9h4Vs1luW3yucJEv3j7/QV5h/wuvWBLLjT7RkJ/dghhtHvzzWHcJf8Aj/xLc3UsjLbeYQrN/AmeFA+ldLH8N9L2Lhpt3cls5rGVaMXZm0KE5q6Kw+M2teeJPsdp5ZHMTA4H45zXc+EviVp2vxrBfmKxvi21UZvlk/3Sf5GuauPh3pEsICxyI4H3w3NcfrvgmfSYmvLGZpBFyUYc49qUa8W7Dlh5xVz6Oorzj4VeMbvXrefTL9/NmtYw8cp+8yZxg+pHrXpFbmAVyfxJu5LPwHqLRPsaRViyOuGYAj8q6yuM+KkJl8B3IHJEsZHP+1SYI4zwdapBo8O0cv8AMfxrt4EygwQfpXm19amJII3kuhDHEBHFa8EkDkk1peE3mhulhVrkRvz++bJ/GvOlG95XPUjK1o2O7bgcsFz61jauqmzlGM5U/wAq5rxPE0uoHzBdyKnzDyXwR9Kk0nzS4CT3hjI+eG7GSPcGlyq1xuTvaxgeAZ2sPiFpwi4jlZ4iM4yCDx/L8q+hK8P8FaSF+KhyB5NsXddx7lTgfX5q9xr0IO6PMmrMK5/xrZfbvDE8XHysr/l/+uugqtqFob7T5rYNtMi4DHsetOavFpBB2kmzgrGG3uIgWVScd6IZbGLV0iEkUeASAeC3/wBaqrxT6bcT2rEGSIkcdDWW0El7JulhnJXo2FUD3Ga85Rd7M9VSulY6KO5sLm6ZfMjlBYruXnaferN3awQRkoAOO1cuEnsiWijmUHg5UMPxxW1LI8tshJwSuTSlGwc3cZ4ds1fXYn25Z7kS7gOm0Yx+lelmsLQdDawCXEzqzlPlUD7ueufet2u6jFxjqefiJqUlYSloqK4uIraIySMAAOBnk/StjA4jx1EtrfxXKZBmT5/qvH8qwkltrmPZK5IPPymn3Or6h4gv7j7dEkcUMzxQIB/CDjJ/KsxdFuPOYW9xsYdFI4rz5yi5s9GnGSgjXa5tYVMcLkYHJaiwl+139tAjbkaVVJ/GsmDR72SZjdOpXPQDrWm1tLaWxNm3lTqMxuOobsai6TLtJo9WPWkrlPBGv32q6Sh1XAuCzKrlQu7acc9s11dekmmro8ySAAAAAGnY/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-79.png', linkedinUrl: '/in/tommy-brown-a3313774fb', jobTitle: 'Civil engineer, consulting', }, @@ -3795,7 +3795,7 @@ export const peopleDemo = [ city: 'North Amanda', email: 'mary.smith@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-80.png', linkedinUrl: '/in/mary-smith-e7451d73fb', jobTitle: 'Commercial/residential surveyor', }, @@ -3805,7 +3805,7 @@ export const peopleDemo = [ city: 'Lake Lauraland', email: 'danielle.dunn@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-81.png', linkedinUrl: '/in/danielle-dunn-afadb3743f', jobTitle: 'Higher education lecturer', }, @@ -3815,7 +3815,7 @@ export const peopleDemo = [ city: 'Stephenview', email: 'daniel.ward@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0ntSZpe1Vr69g02wnvbhtsMCF3PsKYitrOuad4fsDealcCGLOF4yzH0A7mvMtU+Nbebs0nSlKA8vdMckf7q9PzrHmh1P4jarJqd3L9ns4j5cEQyQo9B7+p71cj+G9sv37tzz2WsZVop2N4UJyVySx+Nd6tyo1DSoGhJ+YwMysPpnINeq6NrVjr+mx3+ny+ZC/HPDKe4I7GvKW+G9gY8CeXd3PFUWtr7wHcxanpVxI0GQtxCx4YZ7j0/lRGtFuw5UJxVz3SlFUNH1W21rSrfUbVsxTLuA7qe4PuDxV7vWxgL2riPinLJH4NKISBJcIre45P9BXbVx3xKWOXwsYCf3xlV41xydv3v0NTJ2Q4pt2Rz3hdBDoltEox8ueK6AAbfvZNcTfPcWdrDBbyTJtjGfKXJ4HrRod5qDzJHNNIytz+8HNcDX2j04ytaJ2xYYI3YrnPE5V9HuYyM5WsrWrzUluHFvNKsanJEY5PtU1jJLdxNDdPK4ZcESrgjI9qaVtQk76HTfCWd38LXEDD5ILpgn0IB/nXfCuC+F4W20q6tHIEzSmYL/sYCg/mK72u6LujzZJp6i1zfjKx+06bFMqkvE5UAejDFdIKhvLdby0kgYlQ4xkdqU480Wh05ck1I8+hjgmhw+AfU1FA9pDfqrPGgBOAeC3HPFSX1o9hfTWxbOw9cYyOuax5nM/yvZOwHRyQPyrgs72PVTTSaNL/RJbxwHjYMx+7zg+9TzxwwRYVVye4FYlvJ9myq2brkgFhhvzxWtFE11PDEuSZGCj8TQ072E3Zam14JshFLdTjoqCJfcE55rsaqaZpkemW5hjcvltxYjGauGu6nFxjZnmVZqc20OC5pDxSF8HAyT7UbHfJ9DiquRZnmerao+p61qKlFX7JL5GFHJA6E/nVRWtpYdsrEj0zW9r+jf2Z4juLxE/cahtfd2EgXBH4gA/nXOX+nxSuXjcxv7Hg159R++7np0vgTRJvtUUpDJwOue1R/2tJpElrexKGIuEQBu4Jwf0NQWellHLzuW7gVowacdZ1awso0ykcyzyn+6qHP6nAoj8SsE/hdz1IMGUMO4oqs7vFOIgM8A49vapFmVvavQTR5jTP//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-82.png', linkedinUrl: '/in/daniel-ward-9eba345b13', jobTitle: 'Corporate treasurer', }, @@ -3825,7 +3825,7 @@ export const peopleDemo = [ city: 'New Allisonberg', email: 'louis.bailey@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1h2VFZ3YKqglmJwAPWvFvG3xVuLiZ7Hw9KYbVcq10B88p/wBn0X36n2ruvihqk+l+CbkwYDXLi3Y/7LZzj6gYr50jie4mjiijO5jjJ70NhFFn7VdXb+ZcSyyOe7MWJ/E1D5xVlQhiQTmuutvBV7NCGSJ846lcZ+lXIPhndSDfLcbHP8IHSsfaxOhUJ9jndE8Wan4cu1ewvJEjDZMRJKN9Vr3TwP4yi8UWDJMwW/iPzpjAZT0Irzmb4aR/Y8LOfNB6kVjwWt94H8V2M6szw7lYkfxDPzA/hVQqxeiJnRlFXZ9F0YoUhlBHQjIorY5zzr4zkjwdAoBObxD7fdavGdC41OFsFnVhtHWvfviBZJqul2+lSRbo7iRmMmcGMqvBHvzXl3hXw/8AYvFEkNyRIYU3ow6MD0NYVKiV0dNOlL3ZdGelWkhaFQR82OQKtgEjNcxfzX8cwitQ4B4yo/Uk9BWTpOqa6955MxkCM2MyAErzXEo6XPQ5tbHdOhcelcP45R/Ksyq5kE4VDjuau+JNR1ezlMNmpOIwxIPPpx71DYxXOqGxjv8Ae3l3sLtvGT94dMdRzWlNapmVZ+60euoGEahvvYGfrS0ppK9A8syPEtk99pEix53od3HXHQ1xItIodSjnjQRSRxeVtHAK5zXpvWuE12x/s/WJXVyY5wHReydiPzBP41y4iH2kduGq6cjLEZW4XgAN396haO2hn8sKplxuYgAYFQQT7Y2JXDAZzWPc3tlfROkpjxuyWZ8HNckVc77pHR3UVu88Rk2fMMc4PNTWVvE+p28LIcBw4xxjbyPwyBXGrPDA/Nys3AGPM3FfpXaeGc3V/wCa+T5cefxPH+Nawi+dGNaS9m7nW02lNJ3r0DyR1cH4n1W11LVJrC0Zzc2GFmYr8oLcgD171l2/xMl1/X4dNsbYWlrIH3SO2ZWwpOBjgZxWB4fu/s+t6np92T9rMpcMx5kHY578YP41jXfuNI6MPH302a0V6xRolkCSDKsCaumF3tQsCRKwGPnHFZ2oadDKTIEHm9Qc4z+NYov9VQlEiO1eNzmuKOuqPQ5nFnQvbGCFjOLf1+QYruvC9m9tpYmmXbLcYfHovb/H8a8ovZ54tFubq7lBYoQqjgbjwP1rqvBfjaG28JRf2wzJHbP9nScAtkADGR7A/pXVQSbcjkxU29D0ekqjp+s6dqsQksb2Gdf9huR+HWrtdAAAAAHScR//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-83.png', linkedinUrl: '/in/louis-bailey-a7c289633b', jobTitle: 'Actuary', }, @@ -3835,7 +3835,7 @@ export const peopleDemo = [ city: 'Port Joseph', email: 'melvin.rosario@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-84.png', linkedinUrl: '/in/melvin-rosario-eeb2165a87', jobTitle: 'Mental health nurse', }, @@ -3845,7 +3845,7 @@ export const peopleDemo = [ city: 'Johnland', email: 'jason.fritz@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-85.png', linkedinUrl: '/in/jason-fritz-998e404fcc', jobTitle: 'Counselling psychologist', }, @@ -3855,7 +3855,7 @@ export const peopleDemo = [ city: 'Port Frederickmouth', email: 'candice.weber@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-86.png', linkedinUrl: '/in/candice-weber-8d1a3aa843', jobTitle: 'Scientific laboratory technician', }, @@ -3865,7 +3865,7 @@ export const peopleDemo = [ city: 'Weeksmouth', email: 'john.jones@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDcC8VxvjLxVJpcsdjYOv2huZW6lB2H1NdxsFeH6gputfvQrbme4b5fctXPBXepZClxJPcu0rM0j5JZhk5PrUZaSOcM8hCA9+30r02x8BwyaTESf9I29RxUY+F08vzy3IyegxmmqqNnRkjzWSaW2AVN2wn14rr/AAr4qezC2VyN8UjjYxPK5612Fn8N7RLN1vPnftjtXNeL/DEemQR3tnkGM4kGOCtJzjJ2D2Ukrnd7A3I5FL5eKoeGrhrzw5YzO25jHgk98HH9K1tvFQZMcB0rxyKAReNZ02crdMAMf7RxXsLM4jJTBfB2g+tcxDo0H/CYpcgq7uhklwOBIAOn503K2hrTpuS5jr7P/VqvpWogYIOa4vVNR1KxLLaRSNwSNqZJqPRNf12W7ihu4MebggleQPf0NYqOlzr5tbHcMGKnnmuL8bbk0S5ZWGVXqfrTvE2u6xYTm2tIGeRVDMVXP5etZkjajqemXUN8rf6vkFQOetNLW4pPRo2vD9qbTw/Ywsu1liGR9ef61pgVHb7vssW85baM8VJ0rU4JKzaIh04qjcYg1KzkQgK3mbh3ycH+lXwMCquoIFiSbHKN19jxSkrmlKfK7dzcijgvIcSKuenIqNoLWGby4FG9MFiB0rItrx40cnPyruGO9Zl1qP2zYYXa3kQ5DZZcn39RWUVfQ7bo6y9hgfUm+0Ku1wNpI71Uv0ht4xHGB8xFcwuqXSXbvf3CXCldoVW4U54I962mkM88Ssc9G/TNNrWwpSsrlsE7Rn9Kdg4pnQ07fgVsee9WNHSszVdUs7ee302Ribm7z5aKM8Dkk+grG1jxva2haDT1FxMODIfuL/jXPaFqzX3i2O6v3DyujRIxGNuegHp0/WtJU3ytsINc6R0UkzWUrRyylRg7GPQj0NdAk73unr9nuo4pNoAYrkVQ1XTvtCBtoOB09RWT9lvLOAm1YqCMbeoFcqaO7WL0N25d7TT3N3dxSy7T0GBUeiSrcSSSNJmQIu2MnkL/AHvoSMfhWPFp97eyL9tlzGTkxgYB+tZPi6eXTtUsLi1leGRo3jJRsEqCCP61pTSlOxlWbcW2ejHnikIGK8zsvHGpWThLgrdRnp5nDfmK6nT/ABnpl6oErtbOe0gyPzFbynGpJn//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-87.png', linkedinUrl: '/in/john-jones-f3a69bf1c7', jobTitle: "Politician's assistant", }, @@ -3875,7 +3875,7 @@ export const peopleDemo = [ city: 'Juliefort', email: 'henry.gonzalez@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-88.png', linkedinUrl: '/in/henry-gonzalez-ed4236ae1a', jobTitle: 'Medical secretary', }, @@ -3885,7 +3885,7 @@ export const peopleDemo = [ city: 'Zunigaside', email: 'kaitlyn.brennan@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1RiFUsSAAMkk9K8l8Z/FJ/OfTvDjjA4kvAM59k9vf8q3/AIq6xPp/h+Kygcx/bWZZXB6RqBkfjkD6ZrwnzS0m1B14A/xrOT6I0jHqzWn13XJ28yfUJ3b1aQ0238R6xZfNaX1xGFbdhZDwauaN4Tu9ZkBLskPdumfpXZQfDuxiCZlkLfxZPWsnVjHQ3VCUlexzeg/EnWdKvkkuriW7ticSRSPnj1Ge9e56NrdlrthHeWUm6N1zgjBHtXjuq/DmEBpbSdw3Xaw4qD4c3mpaJ43j0ne3lzkrJEehwM7h78VcKsZbEVKMoas95xRS0Vqc54r8aL4trdnZh/lit97D0LMf6AVwGg2ou7+OPaWBYDnvXqfxN8KjVtcW6imYTNa7lTbxlCep98iue8AaPsuriW4jIki+UZHQ1hUmkn3OulSk3FvZnoGm28draxxRoFwB0q2yniuf1W/mtVMcNrJKWHUttUfU1h6DeajNdKX82NJfm2lidoz3B6Vxct1c7+az5Ttp0ZoyK4TVsaZ4z0HU0U+YLgI+3uM4/kTV/wAXalqNpLHb2u/DY3FM55qjp9m+sazokMsTp5d9iQlywYAFsg+h21rRi1JMyxDTg0e1g5AI7jNLTVAVQo7DFLXeeUc94t0972xV4/vKdjn/AGCRn+Vc5a26WcrlE27iMj6DFegSqHRlIyCMEV5xDPdf8JDq1ncZMVu6LCduMqRnP51yYinrzI9DC1tFTZtjbPHgqD7EVXEVtbzbEQeYRuOBjAqRMopxWdfXOkmJlvpkLN95c5J9sCuVanfoT3sUMtzFvKNuXHY81c0K1hfWIgqD9wDIPY4x/U1zCXmlyT4tpiz4wu4nI+ma7LwlEWW4uXX5jhAf1P8AStaUX7RIwxDSpO509FJRXoHjiGuX1qzCSpOBhpCa6WeVYIHlfO1VJIHU1y93fy6g670WNF5VQc/mawxE0o26nThoSc+ZbGcLnB8tmAPTmknskuIioCezHgipprJLjrjcOlZkttcxlszbUWuBb3PUTK72C2z5LIx/vE9K9C0i2+w6dHG+N5G5vqa4AW+9D5rFwRgg+ldH4fvZrPTLGO4czRbAuT1z2NdFCS5tTlxalJI62iqseowv1DKffmrCyxuMq6n8a7VJPZnmuAAAAAAAItH/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-89.png', linkedinUrl: '/in/kaitlyn-brennan-3e779378d9', jobTitle: 'Osteopath', }, @@ -3895,7 +3895,7 @@ export const peopleDemo = [ city: 'Gordontown', email: 'jeffrey.shepard@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-90.png', linkedinUrl: '/in/jeffrey-shepard-038f3df4d1', jobTitle: 'Designer, graphic', }, @@ -3905,7 +3905,7 @@ export const peopleDemo = [ city: 'North Kennethfort', email: 'emily.smith@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDXwKQ7VBYkADkk0gzXMePdVk03w+Y422vdEx574xzimJHPeJvH9w8z2ejsIo1JVrjGWf8A3fQe9cXNcXEm6Wa4eV26s7Emqyhm7Ese1atv4e1G6j8xLd2J6Z6VDkluaRg3sjJWd4zwSAeuD1rpPDvii60OdGVzLZsf3kBP6j0NN/4QvUmt3kdAGA6CsUwPbblddrDgikpKWw5QlHdHvtrdQX9pFdWzh4ZV3KRUoUZrzH4barLFqc2mOxMMyGRVzwrDuPqP5V6bmtE7mTVgArzD4nXTNrNna87Y4N4HuxP+Ar1EV5b8TLGf+37a5UEpNAEU+hUnI/UUPYI7h4S8Im7Ed/efcbBSPuR716fb2McMaKIwAPauWkH2GygTbes3lAKts23BA9av+HtSv7h0hlaZkPIM4G4D0JFebNuXvM9emlD3UbslspUgRjmvJvG2jTWN01wkZ8iQ5yB90+hru9f1DUYpSkLXCxIMsLcDc3tk1SSNdSspIWju1yhDi5O7Oe+elOD5feCrFT90808N30tj4i0+eMZPmhCPUHgj8jXu5UV4p4X0qaTxfaR+XujiufmP+7n/AAr22vQieTJWGCs/XNJh1awEcg+aJvMQ+9aIpSAykHkHim1dWFF2aZU0xopbdFcDcB0IzUzGJNQjjUKvcngCqscYt7gqM47VWvbzTJpkFyrM6E4IU5X8a8tppuJ7kGpRTRqQ+VJdSo208nB6g0zUxHBbsFxnHAFZ1le6XE7JbDY7tn5lIJNS6rI3kSSKpdlQlUH8R7CizvYHZK7Knh/R4bWWW7CYd3ZvxYDP+feugIqjottd22kwR30he5ILSEnOCTnH4dKvmvSpx5Y2Z41WfPJtDMUopkkiR53Nz6VFazG8ZyoKxICS3eqclexnZ7kGpyxxvCisPPYEhR1Kjqf1FUo1husM8xRhxkcEU1187U7a4Y5JjdPpyDj9KlubFH3Dlc8hh2rzq0k53PWwyapoUxw26kiYt7t1qpd6smmpHdzxs8KMARnHXjNTW+nrGfmZpGJ4JPSk1a0in06aKWMSKy42EdfT9azjK0kzWonKLTOgjmSeFJYzlHUMp9jSnFQ2FibWyt7YN/qYVQk+oFSKylym4BgcEHrXqxd1c8VqAAAAAAs7H//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-91.png', linkedinUrl: '/in/emily-smith-3c11276729', jobTitle: 'Claims inspector/assessor', }, @@ -3915,7 +3915,7 @@ export const peopleDemo = [ city: 'West Christian', email: 'richard.williams@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-92.png', linkedinUrl: '/in/richard-williams-034896141e', jobTitle: 'Artist', }, @@ -3925,7 +3925,7 @@ export const peopleDemo = [ city: 'Antonioview', email: 'david.cruz@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDrx0rkviH4hk0PQlitX2Xd23low6qv8RHv2/GurHSvHvinJJJ4pgi2ZVIFxu6HJJ4rMs41WkcsS5diMtk5J+tQB/NkZSOo4B9e9dv4f8DzapbJPcXCxhxkKq5NdMPhTavGC1yxl7MBio9rFOxqqE2rnj7SGKUbGyAcE4608SNNwzEjJXJr2sfC/RorcLLveQck54rmPEfgizs7B3tS+9OeT1HpR7aLdhvDySub3w58SHU7I6ZcM5uLWMYLfxqOMj9K7g1478NL2K28VvZ43GeFlDf3WXn+Wa9gPSrMRVNeT/EwhPFtm74Km2X8PmavVQeK4T4g6cNRvtJbbjypArN6hmHH6UpOxUE29Da8PgLYxADGAOPwrqYidoyT+FeealLqlk4Fj5vQsqoowcVd8M63rtzcxW1/CB5gyr4wfYEdq43F/EejGS+E7iUsVx2Ncl4lBeykReu04ql4j1fX47qSGwX5YRliACW9QPWqenvqV23+m+dwNxVwMdPai2lwcl8Jx3gO3N54/hYghYN8vHHIGB+pr2415z4I0x7TxLe3ShSjyyRE45AHP88flXopNdkZXPOnFxeowNWP4hszdWiOpwYXD/lyK1M4FRyxR3EflyglfY4pyV1YKcuWVxun/ZL6zVJkVsDvTo4oItVhigRQFOTtrCtS9pcSRgnAJ4+lQXNzaXU6sb5bW4XIBEmCD79vzrhs72PUi01dHRrDbzX00Vwi5LEjdTNTW3s7cpEoGR2rn7S5s7V2P26O4ldhkmXJz7f/AFqu3xedlUnrwPx6UNa2BtJFjQbVIYzKMbnGWwMck5rYPSmRwLDGEQBQB2FOrtjHlVjzKk+eVy2mmsVy35VFLAsX3sDFdCwGSPbivM/Ft5M2qxaesjKkse58HBbLYx+QrVRuZEOq3kRvXntZVkjBGWjORnHNSiKe8iWSB4RKQMF+hqJLJVdolQLHjaABwBVGG0v4xIts4Gw/davPck5XPTheCRsLby20ZadoS54ygGKhsJPtOowruyquCT7joKzvsupzqPtMq5c42xnk1fawWOBYCuV/iFK6TuOTc0dY30ph9q5zSdbW2H2G9mZxGdsc7c7h23e/vXQqwdQykEEcEV6Di1qzADy762P/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-93.png', linkedinUrl: '/in/david-cruz-9821a933f5', jobTitle: 'Lecturer, further education', }, @@ -3935,7 +3935,7 @@ export const peopleDemo = [ city: 'Josephtown', email: 'julie.smith@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-94.png', linkedinUrl: '/in/julie-smith-4b6473adc4', jobTitle: 'Conservator, furniture', }, @@ -3945,7 +3945,7 @@ export const peopleDemo = [ city: 'Brittanymouth', email: 'edward.russell@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDts0U3NIzhFLsQFUZJPYVBRx/jnxxD4etpLCzYtqsiArhciEH+I++Ogrx86rqN7KXnv7mZ35ZnlPWo9b1CXWdev70sW86YlT/s9B+mKSDTL148pC+PXOM0NpbjUW9iGWR1bYVAPdl5/WrGl63f6DeLcWU7xMDyAcqfqO9X4vDOsXuPJtpM92Z+AKp6j4cvdNUeevJ6/Skpx2uU6c7XseweFPiDba5KllfRrbXr48sg5SU+g9D7V2tfMElw1r5XlMyyxncrg8juDX0lpV017pFndN96aBJDxjkqCaogsVm+Ikkl8M6okJIkNrIFI/3TWjRgMCCMg8EUgPC/BuixX0bXEoyVYqAe3TmvTLXQ4UVf3a4FcM2lS6esyZnRDcybEiYAjJ4yfpW74avNS86K3aSdo3GV8/G4exrirJtt3PSoNJKNjs47JY4ztAArm/FGlC8snVR8+DisjW7rU/tQY3F55C87Lb+IZrQ0+aUSeW7XTLjlZxyPoRWXLZcyZq5JtxaPG5o2SZlb+E96+jfCqyJ4U0pZTl/syZPtjj9MV5BqfhuS/wDFk9rENqP++O3qFPXHvXtOj+X/AGLZCIMEECKofrgDHP5V6EZqWh5k6co69CfNOU02nLVGZyT28Uer3ttIAytJ5i5PTdzj9avaVDAmpOBsQRocdBkmofE1uYru3u4xjcCrkdyP/rfyrnZ5rS4nJklkhlA27lDDj0PrXBUi+do9WjJOmjqvstrNcCOQJyNyU+5jt7SHaqAdsisWwvdItITbw/KWIxkMD+GatXRPBY5z61k01obaFa0sI57qS42YmO0B+/GeP1rsoYxDAkQ6IoFZOgWaeQ10wyzt8uewFbJFd1CDSu+p5uIq8z5V0GgcUoqtJeqpIjQuR+ArNudRujKsSfLnk7BkgVrzJHOkzO8c69Fp0VnYeR5st1MFDbseV7/XrWLbB7gAxXfkuBjOM1HrkJvJDMcvLbzCRcnJwOD+hqnNE5jE0BIz121y137yO3DXUXY6JFMEJMtysrHq1VDcPdybVYlB1NZdnBLO482dnB/gxj8634447aHJAAxXM9DqTctyz4M12e+mvtOnVAlq+2JlGDjJ4P5V1prnPDmi/wBnQXNy4Kz3kpmI/ujt/j+NbcczHO4DAOMivRhLRXOL3nY//9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-95.png', linkedinUrl: '/in/edward-russell-34445498de', jobTitle: 'Teaching laboratory technician', }, @@ -3955,7 +3955,7 @@ export const peopleDemo = [ city: 'New Biancamouth', email: 'beth.kennedy@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-96.png', linkedinUrl: '/in/beth-kennedy-956fad5f18', jobTitle: 'Passenger transport manager', }, @@ -3965,7 +3965,7 @@ export const peopleDemo = [ city: 'Millerfort', email: 'craig.maxwell@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDfxUF3d21hbPc3UyQwp952OAKsYryDxnrFzqWuz229vs1uxSNB0yOp9zmkUdHcfEy1PmrZWDyMOEeVwoPuR1rIX4kaorybo7Un+EeWQB+tO0j4eX95bpLPPFCHwdhXJArZk+FybQVvW3gEEFeDWLrwvubrD1Gr2GaF8Qo7r91qkaxOTgSRj5fxGeK7dGWSNXRgysMgjoRXmt98Nrm2i82K7DSAc8d6l8Eand2GtS6NeFjvPyqzcAjJyPrVwqRlsROlKHxI9GxS4pcUYqzIVm2IzY6AmvEbG3N7rG5zndMXP1zmvbnx5T7sAbTnNeU6FYz23iDy7i2LYzKpjI2svYg+lZ1JWRrSg5NHqdjxGinqAOlabZCAhgfauDv9UunyqwTogOP3Z56Zqjpt/qqTh/MuTAcHbK3OM8D2NcKhpc9Nz1sd/dxM0J7V5vq8b2virTby2UCYyiI5HBGe/wCtaHiTVtYS9ktommhSMAsY13tzVKxWa6vLR5zLKbe5RzuUBmOcY/UflWtKNmmY15KUXE9BpKeRTcV2nmjZkEsEkbdGUg1zkkDJqEM7YBIdFUDG1eMfXoTXTDkVlaohRom3ALkgDH9a5sRBv3kdmFqJXg+pYitYbmPBARsY3ev4VUuJbDTZMT3KpEpHzMuAzenA7VJBcAqPXHBqk97LewmNLKV4hkBjtUH1IJrkjrod78g1C50271lTDdqWZAGAGfxo+yRx6laoGORICMYA/QVizGOxuBJHYvCQME4Vt31xWvpmbvU4SWPyDzPw9P1rWKfOrGVVpQfNudN2ppp+KQiu88kYDxWZq0kEqi3EqGdW5QH5l47j8q3ILQs6lwRHn5iOuKi1fwtFb6hc6taoXFyFMuOdpAxkex/nWVdtQdjfDpOornDtdNbs0VyxQj7reoq89zYPbeVPM5QpxsODik1OxW4Qg5GO4Fc1f6fOqnyDGynqucVxR5WehJSjsXppNPhjb7NI/A4DHNdH4UtWTT/tkrBnnA2+yj/E1wVtbMXzL0HPXIr0Xw7FLBo8Mc3D7mYL3Ck5X9DXTStzHJXcuXU16TtSU7sA7V1HGf/Z', + 'https://twentyhq.github.io/placeholder-images/people/image-97.png', linkedinUrl: '/in/craig-maxwell-9b3a04b47e', jobTitle: 'Conservator, furniture', }, @@ -3975,7 +3975,7 @@ export const peopleDemo = [ city: 'Stephaniestad', email: 'christopher.jackson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDoMUuKUikxXIdBS1XU7fSbF7mc8DhVzyx9BXlut+Ib/V2Dyny4EO5Yh90Ht9TXT+KrS51HxHb2isxQxfIo6L6k0g+Gl7OQhvI1jbrhf6U1KK3KVOUtjgYV3ZbeSrHJB7fjUMhjE3kq5AJ4z/Cfb2r1m3+FtjCgVp5nx94noaq6r8OLT7OxtZCkgHy5GaPbRuP6vOxyGieKr/SpBA1xvgib54GAOR3wf5V6rZXltqNnHdWsqyROMgqensfevCrnTpreaWKUEupwSO/sa7z4ZzopvrNdwZVVyD04JGR+Y/KqktLoyT1sz0M0lPIpp61AzEjjaTxhKWHCW67Ppnn9a7CJSMc1xetrd22oJeWjMrSRiI7ACcgkjr25rQ8Oahqd2nl3qlcozBmGGGDjkVlOOtzsoy91I6pyQmM8Vk6jIVgfZ97acVzGp3etxzvLHNPJHHz5UZGW5xwMc1ds5r+4JSdX994H6EVLjpc1UtbHnGuxo96xkJBU7j7mr/w7AbxBPKDx9mbPv8wqx4x0wvqNuYEzJMChUdzWv4N8Otok8rzzGWeaEDKrhVAPQHrXRGa5bHHOlLmbXQ7AnnFNJpccZphoMgAieQLKAQQetWIPJhS4KsikALjOKoXDbVWT+63P0rEuZ7K4umklm2NwChBwcevrWUl7x20H7mm511ultcsQdhdfxp1x5NtGQgA47Vh6dqFqAsUEkbHORt4P5Vdun3bsnoKzatobXRgzW6XmrQO6lmj3Fcep4rdjUJIcKBtGBjsPSualnmjnubi3Y+bGh2gDOTjgVu6Xaz2+nxLdSmW5YbpnPdz1/AdPwrSnG79DCrUtFruS2d1Hd2iTxNuRuhqU1keH7Say00CbIZ237D/D7Vrrg1s1Y473GSRiWJkPG4YzWPDa3DrhWRZVO1t3etO61GysULXNykYAzgnk/h1rmLnWV1K7ZtKEkTBMs8g4f047fWplFtXNaNTllY6cKLS3JkKZPpWTfasu0xRfPK3AUd6qW2n6rqkIlkuYUhbrsyWHqOelaVloVra3AKgs45LE5rF2OnmkyK1tjbJCZiN7yKzn8a6MjmsnU1XyizEKg5JPQVymia21jrMqNdz3FhI+EVyT5efTPv8ApWlG7ujDEK0AAAAAAAWZ/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-98.png', linkedinUrl: '/in/christopher-jackson-0ad43cfe80', jobTitle: 'Education officer, community', }, @@ -3985,7 +3985,7 @@ export const peopleDemo = [ city: 'New Mariabury', email: 'jacob.miller@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0WiiuV8c+J08O6QQoRri4BRFZiOOhNQUQax8SNG0oMsYluplcoY0G3GO+TXGaj8WtVuJF+w28FpErZLH5yw989q4NEvtXvJI7WBpnJycfw/jW5D4C1u4QNJFHF7b+alyS3ZcYSlsjTh+J/iT7b9oYwyQg8xBMKB/nvXpOheO9J1u3j/eeTdnh7f7xHuD3FeXt8OtYRT5dxDjHc81z93pOq+GrlZpo3QBsrKh6Htz2pKcXomN0pLVo+lwQwBByDyDSivOPhl4rvtYkm06+kMrQx71c9QMgY/WvR6szCvGfi9aXY1+zuHbNtJDsj9iPvD9RXs9eb/F63aTTtKlVc7bhkz9V4/lQCM3wVpaWeko+0eZId5Nd1CpKdAfpXB3ls8FrDbg3BVYuEg4JIHJzV7wy11a3EcZeXyJgGxIxLKT2PvXBJXvI9ODtaJ2YB5O0AHpXPeKLOK40i5R0DZQ1n+LFuHn3Rm4aOP5sQsQ3pwKl06OUqYZDOU24eKfk4I7GklZXKbv7pwXhC7l0nxrpvljbHJKIn9weP619CYrwjRbJv+Fk2doUZxHd5yPRecn8q94rvjqjy5KzsJXIeP7eS6srSPaphSTzTxzuGAMfgTXX1leILIXmnglWYxNvAXqaU78rsVStzq5i2kcMyAsoLY7iql1f2Nnq0EU0gjXnop6gUWUrRR5IIZRyp4PFZc2oPJcbjaXE7An5Y1wB+J61wpXdj1F5HQ2V5ZXtw6q4fDlRuQjB/Gr11CkSZGM47CuXsr3yZCvkz2+5hlJk+Un1BHeuhvp8wDbycUSVtAv3MDQtPVfEx1GJR573e0kjP7vbg4/EGvR65zw5YeXHHO0bAhThmHXJzx7c10VdlFPl1PPxDi5JISlpKWtTnOH8QqLDVZMHCyjzF/HqPzqt/o9xB5ckzIWxgocECtLxasN3eRwKQ0ix/MPTniuGNpqlux8sFx0Bz0rimlzs9GlJ8iZ2Qktre2Fuk3mnGPnOTiojd+eUtomDM3BI5wOlc9Y2OqXsgWUeWp4LE84ro7KwTTE3AbyrBifXBqHZMu8mdxHGsUaxqMKoCgewpap6Zqlvq9kt3bEmNiRz2IODVw16C12PLaa3AAAAAAAAAAP/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-99.png', linkedinUrl: '/in/jacob-miller-c0d550cede', jobTitle: 'Surveyor, land/geomatics', }, @@ -3995,7 +3995,7 @@ export const peopleDemo = [ city: 'New Kelly', email: 'kevin.williams@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDpmOKid1VSxOABkk9qHbiud8X3zWuhSKhIadhFkdgev6CqYkcb4j8XXOqyvb2khhtBkYBwZPcn+lc9GLgIH2En+8Oce9ddoPgmO/US3UjqjHiNfSutj+HGngL5M8q/U5FYuojeNGTVzyyN5JYNl3G3mL91wOfal0vxBqWiXgcMSveN/umvbIvBWlRwjzIfMYDlj3rF1/wbptzbuYYykwHysKn2yK+rysN8O6/FrtmZFXZKhw6jp+FbYxXm/hJJdO8Rra42q8bK4PtyPxr0UNxXQnc5mrMRmrnvFu06Sm5Qf3y4/WtsvxisrWYzcQRxnlA4Y/UH/wDXUzdlcqnHmlY0tJRY7WJRwdozXT25HljBzXnt+97BKfJluVQjKJboGJ+ua0PDupazNcxW11G+1jlZJF2nHocd64mup6UX0O43HH3jisrUWHkvt+9j9a53X9R1i2uWgtxKI0yWaJAxI9BnvTtMlvLh0EhugpGWS4jC/iCKVtLjvrYxdNhWXxKZyeURsj3rqRWbBaeTqN9cois+9VGeynGTWgrEiuylJNHBWg4u76iFSarzoXidQccZqz0HFROAwNXJXVjOnLlkmXdM+z3FsiyKpOO4q1F5A1SOOLaAh5I45rAtWeJyFJ4zx9KZJNY3U4eV5IplBAcKwx+OK4ba2PUTTSsdQ32ZrpkmCncxweDzTrsQ20X7v0rn7efS7ZWVCxkk+8zBuT65NXbliYVyxxjNJ6FEMYLWryHHLED1oVcVDamOWLzEYMCSCQe4PSrQHtXZSjyxPMr1OeXoRGm4GakICrknisDUvE1vaOYrZfPl6ZzhQfr3rUxLN/MtpcxlXw7AsV9hgZ/Wr1sBeKGW52ZHBFcat9Pc6zBNcPuLI0fsM84/StVraaOQCKYxI/QjoDXJWSUzvoSfIdWqfZ4yz3AcY6mswu13JsRiUB+Y+3pVOLTr5wPtF4HU9FUda0n8vT7J2HVR+ZrB+RvdvVmHoErWT30crHyjdykew3HmuihuoZwfKlV8dQDXOxosFthj8zEsx9zyarRvLJIQh8tdxOe5r04xj//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-100.png', linkedinUrl: '/in/kevin-williams-41633df75d', jobTitle: 'Doctor, general practice', }, @@ -4005,7 +4005,7 @@ export const peopleDemo = [ city: 'South Isaac', email: 'mary.wiley@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDnTnNGDTyKU7YozI/QUm7FpXFjjYmpkKPkK4bHXHNYV5dSTB0dvLRCCNrH5vQYHWnKNamAFtbSPFxlfL2g+4IrJ1H0NFTXU3djHIAOR1GOlQuCKzNRvfEcXlyPa3KPGeW2HpT4vENvcskckXlynhs8c/TtTU+4nT7FvnNSR05kwcihRzV3IsCrzVTWHaGyYqfl4yB1PpV8rsVnIyFGa4yW+nn1p2yAGbJGew9aieuhdPTU9H8D+GYWtl1K+RZLiTlVIyEHavR1ihEYChMDsBXns9/Ppmm28MJuCxiB2QLyTj1qTw/JrEuoRJctcCB8MxkbPXsfQ+1ZeZ0+R295DH5RRgvI6EV454z0ZLG8j1G0UK5bDjseeDXR+J9Q1W31GSO2a5aBTjMIycVi65cy3ui3Ks0jSQrkiQfMCOvPehb3CW1iO0uDcR4dSjrwRmrSiuV8PSXE1+gYsEKksM9fSuvEeDW0djlluTBQeK4Q6eRrUgCsqrKN3HQV3iAg0WOlQf2hK7TbBMyvtOB8y84GfX09qU9rlU0m7M7rTJoWtgpRCcAZIzVfV9RmspofsmnyTrvwSowB6k1X0kDOc8VV1LVtVfIsraKOJWx5lxIFDfTrWEddDsSu9B2jai17fXIurOSIMeCwGDUOv2tp5E6KgVnjIJH0qrZ6jqomLXlvEyk43wOGA+vSn6nIJMksAO5J4FN6MHpozz3Q7SSy1MCcncVwo9vWuuC81Q+x291qSTwOHjt12Aq2QW789+1aaxnNbx2OOaSdkC8GmahZpqOny2rZG8fKR1B7GpViNTxoQaozKHhK6lj0CGGSTJhd4ic9drEfyxXUMumSxbbmRmBGdobisSzsYI1ubeA5/ebyv90kDisu8guLaQiQNt7YNczSUmdkG+VHRzf2fCh+zMy8dN2a5rxNMX0C7CHICDJ/EVHAWlfbzj3qzqcRXRLhQFyELYIyDjnFCtcb2ZW8KK50goylSjZAPTB5GK6BIj6VNpojurOCRI1iDqPlHQe1Xhb4rpQAAAAABxs//9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-1.png', linkedinUrl: '/in/mary-wiley-2c6f70a754', jobTitle: 'Museum/gallery curator', }, @@ -4015,7 +4015,7 @@ export const peopleDemo = [ city: 'Santanafort', email: 'sierra.mccullough@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDnzQoJqTGTWdrGpppdrwCZ5B8gA6e5rmOkmvNQtrBMyuDJj5YweT/hWUfEsrciGKP6vuz+VYen6Ze67eExJ5rk5YsTgfU119t8MpZUVpr3afRV/rQ3FbscYylqkZFv4nmFz5dyIth6FeK2bbUba9LLE5Eg6owwaLn4YiOJjHesX6jK8Vyd/a3+h3ieaxDocow6GhSjLZg4SirtHZkGlUc1FY3aX1lHcp0ccj0PcVZBGaQDwtcr4yZTLZQj/WMGJPtXXBa5bxTZl9X0x+okPlY9OR/jTjuS9js/COlw6fo8KoBub5nY9STXXhPkBBz9K4jVJWs7VYxayTAjgDoMD69al8Ni7S5jjPmrBKAxVmztz2rnav7zO6LtaJ10qkJgkLn1rhPGlnFcaVK2AWQbgR2qXxXPcm5dAs0kMRxiLqTVSPdcWk8D27RuqEH0bihRt7wSd7xMTwbN5mmzQkcxSfoa6MJXNeCo2WG73Iwy4wxHBx2rq9tdEtzijsOAqG8sFulgdiSYpAyL2BHJP5DFWAKnhcRMSyllwQVHepktNC6bSeps2MsM9uqOoJx3GaLq6srC7t0d0iVmHJ4yfQVT09eARxx0qPVNZsIWWKS2kuJAcYWMnB+tYpNux2K1rli1ns76/ukSRJF3ducH0qLVFt7eEiJQG6cVT07VtPeV4obZrd842shHP1pb8+Y+eT7UmrOw21YzLCzW1hXaoXI5A6Zyeat4p+3r70YrZKyOObTldCipAM0wLUirzVGY5JzbnJOFPf0qyLRL1A6zBPRh2qiC0l3LAyjYqr+Ocn/CoDZ3Me77O5HP3c1jLSR10pPlTLz2YtMuZg5Pc1VEnnzbeqgZz71WMNzIcTyZPYCkkSWG5tmjOFD7HX1BB/riiPxDqNuLL+3ml2ZqcZ//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-2.png', linkedinUrl: '/in/sierra-mccullough-9d4780eddd', jobTitle: 'Tour manager', }, @@ -4025,7 +4025,7 @@ export const peopleDemo = [ city: 'Stevenhaven', email: 'michelle.mcknight@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-3.png', linkedinUrl: '/in/michelle-mcknight-d4229e04f1', jobTitle: 'Adult guidance worker', }, @@ -4035,7 +4035,7 @@ export const peopleDemo = [ city: 'Carlosfort', email: 'devin.aguilar@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-4.png', linkedinUrl: '/in/devin-aguilar-ed9890f7fd', jobTitle: 'Press photographer', }, @@ -4045,7 +4045,7 @@ export const peopleDemo = [ city: 'South Michaelville', email: 'christopher.figueroa@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0gikpxFVr+6Ww065vHVmWCJpCqjk4GaBnD+NviBLoV6NP06JGnAPmSyg4U9gPWvJdV1vVtXvDPqF1JPITgDd8qj0A6Cul0fR38T63PqupZMLPvEbHJZjzyfau4HgrR53WU2oDjB+U1k6qTsbRoSkrnibCRFTeHR1+6dvWuw0P4l63o0yC5mN9aMMGOc5Yf7rdRXpNz4Z0uSNVayjIUYBxziuY1zwrp81q0UUKxN/C69jS9si3hmek6RrFnrmnR3tjKHjcDI7ofQj1q+BXg3gPWp/DniW3tZCzQ3Ugt5UzxycBvqD/AFr3vGK2vc5noGKoa3C0+g6jEnLPbSAf98mtCq9/I8OnXMsahnWJiAeh4oYJXdjzXwbEF0mMgdWJrtYQQvrXAxQ3Fro1kkJuMlCcQYBzknkmtXw1dak8oiuDNsYFlM2Nw9jXG1rc9GDslE6qQttK+tc/qp+Qqo5wazNWvNVNxK0LT+VHk4ixlsHtmm2ctzdDEizrgZImXB/PvStpcfNrY4OzSWfxppsMY5N3GCT2w4r6NPU14lbWJh8bNqEcYdbQrcbOm5scD+te2RuJYkkHR1DD8a6oSTRwVINai0ydBLbyRkZDKRj14qSirITscfpqRiDyHUZQkYParESR/btsSqAinOPWodUiNtrU2z5VfD4+o/xzWRLLZTyk/axDNt25V8fn2rjas7Hpxkmk0a1nHDLM8cmC3UZ706+WOCMhABx2rHtJtPsTtguA7Mf4mOSfxq5fuWjJY9ulJ9h3Muzt/OuSI4x5jyKNw6ntivTVUIoUdFGBXOeFdLgFjHfuhM7MxUknAHTp+ddLiumlGyucNapzNJdBMUUtNZgilmIVQMkk4ArQwMXxJYtLZ/bITiW3Ulh/eXvXPQq9xGrROiMR1I7Voax4ksNTkj0fTbxJ5pnKyGPlQArHGeh5A6VzDG6iw1uwCnqrdjWFWNnc68PN2sbvkmBS8jIxxjNYd3dPOxRXyD1PoKYx1GY7JQFU+hrR0zRXuVLt8sCH53Hf2HvWSi27I1lPS7Oj8J6rFc2Y04oY57eMNg/xoSRuH4g10VeJa54in07xh9q0xhH9jUQqByrAfeU+o5xXd6R8S9C1DZHdSPYzkDIlHyZ9mH9cV28rSscDdwAAAAAAB3P/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-5.png', linkedinUrl: '/in/christopher-figueroa-8ef81242d0', jobTitle: 'Theatre stage manager', }, @@ -4055,7 +4055,7 @@ export const peopleDemo = [ city: 'Coxberg', email: 'anita.orr@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-6.png', linkedinUrl: '/in/anita-orr-7648a03041', jobTitle: 'Air cabin crew', }, @@ -4065,7 +4065,7 @@ export const peopleDemo = [ city: 'Arnoldborough', email: 'richard.young@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1KilqK5nS0tJrmQ/u4kaRvoBmgRynjjxxH4WijtreJZ9RmUsiMflRf7zev0rxafVbzU5Z7nUJHnlc5Y9efpjpWlBZX3jTVrvU5sl5GJyx6eij2ArRHw+1mOPfE0eT/CGIrGVSN7M6IUpWukcpbQRTR7gR82QARg1FHPdaXcLcWs0trOh+WRH7/UV29l8MdSuJvNvZkibH/LPk1f1D4ex2lqBbp58oGTuPU1DqxTNFQk0dD8OvH58TxtYaiY11KJdwZflEy9+PUV39fMXn3Gka3E6W/kXELh0ZfUH9a+mraYXFrDOOkiK4x7jNdEXc5ZKxIagvYPtOn3MH/PWJk/MEVYprsUjdwMlVJA9aYjyvwNaeTpZJGGaVv04/pXoECgqM81wcZu9P0uIWqPuZpGCoB13E8k1q+H9X1K9kjhurcxuw3en4H0NedNXbkerTdkos7AsFU9qyr99sbBeWIJrndW1vWLa5kSKEsiDJ2rkn6c9atWd/d3u1JoJY2wD86YqHF2uXdXseb+IYEu7vy2+WTdwMdD6V75ZwC2sbaAdI4lT8gBXl+o6LDf8AiuIyECIIHYZxk5wBXpGjXNxdaeJLpQJRIycdCAcA120aifunn1qTS5uly9RQaK6DmOXhhiW4mt2UYRyMH61NbCIaiBEFCoDk9KNaRotSWRRgSIOncisGW8sPOZZZmilwV3BTx+NebOLU2j2KcuaCZvwrbyymObbvJJUnvzUlykNtH8gAPrXP6feaZEfKtpCWZupVsk/WtS6bcuWPas2raF3KMaieWUMgYMMHjn2ArsbOH7PZxRd1Xn61keHLeNoprgopbftViORgdq3q7qFPlXMediavN7nYDSU6kxXQcpn6vZtd2ZMf+tj+Zff1FcvBGLhMiQIw711ep6hDp9lPIzoZUjZkjJ5Y49K4fy3mjWWJ9jMOcdDXJiIpNM7cLN2aNUILeMl5Q5xjNZ890077EJPvVOK31C4kZJXCxjrjvWjbWgiAAHXua5XZHXdyNvwxqVrL9o0xGIurfEjqR1VuhH5V0Fea6YWi8Z3t/bniG2jib0Y5JP6V6Baaja3oHlSrv7oeCK9Gn//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-7.png', linkedinUrl: '/in/richard-young-10948fb6af', jobTitle: 'Osteopath', }, @@ -4075,7 +4075,7 @@ export const peopleDemo = [ city: 'New Mariebury', email: 'justin.berry@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDZp60yuN8feJ5dHtI7Cxl2Xs4yzL1jT1+p/wAazRRuax4u0bQn8q7ut0//ADxiG5h9fT8a54fFKxa6RV064FuThpGYZHvt/wDr15hbWk95OBGplcnkc5NdFH4T1e6RVSz2onPzMMmm3FbsFGUtkelJ428OyyrH/aSKzdN6so/MjArbDK6B0YMrDIIOQRXh974c1i1j3zWUmzJyRg4H0rS8IeK7zSr+C1vZpW01yY8Pz5Z7EenPb3o0ewNNbnr+aOtJnIBB4pRSATFeFeJb1tV8WXkrKR+9MaAnoF4H8q92XrXh7WyS+NLqIgsn2t+vX7xoTsrgld2O38L6VbWlmkh2h2AyTxmu7tYcQg7FK+q81yPlQ2cQ8yxa7lK7ljP3QAM4HvWroU4glSUWptRIoYorZAz2I7H2rikr+8z0ou3upGjewDyiTENvvXjnjDTBZ3vnxZ8p2yVHZvWvTPEt3HcwTGWGaeOA4McZ5OT6fjXC+JbSEabJJaQvD5ThZI2bcM9iD+NXR0afczr+8mux3/he/bUvDdjcyOGlMe2Qj+8ODWwKwvBduLfwhpy4wWjLn8STW+BXUcIi1w2teH7e21dNWgZQ/mFZYx755ruV61g+I0FvbiTymdZ5kUlcfIfU+3H61nUTtoa0mr2Zr6QsUtshIDPjjPNP1KaC3dUkkSM5+Zz0Ge1Zuku8EULpyGyCPcUtzqIkuWVgCy84C5P51yJX0PQTLKxQHW3jjmR1ZQMj1xWN4s02O50ya0gVUllIXHbOaWe823cRVBE5PCgYB/wNTlJLzU4w2SFO5sDP+etUotSRM2uV3NbT7UWOnW1qoAEMapx04FWe9GaK7jzBUWsfxHqdnDay6dJuNxLHlMLwCCOp9adJrbNkW0OB0DOefyrDurf7XOzTHfJv3hj60NOzCL95XCz1F7MrDMcDO5G9faujgSC6jDggMw+Vh1FZn9mRX1r5TgZx+tUYtHvISY4L14sdFbkfhXAmj07NbGlfxQWxZ2cPIo4Zj0q9pNs6QtczD55gCB6L/wDXrhtTFxFFPJcXDSpH+AYiu+stUguYI0dlim2gbDxn6V0Uopu5y15vYs0UnKf/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-8.png', linkedinUrl: '/in/justin-berry-4ac0f93944', jobTitle: 'Public house manager', }, @@ -4085,7 +4085,7 @@ export const peopleDemo = [ city: 'New Justinborough', email: 'timothy.davis@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-9.png', linkedinUrl: '/in/timothy-davis-6c07a1c0bc', jobTitle: 'Call centre manager', }, @@ -4095,7 +4095,7 @@ export const peopleDemo = [ city: 'Pottermouth', email: 'brian.williams@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDUAp2KXFNmcRQySEcIpb8qBHNeJ/E76Vi0sEWS8YZYtyIl9T6muHmvdX1VHeaeW6YdI+ig/QV1un6C+t6i93qDkmQ7v3fA56Y+gxXVWPgS0tZEeKaXAO7BFYyrJOx0ww8mrnjUltMWMyxbDuAMfTB71t6fr97pMcItrgMmTuhflODz9Pwr1K/8GaZdyeZJG6yd2HGa5PWPBNnEj+QzA4+UdBUqsinhpI0/DuvR69aO+wRzRttdAePYj2rZ215j4YM+m+JraJyR5jGJgfQj/HFeo4rdO5ytWYgFRXvFhcnGcRNx+FTqKcyB0ZcZ3AjFD2BK7sjL8IASWUbkda7a3YomOtea2y3llYWog+0fNGSohAzkZJ69/auk8Oajqkgiiu/MKyDKvKu1h7MK4WtbnqxeiidLMzFSMVy+t8x4Uc1X1u+1maSZrYyrbwglvLALPjrgVnQNe3rKH88MqbiswHcZ7d6Vuoc3Q5iOQT+I4FUESLOmPbmvRyK4KKyK+KPtcQ3NEC+3sWxgZ/Ou9Qlo1YjBIBIrspyTVjz6sGteg1aeDjBHamLT+1aGSdtSXTlhljeGRB8khxx05qzmH+0FiR0GxScZxzWPDui1BwrcNzg/T/61QzzWFxdFbqGfzVBG9Y2zj6ivPtZ2PYhJTimjY08wTySoxQtk4wevNJfNDawPtAU4NZNpcWUEwhsraZWJ/wCeJGB6k0msy/upS7fdXmh9gehl6OS9xdOgQlmVeRz3rpsYGKwfC0ayWUs5HJlOD+AreNddKNlc86vU5mo9iNelOFMFKzqilnYKoGSScAVqc5BewyNH5sI/epyB6j0p1u8d/bowkwSOvp7GuZ1vx7Y2ayW2nH7VdEFVkX/Vofr3/Cqduuoh41t7gK0gw2ehcdfzrmrxSakduFm7NHbSmGyt3k80ccE1x2o3smqMbW2YkH5pXHQD0p8+j61chUu7lCrH7qH+dP1WW08KaEdgDXEuQgPV29foK51q7Lc6JPS72Mvw94hfTfE8mm3M2LKXCoD0ST19s9K9EJr5+eR5ZHldiXY5J966zS/iHf2EQgvYheIvRy21wPTPevRjG0UjzJPmAAAAAAJNn//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-10.png', linkedinUrl: '/in/brian-williams-07738aaf00', jobTitle: 'Media buyer', }, @@ -4105,7 +4105,7 @@ export const peopleDemo = [ city: 'Wyattbury', email: 'kyle.carr@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0g0x3WNGd2CooyzE4AFONcv4+vfsnhO6iUnzbrEKAH16/hgGh6Alc4Lx14/n1KWSw0adksANjyrwZj3weu3+dcFHbyzxu4OcgAgV2WieE/wC0Yk80LGgPYcmuoT4cWQQGO4dWzzxWDqq50xoSaPHXgIRiwwy9eKnsXcshWXZIpwhbjkdMGvZ5fAOnywYmy0nXcBisLUPA0USP5DYJGAMUvbIr6vI2vh341bWIW0nU5h9vh/1bu3My+nuR+tegV8yzw3miamk6K0c0UoIIHcHivpaCQy28chBBdAxB9xW8XdHLJWY81x/xGtWm8NrcDpbTK7fQ8fzIrryaxPFtsbvwzeRDPC7seuKJbMcFeSRgeHEB06BsYLKCK6uBiAMiuGkGpWUcH2HcymMbFAGOB0Oa2/D+q6rclItQtlR3G5SOOPQjsa4Wup6kX9k6GSRipGOtYuokbOPvdqoavq+tCSVbK3QxxgkserY64qraz6lfbTcRMmBkhlweR9aVuo7rY4HXg93qaW7ZDtIqkd+T/wDqr3yNRHGqDooA/KvKTpYufFazkf6lFfJ7P/D+v8q9O0+SWXTrd5zmUoCx9T6110pJ6HBXpte8TmorqPzrWWP+8pFSmkrVq5zp2dzB04xPbiJ1GV4wR0xU6Rj+0QqKAFQk7RVOZWt9YuOuGO4D6jNUpLuGW7aRb9YJgpUgSAfoa4GrNo9eDUopo17OOOWWRWAJB5Bp92I4IWAwvHasezurW1kIju45WJ/565P61Z1CQvFknGRnmpfYpmdp8L3M8oTq7BRx1+v0rt1UIiqOgGBWR4YjxpG/+/Izf0/pWwa7aUOVX7nm16jk+XsJiilrH1fxLpujDbPL5k/aCLlj/h+NanOQ+Jnis4YbxpQkm8RKvdyew9+v61nJAl6qyo0YcjhtuciuU1vxJLrur6Z5iLFbwXG5UU55IIGT3ra8q5gkDWzhVfsw4B/pXJXspnoYWT5DYS1jtQZG8st3YAVlXNy15IYYmJz94jsKJrLUp1AnmRVP8MZ5NXYrOLTrNycAhcsawbOhty3Mjwt4luLbxde6PdTf6D8oiDDiNyOx9DXpJrwt3Ml1c3Q4aaTdn2HArp7Dx/qNtshuYo7pQMbj8r/n/wDWr0IJqKueVUs5AAAAAAk2j//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-11.png', linkedinUrl: '/in/kyle-carr-ae1d05c89e', jobTitle: 'Environmental education officer', }, @@ -4115,7 +4115,7 @@ export const peopleDemo = [ city: 'New Joshua', email: 'jessica.gonzalez@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-12.png', linkedinUrl: '/in/jessica-gonzalez-26ff71c932', jobTitle: 'Acupuncturist', }, @@ -4125,7 +4125,7 @@ export const peopleDemo = [ city: 'West Joseph', email: 'hannah.nguyen@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDdNJipCtUtVvBpulXF2cZjQ7Qe7dB+tYmxm6z4jh02X7LABNeEfczwn1rCv9TkFmZ7mZd7fdVep+grkBen7U7NKxeRt0j9Wc1uW2L5cNujjVeFT7zf7zVhNt+h0wiltuY0mt6hHc5dnaMc7X7Cuht9UuI4xOR5ZHO6P09x3FRReG3njaaX5c5JU+npVKW4e3sTaNjzIThG9VobT2Dla3O90XXYdSAibCXGM47MPUVsYrxm11OWyu4rmFsMjBwP6V7JbTLdWsNxH9yVA4+hGa1i29zGcUnoWSK4f4iaoILa105OZJW81vQKOB+v8q7o15x8TYdtzp9wB1R0P4EEfzqnsRF6nP6B4eudXnWRFxCT8zmvT9L8NpaIAyDjviuZ0jOm+GLIG1eV5UJyOgPJ/Oug8MXV7PNFEwmEL5IEvVf1rkmm9T0KdkrGtNpHDtHgKw5B7H1rzLxXpc9jMZPLPlE5DDoPauw1+a7FxIyi4aOIHCo33gPxGTUNu39sWhgns2j4wdw6jHeklbUqXve6eVLJHKCrna2fwNeteBrprnwxCjHLW7tFn26j9DXlF/YvZ6vPalTlGI/DtXpPw3Ux6ZfxMfmWcHH1UV1LyOCV7anaVznjHw+db01JIWP2m2y0a9nz1H6V0RpRWljJMy/Dwi/si3tJ48PGgUqw6EVtWwt7fUEQlECru7DNYzQvBflyfvtkUXl9prSqtwsjSoCN0aElc+4rgaak0etBqUU0alsYLl5FOxsHI6EEZqK+eG1hby1AGPTFUbC80tEMNqhiYnIUoVJqS/QsuWPAFS+xVjk7jSLeW9fUJfl2jc7HpgD/AArV8DadJaaRNdzKUkvZfNCnqE6L+lYsF3cat4y/sOYKdOT95IirgthQcMfTOOK9DwAMAYrrpRaV2cGIqJvlREBS8AZJAHvUMl0sV7DbEZ3csfQVFFZNrmpCIgi1jwZAD19vqf5Vo562RzqOl2W5rGW6tfNiGSvKn1rKhhiuD+9lKOOpHWu1voxaaW4iAUIAoAHckAfzrzpEkMZJJ3qxDHv1Nc9eyaZ2YWTs0bRiitY8rLvz6jmq8rG4woJIHU1VhtpWYGSXcOwFakUSpHiuds6jnNNRdO8XSP5HmSX5VEbdyoA5wPTjn8K7KRWQlXG0jqD2qTQtLjm1JLmRFIt8lSR/EeOPwrprrSbLUYDHdQhgw4YcMPoa7aLbgXSU9D//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-13.png', linkedinUrl: '/in/hannah-nguyen-af672e539c', jobTitle: 'Theatre director', }, @@ -4135,7 +4135,7 @@ export const peopleDemo = [ city: 'East Matthew', email: 'tina.salinas@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDzq6ufs0eQAXY4APb3rIOoXF1OFByBx7fWia4a4RASACSS2OcVFDcLHKnyfIvQdj7ms7mqRoSKILTdNHuXPGSOfpVFpomZZIE8sgcjrmtO2sZvElywgQ4XAOBwK620+F959nWVZVZupUrgVm5qOjNVSlJXWxyEN9IyDadx6PEeD+FWvNWQblPfkelamrfDzULFZLpNspxnaucr9K5WxumSdrd15J5J45q4zUtiJ05R+JGoTmnpTBThxVGZzjHadoJdj6dM062s2uLhYIxnJAz7mo2LK24R7fl4HoPWul8D6c17qf2ggeXGCee7dqmcuWLZpThzSUT0Lwb4dh0q3wD5krYLMeK7+HAhABH0Brz25W7t5VhMcrRyEKGBwo/Djn6mqei22rRar51ut3FbhzlZ2IwM45GSPpXCtfeZ6bSVoo9Huo98DEgDjvXg3irTUt/GTRwgKjhZeOmc816T4zl1UxJBA8ogG3zTAMs2ewGRx681wGsWrjULK4jR4l8k5LHJJBI71pRVpXMMRrGxTxgkGnqtJtI604V13OGxo6LpdrrXhpEWNI72OQQz5TLHaDgD6jFXtIsv7EDrESU8zPIwa5nU9VvPD2pJc6bK0bTA+YGG5Xx2INdLpOoy6jbCe6KeZMN52Lgc+1ctWLWvRnfRqRlZfaR6Ppl3bXsAjmjVgR3GasXjWlhEsaeVHv8A4jhR+JrmNHEkRRdxwehrU1TVNJjgEGooJsDcUMRf+lYLsdVuxekFtdJb+YYpA6dAQelcN418r7TbJEu0KhGB6ZrU0m90MXJj04OjHO1HB+TPZfQVzviGY3GqyZ/gAWtKatMxxGlOzMBhQop7rzQorqTPOaLdxYW1/D5V0P3YO7OcY/GktIo7S0jS2l8yKMlVfOcjNaltYpdeZBOP3MymJiO24YzVaLS30+JrF1wFHyMOjDsRWVW6idOHXvGtpeqbdiO4XB6murNl/aMY2XQQjlTjJWvMPNaJzHJ26Gr0Gs3UACwzOMcDmua2tztUjsrizk00PNPdCbaOG24/SuGuJTPcSSnq7E1b1O41K8tYkErtOXVkUexzW1NoMeowJcwHypXUErjgnHNdFGN02cuJm3JJnJlMmkEZzV67065sJQs8eAejDkH8aWGDfzmtc//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-14.png', linkedinUrl: '/in/tina-salinas-4c6898adb4', jobTitle: 'Office manager', }, @@ -4145,7 +4145,7 @@ export const peopleDemo = [ city: 'Edwardbury', email: 'matthew.king@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDdIpGKRqXdgqjkljgCptorzr4ialM13BpsZxCoDyDP3mPQH2AqCjS1b4gW9ldfZ7CFbg4O6Zj8in8OtcXqPivVr64DS6jLE68KIjsX9K1NC8HT6pGJpX8iBx8oA5I9a6mP4c6X5eJHmZuxyBWbqxWhvGhJq5ymmePdTgs2tpjG8inKsRz7g12ujeJbLWY9rEW90ODE56+4PcVk3nw308AvE0gbHr1rjLqxutH1FUmdjAOjjj5e4+uKFUTegpUZRV2ewFKAuKdaSRXFpFLCweNlBVs5yKm2jPStDEfivLb/ABq/iW5MiY/fbOfQcY/SvUxXnU1u1r42mSRG2SSmRWAyCDz/AI0puyLpq7O50uNUgRRwQAAPStY5PvXKXF4YVHFwVzkCFfmNO03VLhplVmn8tmGFlOWGegrjtpc9JS1sdDNnaR2ri/EtpHLauCByCc+h7Vc1bU7k3M0YecJEcFYhljxWZ5xnilB89oypLLMvzDIoStqKbT90vfD9pz4bKTfwTuq/Tj+ua6oisHwYjr4dQuMEyuR7jNb5rtWx5j3FAwK57ULWL7fHKPvLISRj1FdCKo6jbF4WdccEMfwqKsW1obYeai2n1J4YIpo+VCt/Oqk8tja3EaO8afOACRjJ9qdEztDuQ87ciqE0rTEI1nK4HQ8AVyo9DfYm8yxm1mZRKjbsZwM4NM1S2hhhYL1IPNZ7YjnAitZIieM4BH6VdvEkmjRT98gce5oe4PRal7RLdbXS0jU5GSc1fNRWsTQWqRsRuA5xUhrtirJHlTd5NokAodVMThiApU5J+lO2uSAq5GMkk9KrXsTXEU9puws0bIjdOSCKohGDbX3khoXcLgZBPcVpCa3khUNtYMPWs2TTxcWiKww6j05FUjp17CmIycdip4NcCserdo2Jnt4kO0gY6Gqtlew3GpwRvIBnJGT1IHA/r+FZLRXch/eA56ct1NJNph+0WAVmDxzB8g9eDnP4ZqlbmRE7uLO5NNIrPt7m5wqsVkOOp4Jq9vcNgxHHrnmu0wAAAAAAPNP/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-15.png', linkedinUrl: '/in/matthew-king-4fcd69e0e2', jobTitle: 'Scientist, forensic', }, @@ -4155,7 +4155,7 @@ export const peopleDemo = [ city: 'Lake Anthonytown', email: 'carrie.mayer@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDrMUAU7HFQXt3Bp9lNeXL7IYULu3sKxNSDUtW0/SIPOv7uK3Q9N7ct9B1NctJ8UNDDstvFdTY6HYFB/M5rzXVLu+8Y+I57iON33HESE8RoOgrbsvh5fSIPNkhTP1OKUpxjuy4Upz+FHTQ/Fey8wLdabNEp7pIHP5cV1mkeIdL1yEPaXK7ycGKQhXH4V57J8MG+zNtvWLjkZXgVyN7aX/h67UOSk0TZWQdxSjUjLRMc6M4K7R9BlabtrE8HeIl8SaElwwC3MR8udR/eHcex61v4qjIMV5v8WNUu7e1tdOicpb3ILSEfxYPQ/pXpWK8d+Kty03imztBnEUAOO2WJ/wABTQFvwlpaWtjG6jMkmGcmu/s0URD5gSPevOrmQWtpHCVkc7PuofQfzrQ8Om6W9hi3SrDJg/OTxn+tefJOV5M9aElG0D0BWG0/NjNcn4y0q31DSpiyDzEXcrDrxWf4pFxHdEKs0sa84jYgn6Cp9NZpV+zvHMq7eVk5BBFCVkpIcmneLMH4T3T2/iC8sMkpLDv+hU/4E17BivDvB5bT/iTDAHwDJJF9Rg8foK9z7V6G55L0dhAOK8x8faEG8S2+ps2VlCKB6Fe39a9QFcp45lsYtPtmu5FR/NxECM5OOfyqZ35dC6VudXM/TI7eePbNGCR3NOub+y03VbcN8q57L1NUrNz8rIcgjII71FJqO+52rYtcMDjnCg/TPWvPSu7HsLVaHQ2d/p2p3MqD5l3EfMvQ/jVu7EFrARHGoGOCKx7TWEC+VNpslvkgZUbh+JHSrl2SyDJ4FDVtBPTc5/QtGA8TC7Ea+YbjzCSM/Jg4+hyK9LPSuR8Kaja6ldSGyDSRQpiSUjA3k9PfjnNdceld1JPl1PLxDi5WiKOlcf8AEDRRrejiGLBu4iZIl3YPoeK7DpVOW0BumnVyGdQrD1A6VoYI8o8M3ryaPGkxxLAxiP0H/wBauhtbe0uD+9kYDqADWCbi1l1/VIbJFSCOUAbf4m6MfzFS7yp4yPoa4KitNnqUZvkTOtWOztIf3czMPRjWTqt6w026ZCTtiY5H0qlbJJcNgZP1NWtUjnt9DuWtv9csZZT9OalW5kXJtp2D4SxXCaZeebEyxlwVYjG7jn616QRxWV4cuobzQrSeKNYw8YLIowA3etXyHuf/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-16.png', linkedinUrl: '/in/carrie-mayer-19a613bd93', jobTitle: 'Furniture conservator/restorer', }, @@ -4165,7 +4165,7 @@ export const peopleDemo = [ city: 'Kimberlyport', email: 'alan.guerrero@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwCNhWBrGvLZSeRb4eXOHbsvt9a27+b7LYXFx/zzjLD644rzW2iuLyXbuy8jdxkkmpk7FRVy099dXlzveUvszx6Cmrq15FI8UruUcYwR0+ldtpvw83Iryz4JGTgd60f+FbQSbRNeysoOduBzWHtI3Oj2MrHnEesTWc7RGdiGwVIPaum0vW5JpEgvQqs/KSDgN7EdjWtefC61LeZDOy4bPTt6VxniDR7vRLss7NJE/CyelUqivZEypSSuzvkqXbVDSLkXumW9wDncnP1HBrRFbHOZ+toX0W8AHPlmuV8NW6/2nDxuO/v1JruJYBc280BbHmIVzjPJ4H86zPCmiyWPiCaG7AM0Me4EdOeM1jVklodFGDdn0PQLcARgelWs8etctqpuEJwt24AJCwHHQfzqvoU2ptOgklufJcBtsxDFfY+hrmS0udt9bHXSZ246VwvjSOMae5ZQR7+tXvFGoanBI8Fr5uxFBdosFjnsBXPX0FxeaHfJJJcsRGCVuCCQ2QeCKqK1TJnLRof4cgNvosCn+LLAegJrZFU7JTHaQIwwVjUEfhVsV2o817k1qwW7TcOCcVpRRql355UiZkCuSc9yfyrIPrWhb3clzMTKFGFAGO/1rCtH7R1YeorcjOgRVmjBYD8arSyW0DmPciHuTwM0RygJnPbOKxL/AFCwkUxTkEA5/wBWWwfrjFYJXOs07gwNqahnRt6dM55qtqEMHleTt4c4YD0rHhuNPF0fs84aUqAQ4IOPbNaF5N5e2U/NgA4PvTtrYTaS1MskGQkdCalHSq69asDpXaeUPAzUNlepPq1zp0asJYFy5Prx/jV+GAsQSPl96bDpqWniaa+A4vYVGfRlzkfiMflUVV7jZrQ/iIt292QfLfhhwRV5kDw7QwXjAPpVS/sPtHzIQretZUw1K1IjVGk9MVyI77tF+e1CfM5VyO5ArJnuxcyNGsinYeQDz7UmNQupfLuPkXuAeSKwNRt3s/FCXMZIimRY3A6Ajoa1p259TKs5OGhugVMpwKzY0lcOUkYMv3lJ/WnRXMmSrZyOCDXXynBc/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-17.png', linkedinUrl: '/in/alan-guerrero-35f65ce7ed', jobTitle: 'Catering manager', }, @@ -4175,7 +4175,7 @@ export const peopleDemo = [ city: 'New Kimberly', email: 'alan.edwards@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDBCqDxWHrWoby0MEqrsIDH19QKv38z21jNNg/KtclLeR3UOfLCEkDI64rJs0hHqXbi/u4rb75faMKe4qhFqMY2NjEnIZmXJArrNE8L3esWYkjjSKFhgbxkt71sR/CR3G6W6GSRwBwKzU0b+yluefNq91HOirJmMjCoOhrq7K4aaNGmUBmXBJPORWzcfCnyIxJDPudOQMVyutaVfaK/2qcTNHnb8oz/APqo51eyB0mldmzIARVfZg5p2noZNOickFmGT7e1TMmBWyZzNajtVtln0q5RjtBjJz6Y5rkNFihm1a3idQUDj5cda7t7U3EEkLHAdSpPpmuT0bSZ7LxPaQOQ6MSySAEBxjrzWUnubU4t69D1/So1ECrGuAByFHSumh+aFeQfbNeaXt3fWUflwi5J+8qw9al0S/19bqK3neUrLtOZOSoPr6GsIqyudzd3Y9FlGEwSVxzXA+Nyi6PcEpuULkqe4pfFWq6zZ3rWtosr7MEtGMk+3vWPfte3Og3yTmYssDZEmOvtTtezJbsmjnfDkrvYOCMKHO0k5JFa7KSKi0vTRZ2ManO9wHcEYwfSrhj2jiulM8+SadmWxL5ZVsAgGpJrOKS6hv0J2wgLCB0Axg59/wDCoNm5eaWN5Y0MaOQjHkYzWc431NqNXkunszsdPktbmAJNEhYDHzCp51t47mOKIIgGCSDjnNYNiSJFYHg07Vb3SJ40iupQkiHcG2nIPrmueN3od+nQ6K7W2bVpFl2OkgG08HmsrVre2aNrREAWX5SKztMu9IDyJHdi4mbAZyCPpijUZ5I5dyvhwcA+1VZt2JlJRV2ZV6V+0yFegO0fhUSfOOlSGJXGMmpYIvL6iupLQ8yUm5NsgUkVNGm41EI2Pat/T/Dl7caVJqAQBFIKA8llBO44/L9aAWpQidowATgHkH0rShjmuFAiuEjIHBPaoDanyunQ1CIpEOUJHtXGtz002i9JbzwKWnuEk44IGKyblmaTc2Tj1q9HBI7AOTn0q7YaX9suLmJzkKEkU+mdwI/QGtafxGNduUbnOqwJ4FTAEjoa6h/CXV0fb6Cse9sJ7WTa447GumzOA//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-18.png', linkedinUrl: '/in/alan-edwards-2c5694b583', jobTitle: 'Air traffic controller', }, @@ -4185,7 +4185,7 @@ export const peopleDemo = [ city: 'Lake Christina', email: 'ellen.hughes@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-19.png', linkedinUrl: '/in/ellen-hughes-d7dcd7cee8', jobTitle: 'Catering manager', }, @@ -4195,7 +4195,7 @@ export const peopleDemo = [ city: 'Port Josephfort', email: 'jennifer.cox@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDVUVS1bVrXR7Jrm5bA6Ko6sfQVdHSvNPHF1PeayYvM2QWwCrx1bqTUSdioq7Kt14iutUumMjtDESSAjcAf1NUbmUM5dJgYhwu4Y5960vCujPr141sHKKi7i2M4Ga9Nt/h9pSWZhmjMpPRj2PtWEppM6YUnJXR5hbXMsSB4G3NjkxsDn6ium8P+MRcSCxvgC/RHXg/QitW4+GNhEpMFxcRuOVZTjaa861q2fTr6OQNmWKQq0irjdj196IT10CdJpanr2QelNxWP4d1pdYsQSuJYwBJjpn/IrZ7V0J3OVqxDeXBtLKSdYy5QZ2ivIr26m1bWXbaqrLLk4OeteyzQ+dbSRggFlIzXmNtoM9r4jhglUZaQMCOhAPWs6jsa0lc9R8KaLaabZZgiCytje3dq6xMhcbe1cbe3E2mwDyorqR3UkCEgAY+verHh2/1eSRBeu7RyAMBIBuT2OO9ci7s79NkdPNyMEYry/wAaaAnlXE6H5SDIy+hxyR+VdP4n1PU4C62W/bHy7IAWPsM/WsNzNqWm3Uci3SSLEwfz2DAkr1BFPzE7bHI/D83C6nMiZ+z+WSwPrxivRa4LwO4trxopA3mTLhSfQZrvq7IbHnT3JFORTZbZJl80qpkiGV45pF4qvqNob+wktwxUt0IYjn8KVSHMrDpVOSVzprGSG4tlV1B470s6xxTpHEoHQkKPes6wBAUhsk/ex60Xt5pzyBLhpA8ZyCoIIPr71xLserFJ6otIqHUJ45VHrg1V1URCA28QVd/HA9agtbqw+0MIp3eV+8mcmmXY8yXBPtTSbdhTajFtmTa6VBaX5nRRhYxGgxyB1JrQzSlQOBSdK7oqyseTOXNJsUVIoJp0FtJPII4kZ3PRVGa6GDwzcjT2laNTdA8RFuMfh3psSV3YxIS0SlxnaDgkdqtm3ju0BaQAno3enWEBj3xyqc7iGDCmy6cY3PkyMik5A6ivOb1uerG8UivLbR2gLK4LHjPeqKktI5PbFaQsWB3TPvxVSGCaXUjFDEsrOMCNuh/EdKunJKd2RWTnBornrSV0174SnCh7aRSxUExt698GsO70y9sf+PiBkH97qPzrAAADvPMP/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-20.png', linkedinUrl: '/in/jennifer-cox-521071720f', jobTitle: 'Product designer', }, @@ -4205,7 +4205,7 @@ export const peopleDemo = [ city: 'Spencerside', email: 'james.brown@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-21.png', linkedinUrl: '/in/james-brown-a872fe7489', jobTitle: 'Theatre manager', }, @@ -4215,7 +4215,7 @@ export const peopleDemo = [ city: 'New Nicholasshire', email: 'kenneth.mason@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwBKr3t5Dp9nLdTttjjGT7+1WsVwXxDnf7TY2qsdm0yFc9TnA/rWCV2avRGLrniW91o7CBBbA5WNT970ye9ZyFY4TI8XXgLuOT7it3RPBl7q6q29YUIyGfnNdNH8Lb5mWMXkXlnr8uf0NN1ILS5Sozetjgbd3hCXUU7RSp8wweRXV6d40ZVj+1hXhyFaUcEe5FbbfCZFB3Xh3egXpXFeIvCV1oDbwxmtycZHGD70KpCTsDozir2PTYpY7iFJYXV43GVYHginEVheDJN+gJFjmJyp/n/WugIpMkeRXnXjPEniWNXXISJMfQk16P2rkfE+nJPrem3WOrrE4/vDOR/Wi9hqLlsdh4eiWOzhXG0hRx6cV1kJ2oD1NecX8cyMuHutmNyrb4BJA9TWn4evdRV4Y3kujFIQVFxgsuexx0rkUdOY9Dm15bHZzSHaff1rhPGwj/sidiNwABP51Y8T3moFpUje4EcXLC3I3N9M/WsOG0luIriN5LkoYjvjnIbGR2NNRt7wSle8bFPwCHOk3Uh5Vrg7fwArq+9ZHhSzNl4fgRiCWJcke9bJrqbuefa2jCqmowLPa5ZQWiYSKe4INXKRl3KR6jFKUboqnPlldmhp3k3VqiSIDgdTVp/s8N3DGNi8gk9MVh6czKFwe+Me9Je3lrcOsdwj71OQVjJOfrXKl0PRTTRuFbaXVJ432HJyOQap6usFvaPHCoDOMVmWdzaW8zrDv3uRkuhGffJqxfHzZkGcncP8afLrYUmkrsbHHHDGsUS7URQoHpig9adjApprqSsrHmyleTYUSSJDC8shwiAsfpWdea3aWy/uz5z+i9PzrF1y/wBRFpB5yiKK5XzAq91zxk1ViS5aaqZoBewhlgmYsB1KnNbVvNaXcCl5Tz/dOCKyNAt4bjQkWPAC5Ugfwmr1vo8E0hWQlH9jjNcbfvM9GN+VNFmaW0tIXKSE/wC8cmsuPWUTVYIJlIWVDtY9jkfzqzJpMK3IRGd1U/MWOaydfs4kuYJSMSjIUg9F7/0q4NcyM6t3B3OpNMNcpBrl5agBiJkz0c8j8a2LfXbWfiQNEf8Aa102OI//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-22.png', linkedinUrl: '/in/kenneth-mason-7bdf5e7f2b', jobTitle: 'Financial trader', }, @@ -4225,7 +4225,7 @@ export const peopleDemo = [ city: 'Port Jamesport', email: 'kent.mitchell@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0wUyR0ijaSRgqKCWY9gKdXF/ETxYPDuli1WJmuL1GWN+NqY6k9+9Zlk2tfEXQ9NtC0FyLiVsqixdc+vPb3rjp/jHPZRtElrHcv1DyEjb7Y6mvLoILq/vTHbI0krtnAHX3NdMnw31e4jEkjwo57ZJockt2VGEpbI6Ww+NF/JMoudPtDGTztdlbHt1r0nQvF+leIF2W03l3HeCUgN+Hr+FeGz/DnVYkDgxuR1xWZcQz6LKgcukqnKuD0P17VKknsxuEktUfT55pVWuH+HPjCXxHp7296wa8t8Df3dfU+9dz2pkhXg/xZtLj/hLYzPP5pmh3JGGyIlBI9OM4Jr3evEvi/E8Xiq2lLZ861AQY6YYg/wA6AHeBdGS0sRcYBklOcnsK9Jt4iY1JAOB2rzuSN7Oygh825VFiG1LZfmJA55rY8O3F9BdQQyXFxJBIQw8/llz2NcstfePQp6JRO0jhypygAPrXIeLPCMF/YSzpJ5UsYLEgZDgevofepPFT3cd5mGW98pedts+CfbHerOlPNNEYHa6KMuHjul5wR1B70J2VxyV9DzrwXqEuh+NbHeMee4glQdHDHAP1Bwa+gsV886bDt8fafZzZR4NQX5vUBxx+lfRJWupHnS0Y0DIrz34naTHfnS5zFloGYl/Vcr8v9a9C9KxvE+nf2hpXCGRomDhR1P8Ang/hSne2hdK3MrnP6bHDOg3opI4GRUd1d2ljrVskgYLu/gQkDjOT6Co9PLplcYkA6H1FRpcTSXpBs3kwSCzMFH1Fci1dj0o6pWN+2vbO8mkXa+Ffb+8jI/n1HvWjPDFDEGT07ViQXMqRlWsJlU90w4/HvWpLueJQD2zQ9NAatuchpfh2OXxjJqzQ7pFvEKBhwVxyw9wQa9OzxWJoUMU8Md5GDsIO1iPvc/y61sn5eK6ad7anBXcW0ojR0p1CjIpSNorSxz3OH8RQ/wBn6sXQ4Ew8wex6Ef59ais5IP42yp6gmtXxfCJTZsR13r/I1yDWlyjfu89cdelclRJSZ6FGT5EdzAbZYh5LYAHNRGUTSiKM5UkAkdqyNM0q5lQfaJWwewNbkUC2qrtHCsD+tRdXLd2jeiijghWONQqKMKo6AUmM0sU8ckYZGVlPcHIpGNd55gAAAAAAAHmH/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-23.png', linkedinUrl: '/in/kent-mitchell-2685d24cef', jobTitle: 'Horticultural consultant', }, @@ -4235,7 +4235,7 @@ export const peopleDemo = [ city: 'Robertsmouth', email: 'christine.parker@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDkLm5MQULy7nCilsZZLpnRdpC9ZG+6Pp6/Wsi+uCL6XGMKNu49BxzVzSr4RgJCpdzyXI6fSuOq22dVJWRttZ8NP88u0cyy/Ko+lclqsiySkJHGF7t1LfgOldddQm+t0ikmZx1Kg559PrUd74eSDT1jtokMrclh8x/OsYys7s2cW9EefpI0UgKgrjnBNdhpl159orMw3Yq9pfw7mvVEtyWjXqcDnFVtTht/DQ+zCMknrnpj1Fbqqr6GUqMktSwM561Zh6jNVbeRZYEkHRhmrCMAa6DmOR1SJv7UkQAhThsfhVjTba4uf3cWc99o5rsH8Mwato812CVuIgcNng8/dxVv4f6SiC6lkXLb9nI9K5KklqdtKm9G+pHYeGby5a1s4kO/70r/AMMY9PrXo1p4dtrKCNTmRlHVvWsy/wBSbSUIWyuZyegi4H58VV0291OS8jYm6RJUEnlzurhAfXHIPsayS0uzo62R0s0ASPCjjpXkPxGtWaa2IU72ZlH0r0HxNqeo2qi3tY3ZyQC6EcZ+tcNq8PmRQyyRSB1kZN8km/ef7wP/ANYVVON5IirK0GY9orQWkUTfeVADU6sc1GeKAa7zzDqfDGprbXhtZWCxysCpPQMK6ZYktLqR4goEjB229M4HNecqpJBrsNDymnw72Zt2QSxycg/4Yrlrwt7yO3DVW1yvodvA0NzBskUHjv3qForW0JVFAkfkgVUtgR0bgdKdczadIp8+8WOQdWWTaw9qwv0O1JBdIpu0aRco8eefUVxnjGaI/Z4ogAAScVtm7t/tAVL83JVdqqWyR/niuK1u4NzqknPCfKK0oxvMwxL5abXVmWxzSAU7ac04Ia7jzDVtNNup7f7Ssf8Ao4baZCeAf511mkWm61MB7gOPY1saFpLabpqQEBiRl8jgk9at/Y4YpvNiTY44Kjoa5a3NLY6aDjB3ZiwXpt5xbTNsfoCe4q1c6al5HuBjRsfexUmpWtpd4WaPr37g1gXtrdabgRanI8ZPyxkAkfjXNqmd8Z21RBqESaSryBlMhGF2jGa5EguxZuSTkmuh03frFtcTXeXQTNGpP90HGR+OaJ/DZyfIlww/hfofxrrpWitdzhxE3UkYCpUix5qSW1mtpjFMhVx2p8anFbkAAAAAAAcp/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-24.png', linkedinUrl: '/in/christine-parker-53b7e92f21', jobTitle: 'Dietitian', }, @@ -4245,7 +4245,7 @@ export const peopleDemo = [ city: 'Marissashire', email: 'christopher.thomas@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-25.png', linkedinUrl: '/in/christopher-thomas-50eba95625', jobTitle: 'Press photographer', }, @@ -4255,7 +4255,7 @@ export const peopleDemo = [ city: 'Amberborough', email: 'cole.mckenzie@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-26.png', linkedinUrl: '/in/cole-mckenzie-0febe188ad', jobTitle: 'Transport planner', }, @@ -4265,7 +4265,7 @@ export const peopleDemo = [ city: 'Hendersonview', email: 'john.jackson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0s0lOIpMUAcn4+8RT6BoiiycJe3D7I24JUDknB/zzXhTzNftJcXU7GR3LvuPLN3J969T+I2kXGp+JtKiSY4mQiNf7m05Y/qKqXfwtVoRJb3TM+fmVhwaxnUSdjenScldHlv2lwpjc7kBypNQRu0UmUQPjnmvb4vhvpCWaxyqTIEwzg96yrn4e2EEb+XI3c8io9qjT2EjyuaWSTBkbc3p6V6N8MfG93b6nDoOozGW0n+S3ZzkxP2XP909MdjiuB1OzaG8aNmKhTgcVQVpYpFdHZZIzuVhxgjoa1i+phJdD61NJTjSd60Mzm9Ytmk8VafMV+VLWUA++5a1UHAFZXjJ723soLmxDtIjFdiKO/ck9uKy/D9/ql5aub5BHJ5XmDHbnGCOx71x1l71z0MO1yWOlmwMgGsfUSTGyrwxFcrd6x4lW8xHGXiJA+RQOprUiu7+5kMVxAQynG7HB98ismtLm91ex5l4ohkhuGDhkbPQjrXMq7EuM9RXqPjaySXSgzD94rgA1g2fgdXtJ7q8eVWGMLEw+Qepz1PtW8KiUdTknRlKdon0HSUtJXUcZVvSCEVgCrE9ayZRDFbyCMxoWbGBgVqakubUuOqHNcdfjSLtgJrhQFOXTJOSPWuOsnzno4WzhpubtlHbXKupClkOCKLkw2qHao4rJ0+90+ACG1ljLZyArcn86nvctuye1YvTQ6NDF1COO7yJkDJuBAPqKmj0+a5l/cRqJpAVVezD3qGcBmWMevNdF4QtZ3jub65ctukMVuCPuouAT9S2fyrSnDmdjGpV9mm+p1NJS0V3HmEc0QmheMnG5SM1yzWMpUIsiwuh2tgda6zFYGvRR+fD5crR3MmTgchgPX35FY1oXXN2OnDVHGVu5mtCtqpZzGWP8QFZl1qKgN82WPTFUNWOqQv8AcMkZ/iX/AAqKxsp5yJHGB6muS3U7HJstWgkk3SyDGegr0TS1VdKtAuMeUvT6VxwgCx47AUuiz3mm6zcTvPI+nuiJ5BbIVhnLKO3GK3wzvKxz4lWgmf/Z', + 'https://twentyhq.github.io/placeholder-images/people/image-27.png', linkedinUrl: '/in/john-jackson-eaf7698388', jobTitle: 'Engineer, land', }, @@ -4275,7 +4275,7 @@ export const peopleDemo = [ city: 'Christopherport', email: 'denise.gregory@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-28.png', linkedinUrl: '/in/denise-gregory-2a012e2939', jobTitle: 'Community arts worker', }, @@ -4285,7 +4285,7 @@ export const peopleDemo = [ city: 'Cassandrastad', email: 'deanna.mays@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDU20BacBWV4l1JtI0C5ukOJcbI/YnjNSNGPr/jKKwkms9PTzrlPlaQ/cjP9TXG3N5fXsXn3dw9wc52lsL+GOKxY/MuZAMOSx6DvXSQeHbu5hUNBKTj5VOaylLubwhfZGC96Y2AESAZ71tWWs39nBvtrkKOu0dB+BrWtvh1ez2skkuxCV+VAMkfjWDeafNpMbW8/BU8e9Tzp7FunJbno3h3Wl1qwLvtFxGdsig/qPatkLXiFjfzadqcN3auVdWHH94ele3o25FbGMgHFbRdznkrMlUVyPxHkKeHYlHAe4VW/In+ldeK5D4i2FxeaFDJAMpby75B7YwD+f8AOm9hLcXwL4Ws3sodQmUySyDIB6LXo0djEg4RQPYV56sl3p3hzTkt4pzI1uuGjfaFIXP4mtfwpqus3c8dte7iGGQzjkex964Gm9T04NJKJ2JTahCgY+lcR4w8NR6nZSSJ8lwoLL7+1N8SaprcdzIlo0ixRAk+WOWx6UmkXl7ex+XcQXCMBks7ZB4/nRZrUbs/dPGDuinwfvI38q96spDc2FvORgyRK5HpkZrzC98OGfxhcReW5tEbzJGjHIXGa9XhjCW8aqMKFAA9sV2QkmefUg46sUdKbcwJdWskEoykilTT1HFO7Vo9TJOzuGjpGNPjsrgKzRKEORwcd60Lc2sGoIgKRhRnsMmsqJClyW3E5PeoNS1HTHcRzwzvIucPHESV/GvOaak0evTtOKaNaA2lzM8bGN8kkHgg80l60NnCViQLkdBWVpmoaWiGK3hlhYnOHiK5P1q3e/Py3apfYtqxk2+nq1011t2uxwzf3hjGK1x92ub8M3d3fTalPPMzQLcFIIz0RQSK6MdK7aMOVXZ5mIqc7SXQQdKUGlwBgEgZ4GT1q3ZWa3M0iu3yogY49zitbq9jCzKE+FhMm4KRgD3zximRQ296oMk7ROvBxwRVzxLp4gs/3QbGN4HupDj9Fas+4s1mQSxn7wyCK48RbnO/Ct8paFvb2cZP2gv7t1qnNMZVbaSUUEk+tRW9gzEmaRnOeBWmtqog24AHesbnS3cy9DFoNKi+xqVjychuu7POa06k0bQfs1gIVUhCWdXLZYEnoR9D+lMnUW9ybeQgOORnuPUV6MXpdnkHkzVpM//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-29.png', linkedinUrl: '/in/deanna-mays-d96cf68df8', jobTitle: 'Television camera operator', }, @@ -4295,7 +4295,7 @@ export const peopleDemo = [ city: 'Wallaceville', email: 'jennifer.smith@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-30.png', linkedinUrl: '/in/jennifer-smith-cff724d712', jobTitle: 'Science writer', }, @@ -4305,7 +4305,7 @@ export const peopleDemo = [ city: 'Lake Justin', email: 'dylan.jimenez@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-31.png', linkedinUrl: '/in/dylan-jimenez-611f4f7667', jobTitle: 'Runner, broadcasting/film/video', }, @@ -4315,7 +4315,7 @@ export const peopleDemo = [ city: 'East Sarah', email: 'amber.mullins@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwCKlBpm6mS3CW0LzSfdUZNSBLJLHDGZZXVI15LMcAVzlz42tYJmSG3aZV6Nu2g1z+oaleeILxI40YgnEcCHOfeta2+HGqXS+ZIyRHHQtms5VEjaFGUtkNPj0mTH9ng56BZOf5Vt6br1rqigL+7n/iiY8/h61kzfDTUISHhuo9wHIwf51zWpWd7pNwokASVG+V1Hce9SqqbsmVKg4q7R6QwpAKyPDetNrFs8c6gXMONxHRh61t7MGtkznasLWR4mjkfRnMbEBSCwH8Q6Vr4qhra7tFuuDwmePrQ9hx3DwDosccb3zKC7nYnso6/nXpEceF4XivP9PEVp4asTLDdTNJHlYoGK+pyTXQ+GZJkABN0kLchLh9xX8f6V50ld3Z69N2SidBIuFPyce9cP4u0W2vbSdyvzkbtvqR3q94hllmkaQreSxpnCW8hXOKoQlLiImKC7t5EH7yOdiwI9cmklbVDevus8/wDCw+xeIIkjkLecrKy+w/8A1V6Cea83t1ks/G0UanAFyQPof/116XjivQhseTUVnYTbSmAXCmA4xICvIyOaXFKCVII6jmqaurExdmmdDokUK6fDDgERqFGR6cU+9vLW0vIo5ZBGpBIwvoKhsZFldnjPB7dOcVXutWljuDD/AGbJKeclsAEe2a8uzvZnuQtK3KT6RcQXrS7WDrk4yPfHel1hYoLdwoAO09KqWWqyy3RibT5YmPO5QCo+uDS6uC8bs7cLQ9NBtW3OXs9IjM9zfNEoneQMjnB+UYyPbvWmOlVtP1KO/wBPHkwPEI3aNi2PnIOMj2qwOa7qEWldnlYmcW0o9CQDNLtpQOKcK3OYmtZmt2OOhrZia2uogZGBB9e1YiCrI037WuUcoxGeDXFiYpSUu56GEm3Fx7F65ktrNCysoH1rCurg3uQmfLXlj61cTw+wBaeVn9MmluLdbewYIMZrmude5iaZafZdOiiPJ5Y/ic1bC4otH8y3XgZAwal2816kXdaHjSTTAAAAAAAHc//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-32.png', linkedinUrl: '/in/amber-mullins-7c2cf23e98', jobTitle: 'Scientist, research (medical)', }, @@ -4325,7 +4325,7 @@ export const peopleDemo = [ city: 'Vegastad', email: 'kirsten.watson@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-33.png', linkedinUrl: '/in/kirsten-watson-e01dabbf2c', jobTitle: 'Radiographer, therapeutic', }, @@ -4335,7 +4335,7 @@ export const peopleDemo = [ city: 'Lawsonberg', email: 'holly.winters@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0k1z/AIq8V2XhXThcXAMs8nENupwzn+g9TW5czx2ttLcSnEcSF3PoAMmvmbXten8Qa3capdE5c4iTtGg+6o/Ch6DSubOqeNvEWuSky3rW0JPywQHYoH8z+NZX2+/jzi6lbPcSEGqdrDcXkixQIxdjwEGT+NdXZ/DfV7tA8kscII4Vsk1lKajuzaNOUtkYul+Kta0m5D2+oXAOc4dyyN7FTxXuXhHxRF4m0wSMgivI8CaLP6j1BrzqT4X3I07bJcKZlbIIFcjJNqHhbVU2O8VxCwZHXjI9D6j2ojVjJ2Qp0ZRV2fSmKUCqul3Y1DSrS8HSeFZPzGatitTAzfEMby+HNTjiALtayBQen3TXy5bxPcTIifeYhRX1feyRw2NxLKpaNI2LKO4xyK8C0rw09j4ztoXBaBiZYmI6oBkZ9+aipNRNqdOUteh2vhDw1BplmrMA1w3LOe3tXbxIQo6Vx+qvcQJ5cUEkgIxkNgDj69az/Ds2ppcxAmdI5uSkjZ2c459K89pv3meorR91HojZdD2+teWfE/TYzaRXWMSo+3I75/8A1Vt+L7rU4LgQW7TbV27hCcEk1j6tZS3fhx4pkkGy4j3MX3bhuwSM/U1dPRqRnV1i4o9Q8O20tn4b022mx5kVtGrY9dorUqOEL5EezO3YMZ9MVJXoHlDZI1lieNxlXBUj1Brz+70xrTU1uJAd8blB6bcYFehVj69pxu7cTRvseL5iOzqOxrGtT5ldbo6MPW5HZ7MqW7Q3UOx0UjHcU1ra3tpESNF3feJAxiqlmdnK9+ar6jfaTMgW7uFRlYEgMc5H0rgWuh6ljbvLW3uL4rIEYFQQTg1VnsYLlo7IINhdSQPQEGsuxvtL8xxBdCWY4G4tz7da6DSY/OunmYH5AMfU1cItzSM6suSDbNscAAdKKKBXpHjC1HcANbSg9Ch/lUlZ2o6gkUTwxkNKwI46LmlOSirsuEXKVkcclyYVVWOAehqf7Et4AyNGpHRj/nmlltA0eCOBVJrC6T5onAjzXlJntJtbFsWP2fLO0bt0BUdPoK7HTrU2loqNzI3zOfeuPt7d1wS5cnGCa6/T70XkLbhtljO2Rff1Hsa68NZtt7nFjXJpdi5SUtFdhwAAAAAAHnn/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-34.png', linkedinUrl: '/in/holly-winters-ad7c60377c', jobTitle: 'Public house manager', }, @@ -4345,7 +4345,7 @@ export const peopleDemo = [ city: 'New Angelaport', email: 'matthew.jenkins@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDt6KXHFGKRR5/8Q/GFzorx6dYP5czoHklB5UE8AenSvKLi4u7+9828mkkk7M7bq6rU9NvvEnji8tZQI9pIdmHpwD/KtGX4XahDBvhuIpicDbgjiodSKdmWqUpK6RwLlmYhlC7R26Gq0rFpPl4U9q9dh+FMRsh5l0yTEZIAyB7VQ1T4cxWdpJJHNllXPTrU+2iWqEzhNA1yXRNQjukJKLw655avftE1m017TI72zfKtwynqjY5Br5wntnikYY6EjJ7V6f8ABu4YxatARld0cgOeh5GMVqYnqlJTqSgR59psci+NdeMy/OJVwfRTyP0xXewAlFIJPFcT4iN7p+vXd1YxFmuI4gcLnJAYc5qz4Z1jV9TkaC6tvIkVC2egP+FcVVe+2elQfuJHYyZVTzWHrcxSxk2DJ2k8Vzl/4j8Q291IkdskkaD+FeTzjj1q5Z6neX4CXEDRvjkMhBH+NZtO1zW6vY8f1pg11I6NjJ5Fdx8G1l+16swH7ny4wT/tZOP0zWR4x0YDXYo7aP5rhCdo6ZBr0HwFo0WhpdWqKxd0jleTdkMcHoO1dkKisl3PPnSleT6I7EUUY4pK1MShdiJr1VmAIaPv7GnWMcYa6eJVUKm0Y4zVbXo28iK4Q4MbYP0P/wBfFctNcmZ2C3q2+Rh03bc1xVU+dnpYdp01bc66GKzmlMcqKHwDgjk0XaW9pGREAK52zurWFPKS6SWQtwxky2fx5q9dFmI3PnIzWUtNDfQy1s1udbjuSqtJCrBd3RckZNdXpNqLW1OBjcePYVyUdq2o3QhjkZC0qgurEEKDlv0BrvMYFdFCP2mceJqaci6gDxSVR0jVYdXtDPCrKFYoVbsRV6uo4SO4t1uraSB8hXUjI7e9cZ9hvY5TAGiE0fynf0PvXU6trNjodkbq9l2L0VRyzn0ArzyXxZJ4j1ZRFALULGSpVssQDxuNZVo3XN2OjDVHGVl1OnVGtIS0/klyMfLWZc35lkEcbb3PYVREN/eZDTDZ0IBwa09N05IGzwSO9cTsd15N6liw/wCJdLBKVL4bLY6nP/666DTtd0/VpJobWYmeA4lhdSrp9Qe3vWPevDb2zTzOEjQZLGuIOu3EniEX2nDynOI14++PRvWt8M5aroc2KgAjHR9T/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-35.png', linkedinUrl: '/in/matthew-jenkins-d451b82929', jobTitle: 'Neurosurgeon', }, @@ -4355,7 +4355,7 @@ export const peopleDemo = [ city: 'Port Richard', email: 'elizabeth.williams@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-36.png', linkedinUrl: '/in/elizabeth-williams-f8ae89860c', jobTitle: 'Ranger/warden', }, @@ -4365,7 +4365,7 @@ export const peopleDemo = [ city: 'Austinfort', email: 'sophia.carpenter@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-37.png', linkedinUrl: '/in/sophia-carpenter-41f6371dcf', jobTitle: 'Translator', }, @@ -4375,7 +4375,7 @@ export const peopleDemo = [ city: 'Huffmanville', email: 'sarah.duke@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-38.png', linkedinUrl: '/in/sarah-duke-9c48b2bc47', jobTitle: 'Holiday representative', }, @@ -4385,7 +4385,7 @@ export const peopleDemo = [ city: 'South Loriport', email: 'colin.smith@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwC3CCDU1NC4NUda1B9O09pYk3zudkY7bj3P0rzDuDU9astKT/SJR5h+7Gv3j/hWBceLmwGURxKx+UsCc1U03wdqOswyXVzcDfIxKl+d3vWrbfDm7ZDFcywlc8HGTV+6uo1Cb6EEHit0OLlEZP7ynBretNRtr5SYHyR1HcVnH4ZusuDdK0Y/2cVU1bw5d+GrYXthOWCn51Pt3qW43sivZySuzpqMVU0q9XUtOiuQACwwwHZu9XcUiR5Fc74ruPKhtYh/G5P5f/rro657xRD5gsnC7ikhVgOuGxg/mKa3Czex1GloFtokUYAUYrcC4jHz5rhdSvZkgUW63IUjC+Vwcik8P6jqr3MUczymOXoZRyPQVCi7XOrmV7HcMDj72KwNakC27h/mTac1jeIdX1SK4uIbaSRRCPmaNMk/TP1qra39zdW7x3gkb5Od688ik4O1x8yvyj/DMgliuthBiDgrjtxzW7jmuc8Iwm1iuEfCmR8oCeSB1NdJWj3OSzW4GqeoQefbYH3lYMT7DmrZpsgYxOqkfMuORSsVCST1J7NVmjKMM/WlZ7O21GFZGiiwwwScZPtUNpKNi4POOlZ17dR3qbDazSgH7yR5we+D/hUx10Or0NEPZ3OpziN45dx5wc4P/wCqo7+GKGMoq4PXpWVp09vYyMiwTQh2GfNjIyfrWhfzZTGcsaUrrQZW0q3Ealm+8M4z6GtOoreJo4gHADd8HNS1a2OWpK8tAo4AyTge9VL/AFWx0yPzLu4SP0Xqx+grkda8afaraS1soWRJFKmRz82O+AOlaQhKWxhKSRuf2lHHJ5iyE20+WilXpWowtnswv2jyhjAKHpWJpcC3XhmzRMDEYA+o4qt5NwjGMqw+h/lWb3OuLdkzccW8cDL5wlyDy1U9Ona+vEQyB0jy7Edz2FZ7W8xXCkhTxzxmm3F2+gC1uFUsnm7ZFHG4EH+tJauyCbfK2dieKSsC18Y6TdSiJpXgc9PNXA/MVuxSxyrujkRx6q2a9j//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-39.png', linkedinUrl: '/in/colin-smith-319020345b', jobTitle: 'Gaffer', }, @@ -4395,7 +4395,7 @@ export const peopleDemo = [ city: 'East Maryland', email: 'christine.baldwin@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-40.png', linkedinUrl: '/in/christine-baldwin-849d34d1c9', jobTitle: 'Emergency planning/management officer', }, @@ -4405,7 +4405,7 @@ export const peopleDemo = [ city: 'Jeffmouth', email: 'michael.johns@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDgGHNJnFOYGmkYUsegGaRRFNcRW4BkbGegHU1DHqMskgWJGRfXbk1kStNdzmQqTk4UDsPSuo0XQr9lWQRP833Rtz+dZzlY1hC7Bm1MJ5ySRSIcfKVx+tWrXUDuUSoY39M8VuR+DtTmw0s6KG+8AOo965/XvD97pIdkYSRZzk9qzVQ0dJ9jV8yGVMbE3Z5yvBHersIghtLm4jjjUxJ5jYwMjIB/nXK2F2XtxuYll4Oa0opldTG4DI3BU9DWtr6owehmk1Tv5jDasV6t8tXSOarXkBngKjG7qM1TEjc8JaVB9jileMOzfNkivRbWPbGvyAAeleb2zXNnpdkYGlDFAF2EAZ981ueH/EOrzXUFtcQjLngkY49DXHJN6noQaVoneRBmHA4rE8RwLJp8wK7jtPFYniHVtct7gwWpZAmSSgHPt9as6WbyeEi5WXkfMzvkHPtUW0uXfWx5vbs02pSKG69BjrV9GIxVpNI+xRT3zBWJlZU56YOKqquK66bujgqxs0K4waYCAwNTS8LudTGT68g1VJyatSTM7NHX6CbdrZIZcMFGBkdq3IIo11e1jjVQAdxPSuO0dznAJypyPpWzc3Fu91F5zurp93y1JI7dRXJJNSsejTfNFNHYOsJvJEkRTkkqSAajv5YoYSqKASMACszSruy27FZi7P8AMzqQSfqaXW5Gis7iQclEO2otrYttJHNeJHjgWKzjOWJ82TtzjA/rXPjmpJQzNlmLE9yc0iKc13Qjyqx5tSfPK5mRR3rzokhafcMCPPf2x3rpdM8J3d5KjEyQwkcxsoD/AOAr0mw8M2tlAqQxhBj5mIyzH3NaP2WO3iOwAYqFC+rG3bY871bTYtHjgEI+YOqMQeueKbaKJZQHmKH17it7xTYZ0/zgpbyzubAyfr+HX8KwreOK7iDJKgcdcGsqqd7nRRlZG9BGsMI3XPmDrk96nEe9d7jIY4ANZdnB5f32346ZOa2beJryRE3bYgcsR1Pt7VkouT0NZTS1bJrfwlpmoee5tgEYgIQSMEdSKoXvw3lJZ9OvIwf4Y5k/Qkf4V3lpCIoUjVdoA6elXFxx6mu2MFx5XP/Z', + 'https://twentyhq.github.io/placeholder-images/people/image-41.png', linkedinUrl: '/in/michael-johns-d7c1497c08', jobTitle: 'Waste management officer', }, @@ -4415,7 +4415,7 @@ export const peopleDemo = [ city: 'New Jennifer', email: 'jeffery.griffin@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwCHx94sOiWg0+ywLydfmkPHlIeM/U814+pMylir5znOevvXX/ErLeMp97HasMeAenSud0+xm1K6EMK8t6Vm3Y0irl7SbRHUuSiMBxu5BNSKN8nl3KxLg5Qq2QD6fSun0fwYbgIl0pRB3brmuwtfh/pBi24+c87iaw9ornT7GVjx6U3drIXQMAXyrY7/AOeK7TwjrElveJAeI5/vRk9G9q9G/wCEP0xLOOF4Vk8vkEiuM8ReH7fTNc07UIAUTzwskY6E9jVKpd2JlStG52IweRTgvFAFPHStjmPJvirC0fiWOUDKvbp+YJrM8IhheIFQk5yT6Cu78U2aXOoXAuxJOrsoiiHIUAdfbr1rG8N6f9iF3GRlllMYJ68VzzqXTR1wo8ri77nbWJDqPeuhs48j3xjpXAPe39rI0Fujs2CwUJk8fWk03xF4gjniW6tmEcmCpZMED39KwUep0uWvKellSVIJIrmPEdsLlrOLsblM/QZNVvEmp61aRJHZRM0rRh8rj16D1NR6NDqEsfnagZCyOCN5BGcVcVqmRUdotG3jFKOlB5pBXYecZ+s2KyMtwVLADDbRkj3rm7fCTPMj7keTJOOM9M/pXfKMiuOv40hvZ4FUKgc4A7CuatC2qOyhVbXK+hu2cVrej97GM9c96fqUNtbqqRqC2MnHJrLs3eH5gei5/Cob+eO+KtBfrDMPlLBwMj8axXY69Dq3it5Y7ZrpVIZAAWHemTtGAIolAUelY1tcNJbfZ767jkdflXYw/A1oQhiPnPI4rSC99GNZpU2PIpKcaaa6zzi5GOK5XWo86rcFeSCOn0Fb1y10UBtiFUAl+MsfpXOIj/aJS+Tk5yawxEre6dWGhrzEcN0ybORjBVge4NX0sVnYPGkGWHDMorMurZ0YgKSOopbRdQyPKVsdMnpXOu51qVjdWza0iO8xMx4AjUCr8SFYwG+93qhaWbyxj7Q7SE9cHGPpV7S7G6aC4SSdpRFMUjkccsuAefUgkjPtXRRs2+5y4lyaT6DiOKYasPaXCjOzcO+3nFViCCQQQfQ10HGf/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-42.png', linkedinUrl: '/in/jeffery-griffin-755dd4b413', jobTitle: 'Embryologist, clinical', }, @@ -4425,7 +4425,7 @@ export const peopleDemo = [ city: 'West Leah', email: 'mike.hernandez@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDPIpKeVNQ3c62dpLcOMiNc49faoLEuLqCzi825lWNPc9fp61hT+MYVbbBASe/mMBxUWl6Nf+Kr17qR1ijDY3MNwX2Uf1rqofhVZtueW9kZ25yFAxUOok7GipSaujnB4uhbb/o2Rn5mD9B64xW5Bcw3cQeJwfUZ5FNu/hVbKrNHeSZI7iucOl33hzUYx5u+F2xvPr6EUKaewOlKKuzqMUqrzRaSpeWqTp0Yfke9ThKq5nYXbWR4ibZpwTcV8xwDj0HNbe2sbxLCX06JwDhZlycdMgigaOl8J28cOmQJGONoNdgmdgA5rgHS4tNPgijFyVMQ4tx8xIHrVzw0NRS7jEstz9nk+YrP95a5bdTuT2R1tzkIwPBxXCeKBELaTcAVx1PrmjX5NUmv7h4pbn7PCdu235Zv1qjMtxfWc0ExmwIyMSjDA4oS6hJ3Viv4ZuhcW9zGAcRyDHsCP/rVt1heDoGGnTOwwTIB9cCui2V1HCJThardwSo2DgYCk8EngU3HFPt5fInVyMrnkeoqZK6KpyUZJs3tIkhmtI0fBIHcVJc3dlaahBDJNDCD0yQMn2rE06YJI4DYCs2AeuM5pl/qelXAVb2SBSMgbxkjP8q50nex2pq10XdOns7vUruNZY5V3HoQcGoNf+z21u/lgDjnFZVne6bBOx06SFlLYIXg5pdWZp3CD+Ngv50W1sDloQaTbiJUfHzCPY3vzkVpg02KIqvOM8dKkC10RVkcdSSctCEUuKAKcBVmZXnYwurq23PBPatTbNLbA26qzgYA45H41lSs76lLaPF8giRgT/Fuz/LFVftWoWasqxmVIzgYPzAf1rnl8R2Um1FM1pYpYozJKi7+y5BxWFbXD3WrwRkkhGLN9ccCq9xq15dblWOSMnj5qgl87SLRZ4wTKjBm98kZ/ShbhNuSZ17cUgoGT1HNJmug4z//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-43.png', linkedinUrl: '/in/mike-hernandez-619531cf07', jobTitle: 'Conservation officer, nature', }, @@ -4435,7 +4435,7 @@ export const peopleDemo = [ city: 'Morafurt', email: 'chelsea.robinson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDhG5qJl700O1BYnqeKzRoxVwpyxAFSySQpGjktluijrUUNtNe3MMNuu5pW2qOlen6R8PrZY1ku5WmuNv3ugX6Csp1VE2hRctTytbxklKSWyEH86lnuGiCuq4B6gmvTr34Y6e0LbHmVzzuU1574h0KbRVaCfdJHnMbnqKhTUnoaOEorUjtLyK4G0cP6VcDAVyMErQXCyK2MHrXWQQPcRiRWXB7itDL0M8CmsAfl6Z708Ux88YqzM6nwBbx3upyXGzP2VNiD0yev6V7BbjbEOM8dq8e8Fk2tlqMi2rXCvKigK2MZz3ruPDdzeTlV8m5ijbOEuDkr+NcU1eTZ6FN+6kda7HyyVrkfFWlQ6np0sDqC5GVPoara1Nc2ty0zW95dgciOJiFxnHTuatWsk178ps5LfaMEE8f4Ummlcq6bseEXFv5U8kT8OjEGtvw9clbF42P3HOPpVrxlokw8TslrGWEyh+PXvVOys5LFpoiwfkHI78V0qSaOSUWmSlBUbR56VY28c00CruZWO5+HbwLa3lrKB8zq34Yx/Su9tzBDPtUooVCewya8o8LXH2fVlXOBICv49RXc3V3pLSqt4W8xUwdmcgHtXLNPmO+l70LG9CYbpSsgUMnPODkVXv7yGziIjAAxVKzutIW2FvYNHGw6JnB/I1XvYix3yNkDoKzfY0tYy/s8Us76hc/KIBv35xtA5NcPpU0eoapqNyQfJeQlA3bnj9Kk8aX1++opp8NxIto8as8a8AnPf17cVBbQ/ZIVSLpjr6n1renGyuc1WV3ZFtbRG6imvZxp610I0t/7uPrVS502YsQozitNTHQy7cGGZJEOGQgg12llLHqCLIZzCw4JHUe1WdE8Ar5aXOpyMSQGECcAf7xrX8Q2UGnaZZRwQpFEZuQq4/hOKicdLmlKpaVkZwiitYy4n81j1Yjmq5drxwqklR1NQvahpQZHIT09a17K3ZyIbaLdIw4A7VzPXY7L21Zx+taGt5crcnd8p2fKM/Sk1Hw9daSIGuY8CZcj/ZPofevWNH0FLGLfOVluCSSey/SpNTtoLkCGSNZFyCQRXTGLjH3jilNSn7p//9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-44.png', linkedinUrl: '/in/chelsea-robinson-65dedb9ed7', jobTitle: 'Restaurant manager, fast food', }, @@ -4445,7 +4445,7 @@ export const peopleDemo = [ city: 'Michaelview', email: 'derek.small@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-45.png', linkedinUrl: '/in/derek-small-3b02aeb21a', jobTitle: 'Nutritional therapist', }, @@ -4455,7 +4455,7 @@ export const peopleDemo = [ city: 'Port Chelsea', email: 'robin.miranda@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwB+KUUu2lArnNivd3UNjbSXNw4SJBkk/wAh71w+reK57mM+WTbRHhVU/Ow9z/hUfjfVnudUXTo2xFBgvjux/wABVOw0G51RVFunJGVz/MmpbtuXCLexjtcSzuQxVF6kknJpkJVGyV+X2Gc129j4DKB/tL75gDgAcdK5q7svsEkq9UB4z1BpKpF6IuVGUVdkC3clpMs9rK0cg5BU/wA/WvRvDuuRa1ZbuFuI8CVPT3Hsa8qkk80Z4DL6dxWl4Y1M6brkMjZ8qQ+XJ9D3/PFaW0Mmz1/FL2pcUuKQjym00248QeLLpIl8wiUlznoM4r2TTdGj0+IKFUHAGAOg9K85sNGudG1jUkFr56T7WhmDEbAWPfsa7jwrf31zamO7jlUKpZGl+9gHGDXNWTb8jvwzSj6m5Jp5bLAbc9/Q+ory3xxol3azy3CQs0MnLFRkBvWui1i51JbmW5UXLxxjd5aORuGccKCM1cs7ybVYhHJaTQEDBDcqeKhJx941lad4s8MdsMe3tRFLhvQjkV1fjrw8lhdi6tY9sMp+ZR0Vqybbw5NL4em1dpCnlk7UK8OBjPPbr+ldsZxcUzzpUpqbiuh7NSik7UoNIguWCxMzrIoII71dEccaTsigADaAKyI3KSZFNuJtKmcm4uiuD8yhiMketclVe8ephWnTVtzZhhtrn7yqXU4IPUUt2YrSIiMAADoKo2d3pYHl2tzEXJyAGyxNF4jyk5bAArN9jfQ5+5t49Rn23C7o9+dvrWN4v8vS/C32JFEb3Dqix5ycZyx/LArT1a5aztpZYnKNChcMOxFeW3Oq3ut6pDNfTtNIWCjjAAz0AHStaMHJ36I5cRVUU11Z7ZRTgBjrRius84AKVdP+1fMsio4GD70AYrndb1x7LWrKztZMvJIqzKOdqn+vesqkObVHRh6zpyOsgsY7FC3ybj1buao3upKEZUO5j2FQva3d0xjF4cd1xg4qSPTI7cgfeauRne5NnNeKFeHwveyufndcfma8wsn8m4hlH8LA17D4qtVn0S4jY7U2HmvIJIGidozwyGunDv3WjixUXzIAAAAAAAABn//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-46.png', linkedinUrl: '/in/robin-miranda-3d69d8721e', jobTitle: 'Logistics and distribution manager', }, @@ -4465,7 +4465,7 @@ export const peopleDemo = [ city: 'Allenstad', email: 'alexander.bryant@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-47.png', linkedinUrl: '/in/alexander-bryant-8e40b5c156', jobTitle: 'Museum education officer', }, @@ -4475,7 +4475,7 @@ export const peopleDemo = [ city: 'Lake Lauraville', email: 'jennifer.moody@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-48.png', linkedinUrl: '/in/jennifer-moody-92078fa8a0', jobTitle: 'Teacher, adult education', }, @@ -4485,7 +4485,7 @@ export const peopleDemo = [ city: 'Brittneymouth', email: 'kathleen.coleman@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-49.png', linkedinUrl: '/in/kathleen-coleman-fbba0d93b5', jobTitle: 'Exhibition designer', }, @@ -4495,7 +4495,7 @@ export const peopleDemo = [ city: 'Gomeztown', email: 'miguel.malone@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDt8DFGKWkoAzda1uz0GwN3eMcZwiKMs59BXnmqeI9W1krGpMMbnIhTjj39a6PW7P8AtbxPGs4DW9oo2Iehc85P+e1bUWh2jOJ2gBkxXPUq2djppUbrmZ5tPp1xHFi4Tf3yB92ooru90l/tEAkiP99Djj1I716vcWkbx7WiUgDoRXOarawlCpjXZ0xislVZs6CE8L+No9SdbLUSqXJOI5MYD+xHY12eK8K1HRvsd65iZl53RMD0PpXsXh69l1Hw/ZXU2PNaPDkdyDgn9K64yujinHldjUopaKok52ND/bd0SMnzK3kJUciuX11rmC8kltPM3yEYCgAghevP0qXQ9V1GdFW7BXKEjeMN+IrinH3mz0KUvdSOglJCEHgVzGqnfwBVLU9W1l2le3LNDHz+7TLNz0HrUaXF3OcSozEH5weo9/pUuL3NOZbGJq8ilShXJ7A/Su98If8AIq2Xy7chjj/gRrgtTtZLy6EaS+Ucg7sZrvfDM7CzNgyAC1VVVgfvD3966KUlojjqwbvLoblLTe1LWxzlGVI3vmSRQQygjNNaOJTOUCjYmDjjmmaoTBJFcc4AKn+f+Ncfe339oysYZDGrjy3VZNpx6n/PeuSafOz0KUlyI6jSYreZGUqvmqMlT1xSXyw20TiNQGauX0TVYdPCRMUV87eW5atLVr3NsSmdzrlfbNQ00aXRlWq+bqRwqsApznp1/wD112mh2xhsTIy4eQ5z6gcCuN8MLDJrCQ3EgXIK4ZsbyBnHv9PavRcYGBwBW9KOtzlr1NOUQdKKjkmigjLyyKijqWOKx7nxPbRHbbxvMex+6K2cktzmUW9jS1O1kutPljhOJsbo8/3h2/pXNIsjabE0JjimVdrq3GCOvbrmq8+vahezFBN5UQONsfGfx61mWJubiC6Ec5Vo7h1bIzwcEfzrnqTi9UdVFSibEqW8duTL5byOCPXH41yTalLcXcsKv5sg+RQB0A7n0rTbTtZe3KFoI4wMb+pI9R6VLpelLZRtNJg/h+tZ8ySNmpSepzmrWsqXum26El/MMrt3GOc169pF+NS0uG4/jI2yD0Yda80lKzXctyTnjA+lJaXl9bSs9lPJH/e2tgH8K0pzcVqYVYKT0P/Z', + 'https://twentyhq.github.io/placeholder-images/people/image-50.png', linkedinUrl: '/in/miguel-malone-931db4892a', jobTitle: 'Industrial buyer', }, @@ -4505,7 +4505,7 @@ export const peopleDemo = [ city: 'North Tiffany', email: 'eric.kramer@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwC6cU3vS4JJAGTTee/b1rlOpDJp4raFpp5EjjXkuxwBXN3Hje0jci0t2mXtI7bAfoOtUms9Q8Z6yxicRadbsVQkZBPrjuf5V0Vv8LLaRg89/LJ6gKAKOaMdxqE5apGGvj7acyWcRXuFkINdPpOtWWtW/mWz/MB8yHqtOuPhlovlY2zA/wB7dXJar4QufDt0l9pVy/lxsC6sOVHr7ilzwlohulOKuzuiBTgMVS06+XULMTLgMDtdf7rDqKurnsKZJByKz9bmaLRbtlYhim0Ee/FaB5qnqtuZ9MnUAtgBiB6A0dQJ/B9olto1sigA43H3zXbwjCDA/KvO5vtVpa28Vs8yHygQIU3MSBWr4dv9XMkUdw8hRzkNKuGArna+0die0TsJD8pFcxr+xbWXIyNhzmqevXWsvOwtHkCRgkmMAkgdgO5qpZm5nJFwZyCv7xJgMjIpW6lX1sZvhchZbxByrFXBz16j/CukBrnvDVu1vdXoYYiLlIif4sEk4+nFdEVHvXRe5xNNEFDRCeKSI/xKcY9aUcinKdkisO1DWgRlZpmrpaQXFsm4DcB1NTS3Vlb6lBFJNEnPA4GTjnArEsHlTIQ8jOAfakkngun8u4t5Sw4z5JP+RXOk9jvVnsbFjdWV1czIs0TjcehBwR6+lGqCGKFxGqrkckVjQzwW8hS2t5lY8H9yas3x3RHcxyFy3PSlLsHqVdPt0SFXBzlmYcdM9f8APvV0pxUVopW1iBGBtzVoAYrogrLU4qsuaWhngYp4A20oXFKVJ57VdjIqXDPbKZlyFzyR2rRjEFzAheT7w4Iqtdj/AIll0wXcUjLEVzsi3sBX7JISj8hfT6VjOKTOqjNtHWyPBaQnZJk9yTWM1z9ufyIySrctjsKzGt9TuSFnI5/hretLEWVpsiXfO4xx3J7Vm7dDTV7lTQL67vrS/mnC+VbXPkR7VK5HT8ccV0SWshUFjwRkY5qhexLpVhaadGw37vNlYd2Of65rXs5fIghRjksoOO9d8aV4pnnSAAn7zSP/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-51.png', linkedinUrl: '/in/eric-kramer-911574885e', jobTitle: 'Surveyor, planning and development', }, @@ -4515,7 +4515,7 @@ export const peopleDemo = [ city: 'Christinaberg', email: 'david.harmon@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-52.png', linkedinUrl: '/in/david-harmon-a02ccbfe74', jobTitle: 'Trade mark attorney', }, @@ -4525,7 +4525,7 @@ export const peopleDemo = [ city: 'New Dustin', email: 'michael.turner@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDshCmNrAEHsartY2q7mVV2n72OtR2980jEuhVf7x71MSrcj7prndmSZU1rY2xaVVCAck1z954rjRikAB2nBZjgfhUuuvc6pqraTaqypj942cfn7VDH8MfNAeW/fJHIA4oXLHc2hSk1cpHxmJJGRIyu3gNgEE1qaT4lt76T7PuxKOSMjH4VdX4b6asRAlkDkckHArHu/h79h3TWly+9ASvY0OUGjT2Mjoixn5WTp3pFt5PODs5KgdhXE6Jrl1b3gtbmNgvmbGbOa9BUAJt389hS5UjCSsXGh3Dy/LwKZPKYLfKgMFBJq0tzDIQqkg1FPCCjKcEEdKqSJW5zugYuLm4vMEvLJg/QV18SnA5zXn0ElzaaYCjzI0jyH9zHuYkMf8K1/Dt/qM86Q3LyHI3ZkQKR9cVzy3bPUgvdSOtbIGc1n30pWIjGa5zWNQ1SO8YRSz+Wn8MKBifzqxaXs9yoSTzd2MkTR7WH9DUva5aWtjgtTby9TZ4jgM2TXc6SsktlBMWJJQc1yXiHTpW1ww2qElwHAHb1/Cuz0eMWemW8THJCDODn9a6OZcqOCtFptmjNEqEyoS0lPiikmhPmHPsatxW6PLvJA9RUkygY24x7Vq4nMZemwQwxG2k2sY2I5HvmrNo9ql/JtaNNqHAzz9aoyoyXshzweePpWZKwuXObafcONwG3j/CuPXmaPZh70U0b0EtnLNtZkfd/EpDCprtYII8oBWBbSi2Bijs5UB7hAR+JFX7j5kG49smplpoXbUzbaMtqU10OSqqmCOMZJP8AMVYlkFjYBiOF4UVTsZrmTUrmEKgtIwvz4+ZnOeM+gGPzrZa2WWLEgz6VrCDtc4MTVTXIjTGY0GMfhVGe6K5bnGaeryM6pEGZm7KMmr8fh/VLsgmNIFPeU8/kK6Xd7HJymNc4aMTIeT1HtTYVhuIgHlKkc8Ve1Wzk03UvsW4eS8ash28tgc8/XNZU9hKHL277c9q5KtlI9LDpqCLcjxQx4STccdTWbLM05CJ07mkXS7uZsySce1XY7QQxgfrWTsbq7EsxHFByvJJJHqelWBcR7SDn6elXvD+nvqNw0ZjQ28efMYjnkcAVn6ho2o6Y5FxHmPoJU5U/4V2w1imjzKqtNo//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-53.png', linkedinUrl: '/in/michael-turner-c7db3d22d3', jobTitle: 'Illustrator', }, @@ -4535,7 +4535,7 @@ export const peopleDemo = [ city: 'Mannfurt', email: 'kim.nelson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1LFC9z706snX9Zi0LQp7+TBZRiNf7znoKT0GlczfFHjG38PoYYkE95jOwHhB6t/hXm2o/EzXb628qIiBSdxaEYYisW4uL3W79rcEy3E7bpXJ6k+ntWveeB9Qs4PtMCxsOrJ0I+lc0qh0wpeRmW3iLUPtIkTVLmOY85Lnmu80X4g3Vs0cOsATRtwJlGG/wP868+mtITDvljww+9jgj8Kom8eOQQyNvhP3TnqKmMnuipRWzPpS2uIbuBJ7eRZInGVZehqXFeT/DvxI1rqI0u4l3QTnCEno/b8+les10wlzK5yzjyuw0mvIPi5rZGoWWlK37uCPz5AO7HoPy/nXr7fdOK+aPiHqBvfGOpODnExiX6Lx/SlPVWHT0dzufhrpCtZHUpV3TTMcE9hXpLwK8O1hkY6V5/azPofhyxgigupJngDARHaFOMkk1teFdSv7xdt2JRu+YeYc49s1wtX1PSi7aGd4l8LedE8tuu2TGeO9eWz2zQO8EoKru7/wN6/SvXPE2pX8MhFuJmRQSyxEDcB74Ncdq+nx6nA13BbXEE6j96kp3buOoNOLsrimlJ2OUtbqW0uUfJWWIg8eo6GvpTR79dU0azvl/5bRKx+vf9a+aceZ8vHnRdvVa9v8AhfffavCQgJybWZo/wOGH866aT1OOqtDryeVHuK+WPEyvF4kvvMHzLdOD/wB9nNfU5+8v4mvnz4r6X9h8WXEirhLnEw/Ec/qDWsjKJ7FpjQ3GnQHaOUXAP0qbMKXaxgomBnk4zXL+A9T/ALW8OWtxgK6ZidQc4K8fqMH8a17y+08z7ZbeSWVMjcqHK564Nee007HqxtJJouW3kzSOpKk5OD1zTdQihSFhsXp2FUbG9slmMUELwsSTgxkZ/GpdVuUt7Sa6nbEUMbO30AzSa6DatueN+KNPbTtSN1AdoeTjjHPp716t8KVU+Hru5XgTXGdvoQo/xrxrVPEN14mu7ZpIY4Y4ySsaZ/Mmvf8AwRpX9j+ELG3Zdsrp5sn1bn+WK7KcWrXPOrSTvbY3x978K85+Legy6hptpqEEZdrdikgA52nv+f8AOuvXxFBhmMEgUd8isPUfEt7cMYY4oY4mBBDLuJ/PitmrowUrM8++GsmoabqV1atE4spU37ipwHGBx+B/SvUBHb3iBncfh1FZ2k6dHFFFIuS5Hzknqavvp43EoxQnoRXnzleVz1Ka5UKYorcfKw+tcr48ldvB9+kZ+8oB57ZBP8q6gWJVcyOWNc94v0ltV0KeyjIV2wyE9Mg5GaUWlJMc7uLSPPfh1oY1jxFaQuuYk/eSf7o5/wDrfjX0XgKoUDAAwK82+F2mRaPbSNdELdTjap7cHoDXpRrvhtc82o9bdgAAAAAAAAAD/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-54.png', linkedinUrl: '/in/kim-nelson-e9c0c3ac3b', jobTitle: 'Archivist', }, @@ -4545,7 +4545,7 @@ export const peopleDemo = [ city: 'South Matthew', email: 'jason.mcmahon@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-55.png', linkedinUrl: '/in/jason-mcmahon-17a1cf9c23', jobTitle: 'Oncologist', }, @@ -4555,7 +4555,7 @@ export const peopleDemo = [ city: 'Christinestad', email: 'spencer.mason@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDcvb21061a5u5ViiXqx/kPU1yVz4/LylNO0xpVH8czhM/hXLazr91rNys0xKWyk+UnQAeo/wAaZaTRSYaJmLjGCozz+Ncqh3Oly7HQP461Pz0jkt4rZz0VlyH+hzWlB40kEi+ckDIw6qSCDVPT/B1xrEavcyLtY9dvNasnwxtwuWvpCcelHNTK9nUNuw1e11DAQ7XP8DHmtDYMVwb6DceGSk0l080CNu3qMMvpn2rs9LvUv7NJkYMD3FQ0t0OzWjL0SVaRM1FHVmMjOKESz5vgf7fcosrYQcBUHb6112k2FvNeoqqFjXHfrXEpcmCLYibWPU+leh+B9PeS2F2/zAn5fc+taVHZDpLmkei2G0BVQBdnGB6VoysjAYkUn2Oa5S5uJLYlDDNLuGCkYPP1PpWNpYvLjWZfKsZbVEYgszdffrXMlodrep12p2q3Fq6PgqykEHoRXK+BoZbU6nbs2Y4rjYufp/8AqqTxm1/H5cMayy2+E3CI4LZ/pV7wxGi6a0yI0fnyFyr/AHhwBg+vSrjpExq6v0OhV8GpVkxVPcQacr0GJwmpeHotTjS2ljaSUJk3DN9xueAfw6VoaFE+n6ZbxBeg5HpXOeEvGFrNbrYavL5Vwi7RIy5EgHT3DfzrqLC7juLZXjJ2npnrSknH3WdUXGT50dNaXSTjYUCtjk0txcWenYBMau/VjgAD1NUIAchhxmobnUbKHfHeQvcOeWVITJj0HAqIq5roTT3+l6jHAEu4ZSWKqUbIP0NSW5Rd8aABUOBXJPeaTNqCiC0nglc8B4ig/D3rptODfZSzfeLH9OKu1mZVPhsy7nNHQ0wHmnZ4pnMzynU/Bd3p2vC/hjL2X2gNz1wev4CulkDWLqyLiMjoO1Z897f6v4pcrfyDTY8hbdThXI4B9x3rpZLcSWwHX09qqtdNJl4dXi2h1pqqNAG3gYrWgeGVNsc4A6nODk1wl/atasd0bDnqDVAX80fyxyuoHTms1HqbuXc7a/tlhbPniRc5wR0rQtgVtYwwwxGSPrzXD6Tr1pDqKxaqZiSoaNuqDnuK7iGeK5USQyLIh6FTmtORpXZhOopOyJgRimk8UNSdqVjM/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-56.png', linkedinUrl: '/in/spencer-mason-511dce37fd', jobTitle: 'Investment analyst', }, @@ -4565,7 +4565,7 @@ export const peopleDemo = [ city: 'North Amanda', email: 'alison.barber@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-57.png', linkedinUrl: '/in/alison-barber-c6ac41c30c', jobTitle: 'Tourism officer', }, @@ -4575,7 +4575,7 @@ export const peopleDemo = [ city: 'East Pedro', email: 'alicia.kennedy@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-58.png', linkedinUrl: '/in/alicia-kennedy-ffd86f7279', jobTitle: 'Civil engineer, consulting', }, @@ -4585,7 +4585,7 @@ export const peopleDemo = [ city: 'East Elizabethside', email: 'edward.parsons@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDrsigc0zJoLKiF2OFUZJ9BWBsUdc8Qaf4dsftV9JjPEcS8vIfQCvM9Y+J+s3cu3TVTT4e2QHkP1J4/Ss/VZH8WeJbm9Z3W1VvLhUnkKP5ev41o23hGx+80bsT/AHmzSlVhDRlwoTqK6MyP4j+J47gSNfxSDvG8S7T+Qz+tdx4Y+I1prEyWWootpdsMK279259ieh9q5y58KaeEJ+zkY9Ca5nUNC+yI8lu5wOSrentRGtCegTw9SCuz340nFcn4A1ubV9EeG6cyXNq+xnPVlPKn+Y/CurNN6GaFrP19mTw5qLRnD/Z3wfTir4qtq5j/ALGvfNzsMLA4GeooHa55VoMSxwIByT6fWu3skIQbo8j6V5+InXyYx53+rziJtuSBk8/0rb0K/v7eWJDJL5TnKrKcsPrXLUhe8jvpTslCxv34fyziPAPrXI6rgRsMc45q5rMt5qFxMyyy+VCpJVHAJx2HqaxobfMrH9+p25ZZG3D8/WiMLLmuOc23y2Oi+GIcajqmCPLMcZIHrk16MeK4H4cxG2ub8Fc+cAQQeAFJ/nn9K71jXU3c4HFx0YoNQ6gnmaZcpjJMTYH4VKtLInmROm4ruUjI6ihiTszznSoIbqNQwBfPGa0dkA1OKFJYlKDGSQOfp/WsWWOXRtVuIFYnyWOOOo6j9Khhna/mEsiqmBjaVJb8cCuX2bd0ehGoklZG5bxwyahKhkiIYkAggjI9fSodWt7e2gIVQG71j3Mgs7gtB91jgKUII+lNu7l5kBkc525INDg1YftE07rU6jwSuRI+1QFTAIPXJ/8ArV1zNWR4btLeDRreWB1dpY1LsrAjPpWo2a6IqyOCpLmlclUVKvJqrcTpbxljziqceozS7gjICMHIHUHvV2IMXx3pyRQx6rE4WQERun98diPeuXtXE22SO8EDEDJwDkV0vihJJ9EuZC7OYmR+T6MCa4K7s3MqvFKY0fuOg+tZTtc6KTko6G7dbIEeaS7EkmOWbH6Vz8cj3bkqDtHJJo/smUygPcecevH9a2orAW1qVUfM3FQ5RjsaqMpvU1fAt6bezuX2P9nMvKAcg4GcV29vdwXaZhfJ6FWGCPwrn9I077Bp0UBGGxlvqaiST7Nd3i9QOg+n/wCuulanFLQAAAAAAB6H/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-59.png', linkedinUrl: '/in/edward-parsons-0815f3a265', jobTitle: 'Financial controller', }, @@ -4595,7 +4595,7 @@ export const peopleDemo = [ city: 'Smithville', email: 'justin.petersen@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDJZsmg/IhbI6U7yzurG1TUTHM8cYyqYDY9aym7IuCuyZ/EMMStAJUDDguOTmuen1mZbhkWUBGxl8ZzVjStHn16YJHFsVnwzgZwPrXfW/wy00W4Ejys2Oeax5knqdChJrQ88i1MoRH5p8s/x47+4rQ0/VDNDMscj7h94emP511N38M7DGYZJlAHQtmuNutKm0K8kMZZ4gSoJH6Uc0WNwkjd03WEuUMchG4cBh0NasSFm4rz2G5kguN233IAx/8AWr0LRLiPUbITx84+VvrWsexzyXUe0O015pqF29xeXC4IYyHIz0Oa9V2hjXl+qWbQa/dQ8hjLwSMDk8H9acgieseDrOO10S2SNRyoJPrmuujA2jmvPtQjltLCGBJrpFSMBEtVyxIHJJq34WudR+0JBPPO6NyDN94cVx26noJ9DtZAMHntXNanpFrNG6yrlTk/jWX4luNReciCe58pCci3ODx1FT6fdSyRCOV7okDlbhRu/MdaGtLjvrY8m1QFLqSNCAoYj5eCa7jwGXOn3BP3AwUD3x/+quO8UW32PXbuNlbaXyv0IzXbeA0J0OWTnDSnA+gFdcNkzgnu0bcYOORVLVNOS8RJ0TM8LKeByy5GR/WtKXATiooJjDJuxngginNXTsTTaUk2btnFFJHk4/GkiuLK31VUeSKMgHaDgE+uKqW7FUGOgGapXN9pty2yWKR2UEbkhLY/GuGN9j1Ur7Gxbz2NzdPsljkDMR8pBww6g1auIoIFLBFz6gVhW2pafH+7SOSMkj/WRFSfxrUmyyLznNN6A0cnc6Ct9rVxdToskUkXl4I+6R/F/StTT7eCwtFtoAQiknnqSTkmoI9UefUb+xiiAjgKqZs9WIyVx7VYiQjrXTRi0rs4MRNO0UQlWI5pyRZqbaBT4kMjqqDLMcADua3OYaJGhAB6HpVxYPOQFZlTjg98VHeQxx3jaefmmRcv+PpWVKt3auQrEqOme1cFSym7Hp0W+RM3hAY4yHkVz61XeZmYRqcn+VZdrJeXLbc4B7g1s21n5IIPJ7mobNNWZsFtFbeZ5Y5eRpGJ6lieTU2Qela2k2C6lfXNu6gJFHyduCC33SD+BrJuba4s5WjmjZCCR8wxn6V6EHdXUmmf/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-60.png', linkedinUrl: '/in/justin-petersen-5f4849177a', jobTitle: 'Theatre director', }, @@ -4605,7 +4605,7 @@ export const peopleDemo = [ city: 'Port Davidchester', email: 'dawn.dixon@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDvzIBgd6cFLe1KUGc96dvGKkQo+ReTn3rjvEPxK0nQ2a3gP227U4KRH5VPu1Y3xS8WXGmWsek2MhSe5XdI6nBVPTPbNcJpXgLV9RtVum2xBxlQ5OSPpUymo7s0hTc9kdkvxll8mUNp22THyBXzz78VnRfGDVRKGexgdO43EH86jf4bSJa5NyTIV5AFcXqmjzaVcGJ1YL2JFTGrGT0ZpKhKCu0e4eGvHmneJP3QJguwOYXPP4HuK6sdK+Vo5Z7S4SeGRo5UOVdTgg1754E8Vp4l0YCQqL63AWdB39GA9D/OtLmLR1iAkc0S4jQsegGTT15rP1yVrfRryRc7hC23aMnOO3vTJR4mjnxl8SWlky1ushbH+wnQfjx+dezwQ7YwNnAFeP6NpVtoks8k8k1xK6AeWilTzz2P9a7TwzfmJ/KUTLE6l1jc5K/meK4a2rueph1aNjrZEAGWAA965bxLpEN/aSAIpcjis7WpEeX7bPHcXcZ+ZURsgDPp60yO+jDeZDDPFjhoMAA+/Jx+VZpWV0at30Z5NqEbWt48TAqytgqa1fCeuyaB4htr1GIj3bJl/vIetWvHQikvIbhYXidh824Yzj6VzCHcWx3Oa7oS5opnm1I8smj6xTgVznji7a18N3EiHD8bfc5/wzXSZBWuI+Ibk6I7DlY+vpk8f1q5/CZQ+JHOfD+U6sl9LcBHljKR5PdecZrrnNnZPPI8kMcipjAGMA15t8M74ReIrqz34FxDuX3Kn/Amu+1HVpoZyn2BGVfuvKwGfcV59VPnsexhlzwSRZsIYblWjhMR2nIyMjnng1Jc2EUGXdVyB2GBUOm6pLeExHT5IcciQY2ZqTUVeQEF+BWTdtDW1jz7xXZ/2l5USKCwZjnpgAZNcBNGsUzAcY7eld1rfiO30fUQjW32k7SAN2Ap7GuBeUzTPKQAWYnArsoKXLrsediXFy03Pqa8vEsbOS4cZCDgep7CvH/Hd7f3W4TTbIT8xjBwufT3P8q9Y1m0+12UkB42jdn37V4l42u7ma+SGWMI8Q2kDkH3rWc03ypnPTi7XsctY6jNpOrQX8B/eQNux6juPxHFe8aDr2ma3pUV2hGH4KuOUbuDXgy6fcPbvOInZFGWOK9S+HelOnh2W3ukG4yl1HoCBxXPiOW1+p14bnUrdDsbvUrK0X5XUD0Fc3qGtNcAw2al3PfsK2B4btXyxBP1NNbTobSJ/LQDA61yXO08T8Tf8hcxM25kHzn3NZsYzn2FXtdBbX7tm7uSPpVGMknAHoK9OHwI8moAAAAqfGz/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-61.png', linkedinUrl: '/in/dawn-dixon-ab7660d36a', jobTitle: 'Musician', }, @@ -4615,7 +4615,7 @@ export const peopleDemo = [ city: 'New Jennifer', email: 'douglas.ward@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDkmzTF61ITTBwawNhJ7iK0h82VsDoB3J9KyW1u7nfEQWJDwP8A9dQXEN1r2tfZLRC/lgqB29zW/Y/DLWpuWljhB46nmhyjHdgoSlsjDXV3AdfOPmehJyKLXxFKl0sU774mOASBkfjXcwfCGN4wbm+ZpAMnaKxte+HMllbtLZv5xjGSrD71L2sHoV7Ga1I1mSdd8bbgaAOa4631OezuyfLwQcOnSuxgdJ4o5kOVcBhVNWITuKaYae3emjrRYDX+G9hGkVzcyKPNaUqW9hXqkCqIwPMBPoK8ZTTrqHQEEbz7DcS5WI4yd3GT+Fbfg46mZ47RnmCyKXHmsSVx2OelctSN25HZSdkonpk7KiE+YBx61zmq3OyJwACSDiuC8RR3s9+zOt3OEbBEbkA844FX9Jt7iGZoAJjGDgqz7h9QahxVrmik72PNtWBfU5m4XLEn/Cuu0dA2k2pAwPLGKz/EOhSXfil7e2KorqHLt0A7njr9K6Kzt44bSGKNiyooTLLg8cHiuxTTSRxODTb6FBh1poqVhzSBaszudpoKxNp62sg3CX94CRwM/wD181uaaLGwupx5kaFYyASQMk+1cjoNyShjZstHgJ7A1JqlxpdywBE3moCGeJGJ68gkVxSTU2j0KbUoKx0EEdpdymMvEzbd4KkHNNupYbJSiRqHI61haVeaTYxiC2QxyM2QHUo35GrV/MHJyRnvUPTQ0Zm/ZI7i9MwBWcYxIvXAzx+tRS7fNYKuBntUCTzvqbJFcbYEizJGOrknj8Bg1OiZNdFKDS5mclaon7qMoqSagmuIrcMZHA28kCmS3byybY9qpnrnmqWoKi274bK/xGutR7nG5D7XxR9mmE4hKw7tuc/Nj1rs4lW5hUx3xt2A7DB/GvLJR8pDD5fT2rqNLu01bT0V3Md5CAjMD94Doa58RC1pI6cNUa906qUx20BL3KTHruI/Wstrp7uYQxuTk/M3oKzjY3JfbLIzr254q088WkWTzNjcBx7n0rltrodbk92YOsX81r4lm+xzGMpEkRI5GRzyPxrU0XxMl4uy9QRSA7S6/dz/AErjpZHmneZzl5GLk+5p9m5i5zwx/WvSjBKKTPMlKwAAAC8m0f/Z', + 'https://twentyhq.github.io/placeholder-images/people/image-62.png', linkedinUrl: '/in/douglas-ward-a7e9b5a4ef', jobTitle: 'Midwife', }, @@ -4625,7 +4625,7 @@ export const peopleDemo = [ city: 'Granttown', email: 'linda.nguyen@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0g0lOrhviN4pl0PS1t7Gcx3k7bdwXJVccke/+NIY/xH8SdK0XzoLcNeXaAjCfcVvQn/CuBv8A4ma7fRptuEtMN/ywUDP4k1yWnaZdaxfxwRYUsfvNzXoWm/DONY99zceaWGDxWU6kY7msKcpaobpvxXvrRUW/tVuVHBkD7Sf0616H4f8AFml+IoEa1l2THO6CThlI6+xrzvUfhlD5BMEzKy9M9K4q5h1DwzqUbOdkgcMjfwnFEKkZaIJ0pR1Z9LUorL8Paqmt6DaaghBMsYLj+63cfnWoK1MgPSvnzx9qp1LxTcMkgeOI7I+eMV9ASuEjZ2zhQScV806giX3imQxoY45ro7U64UngflSY0d94M0qG209J2RRKw3GRuMZ/lXoNrseEBJUcjrtbNcJeTRafEqSWUlwpXCqq5AA/TNO8Nxuuoq9vbtBFLgsD2z2+vtXC1e8meitLRR215gRkGRV9ia818d2Kz2DSkfPH8ykVreJ2Y6gxuLeWeCHtGMn8qy5Xg1Cynhgt5ISI2BRxjPHH40RVmpCnqnEk+Deoyi9v7E7jGyK+M8KRx+ua9iFeDfC3UPsfif7Pgk3C7OD6ZP8AhXvAruR5xFPGJ4JImJCupUkdeRXkd74W/s3UAJE+eGXesnYrkYx9c/oa9grkPHlz/ZulpfC2aYFvKcL/AAjkgn8qiom46GlKSUtR2nSwXFsI5FXjrkZpl1qunafdxRMRFHkYbafmPfpwKzLNv3YZGyGGR706XVZJD5NtprT7eMvgBvXGetcKTbseii1Fqmm32qyosqyI5wRjp7/SjVltbeBliRRkcbay01IwTeVcaZ9m3cDYAR+OKZeTHG+QkqOw9zT5Xewm7LUo+D/ClzbeJbS+gRhCm55ZccdMbfxzXrorM0SxNjp6q67ZXO+QZzgntWmK74J21PNm05OwlRzW8VxH5c0ayIezDIqaszVbv/Q5oLW5Ed2y4Rl5Kn1qiThdVddP1S5gH7uNJCFAGAB6Cp4UtruHL3ZRSP4eorOgtru+tGGokteEnexOTuBx1rDnivbWUxpuGPeuF2cmehFtRR0s8drZRtsumcdfnOTV7wgI9Q1SXeQVij3AHuSa4qG3urqbbLn1OTV9VuLPWtLNmzI5kKgr9M8/gDVU7KaJqtuDPZAMUtV7S7juoUYMvmFQWX0NWQAArsOE/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-63.png', linkedinUrl: '/in/linda-nguyen-9543ff5b4b', jobTitle: 'General practice doctor', }, @@ -4635,7 +4635,7 @@ export const peopleDemo = [ city: 'Courtneystad', email: 'nicole.hernandez@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwCQikAyakK1HLIlvEZX6DoB1J9KwbN0iO4uYLNQ0z4J6KOSaryaosUSyTKIl65Y5z/hWfNra2rPPMDJMeEhjxwPdu1Z/wDamu6hGbtreBLUttSPZlnPoKzc30NFBFh/FE0V1lvKMB6bRn9a3rTU4rmMb1MZP3Sehrirrw3ql6DMsHldyBwPyFPee503Tobe6O7J6Y6U+bsDhbc74inKlc34Y1oXUn2GUglRmJs9R6GupGAatO5m1Yg25rI8RTNBZqAcDk5HWtzbxXM+L96R2zc7W3Kf0P8ASplsVHco+H9Gl1TaDGWXcS7EcfSvRINGhhjRdo+UYAHauVtZpNN8NWaosxknQviIcjqc8VpeGGvHuEWdpjC43/veqn0PNYuPU64vodBNbxxxYUAEivP/ABVZb7d22/dBPuPpVzxBNc3F1Iy+e0MWQBDkkgH61RWVru2eAxPG6ryrdwR/Oi3Ubd/dOX0G6+w63azFvkdwrfjx/WvVcc147YK0uqxWyglvPXaPx6V7PsrdHExAvFUdY01dRsBFs3OrgqM49v61ogU4Eg0NXQRdmmyzpCW502GFlRgiBRkU241Gw0+7SNsIpBxgdSBzUEKLHIyw42DoATxVW81iJY/IXTbi5HILCPj3xXPrex6EUmtCLRLi1u5Z1yHUscZHv0pNWS2tgwiVQSO1Z9pqUf2ootjNbsT0KHFP1Lc7ZY9KUr7D0Ob0jSUOvi52ASC4DKDyNh5z+dehmuf8NrBdw/b4clcmMErgkjqa6DFdEL21OGq43tEULRtp4FGKsyIZdyIWXt1p6ww3EOGm2jqKkYAROWIACkkmsm6tpdhlhJA6kVhUSTudVCTtYW5ijt23LJnHt1rHvpGkBVTknvTyZZXw+abLGQnHfvWZu9ToNN06PTNOgtI+ka4J9T3NXNvFVNIea4023eZt0hTlj396vj//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-64.png', linkedinUrl: '/in/nicole-hernandez-c31e2859c3', jobTitle: 'Teacher, early years/pre', }, @@ -4645,7 +4645,7 @@ export const peopleDemo = [ city: 'South Brandyland', email: 'anne.massey@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDjN1IXCIzscKoyT6Cm1h+JJ5UgjhXKxuCXI7+1AGZqWsXWpSmNHKW+flQHGfc+tVSotxgtuB6j0NW9C0W71q78myiLEfeZui16BZ/CdnIa9uwQRyEXms5VYxdmaRpSkrpHlsigcocjrSPIZMHoR1r2Bfhdp8ET/vJGcjgnoK4vxB4JudJgknSQSRKeoHSpVaDdipUJpXMXRNcuNIvFkQlojxJGehHr9a9XjkV0V1PDDIrxMZXOfpXqvhy8W70S2dcjauwg9iK1MTNBrH8RJGbMSOfmHyqM9zWtVS/09dShWAsVbcCpHrTBHa/DSyjh8OwyqgDykszY5PNehbTgcdK8rsFvrHw1pq2qXBmaE4kSby1BGT07k10Pg3XNX1Ai21APuKlldwM/Q4rz5LVyPTg7JROukDbcBTXLeIoPOspYivzMp4rL8S6trpvJ4rKaVIYULFYyFLY64OCSfaodIu7y+Aiuba5VgoYs8u8HI/Q1PLpzF813ynkF9GYr6WMqVKtgj0r0TwlZy2ejoJeGkJfGex6VRuPDLXvjG5kIjNunzlX/AIztyBXQadbLaWixISVUtjJzgZPFd0JqWiPOqU3HVmHmiOUxTJIBnawbH0pDTTWpkepaHFZXGkx25CtEBlQR2PI/nWha21vb3pS2jACqSdo71xvg+Ym2kj3n5H6ex/ya1r/UtO34M88UoBG6NW/X1rzZxcZOJ7FJ88U0aEVtaXExiuEXzOcbh15p15FbWFswiRV+lZGnX2mIdkc0rSsc5kVsn86tXhMp3O3yjmoemhdrGBLdWlqWeSWJrhnwkQI3bsdSOuAKpecBwvQVxN1e/wDFeXcrnGZTGPoOB/KumjY7ua76NPljfueXXqubt2KRpKnMdNaMgdK2MC3pF69leBl+6/ysPau5SCC+jAmnMTJxkcEV55YQG8vbeBXKCWUJuHUDGTj8B+teiyWEUiIZAQMbSwPP1rixNlJdzvwkpcr7DfssNmjbLjf7nrVMOZ+FJKDqfWp/7HhhlJed5VPRCaspbbYwAuM9q5WdTlc8X1ewmPiiZ9hTM5OSMZGetdnHbg4YdDW7qunQO9oZYUeYzBVyM8dxW1/wj1tEhkiBCA/c68V6FKpeKLTtJn//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-65.png', linkedinUrl: '/in/anne-massey-68ae91f9e7', jobTitle: 'Engineer, energy', }, @@ -4655,7 +4655,7 @@ export const peopleDemo = [ city: 'Rachelfurt', email: 'jenny.esparza@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDrsAVQ1fWbLRLI3V7KFXoqjlnPoBVu6uIrS2kuJm2xRqWY+gFeO+IdSk1y9kunkAydsKMeEUf55NS3YqMbl3VPijqUjkWFvBaxfwmT53P9Kzf+Fna+Ao8yAEDBIjzn3rlJ4j5xVNzknhsfe9/pVmDQdSuU8yODC+ppcy6j5W9kdrpXxUv7aVRqlvHdW7H/AFkI2sB9Oh/SvTNK1ex1yxW8sJhJE3B4wVPoR2r59uND1G1jLPCSg5OK0fB/iqbwzqoLFmsZTieL2/vD3FNO+wnFrc99xTgKjgniureO4gcSRSKGRl6EGpRVEnAfEnV3hitdLicjzcyy4/ujoPz/AJV5U95mTkbsdF7V1fxLkkPimXlgiwxgfl2rH8H6OmseJLeCX/Ur+8kHsO1ZydrtmsVeyRu+FPDF7q939uuoSkR6MwwCPX6V3FxYW9rhIGRlHBwc1d1u6to7B1htZZlCnYiR/KAB+ArkNFZJJxKI5IAfmKGuRty95ndFKHuo0L61Vl5Ax715r4h0g2E4mTBhc4yOxrrdau1lZhLDLIEONgz/ACrN1e2E2jyrBGEGMlPQjn+Va0/d1MqtpXR23wsvXufCrwSPuNtOUHspAI/rXcV5n8Hy/wBk1RT90vGR9cHNemiuk4Txz4nxbfFtqWHySwKM++SP8K2vAOjrp2tyzBVdWR4hIP74wTir3xM0RL/R49QLFWtD/COoOB/OneF/FulTrpljIPK1SQkOqphWOCc575/nXNiL20OzC8vU7XUbc3FqXtmWM/xAjIP4VgaSdNi88XTQJtYKJJGALOc4A9a6S6UmxmMZ5ANcnNqOm2lgYorCa8lXIMnkkoG7ndiuaOuiO2yMO7ijk1GTy3XJY/h9aq6rbbNJu5HO4+U3brxSJeQvesnleTIcYHX9ak1q9Wz0qSR++FAxnJNaq90jOVrO5a+EdvNHot3KwPkySjZn1A5/pXotUdE0yHSNGtbKBcJGgye5PUk/jWhiu08opahaLe6dPbuoZXQjBHWvIdD8NX9r4005ru3aNBPtHHT5SR/KvdrDS7i8kX5CkXVnYdvasWXTri28e3Nrcys1qIxc2YIHQ8MM/wCyf5isqztG5tQV5WJLhm8lrUsFaQYDGqV/apHpTWyyhUVRitSWBZp3jcckHGa4bVluYLtovOaRByAT0rgT1PSKskSIxXAJJ5buamsdBfX9Zt5biI/2bZtv56Sydh9BVaX7me9bXgnxOL0z6RdIkU9sxWIgYDr/AI11UbOVzmxMmonZ44oxxRkUvauo4D//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-66.png', linkedinUrl: '/in/jenny-esparza-0ce6d348d2', jobTitle: 'Trade union research officer', }, @@ -4665,7 +4665,7 @@ export const peopleDemo = [ city: 'Alejandromouth', email: 'robert.ward@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-67.png', linkedinUrl: '/in/robert-ward-9dbe3cfea4', jobTitle: 'Air broker', }, @@ -4675,7 +4675,7 @@ export const peopleDemo = [ city: 'Hughesshire', email: 'melissa.farrell@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDqiKTFPIpMUhjeg5rhtX8f+TcSQabCkoQkNMx+Uf4074j6rd2tlb6fZsyfaWIldeDgfw5981m6R8Nrm6so5bq4aAMM7MZbHvWc5qJpTpuWxgTePNcLyEag4yeFRRjFTWnjTXNgZL2TIP3WAIrtj8N9JjhKqJA2MFs81yOr+EG0jdJCzyQgHhqj2qehq6ElqdBpPxKVmWLVLcKOhli7fUf4V39vNDd26T28iyRSDcrqcgivm95XSXBBIz0Nd98OvETWeoDSppCbW5OYgf4H/wDr/wCFaKXcxlFdD1Gkp9JirIOT1uyj1HxZpNtKMpEWnCnoSB/+qu5jXagGK43xTD5Ulvei3eZlSSMBCRycY5H0NP8ACV9dyW88N0kiKgYqXJJyDjvXLWTvc7cO1y2OouMDgsAfTNYeqoskLoQDuUjHrXL6tb3q3jXcMPmMCCNzfeya0bGW8uwVltfLKnGUbKHHcVk46XN1K7seVa3CsFy6hdrA8iqtncsjIyNiWJgyke1db4907Y0Vyi4c/K2B1rjo7G8SAXwhYQA4LZHHbOOuO2a6ItONzjnFqTSPpKlFJTgK3OcayRvhZFBBOMGqd21rZxSIrxREkDGdtXZAdhx1HIrn9R1PRYroQ3kZlmAyQF3fn9K5ayfMd+Fs4m3Yrb3VtuIU7WIIIB5FQX08dqp2gCotO1KwuYdliVGOqhSpH1FVr5DIxLHiudvodKSMC7gTUGDTgeWpLcjNYXicLZ+HCsiKjO4jhAXBIOGP5YrevLw2Ae5VVZYVLMpOOMdvevOTqd94w8QQLOMR7sJEnRB3+p960pxbfkjGpNRVurPfxSgUoFLXceaGKzW05ZZGBlEbKev96tOobm1iuFy25WA4ZTg1nUhzLQ2o1fZyM91SyTAdfXIrLu7wbdqHcx9Kbe2NzLHuhlLDPzA1JZ6Y0W158E9gK4WejcwPEUEqeHLw4JkaMnj6Vz/wliQ65PuUEiElcjoc16BqcAkt2BGQeMVn+FPB8uhajLepPsikzmHbnAPQZrf2Z//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-68.png', linkedinUrl: '/in/melissa-farrell-e7db325f4e', jobTitle: 'Sports administrator', }, @@ -4685,7 +4685,7 @@ export const peopleDemo = [ city: 'Johnburgh', email: 'stephen.powers@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-69.png', linkedinUrl: '/in/stephen-powers-848a849fac', jobTitle: 'Occupational psychologist', }, @@ -4695,7 +4695,7 @@ export const peopleDemo = [ city: 'West Elizabethberg', email: 'robin.brown@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-70.png', linkedinUrl: '/in/robin-brown-95dea5c792', jobTitle: 'Publishing rights manager', }, @@ -4705,7 +4705,7 @@ export const peopleDemo = [ city: 'Kimberlyborough', email: 'wanda.moore@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-71.png', linkedinUrl: '/in/wanda-moore-846aac522b', jobTitle: 'Chief Technology Officer', }, @@ -4715,7 +4715,7 @@ export const peopleDemo = [ city: 'Robinsonmouth', email: 'danielle.brown@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-72.png', linkedinUrl: '/in/danielle-brown-9468c67469', jobTitle: 'Biochemist, clinical', }, @@ -4725,7 +4725,7 @@ export const peopleDemo = [ city: 'Armstrongbury', email: 'timothy.phillips@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDtDTTTzTagswfFPiSDwzpf2p082aQ7IYs43N7+wrx7Udc1rxFcD7TcsQxysQ+VF+grv9U05fE/jKdbrcbPTwIkQHgseSf8+gq6/wAP7Dz/AD7eRoyT908gVLqJOxpGlKSueSTWMsDHJJYdSKt6Pr2o+HrkT2szKpI3IRlWHoRXrs/grSZgC6PuAwSG61j6t4M0xbGVYY2DBSV570vbIp4eSOj8NeJbTxJZebD8k6AebCeq+/uK3MV4v4Emm0/xnbW+5tsu6Jx2IwSP1Ar2rFaGIEUmOaeRxQBSA5Wzg8nWNT4+Z7pmP5Ct5AxUck1x+snUWeWaGWSORpjuECjkgADOeg4pfDOqavcyLb3QYtgsC4wfxrmkrvmO6DsuVnXur881kaiW8iRVGW2muZ1nUtdS6eKKWUQoMkRINxGccVp6ZJdyKEuGnOBn98oB/Mdam2lyua7sc54ft2/4TewBH8bE/UKa9axXA21kItVvL1WKTfMsLDsdvOPf/wCvXdWjSPYwPNjzWjUvj1xzXRCd9DkqU3FcxJ2pcUCnAVoYmNIsaX88UoGH+YZHWiyhgW9fyEA2qckDGTS69EVEM68EEqT+tc6+oyMpNncLG4GCC4yfwzXNKNpWO+nJOCfU3EgtprjbKFDnkZHWnXccVtFx17VztpeC3GJ5/Pl3ff8AMDEf4VqXMhcKS3GM1D00LuhtjbteSqpUtHvzwOnvXW4446VznhXVUuXvtP2bXtZBz/eDAGukrppxsrnFVm5O3YaBTZJUiGXYCopZmBKJwR1NZzLneSST3JrZQuYNjtUuDdabMsMbHCl19WxzxXMxxvPboYEgztDDzB1B5rpLZjsRz09PasG+sEhuDau7Rd4JFOMp6fh0rKvG1pI6cNN3aI/IWOLdNHb7z/dAp0MhuGyWzGvU9qzWsrhJsTSs8Z4yOlXYreTUJBYW37tMfvHH8K/41y/E7I6m7ayLnhO3KC/1McG6uWZM91ACj+VdRb30c4IPyODtKk96qpCltAkMShIolCqB6CqyxF5zJnGeoH869FQtFI82UgAAAAvJs//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-73.png', linkedinUrl: '/in/timothy-phillips-f02b8125a6', jobTitle: 'Medical sales representative', }, @@ -4735,7 +4735,7 @@ export const peopleDemo = [ city: 'Elizabethfurt', email: 'daniel.baker@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwCuabTyKacAEk4ArMsCwVSzMAoGSSeBWFe+KrSBtlsjXLeo4X8+9M2SeIrlizsunRttRFOPNI6sfb0Fbdr4QsEYSrEd3uc1lKtGLsbQw8pq5yv/AAmsiN+8sUx7OR/St3Tdds9TAEb7JT/yzY8/h61pXnhXT5U3NbLkeneuX1DwzboC1qpilU5Qg8ZpKvFjlhprU6jrTgtZPh+/lvLZorjP2iHhif4h61s4rYwsIwqhqhZdMuNpwxQgfjxWgwqnfKHspRx0pXsNK4miQrFaxRgcgCuttw2wfLke1edX0chuViaa6WIJlI7YYZiOpJrT8Nz3ltcrD51w0TEFVnOSK4nDTmuejGevLY7K53eWcDArlr4jJ45FUvEDXV9fMpluhDHkkQPjOP5ms6xiYXXyS3QTGXiueT04INNQVr3Bzd+WxLo2BqzNghnVgR+tdIBXP6evlaxI5BEag5fsCegrowK6ou6OGcWmRvUZVHim3gcIWXPrinuaaMZ56EEHFEldWCnLlkmWtLtba8gUyKNwHWnCfT4dSSMSRxbQcZGM+9YVvPcWySqjEFUJVfXFMtbC41eQi7byZIxkb2GCPbANcqpu7TO9VNFyq5sWtxYXN3KDLHIGJGV5249al1C1t7aL90FDEda5y906fSZ8WcnmM/VYz8v45AqS4upTaxIZA0mznB7U3T10F7TT3kS6cqnzjkHc+MYz2HNbgSs3RYw1puAGN55z1I4rWxxW9ONrnJWmpWSKTU3FSEUqRs7AKpY+grUwM+8QIFkYfJuwSO2ae3kNGN8zxkDJZGxkZ4rS1DTJl0iaR0HGDt74zzXFXFpqcbCO3cPEfuqecD05rKpy81mb0ublujoHmtIYx5bSSMxxuZsn/wCtXMi7kluZYYlBJO3I6KKWWw1aZAsrCNT/AAIMZ/GtbStFWyi8xwWlIwB1qOeMFpuXyTm9dEaXhxnbTpk2/JbzGIHv0B5/E1r5zV7TNJ+w6SsEigSyEvIPc/5A/CnnTCw/dHn0NbrZXxOx/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-74.png', linkedinUrl: '/in/daniel-baker-b080dba2cf', jobTitle: 'Learning disability nurse', }, @@ -4745,7 +4745,7 @@ export const peopleDemo = [ city: 'Jorgeside', email: 'jason.parker@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwAK03bU7LTMV2mBTvbu30+1a4uZAka9z39h61yNx40mkdhaWyKgPDOdxx64qv4iubnxBrqadZoWSFygH95v4j9BVmP4eas6gqsXqCOtcdbEKLtc6qVCUldIrL4tvi7Ml1Gf9kxgYrQt/HHl7EvYVbsXjOD9cVNH8K71xvmvAr4yAFz+tU7v4b3cQYx3CMR2PGaxWJSfxGzws7fCdhZX1rqMXmWk6SqMZ2nkfWrSpXkunaleaFNLHE7xSq3zqw4OOxr1LRNRTWNMjvEAUklWUHOGHWu6nU5zilDlLzCoytTsOKjxWpBzPg3T4ze3l0/MpkK7vfOTXpNuAsSgEH2BryadZLe3mULcOGuZSiQnbkhupP4Vu+EH1OS4FrL56RshkBlO7HsT/SvCrR95s93DytFRsegSssan94B+PNYt6+1MDnPc1xGvpqb37sY7mZI+f3bkAj2xVnTXvFkEXk3Crj5kkbcPwNZ8mlzVz15bHH+K4kn1F51TDZw2Pauq+HGTotyh6LPkfiBWN43sza3lvOgwJQdw9xXRfDm1CaDNOFI86cnB9AB/9evSwjvY8nFRtJnSEUgXipStJtrvOMTS7O3Fq0EyKzeYzE9skk/1pG1rS9Mup4XcIwjwoA7dzULSmGd9ucAZP5c1lPeW+ovuGnT3AXoURQOD0yfevAnH32j6Km7wXKbuj6lYasGSGUSLjIbaRg+hzVm5FvZZZIxu6ZJrnrbVksSIzZTQKzAYZBgf8CHFX724DqQTzWbVmXfvuY2r2P8AaFxFMyLKsG5/JI++cdK2dBiZDcOskjW7hGRZOqnHIx2rK+1JHdxBwx3OEUKM5J6frXTW0Ziiwc7icn613YSEnNPojhxdSKptdWMxRtqQCjFeqeQZGrO9qnngZjxtc+lRfZdMuoYzPM3yjICHFaGrXEFnpF1PcnESxnPvngfrXm96l1bztsL+UeVAbgCvLxdJKpddT1MJWfJZ9DtpXsLODZDLu4/jPIrGudXQRnY29ieAOa5nMtz96VjjsTWnpto27ITgVyuKWp0+0lJ2R03hy3Nxc+fcD50G9Qf4SeB+ma6wKMV5lqt7PpOq6ZdwuQys+9AfvLxkGvRLe7iu7dJ4JA8bjIINephGnTPMxd8AAAAAPaM//9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-75.png', linkedinUrl: '/in/jason-parker-c8f6658eb8', jobTitle: 'Public relations officer', }, @@ -4755,7 +4755,7 @@ export const peopleDemo = [ city: 'New Michael', email: 'donald.roy@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1XFFLUc0qW8Ek8hxHGpdj7AZNAGR4l8S23hyyDuvnXUuRBAp5c+p9FHc1wA13WtWcvd3QjQ9EV9iAegAOT+ZrlNQ1q81/X5764Zv3j4jhH8Cfwr7VuQWmoNCBa2KyOx+/J0H071y1Kh006YzULxowVguYt3ujYz9cnFNtfGuu6PGIzPuXsrnzF/D0raTwjrN/Cour0Qp/zziFJ/wgsFopZnaQ5GSazjUsaypNnReF/H9rrWyC8j+zXDcK2fkc+mexrs8V8+6+8dhcGC1Ty0GPlFev+BNZl1vwpbXM5JljJhdj/Ft6H8sV1Qlfc5ZxsdHWdr6SyeHdSSFS0jW0gUA4ydprSNGARgjIPBFaGZ5F4I0C3ewWeRA0hYgn6V6FBZRRgYAOK4Szi1DTdL2Wu8N583yrg4wx4/TFbvhzUtSvCI7yMqSpYMRg/Q+lebJatnqQeiR07jaKzLw4Rh3YYxWBq2qaxFPJ5AZooxk7VyWGccetS2l5d3iqksTq2AfmGKm2lyr62PNPFbZvXYjHXn0Ir1v4ZQpF4JtmU8yyO7exzj+lcH4j0T7fr0cCMqCVdzE9vevSvBdqun6M+nxxFI7aUqrFs78gHNdlKS0RxVYOzZ0NFLRXQcxz5toor25gIBDSGTB/2jn+tOiWJbhxGFARDnHHNSaxEUuopkGC42sfXFYN1c2TsVNyYpRwWXP15rzqkWptHq0WpQTNW1jhnYxyBd+M8jrRcrHbKdo5rK0250+D93bzqzE9GJBP51euzlck1m1bQ0MdoEmuGYopdl2Fj2XrXZaJam00qGNt24/Md3X2z+GKxdAsVub2SeQZjiGNp6Fj0/LBrq67KFO3vM4cRVv7iEoooxXSchV1C2a6tGSP/WD5k+tczHF5ilXfy3U4IxyPaulv9UstLi8y7uI4sglVZsF8DoB3rile41GBLxmEc86iU7OmG5A/AEVy4iK0kdeFm03E0SiwLkurn1xVOe7Mnyocn1qsbW9dis0ny+3FTw24jHA/OuQ622zV8PatZwaj/Y8jFbudDNHno4HBA9x1rqa8T8TXUlt4lsrmByk1qhKsOoOQf6V6X4e8W2GuwKDIkF2OGhdsEn1X1FejST5Fc82s1zsAAAAAAAAsf//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-76.png', linkedinUrl: '/in/donald-roy-81242ff295', jobTitle: 'Ambulance person', }, @@ -4765,7 +4765,7 @@ export const peopleDemo = [ city: 'Karinaberg', email: 'cameron.beck@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-77.png', linkedinUrl: '/in/cameron-beck-4a5b8ac2f9', jobTitle: 'Animal technologist', }, @@ -4775,7 +4775,7 @@ export const peopleDemo = [ city: 'West Steven', email: 'christina.carter@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwBNtIVqXHFNIrMsiYhELOwVQMkntXI6p4zhVjDpyGSQHmQ8L/8AXp/jy8njtrayh3BZ2Jfb1bHRR+Jq5o/wwuJrGOW4uRDK4z5e3O36n1pSnGO5Uacp/Cczd+MtUkZEiuIoscEpHn+dTr451I7Yw1uzjqfLPzfrXaj4S2Ijw9zK0ncqABmuS8SfD260eM3FuxkjTk49KlVoPQt0JxV7GzpHi2G+kSC7jW3lbgMGypPp7V0m3NeMSkIil+46dxXoHgjWXv7OWznctLb4KMx5ZD/hWhkdTjim4qTHFNIpActDEureP1WUjyrCPcqk8buOfzI/KvVrVCI1IIP0NeWXiQJ4kvn+yNcN9kiBQEgEljgnFdR4Re4k8qJYZII3QuEdiduPrXJWV5XO/DO0bHaB1TkyIPYmqupQR3llLC4BEikVxGvwyQakjHT3unLABi5GATgYxXR6d5hxF9mkh2nGN25T7g+lZ2srm17ux4R4htTZ380LDlGK4qXwbeNbeI7P5tqO5jbPuMfzxXVfFLShDfQ3ca8yr82B1IrkNI066TWdKea3ljgnuE8t2UgNyM4rtpyUopnm1YOM2j2PtSYp3ajFWZjtJsLcapd3MoBaeNEx6Bc/41uWstlaSTs0sUQRQBuOAKw4mKSAioJdT0UagYrgeZOB8yKu7Kj1HfrXFVT5z08O06aOuX7LePyULr34IqeaSO3i4xkVh6fqukXgSPT5Iwwz8qjaR6gir8ylxt5rJ6aG2hganZJqt1FLOEKQ7iAwznIx0rH1S0H9taFbmNFn8wyOqjA2xhvm/wDHgK0de16Pw9bPePB5yRj7gbHPQVg+Gv7S1rVp/EmqJ5Qkj8q0hHRUzkn/AD1rahBt36I58RUUYuPVnRAUtBwqlmICjkknpWFc+LdKgl8qOSS4kztCwrnJ9Mmu0843gCenXtRbWLXJ3o6Rv3LLnNYet+ITounJO1v/AKRKdqRM3Q9849KwPC2t6jqE+oF7pjIrh1HbB6ge3FYV4acx1YWryy5e56nHbLbRBpDHuHO4Cq9zqGFKqQWPQCuct31O8fErBk7bTW3ZWO35nHPeuN7nde5x3j9HfTLK0Lqr3VwAWc4HA4FdLotjLp2j21rM4eWNMMw6Vg+PoUu5bCEnAhk84/QD/Gul04ymyiS4BWdY1Lg/TrXZQ+A8/AAAADE/Gf/Z', + 'https://twentyhq.github.io/placeholder-images/people/image-78.png', linkedinUrl: '/in/christina-carter-20e5617e72', jobTitle: 'Historic buildings inspector/conservation officer', }, @@ -4785,7 +4785,7 @@ export const peopleDemo = [ city: 'West Melissa', email: 'roy.jackson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDA70HCgkkADqT2pxWsvxDGz6JPtJG3DHBxkDtUFlLV/Ef2cmCyAeTo0nUL9K5szyMrySO7u5ywzzVvQtCu9blaK3UIq43SN0B9K7eD4a3CvE/25G29QExiolUjHc0hSnLVI83kCkF1YgEcA1pWGtXOmJ5QfzIdwJHXH0rv7j4Z27LuW6YPzn5eMmuK1/wjcaKjTKxmjU8leMfhSVWLdhyozir2OlsdRttQjzBKGYDLL0IqzjNcb4RZv7TcYP3OfpXaEc1oZCmsPxPLJHpqKhwskgV/cYrdIqhq1p9s02WLIU/eBPYjmgaNTwBbLFpAOBudy1ehQjCAkV5lZRTWmiWW03AJjGBAQDu6810mganqbCGOdpWWTkGVQGHscVwzV25Ho03ZKJ1MrHaeOK5DxSqnTZwBuJQ5FM8QX+pybhC84hj5Igxub25qharJKTvNxhRl0mIPX6UlHqVKV/dPPtFm8vxFCkQIDEqR7Yru81y2i6W0WvzzlQEiZ1FdSBXcnc81prcCaTKk4cZU8EeoopCKYjpdGjgW2FowBEfAJ9O1af7lL+GIFFwM9hXN6VIdwyxyDirt3eabLKFu1PmLkKdhyM+9cEotSaPUpyUopo1LM2800y/IcEkdDnmq2rtBBbssaquR2qlZX+mxMY7QbSx6bCKZqrAozscnsKVtbFSaSMoQx29pGgVQ8hMrkdSTUeeakYE43EkgY5puOa7oR5VY8upLmlcjop6QvIwVFLMegAzWtaeHLyYgy4iX35NU3YhIzInMBDZ+8do9z1rUhjW+UP5+xsYyByKmv9FT7Ioh3FraUS9eTxg/of0qjcWLqRLFIybupXtXHVa5rndh7qJbaFLNGcz72PVjWXdStLGXydinO41NFYGV/wB9O8x69MCtCWxMyJbQpkscYrO+uhs7tamOqu9sJ8fKWKkjpkUyu0h0e3tbFLNYwY1XBGKy7vw06gtbPuH9xuv512xl3PNcewAAAAAAAA7H/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-79.png', linkedinUrl: '/in/roy-jackson-12ef80ee4f', jobTitle: 'Theatre stage manager', }, @@ -4795,7 +4795,7 @@ export const peopleDemo = [ city: 'Jessicaburgh', email: 'valerie.green@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-80.png', linkedinUrl: '/in/valerie-green-c4a084e4af', jobTitle: 'Dramatherapist', }, @@ -4805,7 +4805,7 @@ export const peopleDemo = [ city: 'Wendymouth', email: 'ryan.parker@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDgaiuJxbxGRufQetTY4rJ1B2lvEiTOUGT+NQaEE1xcXLkMSEbBCj8qbJJtjW1I+Q8se1dToXhGfUoVmmnEZblSBmt+P4bl2y93EVPX90cn9ah1YpmioTaueZRxvBKJFcCJ+oBq0LprKbzFJa3fjb/hXo138NLMJ+4uZFO3ByM1xniHwrcaVH5iMZUU4PqB9KFVi3YHRnFXJYpVmjDocqeQacazNFmLRvCwKleQD6VqEVZmLWbOBHfk/wB5c8flWpT30gXVtBegnAn8pl9jjH86mTsVGLex6B4djRbGEYwdowPbFdNE2FAxXG3UM9uiCLzzkfIsJC9B6mtDQL/Uf3QuTKUlGQJQNyexxXJbqegnb3ToZnJUgDNcV4t2rYyttz8pJxWl4gv9R2y/ZTJsh++IgNzdOBn61iNay3KTl/PDBP3glfcDkdvzppdQk7+6ef6Z+9vZpgPlK8fnWqRUVjpz2VjG7n/Wltv0BxUxrsuec01uFbugMJ7O+tGwcBZlB6/KecfkKwQakguZbSYTQOVcAjPqD1FTKN1YqnLllc9UsWjntkDgE470+4CrdwxooDE5IFZekTCS3jkU8EAj8qS9urW4uV851VkOQMnI/LpXGlrY9JNNGjaoGv7pHA4Oee9V9ZMUNjLsAU7T0qna3VvBcMbeVHLHJG75v161Fr1wBaysT0XpTtrYUmkjl9ZwkttCAoEUCj5emetZZqaeeS4lMsrbnPU1Ca7IqysebOXNJsZRxgk9KrTXkcZIHzH26VUmu5pFO3Cr3HcirUWyGztPDGqSJYhpD+7EjKD/AHcHj9K66NY7uJWDKGI4YCuA8GXlvJLJplywUTHdET3buK6k6ZcwHZBcmIg8K33TXFUXLN3O+jK8E0ackUVsjOXUsOrEVx/iLVN0UQB/dPJhm9Titi40u7kKpcXKy7uqp0x71z3jBYreC2txjduyB7AU6dnNCrSfK2yhmmk1hGaSFgY3I9u1WodRc8SKD4OY/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-81.png', linkedinUrl: '/in/ryan-parker-f86f7a2a2c', jobTitle: 'Catering manager', }, @@ -4815,7 +4815,7 @@ export const peopleDemo = [ city: 'East Willie', email: 'spencer.cortez@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDujgCoGxyalY1y3jLUpLTSzDC5V5eGZeoX2pN2VxpXdhmq+MbayE0dmn2iaP5Sf4Qf61wd34u1uW7LPO6qDnavCiuv8PeB1m01Li7dgZfmWPOcD1PvWsfBWmAbWjzXO6p1RoaHD2XxGvo7mNblPOiBxgAA4r0HTdXtdTgDwSKWxkrnkViz/D3TS+9AwIORzWNq2h3Hhe4g1PTdzRFgskYPQ9j+NVGrd2JnQaVz0NeTUygYqraSie1imGMOobirS1ucwrdK4XxErXOvJauNyb1J9hjiu4JrAubFLnxRAVYMrbQ2OcEZJB98YrOq9DWim2dLaqI7WOMY2qoFK23PBrmPEN5eI0iWv2kiNcgQjH61neH7zVLm9jhuGm2sNxL4OPY+9cnS53rex2pwTg1keIVVtIuEYZG3IrnvE+o6naXhgtvNZVAYmPqfpVqwmur+zktrnzt0kR4lHOSOMGmgkW/Ck7zaKqyD/VyMgPt1/rW+OlZHhuNY9EhX+IE7/r/nFbAxXZHY82W4bar+UYryBkTCFzI7Y6sRtxmroXioL1pFsyIwAVYNkmoqxvE1oT5ZWfUszQxToTgD1GKoRy2ME2wPHEd2ASQCx64FLJfotk7seUXcwFclcX0WpojhI02HKMELEH64rkO+Ox00rWdxekFo2LY98VZaCO3+bHQcYrirW5XT5HY+XLuA3MQVb8M10jXxmgiYf8tBwCadtQk7Is6fCILRVAI3Hdg+9XB0qNAdihgAQMcVKBxXbBWSPMqO8m0WsYrO1PVNOsTHb31ysTXAIjBB+bp0/MVos3QVg+L/AA+ur6daXAz5tjcLMAOrKD8w/Efyok7IUI3ZlX920Ky28oKyFCD6MM9R61bF3DeaaNk4hZVA4XpV3U7G31Kx+ZA6MMqw6j3FcJq1hq+lcREyxMuFYdfxriVmeim4nTNPFbae5kmS4cgjbjrS6EJb14/l2xW/3vr2H9a5XStK1G/GbuRo0zj5etbUV82jeMdL0yIbbSe2fcvuD94+9XTS5jOrKTi2dsFp3amqQehyKfxXYQAAAAAABwH/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-82.png', linkedinUrl: '/in/spencer-cortez-8653fe9874', jobTitle: 'Logistics and distribution manager', }, @@ -4825,7 +4825,7 @@ export const peopleDemo = [ city: 'Tracyville', email: 'jacqueline.freeman@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-83.png', linkedinUrl: '/in/jacqueline-freeman-4dc0ff463f', jobTitle: 'English as a second language teacher', }, @@ -4835,7 +4835,7 @@ export const peopleDemo = [ city: 'North Henry', email: 'joanne.hernandez@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDt+KOKiJNAJpkjrieG1t5J55FjijUs7scACvK9e+Jt7cXDQaLGkFupx58q5d/cDoBUnxU1yVZINIjcrFtEsoH8XoP51wOn6XeanJtgiLZ45HAqJSsaRhc07rxJrVyA82sXLEc/K21f0xTLbxbrNjP58eqTM5+8jvvVvwPSta08BXV2yhtp7buw+gq7qvw/TTbPzFYs2Bk4rNVYmvsZdhNL+Kt9b3QjvIRNA2M4GCPpXqPh/wAQ2HiC3Z7WT50+/Gwwy/UV88z2EqNyDlT+la/h/XLnQ7+31CIHMbbJV7OncVqpGTie8kUg6040gHNUZnh2tB/EvxCuYs/KszIPZU4/p+temaH4eh0+xSMAZPLEdzXE3+mW+m/ELVfMhkkiaLz1RCQcuR/XNdj4Ula4lWKKOeKIqTsmOSuK462534e1jpbe3jhxlkX6nFR69am50mVUALbcrjvjmuZ1nOn6gHfTpbwkjndnAJ7CuisHe4j2G2khHTB6H6VktFc2erseKapNsu3UAAg8g1mNdKRgjg9RXW/EXRmstWa5jU7JcHAH5/yriBZ3c0MtzHbytBHzJIFOF+tdcJJxucU4tSaPpY0DrTttJt5rYwMO80uA+IG1CQAtLbLDg+zE/wBRVuwlsbFp5JJoYQoAyxAA+p7VLqcRMKyDqjfoa5/+0dLj1BkeIyzgfMFGeB6/nXFVT5z0cPZ0zq3FvdOPuMR36irW6KCPPFY2nappd6Uis2VXGfk27SPwrQlTeCM8Vk9DayOd8QaauvGJGUBUbduPasLU0t7DwtfI1vHHDEhaNl/iLZXb+JP5V1t7MlsANhZe4HXFeY6prdx451u10KxjNvZCX5snlsdWOOgAzgVVOLk7ETmoJvqe0baTZUuKMV6B5RXng86B4+m4Yz6VzMOnl5SGcRSKcMPU112KzNW06Ka3muk3JcRpkMp4bHqKxq0+ZXR0YetyO3cWK3WKIbtmRzuFQTagq5UEFvQVz0M1/MwQzEx5wccVu21gI0DHk1wtnoXKWpJJ/ZV3cN98RMVHpxXGfCbTAdVvbuRDvjjCrkdMn/61ei3tuJ7OSA9HUqfxFUvBttbadb3VjFavFLG4MkjHd5uehB/pXRh2r2OXEgAAAAJ2uf/Z', + 'https://twentyhq.github.io/placeholder-images/people/image-84.png', linkedinUrl: '/in/joanne-hernandez-22617ea91c', jobTitle: 'Research scientist (maths)', }, @@ -4845,7 +4845,7 @@ export const peopleDemo = [ city: 'Cathyberg', email: 'brandon.randolph@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDqMUMVRCzkKqjJJOABTwOK5T4hap/Z3hl4lz5l23lA5xgdT/LH41JRzXiv4kuszWWhOFUcPd4ySfRAf5151eahcX10895NJPK5+ZnbJq3p+i3mrs3kqMDgseK0V8C6mZdiGP8A3iaTnFbspU5PVI5vzCn3RgjsRXVaF421bQ0QRuJ7fvBLlhj2PUUHwHehiHlQD1rF1CwuNNZ4JQWx3FJTi9hunOKu0e86Fr1j4i08Xdk/Q7ZI2+9G3of8a0iK8Y+F+pm18Ui2b7t3GYzzjkcj69D+de0kVZmOArzz4rq32bS2IHliR/zwK9FFcX8UNPa78LpcIoJtZg59cH5ePzFJjRg+D4FTSlOMszEk+tdcmMDcgFcMsV7ZabaR2zyqwiDARgdcZOSa1vD2ranO6Q3gBLfMGIwfoa45RveR6FOVko2OimwVICZzXLeIIoxaSNsBbaecdKXW9U1Z5pI7P5EiBLEAEtjsPeqFp9puNyztMcrllkAxyOxFCj1HKV/dOb8HNjxxpWRkC4Awo9jXv5HFeNeANN8jx2krLmONpEUn+9g4/SvaGFdiaZ57TW4i1T1qzF/ot1bEZ3xnH86uDpTxyMGhq6sCdnc4fT442t0ilALqNpB9RUqwxLfKkSqMddopNQtv7P1WVI92xvnXPoR/+usma4tpZAzziKQZAIJyM1xWd2j0oyTSaLtrFE93KkgGSTjPenahHFBEQgA47VkW0ttBcYhuBIzN/ETmr1+S6EsegzSasO+hP4MsMaoZtnyjdKT/ALR4/wA/Su8aqGjafFYadEEB3yIrOxPU4/lV5q7IRtHU86rPmloItPFNHFRtcxrIYwd8gUtsTk4qzMzPEll5tibtP9ZAMn3WuVWMzxgqwVscNjtWxr+sy3GnXUEMZjCjccn5jg8iueeOUYeCQKr9j0zXLVspXOzDyfKTmHycsXBbuarSSGbKg5A5Y1DJBePJtlkTnshq2Ikgtio645NZSZurvc2PB3iqbUbWWDVGRJYZCiSbdoYDHB7ZrriQRkHIPpXA6HpZllitscyPvf2H/wCqvR0tFVAg4A/QV3Ru1qfnSsnof//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-85.png', linkedinUrl: '/in/brandon-randolph-f206b641f3', jobTitle: 'Games developer', }, @@ -4855,7 +4855,7 @@ export const peopleDemo = [ city: 'Port Crystalland', email: 'william.wells@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDv8UYorP17VU0PQ7vUXUN5KZVT3Y8Afmago5/xl47tvDaPZ2qi41RlyqfwxZ6Fv8K8uPirXtUuGN1qM5yeUVyqr+C8CsYx6jr2pT3JLSzTuWdvUk10Nn4C16SEPHDHnsHNKU4rdlxpylqkZaapqFheNPZ3c8bg8ujkE/X1rvPC/wAUC8sdhraZYnAu14/76X+orIX4b6/dBiY4ocjld+QaydV8K3Hh+4Se6BZEXJx69qlVIvS5TpTSu0e9q6yIrowZWGQQcgilxXnPwr8QS6hHeaZMSwgxJET2BOCK9IqzIXFcJ8WTKPCkKozBGuVD47jBIz+Nd5iuR+JO9/CbQLEGEsq/N/dI5/oaV7FJX0RzPgvTYotNhlCDe3OSK9JtE3Qg5zjsK8xuJ7nToo4rZ5UUIAoiTJOBWz4a1rVbu7htZkYMT95l2nHviuKSb949KDSSiehhwsZ+bGRXOeJraC40e5E0fmfIccc1ga7rmsWd68EQYbOuyMMSB6Va0rUru+CRzrNgjLCWLaf8PwqbaXKur2OP+Gjpa+MjDGcrPbupA7YwR/KvY6848IaONO8aXtwIt0YleCPH8G75s/kMV6URXdGSktDzZwcXqLWdr9ml7otzG6byql1HuP8AJrTxSOiyIyMMqwwR7U2rqxMZWaZxmjrBcQLHOillHfmtK0NrHrkUYKRpHz1AyayZrb7Dq80KZVQ3y5PbqKqSstzdgyWs25RgOoAOPbmuHlfNY9aMk4qx1TPZSXBSby5AzEBwQcc96luXt7WELCgUY5IrBtJra2iaCLTJ1EhG5gob8Tg1bmO4BdxI7e9Q10Kb7lnR7WMXDXAXDSMXb3PTP+fSts1Fa2q20CqB82Bk5zzUtdtOHKrHmVqinK6JThevFZmqarHZQMI2DTkfKo5x7msecBchc7gM9azr8lJkG4YIzmtbmVjEs9d1HWoHu9QRFljkaIbE25CnGfzzW1aSWlymJ2Y98A1TggSOeSPjbIS6/U9R/WmS2JSUhcjPQg1w1Pjdz0KXwKxurLZWsR8lzjHc9KrRX8cNzb3E+RAJkX6kkAfqarWelln3SsWA7GtIaWNUuoLVEzFBIk0zdgFOQPqSB+GamGs1Yqb91tnWmmmqqXe2Qxvzt6kVZV1cZUgivQPMP//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-86.png', linkedinUrl: '/in/william-wells-ddf1c0e80e', jobTitle: 'Teacher, secondary school', }, @@ -4865,7 +4865,7 @@ export const peopleDemo = [ city: 'Pereztown', email: 'monica.wall@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDVJyKaSKCeOKy9b1WLR9PknldVkKnykPVmoGi5dX1pYxeZdTpEnYscViXPjjSreRQiyyx/xOowB+fWvPp7671a8aV5TJKwAXdyfoBVyPwZrs6eaYxg/wAJOP51k5msabex39n4p0m/O1ZjFu6eaNv69K1FdJEDIwdT0KnNeXT+FNb0u3aWWLdH1YLg1HoHiebRr1UcsbRyBJG38Oe4pxncJU7bnqpznk0oqK3uIrmLzInDKe4qYCrMrFsBVHAryzx9eCXxAIlAcRxqnI+6ep/nXqJGa8e8S728aXQYEF5goB9OAKUtio7nXeB/DEduiajc4eZxlFPRR/jXo6RqUGACPauMuWitLaOKS3llXbwEXOAB2HTNWvDolS5UxpJHA5BIfqM/jXE9dWelFWXKjpbqFHgdJVXYRgg968h8WeHLbTxJdWhOc52noPxrsPEbvc30wk88wQn7sIJY/hketY16kN7pdykULxlIyGDAjPHGQe9OLtqKaTVmZnw9v3N5PZSyEqU3pk9++K9DPpXkHg20uLzxBAIn2pE/mu3sO349K9gArsR5zJQ2a5vxFoUN7dW96I182Jly3duRgfzrolNMkAYcjIHNKom46FUmlNX2LdjJBcW6KyKxx/EM0l9eWthcwJJlULAAohPP4dBVDSZEdVeMnac4yMHrUt5qzbxHHYyzY6k4VfwJ61xK97HqRSexHa3dnfavcqjb0b1Xv9ag16OCG1dI1C5UjgU2DUCbllNi8BPdcMPxx0qHUA9zOkeRnPc8UNO9glotTP8ACejQ6ck0kOCHwCSPmz3/AArpCMU3T4B9ijaJdwkG/d2JNWPszudvmIDnpXYpKKSbPLnrJuOxA0c8a7jE4A6naePrUxtpht4DbhkbTXUDS2d97Oyf7rEH+fSrK6eIwCqjA7mhc7epNkef3ebafHQFRkDtVm3NtNF++kOD2zU2txPJrkqyfd2qAMY4IzmshtMkYny3IPpXHNrnZ6NK6gi1dLbW6fuWwDWbA4uNQjQSiMHOGY4BOPWhtPmjGZXzk4Ap1vag6tYRMMo8u1h/wE/4UR1kgqN8rOttbZhaRjfGPL+U8gjA6VaWXysFYg5zn5MU22sjD/qyMA42mrXneVnciqfZa3dNowAAAAOG6P/Z', + 'https://twentyhq.github.io/placeholder-images/people/image-87.png', linkedinUrl: '/in/monica-wall-18fcd0b442', jobTitle: 'Clinical molecular geneticist', }, @@ -4875,7 +4875,7 @@ export const peopleDemo = [ city: 'Fernandezport', email: 'patricia.whitehead@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-88.png', linkedinUrl: '/in/patricia-whitehead-b76f160790', jobTitle: 'Learning disability nurse', }, @@ -4885,7 +4885,7 @@ export const peopleDemo = [ city: 'Port Jessicatown', email: 'chelsey.cruz@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0yjFLRUlDGZUUsxAUDJJ7CvPte+Kun2Fw1rpsX2yUceZnEYP9ar/FTXdQsoo9Mt2aKC6jwzr1fnlc/l+dcZoHw71LU4hc3D/ZIz93cMs34dqiU1Hc0hTcti5d/E3X7iQGGeGEDkKiA5/Ouh0n4sxmBY9StmMuP9ZFgA/UHoadbfC7TFGbiaWWQjkg4FYniL4ePZQPLZSFo0G4hjyKyVVdzV0JW2PStD8Y6TrreVDKY7gDJikGCfp610Ir5hgu5LKSCSOVlkRuGHtXvfg3xRb+JtL3r8l1BhZoye/Zh7GtoyvuYSjbY6SkPAJ7U6msMgiqJPLL65Hij4irG6D7Jpse6NW/ib1P4kflXcwhUQYIP415Xd25sfFGvKyPIxUMioxzhn4zj8DXQeC5LmdjDKkiQmMuC+cjBxzmuKqm3c76FuWx27TRI4DTIrHoCwFRXojuLR42O5ZFK5BrzvxJb3S3u5LVpQDndjJPPaug0k3UZEEsLqvQEfdP0rO2lza+tjybXLEadqMkQbcqsQM+lbvw21g6d4ut0JIjugYXGeuen64qP4i2ElrqyzgYjlGR9e9crpty9rqdvKpwUkVgw7YNdcNYpnBUVptH1ZR2paK2MTz+10sR+MvEE90pYymIRlu6bc/5+lXhf6Zpiz5lSILgE+n1rZ8QQkwRzLwVO0kehrjbjVdJhnRGheSROpRc5x2z+NcVWL52elh7OCsdFbz2V/nDpIABhhyCKsyeVAvyjp0rBtdZ0678uK3VonycKyFCK05ASpDGsXpobOxyvinS21l4HIHlwlmIJ68VxF3pEMOqaUsKDFxIrbGGMYPzD6V6Jreq2WkRGW+Vzb99q557cVyOg/afGnj6C5EDxWcCkxgj7qjPJ9ya3o8z9DmrOKT7nu1LRRXYcBU1GBrmwmiT75XK/WuNWwaVFKzCLHG3pXe4rzvVLxNQvry401+I5miYdmZepH1rnrx2kdWFqNNxNIQGKHEjoxHIxUT3JIwTk+1c3b6jdzXHkyhlwcV0FvblAN3U+tcrR1uVzlfHdnc39rp9hbqXuLq5Cqq+w/pXpfhXw+nhzQoLDzFlkQHdKFxnJzj6VwXi22uLm80f7HM0EtvOZTIpwVUD+pwK9N027W/06C5Q58xAT9e/612UPhODEfEf/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-89.png', linkedinUrl: '/in/chelsey-cruz-3927a3b54f', jobTitle: 'Accountant, chartered management', }, @@ -4895,7 +4895,7 @@ export const peopleDemo = [ city: 'Georgeville', email: 'marie.herrera@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDryKbipDTagoYSFGScAd6oT61ZwOUMgLDr7VV8R6kbCzCxjMkhwuDWDbeHLq/QNfSeWhOdiZyfrWFStyuyOilQ51dmvL4yt45fLjiZj6ngVbt/EsUjKJ49m48EHIrGl8LJEpNtcSIcdMAis2aOa0gbdxIhwwA4x649Kz9tK+5q8OktUeiRukyBkIIpxSuK0LWmSZQT8p4K54H/ANau4jZZY1dTlSM1vTqcxyzhyjKaakxUcgwpIrQg5SRP7U8V7m5hs1yq9i54H5c10gU47ZrkJbn+z5L9lheaWSRVUKccnPerfhu/nnRxcLIo2kguc/zrznd+8z1YWSUUdA4K5PasbU7NbmIkELJ2Pr7Vk6w1yZ3niRn2LuAYnBx2A9al068nu0Cy2rQuv93lTRy6XKck3ymJbR/Z7ogHgNgqeo9a7/QbrfCYi2f4lrzrxDO+m6rHNj91KAG9j610vhm/BmUE9GH5Grg3FpnNUjdNHb0xxlTT6CMiu44TCtLeJbm73oCWcDBHYf8A66hvbm0tlm/exx7AMgDoKv3UBS7Zl4D4rGudTtI5GjSzecocFgucH64rz5Rak4nsUbTgmi9YPBcxnaUYjHI5BFOuNkAJAA+lUrDUYLhzGkTxP/dKED86sXSk5B6VDunY1sjltdt0vYWZ0DKoOaq6OxtrlE6KRgeoHar2q6jY6cim9UsrMNihN2TWTp9019qKzKhRGB2J3A96etjCfL8z14U7FAFLivTPJKd8h8reo5FZiW1vLEDIVz2GK32QOpU8g1yjWZttRuLVpWYAB0/2VPauXERSfMduEqP4SwypERtIxUM0u5MZyaaLdxKY5M57VJ9n2cYrkZ3Hn3jdHd7KIfxMWP4f/rrf8FaX9ouxLIBsRRgUa7pX9p3ESIMyIfk4zya3tA0+70YqboEqRglFyBWkXexzVYtNtH//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-90.png', linkedinUrl: '/in/marie-herrera-3c032f2c87', jobTitle: 'Teacher, English as a foreign language', }, @@ -4905,7 +4905,7 @@ export const peopleDemo = [ city: 'South Heatherstad', email: 'gail.russell@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-91.png', linkedinUrl: '/in/gail-russell-47081f3909', jobTitle: 'Building services engineer', }, @@ -4915,7 +4915,7 @@ export const peopleDemo = [ city: 'Stephanieville', email: 'christopher.whitehead@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-92.png', linkedinUrl: '/in/christopher-whitehead-907e5c7217', jobTitle: 'Research officer, trade union', }, @@ -4925,7 +4925,7 @@ export const peopleDemo = [ city: 'Lake Terri', email: 'vicki.gonzales@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwCcrTQtTleKpapfxaXYSXUgzt4Vf7zHoKzuaDri6gtVBlcAnoo6mmtdgW5mRNwHvXmkmsXF9fNIZMsx+ZsZH0A9K6TTpHuVEbzzIpGCUxz9eKwnOS2NoU0y6fGFnFP5c6YXOCyHOPrW5a3ltfReZbTLIvt2rhp9F1i+dxDCixA8ZUZIq5osr6DAEuQRI0pRlPYdiKaqaahKkdkVo2ZpLWeO7t1miYFW/Q+lWAtbGNh+3ivO/iLfut7a2KEgLGZCPcnH8h+tekha8r+IsbL4njY9Gtl2/mwpDRpeFPCiXVrHc3DY3gEL6V6LY6JaW8AARGI9DXD3Pm2mmW0S28jqYhyvbA7cjmrPhRtR+2ww4nWCbn95n5fTPpXK03qd0Wl7p6AIooUYqFXjHNcP4202JtMe6HDxHfkdxUHi1rtb1l2zyQx8ny8nP0APNQlJbjRb23MMiMIGxuyM8emTzSS6hJ7oi8EXZf7Vas+4cTJ9Dwf6V2QFedfDxZJNWdyCFS3KnjvuFelba6o7HFLceorm/GWiRX9pDelV8y2z17qe35106iiaLzoGTA5HGfWnJaaBFpSVyhpFxDNaLBLGjDaBg1NPf2Gmahao7pFFuHPTcfQVj2oYXD/KyMrspVvUHFOvNZsmAt5dOuLojPKxZx64J/pXHZ3seirNaG1aXdhqNzcRpJFKm44xzg+hqLURbxRPFGgGVIrNsdZ09EMS2M9qxIxviPPpzVmXfcTgjluwJxRZ3sDslqV/DenCxsW+XBcgkY7jj9etbJFEUSxRhFHApxFdcVZWZ585KUm0OWnimjgZzxWXqOvWtmjpE6yzjgKvIB9zV2MyHW8QXKsBjcmWI+tV4oLW9QGS5KY6YPNZmiJcXFvdNeXEk8zzuTvbO0dgPQYqKWAwzOq565GK45/GzvpaQRuCC2toyI7gyZ9au6UPNeRj/CABWFZQFkLuTwehqez1hrLxLBpsoAhuoC6t6Mp/wp0/jFWb5GdSRTCKkNNNdRwn/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-93.png', linkedinUrl: '/in/vicki-gonzales-a6b6db11ce', jobTitle: 'Psychologist, counselling', }, @@ -4935,7 +4935,7 @@ export const peopleDemo = [ city: 'Sydneyfurt', email: 'paul.graham@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDrOKrahf22l2E17dyCOGJdzN/SrWK8/wDipdumnWVkhOJpC7gdwvT9TWRscfrnjHV9dlkTz3trJjhYIxjj3PVjWBIysnlJy/UjGCK6zRPBd3qlstyGVFP3Qe9bbfDKeUqZLuLPfCdPoetQ6kUzRUZtbHnLBbXkkMGHQ9CP8a0tB1+70PUBNZTyNADlrcsdrj6evvXbv8L7ZY8tdSM+PSuW1rwdc6TC7wOJEXk5+8KFVi9AlQmlex63ouuWOv2f2mykzt4kjYYaM+hrSryr4VzNb6ze2Uud0sIkXnj5T/8AXr1Y1ZkKK8/+J0CS/wBm7hyS4z+VegiuX8cact9YWshzmCYHHqDgH+lKTsioRcnZF/w5AkGk26KMYQYFbu7OOK5LUobqIoYZJwoXKJAAOg7k/oKs+HL/AFGchLp3II3DzVAYexxXDbTmPTUrPlN2Zjtxt61yviKPdYygDJ2nIFLrt9qU00y20siRQAlvKA3NjsM1n2aXEjtvkuMbdzJNg/kRVKNtRSld8pkfDu383xRNcIfkitmB/Fhj+tepEVwngWzew1G9dVUpczMnuAuTx+JrvWrsi01oedKLi9RoqvfWy3dq8LAEN/8Ar/pVgdKXGRSkrqwQlyyTGWeyaBcgE46GmPHGl0qRKN2fm21FBmFzg/dzxVO4ubGSQGWZUdc4IYg81wrex6yaauh1miNfzowG7JPPel1FYoYW2gBj6VRt5rKC6P2a4V3dsjL5J/OpdRJkBGeT2qutiXsN8P2uyZ5eNu3IwOhP9etb5NRwW6W0KxoAMDnHc0412Qjyqx5lWfPK4DpThTB0pJrmG1hMs8ixoOpNUZkF4TC4cA4K84qPZHdRAhlBI4bHaqUV8L7W2ZHYwiFQinock5OKstpTSCQQStGwOdo6EVxVLc7PSoNqmiCaKK33OCu4DrWVc6ilvG15KC0UJEj46nHYVem0u4AAuJy7HooH86p6xYK2kXEPRTGQSPpUp6lyvJM6qC5ju7aO4hbdHIoZT7GlNch4W1aKwtItMvZghRVCO3AzjkE9q60OHUMrAg9CDXeeWwAAAAABWZ//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-94.png', linkedinUrl: '/in/paul-graham-0159c4f113', jobTitle: 'Surveyor, commercial/residential', }, @@ -4945,7 +4945,7 @@ export const peopleDemo = [ city: 'Michelleborough', email: 'john.carter@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDlmrE1SUyTuuSVjHCjua3ygzXK3zkXE7DlxJg/SpkOJBBJE7hZTtAH3c1FcsiTFAwaE8AfWp4LF76bbbxEs54JHSuhsfh7q0ilpEXYeRhu9RdI1UZPZHIxLsmLSkL+uavNcCVlUyYXp0PH0rcm+HmswnzAFKjqc85rA1XTbyxZTPGQw53CjmTYckktUaWiTyRXRtWb5WBI56/hXRKpzXF6JI91rVvgjcDlvoBXeIgNaRMpEDVy+tWMtvqAkkRhFcfMpxwwz2rqH4rX/s+HVNLsHMJdkuFDHP3VUgH8+KipLlRpRhzto2fD2i2sWl2hMCiVFHOK6pBsUAAVxutXOsaac2KuYzyoSMHPHQkmmaD4h8QXcyQXliAz4IYDG0HsR61x2drnoJpPlOwnBaMggY9xXB+LLLzdPnVFBbaWHFTeIvE2tWly9tZ2DSOg5bbnH0Hes+wOq3szvqDvsQYZSoC5P0ppNe8KbT904bwrZs+pPcjCpEpyCepPGBXaI3NJb6bHpelxx7FEjMTkDk55NMVsHiuyD5lc8+rBQaRE6mtTRNVSwint51YxycqV52n/ADj8qzGzQFzVSipKzIhNwd0el28kNzbCOVVYY5yMinwRW8V4kcEYG1gWIFYmjzCe0ifdyFww9xU11fWsWDb6hHBcAnhmHJ9xXBZp2PXg1KKaLTiCTUp450XLOSMjrVDVpIIIWjhRVGO1UoL+GS4lNxfwzzM3ARuFPsKi1Es4YqGZjxxzTUbysTUkoxbMm6uGupQzDaAMBc9KhXg9KU8GnLjNd6SSsjyZSbd2Vye1SQpvkVB1YgVdstJutSuFgtYjJIfToo9Sewr0XQvCVpo+ySUCe9P/AC0I+VPoP600hHKWsYha6t4UZfs0pifPViO/5Yq1JA93AvlTxRkDALLn9K7a/wBChumaeHbHO33jjh/r7+9cdqukzQOwZHhY9+x+hrjqwlGV2ejQqKyUdzKntpLZWaa5jdj3VccfSszUHnjtPMiBL9gTgnvx71Zjt5jITM5fB4BroNP8PTXc8Vzcq0MUXzIpHLN24PapgpOXulVZK15libwrZXSLNKsiTOgZ9jY+Yjnism58FXsSs1tKkwHRT8rEfyru4Y3KhpDy3TipxFhgB6Fjyz//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-95.png', linkedinUrl: '/in/john-carter-c39f5f879b', jobTitle: 'Cabin crew', }, @@ -4955,7 +4955,7 @@ export const peopleDemo = [ city: 'South Alexandra', email: 'dennis.taylor@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDo6WlxVTUr6LTNPnvJv9XEpYgdT6CpLH3d9aWEJmu7iOCMfxSNgVzN98R9CtA4QzzsB8uxMK34muPNlrPjjVGupHTyk4RT92Mf3R6n1rYT4Vyy8zXqA46BDWbqxTsaxozkrpGzpvxC0W+X9+72jf8ATTlT+IrpoLiC6jElvNHKh/iRgw/SvN7r4VXUPzW92rexGKh0pr3wZrUSXKbraThyg4I7n6ihVIt2QpUpRV2j1PFLihGV0V0IKsMgjuKUCrMxa5D4gyyDSLa3Xdsmmw+D6DI/z7V2Ncr44jL2diAMj7R83t8pA/WlJ6DirsteFrOK00q3jjXGFB+p9a6lWyPWuKuzNbxrDGbkAJwLdcscVLoEupi5SOaecwMd379fmHsa4rdT007e6dfI3ynPeuO8VQQtZuXAOOc+hpPEFzqRu3jgkuPJj5JgXLH2xVNknvLCeFmnK+UeJ1wytjihLqKTveJteEppLjw7b+actGzRg+oB4/TFbZrF8Hpt8NwA/e3MSPxrcIruWx5r3AVla3arMqu2M7di5HTkGtZaZcQmWP5QCw6AmoqK8bIujJRmmyvYGGWFdwGcdTUN1f2NrfwxPLHEN2BkYyepxVeBHj/dk4dcjHuKrS3KSfuXs55QO4Tg/TPWuRLWx6Sd1oXbW/sbjUJkWWOQFscc4PvT9TWKKFwgAJHashZYopdiWc0IOBymQfy6VenV55I41+ZzjjNFtbBJ2WpY0K38i3lx91iuPwGM1ptTLeIwwBTjPU49aea7IK0UjzKsuabaFWpFUtnHQDJJ7Co1rb0SwF0JmkU+Wy7PrnrVmZxmo/udRlBYYyDkfSnBY5oAry4DDgjrVrUdIvbDU5or1VaKQ/uJF6Ovv6N6isW402ZGAt5gp7K/T8K4ZfE7npQ+FWLjRxQIdsufc07SmE96zdQi5B9zxWWmn3e7FzIOey1c0vMfiK1tkYjzcoE7MO/4jr+FVC3Oiat3BnQmmmpZreaAkSxsuOMkcVAJrsPPP//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-96.png', linkedinUrl: '/in/dennis-taylor-81e83d5e15', jobTitle: 'Sports development officer', }, @@ -4965,7 +4965,7 @@ export const peopleDemo = [ city: 'Willietown', email: 'gail.salinas@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-97.png', linkedinUrl: '/in/gail-salinas-6fd9ac936d', jobTitle: 'Theatre stage manager', }, @@ -4975,7 +4975,7 @@ export const peopleDemo = [ city: 'Kleinfort', email: 'stacey.doyle@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-98.png', linkedinUrl: '/in/stacey-doyle-c2b53da3c1', jobTitle: 'Engineer, water', }, @@ -4985,7 +4985,7 @@ export const peopleDemo = [ city: 'Rogersberg', email: 'nicholas.jones@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-99.png', linkedinUrl: '/in/nicholas-jones-37d87e9bef', jobTitle: 'Runner, broadcasting/film/video', }, @@ -4995,7 +4995,7 @@ export const peopleDemo = [ city: 'Staceyberg', email: 'sheri.donaldson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDcAFYPiHxVp/h+MpIwlvCuUgX9Nx7CtDWdTj0fSLi+kx+6X5QT95uw/OvCp7t7u5eeYmSeRyzsw6k1JZs6l4j1DVLlri8neOBhtEcTEKo9hWY0kbsAshXPO7FNeOfAXKkn+FSTVu28L6tdIGis5Ap9eKlyS3KUW9kQWuqTWDhrWeSOYH76nFdz4c+IIyLbVQXGcCdR29x3/CuUuPBmrQRiRrZtuMnnmsiRXt5PKZBEV9etCknsDjKO6PoNWSSNZI2DIwBVh0Ip3Fcn8Pr973w+yOxcQSlAT2BGcV1lUSc347s0u/CdyzsymDEq4Gcnpg/nXjCoSV5yT0FfQl5aJfWFxayfcmjZD+IrxjRdFkPiuCxlAOyX5iDkYHepk7IcYuT0Ov8ACXhBoYxdXmGkfkL1xXoC2ixRABMY9K5vUbiWxVo0iu34yogO0DA9e5pvh651aa6Ecrz+UwDfvyCVB7Z9a4XeXvM9ONo+4kdFcW+YmG0dOhrzLxxpMQtRcom2RDyQOoro/E97qwuJILdplii5doRlj/nNYsiPd2F1byfaS3lNlZju5xwQaumuW0iKzUk4k3wrWT7DqLn/AFZkRR9QDn+deg1yvw8t3g8KIXx+8md1x6cDn8q6qu084cDgVzM2lLFrqaiiqgT90AB1B5z+db5uIh0LH8Kzr++IaGFYgVd8s3dfSsq8G1dG+Hmotpm7beRc2+2RF/HpVWe8sLSZYRJFCoYDLELub29agtSfLznjtUFxfQOBG2lzTbcgExcfUVwrXQ9NeQvn2VzrU8YljkR8Zwc4NQ6rDbQwtHFGASMcVnLdWlveYj0+W3LdCU/nU7LJeXKpgnOelWovmsRNqMXc0NEtEsdHggQ5GC2fqc1fpAAihVGFUYApc8V3pWVjyZO7uUreCW4fZFG0jeijNW7nSJ4LRpLgBABnAG7+Vd7DZQ20Xlwxqqjsorn/ABM7m0EKkrHISCRxkDHH6inUnaLYU4uUkkcT9oNo2yQnZ2NX1e0uYv30xAI42mo5rRZIlV+nrWVeaTLCxMLfL1GDXmKzPW1RYuoraDJhlY59TmrWjAFJZzywOwfzNc8Y5t21mzjrW74cWRpbiI8x7VYD0PIrejbnOfENuBq7s0dqdJFsPmnnn//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-100.png', linkedinUrl: '/in/sheri-donaldson-aef36dc097', jobTitle: 'Dentist', }, @@ -5005,7 +5005,7 @@ export const peopleDemo = [ city: 'Theresatown', email: 'christopher.christensen@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDvMVV1HULXSrCa+vJRHBEu5mP8h6mruK8o+L+rSmWx0eFyqgG4mI6ei/1/OgCjrfxO1O/keDTVWxg7OT+8YfXoPw/OuMutRvbljNLe3Mzk8kuX/nWzoHgy+8QRpMhCxHo7jP4118Xwos0VfOu5WfuQABWUqsVubxoyex5jBqtzbTLNDNJFMpyGUlWHuK7fwh8Sby2v1t9avGntHYL5snWP3z6V0cnw20fYMLJle+7rXD+KfBX9kRNd2rM8SH5kPUD1pRrRbsEqE0rnudpeWuoW63FpPHPC3R42yKm215Z8Gr0yR6paFz8pSRVz65B/pXq2K2MBa8N+ILzX/jW7t5QV8vYif7mAQf1Jr3QV5N400eWb4kWblcxXYiXKn0OCDSk7IqKuz0HQ7WOz0i0gjQKFiUYH0q5Jkt1zXM6+tyu5YmuSqIWVYOMYHr6+gqp4Xur6edIp5LgqV3/vSCR7H0rha0uejF62OrfI9q5rxIivplypXOY2rO8T3N79rlWJ7jy4lyVhbBYccD1pumrLIvlu1wAVy0cxz1HY0ktLjb1scx8LpXh8ciJT8kttIrAe2CM/lXt9eW/C7Tjb+I9aleNQFBjRj1+/zj9P0r1M13p3R5slZiisHXtN+0Xlldov7yKZXZv9lc/4/wAq3qZPF5sTIMAn1qZx5loVSlyyuyBoUnjzgc9ciq0EVvFMyQqMr94gd6kR2SFlJxgc1i3VzpjAf6Siypn5lc5BPXOP61xWPSjqO8qGS+dZFGSeCe9S3dvHbx5AAwOMCsmCexjnYx3KyOzZG5+T9M1oXLtcbVHfgCi3QbYvhOxFvJdSjPzMTz33HJ/liunNV7KzWyh8sNuJOScYqwa7acWo2Z5lWSlK62FFKBRVLUtWtNLh3TzIsjA+XGT8zn2FWZlS+kEc0iKy7WODz0OOlVp7fzLYCNI1298VjeEZGv7LU/Pbe5vZCc+4U1o3tldxRD7LLuTH3G7Vwz0mz0aTaiipJAkQy0cZf1AzVjTJkOo24ldVXdgFjjLY4H51nx295MGa5IjUcBVPJrH8Zq8Phl5IWKvDLG4K8EYYURfvIdRtxZ6oaQ1zHhbxba6xYW0VzMseobcMjcbyO4+vpXTZruPNAAAAAAAAAAP/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-1.png', linkedinUrl: '/in/christopher-christensen-0405d38686', jobTitle: 'Public relations officer', }, @@ -5015,7 +5015,7 @@ export const peopleDemo = [ city: 'Shortville', email: 'joshua.hernandez@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDxxsmljQs4FOxUkTGMqQO/J9qTdkNK7Na006Foh5zAknj5sVuW9xaaXFukUFO3lnJH4VyUUdzqVx5UJY88BR3rpYPAOuGAOJVGecEniuWevxM64J/ZQatf2MrRy+TGVPL+pHqPWs+50i3nt1utOdmX+JD2rWk+HuqGPBkD4GSM8ZrLS1utAM8NyMZXK5PBPpRGVvhYSg38SOfkRlY5yD3zUfetO9ZLi3WdU2kcPjv71m45rpi7q5ySVnYkbIqKZsHYD0H61bdQRVGZSkhwPvHNEhxPT/BOkwRafDOEDTONxY16NboPKHP4V5pE89jo9skfn7jECFi6k4zWj4eu9Xe6ht5ZJTHNg5kOSvsfSvPkm7yPUi7JRPQQAATXD+N9Phm0u4kIxInzAgVX8TX+q2980Fu1wY0PPk9TQ4u73TLm2mFxvERH73nnHY0krWY3rdHmVl5bho5JThgdxqqfvkDpng0+0R/PyVztBJz9DQE5r0InlyJzxmrWm2CajNImcSLGWXjOcdqhK5BqXT7iSx1CK4j5KHkeo7inNNrQINKSvseraU0UkCRyIpwoHParsUlrbavbqzJGgOSSQMmsPSbhbm3juIwVD5OD2qS9vdLlkQXRUumcHaSVJ/lXmpO9j1001dHSCWyuL2ZN8Um5jggg4PoaivpIYI2jVeSMDFZOnX+jJG0dvtEjEEkjaxPrz1p2rXC2ltNeOcrDGXwT146UNa2BtJXPPNd0pdIt4VbBmnZnbHZc8fzrCAywrS1jVZ9XvPPmREwoVY06KPSqCj5q9GCajqeTUknLTYfg1PbwlmACkn0AqzDYz3EixQxPJIxwFRck/hXpngXwLeWlzNeaxbeUHhMUUZPzDcMMSO3HH41ZBgaIHttPCOrJhiQGGMVrRQeeoxMsZHRsc0f2JcaNLLY3chkkDsRIf41J+Uj8P1zVZ0kibCflXmzfvs9SnpBWNIW4jiIkmSU+uKwfFPnT6OUj3sm9S+0fwjnn2zitGCGVz+8OAewqaW3kbUdLhiUkyXITjsO+fUYzmnBpTQqt5RZ5aY/mpQnIOK7Lxb4I1LR9Ruri3s5H07eWSRBkIp7HuMdK5hIiSCvQPMP/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-2.png', linkedinUrl: '/in/joshua-hernandez-aaf7b631ad', jobTitle: 'Therapist, sports', }, @@ -5025,7 +5025,7 @@ export const peopleDemo = [ city: 'Benjaminland', email: 'ryan.walter@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDsMcVx3i7xxDoDGzs41uL8jLAn5Yvr6n2rqdRuhYaZdXZx+5iZxnuQOK8JsbWfXtW2yne88u6Ricnrk1m3bUtK+g67GseIna8v7qSRR0JGFH0A4FZT2ZjkYcnaOte+2ekabHZxWphBjVce5ps/g/RJlIFqqkjGRXOq51vDHhNjNe2N6lxZTPHOpwCp5r1nwp41OsTixv4liusYVgMBz6EHoa2YPBWjW7b1iBZe7VzHjPw+kEMOrWRMd1aOCGU4yO35GqVZN2Ilh2o3O/K0Bag0u8Go6TaXg/5bRK5+uOf1q3itjnMbxcceENUOOkBNeVeDoyutRFG3c8161rcjNZi0EIkS63RSEnG1dpzXEeGtJGj6ncoV8+NEG2QEZ5J/wrGpNWcep0UqT0m9jvbXEmfTPXNaS+Vjhsn0zXBamZpj8ouVQqSBGcYx/U1S0O+1BJkVnuFjYjiY5IrmUdLnZza2PSDsP3sAVzPisbdFu8cgJn8qy/Et7fxztbRPMAqbm8sYP0FQ6XHc3VjcRTC4ZJYGyJzz93iqS6ilK+h0/hRRH4W09QSf3ef1NbFZPhxZItBtYpcZjXYpHcDgGtTNdid0ebJWbTKt9B9os3TnkdutYEEC2l88aoqoEToMZwTz+tdSoyKx9Ut0t545lB+cEHkn34rGtC/vI6cPVsuRk6RQzxEOB9DzVWO2tXuTHHGm2Fgxb37VAZz5TbWOQKxZruxmjXdMEdGyDkg7q5o3Z26HW6pBaG9WWQKyOApORwe1RzJBDbssa7Se9crBd25ld5rtJn27dobgc9q3o2aUxRkkhsCm072Jk0lqbNtEIbWKJcYVQOKlpQoAAHAFGK7krI8tu7uPAxXM63q9vPqR0eMN9qhUSluwBH/1xXR+YGOF5x1rnL7SY4/Er6jty91brHu9CpOR/L8qVXSDLoK80Zq3W/fE2EccEVreSZ7UeQ0akDgntWbqOnrK5cAhh371QDXdsflYuOnNcStud6bibhs3jgZrgxOfRe9LpN1A+sx20j4lEReNOxxwfyzWJAt3dS/vXKp3GeammtFXxRo8kWVeOOXJB/hwP61pTtzozrSbgzuzikqmk0oc7iGTGc45BqzGTIARyD0xXYcAAAAAAB55/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-3.png', linkedinUrl: '/in/ryan-walter-3f704e09d0', jobTitle: 'Therapeutic radiographer', }, @@ -5035,7 +5035,7 @@ export const peopleDemo = [ city: 'Mccoyland', email: 'brandy.trevino@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-4.png', linkedinUrl: '/in/brandy-trevino-a6f561480a', jobTitle: 'Herpetologist', }, @@ -5045,7 +5045,7 @@ export const peopleDemo = [ city: 'Lake Normanfurt', email: 'john.martinez@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwBSOaKkxWdrd6dO0medc+ZjamBn5j0rgWrsd70VyhrXia30uU28a+bcAAleirn1NYi+PbkyOPscOF6/Oa5yK3vNZnZraJ5psfPjkVt2XgDXpQreSkSt/fIziui0IqzMF7STvFE48e3TSI/2ePyycFF610um6/a6kwSNwJCM7D1Fc/d/DjVobd3iMLMR91SQa5m8tb/R70LcRtEwA2tn096VoS2H+8hrJHrOaOtZHhvV11fTVZ3U3EZ2yAfzraC1g1Z2NlqrofiuX8cXZg0uGEDJmkx17AV1eK5Px3Bv0+1l8tmCSnJA6DHenD4kKfws1Ph5YQxaZ5wiAeRyST3r0NBlR8ox7CvOhaTWuk2SK90IxCGWO2HzM2MnJNbHhtr9JozNc3TRyjO24ILL9cdDUSV7yOmD5UoWOpn4U/KMe9cD410+3udNkdkUuBkN3FWvEs17PdyyRS3hhiONluRuI46DvWelrLcRzI807xbCrxXAG5cjsR1pJWtK45O94WOK8GGWPxIsMbERANvX1r1ACvN/BNox8Tyu24+UjAnHfpzXpQFbVfiOSkvdFps9lFqFtNay/dkQgHGcHtUmKfC3lyq+M47Vmaxeupp6Usb2cSMASqgcipZpbaHU4YXmijZgcBjjJ9qo2MhiQtycbjj6VnXVwl7cAykll5AjjJAz6mpirux0p9jU094Li9uFV43wxAIOeh6VHrKRRWz7QFOOcCseG5+yXTC3Y5Y52OhU/hVrVpPPtzz8xA4+tKStoF++5l6HYRWdmrqmJZcu5IweTmtWkAIAHoAKWrOaTV9B4pQKtW+n3Vyf3EDuPXHH51rz+H7m30YTxIGuo5A7qOcp3A/n+FaKDepk5paHNvObdznhc9fSrwEdzAEE/lsy8MvpSJAbtZDOQxf2rKbR7+GYi2n46hX/AKVgpK51pSSReujFawn96HIGMmsiK6F3dxov3AcsfoOlLJo99M2buQcn7q96e8YsJYtqZUcEDrTurifM0y/immrtrp9xe6PDewwSM0jtgBcHZ2OPwqo6MrFWBBHUHpXP/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-5.png', linkedinUrl: '/in/john-martinez-9b2c36ab60', jobTitle: 'Armed forces technical officer', }, @@ -5055,7 +5055,7 @@ export const peopleDemo = [ city: 'Michaelmouth', email: 'jennifer.morris@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwCHORWBq/idNPm+zWqCacfeYn5U9vc1Y8Vap/ZWlERki4m+VCOw7mvNhIXbdK5RSe3U1Mpdi4rudA+u3sshuJpZNwOUEanC0y38VXUErPveT/Zk6VBZ2V1qrCGwRwoHuSfrWyPh3rLJvkZd3ZWFY86T1ZuqcpLRE+m+K/PybnDLjkovK/h3Fb0VxHcRLLE4dG6EVxN14Q1jSnaZYgRjkA1H4d1KeLVEgXJWVsPH7+taQqJ7MznTa3VjvgQach5pAlOUVqZHC+Nb77Vrhtv4bdQvHqeTWNpOm/2hqEcG4jc2CfStrxdpFxFr11NFBIyMol3AcZPB/UGrPgCw+0axI7jiFN341z1JWTZ0Uoc0kj03w/olnpVokVunzfxOepNbzDKdRuHauS1Se5t9yLb3My4+7EcD8TWRow1KS9Vo47q3STkrJIWCj39K4krq7PRbs7I7a+t/MiPAP1rxvxXZjRfEcN1ajyw434HZga7bxXd6nDdLaxrcsmRu8g4Jz71x/ixGurOxmRZeHaLEnLA8ce/StaKtK/cxxDvFrsdVZzi7tIbgDAkQNj0zVpRVewtvs1hbw4I2RgVbVa70eYW761iuQjugkMO5lQ9GOCKy9M0ttKumuF2hpkUyKowAfb8MVsgll4OD2NYGja7darLPDeWiQTWreVJsP3m9cdq48RBp8y2PQwtWLSg91sdxaagk0RRkUH1NRXV7Z2IxJJHEu3dJK5CqPQVm2yEY/SlvtX0iGHZfRCZkOSoiLnNcsddDudty1NdWN5qIWKWKVZIwSOv41kaza214YIVQKIZhLwPTPFVrfVdGnu2FlC0UhGPmTHPXAqwpaSR2brW1KL9okc9dpUmIVxQoqTZTgleieSSRKSRUUmlxwXk9xEAHuFUvj1GRn8j+ldboWgC5t5JLpSokXERxyv8AtVm3OkXGmzeTcu0hxxKej+4/wrlxM7RsdWFhedzDhu9hCswUjirRgS5iIW6EZ6gkciqOpWJYll4NYzNcxDackDvmuFdz03oa09obdtz3YnbsSOaswoRGCw+Y8mufM09vC10BvaMbwp6HHNdhdWjR21rdKhWK5jVwP7pIBIrsw9rts4cZJ2SKYAp+PSmgetSqOK7DAAAAAAADgP/Z', + 'https://twentyhq.github.io/placeholder-images/people/image-6.png', linkedinUrl: '/in/jennifer-morris-94daa88e52', jobTitle: 'Homeopath', }, @@ -5065,7 +5065,7 @@ export const peopleDemo = [ city: 'Robinhaven', email: 'amanda.barnett@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDlGembuOtJVS+l8mAOGI+bFKUuVXKjG7sWJNTitIt6uGOeeCcVjXGuz3Mu53Crn5VBwMUW+n3erXipAu126HOMmuptvhjcbA890Cx7Bc1zymvtM6I02/hRhWeuyQnbJhozwGJzj61fi1u337XYqpPBPQGr8vw3kETlJiGxjpXG6zpd3ot4iz/cJwGxw3/16cKieiYp0mldo7CSUio/NqC1KXECeVIGUD15q2lqg+8xNdKOYrkAZPYVkXKrf3cdssvl7mAxWqwDKcjIqrolmZPG1nauMqHD+3rWNXubUbbHqug+FtO06GGZYt02wDLHpW5KAOABj2rm9duRbRMjWlxcnaWG1iFUD0x3rO8LC4e6Vf8ASY4XAcpJIWC56delcltLnenZ2Otl4Q1wXjPT473SJ0ZfmT51OOhFT+LJpxdyLi4khiySsLlc/l161StmS8tZoFtpYGEZDK7FgwI6896Ere8KTv7p5zo0vk3cZYYw23Oa63zsiua0y1gc5ckuGPy571urXfE8yRNiuj8M2MUkq3u0+fbSY3D+6RWAorS0/WG0RLiUxNIkigbc4GaitG8TXDy5Z6nqQWG6tsMAfr0qkJrC1n8lWjjwRkk4yfSo7aRpbdGjbKsoYH2IrNu7/TETy3tpLl1JJZYicHuQf8K4VroeolfYVXtbjU542ZHVzwQe9M1GOC1iZIkAJHasqC+01Lhkht5bd2wR5iEE496brF/9ntXuZBu8sfdzjJ6DmnZ7ClZbnC6hpC2eroIDgAbnHv1qwoqVrwX0j3BGGc/Mvp7UgQ16EFZHkVHeTsXVUCpDGJl2EZB9qWG1mnmWKGNpJGOFVRkmu7tPBl3H4Yu0OxdRfEkZU8rj+HPvz+dKpNQQ6cOZlTRJJLfRYI5SwCZTJHIAPH6Vo3FvbXcGJJtq44I6/hT7C0jisEiG4rtw27qT3zVG70kOjCKZkYcgZrzua7uepH3VYpXFvb2IJSbcT3PWuX8Qu9zHDbkgRsd7Z/ix0rZisH84+ezOQeM1W1GwjvXMcgI44I4Iqoys7k1FzKxytvaG2ZhkkE8A9quAcV3Nh4QtrnR7aK58xbmOPBlB+YjPGfXjFZeo+Dr6yRpYGFxEBk4GGA+lddOvB6Hn1KUAAAAAASTP/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-7.png', linkedinUrl: '/in/amanda-barnett-6714ab7883', jobTitle: 'Clothing/textile technologist', }, @@ -5075,7 +5075,7 @@ export const peopleDemo = [ city: 'Larsonstad', email: 'tanner.miller@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-8.png', linkedinUrl: '/in/tanner-miller-dcf9fa91b8', jobTitle: 'Trading standards officer', }, @@ -5085,7 +5085,7 @@ export const peopleDemo = [ city: 'Mikaylamouth', email: 'bobby.sanchez@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-9.png', linkedinUrl: '/in/bobby-sanchez-b2c15c3790', jobTitle: 'Scientist, marine', }, @@ -5095,7 +5095,7 @@ export const peopleDemo = [ city: 'West Alejandroborough', email: 'brian.cortez@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDomjIGKpXEohRnY4CjJq5LKWyAK4nxfqMyuthDkF03MQahspIguPGbxzMiCMHqDXOXfia5+1iTLls/MetdToXga3udNiub+TdPKCSF/hFdJD8OtF8nIySRjBPSsHVjex1LDztc8/g8YTxTLKzsduCM9Peut0vxLFeeXhh84/Grtx8OtJaL5FKtjGc1y3iDwx/Ylut7pYJ8r/WJnk+4oVWLdkEqEkrs7aS4BGBTYpBux3rD8MXzanpCyzN+9UlWH0rWVCXyoyK3Rym15GRgV5r4tlEXihlJ+6iIR69/616sseFzXnXjPTzceJoJEBORGH+Xjk4HP51M3Zal0029Dq9MINsg52gD8K3olQou1tx9M1wGsXGoWkvl2jzKgHAhTczYpPDd/rk9/HDdySFJCG/eLggdgcdK4eTS56inrynfzqoj5bBPauU8QSBbSYEHaVwc1k+KNT1mDUHgs3l2R8nyhkn1xTLSe8vrR4Ll5HzGciVNrAkfrTUeopS3iYHgtpmvryM7gqAlfQ8131mx2kEc1zHgrSWtxcTyZ+YAKD3967JIVXkV3JpnlyTTszSW9UDaetYut27XDI4GApEjEdTt5ArVtYBt3MOT1qWe1E0ZQEjIxkVNSPMrF0Z8krvYo2rQ3MRSRVI9xmnRmzg1GONDGioRk5Aye9ZMDtC5VuCg5HuKoXd1bajgGNgU+66wsSvqcgVwxTbseqmrJrc35PssupzLJ5bK7YByDiq2orDbxskSgEjArnbW5ttOmkCkt5mNzSKVJP4itVm8+5UMSRkflTcXdIiUlZ3JrO2+y2gjQ/dXANXLLeYzvJNPhRXjIQ9KgRpLefLcp3Fd0I8qPMqT55Nm2rqq81JDMu7BNUEjuLltkKFm7+gpuseG7y90kwpdSROJFkk8g4ZkHVQff+lKcuVXCEeZ2MfXT5Wo3BH+rc5JHbjmo8Ce3AjvRA+PlIXPFWBZRraiJAdu3jJ5rnbixuLbeY3YbTwR2/CuFTUnc9TklBJGtPtt7dvMu0nfHLEfzqtpl7EX8+aQLCAQHbgZrLtrS4uJAZ2LJ6HofrWrcxrDaAAAfMBT5+V3QKm6vuvqbEd7CY90Do6k9VbIqIXO4yF+3StLQ/DUEWnxwGHynuWM8ipxg4wD+WPzpl/4PvlLPaXKOD/C4wfzrthNNanmmlqf/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-10.png', linkedinUrl: '/in/brian-cortez-77d96367ee', jobTitle: 'Metallurgist', }, @@ -5105,7 +5105,7 @@ export const peopleDemo = [ city: 'Russellville', email: 'misty.jenkins@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDozOAKhe5HrWA+tDsKgOrO7cCpGb8lyoUlmAHvXLav4mPmtaaeu6QHDP8A0FRXmpzSXMMERy8h2ooGSTW8nw3intFmmn23BGSV/vVg6nY6I0urOLjuruR/30jRnPOf/r1NdzGMDI5HVhV3WNJvtHt2SbMyKeHx2rlpL9wchuPT0qFqW9DrtD8X3ujTqzyPdWJ+/ExyV91Pr7V6rZahbahaRXdrKJIZBlWFfPAutpEifdPUV2fgXW3tp57Df+6l/eRj0PfH1H8q1hJrRmM431Qxox6UKNuTVh0qMJ61qZCeCrUap4mmvX+YWw2oPQnjP869ZQgJt3D6ZryDw28mkWurMtpLcu0yxqqEjHU5J7V2Xhi4vruQJOkqK0ZcLI27b7Zrkadzug1Y6O8tYrmNo3VXDDBB5rx3xn4Rm0mZrq1RjanqByU/+tXV6xd6na3u+OG6uEz91HIXHtir8V1JqQNvPaSRkfKysdyn3BoV1qOST0PEBIwyvQ+laeh3/wBnv4HJxskB/Dv+ma0fGvh46RerNAv7iU8AD7p9K5+Cyu/JN4IWECEbm9OcdK1umrnPZp2PTnFMUYq08eRUXln0rYwN7wpDCkF8sihhNMGOfTaB/jW6tzY2RnUOkZCYHYc965jR2ZJXjBxuGRVm+vdCjmEN2d82MEDqfUGuWaak0d9K0oI6C2ktrxSrFCVA6EMCKbdTw2ifIgAHTFZVlqekSxCLTnRGzwoGDn6UXaSS8N0rNvoapIxdWjXVfkkC+WrbjkZFYeuWi2Phsq0Sq8jiOLaMFg2D/StnVdRj0a2e7aHzUiGSu7Ga46DXbjxR4lszLEI7eNsrCpzj3J7niqhFsznNRT7ndmDI6UzyOelbC2tI1uBXYecZ9shilVxwRWgtoJxuWVIz3yOtR7AnNPks5Yo0kclBITsXufesqsftHRQqOLsTLbparukdHb1Aqlc3o2lV+Yn0qtOk5PJZlNWILPAVmHXoK5WdlzkfHJaLw4d3WSVQf51zngQKviO23Yw+VH1xXc+NNMe/0KRI1JePDqPXH/1s1w9tZT6HqNnI2QeHU/jW1OSUTnqRbkf/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-11.png', linkedinUrl: '/in/misty-jenkins-7bb3609670', jobTitle: 'Teacher, primary school', }, @@ -5115,7 +5115,7 @@ export const peopleDemo = [ city: 'Lucasland', email: 'erin.hernandez@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDQ+IPjIaRbtpVjJi/lT5nBx5Knvn1xXjEl295K3zMw7uzHn15pmo6pNqd/cXl1I0ssrbpHz94+g9BUUdyFA34Cj7sa/wBaz3NNiC7Rd4SIZPsOv0prRPbhZVJHsetWDNGsxduZD29BWnp2hX+rTrstmwx4c9AKHJRWoKLk9A0LxHcaNfR3tmAssZ5Qk4Yehr3Twp4vtPFNl5ka+TcpxLATkr7g9xXhuveFrnQHIAMqSc7gOldD8MPEtlpOqmxu8It2wVZT1R+gBPoaIyT1Q5RcXaR7nS0lFUQfJzPHGmANx6kmn2FvNql2lvbRne5wOasanoc2n5wzSKDtZ9hABxkgV3Pwu0JJVn1B16HZHn9aynUShzI3hSk6nLIuaH8MoEkS4v5zIwGSo4ArvLXTLS2QLbuoA7KQao6q88Z8oW00kZwDtOF/GuS061mutT32tlc2m4kcsRwDgkjNcbbkryO9RUNIncahpkV7AVkRWX3rxPxXpYtfF62lqmDKIyFUdSTjj8q9F8Uy6laPa2MfnMsu3cyMR1OOT2FS+DvDsN34hfWbi0ZBawpHCkp3fvDklhn0GMfWtcOmpXMMS1yno0QKQxqeoUDn6U7NNzRmuw4DhNW8PQXN6lpn/RYcu0Sn72fX8M/lTPDWmvoNu8CkGIylkHoPSl8e22q2uoaVrOlM6+UTBcbRnKMR1HfvV603bAkjl3HVj1NcFaLi7dGenRqKorvdG4l0lxHsKdaZFFa2UyqqKZZfQAYFVYQQc1De3OmNG0V7MBJ/dUncB+HNZRZtZFzVoba78gvsOOCOCRVvSVVbZwq4UNge+K4u1m01JzHaTSf7COD8vsM13djH5VjCvfaCfqea6KEffuc2L92CiTmkpaSuw88wvGOkapfaLG+mzyRvFOhmRTjdESNx+o6/nVK6t3iVXi+8BXobIYiWA47+9c1q9iYkaWBcxdSB/D/9auTEQd+ZHZhqi+FnNRaop+QsA3TmrPltLCQsyD/aYc5rK1G3gmQFBsk9aoxrKAQJ32r3zXItzuNm102aW8jhkmEmWB3eg712mMDA6CuR8NxTiza5nP8ArX/d56heg/xrpLO986V7eaNop4+qk5DDswPcV3YdWR5+Kk5SLB60VIy0XQcp/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-12.png', linkedinUrl: '/in/erin-hernandez-701db083a7', jobTitle: 'Textile designer', }, @@ -5125,7 +5125,7 @@ export const peopleDemo = [ city: 'Shahville', email: 'victoria.larsen@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDni9J5hqt9oX1o89evWsrGtx91fLaxEhS8mOFHeuUmhvJ3a9u9xyeFzj8hWjI0t9qcdnAC08hx8vJ/+tXb2vw78yBPtVzk9SAKxdQ6I0rnmFxHHIcxIST0z2/zzUdtOyPhgoAr2xfBemQxYS33MB941xms+F7bT52dlxGfbpS9otivYtanIPI27ejfMDn5TyDXpXhXX4dW00pKcXUGFkHqOxrzK8RkuD5YLDoMdRV3w1cvba1G6khZVKOP1/mKuJjJGoRSjGCDSsKQCtDMv+AbMXHie8uj8xhTC8dCT/gK9cTKrjFeReGWudOl1A2sLSSSeWVcPtCZJ5PtXb+GNU1S/EkV9EVZVJWQ8ZxXJOLvc7qclax0x37TgcVia3ZQXlo8Uw+90I6g1g6xea6txI8LyGKMbtoONwzjAx1NWrC8vtQjWOeykiYAc7twpcrtcvmV7HleqQCx1KSByQVPGehqtp8hg1aAZ6yDn8a6vx9pOLiG4Xhn+Un3FYlroUqDTrmUuHkmUbSvBXJ5B/D9a2i1ZHNKLuzWIpAKkIpu2tjnOq8EeSZL2OVQSwXr6c12EccUInMSBVC444rzvw9cG21ZBnAkBQ/0rqbqbTJmKXF8YsffAcgn2OK5aqamd+HacDcgitroEOql1PIYdKS7kgs4z5YAA9OlUrObTViCWd0jsT18zcx+ueagv0klJUn5R1rJt7G6SMa9iXVmKyR71DZVfU1m3JhTXLHS0YP9mDTy/wCxxhV/Mk1J4hu5dN0m4ubWZopIl+Vl9Tx/Wuf8LxvJbTajM5e4uH5djknH/wBetqUbu5zVqllZdS0I8io2Qg1spYvKp8qNnIGcAZqjJEwPIrqOJFeEtFKsinDKQQfeu0sETUYFmW4ERxzxk59K5ARn0rZ0uymSCS6lZ0gUDABwWJOKxqpWub0KjjKyOljtEsxuYxO39/bzVS4uzKdiHLsarTWtxJwlw2PRj1rQsbOGIB+p7muVnbe5y/jGyb/hGbiMHBwGY+wIJqhodq9voVoWiKK6kgnndz1/Gu9ubCG/jZJwGhcYKf3x6fSpP7Bt7yARTRfucYQLxt7Aj0xXTRT5Tjr2ctD/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-13.png', linkedinUrl: '/in/victoria-larsen-8bc60c5ec2', jobTitle: 'General practice doctor', }, @@ -5135,7 +5135,7 @@ export const peopleDemo = [ city: 'Port Tonyaview', email: 'brian.diaz@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-14.png', linkedinUrl: '/in/brian-diaz-97d66d36ca', jobTitle: 'Television floor manager', }, @@ -5145,7 +5145,7 @@ export const peopleDemo = [ city: 'Rebeccaton', email: 'krista.murphy@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-15.png', linkedinUrl: '/in/krista-murphy-51da3fe5d2', jobTitle: 'Social researcher', }, @@ -5155,7 +5155,7 @@ export const peopleDemo = [ city: 'Grimeston', email: 'calvin.bond@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0YikxTyKTFIZBdXMFlbSXFzKkUMY3O7nAArgdW+LOm2pZbC1e5x0kkOxT+HX+VZPiCXUfHGvPZwymDSrVyODwxBxuPqT29BQnwwR14vnwexQVnKrGLszWNGcldILb4xTPIPO0yIJnB2swP513Wh+MtJ1zEcUwhuSOYZSAfwPQ1xP/AAq2AKM3r+4CjmqOreAhZ2fm2Lnzo/m5PXFJV43KeHmlc9kxRiuQ8B+JX1iyNleuDfW6856svTNdlitTAMVQ1uWS20K+mh/1iQMV9jitGq2pRrLpd1G7hQ8TLk9sjFAHCeFoUTTI8dXJY/WusjBCCvP7iGZNGs4188qYwSkHDM3Xr6Vd8LvfpcQwyGcRSjcPNOSvsfSuCUd5Hpwla0TtuecEVk6gdqHPOAa5jxHLqn2x1he78pDkiBsE+wHerul/aAfIl+0FQPmWfk59j3FLl0uU5a2M3w3btbePLZ4kKxyblJz1G08V6viuA8LW4h8SyPMQEj3qjE8ZOAB9etehEV3Qd0eZUVmNqlq9qt5pU0LZxgNx7EH+lXaGUOhUjIIwapq6aFGXLJM5GxEU0Kh1AI7Y4qWOW0g1JYzJEhUE4OBn8KguYZbO9eJz8xO4YPUVm3V/pbcXSl25G5YixU/UdK8+zvY9VNNXRtWdxY3k7ok0Uh3EAqQeQehqW7WKEHH38flWLYanpbLstv3ZLDh4yhz+I5rSvXzCcD5iOaGraDuUIrP7TItuoB81w24H5kYMMGu9NYOh6bIojuptoXG9ADycjqa3q66MHFNs4MTNSaS6DaWq95fWmnW7XF5cxW8K9XkYAVxup/FPR7XctjFNesOjAbEz9TyfyrdK5zGl4rube3ubb58XDIzbQP4ARz+ZrNgiFxAHjnCL2Irg4PEV5r/jOO7uCA0yNEkQ6KuMhR+IrZuEvEXdazGMZwyHpXHXjaZ34efuHUmPyoT5syye5qhcXvm5VXyMZbHpWXp8F9cM4vZTsH8Knr+NXtixQSbVAUKT+QrF7m976noGm3dvfaZbXVq+63ljVoz7Yq1Xgfhnxrqvh6zS2gaOa2zu8qUZA9cHqK7fSvi3plyCuo2c1q4OCY/3i/2s8k//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-16.png', linkedinUrl: '/in/calvin-bond-59b4aeacff', jobTitle: 'Early years teacher', }, @@ -5165,7 +5165,7 @@ export const peopleDemo = [ city: 'South Tyler', email: 'terry.perez@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwANMZlVSzHCgZJPanZrlPF+psoXS4C3myAM+3jC/wCRUFDb/wAaxoXTT4fMOMLI/AJ+lYreJL90lWW7dWlXDBRtx/hWv4b8BTatCJ7m4eCFuUVeSR6+1dYvwvstwD3czrjGDisZVYp2OiNCbVzzi38Q6nYsrR3RcNxsk+Za7DQ/EMeqgQyALcgEnH3Tj0q9dfCqw2HyrmZcDjpxXF6roF54WvEmjlZ4A3DgcqfenGrFuyFKjOKuz0GnCsvQdS/tXTFnIIdWKtnua1R1rUwGVw3icN/wk0WELZRB+Ga7ojiue1exZvEenSyRN5Mm1N+DjIbpUzdkVBXZ6FosYjsYVIAYKM1t44BHNcRqnyjLC7kQqSsdvkHjr+NTeHpZ4HUAXCRPj5ZXLEZrh5dLnqc2tjrJDhTniuI8Yxxvpk+Rn5etTeJJ7idpk8y5McX3lg+8cViQx+ZHJGftQiMZLxzndjI601HqKUr+6Z3ggf8AEvuvlwPO49OnNdSBzXPeEbd7bSW3gjfKWAPp2NdCDXetjy3uNzxVh7dJrO3kDAFJVkPHccf1qrU0F15VvNCybhIODn7prOrFyjoa0JqMtep1FrBFLEMgZ96rXc9jaXUSSyRRDcACeMn2pLaYiLIP8OR71l3E8lyxSS0ncDuEAH5nrXHHU9FalyO4sbnWZ0jmikDdQOcGodXt4LeB2jUBiDyKzQ4trgeTaSxE+qZB/LpVnU5DJD8x7Dj60Na2B6LUzYbZLS3jjU5+UEk1MtI5LuT0FKBXdBWikzzKslKbaDGaNvc8D1NOArJ8Rxy3WkywW3MoKvwcdD0qzNG1Ff8A2TYJNxiblHHT6VrPcWs9vteXCsOqnFUoNMSXSIrdhuKIBkewrNk8PXaEfZJuD2Y9K85NXPU1RrTT2lrAQswIA6sc1gxXyXs6KsgZBk5/vN6CoLjRb4ylLiQNuPTdnNUfEmny2emW7WuQ8EgkOOPY/wA6uDSkiKnM4s6HHNLWdZapG8SrcErIowWxwa0AysoZWBEruPOP/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-17.png', linkedinUrl: '/in/terry-perez-68f6738ace', jobTitle: 'Teaching laboratory technician', }, @@ -5175,7 +5175,7 @@ export const peopleDemo = [ city: 'Holmeschester', email: 'stephen.wilson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDtsUuKKyPFOo/2V4Zv7oNhxEUj5/iPAqRlPxF430fw4DHPL593tytvDyfxPQfjXD6l8VdSnjD6fbQ2qd/MHmNn69P0rk9E8O6hrkjvCqIu47pX5yfQV08fwuvJCiy3qbe+FNS6kVo2aRpTaukaWm/FdhFEdSsVdSPmkgbB/wC+Tx+tdvovibS/EEQexlOT/A4ww/CvNrz4WyIreReHbjoR3rmXg1Pwdq0ExYjy3BSRDwcHkGlGpGWiYSpSjq0fQ2KMVBYXSX9hb3cZ+SaMOPxFWaszCuH+KjSL4XgCZ2m6XeB3GDj9a7kVyXxKRH8IupP7zzkZB64PP6E0AjH8IokWk26xgLxmu0QnyxhgT7V5ddxPbCGLzrtY0jARLUck45JrQ8O3d+t1HAJLoxM2R5/JHtkfyricftXPRjLaNjvZdwQ/MBn1rz3xtHFLYuJAGGRz6U7xJcXct5JC8l2Ei6/ZzyaxpIXnsbqJZbtl8liUuR8wOMginGNrSuKcm7xsehfDeWSXwVab/uo7on+6GOK6zFc94CiWLwVpyKwY7CW9iWJ/rXRGuw88QVg+MbFb3RwpJG1+Me4rfFRXlqLy0kgLbdw4OM4NKSuioO0kzj9NW2urdVlUZ9TUi3en2+oRx74o8NgbuC30rMaGSwvZbZmy0bMPTPpVKSYXT7Wt5ZMdMJx/9euNR1seipaaGxJc2M2sTBnjdXbB2nJU+p9qh1iC2hhKRL94Y4rGVktp/kt5ImY4yy8H/CtKCzl1TUorZXALcknkDAyaOV3sgcrLU7HwvbLa+H7dF+62XA9MmtY1HbQC2tYoAciNAucegp5rtirKx50neTYAVIK4LX/ijpOmLLBpym+ulGAw4iB+vU/h+dcFffEvxLqMLR/aYrZGGCLePaSPqcn8qqxFzp/EOtQahrd3PY5aGF/IdlP3mUcsPbnH4U2CWK5tx/pBQEdVOCK5jwfLHKtzavySd4HqOhrXm0fDkwzNEx6Y6GuOek2md9P4E0Xp5ILWJiJyxHdjzXQeA3huJ7yQupnRFCqT820k5OPTIAriBpjmceZMZccsT0rN1LVrvRdagudOuGguEiKll7qT0IP0qqVnMis3yO578aaa8Xsfi1rlsdl3DbXi+pXY35jj9K7qP4gaePDMWtXlvNAkhKJGvz7nGflB/DviugA6rHHc/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-18.png', linkedinUrl: '/in/stephen-wilson-009cf79121', jobTitle: 'Development worker, international aid', }, @@ -5185,7 +5185,7 @@ export const peopleDemo = [ city: 'South Kelly', email: 'lisa.johnson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDiaWjHNI7LGjO5AVRkk9hUlis6opZmCqOpJqjJrVpHwGaQ/wCyKy/9L8QXwhtkdkz8iD09TXUWvw61KVBvuIovYDNZyqRjuzSFKUtkUP7WsxGrtLt3dARyKtB1dQyMGU9CDUl58Pb23hLrcrI69UK8GuWhmuNGvzBOpVc/Mh7e4pxqKWwTpyjudLmjNIpDKGByCMg0uOasgXHNZevORZrCp5lbn6Dn/CtauY1iZptaWEE4UBAPr1pMEeheB9KttN05biZ1WSXDMzHGB2Fd/aS29ymbeWOUDrsYHFcSXt9L0+HzbA3crr8qFdwVQO2eP61s+H5hCRKtmLYSgEgD17cfyrzZq95M9WHupRRt3ZiiT986Ju6byBmvNfHWlwz2xuodvmR87hzkV03iS5hn82WW0a5WL5QijJNYN19nvtJuvIsRaTQoRLGo+VlI49qqmrWkKp7ycTj9BuzNA1u5+aLp9K2Mc1y+gS41Uqe6kV1eK9A8scF5rJutEmudZju4o2MSlS+0Z5zWwOK09Hu4YLhluZBHC45cnABHr7VFRtRbRpSSckpHa6WY5rSIlVJwMZ7Uao6W01ur79rMAfLXJFZ+gTq1upikV0ydrKcgjPY0+/1lYLgoyM7A9NpxXm2fNY9eNmiTTjFc31yU3FM/LvUjP/1qj1yOGKwmwqqSpBwOtQ2urLcXwjVSkjH04/OofEE8ccDyXEgSFMeYx7DvVWfNYmVkmeaweHrjStUhlnwBKhkVe4H+TW1ip7y/tNTmFxaMXhQGNHIIyM84z2qDnNejC7jdnk1FFSajsHekljMtvLGOroVH5U7HNSIKsgm8BX8sOlNa3IKNBMUAPGO+P1ruxBFeAFgpLDg965XQ4IJ57m3IGXVWfHr0B/Stmw07UFBSG7UBTjDrnFebWsqjPUoSfs0XJLaGyy4ADDvXFeNrlrnQ7lYySuRuI7nI4rrLzSr11YXd2GH92MEZrF8QQxWtjHGqfIpBbAzx60qbXMmOrdxZyOgljpMYZduCQK0D1qeW3a3cxlNu3tXyz//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-19.png', linkedinUrl: '/in/lisa-johnson-d9406b185e', jobTitle: 'Archaeologist', }, @@ -5195,7 +5195,7 @@ export const peopleDemo = [ city: 'Jenniferview', email: 'tim.torres@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1ailrhfiJ4yuPDUdtZ2SIbm6Rjub+ADjOP89KTdhpXYutfFLQ9JuZrSIS3VzHuXCDCbh2JP8ASvNNT+KniS/nLwXoso8/LDbxjP4kgmm+GvBEuuhrq8nKQsxIIXLOc8n2FdoPhdorxgHzgcYyGxmsJVlex0xw0mrnI2HxU8SQXqSTXi3iKf3kLxKFI9iBnPvXqvhz4gaL4jkjt43a2vHHEE38R9FPQ/zrjG+FenRqfJkmU57nINcBrWj3vh6/6SKEkBjkGflIPBBojVTdkKdBxV2fTlJWL4R15fEnhm01EEeay7Jh6SLwf8fxrbroOYWvIPilAJPFtpvIKm0UAEf7Zr2CvMPiXYtc+KNDkGGjI8twDyDuyM+3X8qip8JpTV5Gzo0CW9jFCgACKBW8hO0ADNcVqTTRHaPtRjxkC2XJqfw7LerKsbtceQ3P785YZ7H3rz7dT1k+h1czYXniuZ8QxRz6dPG6K4ZDkEVU8RXOoG6ZYXuTFHyfs/3j9B3qtZyyzkxu1xt25ZbhcGnbqTJ9Cf4Q6kjxappajAidZkH1+U/yFem15V8KdPNp4h1yViFDDy41PVsNyR+n516rXoQeh5M1Zi1yPi6yR7u3udpMilDnHZW/+vXXVn6xYNfWTLGyrIoOCR146VNWLlGyLoTUJ3exk2Yikh2uFP1qtd31lbXkMTSRxAtgZ43H2qrbykxNg/MFyBVOZ2uMJPaTsF/2VA/U1wJXdj2FrsaNpe2dxf3EaypIu7HHOD71LqCQxRERqoGO1YCE28xEFtPGW45QMP06VeupHlhAPLEcgetNrWxLdlqW/BlgqXj3AByquxJ77yDXa1Q0jTzp1nscqZWwWK/TAFX67qcXGOp5NeanO62CiiitDE8+1UHTdSmtuqBtye6nnFWPOtbiDZLIRuH8Jwau6/aR32ozRcEhF5HY4rkpdN1G1b92rOvYqa8+aXOz1ablyI2pri2tYjHDIWZRjk81Ho8i3us2sBOUEm5x64GQP0rGj06/uizSKyBjj5j1re0mGPSLy2d87Vb5yOeoxRFpSQT5pRZ39JTY5UmjWSNw6MMhgcg0tegeWf/Z', + 'https://twentyhq.github.io/placeholder-images/people/image-20.png', linkedinUrl: '/in/tim-torres-9031065f9f', jobTitle: 'Accounting technician', }, @@ -5205,7 +5205,7 @@ export const peopleDemo = [ city: 'West Jamie', email: 'claudia.sosa@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-21.png', linkedinUrl: '/in/claudia-sosa-8b95753698', jobTitle: 'Retail buyer', }, @@ -5215,7 +5215,7 @@ export const peopleDemo = [ city: 'New Sandra', email: 'steven.higgins@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDjieeKrzarBakg/Njjj19KS+mNtbNIOvQVzZBknBRyxY8LjNc5ukbpvJ5yXLIqEZUkcZ9CaSO5uVhlnUB4BjhTk++K3dM8HX2oW8aSLtQ8kdAK1z8KZEx5V5JHnrt6VlzpnQqckjkrO+jmAVXCMDyrcce1XmZSeM4962NR+GLWypcW1wWkUYYEdfeuYjW4sL97G8BWUAEE/wAXuKqM03ZETptK7L5UEZoQANSAnuaO9amJn6thrPLYwGBqPwrBbNq0W5AxQgqDzzmtNtLXVYZLdpJEJICmNNxz155HHFP8H6M9t4glhuCN8MeQR0OehFZSkrNG0IO6dtD1O0YMFA4I7CttWzEPm/CuE1C61K2Hk2yN8w++B/WsrSb7xEl2Gc3LRucASjGBnGSO1YJW1Ot66HpE4JiNeUeOI0j1GxmCAyByv4VveJ9S163mFraxyEBVZnQZ6+lcxqsFzdQ2ctyHzHIwJbqTiqgveTIqv3WispBHNGcnik27acgOeK6TiL+j3gtNRAdgqSjYWPY9j+dbv9nCyvopocgiHa+ed3Oc5/OuSODWzoclwJJnlmd0+VYwzZCjHQfj/OsasftHRQqacjO5tr6OWMRyRgnGM1NIbeDbGqpvcEk4AwKxbRcsCD1PFJq91o8tq1vqDx4Xlt2ePyrBdjs0Nm8WKS5i3FGV4x6HkVyXimSMrDFGMBGP8qNKn05bpktr9bo42r8xO3vgZqhqay3V+URSxHFaQXvmNdpUzFY4NOQk1uweGWcAzz7T6KKux+GLVTkyuce9dF0cJzEVvI74Ck1r6dFKmo3VhJE6mKONmY9CWGRj6V6rp3hfT9ORGSEPKOrsMmszWtLRLg3UaASAAOPVR0P4ZoqxfKy6Mlzo4+O6NsfLdyrKeCa1TG11APJuUj44YjNZmpWvmknof51kB7mI7FYgexrjR3ptGtcQS2atJPcxyY4UhQOal0+3VrdbhnxvPJxzmsw2011bBJHJZ3RRn/eFdTpFpexXHkX0MJh8wiORG4dTkgFexHFdFGPMmcmKm7oYbiBAAVBIpouIHOSvP1rSvdBUZlhy3+yTWQIAr7GBU+lW01uYAAAABgmmf//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-22.png', linkedinUrl: '/in/steven-higgins-004f3810c4', jobTitle: 'Environmental health practitioner', }, @@ -5225,7 +5225,7 @@ export const peopleDemo = [ city: 'New Amanda', email: 'james.benson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0uikrlPiF4kn8NeGXns+LudxFE2M7CerfgOnvUjKHif4oaToslxZ2sct5fRZXCjEat6Fu+PavItV8T6zrW6S8vHkBbd5Snai/gKwZGeaUlmd3c7mJPJPerUab9qbW+g6mhjSIGckkuAD65pgnYPv3sCOhB5rft/CV9eFSIXBfoD0FGseE7nSAry/PGOu3tUe0he1y3Sna9jb8KfEa98PEQ3AN5ZMRlC/zJ7r/AIV7lp2oW2qafBfWjh4J0Do3t/jXyoZFY/LF9K9Q+D3iJ0u7jQpmPlSgzQA/wsPvD8Rz+FWZnsleffF6eKDwnHuUtLJOEj9BwST+Q/Wu/wA1x3xQsFvvAt42zdJblZU9iCAf0JoA8y8EeFodUilubgkjdsXH616HYeCNMs3EiQKXznJOa4nw7bLD4Ys2uDeFJS7qlscMTk85rq/Cr3Mkvlh7sW/JH2r7wrz6rbk3c9OikopWOnNnFAuVVFPTFYmtWsN1ayRSKJNykCsnWrd2vHkuoLu5jXLBYZCvH59afpsYlwLWC7hU9UmJrO2lza+tjyG7tntryWIDDISCD2rpfhbvPj2z2oWwsm7/AGRsPNJ4/wBM+y6vHcIOJl5x/eFW/hRA58awy8qgglP+9wBj9a9KnLmimeVUhyyaPes1DeWkV/YT2k4zFPG0bfQjFTUo6VRmcfoemRadpsWlzqjPajyy3Ykd6trf2NveSoZo02Idq9PqcVHqSvBrUzfwuA36f/WrKnu9PupTv0+S4ZRgssWfwzXlyT52j2qXvQVuxr6ffWF4wVZopQ65VkIYfSrdyYLdCY0UfSsSDUrBWMKWj27ucYMRH6irV0h29T0qXpoV6nJeIdKbXLu2XcEhjkLOx+nQCuk8I6JBZ6i84jVJIYBHhegJ7/ktYusamdHspb1IVl8nojHAOeK7PwtbTxaFFcXmBd3YE8oAwFyBhR7AYH511YdN2fRHFiZxSaW7NunU3NLXacBjeIrOWW1F1bqWlhByo6lf/rVz0ENtexh5ZyreqnFdtcXAtoDIeuQAPUmvKnknuBJdRsVZnYsq9OprhxMYqV0ehhJy5bHUAQ2cQEcu4erdarT3+UI3Ak1ziSXb8sOPds1q6dZySzKNpklPRfSuV7nVcrX6NcS2Fr5YkkuLpNqMu4cZbkenFenjO0ZGDjkVFo2gwWRFzKqyXRGA/ZM9QP8AGrV/NaWZVZ51R2GcHk49eK9KjFxjqeXXmpz90//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-23.png', linkedinUrl: '/in/james-benson-6cc556ac5b', jobTitle: 'Games developer', }, @@ -5235,7 +5235,7 @@ export const peopleDemo = [ city: 'Courtneystad', email: 'tyler.bishop@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-24.png', linkedinUrl: '/in/tyler-bishop-b9b8afc542', jobTitle: 'Surveyor, land/geomatics', }, @@ -5245,7 +5245,7 @@ export const peopleDemo = [ city: 'New Jeremy', email: 'monica.smith@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0igCloqCiK7u7awtJLq7mSGCMZZ3OAK8z1v4m3c8zQ6HFDFCDj7RMQWb3C9B+OaxfinrNxqfiiPRogTb2gH7sE4eQjJJHsCB+dZlh4E1W+jTckdujcknORWVSdtLm1Om5a2Kmp+JNWurgyzanNLJ2McpUD2wOKhTX9XbMbX92hHzK4mYYP512sHwusoFSSa6kkcYLAcZrI8ReG0tTJNbhguOhPSsvarY29hK1y14Y+J2oWFzHba1ILyzJwZj/AK2P3/2h+teyQTRXNvHPBIskUihkdTkMD3FfKco8uQq2c17H8HNXkuNMvtLlcstsyyRZPRWzkD2yM/jW8Wc0kemUUUoqyDyldO8/4m6/dXCAPE6LHn0KDB/ECuzhXagAOa5n4gWRh1g3kcEjtPFGpMZIKldwzwRzjAql4RuL+4V4ZjOEKF0M3UY7GuKtH3mz0sPJciR2c+dn3h+dc7rgElu8RH3hjNclrX9om8ed/tkkanIWIk98cDNXNOe7uMxPBMu3jJJIrJw0ubc2vKecaqjQX0kbKVwTXpHwRy2o6q3zYECA+md1cv4x0xvtMLRIS7g5x7V3nwosk0m5urU+a0tzbpMzNwo2k8Af8C6+1dlOaaRwVKUrytsj1ClFJRWxzGJriRy3Uccygo0ff61lRfY7dblY2jj2pt6gcmtbxJEzW0My9Ufafof/ANVcLqt1ozsIbi4dJSMER5JPqK4qyfOz1MM06SN+zjtb0NFME3qAccHim3r29jEVhQDisfR9R0aOMw2Mh3k9GBDZp9+WdyzHgVhLTQ6VYyLuEXcgZ03sCdozjmux8BaY9pHcTvyoHlxsfzIHt0rhtVupbO2M8EmxwQo4znPFeuaJB9n0a1Q43lAzkd2PU10YeN3fsceJqJR5V1L9FJSZrsPOIr22F5ZywE43rgH0PY1wbafPuaPzEhnjO1gy5r0IVxXieeO9vWFtw1v+7aVT95upX8Mj86wrxVuY6sJUcZcvczltmtIy81wkjHuBWbd3okBVDkk1RuftrNh8lfWnWsDMQW/AVxPuei5XKmo20V0LK2uZjDFNcqrSYzt617Vax+RaRRZzsQDPrxXlUmm/2hPZWq/fa4RgfYfeP5Zrv7fxDp0F6NMuLmOK4CBkDnAZSSBz68dK68O/dB9/Q//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-25.png', linkedinUrl: '/in/monica-smith-df2db66e3e', jobTitle: 'Exercise physiologist', }, @@ -5255,7 +5255,7 @@ export const peopleDemo = [ city: 'South Brian', email: 'jillian.carter@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-26.png', linkedinUrl: '/in/jillian-carter-9a44a80690', jobTitle: 'Forest/woodland manager', }, @@ -5265,7 +5265,7 @@ export const peopleDemo = [ city: 'New Juan', email: 'roberta.graves@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-27.png', linkedinUrl: '/in/roberta-graves-5584549fbc', jobTitle: 'Camera operator', }, @@ -5275,7 +5275,7 @@ export const peopleDemo = [ city: 'Tylerfort', email: 'clarence.flores@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-28.png', linkedinUrl: '/in/clarence-flores-bc6d7c12e4', jobTitle: 'Publishing copy', }, @@ -5285,7 +5285,7 @@ export const peopleDemo = [ city: 'West Marc', email: 'robert.gonzalez@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDp8YFc/wCIvFll4fj2MPPuyMrCpxj3J7CtHW706dol5dg4aOIlf97oP1rwvbc6jdCMbpZpm+Z25JJ96mUrFRjc6R/HmuXTbmkVE/uxjb/+usGfUmed5Msu7nnrn613ukeBbMRqb2R5HxyBwK6UeDNFeAR/Y0x/ePWuR11c7I4eVjzWz8bapbTwRx3RaNRgI4yv0r07Rdfs9biPkNtmRQZIz2+nqKo3fw80d0zHDsYd1OK4poL/AMEa7G8QZreZ9u8nOVzyDWlOsm7GdSg0rnq9KBmkHIBHcU4V0nIcn8R5WTwuApI33CA8/U1w3hhA+oxHaNw6GvQPHti994ZKRFfNSZHRCQN55GBnvzXD+EFaG5uHlglZ41AxjBUn61hWejOmgtUel2hB5JwPWtiIqUADDNedapNLIgPl3LJgkJHxjH9abos15aTR5M6xyFSBI2Tz0H1rj5NLnep62PSyfl+Y4rivGqodId2AOxw2fTmq3iu8vEuDChuVVVBYRH5ufoaorFcXelXdpI02WhP+v7HqDTjG1mTOV04na6Rcm70ezuDjMkSk49cVdFUNEtmtNCsYH+9HCoP5VfFekjynuUdZt1uLFWZdxhcSAeuP/wBdcnZ27w3sssmN8yKzADABBPH5YrvCgdSrDIIwRXOalYy2tykoKtGRtHY/Q1y4iDvzI7MNUVuRlq2hWeIDCr65qK7W3t5wkkkfyYbLEAA9B+NRQTlM4zwM4rPur7Tr3K3IU7W7oWINciVzt0OgnNnNfRkTRszKAR1x6U3ULWNLdo+Mt3UAA1g2s+lwu4jdWkK4yQQcZ4wTW3GWuJYQTx1/Cq5XewpNJNs1Il8uFEHRVAp1FFemeMSr0rM15C1ipHUSD+RrViUyOqLyScVjaldySs9qbd4jHLgl++O49qyrSSi0zahFuasYKyncFPykcH6VfWJ5U/cuinGAT2qlf2rY3KKyzc3ELfLvJHHSuBHpXaOj8h4YybiSKVselWtIRpSbg/6sDanue5rnLRLy9cGUssZ69siur0mWOS0aOPrA2xx/dJ5H6Gt6KTnqc+JlLkLxpKU0hgACu488/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-29.png', linkedinUrl: '/in/robert-gonzalez-624dd9bd66', jobTitle: 'Geologist, engineering', }, @@ -5295,7 +5295,7 @@ export const peopleDemo = [ city: 'Boltonview', email: 'melissa.lucas@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDt9UvoNI0+S9nfbGg6d2PYCvJNV1y81iZppppChJ2qGKoo9AB/Ot74l6sRfW1guCsUXmEdsnufwH615qs093LsUszdh2FZTd3Y1grK5uxohwyNhh0UHH6kVbWQQ4nEfKH5uzL78dRS6R4avbvaZJ5Ih7dK6iPwUjgedeO2eMjisro2UGc5/wAJBHp16k9pkRNjzYuqkeor0fw3rMGqqAjgPjcF9qxx4B04Wnl4LsTnOazo5D4V8Q2TtH/o8g8on096qM7OxE6d1c9P80RjB5+lSxSI4yOPWs+3vFeTDL1q+YwVyvFdCZzHjvxKtduurdfwSwDJ/wB04x/KuY8PW/mXQ2rk5yeK7nxiv9sFrHHl/ZSGMrHg7h0+lZHh2yWC1lbb84fb78VzSktbHXCm1a509oSVwo4x2rYtgGTBbB964nUNRmsw0aQzsSM4XgVTsrvV0uY/3k4SUBgrNu2g9j6Go5dLm/Mtj04N8uC22uX8R2wuZrCNhuzdIB7jnNUvEWp6jp6QRQLKzyKGzHjirmgC4unR9QE+bd8q0jZDHBGQfxNNLUibtFnWQkRhdvzBRiriX5I2lcVXSSBVGeKVri3B2lgDXSrnnnL+KdJeYRTgYVmCycZ6dM1lW6+UBtUKB1Ar0GeKO5t2SVNyOPmBriBa+RGdzEtnDZ9Rx/SuecLbHdRqXiovoWovJuVCzRqR7025itoGWKGMF2BOB6VVwyngmqt3eabMphuZMuOGwDn9KhHRodGwtJba1NyEYbdpzg4PaplkiysUSgIOeK5q0k0t4WiWZnLDCMwPFdBpEDCNmlG5ugNNbmdayg7lv93I4BbGKr39qGBeM8461dksw/zdDUU0LmPav41pzaWPNaNhriCI7XlQHHQnmuQ1R/NvJyg6ncAK6H7DLKzMVOTzyBVC907b8xQBh0de1OcW1odNJqL1OUW+ViYy21hwQetWVtxdqFEqrjoSORVTVdMEk4YrtP8AeHSmwafdwBS8gaPsc81jsdafVGxb6a3Ma3Hnu5wB3FdRb2pt4EiHzFRyfeodAsLWKySZADO4Ids5I9vatYw46H86vl6nJWqczsVNhI+YUqQEjpVxVAxmgtRRjY//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-30.png', linkedinUrl: '/in/melissa-lucas-d06ec4efc8', jobTitle: 'Youth worker', }, @@ -5305,7 +5305,7 @@ export const peopleDemo = [ city: 'West Kevinfurt', email: 'lee.lewis@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-31.png', linkedinUrl: '/in/lee-lewis-c341df06f3', jobTitle: 'Graphic designer', }, @@ -5315,7 +5315,7 @@ export const peopleDemo = [ city: 'Ortizchester', email: 'jessica.preston@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-32.png', linkedinUrl: '/in/jessica-preston-011a349bc5', jobTitle: 'Therapist, art', }, @@ -5325,7 +5325,7 @@ export const peopleDemo = [ city: 'North Jason', email: 'henry.west@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwB2KTFPxQBWpA3GBknAHc1j3XivSLMlftBncHBWEbv16VzPijWZ9Wv/AOybFXMcblWx/wAtGH9BUFv4IvJUUyyxx+wyTWNSqo7m1OjKeyOg/wCE/wBN/wCfS6z2GF/xrV07xHpupgCOYRSn/lnKQpP09a5j/hAx5fN05Yf7NYeo+HdQ06N22+bEvJI7VnHERb0ZrLDTirtHq5FAFcB4S8UvDIljqEpMBGI3fkoewz6fyr0ECuhO5ytWE201w2xtv3sHH1qYDimshZGVeCQQKoRwfhSy+We6kG+4kkILHrjPP6129vCduTziuCt5WtNHSNkmeQs/yxHGcEjJP4Vv6A91BdRQyO3kuocZOcZ5x/8AWry66b1PXw0kkkdSkZKHgAVm6hApiIwCfSsXxGLlLhXiWSWPOcByP5VbtZZSoheGSJlA4LblPHY1z8unMdLlrynnGrWQhv2aLCqxJ47V6roFyb3QbKdjljGAx9SOD/KuD8VwBL47ejrux6Guw8Dq3/CLW+4k/O//AKEa9TDy5kePiI8smjfVadtCgt6DNKtKeQR6iug5zl9Pgha1jjePnGTn35/rUi31raakI2ilYBTjy0yB+NVwHtn27iduQfwot9Qn3nybYuecliF/LNeRJNtnuU7WSRtafcQ364lglRs9Jo8Eexq9cxQwRAg4OO3QVlwarMxCT2ciZPUYZf0PFWbv54jk9q55KzsdCsc7caZBqGoCa6UtCi7TjpkngnHaul0S1S00mGBIljCZGF6Hk8/jWPaXNst6LWR8TTD92p6N2P8AOuljGyNUHYYr0MGpXb6HmY1w5UlvcaBTsUKKdxXeecYmuWroguolyq8Pjt71n2qWJw0pJ74z0rqLuMS6fcJ6xn+VeeXMM0jjyTgmuHEQV79z0MLUfLbsdeZLGGIeU/AHPNUpr3zh5cR3E9/SsnT9JuJpNtw+5R1weK3ItPjthhBXnysmehFykVtOsZX1/wC0eWfJih2iTj72c4rpwD3rI0idxdTwMBsI3qe+eh/pW1xivWwzXs0/as//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-33.png', linkedinUrl: '/in/henry-west-168b570375', jobTitle: 'Programme researcher, broadcasting/film/video', }, @@ -5335,7 +5335,7 @@ export const peopleDemo = [ city: 'East Jordan', email: 'kristin.sanchez@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-34.png', linkedinUrl: '/in/kristin-sanchez-16a334fc5e', jobTitle: 'Hydrologist', }, @@ -5345,7 +5345,7 @@ export const peopleDemo = [ city: 'New Raymondport', email: 'derek.davis@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1PjFNJAyemPWk7c15L8X/ABHeRT2+gWU7oksXmXIjOCwJwFJ9OCcUXCxv698V9C0m4a1tA+o3CkhvJIEan/ePX8M1ycvxs1AzDyNFthGD8waViSPrxj8qxNB+Hd5qkKTXEgghYfLkcmuhvfhfaR23+jzN5wAznoaj2iNFSkb+hfF7Q9TkWC/jl06Zjjc53R5/3h0/EV6DFLFNEksTpIjjcrqcgj2NfPV78N9Qhg8xJo2HJ21e+H/ia98La6mjak8gsLhtoVuRG56EegJ601JPYTg1ue8kjjg0lMXcBz0pxP1qiAyelfPXiO4a/wDiFfNID/x9lAD2C/KP5V9Ckcda8O1Sxj/4WbNMButri4MsbqMh+Mtj6HNRJ2RcIts9H08/6LGo4wo/Crczf7YJritXuiYjn7YYznaluvPHcmqOgTTJcgbrkRuRkTOScnoOe9c9tLnZfWx2N8D5RBYDivM/GNuBbi4QfvYmyGFaniK8uJriWIvciKJsMsP3j+VYlyrXFjcRI87qIz8s/UEc9acVZ3Jm7po9z0K/GoaBp15k/vrdHOTzkqM/rWhWP4YQQ+FtKiDKwW1QErzzjn9a1+3tXQcY5gGUg9CMcV5veaWtvqCDZhbE7YyRy27IPP5V6R/DjNY2uWBmt3miC7wAXBHUD+tTUjdXRrRmo3T6mJFDG9vyQv16GqK3Fhb3Q82WJEVwFLDG5vb1xQyyvE4R8Dbms6a9ljtlgOkO644Z2UfjXOtdDtsI81lNrc4ilRg554zg1W1O0iBKKMkgg4xWct1tvxGmnvDuxgqQfzrc0/TpNV1mK2yMD5nJPRR1os72Jk0lqd74ctFsvD1jAp4EQb8+f61p4BpFTYoVQAoGAB2FHI7811JWVjz27u4u44qreZ+yT5AxsOfyqO61KC2UgHzHA+6n+Pas+5vJbqIAYRG6gd/rSnLlWpdOPM9DmpibSfY5Ijbof6VYc2M8BDykKewNWL62W5i2kVyt5YTxE7QSPrXKmduxJffZrcnyW+nNdl4K08JYNqT8y3GVX2UH+przd0YA7uoFeieCvENlfaVFYAiG5tv3RQn7+O4rWkk5XMK0nY6zPNJ9aXHH3OY//9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-35.png', linkedinUrl: '/in/derek-davis-919fba4163', jobTitle: 'Logistics and distribution manager', }, @@ -5355,7 +5355,7 @@ export const peopleDemo = [ city: 'Grantside', email: 'dan.gonzales@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDkjRTsUhO1WY9gTQBWvL+CwQGZiWI+VF6msmXXrh1JVkt/7q4yT+NSaNoN14i1CSSSUqoPzSMMj6Cu3svhjZ5Z7i4eXd0GMYrKVWKdjeFCcldI83fUb2M+YL92Y8gbuvtitK18SrsVLyNt+cF1HGPXFdnefDGxCFo7iVWHIPpXG6v4PurHe8TiREGSehqVWi3uXLDzSvY2ldZFDowZTyCDkGlHWuZ8O3Tx3TWbsNrglVz0IrpwOa2TuczVgxzVbUHKWEzDrjH51bxVa+tnutPnijGXKErk45HND2BbnS+D4Y10yFl4MpLfXmu5jDRxqD+FeZwadK2haaqRzGTygQyMRsOM9O5rW8J3+rSOLaXzyjZw03Ue3PSvPkt5HrQeiidlOrmM9hXKayA0LqpBJBzWX4in1m7uJ1R7kQQgkiE/ex2A7moNPtZEQqY5UOMtvYkH3PvS5dLluTvynn0k3la/G8Y+64Xp2zXcBa5pdIeTxLJKSFhin5JB5OcgV1SrXfBpo8qpFp6kWOamtgjTokg+Rjtb6HimYoHBqmrqxnF2aZ2mhIn9npa3AG+MbGB6cVejW2i1FIk8tFUEtjAzXP6VcNIDIx5z82Kh1G702/KmW4igdSQrliGHqMivOad2j2YyTimjZsRDPcTRybGySRnnPNR6rFDbwssagZHasDS7qw052FrcRzKz8sH5zn0NXtSmMwIJ7ZNJq2g2zGgt9kMs38ErliDzls8EU0VFbyXbm5SZv3KOBEMDgY5/U1IOtd1GNo37nmYipzSsug3FAB7Cp0hLnjoOp9K3tA0yO4u9zAOsS72z39BWjdtDCxnWFteJDJKsbbNuTxzj1q6LeW5t0e1uIEYDA3rlcfSu2+xBbIxqByu9/f0Fed6haSw3s6W5aNlwVAPDAjP881zVo2fMd2GqNLlJnha2UvczW8j/AOwOKrh/tJG05zyTWUVup5dsuOvI9a3rG1WCMDHzGueWh03cnqVtB0hrrxhqNtKjfZpbdZc54DdOPfirF/oc1hJtlDAH7rDkNXXeGLRcXF5gbpMRqf8AZH/166O7sYLi38qeMOh4INdlNPmOx//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-36.png', linkedinUrl: '/in/dan-gonzales-83d3f8867f', jobTitle: 'Location manager', }, @@ -5365,7 +5365,7 @@ export const peopleDemo = [ city: 'South Bradley', email: 'edwin.garcia@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDX20bQOakArN8QXbafoN5co210jO0479qkZy/ivxktov2PSZt1zu/eSqMhB6D3rg9R1i/1K6We8uHkdF2gnjaPYCtTwz4cOuzvcTu6Wytg46ua7mDwFpMZ3GN3BHQtWM68YOzOinhpzV0eTm4feXEjnPfJ5rpPD/ji+0vbHcF7q2zyjNll+hNdlP8AD/SWUlYXX6NXJ674K+xW0k1ozNs52HuKUcRCTsOeFqRVz02wvrbVLKO7tJA8Ugz7j2I7GrQSvL/hjqBi1e4sXziePK5Pdef5E16pjiug5ho6VzXjwyDwpcCPOC6B8f3c8/0rp8Vl+I4PtHhvUY9uSYGIHuBmkBjeEbdYdBtlVcFhu+uTXYRK2wcVwdzZMmn2aBLhiluNoifaAQuT+NaHhe51EOkEssuxl3L5pyQPQ15s43vI9inK1o2OuZWwQB2rndcjLWcyoMsUOMVmeIptTe6lCTXBhjGWSFsbhnoPWjT4pFITZcpxuKytuByM/nSUbLmKlK75bHH+DAyeNbQKpHLhv++TXsYFeeeFNIZfGl1eNxDG8ipx1Yj+gNejYr0oSTWh5E4uLsyHtTLiJZ7aWFvuuhU/iKkA4pccU2rolOzuUbCCGWySOQA7VAOaZG1pDqCxRvFFgEjJAJ9eKqTStZyTKDwmTj171l+cL4B7hHU44AgJx+NeZyu7TPajJNJo34Ws7udkLxSgsQGUg8j19KsXlvDbW52ADjtXKpdf2ZuNujMhIyGhINbF1cme3DE4GMkelS420Hzd9w0G2UTNOP4izY984z+VdBVbTbYW9jEMYZlyfx5q0RXpUo8sbM8itNTldEA6U4U0VXuL+C1Vi75K9QOcVoZFPXLci3NygyV4YDuKzI3jurdWN60LEcMg5xVm+vpbtLfH7uLzfmGevBxn8cVk32mylzJbyGN+vsa4K7jznpYbm9mXJp4beIoLrzWA5LVUjuDNFhCTEgyx/ve1UotInkk3XM28nnAraht1gg2ADgVk2lsbJSlub2jazba1p63NtkD7rIeqn0q/kVw+hL/ZLyNbqFimkZtnaulh1e3kJDkoV4PcV6MZpsrsf//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-37.png', linkedinUrl: '/in/edwin-garcia-7bcfaf8b3a', jobTitle: 'Nurse, mental health', }, @@ -5375,7 +5375,7 @@ export const peopleDemo = [ city: 'New Mark', email: 'tonya.hooper@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwCq8YxmszWdXi0mweZxmQ/LGvq1bUgCRl3ICgZJPavIvEGrnVdWkkJJt0JWJewHr+NZLVl2GXOo3WoykzXW7J6dvypfMESAZG8D5cHg1NoXh+416bbboEiU/M5r0XT/AIZacsQNyzyyHvnAqZVIxdjWFGcldHlhuZEkUuME857VastZm0y+SaCU7c/PH2YdwRXp998N9Na1CIHDAfezk15x4j8MzaG24EvCTwwojVjJ2HKjOKud9Z3trqduJraTcvdTwR9RU4Rl5rzjw1qz2F+isMwucFe/PevTAruuVBIq7GJc1i3gfRboTttQRMSSSMYFeEEEYyMk17f4oS4bwxfLEpLNHjj0714pAhluYk9XA/WhMD2fwZpy2ejQxhcOQGY+5ruoYmEY47V51qbT2kEax2hlDrwxPAwM4AyOaseFbnU4rmCJ5JTDOAwSVslM5wMdulcVrrmPTvZqCO9ljbyyBXA+ObUT6PMgUEqpbijxneagLkxxNMyR9UibBbnHSq1nHPdW91bz26oI1K+Yp4fj680WtaQN3vA8mtZjBOkoGSjBvyr3SwImt0YdGUEH614jc2TWtvG7AjzGYDnrivZ/DbsfDtg8w+cwrkj24ruvfU8xprRmuZY5laM8gjBrzC68OW+l+MPs4H+jzxGSEt2cHOP8+tempGS2VFYHjPSp9R0SRbWHzLtCGjxww55wfpSkrqw4vlaZv6ZJbX1kIbhA3HIYVahtre21K3hgjA53EgYrlfDMsq6TaNKrrMqeXIrjBDLwc/lWtfX+lSyxefqH2eZOhR8HPuP8a4NU7HrK0kmupqvaW91ezxXMakhiQSKqaqLa0tGhhVUGMDsBVawvtLVpPs9+txM7ZJMmST9Kx/GF+bLRLq6+UvtCIGGQSTjp3pWbaiOTUYtnnvid7e41m00/T2EqwgISnO52POPXtXrFhaLaWEMCLtVFAxnPPeuH8EaHHPFJq92itJK2YwBgLz1HpXfLKCAtehGNlY8icnKTbLUcionvUkQV2yagWP5cmr9jpl3dOuyMrGTy7cD8PWnewrXMXVIha3W9B8sq7iB6jiqqWH291mjeFXAxlxkEe4qzJ59xcDzuChZduPu89KpzWUsMhMTlAeQe1efOac20erRjKMEiY6d9k3SSvCz+qgAAe1UL3SLbxAVhvGcxQneEVsBz7/571cgtJJQWmkZwOvGBUF/YvLGximkhkAzHIh5BHT6/SlCdpXZVWLnFovQWUVjbJBAoSJBhVHQCgAs3Fbmp6TLaJbYBZpUGVA6NgZ/Ws42c8B/exOn+8pFeguQ4tH//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-38.png', linkedinUrl: '/in/tonya-hooper-da5e36c5c5', jobTitle: 'Water engineer', }, @@ -5385,7 +5385,7 @@ export const peopleDemo = [ city: 'South Johnhaven', email: 'jennifer.tate@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-39.png', linkedinUrl: '/in/jennifer-tate-ffbd43bb7e', jobTitle: 'Hospital doctor', }, @@ -5395,7 +5395,7 @@ export const peopleDemo = [ city: 'Booneton', email: 'earl.higgins@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDo9uBUcrJFG0kjBUUZZj0AqwRxXA/EHWHRodJhbhx5k+PT+Ef1/KgCPU/H4F35GlxI6qcGaUHB+grCn8QX87lXupZPMHzYOAOe2K3/AAv4Htp7JLvUl8xpRuWMcBR/jXWW/g3R7YlktQc9QTkVzyrxTsdEcPJq553ZeMNQsYPKWSKZEbIWQc49Aa7nRtetNYhDxMFk6FCe9OvPBGjyIzJaBSRg4NcPq+hz6HfR3OnSPHFuHAP3G7H6U4Vot2FOhKKuenqBUm0EVnaHf/2ppMF3gbnGGx/eHBrUArcwFI4rzfxVbM/i12x8pjQ9Pwr0ntXJarapd+JbeYfNCzLCxx0dSSR+VROSSLhFyZ02mDbaRRkYIUcenFaZPyjnOK4nWxeGXy42ugm3IW3GCSPU/wBKq+Gm1P7fHFJLeeS43Ymbdj2Poa4uXS53qWtjvJMlOuK43xIyR2spZQwxg8VU8V3urR37w20twsUYBYwjk1nwC7u7K6t55J3HlHi4UB1bHHI6inGO0hTlvE3fAiOvh7LfdaZyg9uP65rqAKxvCsaReHLSNc5C/Pn+8eT/ADraruWx57VmJ2rLu4j9rjfGI0cN25Y8Vq44qreRs9uwUgAHcePSoqx5loaUZqL1LUUcVzHhl575HWoRJZw3Bgh8tCrAFuBk+gqGG6URMB98AmuYuJ31ZSq20pjjJMbiHPzdyDx+lckY3O7mOguHszrDpMyMkhAU8HBqHVLW3hhdYx87DHFcsu3Sbp5HWfZJhXaaM5+uea33L3UsKrzuIxmnyaic9Hc19MiWCyRVGO5HvV2oYU8uNV64FTV2xVkkefJ3k2LjisvX9Xh0LSJb2dC4X5VQfxE/0q1f6pY6XD5l5cLGD91erN9BXnniPVG8QPKqhltguIkP8z71SVyTow7W6K8zlY2AIPpnsauyraz2ew3DIpXgxnnFMtzDq+lQyAfeUbh6Gsq+0W7Cj7FPj1Rv6V56eup6GttCxMtpBAyrceauP4+1R6HqFsdVgt5pSJJIz9nB4DEdfxx0/GsxdGu1kCXMu4HnArI8Y20tsthfWzMj2z4ypwRnHP6VrBrmRnUUnFnrAFO7V5La+NdatQr/AGgXCYyUmXOR9etdTpfxC028QLeRyWsnr99fzHP6V3XZnFc//9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-40.png', linkedinUrl: '/in/earl-higgins-1785700a3f', jobTitle: 'Administrator, sports', }, @@ -5405,7 +5405,7 @@ export const peopleDemo = [ city: 'Johnsonfurt', email: 'sandra.werner@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-41.png', linkedinUrl: '/in/sandra-werner-ca50c4d94a', jobTitle: 'Administrator', }, @@ -5415,7 +5415,7 @@ export const peopleDemo = [ city: 'North Andre', email: 'brian.johnson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwCsTXJanrMt1dSQwSotuh25B+8a6DW3MWiXbqSDsxke5xXCJC7yRoNoXOMCs5voaQXU2LGGeXe+cRL1coME++TUc15JJcG1nEYjYfLtbK5HP4Gtm00R9Qto4grLgYRA2EjH0HU1dPw9ll2HzUX1JWufmVzp9nKxxct/NaXUkUM37tyDyOK37PUpbUI0oRoGHLL2Na8vw6SILIJMsvPNc7r2kT2UiOX/AHR4Ygc1Smr6EypSSuzq0kWVA6HKsMg0+qmllG023KHKhAKuYrpRykGrxmXSLpAOSlc5pMEJkVGAIBAHrXYvGrxuhXcCpBGcZ4rAsNLW1177PI2dvzqPXPOTWNWVtDejBtX8ztdMSOOIBEUMOuBW2jHaCcfhXE38l9bKywiYjbkCIDninaLe6yssS3EjNHMAQHADJ6A+9cvLpc7+bWx2MrEqVx271xviZESA71DKeoPNT+JdS1WF5YrMECPBYpyxJ9B3rAljvZ7G6W5kdmVed2MZ4PBpxj1JnLRxJ9GjMemIu3HzMR+daGKit08u2iQjBVACPwqYGu5bHly0bJdxUgjtTLyBPOgvQuHLMNw7g9j9KkHNNmVtiNvYIpyU7HPesq0Lq6N8PU5Xyvqbtr5NzCocAkDv3pJ4oYp1VFCvwTjtWfZsyKpU8Yzj6VHeXFjd4FxNGjBsjL4Oa5FqejoaVxBE2rOsgB3qCM+tVb1IBtt1UAMfmGKzoZba3uXZbpZ5DhT+83EVLcuzTbsnPSqUW5JEzkoxbZVbkk+tKKXFFd55BMpqOW9thKbQyAz5Hyd/X+VWYbZmGTwvXNU20VBrUupctJOFHPRcDH+FZ1ZWizWjG80PjnNpN5Ttgj7pPcGtAwLPECvlhiMAlc1Fe2SXMSkjJXrVYWGoqALaZPL7bjmuJM9PVDpbRbYl28vcO4AFVobhblpGEgdkbaw9DSGK6a4ZbiVX28sF6Z9KraZp/lajfzhm2SlWKk8BunH4Yrak1znPiLuBdJpuamNsxyAQSO1RNE6feBHvXXc4AAAAAADgsf/Z', + 'https://twentyhq.github.io/placeholder-images/people/image-42.png', linkedinUrl: '/in/brian-johnson-1b262bb370', jobTitle: 'Environmental consultant', }, @@ -5425,7 +5425,7 @@ export const peopleDemo = [ city: 'Hoborough', email: 'jacqueline.bell@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-43.png', linkedinUrl: '/in/jacqueline-bell-41ae313193', jobTitle: 'Advice worker', }, @@ -5435,7 +5435,7 @@ export const peopleDemo = [ city: 'South Robert', email: 'jeffery.gibson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD02kpaKgoK43xX8RdN8OStZQJ9t1AdYlbCR/7zf0H6V180qwQvK5+VBk155aeDNLmlmubi38+aeVpGeQ5OSc4qJ1FDc0p0nU2OJv8A4k+K7xi8d/FaoTwkEY4/E5P60tn8UPE1lnzbuK6H/TeIH9Rg16enhXRwgC6dbnHqmar3XhfSJYyG0+AD2XFZ+3XY3+qvuZvh/wCLGnag8cGrQ/YZWO3zlbdFn37r+tehKyuodGDKwyGByCK8D8a+FrXS5FnsgUif7yZyAa6b4SeJZWkm8PXkjMFXzbUsc4A+8v07j8a1jJSV0c84ODsz1qiiiqIMzXtx09VUn5pFz7jrVe2TYi1k/EPzv7PsgLmeGBpiHWD77tj5fw61Q8JzXbxNDLJM1uI9yPMMOO2DXLXWtzvwztGx1+5VXlwD9agndSuO59K4DWNOkj1F7gW1zORyAk5UtzjgZ61saXDdAjAuYx0Mczbh+BrJpWubpu9jM8T2/wBo3+aDsHYjrXI+GwLLxzpLwAk/aAuPUNkH9DXoPiNf+JTIW6g9fSua8N6PPD4m07ULhAlpE+4SPwScHGB9TWtKaS1OevTcnpqeyUUUV1HCZOt+XKYIZACOWwfyrJgvtPtrdibmJCXK4PbHar3ihTFFb3YBIRijAe/I/lXEW1zYDUGkLsbgtuZVXP8AKuWom5s9HDtezVjt7aW0uzhdrHPXqD9KtSrDAp2Yz7VzltqEczLDGz8HIzGVK/0rSeYmTbnnuTWT00N7mXqypcBYJORI4FWHAjs3LHep5wBnp0A/WqV/ITdIIyNw6Z6Vf0GefVNZuFkt1S2s0XJzndI3QfQDn8RRCLk0iZ1FBOTOvooorvPJKGtWb32j3EEfMpXcg/2hyB/SuLsbWR9hSQRjGWQCvRB1rgPFem6hory6pZsstkz5aMnDRk/zGayqwb1R0YeryOzNS4kSGDywVPHJ75rMmvxEpJdSPXNcgmtahqI3QW0yhv4q19M0e5lkSS8Ukjpl81zSikdak2aNrG1w8l04OPupn+ddj4diRNIR1UBpGZmI7nOP5AVjywrHbeWo7dq1PD0d5HbHfGBa9UJ+8SeuParw92f/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-44.png', linkedinUrl: '/in/jeffery-gibson-33288473cf', jobTitle: 'Therapist, occupational', }, @@ -5445,7 +5445,7 @@ export const peopleDemo = [ city: 'Oconnorton', email: 'jacqueline.snyder@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDKYVCwq4VGOoqpdSLBAz5HHTNDdlcEruxE8vlDGMnsBUc92kMY85irdSB1rNXVJp5hFaW/nSsdoz0zXVWPgme6iae+2LKw4VcnBrllUbOuFJJHNR6pE8jAwsw6Ljmp3uPJIc5jY8glhn9K0bz4fXVu3mwXJ46grWJfRtFGscuFkXhgOn1FZ9dDSztqb2lat5zGGYYfqpHQ1tJMOlecRmWCQNDK3Bz1rsbO8a4t45O5HP1rppTvozkqwtqihvb1qtfsv2Y7z8vXmrBFUtSiaS0PXg1c/hZMPiRo+AbP7TfzXTgFIvljGO56mvVIgQgry3w9PLpXh5ZIoZpJJ5HI8o4xj1P4V1HhvU9SvpkjuldVYFgXGG+hrja6noQatY6mQZQ8ZFef+LdDch7mFcjqRjpVzW9S1aC5fyPOaJBnbHxu/wATS2moT6jGElt542A5EhyKVna5TtseZSEeu0g4zW/4buHeOaJzkLhh+NZXiOwey1qWNFJjl+ZQKueGoZIr6aNjkeWGyO4PStqfxI5Ki0ZqsMVGQHUqRwetW3jxTVTnpXUcp0nhXyP7JS2lUZRm6/WttLiztrwoZI49qEjtmuW0jcsjqDjBBq9ealpnm+VcWs0zqOqRE4/GuGUWpNHqUXzwT6mxYz2l5lSY24yDwwIpb2WCziPlooHtWXZappzp5FtaywnPCtCVxTr2JnPzngdazfY1skc9d2J1G8WccOnQkcY96z9DjE2sX9ygxbZKRf7WD1FUvFOs31pdDT7ZxHbzRguVHzHqMZ9K1tNi+z2EManOF6j3roox1ucVea5bI0NRsXs7x4CDx0zVZYGznFd7qFjYmAyXS5YjqDz9BXJyoIwdv610Qba1OWaSehHbo0Tq4+hFaEENrc4E7lSO44NVLWOSeZY0UszHgCpbi3AupoBnfFgFvU4ycVjXitzow05J8polLWyi/dyE59etUZpzdHyosnPU1Vj065klGWOw981tWtmluhwMn1NcrZ23ueY+N4Wh1mzfadhi259welbugzLPYKrEGVeCPat/VPDi64ht2B8wkGNh1VqqW+hw6ZIVgBOMAsD94gcn8TW9KT3OAA5K0dT/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-45.png', linkedinUrl: '/in/jacqueline-snyder-cdfcd4794c', jobTitle: 'Press photographer', }, @@ -5455,7 +5455,7 @@ export const peopleDemo = [ city: 'West Sarah', email: 'john.stone@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0PFNI4p9NNSMr3V5bWFs1xdzxwQp955GAArib/wCLOkQO6WNrPdhDjzCRGh9xnn9K53WG1D4jeI5bOzYx6XZOUUk/KzZwWPrnt7VrWvwbVY1LakcnqBGMVjKsk7G8KEpK4+x+MWk3F0IrmwuLdDxvVg+PqOK7vTdVsNXtzPYXMc6Dhtp5U+hHUVw9x8H9MNuQs8ok7NxxXM3Gl6v8PLyPVLK48+FTslU5wy+jD+vaiNaLdhyw8krntOKMVS0XV7XXdJg1C0bMUq52nqp7qfcGr+K2OcfisLxhNJbeEdUkhcpJ5BVWHYnA/rW9XP8AjZDJ4P1JFxvMYKj1IIOPyBpN2Q4q7sZfgWxjstCtljUBnHmMfUnvXdp/qxg5ry++L2mm20SRXb/uBtEBxjC5P41oeEZ9Te4WCR5/Icbg0xyV9q87zPWt0O8uDtjbLAVx3iJIpLGaORQ6MjBgehGKxvFEt/NdSZS5lghycQk5P09TUdpLJcoIvJuYgF+dJjnOR1zQ+40ugz4SXORq9imfIhdHQemcg/yr0yvLfhTaPa69r24hUJCIp6thjkj6ZH516mRXoQ2PJqJqQtZ+tWa3unMjYIRg+0jrjt+taNNkQyRMgOCRjNOcbxaCnLlmpGRpT202nxpMinaACGHSmnV9Ks9TWFpY4QFJRcfex1NZ7W8ttdyxbs4JPH51n3l15wEEmkzzBRjJ2jj1Ga81J3se1FKSujW0nU9MvppIxLHKrMcMOcHPQ0/VzbW0LLEqgY7VzNvdmOYwxaVNCWPYBgPxHSrl6JJnWIks5IUD3NDXQHoW/BljsuJrrGDtOQRydxz/AErsTVLS9POnWpiZ1dycllXAq7XfSi4xszyK81Od1sOOB3FIWCjJIFVTGAM461HswQcda4/r/wDdOj6n5nNatq8c9/M9ujqLdvJm3DqRyCPbBFW1+wahbIZJjyM/KcYNS3mnxR3M1xs/dXON/swGM/iAPyrlNS0aa3nMlpK6A/3T/SsufmfMzthFRikjZuprKwhYRzHdjHJqHw5cw3niCMTMPlVniB/iYf4DJrn7fSp3kL3UjMBzz3rQ0bTZpvE9rdoCLSyBaRgOrHhQP1NXBpTTIq3cGelGikV1kXcpex//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-46.png', linkedinUrl: '/in/john-stone-ed440ef104', jobTitle: 'Advertising account executive', }, @@ -5465,7 +5465,7 @@ export const peopleDemo = [ city: 'New Debraville', email: 'elizabeth.allen@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-47.png', linkedinUrl: '/in/elizabeth-allen-f3a164c8d0', jobTitle: 'Animator', }, @@ -5475,7 +5475,7 @@ export const peopleDemo = [ city: 'New Michael', email: 'daniel.knight@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1k1Vvb2Cwt2mnlVFA7nk/SjUL6HTdPnvbhtsMKF2P0rwXxh4tuvEWojKpDAnyxLnOB7n1qW7FJXO4vPi5ZQSTQx2rsF4SbcME/SuN1P4q63f5WN4beFT/AAJyfrzXPaZ4dv8AXJNtrEXjzy7cVvP8LbzaC06qAPunPWoc4rdmkacnsi5o/wAWdVS9jkvm+024wGjRQvH+NesaH4r0jxCv+g3I83GTDJ8rj8O/4V4fL4B1KwRpEZXGP4eDWPYahcaPq8TiRopIpA27PIojNPYUqbW59RUtZ+i3x1LR7a8bbmVN3ynIx61oVoZmH4wsV1DwxeRtK8axoZTs6ttGcV87mxee4VM8u4A9ee9fTGrWxvNHvbZSQZYHQEepU188eG0ku9et45By8wz7Af8A6qiempcNdD2Lw/psGlaXDBEoBCjc3cmtd9r+hrlNY3BSCl3KoXhLfjp7+tQ6D56zogFzHG2GKyvuIz2+tcfS56C3sdPdQqYmBxj3ry3xtocEEZvol2ybhu9MH/IrpfE01157ojXJji6i3OGNY11bvd6RewNJcsPKJ2T8srYyMGnHR3Jnqmjofg/qNxeaPeW0jAx2rgIO4z/+qvSa88+DtqsXhi7nx88t0VJ9lAx/M16HXatjznuLXlP9jiy8UW91gGTcyzkAAb23bf0Feq1zut6eyF7mGMlSwdyMcHNZVk2ro6MPKKumPgWKaHkAfXvVC6vrCymAkljiXcFyxxliegpq3G2J8dVUtisOa9F4gEtvLhc4CwFv1rljrod5qC9sLjWZUWVHBA3Adj2pmrwQQwSbFUZQ8iubaZLO8326OgxhlliK7voa21M2o3EEEIy8mMKx6d+aGnewm0lqdR4Os2sPCljbuqhlUn5RjOScGtyobWEwWkMJxlECnHTIFS13rY8qTTk7C1HMglgkjPO5SP0p9NkkSKJ5ZDtRBuY+gpko87llMcvlNkPgjOeoq008Uln5f2jyiVwrKOlTX1il9CwHGSSrY6VzF5pmpWjlVLOvYg156sepdo0Jp0trQobgTTY6sK2/BkH2qZ75iCIl2LgdSR1/L+dcQml3l3L/AKU7KrcFR3FegeEpoLXzbAfK7AOi9io4P8xWlPl50ZVnJwZ1VFIDRXYcAAAAAAAAcB//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-48.png', linkedinUrl: '/in/daniel-knight-71d19ed590', jobTitle: 'Producer, television/film/video', }, @@ -5485,7 +5485,7 @@ export const peopleDemo = [ city: 'Birdland', email: 'whitney.thomas@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-49.png', linkedinUrl: '/in/whitney-thomas-ef126a0de0', jobTitle: 'Ophthalmologist', }, @@ -5495,7 +5495,7 @@ export const peopleDemo = [ city: 'Krististad', email: 'christina.anderson@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-50.png', linkedinUrl: '/in/christina-anderson-f8458640de', jobTitle: 'Museum education officer', }, @@ -5505,7 +5505,7 @@ export const peopleDemo = [ city: 'West Jamesview', email: 'joseph.peterson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDvqKKKkoxPEninT/DFmJ7xmaRwfKhT70hH8h715bqPxY1y4kdrVYbSLGFRU3n8Sar+LZrnxX46uLaAkrATDEB0AXqSfrmpovhxfybA00YGeah1Irc0jSlJXSMRfHfiVXaSHWLkDduCsQRnv1rqNH+LepxvHHqVtFcpj5nQbH+vpV6H4Y2aRqZZn3gc46Vh694EFrbtJZzMdnJUjrU+2i3Yt4eaVz1/RdesNfs/tNjIWUfeVhhlPoa0sV816Dq8vh3Wbe7imlyGxKqnGV719JQyCaGOVejqGH0IzWpgOpcccUlLnaCcE45wO9AHkng+xK3V/czDNw87KxPUckn+degxAhBmuC1CGSxkuTHLcwrPcSSokafvBk5x+lWvDeo6k9wsE7zyKyll80AMPrXFUjduR6VGVko2O2ckIcnFYes8WMpRSzbScDrXN6vcapLcGWK4ujCCf3cDAHGcY+tWrG4uRgN9pkxwY5gMj6EVPL1Lc7ux5hqsOy6ZkGRjP1r6O0JGj8P6aj/eW1jB/wC+RXimp6HdXviORIo0jjP7w5P3Vr3SxmiuLC3mgJMTxqVyMcYrshJNHnVINO/QlpwptOFWZnJy26tqd1GxDMshwSO1Jbx28F+5dolKJ9Kta1H9n1HzkH303H3I/wAiuZmNtfz+ZIHMmMZSJjx6ZFcUk+do9Sk04Kxt2kcFw7COSMq3zLjB+vNTTW0dupO3nHUVi21xBZKY7eNkBbO1oiv/ANatS6mZ4hj7xXJ9qhqzNLoxIImfVridVbcioinPBHJbP5ivQ7GAW1hBABjYgGK5vwxYfaDNcynKK4AXsSK6w11UYtanBiKidoojFLRSitjmM7WrCS9siYP9fHlkH971FcmFS5hVHuGib/ZHIx1BrupXYxSrEf3mw7ceuK80e0lubRbyJ3S4KguAep7/AI1zV7JpnZhnKzRsS3MFtblFn3vjGD1rONzJcYjiYnd1PoKrQaNc3K+Y1zlT7da2bOxW2Qc1g2lsdHvN6i6N4gksNUt9GW3jaOaTl8ncMjr+ldwea5Tw7oSXHiFtakT93bxmFD6sf8B/Our2yLIV2gjt7V10n7qucNZe+7H/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-51.png', linkedinUrl: '/in/joseph-peterson-0735ee6e8a', jobTitle: 'Actor', }, @@ -5515,7 +5515,7 @@ export const peopleDemo = [ city: 'Katrinabury', email: 'larry.graham@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-52.png', linkedinUrl: '/in/larry-graham-ec62249904', jobTitle: 'Surveyor, planning and development', }, @@ -5525,7 +5525,7 @@ export const peopleDemo = [ city: 'South Charlesmouth', email: 'rachael.fox@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDvsUYpaQ0gIrieK1geaZ1SNBuZmOABXnGtePri5kkj0vENuoP74/eb6DtVD4keIZ73Vl0GyYlIiPMC/wATnsfp/OrOhfDTfFHNf3B8xhkpGOnsTWU52NqdNyOXl8R69cgj+0Z9p/hDc4pIL/UEbzY7y4jlHQ7yDmu61T4d2+fPtJXSVew6EehFcJqKPZTTW0gwFbp3Wsue+xq6bjudh4Y+IrrcLZa6wwxwtxjG3/e9vevTFKuoZSCpGQR3r5okcufm7d69Z+GXiB72zl0i5fdLbDdCSesfp+H9a3hLozCUeqO/pGOATTqjkGY2A7girMzyHwjaprPjjUtSlAYRyM6Z9WJwfyr1yBdi143YuuiHWYUs3vHF2IV2sVHGeSRXc+EJbxoxHOHVHj8xd7ltvtk/yrjqRbdz0KTSVjrXGQTmvN/H/h9pU/tK1TLqMSqOpX1/CpfEzagl4J0iuZ0znaJGCgewHerVjcT3n7h7WWBk4bD742yOxqUmlzFtpvlPG2cq+D9Me1dF4J1I6f4rsZC2FZ/Lb3VuKd450UadfJPAm2ObOQB0audtzNEYbkIyhXGGx3FdCd1c5JKzaPp+kNO7UlbHOcvpOjw2N/qqyoGFzc+cM+hUf1zWlJc2doJwZI4tigYPGAak1BCssUi8Z+U1jXWpaULhlmt5J5F+U+XGT+BriqJ87R6dD3oKxt2ElteRYLIxGOhBBGKLx4bZCUUAAdqzLDVtOkPkWyNFITkIYypp2ohnGCfrWT00NbHLa5aJqwHm4CI+7PpxXNeJ7GK0trGARhZpm2kAYyB7fiK39b12Pw+sc5g87L7QgbHPrXL6dPeeLvFsE0ke1PMUKi9I1Bz/AJNa009+hz1JJXXU95opaazqgyzAfU12nnle+j32rkfeX5hWVDZ290u53CN0PY1PrGuR6fYSzQx+fIowB2yeB+tYxS6eETvIBcNy+wYXPsK5q9rp9Tswzkl5Gu0UFjHw6kH2rKvtQXYQp3MfSs13vJZSkoIH161YhtGyCw4Fcx1XOB8brLNc2cXJCgu31PArsPhrpkcKTTOo83au3PYHnNYetW0k/ie3jk4tXXB47jn/AAr0nQ9LWymmkQbYiqxoPUDPP6/pXVQ7Nn//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-53.png', linkedinUrl: '/in/rachael-fox-736e697d7a', jobTitle: 'Senior tax professional/tax inspector', }, @@ -5535,7 +5535,7 @@ export const peopleDemo = [ city: 'West Amyborough', email: 'christopher.wilson@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-54.png', linkedinUrl: '/in/christopher-wilson-f6db69b44e', jobTitle: 'Lecturer, further education', }, @@ -5545,7 +5545,7 @@ export const peopleDemo = [ city: 'New Connie', email: 'aaron.mccarty@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDvQOKMU4CjFdHMY2EC1Xlv7WE4aQFvReawNd8RQQXUlmJQqxYEhzyzH+EDqaxb2W7v4ohaR3EO19zMGC7h6VjUrqLsa06Mp7I7D+3LQE70lRR/EVH9DVu2vLW8XdbzI/GcDqPwrHtp4WU/aNMlJK4JVg36Zqr5Nkrma3kaGSM8gfKyfUehqI4i5csO47o6gikxUNlObm2VyQWHBI6H3qwRXQpXMGgpHkWKJ5W+6ilj9AM0tVdT3DR74p977PJj67TWdykjxzS7ltRvrjUHTMk8rMuewzmu8sYJTErnBHsa82tB5NlaRs8yJ5QP7kZcnGa6HQLi+tNbgtBcTS2s2CDMuGA68815tVczbPWoS5Ukd5AsgO7IA96qa2oe0kmQYuIlJR16/Q+o9qwPFMLx6mpEly0RBIELc/QDNaGlIysESSdoSo3JcphhmsrWXMjZu75Wiz4D1BdQhvXjYoqlQ9uf+WcnOSPY8Guvrg/BsAsvEusqCFhcqig92BJwPwru816lOScVY8epBxlqGazfENqt74d1C3ZygaBssO2Of6VoA0yeIXFtLC33ZEKH8Rim9UTF2aZ5hocFrcDy5URtijbkVd02505vE6IJ4kSPITjjI4rJntLjS9QntmZRJGuMjof8g1Hplu0lyc2avjP32AwPUV5zjq7nrwldJI7ue802USK7xzrG+12UZCc9TWhLBbxWitGwJK54PSsAG4itiptHaNlwdpDDHuO9XoYglnHGrNsUZGTyB6VjJWNr9yTTLI+cjjGGn+0bsdDgrj8sfnXR4qhp0JS3Rjj7vAHvV/Nejh4OMdTysVUU5q3QhVwRT9wquv1pWkVBljWpznHePLFUlt7+Ph5Mxv74HB/KsbS3tHYJMxxjkg4rT8Zaqbi8j05UwkQEpY9STkD9K5Vbed7sJCQHPQmuOrbmZ30LqKZ6FBNbQwiOKTIx3PaojMZcpEfkHU+grK03Q7s83c4IPZK3/suyEQQoWZvlVVGSxrlbV9DrV3ub6AKgHoMU7cKs2+g6hDpwa5lWW6LZCKANq+nuaqSxSwttljZD7ivWi7o8aQAAAACSsz//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-55.png', linkedinUrl: '/in/aaron-mccarty-4207ebed52', jobTitle: 'Engineer, structural', }, @@ -5555,7 +5555,7 @@ export const peopleDemo = [ city: 'Jamieberg', email: 'albert.taylor@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-56.png', linkedinUrl: '/in/albert-taylor-715173cf8c', jobTitle: 'Exercise physiologist', }, @@ -5565,7 +5565,7 @@ export const peopleDemo = [ city: 'Port Anaside', email: 'laura.diaz@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDr9tDskMTyOwVEBLE9hUwTivMviT4juIroaNbMUhCBpyON5PRfpWbdi0rsdrPxBu3vXg0iJfLQ481+Q3vj0qgNc8RXiGSbUVCKMlY2C/yFcvpcF1qdwII48huAnTcf8K7eD4ZahNArPdRQsedqDpWMp9LnRCndXSM+D4g6hYSJFI6SxZwWkGSPxFdzovie01RxBIRHOwyoJGHHsa5a7+FTrAxW8VpMcErxXL6pb3mixRwzFllhb5HHcdiD2NNVOwpUmldo9tYelM21k+EtWbW/Dltdyf63lJP94d/x4NbWK1TMGiyAO9eBeI9QGueKLu5U4Uy7FP8Asjgfyr6AC5HNeC6ho7weNJ7JVGw3eAFPABOcfkamb0Lgrs9N8J6JaWNpHNFEDOVAZzya7SMHyxXC39ze6db+XbQzuWGR5Y4GKl8PXGtNcxLdyyGGXDHzByvoDXIk9z0NPhOwuMhMYxXnPjuziuNIlcgb0+YN6YrT8T3+rJcSR2gl8qL7xiGSfYfnWJfyXOo6TcwSRSpIkLBhJzk49aaWtxSas4kPwq1Fz9s0w8xhROh9DnBH8q9KxXlnwktZl1G9laMhFhCbsdDuzivVyK60efLcsCuJ8RaOp1qK8RMFXM7MB16DH6V2wFc74zuruw0dLmyto7iQShGRzj5SD0P1xU1IuS0LozUZa7F6wuYZoBHIoPHenXM9rBcwxB44wWGSSBz6VlWKNuBH5Ul/qekEiG8t5ZmQ5ysDNtPrnFciu9D0tN0X7eW2n1O6iLRyLuyMHNUdcMMcDxRIAWGBgVRsNR0dJnjs45ImY8mWMqWP1PWpGt5NR1JIlfaSTyRkDFFnewpNJXZb8Iaetjp0uPvMwDe5A/8Ar10BpILdLaBIYxhVH5+9OYV2RVlY8ypLmk2icDimTxRy28iTIrRlTuVhkEVFcXYiQiPDv6dh9azJJtQmheO4kj5bpEm0bfTqc05y5Fdipwc5WRlLJ9kmGThCcitMW8d5HuFxsHYjqKhurQTQYx2rnbiK7tSREzqPTNcKZ6mxsXVvFYo0pn8w+pq94aQTrNdkc58tT7dT/SuPYXUwzOxIHY11/hG9trjSnghcGaCRhKvcE8/yxW1FXkc+Jk+U3iKY1PJpjV1HCf/Z', + 'https://twentyhq.github.io/placeholder-images/people/image-57.png', linkedinUrl: '/in/laura-diaz-83aa93da5c', jobTitle: 'Clinical embryologist', }, @@ -5575,7 +5575,7 @@ export const peopleDemo = [ city: 'West Michael', email: 'hannah.craig@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDrwKztX1vT9DtfPvpxGDwqDlnPoB3pNd1m30LSZb6fkLwiA8ux6CvDdV1i71vUWu7qTfK3CgfdQegHpUNlJXO11L4lXkrH7BFFbRDp5o3O34dBUNr8UdRjQieyimx/GpK/mK4+2spriYQWyNLK/Uiuns/h7qOEmkuERj1Ws3NR3ZpGm5bI6jRPiPYajcrbX0Js5H4Ry2Ub8e1doCGAIIIPevGtV8DXljE81tL5ijkoR0ra8AeLpzcjRNSkLE8QO3UEfwn+lVGalsTKDjuemYooFBqyDx74l659t1hNOjbMVqPmAPVz1/TA/OuMhDSzLDFgu5wPapb2Vprye5lbdJK7Ma0fCNmk+rK8gJEfzHaM89qiTsmzSMbtI9H8K6FBpVmHkYGZuWduMV1gKMg2OrfQ5rmLm+EFvujtTcORjayZwPoap6PI/nm4NmLXPLY4wPpXA037zPQTS0R1N5HmFs4HHevHfFUB0rX4r22O3cQ6lT0YGu98T6hhzAUkljUBiqqfmrktb0ttXgiNnAITBnzIzxn1IrWirO5lX1jY9d0y6+3aXa3fH76JXOPcVbrO0G3jtNCsbeKUSpHCqhx0bjrWjXacB8y7suS3dSBXZeB4JLd5ZHQgSKDkj3ripciQnGB2rsvBWsyXF41pOE2pGNhAxkZ71jWvyaHRQa59T1K1hjuI+QA2ODUV2tvbAiZ41jAJdmGAAKltUwgKt1pk9+kZMf2SSZuudny5+prhWuh6FildGxub62kjmjd3jxxzkVS1G1lSWCOyx5kkqqw2jG0nn9M0SXkX2xP9CMLt/EBnn8Ks6fcl/EEUDAEmNmPtWtNPnSMq2kHc6tAAoA4FOpqjinV3nmHzTqtnNY6hLbyA5RiOnX3rX8G27S6vIACCsfX0Oa9E1Pw2l+5u7sLJKxAOFwPwqO10RLO5S7jVRhRFLgenQ1nWTUGa0bOorlyz1F4h5E5KsOM+tbMcsMkf+twpFZ9xZxzqNww3rVF9OmiXKSkLXnJo9MtXscauqwncWPAA61f0bSGtr2W8lOZHUKPYVxWq313p3k3MEp8xJV5PPGeeK7/T9at7hVjmxDNwMHofoa7MPFfEcWJm78pqUtGRRxXSch//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-58.png', linkedinUrl: '/in/hannah-craig-e5a9be07cf', jobTitle: 'Air traffic controller', }, @@ -5585,7 +5585,7 @@ export const peopleDemo = [ city: 'New Cory', email: 'jessica.smith@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-59.png', linkedinUrl: '/in/jessica-smith-59aaca3a47', jobTitle: 'Seismic interpreter', }, @@ -5595,7 +5595,7 @@ export const peopleDemo = [ city: 'Matthewtown', email: 'michael.george@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDoGJ696ixU23tzUN9Othp9xdyD5IYy/PfA6VBZR1LWbDRow95OELfdjHLN9BXI3XxNeOVhbWEewH5RI2XP4dKzNJ0LUPF9zLf30xjDucNjOfYDsBXU23wtswQZrp3P+7g1Dmk7G0aMpK6KWnfEcXEwF1axqrfdKkj8Oe9dfpuq2GsW5ls5lcj7yHhl+orHk+GmkhRzLuBzkHrXL32h3vg3Vo7/AE15JIC21lz0z2I7g0lNMJUZJXPQ3i5pgixzirNvKl3axXEf3JEDD2zSlB3FaGJMK53xxPs8PfZwcfaJAjf7o5P8hXRofSuc8cQCbSIBgbvPXn0BBB/pSew4q7LHh+JLewgRFACqMCunRvlHevPb+S4tiIkmuo0VcKtsm5m45P0q1oF5qHnpFJNdOjEEeeBkflXJ5npxf2Tt2Jx7VzfiVVbTpgRnjNZ3iK5v/tLwxyXIVOvkdSKr2Pn3KMrSXZUod8dyvI44Io8wk/smp4KmabQmRhlYpmRSe44P9a3pFrB8CKIdBeJid/nMxB7A8D+VdI3fNda2PNkrPUiVcCsXxNCJLVJTkmMHAx34/wAK20yTjpUeoWr3Nm8SEbyDtz9KU1dFUpcsrsp2Cw3NupcDp1pjz2Ud9FGskaYbucZNYVpNOlsyhsOq9PpwapSKbqZUuIbgSJ0ITj65zXKlrY9NNW0Os+0WT38itJG+T2Odpp98scERMeMYNcoiG3dhBFcGRhyxj4/Otd2ke1iVyTIy8j68AUNag3ZamjoUKx2zMARnCkY9P/11pP70WsJt4QjEE9SaJGyeK64K0bM8yrJSm2gQYFPByafFCZKkeIQoW647mqsZHAeI2/s/VpkAKxy4dWHQMRyPxqeC4W4t1beyMR94Gs1on1G+1IXDb/Mm3D2G1cVVFjf20ZS1csOhXqV+ma5JW5mejTuopnQtdC3t8B3kkPdulQabfJLf27zyhIInUyOx+XPRR+eKylttQnYCVSgY4255rUudJibRZLTkb8cjqWyCP1pXSY5c0k7nbS7QOoA9c1yviDxNb2CSQQFnn7Fegrp0sobuBbW4j3oQoOGIOQOxFZ974E027yYpLiB8Y+9uH68/of/Z', + 'https://twentyhq.github.io/placeholder-images/people/image-60.png', linkedinUrl: '/in/michael-george-2f16bc3685', jobTitle: 'Insurance risk surveyor', }, @@ -5605,7 +5605,7 @@ export const peopleDemo = [ city: 'Port Anna', email: 'ronald.hogan@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-61.png', linkedinUrl: '/in/ronald-hogan-67f4504d1b', jobTitle: 'Engineer, electrical', }, @@ -5615,7 +5615,7 @@ export const peopleDemo = [ city: 'Mariomouth', email: 'elizabeth.wright@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-62.png', linkedinUrl: '/in/elizabeth-wright-3d2908f9b7', jobTitle: 'Legal secretary', }, @@ -5625,7 +5625,7 @@ export const peopleDemo = [ city: 'Bowenfort', email: 'thomas.zimmerman@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDuqiuZhBbvIRnaOnqe1S1n6ll5beHOFYkt+HT+dJspEFvFcXRaS4JVc8KD1/8ArVYMCZAKDaR1oknjgJ3uqAdMms641eNp0jCuYifmcLxUOSRcYuWxHqWiw3AEqyNFtOW2d6yW1G80DU7eSNWubGQhZcHkA966JZ4JziG4QMex71m31mom2s+A/QDoD7UJ9hNNbnVcMAQcinCq9mSbGAnrsAP4VYAqyBlZWvXSWFj9rYZKZVRnGSe1auK5fxMjXcsdtKQI1ljaMf3j3qZysjSnByeg6wgNwUuLw+bKRkA9F+graOAv3Bj0xXH6tLqMPFkZcgEhUHXHrTdE1bXZrmKC7jHz4OSMED0Nctm1c7k0vdsdc0ayqcxKR7riua1u2e1SS5gdtyKW2FsqcelV/EOq63DcvBZIf3YySBnPsPXrUdj9uuoJI70yZKHcHAxyO1CTWoSs/dsdros4udFtJx/y0jDfnV8VieF966QkJAEcIWOLH90KP61t11xd1c8+UeV2YwGsnXLZHjSfGWTpWpQ4UxMHxtxznpRJXVhwlyyuZNmtvcwbZFB9c0LDbQ6hEkCLuVhkgVmoWjZ9jZHXiqU98qMr2l4kUw7M4+Y+4riV9j01a1zelhtpNSkjnC5ZvlzUV+kMCeXEoBPHFYEV80srve3ccshI2hXA2n2rSRjLPH5jZBI607O9hNqzZ01hAlvYxIvTGasgCqsMxwBkEVcjAccda7I2tY8yV27sgxgZPArD8RNcyQ6aLbPkzzOHbsAF4z685rav87GUccVV0Z477TG06fgxOdh7g9QahybbijRRUUpM5icPboCCQoGDTvKe4hBjkhRugLDPFa+oWDw/JKvXoccMK5W9tri3YtbMdo7dQK5tnqdqfWJovA8URM80LkDqoqFWkaKNwxBz8uR1+o9KzrOO4uGzK+VB+YAYzWyIwZIkP1pN2HrLc3NLlSeBWK7HyQy5yAR1/wA+9bETBTxWHAn2ZbbPDyyOxXvjAA/lWunXNbKTRzsAAAAAAimf/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-63.png', linkedinUrl: '/in/thomas-zimmerman-83ce4ea20a', jobTitle: 'Advertising art director', }, @@ -5635,7 +5635,7 @@ export const peopleDemo = [ city: 'Lake Christopher', email: 'judith.harris@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDYZarXlzFY2zTynCr+tXSM1wXjXVllP2CEkCNvnb1b2rGTsaxVyfUPGRaPZap5YI5bPP8A9auMvNfuZ5ZG8xtxJwc0thY3Wp3HlW0e4jgs3augX4eyMpaS4VXPZRUOS6mqhJr3Tl49euI8Ir5PcseprsNB8WXMIjivfntScBh95f8A61UX+Hkwj3Ccbh6isq80670fG+MlehI5Bo5o9BOEl8R6xHKk8SyRkMjDIIqVBXI+CNTkulns5cbY1DxjuOcEfyrskFWmZNWY8Ed6808W6eU1ydgQI3AcDvz/AJNekc1xXiyzkOt2zEEx3G1R9QcEUplQ3NXw7p0VhpsQiT52ALN3Nbu0kA1z+rTtawCGOKWRipIVG2gY96g0C4vWmSKeSQowDAM27b7ZrmabVzui0nynUYJTFc34jgR9NmyueM/T3qvr95epcstu0mxB0jbbmiynku4zDNFKjgfMrtuByPWi2lwbT9057wXK0HiNAnIkUowHp616iBgV574JsJE8RTvtGyJXUk/XHFeiha6YnDLcRQKzNXtVmnt5CCSrKF9FIOc/pitLNNkXepA60VI3Wg6U1GWpW8qOZMsoJ9xVXNrb3aR744+cDJxuOM4FWiDGreo5xWVNqNmDtaF5WGc7YycevNciu3Y9BWa0J4za3F5KgaNxuODwcH0PpUt3FFbx4QAEjtWbb6haGTy0t5ISeRujIz+NaDK08qA9zim072C6S1G6JaLDJJJtwRnnudxBrbBqKGAQRhM7j1LYxmplFdUItKzPPqzUpXQwAU4AUmKXBrQyKl4MPx0YVUNvHMpV3AA6Vo3SZ8sEdc1mXdq6xeah4BwR6VxVLKbPQot8iZG1vHAPlkBqbTzvvFHYKap29rLNl3bC/wA6t2x8i4VsZGCDSjJKSZU03F2NcjmgGmhw67lORSiu1HnPAAAAAAAAND//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-64.png', linkedinUrl: '/in/judith-harris-c394ff92d4', jobTitle: 'Teacher, secondary school', }, @@ -5645,7 +5645,7 @@ export const peopleDemo = [ city: 'Lake Jeffrey', email: 'james.massey@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1U000uazde1aPRNEu9RkBYQoSqgfeboB+eKAK+v8AifSvDdt5uoXAVj9yJMGRvov9a8s1X4v6tLdk6dbw21sD8qyLvZh7np+VVNA8KXHiu4n1nWLlyZ5CTjqx789h2Arq4vhtosfXznXrtLVm6qTsbxoSauY2jfGG7j3DVYIrgZ4aP5CB/WvUdF17TtfslutPuFkQjlc4ZPYjtXET/DvQiGK27Lnr81cnqejXvg2/i1LRJpBCrfMgP3T/AFB9KFVTdglRklc92pRWfoupx6zo9rqEQKrOm4qeqnoR+dX60MBa4T4pzT/2Da2keRFPP+8P+6Mgfn/Ku7zXH/EFEn0u0hyPNNwCB3AwRn9RSk7IqKuyt4cijttHto4x8qoK29428HNcbqVzdaen2W1WYBU48lck4HXmoPD15qdzfRxXLzeWecyDkexrjfc9BPods7Ajk4rmvEe1rCVSuRg1la/eapBqLx2rS7I+cx9/aixurm/XyLpZuV5Eq88j1oXcG+h0Xwwld/D91Ec7I7ptmewIBx+ea7iuJ+GqrBodzAWHmi4ZmXuBgAH9DXaZrsjsefJWY4CuW8XW6ma0uCMsPkB9BkE/yrqBVDVrOS8tQkQDODkBjjtU1FeJdGSjO7MaJILqDLheeue9VfOsLa7SNZIowGxyQMnrVRZHhR0bIZMg/UVl3F1Y3aqskTllyA/ksce+cVyI9FW6GsJrG41GVWkjdXbHXODUt7DBaRfulHTiuciuLC1YiOOQM2AS0RG79K1JTLO8aAnL4AH1oa1E3bc2PB0AiF3MMAttXjvgk5/WuoL+9Z2k2D2FqyShPMZskoePQVcY4+tdcFaNmedVkpTbRaHSg0gNZ+r65YaLb+ZeXCoxBKR/xOfQCrMzk/ES/ZtYmXO2OTDD8Rz+tRGJ7mAf6QIuBgisHQ7m51hdRlvpWmd7piNxztUgEAegFOuLXU4EP2dxLEvQE8iuOdlNo9Cm2opmv5Jt1OZ/M9zRozG41u0TOQsgJ/DmuetX1K7dll+RBwTmna1FLD4duWgkMcsYV1cHByGB60K3Mgm3KLPXyD6Zpj8DoK4XQviVaDToU1ZJvtCja0yKCG98V11hq9hrEZksblJcdQOCPmjzz//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-65.png', linkedinUrl: '/in/james-massey-14adc3c2b2', jobTitle: 'IT sales professional', }, @@ -5655,7 +5655,7 @@ export const peopleDemo = [ city: 'South Jeremyberg', email: 'louis.huynh@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0OlpKw/F2u/8ACPeHp7yMr9ob93AG6Fz/AIcmsjUh8SeN9H8MfuruVpbsjK20PLY9T2A+tcS/xiuGmLxaXCsGcBXkJf8APpXI2Wg6n4juJL+eYl5ny0sxyWrbT4c3ve7hI+hqXUgtLlqjN62On0X4rW11OItUthbq/KSxEkfiDzXf2d7bX9stxazLLC/RlPFeOzfDSY25/wBLG4cgYq74e1K68E6hb2F7JvsrlwpY9ieM+2KSqRbshypSirs9bpRSUDrVmYleZfFcyPc6ZFu/dbHbb23ZAz+VemivMfibdxz6hZ20ILSWoIm4+7vAK/yqW7FRTewmjKEtoY04AHauohAMYw+fbNecai8ioiRyXCptwBDwSR607Q7nUo7qJWmnMUhH+t689BXJyacx3qevKeksfkPzBeK5bxIkMtrtlUEBvlJHQ9qyPEdxffaXijlnCRnJMPX6VFAlxPp93DLLO+Y9w8/qrDmnGNrSFN3vE9d0md7rR7KeT78kKM31xVysrw3Kk3h2x2Nu2RCNjjHzLwf1FatdaehwNWdmItee+PdLxqcd0g+W5UeYfdP8ivQhVLV9Kj1ey+zu5RgdyuBnBqZRui6c+WV2edWGyRDGw5/vU9pLS11CFJJI0UODluMn2qCON4pGjPDoxU/UVWmkW4PlvZyTAdwox+ZNci3sej0ubck1hcamwjljfecHbzg9s0t5DEI2iVfmYEZFZFq8NmhUWUsatgFigOfxHSt2wtG1LUI4C2BjJbGcCizvZCbSV2dboVstnolrEvdd5+p5/rWjTEQRxqi9FAUUua7UrKx5sndtjgK5rxnqV9Z6Hc/2XIyXUaeZuXrgckflVme+uW48wjJ6LwKzriUiUl+VYYOe9FybHCreSm2juZSxaZA7seu4jJqxBNaTJiV2ZSPu5qW+sltWMGMwt/qj6D0/CsK4tJFP7tsGuNrWzPST91NHRI9kkZEDED0JzXT+DXhea7ySbhFXg9lP/wCquJ0y1EcQeXLPnqa6rwlaSh9Q1BWKrO4jiI6kKME/nmqpW5zKu3yHcmkqlBdSbR5oznow71bR1ccGuo4j/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-66.png', linkedinUrl: '/in/louis-huynh-8409c77412', jobTitle: 'Education officer, environmental', }, @@ -5665,7 +5665,7 @@ export const peopleDemo = [ city: 'South Angela', email: 'lori.alexander@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDJm71WGc1ZkOc02KPfIFHUnFc5sSWlnLcuFjBJNMv5otPuEt9rPITj2zWwXcQpp+lhBducNKRuPvgdKuW3gxIh5t3dTXFwRyzEYB9qydU3jRbOOubueRXktkmyo6gYA+grOtvEVzHPsuSJUJ5yuGH0ruJ/DUsFu0cV2zRk5KsoP615trVlNY3bK4wc8EdGojJNhODSOtjkjuohLC4ZD+lSRQnNcjoGpm21BEY/u5iEcHsexrvETaelXcysZjZqa3YrJuHVQW/IZphWpIULB0BwWjYD6kGnLZijudb4EsIo9NfUGPmT3DH5z2HtXTXCnjj8q4m2N1pvgyxht7UzzSI5JLYVBknP1q54UuLqS1dbwMo2bwS5O32Oelc9tDti+hsXa+WhXpXB+I9OivIXjkwH6q3oai1+6vr2eSWHe8cYyEBPIzjpUVu9xcZgmhCTRjqjZVhimo2VxuV3ynAtHsmkQn95EcE/1r0rTZftOnW8zfeaME/WuC1a2eLxAVSNmMvQKM5zXe6XE0WmWyFSpCDIPatTkasVyKnttqyoW4GRkioiKUKeKtkJ2PTdPgSLTY7XCt5Q24IyDVW+FvBazpG0anad3b8qTSLpbqyjkSTewjVZOMYYAZrP1O+0WNcTJ50gJVmRSSOeRn8K5rO9j0IWeqMrQwkm9GC5H45HrS6p5FpkxqAxHYVU06/sIrlo7MeWecRkYOPSmakxmlLdhSdytDFwiXizmMO7YTGMkL3P61tWsXlWsaZzhR1rOsJlnv5rYoCkfJP95sA4/DI/OthQS1aRT3Zy1ZprlRl7aeBTthpyqSa2OY3PD939md4WOFkxj2Nb1zYwT2nLKoXGMcE1z+nWsqPbSlMCSQLHn+LHJP0FdDe6c1wrlHaNgNwx0rCpZSOqhJ2OTureGynLoFBzyR1P41m3Vz5n3e/Jq7c2c8lw4kYMB3qi0JEbce1Z3Oh6j9NtXiVXIG19z5+uP8K00XmobO6ilRIB8sqIPlPcdM1dRa6FscD3AAAAAAAA1P/Z', + 'https://twentyhq.github.io/placeholder-images/people/image-67.png', linkedinUrl: '/in/lori-alexander-06fabb279c', jobTitle: 'Diplomatic Services operational officer', }, @@ -5675,7 +5675,7 @@ export const peopleDemo = [ city: 'Crosschester', email: 'anna.moore@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDdoApwFKBXGdQDApZf3UJkYHaBnNZ2o6pFYZLkkIMlR1Y9hXONqes+JleOCIW0PYxsSce56VnKb2RcYXNRPE0cl2IYo3aPOGf0rVN4FYEjCHv2rD0XTrjRd7TMDI/Rs5x9fUVHfaltUyxgRMpw8f8ACD9PQ0OfZj9nbdHVRusgyKkKjFc1p+pglQpwrHgf3T6V0sTiSMMPxqoyuRKNhAOKa5CRs56KMmpAKoazcC302Vj3GKb0Qlqzhwlx4h8RS24J8lDmQ+1egWlpDZ2yQxAADjA4rzbS7uS1sr64hheWWWVUG3JxnJ7da6LwtPcv5guTIIthcGQYIPoaxlF2udtNrY6W8iVo2XcpJFcVq9u0Tvno3B9DVfVZL6a8kuY1neNfu7O/p1p0FzcX0RguYSGUYzjg0uWyuOTu+Uz9Nu2t7kW0hPJ259ux/A13mh3wmXaT98fqK82nlNvexq4zsbg55x6V0OhX5SZ13cK+R7f54q9tTna6HoIHFc54xlMWnrxnJ4rpV6Vi+KLT7Tpg4+64P4VrJaGUXqYXw9MMmk3HmAFnnOeM4wBW1ql7p9nDcxb1RgnQADrXLeBwY4b2IN8yz8qO3H/1v0rY1HVtJhYW8li9zKByyoTz/vVi03Jo7qXwJlrQLi2urd13I5AB45DDFGozxQZCIB2FZthqtrI+yCB4SeishWn34LscnpWclZ2ZqjkNdjMkizBcKB8x9OeDUmlzbJVlIPzDDj+dT6g1pkQ3EqLkZCscbuf88VSsm8uCZuoDKR7g1qtYnJNLmuezKOKr6jEZbCVVGWxkD6VaUVHb3EF0HMEqSBHKMVPRh1Fb2uclzzPT7ltI1xlPEU7k9OhPQ5rrRYw3NuGM4Tj+E4JrP8VeHTGk90svlQFS249FPp+dYnh6Wa78PxtFI/mRM0ZyeuD/AIVjKDWrOyjVV7I3HghtGBDgjPJx1qvdzZjPdjzWe0kjHD5JB5GamQFlAx1NZNdTpvc4zxdkT2qnqSTmr+l4uLZ1+n6CrHijSTfrGyHa8fI+lGm2N3YCNpbaTY6q4YDIYe+K13//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-68.png', linkedinUrl: '/in/anna-moore-209cbeb00b', jobTitle: 'Armed forces operational officer', }, @@ -5685,7 +5685,7 @@ export const peopleDemo = [ city: 'Lambville', email: 'richard.smith@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDq9nFNKVZ2Cuc8Z6g1hojJE+yW4PlgjqB3x/nvXLa7N7mL4g8dW9hI1ppqie5zguR8o+nrXMT+J9QnZTc3E5UjGFOAD64AqXR/DE2rNviYgNgZxx+Jrcf4aX64MN9EmTypU4rTmig9nN6mPY+MtTsBy4uIeoD88V3mgeIrPX7fdF8kyj54yenuPUVzA+GdyqHzLhOuQEFZw0m98H3a3sQZo1bDk88d+KluMth8koq7PUCgIqJkxRYXceoWEF3Fny5UDDNTOtSItbeK4/xxbmVrEZ67/wCldrt4rlfFKfa5o1CEfY2BZj/EH44+nFVfl1CMXLYv+H4Y7bS4YkXAxnitwZ29a5XUxfQRJFZeYq8LlAPw57Cs3QLvWnv0huJJzHIx/wBaBuH1xWPmdi00O7OQpA/Wuc17ats5YcfSsjxHf61FetDbNN5SEZ8rBJzxxU8CXFxY3EF00hGwjMnUfj3FJdGEuqNXwyP+JHCuAAjMoA7DNajpVHw7EYdNEHZDkH1yM/1rUZea231OSS5XZk4HFZWr2nmmOT+AHLj+9gcVsY4qveeULWRp5PLjVSzPnGBVyhdWJpz5ZXKlvKssYjbrjrSQRQRXqRRqNwILMABVS0likt1ljYMpAKkdxWfeXWmTYDXXlzISdyuQcn1x/WuZLod6Np4oJL545doYsShIzn2qK7WOOMoB8x46VjWc+npu2XfnTMwO9nOcj0B/pWqT9quYkI6kZ+lFtbA3ZFzTIRDZgDuauEU5YwihVGAOlKVroUbKxwSlzSbIzfW7NtR9x9BWH4olafw/fxoeDCwH5USXP+mrbQoAFG9yP0FMuY2nt5oSfvKRXWoJGFzC8ONLbeFtPlmkwHiBJJ+7noPyraMDz2qiKWJMDg4rD0W4itNCmt7+RUt7dihLfwjOBVW6mWMxJp18hDZwN/H0rhqU5RlqehSqppWOi+ybIWMzROR3qqmqzQeINNgUjY6u8vrsGAP1P6Vz91rH9nW7G4mNxKfuxJ0J+tXtCtbhFm1PUWVru4Awo6RoOij2qqNNuV2RXq+7Y9BguoLkZhlVx7GpieK87tWmttZmAnkJdA6gN93n+VdTaancBQJgJB69DXQ6b6EAAcil3P/Z', + 'https://twentyhq.github.io/placeholder-images/people/image-69.png', linkedinUrl: '/in/richard-smith-37150fdba0', jobTitle: 'Administrator, arts', }, @@ -5695,7 +5695,7 @@ export const peopleDemo = [ city: 'Rodriguezstad', email: 'eric.hunter@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDq1YAU0sC1RjOKOlYmo6eWKGFpJHVEUZLE4Ark9Q8Xbcx6cilsf6yTp+A/xq7rFlLrV0lkJilunzSY7mprTwTp0K5Jd+P4jUOpZmsaTkrnEXHiLVkcu1/Id3UI+APpxVnT/Gmow485luIs8iQfPj6iu0l8HaSU+aFiR33Vi6h4TsDGRGjKegbPSl7RFOg0bum6paavB5ts+SPvIeq/WtFEry2yW+8OaoHUboweSD1H09K9PimEsSSL911DD6GrMWVRJKO9IZJD3qXHFMIJ6CmILMbrmQ9W4rZQHaAOa5a9uLq0SV7ZHZ2IA2Lk5xUmg3uq3L7L9dv7ssDjBHsR2Nc8lq2dtN+6kdHPnaRn8BWFfv2Gaxb7VNfF03kKZIVPRQMtziraXNzdZSeJkdeuR/nNTbqXfoZuqRxzBtxGVHFdHpEpfR7Unrsx+XFc9f27STgINxZcYFdDokkT2K2oz51uoWTjueePWt4S6HJUi9y1gU0gU/HFNK1ZkSWnls7RuAc+tPdraLz8NGm1McYHNVTwwYcHpWdezaPMSLiRd2MNtzk47HH8vesJJ81jtpNOCsammi3uEZT5bMAD2OabfmC1Q7VGcVm6ddadEPLstq88KAVP606++YksT171EtNDUzUzNI4yys3Cleo5610GixYimnfG+QhSR0OB1rI0i1+1X7gk+WEJIH14rpljCIFUYA6AVrTg/iOatUVuREYQdqClTAAD3oIAFb2OS5Vki3RsAcEjg1Tjt2lgAEghZeDjqa0jjNZ2pW5LI8bFGYHkdyP/ANdZVY6cx0UJtPlInX7KmTIrsT1rKuLgzHYjbmJ5PpUU9lqT3AikYeWx+8ver1vpRsztZst/KudnXdsuaCFgefJ5KAAfjW2kgc4rkZobqTUbEWePM+0IpHqpPzfpW7pWoRXM00X3XjYgAnqM8Guqi7zhrq0z/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-70.png', linkedinUrl: '/in/eric-hunter-5944420676', jobTitle: 'Osteopath', }, @@ -5705,7 +5705,7 @@ export const peopleDemo = [ city: 'Lake Katherine', email: 'cody.todd@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-71.png', linkedinUrl: '/in/cody-todd-e59e1908cb', jobTitle: 'Financial planner', }, @@ -5715,7 +5715,7 @@ export const peopleDemo = [ city: 'North Michael', email: 'nicole.patel@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-72.png', linkedinUrl: '/in/nicole-patel-d52be83244', jobTitle: 'Glass blower/designer', }, @@ -5725,7 +5725,7 @@ export const peopleDemo = [ city: 'Mitchellside', email: 'eric.rivera@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1qg4AJJwBySaWvL/i34rmsbePQbKRkkuF33Dqedh6L+Pf2+tDdgRq+IfinoWjhorN/wC0LkNt2xHai+5cjB/DNcq/xg1V5A0Wn2SIRwpZmP55Fc1o3gO/1GBLmeZYhJyqkZIHauih+FUbKokvGA7hBisJVl3N40JNbGnpnxeJkVdU0+NYycGS3c5X/gJ/xr020u4L60iurWVZYJV3I6ngivI5PhZa8lruYnpk9cVV0m+1L4ea9DbTTPNply/Qn5ffjsw604Vk3YU6Moq57bijFCsGQMOhGRS1uYBXz/4ml+3fEW/eflRc+UAewXA/pX0AcAEngV4dq9nFdfEuaWFg9tNMJkYdHBXnH4g1nUaSNKabZ3Gncxqo7DFbqEFRg5NefajealBI8dmk33SVEeBnA6k1H4evtea8hjvGmMUuGy/VfY+lcXJpc9Dm1sehydMEkVxnjKKJtMcyqGCEMp9DUPiy+1u1u5o7EyFIlBJTkn6evWst7i9vdDu7a7E3mJCX/eLyDjPXvTjHZkzlo0eqeFrprzwtps7klmgUNn1HH9K16yPC0K2/hXTIwQcW6kkHPJGT+prXrvR5zAruUqehGK8kn05bTU02qFFoSo4+8TkGvXK5TxNokj+dfweWEUeZIDndkdcVjWi2ro3oTUbp9SrYyRXUARlAPTkdai1K9sdOaMTSxxICMs2BznoKzbKZozgH3qO71C0uz5ctvJKyn+GEtg/XFciV2d99DXTUNN1HVZI47iOTKjcPQ9qTVIII7eSNVGWUisW2uNPsZCFiaJ2GMyRFN30zWoqz31zHFCpdzyBnFVyu9kS2ranVeGrcW2gW0Yzj5mGfcmtWorWEW1rFCvREC1LXdFWSR5k3eTYtRXUYls5oyMho2X8xU1Y3iXWhouliVNhuZ5UggV+hdjjOO4AyfwqiTzL7X9ncI77SOh9a2ogl1AFNx5YxxtPSsa+tDcREgfOjE1k7b2FtkZYHsM8Yrz1qeldo7BooreFgJ/MX/aPSt3wbb+f5t+xyF/doPfqT/IVwEVleyeX9omJ3nJQHt716D4J1G3lhvNMQbZ7Vldhn7yuOD+hFa0kucyryfIdXSUtSV1nEf//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-73.png', linkedinUrl: '/in/eric-rivera-17c826bef0', jobTitle: 'Teacher, primary school', }, @@ -5735,7 +5735,7 @@ export const peopleDemo = [ city: 'Nicholsview', email: 'amy.hall@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-74.png', linkedinUrl: '/in/amy-hall-5b6ee3fd83', jobTitle: 'Recycling officer', }, @@ -5745,7 +5745,7 @@ export const peopleDemo = [ city: 'Kaitlynton', email: 'randy.trujillo@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-75.png', linkedinUrl: '/in/randy-trujillo-c9c04e7445', jobTitle: 'Production engineer', }, @@ -5755,7 +5755,7 @@ export const peopleDemo = [ city: 'South Reneestad', email: 'ashley.conner@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDiKMgAknAHUmn4rF1+5eKKO3T/AJaZLe49K5lqzoeg6fX0VzHap5hH8bDimpqMyR+ZNdKf9lcA1k6dY3F/crDHG7k/wp0ru7X4dajdQKGMEO7+8uSKcnGO4RjKWqRyy628M+6SQvG3TgYrWhvI7jA+6xGQD3+lbE/wrnjgYrdq7Y6bcc1yF5p1zo8rW9w3lzL90n+IfWlzRlsNxlHVm9tNKBTbVxNbI4OciptlIYoUGuV1Vzc6tLH/AM88Iv8An8a6wAGueksnfxZEhQhZpFwex6U4ikrnpnhHRLbT7GN1RfOKjc5ruIE+QHhvpXD6jI9hbhVs3uCy5AzgcD+dWvD/ANpjkhKxSwrMAxVmJC57H0Nc1r+8zsTt7p2EgxGeAB715n8SNMin0trlQPNhYMGHp0Nb3i64nTI8mW4RDjZGep/yaxNRhNzoGoRC2eGSKFgy7tytxkEGnFWakTN3TicR4ZmZ7eaNjkKwI9s1unFYHhuF4oJnZSN5GPwrbLGt5bnNHYcK0bS1juY4JlGJbaTJOM8VnAVZtbyaxEskKq5KEbW6GpkroqErPU9GsZIbmBFdQTjvU9y8FvNAhZEBIySQO9YelSb4opV6OoOPrU+o6jpbyLHdQmeSM7tqoW2msEnsdi1NZWt7i/nj3xuuc8EHmqespAtjLbxKAZFKgAetVdP1HSRI6WsZhkbnDqVLf41W1q8FuvnMNxzhR70Wd7Cdkrs4qa0isZntoTuSI7Q3r71CalcszFmOSTkmo8V0HG2Shamjjz+NKsZJwBzWtBokt1aSxOzQvKhVT3X0P50yWy1YSG2tYk3EKBgMfatiK3iusOZ9voR1FUdP0wxabHbSEl412knuR3qMadclyIXKn61y31O2OiRozQxWaM/nbz/ebrXL6zePc3AT+FB+tbDWEsTZuJS7KM4rCWJ78XrxoTLby4IHdf8AEVpT1ZlVk7GcRSbalZCrYYEEdQaUAma1MD//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-76.png', linkedinUrl: '/in/ashley-conner-7e1f59d6d0', jobTitle: 'Chief Technology Officer', }, @@ -5765,7 +5765,7 @@ export const peopleDemo = [ city: 'Lisamouth', email: 'adriana.larsen@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-77.png', linkedinUrl: '/in/adriana-larsen-790fff0714', jobTitle: 'Financial manager', }, @@ -5775,7 +5775,7 @@ export const peopleDemo = [ city: 'Baileytown', email: 'lindsey.reid@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-78.png', linkedinUrl: '/in/lindsey-reid-9408f405f8', jobTitle: 'Geneticist, molecular', }, @@ -5785,7 +5785,7 @@ export const peopleDemo = [ city: 'Clarkton', email: 'sophia.collins@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-79.png', linkedinUrl: '/in/sophia-collins-65701c7f41', jobTitle: 'Proofreader', }, @@ -5795,7 +5795,7 @@ export const peopleDemo = [ city: 'Lake Robert', email: 'joshua.martin@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-80.png', linkedinUrl: '/in/joshua-martin-3db7199eeb', jobTitle: 'Diplomatic Services operational officer', }, @@ -5805,7 +5805,7 @@ export const peopleDemo = [ city: 'New Rebeccaside', email: 'james.adams@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDnAeaRmxz2oPWs7W7jyNNkA5aT5F/GpKMXV/EUzyNbWTbIwcNIOrfSsFy7EkoWPqa6Hw34Vm1oFzJ5UStjdjJPriu5g+GloWUtdSlQORgc1EqsU7GsKE5K6PIGPOVB+vrV6yvrmzlE9u7f7SngH2xXsE3w80cocQMD65rkvEHgYWtuz2Up+QE7X70lViypYeaVxdN1OPUrbzUG1hwy5zg1bzXG+HWltdY8lvuyoeP1rsTWhgK1ZOvLv0/ceQkisa1GNNazGoQ3FsTgtEzL9QMj+VDdlccU27I6PwhCiaTb4AUldwH15rs4S2BkfpXn32Flt7WTFy2YR5YhfaBhf5mt/wAOXN+giSeWYxScqs+C6exria6npwdvdOjkL7enHvXN64BLaShMF9p4FR66b65klZLi48iIEmKFgpfHYetZ9haGT5liuYWVQxEj5BBHf3otpcJS1sedaf8AvNcQ4KlHbI/CuoJotNCWTWdUv24WNiEAOOSMk0gOa64STPPqQcdX1ENT6dIItTt3PTeAfx4qA9KYRzx1qmrozi7NM9E0wRG0EEiqTGSuMelTsg/tGONF+6u4hRXPeG7t5Q3muWkDck9TV64u0a73PMIpAMfKSDiuJqzsetTkpJNGrYpHLLKrKNwOcHvTtQWOC2faApx2rLsruJJSsMyu55wSQasalNut2J/u5pDk7GBMxg0OdtygTyHAxz2H8hWBtq3cCcrH5hYoQSgJ4x7VWxjrXZTjZHm1qnO/QYabjmpdhre0HTopFaeQBnzhF9B61ZiVNKtL+KXzo4WCEEndxnHoK6G3a31GFXD4fHDDqParaAKysOi1n3OkFJ5JYC8ZJ3DYeGX/ABFYVY/aOvD1HH3S8UgtIzhgXx1PWsqW4N4CseWQfeb19hVoaRHPCC1xPKW6oeB+OK0bewSBUXYAF+6oHSsowcnobVKqWrKKadGLWKGVFcquDkd6z9U0i3jtDLGhRwR06EV03kg5YjrUZha4uDGo4VeT7s99z//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-81.png', linkedinUrl: '/in/james-adams-fade145464', jobTitle: 'Field trials officer', }, @@ -5815,7 +5815,7 @@ export const peopleDemo = [ city: 'New Kimberly', email: 'maureen.clay@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-82.png', linkedinUrl: '/in/maureen-clay-44447f851e', jobTitle: 'Ceramics designer', }, @@ -5825,7 +5825,7 @@ export const peopleDemo = [ city: 'Karenshire', email: 'brenda.moore@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDpMUopBWZ4h1M6RoV3eqMvGnyj3PAqCyprnjPStCkMEsjTXWMiGIZI+p6CuI1j4mancnyrKNbOP1zuf865GzgudUvWI3TXEjZJz1PqTXXRfDm6ubcNJMFm68c1Epxjuy4UpS2RRsPHuvWsu83ouU7xzqMH8etegaF430/WZEtZVNpeN0jc8Mf9k1wlz8PtStI2eKYOw/gK9fxrmbhXizHIpV0OMZ5Uj0NEZp7Mcqbj8SPoYimEVzvgnXTrWgoJpN13b/u5c9T6N+NdIRVmQYrg/ijqP2fSrSwGf9JkLN9F7fmR+Vd4K8y+LaAS6S4Y7sSDbjt8vNAx/wAPtJRbQXjgGWU8Z7CvU7eEhRlQK840uCK00GzMkNxLI0W5FjkKAYGeo711HhjULwBBNJcGKXlUuCGZPx/xrgmrtyPTpvlSidDLHuUjYD74rxLx5osun6pJMi5tZWLgj+EnqDXpvie7nlErJLc+TCCTFbuELY/U/SufltLfU9MljFtPE4TLLLIXDZHqe4zTg+T3gqLnXKcZ4A1B7LxZbR7sR3IMLjPB7j9RXtWK8K8FwP8A8JlYKyZCznr7A17rXajzGMU81j+KdDj1zSxGY1aaJw8THtzz+YrXU05uQRTFcoaDDF9jSCRVLRfJgjpitCeILqMESAZ646Vl2atb3soDdX4z3pbrUbc3m24RzIv90Hj8a89xak4nsU2pRTRqWcSS3U6MBuByM9DUesRQw2ThVAJHQDvVOyv7b7R5cCsrt6qaq+Kb82Gk3V3uG+JfkBGRu7frU2d7Dl7quzk4dAC+M9Ot7MMgtYzc3JJyAxPTI9cV6N2rB8HrJLoMN9cnfdXWZJZCME9gPoBW6xxXoQVonk1Jc0m0RrT6aBg0v0BJqiCrfwrFbvdInzpgnHcZploLfUFVmPz9M9xVbXo7mayiaNikSzDeB3GD/XFLb2cfmxysWVXGHKnHNcVdrn0PQwt1A0ZIrexQlWAI/i71j3ywX7xRXny2xbdz3I5FbMmnW6sNhZz1yxJxWbqtuJpI1A4Bxx1rJStK5vJc6aNaERLboINvlAfLt6YpGNNs9Nexsood7MwHO45681I0bAcivRUro8lqzP/Z', + 'https://twentyhq.github.io/placeholder-images/people/image-83.png', linkedinUrl: '/in/brenda-moore-431d562885', jobTitle: 'Therapist, nutritional', }, @@ -5835,7 +5835,7 @@ export const peopleDemo = [ city: 'Port Nicoleland', email: 'kathy.glover@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-84.png', linkedinUrl: '/in/kathy-glover-1481622628', jobTitle: 'IT consultant', }, @@ -5845,7 +5845,7 @@ export const peopleDemo = [ city: 'Port Gary', email: 'jeffrey.jones@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1OuQ8YfELT/CjpbBPtd84yYVcAIPVj2+lXvHOsHQ/CN9dRymOdl8qFh1DtwCPoMn8K+c7O2k1TUY4AxaSVvmYnJ9zUFJXOnvfip4nvLsSxXn2dAeIoYxt/HOSaif4j+J2u0uRqs2enlkAL/3z0rprP4b6dIiGRpOBzg9TWyngDRktjEYC+eQzHJBrJ1YnSsPMzfD3xbkigWDWYGuXL4WaIhTg/wB4dPx4r0/TNVttWgMtuWBU7WRxhlP+e4rzKf4baXtby5JYz1BB6GtX4czXFpqV9ol6uZrZMxSKeGTIzx6nINOFRSdkZ1KTgrs9FpKWitDI8z+NE0i6PpcSYKvcOSPUheOPxNeaeEiF1yIsuSTxXr3xO0VNasbCFJjHdJI5iyuVIwM59O1eeeEtL+z61OLhCZLfJA/rWc5KzRtThK6fQ9RtPuKD1q+33OtcleXUu3ZG0oB4/djDH/AVR0m8vBKZpZ7oRt/DKw+UA+lc6jpc7efWx2MwJQ84rnLYzp470qW3yDIXhl/2o9uefyqDxNqd2oeGB5AFUMWj+8c+lWfBUSLqbXV3NK32VSAZTuIZvlyCO2P51UI2kmZ1pXi0ej0UtFdRwGR4lgMlgk6rloWz7gEY/wAK4h7WKHVXuIwQXjVCD2wTXp7osiFHGVYYI9RXmU6XVvfXEF66NJHIyoyDAKA/L+OCM1hWjrzHXh6l1yPobVvEk8XzLyBj61HNHbRsVYJu6nPAA+tRRSOIdwPRc1mT31vcK0MrKDn7pUkmsoq51cyNG8S3kuLeRmjJZduMg5q9oMEY1pVQYXYWIHcgjH61xrtDDcxmOQtJjiPBH5V2nhGJnvrmd8kxxqo+p5/pVRi+dGVWS9mzrjSUppK6zzijrutWvh/R59SvCfKiAwqkbnJ6KM968+uNXTxOh1SC1ktUkA2JIQW443HHrXAeMfGd34svUZ0MFtEMRwB8gH+8fek8L+Jn0ydLW6bdascAn+DP9KmrBuOhrQlFS1O9stSwvkykLKnBB9K02jSWEbRGWxgE8ise7sbW9AmQkHsynkf4iq4sdYiX/R7qF0HQvkEVzKx23cS5dRNC25ygI+6F6133hrTpNP0hfPz9omPmSA9s9B+Ary6y1yPSddsbrWSJbcTBCVHCkg4b3APNex215bX1utxaTxzwt92SNgwP4itqcftHNiKjfukpphp5Ya1OY//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-85.png', linkedinUrl: '/in/jeffrey-jones-74128aa05c', jobTitle: 'Corporate treasurer', }, @@ -5855,7 +5855,7 @@ export const peopleDemo = [ city: 'Millerborough', email: 'dylan.ramirez@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-86.png', linkedinUrl: '/in/dylan-ramirez-de68206ac6', jobTitle: 'Textile designer', }, @@ -5865,7 +5865,7 @@ export const peopleDemo = [ city: 'Andrewburgh', email: 'derek.brown@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDecpFE0kjBEUZZj0ArhNX8bytMIdOQKpPDH7zD19h+tSfETV5ohDplu+1XXfNjqeflH04JribO0nnlypBbGSf8KynI0hG50dtfXNxIBJe/f6gL1/E5ovdQhRWS0eMXI/jlkI/LPFP0vRr2SXJtnbIxvA5/Ot5Phst6qtcu8QP8Irnclc6VTlY5yx8ZXlkV+0OGHAeNzuA9wfSu/tL6G+gSaFsowB+lZknwt0yOPiSU4Hc1j6ddTaF4iXR7pR9nYhYpf/Qc/wAq1hNN2RlUpNK7O0xShaUCnha2Oc8p8dFm8VXQkGGQrj02bRtrR8CRK94JJMOxbAzzVnxvoc97rU17bFZSEjDxBTlcD16fhWh8OdMjW0luTzLnAB7ZrnqSVnY66UHzK6PSLTy1UbY1A9hirRZGHB59K4/UrjUVkMMCShP7y4Az9TWJoVzrs99hzdLE55808qM9x2rBbXOt72PQ7hV8o5PXoK8y8Zqi3dpNtzKsmEPf1/pWn4x1HWbGc2tmruqRh2dOpycYHvWF5V1q8+ki53horobi4wfukn69KuC1TM6svdaO5jJaNWZcMQCR6Gnjig0hNdh5ot1bs2EhOwyyBpGABJA7DP5VV0+wh0y6uHtCRHNJv2EfdNXNUkubfS7m4s4lluIomdI2GQ5Azj8azNOv5Lq2jnlVUMyrIFXoARmuOrBxd+56NGqpxSe6OnSaK6j2soAxzkDBqCe5sdPBVpIogBueRyFUVFBsaME9RzgVm3ur6ZJE8UkfmBWySIWfn8BUR1N9C3fXFhd3dtieKQyR4wCD0qpLDb/a4o40AMZLg++CP61z0Vxpceob7eXLkY2sjLjPpmtyz3SXUjN1UAZ+taQXvoyrO1N3LxptOIppHFdh5hooOKw9QgZY/Pgx8jEYHQjNch4xv08QyraxSultEchkOCT3P5cV31pHbS6TALbHkeWFTHoBiufE6JHVhVdszbW/DoMyAZ+U57Vq7RPb+XHMIxjA29q5rVNMeNjIits7kHmsGTU7yKQpEz7em41zpHXzWOmvrMWxLSXAmC8jfWhpkDpa+ZKCHlO4g9h2rz7Ub69Gl3Vy8zZijJXHqBxXXeDvEDa9pIM+PtUIAkI/iBHDV00Y3bkcuJm3ZG8VphXip85D/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-87.png', linkedinUrl: '/in/derek-brown-0bd369600e', jobTitle: 'Maintenance engineer', }, @@ -5875,7 +5875,7 @@ export const peopleDemo = [ city: 'New Amandaville', email: 'nicole.robles@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-88.png', linkedinUrl: '/in/nicole-robles-dc92d47af5', jobTitle: 'Customer service manager', }, @@ -5885,7 +5885,7 @@ export const peopleDemo = [ city: 'West Bill', email: 'lauren.murray@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwCR6i6mpGpirk1mUOyFUsxwB3rFvfFCWsxgtoWkcHliOBVTV9Wd9QFpbbmK8BYxks1aFt8P9WFgt9clWnZ97Rk549DWE6r6HRCjpqSJqk88Adg8UuONw4qO38QmOcQ3gHPRhxWNqN7eQK1vPD5KjgADiuZmv234Yllz3rOm5t3uaTjFKzR67GyTIHjYMp6EVIsdefeH9fa0vEWR8wuQsgJ/Jq9HXBFdMZXRyyjysz2FVNQufsWnT3PdEJH17VdI4rE8VBv+EfmC9yAfpmnLYUdWhnw00xdS1i51WcbliwsYPPzEZJ/CvX3GYguRjpivI/CZm0nwnM8e9nkuWUGFgf4R3HXpXWeG72+ueLp3KGPeC/VT6GuGS1bPRhskWtc0K2vYZI5EViR6c14p4h0K40m+MbZMZPyMR1HpXo2t32pS3TzQtcPCnO2JsZ7VUvo01S3e3uI23Lxyc8+xpwbhqFRKeh5dFIyuB0PT8a9c8K351HQYHc5kjzG/4dP0xXkuoRSafeSQTqflPBx2rvPh1c7lvrcnJ+WQfyP9K61vc4pLSx1VVNTtDeaZPbqMs6YH1q6RxSqK0auZJ2dw+Hawnw0bZ1+ZJ3DA+vFb93cWNgZo2ZUcxkhQOorN0RIobmWKMbWY+aQO+eCan1LVLJW8prGW6dPvFI849s158k1No9Wl70U0Q6L5N1A7IyMODkcgg0zUEht1YCNcn0pmnarbtujhgeJv7rIR+tR358zJY1m73saWscbqemJc6jHO0YcyYTbjn60zwJGU8S6pGDlIkKZ+jAf41X13xU2mXMthBbZuGXKzFuFB9vUVtfD3THttKmvps+ddN1P90d/xOa66MXuzhryjayOj28UgXFTiMngDJp/2OUKGKgKTgEnvXScZk3l42k6hZX21miZjDLtGcKRnP4ECukMdrcwAvJ78Vm38LQaVeTuFdYYXfb6kDpVuPTjJploxf975S5YcZOBXHiElJM78LJ2sVJlitz+7bgVQupS64XnPerclnKjHeM1XaMjOR0rnudW55R4iiebxVNgEhdqj8q9o0y2SLSrVI12oIlwPwrz/APskJ4y+1XA8yyl5lTPIxj/61erpEuwbcYxxj0rvpNNKx5lZNSZ//9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-89.png', linkedinUrl: '/in/lauren-murray-f56eac5c8b', jobTitle: 'Theatre director', }, @@ -5895,7 +5895,7 @@ export const peopleDemo = [ city: 'Jesusmouth', email: 'vanessa.jones@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-90.png', linkedinUrl: '/in/vanessa-jones-83ad40ef01', jobTitle: 'Geophysical data processor', }, @@ -5905,7 +5905,7 @@ export const peopleDemo = [ city: 'Sandersland', email: 'joel.lopez@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-91.png', linkedinUrl: '/in/joel-lopez-6b55707c2c', jobTitle: 'Civil engineer, contracting', }, @@ -5915,7 +5915,7 @@ export const peopleDemo = [ city: 'North Reneechester', email: 'matthew.peterson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0ukpxpKgo4zxp4zbQ/wDQbBVe+Zcs7DKxA9D7mvLNQ8RapezFtQvpJSegLEJ+Q4FXNZaTUfEd8hZp7gysC8fRscfkKrjw3qoiIhtC6ngq5FQ5LqaRg3sZTXRnQmdWAHG9TuH41Se6azmWS2mdGTnCnH4g109t4H1WUM0nlwKR91Tk1R1HwfdWUTSMok29aFOI3Tn2N/wl8RrzT7hItQuJruzbqHILJ7gnn9a9otriK7to7iBw8Ui7lPqK+WBCY/njDHb2B6e1e2/CfXW1TQ57GVgZbRhtwP4G6frmrM2d+ajnYpbSsvVUYj8qlNJjI5oEeS+GLCOTU7q8ZdzkKOffkmuxEYHG0VzGoWl3p9/qq2zTL/pXyCFRkjaCOvYZqx4e1HUrn91d7shS25xg/Q+hrlmtbndSeiRvOpXPFZOpL+4f5QxweKxdXvtXN04jkm8hBkiIDLc9qs2Ut1L+7mEpwP8Alooz+Y61HLpc05tbHn19ahXllQALu+ZfrXa/Bu0ddY1ObcSqwKp98tkfyrF8Raey6gEgXPmjO0etd98L9KbT7XVGfbveVFIHVcLnH611QknY4qkGrndGgUGkFWZGDfQRR6jPkf63Ehz06Y/pVAGBPP2bFwMcYFaPiCNleCdemCh/n/jXIXU2nXGVeTBxhtmckehxXLNe80d9F3grGtaeRM5icLvxkZ5zT7lI7dCQB+FYdhc2VsRFAydeB0P5Vp3chZahqxrcxJ7I3OpJPliVRlVQccnofw5rvvCdrJb6W002PNnfcT64GM/zrjLa2ub3VLO3tiR5kwErAZ2xjlj+Qx+NenABQFUAAcADtW9GP2jkrzVuVDaSlorc5SrqVq15YSRJ/rMZT61xRgdotm4QlDgjHP0rvZJo4QN7AZ6Dua4HV3kvtWvmjYpJE4CgDgrtHX8c1jViviOnDzafKRtGsQ+ZkY+uKrS3TP8AIp3Mx/KqX2fUmkCy7TG3dT1rQtbMQDJ5Nc7sdN2x9t4hh8LOs01s04m+QlWCle/eu90rUotW0+K8hV0WQZ2P1X615xf6YNZuYbZuIkYSSH2Hb8a6zTr5dNlMe39y2AQvbHpXTRfn0P/Z', + 'https://twentyhq.github.io/placeholder-images/people/image-92.png', linkedinUrl: '/in/matthew-peterson-55c3973b59', jobTitle: 'Chief Marketing Officer', }, @@ -5925,7 +5925,7 @@ export const peopleDemo = [ city: 'West Sheilaview', email: 'elaine.gonzalez@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-93.png', linkedinUrl: '/in/elaine-gonzalez-cb7b12c50a', jobTitle: 'Psychologist, educational', }, @@ -5935,7 +5935,7 @@ export const peopleDemo = [ city: 'New Alexander', email: 'charles.jones@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDuzRS0VmWFcfrPxI0bSpnt4BJfTIcN5ONin03d/wAM1T8e6pf3FzB4b0qQJLcR77mQdUjzgDPbPNczF8MrjYpS/TpyPLqZVIx0bNI0pzV4o0P+Fvyljs0mIr6ecc/yrodD+JGkasyQ3GbKduzsCmf97t+IrAj+F9kIgXuZfNxyy8Vk6j8N57YNJZThioyN3BNSq8H1LeGqLoezAhgCpBB5BHelxXlvw48TTQX/APYF87EPnyd/8DDqv0NeqVqYDTRilIoApAcBYWxl8RazdyEvLJdtGCeyrwB9K662hbbn+VcRqwhTUr5Ga4YPcSMqQNjJ6k5rQ8L3dz58cCtN5LfMPO+8B71w1I3k5HpUZWionXGIgE5wKz7zHlMAQTjjFc7ryzPcuZI5plRSwCSEEgdgM9asadKZIY0FrcW5wDiTnI/xqOVWuaczvY4S43W/ia2vI/lljuI2xjGcNXuJryXWLCW48VQxxKSpeN3OOFUH5ifQV60rJIgdGDIwyGHQiu6nK8UedWi1JjaXGVI9RSUoqzI5Gwsrcb7aZAWjbBz61YtrnT7TUpUaRY9keVGKj1e3mtdWMykbJ+Rj2rPS7nkcoLHzMdS+0fiMmvPcWpNHrwkpxTRt211Y3uB/rFbgOUIAPocird1FBbwfIAOO1ZcV9M+IZrGQKx++mCF/XirN0PkwzcAVLVtCyhap+8knXaWJAZSMll/+tnNdRp0AttOghGcKnf8AOsbRLQ3IlZwBErDBHVvb/PrXR4rqw8GveZw4qomlBEVKKKUV0HGUtW086hZNGhAmX5oyfX0/GuZtkhbMd0WjkQ4ZTwQa7N5UhjaSRgqKMlicACvN9bvBqmq3klqxi8uQRlh3GBzWFeKtzHVhptPlOkaW3toMJLke5rPa6a8fy4mJH8TelY1rprtIDdXbTf7KnArc8600y05AX0A6muS2uh230uy/puu2djdppMiTCeT95v2/IAeBk59q6TORxXn9lHcarfiGNd00p69kX3r0qw0iCztVgBkYIOWY5Oa9CmmopM8qowAAUpto/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-94.png', linkedinUrl: '/in/charles-jones-dce2f7c6f3', jobTitle: 'Research officer, government', }, @@ -5945,7 +5945,7 @@ export const peopleDemo = [ city: 'New Melissa', email: 'rachel.barton@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDzliFBJIAHJJrJutUZn2WxwP7+Ksa5MYrZY1JHmHBI9KwY+XUHJGemaxjtc2k9bGjCm1jLOJAOu7rmmSzMw25LgcoSOldL4e8LXXiF/wDRnSK3Xgtjqa7WH4Vx+QUnuyzkcFVxiodaMXY0jQnJXPJYbr5Qm9kfPHvWta3azgo3Eq9R6+4rstR+FnlL5kF029R0IHNcA1jLp+stBdsEeJvzojUjPYJUpwWpq4op3Wgincmxka8xF1ErghNmR7nNSeHtMTVNUjgbOxjyB1xWnqmjy6nb+ZBgyQ5wmCS5PYfka0/hrpxa+upJlxJGoUA9iamU0qbtuaQpt1FdaM9U0SwtNNs47e1jWJFGMCt/HyjoT9a4fUbtrIMrWFxdNgkBTgDA7UaJ9tFyBGlxDHIocpJKXCg9ueh9q40tLne3rY7C4QmM5HbvXj/xIso40jvBGpcN5ZIHY8/0rs/Ft5ewt5Cx3Eicbhbtgn8a43xLaxzaBIscE0JinQSB33AnOMg9+tXTVpKRnVd4uJzViWayhZupWrB5oVAqgAYAGAKdiuq5xWN7QZ1g1WNXxtk+Xns3Y/n/ADrorHTotIvneEEeaFZ89zzzXFAnII6iui0HWLzUL67hvnRhFsERC4O0jv6muerF2ujroTXws9FtWhvIcSIM+9JPJaWrGCPYpA3MSQAKzrXeq5DHpxUd5e6LLH5V4qTsDll2FuaxjrodVi/dG3e/UO6OsiDvnmue8YLbJoU8CIBkqRj1yKdHc6KLofZyd5G1S+fyGayPFV24gWHP+sOD9B/9fFVFe+kRU0g7nGYxxRinlaULXWecWbaGS4nSGJd0jnaq+prX0FY5b6ZEYGVUAfH8ODwD79a2PCHh2Zp01K4TEa8wg9SfWuhuPDsNhfTajaxgLckNMB2bGM1NWL9m2iqMl7RJmdbXxhxFK+0qcc1q/Z0uowfNVOOCOorMv7JZc54PrWZ9mv7f5Um/djuTXEmejsad3bx2e6V5w+B95uwrhtWvzf3hcHKKNq/41o6ndTo1oJD5iy3CRkN0wah1fw7dWDPNFGXtfvAg5Kj0P09a6qUL+8cmIqO/KYmKUClxT3NanOf/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-95.png', linkedinUrl: '/in/rachel-barton-3d81266f5e', jobTitle: 'Cartographer', }, @@ -5955,7 +5955,7 @@ export const peopleDemo = [ city: 'Lake Curtishaven', email: 'alyssa.ellis@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDpgwC88Vian4ltrDzEiKyTAcc8fX6VW8TXoH+ihiEQb5AGwWOOB/WuJtdl40lxKFWJztwGwMDsD+Nc7Zuoj9U8WXV1PHELl3/2FO0H64qsvivU4ZUla82x/wAITluOxp0eiDV7wi1UbmUAbOFUVsx/De5CxhmVgOeuMVLnFaMtUpS1RteH/Gh1FB9sUfNwHRSOfeuoEquu5DkHvXCSeDr/AERDLaN5sZHMfp9DUvh3xCyaoNOu8oxXndxhs0KSewpU3Hc7YHmrcOCOlVgtWYeKpGZ5v4pKnVL92fhnK4+gArk7SO61a/js4dscfTjoK6X4go1rr0ThSIJk35xxu6H+X60z4f2RnuJp3AxAMAe5rOTsmzemuZpHceHPD8WkQ4XDyscluw9q6cYK44zXGapqU0AMCwXcpIOBCCoH4+tUvDjakbrJ+1RQOQSszliB6exrFbXOvrY7yZN0Z/ka8v8AHFksGpWd/FGBIX2SY4yByD+ldF4t1DUbSURWomMYXczQ/e+grm9U36xo1ttW582K4VWWf7wJyOvpyKqO9zOp8LR39q3m2kMmc7kU/mKtoOKrW0Rit4o8AbUC4H0q6gGK6EcLOf8AEGnpcNI92Wls1h+WEc/Pn09TVXQdIXR451T7s0nmKD1UEZwf1rprm3WeLYwyPSsazv7e9aY25LJHIYy2MfMOo/A1zTTTfZnoUpxlFd0bUAhmjxIq/iKqajfWWnId5WKNRkvtOM/QUqA84POOKpS6jLGDGNOmkwfvNgA/TJrOOuhvbsTvfadc3FuvmpJvj5U9/en3FpbSMkCoApYN8vsc1jLeKlwFk0qSAP1YAHn8K3NORnvPn52rkVpFPmSIqpRg7lsJg1ZiiyKUxgHNSoMdK60jymyktZM+nRWM00luu37TIZnUdN2ACfxxWyBVfUBmRIyMMmcg9s4rGppBm9HWojMWc8AnBq2vkSqVdyBjGM1VuLZiCQO1ZMryIcFW4rjTseha5sTW9tb5aKXJ9Cav6ZG6xNM/G/7v0rnYYZZAJHyF6jJrq7Y5gh9NoAIrpoWcrnNim1GxLuJqxHyKhYg4D//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-96.png', linkedinUrl: '/in/alyssa-ellis-c173bc4670', jobTitle: 'Sales promotion account executive', }, @@ -5965,7 +5965,7 @@ export const peopleDemo = [ city: 'East Ricardo', email: 'patricia.lopez@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-97.png', linkedinUrl: '/in/patricia-lopez-149ef1e411', jobTitle: 'Consulting civil engineer', }, @@ -5975,7 +5975,7 @@ export const peopleDemo = [ city: 'North Kristen', email: 'scott.moran@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-98.png', linkedinUrl: '/in/scott-moran-6acf4736cf', jobTitle: 'Heritage manager', }, @@ -5985,7 +5985,7 @@ export const peopleDemo = [ city: 'New Williamshire', email: 'jerome.morris@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1LFGKdikpiMXxF4jsPDVh9pvpMbuEjU/M59AK8c174ma3qsjxW8osLdvlCRfeIPq3+GK0dYs7vx144ulmfy7OzcxDb1CqSOPcnJrrbPwJosGH+xhzjGXOc1hUrqLsdVLDymrnh5v7qOaJ/tUu6N8od5+TvkeldNpvxL8SWd/HPNqMl1DGcGGUjay+/evR7rwJoU3J09AR3UkVyeveA7RYXNmpjcDK5PH0qVXiypYWSPVfDvibTfE2npdWUy7yP3kBYb4z6Ef1rZxXyzo2oXfhrXrS9j3p5Ew37Twy5+ZT9RmvqWGVLiCOaM5jkUOp9QRkV0p3ORqw+joM0uKXGeKBHmPg/E8+pXYUDz7t2x6c/wD167hchAMV579gvdJS/trJ5SBezbDHjOB7n8q2fDF/ql1Hsvy4O0lWYYP0NedNe82erSfupHSSlgCCPpWFqQyuB15rD1e8143UzQTyeTFlsRgZYZxgetS2c15cACZZgwGT5ij+lLl6luWtjybXpPLvZ45EILMcj0NfQ/geSabwRo8lwSXa2Xqc8dB+mK8d8Q+HpdX8UGC2wDIiu7Ht2zXtnhZYU8L6dFAGEcMIiw3UFeD+ortpST0POqwau+hsUCilrUwMGS2jTULpGUYd/M5HXIqAiFJZFQxqEU9MDmrWun7O6XGD9wg4745rhpbn+1T5zOIgy7fkRs469QK8+pF87R61CV6atudJYLBO7I20seeec0+9SK2jO0AfSuR0+8k0oeVGiugfj5GB/lWxqF4ZQFztLLk57cVDWppexl28An1G7mVMOAsayDqMc8fiRXpmm25tdNghYYZV+Ye55P8AOuK8D6fJNqM18xzbopAB/icng/gAfzr0CuyjC3vHn4irf3EFFFFbnKUNYsnvtNkjhIE4G6MnpnHT8a42TFzp8YFw1rOg2kAcgjggivQHkSJSzsFX1JrgvEljDqmoTy2sjxSKyhmU43EAdRXPiIrSR14Wck3FFG/vYbOxMccwlmZSu4jFYi3T6iyQQSl2bmRx0UfWnJ4avZpmS7lZk/u9ARW/pukxWMRCoB+FcrklsddpSepseGtS0/TYvsVxcxwTTSgRK/G/gDAPrXXV5tJp6XupRmRcxwMJAfRh0rrrLWRHGsV3njgSdcj3rsoSvBXODMRG03Y//9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-99.png', linkedinUrl: '/in/jerome-morris-c94af1fc97', jobTitle: 'Systems analyst', }, @@ -5995,7 +5995,7 @@ export const peopleDemo = [ city: 'Deckerfort', email: 'christopher.davis@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDvaKXFJUFmL4j8QwaBZCRgHuJMiGL+8e5PsK8zvvEmsa5cZacrCOkKcJ+Pr+NdB46tZ7vxRYQwvudkAVMcIMnLH9f0p1p4KliYyRzoC3YLisp1EnZm1Ok5K6ORNxPLuinVkU8FFPT6etOt7rUrAGS2klOw5DDOfzr0ex8HWcK7rn97J6dhWpJpNlFC6RwIN3U4rN1V0NVh31OF0/4oXFuGXUrcTbcAFPkb8e1ej6Zqdpq9il3ZTLLE3dT0PofevHtX8P8A2bUpg6Dy5Mjd+v8AStL4e30um+IPsSyk2V0SoTHAYDgj34xW8XdXOaUbOx6zRilNHSqIOa1K13eJPNK5PkLg/ia1IU2IOawfGM0hgtrq2kuI+GX90vzN6cH8ap+GtTv7uN47nd8se7ewwce4rjqx95s9HDy91ROyUcH5uarXLEIVXk964LU9R1pLrAubjyCRgQIDn05rX07VL0OsNzHLIOn3fmH17VHLpc05ruwzWIknh2lgDuw30rH0DTjB4m09TGcGTfnPTHOf0rb1SGe9kiCIIFc4Jc5JP0H+NLo1idM1uxuL13l8wtEjqMIrEcDHXp3reE0rJnNOlKTdjt6BRQK6DkMjVYlMkUZVShVsZ7HNVdNgt4I7h98fPGM46Vd16Mm2jkXqrY49xXF3l1pWfKmuSgJ+aNQSGx2+tcdVPnZ6OHa9mjpFt7aW4+zfuwyKNpHp6VdWCK2U4GTjFYdjfaa0EcNofL5+TMZXn8a2m+VBuPzY5FZvQ20KznEgZgDg5o0ix/08Mo/c587yyc7W5/nmq1yzSFljcqwGQw7V0ml2xgsYy/MsgDOfc1pRhzP0Ma1Xki+7LGKMU6iu080gu7YXVrJDnBYcH0PauT+wzq23csTrwwNbet+KNJ8Pp/ptyPOYZSBPmkb8O31NcgviBvETXF8im2WIxoEByQrbhknvkgCsa1O65l0OnDVeSXL3Oijj2W+JnRvU1XmvCx2qQze1Yoe+dwhfcnTj0rRhtfJAYnk9jXGzuvcnt4SqtuO53rd0bUjdG7s5mBubOUxtjuvY/wBPwqtp8C21pJq11gW8ALKD/GR3+grzeTV7u3vpb63naGeR2csp9TnHvXZh4NLmfU4MVNOSiuh//9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-100.png', linkedinUrl: '/in/christopher-davis-4820898e5c', jobTitle: 'Building control surveyor', }, @@ -6005,7 +6005,7 @@ export const peopleDemo = [ city: 'Port Gabrielle', email: 'jessica.downs@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-1.png', linkedinUrl: '/in/jessica-downs-9f35d94f5c', jobTitle: 'Solicitor', }, @@ -6015,7 +6015,7 @@ export const peopleDemo = [ city: 'Tonytown', email: 'eric.jenkins@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0bNIWpua4z4j61JpugLbQOVlu2KEg4IQDn+YFJ6DWpJrXxI0rTJnt7UfbJk4YqwCA+m7v+FcnN8XtSDlU062Udidx/rWT4c8JNqIW5uspEeVUdT712MfgrSQD+4O7HUnNc8qyTsdEcO2rlXSPiyHkWPV7EIrdJrYkj8j/AI16HZX9tqVol1ZzLNC4+V1P+ea83uvh3p8iHy5JEI6Y7VF4PN/4W8WJpVy5exvsqjfw7wMg+x4xVwqqTsTOjKKuerA07NMzSg1qYkVeZfEIG+8T2FkQWSOIMFHdmJ/wFelu4jjZ26KCTXnGol77xfaX5iKRyw/IM5xtH/16zqSSRrSg5O/Q3LJEgijj4G0AVrJnaCOR7VxurQszEulzKoG4RwnH+TSaCLyC8UG4uRC6g+XK2dvt9a4uXS53qWtjsnLbfT61zOrv5dxZzjGYLqN8+nzAH+dVvFU9083lxvceXHhmMB+Y/T1rOihmms7hfNuGQKCUnAyDkHIPeqgrWkTUd04nrR60uar21yt1bRzopCuMgGpc13nmtW0GOokjZD0YEGuKlh8m6j3qR5bGNOe2K7WsXWrFBA1wGI2uG249eKwrQ5lddDooVOW8X1GxRRSxDgE+4qpOYI5vKQoGGATwOfT3ohkIjyCc7cjFZF3NBctsmViVORtiJx7g1yRV9Dvua1ykS6gBIU2uB3zg0l3DFHFsAGW9Kw0MMdzuEhLldv7wEZHsTW5BD9ruoInJwSCfp1quV3sTKSSdzpLOPybOGMHO1AP0qfNMUBVCjoBilr0EeW3d3EFV9TiL6XcZxwmcE8+tXobWS4+6ML3Y1V8Uafex2yz2q7rdgFuMdVA6H6ev0qKjtFlUleSRyClozsc4BHB9atDEkWzzAuRgMO1SSWouIAOhA4rNOn3iZ8qRWx0VuCK4ItHou62JpIhCuGkDn1Nafh+MSvJOTnYNij61z62Vy82LhgCeSF7CtLQ/tK+LLaC3yYJEZZk7bACQfqDj861ptKaMqqlKDOsNGa0/7MRlBG4H61Xl06VAdh3+3Q12nAf/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-2.png', linkedinUrl: '/in/eric-jenkins-aad0386096', jobTitle: 'International aid/development worker', }, @@ -6025,7 +6025,7 @@ export const peopleDemo = [ city: 'South Tammy', email: 'christy.ramsey@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD080hpaz9cv20vRL2+UKWgiZxuOBkUxGR4t8ZWPhe0wzLNfPxHbK3zfVvQV5Td/EnxNd7vLvFtj0/cxDC59zVXwzoVx4x1O4vLuaXymfMsrHJdvQV69pngrRrOxESWaMv+3yTWMqqTsdEKLaueNW3jnxFYzE2urTykHkStvB/A16H4V+K1vfyLaa6kdnMeEuEz5bH0I/h/lWxfeANAuUbNggJ7qSDXmXizwP8A2Okk9j5rwjllIzgfWpjWV7DlQaVz38EMoIOQehFKK80+EniltR0x9FvbgNdWvMAb7zRfXvg/pXpddCOYK82+MeoXdn4ftIYXK29zKUmx/FgZAPt1P4V6TXnHxktLi58M2jxRlo4bndIR2+UgUnsNbjvAlolvoVsqKAWG8/jXeLxGADnHavNLh30/SbWJbe5l3QLxCxXGFz19at+EbnUpLqOGR7kwSfMPPOSvsa4Wup6S6I7+QkqRmuZ11N9pMoGSykfWsDxVc6il5Jsa7aCPnbbtjPP60/S7ia4xE1vcxADlZTuByOufWlbS4762OA8EyCz+I+nlSR+/KFQOuQRX0XXz7oVrJafFGBwj+VHeHLAE8c/419BV3Qd0edNWYVm69YRanotzazDKsu4fUcitGkdQ6MrdCMGm1dWJi7O5zOlmGSzW3nVSUG0hvarUD2kOppHHsRE5J4GTWbd2hsdRaNHYqcMCetZ17e6PKQs6StOgI8yNDlc9ea4bNOx6kWpK6N+A2k9zJDLsYsSVPBB5pt/9ns4SI1AyOMVg6ffaNETFbLJFKxz88ZBY+uavTh7mRFzlicAVNug3oReHNIhfVmnlTdlvPAPZumfp0ruRVHTrFbKADJaQgbmP8qu13U4uMbM86rNTldBRUnkyE4xSi3fIzV3M7HMeJyq/Z5EILjIbB5xWQkAvolYXQiwOCOv0qabQrjTdb1AzuXiuJTJb+gQ8kfXJP6VlX9jLAxa3kKEnPtXFUleZ6FH3YKxeMC2iMWuBIx/iPWrOht9o1mEZyqKzfXj/AOvWHa2dxKS1zJu9hS3Ek9pqWlfZ9waS7SP5ff19qUH7yY6l3FnplFKwKnBHSkrvPAAAAAAAA80//9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-3.png', linkedinUrl: '/in/christy-ramsey-5a861e76c3', jobTitle: 'Pharmacist, hospital', }, @@ -6035,7 +6035,7 @@ export const peopleDemo = [ city: 'Lake Sarah', email: 'sarah.evans@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-4.png', linkedinUrl: '/in/sarah-evans-f7501659e6', jobTitle: 'Exhibitions officer, museum/gallery', }, @@ -6045,7 +6045,7 @@ export const peopleDemo = [ city: 'Gordonview', email: 'stanley.thomas@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDmcUmKdtoxUjGsyojO7AKoySewrnrnxSMstjBux/y0k6flWhrHn3Cw6barma7baT/dXua1R8MQVge3uy3A8xX/AKVE6kYO0jSFKc1eKOJk1/UmP/H2U/3VA/pTrfxJqVu+HmEwJ6SLn9a9ZHw+0VrNYpYWZwOZFODWLffDvS8HypZo8dO/PvWX1mBt9UqHP6f4jtb+QQyDyJicAE5U/Q1rFea8/wBU0uTTNRlgDb9h4PrXX+HLxr3TdkpzNCdrepHY/wCfSuhNNXRzNNOzNPFNIqXFMYUCDR7cz+JvNIyIYAF+rE5/lXpMEZVBz27V5ZPDIMzI9yCcKBbnBJGSP5103he71aUi3uJWKGMuHk+8B/te9cFeN5OVz08NK0FGx2LgqhOcVj6g3yFVPNcbrR1aW9fM17NCpz5cT7c89q0NNiuI28lRchR1WVt35GsnBWvc3U3zWscH4ky144kyGBOcjmpvBCH7RegfdCL/ADNafjmz3XNq0CsZnJU4HJParHhjQ7rSzcPdtH5k6qQiZO0DPU9PyrupTXIrnnVqUud26Fymmn4ppFbnMbegwwzwSRyqDls5NbMNxp1mt2fPijKAKcnGPrXIQ6iNNhlkYEgDcAO5HasqGK712U6gcgyDlFRsbR06VwVKbc3c9SjP93FRV2ekWkun3z7FaJzgEOvKn8amuRBaoREgyfSuHtdYutKiW3ni3IX++IyOfc+tb11qAI45bb0zWUoWNudP1MLUliuNdsUcMSHZsr24NbEm2MqCSdo2qT6VzCXLR6rJc5DOiF8EZ4rYgkuZ7aGS6AE7IC6jopPYVtRp3kvI5q1a0GurKVJinYpK7jzirfwST2ciwnEuMpnufSi2lhuoIP8ATJbZkQFlTjOOMVa4AJPAHesPVbdLsg2++GVwSCp4fGM5FY1Yp6s3ozcXZHQ6nrdkmmtaws0hdSGZ+9cuusvKR5MrM5AG0HmootDvrv77uV9mABra0rw4sUoLoFVfSue9OKOm1Sb1GQ282naXc30wVpiN+D0wOcVuaddSX2nw3MsYjeRQxUds1Ne2yz24tgv7s8MPb0pq/uXCqPl6ba0w8m02+pliogCTUV0P/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-5.png', linkedinUrl: '/in/stanley-thomas-76273965ad', jobTitle: 'Production assistant, television', }, @@ -6055,7 +6055,7 @@ export const peopleDemo = [ city: 'Morganbury', email: 'hannah.watts@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-6.png', linkedinUrl: '/in/hannah-watts-a4b37f2ae2', jobTitle: 'Learning mentor', }, @@ -6065,7 +6065,7 @@ export const peopleDemo = [ city: 'Christensenville', email: 'michael.maldonado@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-7.png', linkedinUrl: '/in/michael-maldonado-94c0630389', jobTitle: 'Drilling engineer', }, @@ -6075,7 +6075,7 @@ export const peopleDemo = [ city: 'New Raymond', email: 'joseph.nguyen@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-8.png', linkedinUrl: '/in/joseph-nguyen-3f0a744a58', jobTitle: 'Chartered management accountant', }, @@ -6085,7 +6085,7 @@ export const peopleDemo = [ city: 'North Julieberg', email: 'erin.garcia@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDnfmdtqjLelVby9uYSLeCT5zx1AP5ZqxMxjgkYOVG3GR6+lN0hRbO0+I4yefMIyVHfHqa4JzvLU76cLLQxr+7uY2WKcF5QOT0IqOzuLiRBJhBEOgIzk/TvXSaZ4bl1rUprjzB5eeN2Tmta++HitAfJmdX64BwKXNG1i/Zyvc5uK+adNpjICjlwM0kVzvcqVYDsTV2Tw5faPF+7bcv8ak5yK5d5nt9Tzh8A8jNEHrdE1ItK0joSfQ05c1FGwkQODkHvUimuu5yWASoN6SMDhjhc8D3NPiR9X1FLaFsRJgHA6mjUNLkbdPCMs2TtA/hGOT+Na3gHTv39zO3JBwM+prikkrnfBN2Oz0XS49MttgbLE5ZjWm5AweD9K53WNQewiYfYJbnOcfLkCs7QvtUl4P3ckKuAzLv3KoPbrwanl0ubc2tjo7+1WeFlYZB/nXl/ivTIbVTOoxIXwSp6mur8X399BcG1gSVkBBbyzgnP9K5XVtlzpq7LZoTHMsb5OQx5Gc9+vWqhHVMirJWaKeno0dmoYnceTVsU1F2qF7DipFFdi0POep11iFuI57ccOwABHXaSM1f0+xj0yWUQZCO+7BHTiuaguZYJxLE+2Rfumt3QdRudTsEuLwKsshOVUYCkHBH6Vy1oNO534eonFR6o6lfLuYfmVT7GoNtvbyGJFUORubHGKjjJQHaeg6VSvrvRRbsl/NC7Mcsh5JPpislrodNkN1GKJtUQuVZZU9c8isDxLFb/AGL7OiYAcNx6g083mlPfAWtz5kuOASePpmqGsSM0gUn3NXBe+kZVmlTbMUrT1HNOxSgc12nlmtZ2VxcBpY4WaNDhn/hX6mt7S4o3tW8kgruJBU8Enr+tdb4b8Ni10We1vVDG65df7vHA+orMOkSaNObZsmPH7uT+8P8AGscSmonRhLOT1KcV3hvKYgN05qeW1SeEhSgOMBsVXvNPjuCSCVfsayrmPUrSPiUFPc1xp2Z6F7CXlitnJ5zOpK9OK527mNxcM56dqnv9Rmjkgec+ZGZVVx22k4JrQ1Pw1d2paeBDLAeQF5ZR7jvXXRjf3jixVR/CYO2lVaUK3pUscZJroAAAAAAADjP/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-9.png', linkedinUrl: '/in/erin-garcia-f9967e5d34', jobTitle: 'Science writer', }, @@ -6095,7 +6095,7 @@ export const peopleDemo = [ city: 'Heatherside', email: 'eric.howell@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwCbrSbacBWfrl9Jpuky3EShpAQq56AnvWdy7EOpa/aaadmTLNnGxO31rKl8VyZOCE3J8ny5APvS+FvCB1tn1C+nkERbgDgu3c/SvQbTwJo8Y3lS5/2mzWbnrY3jSbVzhNO8WfKI7zYrkkZrastZs79/LjYq+cYOOa6m58A6HPGSLZQQOqnFcZrvhFNCkS/04yNApAliJyR/tCl7TUbo6XNry/apESqWi6nFqtpvU/vYztlTuprVC1pcwM/FY3iPDWcKN9wyZP4Dit3FZOuW5mS1jHRpdv5ikxxV2dHoUSR2MUaAhAo6V00Owxgq+T7mvNdVvLuydraCWeKMLgCBNzH3qTwpdaxcarFbzyXBgY53SjB6cZ/wrnt1O5dj00FWTG7B74NYutbTZyIRlSCDxXHeKrvV7XVWgt5LnyV5Jh6n6CtHR7q7uCttO00kbLk+em1hmk+4/I5vw1EYPE+oQpxFszx9Riu0VeK5zRLGW21++Mq7QMxqzfxc8Y9eBXUAcV0xd0cMk0zLqleqscsVxjLFlT6AHJNXKjnBNtKoXduU/hSmroqlJRlqbtpBZXkGbhVyeOarw6jpVpq0UQkhiRCdq5wWx1P0rAW8lFq0iP8AdUMQOwrKuZItT8sm2uTsGAVt24/HFYJXO1PTQ7yW/wBKuLuRZJIZkL7W2kHYe2R2q7NDbW6qYORjjmuCtLmPTreVTaXJWRcOTbNz75roLedxa2vz7lcHDHrjtmk0NvuNt4DJPJNIoKiUyxuOx5Uj+taK9Kp2kzfZEQoFGcgg9R/SrKOMVvTjZanFWmpNW6GVT0GTSYpJ2khs55oo97xxs6r6kDgVoYmTIIYrw20rbI2YjnuD0/WtKSOREGydY+B8xJFYhM2oadHcXEKpcMgkKr/CTzWdc65dwoILiPjGPM/l9K59GzsTcbHcW0ksdspMqSsSBxk/nms9S6TfZElBf7vI5C9z7Vj6brE9xDstoW3jqewrotLs3jid5B++l5LHqTS0iP3pk4wqgDoKerVQ0s6hPBL9tgVJYpmiyhyHA6MPr/SrmGU4IwfQ160Z/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-10.png', linkedinUrl: '/in/eric-howell-cfccf703d3', jobTitle: 'Merchandiser, retail', }, @@ -6105,7 +6105,7 @@ export const peopleDemo = [ city: 'Jameshaven', email: 'alexandra.atkins@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-11.png', linkedinUrl: '/in/alexandra-atkins-5fe1b160c9', jobTitle: 'Media planner', }, @@ -6115,7 +6115,7 @@ export const peopleDemo = [ city: 'Lake Alexandra', email: 'raymond.mcdonald@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwCQikxUhFQXc6WlpLcPysaliPWvHPSM/VtZttHhDTZaRvuxr1P+Ari9Q8b3d0ojhxajPVeWP4mqN2154i1VvLBZpD8oX0/wq8PhzrBi3sIQ3YEmuyEKcF725ztzl8OxUi8TasDhtTkDDkcAj8eK6fRPGK3BEGohEboJlPyn6+lcveeCdXtYxkK4HXaelYkkU1g4WRSpBwR61bhTmrIm9SG57eMMAQQQehFBSuB8A63I13JpcrloipeHcc7SOoHtivQ8Vxzg4SszohJSVwxXN+NmlXw+wiJAMihwO454rpazPEFib/RLmBQC+Ny5OMY56/TNKDtJDkrqxT+HOmxCxN68amd2wDjoBXe3GcKCAfavPI0bT/DdlCvnnMecQcZPJJzTtA1G/kuEgeWdo2GVEvLDjOK2km7sqDSsjq9RjZU2gDJHIrzLxPpkckMjbcMMnir+sX95c3DM010YkONtvweOOapNmV2QebgfeSTk/nSjFx95DnJSvFnNeFJWg8U6fjvMEP0PFe1Y4ryHwzpznxfas2FSK4OST3GcCvYNtPEtOSMKKaTuR0jRLMhik+442t9DS9qBzWBqPsoNtktpNhXjUA5xgEVHYjTreac74lCAgEnBY45I705zJJvIxvbJNZV1cWc1kkZ0y4kCAgShB0zyQc55rRXZsrW0KVtFbzXrpvUF8shUg555zTL+3gtgUQZY9TVKC7tra4McFpLCxbgMvT6mnXkjSMxJ5HWhp3Ai8P2CnXA+0lfM87J9QP5dK7oms7SdP+xWys2TK6gkEfd9q0amTuzFtdCI00daz5tVzgQxg5OAWNUBqFzLcyK8hEaf3OAT6VtHDze+hk60Ua090v2g2sRLTiIyFR/dyB+fNMmexmtBHLNIpGPkzjBqhpTqni2MSnm4tXRSfUEHH5A1Z1/SllVnjwsgPWpnHklY1pTco3MW9ktrZf3TliDxk5NZV1evFC04AbygZMN0JHODUjWkqvhiSaqasVi02WPuykZoVrlSbs2d5oWtR67pcd4i7GPEiZztatPOa8g0DXbrQYnMO1oyAXjbocV32j+LtP1MKkh+zTn+FzwfoaqrQlF3Wxz06qas9z//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-12.png', linkedinUrl: '/in/raymond-mcdonald-68f29c3dc8', jobTitle: 'Multimedia specialist', }, @@ -6125,7 +6125,7 @@ export const peopleDemo = [ city: 'Karlaburgh', email: 'joseph.barrett@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwCZRzUzDimBfmqDULg29sSudzcA+nvTbElcgvNcgspfJVTLKOoHRfrWLN4mvVlLKy7T0AHSum8OeHLYWguL9DJPLzyfuA/1rWfwppOBsjI5z1rB1DqjQ0PPE8WagsoO4vjquMg102ma3FqQ2Mvlz45Q/wBK3h4Y0mPlbdcjuax/EWkxSQrc2kYjubcbl28bgOxojUCVDQslM0LHik0m4+32xZk2uvDDOfxq/wCRmtzm2M1eWrK1pz9ptkyNvVh7ZrWRctVHU7ZZ7y1CkEA7GKnO0kjAPpUTdkVTTbOks23Ii8jAq+NgHD5/GuL1q7vbctb2nn5CkgRDk496peHLzV7nUIbe6abYxzl8ZHsa5LaXPQT1sd/LtKfe59M1iX8phD9xjmuY8Q3+sW+oTQWjS7IuT5eMn6VNpN3d3G2C6WbkZIlHI/GhLqDfQ0fCu6a8vePkAAB9s8V1iW4Irl/CrRWU00UpIa4m8uLjrjJrtFTiuyDTR584tPU5aJPmNRyxeXMPLjXDsJZHI7rjA/QVdVBupZYneFljClmGPmOKmpHmWhdGajLXqSx+TdKUZBkjBJHWo4Vsba/VVZE2n5mOBz6VXtZAkZyfnAxWLqE+m3iquR5qE4cAkgnryOlcqWp3p6aGyy2VzqcqsUYOcqeD+FJdRQWvCLyBxXPWE1jZudjhpHYElgVYn8etbVy5kYY5YjpTtqJuyH6JbmTVIyeY0Pmqccg4II9+v612CisvSdNexVjKUMhGPlzgD8a1lFdNOLS1OGtNSlp0MHZzUiLTiBmpIk3yKo6k4rQxOdvw0NzIFO1WJ59KcYJHtgsUixAAYNNinOq2zXJj2B2fCnthiv8ASqF/Bd2oV4yXiI6A8iuR/Ez0INpIsPBIkZE5SXPTvUlj+9v7ZDz+8XP51jWv2i4kbOQO5rRSb+zYjdBc+T8/PfFC0YSbkmd7nmpFNVBLlQ3qM09Zq6zzz//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-13.png', linkedinUrl: '/in/joseph-barrett-942d11d82f', jobTitle: 'Geophysical data processor', }, @@ -6135,7 +6135,7 @@ export const peopleDemo = [ city: 'Parkerview', email: 'lisa.salazar@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDYIDDjpTNu01LFEcdabIhFYgIQFUueAKxb3WwsZ8iPec4UevvR4g1P7LBHbhiGlPO0c49PxroNC8FgwLcag2ZXQgRj+AHtnualyd7I2hTurs5CLU57sY/tGIAfwDK/zq3FdyI4SQuD6S8g/QiuivfhvpckbGPzRJ2Ibp+FcZPp9xo15Jp1xIzQupaIt/Aw9Pas3ubctkb8WoCIkFeB/D3FattLFdRb42z6+orgrS9d1MLNieMnbk/p9DWlp+q+RcJOhIjc7ZFPY/8A1qak1uZSgnsdJbtIH56VcfaV560BQi4xTJR+7OeM1uYHI2kI1j4iw20g3RwYkI9dvP8APFewRnaoGRmvEo9SOneIdUnitHupjGURYyQR8w54r0LwpJqEtvGl2rL5kXmrucsV9jnkH2rn8ztja1jrGbjqK4Px9pL3VgtzAMTQnP1HeqmujVYdYhMUdxcJI3UyERoM46CtWKW5uw9tPauhT5Sytujf3BpPa5dtbHjr3jwTiRxg/df39DV63vgzvzlZD8317Go/E1k1nfXMDrhMkqcdAawLSdkcIT97jPvV25lcwejse8kMRVe9m8izkkP8Kk1qJB61V1CzSa2kibowwa2a0OZPU5j4cwRXmu6reTgMViWNQf8AaJJP/jor0JrmxsY5AskcRJC8nA/OvL/Dcr6N4yNjuPl3SmIn/aHKn+Y/Gu0vb/RI5/LuomldeGwmQT7+tc3oelTjzbHSQPbXSkMVJQ49RSXU0MKEKqgCsW11XS51WCxYI45CbCp/I0XnmSKyk1MpNaFcup5x48dWuo5lA5JDe4rgZoRHPlTlSNwru/HLxwpEuc4OK8/lLGQLzgdK0pbHPW+I+kU3Fc1Wmy2R1qcS4TFQt1zXScR59r0ps9VjvFX97DIJB+Br0G2S21azhu4bjy1kQEYP6H6Vy/ibTjOYmSMHPBPpXHDXdW8OXDR27brYHcyOMge49K5OVp2O6nUtqj2QRw2cOC6knqcVkanqscMLbXBY1DLDNd2yTRTu6uobB9DzUMejhhukHHU5rFvU6E+p5h4tupbu7TcCE3YHvWHgBcnnmuv8cQIlwiouMHPH0rlPsk8hGEIDfd966INcpzVFAAAAAAB7x//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-14.png', linkedinUrl: '/in/lisa-salazar-04ed290031', jobTitle: 'Health and safety inspector', }, @@ -6145,7 +6145,7 @@ export const peopleDemo = [ city: 'Port Keithstad', email: 'erica.andrade@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDLdarstW2FR7MmkMquVjQu7BVUZJJ4FYFx4j3OUs1AAOPMfgH6VFreoG8vjZICY0ONo/jatGy8A6jdW6vK0cAYZ8oZJA9/es5VEtzSFNy2M6bxJOqqoK8D5mUUieJ7nIYxxyR/xY4NbsvgBYIf9cSwHPFchd6XPpc0qPjAHBHQ1MailsypUnHdHXWV/b6jHmJsMOqHqKuLGc15rFdSQSrJExSRTkEV6XoV2mq6ZHdAAMflcejDrWqZk0XiOKjNOLcVDJkxuB1KmmIxfC1jDqniu6vCoZIiWQe+cA/zr1mCBljA28n0rx/wlO9haak4tZLiUyJEqqxXn5u4ruvDFxeyKftHmqjoXUSPnb7etcNVPmbPQotcqRvXkLbCAo5rivEmnRXNuyMg8zGQR1zTdbfUTdmeJZp0U8LvIXGccAUJJPeMY2tfKkThijbkb6GpUbe8W3f3Tym5j8mdk9DXX/Dy8/027smPEiCRR7jg/of0rL8W6e0Ooq8aE+YOw71Z8GWs9l4rt1uEKFo27g+1dkZJpM4JxabR2pPFIDxSMDQqmtDMveCbSCB9UjlUFnuA3IzkbeP610V5NaWyzr5kUZSPOOlYWjsUuXx3ANWrzU9KaZlmtDdSINrYTOO+Ca4KiftGj06HvQVi7orw3Vu24oxXB4IYEEdah1eaC2RtoAOKqWesWGTDaQ+TJ3TYVNUNTYzEsx4rN3vY00sYU8LXdyHH3hwvy5707Twn/CbQrtAZLVnkHYFsDH6Vlaxr02juq28UTtIpGXz8tZ3hC5ubvxT58sjNJIDvPqP8iuqlF3uclaatyrc7wrxShRT9uKAMmuk4yW2/dShx1FX4IbO+hEv2kpkdUPWq1nbS3EgWNc+56Cq+nxpeR3ZRQsa3DojLxkDjP55rlxCS97qdeFk78pNcCCwUiOXd71jXV0ZAI4zuJ6mrF5o14s23eXU8g0630/yYy8nLVy36nXqcH4isZbm7Rk+YqNoXvXa+F/D8OlWCTlSbqZAXZv4Qewqrb6bc32rF7VvLaMglyoIx6EHrXUoZGTc6Y5xx0ruR/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-15.png', linkedinUrl: '/in/erica-andrade-64ca983404', jobTitle: 'Lecturer, higher education', }, @@ -6155,7 +6155,7 @@ export const peopleDemo = [ city: 'Courtneyberg', email: 'adam.wright@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1AUtRg1De30NhZy3Vw4SKJSzE0AUtc8SadoFuZLuXMmMrCnLN+HYe9cJc/FfEu6NIkhB6EZJ+tck0ereNvE95Naxhkdsln4CAcD9K6Wx+EKsVl1K8LN/ciXatYSqq50RotonX4tAR7mt4mLH5VGfyrrPDfjKy8RMYFAiulG7yyc5HtXGah8JrVwWtbp0IHAYcVyFzp2reCL5LsMzRKcLIuTg+hojVTHOi0rn0LmnCud8I+I4vEugQ3qjbMPkmT+6w/oetb4NbnMJurhfilLOvh62SAn57kBlB+8Np4rts1x/xDiMmh27KMslwCAOv3WGf1qZ7FQ+Im8GWEGn6HF5Uaqz/ADSEdzXTmRG6PnsRmuLv57vS7GC3tBMcRAhYVyxIHOfQVV8M3et3upRpePL5BO8iQDI44BxXB5nprsdtcOqry30Ga5DxSqS6TcxyJlSp4NZHiC/1uHVZY7RpjBEf+WXU/Spba4uNSga2uPP+ZCCJ1wwJHr3FO3UH2K3wgvNt3rGngYQbZV9sEg/zFerg15L8JbN4tZ1iaTIwixge+7n+Qr1cGu+Ox5ktxKx9esBdwLJjMiAovGQN2BmtfPFMl+aM4XcRyBnGampHmi0VSlyzTKts0M8GxwM4wcioBe6baXoj82GLbnAJALYHOBUMaMm8N8p/iAOcGsrUb7R5Y/Kfa7ICoYRltuevNcKvex6is9ie0u7C51GaMyxSb2PQg4PofSn6kLe2GI0APbHasCK90qKVltwFdiOHXaT+dW5d9xMoySWIAoa1sDdtyz4SsvI1CeVRgbGDHH3ssCP612NZ2lWD2ULCXZ5jEZ28gAds1o12001HU8ytJSnoNAopafEhdwdp2g8mtDI5a61GGe7uBbyZVH8qQ9tw60+4hkmtlWKZIsDqvHFVLXRXstc1u0mAaCWVZ4vcMMn8jWdqlnqNoT9kl3IOiseR9DXnz+NnqU3aCsTSW0kIYyyJI39496pDWrfSZY728DtBFIN2wZPPT8utZsD6neTlJsxjvmptX0ie/htdPtRlpJgXPogByT+lOPxIVRtxZ6bbXMN5axXMDh4ZVDow7g1NWbo6Ja2MdmMDyRtUe3Y81n//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-16.png', linkedinUrl: '/in/adam-wright-bba29daead', jobTitle: 'Psychotherapist, child', }, @@ -6165,7 +6165,7 @@ export const peopleDemo = [ city: 'New Jaymouth', email: 'michael.williams@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDp93FJv4ppbim5qSipqut2Wi2puLyUIOyjlm+grib/AOJN7IjiwgS3Vl+SSX5j+Has27t7jxn4omkVvKtYT5QLDOAD2Hqea7vTPh/o6QgyxPOxHJkOazlVUdDWFGU9UcTp3xA1i2lImZLqM95B0+mK6/QvGlrrEhgmCQT9F+b5X+me/tWnP8PdClXH2Mr7qxFcl4g8B/2TbPc6aGkRAS8R6keo9xSVaLKlh5JXO9JFAIrmPBmtNqWnfZ7hy1zAOWPUrnArpela3MRh6Cs/W746do1zcAZYJtXnueBWjWV4jt2uPD16iJvfy8qM9xSYIyfBVmkOno3V3csx9T0r0S1X92PSvMdLhYaJaSN9qyyEqtudp3cnrXS+HLq/jlgjlluGimOQLjG9fY4+lcklq2ejB6JHaDpyMCs7UwrWknQ/Kf5VgeI0umnaQSXrpHyEtpNuf8as6TE5jHyXUQ25aOc5z+NK2lx31scL4aK2vicRpnEiupHYjqP5V33auM0jTbiHxZNOsZ8pJXAJ6Y5BArte1dcXdHnzVmRgHvTZl3xOpGQVIxVggFcimFTtqmiU7O5Q0ARLB9nkQDyyQFPOB2rUTyzrcEYKLtUtjOKx0ha2v+GJD4NNubywOoBbpyJ1BC7fvCuJpqVj1INSjdHWQmCWQglC2eOc1JdbIo+OuOMVh6de6bIWgt5o/NDZZSNrZrTueVJJzgUn2B2RnrAIImIGBI3mc/3j1/CjtSKZXVfNOSBjgYFLiuunHlWp59WopyuhoORRvzxTV4FHetDIr342wCYHBjNNgtBelZ1dVkYdcZq1qFvMmiyXAhdlMioeMYB/i/PFZCx3Vs6PbuBG/B3dAa5a1lK524aT5ToobUQRjeELeoFNllLg45A6morazu35nmTB7JVi7QW9sdoB2849ayvrc3leRDuwOKCc1rnRJ5NJjn+zmO5bDGI4yB6fWsiSKSJikilGHZjzyup//9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-17.png', linkedinUrl: '/in/michael-williams-ab0d587602', jobTitle: 'Agricultural engineer', }, @@ -6175,7 +6175,7 @@ export const peopleDemo = [ city: 'Anthonyfort', email: 'margaret.morales@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDrQKQkKpJIAHJJ7ClFeSePfGc97eS6Np0m21Q7JXTrKw6jP90dKbJSudZqHxI0CyEiwSPdSocYjUhSfYmuSf4r6q13uS1tEhz/AKsqScfXNc3onh6+1m7CQQb0U/Mf4RXWv8KZWQN9rCN3G3NYyrRi7Nm8KEpK6RpWPxSt3ZRf2DRKeskL7gPwIFdvp+p2Wq2wuLG4SaM9Sp5HsR2rxrUvA2qaZC8g2zxKMkjggVj6Prd54f1JLm2d0ZTh488OPQ1UJqWzInTcd0fQ1LVeyu47+wt7yL/VzRrIv0IqetDIrX9z9l025uNpbyonfA6nAJr50hjkuJlKN+8lbj1JJr6G1OBrrSry3Q4aWB0GPUqRXingqx+3eKrOGVTiNizD02jp+dTUfKrl0lzOx7J4U0aLRtGggAHmlQXPqTW7IMHoDXLazdR2yOj2N1dvtLfISFUAdj6/rVTwpJcSz7AlzBAQG2yyFwM9Bz/KvLauuZnsJ2fKdVcQCSNkKjkcg15L458IRWMb6lZZUA/vIu31FdV4rubtbiRM3TwoMsLdiCf85rNXbqGm3dksN1CzQnKTOXBOMggmtqL5dTGslLQvfDLUzeeGWtXb95aSlcf7Lcj+tdrXB/Cy18rRLy4IIMtxjJ9FH/1zXd16KPKe40Vylroy2PiYX68yMh89uB8zH5QPwFdV2rO1K+s7NreO4fZNcyhIuPvH0rmxUZOKaOrByipNM30WK4tgTj3BFZdxqWn2UoiLpCu4KGI+83tViHcsfXjGazLjVdq7I9NlkwSNzAKD7jPWvOir6Hqpdhkd/p93qssQlWQHAPHQ9qtXsNtbxYRFGemKxl1SJbjY2mSQE8BlUMPxx0qzcSvNjIJ/2RWtmmZy0TuJ4T04adpMiqfllmaQD0BxW9Vazj8q0jUqVOMkHsTVntXpwT5Vc8ao05uwysLxbpMuq6Iy22ftUDiaHHXctdAAMUoAqnsStzIgv/LjSO4bYSo5PGa0HFpcQFZZAyEdM1Rhij1KySSWMBX+YL1wDWVe+H7hdzWlwyoOQuTivF05j203Yvzx2lsD5T4HpniobL/Sp1w3yqd2fWseLTZyf9JmLnP3c1PNcS2V3aiIhVKvuH0xiuii1zowrt8jOwAp2OKo6dqMd7bq33X6FT61nlWP/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-18.png', linkedinUrl: '/in/margaret-morales-7c6376f64a', jobTitle: 'Scientist, product/process development', }, @@ -6185,7 +6185,7 @@ export const peopleDemo = [ city: 'Amberfurt', email: 'david.nelson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDovGvjq08JwrCsYudQlXMcAYAKP7zd8fzrwbVNd1bXbl5b+9lmBOSm47R7Baj1zWr3XtauNSvH3SStkADhVHAA+lR6bp9zqN8sUKbpH9ulS2lqUlfREbyGGQFQykdGXkfl2qJpFDM3c4IwO9elaX8M2lAe8uCi/wBxK2G+F+ktypkDY/vcVl7eJusPM5vwD8Qn0djZXoaS0Zgd5Y5jPSvb7G+ttStEurSZZYX+6y14vqfw0+zwyvYzt5yqSoPRjXX/AAkunk0G5tpFcPHMSSxzzgAjHaqjOMtiJ05Q+I9CxSgUYpRVmZ8iLlujc+9dx4HZbe+XChnYct1rCvvDN3prI7bZoD8xmiDbce+QCK7/AMC6VENOe8wDI7EA46CsKs1yaHTRpyVSzO3t5TKowCDVoKMY8wBj71yOpXN35n2SCOba525U7R9S3pXLaZHrI1qWJDcoFkK7g5xweTz1Fc8Y3VzslOzsen3MBIY7gPTmoPBGmfYrzW5eAJLlSFA6ZUMf1Ncf4tbV4jbWsbSbGClmQkfeOO3b1ru/AcLReGUeQOrySMSrnJGMDr36VtQjbU5sTK6sdLigUtArpOM818h7m6kE5/0MoYhGqDA44yfz4p+g2a6TYwwJkqmd2e5qbXG1HT9cuYFtontbhDLbSMOVbgMp9snIzRC5ZcZwetefOLj7rPWjOM7TRtL5F3GUZAMjmoYrfTtMnSGKNTNNkknAwBVSJ2BwODVC+v8AS2WSC+kDPjLDnIHpxUx10LdjZ1W0stSigaRkLRkjg5IFbegkLZvEv3UfAP4V5naS6PGzQ2dwV3cxxdNp9ua9M8Oxsmiws/33yx/l/SuijFqZy4lrkNOgUtArrOA47X9ZS61qTRPscqzWoWczsRtKsCBj68/lWHdM9tLvB+Q9q7rxDo32jZqUCZuYU2SADl485/MHP5muNvEWZMZ4PQ1xYhNT1PQw1nT0IE1AlRgjJ4zVyOKSSEiDZu/vHjmuUvIZ7N887ezL0og1C+LAQsxNZKPVG3P3Oi+xXzkRzpC7OQF2L1Oa9Ft4Rb20UI6IoWuM8IRyz3Et5dSb2icRhAOASM5+vNdtXZRi0rvqcGJqc0rdhaBRRWxzn//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-19.png', linkedinUrl: '/in/david-nelson-a0ef7e99f1', jobTitle: 'Electrical engineer', }, @@ -6195,7 +6195,7 @@ export const peopleDemo = [ city: 'Haleberg', email: 'holly.allen@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0zFJin1XvLqOxsp7uY4jhjaRj7AZqShl7f2mnW5nvLiKCIfxyMAK5K4+KXhyG5aKOSedVH+tjQbf1IP6V5Truv6j441xggleIHEEEfRB6/X1NW4fhxq8yBnMMY/u5yR9aiVRLdmkacpbI9Ms/ih4dupvLd57ck4Uyx8H8ia7C3uYLuBJ7eVJYnGVdDkGvBpPhpfRLuW8QnHIANZS32v8AhW5WNbqa3wflKsdp/ClGonsxypSjuj6TxRiuX8DeLo/FWls0irHe2+FmQHg+jD2NdVitDIK4r4p6l/Z/gi4iVwJbt1gUdyOrfoK7avKPjY5+zaPGAf8AWSN7dAKGCKvw90mG1003xUeZP3PZRXdCRCgCSo3OCAa4uYJpuhWcJtJbgiBflToOMk/Wm+GFmkvVzA8MTjeQT09M+9cEle8j1IaWidddSRomGlRCfU1w/jHT4r3TGccvEC6kc5qPxFI/20s1rJcIGwNtS2zrPFJAYTGQCpX+E/Skla0kOT5rxZS+DF3HF4ovbV8B5rYlDn+6wJH5fyr3OvnLwBbSD4l2UcbFfLldifYA5FfRtegtjy3uLXEfEvTW1HSbNNimOOYuzEcg4wAPrmu3qpqltHdafLHKFKj5/mHHHNKabi7FU2lJX2OWspke1SLaMhQOfpVebUbKwvEikbaWyF4+82M02zKuzPEwZecEd6p6h4g0+DEX2aS4bJBZYyQD35xXnpNux62gadPa3s8qo6spJxx0IPIp97HDCDtXBxWdaazZzyExQtC5b7rKR+RqxduZCGPpSaaYXRn+E9KEPi2GeFALk3JeQ9f3RBP4V7BXJeDdNhMP9rKciYFY+Oozgt+mK62u6imo6nmYiUXK0egUMAwIIyCMEUUv41qYnD6pZJo106REiKXMi5PTJ5/XNZ7WZljzFcogHQ5qlL4o/wCEi8U30Ct/oscQ+zqe4DEMfx4NZl6l1ZzFkZmiJ6Z6Vw1FabPSoS/dpmlJAYSd0iOT1NRSQzagBZ25HnTgxoSeATWfDNJOcsSFHXmmalfXenWT3tlL5Vxb4kRvoQcfiOKmK95XNJt8rZ7FpljHpumwWkSKixrjavTPU/rVus3QNWTXdDtdRQbfOT5l/usOCPzQPIP/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-20.png', linkedinUrl: '/in/holly-allen-f9240b572e', jobTitle: 'Chief of Staff', }, @@ -6205,7 +6205,7 @@ export const peopleDemo = [ city: 'Carterfurt', email: 'cory.hicks@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1mkzgZJ4FLXmPxV1+6iEGh2cjRiZPMnZDgsCcBc+nBJpsS1L+vfFXStLuZLWxha+mj4Z1bbGD9e/4VyLfF/XXlJjtbNU7KY2/nmqem+A43jR7q6cOw5WMDA/OtwfD3TzDjzp2bHBOOK53iIo6VhZs0tC+LVvcyrBrFn9lYnHmxEso+o6gfnXo8Usc0SyxOrxuNyspyCPUV4pP8OYIt0gu5c46ACum8CX9xo+pf2DcyNLaTAtbO3VXHJX8auFWM3ZGdShOCuz0elFFFamQGvGPGbGfx5e+Zg+UI1Qf8BH+Ne0V5DrSw6t4uGopE6wThRh/7yAjJ/IVnVklE1owcpXNWwO6JQclgBXQRFvLA2/lXC3091BIyxfalGMqLeMEn8T/ACqzo+oa6txHDO5aF8MGkADqD2OO9efy2Vz0+a7sdbdI/lMAO1cnM7w6zYOow63UZzjp82Kk8Satq6XDQ24cRxfM7RAM30APXrVGzmf7ZDNcyTskEscsnmqAw2sCcY4PFXTVmmZ1dYuJ7GRzSU2OQSxJIudrqGGfQ06vRPLFFeZaxamyvJYyrKYpMJ6EHJz+VemCsHxVpcd3pk118wmgTcMdGAOef1rKtT5lfsb4epyNp9TAsJ7e5hCOozjjIBB/Oo7+8srS5jgMsUXIG44UMfQVlWbFWXaeD09qkbURNIYzZTzAf3I8g+vJ61wRTbselfqaE1xZS6u6+fFIrqOhBwfXHpTZ7a3ku4bZQB5jBDj3NZEt1BazlY7KaDcAPniwD+XStzw3aG+1pXkJ2wjzDj1BGBVqD5kiJz5Yts75VCKqL0UYH0opaSvSPIFFZfiDU7PTNMdr0sIp8wgqM/MQcCtYIzdBVfU9Etta0uSxu1yrEOrd1dTlWH0NTLbQqNr6nj7zvZjcwOw85HY1oW0tjcW4M07KCOAjYNaGp6DcWZa1uY8bvutjKuPUVyd1oE0Vyu2do4m/i7A15uzs9D1ul46o2Lg2MCkwysf95iTXaeCbeMaS92HDSTNhgP4QOg/rXnNtpAjuSTO86r/ERjNdd4CeWHUNVtFY+Wdk4B6AnKn+Qrai1znPiFJwO9NBpjsY4y7jgdxQJFZ3Hnn/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-21.png', linkedinUrl: '/in/cory-hicks-63ff8f7cf5', jobTitle: 'Charity officer', }, @@ -6215,7 +6215,7 @@ export const peopleDemo = [ city: 'Krystalmouth', email: 'michael.johnson@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-22.png', linkedinUrl: '/in/michael-johnson-db4d9dc5c3', jobTitle: 'Futures trader', }, @@ -6225,7 +6225,7 @@ export const peopleDemo = [ city: 'Huynhfurt', email: 'ronnie.martinez@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDrcVBe3kGn2cl1cuEijGWP9PrVnFcH8S7qSKGwtwT5Tszuo74xjP61LdkUldmPqPjTWLyRzbuLaFuEVOo+p9a56fU9SEjYkaRW5Zskn8a7Dwv4Xgv7f7dexnEh/dxdAF9T9a6pPBGkYDCHB+tYOqr2OqOHbVzx46jMsnmKzLKp5I6+1dd4b+IdyqrFqqB4Fbb5uPmA/rXZTeC9H3GT7IN3c561yPiTwnA0DNaDY65YKDwaFWVweGla56JaXUF9bJc2zh4nGVYVNivMPhnrEsWqz6K6sUdTINx+4w6/nXqeK3TucrVhAK4Lx9aM2qafKxBiZChU+oP/ANevQAK5jxJbLf6rYoASIGHmcf3iMfyqajtEulFyloaWmwrFbRxgYwo4/Ctdc7QM5/GuP1lZlOBHcyBQWVYODR4ck1A3CRzG4ELjd++PI9Aa4kup6afQ6ybO0rnHtXM6ucRsV5wpP1qh4hu9T+2Spb+eYY/veT1b2AqGyNxKdjLOgxllmFFuoOXQxfBsZk8erJH90RuW+mOn54r1jFedeD7T+z/Ft3M5IjmYwxADuef6V6ORXbBpo8ypFp6jFrM1SJjLE68KpDMR3x0z+daYqK8t2uLdlVsHHpmipHmjZDozUJXYQpFOmGA9DnvUQ+zpeJFFtUKfmPTmqkUpEbEHAArNup9Luim+WMSJkK+TkHvyOlcS10PU06GhB5EmpTxSFSGY7T1yadqMUUEZKjBxWBbvptjM5t7hHdzyWY5J/Gr+oTPLEpyeRmhqwXK2g2gfUI2+bBlMp9Mj0/SuyNZGg2Bt7VJ3YFpEyAB0B5rXNdlKLjHU82vNSlp0GCn5CqWY4AGST2poIVSSQAOpNcp4g8ZafFBPY2cnnzupQun3Uzx17n6VqkYDIdWtrvM9u5FvMzeWW4yMkf0rWMbzwAxOkbEDBNcd4ZSO40BrTgtFK4I9MsWH86luLzUtP+QEyRDoeSR9a4H8TPThJqKZ0Mls0S75mjdh1461h3+okwyBG3EKScHoorMfVr+9ygVgp4JxVyKwEdhMrgAuhz+VJjcnI7Xw9rdnr2jQXlkcJtCtGesZx0Nahr590e9vtIDxWd3ND1GY3IzjoT61u6R8Sdctn8u88q7QHB3rtb9T/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-23.png', linkedinUrl: '/in/ronnie-martinez-11500b150a', jobTitle: 'Camera operator', }, @@ -6235,7 +6235,7 @@ export const peopleDemo = [ city: 'Charlesstad', email: 'jason.holden@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0SoLq4S1tZbiQ4SJC7fQCpq5bx3qf2Dw/JGE3faMoTnG33qSzz3xl41m1xlt7eF4rZBgozfePqa4qSVxCpkLbAcrx39K6Pw5oQ1m4laaRhbo23g8k12K/D/TMEqJCcYAZsgVk6sYuzNY0JyV0eSl2KHaVTIyOOtKlw8aMByvH0r1RPh1p4kLy5I7KvArG1vwEIo91hIFA6q/ej28NhvDTSuY3hXxU+ha1FMhxbt8lwu7IZfX696+gLeaO5gjmiYNHIoZWHQg9K+WWhe3eRdvKnkV7b8KL+S88NzRySBmgl249Bjj8OK1MTvDXOeM1tBoE0l6C1uoywBxz2/WujqvfWMOo2ctrOu6ORcHjp70AeY+BI1bSyyD70rGu8QECuCSxvdGglgsZJf3dxKq8DBwTyfritvQNX1G7KxXcYWQqWzjH5jsa4Zx1bPRpS91ROjfdsIrI1HPlsBycViarrGuJLJ9nC+XHycLkkZxx61NY3d3dfu7hW3YzyuKlx0uXza2PLNaUf2hKpRkcMd1emfB22aLTtRnP/LSREA9gD/jXNa/orah4pihjH3kDSMOMDPJr0zwTo8Oj6bcRQqVVpuuSd2B1rshNOyOCpTavI6WjNJRWhkYF3BANRnRkXDEPjHBzUNvDEt45iUAKmDgd6f4gR47yKdDgMmD+H/66xTco+4rdeS7DaRnGa4pr32j0qTTgjVt7eCWRg6jf1we9S3EMVvGdoANZNpPb2+B9pEj9AS+T+tX7j95HuZuMZxUPQ00MyGLzJ3cFVfHLY5xXZ6dGILCFB/dB/OuE/ss6rr2nQ7iIY3aaUBsblUdPfkivQxXRQjpzHFiKl/cFoqG4u4LVQZ5FTJwM9TTLe9huo/MhJKb9mSMV0HMN1Kz+3WbRqcSD5kPvXIi1eRipVVkXghq6vV702GnTTp95RhfqTgfqa4mEzXD3MokPm+c5+oyeKwrpL3jqw02nY0I7QQ/O6x7unApk1wWXy1OWPp2quYppF+afg9lXmpYYBEMICzk4+tczdzqu3qyDT2ZvF9jAmcxRNIze2cGu/RlddynI6Vi6dpsdkrTEBrmXAdv5KPYVzUviyWz1y6e1ZZbTzNpjPRtoALD0ziuylFw//9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-24.png', linkedinUrl: '/in/jason-holden-1ebdcf4241', jobTitle: 'Automotive engineer', }, @@ -6245,7 +6245,7 @@ export const peopleDemo = [ city: 'East Toddfort', email: 'patrick.gilbert@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-25.png', linkedinUrl: '/in/patrick-gilbert-61fd32c01e', jobTitle: 'Learning disability nurse', }, @@ -6255,7 +6255,7 @@ export const peopleDemo = [ city: 'West Derekbury', email: 'sean.white@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-26.png', linkedinUrl: '/in/sean-white-dad0c13021', jobTitle: 'Scientist, research (physical sciences)', }, @@ -6265,7 +6265,7 @@ export const peopleDemo = [ city: 'East Timothyfort', email: 'valerie.martinez@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0hiFUsSAAMkntXA+IvinpOl7oNO/0+6zjK5Ea/j3/AArivHHj+51vUJNO024ki0wfKdnymX1Ld8e1cOhy5RUBJ/Ok2NI7h/ib4luJSyywwp18tIh/XJrX0j4p33nJ9ujhngHD+Wm119+uKxvDvhCfVVBkby4j1Jrt4Ph3pMcI3Kxf+9msXUSNlSbRvaT4v0rWZ/JtZHEuBlXAB59s1u15Brvgy40GQavo8sjPAd5j74HXGK9O0DUV1jQ7S/RgwlQEkevcfh0rSMlJaGc4OL1NCnCkxThVEHycGYMWx35Nbfhy2S4vIhjczNzWE6zKvzRsm7puUjNeh+ANMQwNdEZf7o9qzqO0TWlG8rHo+lxrHGqRqAqj6AVrKyMv+tQn2bNchdXc1oTGbSaVWOOOFH1rK0xbi81bzo7GS1Ck5LH/AOvXKlpc7G9bHeXkRMDbmA47nrWH8Pbeexl1uxLn7NDcgxIT93cMnHt0rO8ZTXcDW0AikliIUtsbGc10HgiCM6fcX6RyRm5cAo+crtGP8a2oqzMK7ujp6UUmaBXQcp4/LoEF5HDCyqVI3PMzdznGPy/lV7Rbb+yLOOBMkKxOfWsPw74kjgjfStThk+0wJtUgZ3gdAR2Iro7WUXEaHGC2Dg9q4pXWjPQi4y95HWWNzDcptkQcjvU80tlZbY1Eas/fgAfWsK2WRSMdakn1DSfLa3viszkZddu4j8KmOuhpoX7r7FfQRM8kMhU4wGB/KtLSiqwyRRjCI2B+VcFBPoS3LR2TGMvyse3AU+1d1oUbLpcbN99yWJ/HH9K2pL3zCu/c1NGlBxSd6K6TiPAxb2UfjWdIbmaWeOQ+Z5yjLnoxyDzzzmupnc2MobH7tv0qlq0Fo/iSK/gtjCZBgMDkEjg5+vB/OtyWFL2zx1IGDXNXTUrnXQacbdSWDU1MSMrDg9a0ktmuI8wMnrnofrXAzLPYyMqk7amttdvIk2pLjHaskuqNubudZNZXcbATOkmemPWu0tIfs9pFEeqKAfr3rgvDGsRT60ItSkIl2B4gT8uc45/pXoYIIyCCD0IrppRdrs5a8+Z2mB//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-27.png', linkedinUrl: '/in/valerie-martinez-1517f8ad33', jobTitle: 'Biomedical engineer', }, @@ -6275,7 +6275,7 @@ export const peopleDemo = [ city: 'Morrisonville', email: 'james.hawkins@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-28.png', linkedinUrl: '/in/james-hawkins-1cfac0a73a', jobTitle: 'Designer, textile', }, @@ -6285,7 +6285,7 @@ export const peopleDemo = [ city: 'East Jeanette', email: 'mckenzie.meyer@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-29.png', linkedinUrl: '/in/mckenzie-meyer-51b7a8a764', jobTitle: 'Pharmacist, community', }, @@ -6295,7 +6295,7 @@ export const peopleDemo = [ city: 'New Ronaldhaven', email: 'parker.young@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-30.png', linkedinUrl: '/in/parker-young-7d7d0c964f', jobTitle: 'Electronics engineer', }, @@ -6305,7 +6305,7 @@ export const peopleDemo = [ city: 'Charlotteburgh', email: 'john.johnson@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-31.png', linkedinUrl: '/in/john-johnson-08ef07ffe9', jobTitle: 'Control and instrumentation engineer', }, @@ -6315,7 +6315,7 @@ export const peopleDemo = [ city: 'Williamsshire', email: 'sierra.rodriguez@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDsd9JuzUIbimTTGKF3AyVUnGetbEGTrniiz0mKZTlplX5V7E/WvItT1yfUrqWadzkngDoKs6rc3Osaybe3R2klk2qmf611Fl8MHeAG7ugHI6KOlc86i6m8Kbex5q07u/y/Kvqam+07gFUEhR19K9Om+F9mIv8AXyEjviuZ1bwXNYxN5chkQDIGKlTTKdOSOYgvJobhZUlKSKcq6Ng17D4O8Qrr2msJeLy3wso/vDs1eKyxtGxRuCK3vBmqyab4ntCrYimYQSDsQ3H6HBrWLsYs9q83ioZ2MkEiDqykD8qQNSZzXQ0ZnH+D9GWLxPdSSZMluvRuuW716WMcCvPdW+12GoXl1ZJMZJkjXMXHI3dfyrU8M3Gpz5TUZCwMPmKx4I9j7151WNpM9Gi/dSOpuCQuM/hXO6sP3TLgZIPBrl9XuvEDXrSQTTGEHgIe2cVctrvUZ5Db3COxXgtnIP0IpRj1Kk+h5zrcYW7bjDZwwqHQ43fXNPWNcsbmPH/fQrq/GumgQxXSr8+7a3uKo+DNIuT4isJ5oSLdZC6sSBnAOCB1xmuiLucc4tPQ9VzQKkCHFJsxXYznLNkkUiyJIqkHrkVDdXVhaQXSiWKMhduBgYpsYIfAOM1lajqGhCXy5k86UDoibicdifxrzayaqM9Og06asaelfZLyJ1zG+MHIIYEU+9a3s1JRVGOOKyNO1fTpD5dnG0TddpjK0zUC0zNluBWfU10sZOqINTIjY4USBs/Sr2k2oa+t9yDbC5kRwMblwRj+VULlmhAaIKWXBwehroNOEiQl5FCvJjgdhXRSg5SXY5qk1GL7m6sPHShoOOlXljGKRwAtdlzhMqWJgrbeGxxVZbFJ4FZZVhIGDjqavzdaytRtWdd8EjI+O3Q1zYinpznVhari+UjkjW0UkzKxPfHWsa91BEQhTlieg71n3n9oNIUct9afa6dIpV3HJrmVtzpcmy3ZxF5I/O5LtlvaukUK33egFYDExvGQcHcBW7a8oDXdQV43OKv8Vj//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-32.png', linkedinUrl: '/in/sierra-rodriguez-5808a345e5', jobTitle: 'Sports therapist', }, @@ -6325,7 +6325,7 @@ export const peopleDemo = [ city: 'North Joshua', email: 'patricia.thompson@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-33.png', linkedinUrl: '/in/patricia-thompson-8942d96ec6', jobTitle: 'Dance movement psychotherapist', }, @@ -6335,7 +6335,7 @@ export const peopleDemo = [ city: 'Lake Paulaport', email: 'valerie.durham@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-34.png', linkedinUrl: '/in/valerie-durham-4fef3b9462', jobTitle: 'Graphic designer', }, @@ -6345,7 +6345,7 @@ export const peopleDemo = [ city: 'New Christina', email: 'michael.tucker@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-35.png', linkedinUrl: '/in/michael-tucker-6c66202d7e', jobTitle: 'Advertising account executive', }, @@ -6355,7 +6355,7 @@ export const peopleDemo = [ city: 'Justinfurt', email: 'martin.hayes@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDm35NIFqQrUkSqqNI3bge5qW7K4JXdkWLe0G0POQqYzjPJqD+1tPgvkiaGNucfNlsfjWbPqUty0xjXe4IVQOQD6niom8J6nqUCzMRG5zyetYuprqdEaLa0Rt3Ws28uz/VOijG5SAPy61YRIr2JWtGLE9VJ6elc9D4FvhOolmLjHIUnk1alt59Is5ohu2vjnkH6f4UlUV9GVKhK12i1PC8UjI4KsOCCOlRqpBp9nq8erRRJIi/aCNu8cDjufyqwYSrYI5rdO5zNWIyvNYmuSszxWyEgnj/69b5Wue1uOSO8WVR95cAnoPWpnsOG50vhzS47bTYiwXcfmZm9a6q3CGMbJVYD+6a4vUl8u1gidJpAsWdkY5JxkmpPDC3TajHAEMcEgyc8FfTPvXE1fU9aErWidruiQ5eVEJ7Fuv51n6ikbROrBXRhg965LxKLn+05E8l5YkOfl5Yj2rQ0p5VcW/lyrGwyUcdD6/40raXG5a2OVuI3s52FuwUB9y9s57V1cEn26BLnaF8xQcD6da5TW5PsuqzWci45wrHtn/IrsNLtjFp8EZbdtQYOMZFdsOjPKqaNoiZBmq95YLeRxAgBUJYue3t+OatkGp7YI5KSEgZDDnHI5oq35XYrD29olI1Y4LW6TDovyjBJqnBqel6ZqSrlU2glQB97HelUnyCUPB5yPT1qhJcQXcXlR2Ms0eNoYKAPwJIzXDFXZ6y2sjQh1HSdUuXjVxIC5Ukr91vQ1oSwW9mVCAsccHPFYMd7HbQ+VJp8sCEhQdoI/wC+h0/Gtd3LRR5OeMiiSswv3Oc1DSI7rVTeXG1d42xORkbwO4rThYiJAwCttGQOxxQ9zbPeSQFwZIgGK4yVz0NNBLHNdNC+7ODFuKiktxhXNJ5fNWVQUpQZrpOIjMjKgT+EjB+lSNbWs8W2WYgDkCknQbEGM5rB1SO6trg4B2kZU57Vw1ElNnqUJv2abOgSG3gi2Rz+Yp7E1EZySI1OccCubsppnnWMswDcEjtXTx2ItXABzxUM1u5Fa3sRFPcznmSdwSfYAAD/AD61aVAKckqzLIyZwkrRNkdGGMj8iKUGvQg/iZ//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-36.png', linkedinUrl: '/in/martin-hayes-7645eada45', jobTitle: 'Occupational therapist', }, @@ -6365,7 +6365,7 @@ export const peopleDemo = [ city: 'New Ericland', email: 'brittany.watkins@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwC+aSnGo5HWGF5X+6iljXMdAk9zBaQmaeRY4x3NY8/iyGHLRWcskajO5iFz9BXJatrFxqd78mWToqLnge1SQ6drl1EBb2s7r2WRQBSvYaVzprbxxayOqvbMoc4DbuB+lbdnrNreytGP3Z/g3EYce1cBc+DPENyhYwRxcZIDd/8AGszytR0hd10XBVsbT0FO6ezBxa3R7BnBpwxXP+F9X/tXTP3hzLFwT6jsa3d+KCSGs7X2xoV0N5UsoUEe5HFaeKx/E0bHRJGAPyOrHHpmkMo+B/D8Qia7nUOxc7FPIUV6NHCioAFUfSvOrWeSz8P2g3XIaRCwS36nqck1reGbjUZrlI5prloX5Bn+8PasJJ7nbCySR2EigKcAfjXEeLdOgns5WdcNjqO3vTPENxqDXThZbvyI88QHk4qvayNdRNEY7lPl+ZZ+c8daVvtFN390wvB16tvrP2IYxKhGfcDP6813/avMfDFsW8ZxxOxHkvIRjvjPFeo7a6TgY2obyH7RZyw7FfzF27W6Gp8UnNJoIuzuSaMtt9gjgZVIjG3kelPl1Ow0++jVlKIM4KocZA556CqaKVuGK/Lnt71BLfX7P5MdjH5QB+eVh830Ga5rO9j0Y2a0Lem6jZ30silWaNmP3kIxz70/VPs9tbsIUVSR2rPtru/Fz5UlhF5R/wCWkTjj6inaltAJZshal6aFGTo9j5N+06Ltd5TJIwA+ZSDx+Brps1n6ViewguRG0fmIGVG6gGtHYa6YJpanBWkpS90bSU7HFJitDEhuoz5JdfvKM0yCeyuIQLg/hmrMrxw20sspxGiFmPoAOawpbE3MRkX5XxkYrCqkmmdeHk7NGnPcWNrGTE34ZrLkkN2cAHYf1qK00mQ5eZiVHqa0RbhIwFGKwOjc1xGqKEUABRgCnYyKp6bDdJZubibziJmWNmGCVwDg+pBJFa0do7AEFSD6V3JpnmuLjuf/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-37.png', linkedinUrl: '/in/brittany-watkins-af3eeda76b', jobTitle: 'Designer, jewellery', }, @@ -6375,7 +6375,7 @@ export const peopleDemo = [ city: 'Perkinsshire', email: 'jacob.dixon@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDFJ5oaYQxtI2MAdD3p23JrL1e4NsybuUxz7ZrzYK7sejN2VyJtQWZiWnYdSTwAB2xWBJeQzzyhiyLjCnHen3DFztVVjYnAUVesfB+p6qilDHHF6AV16R3Oa0pbGBO6s+fmHHBNWLS+KY8x283jYc9K6+P4azBWa4uAeOMVzfiDw9c6QUYZeIHGQOlCqRbsDpzSubeh6+buc2sx+fsT3rpUXNeS2t1LaX0dxE3zqwPNet20izwJKhyrqCK5q8OV3RvRnzKzKu3Fcz4gc/bNoYcIPlINdRisjWNFkvnW4icKQAjA9896VJpS1KqRbjodh4W8CaTd6PaXlxEzzyIHJ3HBz7V1iaZBYoIoYwF6DFZN/HqGm6Vb29i0wWKAY8pRn5V/X6VW8OXurXcnl3bSEbd26QAEZHQ4q3qOGhtXabIyAAOK4XxPD5mnXC7cnYTipPEWs6u11JDAJfKj+80IyxA44qkj3M5MUzyMQvKyDn8xUNdS7/ZPKG2hzjOc17DpsaLp1t5YwnlrgfhXm0uiTz6rcwRJ8sTksfQV6jawC3tYYQciNAufXAq8TJNKxhQi022Ua0tEt4728aylbaJ0Khh2YYYfyrOp8TvFIskbFHU5VgcEGsFo7m56oqx3FqEbGAOc96rQJap5y2yAbM72UdTiq9nObrS4pFbBaMEn3xzWTdXVqtnstrwRPgru39TnkkdK3FFXKViIZb+aKUDJJIyOvNJqcNvbKfLUAkdqyIJYre8YrfLcMW+Ulv5CrV7MZuTxkZxWT7GjMOz0wHUZ7rd/rGAK+uBW5jmqml7XR5VkRxkrhTnHPOfetJY9xqZp3I5k9jDqa3iaaeOJQSzsFGBnrWjpOg3Oqy4j+SEfflPQfT1NdtpWk2unyIYIhjy8mVhlic+vb8K1p0ZT9DKdVRMOxa4tL/WNMdSIbOVBGfVHXINXbqBrnTwsTRR4HGRnitu/si179uijUlofLlH98A5H4jJx9TXM6nZP5e+yuhGo6xOMgf1FazjyyJpVLpGJc2n2djI/lF/Uc1jvdNcOyqen3j6Ut/bXjSHzZwc8fu6VbZbTT2HTINYSN+Zvc4zw9qcun303mMRFJId/tyea9L06QsBuYMCMqfUV5fPFsnZl4Gc16F4bYy6PaHOSFx+RNdPZn//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-38.png', linkedinUrl: '/in/jacob-dixon-81d8755b18', jobTitle: 'Farm manager', }, @@ -6385,7 +6385,7 @@ export const peopleDemo = [ city: 'New Erin', email: 'sheila.wilson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD2HFIcAZNOrK8Rpcv4c1BbNitx5LGMjrkc/wBKYjz74ifEY6Y7abpUiNMyENKrZMZzj/GvFLu/uJWH2h5JGGW+ds8k5Jq1a6dd67qUkcYDzMSznsK67T/hldDbJc3CsSPu4yKylUjHdm0KUpbI89UqrFyxJx0FWIbm5sriO7tppIZkYMjpkMp+tdndfC28RWdbuM5527SK5fUtCvtIVlmjbjqwPGKFUjLZjlRnHVo9y+GPj/8A4SS0OnapcL/a0XKkjb5yeo9x3/OvRa+SfB05t/GGlM0zQA3SAyDsCcV9a5rRGLDNc747vbrT/BWqXFou6RYSCc/dU8E10OaiuraK9tJrWdFeGZCjq3QgjFAHg/w2tU+w3FzjMjykEn2H/wBevT4QQi5FecW1peeHrSe1tfOEkd5MgCKMEgnGc+wrf8O61q97IsN7aiNmXcGXjI9x2NefUi3JyPVoySionS3BPlkY/SuN8T2yzadKPL3NtJHFP1nXNdS6kjtLdPLjBJbbknHXHPX2qna3N3f5E/n7lGWEiAdfcfyqVFr3i5ST908jBMd4GizuVgy/XPFfYVo8kllA8v8ArGjVm4xyRXzlonhlL7xz5LITbR3aZGcZBYHFfSOa9CMkzypwcdwzxSim0oNUQclrFvbx6xOkkS7ZgJOnBJ4J/MVVtYYhqASFAAi5JAxmtHxbbsTbXa9FJjb8eR/WuVmvLd5ME3UcoXAeNG6f1rz6sWptHr4dqVNdzQtlt5Z5Ip1XOSRuHWo9TNvaQMkKAD29azbO4s7d2hjW5Mh5LSIxP59qL58t8zZxWb3sauyXma3g7Qy98NQdCqo2/JH32I4x9P8ACu/qvZQLb2UESDCogGPwqxXowjyqx5FWo5u4g6UoqKWdIh83J9B1qjLfTtkRqEHr1NVczSbLOprayafLHeSLHCwwWY4we2PfNedpHbSMUnlYbDhWU4JFdNfW0t7C4djJIMMuT3Fc7NZ+YhG3DCuPES1Wh6GEVk9SC4FraRkxSsSf7x5rLmZpIy4zir0WlgOSys3PVjnFTPZPMfJijJPoK5766HU/M7PSvFWn3yxQyOYLhhjY44Jx2PSt4EEZB4riNL0UWqb5QGmIx7LW3F51uB5TsPbt+VejCUre3T//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-39.png', linkedinUrl: '/in/sheila-wilson-b61719f6d6', jobTitle: 'Doctor, hospital', }, @@ -6395,7 +6395,7 @@ export const peopleDemo = [ city: 'Hooperside', email: 'lee.oliver@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0uikrkfiJr8uheGZDbtsubk+Ujg4K56ke+KkZp+IvFml+GrR5budGmBAW3Rhvb8O1ct/wuTQyjH7Bfbx90YX5v1rznR/Cup+Jle9nuCEc4DyZZn9TXSw/C+ABjLeyMx6AIKzdWKdmzaNCcldI7DT/AIp+HL6SGKRp7WSTr5qfKp9CRXXWl5bX9us9rKssTDIZTwa8QvfhnPD89vd7iOzirfgTWr/wz4lXSdUlYWt1lQHPyh+MMD+hpxqRlsyZ0pQV2j2uiiirMxK8b+Lk08viOxtZC/2UQhkA4G4k5Pv2r2MV5f8AESw+1+M9GbJZCgjcenzZH5gn8qmTsioxbdja8PwxW2m28YAXCDA9Bit0ZOMDI9q4/VIER90sd1NhcpHAcbQB/OpfD7ywzqAblI3AbZK+7bnsfeuFR0uemnrynTTBth4496858e2yfYhdLxJCwZWHUGt3xLPJPIyFroxxckW7YY/5zXPX9sLjRb9ImuNohJaOc5IYcgg1UVZqRNR3TjY9R8KXtzqHhXTbu7IM8kALkDGe1a9ZfhoBPC+lorBgtsgyPpWnmu080UGuT8UWy/2jb3DZ4ZGB9MEjH611YrC8XWc1zoc8kDASQpvAx1wQf6VFSN4mlGajLUjiRJEUAAse+Kp3NxbW0yxl1QsQNxHU+1YEfiCS2sJpiN0kUG/b2J6VzD2mu6863NxPJFkbowoOMfSuWML7no8/SKuzv/Mtn1aRBKj5GMjsaZqsEC2kiFdu5SGx3rz6Wy1jRrhryG4d36upBwR9K66C7k1yKxjX5JroLwein/INOULbC591JWZ32lW62mkWkC9EiUfpVukQFY1U4yABxSmuxKyPLbu7iioL0xGznSVlCtGwIJ7Yq15TMcdKyda0Jp0a5gDPIFw6Z647getTOTSukXTipSs3Y8i1a2ubKOaF8hWiKpIP4h1qxYX76jpZtfPeKdVG2WNsfL6V2dzpsF/a+TOmRiuPufA1zC7CyutkbH7rdR+Nc0ZprU7ZU5Rd47FP+0F021m82d7iUghWds4rrPhvYy3kMWqT58uBDFHkfebHJ+gHH41zEXg1knDXlwZscso6V6D4PEsMNzbx8W8ZUquOFJz0rSMo81jGpGfJdnV0hoCv3FKysOoNdBwAAAAAAAByn//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-40.png', linkedinUrl: '/in/lee-oliver-a4da08a2ee', jobTitle: 'Office manager', }, @@ -6405,7 +6405,7 @@ export const peopleDemo = [ city: 'Joeport', email: 'aaron.moreno@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDb20balxxTJCEUsSABWLNUUb/UrXTkBnf5j91R1NYGqeKXg2pDARkZ6c/rWrpGgXGv3Ul7IWiTJVWPVvp6CujXwHYnY10fNKDC9qwdRvY6Y0V1PPY/FzWq75CjqwyF757g+ldHpOswatB5keAQcEZ6Gti58A6MQWFsoPWuQ1/w6+mhLjSlKtE25kU43Dv+lCq62Klh9Lo6rbml2Vm6Fqg1K2+YYlXqPUetbG3it07nI1YUDiqeoKWh2ZwG4JrQA4qrfJnyh2Z9tKWxUPiOm0mGOC1jSNQFVQKvu4Y8ODXJazM8EJhEd1KAuQluDniq/hl7ua5SN4544SM/vOo46H3rl6HoJHWXbKqYLAcVympD1GR71j65c3z6jOuy4lghJGIOWIHoKda3DzERiOdBjJSYEEVLV9S1poYmmFbHxIqx5CStgqOmTx/hXc7eK4GxSRfHa2xBKb949sCvQ9vFdVPY86r8QgFBiypkdiY14EfbfkHd+ABpyip4WiUOJvuFcjjPNOorxHRklPU10ihubbMgUZ6+9UY9Q0mzn2CaKHG4qM4LY6kD0qPzGexIRsEJzWLePFf2yxmzuGRV2h1tz074JrmWp3xV9EP0+90y9v54/OjlDOeQc7T6H0qzqEFvaLmJefrmuaiMFjdOsFncRBzwHiP861L2aR4QxB3Fc4NS1Yt6bnP+S7XtxPGxS4z+6kHtjIrtO3PWue0m2MrJIyNjcWLFePwNdD2rooppNs4cTJOyQDpTsZpBUqLuYKOpOK2scpVlk8p9jthH/Ud6u3H2a5tFDzsp4xwa53QLqbXU1ZL1B+4vpIEXHRVAxj86y/EDazpY2n95bchX7gds1zTSUmd1NvlRv3HlWsZZJNzjpmsK61IyKIkO6WQY452iuY/tTUL8NECYhjOc8n6Vr2Fi1taMcHzCnLE5PtWbSRrzNncW0IitYkH8KAfpUhFct8PtWvNV8MxvfyNJPG7R726sAcDNdUcV3NUAWPMvc//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-41.png', linkedinUrl: '/in/aaron-moreno-cf9f02bc3b', jobTitle: 'Industrial buyer', }, @@ -6415,7 +6415,7 @@ export const peopleDemo = [ city: 'New Trevorhaven', email: 'diana.garcia@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-42.png', linkedinUrl: '/in/diana-garcia-62a0597c29', jobTitle: 'Engineer, biomedical', }, @@ -6425,7 +6425,7 @@ export const peopleDemo = [ city: 'South Scottfort', email: 'jonathan.harvey@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-43.png', linkedinUrl: '/in/jonathan-harvey-8c1d8e255a', jobTitle: 'English as a second language teacher', }, @@ -6435,7 +6435,7 @@ export const peopleDemo = [ city: 'Randallchester', email: 'suzanne.rodriguez@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-44.png', linkedinUrl: '/in/suzanne-rodriguez-dffb493dbb', jobTitle: 'Games developer', }, @@ -6445,7 +6445,7 @@ export const peopleDemo = [ city: 'New Nataliechester', email: 'kelsey.allen@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-45.png', linkedinUrl: '/in/kelsey-allen-27c8b08501', jobTitle: 'TEFL teacher', }, @@ -6455,7 +6455,7 @@ export const peopleDemo = [ city: 'West Stephen', email: 'alexander.mueller@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-46.png', linkedinUrl: '/in/alexander-mueller-ce1f7db6fb', jobTitle: 'Chartered legal executive (England and Wales)', }, @@ -6465,7 +6465,7 @@ export const peopleDemo = [ city: 'North Bradleyhaven', email: 'cynthia.davis@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDJY5qC61GCwjDSkln+4ijLNTriUW1u0x5x2Ncjcmaa6ad3Od3POCBXHc6UjqIdQu7sqI444cjO1myfx7VcWW+RiZkMar95WTke49RWbptnbPEiwRLdyf3dp+X8TW3D4W8QmMiPC27dIixIH07ipvdlqOhDNdwqgk8yN0JwWQ9D7iojtY/KwYHkEUah4I1KwBuopAVZcPFn9ay9IuJFkmtZ12GM4XJzimS4tGmUpUABpeppcAUySlrEirbJGW2mRvTJOPSufhEl5qK2aBVUHk5zgf1rU8UBh5R2bk2kAjqD3qj4MjN5royu0KCaTWly47pHqnhzRrextl8pSzgZYnkmuwjGIRgj864C/v8AUbCEx2ttK+ejLwBVTSbrxGLiJpmm8uUbtrfwAnv6GpSsrm73sd/do0kJXjB65ryPxXAtlrlrLbx/M7bXA7+9dP4u1LWra4js7RZCSFLOme9cvdPcS3Ni8qSJKvmBiTnngZoS1uTP4Wi0nDYNPIJPFKqjHPJ9aUKT92rOczNdmh82CKRmTBzlewPBNXtO006fqTXMSBY+UXH8Q9aqa/brNDGyxlpQSFx79qz9E8R3yX9tpVwEkhBOGdcSKAOme/41Ml2NacklZnrenanBcwCKWNWyMHPQ1YvJrOxhG3yow33mYhQBXOWKYmG0/KelW9Z1vRdN09o9VBdT95fLL/8A6qmLb0N7Lcvzz2N5dRbZopVeIEgHPSuZ15IXuYTCAgiJGPXP/wCqodI1nRL2aaPTS+4DgsOh9AaivHLzndzjg/WnZ8xNRpRKjNinxmkKkmpEXBqzlKV9LKtuxCkEHHB5+tcvbh4vFWnu8ZUSuVAzkng5yfxr1PUPCcl9CFhco/c4zmsgeGo9Pu4lkYyTQchm7bh2/Kizuyk1oTwzNbN5bNgfwsa2khnvLbbBcxrnnLjIrKvIgy7SOccGs2OWeHKpIygehrBOx1JmrdRSadBI9zNCFUZzGm0fpWfbkX8hIUwlgASxyuR71NCklzxOxfPGD6Va0GKIwSW0oyYpWiPOMlTwfxGK3pJSbMMRJ7kT6VLF99JPqACKBprMuVcA+hxmumto0j/cs37onCZ/gPp9KZcaPDKGYqNx6N0/Ot+RHJwAAAAAABzM/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-47.png', linkedinUrl: '/in/cynthia-davis-ab0220f93b', jobTitle: 'Designer, fashion/clothing', }, @@ -6475,7 +6475,7 @@ export const peopleDemo = [ city: 'Lake Sheila', email: 'brittany.smith@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-48.png', linkedinUrl: '/in/brittany-smith-fb1075699d', jobTitle: 'Environmental manager', }, @@ -6485,7 +6485,7 @@ export const peopleDemo = [ city: 'Bowershaven', email: 'tyler.cook@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-49.png', linkedinUrl: '/in/tyler-cook-fe2564bd60', jobTitle: 'Hydrologist', }, @@ -6495,7 +6495,7 @@ export const peopleDemo = [ city: 'East Tiffany', email: 'heather.peck@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDSBwOnNSDBX3qNTx071Fe30Gn2b3E7bUUdfU1zmxDqWo22mWzT3L7VHQdyfQV57qviq9u5S6TmGPPyRIe3vVPVtYudf1VQqHYGxHGf89TXY6R8N45kSfUJAZCvKIMAUuZLc0jTctjzyTVJ2ucyguoPTPStM3D+Qkq7HX0Ociup1H4dfZo5XjLNGATwOa4+cJaW72gJJBxk0KSYOEo7lyLVZ4pFnt5HSReq5yDXd6FrsOtWpOAlwg/eJn9R7V5ZDHtAcvtcehrW0vVV0+9ju41wc4kUfxL3p7E7nqyjBPPHasTxRFHLZwCRgFEm4gnGQBW4n61jeLLF7zRH2rl4/nAHXoR/WhiRx/hWzS98XK8YBSJWkCjpkcD+dex26FEArwzw5I1vdXUYt5XlMaqm1ihGW65r0nwjdahPFPBeLKFRCyNL1+lYzjrc66MtLHU3ALRlSRg9s15T4x8Kzw3L3tmN0b8vH3BrR1SHUUvZLtY7iTb8wAkPIzjgZq/ZS3F9GUkt54yOCrncufY0leOpUrS91nkxYx7gSd68euKashLBs89SK0vFOnPpesyYGEkOR+NZHy4ByQa6VqrnFJcrsfQESgfMTnNSHDAqRnNQxZJINSHg8UhFKz0i1TWp7l41/eQiPge+T/StMta21vKsTxoSQoXODVKZzGUJOMnHFZl0fD9xMWvJQSG+ZMnBI9a55L3jvoWcFbc6i0S1vI2DhGKHBB5qO9khtYyI1UADtWdZahpCoLfT5EDHkKOCfzqDUBK7lc8DrUN9DWyOO8U2ramg2oGdHyPpXKPoptLeW6nRhEgO3P8AE3Qfhmu81I+RbM0YBk7ZGa871zX7zVrgQSLHFBExASPoT6mtqV3ojlrcq1e57YpIqUDABJ61BJJHE4VnUFulTqjN9K3sclzB8T6qLCC1ZN295htAHXHatGzsnvIUmt51iDDJyOTUmoWcc8ABRWkQ7o8jODXHTatd6GF8yZMtLt8rPKjOCayqRd7o6MPV5TufIWxTLMhY9SKzLy+UI3zAk1hXOoX0jlXckeop1lBLPIAQfcmudrW518xM0L3MMkjdMcV5FP8A8fc4PUSN/M17nJEsVrt6ADk1yY8AR3ZjuzK6G73SlAOg7fp/OtqLjdI//9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-50.png', linkedinUrl: '/in/heather-peck-09972b54b0', jobTitle: 'Designer, television/film set', }, @@ -6505,7 +6505,7 @@ export const peopleDemo = [ city: 'East Jennaview', email: 'justin.bender@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDb20MVjRnkZURRlmY4AFSha8s+JOvzTagNGgcrBCA0wB++55APsBWsnZGEVd2NHVPiZBDLNDptkZwp2rPI2FY+oUc4rnIfGHiOaUyJqOSTny9i7R7AYqhoPhy91mT/AEZDtBwWY4AruoPhdNKEMt+obvtTBH41yzrJPVnZDDyaukZdr491K2uI/t/kSxscMoXYV9wRXa6Vr9hrJkS1dhIgyySLg49R6isqb4WW4t3El5I0hGAdvAridQs9Q8G6zbzh1byuUbBw47g06ddN2FVwzSvY9cK0Bajsblb6wgu0GFlQPj0yKsAV1nEWdteG+IjHf+Or8A7kNxs49sD+le6gV4v9hR/iNL5WGt5J2kRgOCOT+hrKs7RNqEW5HpWg2cFraRxQoqKoAwK6yFT5Y715rqInU+UIp3JBK7HKgYHbkc1Z8Mzava3UMTNcfZpxuHnEkp7HPSvLcdLnsqWvKejOGMZ449686+JFpFLoLuUBaJgwPp2q34zm1HeYoTM0KAM4iYgt7ADr1rHvLeabw1qMTRToywElZHLbj1zz3pwVmpCqO6cTovDLb/DOmtjGYF/lWsBWT4VgMHhewiZgzJHg47c9PwrZAr107pHhSTUmmTLXCXmlm11kSEALBlYzjruyST+YrvQKydftJJbYTRAEoRvUjqueuaxxEHKN10OnC1FCTT2Y/TzbX1uqSxqTjHzDNLqDW1pNBEmxBkEkkDvWdpxKldp69KZqF/pV04jvYWlMZz8sRbB+teZbWx7K2OiYWs9+8UjROGAI6HBqvqttAbOS1RQBINnp1rN0+/0dHaK3Bjc4G50KlsdOT1rSkVprmPvzQovmsKbUYtsW1gS3tY4oxhAOKmAqTbRivZirJI+enLmk5dxy05kEilCMhhgioi6Rrud1UepOKwNb8QwfZ5bOzlczOuDIvAUd8H1xSk0ldjiruyM+K6Ns21+NrVp28Au8MtyE/unHIrKNuXhIQcr0qkhu45MQ5HPrgCvI0bue7FuJ1jWot42Mtwsvuwq1pxEweYnOPlFYVlZ3EvzXMu8DnaOlXNIWWHXL1NxMLxxNt9G+YfyArXDte01McW5OmzfxmkK08jF6Z45//9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-51.png', linkedinUrl: '/in/justin-bender-679fb353e6', jobTitle: 'Local government officer', }, @@ -6515,7 +6515,7 @@ export const peopleDemo = [ city: 'South Vincent', email: 'sharon.phillips@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDt+9O7U2ob28hsLKa6uHCQxIXdj2AoAfcXVvaQma5mjhiHV3YAVzV58QtDtHKxvJcEd41wP1xXn2oX2r+PNWP2eNxaxHEUecKg9WPrWra/Ci4dQ8+oAN1wqVDqRW7NY0pS1SO+0XxNYa4rGCQK4GSjHBrX4IyDkV5bL4A1LSITLY32+Qfw425H1rU8J+LJVvzoup4Wf+Anhs9wfWiM09hSpyjujvTRS9aSrMwryz4m+IGmuU0S2Y4jIM2D1bsPwr1MnAzjPHSvnvxHJJceNL9cgs90Rx65xSY0eseD9Pg0/RYF+VXYBnb1J967KFo5I/3ciPjrtYHFcFqDxafaxRyWEt4xQBY1BKqAOvpmrnhyN4rkOlkbWKRQWHpnoCfX2ria+0ektLROsuwqx/Mypnj5jivKPiBYiJotTgOyeE/eXv6V0vjCUvOyTW01zBF/DECTmuT8QNDL4ZuBbQTQeUVEkMpJ289R+dVBWaZNV3i0eleHNQ/tXw9ZXmctJGNx9x1/WtQ1x3wzZv8AhEY0IIAkZlz6E/45rsTXWjzxkjiONnbooJ4FeBWdpJqOvz3kSl0S63tnry2f6H8q9+kjWaJo26MMGvLtP0ceENQMWpQ/6NcSPi83ZG0DK5HUd/zqZ3toXTs5K56NplxBPAFYKTjHIqPVtVs9PaNHJVNwBKoTk+gxWdpBSa3jlgkDRuuVYHgjtTrzWTDIbe2sZLiVfvHbhc/U9a41dux6kVfYfBq+nX2rzRxvvVgAcrxmqXiy0tp9JuLWNVBkTaMetNh1Utc+VcaWbbd0ZVBH44/nTLwNNcIh3NuYLgdeaeqYppJNM0vCGnz6Z4etrW4270XjHpnP9a3TQqBFCjoBgUGu1HksVRmqmp6VFqtnJbSs6q4IyhwRV5RWfrmrQ6Ppks8koWQqREvdm7YFMRx+kCXRLKOwnYoYCY8n2Jx+mK6KNYLyPL3A2sK5nRPP1PT3/tC4+03RdvMZup544+mKZPpN/Ax+xXJ25+4T0rhnpNpnp02+RM3rmG3s0JjmyKk0KD7Zci8YkrCSAPViBzXMpp96Tm7l3N/dBpuk+KZ9H8Xtps5zpskQdvl/1bdNw9vWroq8zPEN8h6YaYaeCGUMpBB5BHekIrrOE//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-52.png', linkedinUrl: '/in/sharon-phillips-c61cfc876b', jobTitle: 'IT sales professional', }, @@ -6525,7 +6525,7 @@ export const peopleDemo = [ city: 'Port Jamestown', email: 'samuel.bailey@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-53.png', linkedinUrl: '/in/samuel-bailey-b423dc1293', jobTitle: 'Charity officer', }, @@ -6535,7 +6535,7 @@ export const peopleDemo = [ city: 'New Jeffrey', email: 'thomas.hull@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDbIwK4/V/FimZrbTCXCHEs6jIz6Lnj8ateOdUW00pbFJds90cMFPIjHX8+n515u90zMsMJ8uNR2FYTb2RtCPVnVx6uSwe4l2r3LHJP4VVvfEM8VyI7WAwjGQWO1z74zxWTaSJj5FLEfxn19q24fD51DTnmt0kN5I2BIzcKPWsLJbm6TexLovjG6Fz9mu5DK5HAcgD867e1u4ryPfEenDKeqmuCl+H98kH2j7QHljOcYPWrmiaykGqpCwMZdvJkQnuBwa0jPWxE6elzuKMZpQKcBW5znlHjcXMfi28WXceV2seyY4ArAgR7m6WFBnPau6+J9i631reLkrJHtPuQeg/Oua8H2Ulzras4wEBY+1ZT0uzaCu0jrdI8HtLbASN8zEE89B6V6Bp2lRW0CxgKMDAFcxd3F3ap5cKyEv8AKNnH5ntVDRJdXFwjzG6RZG+7I2cDPf0rmSbV2duidkeim1UxFeBmvI/GujLpWpRzRsB5+T+K11viy+1SzmjhshKwKqWMfXk1y/im3vL/AEzTjJ5rTRztGRJyckevcVcVqmZ1Ho0dbod017o1tO+dxXBJ744zWkKradaLY6db2y9I0C1arqRwvci16yjvLNHdVLQtvXPTJGP61x+k6O+nXYuNw3yx/vFx3z2rtdYszqGh3tqJPLaWFlD/AN044NcV4Z1PUdRtnXUVjL27eVvC4L8Agn8Kwrxe6OrDzTXKzuLC5jkAR4x0xmnajLbW0a/cTIJZjhQAKzrZCMc0moanpPlGC9xJjqu3cfyrnjrodmhsiexupINkscmYx71la/ZC+FnDANgiuVldh2AB/wDrVW0/UtHdnhtMh+Mbk2n1AFaSs5zuA5x9a1gveSMaz5YMD0pKcabXWecWbi8s7GNXvLiKFHzgyNgGsY2Nn9ou57IgxzlH+XpkKBx+AFdbfaNbX1qbS5iR0yGTIzgjpWO9q1vJJHIu0g5+tc9eTtY6cPFXv1MiO42AKxwwq2lt9pT5ZVUjoSORVS/tjk4X3qpAlyc7QwA75rnW52XsazWptxhpVlbPBxzVpQdg3de9VNOQCdleTdKE37SecZxmr5FdVKOnMcWIqNvlIjSU80mK2Oc//9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-54.png', linkedinUrl: '/in/thomas-hull-f814264a40', jobTitle: 'Professor Emeritus', }, @@ -6545,7 +6545,7 @@ export const peopleDemo = [ city: 'New Apriltown', email: 'shawn.collins@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-55.png', linkedinUrl: '/in/shawn-collins-01f97c07d8', jobTitle: 'Chief Marketing Officer', }, @@ -6555,7 +6555,7 @@ export const peopleDemo = [ city: 'New Angelicaborough', email: 'matthew.salas@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDfxSYFO7VVv7oWdjPcnnykLY9T2rM0Oe8Q+LYtMuDZ2oWS6X75YfKn+J5rhNS12XU3LXl1IcHCqB29h2rW0Xwxc+Jbya7mmKIWy79csecAV1lv8KbMkmW5eUMpGNuMe9S6kY6MtUpyV0eVpdeRhWdfIY/MoFXNL17UNPdpbO4MIB5Q8ow+nSvT5/hVpflnbI4btWDqHwz+zQMbW5BYcqGXv9aXtoMfsJrU6Dwv4lh8QWZyUW6j++i9x6gVukcV4lpJudE162u9x3Ry7ZF9RnBB/Cvb8ZqzMj7Vk+I136BeDPVP6itXtVPUrb7XptzAASXjYDHrjikCK/gqBItFj2ZwzFufrXbQnEYHWvMo/wC0LLSLCO2e5UGAMFt0BZm5JyT0re8L3msSSJDemXZICytKoDD2OK5ZLVyO+D0UTsJGO0isbU3KQMV5ODXOa9da4125tpLgQx5yIAMtz79TTdLa+ebZK90VYZdLlRke4I/lU8ulynLWxweoR79RZlI3Fw2Mdq9bTmJT7CvOtU0mUeLxHbr+7JWRieir3NelIUkiV4yGRhlSO4rrjJNI4JxadyqelMZFl/dv91uDT+1MNU1dWJi7NMv6UkUtlHHIBlBtOR6VMJrWHUBH5kabFJ6gZrKt5mW4fHGSTis+4u9Lvrjy7llE4BGFQlgPqOa4rO9j001a6Oh0+a0u5GXzI5M8ggg96nvBFbodijOMcVy9pfafZzGC1I3k42eWQa17uUkcnnGcUmraBcy4IBJqMtyGBYAIykZ+Xn/EVuQxiOBEAwFUCsfSGkeaUeX+7IDGT1OcY/rW4OldNKNtTjr1E0ooz+1MNO7UYrY5ipdFoV89Rnb97Hp61OIpLiFJIGjDkDBboRUoAPB6Vy1xe3VmQ1kvnQEnaB2+ntWFWOt0deHqNKx04RrWJpJZEZ8H7owBWTdag0kfkwnMknA9vesd7rVr5Di3ZFbqTxWxoumPH++nHzHoKydlqbczkyex1S3stRi0d1cTPHvR/wCE+314roFORXD6rCreIo7pSQ8MOzjtk5/z9a6zS7o3lorsMPjB9Dj0rrgnaP/Z', + 'https://twentyhq.github.io/placeholder-images/people/image-56.png', linkedinUrl: '/in/matthew-salas-f83a70d28d', jobTitle: 'Scientist, product/process development', }, @@ -6565,7 +6565,7 @@ export const peopleDemo = [ city: 'Burkebury', email: 'sandra.branch@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-57.png', linkedinUrl: '/in/sandra-branch-e20208030c', jobTitle: 'Programmer, systems', }, @@ -6575,7 +6575,7 @@ export const peopleDemo = [ city: 'East Bryan', email: 'donald.burns@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDkwKXFKBTZHWKJ5HOFQEk0yiK4uYLSLzJ5Ai9vU/SsmTxEnWOMBOxc8n8BVWCxv/FGosYwqonA3Z2p7fWukh+Gd5NGFkvIxnsEJArKdWMXZs0hRnJXSMSHX2cFisJQdcMQa1LW/guztRsN/dJ61pt8K0RB/pzE98R4rm9X8J3nh/8A0iOTzIFPzMq8r71Ma8W7XKlQmldo26CKoaXffa4irNukUcn1FaNbrUxEAqjq6s2nsB/eGfcVoCq1+P8AQnJGQCD+tJ7Atzc8J2kdrp0K8B2O4k9ya7+2V/LHGR7V5w8MSwW6ywzzDyxtjiOMkDJ5rd8P3UlvJHHGtxFA+MJKckZrzZK/vHqQdvdOvfcAcLx71zmvRo9pIoUMShyBVTxBJNM7Z+1SwjJ2wNg8dR9faq1m6RsCIbyMbfmjnO48+9Ty6XKvrY4axi8jUvLXhcHH07VtYqkEb+37mNIZBHE7HcV4APQfrWgRXpU3eNzy5q0rDBU9vF55li3ld0bcg46DOP0qACpraXyLqKQnAVgTj0pzV4tBB2kmddpNslzAD8oYcgkVLJPZW2rQwz3MSMCcbuO3JFUNKlYAeWcg5IpRe+dKyT6fLIen+rGMe2eteWt7HrLXY1bWayvbiRYLqF8OQduGAPv6VNeW0dtC5JBbacEVmxX3lsY4rCaLOB9wEY/DpVu+O+HknIHIolpoHqc9LbhNPuZXfO594we5+XB/nWMRWlfXwltktFUjy3JZs9azsV6GHi4w1POxE1KenQiFBpAaXrWxgXrDUWs1wSdoOQa6O3ltbiIM8h2sM8NXGNIFkjjBBDNhvbg4pRbXom8uAsD1HPGK8+vFKeh6FCTcDvXnsrSElZOg6k5rGutTNypSFvlxuZvQVnQaRfHDXTbiegrTe1Sy02WRwOFOf8KwbRvq9znYJlubdJ0+7INwp9Q21ubGxhhbOETmn7geQcivUhNSR5c4uLP/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-58.png', linkedinUrl: '/in/donald-burns-eba0c35180', jobTitle: 'Interior and spatial designer', }, @@ -6585,7 +6585,7 @@ export const peopleDemo = [ city: 'North Karen', email: 'robin.allen@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-59.png', linkedinUrl: '/in/robin-allen-bb093171b6', jobTitle: 'Personal assistant', }, @@ -6595,7 +6595,7 @@ export const peopleDemo = [ city: 'East Wesleyview', email: 'andrew.carter@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-60.png', linkedinUrl: '/in/andrew-carter-940e806c3e', jobTitle: 'Broadcast presenter', }, @@ -6605,7 +6605,7 @@ export const peopleDemo = [ city: 'West Keithfort', email: 'natalie.king@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDa8xSKid1NZ8k7KOKhWZ2PWkMtXMkUUTSSMFRRkk1yF94sk81o7KFCvTzH/wAKo+Mb68mv49PhLbTjCJ1djWnpvw2uJbVZby52TMM7F/h+prOU0jWNNy2MObxDqDvuku3Ur2Q4FPi8WX3nKjTOF/hbHWu1j+HGlrBiUyPIRyd2K5jxP4Xk04pJbj91GMY7/nU+0TLdKS1Oh0TxOrukF6ykN0l6Y+tdpFEmARyD3rwp53jCyDnHDL/hXpvgrXDqGltBISZLfABPdT0q4vozKUeqCU5FRIvvUzgGkWMFSPUVZBzHh5F1zxvcXrDItVIjX8cA/wA69VhQ7RXj+mZ07VNZiiheVsKqhWIxluuRXZeDri+mkENwZNrIzr5jEkc4wc1yVFd3O6lZKx2LKevHFZurW8dzZtHIoO4EVx3iD7fHfvIizzoDkL5hAxnGABWzplzdTAQS2ZjxxuQ5U1FtLmt9bHkuqQtaapJGD0JBU1u+DtU+y6zDHnCTfu2H16frR8RtNa21WK5Rf9YvOB3FYWjRXC6xYbleNXnQKxHHUf410Rd0mcclZtHq7pgUkatVsxgihI8Vuc5meHrOBNe1kzKC0vl4B9ME/wA66i0jtbWSYho0wuB2rGFt5d/9qXhimxvfnI/r+dR3d5ozyFbqQs2NrqATn2NcdRNTPRoWlBWOiSK3ueGC7169DTpWitY84Ax0xWVYajpARYLGWNT2QHB/KrN2plGDxisZNrQ2SRzes2y6vMruoIjJ2ArnJPtXLauU0/xLo8SBY5iySSKvQEHA4/Ot3xT4ibw5FC0Vuk7SEqAxwF9/euQ8L2194m8XJe3Pz7HEsrY+VQOij26AVtSi3qznrVEk4rc9ZEdPCDFShRigiuw88haPcCKzUskldhJIInU4OO9arOsXLHnsK5lbxtR13UoSSBAI9mD065rCula51Yack7G/FbRW8ed0bf7W3mo5r3d8itvc+lY6Wt7LIEMxMZNa1tZC3bBwW9q42zuPPfiHC8lzp8ZJ5DH8ciu28A28Y8NJtt1jcOVdlH3yO9R614bXxNc21kCUaNxI0g/hQfe/OuvtbGKxto7a2QLBGu1Avauug7pHDgAAYhWbP//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-61.png', linkedinUrl: '/in/natalie-king-f64767c2da', jobTitle: 'Actor', }, @@ -6615,7 +6615,7 @@ export const peopleDemo = [ city: 'Lake Jeremyfurt', email: 'gregory.rosario@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-62.png', linkedinUrl: '/in/gregory-rosario-17dfa72dac', jobTitle: 'Adult guidance worker', }, @@ -6625,7 +6625,7 @@ export const peopleDemo = [ city: 'Whiteland', email: 'jeffrey.schultz@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0djjuKZkjvTuMcUzn04pDRi+JfFNp4ZsRNcAy3EnEFup+aQ/0A7mvI9U1/X/FDsLq5MVuc4toTtQD37n8a7JtHTxVq11ql1K2zeYoF7Ki8DH86ktvAz2gJW5Vl5xlcGsZVOiOmFB2TZ5Reae9mQ6uQRyGXgiuj8M/EPV9AmSG+kkv9PPGyRsug9VY/wAjXWXPga2lQmed2PfFYWq+F7OOyeOFWDIpKknvUqqipYd7nrthqFtqlhDe2cokgmXcjf0PoasjPavL/hNeSxyajpMjZVQJ0Hoc4b+leogZHWt07nK1YcQDz/KmMGaNgpwSCBUhINQ3BdLaUxEBwpKkjvTeiCKu7HM+HIhDo9umOQDn8615ZGIwDXN3z31pax/YM7ME5VQeeeOai0HVNV1BmW5i2EAkHG0/QjtXC+56kexuXO5YyPauW1TIQqvLEGqup63rMl1KsMWIoupC7icccDvUUc11d5MysCoydwwaLdQcugnw3Rh4xvWIxi1IbPruWvWenpXjdnbbbq627lklkwhB6njH869iQERqG5YAAn1NdVOV9DhrU+Wz7kmPzpSMqQacAMcClxxWpzmHEkSrJAwwFYjBFRLHAnmi3VVCKc7R3xU+pR7L0PyFdevuK5m51EPGRaXCQnlWy/XnniuKStKx6tOSlFSG6WkMszxyAbuvzDrzTtUEFtEyxgDI5wKw7a5NrdH/AEhbhi3DB+fyqxqcxcElu2cVLKb0LfhnSJr3UIbt4X+zLIZBIfunB6D3yK9FI45rI8KtA3huzELBtqlX9mzyPzrZONtdkI2R5tWblLXoKDgdfrTtryfdU1cS2QDpn3NPI2yhR0ArSxkcv4iguIzYMrHy2d1YDpu25XP5NXP3MDXFkEikgilUYxIMj6Yr0e5s0vbNoH47q390joa4PWNKAlaObfDMP4kPUevuK5q8XGXMd2GnpZbnMzRpaK7yywmTuVFZqM125f5vLHOT3NXbrSQZDmV5CTzux0qX7HJMEsrRMyyHav8AUn2FYXvsbu7d5Gr8PZJrXR7l5AWjlun2fQHGa7iOVZFyp61l2OmR2NlDZxD93EgUH1Pc1eSFuNo5Fd6VlY8yTgAAAAAu2z//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-63.png', linkedinUrl: '/in/jeffrey-schultz-396167e978', jobTitle: 'Occupational hygienist', }, @@ -6635,7 +6635,7 @@ export const peopleDemo = [ city: 'Teresamouth', email: 'michelle.cook@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-64.png', linkedinUrl: '/in/michelle-cook-38eb3ee806', jobTitle: 'Futures trader', }, @@ -6645,7 +6645,7 @@ export const peopleDemo = [ city: 'Melissaport', email: 'billy.hutchinson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDf2e1LtqTHFG2pGZet6zaaDpz3Vyw3YIijzzI3YCvGtW1++164eW8nYMP9XAvCJ9P8a7HWdJu/FHxCbSmbKRRgrnpGnUn6mupm+EukrHGUknEgHzFmyD+FZSqqLszaFGUldHhjI43DZgkYqAIR2we2a+gZPAeiiEK9tvZV27s4Jrj9a8BWisz2pKKATtPNQsTFmjws1qec6Xq99ol4LqwuWilHBxyrD0I7ivdfB/iOPxPoi3BCrdRHZcRr2b1Hsa8G1C3NrcMgzgHFdf8ACfUGtvFrWpY7LuBlI/2l+YH9D+ddC1Vzlas7HsxHFIKeRxTcc0AZfh6zCeNtauCMyMkOD7Ff/rV2kpJ4zmuK1WC5hdruwE32iQLGTHIFAxuILcc9al8Mapqd7Zut+jrMqlwz4Bx6H3rhqr3mz0qDvBI37oMF29DXM6qNysnQkVh6vqWvyzzSxPM1vF82yLALDOOOOant5Lq6/cyJMrL/AHsH9RWThpc3UtbHlPie2ktr91kQqc9+4rU+FsHneOLducRRSP8A+O4/rWx41057oWcaKDI7lAfwrZ8BaFD4f1C1ldfNurtXhkcNkJ3wB+HWu2nVXKrnn1KEnN8vQ9DxxTdvNS7eKNtbHMT2SxvvjcAhh3qO5iihtrnyFC8bSQMfWkTKvkcVmak9nLEYhqPkvzvIf8/xrhrq0z1MLrBEmlxQXMTKVUleoI5FLeLDZoxQAHFZmmTwWrkx3YmdurbwSadqDtKCSeDWD7HTYw7qJLm5jdkDsj7kB9cVu+HdOkjuZL2X0wvHG7GCR+Heufu4JbmRYbZykzkRo4P3STjP4da7+3gW2to4FJKxqFBY5J9z7100IXfN2OLEVeVOK3YuOKMUopGYKOSB9a7DzwIzVZ7VZ4CnmLE6HnA61ajDSMAgzk4FZyp/aGqalCXYLaOkSlDg527ifzP6VzYhK1+p14WUlKy2M6S0gs337Y2k/vY5qhcXnmcJ8zE9q0LvRJ3kJE7MnoeDVWKwETEYAC9a4rnoNtla0u7LSbyG61KdYYQ2PMYHAY8DPp1ruNysoZSCCMgjvXnmvacurQLp5OFkdWkb+6oIJ/wrttOEiafAkn3lQDHt2/Su7DP3bHnYpe/c/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-65.png', linkedinUrl: '/in/billy-hutchinson-ad8e6c722e', jobTitle: 'Television camera operator', }, @@ -6655,7 +6655,7 @@ export const peopleDemo = [ city: 'Lake Benjamin', email: 'kim.rhodes@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-66.png', linkedinUrl: '/in/kim-rhodes-acaa899835', jobTitle: 'Engineer, maintenance (IT)', }, @@ -6665,7 +6665,7 @@ export const peopleDemo = [ city: 'Mendezchester', email: 'cristian.garcia@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0zFGKdiigBpIVSScAck15X4n+LywebbaDbh5FbabmYZX/AICvf8fyrpPiXqFxZ+F/s1pL5c99KLZcfeYHqB6cd/SvO7b4eM6oonGCBuPvWc6ijua06Up7HKXvirXNTdmvNTvZA2cgylVI9ABgYqpZ6pqOmy+dYXNzbt1zE5WvUIvhrpwUeZJIz9dwOKlPgvS4ItvlswHXmsnXibrCyKfhr4vXMYit9Zg+0pkK1xHxIo9SOjfpXrOm6lZavZJeWFwk8D9GX17g+h9q+cfEOgf2ZflIZco3KnH863Phh4hu9F8Tw2E8h+xXziN16jefuN+fH41tGV1c5pwcXZnvtFLRVkHG+OrY3F3ojbciOWV/x2jH8zTbZAqKB+VP+I4mXQ7eWFpAVnxiIfMcg9PyrkvC02o3Pmx3ZkVBEWVpPvDnGDXHXXvXPRwkrRsdi544Yn6Vn3chVSq/jXFXkusxaiAJbt03YARwBWxaT3s37uZZOO7jn8+9YOOlzpUruxzHiQmQuXYr820/SuZ0m4ez1qymjBLQ3CMGPswrt/Ftmr2KyqfnDY+tYFp4fuXuYJ7qRIoRKmUKncy5B7dPbNdNKaUdTiq05OdkfR9LRRXScRh+J2T7NbxyDKs5/l/9euYilsbSCYCaNGZtpBOB+ddL4uiLaN56/wDLBw5+h4P8xXlc0unXVyZbiYKv/PIAnOO+B3rkrRbmelhZL2em52tsLK+Z1OxmQ9eCDT52htUIjUdK5+w1WzQR28AUc5UKCMVevJgrFR1xnmsGraHVdGZqMKXJjjk5+cNVqG0muX8hMyJcONqN1BBGMe3WqU7N54UMN3bPrXR+DIbm/wBduLqbC29nEqIqjhpGzk59lH/j1aU48zSMZ1FBOR39FFFd55JBe2y3tjPbMcCVCmfTI615fBpd0gSISJbyxZSRD3I616vXJeLfD0s6y6rY3KxTohaSJwdsmB1GOhxWVWHMro6MPV9nKzOfuPKs7X96UkY+nPPrWLLqY+ZijZPQnvXO3eq3kkzJKWUjjC/41Z0uG5uHDFCEHdufyrl5EtWdjqOTsjY0+KWd2uZhtGMIp/nXceBtWglFzpSQus0B815ONrbun44H6VzKJshVMZP0rrfDmjjRkd2X/TLtxJP/ALIAwq/gMk+5rShdNJn/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-67.png', linkedinUrl: '/in/cristian-garcia-2ebbb7bd5e', jobTitle: 'Clinical cytogeneticist', }, @@ -6675,7 +6675,7 @@ export const peopleDemo = [ city: 'Diazchester', email: 'joseph.rodriguez@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDta5DxP4mNvI9lZuAyHEzjnn+6K6PVLz+z9LubsAExRlgD3PavKXmaa48x1LSTMWORzk+1Y1JW0Nacb6mpYXTy3iG5Zm7/ADHOPypuqhJ73EuQgPLLnIq3pcWwP5nD4ye+K2beGK7gdJISSQcECue6udHKzi8GxvB5LGTHLHHGPauv07WnshHI/wA1rJ1A7Go18LybNzPtA7dTWbrSvBCREcqAfx471SlroEqemp6JHKk0ayRsCjDINOrmPBt95tibWQ5kjAYHsVrpq6U7q5yNWdjJ8TxmTw7dgc7VDY9cEcVwml2CySiV2I3/AHR3r0XVUaTSrlEUMzRkAN0NcfpFiY9UEUrq5gUgbehJrGs7Ox0UYNq/mbthoqGLrxW7a2cdunygZ9cVy99qV7p+5YYJ3wCQI492abo+t61c3KRXFoyK+CGK4Kg+vvXOl1Oy/Q66WIYzxkjrXM6rZRLFKWAOQfoKbr2t6pZztDb2kkpQZJVd2Pp61Vhu7zUoXiuIpI8oc702nJFPzJfYXwgE+1StGvSPa5/HiuurC8K2gttOlfA3SSEk9zitzNdkPhPPqfENcbkK+oxWBLELa6hYAAsXz+JzXQDpWfqlunkicINytyfY8VFWF1c0oVOV8r6l62MF1FiRVOPUVFMbdZxFABuUgtt7VlQvIIiwJIAzgdazrq4troorpNE8eSrFHUg+ucVyrXQ9DQ6WUwLqbpOBtfGMjvUeoeVDEUjAGeOK5aCaKC8dp7iSdmAXcwbgflWzta4ngR8lWIJ55xTs72Jk0ldmpZKEtEVRgVPmkVQihVGAOAKWu1KyseXJ80mx6jiua8Sa29pqVjpKwhkvchpOcqRzgVpzauA6x28ZYk43NwB+FYt3H9qvBLJhp4JN6H8MH9DSn8LsOnpJNjYbz7KxhuG2svc9CK2nK3NtlJghI4Yc1nX+nR6jaiSP74HBrnvM1a1BgjUOBwPauJHpXaOoASCMs84Zx1JFLoebqWS5LghPkVe/1/z71zdpHf3TMLw7QTnaD2qXTbi7s/EOpGIr5QjiwrdOh/wrWlbmMa7bidyaKxLPxCk/E0JjIOCVOQDWzHNHKgZwn//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-68.png', linkedinUrl: '/in/joseph-rodriguez-de666b5949', jobTitle: 'Colour technologist', }, @@ -6685,7 +6685,7 @@ export const peopleDemo = [ city: 'Port Michaelshire', email: 'dennis.blevins@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-69.png', linkedinUrl: '/in/dennis-blevins-f1a0ae91b0', jobTitle: 'Engineer, petroleum', }, @@ -6695,7 +6695,7 @@ export const peopleDemo = [ city: 'Samanthaport', email: 'charles.bright@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwCwoqrqurWmiWJurtiBnaiqMs59BV9Fryfxnqsup67NCGJt7VzHGo4Ge5+ua5IRuzrk7Im1HxzqmoyGO2K2kOekf3j9W/wxWcdRv4p1cXziY87xMSfxpmm6RcXRLRQlgpwQBkVv23gfWLwho4I0A/iZR/SrcorQlQnJXGWfjbV7CULdTJPHjpIB/wChCux0XxJa60pQKYbgDmNjnPuD3Fc3J8NNQe3d3lTeAcLzg1zlpLc+HtYty6sGgb5lYcMvcCp92W25TjOHxbHrhFMxTo5EnhSWM5R1DKfUHmlArMonQc14wIVfW5hLzm4f/wBCNe0p615YmlMvjNllQiKW4MqcYyMk/pVxdricW7HpWhadaW0CeTAit9K6iI7Ix8oA9hXDXYvbVB5TT/MMqsQHp6nvVrQbrVoZo3uJZmimAOybGU+o7Gue3U7eb7NjrJj8pwPxrzjx7DD9jE5iDNG2QR1B6f1roPE1/qW2VLVnVYcFjFgs2ewH41yWs2c82iXh3TFwQHErbgWyORVQWqZNSV4uNje8NfN4Z05s5/citPHNM023jttJtIYlKokSgA/SpiOa0Zy7aEg6Vga3bxrdWl6sZDxS+WWz2bP9cVvrVLWLcTaZKwHKbX/I/wCGaTRUJW0Zr6e0N1bRq4DYXuKdfCKJ40RQrE5OKyNJlIVcGmajeWl4/l3Ekce0/wAR5FZJdDsTVjX8pP7XnjkUYZAwBqhrKW3lLb+WNjONyjvWdbXEFvfM8V4tw7YBy+WFW5R9p1GNWzgEsfy/+uKLa2FKSSuy7wqAAcAYqI8GpXqu55rY4rk61W1fULfTNKmnutxjI2YUZJJ4pLzUILEYc7pD0Rev/wBauS1vUZNTxFKqrEAcIP61pGDZlKaResr5rJjFK+0qA8bH+Idx9a6NUiu7dHWVFkI+ViM1gwWkGsaYpBG9Rj3BHaorew1WD9xb3MZK9El4xXMt9dz0E2tVsa80MdnG8zzI7qD2wBRombiOS+L7t52L7AdT+J/lWLNp19cPsvplKA5ZI+h9iag0e6uNM1G7jB3wyMHCHgDtj9K0gk2Y15StdnZO+KrOcmktrlL9SYgQw+8p6ipRbue1W4s500f/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-70.png', linkedinUrl: '/in/charles-bright-08b96bc983', jobTitle: 'Scientist, biomedical', }, @@ -6705,7 +6705,7 @@ export const peopleDemo = [ city: 'Youngmouth', email: 'pamela.moore@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-71.png', linkedinUrl: '/in/pamela-moore-cf9a7d2df4', jobTitle: 'Clinical embryologist', }, @@ -6715,7 +6715,7 @@ export const peopleDemo = [ city: 'Garciafort', email: 'andrew.bowen@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwCsKyte1tNFtkIQSTSH5UJ7dzWuBzzXnviy5M2uSxjH7tQgz+dccFdnZN2RQvr+41a6El1I21vugH5V9qqea8U4fBZFI/wroPD3habWRu5jjPQ46+9dDN8NL6TaEmDKOm4Vq6kU7EKlJq55+L6a32EPuGOR2BzXQ6DrssUhfJaJTmWIeh4yK6M/C+Ux5LKWA5+tc5r+g3eixI4UrEvDOBS9pGWg/ZTjqdxbXUV9bLPA25D+lTqlcr4InMsd2khJYEMB7etdcorKWjsWtVchBrgPEdt/xU0xIyZFUj2GK9AUc1z3iLShcXkN2m8Mm1G9GyTj8qIOzHKLkjrPDNusFhDGgAKqK7K2B2DPJHpXnUtzdWkUbxJMuRgJEATkepPFW9I1rXo7uKO6R2ScjYJAARntx3rNx6m6kvhPRJGzDyMfWuL8aQpLoVyhXI27uB05qLXta1uCVktIpAqNhlRA7fz96qi5v7qyuYrpJGJjKlZVAIJGOCCRRbqDtZo43wT5jXd9I4xtVU+vP/1q7NTzWTomlLp1mG81pJJgrMSuB07VqitJO7uYKLirMj3YplxAL2BE/wCeTeYR6+lOIoGQeCR9KmxcXZmrpn71TEByDnJxj9QauTRCPUrVZHQAMG7DBrMscrOGB69RU17PpV7PGt8hZozkYRiVPrkVnrex0R1WhuyRpLfy+W8Zyeeh5qC9QCPY2M54Axgn8qqafd6Rb70tgiyORuJUqWI4B560/U5SkZkVsOMbfrSe9gdktTL1JIbaZLaBQqRKBgfnVRTzRIzySM7sWZjkk96RRWqRzSd3cTvTlHNGw5qK5kaGBgn+tZSE+uODVJXdkQ2krkskjRP8pxjBzWlb5uVUm7MZI4K9RWBosF62mKL6fzrphucnoD6D6UssdyMiHcrdOOlZPc6INpJnWbFt4W3XXnf7T9azL2bdHE0jABjhMnGaj0zSLx4hJezEg9EHp71N4l0VdU0aSHzDC8Y3ROP4WHSkmlIcryRQPWkB5qx9hl8pF3BpAg3e5xyahMMkZ+ZSPet3Fo5VNAAAAAAAAADP/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-72.png', linkedinUrl: '/in/andrew-bowen-a1a4379f39', jobTitle: 'Industrial/product designer', }, @@ -6725,7 +6725,7 @@ export const peopleDemo = [ city: 'Port Nicholasfurt', email: 'steven.jones@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-73.png', linkedinUrl: '/in/steven-jones-0b032a0b9f', jobTitle: 'Radio producer', }, @@ -6735,7 +6735,7 @@ export const peopleDemo = [ city: 'Lake Scott', email: 'randy.garza@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDoFj3fe4pjkRtgc1K7DbwcU2PKZmO0kfd3dPrUPQErstR2byIGf92p7nr+VTpZWq8Mzk+ucVlLq0krsk3GOh7VMknmHh2H0qOY1UUaMmmbgTbyBv8AZbg/nWZKTGWR1KsvUHtWnbzmNRuJ+uKdf2631v5igGZBwR/EPSnzEyiYazc1oWci4681nRwEvnHFWo4tp46UJmRCzhsD0qtql/Dp6I0spGPlVF5Lk9gO9TeWxbAHWuB06+udd8ak3CsoilZI4242KvX8aUnobUld2OqjtNT1Aq4ZbONugA3SY9yeBVpfCqPhp7y5lP8AtTkZ/Kp76ae3TbDHI7AEhYxyT+NZ+kXOqT3K/aFlRGPSQ8rz6VzNt6noxhFaWNFfDzQDNveXEZHpMSPyOagfWLzw6RLqBE9kWAeVVw6Z4zjoah8Q3OqWl2UslkdUAbKdW9gO9Z+vNd3nhK8llSUSRoGZJE2kcj04pxbuTUjGz0OoSSN/nhYNG/zKw6EHoatxpuXrWJosy3Gj2csa4VoVOPQ45rXjJAyDXSmeY9ynPA8kDIp2kjANZTWsS69b36KqhXaDnqxI5P5iujYArXP6rfQpdCwWN/tIUThscYzgHP14rKrF3udmHqLlcH6nTR+XMuCoPrkVUu57S0lRXeKIZAyxAySeAPeo7K5Bt9zcMq5YVkXuoWt1xM0SIp/iGSD/AErCOp3K3Q6VprKe82CSJztHGckVU1uKJtLu4MD54inTjkVg2F1aQyv9nngmJ4bB+YemK2551JhLjO5lOKbvcmVrakWnwx2NnDbqBtjXA+laCbWXK1UERaTjp6VehTamDXTG+x5NSXNNtB5RIBFUdR0oTyJcH5XETRZ+pBH6rWlE/RcZJ6Cor1rpLxYHhVYDGHD55LZIIx7D+dVU+Fl0VeaOTiuJbZpYCcOqkOGP61sxvJPZK1qYw+0YBxiq+r6Sbv8AewgLOBhW7H2Nc2NXvbBmhkt2Dqdp4ODXIrHoJuLOtk8yGyMl2kbvjgLg1Vt919dwsCdkQ3MffGAP1JrKsbnUNSfmIohONzD+VdCiDTIrZIoXeNpQsjA5Zd3G4+vPWqi1zakVuaUXY1YYVXkinSqAMrSyLNBxJGR79qh8zJxXHXY86x//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-74.png', linkedinUrl: '/in/randy-garza-e9a6dd8b85', jobTitle: 'Diagnostic radiographer', }, @@ -6745,7 +6745,7 @@ export const peopleDemo = [ city: 'Charleschester', email: 'barbara.wallace@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-75.png', linkedinUrl: '/in/barbara-wallace-69672cb7e7', jobTitle: 'Radiation protection practitioner', }, @@ -6755,7 +6755,7 @@ export const peopleDemo = [ city: 'Hardinville', email: 'robert.johnson@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-76.png', linkedinUrl: '/in/robert-johnson-799ff9ca07', jobTitle: 'Producer, radio', }, @@ -6765,7 +6765,7 @@ export const peopleDemo = [ city: 'South Christina', email: 'daniel.perez@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDoAQD70EgnoRTRjHPWjn+9XJc6LChdxwBmrENl5h5YKO9V7Vm+Z5FwM8ZNXEugSBkIPc072Fa4raWVGVfI9SKrPbvGMkZHqOa2rd0lGA4OfQ0yZY7eULOm1TwJF7fWnuFjEzz04p+ckYqa+tvJcOMbWPboarAkDual6DE4K8E1HIdsTnBOFPSpeccYxVe9DCwn2H5/LYjHrg1JSKIvHupfJhbaiHDsPX0Fbttp9sFVmhDk9SxzXmqyXcem2TxzSxs0QbES7mZsV0nhXVtVmuoLG8DYY5DyLg496znd6nZSUY6WO0g023fDLF5Q9UYqaluVltoW84m4twPmyPnUevvXGeI7nXLG8WOGWdogOkIHzD0Ge9bWhy3m1Ula4weStwvPPoahNpXTLlBSdmi8QJdMPlSCaEfOjg5wKogcYFZlibjSPEWp6eoY6bMhkU54ic9B+Oa1AeK35k0jilBxeo1QTxmq95GZbO4iBIZo2UEdjirScA8U0jA+tBKZkeHY7e4sIlkRWKooGR7Vp6csLeJCN0arEnyjOOawIC+nXk8Y52ZZQBjI6gVQtoftWovOXdLjBA8tG4Pue9Y21Z6MHdKx6XLLZzbN5ibccKwIIz9avCOGGEbQOn5VxET/AGCxkiRAUcgkGIr83rnFb7XbC0t03FmI5rN6FspLCZNUv3U7k2Ijg9AACcj3zikXkc/lUEU1x9ouUXaIZD8xxySAMY9utWgox0renGyucWIndpdhhAIGKDyenNJ074pQOw6+la2Oa5heI0NrB9uA+UDa2PXtUGnzi9t4jFc+VNIoJKjoKu+J4rxLWA7c2hkMdypHTI+Un054/GuONlqGjuXsnLxHoMZIFZzirnTRm0ro9Na/htdMMElwbh2Qg5FZgvpJUjggXMhAAHcVz2m2mtak4YxmJCMb3GAB7V3Gh6JFYZYkyzEfeI5P0rFpI6E2yDyPs4SM8sBkn1JqRWB4IrooPDX2ydp79MRggxxZ+YkevoPan6r4eaV2nt3AbA/d44OBXTShLl1Rw1pR5/cAAAAAAD3Wf//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-77.png', linkedinUrl: '/in/daniel-perez-a5274e65fd', jobTitle: 'Product designer', }, @@ -6775,7 +6775,7 @@ export const peopleDemo = [ city: 'Garciaport', email: 'breanna.chapman@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDuQoFNYgVMy55FQOOKzKG8GuM8RfEGy0a9lsbWFru8j4YA4RT6E1N478SXHh7S0+yBftE5Kq7c7R3OO5rj9B+H0+p24vNQneMzfOVxlznuTSc1Falxpub0En+LeslSsNvaow6kKSP51FbfFLxAXBlkt3UHlTD1/Wuqf4W6Y8IWOSZSBwc1yGu+BrvQX84P5tvnnI5xUe2izR4eS1O50f4hWN+gF/GbVz/GMlPx7iuvjZJYw6MGRhkEHIIr59WaKMgK24A888gV23gzxcbS6TTbs/6HIcI5/wCWTf8AxJ/SqUn1M3Dqj1fIAqqzcmmmYsOtN7VTIRxfjKGPUvEWiae67lTfcOPUDAA/Out0+PbEpOMVx3jIQwa1Y3cqSuDbyR4jOCfmXAz+NXfB081zdC2SO5ig2k4uM5XHv3Fc9XU7cPojt45o4xlpFUn1bFRahBb3to0UyLIkg6HvXF66smnal5g0o30g5Xe+ARnHHvXRadcz3yL5mnyWrcfKSCp+hFYW0udHWx454n0eHT9SkWPMZ3HGawI5pLeUjd+FetfEvR1uNLF0i4mTqR3rx5rW8kt2uPJlaKI4eQKdq+mTXTTfNHU46seWWh9Gqxp24mmKRUqoSK3Zyozr2K3lmhFwgYjdtJ7ZxmptPu9M08TyS3EMATC/McBfqah1SImJXHBRv0rHs9Q06O+kc2rzyhtrMq5HHb9a5KifMelhlzQsjtfMtbuQY2MR3GCDVppYbeP5QucdqxbfULG8CRW6PBIvRGiKf/Wq5JGSME1i21ob2Rl6gh1LMT48vdkk1zWu2cFt4ZvQ1rHF5YPlsnSRXBAXHrnH6Guk1C6SyQMY2dARuC9cdzXAz+Irjxv4nstMsovJ0yCYTPu6uE7n0HoPeqpRcmRUqKCbPSVixU6EDg0vAFJxXczyiK7hFxbSRg4ZlwD6HtXPafpsc0p8yUxSg4YD1966QY3Vla3ZRJA97CxjuBjoeG/Csqsbq6OjD1eSVjXSMRQhC4IHORUUl6qIQWBNcZHearPIIklJQnk10lhpvlFXlcs/U5rie56CZV1lZTot3IFJleNgijr0rI+HHhptJ06e9u4itzcHaoYcog7fia7s6PJfooYmKLsccn6CpbuweySNd7SKFwXYDJPqccV1YdNLU0yTeh//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-78.png', linkedinUrl: '/in/breanna-chapman-6565f5d75b', jobTitle: 'Television camera operator', }, @@ -6785,7 +6785,7 @@ export const peopleDemo = [ city: 'South Kristafurt', email: 'ivan.garcia@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwBwwagvrpLO0aZ+3QepqwFrlvFIuHu4UHCbTt9M+tTN2VyoK7sZeoak13I0jEndkAZ4XpgU+wsFktjJkIwBO4YJFZc4k87yZ2ChTgtjr/jWnpu+3cmKWbyyv3FiyD9K5mzpSHyxSy2TXKtFJOvygjgFe+QP/wBVZuk3SreIiqEYsQQe30rbtvC+s30pmSBreKRs4J2k++O1SXvhpdO3ieMEICQ3cH1o5kVyPcW21WSz1QRyHEZOGUjj6iutXEiBh35ryr7TK9woI3bTjr2r1DTZEl0+FkOV2gfT2ram3sc9VLcmFcV45uWa4trQKVAG8P654rtgvFZevaSup6eVBAkT5gcdeOlXJaEQepiaP4dbU7O2uLdkbAIIfJ5Bxmu+0Dw29lEBMFY5ySF6muX0BtR0rw5ZGzg81n3Hb26k9a6fQPEOp39zHbXOntbyMCevGK4pLqehBnVxRLGnCjH0rmfEuji7trhhJtDqSRjnIHY1Fq3iTWLS4eK203ztgyTnr249amtb+91NAl3ZyQMVydy8Gk9rldbHh9/H5Ny0CZZxkMe9ek+FrV4dAgMhyz5YjPT2rBbwu994ivIt6okL43Y5OD0+uK7WztUs7OO3QkrGMZPeuqk02cVaLiteo3jFN3YpQOOlIRWxgamhi1S3Nrt+RScBucZOa17SOP8AtZFiUDapJwK5i2JScEHFWZr2BrjfFqC204BHLYz9a4ZxtJo9OlLnin1OjSKCWQrMo3gnGRRdmK3iITrismyu9Pjj2/bVnlLZy0u4g+2atXTLnJbPFQ+xo9DLR7KGOZt8b3LOWKg5KsRjJ9OMVXV8iqdvYC2u72YnL3E5cn0AGAPyH61aAxXbShyo82tUc3bsR5zSGjGKQ8DmtTEdgnocGrVvA90APPWN14+Zc1ky6nDEGWIiWbIUKDxknAyauyxSlQysVfGCV9a5q6s0dmFk1c2ordreM+bPHIcfeAxTIT58hbOUXv6msvTbO8uJT9plYxDsOM10MUKxqURcKK5WdTbe5hz/ACzuPc1EGBqz4g8iK1Vd7LdFg0ew4OO+fase3uGkT5xyOCR0NehRbnG9Wuf/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-79.png', linkedinUrl: '/in/ivan-garcia-5b5da68591', jobTitle: 'Police officer', }, @@ -6795,7 +6795,7 @@ export const peopleDemo = [ city: 'North Lisaburgh', email: 'michelle.thomas@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1qs7Vtc0zQrbz9SvI7dD90Mfmb6AcmjXNXt9C0a51K5P7uFMgf3m6AficV8zazrd/4g1WW8vJGeR24UnhR6AdhTbsCVz1PW/jEqyrFodmJBnma5BAP0Uc1FF8aJPlafR0KAfP5c/OfUZFcV4f8HajrTZt4Ds/ieToK7JPg8WhzNfYlzkeWvFZOqkzZUW0dx4f8faB4jmS3tLpo7pxkQTLtY+oB6H8DXT14Fqvw31zRZPtthJ53lHepi+V1I5yK9P8BeL/APhKNLeO5Rk1G0AW4BHD+jD646etaQmpbGc4OO511JRRVmZ5D8bNTmR9L0xHKxMrzuB0Y5wPy5/OvO/DdnBearCk4LIX6Z616l8ZtHuL7T9Mu7S3aWSGR0coMkKRn8siuF+H9oP7WM8qM5gTcFA6E1hVdkzelG7R7hpMUFraRwQRLGij7qjFapfK8GvMtZ8SyWxMWydFxjbGPmY/UVV0bXriGYSxRXHlvglJJM9enJ7+1cqi7XO1tN2PTblWKHivObJ28OfFKD7MALTVx5cyY6P2I/H+Zp3inxFfQ3zwSfaoY48ZWFuTmsmwvbi98U6JdPBcXawXGFXgNlsAZJ446/hWlJWkmY1mnFo9pooortOEyNe06O9gincbjbEsFPQ5GK42x0pdOu2uAFDzpiQKMDrkfzr0ZgGBUjIIwRXnkWrTXmqX1s8ESx2U7QeZG2d3Qg/kfzrkxENeZHdhql1yPoaFzpUeoKGWMFwADnoab9ht9PMRu2ggjQ7yWYYJHTJ+taNmjAD5uDUOqazZ2n7qazmuGzn5YiVz9elc0W3oddkVNasrTU79HglglkaMblJ61L4c0iODVt0oG6FS0ajoD0z+tULLU7Ka+e3ispIHIBBZePzrqdCiO2adx8xbaD7CtqSfOkYYiyps2KKKK7jzSveMBayDnlSODXBaHpDWsd+jurPNMXLJ09Bj8q6GTTFknNw/zTn+I96fBB5ZckYyeleU8ZGurR0PRpUPZu7ZkW+ofZ2MMrbWU4571ptBFfwgCfb3UjqKz9T08Tkso+asYQ3kBwrsF7c0ludFzdNibeQKs5lkY4GetdVaQfZrWOLOSByfU96wPDFn5iPdz5kdW2oW7HHJ/WulrvoQsuZ9Tz8TUcpcvTmP/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-80.png', linkedinUrl: '/in/michelle-thomas-ffd3c66255', jobTitle: 'Ranger/warden', }, @@ -6805,7 +6805,7 @@ export const peopleDemo = [ city: 'New Kelly', email: 'stacey.taylor@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDjTk0gFSFear3bqkZQtgH7309KylLlVzWMeZ2LEBEudmdo6tjiq1/eJbrhCzv7f1qGK/CR5AA7KM9KZPEs0AYKZZm4VQMAVzuUm7s6VGKVkhLTVfPcxudkg7dQavq+9eRg96qR+FtQe2+2xkKY/ur/AJ7Uy5vBDLG2MdNy+h7iqU7PQmVPTVF000ZBqXAZQynIIyDUeOa3OYuOBHG0jDhRmuZv7svOIgckfMxrodabytOJHGXANclpUTX+sRWw582UKT+P+FZT1fob09F6mnpGk3eq3SiJDszjPYV6Zp/hVLO23FQZCMAnrVaYDQ7JLaGxkmBXqBwP/r1J4ce7luVDJLHFJgkMxIXPbqcGsG3JXOyCUXY14bHyNP8As8i5IGD715L4psnsL9sjAY5+vvXf+KLi6junVY5ZIoj0jzz/AI1z+sBdW0S6c2nlXFshOMdcdxSirahU95NGLotwZ7IoeTGcfhV8rzWF4akLTOueCldGV5rsjsedLch8UKy6PuHQSLmqHgrTw97HeLuLQuS3HH+ef0rpNStorzTJopThducjtjmuR8OeIj4euZYZYfMtbhgGIOCh7H9azqJtWRrRaTuz261uI7iERyID9aZd3llYSRo7xxKSMsxA5J4AqvaqWUMhyCM1BqWtafaqsU9vLcSE9FiJAP16Vyq70PSsieO5tLvU7mNXSRSc+vNZ+uJbJYXEMcYG9CuAPaq9nq2myTvFbwSW7g9HXGT7HvUWtX0Vjbvd3LhEQdTnr2HFKzvYHZK7PNdEhNtrk9t08vcp966jFYfh+3knnm1CYfPIx/HPWt/bmu6Ox5Mt9BdTLnSbkIDuKY49K4CS1mkD/ISFOSQM4r3SDwfcMP3syKSeVXn9ak/4RGzto5VjiCxSRkOAOevXPqCAamcraoqnG6sVbOU2lpArkhSi4PpxV2S1hu4gVnC+h7inSWqyWSoy5UDhh7VhTRzW7EKxK+xxXHsejCXYtS2cdqd7TeYfU1wHxA1VpDb6en3f9a59eoA/nXY7Xm5Ykgdc1SfSI9Re8eaFJFj24JHKg5yP0FXTa5yMQ24GNpCj+yrfA/gFXQmasR2SW8YijTao6CpEhnnPc//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-81.png', linkedinUrl: '/in/stacey-taylor-bb60b7c3b6', jobTitle: 'Forensic scientist', }, @@ -6815,7 +6815,7 @@ export const peopleDemo = [ city: 'Danielberg', email: 'randall.cohen@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD14ivO/G/xHj0Z5dN0lfOv1O2SU/chPp7t+grudVuhZaTeXJfZ5ULuG9CAcfrXzEsdxfX4doyVZsAufvMe57n1pNjSuW7zVrnUZDNqF3cTTn+KVicfT0FZ8pR8+dtZxykiNk/jXpWifD6K5gEt874bkL0//VWuvw00RSSI23diWrL2qN/YSPHrHV7zTpNsVzPAwIKSRuQQf8K9l+H3j5tZcaPqsitqCgmObI/er7j1/nUV18PNFkiVTEwZRjcDXEaxoU3g/VbTVtPbKRSgkH27HHY0Kqm7ClRlFXPoCkqKzuUvbKC6j+5NGsg/EZqatTAyPGC7/CGqj/pgSf0rxTQLZJdZhZgr/MMD0+le1+J3zo0lmUZvtmbfcP4Mg815x4S0b7Dq08U4BmgTr2JJ4NZ1JLVG9Km3Z9Dv4SNoHpVgtkcGuR1OW+3tHF54QAkCIc5x6mqOhT6s10qzS3PlPg4mxkD39K5raXO2+tjt5Bx8xwK4rxqqnSJt4yOufSp/E13qkc7Q2pcKi72aPqfYetZKJdahpd5BcNK26EnEwwQcZFOK2ZM3o0eleFomg8KaVGxJItkJJ68jP9a1c1U0qPydHsYgc7LeNc+uFFWq7Dzitq0TTafIE++vzCuRt7VbW8Lr/rDGquSSc4JOf1ruuorm9Ws0tbhJELYcHg9qxqw+0dFCpZcjHRhLheBj1yODUTrBFKYkC7wMsQMYpsTkJx2Gax7+fT5wUlkXerZJGcg/hWCVzt0NW5jiOo7X24cDBPrVe+iiijaMADcCvA9aw4XtkuSReGaQgABmPH0rdtYzf6hbxSZ2k5b6AZp21sKTSjdnW28Yitoo15VEVQfYCnml6UGuw8sdXI6xrAutcl0dYSslvEJxLn7wPHT6ity5v237YR8vdjWPcQIbtb4KN2zypG74zkH8yfzpVU+R2Lo251czoro58ouFccEHrVwx7odqlE4wDiqeoacly4I+Vh/EKxrmTUbRtgV5FHRhzXGmmd92jWmt/LHzssnua2/DVu8m+9kGFxsj9/U/0rjrf7XdNm4YqndfWtPwpq1zbR30LYeNbp9gPYZxxWtJJyMa8nynf0hqha6rFcHa6mNvrkVeyCMg5HtXTY4AAAAAAADiP//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-82.png', linkedinUrl: '/in/randall-cohen-1b5ce9e43e', jobTitle: 'Freight forwarder', }, @@ -6825,7 +6825,7 @@ export const peopleDemo = [ city: 'North Stevetown', email: 'dennis.johnson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0morm6gsrWS5uZVihjG53boBU1eNfEzxa9xrB0SHckFucSEH7z47/AE/xqW7IpK7LGv8AxWvprqSHRESC3AIE0qAu3uAeBXEtr1+l81xLqc7yycmRpCSCfQjpVzQPBepayUZG8uN/mDMM8eorsoPg/bDie8mI64XArCVWPVnTGjLscpafELX9Pu4yNSklTbt8uQ71P516D4Q+IUepulnqUgM7EhZ1ACN6Ajse1Zd18H7Hyj5FzKpHTPNcLr2gX3heZDj9yG+SRBjJHr6GiNVN2QpUZJXZ9GcEZFJXH/D7xY3iXSmS5ZftdvgNjgsPWuwrdO5zvQdXzTeyNq/iG7uZMCS4umOPQFjX0tXgF/pbW3xSk09IysT3u5ARgbCQ3H61NTa5dP4rHsmh28drp0ESIBsQA/gK3VIIGCDXnut3t7bFo4Uum2jKrbj+Zpvhu41dr6GGdrjy5MN+9bJXPY+h9q4EtLnp9bHoUrALycVxfjS2iudBu45YwwKE8j071Q8V3mq299JFb/aGSLk+SeT/AI9arQS3V/bS2s32oM0RylwB1I7EUW6g+xz/AMJpVi8WywRn5JLV/wA1K17XXi/wesnbxLqFy6ECCApz6sw/wr2c16Edjypbi1wXiHSBF40tNUXLMzAtuP3VC44/Gu9xWZrkYWwe42FvLHIXrjNRVi3HQ1oSUZ6j7cW93CQ6L+NV5rjT7G9iiMkUQ3AZYgZPoPWq9q5AIzVS8urG4IjeznmZSfmWAkD6H/CuFanppGgt1p13qsyebHIHOODnB96W+jt7VCEUZI7Vi2s2m2chRLSaF2wN0kJGfTmrt1undET5mbAAoa1sD03GeCNITTLO7kGC1xLuJA9z/jXUmq9hbm2tFRl2seWGc81YNehTTUVc8mq05todSPGJI2RujAg04VjeKNXOk6NO1vKq3zoRbqcE7vXHoKszMKec2Ny0TuQoYgMavBrS7gUSy/L2CmqltC97pFu9y3mSvErSP6sRkn86yLnTJ4W/cllz6HivMurnrq6SN8ra20TCKUlfRj0p+hN9p1IN95UUsD79P61z0OmXTnM8hK+lXTrI8OXum7owbe6m+zyHHK5BIP5irp250RWb5Gd4RTTQrq6hlIZSMgjvQa9AAAAAAADyz//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-83.png', linkedinUrl: '/in/dennis-johnson-a5cf409bc9', jobTitle: 'Petroleum engineer', }, @@ -6835,7 +6835,7 @@ export const peopleDemo = [ city: 'Lake Jennifer', email: 'scott.rodriguez@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDusU4ClxXB/EjxLJptqmk2bsk9wu+WVWwUjz0HuefwqCibxL8SNP0G+ext7c3tyg+fbIFRD6E9z9K5e6+LOp5Uw2tlER1RgzZ/HIxWToPgW81sJciSOOJ+jMM5rql+EnmLiW9jB9ViqfaRNFSk1cbpHxWMk4i1ewWJWbb5kBPy/wDAT1/A16Lb3EN3bpPbyLJE4yrKeCK8u1P4UXcalra8RtuNu8HNN8M61f8AhTXIdG1MD7HMQDIASATwGHtnrQpp7CdOUVdnq+KMU7FGKokkxXinxHTf46dXb5fKjx9MV7aBXk/xC04z+MLa4iIaKVUgcj+Fweh/Aik3YIpvY7TwwiR6PbIi4HljbXUISEFcZex3dtbRw2yyiLaE/dDn8+1VvD51Vb1Hke8EUhwUnbJXnHTtXIl1PQvsjt7jJjOePrXlvj/ZBGkiDEhJVGA6GtzxXd6t9saK2a4EMRAJg+8Sa53WLSa60uETNM6pdICZcbl5wee4qorVMmbvFxPULRWFnBvO5/LXcR3OBUuKchVo1KHKFQV+naiuo4B4rmNd0+KR2yD8sgnB/wBrI/8Ar11FVb+0W5tZOcEIe2c1NSPMtDSlNRevUisJY5YQjjkVJOsMLpGoUM2CSOKzNPkBVfQ9DUGq3WnXGI7rBKNuGFLFT2PHSuaK6HctTTdYX1WeN9hBAYdDWXrUNtJ5cG35SwY49qo2E2nwXUrWs/mSOQCXyGP0z1rRt7U3uqAlhtiG5sjOeaOVt2FKSirs6FF2Rov90AUlONJXWecSAVznjPxG3h3SQ9ukcl1M4REfkBScFsU3VvHGl6axihJu5x/DF90fVv8ADNeaarqNxrF1JcXL7nfp6KOwFaqDZNzt1uGsZAGfajcqT2PpW0ifarVdkqxsRwwrndMu4tc0lVmA8+MbZFHr6/jSC1v7Y+Xaz/KOiv2rz9nZnpJ9YmrdRi1jZ5JQ7j+Jq19AgZbD7S5y053D2Xt/j+Nca0d3Mx+1ybtvJA6ZqnonxAurC0a3uLdLiCGZ0DbiHC7jj24ralG8nYwrydtT1I001g6X4y0bVGEa3HkTH/lnP8ufoehreBDAEEEHoRWzRzH/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-84.png', linkedinUrl: '/in/scott-rodriguez-8a8fffb3b1', jobTitle: 'Neurosurgeon', }, @@ -6845,7 +6845,7 @@ export const peopleDemo = [ city: 'Ortizberg', email: 'katrina.rodriguez@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-85.png', linkedinUrl: '/in/katrina-rodriguez-736608f682', jobTitle: 'Glass blower/designer', }, @@ -6855,7 +6855,7 @@ export const peopleDemo = [ city: 'Saraburgh', email: 'thomas.bradley@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-86.png', linkedinUrl: '/in/thomas-bradley-06ba80922b', jobTitle: 'Automotive engineer', }, @@ -6865,7 +6865,7 @@ export const peopleDemo = [ city: 'Guerrerohaven', email: 'anna.hill@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-87.png', linkedinUrl: '/in/anna-hill-ccdca344ff', jobTitle: 'Therapist, sports', }, @@ -6875,7 +6875,7 @@ export const peopleDemo = [ city: 'Nealtown', email: 'karen.pratt@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-88.png', linkedinUrl: '/in/karen-pratt-7389b464f8', jobTitle: 'Editor, commissioning', }, @@ -6885,7 +6885,7 @@ export const peopleDemo = [ city: 'Millerport', email: 'casey.garza@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDPzSg00CsXxJdvBaRQRkhp22nHUis27FJXIdQ8U+Xdm3sY1lKnDSMeCfQCse41O8uJ/Me5aTA+6g2ge2K6DRPBZ1CJZ2f7MD0AySfc10K/DK1Z98l25P8Asrgn8a55Vo3OqOHla555Z3zWdyswuWAkGCVPIz61tw+IfJnEVwxljJ4kHUe9dPJ8N9MWMhpJC3XOa5PXvCNzYwGS0kLqnO09ce1EasW7IJUJJXZ0aSpKgeNgykZBFLmud8K3ssiz2U6lWi+Zcjt3FdDjmt0zmasyTiuf19o1v7Iv1wcH05Fb9ZGt6a1zLY3IwVEnltzyM9Dj0zSm0kOmm5aHd6PGBbRBeyjFbwJCAc1x149zaQ+VBFO525XyuOg/zxUnh681Z5I47ky+U/OZPvLnoDXnKOlz1k+h01wD5ZA4+tcrrjmOA8E4BJqLXb7Vpp51t/M8iDO4xcs2OwHfrVGKSe5URypMpC5YSnPaqUeopPocpo9w03ieRlY+WVbcB0Jx1rrO9c9oWntaaxfytxGWKIAM5Oc/lXRAc13xaa0PLnFp6iZ4q7bxpdaZLF0dHDg49Of6VRIqezuDazF9u5WUqy5xkGlVjzRsgozUJ3Z1lk8VzbRhwCwUdaJHt4b2OIPHGep5xk1mabL+5jwei/yqvfT2N64WdPnXIDCNiRn3A4rz0uh7Caaui3ZGCXUbmMsjZYkc5zTdU8m1t3ES4ZgR9Kxrd7GwuGNrkOzfxKyk/nU+qz7reUknI/SqasyW9ChaIsUMjDJ8xs5Pr3/CpB1p0cbJbxqQBhegpD1rtpRcY6nmV5qUlboMpKftpVjOa2Ocel0bOPeSQmevpWyZIbm2XfPtDKDlTWBHKLi9ktgFaJUAY/7RJ4/DFMj0a9KE202CpIKk9K8+qkqjPUoSfImbErQWsTFZASO7HNc7Jfi8O1XzGDvkbsKguLTUtzR3Cnb3+bg1YGnNHp0keAJJEI+mRUaLUttyNmRkdAyMCpGQR3FUznNZWjSTtplvb3CkIpEbTKw+VuwI9OnNbZtpIhhm3e/rXo3PKQAAAAAAasf/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-89.png', linkedinUrl: '/in/casey-garza-e265fa80ac', jobTitle: 'Homeopath', }, @@ -6895,7 +6895,7 @@ export const peopleDemo = [ city: 'North Douglastown', email: 'mathew.duran@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-90.png', linkedinUrl: '/in/mathew-duran-667faa2205', jobTitle: 'Mechanical engineer', }, @@ -6905,7 +6905,7 @@ export const peopleDemo = [ city: 'Norrisfurt', email: 'michael.watson@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-91.png', linkedinUrl: '/in/michael-watson-7e29289ceb', jobTitle: 'Scientist, research (physical sciences)', }, @@ -6915,7 +6915,7 @@ export const peopleDemo = [ city: 'Michaelville', email: 'martha.lang@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwBrSfN1rG1O9kk/drIyqONu7ArTm+SN3xkgEgH1rkr6Sc5wcEnkE1x1XdpHZSj1EZVuGZFmIAGAzIcfgaoJNJErW7nIVugPU0KL+7vPskEhwvByM5NaUfg7VdrSHy8Nztz1qdEtTTlcnojPtL2WaTYMhc446AVuwvHb4MZ464zzn8az18KX0Z3lTkeh6VILeSKURy43dnJwR9aiTi9hqMluj0TwxrbXCNC7AEcgZrr4JA3evK9FuVhvIm3oCThggyCPwr0a2cBjzWtGXQwrR6nFkAgqQCCMEGvP72UwXbJHgAMR0yK9A2ndXEaxpM0OplVB8p2BDY9T0p1O46fY6vQdIhhVLthulcAn0FdVGuVHHSuYvLyTTYEWK1mmLLhdj7FXA9am0HVr+d44rpflkG5ckEgehPrXK4trmPQjKKfKdGIlYcqD+FYuv2EP9m3MiwqZFUsDj0qvr+p6jZylLVWZEGWCkAt+P+FT6bdS6jbSw3FrJCwBBZpN6tkdjQotLmCUk3ynM6GnnXcUUKtGCRnHT8K9JtnCkgHocVx3h2zkjlSYuoSPPbJ47V0Uc5BJJ5Jya3o7tnFXVrIyzweajmiW5Ty2xjIIOM4p7nNNhfbKrehBrWSvoZwlytMvWyxyxbJVB9QaTyoo72JIlxg54FJjMhZc8mq899Zwzr5szRyDuoNcVnflPUi1JKSNaSGCSdo5VG7qMjrSlI4VKIoHHboKoWl5Y3Mm1bgtNn+LPX2q/J8kbMepGBRZtqISaimyssCW6FFUrk5IPrTAeafPKZJWYDg1GvWu2MeVWR5c5ucnJlJ+tRjrVtbZ5HCKpZmOAAOSa3Y/B12tnJPPgSBcrCpyT65P9Kp9yF2McH5Fx1xUYtkuGBZ9rL0PerXlAAKo4XpTJoiUEiA9cEjrXnyneVz1aUXGKRLBarCvDhj696fOTsBIOAadHGqRrtyT1JNWYlBQqwyG6g0RnaVwqxc42MlpKFbmugXwu97ZLcWjKrZI2OThgO4NZM+mXNnP5VxGY5MZxkGu5aq55gAAeZLex//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-92.png', linkedinUrl: '/in/martha-lang-37c24a1f79', jobTitle: 'Market researcher', }, @@ -6925,7 +6925,7 @@ export const peopleDemo = [ city: 'Bryanchester', email: 'latasha.perez@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDnuuaZjmpcYPT8aQ4UMx6AE80ARgAYz1PQCieaC3i3yShm7LH8x/HFZlqwvblpC74HOwDcWPv2ArQuLV5dPEpDh1O2OGLnn8KiUjSML9DMi1acXioxcIT8oKjNb3nRyQB0fKnpnjFZ0Xhu+nkDzRlSBu69DVm9uFitohL+7YEeaR39TihNPZg4tbokKnNLtqlBfIJ0gZwyt9xvf0rSC81SdyGrDCDiqOoystmyoQHY4H9a0XHFY2tRsYYpFzhJMt9KHsC3LnhnRdR1GdZLa3ZoWIBcDgHqSa9ZsfD8NnAqsilh3xXK6FE1n4SsG8m7keaNmCWzbcck5J+mK3PDNxd3ClJPtaIwyPtLZYfj/SuKbvuelSVloXpdIVWdgAVYcg15v4n0K5hDEQl4s9R2rrtflvHlkZjeyQxgsUtn27gP6+1NtP38YjFvdwYGSlw24HI9ahPlV0aSipe6zxY5hmjPmn5Dux3GK7q3YSxJIOjKCK5PW9Pa08ST2yRsx8xgiqM9eR/OustFAtogOBsGB+FdsHdXPMnGzsOJULnHNNgjS4ukhkICyHZkjOM8Zp7qB3qtICGyp5HStGrqxEXZpnrOhRRppFvbMgBiQJtPYjirBaFbnYpVVUEk9MnFZGh6guoWi3EbMezhuu4AZpbu502cgzQSmRQVDrG2V9cGvOd72Z7EEnblLdi0ckrxuVJPI7g80++WOGMlQB9KyLK5022k8q0hkjZzwPKart3ucYY9OtZvRWNGrM5dtLifUbi6kCs8yBVYD5osD72fesQHdIxHQkmtC/16QX19pkUChYwoM27k7hnGP61nwoevauzDwaXM+p52KqRbUY9LjD055qGQHtVtQMHcM1G67u1dRxl7w3q50y4eKUkQSnr/AHT613/lw3sCkzbeOCvWvMYraSWVI0XLMQoA7mu8jtS0PlpMySwOYXYd2U45FcmIik+Y7sJUfwloxR2oyJNx9apySmU7VOfU1Gun3fnkTybk9RV9LVYk2gda4md17nB6jaiLVbyQA5kkBY/8BA/pUcZ5rsf7Jik1C8ugu5nhjRkY/KxBJB+uM1PH4XspwjmOSFiMsqN/jXoU6i5UjzJSfM2j/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-93.png', linkedinUrl: '/in/latasha-perez-a903374657', jobTitle: 'Teacher, primary school', }, @@ -6935,7 +6935,7 @@ export const peopleDemo = [ city: 'New Jamesborough', email: 'james.gordon@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDsDIqttHUnG7vUU6sgysyZP51ZeDDGQjOOmK4Px94gOn2wtbU4urheW/uL7e5pMCXW/iFYaPI9vDG95Og5MbAKp9M1x0nxW1d7neltbJH2QqSfzzWtonwwvL7T4rq6uFjaYb9vcDtmr0vwhi283gD/AOyuBUc6NlRkQ6b8ULO8lSG/tvIJOC6NlfxGK7i2mivFVovLeJhlWUcY9q83vPhRPAjNDeKxHTIq34UvL7wz4gh0PU2MlrdDEMg6B+3054/KhNN6EypyW56CiukzRxqeeRmmbnVtsowx4JBq3KI0YNJuBJx1wagliWQBhlR1GepqmuxkWrmbyUC7WB9a8s8SQC88dRRSg7F8sYI7df616aVZm+bJz0zXJz6S03xAgmf5onQEMOmVHI+oxUzlY1pxbZ3dsAIlQHAUAcdqdIydFkyfrXFeI728hmeOE3u1VyFtl5+pP9Kx/DtxqlxqMdu8l1tkwx805wPf0Nc/S53X1seh3KKYyGfBPQVwXjGPZZecq/vIWDK4HI/zxUfivUNRstTe1je5CoOTAMmqrSz3+j3UDvO5CA4mXDDkH8apdyZ6po9AimM6x+dg/IpJ29TjmpZDGHBUMSvBGaRDHJbxOHAG0bcHqOxpqwAyb2YA9etbrY897l2eJWAPQDpk9ayoYmt75QI1EKlpA+OWd8k8+3T8RWpKGPPc/pVSeV8IhC/IfmJODWdWN9Tpw9TlbT6l6SK1ubU/aAuD1GOtZtpPo9tcOsRhgVXCgk4Ln29aq3cztbyBWwVUkAHrXMzONRskSS1m/dnKFbcnB9Qf61jHU7L9jotTm0651Zy7Ruj4HuPf6VHdWltDE0cIB3LiuOwtjMZV85iVw3nREbvoa6CzkkupYEGfnxjPam07icrLU6W2t/KsIIAp2xKF3d+lWWChcRjGPWi3kydobgDGPWp2ZDl0j+buc8V1JaHmSd3cWWMIxYNz2qhfSRRRR+bw1w5jjbH3mAzj8qvRJLeEokRLocc81vy6FbXmkw2c6jdEwlRwPuyD+IfmR9DTkm1oODSkmzze53gGNyFJGA3qKlfbcaf5QulhdVx69K0Nb0iSFvIuI8ejDofcGuD1aK8srr9y0hjxgMvP5iuNb2Z6F3utjXkUW0D77lJnI6Dqa0PDtn55Nw/EaDaoHr3rkrKCe4k3yySFf9riu18MzmSzu4SmI4Jwgb1yoJ/nWlNJyMa0nym7DaiObzNy4PRDUzKrK2cKv86iMjDAIBBPJpSduVPPGAOjY5D/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-94.png', linkedinUrl: '/in/james-gordon-c6aee9e0e7', jobTitle: 'Illustrator', }, @@ -6945,7 +6945,7 @@ export const peopleDemo = [ city: 'Jenniferburgh', email: 'taylor.johnson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwBshqsx5qRjmq15cpZWU104LCJS2PU9hXKdBU1LVrLSgv2iQmRuViTljWHceLLxseRarCnZpAWJrmy93e37OkRmuZGyxzkk+g+ldB/whfiSaJZpIMBuo3Z4+lXotxavYdD4xuI2YzRRSfT5QK2NM8V2N5MsN1/ozt0bdlT+PaqP/CstWNuZGljGRk561yV5aT6fM1rdQsChxmj3XsFpR3PX/IiIBByD0INILZSeprlfBOqtJZy2UkhYwkNHu67T2/A11YuQDyKkZWYVy3ja9a202C3jPM75P0H/ANciusYVx/je3M0mmL0VnZSfyojuD2N/4ZeHQto2p3CAyyn5MjotenmPYoG0fhXERXf2DSbcGK4SPyhthgQlhgeuRVjSdYuGePatzIkhACSjDLnnvWEtXdnZC0UonVSA7SMfhXn/AI+0dbvSpJo0HnJ83A6irmpanNKDNOLvyQxAit+W4ODnFVLm8mMBNtFLKeFMM4I4JA689jUJNWki5NNOLPNPC961v4itgfuyExt9D/8AXxXqflqfWvMYLAweN0hVCqrc5x6DqK9QArrlrZo8+KaumNIqrfWAvfswKbmjmDj24NXRUiSLEfMZC4TnaO9S0VF6nR29ur24xIFHXBANQxSWdtqCefNGrZIjBwCTjnAos3W4tY5omBSRAw/EVVub9chG0tpNoI3uVGR7Zrm8j0Er7DrY2093KsE8ZR3J+XBw3f6Gpby3igjyTuI57Cs+31JPOMa6dJE7fxKAyj8RVi83OhDN061L7F2scxDpwGq3N8T95gAPX5a0M4qlpurw6s1yLdCI7d/LDE/f9T9Kv7a6YJpann1ZKUtAxUkYB4NNJUEgEHFVoWluYLueN9qQEDAHUnp/I1rYw5kW9FLadYPbeb5scMrKCDnaDyAfwNbgnsbmICXn2zWJ4VgjNrqEDnMhumdie+VGD+lSX+lSI5MTfLXJN+8zvpN8qL081rbriE5PpnpWFq94TplyfNEaCM5kPRcjGakispWOHbj2GKr+IrNH8P3kBO0NGRkdqhWuaybs7GZ4S0g6ZZyKX8xZMMrjofpXRhM1heExOmmi2k+ZIUBz3Fblve2k4BiuEOenOP513Pc8AAAADzFsf//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-95.png', linkedinUrl: '/in/taylor-johnson-505c92efc6', jobTitle: 'Hotel manager', }, @@ -6955,7 +6955,7 @@ export const peopleDemo = [ city: 'Christineville', email: 'george.thompson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDt6THNLSGsTQrXl/DZBd/LN0Udcetc9qOsSNbPLnKdlU4A5NM1KWS/1dUtcMOUYnoFHX9akh0G58l4hsWNznnJrNzSdjWNNtXMaPVRNGR8ijPIBwRg5pXvm8mSa2fy3X+JTgj8a1JPA8ZJdJTuPUDpms670S4toGjiAbA5XA5pOaK9kzU8M+KWvpFsb4r5/SOUcCT2I9a6uvDZY7i2uGZMxyI25T05Fev+HNRk1XQbW7lH71lIfHcg4J/StIsykrGpTHBKkDrin0UyTldChy8jn7wbaxx0rqI40CD95n2rhdTmvLQT/ZWkXfPIQI+vU9/wp3hrUdU1Cf7NcrIrbC4LDn6GuWUdWzug9Eju2VQuRL+Gaxb8mPdjlvWuO1TV9ZS6kW384iLqEH3u3HrV6wv7+42x3CSjP9/1+tJx0uVfWxg61Khl8wY3ElT9c967/wAIxvH4ZtA4AJ3EY9CxriNe09m1CPySAzctn1rufC9yJNLNr5bobQiI7+rcZz+tbwkrJHLUg9WbNIaWitDExfLgN3cQOo5ctz055qaxazt5LgoyLsXbnIGTVXV4zDdiRSf3i5/KuXvpbOdsC5aL5drbc/N654965nF8zR305JwVjqbZrGe4NvLsMhXcpGCDTrowWQIjTnHWuX0q5060gWCFkDF9yt0OfxrZunIQFiCxFQ1bQu5l3EK3d784GSpUH0JPWuu0K2+z6cCc7pDkk9TjgVyEM0UepWqzzGOOWdYiR3J6D9K9BChQABgDtW1KP2jmr1NOUbRioby8hsbV7idsIg7dT7CvPtb8UahfRkW0ht424VUPJ+proUWzlbsdD4n1zS7fy7NryMX275IlG489c46VSSCV4Ea3uFQcfiK80hjK6m8zku+MFic8966HRJp5dLZIpW862dkZSc5Gcg/kf0rOtTt7xvh6rvynWPAIoi1w8T/WqM96ZgVR1Z24GK5+a6vbzcrAhe+TU0TxaTatcztl8ce3sKwsdDnch8QyiJ7O0VyZI2892HrjA/mfyrc0r4hzxDytQg+0KBkTIQrY9x0P1rhp7h7qaS5kPzyHn2HYUgDGYIBlU5P1rtpw5Y2ZzSuj/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-96.png', linkedinUrl: '/in/george-thompson-0b7979e007', jobTitle: 'Engineer, mining', }, @@ -6965,7 +6965,7 @@ export const peopleDemo = [ city: 'Millerhaven', email: 'william.gomez@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-97.png', linkedinUrl: '/in/william-gomez-bb381032a2', jobTitle: 'Medical physicist', }, @@ -6975,7 +6975,7 @@ export const peopleDemo = [ city: 'New Connorbury', email: 'patrick.beck@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-98.png', linkedinUrl: '/in/patrick-beck-a53d364316', jobTitle: 'Patent examiner', }, @@ -6985,7 +6985,7 @@ export const peopleDemo = [ city: 'Jeffreyborough', email: 'timothy.parker@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1OoLu8t7C1kuruZIYIxueRzgAVOa8U+Leuy3mtx6NEzC3tVDOAcBpDzz64GPzNSNF3xF8YnZjBoMGyPvdTrkn/dXt9T+Vefz+I7+5lkM+q3jTSnBcTMAf/re1bOjeBLvUraOaeWOFZBkLs3HFa5+FSFji+bHYbAKydWN9zZUZtXsczpfjDXvD7/uNUl2ngxyt5in8DXqngf4kR+IrhNO1CFYL1lJjdT8s2OoA7H2rk5PhbbmI5upN/wBM1y+reH7/AMLX0F7byyMkbgpJGcMh7GnGpFuyFKlKKuz6TpK5zwR4gfxJ4aiu5sfaY2MM3GMsO+PcEGujrQyFr578WRfaPHepu+MG6Ix7CvoSvHte03zfiFOXTME1wrI2OG4+YfgQaibsi4K7Os0hFWzi4w20cfhWqM+n5CuW1J5oQQi3LAAsFt+G4Hr/AEqTQ7y+Dos0k5R8MBMQWXPY4/lXFy6XPQUuh0T5x9a5LxcinSpCVyBjP51Y8RXl63mCCSbZENxEJAY/T86zbdJb2Ca3nM5V4eUmIJ5HYiqStqTN30Nz4ULt0C+GCP8ASyQP+Aiu8rkvhzB9m8KqjACQyszevbGfwrrTXatjz5bi5riNVs0S9VifmgmZxkdd2R/Wu1rN1XTBdxPIhAcLzkdccis6sHJaGtGai2n1M2CKOWMHHI9e9RXBgimVcohyOpA5qOCQqoKntkVQur2zkkKXCFmU/wDPMn9a5Er6HeXlEMmpSpuRs+hzzTbyKKBCUUBjWXFcWUcxFudsh6BlIzWiInvrqKFWwzkcntTs72E2ktTZ8MWwt9NO0kqzcZHoK2qhtLcWtrHCDnaOTjGTU1dsFaKR5tSXNJsKXGQR2IpK4n4gatI2mNpmny/6RIy+YUfGBkDaT71RJA0/2Z9rHCZIDdqtgRzx43YyOCKqw2gk0xYWAyqgflSDRLjYGtrtlU9iMgV56auekromeKOBTyCfU1o+FwJ7qec8+WoCn3PX+VYE2nXEbBJ7kyMTyAMVVn1m68P6xp8sGTbuzRSx9mGMj8eDV02udGdW7gz1A0lU7LV7DUQPstzG7EZ2Zww/A1crtOEAAAAAAAAAA//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-99.png', linkedinUrl: '/in/timothy-parker-fa652d4471', jobTitle: 'Therapist, drama', }, @@ -6995,7 +6995,7 @@ export const peopleDemo = [ city: 'Port Emilyside', email: 'nancy.mullen@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwCxlj0qCQFgeKtKuFxUTArlmwAOTWT8zValLySSPer62KR2zTSo5CjPArnrzWhHIxXJIOFVe5q5Z6Tq+r2R81DDG5z87k8fnXJKrJvTY64UUlruT2gt7rzA29TyVyRhhUY8tjx1BxWifDt1p9tE9tIrtEDlSODnrXLXd9cW1429H45aNuo91PehVJcw5UlY2W2nikHApLWVLuIOpBq0YMjrXVGV1c5JLldjQkYbcisTXdR+zWZRfvsOB61pMSBxXC+Kb4reHByV+VQO5qKu1l1LorW76G74R0Nr24F/dDci8RKf1avSI1QRqA3SuEivZdI0GzRIZZZZIV4Q7QOM8mrfhzUby8uoopxKA/IDtnHsa5bPc7k1sdhKyrGQG6+9ch4k0xbq0d1XEycqf6VW8QajdQ3j+R57qn8CPgHB/U0+z1J9QiKPBLFIo+67ZBGPWiztcd1flOb0S88qcRM3GeD7GutQ5HNebyXDWOsTQt0WUlfoe1d/Zy+bapJnORW9N2du5x1VdX7FyY7UY98V5dfI1/4hWHna0mBivUL5SLSQ/wCyf5V5eZxa61DdtuCRzBiVGTgHmqqP3xUl7t33PYrMxPbJG6KcKBz2qaB7S11BRlUAGf8AeNZelXtvqduLq0lEsZJG4AjJB54NM1DVdLgkSCfLT84Krkqe/Ncivex6OjWhdtRb3M8i5RuSQw570t0sMCsEUDjqKzdM1LTpZHjtWCvu5BGDmrWoMscTyucKilmPoKHdaBocTrtrGoubjaueGLY5B6Yz+tanh6Yyaeqt1Cg/0rlNZ8TjW4Y4LaBorffkljlmxzj2ro9AYxyBQPlK1rrFq5zTammonUX5/wBFaMYLSDYv1NeYapb7Jth6DJNekaw/kIWHVF/ImvOdSc4klbgkECiU+apoTCFqeptfDi9lR760JHlDbIv+yx4P8q7x7FblQQRkdD3rz74dwP8AbL2baRHsVAfU816KkJ2ZQkVNT4zai2oohWzS1Ofl3etc941u2i8N3uxuSm0n6nFdJJEzDkkiuS8cqT4cuEQZ5UnHpkVMdZIqo3ys8+0uLevA+62f0r0TQot7RYHB9K8/0Yc/WvU/CflMkgcDcACM1rU1mlPSFz//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-100.png', linkedinUrl: '/in/nancy-mullen-db4e1644e0', jobTitle: 'Chiropodist', }, @@ -7005,7 +7005,7 @@ export const peopleDemo = [ city: 'Rodrigueztown', email: 'amy.weaver@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-1.png', linkedinUrl: '/in/amy-weaver-f6b74416f5', jobTitle: 'Cabin crew', }, @@ -7015,7 +7015,7 @@ export const peopleDemo = [ city: 'North Benjamin', email: 'matthew.crawford@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0q/vbfTbOS7uX2RRjJP8ASvEvE3i691y+fa3l2658qLccD3OOprqPixezJcafZ8mFkZ8A/wAWcZP4dK8/ttMkvZIYUUkseR3/ADrnnLWx0U49R9vKZ5hvlUL/AHwcc/Q1PM89nJ8oZlfq6jcpHuOxrXt/BU92SJAREvAB4rTg8APGQTfygj+EHisudG6oyOWTxLeafciOGZkI+aNgcjPpXsfhvXYtU0yJpJV8/wC6w75xmuPT4f2XDzMXk+tJp+mtpXi2ygyRaTt8v+yw7Z/z1qo1FeyIqUWo3Z6dRS0V0HKeV/E5idfiLc+XaqIx7ljWR4TBF4kjHc7d/QV13j/TBrN/DBGpE0EG/fnggt0I/A81j+D7Jbdbrev7yNtp+tctSS1R20qclyt9Tr0OV4FTLg9DzXKatqN3CzJCs5wM7YUyaz9L1DVnuUikeba4B/eAZA98dDWKjpc6+bWx3jKGHzHArn9ZnNtLaygZKXCFffmqHibVb/TpY4YElZnXdmIZpdGNzqF5bR3zSbUnjc71A53DGPWqitUzOo9Gj03OecUtJRXceWcz4q0x7kpLEcCQqkvuAen6ms+2hhglkeKPyzIQWHviu1eNZY2RxlWGDXIT27WV5LE0hb5iQT6dv0rkrQs+ZHoYetzRUHui0sUc0ZLqMehqo5tI52ghVd6ruY9MUs0jiFtp5xmsGaaxmhZLhXYZOSYmOffpWMVc67o3btrXNu8xRlI2noce9WrOOL+0IIkUbdwbj25/pXHxy2KHZ5jSMRgblbge2RXV+Gone/3OSRHGcH68VpFe8kZVZWg7nV0UUV2nkjhXM65EWvpCvXAP6VuXt79jjUrH5rsQAgbHHc59Kxrl2nneR+CemPSsK8klY6sLFuV+hil2YFS2OxqXY0sWxXVRjgntUN7ZuzbkJBPpWBdXN9bzeUEckdxXMjt5mjbmtTAhLTrJn8xXU+HrJ7ax82UYkmwcHqF7Vw1pDdSDfO2T/Cvv712vh/xDDrGnrJLthuFJSRCeAynBxW9FJyucuJlLl8jbpBS5yMiiuk4AAAAAAADiP//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-2.png', linkedinUrl: '/in/matthew-crawford-65e6eb72da', jobTitle: 'Technical author', }, @@ -7025,7 +7025,7 @@ export const peopleDemo = [ city: 'Boydton', email: 'daniel.graham@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD101w/xF8XJoGkPb21yiX0uF4b5kB749a7V9xRthw2OD718oeJDcvr19HcyNLItw4bceSQxyTRJjiguNaubmT5pnky24l2JyapTXMksm1hnv8AN2q9pWi3GpypFboMn7xPauyg+GMkgBmu2A9FWsnUitzaNKUldHnK3k1vIV656j1rrvCHiyXw/qhnglkEEq7Zo15z6EDpkVtz/C1Fh+S4Yt15FclregXmhjmMvHnAYDoaSqRb0B0pRV2fS2i6xaa5pUN9ZTLLG4+Yj+Fu4I7EVoDrXl3wVOdGvy0v7wyruiz04Pzfj0/CvURW6d0YNWZU1eee20e+ntV3XEcDtGPVgDivlDzTd3JllYtJI+XJ7k9a+tp4/OgliJI8xCuR2yMV8v8A9gy6Z4u/smbkx3OwsP4gD1/SomXTV2enaDaQ2trGsMSoQozgV1UIbYM1wOoXF1aLiD7RuILKIcDoPU1b0DV9ZaeG3u23LKAysw5UHsa4eXTmPSUvsnbvuIIrjvGkanQ7klQSFz+Rp3ifVtWtpXhsywCDLlACT9Ky5mu7/SL2G4a4MnkNkSYIOVzwRTUeopPeJW+DD3Evim7dWZYfsxMigfKTnjNe6CvLvgrp6W+hahef8tppxGc9lUcfqTXp4Nd8djzJbhmvMPG/h5Y/FNvq6LhXUsfd+Af0/nXpxrJ8Q6U+saU1vDIsU6sHjdhkAjqPxFKceZWRVKfJK7OUsUgu4gsiAnHelkghh1CGOJQCCCSO1ULVngdl5BUnj6VDc3WnXU6me58uVDkFWOQa89X2PVVmjoJoIH1CSOVR82CpNRX9vFFbtEiqNykAD3rLtbnTonYi7EsrY5ZuT9K2bKAajqUMT5KdWAPYDNOzbSCTUYts2vCWlxaR4btLaIdV3sfUmtqkVVRFRQAqjAA7Clr0UrKx48ndthQOtR3VzDZ27z3EixxL1Zq818ZeKY9athpdsZorRmBllVyjuAegx0FDdkCi2xurObXVrsZ+UTNz+NLBELo7hKqk9Gx0qCC0jNuIkGEAG0e1RLp0+XFvNsYc7T0rzebW560U4pGqbcQIS0iucdcV0fhSEPFNdnk58tfp1P8ASuRgsp9gNxNvb+6OlP8A7Y1Dw9d213BI0lpJKIp7VvukHoy+jD9a0pSSndmddSlB2PTjRise08Tabd8GYwsf4ZRj9elayurqGRgynkHeeYf/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-3.png', linkedinUrl: '/in/daniel-graham-a67e125f10', jobTitle: 'Technical sales engineer', }, @@ -7035,7 +7035,7 @@ export const peopleDemo = [ city: 'Emilymouth', email: 'teresa.lang@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwC/4z8aR+HEFrbKkt/Iu4BukY7E/wCFeTXF9Nqk5utRneaRzx5jf06Ae1UdR1G41G9lvLljJcztvYkdPQfTFNiufLkG48/TJrCTbN4pIku4hv8AlRSnu2KQwoYSyhgq9RjkGu28JeBTrai+u3cW+cqD/FXfr4P0e3ICWaehHrWLqJG8aLZ5d4W+Id74fdLS/wB91p5PHOXiH+z6j2r2i0vLfULSK6tZVlhkXcjqeCK4nXvAGm3lvIbeLyJiOCnTP0qn8Lbi9tZNT0K63FbRgyA/w5JyB7HrWtOopbGNWk4as9HxThSUorYwPl5nwnB69z1rofCWlR6jqUXmxGRc/dPeug1P4dW62Mc9pK4nJO2GR87gPw9a1fAlnJp1nLcyWnmlm2bkPzJjqMGuSVVOOh3xoSjO0j0iwVIbVIUQIEGAqjpU8oIwTXL3XiJIiY4VlEpO3YylT+o/lWFYX+o3euTRRteoIyQwd8ofXGcVhZ2Oi6udvcJuQk8ZrltCi8vx9qJXgSWSM+O5DkA1X8T6texolvZTHlN7FRhmHcDNO0CO60xxqwhdoJVEMsBO6Xg53A9+T0rWgrSuYYl3jY7nFKKOoBxj2NKK7TzzjvB2t2+vaNFKHiN5CirNG33gR3+h61oWcP2VSAAFMjNx7nNeG+GjN/wkNo0QdFMwDbCeFJ5/CvdbFAsQgz9wACvOrR5XZHrUanPG7L08S3cS4RC6HcMjrx0P51Sit1iYwm0WOSYFS24HA9gK0I4nXGDVSWbTl837Tcr5g4OGwV9uOalGlivrOnxubWRI1xEvl4b0qbSbQzIHlIEcUmURe5A7msGW7tml8uC+eZMkpGzE7fz5rsNPh8ixhT+Lbub6nmt6Ebzuc2KfLCxYNAoorsPOPOP+EDOhavBJFMXt5F3sSBuMgPI+neusnhaJRPGCSOoHpXRXtqLuBoSPnGHQ46GssOPuMMEcMp7V51VNSuenQknGy3KkOoJKAocBunPappYA9syDbjFUdT0xZ8GEiJ+pf0FYM1/e25EUU7SZYIgI+8elZo3uX4NLL6vHEMFQctj0HWuwrFsraWykLGQyOww5I/StdHDrkV3UFZa7nnYmbnK/QU0opKWtAAAAANzmP//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-4.png', linkedinUrl: '/in/teresa-lang-584a181fe2', jobTitle: 'Solicitor, Scotland', }, @@ -7045,7 +7045,7 @@ export const peopleDemo = [ city: 'Lake Andrew', email: 'anthony.brooks@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-5.png', linkedinUrl: '/in/anthony-brooks-b32a3564da', jobTitle: 'Aeronautical engineer', }, @@ -7055,7 +7055,7 @@ export const peopleDemo = [ city: 'Keithberg', email: 'thomas.price@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDuaKMVxHj/AMYXHh/7NZ2AX7TMCzMy5Cr0rM0LGufEXTtG1F7KOF7qWPIkKnAVvTNcHqPxM129m/dTR2iiQMkcS+nYk8msnR/DOp+IpGnDhYmYkyv/ABHvj1rrofhPG0QMt+xkPPypxSdSMdGXGlOSukYKfEjxEJtz6gjM/G0xjav0rvfDXxCstUdbTUMW12cBT/A5+vaubuPhQiQ7hfN5oH9ziuO1fw/qOhusjnfGpwsin7p7UlUjLRBKlOKu0fRJpMVzngXXpPEHhqKechriE+VI394gcH8RXS1RAteS/E9fP8TWkTcoluCQPcnrXrQFecfEPThN4i0lgD/pC+Wx7fKw/oTRew0r6Gr4egSDTIERcAKMAV1MRPljHP0rz+8uJ7SUxRtcqqjKJbR7mPv6Vd8PXmqvdrFO85jY53TKAQPTiuJrqelF/ZOwmzt54rivFcKNpswYbhjnil8RX+qLemKBrjy0+8YACT+dUIJLi7JjlknZNvzx3CBSP6Gmlb3gk7+6J8KJ3jv9TsVI8ny1l/4FnGfyr1AivN/hfaNDqmtkj5YysQOP9psfpXpJrsPM2YCuT8WWhbUbO7ZshMBVPbGcn9RXVg1m67avdaa/lgF0+b8O9TNXRpSlyy1K1h9nnhxKqdOpFVJ9T061vo4jIsKhsLkfe96z7d5fKYRt0GcVXN88snkyabPLt46KOPx61xpXdj076aGnDqWnT6lMhkSWNmwcD7vuam1NLaCAiFVCkdRWD9p8u4CJplxEx4GFB498VcvwwgALcBcmhqzC+mpd8F2At/tt0D/riMj8Sa6s1l6DZPZaYqyDEknzkenHFaddkVaJ5dRpydhAadjPB5BpoFSAEVRmcHej+zNUntgTsVsrn+6eatxC1uI8PIQG9GxiqetyyXut3KtEEMTeUpHVgO5/OsaRZomO3eMelccklJnpU5S5U2dFObW0j3RSEkd2OaoCY3d7bQA7hJKob86yolnnbLKx/wB41eaCa2CPE5jmByrj+E+tLRMb5pI9INNNVdImuLrR7Oe6AE8kQZ9vH//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-6.png', linkedinUrl: '/in/thomas-price-d5c64ebc73', jobTitle: 'Counselling psychologist', }, @@ -7065,7 +7065,7 @@ export const peopleDemo = [ city: 'Barberhaven', email: 'william.king@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-7.png', linkedinUrl: '/in/william-king-f1790dcb3a', jobTitle: 'Medical laboratory scientific officer', }, @@ -7075,7 +7075,7 @@ export const peopleDemo = [ city: 'Rodgerston', email: 'joseph.ramos@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-8.png', linkedinUrl: '/in/joseph-ramos-c3050c9ec5', jobTitle: 'English as a foreign language teacher', }, @@ -7085,7 +7085,7 @@ export const peopleDemo = [ city: 'North Ryan', email: 'michael.johnson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDIzTG61IBQQKAMHxBqzadCsUAzcSDOf7g9cVxsssjgyTOzZPc8mujvdLm1bxRLbRHspZv7oxXQWfw1QkfaLosnUAKM1nKpGLszaFGU1dHnG/0/SiJsMDnqenevWbr4Z6dJHuid4yByQa5XXPA0lhCJLQvKRndmpVaLKeHmlck8P+IhM0dheEmQfLHMTnd7H3rqkTmvJIJJba8D4w6MGGfUV6/aOtxbRTr0kQMPxFbGBWwMUw9eKdTaBCaRAF1O+l2jczJz7ba7S3XKBs8Yrg72C58mSW3aVQXA/dMASdo6k1peF5tcadLe7OUkQsGcjcvscVxVI3bkelRlaKidhMW8s4zj0rB1bzXt3SL75UgCuf1a58RrqJEck7QBgMRY57VpWLXso2XHmYTP31AP5jrUOOlzTmu3Gx5TqVq0dyQ6lXLEFffPSvVdOiMNhbxEcpEqn8BWO+lW9z4nlnuVzAhVgCDtLHufbiuhgSURnziC4YjIGMjPFdcKibscFSi4rm8zNKmmYqw2KiK1qYGnpLQhWilAIfsa3dPgRLx/LVQscZxtAHJrkFcxMGzjBqnNq019IzQXP2XClD82Gb9K46kHzs9KjUTgtNTuYIbaeQxzKu4DcNwBqPUZIbaFlQDJGM1y2i6pFp8AhYrI5bHmCTcT+daeozKQSTnAzk1k1bQ25la5Bp0kbTXOXHI6HvxirYPFZmk/OHkI69P8/hWmBzXXRhZXOCvUb90yzSU49aAvNbHMMdN6lemRjPpVO2a9KGOFoI7iI7Cso+Vvet7T9Mmvn+QYQfec9KPEfhxY4YJ4XkXHyGRTyDnv7f4VlVStc3oSalZFDElvbs95LbPMR91en5Vm/a21FxCkhZc4Yj0qhNptwZtk1zIVPUsev5VuabZxWqAoPxrlbS1O33pPUc3nwTJHaoWZsIqqO+cD+dbt3ZT2czbkPl5+Vh0xV3w7pbNN/aMqfKARCvqe7V04iDcMoOeOe9dNC6jPQ//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-9.png', linkedinUrl: '/in/michael-johnson-442bf8f6cc', jobTitle: 'Phytotherapist', }, @@ -7095,7 +7095,7 @@ export const peopleDemo = [ city: 'North Shannon', email: 'lisa.farmer@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-10.png', linkedinUrl: '/in/lisa-farmer-7e00712bfa', jobTitle: 'Trade mark attorney', }, @@ -7105,7 +7105,7 @@ export const peopleDemo = [ city: 'Annafurt', email: 'beth.tucker@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDtB0ooHSmSsUjZlxkDPNZmhwnj7xU1lGum2kpieQnzZFPIHoK8snuzPJ5LDK54xya2dZiuNe8TzKEbzpHwqE4x6ZrpY/hRc/2YJRchZgM8DHNJzUdyo05S2OAeEDMkrbQPux4zU4eSKAuSQQMhWxjHtWjfeDdVtnIli3Fe/r7ismUy24MbAYTjPP5U1JPYThKO6ImvlJwAR7jtXovwz8WraXg0W8f9zcN+4fPCP6fQ/wA/rXlwfYTvwfY1NbySRkSIdpX5lweQRyD+dVYm59NjpSMQFJIyAM4pR0pagZ5D8PEbVvHF/fTgblVnC46ZbH8q9rWMhFTGfavNbvw4/h/V76/0mOcLcorDymx5b7jkc/w963/CuraxqNrLHewPFLGm8SN/F7H3rnqr3rnZR+Gxv3lqjoUdAcjkYrx7xl4Pu4rqS7swHibJZO4rf1XW/FKX7NGsvkL2jQHPOOK0bKW+v9yTxznt+8Axn6ipTcdUaSSl7rPDSBG5BGMUwMQeOMV2Hj3QBp2pxzQJiOf72OgaqFj4ckm0+e4mBURqeQwyvHBx3Ga6lUXKmcToy5nFH0GOlKKB0pQKZmSQ7C7LIBgjvQxjS2maLaM/KAMD9KrzD5c9xWTfHSbgFJLmRcHDiInnHbiuaonzHoYf3oKxtWKW1x5kThd6Y3KQDTL2S3tEPlKo7cVm2F1pUK+TZzL5jHOCx3H8+abfAvI248CsW7aG1lcwNUtYdVbFwm5A+4D3rC8XXEGhaG0WFF3dIYo0XshPJP8Anqa6SVc/IOprgNU0G713xTd21vMoa2gQ7pmJHPQZ7f8A1q0ormlZmVafLFtbntwHFOx6UojIGTxSnCiuyx5pA6FgRVNLV5EK/aBCyHBx3q+XyayL9ftAuJlkMaW0ZZnXuR2rOpC+qOihU5GPmAs1yXjZj3xyayri/ADEtlmqG9tr6SJXinZ9wBww5xVe006UuGn/AJ1xM77lu2jaQGVh16Vy8ltq48U395pKq7+XGrRucLIBncPr0rsppFt7Y4wMCm+F7XzheXOPlBCA+pPJ/pWlK+sjGs07AAAAAAALRP/Z', + 'https://twentyhq.github.io/placeholder-images/people/image-11.png', linkedinUrl: '/in/beth-tucker-366a3e9978', jobTitle: 'Site engineer', }, @@ -7115,7 +7115,7 @@ export const peopleDemo = [ city: 'Gillview', email: 'gerald.olsen@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-12.png', linkedinUrl: '/in/gerald-olsen-ec232b4b08', jobTitle: 'Seismic interpreter', }, @@ -7125,7 +7125,7 @@ export const peopleDemo = [ city: 'Michellemouth', email: 'donald.turner@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDscgCmk5qPd70m6gZT1PXNN0aMSX91HDkEqpPzN9BXlerfE3Wbi+32LC0tlYhFVQSw7Fs96ztVS78V+LL2VCoRZCgY9FUcD+Va9v8AD1mClr/PcjZUSqRjuaRpTlqkYa+O/EQvo7yTUpH2HAjY/IR6EV6n4Q8Z2fiKDyZNtveqf9WW4f3X/CuOb4ZJsO29Yt1AK8VzepeG9S8PsJQ52K2d6dV9DSVWLejHKjOKu0fQIIHU09WTvWD4e1M6roFneOR5jxjfj+8OD+orS3VoZEYNUtYllh0W+lgJEqQOyEdQQDU4eklKvBIr/dKEH6YoBHlvhGPbp+8g7nckn1rvbQN5YPtXARPNYaZbJbltxU8qmSeT61p6JrmpyzxwTREF+jEbeK4ppttnp0pKKUTvIGJB9/5VheKmQaROCuflrJ1rWdX0+5MNumAOSQm4mrVrcT6pZSwXiyb2jOfMj29RxUKNtSpSTvEl+Gs8r+GnWRQI0nYRnuc8n9a7LeB2rl/BkX2Pw1BAVwwZiffJz/Wt/wA2u9O6PLaadmJn2pwPbAqIbqeoY0xHGtDFZX8tpKqlVb5c+h5FTQ+QdShjhAVVYFmFP8UWxiv4rgDiRMZ9x/kVhcTTLmGXIzgpj/GuKUbSaPVpS5op9TsrxrP7UY7lUIdiEY4PPpmkk8hUWKActxxWBbmGO3MclrP85BaQgE59etaVjFvulG4kD3qOW7sXKSim2bFvGtvbpEi4CjGKk3c9KQmjNd6VlY8mUuZtkm6gyrGNzsAPeqE2pwIf9TdKv95ox/LOarRXVtfEmG4WU91OQR+BrKVZLZFxpN7mbr+sR6kiW8CNtjcku3GT06VjwtbsQk5YD0BxW3faX5spmgH7wDDJ/e9x71iXVkzOPlII4K9DXO5czuztpxSjZGjA1oqEQFyD2Jyc1q2CtAyuRyR0rM060jgIZUwf9o11djpkt0iOymNOu49SPaou09C5Wt7wsENzcW/neTgbiMK2cgd6acqcMCCOxFdRFEsMCgKAqjCj0FQXDWYXE7Rj/eIrojXa3OECVNN6H//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-13.png', linkedinUrl: '/in/donald-turner-b84598e436', jobTitle: 'Music tutor', }, @@ -7135,7 +7135,7 @@ export const peopleDemo = [ city: 'Millerfurt', email: 'mary.robinson@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-14.png', linkedinUrl: '/in/mary-robinson-173a75d1ef', jobTitle: 'Public house manager', }, @@ -7145,7 +7145,7 @@ export const peopleDemo = [ city: 'West Melinda', email: 'jason.johnson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDGpMgAknAHWnY4rnfFt5Lb2cUMTlRMSHI6kelZFiaj4qit5lisoxO2fmdvuj6etU9Q1vUJIA0jxwIeQIm5NYdlGXm2jJHTLdquHThcs23eiqOhHWk2Wo3LNl4tu7dl81lnj6EMMEfjXS22v2t2iEsEZh90n+XrXNReDtYuosrAyR9i4x/9es+Sxn09PKuMqY5MN6p7j2o5k9gcJLdHooIIBHINFV9MkE2mW7Bw52AEg98VYIqiB/FcT4nnmm1k2+BiMDZj3Ga7gCuN1+3KeJ4XwdsqqB9elJjRseG/Bz3IE8smGYfL6D3rutG8KxaY7TTETyHpleB/U1nAjT7Rf9HeWRkLABioAA7Y71raFf3KeWJjLslUMFkfcVB7HPQ1yttq7O+KitLGq8I2sVj49TXmvjvR45YJLmLIkU5YDuK7HxFqErpN5fmmKAZZYmwW9sd+tc7eIt5YzgQvFKkfzguWDAjjr3oire8hzs1ynH+D5G+1TwbSAEyea68rXM+Drbabm4brwg/nXUmuo84UVFcaamoqg482FxKmRnOOoqYDNSwu0EyyL2okroqEkpJs6Ow8u4tYtyhmxxmpbwRwzwqWWPcwyTxiqukYMasvHzYx6Ut7qEa3XlywvIw5wF4rjtrY9SNpLQltkjl1G5UOjgdCKraxbwx2rpEu13GMAdc0lrfRvd7YYmiY9inFM1d8spJOQwH9adnewpNRWpzlnpselxG2jk8xVY/PjGamOKkIySfWoyK7FseXJ3d0SDFSKM01IndtqqWJ7Cr8WlzMh+YK5XIHpQ2kSlcWyma3VzyUzzjtWvbPDcxjlWDdSe1VNNgCyyK5LBhg5q1BpMUkrIWKP1GDjIribvK56UE4pILow2qMQVAXuK5+7naebnIAGRn3rXvtMSKVY9zOxbPJzgVmT2pmvJCpIwBj39qqMkpXJqJzjZFMnFMY1eewdckMD7GoZLK4QkNE35n/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-15.png', linkedinUrl: '/in/jason-johnson-a909a78a1c', jobTitle: 'Horticulturist, commercial', }, @@ -7155,7 +7155,7 @@ export const peopleDemo = [ city: 'Morrisonfurt', email: 'lisa.jenkins@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDvKyde1600CwNzcsMnhFzyxrUOdpx1rw34gawdS8RSQB8W1qfLXB6t/Efz4/ClJ2HFXY/WPG+q6vOxhlaGID5Y4ztwPzrn7q4mZVEgYyNyT1NWtB0FtaufKTcoHJkPPFeh2nw6tFUeZPM/GDmsJVEtzohRlJaI87tbiZQA91sP8OWIrtfDfju5sL2Kz1RvOt3ITzT95M9z6irV58MLDyiYZZg3bcciuF1vSLjRp2t7lgdnzRv6j0pRqJvQcqTS1R9BnnpSVyHgTxXHrumraTNi+tkAYH/loo4DD+tdca6U7nK1Yoa5NJb6DfyxHEiW7lT6HBr51jjN5cHzmOSwyfqa+l7yAXNjPAQCJI2Qg+4xXzzaabKnihbOWMxkT4ZWGOh6VnU01NKavoes+HbKK2sIVjRVwB0FdfCpx93t2riJZUso1WSO7lZgWVYG24x7+ta2i397FLFHNLM0MgDATYLJnsSP5VxW+0ekpfZOmZflI28fSuD8f6JDe6c1yMiaAFuO47it3xJqFzGcQvdeWv3hbEBj+J+tZzIL/SrqNUu428lgyzvvySvUGmlb3gk7+6ef/DdSvjGJkLBfLcEH0x/jiva68a+HBaPxbGvHKMpzx26V7Ka7obHmT3HjkVxGvaVGdfN4IgHQBt3c9BXcrjFcx44h1AaL5+mZE8Thm2gEle4xU1I80bIqjNQldlzTPKliUOoZgOMilvVVb+CIbVOQTnjGaraV0RwD83anXd/ZvfBLizkmeM5H7s8fQ1wrXQ9Va7GrGkbXkkblCw6c5pNRRY7dlA+YjGAKq2d5ZtMUjt5InbHJjPP1NT3ayTyKqH589+1FnflFJqKbZy2i+DhZ65FfCYGGEEhSPmLnPf0FdqaVItqADtQ3p3r0IR5VY8mpLmk2PA4zTJZYIwBNLGgbpvYDP51IqSMcBcY9axtf8O/2tbRT4Lz2r+YFHcY5H9fwq5JpXJiruxnJIbdy6/6ssSCO3NadoILkBnbOf0pljbCS0EbAHjiiHSQWYJI0bA9Aa8q+tz11oXpBDbR/Iwp1kfMDyMO+BVb7CsJ+Z2kYd2PSodAv5Ly51OzaPD2coxjujDIP862oWczDEt8htNyMCmNjGAKccY54NMOCM967zwAAAAAADzj/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-16.png', linkedinUrl: '/in/lisa-jenkins-c78e76770a', jobTitle: 'Counsellor', }, @@ -7165,7 +7165,7 @@ export const peopleDemo = [ city: 'West Heatherhaven', email: 'kevin.cowan@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDvsUYp+KqaqZE0q5MX+sKEL+PFSxnGeIvFszXMllpkhiSM7Zbnbk59Fz296xI7qMOJrq7kl38LLJkpntk9vzrT0zwtPOXCSBFDHDP824/StaTwfOIGjzBKkvEi7AM++OlYOaZ0RpO1zk57/UdPbf5yyxqwBRz93PQhh1H61e0jx3PBcqLwl7dm2urnLRn1B7j610MXgG2S3CSTSFR/B1AHpWfq3g/T/sZjiVt4+YN3JoU0mP2LaO5RlkRXQhlYZBHel21y3gvUHcTabKW3QjKhucDODzXW4rdanM9B2KrahkWEzAZwM1ZqvqBP2CXBwMfN9O9EtmOKvJIqaeF+zRkd1zWmCQo5rlNX+3QFWs/P2bPlWEA9BR4f1XVrlkt7mGUMwyHkXHHocd64rdT0YvodU5bYQKwdTk2DOM45PvWXr+u6tbyyQ2lvIwQfMyJuOPb3qtYS31xIBcCcKFyRMoBB9sUrdSr9DS8LbZdRupRg7E2k465P/wBauqrlfDELQ6hMEYhDuLrjr/d/ma6s12U3eJ59WPLIbTZFDxspzgjBxTsUoFW1fQzTs7lS38uSHY2OOOadE0AuhHFj5TyfeqlwHjuXCnGeaoXDWsyL5iTROAQkgjbIz1OQK4rWdj1ItSimaEJha8ljk25LHB9ah1MxW8TbBgkYrKtZLCyZkhaZ5JGyzOj5J/EVLftvKh5AoJC5Y4AzSfYb0VzR0G2KRmdlI3KACR1rYNKsYjRUXooAFBrtjHlVjzJz55XExSjisTU/FOnadlQ5nlH8EXOPqelcrqPjHULyNo4VS3ifj5eWx9f8KtIg0Ztelv8Axdd2NvhoLa3DLgfebdgnP+elbEbx3MPzTNH6gHpWH4Eshcz6kcDzHVAjH1GTj9TWvdaYs6ujBopFOCRwQa5a8WpXO3DzXLYjunhtoWf7QWAHeuT19bjU9DvUgLsxibaB1Y4zWu2iSmZY/NlnYnADd/wrWuNKTS9Im3Ya4kQg4PCL3x+FTSpuctCq1RRjqYvgHxb9osbfTtRlJl2AQyufvcfdJ9fSu+JrwFcxoCnGDxjtW1Z+NtbsJFUXXnQjjEx5/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-17.png', linkedinUrl: '/in/kevin-cowan-3177fc23bf', jobTitle: 'Recruitment consultant', }, @@ -7175,7 +7175,7 @@ export const peopleDemo = [ city: 'East Michelle', email: 'tina.williams@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDt+tIy4GaFOOtKzAjFZllae6itYmlmkVEUZLMcVxl94/dt/wBlCxQjO125Zj9O1VfG11NcX8VhG5CSfwjqcHH86s6T4GgeFDdtknnaP61nKdjaFJyOeu/E+p3jqBO7BuzHaBU8Gq3KMoctG3qWrrJPAdhMBt3Fu2TWLqXh9tMJt5ctG3KFv4T7Vk5pm/snE2tK8W3MBCXK+egHBxhj+Ndvpt/bapZpc2j7ozx7g+h968XhmwSokIGeh5FdV4X1Q6ZqCqxxBcOFcA8Bj0P5/wA60hNp2ZhOmrXR2LL6Uz7vWpCpzUcg4rQxRw00a6n47mkVcx2qYH+93P6muztE2ICTnFcZrMf9k6zdy26TA3EaODF13EkH+Wau+ErvUb+5+z3SyKmwsGkGD+Nc9RNu530GkrHb265GQ2DUGs6XbapZmKfIbqrr1U1xeuTapZX37r7VKijO1JNoYegHrXQaXe3M8aRzQXMJIB/e8g/Q1nayubN3djgtR0j+z75oi4cHPXvUNvOYpBbuSR1VieRj/PWun8eWbpaJcx/K4bOQO/8A9evPJrmcOk0aZGfmU9jVx1RzzVme5ls01hkUoFBBrqOMzLzyTcqkqg5Tv9aSwvNOshcyNPFEF+XJOAv41FrsDFYZl/hJU/Q1iW91p0dyXaN5ZA3zbFyDjsa5pr3mejh3eCsdcJ7K9n2jy5MAEMMMCPatIRQwpuAHHQDpXOG/sLpYlhD28gb5A0RTk/pWmFk8tSX7ZxWL0N9Clq6DU7WW2ZflcflXKX2iwWun3W9P9RGXjmz14IIPvXZ3JEERkRC5wW2jqfauH8Q60dUkOmWsbRQq4Dlurnrj6U43bIk4x1Z6Nt4pMVIjLJximsyrnmu+1zySlqELT2UiJ98Dcv1Fc9YWQlfPnGM+g710/mAnrWHq2nmPzbyykIcfM8fb3NZVIX1R04eryOzNtUxbiJipGOTimiTaoU4471yMOu3IIRwzHpwOK3LbzpQsjt17VySR2qVzVijL5kbsOK8stXuZPF1/H5BKQ3DKWAzzyQPyya9WUySR+TbJ5kzDAHYfX0FZMmn2ttJJFBteQPumlA/1spABP4AACtKa6mNV3gAAAAAALRP/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-18.png', linkedinUrl: '/in/tina-williams-2c3d8afa12', jobTitle: 'Scientist, research (maths)', }, @@ -7185,7 +7185,7 @@ export const peopleDemo = [ city: 'Josephborough', email: 'dustin.macdonald@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-19.png', linkedinUrl: '/in/dustin-macdonald-afa9526426', jobTitle: 'Public relations account executive', }, @@ -7195,7 +7195,7 @@ export const peopleDemo = [ city: 'Port Jennifer', email: 'michael.gonzales@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDYPNJjFP21h+KNSbTNJfyifPl+VMdvU027Alcg1bxbZ6ZObeFftE6n5wDwv4+tc2/xCvHuSUkWJVPyrtGD9c1a0PwE97EtxfzPEZRvCqeefU1tH4XWJXBupGb1IrndeNzojh5NXOeg+IV7DdAzMksbdQygAfQiu10nXLbWYS0WFkX7yZz+I9qxX+FtkINpncsPu47ViXGgXXhO7gurWRpImO0jdyp/+vTjWi3ZClQkldnoxXNPVKLR1ubWGdR8siBh+IqwErc5yqBXHeMTm/sUb7oGf1rtFXNcv4rsRcXunurDIby3APIDEYJ/WpqO0S6avI6PTnLW0Kc5VQMegrZUNtHOa4XWpNQgcRWRnGAceUOSR6mo/Dup6491Db3TuRLhgXHI9j6V5/Lpc9NS1sd8wYocHFcj4oZRp8iuMhec/j1qh4n1XW4LuSG0MmxAC3ljJPsKqqL250y7t7ozO3ksf3uM5xnrVRjsyZy3R0nhaR5fD9sZDkjcoPsDxW2q5rL8PRhNCtE3ZZUw3HQ9SP1rYUV6EdjzJKzKQ4rN1WAyAPGg3AqzN7IcgfnWlTXQuhUHGRjpmpqw5o2RdGfJK7FgeG5jKkDJHOR1qJFtbfUI0TYu0jLcDmqEEn2f5W6rx+VZN3qFjfsPNUBkJ2ttJYH1yOleeou9j1E1a508q2lxqUisUYOcqRg81BqEUMMTRKBuYbeOK5uwvbCxmcRFXZyMs2QxPbGetbaq15exruIyc/QdafK+axMpJRuzV02AQWSIDnPNXgtMjTACjoBirKpxXoRVkkeVOXNJszQuacFp+0DmrFlbm5uVQKSo5Y+lWyTldX3QXTkD5Tg8duKgG2S2VVuVhwPlKjmnWy6hdif+0023AleMr6BSQP5Z/GqOoaYwiD2jMrg4YZ/XFeZKS52erTTUETy7EhYPcLOR1LCtbw7h5ZZH6hQFz1965yy0mZfnupN5PIUcCrN19ptb/TZ7cPk3CRHb6MQMEelXTklNEVU5QZ3i4BqwmDVWaKS3kIKtt7NinxyjHR1rvPNP/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-20.png', linkedinUrl: '/in/michael-gonzales-3eb48a8cc2', jobTitle: "Nurse, children's", }, @@ -7205,7 +7205,7 @@ export const peopleDemo = [ city: 'Margaretmouth', email: 'allen.miller@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDQeozjPvVhlx0qIxseeK849AYOmegrm7/xxZ20jxWMf2pkOGfOE/A96seKPtlzFb6PYsFmvSQxz0QdaIPhMZI4/wDiYnH8SBMCtI8q1kRJTfwnPN491RpPke2RSeAI84/OrVh8RbtZCl/BBIP+meVIruv+FbaCtqkbwEsg5cHkn1rC1L4Y6c6t9muJIj2B5qnUpdheyq73NbTtXstYh820lDcfMh4ZfqKubTXjj2+peGdUdIpWSWFsq69x7+or17TLwX+mW92oA81AxA7HuPzqZw5dVsEZX0e5MV/nTSvB9assoNRtHgd6zLMiwhNx4qup35+zxJDGPTPzMf8APpXcwDEY5yfavM9SW4TUbt4pbmNHkUAW6/MzBB/jWp4TvNWnl+zTNMU2lg84w340SXU0pvSx3UmQD82PxrKvZNqH1/nXDa2uqyahIXe+kiQfcgfaG57e9X9KjuxIARdquMMk7bvxBFS4q17lqTvaxyniZRdzyF+G5BHQ4roPABc+HGhdtwinZVz1AIB/qazvGVmyX1tJECzSAqVA6ntW/wCBrF7XR545tom88lkDZK/KMZre6dNI5ZRaqNm8MUjNxS5GaCoNZlDbO3t5XmSRR8zbjn1wKtW13p9s10BNEnlpt5wMe5rHnkeC7ZlzgrnFZkkum30xkkhkdh8reXETnHbI61KV2dEfhVjqrW60+7l8kyRSbgCHUhlP41LdfZ7RT5SjPtXP22padCgtIoHi3sMBoihzWhOQpIY5IFKStoVcx7u2jur1JXZgybtpHPJGK3dGh8tJnYKHYqrYGBwMVgNcmKd5EUOU5wTxW9o8lw+kwS3aBJ5V8x0HG3PIH4DFVBdTKpLS3cYBzUg6U4JinBP1pmJmapBK1s0sHMiDOPUdxVS3t/tUEciXogJAztOM10AXZksQAOTntXnuraxDNrUyaTkRogZmH3WOTkinyPcqFS2h18pjs7T5p0kPUsRWRPqTumN4JY8Yrlv7RuppNhEjH3GBW1plm7yCW44UdBUySRqpORbINtpd1dMeRGdvucVL4CvNRvrFre9llubgDzC7HO3P8P8An3rnvEmuC5mGn2n+rQ4cr3PoK9Q8D6F/YulRvOn+kyfPJ7Meg/AfrXRRpe63LqdHof/Z', + 'https://twentyhq.github.io/placeholder-images/people/image-21.png', linkedinUrl: '/in/allen-miller-5378b7d05d', jobTitle: 'Therapist, speech and language', }, @@ -7215,7 +7215,7 @@ export const peopleDemo = [ city: 'South Alexandra', email: 'meghan.tapia@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-22.png', linkedinUrl: '/in/meghan-tapia-8d4336f0bc', jobTitle: 'Primary school teacher', }, @@ -7225,7 +7225,7 @@ export const peopleDemo = [ city: 'Lewisfurt', email: 'garrett.kim@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDo8UU/FNb5VLdcDPFUI5rxP4utfDqiIxtNdOm5EH3R6FjXkuq+IdT1dj9suXkQtuEecIPwrauY7jxh4qYOwVSSMjoqCupj+G2nFlZmlK+maxnVSdmbwoykro8qLng/KT60sbETKQTz3r1tvh3o4wRDIMf7VZupeB7NYWFtmOTsTyKj20TT6tM47RvEWo6LdNJazFR/HG/IcV7ZpGqW+taXDfWxykg5Xurdwa8BvbSWxu5El5KNg46V6B8J72VrnULNv9V5ayge+cH+dbRZzSVj07FGKXFLirJOA8OWKJ4h1aUIExKEC+neu5AYACuS1OyEWq6hIEnZJJVO2E4Odg71b8OXM7ho5BOsW0svnHLD2NcNRe82enQfupG/LuUEE4rKuyCAB1rC1N7uWeSV1uJYkGdsUmC3PTHerFkJXwgimQY6SHP61HLpc05tbHn3iOLGpOJPkYtg5rf+Fkbrrl/vHS2GCOn3hUHje0DS2zgfO2UOBW98NNOmsZr03OFkkiQohOSFycn+VdVOSsjgqwd3Y76lFGKUVuc5TeOP7XIGAJbDfpj+lVnaCNp8PGoVcHtVi8ys6N6rj8qxLibSZXJn2E4wcAknHbj+VcNRe+z1aDvTVty/p/2e4LJ8pcANxggiprmOOBSw6joBWZY3dhG+22ZAT0AG0/lWhdN8hYnPHSoehoc3e2MNzewXM7N+4LMAOh4rd8PQMbiW4dcFU8sEjGRnIrHubhrYSXKqG8oFtvr7V11hCYLGIMgSRlDSAf3iOa2oxblfsc1eajBrqybtS0lLmus88gvYmktm8sZdeQPX2rJigWeBShWMjg44reFc1qmf7Qm+yMVC43gdC2MnFc9aH2jrw1Vr3ScxJCCxKsfXFVJbsyqRnrVMpeyth43I9cjFOjh8s7m4x2rnZ1czZFPcGxRJiqs3moArDIJLAYruWyOowe4qjpHh5ZXjvb5AQh3RRHsezH+g/Gs/W/E9npPiN7OZnZDGhkK8+U/P9MZrrowcY6nDiSlLQ//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-23.png', linkedinUrl: '/in/garrett-kim-f7e6805c01', jobTitle: 'Education administrator', }, @@ -7235,7 +7235,7 @@ export const peopleDemo = [ city: 'New Colleenchester', email: 'heather.chase@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-24.png', linkedinUrl: '/in/heather-chase-0a2eb1532b', jobTitle: 'Engineer, civil (consulting)', }, @@ -7245,7 +7245,7 @@ export const peopleDemo = [ city: 'Bradleystad', email: 'kevin.cruz@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-25.png', linkedinUrl: '/in/kevin-cruz-d3f02830aa', jobTitle: 'Naval architect', }, @@ -7255,7 +7255,7 @@ export const peopleDemo = [ city: 'Jessicaview', email: 'desiree.adkins@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-26.png', linkedinUrl: '/in/desiree-adkins-c85deab253', jobTitle: 'Corporate treasurer', }, @@ -7265,7 +7265,7 @@ export const peopleDemo = [ city: 'Kristinamouth', email: 'teresa.rhodes@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDpC9JuzTAKM4HJwPWoNhs1xFbRmSZwiAZJJwBXM6t8QdL09dltm5lPTbwo+prkPFPiqfVbpreHEdtExVVySznOMnH8qg0/wPrepATvbGNSMjzOM1LkluOMHLZE1x8QdYuLhmhu47eM9FVAcfiasWvxC1S3z9ojiuwe+3b+oqnc+BNUt38xo42AHIWufvwYG8tgQR6UlJS2KlGUd0es6D4rsdfHlrmC7AyYHPX3U966FBXzzBdyW9wk0ErpLGQysDyD617Z4V13+3NFjunULOhMcoHTcO49iCDVGZp/aX9Kq6l51zplzDE22R4yFI45qYUnU0xo848GaKL/AMSyeYmY7Ri7Ajq2cAfzr2yGMLGBtHToK8p0bOhf2wzRT3Er3XlIIiVzhdxJI+tdl4auL1srdPJsaPevmPuK5HTNcdVO9zvoWUbG9dxnyipQHNeO+M/DVxDcyXlqm6NiSydxXTa1dao92Z4/tMsIOQiOQMD2Hemi6lvnMDW0kMqcOu7eh+hpQvH3h1Ep+6zx7GDyOa7/AOF96wur+xY/KyCUexBwf5j8q57xXpiWF+HjXasw3Y9DWp8M0d/Ekrr91bZt34kYrsi7q557jyyseodqQcU7HFNxVWFcvaLZWypcBlVvOmMrZHcgD+lGo6hYWP2iItsZY+Nq8c1DaFlkwp61VudbY3DwW+mmfYMF3X5f1rgmnztHq0VeCaLegzW15CyN8xAByyEAg+x70ao1vaKTGiA+wxVDT9blnuGt2sZIn55AG38cdKi1VWk3bm6VDVnY02OQ1myTV5Y96kohYtt64rpvDOlW9tLNPDCsY8pY1AUAgdSDj3Fc/LqNpptwn2pZGjclVCDPzdRkV0PhW+N/p0l5gqk0p8tT2UcD8+TXTSTbXY4qziovuza8ukMeKtBKVkGK6jiKmGRSyD5hU0UVhdRhp2w3t1py4BrHvbfz5ZmhYqyvtOOOa5cRBL3jtwlR/AWbuay04fum5+tYN/qXmJtj5Y1FcWFzvO8MfekgsX3bmHA7Vyqx1u5zGt3ctjdWUqFfNQs4LKCM4x0P1rtvCXlvoFr5WNuzt655/WuW1LT49Q1a3tplO11YKynBBHNdL4NtH0pLjTZW3oreZE54yD1BruovRHnVovmbP//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-27.png', linkedinUrl: '/in/teresa-rhodes-f990f416da', jobTitle: 'Primary school teacher', }, @@ -7275,7 +7275,7 @@ export const peopleDemo = [ city: 'West Jessicaland', email: 'catherine.wilson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDtifauU1bxja2rNFaqZXBILnhRj+dW/F+uHR9NEcf+uuAyr7AdT+teYWtzD5/nSItzMv8Aq4z9xT2z9OtY1JtOyNadO+rN6/8AGVz5TnLwsV4GOv0Nc+viYrMspuHEitlTnOD7USadqer3TbpDMSN2xQFQD0xV5fAkssoRmVTtGCB3xzWV+7N1B9EbOn+PbxTiRROp/hIwfzrtNJ1u01iLdASkoGWibqP8a81/4Ry804+XK++PBGccr6EVW0/UrnRNYi84kmNs8cbh3x+FVGo7kzpKx7IFzQOKbHIs8McsTbkdQykdwasKmV5roOU87+JaCS/0/eT5flthB3Oe9cFbGWa9EcY5AHygevavTviLo9xfafBeWkbSSxZRlB5weRj8RXD+ErN7jXFDryBvckd65qq95nXR1SPRtB0wWlonmAeYwBOK1Wsh5gdV+orHvNQNlGUWCeeQjhIh0+po0vULySdY5RIqNg4c5K+2ay6HWuxpXViJkwVrgPF+ni1jiuQoLRttHuK6zxBq15aTmG2jdwBkmMZNc7r07aloFyWjkSWLaxWQYI5H59aaIntY6vwY0svhWyaU84YLnuuTiugYnFZ2hWQsPD9jbKc7IV/Xn+tX8lcg12rY81vUrapCs9qhYnEUgkx64rmLDTkivGv12o9wpDIowBzkfjiuxYKyEHBB4NYNxcRpq7WIQho4hIW9QTgVz1oO/Mjsw1RcvIzTt0jlTlRn3FVL6a1tjhnjiA6uxAGT0FSoW2EpycZAqjNeWx+Sa1nkIP8AzyJBrCOuh22RLJLatqYXzEYsgzjsaq6vZRTwvagACYbSRVY3FotztjglRiMAtGRmtG2SSW9iDLkDBPsKqzckiZ2jFtmxGoijSJeiqAPwFTAZHIphAVxTy/HFdx44zquR1qjfQRsPOAxIQEJ9RzitAxjGKgvNogVf4iwxUVPhZdL40ZsM2xdrnBH6irMZQj73BpDZiYFSOcZFUZ7OWIDYSPbNcO2p6l+hJeKijIbIFWtMQmJp253cD6Cs02UoCmVic84zWtp0qfZljBwy5yPxrajZyOfEt8mhbAOMladlfxoaQk/L09KazZ/NdZ55/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-28.png', linkedinUrl: '/in/catherine-wilson-7add346581', jobTitle: 'Optician, dispensing', }, @@ -7285,7 +7285,7 @@ export const peopleDemo = [ city: 'Watsontown', email: 'marvin.nelson@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-29.png', linkedinUrl: '/in/marvin-nelson-fde56b8b5d', jobTitle: 'Operational investment banker', }, @@ -7295,7 +7295,7 @@ export const peopleDemo = [ city: 'Jacksonport', email: 'linda.hull@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDvMUYp1JSAQ4AJJAA7muc1fxXDYA/Z7drhR1k6L+HrWJ4/8Vtp7rplupZiN0xzgY7CuPt7bxD4hCvJbP8AZH6BTgY9qxnNrRG9OnfVm7d+OZpplD7kQ87I+PwqC71WWULMwmQdtxOR+R4qiuhz6ZL5k9qHAOQM9BUd5qEsuUjZ4iv8DHII/wA/SsXK73N1DlWxt6V40utPul+0vJdWrdVY5YD1U/0r061uIL21jubdw8Ui7lYdxXgi3Sl2SYbT69q9B+HOsEST6TK3GDLFz0PcD69fwNa05NaMxqQVro72jFLRitznPJfEtimp/EIWpXKmRTJ/tBVyR/Su7ijMESogAHTAFc341sGsdei1K2hd3nt3BCkjDggZ49m/Sq/hi/v5opUu2kG1WdXkzkYOMGuKtF3uelhpLlsdFeQkoQygk1wPiDT5Iy0qLwOoHUU28utafUfMSScx7gFwTjn8eBV63lurxCk0bkjg55H51mouOprJqXunD/aSGIOGA7HtW54W1BrPxJp0ythfOVCM9m4I/WsbXbN9P1Q7V+RuR7irWjabdy6zpmUCiadAADkgE5BI/A10q1k0cTTu12PoijFLRXQcpnauUEMQdQQWK8/SuXvZbGyt7pRJGjEAEdAP8K63VofN06TH3kw4/CvPdVv9Ft3W3u0Mk7AnAGSfqa468XznpYSS9mammLa3lq2SjFDg4wwNRX0sVtGyxqBmqWk6nYzIUsfu9CAuMH3pt4NznnvXO1Z2Ou6sZl1BHOwmkXJTOOMmr/hS1kufENgJ48SQB5WOB90DjI7HcwFUL+6ayie4VFcRgkqTjtxXXfDu1MmjyavNtM94xAwOEjU4Cj8cmuijFt3OTEVFGLS3Z2lGKUClxXYeaMZA6Mp6EYNcLc6ZIjyRF443jY5LDO73/Gu8rI1+ytZ7JppNyzqNsbIcEknAB9Rk1nVhzK63R0Yet7OWuzOKIa0A3SKT1yO9V5ZAUwOT1qK+imjlKsGbHUk1HAjZ5BA9DXDbqek5NlHWkb+w7ojlgMn869J8FWps/ClnB5iyKAWV1OQQea4e6hSW2nikztdCpx16V2um6bfWfhuztreQw3SQr/uliMkH866KEtE21Y//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-30.png', linkedinUrl: '/in/linda-hull-4d41c26e8b', jobTitle: 'Clinical cytogeneticist', }, @@ -7305,7 +7305,7 @@ export const peopleDemo = [ city: 'Beckyfort', email: 'dawn.martin@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-31.png', linkedinUrl: '/in/dawn-martin-fe75b2575e', jobTitle: 'Housing manager/officer', }, @@ -7315,7 +7315,7 @@ export const peopleDemo = [ city: 'East Marieshire', email: 'travis.leon@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-32.png', linkedinUrl: '/in/travis-leon-5c56017c27', jobTitle: 'Further education lecturer', }, @@ -7325,7 +7325,7 @@ export const peopleDemo = [ city: 'Edwardsfurt', email: 'jeffrey.anderson@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-33.png', linkedinUrl: '/in/jeffrey-anderson-1b6caa26b8', jobTitle: 'Merchant navy officer', }, @@ -7335,7 +7335,7 @@ export const peopleDemo = [ city: 'Paulmouth', email: 'jacqueline.gomez@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-34.png', linkedinUrl: '/in/jacqueline-gomez-0bc243917e', jobTitle: 'Producer, radio', }, @@ -7345,7 +7345,7 @@ export const peopleDemo = [ city: 'Karenburgh', email: 'laura.salazar@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDr8VUvtSttOhMk7duFHU0mp366dYvcNgkcIp/iY9K8+vNUku7zDtuJ5Z2OAK5JStodUIX1ZrX3xHWI+VaWL+ae7nge/FOg8V6nJF5mYmx1Ujg1zmmaHJr+qSJaBjbhcGTofqK0tQ0bVtJiA8ppVUY3qeaiUvM1jT62Oj03xfZ3k4trpfs054G45Vj7Gug614ff3bM2Jo/LkHfGAa7rwZ4qW7Eel3RPnqv7t2OdwHb61ab6mco22O3o4pKXtTIPPvGmrb9YSz3/ALm1Tc4Hdz/9auJklnu7kQxgl3ONo/lWh4y8yHxNfLjmSQMMdxgVP4EtY7jxKrSqSkK7uBnLVDVrs2jraJ6x4K0M6RpMYkwZnG58dj6Vt30Mcq4O057Vh6jq/k2rJFa3E3GNka4JrE0i5nabzfJnto2wWSVydo/xrHdHStyHxP4SS5jaWGJS45x615YTPpGqKwV43hcMoPBGD0r1nxNqUkV08OLh0QAlYAcnNcd4j0ttXWOSzRo3hUsyzHk+oz+tXTutDOsk1dbnptlcpe2MF1H9yVA4/EVOaz9Btms9AsLdwQ8cChgexxzWhWxyHlfiWFbj4ii2kJVZfLXPoSBXTeGdKOlsZ1i2+apyp6j5uP0qv8QtMR7a31K3jK3cbqPNTqAOR+tS+GPF767dC1ms1ikhjBkkU8MenTt3rKqnujqoSVrPc7uMpMmFUA4xVW5a1hk23DQpEo3yPIQAAOnP1qSKIg/K1QXN7YQxPFNbS3LZywWEsM/XpWK10Oqy6FW+ezn1hJIZY3MkYB7/AErn/EsMixQw2nEs0yRHaueCef0FWPt1g99thtJbdiON6Fcn2q5aqbm/DSdUG7H6U4p86RNX3YM1kyIlBOSAMmnUlHauo80w/Fhkk0k2sIkEkjBSQvA+p/wrD8EeHZ7HUL55gTujC7weCc54r1+20WF7WSK7VZVlXDAjjFZH9ix6Li2hj224H7o+v196ismlc1oNOVjJS5aBjFI+0jgE1b2xPblPOwu3vzUV7Zrc+m6sOW0uIWK7iEHvXJc7yS8gihcBH3OTxgVoWNqYIt7/AOscfN7e1ZGlkNq8aSPnIOwE9TiukYeldFKKfvHLiajvykeKWlxS44rc5D//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-35.png', linkedinUrl: '/in/laura-salazar-b649ef3e65', jobTitle: 'Investment analyst', }, @@ -7355,7 +7355,7 @@ export const peopleDemo = [ city: 'Adamsberg', email: 'jacob.berry@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0IcVHdXdtY2z3N3PHBCgy0kjBQPxqcAkV4T8U9fl1bxG2mROwtbE7NueHk7n+n4VBZueIfjEyySwaBbIVXj7VOM591X/H8q5iD4teK4Xy91BOufuyQL/TFN0/4eald2aTtLFH5gyEPXHvWpD8K2CZmv8A5+wVKn2kF1LVGb6G94b+L8F7IIdctlt2JwJoM7B9QTkfUZr0yGWK4hSaCRJInGVdDkMPY14JqPw2urfMlvcoy9w1dX8LNWu9Pv7jwxqOehmtv/ZgD6Hr+dClGWwpQlHdHqY60o5NG3uDS85pkj07cV836hbmXxZeMwGPtbkj/gRr6NeRIIXlckKilm+g5rxyHSo5fG1xcOhMEzPdQ7h2bkZHrk/pSlJJFwg5M7WxyYIsj5to49KvyFgvKiuS1O9vrXckCzn5SVEMeT0qroepeIJrlYLgFkcBtzgAovv71y8ulzt5tbHV3aFoiNv51xV0Hg8V6RcQJ+/F0iDHcE8j8s1Z8Ta5rFvcta2sDN5fLSKN2Pwqvocsk+vacb6ZlMFyju8ibcHnA49SQKuCs7kVXdOJ7ERjimVI3vTK6DiHNGJY2jb7rAqfxrz65tDDfb5AQ8bNEo7BBj+or0VeK5zxNaRxiK7G7LSbWHbp/wDWrOrG6ubUJ2fL3KlssdxCVbAPuOtVXms4JHijaNWXqxwoJ9BTYkZo8q3BGRWdczQSxiB9NlnVScExDBPqCa50r6HbcfefZxrO2R4ykqjJyDzU9pbWn9u2MQjXaZQSOxI5H6iuYZLaC/UrZXCSMNoMg3f1OK6XwzA0/iNC/wAywIz59+g/nVKPvJEVHaLuegMc1GacaZ9K6jzyccda5zXtIn1KaK7t5WBjyrwknbIvY49R/I1tNLJKG2LgDse9PVhJGGTg9CD2NKVnoVG8Xc4BpmtV8iUlCDxnvUoktZrcrNMdhGBtODXR6tpsOoRsHjXeeue9ea6vpc9lKyLPNC38IcZU/iK5nGz1OyM7rQt3n2WCQi3J/PJrufCeky6fp7XFypFzcYYqeqL2H1715GHubZRMz7njYMD1yc8V7EmoXoUMxRhjkEdK0gkncxqybVjYJ4qMmqsF+szbHXa3t0qxIwjQgrYwP//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-36.png', linkedinUrl: '/in/jacob-berry-b613f63da8', jobTitle: 'Dispensing optician', }, @@ -7365,7 +7365,7 @@ export const peopleDemo = [ city: 'New Michaelton', email: 'justin.cruz@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDo8ZqO5uobG2aeY4ReuBmpAT6VjeK4mk0NyrFWRgwpMaOK8SeKbqeeVI3MVtsOFz1zXMQ6iI4ylv8AIQMsxPJNblj4auPEYkaNxHEjbA5H3j3rSk+E8oiLLegyHkDbwazdSK3NlSk1dI4iW8kxEiXDZJ+Ze2fXNXHuGSOISpt2n5ymQCPWujX4XXUcZeS8w+P4VrMvPCGp6esjq4kRRlueoFL2kdrh7GaV7G14A18W2q/2ZJK0kdwf3eedp+terBeK+d9MaWx1m2uItwZZlIx/Dz0r6NAyMitEZMr+WBWF4xGPC16vTcFXOOmSK6TbVPVoIptHu4pQdjxFSQMkZ6H8DQ3ZXCKbaSOd8HW6xaBbBAfmBb9a6n5toyP0riLiz1K30izjsWnDJAOYiAAQMk+5PpVzw3qWuzbLe9jJYruDuMHHofQ1yOPU9GMtonTyq+wgDrXPayrG1mVVLNtIx61meINU8RSzyR2fmJFENzGJQSQDjj1qTTjqG4R3nnk4z+8A7+4/lU8ulyubXlOFsLFbjXrWFiRuuUJTH+0K95K815lBpe/xlLdqQBbFZlQnG98cD9M16VYzPdWFvcSJ5byIGK+hNdUJp6HDUpuK5ugooZQyFSMgjGKTNLmtDFaFG2ihaBraQAhDtINLbw20d0VgQAIDkgdTVW7UwXbMpwrDcayru40+4UMl75Mu0jerkfn2rjaabR6cGpJNGrDDBNK0c6jJJIyKW8hhtYvlA46Vz9jd2FpuVLsyuzZ3PIc59s/0rQuZWmA3Nx1qXpoWQW1p9qfAQFzICG7k/X0rs0jEUSRr0VQo/Csfw/5Ajc4Xzdx5PXFbpFdFGNlfucOIqOT5eiKAORS5qS1tZbp9kS5Pc9hWncaQEtkEYy4Yb27474rexzXMW50y5v7Znt4yWjBIP971ArBEb3NsNt0ICOAQOcelem2yCNY8DChcAelec+I9JNtdSojNFJkshB4YHpWFaNveR1Yao/hKEkJgQ77hZif4iKz4pmmm2K+5QeSO1ZU8V2ZCkksh55GMA1qafCWkEKYVVXdI/ZFHU/571zPV6HU5dWbVlJ5TyOvGDkf5/Cuogm3ICehFclFxCMDHmtwPQdq6m2XEag+mK6IqzOaTursAAAAAAAAAA//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-37.png', linkedinUrl: '/in/justin-cruz-e21f40fce4', jobTitle: 'Sports development officer', }, @@ -7375,7 +7375,7 @@ export const peopleDemo = [ city: 'West Jeffrey', email: 'derek.avery@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwCoWphamlqYWxQAk91HbJuc5PZR1NQDVsQ+aE68Kvc0ujaDNrd+8s7MkCP95TyT6D8K7q28BaaHWU72wc/M2a5p1tbHXDD3V2ef2+vpgLONvOOBzWlHdJM37uVXXGQRXbXHgbSJVJFuM9c5rkdZ8JHTIpbjS3KsB88bchhUxr6lSw2mgwNnvQKz9Pu1uocbgZE+VwPWrw611J3RxtWdisetNdtq5I+XI3fSnk81HKjtC+xSxAzx2pT+Fjh8SO28Pwolqu0cNzXVx/cG05rzW/e9tkWG3kuFCxDAgXJOBzV/wxd6xLdRQXUsrRvyrSptYexrzvM9ZLod6xOOWxWHqpVYHPUYNcz4juNY+3SJbzXAijyT5AyT7AHqafpcl3NtjlFztZcstyuD0oe1x26HNtAkGsSvEgVZFycetWweagNrNBfXYcHy43wjE9s9KkVq76TvE8uqrSITVrTkEtw0Z6sjY+oGRVQip7Ob7NdxTEEhDkgd6uavFomnLlmmd5psdtd2qF8ZwOtSRXFhBq8cKyxJsycEgE/hXPWFxJ5BaMnABYCqlw0WpyqXgnBUYDiJs/n6fSvNSd7HrqzWh1cc+nzXjpJJE+5iAQQcH0PpVi7jhto8x+lcbDLFpqSIlrKFf7xMLZz65rcmmL2yfNk7Mk/hRJWG/Mxb5B/Z8s7cmSX5c9v84/WsZetaN/f/AGq2ht1TasRJJz941RRea7qEXGOp5eImpT0IttOVc1L5RLYAyTWna6O7DfO3loP4e9auSjuYxi5bFK21BLeR7fdzHjeMfdz6/hXQSG1uIkEkrKSByp6Viy6OYvEct5uzDeQKGXsHBwf0x+tQPpd4JTFDcbCOQGOePavNnJOTZ6tNOMVY6bzoba32Ry729T6VhSai13bzCLf5caku57gZ4FV00rUJAftM4IJxtXjNba6aqWD2sab2kXZj61Lkuhdm9zmtOkfU7W4nSIqkBXJzndn0+lTJ1rqtI0KHSNKWxUl+CZGPVietVX8PxtkwykegIyK7YVtPbxP/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-38.png', linkedinUrl: '/in/derek-avery-2e68141d8b', jobTitle: 'Tax adviser', }, @@ -7385,7 +7385,7 @@ export const peopleDemo = [ city: 'North Kelsey', email: 'julie.richardson@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-39.png', linkedinUrl: '/in/julie-richardson-c004cc7600', jobTitle: 'Visual merchandiser', }, @@ -7395,7 +7395,7 @@ export const peopleDemo = [ city: 'Edwardchester', email: 'linda.perry@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDreKrX19b6daSXNy+2NBk+p9hVjtXkfjfXLjUNUltYXZbaI7AOxIPJ/wA+lZM0SNLUfiVdPKY9OiijTnlxlv8ACuc1bxbq2pOqvcNiPnbGNuD61m6Xpl1qdyLe1XzJDyzNwAK69fhtKbYE3KrMBwAOKlzS3ZpGnKWyMGw8b6pp92kkcnmyEbXWXJDfXvXe+GPHI1e7FlfxxwXD/wCrKfdc+nPQ1yd18ObmOEyC4VpAOhXiuQuFu9LvwjoUdGzkGiMk9hShKPxI+jTSYrmPAusSar4eU3ErSTROUZm5OOoz+Brp6sgZKwSFmZgqgZJJxgV4HqcyHWrtIOUMrBSDxjNex+LoJJ/DtzslWMKu5gwJDDHTivDrISTalDGed0gH1yaTGj13wlo0FhYq6LmV8F3Pc11pXIHNcVqM32O3EW26fK5EcBK4wPUU7w1LeG4WN5Lnynw2Jm3bfauNq65j0Iu3unWzL+7PbivOPGmkxyQyXaqBKg6juK1vFFxdfaXjBuTHGOfIYgmslgLnTLqJVuUfyTlJm3c4yCDTire8Ket4mZ8ONWls9fjsjIVtrgFSpOQX6jHpXsdeD+CWceKLNo4hNJ5owv8AdHc/gM17x2rrPPIriIXFtLCeA6Fc+mRXjWmaGYNfljeQNLZTDdgZB68/oa9oxxXB+KoU8N6l/b8KNMk4MVzbjjOeQwP1/nUzTtoXTaUlc62zEFxANygnHeop7uws7qOLfHECwGTxk+grP0m6W5sYbiI/JLGHA+ozRPqdtjy2s5ZyOuIif1xXIk72PRVmtCaO5srrU5kDo4Y445wfemarFbxQMsaAEjtWfDqVok2xLKWDd03RkfrUes332WykunUvsAwgP3iTgCizvYJWS1Of8OaJdWfjK2mtIz5cQBmfGBhgcj64r1XtWXotq0dhFLIqrLIod1HIUkdAfStTtXZFO2p5smm9AB4qO6tYb23eCeNZI3GGVhkGpBTgasg5L7CNCX7LGx8kZZPYEk4qyscdzHnzto7EdaZczz3Ws30cuPKhcRRr7bQTn8TVSewfG+ByvqK4Z2U2ehSb5USXEKW+T52/Pc9aig0y216UW9xKypGRKoRsFiP8KrmzkUZmk3segqtMlzBq+mXMDYCTBJBnqrYFODXOgq3cGd/DCtvCkSZ2oMDPWnnpTVfd14I6ilzXYeef/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-40.png', linkedinUrl: '/in/linda-perry-81b2a5fe77', jobTitle: 'Records manager', }, @@ -7405,7 +7405,7 @@ export const peopleDemo = [ city: 'Davidland', email: 'shannon.johnston@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDjuc1R1LVotOiI4ecj5U/qas3k6WlrJM7bQBwcZ57Vw0skk8jzSMWduST3pAXJNVvr0lZJjsbqi8CoJC8fzKOPRWzVjSLOW9u/JtseYRxnp712EXw8mkhBlux5h5ICZFZTqxi9WbQozmrxRyVnq1xbAus7D1RvmBrodN1gaiGUpskTGRnr9KTUPh9Na28k6TCQopYrtI+tcxBdG1vYy2SY2yB6+1OFSMvhFOnKHxI7UmkBOaitrhbu3SZRgN2qbFamJS1+aOHTHV9peQ7UUnv6/hXGwx+ZOsYHLHHNdn4isvtOm71GZIm3KPX2rl9Lgb+1YVZSMkHBqZOyLirs9D8KaLbWg86NcykBSxr0C2jZU3GMGuDAWwtlBgnnldC6hZCgGPTHU1taHcX9jNG8085imVT5csm7y884Poa82UW/fbPVhJL3EjoLyLz7d0Me1WUqSB6ivIvFnh1NPU3MRUlWGT059a9B8VaheNC620kwSHBfyThmz2H51x+uQibQLsrFMssW0SB5TIG5HINVSumpJkVrSTi0c94dm3STpvyCAwH866ECub8PW7G6JC7URct7k104HNeijy3uSyHIwaqXVkiQQXSxrujKpuHXGMVZPNVdQF2YYjbSYRJAZU/vrms6sXJaG1Kai3fqd1on2e4tY/MVWYAYyM1NqyrE8MYCoWOfQDnrWPoztHGmzkkZA9auXOpWdzOY7yPeyfw7Ca83W9j146pF9YANTeJwpygb1qnqtraSotuYx5bN86jjI60yO+tFnHk5Vm4+bOTVTUbuSOXKNgsCpPt3pwg3NRJqyUIts5tLVLe4uHXH72Qtx0AycCn96kemDrXqpWPEbu7i4qRFJBx6VNa2U93cpBBG0krnCqoyTVm90y+02V7e6t2gcDqe49R61M5qKuyoQlN2Qy0d7aKN+dh5UjsfSt+0ghulVyw3H+LHIqto9ss1oIZVBBGCDV+DRRExVJpIx6Z4rynLU9mN4le7torXJDBmx97viudupWlnJPQcCukubIRlyZGfaO/rWJDZS3kqQov7yV9iHtknjPpW+GnFTuznxSlKGhmtUZ61oalpN/pc3l3lrJCexI4P0PQ1Q2kmvRPLAAAAAAAAAAP/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-41.png', linkedinUrl: '/in/shannon-johnston-730f636101', jobTitle: 'Local government officer', }, @@ -7415,7 +7415,7 @@ export const peopleDemo = [ city: 'North Emmamouth', email: 'teresa.peters@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-42.png', linkedinUrl: '/in/teresa-peters-79db7ef10b', jobTitle: 'Ecologist', }, @@ -7425,7 +7425,7 @@ export const peopleDemo = [ city: 'Douglasmouth', email: 'vanessa.woods@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-43.png', linkedinUrl: '/in/vanessa-woods-6e5bdf7c9a', jobTitle: 'QuickActions analyst', }, @@ -7435,7 +7435,7 @@ export const peopleDemo = [ city: 'Courtneybury', email: 'ashley.ortiz@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-44.png', linkedinUrl: '/in/ashley-ortiz-5cc26fa72b', jobTitle: 'Surveyor, mining', }, @@ -7445,7 +7445,7 @@ export const peopleDemo = [ city: 'Ryanland', email: 'eric.bailey@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1uilopiOd8ZeJY/DGhS3hUtMRtjHGAT3NeCap4+8S6mk0T6jM1rIf9XxwPy/lWn8VNUvtV8Ztp4LtHCwjijHAyfb+tU7DwJqE6CR3jQ/TJrOU1Hc1hTlLZHKPfXUqCF7iVoc7thY7QfXHrTN0keSrkZ5K5616JD8NnncG4usDvsXrU1x8NII1Z1uGKqp4IqPbRNPq8yp4S+J93pYstPv5WNhb7hlfvEHoD7Dnj6V7jomu6f4gsRd6fcpMnRscFT7jtXyjdWLwTuAPunAHrXa/CfVpdM8awQyTCK3u1aGRXYAE4yvXvkfrWqZg0fRtFLRVEnj/AIl06O6+LE8pQZgto3xjqSMZrooYisYwRWH8RrGWDxW93DNLH9ptYlIi65DMPy4FZ3g+5v7qR7eczeWqlg0vX8a46y95s9DDu0UjssIpyZFB9M0yeQCAhcHI4rzzWrS5S/kkYXEqoM4SQgsM9AK3tGW6XCGOcIQOJDkdKxcdLnQpNu1jz/WU/wCJjMDHtfewx2zVTRYHPibSjEm6Q3kaAevzCup8eWJgurW5TAaU7SPU1W8A6LdTeMNLlkiPkLP5pJ4yFBIOPTPFdlOScUefVg1N2PoygUUVsc5ynitIZL6BZEBbyup9MmsSxFpbecweOPtzxW54zhYJa3S9F3I38x/WuBmbT7mUsW3ZIDhAWBx2PYmuGqnzs9TDtOmrHT+XaXU5ikCFgAexzVloYbVPlA46Vz1peWESpBBhTn5Rgqf1rXkJxjOcjrWMtDoTRz3ifSptYFoIioEU4diT0Xvit3wnZGXV4CFAitS7xuoxuUjGP1FV5XIICgN7HvW34Ca4v4LzU5EEVu0n2e2Qc5VCdzn6nj8K2opyaXY5q01CMn1eh2dFFFdx5hn61YNqWkz26f60jdHn+8P84rzVbaUrtSTySvyso45r1uvP/HmnfZJYr+0XaZiRIAeCw5z+IrCtC65jqw1VxfKUMMkIEm1z61G14xG3iuXj1m8MvliJznvWvaCSVgW49a42juUmzThUupY8FuB7V6LpenQaTpdtYWwIigQKM9T6k+5OTXn6cBR78Cuo8FaXPpultC8ryRFtys5JJJJyR6DoB9K6MM85MWtj/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-45.png', linkedinUrl: '/in/eric-bailey-c789b6c993', jobTitle: 'Financial controller', }, @@ -7455,7 +7455,7 @@ export const peopleDemo = [ city: 'West Linda', email: 'rebecca.palmer@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDMc571GWWNGd2CqoySewobJNU9XhWbSLhHYqu3JIPpUFmLqnizbvgsPTmQ9vpXKSyS5Z5CWdjklzk1EqNLOUjJbJ4x1NbcPh7WbwI0FmZE7A0OSW4RjKWyMJpgWztwOmBU0N3NBL59pI8Lr/EhrpbzwZq6wea1lHvbkrH/AA1zc9rLbJJFOhidex70lOMthypyjujvvDPiAaxbGGc/6XEMtxjcPWt9cZrzXwcY01gNJMI2KkLk43HjivSQrelNkorHrXO+NJHj0qBVJ+eXBweowetdEc5rO1+1F3olwpOCi7wfpQBV8B+EU1mBryaRo137AEHJHfB7V7LZaXb2VtHDFEqIowMCvNPCiz2ngyweGC5eSYuQYZRGFOTyTXVeFtT1u6kWK9jkCtyGlADAehx3/CuCrdtu56lG0YpHRXMSiMjZx9K8f+IHh93lkvIh8uASO4rsfEOpa5LcSR2/nC3iBLCHAZwOuCe/sKzPm1CExPBdRbE+cTvvByPX1pQvD3iqlppwZ41ahvtsIQ4bzAB+de0oSFUHrivMtM0kSeLPIfKxwzE5A67TkCvSCxzxXoXueVZoiZead5ayRsjqGVhgg96tG296VYQKYjf8JW8FpoyafIAUUlkzj7pJIrfiSNLxIoVACjc2BiuT035JTzitC9vdJJCXF4YJgCoZWIYZrzakWptHsUJKdNFy0MU1zLFMoyCSMgYPNUdbktrW3ZIVUZ4AA71QsLnSYDIlreea5b7zyEt+tVL8vcSk5y33UB9alK7sXNqKuZVvYwwFpRGPNdi5YjnJ4qfvTrWwaztEgLFmGSzE5ySc04wMTXowjyqx49SfPK5ZZqYWxyTgCobq7S3cxKN0nf0FZ2oPcRMomBViu4KQRwehrOdaMdtS4UJS30HaprMtu9qLKTBWdPMOOCucEV1RjmnG6OaKNwMYlXIrzu6DOuTwGHau002+tdY0dNzj7VGgWQA4OR3rkqTcveO+glT0QXMctvuluLiEt/0zXAH4ViaoJbrTpFjlaNn4RwcEH1qS6hWGUvNOXQHPznpWHreuLdRi2s8nsX/wojdu6KqT35hvh3XJbOP7JeytKpYkSFixU+n0rsLaeO5XfC6uPbtXn0Ft5SgnljWnp0k0EvmxSlSOvs//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-46.png', linkedinUrl: '/in/rebecca-palmer-ef38ef5cea', jobTitle: 'Site engineer', }, @@ -7465,7 +7465,7 @@ export const peopleDemo = [ city: 'Nicholsborough', email: 'lee.jones@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDBOcmmM6opZ3CqOpJwBUzIa5nXDdXt5DZWyb0LAbfVs9/as7miRPd+JEiZ0tE83aOZD0/Ad6zF1/VZG3llRB22gV6ZoHw/063tV+2gzTvgt2APtW7J8PtGePyzC2Oxz0rH2yOn6rKx4/b+LHUBLhFJB6gYyK3rO+gv4vMgfOOq9xXYXfwz0NYsLEwKnPWuK1fw3P4cvEudNRpITw6Z6f4iqVVN2Jlh5RV2XNpp6Kc1LGBJGkg6MAaeqc1dzCxI0YrB0ZQvibd1LSYwTnvXTrCXYKOprK0HSpF8Zus6kKC8sfowPQj1qJtWZrSi3JM9PtdpXp0q+XBAwc1wWtveoZB5d5JEq5CW/wDnrUHhn+1lv41lkuvssmGInbJTPQH0rlSsrnoc2tjv5wNuGJFcZ4oby7CZsZwuapeMLvVo9Skgtmufs8ShmMHLH2ArPgW6ubWeCVrll8lsrcdQSOKpR6kylvEh01zLpsLEc4P5Zq2q1HpcGzTLZDgMIxuUHpnnmroi5rquec009SWLYZ1Vz8rHafx4rVMKLqMdyqqoizCgAwcYByfyrEZTWrDqAnW3idMSITmTPWsq0G9UdOGqJJwZ1MSQ3cHzAD1zVF5bKGbyYXjXaQGJIGTUaS/uGw2MDPFYN5eaTdxrHMqM0ZO1vLLEH1yBxWEVc7U+xszvZTazIjyRukgGMHODUepwQWtsyRj7wxmubtn0qxmcxSZlYBSzqwLc9ietal/M0qLkknjim1qS3pqUjGsSIigA45x+X9KVQallxLLuxj2NKiDNdMVaJ51WXNNtFQnipbZcygHjPH0poTNT+RMlhNdwxmTyXjDAdgzYLfh1rSSujODtJE8d1IHMLHa44IPpWpLFNc2u2KVYmxgH0+lZt/YPdxJJGcSDvWJdz63Yph0cov8AEozXFGzPTu4m81pLChMsqSkdzzWaJ/PnKA5Cckj9Kw01PULsNhm2txkDFa2nReUWQnL7QTmtYr3jGrNuLZcwfSnp1oPArY4j/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-47.png', linkedinUrl: '/in/lee-jones-0adef06cd7', jobTitle: 'Radiographer, therapeutic', }, @@ -7475,7 +7475,7 @@ export const peopleDemo = [ city: 'East Kathrynchester', email: 'samuel.king@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-48.png', linkedinUrl: '/in/samuel-king-57c6f39f1c', jobTitle: 'Illustrator', }, @@ -7485,7 +7485,7 @@ export const peopleDemo = [ city: 'Mcphersonport', email: 'timothy.moreno@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDusVW1DUbPSbN7u+nSCBOrsf0HqatEhVLMcADJNfPfi3xDdeLdayMiBGMdtCvYZ6n3NTcqx12sfF1jOYdEskKAY865ByT7KD/M1gD4meJ4bndJeRHPBje3UIPp/wDrq1p/w5nmgV5blVcj7oWtKL4YFoz5t8cnouzIH51j7eHc6FhqnYdo3xXuVnjj1u3hMLE5mgUqw99ucH8K9NsL+01SzS7sp0mgfo6/y9jXk958MB5GReEMpzgLU/gG8ufD3iZ9Du5T5N2CUB+6XHQj6jIP0FVGpGWiInRnBXkes4pMU/FJitDIzvEt2+n+GdRuoxmRIG2/U8f1rwnQIVh1e3Zl3ENwPevePEkaTeG7+BmCtNC0aZ7sRwPzryXwpp0ia2Eu4yksMZYow5B7VlVkkmb0YNtM9LsseWoyA1aOSAOM1yeomeBD+7uZcfMEgAz09aTRJL3z13NdKjgMVmk3FfY+hrhUdLnp82tjppxlDxXm/jaJY/KuIxiVJAUYdQ3bFdF4n1G9jMkUHnFUALGEZY/Sucubc3ccMc8k2wXEPmfaCMr84yc+mDWlNWaZlWleLietWhmayga4x5xjUyY/vY5/WpTUhx26dqYa7jyyjrUIltI3Of3Ugbj8q5F7SOPVheh8vLCEYAY75/rXftGsiFHGVYYIrjtYha11RYSg8sICj92B/wAMVy14O/Mjuw1VcvI9zXt0WaJcgZx3qG4e3t9w3RoQMkkgAfjUFvIwiUqf4eKzrvUNOf8Ac3I3lTjaYif6VzRVzuuizO9udTiHmRt5sfIB/WqerWcEsYtwAolIUnFZ8s1hDdxiEMsrcLuQjNa1pbSXms20W4fuyJG3eg5q1F8yRE5JRbZ2qqERUHRQBTTTzTDXoHjEqiuZ8VIHu7VVYbyjdOoIIx/WtfWtXg0LR7jUbjlYVyFzyzdgPqa8a8Pa5BBqNxLdZVrmXzTJnIBPb6c1FZNwdjWg0qiudrbXjRt5UhCuh79xWp8kycFdxHBqjc2Md9EskTgZGQw5rONnrEC4iZJFHTnBrgVj1NYly8gWFxI7DcvQ+lb/AIbsZIoXvrgHzZx8oPZf/r1wd3LelhHduF/vc8AV6xGqpCioQVCgAj0xXTQim7nJiqjsl3A0007XUcJ//9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-49.png', linkedinUrl: '/in/timothy-moreno-eb7ae88f2f', jobTitle: 'Physiotherapist', }, @@ -7495,7 +7495,7 @@ export const peopleDemo = [ city: 'New Makayla', email: 'darlene.jones@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-50.png', linkedinUrl: '/in/darlene-jones-e27174b679', jobTitle: 'Health physicist', }, @@ -7505,7 +7505,7 @@ export const peopleDemo = [ city: 'Port Justin', email: 'gregory.liu@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDFC0oWpAlYfiLVXsFitYDiaYcnuo9qpuyuCVw1LxFbWLGGIefOOoB+VfqaoL4luBEZJY4wo7KpJH607SfB19qYWbasayHID8kj1rrrT4bS+Tskv9gPZF6fSuaVbzOmNCTWxyya7d+dETHDLDKMqVyp/Wt2GZJ4leNsgjOO9XLn4XEWoih1B/vbvmXp9K5y90vUfDN2iyN50XJRgOuOq+xxzThWV7EzoNK5t4o209MOisOhGaXbXSc5MF4rlNUhiu/FG2RSdgRB/P8ArXYBawPshfxmFP3X2N9eD/hWVV2iaUleVj0DR4UjhUAAEDFdFEGI9a4i/klgRwsFzMdpYLCcfr61b0OXUbWaJZfNFvIoYeY24rnsfeuC2lz0762Ow52kbcfWuU8WW0MmnSMyg7Bu59aXxPqF9AT9nW4kjXBbyThvw9apzGW6024icXAKwNvSbBPIyORTS6ifYwLJvMsomIwcYP4VPiorBf8AQYu+VzVnFelHY8p7kwFTvaIbu2nOGmiyzN3CtkKKiAq0k8f2fYyfvdwww9PesMRFtJo6cNNJtPqdLZ+VJGDgFvcVR1i9t7SeFZSygsB8iFuc+386ksGwu7uO1QyaqBOQtnPMQf4UwPzNcSV9D0F5FuzvrO8v5UikLgAfeQjqOPrU+oxRpDIABuZduMVQh1KPzir2stuTgAunB/EdKnv5l+V3bCjG4n0qmuhL03OavLZbV44k+6qDA9B2qtirV9Ks95I6HKdFPsKrV6FNNRSZ5dVpzbRMBTlXJ56UKKhluZUv7W2t40dZHKzOx/1YxkY9zinN2i2yYK8kkacNyYX8t2wy+vcVrReTKmHfgjselUbvTzPCrL94VkPZakHMcbNH6Z5FeYj1djqXW3gjOx/lx3NYuo3hmjWNfuE5J9ait9K1JkzeyhlzjAPWkvSn2vyFIzGgyvoDnH8jW1FJzRjXk+RlTbSEVDzj/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-51.png', linkedinUrl: '/in/gregory-liu-aac65508df', jobTitle: 'Psychiatric nurse', }, @@ -7515,7 +7515,7 @@ export const peopleDemo = [ city: 'Donaldbury', email: 'cheryl.chambers@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0o0lKaaxIU460xHJ+OfFq+HNPSKCRPt05+RTyUXu2P5V47dalNfzG4u7u5uJD3Yk0vie7m1nxJeXDzOx8wohJ6KvAAxTtL8NahesGhkfy/VxxWM5Lqbwg+iKa3VtMSqsVcdVbPP8A9es6RmE5YHIJ7d69At/hvNKQ9zc5Poo6Vm614SbTo/kOVXue5qFUiW6cjm4554iCGVMdsnNeu/DfxkdSQ6VqVzuvBzbs3WRR1BPcj+VeP3DHyY1YguOM4p1leyWN3Dd27FZ4JBIv1BrROxm1c+oKoa1cPa6JfTxoXeOB2VV6k4q/SMAwIIBB6g1qYnhXgzSUvdWuTcLveEcg+pP/ANavU7ayigjVUjVQOwFcnrOir4b1S8Omx3JF0qOmx8bWJbOT6f41oeF7/UbuMx3e7cE3hm6/Q1xVIu56FKSasdKEI5rJ1y0W7sZIio3MOPrXO65daxHds8c1wYl52RnAIz29a0dPurq5URzRTKQB9/kfgaztZXNL3djybVITBeOrDADEMCO9Zo5YkeuDXdeOtL23Uc8a5aUbSPU1zLaBdw6c11KpjHBVCOoyAefxFdEZKxyyg+Z2PpikpTSV0nKZWqpG86LIoIKd+/NUraKKETNGFUdABxV7XIi1qkq9Y2wfoa5SefTJCyTSt1w6rnnHY1xVU+dno4d3grG/HDbzsUdVLr1Bp8qxW0eVAGOwrLs73TBtitZEV88LyD+tWrkFwQTxWLNzBvraPUJUaVSRG+5QO/GKhbTvteo2GktyLiXzXTqUiUAt+ZAH41Z1CU20UsyNtMKFxx6Crvw6tpbrTZNevmaS+vDs3EYCRqeAo7DPNbUY8z9DnrVOWLtuztaKWiu088huYBc20kJON64z6GuRWxk3tG7rFIh2kV2lY2v2ds9sbg5S4GArA4z9axrQurrodFCo4u3czVgECc+WTjqBVaa9xlQdzH0rOMWoSH5Zsxk4PHIrQtrDycbjuJriZ3XuV5rNLm1eK5ZlSb5XZeoU9cfhXb2VrBZWUNvbKBBEgVAPQCuYnQsuxFLMeFAq9pWlzadI85uZSZcZiLkov0Hat8PO10c2Ihezuf/Z', + 'https://twentyhq.github.io/placeholder-images/people/image-52.png', linkedinUrl: '/in/cheryl-chambers-0f636392e0', jobTitle: 'Education officer, community', }, @@ -7525,7 +7525,7 @@ export const peopleDemo = [ city: 'Shaneton', email: 'mark.gonzalez@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDGApcU7FL0GTQMgubq3soTNcyrGg4yaxbnxVaombeJ5M/xP8oFZmpPL4h1hYbVXdEG1FBwPdj6Vr23w21S4iAZoAuc/eOR+lZSqRjuzWFKUtkV4fFpZvntk2D+6/NbVlqlpfoDFIAx/hY8/wD16gl+Ft7Gn7q7jPtgiuc1Xw/qXhyNhKv7pj99MkZ9/SpVaLdkypUJJXaO2IphWsbw3rB1G3MExJniH3j/ABD1+tbmOa2RgGKo6xO1to91Kv3gmB+PH9a0MVn66o/sO8JGQEzgfUUMCPwLYQxRvMSCzkAt9K9Ts0KRA8Ee1eTaJZrJ4dt3kjmlVnbCRnGTmuu8Mrc20sSRxTRW84yVlbJU/wCRXnVVdtnq0dIpHZO21CTtUepOK53X47e50ycEJKhQ5xyKzvEVvI9x50trNdIp4EbY79uamtbJRGwitpLcciRGOQfes7aXNOtjy3TZFsNZtgjfIZNpHseK7nHNcELOT/hJjAqnEd2M8dBur0LbXpw2PJnuMxSMiyI0bgFWGCD6U4UYqiDS8MRQw2n2GQA+U7DgdeetbUt1a22p28MssUIKllBOMmuctHK3G5euBU95qumG5Vb5Qz/dUeXuIrzJRak0z2Kck4po6bTbm01BGaKWKVQTtKkEdcUak6RQMqdSMVl6Zq+nSgraMvLYI27Wz/WptRbMbtnoOpqGraFnOw6UsEE9y+PMkmModeMhs/KfXsaKINTl1GyQtbmCJWIRSclwOAx9M+lBFejQi4x1PLxE1KXu7IhFLTRTZZooE3zSKi+rHFbGBIGaPLqMkc1oW0Zv41ljuBE5HUAGuJ1bxNG0ElvZBiSOZc46dcCra3V3GqS2km1ZRkDtmuPER95NHdhajSaO+jgW0hzJMsj92P8Anis29v8AzIZWB3RxqXbHfAzisi1ttYvQPtbLsPQA9a1762js9FuFkxjyyGP4VyuyZ1OTlqZmn6hDqNhHcwAhGH3T1HtVgmuS0Of+ybaONyWj2gP7e9dNDcw3Kb4JUkH+yc4r1E7nkAAAAAAA1Y//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-53.png', linkedinUrl: '/in/mark-gonzalez-4546b149d7', jobTitle: 'Adult nurse', }, @@ -7535,7 +7535,7 @@ export const peopleDemo = [ city: 'Roblesport', email: 'douglas.andrews@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-54.png', linkedinUrl: '/in/douglas-andrews-7a6a535f81', jobTitle: 'Accountant, chartered management', }, @@ -7545,7 +7545,7 @@ export const peopleDemo = [ city: 'East Lisaburgh', email: 'stephanie.porter@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-55.png', linkedinUrl: '/in/stephanie-porter-74bdb68326', jobTitle: 'Computer games developer', }, @@ -7555,7 +7555,7 @@ export const peopleDemo = [ city: 'Alexischester', email: 'meghan.campbell@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDZZRTcVIaxfE2sromlPOuGnfKxL6n1+gpDItb8V6fomY3Jnuf+eMfUfU9q5e7+I9/PEBaRRW+08kqXJ+ma4uGK81S+YJmSVjuJIya66w+Hs1xAJLuVo2P8I7VEpqO5pGnKWyH2PxHv7eOY3SR3DPzGCQu38q6zRvFtlq0SLKVgumYqIs9fcVylz8Odqlobls46MK5xorzQdXt2lIMkLgq3r9faiM1LYJU5R3R7QcHkdKcoqrpt9BqlhHdW7Aq3DAdj3FWwKogeBXmHxHvfM1OK23ZSJcbcdCev9K9TC15B42c3PidQyeWwKxsD+lAI3vBulx2+nJME/ePyWPWu6iRhHhefauQN1Hp1skJ88KVwohXnirWj3l612iGaZoWOR5w+Ye1cTu/ePSjZWidJIj7T/KuF8Z6bDPZSTlSJkGQ461q61qF3FeGON5xEPvGEZNVpJl1KxlhBnJCEETLgnIojp7wT1vEyfhvqUn2iWxd8QsuVB/vV6TivJPAMTP4mjG7aEySD3OK9eIrtPNHbcgjOM965HxR4ehle1ukiA8ogbgMk8559a69ahvrc3VqY1OD1HvUzu1oXTaUlcytM8iSELKin3NJPc2VtfwoSI03cHb1PeoII5I8Kw8t8fMPQ+lRma5LMn2eMIOhlYc1xJO9j1FZpWJ47uxm1CVS4kQnHA+79al1GG3ihxEFHHYVnxyTRuE+zoyHg+Uw4pdQlEFs8rZZY0LYHU+1DTTsD0TuY2m+H501mzubSJ1CSF5pOAAOwPua9Cxms7QmaXS45ngaF5MsUfr7VpgV2QTS1PLqNOTsN6U5aTFXrHTJ7oq+NsWep7/SrIOV1ceVfnsGUMDTIHtWB84bs9s1d1nSLmx1F1uGeSNifLkboyk5A/DpWDdafMvzQNwe1cNR2kz06SvBF+eSzQfuF2/0qhJZNrJFisvlLIQWfrwOePfimQ2M5b9436VMI8SoF4walStK5Uo3i0dZHGkESxpwqjAp4NaFlpaQ+HIZboMZipYEn5uTwD+lQrZccNmu3nStc872cnex//9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-56.png', linkedinUrl: '/in/meghan-campbell-5098a6f7a9', jobTitle: 'Theatre manager', }, @@ -7565,7 +7565,7 @@ export const peopleDemo = [ city: 'North William', email: 'caitlin.martin@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-57.png', linkedinUrl: '/in/caitlin-martin-93755bb8ba', jobTitle: 'Scientist, research (maths)', }, @@ -7575,7 +7575,7 @@ export const peopleDemo = [ city: 'North Sean', email: 'kimberly.terry@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDodf8AEMWlIY1cCTaST/ID3ryfVNVuNYvFlmdiegXPFaPizUI73WZJlYpwFKMMgEVzE1ykUjEqNwBxk55rCc3J2RvCKSuaMV5aRYTyppeefKHB/HvUN1NbXn7qN5IGHSKUZz9DVS2tdT1W5W3t2JyMnbgACuw0z4Y3DbZbm8y/XbjIqbJPcvV9DmLOOZWeKW4I2HAVRyxrU0nxHdaTckA/ui3MROQ3+Brs734f2kkYbzXWYL95fWvNtc0ifR9Q/fZaMn5XP8qFJX0BwaWp67oevG+cLtfDfNvz8oFdIDkZrxLRNdksbyIJKMEjIHQivX9J1GPUrFZ4jlclT7EVvCV9DnnG2p4BfzzTOXc9WJVT/M1VM6yOuVBc8DGM025Bdyxfv82KueG7BtR12JNp8tOSTWOiVzZas9J8D6ALK2FxMd00uCR6DsK9CjQhAMVxpupbBBBHbzSO4O3a2xRgetGgapqks6+f5whkPAkOStZJO12dGmx2Minae1ecfEaALorShcsjD9a3vFV3qMRkjtGYLGu9th5b2FcprzXF94MvjLA8UsQUnLlg3I5ppapik9GjgtNYM6+YG4/unBIr23wggttPWI5RJAGRSOhPJyfWvENKdmuYtqvktw69j9K990HTzbWCpLIZmHJJGK6Ip8xxyfunz3dOsN3GHX90JMtkdRn/AAr0rR9GXS5Yp42V0kU4Ze46iuN8U2E9rdyrc2rp5ZxuHI9ual8C310NfS1knke38lgsbMSq9DwO1ZzV43N6crO3c9ts1gu4QJEBI7EUl1HDAUSJAGznAHSq1gCg4PbIpmoXWkTqEvLlAwOcK5z+lYx1Om13oaE0MT3xEqg7lBGawPGSW6eGr2NV2r5eSB6Dn+lWoLrTTKwhvBNIABlm5rnfH4uLjRUghVmkmmHyr3ABP+FUlqkTP3Yu5hfD/RYbm9865HmgLlV7KTXsCDA/wrkfBGgy6dpcE10uycptKY6DORmuuHArrgtDz5vU5DVvCx1JZ7aabfG3zJ8mCOc5Jz1rh9Ls9O03xTbWdqlw9yoZZ5DjYvHQEfhXdeK9aMVukNnN/rOZGT09M1haTao8ruqqrq4IwO1ZVfdjoa0dXqdHbXfkuIpGwQcAnuK0fsSXYz8gJ6Njms57dbgbWGGxwajtlvVjfbLhU9a5oux1p21L0lgtqSzlGP8AexWGviRU8RtbT2RNtCoxcZ7nrx7Yq+ZpWiaSV92OnpXMXDEtM2c9vxralrMyryvHU9JhurZ4laOeMr2+arArz1QCIlJORgnH9a3bbVLiFTufco4w3OK6AAAOuxxH/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-58.png', linkedinUrl: '/in/kimberly-terry-5f017ebb4b', jobTitle: 'Surveyor, building', }, @@ -7585,7 +7585,7 @@ export const peopleDemo = [ city: 'Lake Amandaborough', email: 'levi.smith@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDX60dOtPUYPNc5481F9O8MyeS5SWdxCCOuD1/QVxpXdjoeiOf8Q+P3humtNHCMq5VrhhkE/wCyP61xNzrF/dSEXF3NNk/NvckUulaReapL5duo2jqx6CuztPhqzxfvbsb29F4re8YaEKE56o4eC/uoJowlzNHsORsbFd3oHjq6W4S31MiWBsL5uMMnufUU2b4WXOC0V0hPuDXP6poF7okiRXHyxk4EgGRmjmjLQfJOGrPY+Dgqcg9DT0HPSub8Faol9pAtWbM1r8p/2lPQ/wBPwrpxWDVnYrdDCO1cN8S2Y6dYQY4eYnP0H/1670gZrjviJCJdGtSCfMSfIUDqMc04/EDV0UPCNktvpalR80hLE139mrMoJ7AV5/PHc2lrbpbvICIwAsY6kCtLw/qurrc29vckkSYYFxggehqZK/vHTCVrRPQrYknAAx05FYHjeCKXQZt0anbgnI96zvEl/rNhOIrNpNo+bMYBJHoM9TVuxhur6zltL8TnzIyGEyjnI7EUJW1HJ30OQ8CHdrF4U4TysEevzV6AAcVx3gbSXtJbyeVSrMBGue4BOT+YrtNuBVTd5HKk0tRpPNYvia0a50s7V3Mhzj68VsHrSTw/aLd4txXcMZHWpKi7MxdPWCZQJFBOO9TCJBrFukajAYZIqk0LWl0YwxO09fWq8kltLfq01wyOv/PPOQfwpHUmrKx3csdvJLtnVd2flzzUsyRww7gecfgK5+yn00RMhlJlcgln3DLeozxWxMu8Bd2Rih9hsoWlr9mi28YySPXBOefzNWD0qZkOBk5OKbt45ppHLOV3cgKc0oXmpAAadtFOxJh66iRvDIGAdsgjPp3qlaosjDdJt54K9RWhr2j3F1c219bZbyEaOWIDllOCCPof51hmNw48qQJnuw4FOUXF6mtKV1odfaRrHbhPO81cfxdaJ7gQQNMxJSPk4HNZmk2twVP2m4GP7sf+Na11p0up2j6daZWSVdu8D/Vjux/zzULV6FyejuSW86zQRTgHZKgdcjqKexU9K3pdFtxaRW6AqIUCoR1AArMk0iZE3xnePyrplSa2OJTTAAAAAAAAAAP/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-59.png', linkedinUrl: '/in/levi-smith-4d6387a547', jobTitle: 'Mental health nurse', }, @@ -7595,7 +7595,7 @@ export const peopleDemo = [ city: 'Lake Paigeborough', email: 'tracy.alvarez@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-60.png', linkedinUrl: '/in/tracy-alvarez-633fc7a383', jobTitle: 'Environmental health practitioner', }, @@ -7605,7 +7605,7 @@ export const peopleDemo = [ city: 'Owensstad', email: 'david.gonzales@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0LFLRWN4p8QQ+GtFkv5V3tkJHH/eY9qYjO8RePdK8PTvbuHuLlR80UfUelcHffF3VHdVt7W3tlPcguwHY81iWOj3vjDV5tSu5zEsjlmZB39F9hXa2vwq0yTDSz3EpI5yRWMqyi7HRDDykro5pfir4iUoWmtSDzhoBz7da7bQfifpWoyrbaghs7k4G770bH69R+P51Tl+E+kJyGnAHqa4/xL4Gk0i2a5sJHkWPl0I+bHqKSrxbsVLDTSue78EZHQ0mK84+FXiiS/s5NGvXka4hy8DMM5j7jPsa9JrdM5QxXm3xecCy0iNgNrTuxz7L/wDXr0oV578XrYy6BYSbSQl1gkDplT/hSew1uVfCluiWEIQfLtB/Ou9tCAgAOfavK5/OtI44B9qEYjG1bYfMxA9a1/C66tDqUUcs1wbWU5xOcsvHHSvPlHqerCVvdPQpZMpgnFc3rxX7JIwGcIc/lWB4lGqtqLyRS3Rt0ONtu2GI+h602we5lIiLXJQL86XAGfrS5dLlOXQ5nwZIIfiTp4iyBJvQ7e42ng17rXivgnT5U+KBjAzHbtK+fQbSB/MV7YRXoQeh5U1ZiCuN+INo91a2o3Hy13HZ2LZXFdmKzNe09r/T8Rpvkjbcq+vqP8+lKabjoOk0pq5iaUtpeWiB0UsBjkU+S9sLPXbeCWeKIAEqDxk/SsPTXmtHeJwQ8edyd8g9KiuJrDVLgfalDMmQdkZYj8QK4eXU9SLulbc6awutPvbyeNZ4Zl3EcEHB9D6VNqMVvbRN5SgEj2rnbW7sbOZkgXZuwNrxFM/iavalOWiODztzSa1sU3pqZ2gaSX1f7a3DSXSyIVOMqOOfyr0Y1z/hzT5YreCWaPYFTK5I+Ynvx7V0BrtoxaWp5uIkm0l0EFOFNFLWpznnfil/7L8SM8fAmAkx9eCP0zUscbzoDFOInfHINQ+OjFeayIYXDyRwBZAP4WySB+RrkINRvrZdmWfHGDyRXHUS52ehSk1BHoO02lsWllWVwKwp71p2ECsC0h5I6gVjJfapfAhYmRehcj+Vatjpj2Vs07jMh5ANRojS7keqIgSNVAwFAAoNZPh3X4vEOnG5SFoXV2jeNjnBHWtY1+jzGrH/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-61.png', linkedinUrl: '/in/david-gonzales-6df036cad1', jobTitle: 'Legal secretary', }, @@ -7615,7 +7615,7 @@ export const peopleDemo = [ city: 'East Thomasbury', email: 'lisa.tran@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-62.png', linkedinUrl: '/in/lisa-tran-e0115b5653', jobTitle: 'Therapist, speech and language', }, @@ -7625,7 +7625,7 @@ export const peopleDemo = [ city: 'Williamhaven', email: 'kristin.pearson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwCxigcdacBWB4u1RtN0V/KOJpj5an+7xyfyoAo+IPGcFg32ex2zT8hn/hX/ABrjZdXvtRcme7kcf3Q2FH4VlwwPczhQu5icKvXJrr7PwJqE8SEvFDnqBnOKynNLdm0KcpbIwF1W/tTthvJlA6R78itbS/G99YyqbkfaLUn51xhl+lbjfD6GBVcTyFxyQRkZrkNa0abSZm3EFG6EUo1YydkxzoyirtHq+nala6rZpc2j7o29sEH0Iq1ivMPA2sG21BbKSXZFM3ygjjdj1r1AcitkYMAMCvKPGGqNf6o8fmf6PCSqY6E9zXqsz+Xbu2M4U4rw3UMtfyhSGQN1HSlIcTtPA+jRvH9vkXdIxwmedor1C2gYRjIrze38zT9GtY0ild3jyNjlADjPbqa3PDF7qSzpFPLM0co3ASHJX2rgmnK8j06bUUoHW3ERMZAFcP4s01L2zKEYdcsCKl8S3l/LK5hefyYuqxvjdz+tUraSS5iMbQSROg+bLllbI/nUxjb3ipNO8TzVXeG4DK2GRh8w7GvatCvv7S0iG4bG8jD49a8ZvIGhvbhGHyhyM/jXqHgKQPoJ+bLiQqfbHT9K9CLPLkjobgK1tIr/AHSpB/GvG5dP8nW00+RvlaYJuA656V7QV3IV6g9a818Y6cYNRNxG2ON3HBUjpzRIIbndaQlvNapBMgZk4weRxWisMMOowxRqi8ZPQVx/hfU3v7ITsAsiuUcA56dDW1d6jpjzL9rLGVMgFM5Un3rznFpuJ68GpRTRo2UUNxPOkio2G7855qLVlt7a3ZY1VeOgFUdP1HS4naO0IViejDkmq+tXPl281xIfliQsfypWd7DbSVzjfElqlrpIn6STzA8856kmug+HLf8AEuuUI/5abh+X/wBauAudRv8AXruL7Q4bb8qRoMBR3wK9T8K6T/Z1irP/AK1l5HpXoU4tKzPLqyUndG6p4rn/ABBo39qskYVixI5A4H1Paug2tjgZqJ/NJIBC8Z6c1UpxMkmcXpVlFody9n5rm7fLyJj5QB0Irora2W+YSpcLG2MZxVK808rrVtqRJbzITGT7g5/z9KfNaSJIXgk8sNzkdK4asvf0PSw91AtT2i2bGWSZXb1xXM+Kboy6NOkeSGwCfXmtY2c8j4nmMh7AdKranYLcxJAPlXOcjtURaUk2aVLyizh/D9vcDVLZ4Yzu3jHHUdxXtEaBEAHQVjaVpzaZp9orKrNtG5sYIzzx6VtoQy8//9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-63.png', linkedinUrl: '/in/kristin-pearson-e0ebe90624', jobTitle: 'Editor, film/video', }, @@ -7635,7 +7635,7 @@ export const peopleDemo = [ city: 'North Lindsey', email: 'bruce.wood@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDDbais7MAqjJJ7CuN1DxLdXcjxWbGCEHhgcM349q2fFdy0GlrChwZ2wT7D/IrD8O6Omp6lDA2SvV29KmcrFQjzOxnPbGRGdhvZupPXP171D5U8cZilVjGwyCR0/wA4r3ex8N6RDCEFlH05J5NX38O6S9v9naxhMX+7XMq6Oz6q+587QXE9rKNrtGQeGU4rsvDutSagXt7lwZlGVOMbh3rvdQ8D6HJGXW0AI7g159rGit4c1mC8tBmBm5U84rWFZN2MqmHlFXOj2ZpNlSghgCOh5pQK6DlOf8XxA2VsxHAcj9KPBq7byMJjcx5+lbmq6U+r6W1vAR5wxINw4wDjGexPNJ4J09YLm8V0ImhAQ57GuWtNWaR2UKUk02tzvLfG3H61bPT71cRrx1EIwgjuXVMsoi4x/iaoaCuti9jSWefypFDMHbOwHsfQ1yqOlzu5tbHoFwo8ogkDNefeMBmzIA/iUZ+pxU3jPUdYtrv7HZLIV2gs8fXmsQx3ktk0d08rbJU3GTnow5FXCNrSM6srpxSNeNdqKvoAKlAqMcGpBXonkmpZktbPHESshwpKnB255x79atxRQ2t9LJCuDIVLk9TgY5rKhkeGVZIzhgeDV6OeZ5GlmKnd0CjGK4a9Oz5l1PTw1ZSioPdHRIYbqPBC+4NQMLSCR4YlRX25bHGKrwk7OuOM1k6pd6I0Rgvp7cndk725z+Fc8VfQ69EX9Qht31OMy7GWSMDqOCKzNSSCIiONRgckfSseKfTxeYi1Bbh8cDdyBntVu4dnk+britYxbkkY1JpQbIBTx0pmOalUV6J45YVcmr4gLwsqn5lwwrS0LRP7Vt7pWOxXjMccg6q3XI+lZuj2Ooac81tqpY3ayHcScgjsR7EVz4l2gdWEV5iQXT7dgPzdCD2qee1a5t9sUMRcD+JQRUWoaaZH3wEo/qKw59Z1Cxk8jy3Yj+JRXFFa6HoczjuWJ9PktpTJNFbqwHGxQKhUtIDI3fp9KoXGpXdxG8k+VVRlh3rYCiS1guEB8uaMOn0NddCN5XZx4qo2ku5BtpRT9vNAGK6jAAAAAAADhP/Z', + 'https://twentyhq.github.io/placeholder-images/people/image-64.png', linkedinUrl: '/in/bruce-wood-e61cf3a298', jobTitle: 'Charity fundraiser', }, @@ -7645,7 +7645,7 @@ export const peopleDemo = [ city: 'Kristinshire', email: 'stephanie.stout@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-65.png', linkedinUrl: '/in/stephanie-stout-da19425869', jobTitle: 'Conservator, furniture', }, @@ -7655,7 +7655,7 @@ export const peopleDemo = [ city: 'Daisyburgh', email: 'denise.sandoval@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwCu1MJp5qPBJpFCAEmmvcQwKTJKox2zzVPU7w20PlQ83Lj5V9PeqNr4J8Q38CkKLWMndulb5j+Has5VEi402zYi1G0k4EyhvRuKmEiSKGjdXU9GU5FYF18P9cs4/Miu0kZewOCf84rn21LVtCvNlyNgzypGQaI1E9hypuO6O+JqRKo6dfR6larPHwSPmX0NaCCruZiGmnGCT2pxFVb2VILKaWRtqhTzQxot+FNIiv8AWJNUkPmBMBFPQGvRcgKFVlPY15f4duPJ8JLNMk582ZlVIc5OAP8AA1v+GUYSl2SWOFl34kPPTvz1rilu2d8Nkjo75o1XaZEUkdMjJrzjxpp0V1YSEqNy/MDU+sFri8kne2nuY1PypGefamE+cjxeS8e0YKMcgiktNSnr7pw/hrVBpmoGCZj5TgIcHvng16PHXj16jQas6AfckIH516zpMrXOm28xOSyA5rtR57LBAqG6tEvLZoWJXPQjsanNANMlHR+FrSK00OKzlQF42YHcO+T2qTU9Tt9Pl8kW8jAxsQyIdox1yRRatHIySRkfOoZgD0PfNZeseJpLV1htbGecDILpESoPfmuDVto9SKVlYh0G4iui+5XUnnZIuCvPSpNXNvGG2ABsHpWfpurTXLv5lnNA5YnLx7c+9JfN5hJJpNNOxWhyM3hu3vrueZyRNI2VHYA8Z+oNdhaWyWltHAn3Y1Cis7TLqyvJnS33NLAcTZXG0+mfw7VrqSa66V7anBX5bpRItoo2ingUYrUwLNhKYJTjowxWlPZrc2wIufKxyMHmsq3XEqn0NWdQsLjaZbdiQOSma5K+krnbhm+WxSuIhajCyhs9T61mXEpYYHPrTjDcSP8AOCB70rwbYiTWFzpItB0ddOjnuGYtLdP5jegHYVsrjNQWk3nRBVRgY1G7jjHTOasKtejFprQ8uSYAAAAAAnqf/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-66.png', linkedinUrl: '/in/denise-sandoval-07f4d63a26', jobTitle: 'Immunologist', }, @@ -7665,7 +7665,7 @@ export const peopleDemo = [ city: 'North Ryanmouth', email: 'christopher.clarke@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-67.png', linkedinUrl: '/in/christopher-clarke-44a16b8bf4', jobTitle: 'Stage manager', }, @@ -7675,7 +7675,7 @@ export const peopleDemo = [ city: 'Barnesburgh', email: 'kimberly.jefferson@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-68.png', linkedinUrl: '/in/kimberly-jefferson-ff1550e548', jobTitle: 'Advertising account executive', }, @@ -7685,7 +7685,7 @@ export const peopleDemo = [ city: 'East Austin', email: 'jeffrey.hunt@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDsCwI5P5VzPizxjaeGbcKV869kGY4QcceregroQ3FeEePpzdeNL/8AeFwjLGvtgDgfjmpKZnav4h1TXblpry5d0LFliDHYnsBWUGIYZzXY6b4KF1aRySXDK7jPHatBvh1EQCLx8n2GKn2sUaKhN6nCRXk9q4aGV4z0yrEV7P8ADzxPJrGltaXcwa5t8BSerLj9a5J/hlMYs/avm9NtRaXptx4P8V2BnkDW8rBWYccHijni9EJ05RV2e0iTjvT1kwOtVsjtRuPtVXJIgTjrmvB/EkbHxjqII5+1Nx+Ne5zTeRayzbd3loWwO+BmvJL22e68SpqTKm65PnNHnhSAOKlySLjTcldHR6VvNpCrDDBRkV0MEQdF+bkdjXA3N3eKCxaWPPASHB/HNR2epanBtJnuPLYjHm4JznpXO4X1OtVLaWPTokZkZd20j3rjPGsLT2sA/jW4UBh71W1vU9ZhuCkTSRBQpIiwW6e9HnX1zbRrMstw4licJLhSSHHGR2NEY2aYqkrpqx6SrbY0HJIUCl3E9BTAGKgkYJHIz0oya6TjH4VoypGQRgivObvTDYX8ivy285PtjivT1RQOlYXi23hGmxziNd4kA345xg96ipG6uaUZ2du5yttCkwI4U561I0UK3HlGRCEwTuwATVWGXBGPzqtcP9qk2SW0rhTkbUzn8a5lc7dDqNT+ySywSLPHnYFfHJ9M4qS2tojcRR7g7btwbp0rm7WWOzd2+xXHzDaWljJyM9M9q6fQIPtGokkZSNS39BTSfMkKbSi2ze2E8A4/CnCI89Ks+QoP3jT1iFdh5xTmuorePfK4Ue5615tNqWp6hfXf2jUJJLMvmG2OML9fp2rd1W1vEJkYvKc8nPOK5C+32tw0qBlyc4PUGs53asaQtF3JZphaS4fIU8g+lWo5Yp4tn2ryz1Vl61nf2hDeoEfCS9Oehqo1thjhih9uhrC1tzqv1idOu2OE4vWnY9d3Wuj8KXscdtepIhSSOXazdcgAfyzXI6HbRRMJ5csR3Y/yro9EzHFNOwwZJGZvqTTg7O6Jq6xszsFmRwCDkVMjjsKx9OQiOXIYxk/KM9PpWjFG20eW2G7h+h/GulNnI0f/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-69.png', linkedinUrl: '/in/jeffrey-hunt-faa3d941ee', jobTitle: 'Customer service manager', }, @@ -7695,7 +7695,7 @@ export const peopleDemo = [ city: 'South Gregorytown', email: 'nichole.lowery@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0+jpS1yXj7xSnhvRGWKQi/uQVgC9VHdvw/nWTdjRK5J4n8eaV4cUxFxc3n/PCNh8v+8e3864OL4v6kL9XltIDbE8xAHOPY15/aWtzrF5sjQvIzcluea7zTfhk7Ij3dzhupUDispVLbs3hSbWiNn/hckLzBYtIkZAeS0uD/Ku30DxVpXiSEmynxMoy8D8Ov4dx7ivKtQ+GEkZaW1vXz12svFcwtxfeGtUguU/d3ltJ2PDf/WNEaib0CVFpao+lSKTFUtG1W31vSLfULVgY5lzjup7qfcGr1amAV88eP9Um1XxjflnOyBvIjX+6FP8Ajk19D183+JrR0+IV3YENmS9ycjqCQc/rUyKhud74N0K3sdOhm2Dz3UMzH3rtlX5Rg5+lcPqTNbWgjCzONpIEQ7AVZ0GW5R4omeURvg4c8jPauOzfvM9NNL3TrJCVU5Irzfxz4eNwj31uwJQEuvt6itfxJd3DlwrTGOI8iL7xx6fnUEP7+3kgfzRlCGDnOcjrQtPeCVpe6RfBzWpRdXmiSMGhK+fF6hhgEfiMflXr1eDfCgmHx40TDJ8mRfoeK95rtjseXLcSvMfGWiqPF0OpquM4LHB5IGK9PrmvGxW30Q3zqWEBAYDrhiBn8OKVRNx0LoySmrmfZeTPCAyjI9aV3tLe/hjLRoSwySQMn0FUrRWUYU9uKhvL3TpHEcsMksi55SMnH41xJX0PV0NGJrSfUJ13Rvzxg55puoRwQxNtUBsYrLtLzTo5GjhjeJ2/56IQT+NW7lXkdFOSTgY+tDXQHZblf4feHfs+o3OqM/zkkAAepPf8q9IFUNLsRp9ikWP3jfNIf9o9aviu6CaWp5NVpydth1V720tr60ktrkI0bjkMR+dT5Yn5VrlfEuiST3VvqQY7EUrKo9f4T/P9KJysrkwhzSsYqzeQ5BOBnINXFggnj5k4PTHao5bIT2wXHIFZL215A2EJZe2DXCn1PV2NeSCK3jJDBvrWl4bgW8u5bhjkQYA/3j/9auZENw3Ezn6ZroPB+pRi9utMAAcAS++On5VpSs56mOIk+R2OtYYpRSOaVeauzqecf//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-70.png', linkedinUrl: '/in/nichole-lowery-fb08af1201', jobTitle: 'Planning and development surveyor', }, @@ -7705,7 +7705,7 @@ export const peopleDemo = [ city: 'Lauraburgh', email: 'daniel.wiley@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0ClFGK5jx/rJ0bwpclA4muVMKOOiEjkn8M1maHOeLvilFZGSx0ILLOGKNdOMouOu0fxfXp9a82m1jVtRWWWfU7uct8zo0hIP4f4VBpmk3eptttVMmDzgYAH1NdNH4F1WWNE8uBefvBvmFS5pbmkacnqkcvb3lzbOJra6kjZ+rxyFW/E16L4K+IUyE2WuXJlix8lw/LKfQnuP1qqPhdK0YZr0BjywINc3r/hG90VWmjfzYAeWXgj60lUjsDpTSu0e9wTw3lss8D7436GlIrgvhhrz3FrLpV5LunT95ESfvL3A+legOKogsYrifitHv8IRjB5u48/TB613GBXM/EO1N14Ku9uN8TJKoJ64bnHvjNMSOO8IWiR6bEyjDPlv1rtIImCg+npXBx200Oj2ca+eT5IOIuDnGa1fDlxfxzwxO83lS8gTH5l+tcco3vI9KErJROwKMVPYH1rm/E8Ky6ZOp5+U5qp4ga7knkZGnZIssBExyfoKWyjnmi2yCcfLkpNz1pcvUpyv7px/gsSP4700WsjK+G3kdNoByMV7iy15L8P8ATHt/Hc9y6stujyxRkDguc8flmvXnFdiaaPNknF6klYfi+DztCOULqjhiB9CB+prexUdxbrdWskD/AHXXGfT3okrqwU5cskzitJWCa0jjcAkKBgipkjhj1mJF2IFGfSq01pJpepSW7OGI5BAxkEZqjNNY3NyGuWAmXIBXJK59xXHZ3senFppNHQQpBNcOr7G5OD1zT79I7eEhABx2rIsZ9OtyUgZQ7HJBBUk/jV7UPmjJJ6Ck1bQq6IvDVmIr2PYGKs7TMT2Y5zj25FdkwqtpumpYQDks5UAk9varTV104uK1PMrVFOWnQfSijFOFaGRyfjFPKmtbhOGYFSfpjH8zWLaq0wGJQmehHWtXxhqUL39tpaqWmRDM7Z4APAH171zEdve+c8duygjkK3pXLU+M76DfImdEsRhjw0gc+pqq0puJUjByu4bj+NQwafqRVvtUqInonJNWVtvIiwnB7GsmzbVnfHpUTiud8IeJzrVh5d+Y49QjYoyjjzACRuA/CujfgeTsf//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-71.png', linkedinUrl: '/in/daniel-wiley-9ed6e2002f', jobTitle: 'Surveyor, mining', }, @@ -7715,7 +7715,7 @@ export const peopleDemo = [ city: 'Mitchellbury', email: 'elizabeth.watson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDumQjpUDnB6VfnABzjiqjqD2pMZAAWbAGSegFWFsyD+9kSLHXJzj6+laUNhssSY5AszDcWPYelZ00unx7Q5EjR9cHcCfw4pOy3Gk3sWH03EatHOrhhlcDr9KqTW8kQy68dNw5FSNqNhMRi6EPrkbcn15xRBdFZ/L+SRHIDKp4YeoFF09gaa3KRHNKKuXtqIXzGcxk4x/dPpVUCgDUf5lwapkYPSrjdKhcqOSQAOpPamSjntX1ye9u2tInIt4jsIX+Nu+fao4pW8rAYH2zXKXsy28I80TSozOW8nOWJY9xVXRJ5GvEWFZo4XOdspyRXHNtts9KmkkonYTyOByVx7ms99Rn0/wDeQSFos5ePghh3APb8K5rVpWN8zTQyzwqfuxnmrlnKJ02JFLGg6K4xikrrUbtL3WeiaXqy6vpIuMhgVHPfIP8APqKkwT0riPBN59k1TUtPnk2wySqbcEcbiCWH8vzrvNorri+ZXOCUeV2NOeEdVqjNCstvJGwyHQqR9RWo1VJU5yKtmadjzi1MUSG2kQLsG0A+1LbtaxakoJSMKCQM8n3xVvX9OezvRKXDCUlhgYxz0rAubqzlOHhMjKCMqvK/jXBytSsespKUU0XYWtZrhkLxuMkblIOPrU9w0UKbY1HI7VlWl3aRt5ccPlM395Cufx71alXPLGpldOxSsS6FD5mt24K5G/zCfcCu/rL0XSobS3huRuMrxgnJ4GeTitTFdlOPKtTzq81KWnQ2psdqpympXlqq7gmtTAxPFMYfSxJj5kkGD6Zri0iZwQtwIiOldr4nl2aUsTI26dsoccYUjNcPd2soXzIsH2rkrNKR34ZPkJGiMQ+eVZCe4qKSRhHnPPaq9vFcPJyqoD1Oc1aeIAYzWPU6bXR6NZ4NhbY6eUv8hUhAqrocF9LokMkluwRRtRv7y9jirO7Nd8dVc8mSs2j/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-72.png', linkedinUrl: '/in/elizabeth-watson-037218b4e1', jobTitle: 'Journalist, broadcasting', }, @@ -7725,7 +7725,7 @@ export const peopleDemo = [ city: 'South Natalieport', email: 'sandra.bailey@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDqkAbqMU1lU9G6VI2CP8KytU1KHSrMykAueEUnqf8ACuJs6LF4lEG53AA9axp/Emlm6EAuckfeKDP4VwOp6vf6pdeRGC8r9zngeoHQCq40PULZQZLbcvcqf6UubQtU7nrcGp2UkGLdwSOxGDVuKQyoCgGK8y06SW1UiTcFAyu48j8a6rRdezMkE75jcfKx7U4VddRTpWWh1sYO75lq3GeKrLICoyD9alDL2Y10pnO0ZzKSuFPX1ry/xbqvnarcANuS2/doo6buhP55/KvTJpvs9rNcsP8AVozY+gzXhsMj3d2BJkvLOCfrnJ/nXLa51ROy0CwEKG5lA86U7jnsOwrrY4kmjyNrevNcjeX0WnhQ1s9wzD7oXOB/KrelSlbhJIoHgilALK3YH+tTbS5un0Nq50ZJ0JUAEc81yWo202mz/dKrnIz0+ord8SzC2kjZoJp0HaPJH5VU1Gcaj4eu9sDpLAm7ay46c/5xQ49Qb6HV6BftqOjwyl8sBtb6itETeWSC2a434czma1u4S33SrqvsRj+ldNd2DvdCYMwx2FbJtI5JJXLjwebE8bLwylcGvGtP0qWHUYJJAcpOyMp6ggmvb0IIya5HxRpMNvcHV8okY5kJOMMeN38qzd7aGlNq9mV7GRGIDopI45GaXV7uC1eIsCEJH3VJJyfQVFCuGBB61Fcas0VwFSzeZwe4wPwJqFroddr7G1Z39rd3MkeGKjH304zj34NT6kkP2WWMKMMhBx06VnWmsGbMU+nSQr2YAMPxx0rQlXjc5O1VyeM8U3fYTVtzG8A2L2dzfnb8q7Uz6d8frXcOdwqK1t4ra3VYlADfMT/eJHU1YSGSXlEJFbWexwyavcrJkD7jVDqenJrGl3NhcIfLmQrk9j2P4GtTy2HpTVkiV8NMm70zVKNiL3PMtH89dMS3uuLm3ZoZM9cqcfyxWlFDE7ESscHtmrevi1GsytarhmwZsdC/r+WKp7CwDY4Nc8rKTO6m3yo1YIreFP3chI9CatWkf2mQow3IR8wI6j0qlZ2o8pnbt0rQs5mt5+wD4Qk9s9KqFuZXJq3cXY3Le2VVUEYVRgCrqzOFAQLgcVWRgXSCQhJSpZfRsdadsdDhP//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-73.png', linkedinUrl: '/in/sandra-bailey-74db8eab37', jobTitle: 'Minerals surveyor', }, @@ -7735,7 +7735,7 @@ export const peopleDemo = [ city: 'New Kristin', email: 'andrew.henson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwCYJTLiaG0t3nuJFjijGWZjwBVwJxXnPj7U2u7yPR7cnbCQ83ozEcD8P61yRV2dUnZDdW8fu7GLSYSq95pVyT9F/wAaxpvFmsOGD30mGAGUwm38q39B+Hi3tokt7cPEz8hFPSurtvhXpuwF7mZ8nPbtT9tTWg/YVWrnnlv4x1e0ki827M0aEZVwPmHoTXoel6rbaxZi4tm46Mh6qfQ1DqHwnsPKbyLmUEHIyAa5KSxv/AmqxOrefaTna/bgdQffuKOeE9FuHs6kFeWx6AVpNmakjKyxrIhyrAMD6g07bUgWgvFeNa2W/wCE0vt5Jb7TgfTjFe0AfLmvMrjTlufiDHcL89rdSeahI7gcj8xVKSje4uRytY9F0gZgSMj+EfhXT26YjHz5PpmvNNSN4tyEQ3G3HyCJtv4k0vhq61hL+KNmuvKlPSdslfr6VyKGnMeg568p6XKCUI3Yrznx+B/ZLMQCUdWB/SpfF93q0V7Jb27z+XEoLeScE/T1rCvY7u98PX0crXDFYwdk/JDAg8GrhHVSIqS0cTo/Du5/D1gz53GEda0ytRaciJplqqEFViVePYYqc1sclraE68rg1zV1aLDfQzAHbC+1B6cHP866VRVDWLf/AEQzgnMbBiB061M4tmlKajo+pespLe+gEcqL06kdaS4udOsLiKLzIoVDD5mIG4k9BWJZ3PldDxjIqteanaXgC3ETGND/AAwliD9a54xvodvMdZc3GnXeruhlilDgZAOStVdVtbQQNbIg2y/Kce9c3p+oabaXMhtixZgFYSxlc/Qmtd5Wnuoh7g8/nVOLTsS5K2pajURxrGv3VGBSmnYpCK6LHA3d3LAFc/4n8RWulLHYSRtLPefIqqcBQeMmob7xpYwb47RXnkAID4wmf5muMST+0/ENrNeMXbzdxJ9cHFbqk7Nsx51dJG1HdtbSiKaTaw+63qK6CBGmhBt7yOBgMBuv6Vjalpzt8pX506A9xWXEl7HJtiDA9ACelcKsz0buOx1V0jQwMbq8juGA6kYFO0FhctNO0oYoQgUfw8ZyfrXPW9rdTzZuTkKfu54qpYaxLpnifUSgDxsVQoTgEhRW1KPNKyMa83y3Z6PSEVg2ni7TLhxHIzwSdxIvAP1Fbcc8U0e+KRJF9VOa1ex//9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-74.png', linkedinUrl: '/in/andrew-henson-23fb7e5d05', jobTitle: 'Biomedical scientist', }, @@ -7745,7 +7745,7 @@ export const peopleDemo = [ city: 'Wallston', email: 'samantha.alexander@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-75.png', linkedinUrl: '/in/samantha-alexander-4a24cc632b', jobTitle: 'Production assistant, television', }, @@ -7755,7 +7755,7 @@ export const peopleDemo = [ city: 'Lake Rachel', email: 'jeanette.nichols@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-76.png', linkedinUrl: '/in/jeanette-nichols-a24214c373', jobTitle: 'Engineer, biomedical', }, @@ -7765,7 +7765,7 @@ export const peopleDemo = [ city: 'Susanbury', email: 'kevin.williams@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-77.png', linkedinUrl: '/in/kevin-williams-0165f2638b', jobTitle: 'Broadcast journalist', }, @@ -7775,7 +7775,7 @@ export const peopleDemo = [ city: 'Jacquelineshire', email: 'brenda.harper@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-78.png', linkedinUrl: '/in/brenda-harper-30b61b982b', jobTitle: 'Public relations account executive', }, @@ -7785,7 +7785,7 @@ export const peopleDemo = [ city: 'Brownbury', email: 'shawn.jenkins@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDtSoxUD4zUznPSojjvQwK7sqgsTgDkk1iXHijTkd0jZpSg5Kjg/jUt7Zz+INQbTY3aGxTBuZVPLeiitBPh9o+EMfmLj/bPNZSqW0RtCjzK7Oej8Z6c8m11eNezt0rctNTtbtQYJ0fIyMGtD/hBdEMexrfdnuWqjeeDLG3t92n7redDlCp4z71Ptn1LeHXQWRwelNV8Gs7TtTS6vJLK4j8m6i6js3uK1fKrZO5ztWdjVZOM1SumMcTuP4VJq+/3apXg/wBDmJ6BG/lQwQaMq/Zww5Lncx966CIpt+U5PvXnOoX9zYWMEUTzruhDDyE3MTjJqz4Uv9Xu7xba6aYoV3h5Rzj0OOh9q4n3PSitLHoDsm3BPNZ11LtGBXCeIdR1mDUWS3e68pDn9yAcj2z1rQ0rU7qUJDMLjkAsJ0ww/Gk9rjtZ2MvVwn9txXq5SVZM7l7juDXSqSygjvXM62rwa15WMxsAR9TXWRwkIB6CuqlscNZWZpSRmql7DK9lIIm2txn6Z5H5ZrWKhhTHjG08Z4rSUbpoyhLlkmZtn9lubVQyIVAAGRVU63pemaiYmIjIjJUBcDGcZqo0jWrXHylVjydvTisuSSTVBuks52T+HhVGO2MnkVwq7dj1krrQ39M1bTNVYiMl0JwS0ZXBz0ORWhPHa23MarXHrfXWmRsq2UvlE5IChgOeuRWrJcmdYzk8qGI+tKWgddSJ0S51FpHUlMeV5i9VJyc/yrXs1kSyiWZt8gQBm9TWTpM8dzd3lvGrb4SvmMB8vIyBn14rdVSBiuijBrVnHiakXFRRpjFI1OOKaoLttWuk4zlfEqi1lEzNiKYYb2xVV5NPuoE8ydg644UiluL661XU9TsLy3VIrObyk4++CM5/IiuO1TTtQs5nELMYhwAD0HpXDUac2elS5lBHW3V7aW1oYrWUvKwx8/TFZT6nuljt7bDyNgELzgepNcnBHf3k+0B3zx7fia7bR9HayiBcDeRzjtUOyLV2dXpFhFaaeu1cPL+8kbuzEdfyxV0rWb4dv59Q0uSeeIR+VcPbjAIDbOM/zH4VqFhXfHZHmSsAAAL8zuf/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-79.png', linkedinUrl: '/in/shawn-jenkins-c839f2afce', jobTitle: 'Optometrist', }, @@ -7795,7 +7795,7 @@ export const peopleDemo = [ city: 'Brendaport', email: 'michelle.bush@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDkY4GmcKo5NdTpuh2McStdsXc/wg4FZ9pAkG1sgr3b+8f8KSXWQkjbSSQcZPf/AOtXDUrOTtHY7KdFJXludobPTRak+TbIMcZXk1hWc1k0ssLWsRG77zHnFYdh9r1+/kkYt5QGxcHG0e1dFL4QkmstizEP2J/rWSclpc3UE9Snqnhy3uIzLZhQw6hTmuPuIpLeVo5FKkcEGuhS31rw1c5mc3NoTh1zyo9QaXVo49TjkaLBnjUOD/fQ/wBRW9Kq07SMKtHS6OXxuNAGDTgMHFBHNdhxlxb6STfK7nb92MHufWqF1LkiNDljxTJL+JnAWPgcDk4FW9DiGo6kMJlU7151ranorV2O78HaebWyHmfeI3H2rso5Idu0Ou4ehriZryWxCxrbySZOM4+Ue5NVdJmvrq8MzWb2yFsfhUpO1zd2vY7LULNLtGXIye1edOF03VXhL7ZYONrfxDqPzFb3i68vrG6hWCOaSLarExkjOfpXMazdpeahaXBjZDcQ7WDjkMpxT5epMmtinqNt9lu5FAwhYlfoeaq1p61GftEUn8DoNp/DpVAJXfTd4pnmTVpNGLbRCSPdnO08+5xXYeGrSaxMjSx4LEYx2HpXJaJqsGm3rLfRh4H6HbkKw6fhXoemXNrdKfs3+qIBU9jx29q4q10ejQ5XqtzpLS838FVx6mpdQvoLSHLsqIQS7sOgH0rPhTkU+71eztIfLuI3lYclVjLHNZR10OmSRci1OwvltUVgxZP4h1Hrg1zPjSOEXemSJGqsrunseAR/Kr9lrOm3krQR28kUjDO5lxz6Z/CsTxDJ9q1yytJGwY0Ln6k//WqrNMzmlYpX/mtZ2iyYz8zYHaqITmr14yyXTBOUT5VPsKg2130laCTPKqO82zldT0i4S+mSON5EBJVtp6V3XhaBk8P2pZSsiAqQRzwTXXXvgqa0iEpn8+LaPMAXGG/wqhb23kQlD2PeuWvK3unZhY3fMTxyDaMnBFWkt45wR5gx1+YVVaHKgkUxcAYy351zo7L3LMlktvy0ok/pXM3MTza3cag8AaIRbUcnrxjittrf7SjQyStGsg27/T61l3tndafM9pcLsZeo9R6g+ldFKHNqcmIq8uhlBKTZzVpgKfPP/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-80.png', linkedinUrl: '/in/michelle-bush-2e2e3d23ee', jobTitle: 'Teacher, English as a foreign language', }, @@ -7805,7 +7805,7 @@ export const peopleDemo = [ city: 'East David', email: 'melanie.gilbert@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD04GjIxmog1cl4p8Uw6bNJYzu0IZAVfb97Pp/KhuwJXN3VNcttOs5Lh5ECp3zkVwuo/FBATHbJuQctITj8AK4bW9fl1i5MCbiG4VIxy/4Vds/h7rF6iyTRxwqw7nLYrJ1DaNJvY1j8Uru5Ty44VU5GXLHkfSum0X4i211MlveskEjYCufuk++elcHP8NtYAYLLCVHTGRiuW1Wxv9LlW2uwQycjBzkUlO70Y5U7LVH05a3SXcAlQgg9wcg1NXk/ws8Rw21heWd9crFGrK8Ikb14IH6V6hBcxXUImhcOh6EVsncwasxm+vPPFfiTTLq1kUKkkoVkUOoO3qD+orvd3FfP/iebydRuIVnJRZWHllcFcnOKiZcLHR/DjR4bueXVHXLI+yPPb3r1tAoUDcDivINCuWsPCtttju2a4LsBbtt6E8k/hXReELnU7u9WGZ7nyWBINx1H41yzTbbO+m0kkd3IRtIBrgfG+i21/ZtMylbiJSUcenoar+Ipr9NRfa960cYPED7cgU2yvG1C3a3MN1GQhyJ2LZyPU0kre8OTT908zs7xraVWjfDq2fQ59q+iPDNwtxosMisCSo3Y7HAr50trG4n1r7FFGGmMpjCn619A+F9Ol0rSYYZHyRGoIxjBx3rrjuefLY1Qwri/iHothd6FJduEiniO5XA5Y+nvXWisvW7CyuLd5LkYYqVVzkhTj8h9apkLcyPBSW0nhayt7hF+VOQ3rk1uQXumWWoCPzI4lRTgf3j3rldDlAjktoxs8htmAMZGMg/zq5dXME6CF9Llk2j75wp/DJzXE0+Zo9anZxVjXtbvTr2domeKVGztZTkdeh9KTUTaWcBSBFGfSse1uraNTAmlzQZP3kAYZ9cim6lMLa1mupWysMbOfwFS10KdlucFrumHTJl1BHxNPOSi55x1Jr1jwnqF3e6PHNdqvzKNrDrxwQR+FeWaFDqPjbWVuLwxmOIYAX5UjH0717LZ28dlZxW0Q+WNQo967Kaa3PMqyi3oKrUshZoyFxk+pxTVQU6RkiXLHitG0tWZJNuyOD1g3Gl+KrQJBi3vIihYDHzLk5z6/wCNbAXTbpALtmJHbNWtVvDdSw2UcS4YNI0jrkqBj7voTnr6ZrDv7FmXcuQx9K4qkouV0ehQjOMbSNGU6faRFYHJHYFs4rE1gPd6JfJGpbMLBQOpNJY2UzyHzRwK3UtgEVAOtZ3s7mzV1Y57wT4d1DQ72FpgNs8ZfZu5XjuK9GJ4rORXjCtAwVsgv8oO4ehNXvMAGWGK6oVodzhqotbXP//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-81.png', linkedinUrl: '/in/melanie-gilbert-01fe35dd5f', jobTitle: 'Trading standards officer', }, @@ -7815,7 +7815,7 @@ export const peopleDemo = [ city: 'Gomezville', email: 'brandon.sanders@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0ykJCgliABySe1Fcd8TdUn07wjJFAQr3ji3L/AN1SCT+gx+NIo5bxf8VpPOex8OOoVTh7wrnP+4D/ADrzO41Ke/uWlu7uWdj1eUlifzrd0HwPNrFsZ1n8tM7UyOta8vwp1BiD9tjP4Vm6sU7XNFRm1dI4aO/aGUMsjIynKOpI/l0r0Twd8ULm1KWesMbi3yFEpbLxj1z/ABCqcnwouREMXalh144rF1XwVqGkQtcx+WyxjLbTzQqsH1G6M0rtH0VDNFcQpNDIskTjcrqcgj1FSV5d8IdamnhvNImk3rComhB/hBOGA9s4r1CtDEK84+MAdtG05QPk+0En67eP616NXFfEm2W/0u2thxJHJ5+T02j5SPr8wpSdlqVGLk7Ip+EYhBolsmMHbn866rnANcJqMl1awxxWTzphMKIV5OB3zUuga1q8k0cF5llfBV2TBHoDjvXC4t+8ekpJe6dpJuKEZrlvETH+zpwBk7DVHXtZ1nzpI7JykUYJZlj3E49Kr6XcXTExXrzMCM4lUZ/DFCj1ByT90r/C1Nni25KDCtaNn/vpa9hryjwjAuieJrq+kX9zI5tkVeq7mByfbp+dermu2MkzzpwcXqNzzWH4msxc2QcA7lyMg9uv9K26iuIBc27xMcBhjPpROPMrDpy5ZJnM2kUdzEN2M9eRRFBarqKBQg8s53ZA5xUEe+2leA/ejJB/Csq5ltb1gskU29cgSJCxI9fmH9K4Unex6aaaujWWC3a/kVinzuSp4PNOuraC3B2qASOtYFpLaWFwwiSVWdhuMsbAk+ua2bx/MXr2oasxEWjWXnavFjlGfzJAecleR/Ku8NZGhactraJOxJklUNyPug84rWNdlOPKtTz601KWnQSlqOWaOFC8jhVHc1kSeIUJPkQM69nY4H5VtGDlsYN2MjxLPFbao3lt8xRTIB/CT0/MCq6i2ubZVkmKqRxsPNV7wmbWJZ5cZuIwMdsqT/Q/pWVd6ddK2bObbjkoT/KuKtHlqNM9GjJummjcKQW8ZVJSw/2jmqL3Pm/u0bI7kVkR21/ISs8oIz271r28Ahj6DNZuyNNWdZ4S1+LxDoEF0oCSqNkiDsRx+XFbleR+GJLjQ4z9lkwryP2yCCxNdzYeKYp0AuImVx95k5H5V6fs5cqkjym0m0f/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-82.png', linkedinUrl: '/in/brandon-sanders-4661fbd2df', jobTitle: 'Radiation protection practitioner', }, @@ -7825,7 +7825,7 @@ export const peopleDemo = [ city: 'Emilyside', email: 'samantha.hicks@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-83.png', linkedinUrl: '/in/samantha-hicks-d7b99728fd', jobTitle: 'Firefighter', }, @@ -7835,7 +7835,7 @@ export const peopleDemo = [ city: 'Adamchester', email: 'joann.booth@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwCsYleopIucAVZ428UDGCTjA5rEopPGFAyQCeBmlhlsI5gjzEsBuYFcbQP51Fca7JFIkOlwbrluA5QMT9Ae1acHh/U7xXub5k+0Om0E9RWbnc6I0tCrc38RjLWtnPtH8bRdfpWYuqFpCTGM55U8Gtv+ztcsoWCtE8foxOT/AErl9SDpI2UZXHJRv6GoUmU4WWqOitJobvmMkOOqnrWjFBkVxVlfOpSVCBKh4PqPQ13tncRz20coGA6g49K1i7mE42MDdJjim3MrR2MzYy2w1PDlhTLtSbaVQM5Q8fhVS2Jjuh3gHTQYpr+TDSyNtBPOAK73DbQCK8602fULDwjbfZbV5ZpZH+YMVCDPU1s+F77VLl1hvd+XTcGY9PY+lc7i9z0INaI6eYEJjFcprmmR3MJBGJBnBFZviHUNa+2n7G0nlJ/d6HnHap9Pu9QuWa3u4XV0/iDblP0NCi7XG5JvlOIctDMy7sOhw2O9dt4eumuNKQ91JWuW8QaXcDxAq2y588DnsD711Hha0e006aJ2D4lJDqCAeB61rHc5akXZj1UqeBVryQyZIpzx7BmjLFMkVs0cyZt6PHFFpqWj4ZV6e4PNWUS2hncR7F2oSTwOSKzLBjJEMMNy/KR7dqr6ne6PEwgubgi5OR8mSw9elcjTUrHq02pRTRc09Le43JIq7hzk85HrS3hhtVPlqB9KyNHvtKWRobKbLA4KMfm/Kr10vmPknpSfYrQxZY5ZZRLGdsoPB7Y960tNBa2kkUfI8jFPcZ6/nmuV1LVbv+3W0q3dUhMalmA+YE+hrr7VhBbJEq4VFCgewranHW7OOvUXLyoPIYjkVIYDsxitYW4xTWtxXRY4zMtQYHLdMjmpnsUu4wyuikc5IzVv7Og6jiqJgE8StCSvPy/0rCskmmdmFm1oVRZC0YuzIzeoFNmlLDCnJP6VGUneYo9SGHYMY5rHzOpts4W6jdPGzSsCEBXDY4xgV6RbW5kgVvaslLdYtTjkaMSpc/u2jIzhgCQR+AI/Kuo0+S0lcQxt5ZxgRtwQfTmt6ckcNQAAAAAVYM//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-84.png', linkedinUrl: '/in/joann-booth-c081ce2c43', jobTitle: 'Geoscientist', }, @@ -7845,7 +7845,7 @@ export const peopleDemo = [ city: 'Juliehaven', email: 'robert.hernandez@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDusVWv9QtNLs3u724SCBOrucc+g9T7Vb7V4X8Ttek1HxM9pFMWtLHCKo6eZ/Efc9vwqRl7WPitqd3M0WkxR2sIf5XZd0jL+PAz6YrFbx14jaYsuszfMeVG0D8OOKxdN0fUNTmxaW2cjPPQCt+L4d6zc8iO3i9eTUOcVuzSNOctkS2vxI8Q2hhFxeCeNW+YPGu4j0JxXrXhvxJZ+JdPNzbDZIh2yQscsh7fgfWvKJvhjq/2ct50TsOQOma562vtU8KaphWe2uYj9Mj37EURnGWzFKnKOrR9I0EVU0m+XVNItL5QAJ4lkwOxI5H51cxVED8V80X0Bm8QXiyMxd7pwSR1O45r6Z6c14ZbaYP+FgXMTYkgEzzo+OHBOQf1/SlKSimyoRcmkd9oFnDaWMMaKiMFAbtk11MSrsBAB+led39skl1tuku5oxykUHHb19aveHmnjmRLdL2K3Y/dun3Ef4fSuDl0uepfXlO1l4TpivOviFYQzaas/lKzxuDuA5x0rR8StPLK8cou3ij5ItnweKyIbBbi1ubeM3YieI74ro5IJHBBpxVmpE1PeThY634eSGXwVZhvvRs6H/vo/wCNdPiub+H0DweDLLeuGcs/1yTzXSkV3nljyNykeoxXm0+nLaaqkqkDykaLGMZ5BzXpIrl/EVg0couht8pnwQOoJH/1qxrxbV0dOGmk3F9SzYpDdwgSIvHc1Dd6np9ncRxPJHCoYBS3G857VTtHZV+VugyKpXGotNJ5LadcTY6bVABH49a5Iq56Jti/0241SSMTRyhsAhedvuR6U/UoLeG3cRKAWBGRXOW99Fb3flrptxakjG5o/lI98VsXTNMEUHOcAD60NW0Je2pseH7Eafo0UAbOMnP+fpWiabbx+TbRxnqqgU416EVZJHkzd5NjxVDW4PP0W6XuqF1+o5q5JNHCm+SRUUd2OBXPeLbpm8POIT+5nOzzge/UY9QcYpy2FH4kc1bamsa4kOCv6ituP7HdQgNKcMP4WxXLzWxmh8xACR19xVNDcxt+7R/+AnFearM9a7R2jJa2yMUlOB3Zs1NoeNRvTICDFbkE+7dv8a4uKK6u5AsrOEzyC2a6jwriyur64dwlqsaqWbgKRk5z+Jrakk5mFeUlBnaGkNRwXUF0m+CaOVfVzj//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-85.png', linkedinUrl: '/in/robert-hernandez-5e65b16f59', jobTitle: 'Nurse, learning disability', }, @@ -7855,7 +7855,7 @@ export const peopleDemo = [ city: 'West Nicoleshire', email: 'jeremy.stewart@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDvcUYpaKQwrE1HxdoWlTGG61CPzhwY4wXYfXHSsDxfqt9qWoDQNHnMQAzeTqcbc9EBH61l23wytSoLXs7E9RgAGs51VF2NoUZTV0dND8RPDU0/lC8kQ5xueFgv54rpILiG6iEtvKksZ6MjAivPp/hfpvlr5dxcIwHJyOapx6dq3g+U3VhdGeBcedCw++BUqtFlSw8krnqOKSqul6lb6vp0V5bNlHHIPVT3B96t1sc4tQ3cxtrKecDcYo2cA98DNT1U1RC+kXqjqYHx/wB8mgDiPDURljNzId89w7SSt6sTXZxLhRzXmjS3UGm2v2c3ALR7gsA+Zj161r+GLrWPtEEN08jRyjcDL95fY1wSje7PUhKyUTt24B5rF1MqsZbg+tc14luNaNzJ9me4MUf8MJ5PPQDvT9Pe7dRDN5/A+ZJsEj6EdaXLpcblrY0vA85F9fW68RlRIAPUHH8iK7WuB8AxMmuasGziP5VJ9C3/ANau/Iruh8J5tT4grN15JZNJkELsrblyV9M8j6VpVHcw+fayxf3lIpyV00KDtJM5XSRbvbxxsgyq4AI6VNcalYabqsEdzKseVJXjqay42ezu5kdDGyMTsIxx1qCW/h1GdTLCWKZwFiL4+tcCTbseqnpob2j31lqfmvDIsg3HqOeD3zUmoCKGNioG7Fc/aaolhKybDh3yA6FWB/GrOq3ReE7Sckc+1DXQL9ybw9at9tgmVsZlaQ7T1BBHNdmax9D017WCKWYAOEAVQeme5962DXXSi1HU8+vNSloIKWkFKSACSQAOprUwOP8AGK/Y7qC8BAEo2t9R/wDWP6VRXZLbhBOIiQDwM8VR1PWrrxBrF9YyxIlnbMEhIHLbhySfyrm5LfWbffHD+8EZxyeQK452c2d9JyjBHazzw21n5fmLK7DGWrNsboX+qW1ip375F8wjnAz0rno7LWrpAbgBIm67Tyf8K0JIZ/DujS3dp8lxD+9BA9Ofx4pKyZTcpJnr+KQ1S0e//tPSoLogB3Ub16YNXU86x//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-86.png', linkedinUrl: '/in/jeremy-stewart-27f2b87ae6', jobTitle: 'Chartered public finance accountant', }, @@ -7865,7 +7865,7 @@ export const peopleDemo = [ city: 'West Tracy', email: 'lisa.brown@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDojSU41G7BELMcADJNAjO13XrPQLA3F02XPEcQPzSH0H+NefXfjbUtUcqjpaQgZIib5j+NY3ibUTq+uz3DyMyA7Ih/dUdAP51b0nwdqGow+bGpjRuAXPWolJLc0jBvZGeuuX8F59ptrqTzAcbmbPH41dh8RaoH8xL+ZJ85wWyD+FaV58PdQjhV0ZN6joBx+Fc89lc6fMYbtSUPcj7vvUqSexbg1uj0vw14yg1Ty7K+ZYtQ6DjCyfT39q60DNfPnmSQXIkjlO5CGRwe/bFey+D/ABB/wkGk75ABdQkJMB0J7H8a0TMmjcNYniu6ez8M308b7WWPGfrx/Wto1jeKI45PDOoCUZQRFse45H60yTzzwLoianfPdTqXSLGF9Sa9htYBHGqhQAB0FeW+Hro6b4TE4spLl55nAVCQOOMk/hXYeG576SaKKQuEdN4DPu25HTP9K46ibbZ6FJpJI6ox8HAH41wXjXw7NdxfabPHmrnch6MPb3qfxLd6nbXSmJJ5os/cRyq9e+OTVqzup7pxbvaPEycEqdyN9DUpNe8ipWl7rPFpUMZZDlWU8qe1d/8ACmRxfajDglTEjE9gQeP5msLxzpn2LXS0S4WVd/A7961PhYsieIJ1YMoNsTj1+YV1xd0mcM42bR6iahu7dbq0mt3HyyoUP4ipzSdjVmZleHrCLTtLTTZgrGEkfXJJz+takVxZWt4yGSOMpHuC9/riqVyDHcCQZ+YYNZ9xq1l55Q2Ml1IowxVentmuGUXzNHp0vegrHQWNzaX2AJIpQRuV0IYEVJdyQ20eVVfwrGtNZspT5CW0ltLnIUxkfrVi9DSp8xwBUNW0NNjnbyx/tO9EzAEqDtBGQRmtLwxpK2mo6jeJGEiOIIfoCS2PbJx+FZ8epzDxNBpFvCjLLFvllPWMc9B+FdbBEtvCkUedqjAycmumjF7s4q81blQlNHQ040iAngcmug5SG6heSAmP768j3rNitre5AMsmwjpgc1uXkN3a6bJdpBu2FflbjgkAn8BXNz20vl+ZESGHUVy17KR24ZysaPlwWcW1JQwx6YqlPdtLhFbPvVCC3vbh8MVVc8kVqLZLbwknlqwudBY0bTbeJn1ALm4nG1nP90HgVrYqn4etry8n+zhf9HjBZn9PQfXJ/StKWzuLckSRkY7jkfnXdTknFWNak7n/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-87.png', linkedinUrl: '/in/lisa-brown-01aa1694a4', jobTitle: 'Patent attorney', }, @@ -7875,7 +7875,7 @@ export const peopleDemo = [ city: 'East Aaron', email: 'kristine.benson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDmACTWVfayVLQ2eGYcF+oFX9XzFpFw6kq2AMjr1rkIx5mxAGGT91axbNkixCJpy0ssxcdz15/HrSC8ZSYZFV1P3SOxro7Lw3c6uyR28SGNU5L81uQ/DC6Mf72aKPjICqTio9ojX2Umee212bW4zFLt7DI6/Wuis9TW6CxyYWbHKite/wDhjN5AdLkCReT8vWuWFnPZa8lvc5VwflfP3qamm9CZU5RWpuEUDINSFcdKbiruZ2IvEBKacCACm8bwe/p+tZnh+wS61OLccjI+WupuNOXU7SW2Zwm4Da2M/NkY4+tQeCdIkt9dmjul2ywJjb1wTWM5WTN6cG2n0PTNLsbezhUW8Sp0JxWq361x+q3stkhVra7lU/d8rgD/AOvVfR31RrsBZbkROoYrOwbYD79j7Vilpc6nvY664X92c/rXlXju3WNIp0Ueaj4DDrzXU+KtR1KCc20Cz7FxuaHBPP1rk9Sg+2WeD9oGydA/ntuyQeSD/hTitUyaj91ohjbzIkfGCygmlqTYO3ApNnNdRxGrYXIt72J3GUzhs+lbws0tLtLpAfNlB3uTndzkVzOMmtTT7i5M22WUtAigIh7HPP8ASsasep0UJ291nbW0sN1DtkVT9Rmkla1t28mMKrY3HsKoWqnAKtwag1HUdERPs98RK5OShQtk1gtdDqsie78n+1gJCjLKgOM55FYXiMwCIRxIAAw6VFFe6S2pGO1aQzEDhwcgdsZqpqjl5trGrivfSIqtKDMkigLzUpQ5pAtdRwF7T7R728it0BJdgOOw7mt6XRLrTtU8iSPNqyfu58/fPp7Yro/DXhf+zR9quDm4dcbeyD0+tdJNAksJjkUMp7GiUOaNghPlkmeeR3f2N/JlbaM/KTV+S3+1wDZIg44brT9e0hYkLOu+I9G9PrXITSTWa7YLmRVz9xhn8q4rOMrM9GMk1eJoXlu1m5keZWYDAwMVhyyGSQse9WdPmkvtcisrj94syMM90OMgj8qXUdMudOm8udME9GHQ10Uo/aOWvUbfKUs0L16UYp6JmgAAAA1Oc//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-88.png', linkedinUrl: '/in/kristine-benson-ee3307c3e8', jobTitle: 'Financial risk analyst', }, @@ -7885,7 +7885,7 @@ export const peopleDemo = [ city: 'Steeleport', email: 'stephanie.carter@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDreKq3l/DZACRgGb7oNWq808Vazcy6lLbvCyeSSqsG4I9cVMpWVyoR5nYdrnit1jlSIASnOCD0rgW1See6bzOSx6gVceOS5lLcj8c1GNInEu4Ecc8jkCsua+5vyNbFa5dkZsAZxwe+c9KtQXt0qq8sJERPO7ionsZLm9eEHPP61NCj2LSxyZ2FCGGcik2gSZ2vg/xNHG/2GR87m/dsT+lekIdyAjvXztDO0FyrRybQGypHFe7eHdUt9W0eKa3cttGx93UMOua1g+hjNdTSryPxJqdwb+4iuSh2sVBC9Rn9a9azXk/jXS5LDUpJtiGOUl1Zc8AnvRUV0Om7Mg8Maeby2mlRj5jSYDHnAArpbfRHiLtON7OeWA7elcvoUl1beHvMt1nMjzMF8vGB05Oa3/Dt/q97cCG9VlGCQzDHTtXLJPVndTaskR3fhh/tIuIZPL5yRisjVNIaBZpGO4g7lH9Kt6vqOsfanS28zykHJQfexTYZ57y3ZJo5wwXnze9CTSuDabscVNKmRsTAYV6d8LN7adesQQvmLj3OK8xkQB3jI6E4/OvW/htEkfh55BLvkeT5l7LgcCumO5xT2OtBrM8QaSNZ0iW1G0SEZQt0yK0xThWjMk7HD+Grf7BZNY3kW2RHIYN0Pv71tRfZ0vWWPYqohJwAASadrlqBNHOgwzfKxHf0rnr6bSnj2TXBSYZG5c5H1xXFOLUmj06UlKCZdsTBJK8UqqT1GRnPNR6m0ECFI1AGOgrKsJdMg+S1uCzZ4Lkhifxqe7HmNuY1D3NLqxyv/COXGq6mY7coGckruOB+NereGtFXQtIS22x+aeZGQdT9e9c34D064e7vdUuWZoy7RW6k/dAPJH6V3nQV201ZanmVZJvQjFOFMBpwNaGZX1K3NxYSKvDqNy/UVyS273CDE6w+9dRrMV9Npk0dhJ5VwQCre2eR+IzXJXltIU/dybHHc9PxrkrW5kduGbSZHJaNBktMsnviqrsXDc545NUW/tBpjHMQB0yO9aUcQWFUUFmbjA5JrJnRe53Om3VmbOCOGaHIjX5AwBHHpV3PHFcjZaAkxglvI8SINwQf1/wrp7ZJAAmBt9+1dcJ3Wp504JPRAAAAAAAAAGf/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-89.png', linkedinUrl: '/in/stephanie-carter-aa789505dc', jobTitle: 'Patent attorney', }, @@ -7895,7 +7895,7 @@ export const peopleDemo = [ city: 'Lake Brianmouth', email: 'benjamin.castro@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwCReaeFApgBpZJVggkmk4SNS5+gGayNCpq+vWOg2vnXb5Y/ciXln+g/rXCah8R9WncrYxRWsfb5d7Y9yeP0qbRdCl8X3U+p38zgSOQgHYeg9AK6+y+GumwksZJZc/3scVLqxjoaRoTkro4O2+ImvQPm4kiuE7rJGB+oxXbaF4osfECbF/c3IGWhc9foe9T33w40iSNtqyqSOCG6GuF1nwlLoci3dnct+6bOSMEGmqsZBKhOOp6ayCkCiq+lXq6jpdtdJ0kQE+x7j86tEYqjMQKQcVj+LjInhe92HBIVTj0LDNbS9aqa5bG70O8gA+9Hn8uaTdtRxTeiI/BtrHBo1sqjGUBArtYiQoz0rz6Vb6ygtxbNMiCIbBCgYsQO+eK2PD2oaw5jW8bKyYK712svsRXI19o9CLtaJ005O04FcR4tVTp8xUZ+XJFW9e1DWWklWzYiCIfPsUF2/wB2sdYrq6hl82SZgEw6TKARkdiKaXUJP7I3wLk6Axz8pncqPTpXSvWJ4RtmtNCihIHUvn3J/wD1VuEV03ucDi46MABmpFwCQVDAqRtPeoowTUu09R1FEldWCEuWSZY0qSKeyiRgCQOBU8/lpfwxKUU9ccCsLTy1pK8bE4jLYHt1H6VXub1dRnR5DHCV6Bs7uf5Vy21selGSaTRvWIjlu7hG2kgn3zUGstDFZuFAHynOKwLW8awuXELxyKxyAMgj9Km1m4aaHA43KBt9z2otrYUpWWu5b0vH2GMbVVlRQdvQ8VbNJHEsEYRBgCmsa6oqyPPnLmlcEOOlTBuKltrCa4xtXC/3jWrbaRCvzPmQg9+lURY4/WpGtZIp0Bw6EsR6A4zTrW6S8sEKusVxjAYjIrr9S0VL63RokHnQZCr2ZT1H6CuEvdBntpG+x3H2fJ5V1yF9R7VzVNJanZRb5dC/JNDa2bSPcI84HPFc9Z3pvr21dyTGJVyccFuij+tSDQ7qf93cXSyKTlhGpGfxrf0rQVmu7crGEtLVg7HHVh0A/HmlFrm0KqXabkW3yuQwwaiLV0ptA5yVHPNQXGipIC0XyP6djQBXScNj/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-90.png', linkedinUrl: '/in/benjamin-castro-5609ebd89b', jobTitle: 'Surveyor, mining', }, @@ -7905,7 +7905,7 @@ export const peopleDemo = [ city: 'Stevenshire', email: 'ryan.davis@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1GiiikMxvFHiCLw3osl86CSUnZDFnG9z0H0rwjxB4n1rXt3227k27siFTtjX2A/xr1jxxaLqmsaXZP/q4w0znPbOAK5u48BRST745CUY5IOKwnVUXZnRTouUbo8xjWZBksXDcYrZt/Dl3eWrzcqgXIGDz7V6Za+D9Mt0XMIdhySavy20UUAVUCqOMCsZV+x0xw1viPCUluLK4DwyOjxtlWQkFSO9e/wDw98VnxNopW5bN/bYWbP8AGOzV5LrOnLHqUzxriNmPQVtfDJ5bLxoibiYbiKRPTtkZ/KumErq5x1I2dj22iloFaGRy3iC0Y63Dc4JVoNmfcNn+tNXIx1qfxol3/ZkM1nJIskb42pjkEe/0rl9Ev9SvMx3SbH8suD3GDjkdjXDXj77Z6WGl7iR0RDAEZqldkspA6gfrXOTa/rceorb/AGZWUsFDIuc1s213NdgiSExuOvHWsXFrU35k9DktZU27DcCDnn6etT+AXR/GloijJVJD9BtrW1ixF7dW0W0/MSCwHQdf6Vf0e1itL+zWwJjkW4HmrjBZSOSfX610QqWsc06LlfU9BpaSiu088ztax9kQt034P5VhWsEcZndFHTBKjFb+tRmTSZ9v3kG8fhXn89yWjMcF75LZxJ84Bz3rirr3z0cLJezN02lvcS7gFEqjkEVIwFuuDy30rItLi3iChboSSk/f37ifatKZgY9zH5iK53odV0UpJfLkyWA56mtnw9p2+5F64J8sbQ5/iPt7DJ/OufZ1klI4Ir0O0jEVlBGBgLGox+Fb0Ic0rvocuJquMbLqSUVHPcQ20ZknlSJB1Z2AH61y2ofEbQrKRo4mmumHeJfl/M13HmnWModSrDIIwR7Vwd9o89pcPbK0aqGLI5A5Xt+NYGp/FTUbncmn28VpH/fPzv8ArwPyrK0bVL/WdWkF7fTyEwvISW54wePTjNZVoc0b9UdGHqckvU7GO3WKImVYWb1AqvLeNITGuCRxmq0ltOuwC4do27cZI9jVpdPitxuilLBh0NcDPRbbG28W1SSck8k0/wAD+JryPxBf+H9UlLKJCbN3OSAeQufTHT8qnihYRO54RBliTwK861G/MmryXULEEMNjDg8dDXThoyu30OTFOAAAi0l1P//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-91.png', linkedinUrl: '/in/ryan-davis-04fe8f1d38', jobTitle: 'Therapeutic radiographer', }, @@ -7915,7 +7915,7 @@ export const peopleDemo = [ city: 'Port Robert', email: 'david.rhodes@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0LFMkkSGJ5ZXVI0BZmY4AA7mn15d8U9fuGI0O0yqKFkuG3ffz0T6d/wAqTdhpFnWPi1bW5mj0uzFwVOEnlbCH3x1IridQ+IfiLU3V11Dy9nPl2w2D/E1c0DwJeavarLdyrDDIOEC/MR2+lb5+E9iel3Oo9ABWDrRTtc6I4ebV0jJ0X4palp0jRagf7QiYZTOFZfbIHP416loniPTPEFuJLG4DOFDPC3Dp9R/WvNbr4XC1j8y0vXMqcjeODXOafPqXhLxZZvcF1iVwXZeQyfxfXjtVwqRlsROlKO6PoKikjkSaJJYmDRuoZWHQg9DS1oZDq8a8Rs154+uYmH7vzwrZHXAGK9lry3XrCRfiJ5zxk28zrsZeQSF5H14qKjtE0pJuR3OnBUgQAAEDpWkxJA+X9K4nUrmRBkJeEDO1LcYb86doV7fxzKs8tyY5CuBM4JGeg+tcHLpc9Pm1sdXOPkIIwK888aW8TWomaPcY/mBHUVo+JtT1B7ma2gluESIAt5IBYisCRJp9NuonkuJB5TZE4+YHHqKuCtqZ1XdNHofgtpG8GaUZTlvIx17AkD9MVumsnwrGsPhTTI1bdtgUE+/f9a1TXetjzHuOBrmNZs4vtkEvIMc+7/voEH+ldMKoata+dZSsPvKA/Trjmsq0HKOhvQqKEmn1IYbZJY+AA/v0NV7t7S0kjFxLEnzAAnCgt7epptvdbUJDDO0kc1Qurpp1CzW83TjEWfxzXDHXQ9NajnNpPr8yRTROxUFgOeap61bxxxFcAA8fKMdapMUgvR9igkRyAMNERk+tXGik1TULe1JKFuXbrjjJq0nzJIzm0ovmOs0iBbbR7SFPurEP8auGmxoIokjHRVCj8KU13pWVjypO7bFFDrvjZfUEUmaoa294mi3UlgcXEahgc9BuGf0zRJpK7CKu7I4+8vn05lSQhUYHy5COD7GtSLUILnTwsjspZeGHFSGwjvtP8mdQ/Hf1rn7rw3qcEZWzuQ0fQK38Neammeq00y5dXltZ2b/vSXCn5jV3wQBerPqT5yMRp+IBJ/lXFPoepNMsN9OGU8sq+nvXW+Dr9oL2905lxAgR0PoTkY/8dropcqkc1dycTtjSGmhs0E11nEf/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-92.png', linkedinUrl: '/in/david-rhodes-b30501dc23', jobTitle: 'Leisure centre manager', }, @@ -7925,7 +7925,7 @@ export const peopleDemo = [ city: 'New Toni', email: 'elizabeth.evans@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-93.png', linkedinUrl: '/in/elizabeth-evans-1c62f6e072', jobTitle: 'Emergency planning/management officer', }, @@ -7935,7 +7935,7 @@ export const peopleDemo = [ city: 'North Craigside', email: 'kenneth.solis@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-94.png', linkedinUrl: '/in/kenneth-solis-abc002b3d7', jobTitle: 'Operational researcher', }, @@ -7945,7 +7945,7 @@ export const peopleDemo = [ city: 'West Jonathanside', email: 'barbara.hudson@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-95.png', linkedinUrl: '/in/barbara-hudson-d52a7f47e3', jobTitle: 'Engineer, manufacturing systems', }, @@ -7955,7 +7955,7 @@ export const peopleDemo = [ city: 'New Raymond', email: 'kelly.hooper@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-96.png', linkedinUrl: '/in/kelly-hooper-9a2d9e03bd', jobTitle: 'Automotive engineer', }, @@ -7965,7 +7965,7 @@ export const peopleDemo = [ city: 'Archerhaven', email: 'shannon.brown@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDocUYp1FIBpwoyTgVQm1SFXMcLCRx1AIrJ8XajLa26wQvtZ+S3oKqeGfAt5fxpe315JGkvzJEowSvqfSuapVd+WJ1UqKa5maR8Rqk7RKGYLw2B0NSDWPl8xMSJ/smr914Bt/LL293cRS9Q6noa55rW5s2lsNTZZARlJwNpP1rGU533NvZRtsdBZ6nBd8Buffir+3IrziC5ksb4xl2wOOf5139hdLcWyN0JFb0q3M7SOerS5dUWaSnYqOYhUOTjIPNdDdtTBK5xOrINV8X2lryYgwyPUDk/yr1OzQxxJxjjpXl7Tx2Gsm9aN5W2uIljOCTiuw8M399dri6EgjKMwMn3lwcYNefq/ePTjZKx1hJKVyPi7TGu7IyQ/wCuQ7gPUdxVPUrrVLS882JLiZc8KHOCM44FaMd1Pfx/vIJYmXgq/wDQ02tB9bHlcUzyTmCdcsh4z1FdTod8tsfs5fIPQHtXOeN4H0zVVuYiU38kgVVV3jv/ADmcqhA2gdqhq2qIf8p66KiuYxLCUPepsUyU7Yz6gZr0ZWtqedG99DntNgj/AOEjj81QQqPtH6fyrrw9vbxSbXiQ8KFziuIR2h1GG7c43SbAP9k8VuT3+ipcbL91LgDKEZB+tefC560FdHT2v2eYZ+UkHBB7VHfzx28bbQPaqdle6bdRhdPmjJHO1Tz+IqK+iaTIZvlHWm30HZHHeIbE6oscpUNsOAuM7s9q5aZB/aD28xG5cbWHTNdRrviKTRpRBBaLMZx5asWxsP8AUVxs07tdEk7ySCT6tml0Jk0eyCo7kDyHOcHHBqQCobiNmIAG4Hj6V3z+E8uG5zGrg+WHHUABR2X3rb0qCLVoEuI3X5hyc9+4rN1DSbm5hkVXLKc4OOaxPB639pqeoWTs8SRYIUnIDd8fhiuBJp3Z6NOfY9JS3Sxj6Ip7kdaz7653jy4uWPpUSxXd1gNJlT6VcisFgx3ah6mlzyvx35sepWUCHHBJb3NVra1nMCMUC/LncBk1teM7I3Oqb/4UA59xVHSILudo02syEkBRSk9CAAACba3P/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-97.png', linkedinUrl: '/in/shannon-brown-a9e4eebc94', jobTitle: 'Scientist, forensic', }, @@ -7975,7 +7975,7 @@ export const peopleDemo = [ city: 'North Tinamouth', email: 'lucas.price@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-98.png', linkedinUrl: '/in/lucas-price-8220b81a6d', jobTitle: 'Health promotion specialist', }, @@ -7985,7 +7985,7 @@ export const peopleDemo = [ city: 'Campbellburgh', email: 'theodore.booth@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDuSMVXubmG0haaeRURepY1YPNed/Eu9lj+zQI+wKPMx6miTsrjiruxkeLPGrT3XlWkrLCh4xkFjXG3GtT3OXd8knnB61Y07SbvXWeWCNnVTtz1yfSup034YsYxJeylSR9xKwc0tzpjSk/hOJhvWQ5A2MvQVuaV431DTxLCGDo3J8znH0rrrn4d6fJCFVpFdRjfnmuO17wi2jxNcRSbwvXI5xSjUixypSSPVvCHiFdf0nzHZPtEZ2uoPOOxxXRYr5/8I67LpWsxsj4jPyPuOBjNe92V1DfWcdxBIJI3HDCt4u5yyVhbmSSK2keKMyOq5CDqa8H8U61eapqMq3ZYbMqquACo9K99I4IrwDxhp09t4huJHjkRZpCyhgfWlMqmeh+ArFbTQoECjLDeT7muvIOMDrXEXAl0/TbeGNrwYiGBbL3A7k1N4bvtUuLhYLl5mjI3BpQAw9jiuJq+p6UdNDrJtyg1zWuQJcWskci5DA5rN8Qajqa3jRxPciJOpgwSfzotJZJ02lrrgZZbhefzpW0uDetjyudVS5dEY8HFfQnhBIo/CtgsJDL5QbIPUnk/rXz9qkEkWrXMYHCyEAj617f8O4Zo/CtuzOhifJQAnI55znpXbA82Z1orj/GPhufVrmC5iZCka4IY4KnrkfXj8q7ICo7iIywPGCAWUgE9jVyV1YmDtJMx7Ewy2qq4HAAOaZHNaJfGNGjQKD1IGfWqlurwxskpG9MhsdyOtZt5PbXYCm2uCQMB1hPA9j1/KvPSd7HrqzV0aFtJbSXjxyFGLMcEYIp2orFAhCADjtWBbTwWrssUEqbmyd8RBJ9c1bvrn90zueFUsfyofYTdjItPCa6vNIjfL58vmO/Uhc84/ID8a9LsrSDT7OO1tYxHDGMKo7VzPgiz1JbE32pTI5nVTCiDGxDzzx1rrc12048q1PMrTUpabEgpruka7ndVX1Y4FTCCUnAQ1W1nQ5dT0Ge3jIW54kiJ6bhyP8Pxq5SstCIxu9TndZkRLt5ImVkIG4ryAagl+yXUCiW4bGMjYcU7T7Ew2QgmB8wDEgbqG71i6jolxES9pOyZ6qOlee5Xk2enBOMUi3KbWCIiOYkY/j7VX0+3h1e8jtZstbOTv5xuA5xWZa6NeSSk3Upde46VPrFuY7HMYOI8NhTg4HpTi0pJineUWelpGkSKiKFVRgAdhQ1ZfhuG+j0O2N5JJK7rvUt94KegP4Vpmu9O6pjVnY//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-99.png', linkedinUrl: '/in/theodore-booth-28b999e5b3', jobTitle: 'Camera operator', }, @@ -7995,7 +7995,7 @@ export const peopleDemo = [ city: 'Lake Mariahmouth', email: 'christopher.johnson@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-100.png', linkedinUrl: '/in/christopher-johnson-9e6100ff7b', jobTitle: 'Art therapist', }, @@ -8005,7 +8005,7 @@ export const peopleDemo = [ city: 'Lake Williamburgh', email: 'sara.higgins@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-1.png', linkedinUrl: '/in/sara-higgins-3f7fd986f9', jobTitle: 'IT sales professional', }, @@ -8015,7 +8015,7 @@ export const peopleDemo = [ city: 'Kathrynton', email: 'kelly.brown@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-2.png', linkedinUrl: '/in/kelly-brown-759dbe09e0', jobTitle: 'Psychologist, clinical', }, @@ -8025,7 +8025,7 @@ export const peopleDemo = [ city: 'Bethanymouth', email: 'andrea.weaver@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwCy5zUXepSKaE3HFcxsKiZHoPWm71aIvHKgjAyzk8VS1LUUs1MTDK4wcZzn0AqDTvB+p6iBNLcCzhfkQr1x/te9ZOfRG0afVle58QrHlIYwxBxvFWxqnm24P2ZgQPmPC/8A66v3Hgi2gtysbs+Bnn1rIaSXT7GeCdt4iwF3d854/SpbuXyW1Fi14BsmM4HUE1vQslxCssZyrDIrzh7p1uCVcheoB5xXQ+HNZeG5FvMwaGQ8YPQ+1aJtbmUo32Om20qjBpcUYJGPXirZmZK2Dah4sh8xB5cK79o6HHr+Jru4yqgIGGfrXAahdNp7XLi3eaUxqoVCc8t1JFX/AAtLevDKbvzAhiMi+YSSOehrmafxHbBrY6q6f5TsYH8a4nxLp0s37yI84+ZfX0IrK1b+0hqAnjjnmQnON5xjtxV+2u7u7cxvbyIVO085U+4p8tlcbafunFTiNHKyhkYHqORQJdhWSBs4OeOtWPF1k9tfJcKp2OMHFYwV0hWQBwg4344zWqV1c5paOx7KelLGce/tQV4pyLVmRJplvD9tunlRWEiqvI7c0ajqFhZ2kyCRIvmC9gB9aVVYbsEisy8vtDL4lgknkXhiiZyR6+vWueUbSsd1J80Vbc2dLe2uoH3bSUODjkGq+oXEMG4RIoxxWfa6tp7/ALi0Bjcc7ChU1DdqzuwJ6dah32ZroYeqQDURh/uq2awNStRZ6W0jptdyEUdMjg10WoXa6fAZzH5ix8lc4yK47UdWl12+UmPyoYz8kec5J7n3rWCfyMKkkvU9gC1IiigLTgK3OIWQqkTFmC8dTVP+zoZ4wTMIzjBAyM/WtBAD1ANZN9ZSW+pzI0kgMiCZUI+52P5+lZ1I/aN6FRp8o2SOGyTaJFbP90YrPuLrCHByxqrdLOshVx+Oc0tvA0jDI4rA6rmZrccr6PIEGZHwAKx/CGlR3+txw3RwB8xX++euK62+hLYjBKn1HatPwn4eXTreS8kiZ5mYqspHRfb/ABrWm7qxz1kAAAABWdz/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-3.png', linkedinUrl: '/in/andrea-weaver-6d792fc29a', jobTitle: 'Ceramics designer', }, @@ -8035,7 +8035,7 @@ export const peopleDemo = [ city: 'Lake Veronica', email: 'david.ford@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-4.png', linkedinUrl: '/in/david-ford-ed83f54167', jobTitle: 'Designer, furniture', }, @@ -8045,7 +8045,7 @@ export const peopleDemo = [ city: 'Darrellshire', email: 'elizabeth.scott@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0rtSilxxVHWbiW00S+uIMCWKBmUnoCB1rA3uee+PPH1xa37aTo8pUp8s88QBbcf4VPbHc15xAXu5JZpJV37yGZ5MuT7/41EkNxd37i3YyPIxwx5P1rpbT4f6jIEmmeNl7j+L86u8Y7kqMpbGJBJNYyGWCQ/MuDk8kehrQ0vxffeHr4XFpKJInGZIHJKt/gfeuiPgIxo7tOdoJwoHauF1TSrnTZZN6lIiepHWkpxloU6co6nuHhLxtZ+KYyoha2ul6xMwbPuDXUV84+C9bTw/4ntr6VT9n5jlAH8J7j6cGvo1WV0DKQVIyCO4pNWEnclIxXD/FHUrnT/CTfZ5AgmcRuM4LKe3+NdwTkV5Z8aIgdO01xuLmRkAxxjAJ57dqOodDD8B2KSQyXbKAzNhc+1elRRMiAZBHbHNcLo1pNY+FrAR2wkMkfzMwyFJ579+1X/Dc+oLdJEYiiTAnDcFfTI7VzT1bkdtPRKJ1c6N5ZAYDPrXHeKdOFzYyAKCwGRjvTfEEt8185S3aURY+7yTzjgVatDcT7oJ4FXZxvTowqbW94p2funjTrtuGToVONtfUWkf8gWxwMD7PGMenyivnvUNHkjvr26BCrDMdpA75yM19C6M3m6HYyHGWgQnHTOBnFdd+ZaHA48u5erD8Y2Ud94VvkdEZkj3oWGdpHcenGa3BQyK6MjKGVhggjIIoC5yWmLCunLp7gfIoXBHb6VYsra2tL1UQIoX5mbAUZ9Kbf2SaffjyVKo4yoyTWVe3uks6i4V5JkyC0QOVz7jpXK0+ax3walFNGj5UF1cPHKE3cspIBDDNR3QitYWVQM4xwMVm2N5o0alLRTFIWyN4IYn8etWL1g65Y4wMnNQ9NCzi/EcAKQWcKM1zfTKCV7AEfrkivabW3FrZw265IiRUGfYYrx3wAIPEXjaW9vb8k2xb7JbnjcN3Y+2M4r2o8V2wjyxsedUnzSuirc3ltZx+Zc3EUKf3pGCiuS1r4laTpiMLSN7yboAPlU/ia861TXJ9YvHmuZC7cgDsPoK567kZWO3k9jXQqS6mDn2OwuPH15d6zb3l1GiQyKIfLiJwhzwefc8100DtMgeO88hvcc/lXj0jjy8OTg8++a7XTNQOs6ShD7byJdrnON2O9c2IhZqSOvDVH8LOrlRYUMs90k3csRWde3rTWNwwfKBDk+vHSsKNblpNt08jAHox4p+uajHa6LIgOCwKIB3JrlUW5HVKdk2zgtMuntXLo7I4+6VOCD7ele96P4vlk8Lw39yvnMIAzc4JI4PP5189AFQRzxXqPhmRpvhteh2w0Ucu0+3X+tdla6s13OGhZ8yfY//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-5.png', linkedinUrl: '/in/elizabeth-scott-56456b1569', jobTitle: 'Government social research officer', }, @@ -8055,7 +8055,7 @@ export const peopleDemo = [ city: 'Shawnside', email: 'haley.rodriguez@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-6.png', linkedinUrl: '/in/haley-rodriguez-5998488ad7', jobTitle: 'Librarian, public', }, @@ -8065,7 +8065,7 @@ export const peopleDemo = [ city: 'New Alexander', email: 'joshua.harris@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0HFZus6rFo+my3cilio+VB/EewrRrgfH8pudRstPUM2IzJtB4JJwP5frUydkNK7OY1HxFdX100zzNl+CqdF9sdqgtrq6yq28jsB6j+ncV2nh3wta2div2iNZJpPmdiO/tXVQaPYxlWS3jBA4O2uR1lc7o4d2ueR3AvUV1eKRSBuQ7enP/AOqtfTfGV/pyQwTLuU5IEnXHoDXpk9lDJGQ0KMMd1rlvEWgwanZtHtVZF5jcD7poVbUJYbTc6eyu47+ziuYjlJFDD2qyBXmvgbU76x15tFvAfKlUtGM9GAzkfXBr0yuxO6OFqzG1x3ia3VvEFtKV5EIGfbca7E1zt+n23VonMeEik8nOeves6skomlGDlK66GjaqNij0FaSZCYFcbq73iyssLXWFUsq2454HJJ/kKXwzfas8yw3Xn7HGQ82Mj2Poa4eXS56SlrY7F87T1GaxdRbCHH8IJrF8T3+sJcvDZebsRdzNHjJ9h6moNHnvJtqTm5Hy7mS4XB+oP9KOXS4c2tiDQFjm8YxTFdzKj7W/u8V6FXFeHrU2etzz7dwkcxKAfu98/p+tdoOld9Jpx0PNqxalqITWRfREXUcw4VWyR6k8VrNVW7gM0DAMRjnjvilVhzR0HQqcktR8UMc684B7+9RZtluVii2gqwyemTVR7owWskuc7E3DHeudN1LqgSQW0qKozGxgYEHuc4/lXDGNz07nV5tm1B45SmGOFPXmlvIordcqOcVxUMz6RczSyoxSTAZ3Rs/XJFdHc3PnWqvu4ZMg+2KbjYXN3F0i3Bm83sSX/HJGfyxW+vSqWnWhtrVNxyxUZ4xj2q8td1KLjHU82vNTloIRSAVIQKq31ylpbMxcK5BCDPJPtWhic9dTQ29zND5u6DcULKchT3U+4q65hmtdjSsmR1U9q5fwjayto1ytw/mO11LnPPfH9M/jWkdKu1VvKuSFx8vGcV58muZo9OHNypl6SSG3t9iv5hbgb+RXOz3sr2E4tpNwgiYhgMgbQcD35AqCK21K6klimTYkZ2lwfvD/AOvW5BZR22nujqAuw7uOMYpNpbDs5bkvgbxefE+mL9rRIr1QdwXhXx3A/pXW4rxfw8j6PDFLbkhopCyH1Gf8K72w8d2U2I7yCWGUAFio3L9fXFeitVc8tgAAAAKzsf/Z', + 'https://twentyhq.github.io/placeholder-images/people/image-7.png', linkedinUrl: '/in/joshua-harris-c48d311bee', jobTitle: 'Energy engineer', }, @@ -8075,7 +8075,7 @@ export const peopleDemo = [ city: 'Brownshire', email: 'ellen.mcdaniel@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDkzyaACT/jQRUVzIYrdlEi7mH3RyeazcrK5sldm1ounQ6ncGEXCiQA4U8HNWpr/StNkW1W3FzOB8xK5Of6VxOmnVdT1PyLHIK/fYHhffNdU/gDVLlfOOoR+e3J4P8AOsZtvdm0I9kahhiu4NwiRZWGf3Y4H61i3LtbNiVSFzjcOQPrViPwlr9iMi7jn9VI/kazbw31s7JcZByflcjmsU5RejuauCtqiVzg4zTo2OaqW8ySoEA2Feg9RVpOo5rpjLmRzuNmR7QTz0rmtQZzqskI45znPbHX8q6euY1fzF1RsINzgKD7U2riTsd74K05LXSw4HzytvY139shEOevHauE+2w6Jp8SSWUl27KFjiXgcDkk1s6NeXEbxr5Rhgmw2zfvxkev9K5pxb1O2DS906gAhSSoA965jxPpVvfWMjlP3igsDTPE19PHLEYrF7tN2OHKhfrinWV7/aCPE1o9tNF8rpnKN9D0P1FRZ25i203ynm2Eh8qaJ2jGSCM52kdQfat3y9r7c5rm73MWo3VucgLKwx9D/hXTWyEQxhjkhQCfwrohoccyDbzUM2ii9miusn9ywyPbP/16sZq7pssfmNDMSEb5gQccirle2hNNJyszqtOkikVdyBmXgZFLfXKW+qWqyxTSK2f9UmQvBOT6DioNPXhWQggjIx3plxrktvdCOK2eWQdeMAVzWbdjvirpWNfS7lLp5sJLHhyAsqY6H+VWbspGhbuB6Vm6brRvJDHNbSwyZ4JXg/iKt3qGQDnp1qJXWhe25xF34bjuJr6/k4JfcoI4II5P51HGAABWze6nBcaf5VujAlirswxnHp61ig/NXTTTtqcVZxukinjmrFl5S3OZm2ptbnGe1M280BMmtTnN7R5zFaRrnhDhfp6Vs2lvbyjMhDbjnntXP6ZFvVoj35HtVtILxW/d8KTjOehrlnZSZ3Um+VHTCCG2QCNl2+1Z+o3JNtKqHnaSSO3FEGm3cq/vpgB6LTru0Edm8aD7wIrK6ua9Dk8wrpkMSsfMjO3aR1GBzn6iq/enMjxuUZSCDmn/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-8.png', linkedinUrl: '/in/ellen-mcdaniel-4308564cbb', jobTitle: 'Rural practice surveyor', }, @@ -8085,7 +8085,7 @@ export const peopleDemo = [ city: 'Joshuastad', email: 'anthony.macias@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-9.png', linkedinUrl: '/in/anthony-macias-cd01ea615c', jobTitle: 'Estate manager/land agent', }, @@ -8095,7 +8095,7 @@ export const peopleDemo = [ city: 'South Martinstad', email: 'samantha.bell@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwC8QaQ4AycDHrVjaK4jxlr7QSnTrdwiAfvnzyf9kf1ok7K4RV3Yuah41trVmjs4DcuON5OFz/WuYufG+tPuIdIM9NiDj86xxLcTW+YU3bjtTP3j7+wrQg8Ga1NGJPLjQsM/MeaxdR9Wbqnf4UWLDxzqYlDTXQkUdUeMc/iMV2uk+KNO1WRYd/kzt0Rzwx9jXn03gbVIQX+VmHPBrNmd7aQJOrJKvUjqCO4pqeujFKm0tVY9zWFamWJfSuf8Ha0+r6Mry5aSHEbSH+I+v1rod9bJ3MGrFYHivJfFIRvEl95bByJPm3LnnjgV6yFNeT61p80Pi+6tmBzPMGT3Vjn/ABqKmxpT3Ov8KeEBAIdQu5A7OgKxbfu12MkYGOlZOrz/AGO28iOCaVkjzhCQFAH86z/Dk93PcrFOZRGRv+Zs7fY1xNX1PQjZaHQyxhozwOlee+K/D8bwzXUZw65faR+da3iK/vEuXSAy+VHyfKJBPtUEbm+tJIHiljk8shldt2cj1px01Cdn7pk/De+ZNVubEnEbx79v+0CP8TXpnavJfh/byP4tLDOIYn3H9K9awcV3R2PNluIorG1bTEuNXsLxj80cihFx6ZZv5CtpRxTwBzuGeDipqxbjoXRkoz1LDKk0fQe+RWd9qsrS48tnSLcwUE/xN6CryZEJ+nNZU9/aCLC2c0pBPz+VwPU5PX8K4UrnprXYpwyWs99MisjjdjjnB9DT72KKBPlA59KpJfW6zER2ksJJHWP+oqeZmmZRgk+lDWtgbstSDwnpSWJu5kwfObk475P/ANaulqCyh8q1QYwW+Yj0zVnbXfBNRVzyqrTm7DgvFLtp4Q0oXmrIK8rFAVJwp60y4W3eAq8vy44AqyyrIWUc44P1rO1OxCxF1z7YNefUspM9Kk3yoz7gRxghHJ9qNPHm30ankcn68VBBbFlZ3J46A1LHJJaziWKMOyg4UnGfaiDSkmOpdxdjoQoHAHApSKjtLmO9t0nhOUcZ56j2NWAtegAAAegeYf/Z', + 'https://twentyhq.github.io/placeholder-images/people/image-10.png', linkedinUrl: '/in/samantha-bell-3246e99ce4', jobTitle: 'Armed forces technical officer', }, @@ -8105,7 +8105,7 @@ export const peopleDemo = [ city: 'Wileyland', email: 'roger.king@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwCUmjPFB60CuE7BskiQxtJK6oijLMxwAKwLzxzpNpxEJbn1Ma4A/E1geLdUuNUuzptmS0KMAVQZMj/1Apln8P8AWrxEeeNIVPOGb5q0SjFXkyPek7RRpp8RrV7oIbGRYO77wW/L/wCvXQ6brlhq6E2k2XX70bDDD8K4u7+HGrQBnjaJwOgBwa5qaC/0W7UyCSCVT8rDj9ar3J/CxNTh8SPZ80lZPh3Wota09ZAcTxgLMp7Njr9DWxjNZO6ZotVcDWfrl6dP0a5uVXcyrge2eM1omsXxWrnw9MqjhmUP7Lmhbg9if4c6DF9kOq3MYeeQ4iz2HevQGjOR8gx7VxtjHHY+GrCOdbl8wAiO3yDnGSc1f8PXbSLlTcpGOdkxyawn7zcmddP3Uoo2boFVOVAGO9cJ4s02G9sJQyAsAWBHUVp6xOt4zyXCXU6rkiOJscDt9ay4kt5HJgW4hAX54ZeaSjb3kVJ83us4XwVdtY+I1g3ZS4zGR79Qf8+teqCvLNOtWh8dwpGpwtycDHbmvVQK66ju0zggrJobStDHcRmCVQySfKQfejGTTlOGUnsc1mWjqbKzgbT0R8K6AKfwGKqNNZRSNGSyfIWU+WcEdOvQVPBILlHliJVWycN2qlcXF6IziBI414XzG6/lXMlrY9CNnsUNOe2uLgqW4fJDbCMHPfI/WpNTt4LeFgoXcR1FVVubs3W1oFKk8uhxj8DUmogtGQxyw4OPWh9hs5vT7KNdRlnGPNaQNkdcAYxW6KrWShoVk2kZyBn69atCt4p21OKo03oIBR3rp7PwdfXGGnZLdO+eW/Ktu28IadFtLo8x7lz/AEFbKDZz86RyOnNIsbDnyycZ98dPyrQkuLXygrLuPb2rotf0mOLR4pbOBVNpL5xRBjcuCrfoc/hXNXWnx3EImiIwwyCK560eSR2YefNAyr6eMf6rg5rNuJS0R5OB1NaEmmlW+eUkemKINGl1q4+wW6lY/wDlvJ2RO/4ntWUdXZG0nZXZBjEELhcJIm5cjt0poPNd9PoFrNAkHkgCNQkeONoHbNc1qegy6e+9dzwk4zjlT6Gu2UGjzYzTP//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-11.png', linkedinUrl: '/in/roger-king-91a87f58dd', jobTitle: 'Programme researcher, broadcasting/film/video', }, @@ -8115,7 +8115,7 @@ export const peopleDemo = [ city: 'East Richard', email: 'logan.kim@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDnwaq32p2umx77h+T91ByT+FN1K7FjYSznG4DCg9z2riHabUJTI+53buf89K4acObV7HZOdtFubT+Lbln/AHMMcY7BgWNRnxHqe45kQD1CjFTaX4Qv9QG+KMCPONxOB/8AXro0+GreXuN8RLjoF4+lW5UkCp1WrmZYa+bmTybpURuzqeDWoWyMg5BqrefDye3hE1vdbplGSCODWVok1xFez2NwCrpzt9COuKhqMtYlWlHSSN7dQDzTaUVBRi+Ji7LbRr3LMf0H9ar+HLcT6lErxZ77ccfU1p67Z3FxbxTW8Ekvlsd4QZIUjrirPhHaonkMTtIpC5C8j25rTmtTJjG9RXO9tXhhiAZ1QDjk4FaCSRyj91Ij4/usDXJXO2UAyWskmAflfgD/APXSaJcCHE32RYA3JQZDAZ6GsFDS518+tjqbr5YyTgD3rzfXoFt9etpo8DzX2kiuj8T3odp4ZBIUjjDbVzlgT7Vy7WyPPAq+YqxSZ2sSwBweh9OR+VXCNtTOrK/uls0gpCc8jvRmgyN7Rgjxsu4K65AJ9TjH9ajtrZbO+uvlGZJd5x05AqlZ3P2a4DHJQ/eFWYNTg1C8uHhjeNVfaQ4xkjrj2qJJm8JJpdzqoYo7hASMNjGar3gtrRR5jAbeSzdB+VPtTjYQeSM1VvtThhYqylmJzhUJP51MddDYZMtleX9uY5kd2jxwM/nWXrNtHbxARkKwbJAXrRHqFu16pijaKb0K4B/Gma1Nvbk8ntV2s7Gc/hdzHJpAaDQKs5ScD5qkiQq0jxD5x85Hr2P8hVe4nS1geaQ/Koz9aPDd5cX8z3E8axxk7Y1HoO5okny3HB+9Y6LT9USSJAWw6nBB61r+XHLHgsCD0rnpNFE052OVwe3pUr6RqMCgQ3o2joHHT8ay0OlSaJ7q2htTv+UsvesK8uPtMxbqO1V9Ue9ignae48xYlJ2qMAkCoradbm2SVf4hyPQ1oo9TGpUvoPNKyP/Z', + 'https://twentyhq.github.io/placeholder-images/people/image-12.png', linkedinUrl: '/in/logan-kim-24c952a76b', jobTitle: 'Ranger/warden', }, @@ -8125,7 +8125,7 @@ export const peopleDemo = [ city: 'Michelemouth', email: 'nicole.bass@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-13.png', linkedinUrl: '/in/nicole-bass-3323b936fa', jobTitle: 'Commercial/residential surveyor', }, @@ -8135,7 +8135,7 @@ export const peopleDemo = [ city: 'East Allison', email: 'tony.dean@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDULjY1QA5qTjkc1Vu51tLOWdh9xcj3NSMuSajb2NmrzPjjhRyTWVJ4stwm8KAO4Y81yto1/rN80cDCScngdgPc11sHw7WW2Z7uf9+w/h6Cs3M2jTbII/FkblfNVSrdNuSa04L6C5T924J9D1rCuPh1cWysYL1yM5K9AfyrmZ0v9Bv0ik+VSchgTSUxypWR6QOTz2q5GwKisqwuo721WaM5BGD7GrykjjHFapmLRGO9YPii5CaaLRWAmuDgDvjvXQBTXIeME8m5trhOZGGz9ev86mWw47nTeBtGh07St+MzSnLP14rry3GA2a4qQS2el20KC5LeSD+645xTvDst9NcrHKZhETuzIcke1c77ndHsddKeOSBXGeLdPhu7CTco3DlW9Kh16XUPtzrE8/lx55iPJptr5tzA8MqzjK8iXvmp8yn2OZ8J6pcW2qLYzcxSnZn0bt/hXoeMjqM15hoMcqeIo0VNzJKAQwzjHU/lXpwIx2rpicE9xFbiqep2IvrMqFBlX5lH07VcC8U4ZUhvQ5qmrqxMXZpmlZSRTWqKVB+UcEU1rqztrxI2dIxnjtk4zxVe3ALs3IBycVSvb3TrgeWy72XIysZbb681yq+x6cbPYsWs9rcXcqh0kBYgHIPPoak1DyYY9qKB9Kxba6sYJSsK7SzZ+dSpJq5dvkb2PyqCTUvsN6Gbo+kpDeS3O3a7Mcn1zyK3jAMfe/SmWgH2dGAI3AN09asgFztUEn0ArrgrLU86rJSk2iBYTj7wpRFg8vn8Kux2Usp2qpz3qYaPPuCgAu3ReuaozMuQNEmQevBoaAywALMsXHBAq7qFnLaXK2smw4iV2IHck9PYAVkTW80ZyhJX0rmnbmO6i2oIcYGRcNIr++KI182ZU6gnBqCJZnYhsge9W0j2cDrWd7O5q7yVi8kccKLGcHFaWnRMhcldpbGDUGl6WkxuJWkkKbQcFshT6jPStm2CoApO9OOvU12w2P/Z', + 'https://twentyhq.github.io/placeholder-images/people/image-14.png', linkedinUrl: '/in/tony-dean-6a37678e19', jobTitle: 'Tax inspector', }, @@ -8145,7 +8145,7 @@ export const peopleDemo = [ city: 'Lindseyton', email: 'mercedes.green@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDqtvFQXE0VtEZJnVEHc1PNKkEDzSsFjRSzE9gK851XXjc3nnzK3l5xHGD2+lRUqcvqXTp8z8joLzxVBACY4HYep4z+FZo8fw7vLW1YN2LnANYFzJf67cR2lgnPQoh4X6kV0Fj8PryOEi6mhJZcFQM4/Gsfavqzf2KeyNLTfFtnez/Z5x9mnJ4DEFW+hrogARXmWs+EdZ09GlhkjnRewHOK3fA/iY6ip026yLmJflJ7gdj7itKdTmMqlLlOx208LTttOArYxOZ8aaitlpKxM2BKct/urz/PFeV2r3Ouamttb5BdsM57D0FdL8VLlxf2dvk7PJLEevNQfDLT2u9aMzL8salulc1RauTOql0iep+HdAs9B09FhUGQj55G65rUbaxyrA/Q5rE1i7u41aG1tmf5TukZcquB0GeOa57wvJezXSebEYjL8x2jbgehFc1rq52J2djsbqEyRHIHTvXmWoxL4f8AHOn6gg2w3L7JFHrnBP8AI10fjK/u7aUW8SO6jBYKDz+Vcn4lWW9sNOZYykyXXklAcgMehB9OKumrO5nVs4tHqopwqO3DGCPd97aM/WpQtdx5phatbRz6xZxuwVZY3Dgj76qM4/XOKj8M2ENgXubeERRzr8qD+HBP9OaseKLWZ9LF7a4F3ZN58RPfH3h9CM1X0TxVpWrPb29udlxJFvaL+5jgg/09q468WpNnoYeacEnujr9yTwEAAeoNUfNsrGVwSiEJud2IAUVKgKggVlXl/pkSyR3MZuJByyrGW59PSsVqdNkPvDbXF8uHRw6/WsbXbSEx2qKgDrdxMPT71JFqGnz3W2GN4nwMb12/gK0AouLmEOOQ27HuBVwT50iK2kHc2FHA4p4FCqaftr0DyTF8QarDpWjzTTcllKqv9415d4EUHxpGoyvmwuR+HP8ASus8fRzTjyAjMu1SoUZJ6/1rG8BaBfr4mh1GWNooIkdRvGN+Rjj2rlqy1aZ10YaJo9QMjKBGWAb1NK1shgZA67cdCKkls0n2lx3xWPOksU5hVm2jsTXL5nYmMuLSOLAUIST1xWPY6st54qCRNuhhUxZH8THkn+laF6siWsxDZcIcfXFY/gyy+0OmpttUbShUf3h6+lb0VeVzHESfKegKKdjilQZRT7VIEzXaAAAAAAHnH//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-15.png', linkedinUrl: '/in/mercedes-green-4b158a8688', jobTitle: 'Clinical cytogeneticist', }, @@ -8155,7 +8155,7 @@ export const peopleDemo = [ city: 'Mayerfurt', email: 'stephen.owens@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDIIqKe4itYTLM4RB69z6VaKHmuO8SXAnvTbliBEMKvYn1qDRlyTxThCUjWMbsZJycVn/8ACQXFyxzJhR05xV3TfBd/qtqkmFjV/ukjnHrWz/wqWYJk3hBxkKF4zUurBFqhUetjEtPEcp37JfMCjlXGT+FbllqcGoIGiOHxyp6isuTwBrOmSGWMqw6HaOcViqb3R9ZTzlKZYEjGM01OMtmJwnH4kd0Fyadsp8eHQMpyCMginbaBAfSuMitPtuqPLKMb5SB7DJ/wrt9uSKw7G3eHxA1vNGxiabzEkT5lZecjI+mKUpWRUYOTPQdOUGCFFG3aoHArcXcEGXzjtmvP9TvJQNsK3RXBIEAwePUn+VV9EvdTS6jWWa5EUhBxOQSM9vY+1cajpc9Dm1seizKWiKnjjvXA+L7C3mtQZYlJjfIbFSeJNS1OO4eGCW4EaEE+QuWqiTc3On3UM7XDEwk4nUBlOMg8U4qzUiZu6cRumEDToQCeARz9audagsIWis4wwG5huIznk81Y212HnjQSMGrItQzW80YCwxjKgDqzZzzVfGRVi3uGji8ggbC27PcVnVjdXRtQqcrs+pv20Uc8BVgqk9z3/Cqw+yrfCHfEFRh8zEDc3t64pke50+Q9siqck1vPEsUumzy7CSH8rnPqD/hXJG70PQ0NW9+xnUyxkjKuQMgg4PuKjvraFIyigFn4DCseOWysyyiwuQzjBkkiJLfU9attK42l+duCPem072E7Jamf5awfukOVT5QfWlAzTiCWJI6nNOVDXclZWPLbu7kPalBWNTI5wi4yT0GTgfqQKtWunXF5KI7eJpG9h0rqbPwnHJpc9tdAGaZQCeoUg5XH4gGqtdEJ2Zyq3BgwrHaP6VdPk3FvhrkxjHbrTL6yYFonTDocMp7GsCeK5hbKAlew9K83qet0ujZZYYImC3LSf7xqFHMo3E8DgVQt4JXj3S8ZPStHS4pLz7bBDHmS1dSQD95WXOfwOa2pJOZhXk+QUDJqVVGKQxsjFXUqR1BGKmRcADNdZwn/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-16.png', linkedinUrl: '/in/stephen-owens-8863b05296', jobTitle: 'Pathologist', }, @@ -8165,7 +8165,7 @@ export const peopleDemo = [ city: 'Lunaport', email: 'nathan.williamson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1zFQ3NxDZ20lxcSrFDGpZ3c4CgVPXhHxK1i81zxTNo8U7i0tpFhWJThWfuSO5zn6YpN2BK50Or/GGJJZE0axWaNeBPcMQGPso5/M1x83xK8TPcmUasy88JHEoQe3Sut0L4eaVb2SC6jM8xGWZicfhXQP4O0MwGH7FHgjqRzWDrrodSw76nH6R8Y9QR1TUbSG6XOGKfu3H9D+Qr13TNStdX0+G+s5BJBKMqf5g+9eY3vw40nBaNXU9cg0ngtrrwn4vGkTzO+nagp8kk5AkHT6Ht75FVCqpOxnOjKKuetYoxS0VsYijrXz2EM3jm6lcZIu5G59d5r6BlkSGJ5ZGCogLMx6ACvGRp6P48uJUObead7iE44ZSM/zNZ1WlE1pRblc7y0l3KoJIIq6SCBhs1w2rX9/CzR2onJVSwWJevuT/ACFVNF1LWZr2KC5eXa+G+bB2j0PpXEo6XO++tjvZlDKQTiuK8SM0TQSqPnimVkbuDmo/FGo6pbXslvb+YfLAYmP/ADzWf59ze2EkNwZGkQo3zjkfMO/fiqgtUyaj0aPblJKgnuM0U2ORJYkkjYMjAFWHQinV3nmjLmBLq1mt5PuSoUP0IxXmksD22qRM6hfIJhXjqNvJ/MV6fXKeKdLcK1/GybAwLKQc88ZrCtC6ujpw9RRvF9SKFIbuM8AevHWq7Pp9tOY0MalSAznAySegqrbXJWBsHkLnHrWPdT219F5bRO4UnDCFmwfXOK5Iq+h3XNu8exl1b55I2WQAdc4Paq+o2cUaPEg5dcA1zgFtZ3BdS+WUKWlRhn6E10enCfUdSt4oyC2Q3zdMDk0+V3sS5JLU9As4FtLG3t16RRqg/AYqWiivRPKvd3HVkeJr21sdAuZLssI3AiG0ZO5jhf1IqxqOs2GlKTeXKo2M7Byx/CuM8XakNVspbbOISA0efVeQfzFJ7DitTnxf+VK1vM2yQAg9sg9xWvvjkswhuPLXbgbKxryG31a0jkTAcDIPoe4rGuRqFnhV+ZMfKwORXArP1PSu4+h0U5ihiZVm80noHrqvBNg/kNqUowHXZCPbuf0xXmdqLm5b/SGyO4Fdh8PfEZgmvNJvGOz7YyW7dlyAdv0raklzGFeUuU9LpEcR/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-17.png', linkedinUrl: '/in/nathan-williamson-ffdb40e0ae', jobTitle: 'Publishing copy', }, @@ -8175,7 +8175,7 @@ export const peopleDemo = [ city: 'Port Jackieshire', email: 'anthony.davis@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDapRSVy3jjxE+i6YLe2yLm5BVXI4Re5+tQUYfjLx1Klz/Z2jTYCH99cJ1J/uqf5muIudQv9Rfzbu8mm9A8hI/WmadptzqNwI7dXdvYcV1kfw/1SSAHdDHn+Hk0nOK3LjTlLVI5vTfEOpaNPut52C94nOVNdXpPxMuftarqcafZmOC0a8pUj/Dh1tAGu1Mvf5a47V9EutJkKzqNvQFeQaFOL0Q5UpxV2j3W2uob22juLeRZIpBuVlPBFSYBri/hrqUVzoT2O/8AfW7k7D/dPQj8c12uKZmLivOPijGWudLGTgh/oORXpArlfG1j9tGljbkJcjcfY0m7ajjFydkP8IaXDY6TDiMeY4DMSOa6pcjqtcdqLXdoAIjOVwWQQqOMD1P8qtaDqmrzSRx3UgKNhssoDAehx3rjtf3j1ItL3Torg/Ifl4+lcR4qt45dPlLKGwCSKu+IdW1EvIlo7iOLO8xqGY/TNY8RuLwukksrqqZdJlGeR2IppW94JST92xR+FsJ/tjUHU/IkIH1yf/rV6livPPhtb/ZtQ1dSjckKrdsA9P1FeiV2XueW01uItVNSiEtvygYqdwz2xz/SrYpJIxKu0kge1KcbxsVSlyzTZXg8ue3QEAkjuKhdYkulii27gcE9OaWCMxqcHpnj6VmXk9u8qh4ZXdckMsZ4+h/wriS6HrpprQktY421KeKUKDk4PY0apHBb27BAqkjsKzYp4VumWBJEdjn51P8AOp9QzKmD97A49zTatoJuy1LHhSCOK0ldVAcn5sd85NdDVeys47G3EMf1JPc1YrshGyseTUlzSbQBTjgE/QVKIXETSlSEVSx45OBmt2KFOQFGO3FNiQMoDepBHsadyVE4SG9eVDPIuzfyQO1WUNvPHtdsq36VI+nNp97NZzL+7zmNv7ydj/SqNzpTgl4ZGUe3I/KvPu1L3j1o2suXYbdi3gjJjIGOlY9xqUsEkc8cSylWB2t0Jq+NNZ5MzSM49SMCq01s11fxW0K/QU1LXQGrrU6q2me5top9m1ZEDjn1qcKwHKmrcdqsUMcQ4VFCj8BVpbcNge1dykzyAAAAPKcUf//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-18.png', linkedinUrl: '/in/anthony-davis-c8f6c37766', jobTitle: 'Ship broker', }, @@ -8185,7 +8185,7 @@ export const peopleDemo = [ city: 'New Angelaburgh', email: 'kathleen.stewart@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-19.png', linkedinUrl: '/in/kathleen-stewart-3c65492da0', jobTitle: 'Economist', }, @@ -8195,7 +8195,7 @@ export const peopleDemo = [ city: 'Port Jamesfort', email: 'victoria.ruiz@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-20.png', linkedinUrl: '/in/victoria-ruiz-a5f8ac2c75', jobTitle: 'IT trainer', }, @@ -8205,7 +8205,7 @@ export const peopleDemo = [ city: 'Johnsonmouth', email: 'danielle.ibarra@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDP1bW7XSYsOd87D5Igf1PoK5Z/FN3d3AQPtX+6g4/EmuXub2a8nlmlcszHljTEuNuFXgdKh3ZasjrL3Wr6J4xZXTO7L9wLnH1NQWvim7gn8u4GMnkk5zWdpUk09wba0BLt1YjOa6uH4ZahfW/myTKZGGeFxioclHRmsYSlqkadtfpdQI5IG7oexqUjJ4rmxomreG/NS8jaWzAzuUHKmtjTb+O8iIWRXKjqPSqhO+hnUpuOpeA4qSM801RkU5V5rQyPGTIM4wcelPhjkuJFihVmduAAOtVxjOT0Fdp4F0/7RNJdFRwdq+1Zzlyxua0488rHVeBfDC6ZE11elBO3LAniNfr616ZptzaS/JHcQufRXBrz28uZLKRYzamQscbmGVX8DxUWmwS3F9HeW+nyWuSd25QpGD149a5NX7zPQsorkR6neadDewsrhDx3rwhrU6B4/utNjz5RbaozxhhuFeheMbq/gXTrWJJniuNu9489zjsRXMfYU1DxR9tWBolht4wQ4OS/zDv7D9a1p73MK3wmkiH0qRUOasLHjpUixZ610nCeJxacZliKnKuO3r6V3/hG3k0+y8uRcEOc1yXh3X4bBxa3sJeMthXUBsZPQg9a9C00ieHOzYcnjNclZy2Z6GHjH4kdjZSQXACyxIykc5Gav3jWdhbxLGiJ5jY6YFc/aK6lTU99qmnGP7JesGfGSm3cRWEex1NI2LeXT9RsY0mkhlKOdpVs9fQ1R1y3hjvYniGA0eCPp0P61S0q68PsrWtpH5UjDgFNuD/SpLx3e52scmNQprekvfObEq0NSt5YNTLFxTkTNSbCK6zzj52uSf7SduCfOz8vTr2r120VoljlX7rAcVl33wyNpqMlxas88ce1/K6lR3PvjrXRW8BW1VCOgFcmIeqR3YVaNmhDcgxKQeavJb/bF+Vk+rdRWGsLA9OPartsk5KiHep9jxWC3OvmN+HT57eJmuLlZUxx7Vl7S9xK55LsWqeCxu9Raa3W7YtCw82NV+9xnH61YNusfAGMcc110o/aOHE1OZ2IY46sCHiljQA5qwgV0HIf/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-21.png', linkedinUrl: '/in/danielle-ibarra-d11e8407ab', jobTitle: 'Nurse, adult', }, @@ -8215,7 +8215,7 @@ export const peopleDemo = [ city: 'Elizabethburgh', email: 'meghan.delgado@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwC8KcWVVLMcAdTUYrjtf8ZW0ay2lnueQHbuxwSDWbZokXNR8d2djfGCKIzInDsOCT7VnT/EKeQF7ezUKG4DtziuW0rSL7xHfyC2i3sTlpHOFFdvbfC2eSMG4vEVxjAjU4xUSqJaNmsaUpapFeP4hIUQyWUpOPmwRgfSuh0nW4NWt/MjG0g4K5zWBe/C+6ijD21/l15w68GuVtNQvvC2tNFMPlU4lTqD7iiM1LYJUnFao9aJphqrZ6jb31uksEquD6Hoas5qzKwmflNeP69HFHrdxHARsBG0g5JPU163OzLaylBuYISB6nFeMRpJNriJcKUd5wCvPGT0pMaPavBWmQ2OkRYCqxAZie5NdrEoZcphh7HNcNcSwabZIstk927KWVMZAAHYdM1oeGpTCVkjtmgjmAYg9RnseevtXFa/vM9Lb3UdNOAqHdtXPTNeX/ELS4JrX7YEQSxHJYDqPSul8V3SSeaZoJZ4oP4Yxkn8M+9czq3lXnh2++z2r20kUX7yI8gjGQfrTirNNCnqmmcp4Ou3tNWEZYmN87wT93jg16XmvLfCLI+tqdm9sbgfTtXp+a7Eecx3BUjsa5RfCCpdyag02+VbrzVXHUYya6kNVPU9Zj0S2NzLC00LfKyJ976ipqJuOhdFxUve2Ou05obq2i3KrEDjIo1Ke3sZYFkYRqzgEhe/4Vm+H5hNZ288ROyVAy/iM1LfaykM5iNu8rr2KnH4VxLXQ9RK+xYt5La71O5WORZFHGcd6p6/awHT5oI1VDKpQ4HrxTLTVYpbsRi3aBm6ALxVTxLq0ejWrahcK0iQsvyKRliT05p2d7CmrJ3OH0vQ20bxYbWJhNHDEPNkHHLDP+FdiDWJpNvJNcXGs3KbLi8bcED5CJxtH5AVsA13RTtqeTNpydiTNVdRsItTs5LeUkBlKhl6jPerFTQxPJuKqSqDcx7KPU1TaW5KVyDw+r6RpNpaTSbvKUJ5g6Eiumjjt7pAXKsrDg+lZthard2skbD5WYlada6LOVYRXLx4PK9cGvOb95nqx0irly4igslZkKjHcVyesLJql7axMqNaoTK+8Z3EcDj8TW9c6XLG6Ce4aTJ+7VGRBLf+Qm3zCvyJnBbHJxVU2udXIrXdN2IMgKFAAApBSEEGXeeaf//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-22.png', linkedinUrl: '/in/meghan-delgado-7954afab5b', jobTitle: 'Psychiatric nurse', }, @@ -8225,7 +8225,7 @@ export const peopleDemo = [ city: 'West Andrewfort', email: 'lauren.skinner@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-23.png', linkedinUrl: '/in/lauren-skinner-447a3bcd28', jobTitle: 'Psychologist, prison and probation services', }, @@ -8235,7 +8235,7 @@ export const peopleDemo = [ city: 'North Angela', email: 'jesse.underwood@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDrsjHNeeeIviE9pPc2unonyAqJW55z1Fa3j3VpdM8P7ISVe5fyy46quMnHv2rx9tkkqmUkKT+lc5skTXmrXd9Ibq4mkkmP949vYVDFK6quMA4+YDrXQ2Phy51i3EkcaRx4+VSOoqePwFqJ6lAp7DjFQ5x6mypyexiWery2UqTwySBx6nkV7F4V8UR69Zqk3yXsajepGN/uK4O4+HtzDbfaBJvPBIx0qkGuNF1eLEnl+WA2R2Pt6ikpq+gSpu2p7ZmgkYqpZ3IurKC5HSWNX/MZqbdxWtzA4L4oE/2RYYXP+kH/ANBNebWlolxcRozcE17B480oan4cCK6pKkymMsTjJ4I4+tea6JpNxb65FBdxHdHlyAeoFRJpGsIt2dtD03R40ihjRVC4A4rfjUEhigNcbLM8abttycn7sIGansLq4sXVjNdGJ8HZOQSua5Wup3KXQ7ZAGBBUbfeuA+IWnWjQ28vlqsu4qrKMe/8AStbX9Vvo3EVu06D5STCoZufSs3UbWfV7CNJppGEMyuxePD9cMOOvBqo9yKlrM3vD7E+H7DIIHkrgHsMVpbsCq8QSOJEjG1FUBR6Cnlq6TzyLUws9kVIztYPj6GuOFtuvY7x9wn2srA9MH09hXYF8rzWNfRSJdKcL9m2ceobPI+mKyqJ/EdNCouXkZd06OOSMBhz2IpmsvBbbFkkVTjOXOAKSyOxkAP0qK7u7c3JW7jkfbzhYi361gtWdq1NeNrSR4G89GZo/4TmnXlupTAJyvz/XFZ9nd2LStHbgof7rRFRg+hq3duysEB4I5+lVFPmSJqtRi2xobipFb5TVYZFP3cV1HmDck1BerugUHoWx+lWUXOKpXN2sqiJEYbZCCWGORxxUVLKLNKSbkrFBJngl2MxDA5U1q2xWQAswBbge1V7mwFwEJ4zxn0psOjalCAY5Edc8ZrlO5No2CqwptLhj15qszNK+4/QCnwafOh3XLhmAzgdM0iq7eYoQ7kPzAc8djW1K1zDENtEZB69aM9eMU5Rg5JpGGQ5roOM//9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-24.png', linkedinUrl: '/in/jesse-underwood-072dbeda4c', jobTitle: 'Pharmacist, hospital', }, @@ -8245,7 +8245,7 @@ export const peopleDemo = [ city: 'Port Jennifer', email: 'antonio.gentry@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDqy27603gUDpXO+NdYXRvDdw25hNcAwxbeuSOv5UhnFeLPHt7NqM1jpNz5VrGxRpkHzSHvg9h9K5JJpvLkedmkd2wWY5P41oeHvDkurhmeQxxA7eOpNdvZ/DuEIm27k59QDWcqiWhtCjKSujzRmZVIlU546VraB4mvdJmV7eaQBTmSE/ccV6knw/0sxgSRvI/Uv0zXN614Dhtopp7IsXGSYz0I9Kj20TR4aVjt9E1q213TUvLbIBO10bqrDqK0Mc15B4B1ptL8Rf2bIzrb3Z2bD/DJ2P8ASvX/AG5rdHK1YAOMnFcD8ULZ5LDTZ/8AlklwQ/4jj+Vd/tyOvFcn8RYPO8Moo6i4Ug+nBoeg0rsyfC0KrYR7BgHmu9sl/dLznBryu8uL/ThDDas6oIwFCJkscVteGNZ1ye9gtLu3wsnIkPH4GuKcW/ePRpyS909Hjkypw3WsvU32W7lRkgE4rk/EGr6/YXzQ2qv5SjqiBs+w96t6Rd392yi4FwBjLLLEF/Ij+VQ1pc1vrY4a3KSeNdLOOHulB2jkHNe0YOPavM9P0dYvHbXW0m3huFIA/hLdP516eQQPau2m00eZVi4vUjXnsKzPE1t9r8PXkYUFtu5c+oNaygbetJNCk0LxSDKMNpHtVtXREXZ3OQ0Vra6tlSdFZgO4rTt/J/t+CFSirEuTjA5rnvJOnazcWq52xk7RnkjqP0rMkmj1K/8ANkcwyqDtKhs59yBXE4vmaPTjNOKaPRy1o9z5NwqEuxCk4IyKddCK2jIQY4/CuN0y7g0+N0kQZlYM0hVgd3rkj1ro72Uy2ykHAZc5NZyVtDW5T0O1WS8lusENJM2R2IAAB/T9a6U9MVnaHAqWCS9TJlhz0Ga0mHGfWu2lHlieZXqc8tOgiDI5pSyou5iFUckk4AriNR8fgb4tMtdx6CWbgf8AfNcDq2r6rqk5+13csqf3M4QfgOK2sYHSeJfEsLeL544djRQxKBLGc7z3/mB+FT6fP9sijZbkwsV5Kdh6V51DKYrhZj2JDD271un7REgktn2q/wDEOlc1WKTOuhN20PRvPhtbBo2mFw5BB3DrWauoPcWDs8hEUEZaRh6AdPrxWFptjqF6225mURekff61p6u9vFarpNvgeZjzSP7vp+NYJJystzolJ25pbGp4R1+3s9LhsdQmETgZRm+7g84J7c5rswyuoZSCpHBBzmvJLiNJZET+HoPwqxpOq6hpSAW8xMW7mD//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-25.png', linkedinUrl: '/in/antonio-gentry-0f29dc0871', jobTitle: 'Magazine features editor', }, @@ -8255,7 +8255,7 @@ export const peopleDemo = [ city: 'South Saraport', email: 'gabriela.murphy@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDp7y6gsLSW6uZFihiXc7t0Arx7xF471DWZ5IrFpLaxztVVO1nHqx/pWj8U9anl1GLRYW/cRqskqr/Ex5AP0GK4NCQRvKjHGDyPyrFLqa3LG9yrO0pA6Z3E/rS2etX2lXAmsbyWJx75B9iOhqVwWjRYwCPXFWLfQNRvioitXOehNLmS3Hyt6I7bQ/ilDNGItYg8qYf8tYhlGHrjqDXe2N/a6naJc2cyTQt0ZT+leOt8Pb5Ldp5JFVwMhRWz8NrqSDWLmxLMpIJkiboMdx79qV4vYbjKPxHqOKXFFFIR4Z4+ilTxpfoxGXcOCP7pUYqloOiSaxeCFGAUdWPau08b+Hm1XVbvUbVnE0YWN4yAQwA6iq/gqOSys5pFtTIS+wkNhhj2olUXLoaRpPmXMb+m+BtOR0kuHaQoBtQcKP8AE11KWsEEYWNAAB2rlLrWLkK6JbzgYxjGKo6Pql8XZj56xn5isj9B+PSsNWrs6lyp2SOzuVDRMMcVwUFkbf4kadNEMecGDY9QDz+VaXiHWbyL9xCk6r5YkJUDcR7VB4abfq63skc0htY2O1zlgW4J/KnTTTuRWaaseijpRSRuJIkk2su4A7WGCPrTq3OQxdVtx9tXKEpIATjuRWLa2sdnJIIchJJWc/U11OrIw02eaJQZYkLpnvgdK5m3d2/1pBcnPTHWueorP1OylNSiu6NZYhcr8qruxgg9DVeS3ton8mQQgMCXJPb61LGrhcqe1VJtRsIYHW5BkZjlsRlufy7VMVc20E1P7JPJazCSFmI2YzkEdqNMtlOqpCNqxFDuVB171z8l3p8l4nkJKHJ4DIQPw7V1HhuJnurid/4FCD8eT/KqinzIzqO0Hc6M0UUldBwmPr3ia10WWO1mtJ53nUhfLA2+mDWKIWe1SReGAqK8mNxN50oDsW3AkfdPt+FadsyNbKFIIxXPVbbR04dKzKtvqH7va7YdeCPSrhjSeHZuUrjvzWfc6Ylw5dTtese6ivbPhLg7Pc8ipRu20W7qzS2lBVtzdsc12OjWbWenIsgxK53v9T2/KvNodYvLPVLeQhZtmWIYZ6f5NeoWF9DqNqs8JyD1B6qfQ1tTXU5q076FiilxSMyqpJzn/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-26.png', linkedinUrl: '/in/gabriela-murphy-e59b96e98f', jobTitle: 'Exercise physiologist', }, @@ -8265,7 +8265,7 @@ export const peopleDemo = [ city: 'Mooreville', email: 'kyle.kramer@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwCYCq99ewadaPc3LhY1H4k+g96tYri/Hc0peztlHycvn1PT/P1rI1Oe1DX7/UJXMs7RIc7YxwoH9ax0kikc+Z17Fq6vRfCVxqsIklkWMN6DmtmP4WGSQb77Cey84qXUitDRUJtXSPO5nMWSjKTxg96uWtw9uySwSyRXI5DKcGvRJfhjZLACs0m/H3jXMa/4RurNDJGVlVB1HDYoVWLG6E0rnVeHtcTV7UJJhLyNf3iYxn/aHtWyRXl3hK5msPEVssp+SfMR75z0/XFepkVRkOA4rifGMSNqtszjH7rAPrzXbiua8Xac919hnQ/Kknlv9Dj/AD+NJuw4pt6G/wCHY1SwhXjOBiumjZgBn9BXB6hYvHIrlbuTCZjSB9gAA9fWtLw1LfQuiSSTmKQZAnbcyk+prka+0elGVvdsdRO52nA4965fXPmt2C8tg8VX8QSXt7NN5ck/kQA7lhfaWxjgetZtlaM84ZTdo4Xc6zPuBGM9fWmo6XCUteWxyOnxrP4gsQhxtuVzgdOa9TIzXAafp0kfjNpwhMKS7yF9T0/WvQiOK6k7nnSi0RjpTLiBbm0lhdSejLjsQc/0p4pQccj0xSkrqw6cuWSbNGz8q4towyqxx3pJI0F/HFEqgjlsVS05njQAc4H8qrz3OnXE+Z50jlXKg7sMK40uh6qaaui5ZRo1/OjgZyTg96ffLFBCwUBSQayoZ7C0n/0a5jd2bH38kmrWpuXjJbg7ckU3oJtWMjTIFEkkgQ5kk+ZieOMf5/Gts9Ko6ZDttUkyfmyQPxq6TXVBWR51aak7LoRilFIKhu7610+EzXU6RIO7Hr9B3qzAc1yLOYE8K386tGCO7VXUoJGHDYByK5aDX4Nb1X7Nbhvs6xEkuuCzZH6Yq9FDqUO6O1YOEP3Sece1c1SPLM9ChN8iZsCzjtWMpZTIO+BWRqN/5qmNG+Z+vsBUFz/azoVnQxhuvPWhdPaG2LOPnI59hUO25o5OTL2iajBqGmRyQAgITGynsRxV81wXg66Nvq9xaI26CXc/PYg8H9a7x5Z//9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-27.png', linkedinUrl: '/in/kyle-kramer-3412f7e41b', jobTitle: 'Exhibitions officer, museum/gallery', }, @@ -8275,7 +8275,7 @@ export const peopleDemo = [ city: 'Brownmouth', email: 'daniel.burton@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-28.png', linkedinUrl: '/in/daniel-burton-c79414d37b', jobTitle: 'Commercial horticulturist', }, @@ -8285,7 +8285,7 @@ export const peopleDemo = [ city: 'Lake Laurahaven', email: 'mark.stevens@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDu6hu7yCxtXubiQJEgySTUorzn4r6xJBZWulw7h5x8yVtvYdBn60hmL4g+I+o3F1IunP5NuW+QkDOB/WuCuL157hnlkZi53SE8kmtnw/4f/tTdNPI6wg4Cjjcf8K7iz8E6QsQBt93flqwnWjF2Z008NOaujydJM4XHHatnR/EWoaHdxz2k5DKeVYnaw7givQLjwNpJUFbYoR6Ma5TxF4YjtITNaKQU5ZRSVeLdipYWcVc9V8I+J08Sae7kBZ4jhwO47GugNeD+BfEf/CO67H5is9tdYhkAP3ckYb8P8a93auhPQ5Wh2a82+LKAQ6VJjAMjqxxx0GP616RXG/EzTZdQ8MRtFj9xcLIwPcYI4/Ok9gjqznfDkSfYodo4IyBXY26kKK4SS2lgtrZUacARjasOASQPU1r6BdairxJO8rRyHgTY3L7HFefKN/ePXhO1o2Oolzsx2965nXI91rIE+ZipqHW5b+WaQxyz+TGDmOEgFu3FQWMUz53NcAAfMkuDj6EUculxuV3y2OA8oSajbpGQu6VRk9hmvo4jC4HQdK8N07w/Ne+LY1+7bpdKWbsBuzXuTV3waaPKqRaeo6s/XoRPolyhTfhc7fWtAUSRrLE8bZ2sCpxTaurExlyyTOG0wwz2iK4BOARmrRSJNShTciEKT1xmsp0/sq7uYCzbLdm5PXaOR+lYt3qz6tIJYokBTO3J5/8ArVwcju0esqkeVNbnYWSwzzzDKMQcggg5pb7y4YGCAAkYrkdM1h9NuGjmjQIW+VgQCPyrdvLsTwgqfvpuH0NTKLTsWpprzJPC1t5l2HCgbpmdj3wK7hulY/hOzSLRYp9vzylmyR/Dk4raZeK7qUeWJ5depzy06AKeKaKUsFGScVqYHGeOLc2g/tBANsqGJ/8AewcH8Rx+ArnoXLWcbW0kaSYC/OPQV1HjO5lkhtrYRg20hYuxH8Q6D8ia4SSzukJhtnBVv4XOOPY1yVHHnO+hzqCZtYiFi32qSN55FwVHbNZSXUk6JBE5aRRsZhwABxRHpl+wRJ2SNccbTkkVqwWKWtvgDnHWsnJI3UZTep3OiX9kdNtLWOePzFiVdmcHOP1rWIri/DeiXG8X1xuSFc+QhHJJ/iHtXYqZMYZefUV2U5XimzzasOUAAAAAk0j/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-29.png', linkedinUrl: '/in/mark-stevens-8d430f5e85', jobTitle: 'Data processing manager', }, @@ -8295,7 +8295,7 @@ export const peopleDemo = [ city: 'Wuhaven', email: 'kevin.lawson@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-30.png', linkedinUrl: '/in/kevin-lawson-3923eb16c8', jobTitle: 'Radiographer, therapeutic', }, @@ -8305,7 +8305,7 @@ export const peopleDemo = [ city: 'New Cathymouth', email: 'christopher.larson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDmmbJqpe38Wn27TzHgcADqT6CrTDk1y/i1/mtowOgLda54q7sdEnZXM/UdavNTYqZPKgzxGvGfr61mtuZQmOAetdfoPgkalaRT3Nw0fmchUHautg+HGmpAy5mckcbj39ap1oR0CNCpJXPIHLIQQxyOPpXTaBr0iTJZXcm5GH7uQ9R7Guou/hjAU3RXbhx6rkVxOteH7rRrlS5Eke7G4dsUKpCeiE6U4atHck80A81HFIs0EcqfcdQw+hpwFQWDDmuU8UqTfW+eVKcfnXWE9arappcN5psN0QfNhnA+oJAwaafK7i5XJWR03hxBDp1tHIQrhRwa6yNiEGRketefahp8jlJWNyY+AiQMBg+pJrR8Oz6lCyeZcXRhfB8ufDMo6Y46VzON/eudsZW92x1k5O1sKK848eIp0yRlGcYzit3xNc6lMsiwSzJFEfmWHAZvpn61zEukyS2F9tkuCGTayTMG+b1BpwjZqVxVJXTikLpaNFpFojZyIxVoU8xiNRGOijb+VIowa3OTbQaw5q7ZfvLS6t/9kSAepBqoRk05FJPy5z7UNXQQlyu52eltDJaKrjJxU92ESSJVQAsc8CsXSpg8SurdwDTr+9S5dRJIkZU8fNz+lc1tbHemrGpGif2ncRSJ2Dc1Q1kQhVijUDceR9OapQXawXLvDOsrN2LZNQapP5sqjv1NNR1sTOaSuZjc81HzmpWpoGTXQcJMtvI7YRSfetGCw8ko0j8k9ugrWFqqDoAPpxUd3Yz2lpEJSWJ5ZiOR6VaiZuRgWST2dqpYsduVkx6jvWnBLBcwhmkAPZgMmpoGjVmWVRsfr7GobjSYQ3mxhgpOS0ZxmuSS5ZanfCV1eJHcGCBSRIGPQsRVeFRM0hdckEKPxFSf2dGr+cVYIg43nJJ9atWlowiZnABdtxHcelaU9WZ127ahDoSXUmxGZGIJz2FQvoNzHJ5fyk4zk8V1mi2+VlkOM7doqzqSBIl474/SurlXLc7j5nzWP//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-31.png', linkedinUrl: '/in/christopher-larson-c3acf6c87e', jobTitle: 'Research scientist (life sciences)', }, @@ -8315,7 +8315,7 @@ export const peopleDemo = [ city: 'Oliviaside', email: 'james.ward@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDfC0oWnhaw/F+troOgTTq2LiX91CO+4jr+A5pFEOueL9K0NzBI7T3QGfJh5I+p6CuG1D4j6vK5W3ihtF7ALvb8zx+lYOi+HdQ16UmEbUz80r+v9TXY2/wpkmYGa+2juESspVYxdmzaFCcldIpWPxL1GOZY7yC3nTuwUo3+H6V3GjeLdL1mUQIzQXB+7FNgFv8AdPQ1zc3wkIUmK+cuOhZa43W9G1Hwpfp5yvnOY5l6Z9vQ0Rqxk7JhOhOCu0e5MtMK1j+E9eGv6SskgVbiMBZQD39fxrdK1qYj1FeWfFGaSTX7CzOfKWHeB/tMxGf0FerqtebfECxebxjpBI/dzRiPPuH5/mKUnZDSu7HReG7KKz063hjAAVR+ddjbqSo4z9K4C8ikjmKn7WVC5SO1wDwOua19CuL20nhjZ7nyZAGAuCCwz2Pv7V5rX2mexGVvdOwycHA4965vxXa297o1zFNEsi7CcEdD6iofEUt35haN7xo05ItnCsfYepqGyR3fH+lqNuZIrnDEgj1pW0uDd3ynG/DeY22tXlishMU0XmhD2K4GfyNenFa848CWUkXjTUkEYEdssiFj15YYH6V6Wy16cXdHjyVnYVa5bxNZK2q2tw7EtvRowTwNuc11aCqWq2jXNvmNQWUHg+n+RWdWLcdDWhJRnqO0+OG4iXeoLD1FV7yW3XVYIRJGmHA5OOfSotNZ1OFPbIHrVRLixvb945rV5pUJyBEcj8T/AErz0esmrG/C9vLeSxmSN/mwMHPP9Knu4khjJHBxWOs9laXAhEZhkkAwGjILfjWldsXjHPIFDVguY2jacLa4eZcB5Z3mcrxuVsgA+uMVuNUFjHtt0OMcfn71ZYV30ItR1PLxMlKenQROlSAZpg4FPBrY5zmpphpmoPCx+UfMh/2TVyGEXJEiOoYjg4zWFqupQarrl1aQlG+zqqh1PU85/I8VQjvtRsciIM6jjGM4rzqkUpux6tGo+RM7pYBCu6RlLDvjFVJ7sOREhGWOCc9BWDbXmqakmGRo1+mKfrtrJa+G7sIf37JgHvkkAVNlzIqUm02dgFCqFHQDApDVbTrhriwikb72ME+uOA//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-32.png', linkedinUrl: '/in/james-ward-bd728eec7b', jobTitle: 'Chief Marketing Officer', }, @@ -8325,7 +8325,7 @@ export const peopleDemo = [ city: 'Victoriamouth', email: 'thomas.ramirez@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-33.png', linkedinUrl: '/in/thomas-ramirez-2aeaabdca6', jobTitle: 'Claims inspector/assessor', }, @@ -8335,7 +8335,7 @@ export const peopleDemo = [ city: 'Linside', email: 'makayla.schmitt@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDrMDFUNU1ay0e3E17MEDHCL1Zj6AVammS3geaVtsaKWY+gFeQ6tqNx4m1ozcqinbEg/hXP8zUSlYuEeY6y78W3dzGzadCscR5WR+WP4dB+tZL+JtdilJS6BHUh0UgD8q6XRPDCQwxtdPu4B2dq6ZtD06WHYbaPpjOOa5/au51KjocHY/EFldI9SswV6GaH1+hrsrW8t761W4tpVkjboymqOpeBdJuoTiMxsOjKa57R4X8K601hM5ezuz+7fP3X9x+n5VpCrd2ZlUotK6O04NKAKaOtOFbGBT11s+H9Q6f8e7/yrzjwmkTX4VVyc5ya9K1OOOTSLuOZwkbxMpY9sjFcH4M06a2vLmKddsiryPxrGszegnueiWr7ox7VpIw2jBH51wWsXdxCGhS1lkGCeM/pz1qHw/HfQXSZEipIAzAsflB7H3rntpc7L62PQpDlcE1xvihUEdvM45huEfP/AAIVF4xur63kEEHmlVAZjGTk/lWZtuLvTJLeVZI2Rk3GRsgjcM8n2NCXUU3pY7cEZyKf2qJANi7TlcDH0qQCu480beRLPaMjcjIYj1wc1hWyPDObmUDzZSdwwOBngce1dEORis69t3DI67fKXO4Ec+1YVqbb5kdOHqpLkZfiMF3FtkRT/vCoLp7O0byk2KcZZiQAKpxFl+6e2ap3mo6Y6eVdQyTEHOBEW5rmWuh3WRszSWVxfhHeOQOg98Gor2C2aM2iqAr8HHpWHa3mlxuyxLKsjfxyIQT9DWraB5Lrc/OBVKLcrEzajFtl9QFAHYcU+kxk08DArvPJFUcVHcpvtpB/sk1YCcU2YKkDs3TBH4mlLYcb3VjnhIV+QkrU/wBmiuo9rz7FHT2+lNkt9yAkVn3EE0J4BI7EGvOPVWhcayhtAWW48zPr1q/pyHyjIx5b9BWTb2MjFZJST7VuWYZlEaj5iTtHrW1GS59THEKThoT0vamkkEgjBHUGnA12AAAAHaecf//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-34.png', linkedinUrl: '/in/makayla-schmitt-5c93328d2c', jobTitle: 'Web designer', }, @@ -8345,7 +8345,7 @@ export const peopleDemo = [ city: 'Kristyville', email: 'andrew.miller@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDrwOK5zV/GOnaVcG3U/aJx95Yz0Ppn1pfGuty6JoWbZwt3cN5UTH+HjJb8B/OvHjN90BjjPzSN1Y965zZI7XVvG2rC2MsJSEOcbEUMVH19a5+18V36y72v5/MJ5bqTTbeGXWHjtLV2zg4VOn1J71sL8MNVaMSbozIeT1o5ktGWoSeqR0Gm+NysCtfRtLHnmVR8y/Ud67G3uILy3juLeRZIZBlXU5BFeQXuh6tocDLcoCi/xqOn1rV8B+IGttS/s+WUGC4+6v8Acf2+tJO4pRa3PT8ClC8U4ClA4pkHmnxbYqdJUAkESf8AstecQRPO6wxAs7nb6V6v8TtJm1C0sJLdlM8RcLH/ABPnHT6YrjfAulNceIgJ04hBJVhjkU3JKLLjBtrzO88GeE4tHj8+V/NuJVGTjhR6Cu9i+6ACpP1rmL0yRxeXslkVuNqcdfU+lZGixXUV750dtcQqWIPmscjnHqeK5Vd6s7tFaKO4ubGO8iZZYlZSOd1eM+M9GXw74js57AbPNIYKOgYN/wDXr0LxVLfIIoIlmZPlLeUTk5+hH41kT+HxquuaKLiKRIIkkeSNyTypXAz6EkGtKejMa3ws7UAlQSMEinDpTyMUoUYrU5CnqNuk0CuUDPEdyZ9cYrmrLRxZX63g/wBbJEVm7ZOcgjH5V2HUYNclBe3reKtU0+7KGGFUktyq4JRs9fUjGKyqRe6OqjUVuRnVWcsci7WUHjHSnXCwQqFRF3P2Ax0qlbKQRg9aZqVxpjwNBfTIMjDKW5rKJ1aM1ZEhfyC+1sr3weaYVR5VIX5kBGfr/wDqrHsLjS5C0NtcrI6gBQWyV9q2YFIjyeprWC94wrtKGoEUoFP8p26Cn+UwHKmt7HDcqrzVK/hgeZHAT7RjaSMbtvX8s1r21o08wjBwD1PpWbqGjpp+uXE6qc3OxgxPYKBj9P1qKt1C5rQSc0U45mj+UnBFWDA06ZUpnsTUU8CyHnj3pkdrdLIqBhsPcmuVM772LCWzwj5/LyTwVArfslhZRnDYHUVjRWg2lXYsTxk1q6dKrWkMxQAPlWI7MDg10UnqzlxF5bmqIY8ZGKUIOigGkQ++R2NO256cGutHE9D/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-35.png', linkedinUrl: '/in/andrew-miller-f2fe0c545b', jobTitle: 'Environmental education officer', }, @@ -8355,7 +8355,7 @@ export const peopleDemo = [ city: 'East Preston', email: 'matthew.perez@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD12ilo7iqEcj4p8dWnh+Y2UCrcX+MlCcKmfX39q4C/+IniK6RlW6S1H/TCMKfzOTWNq/lnVLq5k3TSvIzFz9T37VmTxXtyn7q3fbXNOo2zohTVthLjxXrzSNs1u+BJz/x8N1/OrelfFHxXo0iLLdjULdeqXAycfXr+tc1e2lzC+yaF0PbcKrxozNgqGHcelOMrClE+mfB/i2z8X6R9ttlMUqHbNCxyUb69xXQ14F8KL59J8XiAMVtL5fJdW7P1U/nx+Ne+1tF3Ri1YdVbUHuI9PuXtIvNuViYxR5xubHA/OrFV7+4ktLC4uIYvNkijLrHnG4jtTYJXdjw2HSbm5uXe7IysjKUHYg4J9+c10cdiIo1wAQOKxNaa+bZJa+avmqZNkQBIYkk5J+uKf4Yu9VumeG+3AKu5Wcc/Q47158431uepTlZctjR1HTo7qErcIhB6etcTqHh5opv3bEr/AAsPvCr2r3+syXsqW5k8lepQAkgeme9FnLdOdkvmdORKuGH9KcU0r3FNqWlir4cvDZ+KtNtpiGP2iMrJtxyGHFfSB6185i0Y+IY7hMb7crMmf7w6fyr3jQL+bU9Bsr24CiaaPc4UYGc44rqpNbHDVg173Q080jgMhU9CMUUVsYnnltDCYzDMoyhKsCM4xxSIsBabyFRURSARgZNN8QKbHW77sh/fADuCM/zBriHvLjUHMsMi2ybdvBPI9+MV5rg+Zo9eE04ppanR6dHBJcPFMoG4ZGe9LfxW8AKxqoAHauOsr2XSpz5p8xS/DlyTj6GtjU7xjgKcll3Z9BQ42Yc6t5lextZNS1loIFBcuiKR1J/yf0r3O2gS1toreIAJEgRQPQDFcF8L7K1bSZ78rE11JcOFbILqgAHTtk5r0Gu2lDlVzzq1Tm07D6Ko6tq1to9p59yTycIi9XPoK851nxrqV6GjhcWsJO3bGfmP/AqqVRR3IjByL3xK1C3gmsktw0l8Q+8JggRDru989PxrnftUtzpSPp08MU20YVu49KqxziLVLZpB8pODu9D/APXqPVPD80Ekk2l3AhVskxkZA+npXJOacrvQ7qKlGHuk105trMyXEkBnKkYHOTXLPc3GpSiOB+WUCRh0QDt9abNpupSSbLqdSD3Q8mte0tItPtugXA/Kk2o+bH703rojnwt5p3ihLqxneFoUG1kbBBAxivoTQfFOm6zaQbbuNbsovmROdp3Y5wD1GfSvA96tcSzH7ue/f0q0M4BOM9ea2jUcUYKTdj//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-36.png', linkedinUrl: '/in/matthew-perez-e0f9b3e4cb', jobTitle: 'Ranger/warden', }, @@ -8365,7 +8365,7 @@ export const peopleDemo = [ city: 'Jenniferhaven', email: 'molly.peterson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDtaSl7UhIAJJwB1qSinqeqWekWbXV5KEjHAHUsfQDua4K8+KcwkYWOnRCPs0suW/IcfrXKeJtW1DxV4gaBCWjjdkhhjOQBnr9ferMXw91N0VnMKZ7DtUSmo7suNOUtkWIviVrpdg9zFye8QytaEPxS1NbgpJDayIDjbggkeuc1CPhopRXe8YOB8wAzXPa74bn0uQyRozRj+M0lVi3ZMqVGcVdo9c8PeN9K1+T7OjPBdYz5Uoxn6HvXUDivl+C6mtblJondJkbIYHpX0R4Y1RtX8OWd5IwaRkw5Hdh1rVGTReqjrUqQaJeyyOURYWJYdRx1q/UF3bR3dnNbSjMcqFG+hFIDyvwBZCe4u9SYAySNtXAA29zgdu1ekKvygZBrzDTIG0vTLmzkgllkW7kjXYxUAgDnjvW54Rubqd2hcTJGVLDzWJxXDVjduR6NGSUVE6+ZflJyFH1rnNdi+0afLGACWU475NYWu+dJdySvBJMqDIG84I9AM1PpVy86+WbFoMDt0PH86lRsuYtyu+U83ukEdy4xj1HSvZPhbqQu/DD2hGGtJSv1Dcg/zrzLxNp8p8QeVAhZpMYA7k13/wAJ7Wa1h1aKUL8sifdOc8Zzn6Gu6Mk0jzpxabPQaUUlKKog5uKwhtrq9t5FU+bO0/Po3NEUtjaTzKHjj2px2z71Y1yN1uYZ16Fdp/Cufu73T512tbSzsowTGhOPbNcFSL52j1KDUqasX7NrS7Yxs0b5GQykMDTrtYbVP3aqB2xWXaajZofJit3hYnhWjI/WrFwTJyxrN3Tsa6GRJbPJcm5jx5uQBkDGAT1ro/AEREeqXKriCW5KRnsQgAJH45ri9RvrqXXYNEguEt4rsKrSkfMuT2PuOK9asbSHTrGG0t0CQwoEVR6CuyhBr3mefiKifuIlxTsUuKXaa6DmKl/afbLN4lOH6ofQ1xj2uSY5ZPJkQ4Kkciu7klS3jMkrBVHUmuDvJm1e6u7hV8orM0aEdwvGTXNiEtJHXhZSTcRhjFumPOVvcCoxKZPlBz6mqCW908zJM2Av61p20KooAHX1rkZ2bnPTabFd/ECwjuGZUKLIu0dSpPH04r2CJlZQNwJA5zXJ6faRXGqpM0YJtkIViOdzdvy/nXXJbxSW4inTcCOcHBGfQ110H//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-37.png', linkedinUrl: '/in/molly-peterson-9556e9927d', jobTitle: 'Environmental consultant', }, @@ -8375,7 +8375,7 @@ export const peopleDemo = [ city: 'Baileyfort', email: 'eric.kennedy@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-38.png', linkedinUrl: '/in/eric-kennedy-f791a22768', jobTitle: 'Garment/textile technologist', }, @@ -8385,7 +8385,7 @@ export const peopleDemo = [ city: 'South Sharon', email: 'daniel.nguyen@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1SkoNJTA8/wDHXje50i7Nhp2wEIDJMOSpPYD6V5Ne6pdXfmzmfc0p3MxPJPvXU6nbN4n8Z35hAjt0JUbfQcZPuTUifDOSQnfeFUb+EJWEqiTszeNGTV0cSt5HJG0E8gC4A2g9D61St7mRIZos7lLfKCe+eteoN8LLDyh+8k345Y96qXfgGzt7ORYmYybTgk96n20S/q8zm/Cviy48OaoLyIFoiNk8OcK47fj717z4b8RWXifSVv7LcF3FHjcfMjDqD/jXzLdWs0G+ErsKfKwPGRmvT/gndtHc6rYBi0RRJlHoclT/ADH5VtFmEkew0hGRj1ozSZqiDy3RLD7FrWrRBCrpdFcE546j9Dn8a7KLOBk9K5zxZFf2WvzTWIZTdBGBUDGQuOc/Sm+HNY1W/DRXVv5cioWDEYyB7djXDVi+Zs9KjL3Ujp3L7CM1i6mT5TKo+bBrBv8AVfED3EphBWKJSxCLksM9vWp7G8v74KLiKVcjPzrgjio5dLmnNrY8z8QttuSrxkPnPIxXd/BODE+rzqBs2RJnvkkmsrxZpgudStERcyOCp98V3Pw9sItIa5s4Ik8uSJJTKOSxHHJ/GuqnNaI4qlJ6vsd5SUZoroOYwtcjie8jWUAq0fGfY1UtIY41uHiAAC7RirfiiEmyiuVzmF+ceh/+viuInuI7gsq3fkg8OgYjNcVWL52ejh5J013OoghtZ5DFIF3jnB60+5SCziIjAFc9YXdna/uYZEck9d3OfxrQvDvXLMTxmsWje6M3YJb1Xwpk52kjOAa7Lw7ZrBavOP8Als3H0BP9c1w5CzO5PQd/SvSNNjtYLCC3tJEeGGMIu1g3AHrXRQjd37HJiJ2jy9y0KKKK6ziIbq2S8tJbeT7kilSR2964CawureZ7bz1jliO0nH3h2r0KWaOCJpZXVEUZLE8CvO/FmsW98j3FvC0ZhGBMDhpPbHp+tZVKfMro3oVeRlhVNvATI6MT1NZVxqJkbyo23yPxgdqyUjub1nSe+ZExuUd2H1q5Zw2+moZBlmPQt1NcdtdNzt5m9XsXZ0FrZqjH55DzSeD4B4ZdXDGTf/rvce30qASNcTeY/Ldh6VbTczYTHHUmu+hR5Fd7s1sj/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-39.png', linkedinUrl: '/in/daniel-nguyen-9ecda3ed3b', jobTitle: 'Analytical chemist', }, @@ -8395,7 +8395,7 @@ export const peopleDemo = [ city: 'West Melanie', email: 'edward.washington@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-40.png', linkedinUrl: '/in/edward-washington-611f90b992', jobTitle: 'Field trials officer', }, @@ -8405,7 +8405,7 @@ export const peopleDemo = [ city: 'Calebville', email: 'stephanie.phillips@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1KiisTxP4ltPDGkteXXzO3ywxDrI3p9PU0gLGq+INK0Vf9PvI4nIysecu30Uc1z8XxK0mad41guMD7rHaN34Zrymx0zWfGOoS3zsf3jktNL0X2H0rutO+Fdr5Qe5vpZJSPvDis3USdjaNJtXOytPGGj3SgtceRk4HnDA/PpW6jpIgdGDKwyCDkEV5XqPwweBTJY37Ej+CX5lJrH0fxTq/grVobHUFZ7Fmw6HkAeq+h9qcZp6ClTaVz22ikjkWVFdDlSMg06rMhprw/wCK979u8ZW9grsyW8Kgr2VmOT+mK9wNeFeO7fzfim8abhvEGQR1OAOKT2Kjud74etYrfTIIIUCqijNdRCyiMASKT7GvMdev5LRRbRRTOuOFQkDj+tN8KrqKX8AMcscExDMGJ+XPr71xW05j0OvKeou25CN4+ma4D4g6XDeaQ7yJiWM7kf0NU/G0t7BflYlnkhTB/dk5/ACmQTT6ho97ZzJOsiwEqspz82MjBprpIUlujqvhdq8mp+EI4pmLS2b+QWPUgDI/IcV2tedfCAgaJqK7SCboNz7qP8K9FrsR573EryzxLbpeeMxeTQiOa3mESYzmRFwdx/OvUxXI+K7CKGf+03KIuzazsfu4/wAcVnVvy6G1Dl5rMbaSW13EFaJCehLAVBqOq2GkXVusmQu4AAKTuP4dBVSyJXlejcio7vWjv8q1097qRDg/LgZ9iev4VyLV2O807bVtM1a/mjByGxkMh4P4jBqzeR2tshVYx90gYArKstbLqYbvSJLQHABCcfp0+tWb2VFTzJCdqjnHNNprQT03JfAdq1hDPbIcw43Ed1k3HOfwxXZVmaNbCG2MoBHm4IBXBAHr71p12U78up59Zpz0Eqlqmm22q2ElpdRCWJudpJGSOnSr1JirMjyq0uGSyhTO0ouw5PQrwf5VoJaQXa83JiGO3ajxFDbx6xcpa7SM7nCno55b8c1zcs0kb9Mj61wSVpM9Om/dTOuitra1jOy7aQHruOTVd0e+VViBcJIj4H8W1g2P0rK0u3e+DsSVCjp61vJdtotp9tS3M6wjc8anBK9yPfHNOHxK4ql3F2O0tIkigCxlyhJYbzkjJzj9anqnp2oWup2Ud1ZyiSKRQwI/rVuuAAAA7jzj/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-41.png', linkedinUrl: '/in/stephanie-phillips-7959a94ad5', jobTitle: 'Ecologist', }, @@ -8415,7 +8415,7 @@ export const peopleDemo = [ city: 'New Heatherfort', email: 'francisco.leach@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDrdvFZHiTX4PDekNfSp5jlgkUQON7H+lbu3FeQfFHU2ufEEOmA/u7aMMR6u3J/TFIZymq+ItT168+0Xtw0gVtywjhE+g/yaqKtw+6VlLK3XjoK9H8L+GNPOlxy3MCySTDJz2rsbPw1o8FuyR2qEMMHNYOur2OpYWTV2zwMzGFgVLIw5Ujg16p4B8cPqZTSdUbNyq/up2PMnsff371sX3gXQ5U4tACBxhq898ReFG0pRd6e7jy3B2g8jnqKca0W7Eyw8oq57UwpoFVdDuZL7QrG5mYNLLCrOR645q9trY5ycCvGfiDbvF47kYoMSxxuvuMY/mDXtOOK808Tab53i2OadmYicBMjpHgHr6ZqJy5UaU4c7NPSl/0WOPBGAOB2roYEbZkEH2ri9RuLq1cx25mXPKmNQST+NR6LqutG7jilWZhJ/wA9AAQD646Vw8ulz0+b7J3UocoR0/AVxniwldMnKjO1cmk8Qapq8U720KTDaMsY8bj7DNV0iuL7T7mK5aUgxlT5gGQceo600tmTN6OJ0fw6klm8HQGUcLK6ofVc/wCJNdUUrN8L2ZsfDVlbsMbUyB7EkithVrvWqPMkrNoAK5zxLZnzFu1jJ+TazAZxg/5/Kuo24qOaETQSRHo6lfzFKceZWHTnySuchavBdQeTMgzjG44/rU8EdvFeJDbxjKsC7gAcmshAVkIyOCQcHjiqt3dWc8iEXQgljPDhyDn39fxrgS1seqmrXOlvI7d9TdLhBh2O1iARn0qpdxoGS1tY8s7AACsG1uoDPIZL4XUjEDdv+6R6Cuj0aFptZjZufKBYn8MD+dUo3kkTOdotnURIY4Y0OMqoBx9KkFLijFegeTcZLewIdqtvb0Tmqkt3MTgKqA8c8mlaMIAqqMn9KqqC1sJCxJMjflmqsI4dlfTzJGxJEcrqf++j/SrEaPcRq9tNChxxvGQR9Kv6/arBdecynybjHI7OB/Uf1rBmspo1EltJjn1rzprlm0z1aUrwTRfe1eJd08kTt22Dj8q3tCnazsTPsEvmsQxzgjaSP55rk3ea1jQAGe9lOyKIfxOen4V3Frp32DSre1ZtzRIA7Z6seSfzJrXDxvJyMMVPRI1Yb2GZVIbaT2arHasS1tVEKKCePmzV1XkiwFKE/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-42.png', linkedinUrl: '/in/francisco-leach-ae0211a300', jobTitle: 'Photographer', }, @@ -8425,7 +8425,7 @@ export const peopleDemo = [ city: 'Stokesstad', email: 'lisa.gutierrez@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDt80hNRhqpateNZaZPPGV8wLhd3QH1pN2VxpXdhl/rMdtIYIyGmA+bPRPrXMalr0pmWKJtzldzSP0UeoHvWJHeq26SVmZC2SWPMrf4VFFMs7+Y/DSy8nvjOBXK5uTuzqUFFaFpNTvhflpJ3MO4IAxwM/0+tdbZ6y1koMpJQ8nPauSCJdiW3lx+8QD/AHWBPP41cS/WS0SOQ/NHwxPUds/57Glfqh8qejPS7a5S5gWWM5BqcEVwOga19hvEtJmxFI20c8KT0/Cu4D11QnzI5Zx5WZ4PFcP411aR7ltOgx+7RS/1P/1q7cV5v46he01trsAlZUUp7t0/pUVfhLo/EcxLcObneXJSM4Ue+OtXdNgnv5i6K2zqv4V0TaNA2l2sslo8s0sQYhPlAOOa1/DBkuZIraWzWJMfL8uCB6VzO9jtjFX1OKje5W5JwQ65yKmmmeGYXAQ7JOo649RXTa9aNHfuILfIiBbgfex/M0yGxGpWhDWkkMm3du6Z/D1pa2uNpXsc9DK148axOCytwMeh7V6/Gx8pdx52jP1rxfTRLZ6gsinaYpMnPYg17Fbzi4to5gMB1DY+tdFHqcddbDR0rn/FWhS6vFbyQgM0J5U+ntXRhTjpTwDjpitpR5lZmMZcrujO0uOKXTYYJk5VACGHTirdtDbwXyKgVQvJPSqph8uQ7GPJ55qtdXNkCFdZTKuRvVCcZ681wNNOx6sGppNGl5NvPO6yhSSSQeuaLlILaDagA+lZtlcWCDZEJVkY7stGRk+tWbs7YmlY5CKWx68UnfYppI5NfD0t5c3Yj2oJnBDt/Dzz/Ou3ggFvbRwqSVjQKCfYVyPgy91OaWVtUMh84Dyty7do5/nXbAZFddGNlc87ETvK3QaOBRgmnEYqSKOSZwkaFmPYVsYFaSAyRkDg9RWeqJIux5CuK6ldHnEEjsQZVQlYx3bHGT9a5WFGmt43l4kZQWwMYPf9a5a6V0zsw0nZonWNIkOJdwqBx5qEEnaeM+1SJaheZXLDsKtR2U9yfLtoi59ug+prFX6HRKV9xiW8DToBIpaPAVARn2q2FIJByCOCK3bDQoYJ0uJ1WS5VcBgOFqfUNPtmBlYFJDxle5rtg+yP/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-43.png', linkedinUrl: '/in/lisa-gutierrez-372eee2535', jobTitle: 'Community development worker', }, @@ -8435,7 +8435,7 @@ export const peopleDemo = [ city: 'Gregoryville', email: 'robert.martinez@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1ykJCqSxAAGST0FFeb/FLxFLBZjRbGVlmlG64Kddh6L+Pf2obsCVyTXvivY2kr22kW7XkgOPOfiL8O7fpXH3PxY8RuxCG2iX/AGIRx+easeH/AAPbSWUU+ouzTOAdoOAtb58E6GoyIGOep3VzuujpWHbMHTPjJqVtcxx6paw3MJPzNGux/wDD9K9c0fWbHXbBLywmWSJhyAeVPoR2Nea3PgfRmQt5R47ZrJ0u8m8A68l1AGl0m5xHcR9SnPDD6VUKyk7EToSirnt9KKYjrJGrqcqwDA+xp1bmAleJeKCZviFemT+GZQR9AAK9sHNeO6oYr7xpLexxn7LPJkHHO5Bhs/lWVWSSNaUW3c6K0fKhc8Cr+5COHyfrXCa2JnIZGutmCVSHjp6n1qpob6it4iNNc+S5BxKc4z0FcXLpc9Dm1segT7fLIL44rj/ETqlm4cbkPB9qo+I7jUDcyRwy3Cxx/e8kc1UtknltLiCR533Rk4m6g4qoxtaRM5XvE9v8PyCXw7prqSQbaPr/ALorRzWL4TKjwppqqSQkIQk9yOD+ua2c13rY81qzsIDXm2tae1lq8u3iFHJRf97Jz+tej1heJNKF5avdCUo8KZ244YDn8KzrQ5o6G1CpyS16nM23l3EZVgB9RkVEotIL1Y8xqqkEliOWPpVVZSg+XpgnNZN1eWmors8ssUJ2uIySD3ORXBFN6HotpGxN9lk1mTDIyv6HPNQ36QRKVRQrEYyK5uOS30+8LIxYNgMzgg/hmuhsYTrGrWtoxISU8sOoXqf0q+V3SIclZtnpOgwC20CxiHOIVOfc8/1rRqG3hS1to4IgQkahVyc8CpM16CVlY8uTu2xa4b4mXFzFolr9nV3DXaIyp1bIOP1xXYkszcscVT1PTV1PTpbY4DZDxk9nU5H6iom7qyLgrO7PNJJWtW2yvsU9Gx0qwUiazCpOIQBgbRU+o2+8NG6bWGVZWHQ+lcjfpeQsViYBcYHqB7VwRs99z0neOq2NW5SKOJi86zH/AGqv+ENTjtvEkSyLuZoGKn0UEA49+a5Wzt5pWxcNuHfFbfh2E3PjXeo/d2toc+244FawtzGNS7i2z11NRtX/AOWoX/eGKsghhkEEeorlnhyyv2GBj3q1DJNF8yuRjtmurn7nAAAAAcXIf//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-44.png', linkedinUrl: '/in/robert-martinez-a6ae2c5b1f', jobTitle: 'Secretary/administrator', }, @@ -8445,7 +8445,7 @@ export const peopleDemo = [ city: 'Smithtown', email: 'courtney.kelley@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-45.png', linkedinUrl: '/in/courtney-kelley-950cfddf8b', jobTitle: 'Environmental education officer', }, @@ -8455,7 +8455,7 @@ export const peopleDemo = [ city: 'New Lori', email: 'samuel.davis@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-46.png', linkedinUrl: '/in/samuel-davis-dd4df4491c', jobTitle: 'Engineer, technical sales', }, @@ -8465,7 +8465,7 @@ export const peopleDemo = [ city: 'Davidport', email: 'paul.kim@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDvjR05NONcl8QdcGjeHWUEiS6JiUD6c0mNGX4h+JcFlKbbSIVuJVbDSyghB9McmuE1nxdruqymS4luEQdI7ZyiqPoOv41i2ltd6lK4t97yd9nT6f8A6q1h4J8SMgI289t/SsnLzNYwb2RWsvGev6deRzx6rdsCOUuCXRh9DXf+H/ivb3LeVrduLYk4WaFSU/4EOoriLj4f66qAyFXJ5IDdKxru0n0+JoZx5bocbexpqa2QOm1q0fS6uksayRsGRgCrKcgg9xS4rz34U+I5tT0ybS7li8lkB5bHr5Z4A/CvQ8VoZDq8l+K00smuWdsASiQZGem5iefyFet15r8T7Cd77TLmKImNgYncDo2RgE/iaUtio7lzwPoFvZaXDPIu6WQZOa7B414wo/CuP1CeWztIhAbhQqDy1hTLHA79qZ4f1TUZp1W6kmeNjkeYAGye1cnmd6stDqLtVjQ8YyK868X6VDd2zyYAkUE5q/rmqajNNKsE80ccJIYQqCxx1rJ+1TXKsrtO/HzLKoBpWa1G2n7pm/CmSS38bpAuQksEiuPXAyP5V7rXjPwxs2Hjq4codsEEgye2SAK9orsjqjzpKzCsDxTZNcw28quVKOBjPB5B5/Kt+orqEzQMi43dsnFKavGxVKXLJNmPBEk0I+bntnmqrS2FneIsssSNkhC2Bk45x+FSxI0W5D1Tgj3FULrUbUqImsLibAI3LDke/JrkXY9JJPYoWMlrd6lciGVGDOenPPfNN1K3htwxHLHvUEV7bLelYLOa3YngGPH6imapIzE5PPSplpoMf4JsXbxG1wrECPe746EEYx+tekmsPwxpMmm2TPOFE0uDwc4X0/Wtw12UotR1POrSUpadApRQKGZUGWIH1rQxOc1h/st85ztSQA596hxbXFsFkk+Q9MGq8bPe6trEU/zKs67AeylF/wDr1najpU8ShrVmCnqM1xTtzs9Gk3yIfeeRagujnjpzWRFOtxqFrG7gK8q72Y4AGagmt7ktiUlvqapavA6aRc7eH8skfWp0uU22me1HrSGuc8Iax9u0eK3uZR9rgGxgTyw7GuiNAAFd55h//9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-47.png', linkedinUrl: '/in/paul-kim-01704924f8', jobTitle: 'Optometrist', }, @@ -8475,7 +8475,7 @@ export const peopleDemo = [ city: 'Johnsonbury', email: 'samantha.jones@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDkiTTWcIMk06qV9KVKheo5PHaolKyuXFczsVru/fmJcpnuOv4VctrGOKwNy5JJH8Rxms+wt5NQvEhEJYk4GDxiuwXwTd3MSrxGO/Nckm3udkIdjlmnt7Fh5TnynXcU9D6j2pWuGltxcRkMp45OK7RvAltHEVLs3GORXKa7pY0qJoVMm3qAvGKOZDdNrUW1uPPgDE89/rUvIPFZOlTJEpSRxyflPrWzwQDXVB3WpxzVmFYV3LM0pjDbQxI9a3m6Vz1/ATcqyBgGbByMd6mqiqW56F4P0+KCxhkUAuf4j1Nd3HkKCR+VcESLGyiRre4kLLuQxttxgdvetTw9qV6zRpI9x5cmConOWX2NcvL1PQTXwnTTAlCSMVx3iK2iuIGEiBiOlT+INQuJXlUG4aGLOUhbBbH86yoSt5AwjtpoXRd5MjE8Y6UKOlwb6HATQoL4RwDq3BWuggJ2Csm2tpItcuSyNsyQD2rZUY6GumnY4KtxW6Gm6akcupJbzEt5uQMnoRyP5VKw4qjJBdvdo0EbKqfMZMc/hVVI3RNKXLK56TpskU9mkbqGKjv2qxIiR6jBHGVGOTzisLw7M80Cu7fOSQ31q1qF9Yi7WK5DmQH5QqnP51yWd7HqRaaTRcslikvblJNpIYkd81Hqrw29syooXI7VRtb2yW98iAsshPKspz+dReJrkW2n3EzNzHGT+OOKLa2CTSVzndWCQxWVoWVZWYzOU6kdgfzquihWOOmaxdGvHvZi9zKZpj1djk1vhQO1dVONjza0+Zm9pejPdlZAFZGGVORgj2qTxEv9h6eLiSNSWOxFz1NdtZafBYWMUcaBVVdoA/hA6VleLNJOsaBNAgBmTDxk9yK2RgefeFrq7+0XlwzF4mYEIP4SBziuzEEepxrKpUsejV5zoGsLoeqFbtHELHDjqVP0rulubWVftOlahAUflkDDr9OoNc1aDU7ndhqqUUrlz7HHp4aXgMO9cxr1vLrsP2WOQqjtu3dmx/Srl5qNuX/4mOowrEOSgb734dawdZ8VWzxtDpocsV2ebtwAD6CohCTehdWrH7TF8MaBb39vLNAuJrU7Dg8NnvWrNpNzCTuifA74rovBOkHS/D6+aMT3B8xxjpxwPyroDAksZVhw3Brrslsee23uf//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-48.png', linkedinUrl: '/in/samantha-jones-2abb1198e0', jobTitle: 'Medical secretary', }, @@ -8485,7 +8485,7 @@ export const peopleDemo = [ city: 'Brianshire', email: 'daniel.buchanan@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-49.png', linkedinUrl: '/in/daniel-buchanan-962af5531b', jobTitle: 'Surveyor, land/geomatics', }, @@ -8495,7 +8495,7 @@ export const peopleDemo = [ city: 'Lake Emily', email: 'sherry.oliver@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-50.png', linkedinUrl: '/in/sherry-oliver-f3bbba4a94', jobTitle: 'Buyer, industrial', }, @@ -8505,7 +8505,7 @@ export const peopleDemo = [ city: 'Brittanyport', email: 'richard.burton@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-51.png', linkedinUrl: '/in/richard-burton-eba4d16199', jobTitle: 'Trading standards officer', }, @@ -8515,7 +8515,7 @@ export const peopleDemo = [ city: 'South Matthew', email: 'larry.floyd@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-52.png', linkedinUrl: '/in/larry-floyd-a72834d039', jobTitle: 'Herpetologist', }, @@ -8525,7 +8525,7 @@ export const peopleDemo = [ city: 'North Briana', email: 'abigail.garrett@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-53.png', linkedinUrl: '/in/abigail-garrett-fc4de32453', jobTitle: 'Training and development officer', }, @@ -8535,7 +8535,7 @@ export const peopleDemo = [ city: 'Hardyton', email: 'craig.miller@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDUK0m2pivFJtrlOko317babaPdXcqxQoOWP8h6mvN9T+IOoT3+7Tf3FqvCh0DFvc/4Vq64lx4u16TTYpPL0+xfEjjne/f8uRWlbfDvSgqn99uHOS/Wm5xjuVGlOfwnDQ+M9djn3tfM5LZKsoK/lXRaR8RWLtHqduGGeJIBgge4Nb7/AA50aVSNkwJ5JV6wtT+GhtoJJbK4ZmAyqsOT7Zpe2psbw9VHd2txDeW0dxbuHikG5WHcVPtrzLwPrM2m6sNMuQ3kTtsAPRJPX8en5V6lt4qnoZofjiobhjFayyKMsiMwHuBVnHFMkUGNwehU5qRnG+DrcppSzN80s7tI7HuSetdlCrbc8EVwly0lppFrDH9p4gB224wxOM5JNaHhjUNQa5itZnkKEBg0h3HnsfesJq95HdTdrRO2gVs5HFR6goa2cADftJHvXGeJ7zUbPUPLie5ePGSIJNpIz0HrWzpk85KQyrcowAOJ8Nn6MOtZ8ulzTm1seaz223X4pU4YTK4J7YYV6/iuA8Qac8vi9Vt0GwlZJCOAi/xEnsOtehAArkHIPQ11xldI8+pFxbAdKgvYmksZ0RirNGQCO3FWAKVl3IV9RihiTs7mNaxQS2iZVSu0Yz6YqLT5rAaiFWaKPGSATye2fzpsokhdojxjqAazob22klMS2jzkDacLgL9M9a5uVvQ9BSVtDoJLzTbidEMkUuXKeYvIVvQ+la5tYYbcODz2ArlhqVuUa0mt50yAP9XuXP8AvDoa3xu8hEYk4HX1qZKxaaZR8oLPLOiCR5iIpEIzlOefbGa0IYlht44l+6ihR9BUVru/eDC7CevfNWccVtSi1qzkxE07RQgFOxSLTxitjlMTWYTGyzD7r/KfrVJbWSdVaKdYjjGcdRV/Xbgi5t7MxHa8Zl39uu3FczNHqUV0VttrDsGOOKxmrSOujJqNzq7eExWwSWVZGIwTimSXTH93H16A1iWEGsyzGORUjBH3gc8e1bcdp5CkHlh1JrJmybkaFmm22T1IzU5FZXh6e7u7fUjOp2Wl35CNjGRgH9Mj861WPFdaWs+XxM//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-54.png', linkedinUrl: '/in/craig-miller-e5dbce647e', jobTitle: 'Architect', }, @@ -8545,7 +8545,7 @@ export const peopleDemo = [ city: 'Donnaton', email: 'christina.garcia@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDpHORUdNJNNaQIhZiABySaogbd6pbaZbtNdSiNF7nv9K43UPiFdyyFdPjjhhHR5Rlm/CuW8UeIJNX1Rgh/cRkrEv8AWmRaDeyWX2oAgL82D1NZuZtGDZt3XxA1Z7dFR4xICfnC8n8Kn0rx5qsci/aik6HnJ4J/GuKW1lmlEYBD5+Ue9XIVe3kIkXaQfmHpS5g5T3LRvENvrFrviba44dD1WtBnz3rx7QdW/s3Uo5g3yZ2uM9VPUf1r16IpJGrA5BGQfWtE7kSVjJA4rmPHV+1j4fdYziSdhHkenU/y/WumDACuD+Jk22ytVz1YnFEthR3OQ8N6edT1ZRtyifM57e1evxaaq2gjwMbcYrzrw1GmnaHHO9m1xLdMdvzbQAPeus8NXc95NHGI5okk5CyMWx+Jrjqa6nfS0VjIv/DLreFl+UE7kb0PpWRrcEgZZnTZMPlkA6N/tD611viBntbpmkgluQgJEQbCnH8zUUljDrtnhbE2dyqjBUfI49D/AJyKItpXHKKbsjzg3BjAdScDg/SvZPCOoPeeGbV2OWQFCfoeP0rxvUbC4s797Xy3JboMd+lehfDW8aTSrrTpcrNbSZ2t12n/AOuK6YPU45ppHWAkn2rgfibG32azkwSoJH416BGB35rB8aWsV14fuPMA+VQy/wC8DxVy2M47kfg9rW68M2KMoOIwCD6jg10FqbaDU0TKRqoyO2TXCeBrg/YpbUqFa3k7dw3PP45rprm9037SomjaWVMjKKSVz71wyXvNHqU/eirHQf6LdyY3Rv3VgQQealfyrePG1RjsBWRZX2lECO2XyHLfdKbcmtCdTIAD071LKsczeael1qwuxGpJIVlYcFe5rnvAOf8AhK9UliyYArID6gMAP5VW8ZeKr6z1W40m08uOLYoaUD58EcgHtW18NYojpE6pgSrJ8/qc4x/WuijFp3ZyV5pqyO6FsFFc/wCLYidPgjUZWSdVf6V1DDpk1XuoIbiApKm5Ov5d66Xsckb30PKIHl8N64JJEbybkEPgZxjvXZW6JdBXW4VcjIZT1FO1S3s76B7f7Mxx8wkJwVPbFZOlfPayRxjaImIjx/drjq8t7pndQclozq7eARxAvMrj1xzStcmX5EbIHesi0tZ5iN058s9q1VRY12oOBWLZueMeLlkPi+9Z0IG4YPqMCt74f30tvrcSLkxzIUcD9DXa3fh+01N3N1ArjOQSOR9K6TQfBmm6PbCSO1C3D5JcklgD2zW8J3t5HLUp2u8AAAAAAADuf//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-55.png', linkedinUrl: '/in/christina-garcia-7ba1c75253', jobTitle: 'Radio producer', }, @@ -8555,7 +8555,7 @@ export const peopleDemo = [ city: 'Chadmouth', email: 'lynn.gallagher@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDtsUmKfXH/ABF1yTR/Dhjt5Nlzdt5SsDghf4iPw4/GgCPxJ4+sdHma1tSl1cjhlR/un64xXHn4j+IWhYCOONCeJPL3Mvt6fpXL6ZbPLlreNpZidqZGcnucegrcXwPrd0m+Uwru7EnP6Vk52No021ojpdN+KClNmpWoDgffh6E/Q11GjeMtI1mUQxSNFMeiSrjP0PSvLJ/h1qkK7luIjjkAE9azYbm90LUUW6QbkPTHDDuKFUvsDpNbo+hsUhWqOhXq6jolpdKSQ6dT19Oa0K1MR1eG/EDVZtZ8WzWQOIbMmJB6f3j+Jr3OvDdY01l+JF9Zk7muLpXz/sthv5GplsVBXZ2ngzw5FpunRSyENK6g8j7tdc8Y6ACuV1a5hsogjQ3cz4+VYCQFAHrUfhq6uJ5wjfa0iOGxO+7HtmuNq+p6UXZ8p0s6YB4Fec+OtLWW0+1qAHjOW+lbXiW+m8+RMXLRR8kQMVJ/zmsZ5I9R0u7hiW6RxEd0c7bsnGQQe9JK3vBNp3idV8M9QN34USBzl7WQx59VPI/nXZV578KLKSLTb27L/upnVFT0Kjk/qK9DNd0djzJbjq4TxBo5/wCEzt9SBPC7sH0AC8fnXd1i+JLm3s7OOe4YKrOIwcdz0qKqbjoa0GlPUkgEc0Iz1HrWfd6hZ2kqqxKKXCbgpOT7YqaJW8olTwBms+TV0RhCljNIRn5mXaPrk1xpXPT06Edvd2dxqs6K25c4yR3p+pQwRphFUEg5xWa2pp9vVDYvEzdCi5H6VYuTJJIowSfQc/hSasHQ0/Aenvp+gspk3RyymRB6AgV05qvp8At9Pgi2lSEGQexPJ/WrBrvirJXPIm05Ow6svxBpSaxo81q+B/GCfUVpSyxQRGSaRI41GSzsAB+JrJ169H/COXU9tIrRvFxKpyNpwCRjrwc1TEjMt7kIgQyDaRlW/vCrjQpcRkbxt7GsLSYRcaHbwTj97AghkHcMvyn+VV7yDUbL/UTF4z0BPSuDZnqRehfuoEtzvVhxTLES3N7GYhu2uCx9jWUBeSkfaH69hTLC+lsvG2nCLLRvE8bxjvkjH8qdOzmiKzfI7HpqZ28040IwZAyngjIoANdx5p//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-56.png', linkedinUrl: '/in/lynn-gallagher-03ab6cdaae', jobTitle: 'Management consultant', }, @@ -8565,7 +8565,7 @@ export const peopleDemo = [ city: 'Tiffanystad', email: 'veronica.oliver@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDsTjFZ9xqUEI4IY+3+eazvEOtC1Is4Dulb72O1c5NftGTlwrqOWPOz/E+1cs6mtkaxhpdnS3esGKFmaaKEkcbm5/IVzEvie+s28yZpJo2YKrxuQCff0+hpbWaW5wluSshPyooyT7sa1V8L6jfKxu7hMMOVA61nzO+puoaaGlpHiKa4gR5F8+E9XUYYe/v+ldJG6yKHQgqeQRXnjeFdS0Ul7S5Zo+oUdvzrX8M667SPa3WQ4O3ngg1cKjTsyJ0tLo7BetTrVdTg1OproRzniOp6u6XbNGd1zKSWkPRBnsKqW9z9qnEMTNLITjd2BqfxVo15Za3dtLEBGZC0e3oR2OPTmpvBtkJNQZSP9Uu4/U1yOKSOqOrO48O6RHYwg/fmPLNXURDI5ODXI6hqF1YJ5cEErsR/AMY/GqNnPrQngmkkmWOXkoTkoM9xSUdLm11ex6GUEkZDAV5n4lD6V4ojkhXBmQHA9RxXR+ItQ1Oye0t7BHZpgC0i9FzVWDTZNZ1izub2OVfs8Z8wPzuIbjn0PJpqNyZuyOrgkLwROwwWUEj0OKsK2KrscU9W4rqOE5vxbZAh7yOLfLJD5PTODng/qaw9C0ptMlllQ5STGQeoPeu51GFrjT5kj2+ZtJTcMjcOnFcloOoSapYC5lhSLcShRTnDAkHn8qwqRadzrpTTST3R0du8M4xIin1z3pl79mg2RxqodsnAwOBVdImBGDiq19Ppk2ba8be2PmXaT+HFZJPY6NDbh+zTW1uZTG2Pl5IODVglQwVR0GM1h2SaR5JhtjjP3NwII9hmtmBCEG484rSCfMZV9IahJ0py/dpHHFKn3a3OEmCmucXSF0yS6hhAEbzGZAO24DI/MGulkYrGdp+Y8DjvWXJFcqEN0weQry6rhWPsO1Kqny3NKPxGeJiF25GalSNphgOo+oqC4tiz5Xqf1qsqXSzrGAeTjOelcy11Oy9jbS3ZIiDKJCenqDWgilUAPXvUGnWSW8rbmZ3C9WPT6VeZRW9OPU5q07uxXYUqLxVamB//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-57.png', linkedinUrl: '/in/veronica-oliver-e46c83d82a', jobTitle: 'Theatre stage manager', }, @@ -8575,7 +8575,7 @@ export const peopleDemo = [ city: 'Amandamouth', email: 'julie.stevenson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDoTIwzjG3vVd7gZwOfSmmTah3A571XE6FzxnHJzxWTfLqwim3ZEt9rVtpkAeduTwAO9VT4gnkw0UBSI9GZSP1rLm0aTxDq0Kxksg6+3v7V0LeFr6yi22+oM2OsbjKkVjKbkro6o0kjHk8R3tvL8yxSJ6AYNTQazDf5wdhHJQ9axdZ0u+tSzzwDZniWIYx9R0rnVvZIJgwb5geopKTYTprY9Hs2ByyLj8OtaEUgU5A5rM0TUIb/AE9bjIDj5XA9a00kQ88ZrZbHJJNCXSrtOOa5rWbowwNHGQGIyfpXSzkEHBBFcR4hEn2/yVGfN2Y/OlW1VjajuegeD7E2WjRyOd08vzM1bcpJbnmuc1S5NhZpAltNN+7/AICQFwP51V8NzXcsqpIJlicb8SOW257c1lsjqW50txErptdQwPUEV5l4s8LrBvu7IBQPmaP/AArofEN7drM/lec0UXaJiM1XhmfULWSGSGWJgnIckg5FJ9xtdDk/Cd24v2twTtkXJU+o/wAmuzdZGhIjJBrg/DKGLxDEJDggspPvg16RbOpJHGfetYo4qi1Im8zHzflVc2Ed4/mOBvhwRnH94d/zrYkiVzjOKdDDFDIHJBHRh1yKqpHmWgUpcsrs2EaO4hwwB+oqq9xZ2twsRdIyTgZONxx0FLbkOu5MgHnmqV3fwKDF9hlmK5y3l8e+CetYpvY74pPYZaNbz3M6B0cbj0OcH0NJfrHCpCqB9KrW17E0rItpLCxPB2cfnT79iY2bGSqk49al32Kem5z0OnRQ/vYkUP5rF2x97uPy6VfiVnBwD9RU1p/pFusjJtaQfdznaKswxLbnZ1JrSKtucFaSlLTYum1kI3AndTvsLEAkkNWvHCCgfp7U1o2ZwqqSfQCtGmZlGON4Ewfu09lgeHDyE+1W5EZZTAyYZQC3tntVOaxV0bGQw54rGduY7KTfKrlOYRoMI3FR28QurtIWHykEn34qRLXqWyQPWmCR7e4WWPAI45FSmk7mk9U0jTjsIosYjAx6VL9jic52AH6U7S55L23dpFXfG5RtvQ8Ag/ka04bfccnj611RXVHA7p0AAAAAAAFmf//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-58.png', linkedinUrl: '/in/julie-stevenson-482959b900', jobTitle: 'Pharmacist, community', }, @@ -8585,7 +8585,7 @@ export const peopleDemo = [ city: 'New Julie', email: 'kathleen.gardner@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDqXAAqrIwNWZT8tUWJLYoEMI3Hiqs13BA2xpF3e5qp4j1QaXYqEbbJJ37gVn6N4M1TVwLy/u3t43+ZYQOce9c9Sq72idFKldXZYuPEEMLFETzpPVHyKWDXJLwjbGquByGbBrd/4QXToLcpF5iueS4PJNc5e20mnX6Wt2xlhcHa5GGQ9iDWPtHtc29kt7G5ZXa3XyFdkg6qetaCRVwcN9La3xj3khDkHPQeo9q7zTbtLyAHI345ranV1szCpTsrolflaqkc1bdSRxVOdSIn9dprduyuYpXZyoiTxB42trZvmt7cmRl7MV6fhmvU4k2rjFeR2Fyml6jeziGSaUxEIkZIJJYZ5H1Fdp4TvL24jAullRWRnXzG3Ec4wa4E2/ePSSS0OqbjniuY8V6UNSsHCcTKMofesfxB9viv/PhhmuBnODIwXGewFalldXFyPKltXhdOCQdyN9DQ1pcrrY8sS6livNs4IdDtPqK7HQr9bcptbMbfdP8ASud8f2Tafq0d3EvyyjDgd6oaVqZEYG75M/l702m1zIyekuVnsJDKvSqsxwjFhwBWhIwI4FV2jDKQeld0tjgW5z3hK0il8QX88qghYgig/wC02T/IV10ktpZpKfMiiHA5OAPxrlNLJs/EDKOFuFKgfTkf1rTvNS0eO4MdwpkkHDADP5/nXmq+x60FdaHQW3kTp/CSpwe9JcNFApIAAHpWdYalp9wBHZuqt12Ywfyqe5QyAqTxQ21oVZXON8VWR1eABQP3ZLbj2FcDJbCyZOAqyg4A9R1r0TXtasNEj3XyM8LnaFVdwJ9xXm2raydb1I3MURht4yFiQ9Tk8k44q4JteRlUcV6nuRHFAA6GpAKUKK9A8s5HXLoWOpQTgf6kh2x6f5zXR29rBfwJcRyrtcZUg/eBrI1/RHvnEilQn8Q9frWH4Dlu5W1O3ed/Lt5F8tT0UnOQP0rz5RcW2z0qVTax3yW6Wy4+Qe4qtdXIWMgHLH0pqwTyttdyR7VK1ksceTWbdza55L8SXleWyt8/eJcgfp/Oqfh7RJtSu7a2RcAncxrf8aWEl5r9mioTxhMD+Ku08HaAdNgZ5YtkxAGT6elbQ95KKOapAAe63Jn/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-59.png', linkedinUrl: '/in/kathleen-gardner-b144fa40bf', jobTitle: 'Research scientist (life sciences)', }, @@ -8595,7 +8595,7 @@ export const peopleDemo = [ city: 'West Brittany', email: 'james.ward@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-60.png', linkedinUrl: '/in/james-ward-9590de76ac', jobTitle: 'Psychologist, clinical', }, @@ -8605,7 +8605,7 @@ export const peopleDemo = [ city: 'Mccannchester', email: 'brandon.baker@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-61.png', linkedinUrl: '/in/brandon-baker-79f5bc09a5', jobTitle: 'Geologist, wellsite', }, @@ -8615,7 +8615,7 @@ export const peopleDemo = [ city: 'Williamchester', email: 'cheyenne.stevens@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-62.png', linkedinUrl: '/in/cheyenne-stevens-9102d355f5', jobTitle: 'Freight forwarder', }, @@ -8625,7 +8625,7 @@ export const peopleDemo = [ city: 'New Traviston', email: 'nicholas.chaney@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDstlMcKilmICgZJParBXiuG+JmpNaaElrFKA87fOg6lR/TNSMztd+IoSWe00qMBlO0XD4IJHXArnX8WaxfJtmndsJ246delX/B3g+G/the6mm7zOUj6YHqa7eDwfo1ucpB94YIJ4xWUqqTsdMMPJq557a+NdThli2z5aMY2PyrCvQ/Dvie316DhPLmX7y54/Co5vAmi3DblhKN/smsXxB4XbRbNbzSSVaJgXXPB96I1UxSoNI7zGaXbWZ4c1QavpEc5AEqnZKo/hYda2AtanOSEV5J8RInPi2LzfmjMKbR6DJz+ua9exXm3j6yF54m0zySSQBFMB/Dlsr/AFpSdkVBNvQ3tMUR2sKKMDYOnbitmMAgfNXH6u1zFhYjcYC/KsA5JHfJqHw9eanJdRQ3Ek5jk5Hm4JX6+9cNtLnpp9DuwcY+aszXnP8AZF0vUbCK5jxNeapBqDx2zXHlJgnyTgn6fnV7TGuLq3ktbn7R80ZBE4BOcdQR1FXHuTPsL8PWDWd8VXAMqkj/AGsEH+VdrjiuQ+H1u9tZXkUqkN5gYe45/rmuxxXYndHnSTT1HgVyXii1KXsc6KeXSRzn+6cV14rL1+ya60ud4ziSONiAR14zipqR5o6FUZqMtSjCI7hPujPTOKjRII9QjRdq7TyeBWfZ34t9PaSQndGmWrBur+PVXSVTHEYySjNJhs1xpHpqStodzIltLelW2Nv6Hg06WGO3JPoOmO1cPp17Hp7u8rRyO5BLiTkGuqlvTc28TIcF1q7amcpWRb8PW3k2zuw+YnA+mSf61s4qK1t/s1usZbcR1IGKnxXVCNlY8+rLmm2hwFYvirXh4e0SW8EKzOOAjHjnjJ9qiu/EYVxDbRgytwu49Pc1la5F/bFrc2c7bvMTaDW3IzJGFLdSWsLRvwsqfI2MAgjpV+OVLm0HlSRwuAAPkzTEiTU9K8iVRvQbHU9iK565tdQsSfs7lkHynPJFecrddz003HVbHTTTpaWR854p3PAwB1qCz1mCzk02a7yIDMIeDwDgkH3HGawrKyv7mZFnc+W3VgOT7e1XPFNsJYtKtYRgi4B2jtxj+tXFpSRFTmlF3PVgQQCOQehpa5611WSxhtreb5iIx17444Pr0rWg1K3n43bH/utwa7XFAAAAGjzz/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-63.png', linkedinUrl: '/in/nicholas-chaney-3bd29a6f7f', jobTitle: 'Civil engineer, contracting', }, @@ -8635,7 +8635,7 @@ export const peopleDemo = [ city: 'North Courtney', email: 'robert.allen@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDucUoFOxVHWNQXSdJuL1l3GNflX+83YfnQBleJvGWneGVEcoae7Zcpbx9fYk9hXnt18TPEc5MkMUFuh+7Gke4j6k5q5pHhO41+6uNQ1GcmSViQxGSx9foPSujh+GVrsG67k357AYrB1lex0xw8mrnF23xO8RW0jG4EMozyksQGP++cV6L4U8Y2XiaJoxthvU+/DuzuHqvqKpXXw4014+ZJNx+8cZzXJ6r4ObRs3elzOs8PzHBwWHtQqyvYJYeSVz10imlaxfCXiBfEGkq78XUICzL79j+NbxWtzmHAVzHj5FPh2PcxGLmM4Hfr1rqgK5zxmi3Olx2m0ljKknHoDg/zqZtKN2XCLlKyJNDjC2MPABKA/SugTOwCuO1GS4tcJDDdP8vyC3IHQdyal8OXmpyyolz56xv8wM2Cw9Aa4Uup6f8AdOpn4GK5LXSFiYqM8HP0qDXNR1c3E62wmMMP3vKwWb2H51Rhkubk7XFwoVcsk4GR9COtFuoX6EHwzQnWNTZBiIxLke+4/wD169KIrgfAXladqF9FIrA3c+yIjoNu48/nXoJFdsGmjzakXGWogrL1qEPEG2kkgg49Ota2KiuIPPhKZwT0OKKkeaNgpT5JpsqWRjuIVDYzild7eK9jiR0XBzycZNZ1mxjOzP3eD+FU7y+0aeVVu5IQ6ZCkgkqT15HSuFLoeotdUXbBoJtQuoiyN8xIwc0mq+VBA4RQDjFY9nd6RZXB+wTRFmbkcgk/j1qbWZi0LH1GfpQ1bQZH4ct0k1CDaDgM0p+oz/8AWrtjWPoGkGwt0lkk3SPGOMY255NbBrtpRcY6nm15qctOg7FBKopZiAoGST2FchqvxL8OaYSkdw97L022y5H/AH0cCuD8UfEO81+1NnbQmytW++A+Xf2J7D2rVIwOrtfEkV9LLfInl200riM/RiOfrjP41vCI3MCtDIiOQMHAORXnngqRLzR57CTG6OQsoPcHn+ea2G/tWwxHavvQdEbqPpXBPSbPTpS9xNHRPa+QfMldGZR1xWH/AGhDd6ra28kiiKSdQ7E4GM8D8elZV1farc/ubhWTd2HGaytfia10SQ52yZUgjsciiKvJBOTcWe49KSvENP8Aixr1iyfbVgvoejBl2P8Agw/qK7vS/ih4dv1UTyy2Uh6iZMqPw//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-64.png', linkedinUrl: '/in/robert-allen-d4a0e6e38b', jobTitle: 'Media buyer', }, @@ -8645,7 +8645,7 @@ export const peopleDemo = [ city: 'Mcknightberg', email: 'steven.walters@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-65.png', linkedinUrl: '/in/steven-walters-cecce0a460', jobTitle: 'Sports administrator', }, @@ -8655,7 +8655,7 @@ export const peopleDemo = [ city: 'West Jasonville', email: 'alexandra.rivera@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-66.png', linkedinUrl: '/in/alexandra-rivera-82738fef4b', jobTitle: 'Scientist, research (maths)', }, @@ -8665,7 +8665,7 @@ export const peopleDemo = [ city: 'West Samuelmouth', email: 'robert.doyle@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-67.png', linkedinUrl: '/in/robert-doyle-5012cb4f96', jobTitle: 'Early years teacher', }, @@ -8675,7 +8675,7 @@ export const peopleDemo = [ city: 'Jeremiahside', email: 'melinda.graves@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDpcUYqIs/rSbpPWoGPlmit4XmmdUjQZZmOABXE6x4/MUpTTYo/KHWaYH5voKreN9Subm8h0i03SOx5Qdz70/T/AIZ39zbq99MiO3JAGStZSnY3hSbVzlrrxjrE0rN/aEoUnkKcD8AK09L8c6rsEbymQr/E6Amuri+GGmxpiQyStjucCuY1jwwNDmypJifO0n+Gp9onoi3Sa1Z3eheI7fV08t9qXGOmeG+lbZUHtXhMWqS284KuykHKsOMEV7D4d1U6vosN04xLykn+8K0i3szCUbaoukcU04AJPapMcU1lDKQeh4qyDjfA8I1vxVfazMmTF8qKeQCSf5AD869U9q8j8JMdJtdXhaKeSUXnlL5TY5APOa7Tw1e3dySs6zBNpYeaeR9a453uz0KduVHRuCM9K5/xHpMOq6e8EhKNyUcdjWXrEl/HcPIBPKiDcFSQqCPQY71YsL6a9jCPaTQEdQxyPzqelzTyPGLy3e0vJbaXG5Gxmu/+G98WhvLBj80ZEi/yP9K53x7p5tNaMijiZA/49D/Sr3w6trqHxCzTRSRq9qWG5SNwyBkV0wd7M4qitdHp2OKKXtQBWxgVvD2nx2lzqizIMXFz5yn1BUf1zWlNeWNnJMpkVCqZwB29f0qBAfNBBqpdaxAt4bRbJpmRc72GFznsSOTXFUTU2j0qDUoI0tPntb6PKsr8Ag4yCKfdGO3QlVA+lZ+n6tDeSGEW00Min+KMhT9DjBqe8QufmPArJ3WhrY5fVdNTU7qO5dUYxAqqOMhian0eJI/Ed0scYUJbKXA/gZiPl/Jc1S1zxI2hTQww2S3M1zlYsvt2n39uRW14d0ubTtPZrxw99cuZrhx/ePb6AcV0UItu7OXEVEouK3ZpgcUoFApSyBgpYbj0FdWiOKwYPbrQtrDcIN8pRxxwcGnAgcnpWZdXUU+qJZKrBxD5pYccZwBWFdLfqdOGnJOxphY7NP8AW5Hqe9UprkznZGck9T6VAumztMRJIWj6gk1oW9rHCDgVxtnbc4fxBpcd54p0xbi5iggjXO53A3HdyB6npXfcY4rE1HSbbUdStLifpZSeYB/fbsPzwfwFatuxYFWPzZIAI/TPeu2g7xPPxC8AAAAAAA98/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-68.png', linkedinUrl: '/in/melinda-graves-4b5dc7a605', jobTitle: 'Scientific laboratory technician', }, @@ -8685,7 +8685,7 @@ export const peopleDemo = [ city: 'North Christopher', email: 'phillip.johnson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDqQKGZUQuxCqBkkngU8LXG/EPU5LTTrawgYh7tzvA6lB2/EkflSbsNK5n658RPLuprLSolJX5RcuCRn2WuS1LV9SuEH2u6edyMnnjH4cCtbSvCzao4nm/cxnouMk1vS+AY7mVAJ2RAMZI/lWLqK50Roytc4i01S6sCj2t7NBzyEc7Sf5V6BoXjmK6WOLUlWJjhfOHC59x2+vSoH+HNhEmfNmYgYOe9cj4k0KbTUD2ys0a8HnpRGor2QSotK7PZVKugZCGUjIIOQaQiuG+GGqSXenXdlKSTA4dc9g3UfmP1rvCK3OYkArzrx7ER4o02R2xH5Bxnpwxz/MV6Oo4riviDYGZtOulz+7cxtgdjz/SplsVBXZc0FV8kYPPGDXTRswXoCPpXCz/bbOFVtBISVLDyxknArT0C+1Z2jF4zeXINwLrtZfQECuK3U9JPodHcNx0rjvERVYCSM8HNT61qGrvLP9jyIYAdxUbmbHYDvWLI93eI63Ak3qgZwwA600uopPoVvhvJnxPexxHMJtyf/Hhj+deoMK4D4bWaWuoagSpLsgCuOgXOSPryPyr0NhXbF6HnSTTFWs7XLRLuy8uRNyk469D2NaS0SRrLGUbIB7ilJXVhwlyyTMLSDDc2UayAEqKsz+Sl5DGmxSTk84rLgjNnqM0AJwrtj6dRUN7dabczhLllEiZ2nacr+NcVtbHpxaaTReslhk1K8iYqcHI5zVPXTb2djL5SgEqc1RtZtOsroixYF3PIOdxP49aj1kG7nWDJJd1QD3Jp9bCk7I2PBcHl2szGMKwCjI755/wrpWqKysINNt/s9uDtzkljkk1M1dkVZWPNqS5pXQq9KcKYDVPVNa0/RLU3GoXKQp/CDyzH0A6mqIMPxRL9g1GG4UEB0+Yj2OP5UsciXUKMsigsOCK5S11eTxL4g1C+Jb7K4EUEbD7iD+pzmnx2Gp+U4tJ8FH2lD29646ludnoUW1BHRTRx24aQyjKjkmuSfxFDa6rb30gaW2gnV5CvfnHH060l7p+sO6291cKfMP3EPX61Fr+n29loLxuBgAfie360o25kOo3JM9gSVJokljYNG6hlYdCDyDQ1ePeFPiPLo1nFp+oQG4tI/lSRD86D054I/KvSNM8VaJrOFs7+NpD/AMsn+R/yecf/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-69.png', linkedinUrl: '/in/phillip-johnson-1dbd354784', jobTitle: 'Librarian, public', }, @@ -8695,7 +8695,7 @@ export const peopleDemo = [ city: 'Averyfurt', email: 'kristin.garcia@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDs+1FIaZPPFa28lxO4SKJS7sewHWsizM8ReIbPw7YfaLj55X4ihBwXP9B715lN401XUp2Mt4sEXXy4vlCj+f51geI9cn8Qa1PdOzCMnEYP8CDoBUWm6TcX7bIYCY+5bjND0WpUU29DSTxLqNrdNLaX78Z53kg/geK2tD8bay04Mt00w7rIARWSngjVGJbYijsB6VFaafd6NqoSdP3Z4OentU8ya0ZXJJbo9j0fW4NWiIUeXMv3oz/Me1avWvGYNafTb+G6hODHJkqOhU9RXsVtPHdW0VxEwaORQ6n1BppkNWHVxnxNvJLfwssMZIFzOqOR3UAnH6CuzrjfibbtP4ZiKjJW5XnsMgjmgDzTQdElv5RIUPlknk9DXqWkaOllEPlUE9sVytpZtbaRbo0kvyxkbYjtywyTzWr4fvJ2nii3TmN+VWQ7iK56l5anZStHQ7WC3U+ma4zx1o8v2QXUSnC5Bx+lJrsk4mMjTXJiTJCwvtJA+netXTbxXh8uZblo2Qbo5zuOCPWoSsuZFyaejPGknbLqxzXtvgC4e58H2pc8xlox9AeP515X4k0d7PxDMltCwidgyD2Nep/D+zms/CyJOhR2lZsH04xXWmnscUotbnSgVT1nThqui3djkK0sZCsR0bqD+dX8U7Ap2IOL0i2H9mwRzx4mRBuB/vd/1q9p8NrFqis5RNmSM9Se9T3dobac7WLbstk/WsWW7ga4YNazSMAV3BMfka4mnex6cLSSsbRjs7icIhikjkJdXTBwc81oi0tooMqi+5ArEs760jjEcdjLBk5yI+PzFaxZmABNS7rQbRiXGnmbXU1AIHKKIzGRwVzyfw4rpbC2WzsIbdeiLisPRby6v9b1KLyYhY2rhFl53M+ASPwro8V00oNas5K9RNcqH9qSrK6fdMOI/wBRTv7NnAJYquPxrexymPqiL9l8zupx+dYaRRyDY7YGcirevWl5Z695slxIbO5iURRfwK6/e/HofzqjJGy/dOM1x1muc76F1E0okhig2iTcuKiEpclVOQO9VILeaV/mJ21pRW+2NlXjPGayNdzRsbOGythFEMAsXY+rE5JqwRVHwvDf6joUtzIrO0Vw8QyeWC8HHrzmrzq0bFXUqw6gjBr0FqqVnZn/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-70.png', linkedinUrl: '/in/kristin-garcia-667a8d3bf0', jobTitle: 'Maintenance engineer', }, @@ -8705,7 +8705,7 @@ export const peopleDemo = [ city: 'Lake Jeanside', email: 'randy.white@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0Wig0ViagSFBJIAHJJrzfX/ivb2d49ppNulyUJDTyNhCf9kdT9a2PiNqVzZ+H0srNS1xqEotxt64PXH16Vw9v8K9RaMMbqEFh8ylM0nKMdyowlL4TKm+IniK8nZ11Z4uc7IlUAfp0qW3+KniS3kAmuIpwp5Dwrhh9RiuotvhFYCL/AEi6laXH8GABUN38M7KNGWGZl/2jzipdaBaw9Q63w14+0jxGojD/AGW76eTKw+Y/7J711WK+Y9T0u+0DUJYs5C/xr0x617J8NPFkniDTJLK8bdeWaqDJ/wA9EPAJ9+MGtNGroxd07M7ikp1IKQzmdat1u/FOmq65W2gkmX/eYhf5A/nW5CoCAA/rXM+OIrmLyby284sIjFtg++xzkfhVLwpLqrutvfNIFaEyguclfZvQ1zVlrc7cO/dsdpJgA4f8AaxNQkKjaDzXE65Prz6lstzdvHuC/umwCM1p2c2oF/s84lbacZk559j3FYuOlzdPWxxvi5jc3BLJl87TzjitH4PB4/FV8nODaHP4OuM1H43stpt514ZzhsVtfCPTZrfUdTu7pTG0sKLCrnDMuSScdcdK7KUlyI4K0Xzs9ToFFFaGJTu9jzLG4BBTvWW13p1nFc/vYo9o2k9B/wDWq3rJZFjkHoQf51xWozaPdOpnfBxghEJLAdsjrzXJUTc2ejQt7NWOp0yexvgUWaKXABVkIYEfWn3n2a1BKIC3auZ03VLG3XyLbABbKqUKHPrzWpeTdd3XFZSVtDa5iX9rFe3kEkrY8pywzyM47itnwzaPNq9vdMoSWGJxKV5D54/KsRpGN6iiNpcsF2L1JJxXoWmaeLGFi2DNJy5Bz+A9q1oxbkn0RhWqKMGurLdFFFdZ55R1eNn02Uou5kG7Ht3/AErnY7SSa1iNvMIAB91e4rcvvEmk6dMkM12jTOcCKP5m/HHT8a4KLUbu+tZb61dVTzpF8kDhcMcAfhisa0NpHThqjT5TfmVbWLdNKjt15rBvtVwrtnczHjHesG71K8ndo5Q47GrGnWckjBnyQOnvXO0lqdXM2zo/Caq+tWz3LqrtuZQT1OOAPf8Awr0avG/Ekc1vpK3VuxjltZY5UI4PDD/Gu+0Txlpt/aQrd3Udvd4AZZGxuOByD05rpw+sDjxOAAAAAABpM//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-71.png', linkedinUrl: '/in/randy-white-158e05e8b0', jobTitle: 'Financial risk analyst', }, @@ -8715,7 +8715,7 @@ export const peopleDemo = [ city: 'Caitlinmouth', email: 'david.woods@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-72.png', linkedinUrl: '/in/david-woods-46b2d4b34e', jobTitle: 'Emergency planning/management officer', }, @@ -8725,7 +8725,7 @@ export const peopleDemo = [ city: 'Rebeccafurt', email: 'taylor.humphrey@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDaxRilxRUlDZJY4ImlldURRksxwBWNdeJkjhaS2i3IP43OM/QVyfiXxDNqGpm0tcG2hbaM9Hb19/arMPhTVtShSeeNEjAyEyRn8KwqVHeyOmlSVrssL47uJ5xG0XkjtwTmty18Rq2zzQGVv4l4P5Vycnhm9iYt5TKw6MDkCobi48iBVb5JAf3igcZ9aydSV7pmypRtZo9PR45ow8bBlPQijFcHo2uvaXS73zA5AcZ/Iiu9BDKCDkHkEd66YT5kclSnyMZVTVLxNO0y4u35EaEgep6AfnVysbxXbPc+Gb1I/vKocD1wc1b2IW5xvgew/tHWZLyYBhHyi9txJr12KN0jHTHtXjHhmRodOvQLYzMZEUdflznmu48HT3xnFsyyrDICw8zOVI/E1xTjd3O+EtEjrZrceWxcoARzuIFeWeJtJktLx3HzQuSVkU9PbNbHiGC5XUWnEEshB7HORnHfirdvby6jZSw3Nns7b1UAH8uKXLZXLvfQ88RthAB/TFemeFb43+iR7jl4T5Z/pXlF0DaX01u4K4bA9q7n4d3WXvbVzzgOPfHX+dbU9JHNV1jbsdqKGUOhVhlSMEUooAroOU5jwhpi6Xe6nYXiA75AyEjhk5wa7SyW0tbmQBo4wkfA4HWsm8TCrKB8yNnPtVC+vNIlmX7U7+Yq7WCZzj0NclSLUjvovmgdPCLe6yrhGK884INR308FtAwCgcY4rP0u+0YQLBYsqNn7vQ/kaL5PNJLH5R2rJ9jayPP9Z8PtqOoNcpgb/vZHAFP+HsQbW5HUkqkLqSOh5wDVPxjq19bXAsIJdltMuW2r8xHTGfSu18JaLDpelRyq4kknjViwHGMZAH510U03Y5a0kk0bQpcUAYpa6DkGSIJEZD0IxWNFZu85jefyZFOCcda3QOayfEDJGtrgFZXYgMOuAKyqpWub4ebjKxcjtvs0WWmRz/exzVSWc3D+TGd3qax4ftk02x3Ji+tdDYwRxLx19a5Gdt7nBeN9NK6haXLHbBt8tjjODnP+NehaOqDR7NYtxjEK7SwwSMccVMdDh1kmK6iD2g5k3fxEHIArfFo8UqGNUaMLzGVx9MH/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-73.png', linkedinUrl: '/in/taylor-humphrey-7143e1cb93', jobTitle: 'Catering manager', }, @@ -8735,7 +8735,7 @@ export const peopleDemo = [ city: 'Stevenview', email: 'emily.evans@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDlNd8QPdTNDbFgg+XA6t7n2qjo1l5jEsju+c4DAY/E1RjbOQmevJHJb8auWGoLZSFJFZXfge3+Nc9zosWbm3nMzBWLMn3Q3B9cH1qGKaaIhLxmER64H6123hjw212y3LMwRzkZ6ke9dld+CNMnsmQRBSy43ChTuU6djxpJHs50utPV2jU/fxgN7Y7iuu0rV01SEny/LdfvrnoaW++HjWsLrBOxHvzWBoCHStYuNPuG/enkA9CKFO7FOm0rnWkA06MCkFSKpqzE8iMk08nnMRHGvRQcVoeG9NXUdXQMS53c98U/VNEa2thPbmRoipKiRQrH3612/wAPNBSDS1upADcS8/QelZSn7uh1RptTsz0HSoI4rZI4kxsHQVsLnZtLYPpXDahrt1pkxhSxu5Nx2jYuF/76/wDr1gadrXiC61ANFFeQwyk7UlO7AzznI4qErK5q9XY9Muoi8ZBIHpXmmu6Vu8WwyopBjiVmK9/mNavjHUtcsbeC2tI2aSRQzuGxgE461Fo63Daej3dv5U565bduHY57561UVrcyqu0bDxHxUsa1L5dOCYrY5TLt7O01Zf7QCozZ8oxsehAIKexB5960NPP9mhIkGI1+77Vxk9lfW/jCeezeSG1kcCVFbgEqcE+/+NdjZDdbLFI2XQAZPXiuacbaHoQnz6nVW9zb38BjuIVZT6mpEjsLJ1hgiBkl6Y64rnohKpAQnNTXE2lzWzJdaokFyD99JgrL7CiLexTijY1CGCaOCa5iDIBtO4cg54rIvTG0wEahVVcACsq1miNtJbnVftZz+6y5Y4zwSe5q9GCFGeTWkFeRhX0jYYVpQKkKmm4rY5CvcWjq0sK25j3Oru79XPr9KguIntpfMHQ9a9CvdNju4AvAkX7jf0NcvqVmUiZGXDjgisa9NwlfodOHnGUbLczYLwFlG/GeCa0H0/7VGGtnhjYDhiOf0rmpY5IH4BxU0Mt0ThHZfoayW50XsaTWc8LhZ5Uk5yNgxVgCrGlWCXuniTewmDMrsTkZB/lRc2VxaECZMA9GHQ11Rg0r9ziq1eeZBikIp0ZH/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-74.png', linkedinUrl: '/in/emily-evans-df56e8e3d2', jobTitle: 'Engineer, materials', }, @@ -8745,7 +8745,7 @@ export const peopleDemo = [ city: 'West Rachel', email: 'mike.weber@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDWFO4pKzdf1E6VotxdJ/rQNsf+8eB/jWZRR8Q+LbPQW8jYbi8IyIlOAvpuPauMl8ba25LyTrArn5VRB8o7e9P0Pwnda6xvbq6dVlbO4jc7H1ya6hPhZauVb7ZM/rvqHWhF2bNo4epJXSOQsvF+sadMzyXf2lG+YrL83/6q7nR/FVlq7JDtMVwwztJyCfY1DP8AC7TSjASzKa47WfCFxoUiz29yzxRtknHKeh4pKtCTsglh6kVdo9TxS4FZ2hXp1DRra4ZtzlAHPqw4NaVaGQVzfjc40JeODMufyNdL3rH8U232vQJosc5VgfTBzQ3bVgk27IseGVT+zLYdP3YIzXY26ERjjP0rze7gCGFWF0yLH+7jgOM4HP41t+G57y3kjTdcCKUgqszZZfQH0+lee4/aPVjJ/DY6ycsAwAwPeuH8XNs06Z1GcDn6Vb8SS3V1LIpa4aKHllgbDNj09axEtzNBNGgukXyiHjnbcORwR70KKVpBJvWNiz4OTHh5GH3XkdgPTn/61b1Zvhy3+y6DbQnqFyT2yea0zXoJ3Vzy5Jp2YZqOdVeJlZdwIIxT6DyKUldNBCXLJMl0mO2vLONJVG5R1q2xtYdSggV40IPcgEn2rFsiYJ2jVsMGI5/MVI84nk2y2sshHO4IMfnXByu9j1oyTSaNRBay6lPGzxtk8YIOD71W1hbe3s3SMAMwqnDMsMpWK0ljJH3ioI/Si+HnyohPJYD/ABpcrvYJSsncmhCrCqqu0KAMClJp+3Aphr0IRtFI8qpLmm2hcUoWsfU/E2n6aCof7RMP4IzwPqa5G+8Z6rcFhCy20fpGMn8zVpGZ0eqaiRrE0MCEtbIm/B6k5PH0rWsb60u7ceY2T/EM4wa898NX+dZb7XIW+1cF3OTu7c12Z0G3kky+5Q38aEgiuGuuWo7no4dt01Y07rULK0t3ZXAA7Vgf2y1tNbXcylbcyeWd3UBv4qvDw7bwtlXeUj+J2zisfxf5cGnQwjALyZA9hU02nNJFVb8jbOuhu7a6GbeeOUf7DA04144ryxNvikdH9VOK3dO8U6pb4RphMo7SjP69a9Fo8w//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-75.png', linkedinUrl: '/in/mike-weber-d97f9c1f39', jobTitle: 'Health service manager', }, @@ -8755,7 +8755,7 @@ export const peopleDemo = [ city: 'Eileentown', email: 'bonnie.anderson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDiiKTFONAGTWdzQEjaRtq4z71ai08OjNLIECnoep+lVYVvL64EFgilidoLd67e28I3EttGl5diRwP4UxWEqr6HTCjdanLJFYsCgl+f1Of6VHLbhSdjhsdq6uXwL5QMkF0yvnOGXIrn9Ss7qzYiUIJFPUDAcVCqyT3KlRVtjLIpKk3iUZ2kEdc00rXTGV1c5pRs7BTlGcgDORTTTZGKQvjqw2ilPSLHDWSOr8E2KhZbvgktsT2A616DGmFBrzeyu/7L8N2aize4kmDEAdByT1rovDdxcyGNZEljR/mw7Z21xuPU9CMl8J07D5Sc4Fc54hsYbuykGBuxwR2NUfEs9xFKZEglnC/dVWIXrTdOvZr+MwzWTQSIMEj7rDHr3p8ulwclflOGh4Z1Jyyna1SEHoagvHaz1y5jPBD9P5GrTjLEjoa3pPocdVdSPbzT/KEqle+Mim96mjJG7/dP8q1n8LMofEj0XRo4P7Ot4WUERoBgj2q3Jd2dtfxxySpH8pKj1IFYfh+aS4020lZgXaJd+PXFWrrWbCK4+zyWz3EnOdseQPxrhSd7HqKzV0aOm3dpfK210kUk7T1HWpL0xW8ZKgD6Vm2etWV3I0EcEsEoP3WjIGfY9Kmv1Z1+Y8DrQ7rQdkcbqtjHIl5fOFDhQQcdR0x9c4rLdSuMjBKg1b1XXI9Vt4raxQi33ZLt1dgcDj0zz+VQ3JJkA/uqBW1G/MceIaaVioBzViNR36VCBg1MnUCuo5DY0jUjY3kcMrExzAJG391h0FdfDbRXY3lwp6ZFcEIJJfLkUH9xIshI+orrWgm5MDlSRkDtXHVjyyO/DzbiahgjtAWMgOep7msnVrppLC58s5CxMc++KdDZXM7D7RJlfQU+9tAbCaFeN6lePesm9TdnnmiRhLcd9o3AfhVsgsxJ71etdKksLXcybtrsjMDx04qFo8Hpiuui626R/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-76.png', linkedinUrl: '/in/bonnie-anderson-e54636e584', jobTitle: 'Town planner', }, @@ -8765,7 +8765,7 @@ export const peopleDemo = [ city: 'Port Dawn', email: 'tyler.barnett@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-77.png', linkedinUrl: '/in/tyler-barnett-39213ade04', jobTitle: 'Industrial buyer', }, @@ -8775,7 +8775,7 @@ export const peopleDemo = [ city: 'Nathanielburgh', email: 'brenda.brown@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDs802e5htYHnnkWOJBlmY4AorzH4o6jdR3trYpOVgZA5jB6nJ5NYLU3ZV8WfEOW9uPsulO8Vuh+aQcM/8AgK5hrwPZvLJv8zOQSOWP1rNG7euSGHTIFdppHgPVNahjuS4hiP3RIvJHriqbjHcUYylsZVv4l1jTrNLeO/mQA5VVbha77wn45GpMbXVXihuOPLcnasnt9axLv4XaoqOBexMnXATFcLqVteabetbXBGYjsyOM+9JOMthuMo7o+jaSuW8Ca+dc0MLLkz2pETsf4+OGrqaTBDK8T8f3KXHiu7MEgYIFVgezAYIr2tuhGcV4N4t0m403xLMkrNKHfesm3G/PP9acRSOx8DeHLWSBb24iWSVjlCw6V6rZReXEMYwOwrgYlfStHt40tWnZkCqpOEBx1NXvDFxeJNHI1sYkn/hJOV5xyCeK5Xq+ZnckopRR2s2dhzXk3xF0C3likv4gVlX5nA6H3rpvF11diQmOKSWOH7yoT83TsDzWJfbr7Qb7baNbzRxMHQHKsccEU1dNSQSs04sx/hSWXUb1A+5SgJ5I/SvWK8d+HDzW2ugyQyMZ1x8q8KPU+1ewg10Pc4kiNjxWD4g0yHUUi8yBXKndnoRgdq3W6VBMiSQEOGx/s9RUSTeiNISUXdkejyRT2axSqDxyDWg8cMNxBEgRctnjArB01+dyB1GSAr8Ec96m1G/05mSO5V3ljO4eWpJU+ua51e9juS5kmjWCRS39xFIEYZyM81R1qOBbR7aJFHmfLgcdaqaZe6b5kiQNIsrncTKCGb3puotI8uVjklPTbGuT70Wd7ClaKuxNJ0a2tBFLDH5TICqlRgkdwfUVuCoYFVIlCKVXHAIwRUwrqSsrHBKXM7jD0pIxTyOKaGWNSzMAo5JNHUXQx9VlNtqA7Bowc+hyanhijvVVzMBnoe4rPuRNdaxI7tvtXQCEY6dc/rVd7W6tpdsEhUHoe1ctTSbO6j8CNee1islMhlDk/wAR61FpuoQG/aKV9ryL+7yPvev9KpJaTyuDcymQjsOlRPZTSazavGMRoSZD/dHb/CnTfvoVe7gzrD1pRVCG+Z2ZXT7vRvUVcjkEgC5//9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-78.png', linkedinUrl: '/in/brenda-brown-dbcd1ad947', jobTitle: 'Secretary, company', }, @@ -8785,7 +8785,7 @@ export const peopleDemo = [ city: 'Lake Wendymouth', email: 'matthew.mills@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0ukpM1i+KdZm0PQpryCF5ZBwNoyF9z7UxE2s+ItO0S0mnurmMNEpPl7huJ9MV5s/xnuWZ1XTIQn8LrIcj8+v6V5pe6ne6ze7p2eZyeAAMn8hzWla+ENXu4w32dYgeRuODUSmluXGDlsjsYvjHfLtMtlCwXrhiN3+FdPpfxW0a8vvKmEsMBHErrwD7gHpXmh+HWoiPInjzj7vNc/qGkX2kSeVdJgdm7Uo1IvRMqVKS1aPqeKaK4jWSGRJEYAhlbIIPen1458JdagW+azub+QMUKxRSNhM5zx78V7HVmQzNeZ/F3XLm0sbbSrcqq3OXlfPO0Hp9K9KzXm3xijQ6XpkmPm88rk8Dp3NDGjkvBWkRRo124Dyu2FJHQV6RDEQoO0celcCbNbSwto5JLjbsBC2xxuOMnmtTQZpo5Y0R7ry3PCztlhXDNc3vHo03ypRsdawZUJwAPeud8QWVveWEqSRq/wApI9Qfas7Ww1zKZJTdSxgk+XFJt6dvrSWIC4MS3SLgboZm3flUqNlcpyu7WPNUD2epxhJGTDgBgMEc19TWMfkWEEW9n2xqNzdTx1r5r1iAHxQbdRhXmUAHjGSP8a+mR8oA9Biu+LurnmzVnYbXOeOtKOr+E7qJUDyRYmTjn5Tk4/DNdFmobxDJYzoFZi0bDavU8dqbEtzgtKgingUN1A4zSteafYawkM0gT5SVwveqNo89p5kTIVljzlG6gjtVbzzeTZmt53ZfRQB+vWvPS1seqtVobVhNp97O+2QEMxxlSMHPvV28tre2gJUAtjqK5wXbW7ny4JlB6hk3D8xWjcymWAZb5sAkZ6UmrB6mBp+gRa74qEkw+RZUBx1IAy39K9l6CuI8F2wklluEA2QyMrnHVyOg9cA12tdtFPl1PPrtc2g2nU2lzitTE4bxjZSWF5/aKD9xMQHI/hbHf64rIQ2twgR5myfmypxius8aXH/EkEGwETShcntjmvMDZ3ttceXDIdj/AHea4qijzaHdScuTU603FtDGVik5A5J5OKoSXytiKI72b07CsxNKvm5mYEHrzWxa6YllAWI+cis3ZGquzv8Aw/YxWOi26RA5kHmuT3ZuTWlXFeHLC9uryGWOVltIcmU7iMkdFrt/LdQMjORmu//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-79.png', linkedinUrl: '/in/matthew-mills-0b84ace87f', jobTitle: 'Nutritional therapist', }, @@ -8795,7 +8795,7 @@ export const peopleDemo = [ city: 'Jesseport', email: 'bradley.henderson@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-80.png', linkedinUrl: '/in/bradley-henderson-8d96b99f04', jobTitle: "Politician's assistant", }, @@ -8805,7 +8805,7 @@ export const peopleDemo = [ city: 'New Joe', email: 'christopher.wilson@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-81.png', linkedinUrl: '/in/christopher-wilson-04a5992bf8', jobTitle: 'Historic buildings inspector/conservation officer', }, @@ -8815,7 +8815,7 @@ export const peopleDemo = [ city: 'Williambury', email: 'janet.cooper@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-82.png', linkedinUrl: '/in/janet-cooper-5b3b8ebf22', jobTitle: 'Mental health nurse', }, @@ -8825,7 +8825,7 @@ export const peopleDemo = [ city: 'Wilsonton', email: 'ashlee.barajas@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-83.png', linkedinUrl: '/in/ashlee-barajas-7db08816c2', jobTitle: 'Designer, television/film set', }, @@ -8835,7 +8835,7 @@ export const peopleDemo = [ city: 'Halefort', email: 'amanda.valenzuela@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1BjgGvOPFXjgL9psbJgCvyM/Xn2rt9bdk0O+ZXCN5D7WJxg4NfN99dC7kUb2aU/KQvGTUzb2Lgluy015I87yOrvu+91yfyqq1ySxjB3bsFPMHQDtXSeHPBl3ezkXDyRRADBXvXat4D0z7L5LDcxH3j1rF1EjoVGTPKP7WnjjjKSHg7QP7tegeCfF88U4tZ33wuAFyckNn+VW2+HWmrAARucd81yOpaO3hfW7O9TLW/mDr7HNEaib0FKk0rs9+hmWeJZFzgjvUoNYuha9Za5bCWy37APm3LjB9PetgGulHK1Y5nxpCs+iuokKyKCygd+K8N0y2e71fPlkuhzgfWvoHW7KK802cvD5siRsUGepxXmmmaJDZ+J1aAZV1zIccK2OgrCrKzOmjDmVzs9NUrbIAMHHNXG3ZrndVuLi2jaOK3nf5Scq5UcDt71m6PeauLqKKWaQxyKG2SHcUB7E+tcttLnanrY7QhiCAccVxfji38/RpEK5YOu3jvkD+tWfE2palZzLDa+ZyAW2dee1QJby3VuI7mOZsTx7iZM7/AJh0NOC1TIqPRo3fAWn32nWQFxAViljVlfjj2rtgeKrQOnlqkasqqoABGMCpc13pWR5sndidRXK3tkmn3WEwN7lxx1zXVrVHVYhJZO2ASnI9qirBSRpRqOErdzNzHcwFWUH6jiqXlW8EwijQF+pIHSnxgqnHSqVzc6eCQ93smBydjfNx2OO1cB6asX723hkuwJ1HzAFSR39KnsYYZLyOIRjZH8/tkdP1rDivLaYlDd+bL2yf5Cul0KEiCSZhyxAH0Fa0o3mjKvJRgzVFO6CgUYwM13nlj4U82ZE9TzWTrT3VtObZlKoykhgvDD6+vtXWwWiRD5Bz3J60tzbpcRGOZA6HqpFZzTkrIuDUXdnmdzIYB1IQ9SO1Vmh+0J8ska4HDEV1WpaC6oxtgZY/7v8AEP8AGuQnsfIlKuJIufukEVxShKL1PSp1E9UI0DQqRvWQ9RtFdf4fu4tR0S3uLUHZtwy91PfP41yyolvCX6nt711PgvTLjTNMlFwu2SaVpvLI+4pPT+v41rQb5jDE6x1NDPODwfQ0ueKv3EHmqy4w2Plb3rJVyRzXAAAHWjiP/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-84.png', linkedinUrl: '/in/amanda-valenzuela-30589a563a', jobTitle: 'Engineer, automotive', }, @@ -8845,7 +8845,7 @@ export const peopleDemo = [ city: 'West Ianstad', email: 'charles.evans@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-85.png', linkedinUrl: '/in/charles-evans-afcfd375f0', jobTitle: 'Financial planner', }, @@ -8855,7 +8855,7 @@ export const peopleDemo = [ city: 'Myersberg', email: 'patricia.martinez@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-86.png', linkedinUrl: '/in/patricia-martinez-a6795704a8', jobTitle: 'Chartered public finance accountant', }, @@ -8865,7 +8865,7 @@ export const peopleDemo = [ city: 'East Nicholas', email: 'andrea.byrd@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDn7m4S1haWQ8DoB1J9KwZL+5upTuwg7JnGB7+lLr14RdbF6RjH0J5J/lWZBcFRncVyclu5+lck3fQ6IRtqbFwqQWO+U8t2A5P0HWsCSOZ2Ep3qeiknmui0947mdUKMRn6muhXwl/aMquV8mIYO0Dms07G3Jc5GzuLp7cuHVpU4I71tabqP26NkcBZk+8B3962dR8IwQWrC0yHI6+prhLSd9O1lVnyGB2NnuD3q4S1IqQsjrzRRRitjnOD1O7FzeyY5UuTj1ptrDJeTpFEMsTjj+laOl6Fa6loc12WkW4AZhIG+VcdiO9a/grSgWlll+8p2rnsaydjoUXdHXeGdChsrVd4DSnqcdPpXWDakYA4rjL3UH08iI280hbIUjOP/ANdVtEvb25uC6/aEjPJEhPA/Emotpc3ur2OxuF3qa8s8eWiRhLhVw5fb8v511vii5vLZ3jhaQIkYc+X95vYVyN6kmq2FsrQGMpdIpJ/iHf61UVrcio9GjXtN5soPM+/5a7vripgKdgDgdKBWpyHPeDJUjmutIuCP3knyA9yOCP5H8K7IW/2K5JRdoYgkD6V5TJcu11LcRkpIH3Bl4Oc9a6vwlrF9qLXZvrp52Uqo3Y+UY9qzkup0wnsmekwmC+h8uWNT9aJI7a0xFEihzycDFUbTcoGD9KS+v9ISIw30qs56jGTWaOjRk17HFJdwmQqyyRYI9xWPqyW/7uKJNoRw3HqKggvdOa9KW87O4GArdVFQXcu66C7slRz+NXFe8ZVXaDA0lJnNKK2OI89MLNdOijIPtW/4NtZYNXubeaNk82EPhhjHOB/WoNOiDaj8y8HBGK9M/smOOCC7UjcFALY6jtWau4uxvdKSuVre48hhFKcEHGat3Fj9sjBWRV9Diq9xAJCcj8aqbLmP5YpW2+lZm6lYhubdNN3TSyrgdwBVK8s5rS/Z5VO2Rcq2OD/nithdIfUtsM7FlZlLn/ZBzj8ela3imx8zRZpkHzQFZBj0zg/oa6KcLxcjmxFS8kjkFp4FVoZiUU1ZWRW9qOYAAEzKzP/Z', + 'https://twentyhq.github.io/placeholder-images/people/image-87.png', linkedinUrl: '/in/andrea-byrd-6adea7eafa', jobTitle: 'Ecologist', }, @@ -8875,7 +8875,7 @@ export const peopleDemo = [ city: 'Walkerfurt', email: 'martin.hebert@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDoKcKTFBIVSScAdTXMbFTVNXsdGs2ur6dYox0HVmPoB3rhbv4qMXIsdOUJ2e4c5P4L/jWHfQX/AI2164uQ2y1RvLh3chVHTA9+p+ta1r8Nnwoe6BU/eAWm5Qjuyo0py1SEj+KV+HUzabbNH32OwP4da7fRfEen67DvtJcSAfNE3DLXL3Xw3sDF+7eZGxyQcj8q5HUdA1Hw3L9qs53whzvjJVl96FOEtEOVGpFXaPa6KwfCOttruhRzykfaYz5cwHqO/wCIreoIFrC8aXk9h4Vu5bc4kbEe4fwhjgmt4Vz/AI5i3+E7n1V0I/76FC3AyfBlmkWk24xyRu5967eJSF6fkK88a3MUUYma6KpGPKitjgnA5JNbXh6a4tpYwZbrynwdkzZIrncb+8ehCVrRsdNLuCk8Ae9crr6JJZy4AJ2tx7Ypmv8AmX00r77l4oskxxPgnHYetZlnao7boBdwuq5kimbcCpH86SirXCU3e1ir8OLlo9bvbNCDDJD5h/3lIA/Q16XXmXgOAxeNL9RgIsbgfiwwK9PNdLPPtYQVneILUXmmGFmUKT1bp04rQBpLiHz4CmATwRn1qXsXBpSTZl6WsVzaxZAJ2gg0t5Na2+owRyMIx/ex3rM0iaWzM9sw/fW5ZQPp0qCVJ7m68ydZXdeVK4Cj6Vio62Z3xlde7ua2mvbz3MwV9wYnaSMd6dqUSQwsVAVsGseOGWG43QLNEx5JOCtT63esbb5sBtnzUOISlbdalTwvbxtcGdWBeS4ZiO+B/wDqrtGrB8MWe3Tra56AxnauOeT1rdY1rFaHFWkm1YaKlWoWZI0LuwVQMkk4ArOtPEml3179ktLgzygEnYh2gDvnpVmJjeMA+mXAvoyRHcLsYr/C4HB/EfyqCw1OLULFYZA27bywOKPEmrrf6uuklP3ETbZM/wATFSf0rFi8PXcMjQ28zYPQZ6iomlezOik5Wujfu9XtrG1McQ2kdWY5zXNXWqS6okVtDlt/LkDhR61PN4Y1CSQLPKSp6KT1/Cti30aHTbRs4MhGWf0FS3GK0NLSm9djV8M69Be2KWrIsMkA8tRuyHCgcj/Ct881xvhq0XfJcKoC5bYMdcnk/wAq61JCCI+M9z6Dua3Ubo45AAAAAk0mf//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-88.png', linkedinUrl: '/in/martin-hebert-0fdd8cb20a', jobTitle: 'Statistician', }, @@ -8885,7 +8885,7 @@ export const peopleDemo = [ city: 'Michaelmouth', email: 'joyce.mathis@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwCrmoZrkREIo3SHt6VM2UjZh1A4z61iteJDcLFGzMxOZWXqx/wrGpPl0RtThfVmpIszRZeRFA9WArEv9UitgQh3Nn7wP+Fad5C1xaRpEFSQjHAG4f4f55rFuNLisBuuZpZXIz5ZJYfyrDm11N7diS08RvM2FlVyvVGGCB7Vu2moRX0e5D868Op6g1xb2E+oSD7JC0YB4bbtAqzpc0ltrUVvMSsqnaxH8VbRkZSgdljPNKBin7RnjpRitjEzNauGit1hjP7yTv6D1rnluSjeVZfOerPjnPrnvWv4nRy9vtyVbKkVS0GyNzrdrYJFnc2ZW9AOTXJU1kzqpr3UbHh3R9XupROjuF7u4zn6Z4rpJPDxL+ZcnzX9Sa09TvLjTbVorO1kkwvVeFWud0u/1i7u0hndh5ozhudg9D6GpceptHR2NFtPSGA7EGK878U2/wBlvILmM7WL4yPXqK67xLqd9Y3X2S3jZiMZIPTNcl4haS7trIMGDGfYxY557HPpTitRVGrNHT2VwbiygmP3nQE/WpweKr2kH2e1ihHOxQM1ZxXWjhZi+JS6RW8gUlUbJrodCsBHfQajDFtibhOnKFRg/nUNzBHd25R1yByPrWT4f1rUrLXYNGcq9qWJAZfmQYyQp9K56sXe51UZrl5T1QzpcRFMDd3B6Gqsa2ttcNGEXzWXLEDoKfFGPvDuM1l39zo4imW9kV5CfnVckjHQcdKzTZukjM1aKP8Atxt20h19jgiua8SwRzi2gjUgmccj6Grr3VlPek285dscEnvSDbLegMMlVLD2PT/GnFNysKrZQZKnCKD1AwaeKNlOCV1nnjlDbDg4PaqOj2Ny3i+1SWAl9jTNIMbdmCOO+c10tnpQaZftLbI84OOatTBLZ4L+KMFrYlGA6mM9R+GAfwrOorq5dJ2di9I5tiFLYDcAmq88DG0ZEdAMdTVma4trmAMSrRNyDXP6tHLCyiCciE89a5bndFmZdweTMASrPnr60gtjHJ5h+8V+asvV0aexmQux3DAbPI9DUOga5JdW8MF4d0h+USepHY1tRtqzDESbsjdBqRaBH71Ik5D/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-89.png', linkedinUrl: '/in/joyce-mathis-4aefab1ba3', jobTitle: 'Multimedia specialist', }, @@ -8895,7 +8895,7 @@ export const peopleDemo = [ city: 'Lake Matthewmouth', email: 'charles.ray@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-90.png', linkedinUrl: '/in/charles-ray-d81d2e4cf7', jobTitle: 'Communications engineer', }, @@ -8905,7 +8905,7 @@ export const peopleDemo = [ city: 'Brittanyhaven', email: 'amanda.vega@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-91.png', linkedinUrl: '/in/amanda-vega-bc1c79f067', jobTitle: 'Occupational therapist', }, @@ -8915,7 +8915,7 @@ export const peopleDemo = [ city: 'Richardchester', email: 'kathryn.freeman@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1OilNY3iTX4fD2ltcuA8rfLFHnG5vf0A70m7K7BK7sjRu722sYTNczJFGO7HFYbeONEWUIbjqep/w615TcX2s+Mb0rFOxGSN/YfT+6v6mtXT/AIVoGWW4v5S567BgZrCVY6I0G0emW/ijRro4hvUbBwTzitaORJUDxurIeQynINePXnw/vtLd7nSNQYSDnZIMg+2ab4Z8WXWh6m0N60ixhgLm3f8Ag/21pxrXYpUGkey0opsbpLGskbBkYBlYdCD3pwrc5wrwPx9rcuv+J2tLdiURjFHzwqg4J/E17zM2yCRh/ChP6V8yaGzXviKLOS0s2CfbNZ1NjWlues+FdGh0vTI4Yx83V2PUn1rrEA8sYYE1wGqajcWyGG3tpZ3YcKCQowO5pvhaTUzdoZ4ZYYZOSGJ4/PvXDyu3Mz0U18J6BIAVOT+Fee+P9EWS0/tGAbbiHhsfxoeoqfxjdahBO32WOaWJeSI8/wBKpyXs+peHb63mimjnihJMcnPIGeD3BFOKtaQp2aaOs+GGsNqXhn7LKxaWyfy8nup5X+o/Cu2rx34MXhOpajanJDQq4/A4/rXsVd8djzJbjZE8yNk/vAj868D0nw8+keIopNr+Wpk+8QTxlc+2a9+rhvEGmrbajPcAACTBHPbPT8yayrtpXRvhknJp7lqwnhniACLnHcVBq2qW2mzQb1kfLAbY0LEkn26Cq9krIMr9RUN74gFu4WCxlupB12pwD/X8K4oq7seiX9P1e01HUJ41DL04dDg8Z4J6ip76O2VJAUAYoVzisi01+O5cpcafJaO2ApZMA1cn3TMufpTas7CZm/C3Rv7OutTmaM8qoR/9kknH6CvS6yfD9qLbTvlUKHbI9x2P861q9CndxTZ5VWym0grg/ixazS+EVuYA3mW1wj7lOCozjP0ziu8rO1i90u2tPI1WWNYbnMXlsCTJnqAByatkLfQ4WzvSYoyzAZUHP1FX1tbW6B3TBVPb0rJntQYP3AOxcqgPoOn6Vj/a5ovkKng8c15ttdD1kzsPssFsreXKHU9c9aYtjca1i1tpFSMuvnyZ5EffGO5xj8a5+zE98rEsQg6813HhIwIt1bqw85drFf8AZ5AP55rSlFOdmZ15NQbR0FtbxWttHbwIEiiUIijsB/MP/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-92.png', linkedinUrl: '/in/kathryn-freeman-5cbbc22506', jobTitle: 'Wellsite geologist', }, @@ -8925,7 +8925,7 @@ export const peopleDemo = [ city: 'South Robinberg', email: 'ryan.chambers@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-93.png', linkedinUrl: '/in/ryan-chambers-2ce1a65a0c', jobTitle: 'Agricultural consultant', }, @@ -8935,7 +8935,7 @@ export const peopleDemo = [ city: 'Boydburgh', email: 'dustin.carr@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1TFJS9aTpQBV1LUbXSdPmvryTZBEMsQMn0AA9a8e1/wCLeo3RePTFWyg3HEg+aRl9+w/Ct/4t6ncCGx0e3U/6U2446sc4AH41zNt8LpZRHJPd55BdAKznUUdzWFKU9jir7WZ9RkNze3ktxL28x9xAqOO+5GyTp07Y+ld1cfCoIpNvdNu9GWuevfA2o2e9yofYM8DNQqsH1NHQqLoa/h74maxo08SXcjXtjna0bnLKP9luv4GvbtJ1ay1rT476wnWWBx1HUH0I7GvlO58yOVlPNdl8NPE0uj+JLeCSRhaXjiKVT0yeFb8Dj8Ca1TMGj6HoNFJVEnmWvxzXnxTginG6O2tvNgGOOeP5k110IYKM1z/j+3nj1WyvrXzllFs8YaEDJO9cDmqnhm91m6ieK9JDeWXV24Yc4wR2NcVde9c9HDP3LHVTbwCBWTeEhTxk1xuo3XiU35UXFw0IOMRADPNbFg2oSExT+c6jvIBn8COorFx0vc3UtbWPNvEqRx6lMzR4bJyMYrE07e97brCpDGVdvrnNd74/01THbzooMhba2Oprn9A0S9h1XTr10wiXcfyOvJG8A+3euylNOKOCrTfO7H0vRilxgUda3OYytX8siFJACG3Dn8KyAbW3jmKPEnO3HArX12LOnmYZzCd3Hp0NefXT6fqExeSUBcjdHgnJHr2JrirJ856WGa9npudbbpaXTOmI2dOvQ0ly0NqpwBxWHYanY24EEPlg542HB/I1ZvG3sQSSawemh06GHqttHqNzbCXOxZd5A74Fa+n6eJtUsLYDcvm+dtY8oq4J/XaPxrMkd0n3pjcvIzyK0/hrBe38t/4g1HzN8p+z2gZdqiIHJKj3OOfatqMHJryOavUUIvuz0LtRSZxSZruPNGTRCeCSJujqVP41wLadcBjCLj7PJEdrhf4q9AJPYZrk/GliI/sl4srQzyyeUxXkEYOMj1zxWFaN1ddDpw03GVu5nSRR2kWX8t2P8RHNZl1qgUH5wWbsKxr+HVTceV5oKn+IcGp9L0YxTCe5fcV6CuN23ud95N7Fsgw6fPdXBwdpJB7Cu88J3Oo3OhwTanHHFJIoaKKNNmxOwI9aoaVoH20x3F7GBaqQyRMP9YR0JHp/Ouill23CYBPcgeldOHi1q+px4mUXAAAABouh/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-94.png', linkedinUrl: '/in/dustin-carr-aea35977e8', jobTitle: 'Ergonomist', }, @@ -8945,7 +8945,7 @@ export const peopleDemo = [ city: 'Joannport', email: 'eugene.sims@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-95.png', linkedinUrl: '/in/eugene-sims-35b50bccf6', jobTitle: 'Banker', }, @@ -8955,7 +8955,7 @@ export const peopleDemo = [ city: 'Darrenmouth', email: 'gwendolyn.glover@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1E0lFMlkEUTOewoAbNcxW4G9vmPRRyTVGXWTGciJce55rPu5jGHkdsyN1P9KyJbsuTkjFZObNFE3j4ojjbbNbMPdHz/OtKy1Wz1DiCYF8ZKNww/CvPrl94IY8ms+K9e3mUrKVkRsq3pSVR9QcEevA4NPB3VR028XUNPgul/5aLkj0Pf8AWri8GtkzMiqvekeRz03CrOOKx/FLNF4avpY5likSMsjt2NJ7DWrOf1XVIRK0UAM0nQhTwPqaxZZbyMgtDGuf9qs3UYETToEeCSeTychQ2ADjJJPrVDw9M93Gy7ZY9o3bZGJArld2rnXGKTsbU91Ki7pI0A/3sVmvewvcKkilN/AY9D+NY2tSm5mbfG8qxqSFDYBxRYiK5t2h8h4crjYTkfUUW0uDSbsj2DwU5XSZoCSRFL8uT0BGa6TfXA/C++kuNEuYLlibuKX5hjqvRT+hrus10x2OWS1Hg1U1WzW/0q4tWGd6HH1HIqyKWm1dWEnZ3POpIFa32uRuUbWHaqEH2ZBIsCoAuck8ZOK2PEFoba/lSP5UYbxXJTT2IgwsTuVyu9UPHrzXHZ3segmmk0RxxxNPskC/MTtPY1PLBDCQEAz7VlRzWkcpEUckZZsjeD1rVsoWu76CHr5jhfzNDTvYLqx2Xw+057bTrm7kHM8m1D6qM/1J/KuyqCytIrGzjtYF2xRjCgnP86sV1xVlY4Jy5pXClFVZrjbNsU4VRlvc1JprvdKZJAAjMVjHrjvTuSYXi2O3kto/3qC6XomeWQ9eK4a5iVrcp5wjA6Y610erceJNRVxl5JAFJ7IqLgfmSfxrCvbWKVJPmKv1UiuScryO6mmoowpY0jGBLu9Sau6Bcxprdk8zhIVlBZm6AetVJdPCW4kklLMzYAqCT9yrEdQKV9bjeqse6RSRzJvikSRP7ysCKkrzbwzBJZIb9CUlmwoA6MB3I712trqpd2ScLkY5WuqMrnEHFKNnY//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-96.png', linkedinUrl: '/in/gwendolyn-glover-c850972ca2', jobTitle: 'Geochemist', }, @@ -8965,7 +8965,7 @@ export const peopleDemo = [ city: 'Woodberg', email: 'kevin.oconnell@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDrKUUlKzBEZ2OFUEn6VianOeKfGdn4ZVYjE1xeOu5YVOAB6se1eeXHxE8R30ryQypbRj7scaDA/E8mszXLqfxJ4oup7aIku2EXqdo4GasxeFdZgh4ttwcYxupOcY7sqNOUtUiKLxv4kim+0LqMzbW+ZHwR9MV2ml/FWGeSJL+z8sdJJYjnbx1xXLxeAtZkgMriOLJxszk1m6t4XvdGTzeNmPmINJVYPS5TozSu0e66dqVnq9mt1YzrNCTjcvY+hB6VORXingHWW03xRbweeyW12fLkUn5S3Y4+vevbSKszGgVS1x2i8P6jIn3ltpCP++TWgBSS28dzBJBKu6ORSjA9wRg0gPJ/A9lEfMn25csAT+H/ANevSreAHBaIDFeb6XZ3FnYzRwNJkXciI0ffBwCc/Suq8OahqztHBdgkSZIaQYYfUVw1Y3k2epRlaKjY6aRTtIWMY9elcx4it0lsJVKZypyDTdcu9XeVzE0wijGSsOMsM9B6mmWwuJ1Ky+cML8yy4/mKz5bamt7+6eZaZDHB4p01YF3ZuY8An1YZFfQTCvH9F0QN42SZwRb212HG0ZySeB9K9jcV6MZKSPInBxepGtPFMWpBTJOWs7K3t727s3+Yec0gz/tHP9a0oI4v7TWNSi7Ez2FVNbgNvqEN1FkGXhvcj/61Zj3On3FxuuCROAVBQHI9siuCcWptHr0ZKUE0dBapBPIysELdRnnNN1Tyba2YKACRxWfYXOmQZitgsbE/dKlT+tGqtmNyzHj1rNq2hoV9Dso2uEZEwZJd0jZ+9j/9Vdg1Z2hWiw6ZBLt+eRdxJ9Cc1ovXfRg4x1PKxFRTlZdCNelOFNXpTLi7t7OEzXM8cMQ6vIwArUwI9TsTf2LRIQso+aMnswrlbFhKpEkxjdeHx1BFM1v4hWq289tpSvLIUIFwflVeOoHU/pXOad5l7ptrKJmRnQB3B7+prmxCWjO3CSeqO0leK1gLmcP7msa6uZL4gKSYxyT60LpKRojT3Mk8h6KTxVi6aKwsZHchQB1rkb10O7zZW8EeMrq81GbS9TkjKK5it32hSCP4T68V6C1eFRnLGaEeWS5cEdc5613GmfEMIBDqluxIAHnxc59yv+FemnpqNJa3R//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-97.png', linkedinUrl: '/in/kevin-oconnell-366df31264', jobTitle: 'Editor, commissioning', }, @@ -8975,7 +8975,7 @@ export const peopleDemo = [ city: 'Port Ginatown', email: 'mark.williams@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-98.png', linkedinUrl: '/in/mark-williams-34678a412b', jobTitle: 'Education administrator', }, @@ -8985,7 +8985,7 @@ export const peopleDemo = [ city: 'West Heatherbury', email: 'jack.reed@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-99.png', linkedinUrl: '/in/jack-reed-624aef385a', jobTitle: 'Corporate treasurer', }, @@ -8995,7 +8995,7 @@ export const peopleDemo = [ city: 'West Dannyside', email: 'anthony.green@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwC9jimkVJimlea4jqMjW9Yh0axMz4aVuIo84LH/AArzS+1TUtVmMlxLuUHIXoo+grv73Ro9Z8S5uV3wW0agJ6seeatTeArHb5waQZ52BuBWkZxiDpykro8kkcLkZyfrSQXNxbHzImdCe6kivUX8L6VEhb7Ire7msrUNKs/s7xpCiAjjAqvbJieHa1uTeFfHBupotP1Qje+Fjn6ZPo3+Nd95fHSvCLi1Ns+0A5BznpXuOiTteaBYXL8vJAhb645pTilqiYt7MMU3FSY4pMVkWZ9qhTVrptudzL/6CK3JWfYE5Oe1cvrcV0P3tu0wD5B8s4wQP1qh4e1HU7tJoZ/NBjjMiu/UY7H3oceptCWyNzUYpuVyAPT1rlb4sshQ5rNvtQ1i9nlcvOYouvl9+ccVJbyS/cl8xiem7n9afJbUHUvoYWrBt+Dx7+te0+H7cweGNMTGCLZDj6jNeV3tpHNeASEiLZuY/wBK9H8FXF1dWV4txM0sMUirCzHOBt5A9ulac10kYODV5FzHFJin9qSsxjESKRnhlICkZ56VGFtUsLprVVEYUorDA3HucVDfYXBJIBBBxWRdy6de2cflTPAgADNErdB9BgmklqdEX7qILO3jlmktplCtt3YODmoLy1t7XiP7x61nQSw2c5WKZy5OAXJz+tPuJHMp3Gm1qK42ZBKrRK20twTjPHevQfC1kunaHHFtKlyXIPX2/QCuN8PKJtctUIDAvk/hz/SvRmPzYqo9zKo+hmDpQacBUNxdQWqb55kjX1Y4pWuRcju7c3Fs8YO1iPlPoaydtw9n5f277I8fBUKOfai78VWMKnyN07dtowPzNWDpw1nwz/adwuyZbny8xEjaCoIB9a0dKSjzNWHCqr8qOXvEMDZe5SZvXH61neYz5YnOe9aeoeHbtIjNb3IkGeVK/MKy/skrusWSWOBhRyfaszR3L+kyuL6MxEq65YMOowM5rvPDGs/25o8dyxX7QnyTBezev49a5S/07/hGvDdxcS/8fs0flgf3Ae319a4nSdZvtJk82zuHiY9cHhvqO9dEKV4nNOp72gAAAAAAAAaH/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-100.png', linkedinUrl: '/in/anthony-green-26a1d57a62', jobTitle: 'Land', }, @@ -9005,7 +9005,7 @@ export const peopleDemo = [ city: 'Cameronton', email: 'louis.johnson@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-1.png', linkedinUrl: '/in/louis-johnson-dec8e3a5a2', jobTitle: 'Pathologist', }, @@ -9015,7 +9015,7 @@ export const peopleDemo = [ city: 'South Scott', email: 'fernando.stephens@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-2.png', linkedinUrl: '/in/fernando-stephens-d825082895', jobTitle: 'Sports development officer', }, @@ -9025,7 +9025,7 @@ export const peopleDemo = [ city: 'Sampsonville', email: 'tammy.soto@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-3.png', linkedinUrl: '/in/tammy-soto-dc33b99453', jobTitle: 'Consulting civil engineer', }, @@ -9035,7 +9035,7 @@ export const peopleDemo = [ city: 'Mcdonaldside', email: 'anthony.clay@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDoSKSnGkNIZDPPFawPNM4SNBlmPYVzk/jjTUyIEkk9zhQawPFfiOXUbl9Js0O1ZNrAdZCKq2vgDV7mFWkKRgnO0tkisZ1LG0KTfQ3IPHMzzfNawbD90Bzk10NlrUVxHmdfJbODzkfnXDP4R1qyO0bWi7qDmo4xPp2+3njKsQWUgcHHb61n7WXRmnsV1R6iMEAg5B9KXFcN4a8SbL1LGZy8Mpwhzyjf4Gu7xXRGXMrnNKPK7BUNxIIbaWXONiM2foM1NVPVP+QTeZ6eS+fyqmJHCeCtLFxetqUwzKeQG7E85/L+depQoVQcivLINtno8bEzSK7kgQ8E+g/IV0fhm4uGuFgJnETLvXeeRx3rgmm9T0qbSVjsZEGCSR+Ncr4h01Lu1YptEo5BFZOtyXMk3nMlzPEGOEhYjGDjtU9tceWCiwTpg4KOxb8RU8uly3K7seeuXsdRWRT+9iYHHrivabWdbq0hnT7siBx+IrxrxAgGuXCRqy7hlVYYOetereGCzeF9NLDB8hc12Utjz6u5q1FcQie2lhbpIhU/iKlorUyOc0C2jFjFC67XQY57Grz6hZ6TqDLIrljGSpVSRUP3NRlCEY3dqrXPiRI7sW8OnTXR5y4U7QfrivOs7tHrRtZNF/SZrfUN7oZUD/NtdSpB7jnvVm7EVrESFBbsc5rOstfS5YwvYzW0m7GGjO3PqDip78ZU7j0FJqxWhy91py32ri4ljU/L+7crnD89RXbaWrLpVqHjEbCMAqowBWHpYguruS3V8zR4Zxj7qnp+ddOBxgV1UE92cOJcdEtxtFLxRxXQcpl6urQxi6UcJw+PT1qC3gtbiIN55QHoVOKm8RahBZacsUnMly4hjUdyT1+grj5kurd/3ZbaemDXJWiua53Yeb5TsXEFpDnz9wHc1kXd952I423E9cdqyYYLy5H70kr1wTWnb2nlpux0rB6HRds2NA01bWKa6JJlumDsT2AGAP6/jWziuI8G61ONT1HSL2QkJOxt2Y9jzt/Xiu3Jr0IfCjy535nc/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-4.png', linkedinUrl: '/in/anthony-clay-d0ffc44035', jobTitle: 'Site engineer', }, @@ -9045,7 +9045,7 @@ export const peopleDemo = [ city: 'South Deanbury', email: 'jennifer.haney@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1EMQO1VlaSSRmOAvYUecRxiguzdOKGybCvI2celcrrfjaz0uRoLcie5HUA/Kp9zT/ABtrEujeH5JYXCyyny1b0964XQvBF/q8C32o3PlpL8yR45x6ms51OU2hT5tS5N4w1i5fdJNsTP3YTio9Q8VaysIhaUrx/CcN+Jrp7bwPYW0PV2lA4bPSuS1rSm0q7JIZom67uaj2qbNXRaRBY+JNU0+586KZtzdVkO4H2Nem+FfF9vrqmCRRDeoMmPPDD1WvI5ol2bo2BU9QKfaPLaTxzwyGOeFgyMDzirUrGbhc9v59BSMcCnnHao5FUqRk1bMTzrx2H1LW9L07nynmVSB3yea7y3QRxqoGABgD0rk/FQNpdWtytq1w6s5UKcNnaRwas+Fb2+u1lhuYJI9mcF23ZA9D3FclRO9zvotcp1Y+orH17TI760ZcYYjg4rndTuL/AE+7aRILq7A5KmUgYJ4Cgda3dPvpL6IBre4hYcGOTkD6H0rO1lc23djyDUTLpt+0bnG04NSJc7kByMjkEdxXV/EHQo3szfRriUcMfUV5rbTvGm1s7QevpW8Zc0bnLOPLKx9NKp29aay461MFGKayeldNjkM6aOJ7hfMQHaMjPanWyRRCQxqoLcYHWodTbyDGxONxwayLibTfO8u6uSpByyBiOa463xnoYZXgdCsdvcH5lUlTg5FSSPHCmFAAHTFZUF5YSBVs7lGc9t2Sfr3qSQSPlSPxrCTsdKijF8QH+0LSS2A4auGm0eGG1mdwpEYO9hxyOea9A1ApbQlgu5hzgd68t8X+MGv9+k2kBhiU4lZsbmHXAx09/WqpXloiKjjFXZ9C+WKMKvepDio2K16R5ByHi+4CQ7M4Hc/5+lQaXs1iyiuwdjMMMD6g4NSeL7NpkDA8dcevNZcUd5paXbRqq28YBVSeC2O3fJ4rkqRbk2juoVFBI6uO1jt487UDf3u9V57tI1OWGazree5uY9srhH7qvb0qzDpm0l5GLH3rkk9TsTvqZ17uMEk7jgA4FeESOZ9UupTzukb+dfQ2qQA2DxqPmYbRXi9/4YvrbU5mit2eNmJBUZx9a1oSSbuYV4uSVj//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-5.png', linkedinUrl: '/in/jennifer-haney-fe08f83150', jobTitle: 'Engineer, broadcasting (operations)', }, @@ -9055,7 +9055,7 @@ export const peopleDemo = [ city: 'West Jillian', email: 'kevin.harris@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1CkpaKAK97e22nWcl3eTJDBGMu7ngV5vqPxmsoZHSw0yWZRwJJn2Z/wCAgE1U1kXfjjXpg9w0Ok2jFIY16O3TcfU9/biqsnw4QnMNySD2YYrJ1UnY3jQlJXEh+NV8Jcz6VavHnojsp/M5/lXf+F/HOk+KV8u3cwXYGTbyEbj7qe4rgpPhvbMuZLp8j0FUbzweNPiW40yZ4ruE70dTgkihVUN4eSPccUYrjvAHi2XxDZSWt9gahbAb26eYvTOPX1rsq1OcKrakzJpV46HDLA5H12mrVVNTkij0y4ErhA8bICe5IOBSY0rs4LwxbpFpkQHuTXRjOBjkVyLSXNnpdssAmDNEGxEmWz1PWpvDd3qE05S8eYqQWUyAZHscVxNdT04y2idHNkLg96xtQIWNiPSsbWLnUmu3NvLP5afwxHkgelS2l1cXKqkyyjAyRKmGH9DRbS4OV9Cv4FR4vHqeVxG0Uoce2M/zxXr9eU+HJ4tJ8UXN9Or+QiMnyDOCxH6da9WyCAR0NddN3R59SLTuFZmvRLJpwdhkROHxj2P+NadR3EXn27x8fMMDPrTkrxaFTlyyTOWsxHLbqDt6Y6VG0ltHdFA8aYUnGcZqKWOWyuponIymWODx61kz3Njdspk2llGMhCePqBXEk72PUTVk0XbD7NcSuA0b5JwQQc81JeQpCDtA6dqw4rm2tZSttxk9GQqTWhczPIoJ6lc/Sm0K6sVLS1NzcNBHktcvsbj7vQA5/A16gi7I1QHO0AZ+lc54Z0XyI4b+SQMXj3Im37pPc/h/OulxXTSjZXZwV6ilZLoJRRVPU9Vs9HsZLu8mSNFBIBYAuQOgHc1qYGB4p/c3qyjjfGNxx7kVnlBPCoSYRHA6DtWF4Zv77XhqGo6hMZDcXBEaZ4jQcBQO1T3Gn6imTZOrL/cbt9K46jXOz0qV1BF+VFhXLSqzdPrWXNcl8xo24nqR2FVhZ6tJJ5dwFTPUg5NXUtBb2/A6d6l2K1Z6Vp2z+zLXy2VlESgFTkdKsV4X4H1u68MeL57G7uiumzSkOrt8i5yQ/t2r3NWDqGUgqRkEHgjqf//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-6.png', linkedinUrl: '/in/kevin-harris-5184b24b32', jobTitle: 'Presenter, broadcasting', }, @@ -9065,7 +9065,7 @@ export const peopleDemo = [ city: 'Jeffreyland', email: 'allison.crawford@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-7.png', linkedinUrl: '/in/allison-crawford-67b761b025', jobTitle: 'Homeopath', }, @@ -9075,7 +9075,7 @@ export const peopleDemo = [ city: 'South Rebeccaburgh', email: 'stacey.garcia@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-8.png', linkedinUrl: '/in/stacey-garcia-9250901bae', jobTitle: 'Bonds trader', }, @@ -9085,7 +9085,7 @@ export const peopleDemo = [ city: 'Johnport', email: 'stacey.romero@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-9.png', linkedinUrl: '/in/stacey-romero-7728909deb', jobTitle: 'Civil Service fast streamer', }, @@ -9095,7 +9095,7 @@ export const peopleDemo = [ city: 'Danielfort', email: 'joseph.bell@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDc20bam21leIdWXRNHlu8BpMhI1PQsen+P4UgKut+J9N0EiO5dnnK7hDGMtj1PYVyl38RbkuWtrGOKLjaZssW/LArnLbRtV8S3Ml5CjzSOx3ys3Bb2rWb4c+I/JANtCxH+1zUOpFaXNVSk1dI07L4jHK/bbKMxnq0Lcj8D1/Oux0jV7LWrXz7NyQOGVlwVPvXmh+G2vbGJiVMc4Bqjpt1q3hTUkBVkb+JG6OO4ojUi9ExSpyirtHs5Wm7KW1njvLSK5iOY5VDKfrUm2tDMn21w/wASomk0qyQNgeeTj1wtd2BxXK+O7FrvTLZkYboZwzDPO0jbnHpkipbshxTbsjW8FWcVpoNqiKASu4nHrXZ9VGMHjtXnGrRXVvDDbW4ufLSP5fs/ByB6/wAhUvhSfVzdxwzSXBik+bMxyRn19D7V59vtHqLS0TurlcREcDIrzTxxZWs1izzRKSCCGxgj8aseKbzWJLqaGFrjyIOS0HU+wHfrWQYLi7tLi2me4ZTEdyz8lTjgg00rNSCTunE3fBTmTw1EmMLE7Rr9B/8ArrodtYfglceGoUbAlBLOvcZPGfwroCtegnoeW1Z6jwOKo6pYLdQPx87LszjOBnP9K0QKHUlCFxnHeoqR5o2Loz5JpsdY+Vc2oWQAccGkN1p9rfRQLJHH8wG5iBuPU4HfFULbeo2qfu5GPcVXnu7e4iEcun3EirkBxDn6kH/CvPinservsWre4srjVbmIyxurOQMEHB96r64ltbW0iRRgFxgmsiG6srGdkt7KeEuRkvCcn6nmpr9nu50iU/MWAwfU02newN2Wpc8PWi29vIw4ztTH+7/+utYim2sH2e3WPjI649akIrvpx5YpHlVZc020PHSlYhVLHoBmmg8HAyB3pYR5hG8YHcVTaISOXt9YF3brqEaOlvcZYL1I5xz+VbANle2oEk5CEdAcVFFp0VpbNp4UDyiQox1UkkGsW+02QKTCxVx3U4/SvNk/edz1YfCrFu9NlYxs0UjHHTcc0zw86317JMTnylyM/wB4/wD1q5x4LlpNkzZPerfh+aWz8QylBuiFt8y5xzu4rWlbnRnWb5Gd/TTVS31O3uOA+1v7rcGr7jzT/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-10.png', linkedinUrl: '/in/joseph-bell-0f0d64c86b', jobTitle: 'Historic buildings inspector/conservation officer', }, @@ -9105,7 +9105,7 @@ export const peopleDemo = [ city: 'Jerrybury', email: 'nicholas.edwards@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0I1HNNFbQvNPIscSDczscAD3qQ1578U71l0+1sFfAmJdkPRsdM/SkMqaz8V44554NKtlkVcrHO5++fUDsPrXn+qeK9X1icPeXMkijomcKMewrpfC/gQ6lapeXEmyJidgUYz71t3XwxsWj2LcuG65A61m6iRqqMmrnnNh4l1LTr9GtbuSMDjKsen06V7F4Q8bQ667Wl3Ii3YPybeBIP6H2rjpfhisZyLkgDsBXP6no194YuYby2c7d4AkTqG7ZFCqRbsgdKSV2fQBFAFZ3h/U/7Z0Cy1DGGmjBcejDg/qDWjWhkPrzD4m25udYsowePJ5HtuNeniuE8Zwrf6vaGAbmgIhmHTliCv8AWpk7IuEXJ6GjokXkaXbW65CovHtWoQCOH3exNctqN7LHGEiFxGvICxKM8ep6Vn6RqF+9zGsss7I7cLLjP0rktfU7k7aHayhdmC2M9q47xZGn9lTK67gCD9OetR6zqGoefKsEkqJE3zLEBu9/502KSW5R45xNKrJhklABGaaVtRSafunTfDwt/wAIvsJyEncKfUHB/rXVVyPw9YRaQ9m+fODeafQKflA+vy115rri7o4JJp6gK5vWrEjUkmQYjZhK/uwGBXSVV1G1N1akK2GXkcZz7VNSPMjSlPlkYcSLMhAOwjqarwx20V8AXHysCWbHJ9qesgEZ2g55zWRcz2NwwDj50OQwQkqfXI6VyLU7tC+Y4H1WQq4+c8EetOvIo4+Dy396sW2mtbedmibLuRkuCCfpmtS5czFMdT2oaB2NbwnZLbwTzc7iQg57df610NV9PtDZWaQlgzDkkDHNWa7IK0bHn1Jc0m0JSinJG8hwik1YisHcZdgARwBVmZwl8fJuJ41OBuIz+NQeXut9glCYHGKuS2LW0f2aQlpIhsYnqSO9Y0yTJIcHp0FcF1c9JXSRNJGETDOkhq5owWfVbdZMEKc89yBxWKqyyOSx2g9fU1p6bbtNq+mxxZBE+84/uhTn+lVG3MiZ3cWd3SVIYJATgZzXYeef/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-11.png', linkedinUrl: '/in/nicholas-edwards-208dfccc7e', jobTitle: 'Community development worker', }, @@ -9115,7 +9115,7 @@ export const peopleDemo = [ city: 'North Ashleyburgh', email: 'brian.freeman@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDpcCkIp5FNNSUZusaxZ6HYtdXb4HREHVz6CuNfxtqmoM62kC28bD5GA3P+v+FdBdaG/iPxIyOwEFsoUEjO09Tgev8AhXQWvw6txIshuCyjnBFQ562NY09LnmsXifXbKTM8jshJyXUECuq0HxTBqhEFxtiuScLj7r/T0PtXYX3gvTbmEJIh+UYyK4LX/BosI5Z9PUeYh3dece1SplOnodhijbmqGh3jaho1tcOQZCu1yP7w4NaWK1MB2KTbzT8UhJVSwXcQMgetALUr+HsLdagCOftB5rrkYbMq+fYVwsjXljHc3NlES8s24qRkjKrx+dJoGr6/f38MV5arCrM3bB445+tc73udiVlZnbXDhV5f8K5DxJOUtZCvXHJHpWZquv8AiC3v3htrTzY0YKSFyT24qSSa71C3nFzEUYIwwR3x+oqfMryDwmmNCXHeVzkd+a3MVi+HPMisbS3UKYTAXLD+9nP9f0rdxXTF3RyTi4vUXFGOacBSgVRmJp86QXlxby4+chx9CP8A61alvFEL5BEqjClmIGPpXJz39mniWO1WdTciIGSMdVGeP61S1fX/ALVMY7KZLUxsVM0km0t7Aen1rmaadjuhJSVzqrSOGWaUSqu9TnJHWszxHdR2tjN5YG7accVg6FrEVkXjlkWdjIcTpLuJyehFO1ub7ZqVvaq/3plUjPXJ5/SklrYcmkrmxpMBithkg4UDjpnAzWhSJGsahUACjoBTq6Yqyscc5c0riXNzbWUBmup44Yx1Z2wK5m9+IGkw7kst93KB1A2oPxP9BXnd5cz37s9zcvKfV2JrFDNHITGD8pP4juK05TK50WnzXt542F8khM7wvIy/3yDnb+ROK7lLuabRhLYQxSvnJR8fNk815hY6k2m6nb3cfJjbcPcdx+IruZEjvYjqWi3Zi835mUDIB75HY1hWVpXOqhLTTc0rqeaDSnlnhiWdhtEYI4/LpXE6/d3baUNTRijC7TyWHG45zn6cVq21lc3lwUvrh5Ih95du0N9ay/GeowzGHTrcqVtzvfb0U9hUQ1loVVldNs9L0XxNputQxrFcoLooC8LHawOOcDuPpWwelfNcsjrPHKrsrg8EHBGOhr0vwv8AERikdprHzADaLkdf+BDv9RXSAAANHJc//9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-12.png', linkedinUrl: '/in/brian-freeman-f01b205c86', jobTitle: 'Social researcher', }, @@ -9125,7 +9125,7 @@ export const peopleDemo = [ city: 'Alvaradoberg', email: 'christine.johnson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDvpZUhheWVwkaKWZj0AHU14d4y8a3XiC/a3s3eLTUOFXJHmf7RH9K7T4q6zNp+j29hCQPtjEOc87Rjj9a8aBZH3uT6jNZtmkV1L9tEZH+ZgPc1FcWrCUiNlIBz8p60WdvLdsEijBLdEUZJ+tdBp/gDWLohxBHCPVjyalyS3LUXLZHOQX5Tarnbt6DFei+DPGj6fJHY3bKbOQ8MeDGf8KztR+Hl+reaCgOOi1ys8FxpepiC4yMHvQpJ7A4NLU+kEdZUDowZSMginisfw00b6JbvC5eN13Ak569f1rXrRGR458XJk/4SCCLcWdYBx2Xk8V5/bwSXdysMY3O5wK9U+IXhWS78SxagCWiuY/LIHVXVePwNcv4V0MR+KSrNvEIJzjjPSs5SSuawg2kzsPBvhCLSk8+4fzbh+uOi+wrvYlwBhcY9q5e7vZ9PUJDbzSFum0hRn3JqDR9W1g3UIuN3lTfMFcglOehPaufV6s61Ze6jt9gkX7orzX4oaLbLpiX6rtmSQAH1z2rovFOq6rpzxx2CEs2NxGM8+lc74rN1f+D7j7SkqPDMhLO+9WOeoPpzVR3TIns0Uvhlf6g14LLzZBbgbwjfdx3/AKV6zXJeC9PgOmWd+FxIIAnHc9ya63NdMdjjluUtWtI72zw4O6JvMQjqGH+cVx1ha2sUVtc2jbkww5+8MnJB967w9K8pu9Lm0T4iW3kNIbOZWJUngbge34Dms6sbq5rRnbQ9EtpYriLa6KeOhFQ3SQxOiRxjefmwoximWgC8joah1C80liEu5huBBKqTu4+lcyO1JGzLBDJKolVWJUEZwaztd06PVNL/ALPTCh3QnjjAYH+lNtLzS5crbTBpOANzHd+tPlbdf2y5OQ27H6f1q4q8rGdR8sWaFrbR2kXlxKFX0FWAeKSius4BetY2raNFdTJfnImgHyn1HpW0SEXJrHnmu52dJWCruI2KMce571FSSS1LpxcpaFDzGt/lJwOxqVbcXOCZEHocc1YkgVkG9cr3qGLR2MnyTkJ2rkR3p2JkthAnMiOT0IFXreOGQLOm1yRjeKgitFi+UZPbJ70yGI22oZjO1Z1LMnbeMc/iD+la0pLm1MKyclc1O9FRpLv4PDelPAABXUcZ/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-13.png', linkedinUrl: '/in/christine-johnson-20bfd043a5', jobTitle: 'Systems analyst', }, @@ -9135,7 +9135,7 @@ export const peopleDemo = [ city: 'East Anthonychester', email: 'christine.brown@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDWupY7eCSaRgsaKWY+1ef3ms3+qXBMcnkQ5+VR1A9/etnxndOIILUPtifLyHPXHQVxf29BOsW4JEOqqeT9TXLJ3djpgrK5sI0EUTl9RjWQ9wCTn3NZAjuJZJbiNlkVOGk9BWnpfh+98VTGWItDaKcIgYjiu3g+HMUWmyW7SsGf7xB60k0i+Vs4aKb/AELO5Vc9wDz/AI1b0HXHgu/sl1OzQMMIZP4W9AfSrtz4J1TT45Ft7slB91CM1xd9Jc21z5VwqK46nb1+lEXroKUbLU9OkYHoeKSNvmqC1eOWygeLJjaMFST1GKlQc1qYnI+Nr121y5gkykcACKPXjOf1rB0LTX1PU4oWJIc/MPau68X+GrvVfEMs7xs0TxRpblMcnnIb/Peofh7o7x6vetOuGiUKv1NZyla5tCLdn0PSdA0y303T44baPAA5rZPI9K43VtQuLAmIWt5IrgkGN9q8D19aoeHL7V7i6XzJLsQvg7Z2DbR9exrO2lzfrY7W5h3A9M+9eXfEPSYF083qxhZ0cDcO4JrpPGGpanZymK0E2EAZjDjcfYZrltZaXUfCV4ZEuUMRXcJn3ZO4cg00tUyZ7NDPCCz/ANiMJQdgkIjz2Hf9a3gMGodLO/R7RtoB8pQQPXHNWM81sjkZ0Go3UMFhLPMdsUSlmb+6Mcn8KqWdpFprRvbhSroCWU5Dd8/rVlkWeF4pFDI6lWB7g1w/hpdU03xNc6ddyTNZqjiFXJKjDDG38CKzqRvqb0alvdZ6hHcR3UWx41P16UyRrW1IjGxONzMSABVW1+XpyO1V9T1XRUTyr1fOYHJRYi/P8qyjdnVbsXLgwTamyl0dXQH1wax9dtoLyxksFUIjkbsccAgmobLU9Ilu5Fs96y8f6xSCfzqWdmZyxPXrVJe9Yip7sXcoJbpBEsUYwqjA5qs77ZMVffJrJvTsJNdFjhOtTHFSSwxyoowN2eDV7/hHw9pJBNM4Z8fPGdpXHYH3oNkLYhFTaEGAOvFZTqdEbU6et2zHSc20nlyMVAPWrb28F3EMzhAPunHIp97apOpOMcYzWHLaXMDY3kL2rC9jrTLEtrFasWEvmMf4j1qBJ450LJIr84OD0PpSx27BS8jFj2zVrSdMt57y4nMQBaMJIw43HORn3GOvvVxnZ3M6sXJblFiKy9TTKk+1ddc+HCwDW02P9mT/ABrE1LRL5Yz+5LqP4k5rpTicWj//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-14.png', linkedinUrl: '/in/christine-brown-cf7634fc0b', jobTitle: 'Museum/gallery exhibitions officer', }, @@ -9145,7 +9145,7 @@ export const peopleDemo = [ city: 'Port Brian', email: 'grant.brown@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDapRSVy3jjxE+i6YLe2yLm5BVXI4Re5+tQUYfjLx1Klz/Z2jTYCH99cJ1J/uqf5muIudQv9Rfzbu8mm9A8hI/WmadptzqNwI7dXdvYcV1kfw/1SSAHdDHn+Hk0nOK3LjTlLVI5vTfEOpaNPut52C94nOVNdXpPxMuftarqcafZmOC0a8pUj/Dh1tAGu1Mvf5a47V9EutJkKzqNvQFeQaFOL0Q5UpxV2j3W2uob22juLeRZIpBuVlPBFSYBri/hrqUVzoT2O/8AfW7k7D/dPQj8c12uKZmLivOPijGWudLGTgh/oORXpArlfG1j9tGljbkJcjcfY0m7ajjFydkP8IaXDY6TDiMeY4DMSOa6pcjqtcdqLXdoAIjOVwWQQqOMD1P8qtaDqmrzSRx3UgKNhssoDAehx3rjtf3j1ItL3Torg/Ifl4+lcR4qt45dPlLKGwCSKu+IdW1EvIlo7iOLO8xqGY/TNY8RuLwukksrqqZdJlGeR2IppW94JST92xR+FsJ/tjUHU/IkIH1yf/rV6livPPhtb/ZtQ1dSjckKrdsA9P1FeiV2XueW01uItVNSiEtvygYqdwz2xz/SrYpJIxKu0kge1KcbxsVSlyzTZXg8ue3QEAkjuKhdYkulii27gcE9OaWCMxqcHpnj6VmXk9u8qh4ZXdckMsZ4+h/wriS6HrpprQktY421KeKUKDk4PY0apHBb27BAqkjsKzYp4VumWBJEdjn51P8AOp9QzKmD97A49zTatoJuy1LHhSCOK0ldVAcn5sd85NdDVeys47G3EMf1JPc1YrshGyseTUlzSbQBTjgE/QVKIXETSlSEVSx45OBmt2KFOQFGO3FNiQMoDepBHsadyVE4SG9eVDPIuzfyQO1WUNvPHtdsq36VI+nNp97NZzL+7zmNv7ydj/SqNzpTgl4ZGUe3I/KvPu1L3j1o2suXYbdi3gjJjIGOlY9xqUsEkc8cSylWB2t0Jq+NNZ5MzSM49SMCq01s11fxW0K/QU1LXQGrrU6q2me5top9m1ZEDjn1qcKwHKmrcdqsUMcQ4VFCj8BVpbcNge1dykzyAAAAPKcUf//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-15.png', linkedinUrl: '/in/grant-brown-b0072f7d7c', jobTitle: 'Financial trader', }, @@ -9155,7 +9155,7 @@ export const peopleDemo = [ city: 'Thomasmouth', email: 'megan.robinson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDN1XUk02yaZxuYnaijua4C5vZ7olndmOfzrb8VTeddxwZOyJdzfU1hSrHEQSd2PQ1hJ6m8VoW/LENn5gQySdclwpH0rKAL73XIf0Pp7Vt2cMmpypb2cEZIGfm5P19q2j8P9TmRWaSFWP8ADz0qeZLcvkctUcxYupjkGSHGecdKu6XqUtpdhlztJ2sufvCtSfwVqFgHuF2OQOVWuUaRoLouQVYHlcUKSb0BxcVqeorIJEDA9RmjisjQ9TTUbQHI81OGArUzitkYM43xDmLV5C2Dv+63YD6VTsLaO7kjgUFyx6k8D8K6TW9En1C/LRKDlAMZ69f/AK1ReDtOLapL5qY8oDAI79qwm7XOmnFux1Xh3w7baWPNXLyv1Y11BUhRkVzWoTXVuhjgSZiQSu0gcgZ61T0u+1syRieVgkgBKSKNyDPf0NYcraudSaT5TqpVyDx271534t022hjeeNQkrMBkfyrovEV9qUJkitSwKKCdmNxz2Ga5TU7eWTT28xpGcTKrFn3Bm7EfjVQjqmTUejQvh2ymtonkldQHHCqP1rfBFUbESraIs6gSAYOKsoea61see9y6JlinWVgNoyCfQGrLQrb3UdxGqDegBKdGA/8A11mEk8HpVTSLGaw1Cdmld4JVHlgsSFxnjmsq0L+8b0KlvdZ3KeVcxASKD3wailt4LcDaoDt2AqG3yAMHI7Ul5PYyRfv7gI3Th8H6cVyrsd1kJc2ySaj+8UFXjB59RWTq8Ns8ccCoNiuHI+lSLd2y3OUu/PbG0ZbkVVuW3yMe1a01eaRlXdoMqHjgUqdaQ9aVetdh5po2dnJdXKRohbkbvYVe1eGS31VrQxERbg6Oem09APpzXXw2MNrGEhRVHsOtR6hYrqECqcCaPlGP8qmpFyi0jSlJRkmzjxcm0cRSNgdm7VNLapcpnKA44bFT3VttcrInzLwyms2dIV3CFpV/2V6VwLRnop22Ks9slkxkLrxxnFXr3SntrdZQSwx8/sf8KofYZ9QuIbVCWZzkn+6B3rtpbcSWkkbc/KVPua6aKumzlxE7tJnAOpHI5X1p4Qg4YEEdjVyW3Ec4H8Eg/Wug0eCK+sXguY1kMRwCRzt7VtBt7nPOAAAACKWx/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-16.png', linkedinUrl: '/in/megan-robinson-ee228aab40', jobTitle: 'Cartographer', }, @@ -9165,7 +9165,7 @@ export const peopleDemo = [ city: 'South Nathan', email: 'ronald.smith@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDDjJ71Q1vWRpcCxxEG5kHy99o9cVrLFg9K8+uRJqmsTt1Jl2D6A1xwjd6nVJ2WhFJdXmqSxtPMzsM43Hr/AEFSSXEqfu1haMA7eegPtXodh8PLO4ghMk8ivtG7b0robf4a6eYwsk0kqkdH7VarR2QfV5bs8dhvTEqJI3yv0I4weufzrpdG16KVEtLmTEjf6pm6H2zXd33wv0qaFlDyKeq89K4rxF4HfSYVmtJd4jOCrdh6ilKcZaDVKcVzGmy80ijmnWrfaLSGXGNygkehqcRVkMsCEGvPtGkMutogGXMpyMe9ekJuwdgBfHyg9Ce1YOj6RHb+LruTYq5jMuByFLHkCmpWTKUHKzPQdPA8pR1xwa34ABENpzXl+o3GpWtw6o14BglFgUdB7nvVzw9rOu/aYoLlZXWXBVpFAKj3x3rNRsrnTza8p6NIPk5yK47xe2zSLhsAgJk/hVPxZrOsWk721osu5VDM0QBOPQZ6msq3GoahY3UNzJclWhbeJ1AwSvGMU7dRSl9kr6OpOmQlhgnJ/A1o7cVWs8RWduiqQBEo5+lTNITVPVnK1bQlRyrAjqDmiVRb6rFcL0miYk/8CBpoHNNnXYYZT0yUJ9Mj/EUmi4Ttoddam3v4gJo14GMmmXD2cFysMZRNpBJJA79qydOmbGA+SBkDPWqd68GosqXNvKShOCsDH8QcVMVfQ679jqrlrR9TZZDG6uB3BxUeoCC3gaONQAw7d65m1a006dn/AHjSsoXdJGwz+JFaOoz7oQc84GBTa1sJuy1Mi5UJdSKAAqttGPQcVGFB7UjlixJJJJySafH0qzibvqTheaz7/VbRLyPSX3/abhdybRwAPU/hU97qUNn8oHmSeg6D6muZtpFn8RQ3lx9/5lDdlzWns3ytkKa5kjag1BreUwXB2SKevZhXToYry3Aa5KZAwV6iuf1PTXuFWaEDzF6g96zYG1CFgkYbk4APasFZnXrFnYSiCztnAuWlODy5zWTHO12/mZ/doMKPU+tUvsV/dyCO6f5SclV7/WqVxcTWPiOaJSPJNuhC9hyRVwXNKyM6sny3ZsSEZpY8ZFZ8d6srYYbT9circZ3cg5FW4NbowUk9j//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-17.png', linkedinUrl: '/in/ronald-smith-9a58c743fc', jobTitle: 'Engineer, aeronautical', }, @@ -9175,7 +9175,7 @@ export const peopleDemo = [ city: 'Lake Nicolefurt', email: 'tonya.chandler@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDKAyadimKwNPGD3qShy1VuNXsbQkSTAsOqoNxFc94h1yRZjYWbHI4ldf5Z7VTTRtQvIUjt4nYsMkIOtS5WKjG51Nt4k0q5LBbnay9nGK0EuIZ13RSo49jmuLPgDXUAkECqRzgyDNQpHfaVPmUGO4i/h7OPQ0udPYp05LdHdseKjP1qpZalFf2qTxAkHqPQ+lTGX/ZqjMQCq2p3RsdPmnUAsq/Ln1q1isjxK2NHdezMoP0zQwRU8K+G21ktdSN95/vNzz1JxXrumaXDYW6xxxcKPvHqa4zQFgstCike3aZpgWSPJACjnPHfFdLoV21vskAljimwfLdycfgen0rlkr6noU7JWNqSIbCTGAPU15/400Zby1kntz+9X5uP1FdNrVyt0rzPDJMkQJ8sMR09h1NZCmG/s3EVmbWVF3MoztZSP5/ypJW1Kk76M888KTSLdT2rnjG7HoQa6sjiuT0MsPE0qN1CsM+1dcfSupbHnPcYCRVbUrE6nAttu27pFyfbNTeYPWnecFIYHkHNUwW52Hh+1VbGG0KjdCNh74Iq9dRx2+owiRHdMHJTsar6DNHc+Y8MgyT1HrimS3GpC7fy4PlH8ec5rj62PUhZqyLWlqkzSBkeNs/KJByOelN1WFYLaQYCtg8gVFbTXxuwJbfCE8yFsU/X2SCwnlmf5Y0yzfhk0PewS0OAXw6NPn/tUyHfcuwCDoATVvPFT3GoW2pRwvZgi3C5UsuCfwqua6YXtqedVceb3SnTT6VIUOauado95qkpS1iLBfvOeFX6mrMyxoWotZTNHg7X9Oxrs7C7inQESKB3z1rFufDT6NbWkjkPJKTvfHCkYwo/XmrsOlxPMrkEK45x2Nc1WykdtBvlNG7uYk6OpI6EVzPiiR77SZrcHaso2ZPfNdINKt43BUZ9SapXWnT6jfxW9rEWKnPTIX3PtWa3NJapnCWdubO1SENu2jrU289677UvA4mWN4ZUikVcSBU+Vj6gdq5XUPDeo6fueWAtCP8AlqnK/wB51z//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-18.png', linkedinUrl: '/in/tonya-chandler-8cba0ccb14', jobTitle: 'Surveyor, building', }, @@ -9185,7 +9185,7 @@ export const peopleDemo = [ city: 'West John', email: 'jose.jacobs@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDssUYpabNKkELyyNtRFLMfQCkMp6rq9lotkbq+mEcY4A6lj6AdzXn1/wDEzULiYjS7JI4gesi72P8AQVbtNKm8Z6vJqmqs/wBhjcpa24OBj1rrYPBWlQISID83XmsZVknZG8aLauzz21+J+q213/xMLeKWE/whNhH0Neg6D4ksPENuz2rESIBvibqv+IqlfeBtHkRiLfn1zXJX2kyeHZ01LSC0bwn94mchlojWTdglQaVz1LFGKpaNqSavpUF6qhS4+ZM52sOoq/itjASsnxMzJ4dvNo5ZQv5kCtesvxEN2hXKBgJGX5AT1I5OPwBpN2Q0rsi8PxpDp9vEo4C5roWdQoAfPbrXnWpO5tYI4vtSqI+Fi+ViQOai8NXmovepBLJdGFuR53J9hXFbS5331seg3LDyyC2DiuO1plSKQYyNpz71i+IrnUZr2aNJrryYz0hHPHaq1lPN5m2Y3LKVGVm5NNR6icuh1PgEn7DeKDlPNDL+I/8ArV1uK4rwFPHbrc20rbHnmPkoepCg5/z7V25FdcXdHFJNMaKparZreWmD99CSh64JBH9auihhuUj1okrpoIS5ZJmPbW4miwWxx3AIzUMEun218BLLFHsJ2EkAk45I/lTnEkMkke4AgknFZN2/221CzaZJ5QyFkYouB6jJzzXEk72PQjZ6oIpLW51KYRTRukjHkYPPvTb23igLADJ9aybf/QZX+zafIgYjlSHB/EGrl27yHGck9vf0pta2B+Zb8L2Ik1RJnXiENIh92yD/ADrtTVHStMXTYNu8u7AbjjH4Vfrrpx5VqcNWfNLQaBSgUClyBySBVmZheIIjEqXEedx+VlHcVRkvNOksws5aT5c4zjB96teIIZTq2mTgnySksbD/AGjtI/kaxNV0Y3q+ZG+yReo6ZFcdW3OdlJvkI7m+sIUIhYr25PSsj+1RCDdqheO3PmkdN23nH6VUewkhmKPlvrVu4hRNNlh25Z0K49SeP60tEyndo9P0++h1PT4L2A/u5kDDPUZ7VYrjdBuX0SxjttpkhSNQRnkEDGRXUQ6hbXGNkgBPZuK7E7kAAAAAcLR//9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-19.png', linkedinUrl: '/in/jose-jacobs-e5dd5c613f', jobTitle: 'Environmental consultant', }, @@ -9195,7 +9195,7 @@ export const peopleDemo = [ city: 'Port Charlesfurt', email: 'william.johnson@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-20.png', linkedinUrl: '/in/william-johnson-fffd051063', jobTitle: 'Oceanographer', }, @@ -9205,7 +9205,7 @@ export const peopleDemo = [ city: 'East Thomas', email: 'jason.mitchell@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1EsfSjJ70h60uaYCiuW1n4i+HNEuJLaa7ea4jOGjt0L4Ppnpn8ap+ONZvmMfhzRSV1C7TdNMDjyIumc+p6Vxll8Jr4t+8vIdhHJwSaiU0tzSNOUldHX2Pxa8M3kojka6tSTjM0XH5gmuztby3vYFuLWeOaFuVeNgwNeSXfwelC5gvl3DkblP86p2cfiT4c3K3O5bjT5HAnjU8H/A+hpKpFjdGS1Pbs0oqhpmpW+radDfWrEwzLldwwR6g++auqRWhkIwIoAOQKcTTWO1CSwUAZyegpAeceHJGvtW1XUpuZp7llB9FXhR9AK7612iMFTk15ZZ+baaWmZpkxM+4wKGZyW4rY8P3l6b+GPzbx0kJIW4A3Dj2rjlq2z0YaRUT0CRhtIJArlvFKRvo1ypUMChyMViavcal9qMqz3bxBiAlswzgHGDmrEF1NLmKQ3EiEFSsqjcPxHWpt1KfYT4WXck2n6jasRshnDoD1AYc/qK9CH4V5t8MYGtb3UxKBGZ22xKx5bYTuI+ma9J2n3rsi7o86aaeo4qM8VHc24ubSWBiQsqFCR7jFTHk+1B9jVErQ4DRreOMPbOOY3ZefY1qwTWVlq6LPPGh2koCeT61VvIDZ6/OrPkSMJFOMcH/AOuDWLf6zptzeLHdnDDKoojyfrmuJxfNY9SElKN0dLZvZ31xI1tPFJGWJ+Q5Gc81JeiGKNgFAIHWsHS9ds4i0UCBo2kA/wBWVKn69DVjWZiInCnqMZ/pUtO9im0WfCVoHMd0R3kkU45wxNdh+NUdJsRYWEUWfmCjdxjnHSr+M12U48qPOqz55XRJj3qNhXI3XjOdsraWyIx4BkO4/wCArCvtf1SRCsl7KCRyE+UfpWljIk8T+I1l8QTWlvCCtjEpkmBySWJ4A9Bj+dV4bm4u7BJ9Pa3MuMbJOhFUNLjQajJuH/HxGFz7qSf6mob3RrzT7ozafN5StyVIyv8A9auSq7TdzvoXUE0dLcXUlppmbloWncYKoeB61kLrCLPFfXAdrK3mRnx/EdwAA9cE/pVKz0O/1CUPfXLMnUqvAP1rV1XTYZbKDTY1ADyITjsqsGP8sfjURtzIqbbi2z01WDorKcgjIPqKd2rmtO8QRQLFaXMbKFG0SryOPX0roUmjlQPG6sp6FTXdax5x/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-21.png', linkedinUrl: '/in/jason-mitchell-d3f1d47944', jobTitle: 'Hydrographic surveyor', }, @@ -9215,7 +9215,7 @@ export const peopleDemo = [ city: 'Lake Nathan', email: 'wendy.soto@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDNZ1ORTAMngCkKiql/ctaQBlGWJxj2rmk7I2iruxbmvobGJmyCwHGO1c7da691K0JcMh6KeMGmwyXOs3oggGWLbSSM4zXYx/Da0Nr+9ldnxnjjms07bnQoNr3TizqZgmiycxk4ZfStcamIiBHJujk6ccD8Khl8C3CzsPMZl6ZPUVjtBNYJNbunmqrYVz2xxRo9hWktzqrTUEmLrIMHP3uxz6VdQ+lcRaTSLMrSRnYuOneu1tD58QcHqKpGcktxZYR1Brl9dvMTGEchBzziur+bvzXKeKbJjILhUOMckdz6U2KJ0/w/tkbS/tBUGR5WG7HQDtXocXCDvXmXhN7iy8JQtGJt7yPjy1B5z710+galqd7cRx3UZUMCckbT9CKxa1bOyD0SOhngRzkqK5XUfDdkVlLb8MSyrnoTT9V1XVra4ZYo3aJO6KCxHTjNWoJ5r2PEscqsBz5i4NKz3K02PIppI4piqb/vEZ7Ag12HhVjPZSDB+U8muU1O1kj1a7iCFwsjdB05rs/Bak6VIzEZL8AelbHHI0TEAnXNZ+o2TXlk8W0sSRjHUVpKGccnFNZtoxVWM0y/4Xgjs9KSxkw20kjI963rVIl1DCKoCpkkDGTXPaacuw7jBFW7meyZgr3BimAIyCf1rBpqVjvptSijVjEMjlJFG/ryM5pl3IkMRRF5IxWfZTadGgSCZWfPdjnP41buVHUnJxSfYt2RyWo2lpEJTGUN9dBkVc5IyOSR2wKu6ZZpplhHaxkHYOWA+8fWsTRdOabWb/VJs5advLH5j+VdER81axjZHFUnzOxVUsR6Uw/KcnmtrT/Duoamoa2hPl5x5jnav/1/wrrbDwHp8Kh713uZB1AO1Py61sotmDaRwVozedujBOB82Ow6VoiMSjBk2MO+Oa9Hm0a0k0yazhhjhV1wNi4wex/OuEurRo5ZIpV2TRnDCsq0eVpnVhp3TREsQRMeYr++KMGQHnNMhgBBLsxHYVcVflARSzHgKByT6Vibt3epnR2P2mG7FruaS2QOyAZJBPp+Z/Cs1ZDuIIPFepeHtFbTLI+dj7RKd0hHb0X8P8aNX8MWOqIXCLDc/wAMqjr/ALw711qD5ddzz5SXM7YAAAAAAAAbH//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-22.png', linkedinUrl: '/in/wendy-soto-507c1d708f', jobTitle: 'Metallurgist', }, @@ -9225,7 +9225,7 @@ export const peopleDemo = [ city: 'North Isaac', email: 'patrick.jones@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-23.png', linkedinUrl: '/in/patrick-jones-33ee1b90f5', jobTitle: 'Engineer, biomedical', }, @@ -9235,7 +9235,7 @@ export const peopleDemo = [ city: 'Bowenbury', email: 'vanessa.ingram@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDqqWkrjviB4mOjaWbG2LC9ulwGH/LNOhP16gU2Ib4j+IVlpUslnYILy8XgnOI0Pue59hXHS+MtdvlZn1BYF9IVCj/GuTt4jLKqZJY+ldpp/gTULmDcscSbhnfIcmsZztubwpt7Io2HjvV9Llcm4N3Gw+5Pzg+oNdbo3xJtrh1XUYRCjcebGdwH1HUfWs4/C1woZ74k9SqrxXL6poc2gTSwykMrKSrY4Pt9aI1U9ExyoyWrR7qkiSxrJG6ujDKspyCKcRXnPws1meeK60qZ9yQqJIcnlQTyPp0Nej1sncwYgrxj4l37Xfiv7KAMW8QQAdcnk5/OvaAOK8R8eae9v44nKMX+0FJM4+7njH6UpbDjudB4K8J22yK/uv3khwVjPRfc+teoQRbUAC8e1cE8b2VjHGsU0jbAVEb7QMD+da3h66vkaFJXm8uXDASnLLnsa4JXfvM9OFo+6dQwOOnFcB8QdJF/pJmiOJYMvx3HcVqeJbm7bzDEZmii6pExBb8uvWqMETXFu8LQyxOq/OGfcrZHr60LT3hy1vE4T4d3DW/jK1UE4lV0YDvwT/MV7j2rwPwxFNaeOLEoCBHdbGOO2cH9K9+IrvjseXJaiCua8WaHDqEcNz8yyxOOVHLAcgfSulHSorqLzrd07kcfWiavFpDg0pJszdNMF3ZxiRQSOgNTzPBBfW0ZZI8nucc+lZdgrwSlB2YggVLdalpZmC3YDuvbZuIrzra2PXjZrQ0LQ291cXADRybWI4Oc03UhFBav5agHFVbLUtMMhS1YIx/hK7Sai1qUJbSTyNiONSzflmh72B6FLRtEt1e3YA+YszXDbh3PP5ZIrru1Y/hy5k1DSIb6W1Nu04ysZOSE/h/xrXNd9OLjHU8qtNSnpsAp2Mim7goySABXP6x410bSI2BuVuLgDiGE7jn3PQVoZBq8y2OpBhwGQMT6Hn/Clt4YL4CTzByOGHUVyHhqS61f7bf3kpkkvJSTnooHAA9q3YNJuGXdbXDQsDhgOlefUtzs9Si2oI2Gt4LJC5ZT6saou0OrXEVnI6iKRsNn+PHO0evSoJdMuS4S4uWlJ7dMVgeLDNp406e1babe4VhjjPBop2c0FaT5GenBQowBgCkNUtJ1e11rT47u2YYYfNGT8yN3Bq6TXoEAAAAAAHln/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-24.png', linkedinUrl: '/in/vanessa-ingram-dd5d4ea14e', jobTitle: 'Hospital pharmacist', }, @@ -9245,7 +9245,7 @@ export const peopleDemo = [ city: 'Stanleymouth', email: 'walter.rhodes@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-25.png', linkedinUrl: '/in/walter-rhodes-8cff091883', jobTitle: 'Actuary', }, @@ -9255,7 +9255,7 @@ export const peopleDemo = [ city: 'Gibsonfort', email: 'heather.cardenas@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-26.png', linkedinUrl: '/in/heather-cardenas-0a0d52106f', jobTitle: 'Sport and exercise psychologist', }, @@ -9265,7 +9265,7 @@ export const peopleDemo = [ city: 'North Janicebury', email: 'nathan.schwartz@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-27.png', linkedinUrl: '/in/nathan-schwartz-db3bb93189', jobTitle: 'Merchandiser, retail', }, @@ -9275,7 +9275,7 @@ export const peopleDemo = [ city: 'New Michaelberg', email: 'roger.gill@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-28.png', linkedinUrl: '/in/roger-gill-367ad4e3fc', jobTitle: 'Lighting technician, broadcasting/film/video', }, @@ -9285,7 +9285,7 @@ export const peopleDemo = [ city: 'New Jerryfort', email: 'cynthia.taylor@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-29.png', linkedinUrl: '/in/cynthia-taylor-c8c2e63cb4', jobTitle: 'Biomedical scientist', }, @@ -9295,7 +9295,7 @@ export const peopleDemo = [ city: 'Christopherberg', email: 'jenna.rojas@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-30.png', linkedinUrl: '/in/jenna-rojas-01776ae7b4', jobTitle: 'Clinical biochemist', }, @@ -9305,7 +9305,7 @@ export const peopleDemo = [ city: 'Williamview', email: 'trevor.chase@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDt6KXFGK5jczdY1yw0KzNzfTCNM4UdSx9AK4e6+LkAjP2PTHLZ4M77R+lc1rFtdeLfG97DFKxt4pCvmHkIo4wBXRwfDbTwqF3mkbuWPB/CnzRjuOMJz1RQX4uanvBfS7Qpu5AdgSPQGum034naJfyrDLFcW0xONrqGH5g1lXnw40sx/u1ljYdw1cTr3ha40kGaCUyRKfmyPmX3oUoS0CVOcVdnvysroroQVYZBHcUtcP8ADXxPLrenSWF0UM9kqhSM5ZOgz+Vd1ik1ZiWooFQahI0GmXcqffSF2X6hSRVkCq2psiaTdl2Cr5LjJ9wRTA8+8DWKQ6YszYMszl2Y967yJTtHAI9q8/e2EGn2cEiTyKIA3lQnGSBkk1reFpJYZBGBOkMg3KsrZK/4Vk1e8jri7JROmuCRGckAe9cnr8Cy2kyhQxKHj1qLxAjXl3LKwuJI4RkrFJgnHYD8ao2CF3Pli5jCqC0U53cY4waXLpcOZ3sY/wALw0PjieJeEa1fcPoRXs5FeU+Crf7L8Q7qVvlhKNGpxwWbBA/Q16uRWzd9TktbQcBVXVYll0m5VhkeWWI+nNXMVHcwm4tZYQdpdCufTIp2BOzuYdjbQ3NnEWAyFHP4UI1muorCksSFVJwSATXJzaxdaP4ekcfNNB+6K+4baaxLez8R6zdpdTTNEQPulMAD0xWap33Or2mySud5Zm1muZQzxsCTtYEHv+lPv7WG3iKoMEjrXnnk+I9DllWJ/PHOU27uP89q3o9be58PQTTnE8ingHsDjNKULDVTo1Ys+FEjn1icLuyLnJOOPlUV6Ea5HwHpPl6YmpM5zO8jquPU4z+ldeRVpWOacrscKdiqd/qljpcXmXtykIPQMeT9B1NclqPxDiBKabblv+mk3A/BR/WtEmzK5hfEm2k0m5eeLDWt9hmX/nnICMn6HH55qhDqd9d2EBs79op2H7wdsY45rWtF/t22uLm+AnkuXPmBhwAOAAOwArnrnwpqsEjRaUweEnIR2wy+2e9Tzxbs+htyTirrqa82opYaM817qTXF3Kp2pt4X1/GuRs3mv7ZLeFHYZIL/AMKLk8VpN4S1W4CJfGOOMNk7W3Mfp6V01vpMdjZCOOMKoGAKlzjHYajKb97RHZeFNU03UdEhi06QEWiLBJHjBRgMHI/rW2RXiWkao/hfxJdXFoA6yEiSJidp9f1r0bS/Hmk6iVjnY2kx4xJ90/Rv8cVra6uYvQAAAAANHY//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-31.png', linkedinUrl: '/in/trevor-chase-c2e65df749', jobTitle: 'Lobbyist', }, @@ -9315,7 +9315,7 @@ export const peopleDemo = [ city: 'Charlesberg', email: 'scott.murphy@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1jFJS15j8YfENxpun2el2lwYmvNxl8tsMUGBj2ByfyobBIj8V/F6PSb+Wy0m0jujGdrTs/wAue+AK5yT416w20nTrVVz/AA7ua4vT/DWo6n/x62jvH6+v411Fp8LNQlAN1cLErclVGTWMq0VuzeNCctkb2kfGkG8capYusDAbfJO4p784yK9J0TxRpevj/QbgM2NwUkZI+leQXfwo8uFvK1BjheNyd652wur7wP4ptXuDuiiYM23jevfmnCrGWzFOjKCu0fTWKMVFaXKXlnDcxn5JUDr9CM1NWxiJKxSJ3VS7KpIUdz6V8x6hdXnivxXJJqsji4MnlmPGPLUH7oHbFfT9fOtpYz23xEuY72J0drtmO4dckk/Ws6jtG5pSV5WPX9Jt4rWyiiiUKqqAAB0rQcHIIH5VyeqXBWIsGuiCMpHbKdx/Gm6HeXKlfOkufLLDiZstz0FedbS563NrY6K6UiMg8Zrzjx1p0N1pskjKPMj+ZWHUVteI9QuJ5pYUkulSPgrAPmrFlElxaywl53TyyGE6/MOKqKs1IibTTidf8JNafVPBy2s7hprB/I99nVc/y/Cu9rzr4OafLa+GLueaMqbi5ypI6gKB/PNei16S2PJe46uJ8QaUh8SRXgcmRT5hDZIC4C4HpXbVjeIUZbFrlImlZNqsq9cFhz+Gc1jXi5Q0N8NNRnrsynDbLJDnjPbNVZns4ZY1leJPnAUtxlvb1qzErGM7XxxxVGe7kWPyzpzsg6M5UZ9689a6HqpFINbvrs6JJG27Gcc4NQazbpEjbcBsckCq/nJHehYdOeIt3XB/OrVxb3GoXsdrEAZm4wTgZxmqs72FKyTudP4MsvsPhe1i8zeWy+fqf/rVvVDZ262llBbooVY0C4HsKmr04qySPFm7ybFpkiB4nVgCCpBBpXkSMZdgB7muT8V6Tc6rDDf2bOsltINyAkboifm/HvUVJ8qHCHM7EbTG2++SI26NVkXNpJB85VlI9alS3Wa1UEAgisDUfDrnMlvMyg9QDXmJ9T2A1S5t4FLRkA9q1fBsQujcag+Syny0J+mSf5VyDaTLA376Rn+prpPAutRvLd6Q6hWik3I397IBx/n0rehbnOfEuXIdxRRSVwAAHoHmH//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-32.png', linkedinUrl: '/in/scott-murphy-2e879fc86d', jobTitle: 'Commissioning editor', }, @@ -9325,7 +9325,7 @@ export const peopleDemo = [ city: 'New Laura', email: 'zachary.thornton@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-33.png', linkedinUrl: '/in/zachary-thornton-303f2657b8', jobTitle: 'Wellsite geologist', }, @@ -9335,7 +9335,7 @@ export const peopleDemo = [ city: 'Kimberlychester', email: 'richard.aguirre@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-34.png', linkedinUrl: '/in/richard-aguirre-40f00db472', jobTitle: 'Barista', }, @@ -9345,7 +9345,7 @@ export const peopleDemo = [ city: 'Danielhaven', email: 'mckenzie.black@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0w4Aridf+Jek6TM9taK19cqcHYcID/vd/wrG+InjNozPo9i5VEG25lB5Y/wBwH09T+FeUK+ThQNx5YnsKiU+iNI0+rO2vPilr8kpkie3gj7IseR+Z5NNs/i9rkNwDcw21zH3XYUP5iuIljM0qhjx2HtWxp3g+61Q7y5iiPfHWo5+Xdmns3LSKPWPDvxO0fW51trlTY3LfdDtuRvbd2/Gu2Uh1DKQQeQR3r521Twrc6RF5qfvEUZ6ciu1+G/jvzXXRdSb5mP8Ao8x/9Bb/ABq4VFIzqUnE9VxQBS0VqZHy9qF5JdSNI7El2LEn+JjUCgnEEQ3t3wO9V1zKfMY/KvQV13ge0jkvJbloWk2DaoA7965ZPlidcVzSL/hzwbK+y81EqkfDBWP5Zrv7ZbJIxHbyRttGMKwNZN3qlxHEwSxlcqB8oA/rWZp9xM85nnt/soA3NnsPwrmd5as7I2jojpNRtEnt3U9CO9eOarC+j+Ij5R2kMJIyOMd/513/AIk1Qxulu0MzI6hwoH3h+FZaeHrPXLqK8mle3t7bCzQiNmdxnPynt/8AXrWitTHENWPZNIu/t2j2l0QQZYlYg9jjmrtQWbwPZxPa4MDKDHjpipq7jzj5Wt4/PtPl6g4OB1PavRPA1vJp8VxDLGQwYZyPUVxHhueystU8vVMpCSNxYHCsOmR6da9R0i5tLne9ocxl+GI+96H6VwVm1oelQSfvdToBFHcLuwFb1qhMbaCfypZE2YLSM+AAPc1fRTs4rMmv7W3WWNraa4cHLbI8gn69KwWux1aFfUpbC8a2lSeJz0UrzkVe0K033r2m/EUi7n29Tj/9dcvcXlrLdqJLGWBnPDMOK7LwdCzzXNw45RRGv48n+QrelF86RhiLKm7nWjAAApaSiu88o+bfH1olv4z1GGBQEDA49yAT+prtvDUbw+HbKYLg+UuRiqXxA0yw1LxdO8aPG42rKynh3A5OPpx+FdNo8ttcaWqQlcxjayD+GuLE6I7sLuy1BqAljADAGpwoMJQOuMd6ybjTCzF4XKH2rFupr+3kMYkYj1rmSuzsbsal5aJAQQ4P1rt/DVo1tpCNIpDzHzCD1x2/SuJ8IJHf66kd/KrBULRxsfvsP545P4V6dXbQh9pnDiqt3yiUUtIACV0nGf/Z', + 'https://twentyhq.github.io/placeholder-images/people/image-35.png', linkedinUrl: '/in/mckenzie-black-5e934e9a1d', jobTitle: 'Scientist, biomedical', }, @@ -9355,7 +9355,7 @@ export const peopleDemo = [ city: 'Port Chadport', email: 'jacqueline.randall@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDnmGTUdzdxWVs00xIUdh1J9BVryjnpXI+Jbs/2l5IfKxLwvYMeprE2K9zqVzfzFnZoos/KmeAKlgltYQC8oLegGSaxlYPlpCfpmtbT9B1HVgFtoljiP8WMZ/Gk7LcqN3si0NSs/NAiZoZPVuhp0+s3KXaxbw0LfpW/ZfCi6miDzXShuo4rJ8QeGpNFto45Vzhs+YO/tUKUb2TLcJpXaL8OoBWRXxhuh9K0owSa4dL2NQoxvxyMmu10mcXlmkuevFWtCHqaGxUBZugGTXkt3M9zfTyv1dyTjp1r10c8V5TqVpJa6vcW74Q+YcZ4GCePwpxJkbnhvw5JqpWeX/VE/KPWvXtE0eOzgRQF4HTFcVpyjSdIijZZX+TbtiOCTjJ5ra0HUbo3MCfv1ilIwsxywz2rlneWp207RVup3sQ4wvBFch48sUutElyPmX5s1W8RahdR3B2tdNArcpbnDE984qSG7W5tXikt7kLtw0UnJ5HY5qbWsy207o8PJ2yFOwOK9C8KRldGU5JyxIJ7iuP1DRriC7uXKfu4pGUn1wa9F0gNHpNssqBGEYG2uy6exwWa3FSTBqhrOjx6mFmXAnjUqPfNXAOaljznrUtdhppbmpoqpJbpG6ruAGcitKBYI9ZhV2RVU5BJA5rE0tZYol81gXBI+X0zx+lSz32nS3IW4t5ZWTOCkZJX6GuSzvY9GNpJNHROlvLfuEkjZXJOVweaW8WOGIqqjJ7juazrHUNJWMwwW8lvI5B+eIqWPrmjV7lrbTri66vFESo9Wxx+uKTvew2kldmRf6LALWQy8C4mErDvx1/A4FVTJlsCqGky6jNYmXU5pJZ5DwXPIUdB7VbC812QjZWPPqT5pXQ8JUqJyKk8kirS2DtaSK4KPIpVD0K+9UZkLt5IXDDce2eamt44bn78pQ+o6iuQ8PaTfWepXDXspLRsUVSc7v8AaNdJc2rk/uyQe2DXJVa59DvoXUEbYW3tbYg3G8epGDVDUpx/Zz3ExIhUjqO2etGnaY24PcFm9ATmtmSFDbMrKCOhB6VmpWdzSS5k0zkreeC+migtpVaWQ4ReQSaWVXt52ilUq6HDKexrp/D3hyys7241CKER+YNioOg9SB2yf5Vpal4Sh1ST7UZmhlIwSACD6Eiu2Erq7POnGzsj/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-36.png', linkedinUrl: '/in/jacqueline-randall-38109939cb', jobTitle: 'Retail manager', }, @@ -9365,7 +9365,7 @@ export const peopleDemo = [ city: 'Port William', email: 'sheri.taylor@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDU60Ac0opcVBRDdXcNlD5szbV9cZrz/wAQeNbm6T7PZk2sI/1jq3zP9D2FbXjS8mW2gs4V+ed9q4qtp/w9je3je4lLTHlvSolNR3NIU5S2PO57h5D5hyZHblm5IqN2IwGIZvUV6befD+xCMVaUN6g1xOreHn01mJLGMHrSjUixypSiP0bxnqejEReZ59uP+WUpJwPY9q9Y0fVLTXLBbu0fcp4Ze6H0NeCkbGI3fnXUeAtTlsfE0CRt+6uP3UiFsBvQ/UGtDI9cFLSCg0AYGqQG48TaZH1ULJJj3GAP5119vG6RBSBnFch4ijKGG6EEkzKrRhI22nLFec/hVjw3PeNEyTmVV8suPNbLD2Nc1Va3Oyg/dsdDdRSEYxx7VyuvQebbyRhfmIxjFZt62orqO8Ld3CFuglIXk+g7VchkkuflKTqF4xJzj6HuKzcbam176HlmoxmG6ZQvlkHkEVVhleG4SWM8qwI9iK6zxhYn7TE8aks2RwKyl8O3cFnBeuyqWZT5ZHIG4DOfxHHvXVGaaVzilTfM7HtgPFJupo6UAVoYkkQjklCSAFT60TvZ2sE4jeFDwuOFqvNuC7l6jmsu6vNDMmy9RXlGNynvj19a5aqfOd2HacNDorGOyvImDCMshwwODVTVJoLaNhGqjjAxVO21fTHTybHYr8naBg1RvUaUlnbgdqxfZm5kSxrczKzgkA/KB1NMvIfnsNKDF3uZwMZyVQYZ/wAMim6hcyWUL3EDBWiBYZGQeOlZvgmW71PxTJfTuZJBEQXPYEjgelbUo3dznq1OVNdWem44puKdnikzXWcQ0gGstrGWSVhHPHE44yw61rcUySyS8dVw3mdFKHBrOpDmWhrRq+zZjtCtjGS8qNIeSw5JrIu9T3/u4zuJqTUNOupZHVJCSrEMCaZaaO8MoMpBPYCuJ92d12ypd2hnsTFKcCThj6V1fhzQI9DstoKtJJgsy/pWXewFlCouT6V1GkaNe2tl/pE7EtjZE3SMelbUEOp//9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-37.png', linkedinUrl: '/in/sheri-taylor-df26d6d5ee', jobTitle: 'Commercial art gallery manager', }, @@ -9375,7 +9375,7 @@ export const peopleDemo = [ city: 'East Christinaburgh', email: 'brandon.acevedo@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDBOcmmM6opZ3CqOpJwBUzIa5nXDdXt5DZWyb0LAbfVs9/as7miRPd+JEiZ0tE83aOZD0/Ad6zF1/VZG3llRB22gV6ZoHw/063tV+2gzTvgt2APtW7J8PtGePyzC2Oxz0rH2yOn6rKx4/b+LHUBLhFJB6gYyK3rO+gv4vMgfOOq9xXYXfwz0NYsLEwKnPWuK1fw3P4cvEudNRpITw6Z6f4iqVVN2Jlh5RV2XNpp6Kc1LGBJGkg6MAaeqc1dzCxI0YrB0ZQvibd1LSYwTnvXTrCXYKOprK0HSpF8Zus6kKC8sfowPQj1qJtWZrSi3JM9PtdpXp0q+XBAwc1wWtveoZB5d5JEq5CW/wDnrUHhn+1lv41lkuvssmGInbJTPQH0rlSsrnoc2tjv5wNuGJFcZ4oby7CZsZwuapeMLvVo9Skgtmufs8ShmMHLH2ArPgW6ubWeCVrll8lsrcdQSOKpR6kylvEh01zLpsLEc4P5Zq2q1HpcGzTLZDgMIxuUHpnnmroi5rquec009SWLYZ1Vz8rHafx4rVMKLqMdyqqoizCgAwcYByfyrEZTWrDqAnW3idMSITmTPWsq0G9UdOGqJJwZ1MSQ3cHzAD1zVF5bKGbyYXjXaQGJIGTUaS/uGw2MDPFYN5eaTdxrHMqM0ZO1vLLEH1yBxWEVc7U+xszvZTazIjyRukgGMHODUepwQWtsyRj7wxmubtn0qxmcxSZlYBSzqwLc9ietal/M0qLkknjim1qS3pqUjGsSIigA45x+X9KVQallxLLuxj2NKiDNdMVaJ51WXNNtFQnipbZcygHjPH0poTNT+RMlhNdwxmTyXjDAdgzYLfh1rSSujODtJE8d1IHMLHa44IPpWpLFNc2u2KVYmxgH0+lZt/YPdxJJGcSDvWJdz63Yph0cov8AEozXFGzPTu4m81pLChMsqSkdzzWaJ/PnKA5Cckj9Kw01PULsNhm2txkDFa2nReUWQnL7QTmtYr3jGrNuLZcwfSnp1oPAoVua2OI//9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-38.png', linkedinUrl: '/in/brandon-acevedo-32a27033d1', jobTitle: 'Investment banker, corporate', }, @@ -9385,7 +9385,7 @@ export const peopleDemo = [ city: 'Wintersside', email: 'katherine.best@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-39.png', linkedinUrl: '/in/katherine-best-9e3dcb6aa0', jobTitle: 'Corporate treasurer', }, @@ -9395,7 +9395,7 @@ export const peopleDemo = [ city: 'Lake Betty', email: 'daniel.adams@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDuQBimTzw2tvJPPIscUalndjgACnjpXmHxW1mYNBpMEn7sqJZkHc5+UH+eKuTsiIq7sP134pOSYNDt8Dr9pnHb1C/4/lXEN448RS3DTHVp94ORhsL+Q4pmkaFf6uRDBGXBPzEf1NdMPhZqEce9biPeRjBU1yusk9WdcaEmrpFfQ/iLq8GpN9suGvYzy0bgDj/ZI6V6to2v6br9uZbCcOV+/GwwyfUV5Hd/DnV7JPPjMcjJz8vUVneH9cl8NeJ4bueNlUZinj6FlP8AnP4VUKqb0ZFSk0tUe/GlpFZZEV1OVYAg+oNLXQcwZ4rwrxZGb7xzfoXOGn8vHcAACvdRyK8d8RWUy/EKSZIt8E86lWj5zgDcOOh4NZ1naJrQTcj0PQLKCy06GKCNUwozgcn610Q4jHevN9Q1W8EIaJbuFDkLHCgLnHcnoKZourazBKN4u54nZfklI3cngZ9eeleZyu1z1uZbHodwPkOeK8y8f6bby2BufJHmxn76jBx71b8Qa5rbzzRwx3EAgbDBVDN0B7cd6yrq5vrvSLtJ2kmzHyJk2sp/CrgmmmRUaaaPSPDE/wBp8LaXLzk2yA59QMf0rUNZXha3Nr4W06EuHZYRkg9+uPw6VrGvUjseRLRiCuT1XSkjuI5IwFEEhlzjlix5/QmusFVNRtftFtJg4O30645rHEU3OOm6N8NVVOTT2ZkwQOysI0R8kEq54B9jSXEsNpPD9se2t0VxtAPVug5/pS2rk42ng9KZc34Zdk9hPJz8rCMH8RzXmK+x66VyJpLe51m5NpJBNkDzEb17c9qqanal02GNIuwVOeT702G4t7aZo7aymiJwPmixn3yKuC3e+1CKEtgnk98Ac1aTcrIidoxfMb2jWq2WkW8CHIC7s/U5q6aEQRoqKMKoAFKelerFWSR4s5c0nIaKHXMbD1BoBqS4s742TyW6DeADtIySvf8AGiclFXYQi5OyONkP2ZvmJCHlSP5VfzbXVsFklwGHGDipJLJZ7by25xXN3Wn3trIwiyy9Rg14yaZ7WqNOYW1ohEcxLf7Rq/4ZRZjcXROSCEU/qf6VyCQXcz4mUjnnJrtPDDIunyoOCsvP5DFdOHS9oc2Jb5GblIRxSbqCa9EAAAAAA80//9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-40.png', linkedinUrl: '/in/daniel-adams-fbc7ca02b9', jobTitle: 'Research officer, trade union', }, @@ -9405,7 +9405,7 @@ export const peopleDemo = [ city: 'East Robertfurt', email: 'elizabeth.vega@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDuqRmCqWYgADJJ7UA1wfxH8QG0tU0m3k2yzjdMwPROw/GpbsikruxW17xm980tvp5MdqpIMucF/p6CvNr+8ma6Zt5IHqc1dVXaAxwMQ7DLOev0FRf2TLF1Qk56nvWV9bs25eiCzvp5BhkV1HUY5rVtNVn06VZbKaSF/wDZP8x3rNjsJ4o/PAw6nI9CKLuY4B2jnqM9DS9B27nrnhbxVHrSfZrnbHfKM4HSQeo/wrpTXgumanJZXcF1E22aFgyn1HcGvdLa4S7s4bmP7kqB1+hGa1i77mMlYsV4z8QXDeMLrnJRIwAex2ivZa8i+J1g9tr63wGVuoQB/vDg/piiewQ3KvhnQ571lun4hJyM9Sa6u48MtP8AKrAKfXjFZtjLc6d4eshBFK8rRjaEIUA47k1seH9T1O6Kx3qAFuQ3oPQ1yST3O+FkuUpXHhtreBkz5iuOccbT61x2taDeQKZAmVAyccYrttc1PVFd1sgRHEDuPGTj0rPhuZtRhaOaKRHC/NvIYHjsf6U43Wop2eh5yJcIpHBHX3r2vwBdNc+DrTcSTEzxDPoDx/OvGLiykjuriBR9yRh+Ga9o8A2T2XhC2EgKmUmUA+h6fyrpjucc9jqKx/Emgwa/ppicATx5aF/7rf4GtbtThVvUzTscvpUca2iW0yrvjAUqRxkVZZIo7yOOJQMDJ2imXlsbbUWKkkP83NULq604yYnkdZRkbkzkZ+lcDTUrHqwalFNE9kkUtxPG4BOScHoeaZqQgt4SsagewFUrO506GYpayMXJz8+dx/OpNQ+f5mPFPqJ6IwbXQhf352fLJc/Jn0Hdvyr1CKJIYEijGERQqj2AxXnfw3e5vtS1G9nkd0H7uEMeFBOcD9K9HPSuuCsjz6srsSlFNFLkAZJqzIo6tAWtTOvDxc/UVixxxXIyzhT0z3FW9Y1pHiFrZOGeR/LeQDIUYycepwMfjWU9m8uWjcqxHY965a1lI78M5co+eCK2y6tn39apTym4UjkjvVkaZKIjJcTM2Oi0n2bZDnHLdBWVzWWpp+Eb3SLrT9mmwLBJCNkqFRuH49xXQk8V53ZW/wDZGrNd22UeXb5i9jye3vXdwzM6kOMOOuOh9xXbz//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-41.png', linkedinUrl: '/in/elizabeth-vega-4755e545bd', jobTitle: 'Investment banker, corporate', }, @@ -9415,7 +9415,7 @@ export const peopleDemo = [ city: 'Ronaldland', email: 'jennifer.kim@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDtcUcAZPApM8VkeKJbmPwzfvaNtlER+b0Hf9M1Qkcd4h8cXU189vpMpjt4+DKBkv7j2rh73Upb+SQu7NKTlmbnNWtC0ybVJzAszqT1x0Fdy/w5jazAilInKj5iO9c0qnc64Um1oefW0DsAW2jPIduCPwPWteOOZIQJsFezhQQasS+BNTtJsyJ5gzwy5Jp6WFzZFVUK0BOJF9BWTkaKDW43SvE19oF0fLxLb5/eQknBHqPQ16zp+oW2q6fDe2j74ZVyPUeoPuK8M1lv3irGD5gyp9HHY/Wu9+F14Tp17ZOCrxyCQA+h4P8AKt6Uuhz1Y9TuqyPE9vPd+GtQht/9a0RIHrjkj8hWruprYdSp6EYNbmB5z4Fto1gklQAvvCsfevULbOxSe1eZwWV1o9zeWtj5vFyyxkEAY2gjOfrXVeGdU1W8xBfW+xypKv0zj1HauCadz06UlypHVj5lIaMEetcp4g0JZUkmtcJI3VexpmralrkMr/ZwfJjXcQgGWAPbP8ql0+7vr+NTPFLGSMkSKB/Kotpcu6vY8g1VWSdwch0JBFdn8LEY/wBpXBIwdi4/M1V8WaE0mro0A+aXk11vhXRotFguYUVwzMpZi2Q3HbjjrXRRaukctaD5WzczSZoNNrrOIqsYTqLRyoCHQNz69KvWSr9ulKLhY48ce9ZOrRsPInTgo+0/Q/8A6qoC7sXvZDNf+RJgKyB8bgOxrhqpqbPTw7Uqa7nXxRW9w3zKCw/vdakujFaQkLgcVkWl1pW0R2d5EzZ4xJlv15qa5Uty7Zx2rF9jdpFG2hFxeGVwuVGQWHSr8IEaBR0FYF5bzXdxZiB2UfaVLkMRlByR79q6LbXVh4/aOHE1H8BHmkNLjFFdRxkNxCLm3eInG4YB9D2NYUGmSTznfIi3C/K4Zcg10QxmsXxBc2lrH5izGO+2/IEPUf7Q9Kxqw5ldHRh63s5GnbaetnGWcRlz/EAKhlujcuIIW3MfvEdhXPadc6hqrFJ7rbEvDBRg11WmW1vbJlFBHqe9cMtz0ebm1K8iNaSweWM7ckj1FSWOsWepPJHbuwkjYq6OhUgj+f4VW1C933jCDBwMbuwqrFAA4dAd2c7ycc10UHKKn//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-42.png', linkedinUrl: '/in/jennifer-kim-e40f68f1d3', jobTitle: 'Counselling psychologist', }, @@ -9425,7 +9425,7 @@ export const peopleDemo = [ city: 'Jenniferstad', email: 'stephen.saunders@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-43.png', linkedinUrl: '/in/stephen-saunders-d055c5642e', jobTitle: 'Biomedical engineer', }, @@ -9435,7 +9435,7 @@ export const peopleDemo = [ city: 'South Amanda', email: 'ashley.prince@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDrSRRmm0UyRxdUUliABWXe+I7ax5dSV9c9fwrJ12+mnvVtbeTaoOGAwST9KY3g3VdUZHedreDHKSHcT+HauadZ3tE6qdC6uzZtPFNjdYTeFkPbrV+PUIZDtYhWPTPeuVm+Hk8WXt7va5GCdtY2oNq2k7IbjL7eFYdDU+2lcp4dWPS8ikrm/DGutqUPkykeao9eT9a6MV0xkpK6OWUXF2YyoLm5itYS8rheDj3NT1ieI0UWyTOflQ9KVRtRbQ6aTkkx3hXSXn1SfVLkZkOBGp/hyMk/XkCu56KAMGuA0+6caGJp0uC80jbEhJBA/D6Vp+Grm4uG2yrcpBgkefncDXEekkdLOQBjIHrXMa7aw3Nu4kQMCM5qhrLXEtzJKYZpoowSFjJywHbrRZ3EtygjNpNAAM7X/wD1mn5j8jmLNPs1z51nLnadwB616DaTfaLWOX+8ua81cvaX15CqndFMWAA6qea9A0N/N0iB8EEg8HtzW1F62OKutLlzNVdRhSa1IYZ2nIGM81aowCK6JK6sYRdncm8NpENIhhlUEqDnPrk0X+rWOnXLRFWH7sldq8enXp3FLBgy/JwMcj3rK1HxPZ2N6lkLaSaQgnPlnbx15xiuGzTserCzSaLehX9rfoflYZGcSIVI56EGrN+0UCnYqge1Y+ma9b6jO0aW00MisR80RCn6HFWb5S7HJ6daT00K0OC1tZY9XNxEGUyIAGHTcK7DwvdzXGnr9oUq7DcQR3rnr/WtLivzp7h2vuACU+VAe+a6rQrRLayAR2cH+JutbUk3I48Q4pFwUZpcUAV1HEKjmMlhU8ls11EpjcLjmmwQtPKsSDLMcCst/t4hV7UkA9Y26qfSuatGz5juwtR2t2LbQvbgl5QfeqNxOSNgOWasy4utTZ9kkTj3OAK09M0u5mTeBuc9WPAFY2u9DolLqzgYdM/tHxfdSNIquJfLQMwGSAPxr1C1hNvbqjOGYDlgODWYuiaZ4eS81maFJr12KtKepPZV9KzbPVrgzuZGLbvmIHRfYe1ddONlc86rK7P/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-44.png', linkedinUrl: '/in/ashley-prince-59d88abe81', jobTitle: 'Ophthalmologist', }, @@ -9445,7 +9445,7 @@ export const peopleDemo = [ city: 'Port Charlesfurt', email: 'paul.mckay@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-45.png', linkedinUrl: '/in/paul-mckay-00b47ec261', jobTitle: 'Physiotherapist', }, @@ -9455,7 +9455,7 @@ export const peopleDemo = [ city: 'East Lauraview', email: 'shelby.hughes@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-46.png', linkedinUrl: '/in/shelby-hughes-7c90e603de', jobTitle: 'Video editor', }, @@ -9465,7 +9465,7 @@ export const peopleDemo = [ city: 'North Keith', email: 'cheryl.townsend@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwCBzTBTj1oC81gbABxk9Kga6iMmxZ4VI/hY81heJ9Ymg22doSJHO3K9SfQVraF8NJZrdJ7+7Ilfkqo6fjUuRpGJFd6jdMrGAhEU7QVH3j7VBaLLOdzc467Thh+BrtrzwXa/2ctvEXOwcNnnNc1dadLp6FZWy6ZCv03Dt+NDZXK1qOVngT5JNyjqGrY029juUZPuyJ1FcmNQ3Mcn5xwc9x71ZtbkRzRTI2Bu2N/un/A0k7EuNzXMdNb92jOf4QTVwqMVHLCJInT+8pFUQcV4etv7c8ZWrONyQlpGH06frivbbdAiAZ/CvHPCxOm32q3AtnuWiQRhIzgnLevbpXovh6a5uJIQ6PGskfmbHfds9ifWs2jogdNjd0I/OuY8T6cXtZHC54/WqerXd9ZanGEgublZHCjbJtRRWvb3bXgaF4ZI9p2lW5B9we4o6XKe9jxe8leKZuoKn8qktdUVSVb8RW/8QNE+wyLeQJ8j8MAO9cIsdwAZ1iYxKMlsdKtaoxd07HsRpVHFIaVQadjIb4Nso7S/1gSKCZJVIJ7rgkfzrrIZrO1edi6R7Vxk8Y9652yPlahxwZUx9SP/AKxNWbi90aO48u8ZTMRgrjJI9xWbvc7KdnE3omt7o/eQkAEEYII9afLLHAvA6Vi22p6RIoi0+SIOD9xODn0xVuTc64PFTJ2NEkY+txDVoGhIBUHPNcn4hsYbLwtcSeUirGSsTAY3bvlx/Wut1a/t9HtHup1LQxjc4XrjvXmHjDxNPrtzHapF5NrEdwXPLnsT+B4HvTgmzOclFPueiEc0oq6unzyDKxnHqeKDYSL1KAjtmulRZxXKoLJLFKP4GyfpV6O0S5YSAIW/vGqUh8oHkGqOjXVxcX2owmUhYnUxjtyOazqQsuY3oTadjqIrJIRudUz69abcXaohA+8aymnumby2yF9RV6C0IXe3J96wbudTfc474g3MkHh0biN08yp+HX+lcZBJc+JtYR52V7iZlUsFAGAABwPQCu0+JljPc6LbyRLlYJdzj2Ixmue8I6dcWWt2zywuU3YDAcdP/r1tBrlOA5aibmf/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-47.png', linkedinUrl: '/in/cheryl-townsend-62c7a27460', jobTitle: 'Marketing executive', }, @@ -9475,7 +9475,7 @@ export const peopleDemo = [ city: 'Angelaborough', email: 'brianna.peck@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-48.png', linkedinUrl: '/in/brianna-peck-ab76fe8301', jobTitle: 'Mudlogger', }, @@ -9485,7 +9485,7 @@ export const peopleDemo = [ city: 'New Destiny', email: 'andrew.ford@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-49.png', linkedinUrl: '/in/andrew-ford-1ddb22e213', jobTitle: 'Interpreter', }, @@ -9495,7 +9495,7 @@ export const peopleDemo = [ city: 'Port Grace', email: 'robert.brown@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0cSYFJ5uarb6Y0yRozuQFUZJPYUrhYfd3sFnC01xKsUa9WY1yd/4+jttzW9oXjB+VpDgv9BWH5GreONZmmjcwWETbEBHAHr7k1tr4AtYyGurmadvfgVjKskdEaDaKSfFCFJAbqzCxE9Vf5h+BrsNL1yy1i1FxZTiRO46FfqK5PUvAmk3FsV2OrDowbpXHiPUfA2oC5t5TLaMwDj/Z9CKcaqkKdCUdT20S0u8HrWfa3cd1axXELh4pUDqy9CDVlW461omYWK5YgVheKLqSHTFVDgSSBWPtg1tE8Vj+IIhNp2GJ4cY+p4qJvRmlNXkjX0CCK10mCKBcDG4nuSepNXZyc43ZrmNUvJNOtRbxPcjCZAt0yeB61T8PXOpXNwEuJ52j+8fOAyOOOlcfS56NtbHTXAOw9uK4jxRGj6bOrrkEVNr2oXy3BSKW4ESZ/wBQASfzqkkv9oxNDI87KVw6TqAwz7imlbUUtdCf4Y6jLLpd1psmStq4MZP91s8fnXeB8V5/8OIGt21WNgflkVVb1xmu8zxXYmedJDvLyvWoLmzW5i2MMlfmX6gcVcAbHTFN3FDkAZHrRON4tBTlyyTHRvBLagSYBHqKzTqdhDMULLGDkKdv3sdTUjRFg/zbQRk1mXNzcrbFFsUWEcAysPmH9K4Fe9j1Y2exDZXFtNeSJvVgzEAjsfenakkESEIqgkdRWZFczC42tZhVY/eiIIWrU6PcSRx9WYgU7a2B2W5Y8OW3kieQDG/AIx3yT/Wt7GBUNlai1twnBbqxHc1OwrsgrLU8yrLmk2icvheabCPtF1HCnLOwX6V1semWURG23Q+7fN/OrCxxw48uNFH+yoFWZ2OH1CNbe8mhAbdEcOCcnb2P5VTleyeLDncO3Ndnq2kJdS/bYYwboR7D28xc5wfp2/GuH1LTreV2A3wyj7yngj8K4qsXGV2ejRmpRsjLvXt0H7r5Rml0mdJdWt4cAvJkIM+2SfwGarjS2e4EUSy3MxPyxrzXXaB4YbTHa9vQrXzrtULyIl7ge57n8KdJNyugrSSjZkQbIpSRitprKO6BVk2P2ZR/OsQbSzqGBDgaP//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-50.png', linkedinUrl: '/in/robert-brown-28cac6c157', jobTitle: 'Public house manager', }, @@ -9505,7 +9505,7 @@ export const peopleDemo = [ city: 'East Melvinberg', email: 'joy.richards@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-51.png', linkedinUrl: '/in/joy-richards-f0af7d1ee4', jobTitle: 'Tree surgeon', }, @@ -9515,7 +9515,7 @@ export const peopleDemo = [ city: 'South Jamesview', email: 'jessica.hogan@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-52.png', linkedinUrl: '/in/jessica-hogan-54aff81ceb', jobTitle: 'Land', }, @@ -9525,7 +9525,7 @@ export const peopleDemo = [ city: 'Lisaport', email: 'lisa.watson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0ymyOkUbSSMFRQWZj0AHen4rgfi1rMmmeEvskJKyXz+UWHZBy358D86AOO8X/ABTv9RuXs/D7Pa2ikqbgD95L9P7o/WuDne4uDJNdyySynly5JY+5z1qzoegX2rsBao5GeX6AV2MXwvvtoZrwbuuOuKxlUinZs2jSk1dI89a5CIAq5HSr+neJtV0lopbC9lhdG3bA3yt9R0NehW/wsiFu7XVyTKeRtHSuU1zwTcaRBJOsodAecDnFJVot2KdCaVz2DwP41g8XWDB0WG/hA86EHgj+8PausxXzL4K1a50XxjYTwjdukELoDjercEH+f4V9N4rZGDCvOvjNCX8I20m3IS7XJ7jKmvRq5D4m2/2rwTcxbCxMiFSP4SDnP9PxobsrhFNuyMDwPp4tfD9sAMOw3n8ea7VFOwetcTfpLaWsSw28z5j+Vo5CoXA7e9WPC1/qszJDc+YUYblaX7w9Aa81q/vHqxdrROukDbSBxXM+ILX7TZSwYGXXjPrVHxLd6qZXWEziGJSWERwW5/Mmo9Lee5BWS1kjIAJZmJzx35PNJR0uNvWx534ZsnT4j6XbSR/Mt4pKkehzX0rXjWn2M0Hju81O22ebCgEQYZyzAA/pn869l7c9a9CnNSR5tWm46hVLV7NdQ0m5tWAPmIRV2iraurGcXZ3Rytj5U1sIpFBxwQRkVMqwxX0cUQVQvJ6CormAWmqSIi7UJyAOwxVC7vtMklAnSRpFyAyI2Vz15FeY01JxPYg1JJovwLDNPLFLtbJJHcGi8WG2hKxoFGO1Zljf6ZBIY7eN42c5+eMgsfXNW707lyx7dKTXQb0INE09LrUo3ZQSj7yR7ev6Cu4qnplotpZRLtAfYN5x1PX+tXa9GlDkR5Vapzy9BKKKRmCKWYgAdSa0MjJ1+2Jtftcf34hgj1FYUCw3UY3S7CPTgitbWNQ85UtYG+VwWdvUDt+Z/Sudu7GQqzxEq+M5FcGIa59D0sLzKGpceGG2UsJt3uapy3it87ZMaHc+PQdaqQWVxKA1zKzeiitJbVFiK4GAOaxvqby1R2Nhf22p2MV7aSCSCVdyNVmuQ8MlNC0YQ/N9kjOdoGSpYkiuntruC7TfBKrj26ivUi7q548oAAAACNnY/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-53.png', linkedinUrl: '/in/lisa-watson-0cae086726', jobTitle: 'Graphic designer', }, @@ -9535,7 +9535,7 @@ export const peopleDemo = [ city: 'Billyfurt', email: 'christine.morton@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-54.png', linkedinUrl: '/in/christine-morton-3d83c68241', jobTitle: 'Stage manager', }, @@ -9545,7 +9545,7 @@ export const peopleDemo = [ city: 'Ballfurt', email: 'brian.lewis@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD08015EhjaSR1RF5LMcAU81xfxG1CWy0aOOJtplYhj7Y/nSbsrjSu7HF+PfiI180mlWCmO2Vyryd5O3TsK4y1sYDGJWuoyrDlWIB/KtnRPDI1q7aW54QAZ29ya6O8+Hlt5O61ZgwX5Qema55VE9DphSdrnLW6W0KEqz9MZA6/UGsq5kxNu3DAPbj9K0r3SbqwRhcIysvcrxXO3L7SWHHrzSjqEk1udj4T8aXnh3UUWUySabKw81GGQoP8AEPQj9a93gniureOeBxJFIoZHHRgehr5Vid2X7xAHv1r3b4V6q+oeFWtpDlrOXy1P+yRkf1raLtoYSV9Tuq4D4sNjQLFSPla7AZsdBtNd+awvFnh7/hJdENkJvKdZBKpIyCRng/nVtXRKdmcH4KQHSt6j78jH8jj+ldmpbbjPFecWdvqdnoln9llmV2DfKuAAck8k1v8AhjU9Xuf3WoDkqWUng/QiuFx3Z6MJaJG3qFtHNEUljBz6ivONf8JIHaW0YJnqh6Vr6vqeu3F1ObRysMIJwAMtjjiq9nLqF1hLgPnGSHUfzFCTSuhtqT5WjzqTMQeDbiRTzXsHwXRhpGpSHO0yoPxwf8a831zTJDrhSJctIA1exfDLTzp3huaNlKublt3oSABkV0wadjinBpNnbUCkorYxOTNrBb3NxaFF2rISFPIwTn+tMSGNLiQRoqhUOcDFW9ej8rUo5wMCROcdyP8AIrnru4sp5CTdiGTG07Xxx/KuGStJo9Sk+aCZNpsEU0sqSKNw557+9Ov4oLWMiNVX6VmWM1lZS7ba4V2zgZfk/nU+oSGTJJ7ZqH2KMU2aXF00mBvK7Scc49BXqeiWR0/SLe3YYdVyw9CeTXnekaI2s+JLIMXW2tczzbf4iMbVP1P8q9Urqox05jixFS/uBRQaK3OYz9ZsnvbE+UMzR/Mg9fUVx32d7iMFQiSLwSR+lehcAZJwB3rhtfnjk1aZ7JgCoUSccM3r/KuetFL3jqw1Rp8pmmz+zMZW8st64qjcXJdtoO52PSm3o1Vn2eWoU/xhs1JY2JhUyS8sa5mzru2zZ8N6zYaIbk6hN5Ky7QJCpIzz1x0613qsrqGUhlYZBHQivD9WvhLdfZ4TlQfnI/lXSeHPFV5plqlrLGJ7dT8oJwyj0BrtoKX0P//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-55.png', linkedinUrl: '/in/brian-lewis-de68c08ac1', jobTitle: 'Trade union research officer', }, @@ -9555,7 +9555,7 @@ export const peopleDemo = [ city: 'North Dylanbury', email: 'matthew.fernandez@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0LFMkkSGJ5ZXVI0BZmY4AA7mn15d8U9fuGI0O0yqKFkuG3ffz0T6d/wAqTdhpFnWPi1bW5mj0uzFwVOEnlbCH3x1IridQ+IfiLU3V11Dy9nPl2w2D/E1c0DwJeavarLdyrDDIOEC/MR2+lb5+E9iel3Oo9ABWDrRTtc6I4ebV0jJ0X4palp0jRagf7QiYZTOFZfbIHP416loniPTPEFuJLG4DOFDPC3Dp9R/WvNbr4XC1j8y0vXMqcjeODXOafPqXhLxZZvcF1iVwXZeQyfxfXjtVwqRlsROlKO6PoKikjkSaJJYmDRuoZWHQg9DS1oZDq8a8Rs154+uYmH7vzwrZHXAGK9lry3XrCRfiJ5zxk28zrsZeQSF5H14qKjtE0pJuR3OnBUgQAAEDpWkxJA+X9K4nUrmRBkJeEDO1LcYb86doV7fxzKs8tyY5CuBM4JGeg+tcHLpc9Pm1sdXOPkIIwK888aW8TWomaPcY/mBHUVo+JtT1B7ma2gluESIAt5IBYisCRJp9NuonkuJB5TZE4+YHHqKuCtqZ1XdNHofgtpG8GaUZTlvIx17AkD9MVumsnwrGsPhTTI1bdtgUE+/f9a1TXetjzHuOBrmNZs4vtkEvIMc+7/voEH+ldMKoata+dZSsPvKA/Trjmsq0HKOhvQqKEmn1IYbZJY+AA/v0NV7t7S0kjFxLEnzAAnCgt7epptvdbUJDDO0kc1Qurpp1CzW83TjEWfxzXDHXQ9NajnNpPr8yRTROxUFgOeap61bxxxFcAA8fKMdapMUgvR9igkRyAMNERk+tXGik1TULe1JKFuXbrjjJq0nzJIzm0ovmOs0iBbbR7SFPurEP8auGmxoIokjHRVCj8KU13pWVjypO7bFFDrvjZfUEUmaoa294mi3UlgcXEahgc9BuGf0zRJpK7CKu7I4+8vn05lSQhUYHy5COD7GtSLUILnTwsjspZeGHFSGwjvtP8mdQ/Hf1rn7rw3qcEZWzuQ0fQK38Neammeq00y5dXltZ2b/vSXCn5jV3wQBerPqT5yMRp+IBJ/lXFPoepNMsN9OGU8sq+nvXW+Dr9oL2905lxAgR0PoTkY/8dropcqkc1dycTtjSGnEf/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-56.png', linkedinUrl: '/in/matthew-fernandez-1cd32d9567', jobTitle: 'Lecturer, further education', }, @@ -9565,7 +9565,7 @@ export const peopleDemo = [ city: 'Masseyfurt', email: 'linda.mitchell@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1iSRIY2kkdUjQFmZjgKB1JNeReLfjKsFw1n4bjjkC8NeSqSuf9he/1P5Uz41eKpoWg8OWkxRGQTXhU8sD91Pp3P4V41AwEylufapbLSNW81zVNUnkll1C6lmY7my5AP4U1dVm+WT+0p1nH8W9sj8c13/hrwFFc2sN1eOwMgzsC9Aa6e4+G+gTwlBalGI+8Ca5nXjex1LDytcwfBXxRm06RLHXrtrqzJwt03MkX+93YfrXs1vcwXdtHc20qTQSKGSRGyrD1BrwLXfhjNpsUk1hKZFAJMbDn8DXR/BDXJni1HQJ3LLb/v4Af4QThh+eD+JrWnNS2ZjVpuO6PX6KSlFamJ8vfEe8/tD4j6xIudkc3lD/AIAoX+lZ/hu1judZhQoHIYHBrq/Hngu7PjDWLi04WWQ3CR7eoIBJz25JqL4caJ/xNp5rlcNANoB9TWFWa5XZnRRpy5o3WjPXNPwI0TuAOla2whBwK5a9nubYiOKCeXdhfkIUfi3YVz2k/wBsNrkjCG5ghEjKczMynBwTg9j2rijHS56Detj0G7haSJiR1HevO/B1iunfGa5ihJRJLR5Sg6HOMj8+a0/Gl1q8YhtbQSFCV8xo32k7uOvp61a+HugSDXLvxBLHNGhtktoVmfc2c5fn0GAB9a3w6965z4l+5Y9IpRSUV2nnnE+MVg/ti0tpztGoRlFJ4yyEEr+IPT2NYsNoLHU5p4owm8IGUewxmut8b6Da694auI7jzVktgbiCSEZkR1BI2/Xp+Nee+FBqcVjjV55JppGLKZGyQvQAn8K4sTTt7yO/C1brkfQ9As7iK5i2OoyR+dPMVrZ8Ki+bJ2HHArPtEKAEHg9Kj1G60qSFor9o3J6ock49MCueOuh121Ll1FBO0TSBGDL7HkVs6JgWLBRhBIQP0rgra90rztlk5zjCqwPy+wzXoWlReTpdup6lNx+p5row8ffObFu0LFyiigV2nnGZ4g1uLw9o82ozW806R9Y4QNx/P6VwSa3a+LoRqenWUtnHjavmAAuR347dvwrS1K/n1M+ddJtgHHk7sgD+tVtIs4rSH7LAAIlGYgOy+n4Vy4mT5dDsw0EpXZHa6oEwkrhJAcYb+laptvtUWVmVeOG71kalpSXKttwH6/WseK31S3wPtJWMnCrnJriTO86S20mW51KO287zQTlnx0XvXoAAUAAYA4AryPS9avtI8aQxhnmt2tWM0ZPXng/pXpllrdhf7RFOokYA+W/B/wDr134dJRv3POxUnKfoaFKKTFLXQcp//9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-57.png', linkedinUrl: '/in/linda-mitchell-825783bf1c', jobTitle: 'Mechanical engineer', }, @@ -9575,7 +9575,7 @@ export const peopleDemo = [ city: 'East Scott', email: 'colin.walker@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDoglYfijX4/D+nrIFV7iU7Y0Jx/wACPsK6MJxXiXjC9uL7xNfLuyEkMaZ/hVeOPTmsDewy41bUNRuZXuZ2kXAbHYfQVlm6LTOoc+WwxhskD3zXZ+HfBT3Olfa52dWf7qgcn3q1J8Mry6O8yeTGeVQjms+eNzo9jOyOCa7a28vL8DptODXqPhXxVFqMMFnd5W4K4SQ9JP8A69Ul+GKQxFppt7AZxiuO1rS9R8PXEcysfLEmUI7Ec01NN2RMqUoq7PaSlNKU3Trn7fplrd7SPOiVyPQkVY21ZiWwvFeFamw/4TS/DgbftjBs+gaveR0ryfxBoTT+IrfUighF9NhkBzhgcZ/ECplJLRmlOEpXa6Hoek7UtYlXptBGPSt0SHyx82QPauWu7m706NVtIHlOMLtFUdL1vXrm6jFzaeXHLwARgoM45FcqT3PRutjrrksY+OnrXnHjthFpZkGMhwRkVs+Itb1m0u2tLS0aUpjcw561h61Fc6pocsdwhWRZFByO+4fpVRWqZFR3i4o63wtGw8K6YWBDGBSc1qlaTTj5ml2rbVXMS/KvQcdKmZa6TzmrOxMBWBqmnKzTTOgYrtMZx9zBzkV0C1HeW6TWsgZckKSPrSnDmRdGr7NvsyrY3EUsYikAPbNSTR28MipEqBzydo7ZrIsyHYENjPamX9xY4w+opbTBs7/OCnPYY7j2rlSex6Sa3NGeOFtXmjmUEHDLke1Z2pJFI6W0aZ3MPlFZ0Vwkl2zS6nHeTZAyjg7SPYVr6XELjU2kcZ8pc/j/AJzVKN5WJnNRjc24ohDAkY6IoWgipTUZrqseVckUcVzHjbXb3SbCJdMKG5d13hlz8hOD/P8ASs3VPGNzM5h0+Pyk7yH7x+npXP3Nw9ypaR2YtwWY5Oa0URHV5a1YZYANhgT69xVm5tpLu0Ux2sMzjtIBg+9c/p/iCC5t/sOoFUmxtV2+7J/gamN/eWR8q2nXA4CzHGPx71w8ri7M9SFRP3o7Fr7FJbAyy28EJzyEA/Mmr/hXVbS5uL+034u4XXeGP3lIBBH51gG+uLje93KoiTk4Py/nXGC4Fzq89zGxUTSNtYccYwP5VtRV5XOfFTvFHu5NNNeSaJ4p1DSJJQ0huYuhjkY4B9Qe1el6TqkWrafHdRDG4fMhPKnuascaP//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-58.png', linkedinUrl: '/in/colin-walker-bc08fcfaa1', jobTitle: 'Surveyor, mining', }, @@ -9585,7 +9585,7 @@ export const peopleDemo = [ city: 'South Georgehaven', email: 'robert.gray@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwCCV0jjaSRgqICWY9AK4rVPGUpnaOwGxAPlcgZb861fG95JZ6THEg4uHKvjrgDOK4BFlkkXy1wScKPU1zwit2bSl0RvR6xdD9/emQluN2Dj/CoTqfnOFSQqmedp4Ga3LDwTql1Au6RYQ4+6ast8L7qN8rdozHttwPzpe1hfc09jUtsZVp4suFWO1L5K8biucjtXWRzrcQrIjA7hn6Vzl38Or+3kE0Uykbs4PGBT/D80iajNZ3GVlVcMuO4pNxl8LFyyj8SOg5py9aCOaFBzSAwPH+GttPjLbSZGOfbArmNCX/iZxOeSpBWu98UaUmrWsNoHZLhS0iMEyAAMHPt06Vz/AIU0Rk1+SG9QK9um7GcgnsaftEoNdhqlLmTtoz0ywfzQqnPTtWyqoyYEisV7Z5/lXC6wt4v7qMzJD/GU4z9T6VhaVDepqzi3FwiB9rMznn9elckYXVzvlKzseoTQExtluPSvOr63EXjhGA2+ZFlgO5GR/Srni+TVILqO3R5hGFQkxEgnPpVaxtJpNStrqZnfZbMoZ/vfeHX9aulG2pjXd1Y0ytAXmptuKAmTWpzFm7haRCYiUkI2b16gHris5LaODUxPFkMIljOTnOCec1tJjoelZEkckF3IJZmkJOAW7Dt+lZVFbU6aM7rlfQ3ob1bhBCy/PjG4Uj/ZNOwHaJd4LPI2FVQKy7R8SAE5PSm6hqVhPbvDdRBwDlsxlz+QrKKvodDdjZvzY6jLatFNE7eXjkg5rPuNhZVVNpQEH3rE0+901ZyLVmB+7ho9uD1wK2Q28Fj61pGLUjKrJchCRzSqKlK0BOa2OMlhLSMdoJwCxwOwGaxvtP8Aa9mL2FHiWQZTd144zXokUUEERjhjVUPGB3HvXH3kP2OQ2oAAj+Vf93t+lKuuWKNcNrJ3MGDUGRgjugkU4Of6VqxJ58BSG4jR85B9/WsS/wBND7njkAl75HBrLjN6jECbaF/iBrFJPU6eZpnT3CywQvJc3KS7Rnd6VetC7afazSRtH50fmBW64P8AnP41U0DTRvSXUHaQNysZGc/Udq7O3NrqaSI8QfyW2nHb8fyrenFddzmrTctehzmaVetdDP4dhkXdBJ5R9DyD/hWbPo93akloy6/3aP/Z', + 'https://twentyhq.github.io/placeholder-images/people/image-59.png', linkedinUrl: '/in/robert-gray-2c8a3e5f3a', jobTitle: 'Development worker, international aid', }, @@ -9595,7 +9595,7 @@ export const peopleDemo = [ city: 'Lozanofurt', email: 'natalie.lawrence@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-60.png', linkedinUrl: '/in/natalie-lawrence-d8c06e2d82', jobTitle: 'Therapeutic radiographer', }, @@ -9605,7 +9605,7 @@ export const peopleDemo = [ city: 'South Michaelbury', email: 'mark.castro@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDe2qRkk0ExqOM5o3EDGys/WdQOm6VPcqo8xVxGGHVj0pMERarrlnpKjz5MysMrEv3j/hXO3HjaR8i3Cp6fLux9T0o0DwqurudT1R5HeU5wx5b3P+Fd1YeCdJ8tSUHIx0rF1dbI6Y0Ha7PPovHMsUxWWdHU4xmPGD9RXS6X4ktdTk+zkiO46hc8OPUGtbUPh1o00e/y8Y9DXEeI/B7adAbrTJZA0XJTPQeo+lJVdbBKg7XR3QUnnkVIgwOuayPC+q/2po0UkxP2mP8AdzjH8Q7/AI9a2dyn1rdHMNO4fw1y3jK5McNpEw+VnLH8P/111pQnGG4965XxrbebBaFWUsjkOoPIVuAfpkUT2HBXZtaPj7LEi9FAxj0rq4EQxDEuT6Zrza81GfS28uASMwXhYxyTip9B1zVry9itpo2UyEcsvIHvXDbqemn0PRJ1Xy8GTHsDXLavIkcUnddpzkVia5r+qWd7NbQxO5i67Vyfw9ajtdSuNSIhulkGRyrjGKLdQb6CeDpVMupIgAXzFbA+hrqyT6Vyng20+xy3iykB5ZNsQzywXOT+tdcUPc4Fd0HdHmTTT1HbQeRisLxBp4mKXCLmQqE/AHNdAUz0wKguYGniMecHsTROPNGw6U+WV2Z+nPb3cAR40LAfeI5qyl5p9hqsKSyxoARjJwWPXisO23W1y0Y6gkH8KZf6hps6rFOjGRcjesRbbnqc1w2d7HqJpo3UurC+1CZI5opNzH7pBIPoaiv3t7RSkcYDEYzWTp2qaVCpigR1LEAs8RUk+uaffuXkJLZI4FJrWwN6FvQ7BUuPPJyRuZfUbuufxzW+UBqLT7BrW2CPtLnrtGBV0RYrupx5Y6nm1p889NiLy+Mik2GrO0AVDJNDGwVnUMegzzWhkcrr6/YdQWQHaJV3E+/Q0yGL7TCnlXghOOCKd4md5ruE8+V5ZAHvnn+Y/Kuf2SREBWIFcVVWmz0KMnyI3zH5ET+ZeCYnuazXvIYZFnncmCAh5SBngHNUSJWONxOew71dl0wXGjXNv0eZCgx1yeBUKyZcm5I9HjdJokmibKOAyn1Bp+2shJptMtraBLWS4iRAsnlHLIAOoXv+Fa1u63UIlgbeh7j+o6ivQs7XPAAAAAAAA8w//9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-61.png', linkedinUrl: '/in/mark-castro-4184957d96', jobTitle: 'Engineer, control and instrumentation', }, @@ -9615,7 +9615,7 @@ export const peopleDemo = [ city: 'Boothville', email: 'melissa.molina@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD03imPgDNOzTHPakwRXkkCAsSAB1NcL4h+I1vYs1vpoWeYcGRj8gP9aZ8UdXuNN0qG3t5jF9oJDberD0+lcJ4f8F6lrES3VxJ5MD8qCOSKhysaxhzbBf8AirWNSObi+dk/uIdoH5Vm/wBoXvzLA0rx/eI3HafrXocHw5skjAeaRz9aydb0BNNt2igyqnqfWpVRFuk0cha6/fx4C3k0ZU5wjnAr0Twn8SSXisdXIbLbUuievoG/xrzm5s4yuOFbviqTBUJUAY9OlWZs+ovMFNJBqIHNIZADigk8l+JTPf8Ai+w08g+UpjT67zzXoNtCsMSRjChRgAdqxvGunRTG01ZbWWae2fBWPqy4OPpg96qeFp7q8jmjminiUKSBK24jn1rGojponWgdwaw/E1iLrTnKKfNUbl/wrnppbuw1kQpZ3NxuI/emY8f0FdLZzyX0ILRzL6iVcEf41ltqb76HimoXJW5cEYwelZzTAuM8jtXbeP8AQktroXcAwZPvKOma4yGwup4nkjhYqnJPT8vWumMk1c45RalY+ngT2pBwaUU4AGqMytdFRCwIGDxVC0jtrdZFh2BnPIzgmr13CZInUdxxXITyaRHcql/LiQHcUJ7+tYVb3OvD2tY6UQWd03mMillODkUlxcRwRkKB0rOtr7TrjEWn3Cs2OVB5/GnSRM5+YkgGsJM6UkYesW39qKiuo2Bskmsy5tk0rR7ueVUFsgLAFcHIPGPr0rfv5jHhYQC46A9D9a8u8aa7eX+oLp7kR28OCUU/eb1J7+1XBOTsZzkoK59ChDmnhTU2zikrssecQuveuW1TS3a+ZovKGfmG9Qa60jIqhfafHehd0jxuvRkqZxutDWlU5JXMaK3+zwguEVvUVTu9RWMbdwLHsKTV7G6tHCLcu0THAJGD0H+NQWmm4O+Q5PvXFJNPU7oyTV0EMDyKZpOuOBXk+uafcT+L5LdELPMy7PfNe1lAY9oFZa+H5LnVIry0gRrmHIVnHAB65qqUrSM6sbxP/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-62.png', linkedinUrl: '/in/melissa-molina-aae4218215', jobTitle: 'Psychologist, clinical', }, @@ -9625,7 +9625,7 @@ export const peopleDemo = [ city: 'Murrayburgh', email: 'terry.melendez@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDe28VwnxB8Stp1uulWTMt1Ou53Q4KJ6fU/yrviOK8I8YTm58X6kzZ+WXy1A9FGP6UAZI5AyCzk8880shQAKhIbuHGPyrqtH8AahqMSSvIIVYZGRk4rfb4WSmMKL9ix/vJxWLqwT3NlRm1ex5udojLA7WxgqeeaveH/ABBdaJqKyQuxiY/vI88MP8a7+L4TxiP97dncOyrxXI+J/Bc+hJ9oSQSQbsEgcrmmq0G7Jg6E0rtHsFlcR3tnDcxEMkiBgR7irO0YrjvhvqH2zw81uQc2smzPqDyK7MCtTAeeleKa5ZM/jq+i253XOcDvnFe19q4ybSA3j611IqAs6uCh5wyDGfx4rOpNRRrTpubOusUSC0hUlVIAXk98VqRqdowQfpXIaxaoWzcW93cIASqwtjGB9RzR4dM6zpFbrdxwMA4S4fdjPb2PtXDyq1z0uZ3sdg4IUnOB71xnjOMS6JdKq78Lkgc9DT/FE1xuZZo7uSJOqWrYP+eaqafYKJJUQXSxlSHjnbd19DQkl7wpNu8Sv8N7ZI/D80q9ZbhifwAFdlisLwdbCz8OxQBcFWbJ9STmt+vRTuro8uSadmJ2qjcWyC6juyoLIdqn+7nOfz/pV4dKiuEzCx9OfyrOtDmjoa0KnJLXqaMSx3EeSAfYjioyIkuFjiA+UgsQMCqttLtQEHjGaqXdxo87IbiZA6NkEOQQfwrhXY9I0WER1CRJCpVzweoz6Uy+SG2t22gAkY4rKt5tIimfybhXkcjJaTk/nVq7Yzsi5zkgUW1sDdldkttGIoERQAAO1TUgGBS16UVZJHkzlzSbEFcT4+1qW3ihsrSVlYSK0+04yMjC/wBaraz42uJJPJ079xHnBkIBY/4Vy8lw955hndnkY5LMckmqsSmenLcta4WRsIehq+sIuYg0bRqccHGaytHu4tZ0eNmwZUULIp7EVFc2V5EwFpchAf4W6V5Wzsz1lLqjRltVgBkkMTMO4A4rGu/E8WmavYw3CboZ1YmT+7jAz+tPit7uaTbdTBwD0UYFcn4yKSa3bIpy0MRz7ZP/ANatqOtRGNeT5Gz1KOaOVQ0bq6nkFTmn5rxSK7mt2SaGV45E5BU4rqtK8cXS/Leos6f3lG1h/Q0Fd9jzj//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-63.png', linkedinUrl: '/in/terry-melendez-692cdf776c', jobTitle: 'Public relations officer', }, @@ -9635,7 +9635,7 @@ export const peopleDemo = [ city: 'Madisonbury', email: 'charlene.beck@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-64.png', linkedinUrl: '/in/charlene-beck-810d5075ae', jobTitle: 'Tax inspector', }, @@ -9645,7 +9645,7 @@ export const peopleDemo = [ city: 'West Geoffrey', email: 'yvonne.avila@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDexRiiq1/diwsLi7YZEMZfHrikBR1jxDYaPG3mvvnx8sKcsT/SuVtvFesahI5hZYo+w2/41ysMV9rOpkITJNIxb1PJr0LRvA2oRRq0l3H838O3OKwnM6IU79DHt/GF3ZTvHcO0xzg5HT8q6Wx8S29xGpmIUE/eHQfWln+GtvNCw+0PvPPA4zXLSeH73w/ftbz/ADQuhKEdDj+tSqj7lul3R6GrK6hlIKkZBHejFc54Sv8A7RazW247oH4U9lNdJ2roi7q5yyVnYMVw3j7U545IdOTcsTgO7dmzxiu8FeefEu48uSxiC9mct+mKUthw3NDwTp8cdn9oVQZJGPzY7dq9LtFxGAeoFeWadJLaeHLLYs++WIcRNt5610Xhe+1L7VBbzvM0c3IM33l9jXI11O+L0SO+t/wrnvGenC60eWeP5ZoAXUjuO4/KsrxRPqFrcnyHujGv8MLYyM/rV2x8+6sJreSGeMmMj94SQ2R70W0uNnm+gztYeIYJlkDQ3H7skd89K9J6ivMdFjlW/e2lU/uZ/lJHT6V6dGu2ML6Cumm+hxVV1HiuI8e6dcXk9jKqFoEOH28lckc49K7gGqWrsIdNubnGTHHux64q5K6M4uzINB8n7DFbzINyKFwe2K1oPJXWrdBtRV59K5PQ7t7yMzY2sHwfcdjWjdXml/bU+2SESR52lc5U4ris72PTjZrQ7T/Rp5CG8tmycHg5p1y0cMRwOccYrE0690W4QJZyokgbJAG0lu/1qfWLoWOn3F45ysMRfB7nHAofYbSRx11ZHTtSSU7Sbi5Lop/u8Z+nJrqF6Vzelvd68y6neRIgbGxVPCgHgAfXmujUYFdNFNLU4a8k5aCgUkkcc0TxSqGjdSrKe4Nan2BNx5JA71WngWNgNuBmtbmBwOl3gTVNQ06O18hbZskly7PnoST7CuitrUXjK4mCN64o1PSEtNTGrxJ+7mjENxjtg/K36kflUYsXWbEc/lbuVJ6VyVNJHdRl7t0dBb2wt4NryI/+1jmsbxPDLqttb6dHIFE0gZxnBZF5I/PFaNjauqEXEplYenSqdvDJqfjqGBFJhtLdnZuwLZGP8+lKKvIqpJ8rZJaWUVjbLDEMKvvU+Ks3VlPaNiVOM43DpVaux571P//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-65.png', linkedinUrl: '/in/yvonne-avila-cd93548e92', jobTitle: 'Merchant navy officer', }, @@ -9655,7 +9655,7 @@ export const peopleDemo = [ city: 'Lake Kathy', email: 'andrea.garcia@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-66.png', linkedinUrl: '/in/andrea-garcia-21bf3350f1', jobTitle: 'Contracting civil engineer', }, @@ -9665,7 +9665,7 @@ export const peopleDemo = [ city: 'Daniellehaven', email: 'mary.goodman@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwCjvOMVzusa+YJGt7TaZF++56D2HvV7W7yS10+Rom2ux2qfr/8AWrhsCRwm/gnnn9TUyl0LhG+pbbU3kZne5ZpSOp5xVCW8MkhZgNwFXLlQyRw2qKF6bieT7mlTQLy5fy4IWcDq+OCazuluacrexTh1CTBDP+NbWm628cyRzNuhbjJ6j3qKbwff26LM8Y245C9qxvmin2MDgHnNNST2JcWviPQS2ehyKFPNUdMvEu7RSrAlflI9KvCtTJmL4om4t4yTtO5jjv0Fc7GvmnCptXoPeug8VW0syWvlKTlip/HGKh8KaabzxBBAy5WPLNn2rKo7XZtTV7I1/DXhSa7Zbm6jIT+FT6V6DDpkdtGFWMD6VR1K/bTYDHFZvO2Pooqtot1e3FyscpdVbDEbtwXvjNcju9Wd0bR91Gvc2waBgVyPevLvF+jpasbuJSDn5x612XiPUr6K4eCDf5cfLbDyfaud1aU3+jXi+S0ckUZ3gtuBPXINVC6aZNSzTRzfheVhfSoCSrLk+1deBmuZ8JQfJPKepwAK6deK7UecyUxo42yAFc9DVnQdMey1GS+ddquSijHUetMlt5g5QRMW9AM0+y1S6tb2PT7qFBHJKBGxOGUFT29MjFY11dXR0YeSTszuEaOePBUE+jCq8r21tJ5eUQjBZiQACegpLfOOMn0qpfX+mxptuU85wdxAjLYNci10PQsitOIW1uVd6urqD681l+IYoU0+eKBAHdCoA7nFOW+097xjbIyOf7ykZ/Oq19Nm5RmQsM5IHoBkmqSfMkROyi2zE0zT10+0RMfOQC59TV6tG70t4VLxP5i43Yxg4rMrvTueUzs9Gspf7TI+ZiIiCccA5FP17QooVtbyVUaZHVEPO48+g/Gu5ttOhs02RoAScse7GszW9PN3HtUkOjCRMdyO34jI/GsnG0X3NotOSuc3HN5PyscZ6E1I0KSxkb1Axwe9JcQRywDPNZ9xaSxoDDKdvoa4U9T0NipeW6wSBw24+pqK0aCa4JmRW52o5GRnuKZOsjN87bsVNouns1k8cnV2Mqn8Sf5V0UUpSMMRJ8prTwH7OrcAqpBrmL60ELmSM5jJ59jXXQbvJMUvJAwDWXNbDEsbA7WPP5cVZx7o/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-67.png', linkedinUrl: '/in/mary-goodman-97470c0612', jobTitle: 'Metallurgist', }, @@ -9675,7 +9675,7 @@ export const peopleDemo = [ city: 'Lake Ryanbury', email: 'shelly.powers@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD08dabI4QEscAU41y3jq4vItFWKxlaKZ3yX6DaOoz2zmk3ZDSuzJ8aeO30Rvs1nsMrJuVzzj8K8guL172WW8upRJLISWLcc1BfzTXV0SdzMx27c5Nbtj4G1S+CtKqRRkfdbr+NZOS6mqg+hzrlDlS7MGH5H2pisURkRNxHcc4rqtS8A3tvH5kRUxqOdtcxJYTWUuJWKMrD5vahSTBxktyDzwyYIz745Fbvg/xfP4V1cXUeZYGG2aLON4/xFc+0KgsDIQTzmogqkHbjgfnVEM+ua4z4iXy2+hmDI8yVhjPYA8mu0rzf4lx/abVg1rIHiwqPyAwPv0qp7Chuec+E7db/AMWwFlyI1Z8Y4yB/9evX1QooXHNePeHvtdnfl4bZjJLEyxNv27eRls+leg+HtT1G9huIb2LZLDnEgPDDpXJUWtztotWsbtxGJI2RuhHNeZeK9DnSR5VyUwTnFbN/q2vxXb+WpeFOSoG3cCccVdWWXVLZklgkRuhD4I/AjrUq8dS3aXunkEgEZKkduaFx8pHTFdD4p0tLO9DKmFYdB0rAVNkZIIx2rqjLmVzilFxdj61rA8YWUt9oEkUMZdw6twCSADknA61vZzUVzG8lvIkbbXZSFb0NaPYzWjPJvDSCXxDLJJAEjSJokBHuM/hXVusUEM3lKoB4+UAU+/sPssC3BhWGRTmTBzx3rEvDp4AS4u3hYHJ2scn8q4qiakejQalE2LWC2u0YSKjFeqsOlR3hit1KRgADgYqlZXVhytrdK7E/38sfrmpZ0Ln5jWcn0Nkkcd4i05tQKMMbUOTnvXL6zp0ekWe6cr5soxEg7c9TXfamoeExr34NeSaw7PqkvzlgpwCxzgVrRu3Y5q7UVex9aCg0gNKWFdpwFS7s0ukMcnKHqPWuW1DS0E5Xf5a4yp9fauzGWOAM5qCfSor4eXcplUycg4I/GsqsbrTc3oVHCV+hwwtEtORsJPcDk1FPeAKQDkntU5t438wbmIVyv3uwNMFiiMDwQemK89vU9G99TOkhY27u33mB/CvL77w5f3OoSNbwl1PJOemT0r1ydXmIt4ELyMcKo71cfRk022jt+Gk+/Iw7t/gK1pSR/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-68.png', linkedinUrl: '/in/shelly-powers-8790890d27', jobTitle: 'Glass blower/designer', }, @@ -9685,7 +9685,7 @@ export const peopleDemo = [ city: 'Morgantown', email: 'holly.hensley@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDVK0gWpMUgFcjOsjmlitoXmnkWOJBlmY4AFcVqfxEhjkMek2v2rHWWQlV/AdTWV4/1ma+1ZNEtdxSIjeq/xue34VNpPwz1K8hSS6nW3zzsHJFXeMVeRPLKbtFFC7+IesvKjwmGJQOUVM5P402y+IGuxTGSQxXEecsjx7Tj2IrtG+F9mlqUSeRpCPvHsa4LWfDF1oMzq774+zAYzRGpCTsEqVSKuz0LQvFWn6+THFuhugMtDJ1P0PetkrXga3MttcLPBI0cqHKupwQa9n8Lax/b+hRXbACdSY5gP7w7/jwaco21RMZX0Z0GKaehx17U/tSY5rNlo878L6St34z1e/nHzQTsqBv7xJ5/L+deq2wCoBuB/GvN7oQ2VzrExsp7lZb0gRxEjnYpJ4/Gtvwss7XAhVZ4omTfslcttyM4z/Ssaqu7nXQ0jynZO4AOGA/Gue8QadBqVk8Ey8sOGHUGue8QefDfiSS1u7sZwqxyFVA+gq/YSySsYVt7iHYcFHO5fqDUW0ubXu+VnjGpWzWd7LCw+6xHNegfCl2az1OI9BJGwH1B/wAKzPiLp6w3sFzGuGlUh8DqRXQ/DLSrmwsr+S6jMckrRlUJGduCckduveu1TUoJnmSpuM2ux3NAFOxSgVNh3IbS2tlluY2QESSeY271IH+FSw3VhaTzrvji2R8duveql0HS4DJn5l5xWTd3WkTzfvYJZXUbSY0J4z0JrlknzNHpUkpQVjorWayvsRs8b/KCGUhgRUl08NpGfKVQAO1YlrqejxIbe3haB2OQrRlTmp7nzHGGPFQ9NDSxg3touo38crkYiZiuRnkjFb+jW7JJNM6qrMiowUdxnmsCTUWtdWtrWG2M7zEqADjZ/tH25rrokEUexfxPqa2pRd0zlrVIqLit2OxSgUtQT3lvbgmWZFwMnJrpscIXkMkkBaIZkXkD19qy4rW2u1DPMYmx26/SptW1GaLR55bYPHJ5W9WYYIU9wPpWTe20ixia3kYHGevX3rnrRSaZ2YWo7PsbPkW9lFjzRJx1IrMu9RyCiNuY9MVkILq4bDuSPQGtCK02LuIrB2OrmbLmhaaHvH1CQbmA8pD6c5P+fauj8usLwrqLTy32nyqAbdwyH1Vhn+ddIQK7YfCjzKl+dgAAAAAAAAAB/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-69.png', linkedinUrl: '/in/holly-hensley-111036f6da', jobTitle: 'Geophysicist/field seismologist', }, @@ -9695,7 +9695,7 @@ export const peopleDemo = [ city: 'New Kelly', email: 'christina.davis@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDLLHdRJJ8uM0SDbk1XLZapLMPxLqs1tGtpA215F3OwPIHoK5iK3KxGaQFs9F7/AFrbewn1jxFNBCuX3YHoAK6BPh1qaNG0k0boeoXtUOpFPUuNOUtUjg3tgsDSISVI4HrUAQPCCCQ47etepzfDtBE3708joO1cpq3hO406CScKzJ32jOBSVWLG6M1rY5MuVOMjI65rtfBGtNvfTJGzuBePP6j+v51xZiZt3tzU2mXDWOqWtwGI8uQEkemef0q2tDNOzO6tPEFrfMIj8kh6c5B/GrpHNeb2zOtwoXsa9Dt38yCN88lRmmgLPg+BR4k1HgbhtK/Qk5r0pVIQBh+lecW1h55aWKFDNuRTMWK+WOeeK6zwzqOoTQPa3qPvj3bHc53AVx1o+82d9CXuqJsTRlk+7WFqsHm2zxeoxVDUrrWJJZ5lnuHghXeYo2C7hnGF4JNSWTy3kYGLlXXqkxDY4z1FZ8tlc157vlseQa3byWV+8bxmM5IOe9ZYBOeK9K8b6U11BG0Ue6UOBwOaq6b4bi0/w5eXV8itM8LnB5AXBGP97OK6o1Vy3ON0W5tdDlNNiLy+Y4yfpXUWtwYPkPKisbTofKX3PWtH+HPc1oc56D4QeKVblTg9DXRsiRmYrhQqY4Feb+F75rTVIxuwsw2H69v8+9dwbuJ45I/tXk5+8O5I+tclX4z0cO06duqLdnb290v3Vdk4IPUVYnhhtITswB7Cs61ntYnPlzgyOQNxbr7VJcrJNwThQMms2baHPSlXuS8hARWzk9B71ynjvxFbRWh0uxmE0sn/AB8SA52jOdo+pxXWyqDIVA4FefR6HDqWt6i9ypZRKcckY5/wrWik5anNWk1Gy6ixqF4xT2ODj0oUZmHoOas6fZtf3uz+Bfmc+1dO5wk9jbyTkMmVCnO4f0rt47V7+JGZUeQDDhh39ahtNPjhRQFGFGSPU9qz7a+mTxHNFFKRDHES47Ejkn+lKpTutNzahW9nK/Q37XSUtZjcSJHvA+VQOBRc6huzFGdztwAKgtZbnUrMNNIVfarFE4BBGeKs29pbxMPKRge+7rXDJ66ne5X1Ivsmy355Y9TXNT2yW5uGjXDSNyfU9P6V195KI4Pc8CsMweZOi+nJrfDxbdzmAxElax//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-70.png', linkedinUrl: '/in/christina-davis-2b07b44392', jobTitle: 'Chiropodist', }, @@ -9705,7 +9705,7 @@ export const peopleDemo = [ city: 'Port Markhaven', email: 'adam.cochran@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDFFUdW1VNKtlcrvlc4RM4z7k1fArzzV737XrFw+8sisVT6Djihght7fXeo3u6VznsinCqPaoWZkmwQwBz8wrpNI8IXmqBZGkERddwyMnFdbY/DqNEInvHbI5CLgVhKrFHRGhN9DzhNRvIdkK3LJgblKnoa6HR/EMlzcpaXcah2HyyKep966PUPhnaNmS3uJEYDgEZrgNY0u60K+WNixAbMbgYz/wDXpxqxk7IU6Moq7O+pCOaraddLe2MU4IJKgN7N3qya2MBkwPkSbc52nGPpXnWl24lu1VsYzg16QRu49eK5e10WfT/EUMFwhkgZtyMn8QGfXHpWc5WRpTg5M9Q0hES1jHAIArdTO0cZriL52MIIW6aNhxHCNrE/WpNCmuLZhIz3YSTHyzybiOeOOxrh5dLnqc2tjsJmIU8VwHji3il05mYcodwI7VoeJbq4uDNGGufLixuWA4Y1z93DLJpV3GpnIMRBWdskN2OaqKs0yakrpxM7wmNulyKTkiUn9BW9Wdo9m1jYrE+N5O5tvTmtDvXoLY8p6MM45rRuYYrhbS7AIaI8enIOazat29y6xC3IBjLhs9waxrQ5lddDfD1FFtPqdTYpFNEMj5gOKL1baJ0RigbIJLYGD2qCxb5VINVr29sJ22XRjJU52ldxBriXY9PQveXC2rSqWQllB6g81Q1i1h8kxKdvmHaSB61Wgn0+C6JtJELnGQcgn6Zp+pzbGEjfNjGBmmk+awpNKLbMNwFkKqcgHAP0pAeabz3pa9JKyseM3d3HKMmoL+6ewmtEKDy7kYDH13Yx+XNakFk8hyBgDrmrd5pcep2KQkDfE6yRH0YdKUthx3VxlndtAfLkcBl5XPcVsKFnj+8qsRgHGayJLBb21G9cSJwR6Gqpi1OBc2rpIi/wk8rXmrfU9e7Wq2NeaBYQWZlZh3IrCu7z7VKVVgwQ849aHXUZpAt2yjjJVfT3rO06OSS71FiPlEwVff5RW9FJzuc2JlLkLBNIOtL1YgA5FJjFdgAAAB2nnn//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-71.png', linkedinUrl: '/in/adam-cochran-1657e82dbf', jobTitle: 'Communications engineer', }, @@ -9715,7 +9715,7 @@ export const peopleDemo = [ city: 'Johnsonland', email: 'katherine.abbott@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-72.png', linkedinUrl: '/in/katherine-abbott-ec30f06ab2', jobTitle: 'Solicitor, Scotland', }, @@ -9725,7 +9725,7 @@ export const peopleDemo = [ city: 'Jameshaven', email: 'jenna.mendez@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDl80D2pualt03vz06mlJpK7KSu7IntLCW8cBOPc1YeO30u58u53S4GSF4FRJ4gNvex2VpatLK38KHke5refQdRvf8AShtSZjnDAdMelcUq035I640Ykdr9lvUGy2VVPdTzT73QnSDzrZjIoHKkcimGzutObzZ7ILg/M0HGfcgVtQX0TogDZVhlW9P8RURqyi9xzpJrY4otg4NPRua1NfsVjkF3EuEc4cDs1Y6nFd0JKSujjlFxdmUQaZe3f2WwbZ/rHIAqQDmsjVZcOpP3VBb6ntWdd6JGlFa3Ow8A6YvlyahMN00p+U+gr02FMoPavM9Pv30fRLJFtpZpJIhtVG24OMk5rpNA1DUnlgjuBJ5c2GHmclQexNcjT+I7lb4TqnhWVSpUEdK4jW7OTRroXCgm0kOGA/gPrV7xNfajZS5tzOyLyViOA349ar/a59U0y4tLizlhcRnktuVjjPX1pNaXH1sVzMlzbvCzghxwc/ka5wqVYqeoODUek6i2Ht5mOUOFJ7Grl6pW6Y44cBx+Nb4aVm4nJiI6KRmCud1hwztg9QQPwrowueK5vW4GWQlfU1tV3RnS2Z67oElpdaZa70Vh5akAjPataSW3h1C1iLJGucjJxk+lcP4JvBd6LAykhoj5Tj3FdJdX6C5SN9Pe4K/xHAH4E1w2d3E9OKUkmjo457S6leMPHINxwRgjI6g+9JdtDBEVCgDHQDis2yvo5VEZ0+W3OchlAYZ+o/rT9WuEtbGa6nbEUMbO34CiV9hctnqeT3Y+w65IGQiKdzgHjHPBH51vznzbS3kwcgFTXPSSya9JHqLBV24xHGDhf9nnrXRlPLsYImI3bdx9zWtP+IjmrWcGZgFUdYt1axeYgbsbR71q+URStai4j8t/u111U3HQ5KbtLU53wpqkuk6qtuQWt7tghGfut2Ir1S0mtnP74bvY1xL+EJoYotQZGSOOVfLyMFjnt7V10VvvKg8bh1rhrfF5noUH7vkbQns4Yf3eFH93Nc741aSfwffYyqkL14yNwrobWwhjXeV+b3puqafHqGny2soJRxggcVmnZplvVNHlXhaVIt8JUOvG33PeuonhJuM4O0jIGOlX4vCTaXo6XdsPPm89gPM4ymO34g1cjtZbyKOaSBohtAAJBzXVRT5+Q//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-73.png', linkedinUrl: '/in/jenna-mendez-38ef424a7f', jobTitle: 'Automotive engineer', }, @@ -9735,7 +9735,7 @@ export const peopleDemo = [ city: 'Lake Ronald', email: 'steven.barnes@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1mkpaSgBelefa98WNJ02R4LCF7yZWKmQnbECPfqfwFWvijqtxpvhQRW0rxS3cwh3IcNtwSQPrwK8hj8E63JGP9D3hvVqmUlHcuMJS2RsXHxZ8S3E4ngmghhGf3UcSkEf8CyTWxpnxmuop4l1S0hntyQryQgq6++Oh/SsW0+GWpvF5kpii54QHJxVa/wDh3fwRO0QVyOcBuaz9tHuaewnbY920bX9L8QW7zaZdrOqEBwAQyE+oNaVfLWh6rqXhvVBeWTyJMjYdWHDDuCO9fS2h6rHrmiWmpRKFWeMMVBztPcfga1TMGrF+kpaKYHGeN7UXer6CjjMSSSybf9oBcfzq/bxlEXOKq+P4rj+z7S5tWZZIncFkGSAV7e/Fc94UvNbnYJfs5ikVyruMMuPUVyV43dzvwsrRsdo5YIRxWHq03lWzsvLAda5TUn8UjVVSGeZ4C4A24A59fatuykv7mMreR4I4JK4J+vasHGyudKldtHmWuWokujKzYB52+9esfCUyjwlNG7MY0unEeT0GASPz/nXDa5pTHVnt7aPcZBuVBXpHw6iS08MixZ0N1FK7TKv8JJ4+vAFdlOadkedVptXdjrKUUlFamBn60yrZKXHy+YAfyNYP2mxtVnMk8MRVB1OMZ710GsxedpFwAMlV3j8Oa811DVNJivYYryGSWc/dCJuPHOD/ADrlrp856GFa5GdjYSWt5GWSSN9uOVIYEUXssUKsEwWYday9K1eyukVLJSq88GMoR+dSXrqBmud6aHXpuZX2dJrySQuUldRGGHJAz6Guu8OW+2S4ujjcyrEcdDj/APXXJ6Yk93rEcMW3EjbWLDkDqSPoM16NbwR20CwxLhFGBW9CDb5jkxNVKHIt2SUUUV2HniModGRvusCD9K87uNMuoLiW3EqwyIx+cgHcvY/lXojEIpZiAoGSSeBXAeMNWs9QkhTT7hWljB3zx89wAvoRz+tZVYXjfsdGHqOErdyVENrbKJJ1du7etZF7qHnERQsGYnqO1Y1vaapfTtHNe4jBwQODW3b6StrjJ3N6VxNJHfzORd0G7s9J1KCS+nWFGBRXfoXbgZPbPNeiV5D4os/tOiToCFcYKY/vZGK7rwprkd7p8dnPMovIRswx5cdiPWuvDu8DhxStAAAAAAAAEz//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-74.png', linkedinUrl: '/in/steven-barnes-f5d1f0c993', jobTitle: 'Occupational hygienist', }, @@ -9745,7 +9745,7 @@ export const peopleDemo = [ city: 'Spencefort', email: 'ashley.manning@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-75.png', linkedinUrl: '/in/ashley-manning-8b3cc7cf6f', jobTitle: 'Firefighter', }, @@ -9755,7 +9755,7 @@ export const peopleDemo = [ city: 'Amytown', email: 'david.peterson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDv68q+Ifjy5gvZtD0uRYhHgXFwD82eu1cdPc16Rrd1LY6Ff3UHEsNu7oT2IBxXzK7O7NLJlpJG3F35LE8mkyiXznmkLzSvI3qSSack4EuYmJPdTxmrtjoOoX6gW8JGed1aB8D67M3McX1LYNZ88e5oqc2tjEg1S602VbmyupYn9UbB+h9a9m8F+PbfX4orS9ZIdQ2/RZfce/tXnbfDjVDbsxZC/XaDWDPp99ot3GsiMjqchs8cGmpxeiYpU5JXaPpijFVtOlefTLSWT77wozfUgVaqyClr8Pn+HdSixu3WsgA9flNfOVhbpNfRIxLFmAxX0pqdytnpdzcPGZFSMkoP4vavG/D/AIdFl4ueGcBliQyxkjqCeKic0i6dNy16Hf2MMcNvGqIFIUdBV4Rg88Vyes/a/NAWW5SMfdEA7+5qnoN/qzXiQvNcSQyc5nUbh7cVx8ulz0FLWx3ZQ89MVxHj2CM6T5pUbo3B3Y/D+tT+KNR1a1ujBaNIqKAzNGAT9AD1rLuI7y90DUI555pf3ecTKAQ2QeMVUFZpk1HdNHo/hPzD4R0ky/f+ypnP04rYqtpoQaTZhAVQQIFB9NoqzXaed1G3MIuLSWE4O9SvNcJDYm11JJ5cmch1Zj3BIIH4Yr0AVg67axpNDOCwZyQRnjNZVo3943oVLe6+pCgSdSCo9Dmqzi3huPKjVQy4LHgU6KdUjbn5gM4rAvp7bUTslAGxtwIUswPrxXKlc7rnQTC2e+xIUYOAB0PNMvrWFoXhCAiQbSAMVz1vJBbTsxk3uwAy+QeOmM11Ngv2q8gznAG4/lTUdbEzlZXZ0MaCOJEAwFUAD0wKdS0ldx5YpIFclfX17f6rfWU0IS2tXAifu2VB/rXV5/eZ6is7VLPLm8jXqAsmPbof6VNZPk0NKDXPqcpNMYJPKd9pIxk96lLxvD5fm+Xxj5OtPv7UXERAIB7HGa56S2vYn2qygDuWrjTTO7VGyRHHCyecJeP4+tbHhieOS7uo2z5sSJ16YP8A+qubsbPEokmcyH0x1Ndbo+nPaSTTy8TXJBK/3VAwB/n1rWiry0Ma8ny6m7RVVQ6LIUyxHO30q3//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-76.png', linkedinUrl: '/in/david-peterson-296c6d71cf', jobTitle: 'Scientist, water quality', }, @@ -9765,7 +9765,7 @@ export const peopleDemo = [ city: 'East Michael', email: 'patrick.ellis@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDWwKYU56VYMZzWN4q1CTS9DkeE4nlIijPoT1P5Zrl3Z0dDD8Q+N4dLuGsrCNbm6U4difkT29zXHT6tr2ssxe+fy1/hQ7Bn0wOtdn4W8H2E1kJr2LzJZ+SSegro4Ph7ZwEfZ5Ts3bgr81SnFaD9jJq55Vb+Itd0mRdly8iJw0bncP1ruPD/AI1s9YkjtrhTb3jcBT91j7H+lbzfDnTmR3uJXZmzkLxiua8S+DILW3W604mK4gO4En7wFDlFuweymlc65o8mmmKm6HdHVNHt7pgPMZdsg9GHBq+YDU2YiXaK5Dx8m6307rtEzHp7V2fl85Nc74lja6MULKvlxujKT3JOD+hp3tqOMXLRFvRV22cAPDbBXTw5EY5rgdQuNQsm/wBD8zoSqxpuJx9e1WvD2ta3czx295BtL8q5XBx6EVgl1Oy/2TtXZipwe3euY8QuVs5OCflOcVU8Q61rNrcSQ2duX8sZYhd3HsO5qrZTX16JBeGX7nzJKgXBI7Yp26g39k0vCFsY9AQ9nkZx9DW8I91ZXhrcukxQ5+REG3jpnJNbsait1rqcUouLsyBRkVka1AGh3cHaN34g1qAEDrQ0CXEZSRcgjFDjfQIT5XcqWBgubdUkUcDrUwjgj1CGOFVyrAsRWHbmSFigJ3JkEe4qpc3UNzKpMrQzJ0bkVhFdDvurXOqaO3bUJEnC5ZvlJqvqQitoGVAOR1rnbW6htnkL3PnSORksTwfbP9K15g1zPFETncQP8/hQ1rYTaSuzR06PZagD2/lV1cinRwrGgVFCqOwpHU5roUbI4JS5pNlc5HWq+p3psNMnuVALohKA9zjis641aeVtsSrGv97qazJpWuNySMzggg7jnrXZDDvdnO6i6Gdpuo3E2nW99cE7503vkdz3xW7EqXsCsl15LEDDKM1nw2oNgkLdFUL+XFVDaTQuEglKE+vQ15bdpO56sb2TR0LRx20DNLciQgclhXO6lrdxpsdtqEO4qtwitx1UnBz7VY/s65yonnEu70qLXbYNoEsSjklQv1yKcZLmTQppyi7nf2t5DcxJIjr8wztzyKshlNcMIWMChW2yKowR2NXrLU7tDgvux1Vua9SWVO5//9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-77.png', linkedinUrl: '/in/patrick-ellis-984f4db9b8', jobTitle: 'Graphic designer', }, @@ -9775,7 +9775,7 @@ export const peopleDemo = [ city: 'Shepherdburgh', email: 'james.sullivan@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-78.png', linkedinUrl: '/in/james-sullivan-711645bcdd', jobTitle: 'Chief Strategy Officer', }, @@ -9785,7 +9785,7 @@ export const peopleDemo = [ city: 'East Rodneyshire', email: 'jeffrey.beck@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-79.png', linkedinUrl: '/in/jeffrey-beck-a78371285a', jobTitle: 'Corporate investment banker', }, @@ -9795,7 +9795,7 @@ export const peopleDemo = [ city: 'Tammyville', email: 'joyce.phillips@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-80.png', linkedinUrl: '/in/joyce-phillips-781047cb11', jobTitle: 'Community pharmacist', }, @@ -9805,7 +9805,7 @@ export const peopleDemo = [ city: 'Port Daniellemouth', email: 'nicholas.sanchez@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1GoLu7t7C0kurqVY4YxlmboBU1edfFy5lh0iwSOQnfMcwg/f44PvjP60SdlcIq7scb4i8e6rql5N9mYpaBiqwqduV9z3Nc3JczXcYEIZ/MOGjY4IP9a7vwb4Qhv411DUk8zP+ri7AV38fhHR49si2MKkcjC1xyrXZ3RoaXPniW4vImVJUPmIABkelaejeJNU0+Rpobto26bNxAYe4Fe533hvTLjmSyiJHQ7a4bxN4OtJbKY2kQjkwSAOhNCrag8O7Hb+CvEa+ItHMryKbiJtsi55A7E/rXSV87/DnV5dD8b2ttI7CO4b7NKp/2vu/kcV9EV2Rd0cUlZhXkvxXM8XiLSJTxb+Syqc/xbsn9CK9arh/iZpcWoaVZOwPmxT/ACkHoDwf6VNTSLKpJuSSL3h2MJp0CKONin9K6PBIAHPFcLqtzqWnIsWnRyMVTI2LnoKl8NaxrV/cRxX0RQsM8jH4H0rzrdT1L9Drp8hcHjiuc1Vv3DAD1rI17WNcjupYrWNmSMEnaMk47D1NJaX15fIsd1BJG4XJ3rg0W6jv0PMd5l8d6cIflZrqNd3/AAMV9Lnqa8U8NeH4v+Fhi8uF3wQ3WIwP75BIz9K9qr0KTTWh5laLT1Cs7XLEX+mvCfY59K0aCAykEZBqpR5lYiEuWSkZVokF1bLvAzjnNOhit475EgVQF+8R64rNlDWt3NGpwikkD2rLurqzuWUpcPDMqkKw3Dr3PGK82zTsevG0kmjYhhgmvZo5gu4sSM96NQjgtIiI1A47VzdpdWlhJIEuDM7tn5t2c+2avX07yk56YzSfYb0F8M2KjVPtAOC7NIy+pxgH+VdtVPTbCOytY1VFEmwB2Hc1cNejShyKzPKrVFOV0HagUUyaeK3iaWaRY40GWZjgAVoZGN4ghMSLeR9chXAH61TJju4FP2ny8jIK1i6x4nk1LxhpmnWEm6w8qSWUjjzCBwfoCamvtMn2mS0kKP3XsRXBXsqh6OHb5CzMY7RD+/3kjqeKyvtXmbpTuaGP53I6kDnAqqul3082LqbKdx0zWtLHBZadK8hCoqEkmsr6mzu9zd8MeNNG8WpL/ZsknmRYLxSptYA9/Q10Br5/8LmTQLhJ9PY+YJC2SPvA9j7Yr2qw8Q6dqAVUuFSYjmN/lIP49bVj/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-81.png', linkedinUrl: '/in/nicholas-sanchez-ba28dda9a9', jobTitle: 'Technical sales engineer', }, @@ -9815,7 +9815,7 @@ export const peopleDemo = [ city: 'Port Brandonberg', email: 'john.perez@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDTpwoxWJ4ovJ7TSSlqWWaZvLDDqo7muU6TM1/xsLKd7PTIVuZ14aQn5FPp71yl14g1m+uEMtzIHGSsUI2gflXQeHvCcV7Gs147DecqFOOPWuxtPA+mwtvBlYn1OaPawWhccPOSueaQeMNXtoiHudyg9HUMR+Nd1o3iC21GCJHmjFyw+6P4vpV+68CaNIS4gI45APWuP17wsdNkjudLdozE2SucfQil7SMnYHQnBXO5NJiqul3L3umW9xJgSMnzgevereKZA/Fc54qJX7Hn7pZsj8q6UVz3ihGdbZguRG+SPXPGP5Ur2HFX2NTRlUxJgdBXUwcRjv8ASvNdRluYxH5Elwi4+XyV+YkDvmtHw9qmseZFHcyyPHKRtMqAMM9sCsFHS53c+vKdxMTtPauR8RyLHbSOBkAc1V8R6rq4klS1kkVIidxjQMT7YNZVm17MJ1upJnVozuSRRkEjtiny9ROf2TY8MktpbD+ASnZ9CAa1yKzPDkRi0sKW3ZOenTjp+lapra9ziaadmKKztYiElm3yg4557Y5rRFNmhWaJkboRihq4Qlyu5X0xIbq3VXUE46mrbR20Oo20eYwQwOeBzWFaF4SFBO5cgj3FVrq7t9SZBcIUeM5BMbZB9c4rCK6HoXVtDplitZdSnQmNstnqDzVXVo4be3dY0AJHUVg2d1babPJ5ZJ8wjJKN19ckfrWnfObgxrk/Pjj60Na2E2ra7l2wiWG1RQoGAAcVO1KiBECjtTTW6VkcE5c0mxRTiwRCzdFGTRsIOMGmyxlUG8/e6iqJOSuNTikupLiFm+zSNlXA6HFaJ2SwKVufKZh8rDnAqt/YcdpG9nGuIuTH9KyJLG8VjbwT7CeMN0/Cue+rud0U1FNHQbooICTcCR+5bpWXZ6uh1G1aUlojJsDdAWwcflVWPTLssIrmdWP91Bx+NaP9kLczWkCjAikWTPpjk/596pNJkzUpRbZ1e4EcU00giPG1vlzUogYjIrY4AAAAAAAAOI//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-82.png', linkedinUrl: '/in/john-perez-55c123ef5d', jobTitle: 'Research scientist (physical sciences)', }, @@ -9825,7 +9825,7 @@ export const peopleDemo = [ city: 'Taraview', email: 'tammy.mueller@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDviKSnUlYmhDc3MFnbvPcSpFEgyzucAVwutfE6zsnaOxgNwMcTZwpPt3NYvjrULjxD4ii0O1dmhh6oh+/IfX6VqaN8NLSCENfyvPLjJUH5VPtWcqkY7msKUp7GI3xQ1i4dFiS3hHclM5/M1p6f8TruCdU1W0ilhJ5ltzhl/DPNWbr4Y6Y4d0mmVz02HGK4TxDok+gziN2Lxt0cj+dKNSMnoypUZRV2j3TTNVstYs1urGdZYj1x1U+hHY1cxXzv4c8SXfhzU1uoCTGSBNDniRf8fSvoOzuob6zhu7dw8MyB0Ydwa1MGTmmmnUhXIwehoA8x8G2kN1r2q6sygSee6KD/AA5Y/wBMV6KrAKAGH515q1sdHsL03FvLL5t7IVjQngds+/FbHheSQkqRIkRj34ZiSvtzXFUV25HoUnZKJ1dxKqDl1U/XFc1r+n22q2TwTgMGHysOoPqKwteLyXRuGtZblAeApNWrSYgmIQSJsOMA5U/Sp5bLmRbld2Z5Ne27Wd3LDuzsYivafhTqRvfCP2Zjl7OZo/8AgJ+YfzNeY+OLXytXEyRsgkUE8dTXa/ByK6txqkc8MsauInUOpGfvcjNd8XeKZ5048smj1OkpaKCDBWzVbi6il+bfK0gJ9Cciqsl1p1gbiMOquqZI749a09SQi5Vl/iXB/CubvtWs0kMK6dJdsowWVOAc+v1rhnF87R6tHWCsXNKezvY22SK2VBBHQg1JdeXbRFVRR7is+w1eGVjGtpJA+ejJgfnVi7zIDmoaszQ56/sIr2ZJZlRvLB2hxkZNdf4Styv2q5wVWUINpPQgc/zFcfdaxFp+oQW5t3mluDtiVCB83bP+Nei6PaPZ6ekcpBlYlnI6Z9K6KMXe/Q5K84qLit2X6SnUV1HCUNSjZrbegy6c49RWJ9ltJol3yAYHAArb1TU4NO0+5uGZWMMZbZn24zXM3FrLJCswIErLuYDoT14rlrpJpnbhpu1h0iwWo+V8j8qo3N5lNqHcT6VXME8md+MD3pyQlMkjoK59Dpvc469uv+K9sVJyIWRfxJyf6V7nAd0CE9SBmvJNB0221fxfcR3KBZ7eUTIf76jBxXryDCADsK7qe9q/Ez//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-83.png', linkedinUrl: '/in/tammy-mueller-69c65883c9', jobTitle: 'Energy manager', }, @@ -9835,7 +9835,7 @@ export const peopleDemo = [ city: 'Santiagochester', email: 'susan.wong@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-84.png', linkedinUrl: '/in/susan-wong-9581ecf892', jobTitle: 'Lobbyist', }, @@ -9845,7 +9845,7 @@ export const peopleDemo = [ city: 'Lake Charles', email: 'jacob.lutz@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-85.png', linkedinUrl: '/in/jacob-lutz-29f1197777', jobTitle: 'Energy engineer', }, @@ -9855,7 +9855,7 @@ export const peopleDemo = [ city: 'Port Tammyshire', email: 'mark.cruz@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwC4aTJpTSetYGxi6zr8Glp5cZSW6PRM/d92xXHXXiTVbm42rd4T/Y+QH8qqPY3GreIrm1tVLfvW+fPHXr9K2ofh7rKKWDJz3BPSnzRjuCjKWyMGS/eS6JmlczDozMTj6GtaHxjqUEEMUVxHIsXVZFySPrW6nwwuHtSJrpfN6jArn9V8B6lp8LSJtcKCWIPOKPaRY3Smuh2mia7DrVoXwsU6sVeLdz9R7Vq4rxK0vn0/UYZUkLNGwOa9sglS4t45o2DJIoZSO4NNqxKdxTVDWJJIdGvZIeJFhYqfwrQqG5hW4tJoW+7JGyn8RUjOc8BWcfkPcjmRm2k/5+telQp8g5zXkmnW00egWbBrnLF2VYDtycnkn6Cum8IXWqSXEdvNJMY3UuDN95fY1hON22ddN2SjY7pgVBO78KyNUAkt5ARnINch4ik1Rr2TbPdmJOfLhfG4Z7epqxpC3GVUC7TIy0c7bh07Gp5dLl82trHmOqQJDfyBCB83pXqfhaNo/DViGYsWTdk+5zXB+JdLnPimWG1XhsSc9FB6k+1elaXbm10m0gYgtHEqkr06dq6k7pHE4tNklJjjnoadijFBImi2cENitk4DeUSoyO2cj+datl9lgvpRujTZH9KxQzRXRYdwD+lUrm6sLubdI6iUDaSoJOO4JFc1nex3xacVY6e2+yXcpRjGzEZUggg067WG1jO0Dd2xXP2N/plovkwGMEtkADa2fpWrdy7k5OTjNJq2hVzDh09ZNTmvtxMjKIyp6Bec/jz+lakYCRqg6KMCs7T57qS/u4fLUWkariTHLOeSPoBj860wtb04tas5K00/dQzFAHNPK1Xuby3tELTSAY7Dk1rYwuMv/wB1AJgwUqcc981HBGZ41aKWOLIyDisLWdTa7urEICkUdwhIJ6k8c/nU9xFdwOHtm+Vv4T0rGquWR00JPlOg8gRRZleKQ+uKpS3DzMI1bJPUjsKz4YNRuRmdwsZ7A81r29qltHk8tjOTWLZtq9yrpOs291e3WmrE6S2zYLHGH+lbIrkbK2+zX91eKf3lxNvHsOw/z6108F1HNwcq3cEfyrtUfdTOCQAAAk/eZ//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-86.png', linkedinUrl: '/in/mark-cruz-88019b5101', jobTitle: 'Pilot, airline', }, @@ -9865,7 +9865,7 @@ export const peopleDemo = [ city: 'East Matthewtown', email: 'sharon.soto@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0zePWqt/qFvp9nJdXMgSKMZJ/pS4PrXFfE2byPDsR3HLTgBex4PJ+lS2UjB1/4i311L5Vlm2gPA2n5m+p7fSuGudVupZGlkBMhPBb1roPD/hebXCs7ybIgeSB1ruT4E0xrVYpAXbru71m6qRtGjJ6nkdpeusu5pCz9y39BW5YaxfabcfatPuPIkxyNuQ31HcV1svwz0/aTHLIG+tclrHhW70RWkiw8YPXvSVRNjdKSR7B4W8TW/iTTBOhC3EeFmjB+63qPY1uhhXkfwwZzrl4zSBH8gZjH8QyOa9VDGtUzBqwEV5h8UGc6lp8coJgETMg7bs4P9K9QrhPiLbrdzaPDsO5bjLN22EgEfmBUydkVBNvQteH4BBpdvGi7cKCcV0ABI4Oa4/VriW1j8qKG6bIJUwttAwPX1pPDd7qk08UVw8rI3zDzcbgPQkVx20uegnb3TsSDisPXIy+nzps3EoeMdayfEN7qcU7rA84jjGSsRAJp2kXNxcjy5o7lTgE+a24H8fWi2lwb1sc/wDDzzG8aHaMRiBwee3H9a9fArz7wZYiy8VahJ5RIkZ40YdFGdx/oK9Drsi7o8+cWnqKBWV4gsEvLAMVG+Jgyk9uQf6VrgU2WJZomjcZVhgiqlHmVhQlyyTOetzFdW4V1U+uaWCOBL1Y41AC8k9BVa5iNnfyxLkIDlfpWfc3mmO4EszrMuRuTPBNcNmnY9SLTSaNlo4JLl0lC5YnB6g0XCxWseEUD0xWLbXmmISsUzeY5zubOSa00V7qeKPuSBSs72B2SuyzoFoiXE8wHzHkj3Pet7FJDbxW67YkCj2qXbXbCPLGx5lWfPK4mKWkJAGSary3ODtUcnua0M7GN4klt0mhVZV+1lcmMHkp6/nWQiLcgHzhGR3HUVNqWl58QnU5CzSSWwiQ54UBiTx+IrPvLXLZjcox7iuGq7TZ6VC6gi6YlgQ5mD57nrS2usW2kyi7vN/kAbdyrnBPeqEFmVGZpWkf0zxUt9aw3OmzQzRh0Zcbfftj3qIytK5c1zJo7u3uYru3jngcPFINysO4qWsXRLd9O0q2tST+7jVTn2FaqX//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-87.png', linkedinUrl: '/in/sharon-soto-288840ca64', jobTitle: 'Therapist, drama', }, @@ -9875,7 +9875,7 @@ export const peopleDemo = [ city: 'Whitefurt', email: 'maria.rodgers@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-88.png', linkedinUrl: '/in/maria-rodgers-3b3e0df751', jobTitle: 'Merchandiser, retail', }, @@ -9885,7 +9885,7 @@ export const peopleDemo = [ city: 'Hernandezchester', email: 'scott.norton@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDhZJRDG0jnCqMmududUubqQvG4ROgXPb39ata3I0l0lsuNqjJB6EmpdJ0z7VeR24AJJznHArG6SuzZJt2RWiju0XzpQZUxypOeParCH7VbtGXIAGV7dK7uz8E2+CZp2+bkheBWi/gfTWAK+Yrjv61j7aJ0fVpnndleoY2iEg3jna3f6VZimEyb1Bx79q6XUfAVlGvm28kqyqPvZrj0We01GW1nbLA9cYyPWrjUUtiJ0pQWpeoBwaKO9WZGVdIsmsys6Z2ED8hxXSaCirLHIqAOzYAHYVUn0G4upJru2dSxUHyyD24PP4VseFIgIZJXGH3bR7VjUkrOx00abUlc7a1HmDGfmFX3yAO5rkryW5iIi2zbT3jFU9GuNQNwcPdCFuSJzyBn07VzqOlzt5tbHXXSloSOgrzPxTGF1W3kUfOSRmuk8UX1+m62gMmwAFmi5Y59K5qa03ojkyjymOTM2STitKas0zGu7xaK4oHWnYoHWuk4DpNKKyxNCd3UA7Tglf8A9dTR20drPKYQdrybiDWJDNcWzNLbMFmCnZu6Z7Z9q17K7lnhWWfHmSAOwAxjI6VzVY2d+53UKilFLqjqbWSO5jCMgzjHNR3M9paP5ZMcZA3MxIVQKggUjBX0yKgudS0uJGS5xIQcn92XOfyrKOuh1aDriWzku7ZzNC4lTBGQc+lYviAQLbiOJNuG7VEbrSHv1NmrCU/wtGV6+marauzNMEY8jk1pFe+jGrJezZlEUgHNPIpMc11HmlqR1trWW6kB8qLG8jtk4FaFmxvNPS5hBHdQeuK27TQ4X02S2uUDpcx4f8ajtbE2Km3cY28celYV3ojpwqvJjbLU1CKsj7XXgg1qiNZ4sK4AxwcZxXP3WliaTcmCf7prLmOpWZIWRkjHTLVzqx2czW5tX8C2riQyBtvINYFzMZ52kPemCS8ur+0hkkLB33MD/dAJ/wAKfcwNBcMg5Hb6V1Uo9TjxFS75SAikA5p5U0oQkwBxWpyn/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-89.png', linkedinUrl: '/in/scott-norton-fa28a83774', jobTitle: 'Museum/gallery exhibitions officer', }, @@ -9895,7 +9895,7 @@ export const peopleDemo = [ city: 'East David', email: 'caitlin.harper@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDz/AEYAFAK8ZNKcYGORUTHackE+gpDLgdRg5/LvUyJLICY0BPbdkD86ZpFpcX9wQkhjQfxKMH867FNB1RoQkTEx4wS/JIrCVU3jSucfP5kEG6RBkHDgHpTY3SRAyEGuqufBVzPa5eXDZziuVudHuNLvAHG1WOMk8GmqiegSpSWtix8u4MTzWnHL+6UDnArCMm0kHqO1SpcuEwHwa0MWUd3rSRr5khAPsOKcVyKsafF+/3Yz2pT2HDc9C8K6TFBYxysmZW557V20UaqgO38q5GQtZWUSLbyys64Ta5UKQPX1q5oE+orKhleVYpMHa77tvt7VxtdT0k0vdOhljBQnb+Jrg/GdokmnykjBHIPoa1/FF3fySsLd5vLiOCImwTWLqCS3uk3KtBJHJGuGDSbw3uDSS6hJ6NHn1u7PCC45yefWp0AAzg1JNbrAkWPlfGGXHT0pig4rtWx5z3GleOK2fDCRy30tq4+aWM7P94cj9M1bfwZfeXnz4fMxkrg8fjWW9ndaJexzNLEXiYNiN84+tOSurBCXLJM9b0toZrZVlAJHY+tWLwJHLBGgVdxHTjvXPeGNSTWLJL2IBQXZHUHoQa1dZ1PSrWSCO+O+Rm/dxqpLE+1cVnex6cWmk0TIqf2jcxuFxnIB5qlrAh8nyIwql+OmBTNNv8AT7uecWhcOmA4cEMOOKwvEd6VdIFuBC8oOSTjKjt+NCTbsE2oxuzjdTmSbUJ2TGzeQv0HFSWujajdoGhspmQ9G24B/Ouv0Pw5YLEt2WE0wwcOOEz04/rXWx2O2PJcFT0OeK7ktDypSu2zj7/ULi8YsoMER6KD8x+prm73K5ReBgk/SuruoQAa5ec75pm9Dj8KaB6G34Il8uwZIh8m1JVA9CMH8iprsjbDUo1bfH/wNQw/KvNfDeqpot/9lu2CWsrEwzHpGT1Vv9k9c9j+Nd7coVQSK8kW4ZDLyre4I4NcdWEoyud1CqrWvqStbCwRiWjHb5F2j8q8+1//AEvX9/UIfKGfYAn+ddfNLN9mZ03zOozvkyI09yelcY7JPdF4mMkUeQJD/wAtGJyzfif0q6EW5czJxNRNW6ktneTWc22ORo2YdVOM+1dNpfi25s4zFLEsyH32n/CuRu/kMUndWFX1QFgR3rsOAAAAAAAA4T//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-90.png', linkedinUrl: '/in/caitlin-harper-13e7507d0b', jobTitle: 'Animal nutritionist', }, @@ -9905,7 +9905,7 @@ export const peopleDemo = [ city: 'East Robertburgh', email: 'elizabeth.newman@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-91.png', linkedinUrl: '/in/elizabeth-newman-b3274ecf1c', jobTitle: 'Curator', }, @@ -9915,7 +9915,7 @@ export const peopleDemo = [ city: 'Joshualand', email: 'rebecca.knight@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwBrGkB5oNZWramtmhjQgv39qyk7GkVdlu61SG1zzuI649ayG1qe7gdLh/IDMQrR9Mdgax7SO91u68m2HmSFun8I9ya7K3+HWoXEI+0TxoSOfLFYuTZvGn1MOLUZNNtwzyswIypByB61sWOrw3VrvQ/KvLnHSrn/AAqpZVJe9kOB3rm9U8O3HhmGWFJMljwDxkdsVN7FOFzojICMqQQehFMEhrO0aQmz8t33OuAR6Vfroi7o5pKzsT9K5DxD5FxqRiAIZMbtp6+1djiuB1KI23ii55JDsGye5alPYqnuejeCNGjsNOjkRR5knLGvQISoTggmvPXuIrG3SGeO4dSo2rDnPA9q0fD/AJxvYliWdLWQ5ImJyK513O23Q7TeADyBWJ4j02z1LTJFuIgzKp2N3U1jeIt63js8NxNCh4EROfyzUun3JnUQxwTxLjlZAR/Om3oKx5eGm0/UgkchbBA2gda60cgEisBSB4gSLywGWVkJ9ACa6UitqZyVNw3Vk6vpJvLm3vU25gHzLjlhnitanqQDyoYEYIPeqkromDSkrnS6Ube5gUSIrEeozTrnU7PTdVt0kUrGc7dqkjOM/hWRpJZXCg8dqnm1uJLjyZLC4lwSC3l/L+dcy7HpJJ7GxZ6lZX88oAbYXI+dCMHPv2q5ciG3j+QADHasS21m1uSbdrK4t+QAWhO0/Q4q3dgooLP8qjJPtTemhLVjiLvQydTuL9mKoZsrt755/wAatZNWJNUTUbWIxR+XEfmGTyfeq+a3grLU4ask5aDaetKyYNEaM7bVGT6CtDEmjlMEi84B5zW1b2pu1Eiz7M9weaxJI2W6it5APnjZvpyOKaEvbZzHA7cc4z2rjk05XR6NLmjFXOtiga2Ql5g3vWZqMpms7pVYY8tgT9RiqllHf3akTyMq+nrV++sIzotzbYIDxMCR1zigbdzmYo/JhSL+4oWn1G7tHqT2j4LJsTcT1baAf1zVmW2lhcpKjI3oa609EecAAee1Zs//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-92.png', linkedinUrl: '/in/rebecca-knight-f9ba229de1', jobTitle: 'Marine scientist', }, @@ -9925,7 +9925,7 @@ export const peopleDemo = [ city: 'Port Tammyside', email: 'rebecca.henry@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwC26mq0g4rRdeKpSKSeK4TrREuFUsTgDkmnw3NqAWlmVFHqRk/SpF0qTUpo7XYUjA3O5bG7/wCtWsPCGgWUKLHEZZQPmcsaylU7G0afc5ufWbWJwVZXXBLfNgjFXYmS5gjlhdWWQZAzyK130mwaExC2i2n1WuW1fRWtYJJLCVoWXnaOQamNUp0uxfJ7Uqgk1j6DqzaijQT4FxEPmOMbsf1rfiTPNbGBYfpUcEQmukiA3bjyM44pzniremIpE0jk7UUkgd+DRJ2VxJX0Et7prqJmiG0liM9MKOBVtcDA37j7Vw+p3slppsUAtZJS6bzgkepqTw5czm4jttjp5q78Fy23jPfpXJyu1zvja9jtHYBeuKyr7BQqecg1zXiG7lW5LLBJOU527jjrjoOtWdPvGkbyZYfJkAHCn5TRZ2uV1scjDeJp2v8An7cgMMqT+dek25EsKSqMK43KPavNfEdq6a4wgRs8MMDPNd54eupLvSYpJSTIBtbPbFdUdUmcM1ZsvuDiprWZokeNQP3o2nPamEcU+NBxkd6tq+hCdh6mG4tVt5kX5AA2fWs+C70601B0DLGQCFHc+pp9/IXvJZEGCxOQO1ZE13HkImn+aFP33IXP0zXCk72PSjZrQ1LKazvJzGrI+clXH15FWbiOG2yQgz2NZFrf7m2tZvES2Qy4K/mKv3Em5BnrUvRlMxpoEednKbjICrHH3Rjg5qfwpGwtpX8wOhY4x0656/jWTFrQvNTmsIoQUR2Qy56nHT27811mnktBuCbARgL6V004tbnJWmmrImqaLB69B1q0+jXcULTTmKGNBlmdxx+VJLDHpunteTOJGZcxqBxz0+tbuSRy2bOXaO7huLmSVNkUh3Imcle3P1GDU9ubKVQHY5HvWJ4ZS5vNX1ZpZGeGJcKWbOSzZ/TmrN7ahJQ8ZIPcVxVLc1jvpN2NK5ktoUAVuB6mqEt4XQ7egGSarxwM7Zcce5qSWPMTIOMqRUGz2Oa8JJcHXHmCnyZGIc9QWJJ/xr0+3hEcW0V5h4AkmsdcltLgjZhl+b+Fh3HpmvVR04PFet2sf//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-93.png', linkedinUrl: '/in/rebecca-henry-8af895981f', jobTitle: 'Graphic designer', }, @@ -9935,7 +9935,7 @@ export const peopleDemo = [ city: 'Leslieberg', email: 'douglas.mccall@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0M1Xu7qGxtZLm4cLGgyT/AEqzivOfilqzWqWFihI3lpXI/If1pSdlccVd2Oe8R+Lb6+1AzK721up2xorHjHc47mufnvJp42uBP52fvrn5h7jNdB4e8H3Gu2n2ueVlVzhQvAIrqLf4Z6TC2+QzMxHZsVzOa6nXGk7aHlT3s5eIkll/vHqprotO8b3theIyzvMq4BSTJH59q7i+8A6RPbmMROpBzuB5zXAeJPCJ0aBp4GZo05bjn8aamhSpSSPZNA1228Q6al3ANjdHjJyUPpWpivCvh54hfS/E1vbNJi2u28p0J4BP3T+f8692xXRF3RzSVmOxXjPjuRrrxtPbzNwiqEB7DaMfqTXtGOK8s8d6JNceN7OdQvlXMaISDyCDjkVNTYqkryO18NwrBo1siDgIMVrtuJ5Fc1qT3Flb7bbzyVTKrAoJAA96k8OajeXUai687kbsy4yPY4rj8z0V2NifKg8VzOtxpJbyBlDAg5HrRrmp373Eot/N8uEZbyupx6Dueaow3E14PnWdeMlZ0wf8KLdQv0PKZwsOrp9kGJUmUx7fXPFfSqbvLXf97Az9a8DsNIlk+IsFukbGP7WjEjsoOT+lfQGK7Kex51TcdWB4hsRNNa3AHzJIpzjoASf610GOKguYTNAyjG7BxmipHmjYdGfLO7IIlWSLP51ADD5oWMrweccVFGXELc9BWVNd2kkgWS3n3oCoYQMCB9a4lqemvImsjEb+ZHI3MTj3qTUQkKEAAEisVbi0hvvLtopUkc5w0Z5/Gr2qFmTLHnHT0oemgGX4bsll8RtIyk/vRKGx02rjFeh1i+H9Ma0gE8hUtIg2gD7oPNbddlKLUdTza81KWnQdSYp2KR2CLn9PWtTExbt1t7mSM8BuRn3pZESWPBbHGQaxtBml1iLUmu8uwvZUGewBAFPurXUbZcQHzYx0U9RXBKykz06bfKiW4WOE7gRuHf1rKuLnz5FQuArEbmJwFX3qKRNTuSRNH5aj3qrrNsbfw/e5+80D/wAjU6XKbbPTFVQo24244x6UprmfBdxPFotrp162Z4oVKknkjHI/CumNABXonlH/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-94.png', linkedinUrl: '/in/douglas-mccall-bbacffb65f', jobTitle: 'Producer, television/film/video', }, @@ -9945,7 +9945,7 @@ export const peopleDemo = [ city: 'South Thomas', email: 'shelia.mcneil@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-95.png', linkedinUrl: '/in/shelia-mcneil-09a1a630f5', jobTitle: 'Surveyor, quantity', }, @@ -9955,7 +9955,7 @@ export const peopleDemo = [ city: 'Port George', email: 'diana.moore@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-96.png', linkedinUrl: '/in/diana-moore-bfde41a990', jobTitle: 'Public house manager', }, @@ -9965,7 +9965,7 @@ export const peopleDemo = [ city: 'North Dennis', email: 'andrea.gregory@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDjGFRY59qtyJ6Vja5K0NlhWwXbB9xQ3YpK7IrjWNrlYNuB/Ge/0pYL8zklpAR/tHgViWWn3epzCO3DMc4yOgr0fR/hiGgV7u7cSMOVXpXPOS6s6KcJPVI5CPxDPAWilCzR9mAwfpWhbapa3bmKNnDnkBiMGvQF+Gmjm32bJC3dt3WuO17wiPD10L4DfbK2GAGCoqFUXQt0pfaK55oANZ9pq5urkxysCCSFb19M1rhK6ou6OWSsyYiuT8SyF9RhgzhETcfxNdcRXOeJLFpLm1nQffPlnmiWwktTs/B+mR22mwbFAZhuJ7816FZqFiHOSK84v7iSwt0ghjlY7ONjYxgfzqx4X1DVJr2C1maXy5cEFzkjPrXA037x6cWl7p6bE+RwcGsXxHbR3el3EEiBg6ngiuT8V32pWd68UJnZI/mIiYjI9vWtDRbu7nKQ3FtcRggEGQ5ByKXLpcd1ex426rBqpVBtWOTt1wDXbKdyg+tYd7ocp8V3qhVWKKcnLcBuc4Hvit0DAxXdTdzzqia3JDQ1sLqErt3OjK64Ge4z+lOxUkEnkTB+cc9KqavFpCpy5ZJs6mxS3uYwsqKfrU1vLY2utwJujjRTnk4yaybVjtRlOMjNQz3dpPMFeynmdcgMqYIz6Z6159nex6qs1ode02m3ly0btFLljtYEHHsfSrEn2e1j2xKOlc7Y32nLD5RsLi3ZiMsYs5PqSP61pSHJGW+UDJJpNdBvQwtStRDaX1wcFZXVxnqH6HHtiuZNampatPfoIW2rErZAUY3ehNZZFd1GDjHU82vUU5adCbFGKcQajuS0SMv3ZSp2gjoccVqYGnbybYBk4HrWhbxWtyMTynHYA1g+HVu59GRr6TfO5JPAGBnAHFSzxTRn92SD6VwTs5M9OldQR1kC2cFuVinZlx0Jqlf3DNp05RjtC7Q3rnis7SbGe5YmZjtHUVL4vkm07wvJNbqMxyJkYzkFgKmNuZBNvlZibaaVq1cW0lsU3oVDqHUnuCKg616JAAAAAAB5h//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-97.png', linkedinUrl: '/in/andrea-gregory-1bed92c29b', jobTitle: 'Clinical cytogeneticist', }, @@ -9975,7 +9975,7 @@ export const peopleDemo = [ city: 'Port Michael', email: 'sandra.houston@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD07FLS0YoERXNzBZ20lzczJDDGNzyO2Ao9zXluv/GNEma38P2izgHH2m4yFP8AuqOfxOKwvjB4okv9bXw/bykWtrhpgp+/Ke34DH4k1zmkeBdZvYVnjtjGrchpG2nHriolNR3ZpCm5bI6GD4v+ILaVjcR2tyP+eYj2FT+BrRsPjJqLzCS5063lt8/OsRKuB6jJINVIfhXcFfMnvlaXaeFXp+Nchqfh++8OX+ycEwMcBhUKrGWiZrKhKOrR9F6F4h03xHYi60+cOP44zw8Z9GHatTFfLeka9eaHq0d7ZTGKZD2+7IO4I96+lNA1q28QaNb6lan5ZR8yd0YdVP0NaJ3MJRsaNQX11HY6fc3kv+rgiaVvooz/AEqxWb4gYL4c1ImMSD7LJ8h6N8p4qiTwTwRZf8JL4svNXvR5hVzLtPOWYnH5V7TbxBIgvGR6V4N4PeVNL1Voo5JHBjAVGK8nPJxXoHgufUpZIbe4ZwkqM67mJK47HPTpXBiE3Js9TCtKCXc78cZ+YfTNcz4r0iLVtMmhbiXbmNh2Ncl4nj1MaqojMzrvABDnuccDNbmkm+ybaeMkJwJEOVaslGy5kdDlzNxZ4pcrJbTyQyD5kYgj0NevfA7U2eTVdOZ+NqTop9c7Sf1WvPvHmntZeJpSqnbMA4AHrW78IHnsviFFBLG8ZntpFKsMHGNw/lXowaaTPIqRcZNH0NVe+tVvrC4tGYqs0bRlh2yMZqxS1ZkeI/DvSf7Iudc0zUIx9pinWNgehUA4I9j1rurOKxsbmVg0cQEfGeOtW9f0yCHUP7RiQLNMqpIw/i25x/OuU1TVNHjuEgvC7ynjCD9Ca8+tF+0Z7GFadJHQwLZagNrGN2UAhlwwINSzyQ2UfyKOB6VkaPqmjTRpFp7IpBI2gbSD9KvXabuWrBq2h0aHI6rpo1HUEvGQPIqlUQjO7nNV/Cdoh+MHlQDCW0DsdvRSeSP1xVfxL4xk8PXT2tvaxyyzJ8sjt9z8O9dB8HNGuBBfeIb0EzXjlY2bqy5BJ/E/yrsoQl8TPPxVSNuVb9T1WioJryCAkPINw6gdRVSPUpLohoFCQ7sbmGS30rplJRV2cMYuTsjH8canFp9laDy2lmedSETqq9GbHfrXLSyRTXMcNvJEtyTjMg4Jrq/EFtFcxO8quhxtWRiCM/0rzWGW6W5ubFwpSOQujn7ysMYI/DP6VzScajud0OeglZ6HZWthPZpvnaIt6r2pl5efLtB3OegFc8l9e3BCSTsfXtWtZ2uwb2O7jqa5Xpudzk5Hlfi5ZL3xh9mQFmVUTgevJ/nX0b4btobTw3p1vAMRxQIo/LmvPvDugxt4l1LUZI/MSTah+XJBUAnb+S16RpVutrZ+Uhym4sv0POK9Ck04o8iumpu5/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-98.png', linkedinUrl: '/in/sandra-houston-5eb9930bec', jobTitle: 'Research scientist (maths)', }, @@ -9985,7 +9985,7 @@ export const peopleDemo = [ city: 'West Judyfort', email: 'christina.rangel@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDlyM05FOaftzVDXLg2elSFX2yyfKuOvvitHoCRS1PxElpMbe1CySrw7k/Kvt7msW51OS4U+deZfsvQD8qo20QdyCN3og7mulsvh9q19Cs0iRQK/IVjzXPOol8TNoU5S+FGBaateadIXhmZVPUZyK2bLxbMjKl6nmxt0kUYYf0NaUnw1uYgWa5Tb6DvXJahpVzpc7QT4x1UDvShVi9mE6M4q8kehK6TRrLGwZHGVYdxQF5rk/DGtGKZNOn5jdv3bZ+6fT6V2YjroTuYsaFzXDeK7p5NZ8peBCoXH15rvlHNee+JLC4g1u4baWEp8xSOflp1Ngjudf4C8JR3EcerXeXbcfLj7DHc16ksZSILtrjbdbjSfDtjFBHcOxgX5IQAc4ySTVnw1d6tcyFLx5fLI3ZlxkegryJ3k3Jns0koJRSN+6Q+WRtwPevOvGWlJdWjy4xLGMgj0rR8S3+ry3Tx23nfZ4fvGHqaqRvNdRPBKswITDLNyfz70QTjaQ6jUrwPL4XKXCFWIKsNp98167GCUUnuM15LLayR3ki7W2pIVJA6c17BEm2JQOgUV6tPU8aSsRAc1PHplrqTNHMg80oVRx94VCDU8ErQyrIn3lORmrqQ5oNDpy5Zps6rTAhtEhfG5V28j0pxltUuRBG0aHPPIGTVKxkMsPmcAtkkDpVW7vNPZdktrLMyggOsJOM9SD/hXicru4nuxakk11G6c8D6jcROyMGY45znBpNZ+zwRMIlUEjHArJtLnTLe8ZbSCS3dzn94pBJ+ppurXOIpp5D8salj+WafLrYUnZamTZ6PDOZFlXEZkE3uTnkfQ4/nW/8Ae6VR0s3MmmRS3SLHLKA5jH8I7CrqcGvYowcIa7ni15qc9NisKepoWJicAZJ6AVrWPh29u3G5PKTgkvwcfStm0tzFDdOmdEbHI64rQZILu35uCg9V4NVINPuLTxbq0UjEW8YiFvF2Clck/ic/lU13o6zh2SZ4n65U/wBK8XESTqto9nDcypK5j3sEFo5ZZS/f5utUYZI7y6WKTBQ5JB7nsKo3EOoJdPDcNubOFIGAw9ao6vFLEtp5BPmrcx9O+Tj+tOlZTTY6zbgzr3AqPHNSvCynZnLAcioyGX7wIz//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-99.png', linkedinUrl: '/in/christina-rangel-14f26a977d', jobTitle: 'Immunologist', }, @@ -9995,7 +9995,7 @@ export const peopleDemo = [ city: 'Smithchester', email: 'ruben.aguilar@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-100.png', linkedinUrl: '/in/ruben-aguilar-abaeafdd06', jobTitle: 'Counselling psychologist', }, @@ -10005,7 +10005,7 @@ export const peopleDemo = [ city: 'Smithstad', email: 'briana.townsend@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0iqmoahaaXZSXd7OkMCDLOx/T3PtVtiACScAda+fPHPiy48Q6y0cbsLKBiIox0/3j7mk3YpK53F/8V0MjJpWnNIo6S3DbR/3yP8awB8UdehmLSfZpUP8ADswB9CDmuEj3uyr80kjcLGOa37TwHq2oBZCiRKRnL5/lWTnbdmsYN/CjutH+LVrcjyr+0eOYHrFyCPoa7zS9ZsdXg82zuY5R3CnkfUdRXjMnw3vIrct9oQyrypUGsjRtVvvDHiNBISp3hZF/vCnGonsE6TitUfRmKKZBKs8EcqHKuoINSVqYmH4x1ddE8LX14WAfyykee7NwK+a7dZbq5VFyzyNgKO5r1/403ci6VY2qZ2PKWb3OOB/OvP8AwNYG88VWcbqQI2LtkegzWc3ZNmkFdpHong7wJDpKC/1IpLdMBtU/djH+NdlJ5YPyFfwrC16eSJZAtnJMoQktt3AYHQA8ZrB8MCea9QeS8IkAYgE4A7Ajsa4neSuz0Y2j7qO0nwUIyB+NeY/EHTENtHfRriSN9rEdwa2vF9zNBMYikkqJztTPJrG1f/SPCl9GIDHJEFLLnIIyOadNWaZNV3TR6F8OteOt+GIhIcz237qQ+uOh/KuuryT4OpOl5f8ABEDwoT6bgeP0NeuV3x2PNluedfFy0ik0K2uyMywTggZ6g1i+EtO8jUotQRT5JQKhI+9uUEnPfniun+IVrNqNlb6dEpDzM7biOMKM4z+VcD4Z8WLpDR6FfxszfaQkUg6ICcYPtn+dc9dN7HTh5JbnrpaO6gKMox3B6VTSSxs5mhQImAC7kgcnoKkjB2HHpWHqOraJap5FyouJy+doTOG9z2rkV3od+hLdi2udTkUlHV+foaoa3ZxDSLuCNPmeIqAB1Jqraalps926QgpIMfe6n05pviXVI9O0ea4kZgzAxxbepcg4/wAapJ3sTJpR1NT4cRfZ9LhyApYumQPvBTj+YrvxXJeCbdf+Ed0rH/LOHcD65/8A111tejHY8mW5zfi/U7LTtMke5jEroMopGcE8D8ev618730we/W4Ixl93HbmvcvH+mzvp9zdxo0gDxvkc7VAIPHtwc/4V4a9nJKzYGR/n/Gs5fFqaRXu6Hv0NwRbopfG5Rhj6YomsmkttqSooHQ1XsYUm0S1WQ5xEoJ9wKo30dzaMFjlYp2Ga4E9T0k2hZLXyTh3Vz61554+1NrnUYNNT/VwAO3+0zf4D+dd6iOwVpXJ74rznxXaPJ4mdgRul27M8AdsfpWtJrnMcQ24nrnw2u/tfhS3DYLQfuuPTtXZV5l4E1NdG0e5LQPLAp8xliwWixwwI74P6V0kHxA0GeTZ50sZ7F4+v5V2xeh58lgAAAAAAABqf/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-1.png', linkedinUrl: '/in/briana-townsend-b3b34529fe', jobTitle: 'Cytogeneticist', }, @@ -10015,7 +10015,7 @@ export const peopleDemo = [ city: 'Lake Kimstad', email: 'william.thompson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDfC0oWnhaw/F+troOgTTq2LiX91CO+4jr+A5pFEOueL9K0NzBI7T3QGfJh5I+p6CuG1D4j6vK5W3ihtF7ALvb8zx+lYOi+HdQ16UmEbUz80r+v9TXY2/wpkmYGa+2juESspVYxdmzaFCcldIpWPxL1GOZY7yC3nTuwUo3+H6V3GjeLdL1mUQIzQXB+7FNgFv8AdPQ1zc3wkIUmK+cuOhZa43W9G1Hwpfp5yvnOY5l6Z9vQ0Rqxk7JhOhOCu0e5MtMK1j+E9eGv6SskgVbiMBZQD39fxrdK1qYj1FeWfFGaSTX7CzOfKWHeB/tMxGf0FerqtebfECxebxjpBI/dzRiPPuH5/mKUnZDSu7HReG7KKz063hjAAVR+ddjbqSo4z9K4C8ikjmKn7WVC5SO1wDwOua19CuL20nhjZ7nyZAGAuCCwz2Pv7V5rX2mexGVvdOwycHA4965vxXa297o1zFNEsi7CcEdD6iofEUt35haN7xo05ItnCsfYepqGyR3fH+lqNuZIrnDEgj1pW0uDd3ynG/DeY22tXlishMU0XmhD2K4GfyNenFa848CWUkXjTUkEYEdssiFj15YYH6V6Wy16cXdHjyVnYVa5bxNZK2q2tw7EtvRowTwNuc11aCqWq2jXNvmNQWUHg+n+RWdWLcdDWhJRnqO0+OG4iXeoLD1FV7yW3XVYIRJGmHA5OOfSotNZ1OFPbIHrVRLixvb945rV5pUJyBEcj8T/AErz0esmrG/C9vLeSxmSN/mwMHPP9Knu4khjJHBxWOs9laXAhEZhkkAwGjILfjWldsXjHPIFDVguY2jacLa4eZcB5Z3mcrxuVsgA+uMVuNUFjHtt0OMcfn71ZYV30ItR1PLxMlKenQROlSAZpg4FPBrY5zmpphpmoPCx+UfMh/2TVyGEXJEiOoYjg4zWFqupQarrl1aQlG+zqqh1PU85/I8VQjvtRsciIM6jjGM4rzqkUpux6tGo+RM7pYBCu6RlLDvjFVJ7sOREhGWOCc9BWDbXmqakmGRo1+mKfrtrJa+G7sIf37JgHvkkAVNlzIqUm02dgFCqFHQDApDVbTrhriwikb72ME+uOM/pVkmvTPIP/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-2.png', linkedinUrl: '/in/william-thompson-94dc40f1de', jobTitle: 'Equities trader', }, @@ -10025,7 +10025,7 @@ export const peopleDemo = [ city: 'Donaldburgh', email: 'ashley.martinez@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDt9R1K10uwmvbyURQRLuZj/L614nrnjPUvFN8YI5HtrAn5YUPJHqx7/wAq1Pi1rxuL+30OFjsgxLNjoXP3R+A5/GuDtbgQZx1PVhUlIv6gES0wg6HGT6/1rKCq0J/56KeDntW0qxzBRIwAUcZ7Zp0egSvA04wYw+2hjSuO8Paxfae4nsp2ikTt1VvZhXs3hjxRb+JNP81QIrmP5ZoT/CfUeoNeTDRZbKBrqAh0KglfWo9B8QDRNaiuV4Bk2TKD95Cefy61N7jcWtz3rNJTUYOisOQRkU/FBJ8zeIL86n4gv7358TTMRuHOM8VRJCkKBnHQeppz/eY89eSabawzXlykEEbPLIcBQOTTbGl0JjLJKyRqSx7AdzXrS6FNp3geUXAxJtEjk9c9xXJ2PhifQ7m3u76wuLiT74WM/KMDsfWutsYNQvpFguBdLazoH8iWTeFUnoe4PtXPUldXR10ocrs9xukaadQ8NoGOx5Yvkz3HY15VrME1vqTRyIUkT5XB9Rx+teveMZNQsEjsbCKREUKMQqMjsAPSuD8R6fnSjdPbPHLbyiOSUyb/ADffPeik3e76hWSasuh674LnmuPCOnPcZLiILknJIHSt4muO+HGuJqfhuG1MTrNajy3bb8remD612BNbnIfMdzbSLeeW6lFPO5hgc11vhbSn0vVxNKFYAfeHPB711/xDsLKPw7uljHmpxEyj+I1w/gBiuoXcb/cZFOD+NZ1b8rsbUGuZXPcLJra+tfJmiV1I4zUhtrOyxDbxDe3zNgVi6axj2qp47VLqepaHPCYLu4kEgPIi3BvzFcq10PRsm9DR1K3hmvUWdFZJEHXnBFch4y0+LUrS00azVIzPcqBxwAMkmrVrqGmfaCsV7NPIF2p5uentSWtlc3niW1vGUiCBTg+pPBqoJuZlWajBp7nQaRpNtoumw2NouI4x1PVj3Jq6RxTugpDXaeYVNT0iz1a0MF6mYgd3XGMd65m9sNGSaAaSsOQCrPFyOPfvzXotrpryDc/C9hVTUfCUDt9psEEco5aIcK309DUVYycfdNKMoqfvHBRXD28ohkJU56+orX8iK9jUtdGMgfKy9RUWpacJAUkQrIOCCORWE1vcW77VlYj0NcKZ6SbWxq/2eWvVhiujK78BnPIFdZbwRwQJEg+VF2iuEFvI5U7ysg5VwcFT6iu78OO+s6FHcXHy3CM0cjKMBipxnH4V1UGm33OTFOT1ewrCmGpp43glMcg57H1FQHmtzgAAAAAAAOQ//9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-3.png', linkedinUrl: '/in/ashley-martinez-a406dfe50c', jobTitle: 'Ecologist', }, @@ -10035,7 +10035,7 @@ export const peopleDemo = [ city: 'Karlland', email: 'carla.wilson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDoNd8QWehwAytvncfu4V6n/AVyZ8TT3LkyyCLPRU4A/GuEv9Xn1HUZb65cs7Hj0UegqCK9kmnGWIA6e3/165pSbOiMUjup77Up3ES3zGMngEZBPoT1pkGpanHOY1njt5YzgoXIz+fFW/Cmly6lCNmUjJ5fqT+Pr9K7LUPAOn38EZLOksa4DqefzrNz8zZU9NjL0bxOtzItpqCrFOeFcH5W/wAK6TFea+IPB2p6TE11FK13DHyf+eij1966PwRr/wDbWlNFK++4t8Atn7ynof6VrSqc2jMKtLl1R02KcFoxThW5gfM7HLcsAi9T61qaDYf2rqUduuRFn5yO/tWRd2V5ayBbmB0J+6Oox65HBr1H4d6Mseni7kX95IeM9hXLUlyxujspwcp2Z6JokENpZxwxoFCDtW4k6MuBKhI6gHNcjd3k2nn5bWSUHA6fKPrWZp89zqWtT7dOa3WJiDIOj478VzxTtc6pWvY7m6iWWMhiMY5B715L4d0+XSPidf2lqp+zDdvA6BWG4frius8aXV7YxWyxQSTIxXIU9z6+1P8AD9qJbi41WS1ME1wkaEN1wq/4n9K2op8xz4hrlN3FKKKUV2HCcLPpMN84LIGtRGFXaoPOMg//AF60dNhNhbxRoBtWvMfCHjTUbOa30aTE1uzbYixwU/2c9xntXqenStPboJgFlx8wHrXmVIuDsz2KdSNT3kdFZ3izjZIgOatbrayUBQu+U4GMACsiKMgjtUtxeWEcRivWBY9EAJP6Uot7FuKZcuWtb2OIO8bMpK4BBpvygkIMAcVh2k+lBzDZQPA/VUaPYPwrYhwYwfWuignzs5MWuWCT3H0opMUorsPPPmTR0Y+ILDYPm+0IePrmveGhaJ1lTv1Fcd4S8DPYNHf3mGuWGVUdEB/rXorwZQDHbFedWmpy0PToQcI6leO7BABOKvqsM6bDIAP9oZzWdJbEHOOKguWa0gaUnhVLGslozZs0HtUt/uSBx29qs2ZzAK870bV9bv8AUbv7QY2ECE7B8gAz1HXJ+teh6YGaxjkYEFwG59+a7qCscGJm5Ms4okHKf//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-4.png', linkedinUrl: '/in/carla-wilson-d059473869', jobTitle: 'Media buyer', }, @@ -10045,7 +10045,7 @@ export const peopleDemo = [ city: 'Lesterfort', email: 'robert.contreras@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-5.png', linkedinUrl: '/in/robert-contreras-50f852ba89', jobTitle: 'Ecologist', }, @@ -10055,7 +10055,7 @@ export const peopleDemo = [ city: 'Mahoneyhaven', email: 'denise.burton@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDqinHFVmPz4q7kAYqv5eZc4rzrGrEAwOlZWpeIbSw+UyJuHVmPA/xqHxnrZ0TSF8kZuJ22IB1/D9BVPRPhxJe2yXuuXkj3Mg3GJDgIPSrStqzSMWzIu/FiSy/u77j/AGUwB+BpkOqX9wztbSYCDLSE/Liu/j8AaHHDta3DH+8etYGu6XYaRbC3gQoCcgDofrV86K9mzH/t6aFASX3d2xn9K6TQddivgIJSolIyjD7rj296821CRAxw21vaoNN1SW3uArEghsgjjB9aJRuiD3ExY5o2ZOalkBA4pqPkYNRYg4nX7VtQ8e6FbSDMKZl56Erk/wBBXo0eFA+cVxfiwGFYLuKzN1MiugjBxkED0+lTeEJr2ezZJ4JIPlZlWRyxABx35FJp2udNFq1jsmcf3h+dYXiCwjvrJ0dAXxwa43UhdWOtqU0+5vWdh88krbVyePwrpNN1Ce9zHJYzwMp2lW5U+4PpSe1zbrY8U1yM2V7JAyuhU9+1UYbrcyliGK8ZB6ivWPHuhRXOlPceWDNHyCOteTW2kXl2ztBGoKDLF2Cj6c9zXRCSlHU5KkHGdkfTDJxUewGp24WogpLVmZkEVvG14TKAyhCAD71YgS2tonW3CKznG0HmqOpTfZPKbOPMcJn61k3kujGRUvLh1dT86hiMms5bnZQV4nTrFaXZJlVd0ZwQaSaaG3XCIAB6VjW1/pbIsVhdI0hycbss31zzT5BI52k1nJtG6SM3WGfUIXhUcE1iTadHZWN3M5WO08ttwZQOgzkd+tbWp3KWVszjBKjOPWvKvFHjG61jfp0cYhtEf5gDkuR0BPoD2qqcHJ2RnUqKGrPoLGRSAYp2QBSbhW5wHMeLZHMUaRg5U7uPXoKTTM6xYx3EUqxyKTHKD/eB5/xqv4mvTaedIRnrtz244P615nB4rv8AQ7uVrcBopGJaJj3HGc9jScHLVG9OpyHsotktY9zmMuf4h/jVC61JIVPzAmud0jWrnxFoqXqSbGLFHjHO0jtn6YNXrWwMnzODnvurmldOzOpSuroytanmk0+e5YEKAdoryu3j3F5G+8XJ/WvZPEUaJo8keONteUGPE4jAwBz/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-6.png', linkedinUrl: '/in/denise-burton-3a79ce7f23', jobTitle: 'Clothing/textile technologist', }, @@ -10065,7 +10065,7 @@ export const peopleDemo = [ city: 'East Sydneymouth', email: 'cassidy.mckee@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-7.png', linkedinUrl: '/in/cassidy-mckee-1189782a1e', jobTitle: 'Psychotherapist, child', }, @@ -10075,7 +10075,7 @@ export const peopleDemo = [ city: 'East Kaitlinborough', email: 'angela.torres@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0fFFKapapqEel6dLdyAkIOFHVj2FS3bUtK+hh+LfE6aTavbW7A3Tryc4EY/xrydnnu2M1xKV3HPJBB/XNXhDdeLNblhxhpGLs3YD3rfvvCo0i2WJSHbGVLLlT7e1ck531OyFPlMG1SW3AIWOaJuwFTs+f3ltKWx1jc9D9e1V7hmX5oiYpFPToCfQis9rpmnMykJJ0eNuM1CKZsW2olmLws0U6HLL0P1HvXqPhjXF1vTiXwLqA7JgO/ow9iK8gfFxtnjO2VeCe/wBDXUeAb/yfEHlZ+S5iKfiOQP5/nWlOVpGdWN4nqNY/ihcaBdSYBMaFgPqCP61s1XvrOPULCe0lJCTIUJHUZ710tXVjlTs7nmXw3UXFxqNyACwZUHsOTXeahardRFHGSelcLa+GtU8MtqEKeXIJJI3inBK4ByCfbHFbXhjWtS1ATW17EVliBIk/vAHFcUotHpU5JpGZqvhO6cmSH9RzXI6lpMls+6QssmMHI4P511eqa94gS7m8lcwxckKACRnHHrVu2aTWYtl5bSAjglsEH8RSSaVxu0nY80Ny8HDRlewINXdE1U2upW8wbHlyq4P0P+FR6/pV1Yau0SIxjY5UDuKbNYix062nwrSySABgTk9cqR+RqtLGSi7vyPoigUlKK7jgKt6EJRXAKsCOapW9tBD9oMCAYXGQMDNXb+MyWrbfvL8wrnbma3WIx/2isEp+9lq46yamehhmpQsXI7S0uzh1TzFAyGFPn8i0i2xqBgdqpWMlkifur1Z5TwXLgsfapLlC/U1i+x0WRi3UEd0xaYom3JR2IG335rir17bXvEtjpOn7nt45R5jpyXY4zj14HWuo8VxhvD98QMqkRP6VQ+EOnwM15qUoQyqRDEx6g4ycfhxWtKNznrVHFWPWqRpFRcuwUe9LwqljwBWFdXElzLtGT82FUV2M880n1CE5VA0hPAAHWsG50xrj5SsS4JbEgBrobLThAu58GQjn0Ht9KxNfuUjjuGUn9wMswPOccCs6kHJX6m1Cr7OVyrb6cLP5njg3eqgfpT3m8w7Q2SfSo7e2knsoZJZXDugLDPAJFW4LVbfHf3rie56DlcqXmnpdafNbOMrKhRvxFct8O9JvLe31RAXieJzGob7vmD29+K7mdhHEWNaOkWC29qOBvYmSTHdj/h0/CtqCbTSSZ//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-8.png', linkedinUrl: '/in/angela-torres-1c99a88f63', jobTitle: 'Agricultural engineer', }, @@ -10085,7 +10085,7 @@ export const peopleDemo = [ city: 'Millerbury', email: 'shirley.hall@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDIlY4NRLk1ZlTg1XnlW1tJZ2GRGpOPWmBDdX0NigaZvmP3UHU1nz69si3EqCRwmf8AJrmri9lubpppiS7HgDqB2Ara07wnqWsQ744ljU9C5JrCc+70OinB9FdlSPxFcpNvViuO3UfiDWzpHiZr12SZYxgZwvBxV1fhVL9nBN6TJ344rEvvD1x4bukll/ewkYYgfd/GpjUjtFlSoy3kjrkZZlDxtuU9xU0cRrjtG8QpDd+S5zC3OfSu8hUOgZSCCMgjvW8ZXOeUbGdKDmua8W3LQWEUKnBlfJPsP/111cwBrkvGkBNvZy9g7KfxH/1qctgjuafgXwlbXtqdRvF8xt5CITwAO5r1W2tUhhCxKu0dl7V51pAaDwRYOIJZjKGwiZx948nFbnhNbtZERomihmXed2cqfQjNefNNttnqU7KKSOsmIiUlnVPqa5zXbSC9spYpVDK47daxvFH2qS6L/ZnuIkPAUEnGccVLYiYnyWt5IivbOVPFTy6XLb1seR6hAtnqDiJsoG4r07wjcm60GMu2WjYx59h0/Q15z4pga38QXSkYG7I/Gu78Agnw8zFSN0zfjwK74a2Z5dTRtGo9VNQ0lNXs/szHDbgyH/a7fhV6RaEYoQR1HNaNXRCdmdF4Zgit9BtrN0GYlKEH1yc1ee5s7W68tpI48ISB0z+FVbaSOUh4SMEAsB2Pes/VtZ0iNxBcQtPJyvyJnb6815jTvY9iCTWhoaXcWl4HVJI5R1BUhh1qS+aGBDtUDjjFY2la1pcjmG1haB8/dZCM/j3q3f8A7wkk9Klq2hWhyVxocV7rEt3cxq4lQJH6owHX+VbOl2aafZrbp0BLH6k5NU7LW4bjVbrTIoH8y3G6SXI244wPXvWrHmu2hGW7POxM4u0Y/MpyIetM21fZBimeUK6TlH6fMYGYdm/nWo1lHdxKfNCHsR1rKG2CN5m+5GpZsegq1d2dwwMtrIV4zt7VxYiKUkzvwk3ytdh32RLLLNKHY9z3qlPcmQ7FOSep9KoKL65mKSggfWtBLbyY+nJrmOtu5l6Hoa2El1eOxe4u3Lueyrk4ArcWPiszRL6e9iuhOiq1vcvD8vcDofyrYQ167n//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-9.png', linkedinUrl: '/in/shirley-hall-68f8f386ca', jobTitle: 'Editorial assistant', }, @@ -10095,7 +10095,7 @@ export const peopleDemo = [ city: 'New Todd', email: 'robert.arroyo@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-10.png', linkedinUrl: '/in/robert-arroyo-956557b51d', jobTitle: 'Counselling psychologist', }, @@ -10105,7 +10105,7 @@ export const peopleDemo = [ city: 'Kennedystad', email: 'kurt.moon@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-11.png', linkedinUrl: '/in/kurt-moon-c7b749a5da', jobTitle: 'Cabin crew', }, @@ -10115,7 +10115,7 @@ export const peopleDemo = [ city: 'North Krystal', email: 'nicholas.bradshaw@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0kikxTqKAGgYrj9a+J2gaPctaxtLf3CnDLbAFVPoWJx+Wazviz4ik03RItKtZClzfE72VsFYx1/M8fnXj+n6RfzsHS1YqOh2UnJIpRb2PVz8XN1yiR6KyoeT5k+GI9uMV0+heO9G16Y28UjW9yBzFPgZ+h6GvJovDOt3CDZahEPUM/wCuKzNQ0HV9DuI7ho2BzjcD/OkqkXpcp0pJXsfSWKMV5r8OPFs9xdjRb9yxdC1uzHJBHVM9/UV6ZirMxtLiilFIDxbxLD/anxLv5JkJjtVSJFbnOFHP6muosLfZCP3a7a5zxxE8fjO/ZZZY/MMR/dDknYKXwtfXst5HabpirHrOOa5Kyu2z0MPJJJWO5gQnDAqB71R16GK50ucMA5CkjFc1rcEsd86ypdShF3BY5SoYeg962NKVvLRRbXNvHtH7uY7gaxtZXNrtuxwunM1n4i0i4hBUC7QPj3YD+Rr6BI5rxQ2Yi8YpABi1SeOZ2/hjXIJ59OK9t4IyDkHnNd8JXR5tSDiyOlFJThVGZ574otrceKJd65MqI5ye+Mf0qtpEljBqsjSTRxiJMgZ6e9avjyzZZ7K/ToQYn/mP61yEM9tNdMTaPNIOCQhOMHNcVRPnZ6dBpwVjsFu7C+ljAeGZXXKSIQwPtmrtyIIIMrjOO3asW21GxnC2zWz20jNlQ0RXn69DV27XC4z0rF6aHQZnkB5JGVQ7T/JIpHVMYz7YzXpFvH5NtFETkoirz7DFcr4bs1ubqSRwCkWGAx1P+RXXV14eLS5mefiqibUV0IqUUuKK6DkKGt6b/a2kzWoIEhG6Nj2YdP8AD8a8rt4GjneGeR7eZDtcdCD6Gu98VeNrHwxsgKfaL2QZWENgKPVj2H868jk1i713Ur+8mlxcNJvG3oFI4A9hisa0NOY6cPUafKd/EfKt1VpxL3BNMku2nYruGR1PYCuGhvpoF33d4UiH4Uo1t71hFCrJBnhf4pPrXPCk5vQ6p1lBXZ2Nrq0tnqsN1bXEn2SP5XiU4WX1J9cDp9a9OSRZY1kQ5VgCD6ivILRDsBkA3cYX0q/Y+KbvTLoJE/mWynDxtzn1x6V3xgoxsjkz/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-12.png', linkedinUrl: '/in/nicholas-bradshaw-414f2727de', jobTitle: 'Financial controller', }, @@ -10125,7 +10125,7 @@ export const peopleDemo = [ city: 'Gregoryport', email: 'tyler.murray@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-13.png', linkedinUrl: '/in/tyler-murray-244f09586c', jobTitle: 'Psychotherapist, child', }, @@ -10135,7 +10135,7 @@ export const peopleDemo = [ city: 'Desireebury', email: 'shawn.lowery@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwBlLRimyN5cbOeiqT+VcB3HN+JfEx0xxZ2QV7thlieRGP8AGuMuru5upN87yzOeMk5wO9dJoegHxDeS3MrlBIxZmAyST2rrLX4cW9s6yLdyOfRlHFbKcIadTP2c569DyVgOqghc87uoqW0vrvTXE9vKUJ7r/UV7BN8PtJaM/I+/u2etcvqvgCKKKT7NckN1AYf1p+2i9GH1ea1RY8OeI11qNo5EEdwgyQDww9R/hW9jNeVaa0ukatBNISAkmHAPUZwa9XAyMjpUTjZ6DhJtahVe+UvYXCr1MbY/KrFAAYhT0PBrMvcreB4lTSkbHLMSP5f0ruItwXnNecC1vrPTbQW0s64DALFgfMCTzmt/w7e6szxx3sjMJF3LvADL7ECpcb3kbwlZKNjqZGOwjtXN6uT5RCD5iCazNcvtbaaVraWQQx9UjUFm5xx61BZLfyyFZnlYryyyD+RpculyubW1jzq/ZZNQO9CCGA57HNerKPlGeuK5GfRo7/xaQSRHgSsFOMkdBXXIWKjfjd7VtKSdjlUHG7I80UlFQM2dNWCS2aFgDtY9auRQxre4iQAIhzgVgWEhjmcZ681DPetPc+ZHcrbvgqw34JHvUpa2OmMk1c6C0ht53cOo3jnBHX3ovEhtoWEagEjtXP2F4lmSomSVs8HzOevvWhqNwZIcg4JXJz2pNW0HcxtNQnUrybK7RGi5xz1Jq/WTohV0uHDbsyY/AVrVaVjCU7qxBTgKqT38aNtjG9vXPFUbi7uJlIDhFH93vWiptmLmkXb67W0jMyuvmJ1XPUVcjIv7SOWB4klwMbhnj3rmmQFNhJO9Pmz3q9BaSz26XVpMYpCuJFAyNw6nFFSCjZl0ajbdjdWKKzhMszxPLjnArn76/kvW+zWzkvJwzDogpTpeoXkLSTXsflnghQQx/wAK0dM0lLKIttAZugrJtLU1blJ6nP2kzab4huEwRAsaKR7YNdNBd29yMxSqfbofyrm74pJf3EinK5259cVUWJi24c/SulU7xV+0nY//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-14.png', linkedinUrl: '/in/shawn-lowery-7baa4120f2', jobTitle: 'Chartered management accountant', }, @@ -10145,7 +10145,7 @@ export const peopleDemo = [ city: 'Gabrielborough', email: 'jessica.ward@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDlWOaaOtKc1FcNJHbs0a7n7e1ZmhDe6ktmNq4Z/ftWLNqNwUMkmWJ7f4CiOKe7vRaxr5jyHAyOSa6eL4eavPbKGkjjXrtyeKzcl1NYwfQ42e4YxI0eMk9T2qW2upHQ5UOo65Nde/w3u1X95cB27qOK57UdHl0iaSMnLqMjB6fhS5ovQrkktWUkv5YZTJBIykHgA13GiaiupWfmZ/eLxIPQ15xI7yPksOeT6it3wrfraamInfCT/KQfXtVrQzepv4qC+uFtbKSY87RwMd6tEVFcW4uLeSI/xKRTIJvhxZC91G6vpBuaMBVGOmf/ANVeuRxgoOR0ryTw1aTaPo9yzmWSSSUY8hsEccV2Ph671C4YJcu23yi+X+8PY+9c0lq2d1PSKTOnmiB9/auQ8S+GYNUPnrIYbgKQTjIYe9VdVvNUFz5iPdPAD92HHPNaFtdTSjynSUFeMP1/A96mzWpbs9DxXVbRrC8eEjJU45GDTNL8x9UttoO8yrj3ORXXePrDZqEM8cZy4Ib6isHT9Pure9sbnZtZriMBWGDyeD+hrpjJNHHODUnY64jJoWnkUAVZlc6TwsYxBcRSfMGkyM9hgV0EdxZWpuA0kaFUxzxXI6A5F1JHn7y5H4VrXl3o5k2XEUkrqMHYhP4HFcs1aTR6FH3oK25q2TWs7MqshKgEbSCCD70+eWO3RsIvpxVC11DS2iEVqPKYHIUpsP5GprpCw5BxiofY1sjDu7SPULhWlTdtYlR79KoT2KzeI9JtAwP2QG5mJ5woOEH4nNS69qE+l6bPd2zKskQ+XcMg54rP8HvcXFtc6ndSGS5u3yzEc4HAH0rWlG7uc1epaLj1YzbRirS2ryMFRSzHoAM5p32CckjYQQcEGuk4hljMba6SUduv0rpbeGG8jDmfyjjqvesux0K4uF81yI4s4yep+lXp7EQXDWsWQUjVgc8knOc/pWFVLc6cPNp2NAxQ2kOfNV/fFVp7wyLtVssfSstFuJJCpBOD61pW1oQcsOe+K52dlzA8S2RudGMJYqHkXcQM8ZqzodlHZaXBDE5dQM7sdc1u3GlnUENqB/rBjI/h9/wq2dES3t4o4WJWJAmT1YAdfr3ralKyOWtG8tD/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-15.png', linkedinUrl: '/in/jessica-ward-c7e5de5066', jobTitle: 'Acupuncturist', }, @@ -10155,7 +10155,7 @@ export const peopleDemo = [ city: 'Williamsfort', email: 'james.vazquez@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-16.png', linkedinUrl: '/in/james-vazquez-edc804602a', jobTitle: 'Housing manager/officer', }, @@ -10165,7 +10165,7 @@ export const peopleDemo = [ city: 'Joshuamouth', email: 'jeffrey.moyer@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD02ilxVHWtSTR9Fu9Qdd3kxlgo7noB+ZFZGhleKvGFl4YtDuxPesP3Vup5Pu3oK85T4k6/cSmT7XDGCP8AVrCoUfnk/rVfSPDuoa/NPeX06vLI5Yu67uT6ZrZX4dvGCRNHk9DsAx+VYSq9DpjQdrmOPiTr/m+V9tKsxwrGJSM+nTFdp4O+IB1q8XS9RjVL05CyIMByOxHY/wA6wv8AhWlqULSXDlzydvArL1DwZ/Zf+l2t1KJYjuBU4YAehoVVIJUJHtxpuK4/4feILnV7K6s76XzbqzYDeerIehP5V2Vbp3Vzmas7C1znjptvhO5U/dd0Vvcbh/hXSVzvjfy38NT27Z8yUr5f1BB/lmlLZjgm5KxlaJCsdlEEGBtBrb4IGCTXF6tNdWqCK3S4IVMr5PHQU3w5e6nPcxwztMFkG4GXqv1rh5dLnqKX2Ts5cBcZxWBqjDy3/i4P41g67e6kbmVIzOY4skiE8t9B3pLG7ublFjlSdMDOJevT1p8ulwctbFr4ckf8JhqJj4RrUbx7hhj+depV5n4AMNh4l1BJQd9y3lwkDjjLH+lem12U3eJ5tVNS1CsXxRbNcaWGUbjG2QPqMVtVHcwC5tpISxXeMZA6VU1eLQqcuWSZylq0N1bhJFUj3pkcllbaisatHGFyeSBk1VMT2V7Nbs2djEZ6ZrKvbrTbptkqOZFyAyRMdvryBXAk72PWi01dGlavZ3N1JG7I4Zjgg571JfRwWsJWJAMjtWDZ3OnWsxS3V0LnpJGVJNXb6VnOMk0NW0C+hb8JWmdbSTHA3SnPrgj+or0Gs3RdHi0q1GCzTOo3s3b2HtWlXbTi4xszy69RTldC0opKgvb61061e5u5kiiUdWOM+w9TWhicn4vUWmoR3AyBKnzH3HH8sVmiD7VCuLnyjjgr6Vg6Pq+peItW1i41CVpIPNVIEP3Y1wTgD8RTrmzv7cn7LKMD+A9vpXFUtzs9Ki2qaNZ7f7MhzP5h9TVTTZPtmtWcAO4NOu4+2axhFqVyzLcSbV7gHk1JqdlMmiXKWhZbjyyUKnByOeDUqykXJuSZ7YaSvPPhb4vuta0x7DV5997AAySSMA0iHsfUjH616KHXeeUf/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-17.png', linkedinUrl: '/in/jeffrey-moyer-82eb5b4ba8', jobTitle: 'Herpetologist', }, @@ -10175,7 +10175,7 @@ export const peopleDemo = [ city: 'Fosterview', email: 'matthew.moore@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD13aQvaszV9Ut9IsJLy6JCLgAAZLMegFXjJxXn/j3UVlMNvE+TbkvJg9yOP0zTbEkZN/ruq6nI0k1wbeHPyxKcBR745J+tUZdQtbaImW8MsnUKqFse/esiJ2vpsxPL5Y/h4x+tS/2fcTyH5TDEvQIAWY1lKRrGNxj69czvuhnb5TuR0OGU/Su60X4ixXFpEl8mLkAq7KeGx3A65ril8L6lPKZMIikY5OTWfeaHPpUzXDyFiqFvl7n0ojNDlTe7R77Z3cV7ax3EDbo3HBFWQDXl3wy8SGSR9OnbHmfNHk9D6fjXp+8kdMVqmYtWI+vG2vGNcaRtQvoUQllkYFQO2a9nLCvKPEEE0XiK8gh+Vp51UFhzyQc/lUydioq7J9J0ImzRn4JAzgYrbh01IABjPoBWfq809nAIbbziVTKiJcnjuSeKp+H9Q1W6nRL1mwfmGVxj2NcrV9TvjpodGybF9K5zX4FntXGcMOVPvVfxBqmqRXLR2e7ZGcsVGSeeQBUcM099G8cxkyV5WRNpB9scGp8xvXQ5rw9LNb+ILdIEVphcKFCcZOa+g1ORnHSvDfAdlK/j21JXlC0kntgH/EV7rxjgCuyOx589xvltXJ+JtLB1a0vVU7v429AvT+ddWGPrVPUrRr232xuA68jIzn2pTV1oOnK0tTBULMp4H41EnkJcFVKhh1PA59KUZRGA696y7y50klVlkUypnDBSSpPXkdK5kj0E0OhELX8qPtyW4PrRfqkS4UAHtis2G406OZxbyKXY5O7IJ/OrvlPf3kMCnmRgv0qWug7pK7NTwDp0cC3tzs/eswTcR25P9RXbgAdRWXplmml2S26HcclmbGNxq6ZD2IrshpGzPNqPmk2hCPSs3XNctPDulTajesRHGMhV+8x9BWLe+P8AT45PKsoZLmT1PyL+fWvOvHOs3PiBCkzKsS4QImcDJ5NaculyE7ux28WpC9s4b3aIku0EoBOdoYZxn8alki8yEBGRQBwcdqLSOGXSbZY0AiEShQOgAGMVnXljdx8203yf3W7Vwc2tz0loJcRCIEsysfXFT6BqlhBr9tDdyBZbgMttnoXHb8ulZa2tzISLqUHn7q9K5Tx0Hil0u4gYo0MhwR2Jxg/pThrNE1W+RnvnFKBXBaN8TLCe2hXVY2glKjdIg3KT3JHUfrXbWd/Z6hAJ7O4injPRkbP/AOqucbHBc//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-18.png', linkedinUrl: '/in/matthew-moore-13cab3f864', jobTitle: 'Secondary school teacher', }, @@ -10185,7 +10185,7 @@ export const peopleDemo = [ city: 'Mariamouth', email: 'crystal.pena@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-19.png', linkedinUrl: '/in/crystal-pena-620fa626fd', jobTitle: 'Therapist, occupational', }, @@ -10195,7 +10195,7 @@ export const peopleDemo = [ city: 'Michaelfort', email: 'ann.mclaughlin@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDttX1ix0Owa7vpxFGOFH8Tn0UdzXlmq/FLVrovFp1vFaxE8SMQXx+PANct4k8R3fiHUZby5ciIHEUSnhF7Af1rMsre5vZQIuATwFGTWU6jexrCmvmdMPE2p3KZutTnH/bU4otvGV/pF40iOxcjaWY71ce9bui+BZruNftshjiP8J6muh/4VporIF/eA+ua51U1Op0nYr+G/iEuoypbXiospYAMvQj+legjBGR0NeX6h8Pl0a2e/wBKkeW5h+YRueHA7D3rufDGsQa3ocF1Dx8u1kPVWHUV1UqnMclanyGxilAopRWxifLAXz2HmNhfQf0r0LwXFCkvyIM4646VwE+nXthL5d3byQv1ww7fWvTPBVns0lZ/45D+grhqv3Tvop82p3NrJvH+6a0UdSo+YZrjL+5u4cxxwTOvcLwPxrJ0xdUuL0TJFcQI3VWPKjPpmsEtLnU3rY9FnG5DzWB4Ps/sesa5HGxEAlVlj7AsMmsrxbeanZfYbe0EjpOBukTsfSuj8HhpNLe7feXncZLj5vlGOa6KC965zYlrlsdFS02lBrtPPPM7rTYL0yWhijS2KbM9ycZ4HYdKsaVanS7OGFSWCdSfWoH1R9P1rUNKvLZ28r95FIg+9Gfu5B7jOMirkEvmRrkFTjO09q8uScfdZ7KlGdpxN61ukl+VlHI5qS6urOyVFJRd55J4AHvWVAjEjHGabdanp9qDDeKZXPJURl/pxUx10Ldi39v0y/gjAuoJSHwuw5H51s6Ww8l0UYVXwPyrgYr7R5b4x28ckUkoyFMeAPeu90dCumRlurEkn8f/AK1dNCPvnJimvZl/NFJS12nnHN+JtOh+02moBcT/AOoJ9V6j9f51hzq0DiQDg9a6XUNP1O4QyPKtxApDIiJtZT3z61m3EAlhIxzXnVpXnc9TDq0LFOG7DRggjir8a/aI9qMtcreRzWzkoSB7VWj1G6VgqO+R6VmlqauR1T6fNESZJVkHYd811tpEYLOKI9VUA/XvXNeFrKW8X7fdzMQjYSLtn1NdbXbQg0uZnBiqnM+XsNopaDiug5T/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-20.png', linkedinUrl: '/in/ann-mclaughlin-cfe670a52c', jobTitle: 'Quality manager', }, @@ -10205,7 +10205,7 @@ export const peopleDemo = [ city: 'Navarromouth', email: 'corey.jones@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0ClFLiuI+IviyTw/p6WdmwW8ulP7zPMSdMj3PapKLeu+PtK0Z5bePdd3UZ2lIyAqn0LHj8s1wV98QtevpGEF7BakniOEDKj6nOTXJ6Xp11qVwohg8xnPBJJH1rq7T4XXEh864ulRzzhFzzWUqiW7NoUZS2RNY/EbXNMWOG+miugTw0yfNj6qa9D0LxhpuuBI1YwXLD/VOev0Pf+deX3/w51ON8xSpPjuRg1hXzXuj3K5V4mU4znoR3BojUT2Yp0pR3R9G4pQK5zwb4mi8S6Osh+W7hAWdPf8AvD2NdIBWxiLivF/iOjXHjVopS2wRJsXtjH+Oa9qxXlPxHtJf+ExsCv3LmBUBx0IfH9amWxUdze8P6dbWlhbrFGoIQc4rpY1wuOCPauH1U3cTeVAbnaq5RLYfMcDqSelTeG7jVkuI4bl5zFIN2ZuWXPY+9ee46cx60ZWfLY7QgAHj9K5PxRo2n3dnMZ4FLbT8w4IqLxVe6rFOY7RrgxAbmMH3voPeorI3V3C9vO9wQ0eHS5QK65HXI4IoSt7wpST92xmfDEJa+KLy0iyA1tzzkEhhz+tesgV5d8LbSWbWNRup15tl8pWx3J5/lXqeK9GOx5Mtwri/FenLNqscrtli8bxAnhQvLY+uK7Ws3V7F7qINCm+QAjGQOPxrOtFuOhth5KM9dmUbJYpYxuAz7jrVe5ubRL6KLzYo/mA5IGT7etQW5YLwcEDpVKa7s5X8ue0nk2kjKwE/kf8ACuBK+h6i20NiO5s3v5I2licZxwc4+vpU19HFChKgZx2rAhu7CGTZHbyxFxtzJAw3D61p3Ad1VQSeOBTatoDfcd4S08Wk1w652kENzwWLZz+XH4V1HeqOl2z21uxkUqzkfKe1X676SajqeVXknN22ClApKSRZGt5RCcSbG2H3xx+taGJx+oMLPVZ4x8qb8j8ealRI548eZtB6EGsPRWutU0aOa/LtcyAly5yc5NMls9RhJFuwI7AnivOlbmZ60G1FHQGJYI8ebu9zUukFbzUVXqkY38dyOlYFvYalLAXupVVc4wtXrHUxpOv6bZ7PkvWaEn0IG4fyqqaTmiK0nyNnbsP/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-21.png', linkedinUrl: '/in/corey-jones-2b4ff4b6c5', jobTitle: 'Nutritional therapist', }, @@ -10215,7 +10215,7 @@ export const peopleDemo = [ city: 'Lake James', email: 'james.boyer@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-22.png', linkedinUrl: '/in/james-boyer-dcd4131baf', jobTitle: 'Management consultant', }, @@ -10225,7 +10225,7 @@ export const peopleDemo = [ city: 'Lake Mary', email: 'karen.schroeder@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDnOpqtJqMUMvlqDI/U46D8ararqUdsWhVsMBl651L2aebcTsDEYGP1NZGtjodQ1ua22hfLGexptr4kaaQQyoiye/Q1QttJl1e+KWpLyJglnGck1sT/AAz1eSA3CsvmjkVLlFaNlqEpK6RNHfRzvsPyy/3T3+lSEmuYvbPVdJUC/jdQPuyrzg1raRqH26Ah2BlTqfX3qk77EuNtzQxSqMGlFOAoJPPp53uHZ5G5kbcT3NJGXlkEMClnc4AHU1XZsqWAwBgCu0+Gekf2jrL3LrlIBxn1NKb5Y3KhHnkkd54A8LSabZG5vABLJ8zbj92u9V7aQbY7iNzjojA1zupTXFoPLWxmuI+h2j5R+fFc7osc99qnnw6ZLYkkn5hggZxz/hXJe+rO+1tEdD4i0FNQspF2o5x0bvXh0scvh/xK1ocgIwBB/unpXrXi2We2v7e1mhuZomK8Qg4JPr7fWvOfFsEV54ospreN41uYVyrDlSpKkfoK1o6MxxCurm6o4zTgvOaVU2ooPUAZPrT1U5ra5ynnNjYve27SL91XCt7E9K9Q+HNvJpVpOZEwzS+lcP4av7fw5rVxa6zC32dyMkrnaynKkj05r1jSLu0u0kktOYmbg4xngcj2rCvKW3Q68NGNuZbnXwXsdxDtkRcHqTUb31hpziNPKjVgWklc7QoFZqRsSAO9V73U9Jtke2vENxJ94xrGXP8A9asIts6WkXry+0rVGtnW4ilEi4yrZBx3BrjfHWlQzXGmXNuoD27spb/ZIB/mKsx6lpD3QgjtHgeQEpkcD6elQ6u7uYo5DyoJrSCamZ1klT1MjaMdaVRzTitOROa6DgOE8U2LnWZiXBLYYDB4GK9O8P28lr4fsJNpVvJXePfFd3a+BtP1Lw8lpq1urSM3mBxw6enP4ciql5pT2KNayKAVHykdGHqKjEJqKN8M1zMzYL3cB8wBq6IPNhKxzKvfJ659awbm3eFtyglfQdaRZmZcAvx6GuVHYXJ7SaEnz7gSjt7VgXztPdO+eOg/CtSGOS8kkgViZtm9U6lgDzVCSPLYAropx+0ctepd8pRK1JHGSasfZuasRW0AGK1Oc//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-23.png', linkedinUrl: '/in/karen-schroeder-9ded3a0da2', jobTitle: 'Chiropodist', }, @@ -10235,7 +10235,7 @@ export const peopleDemo = [ city: 'Robinsonchester', email: 'ashley.johnson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDJkcIhdmCqoySe1cjqXih3LR2fyJ0D/wAR/wAKXxnqrCVdPiJUY3SkHr6CuRQuzZHTsazk2zaCS1Zv2l7I0o8+TOewBJrSuJ5wV+yWg2gZ3SOAT+H+Nc5ab1JKAkn7zGuu0rwpd6/aAxJOBnIZidv4CuWaSdzupttWI7DxIwmEF4uzPAPfPpW9FOk67kORTX+FjJat5s7CYDKhegrF0uSWHVJLO5yGj/dgH1HX+hranVu7HPVoWXMb/pSAc5p+ARijbg10nIeXare/2hqlxdYwJHO0eg6D9Km0rTzqN2sAchfWqdxZzQyOGUnaxBI5zg4NdL4LtTLPK/TAwD71zzdo3OmlG8kmdz4e8HaWEVp1M7oOA3CD8O/416PYrHFbiOIINo+6prz8m5sECLbvKXAGcZH5ZFSadHqEFzHdRQyxq/JV1wyjOOeeK49dz0brZHfXKs0ZJFeJePcab4oiuohhpVD8dmHGfyxXoHiq61P/AEa3tN5jk273QE4z+XFedeM4HurnSlWF1lYMhUnOSCBmrpr3kzOs/daN20nFzbRTAYEihsVZHNVrG2NtZxRH+EYq2Fr0FseU9znJtOQ3+pacxU3SyBlbbt/dsxOQOnX+dWtOsf7MeUIMIXBwRjFReMo5bO5h1m1cR3UQ5b+8M/dI7jmp9L1KbVrIXVwkamUAgRjA9DXHWi079D0MPUUkk90ehaRewzoqSoGyMMDV/U2hggURKoLnAA4zXMaSkismG61p6jd6TND9k1OaNMckM2CO1cy7HbZbmlEsclrbNIFYFSCCc81yHiqOGbW9O8tMGGOQ9Pda0NMk0e2Jgsb1J8fcUNkoD0FUNQJk1Asw5Rdta0Y3qIwxLtSd9ysAcU4A0AGnrkGvRPIOE8dalNLcpZBGWNMk8/f961PDULp4ftSykEZyD7mn61os2reJmPnRxRRgAhV+cgds10Gk6fstpYtuMHIFcVea2R34WDvzFzT7kRrEGIBVgD9K3ZbT7cN6mMnoCRXIzo8JwynHrVmz1K9i+SIswrm6ncnY2jZNYbpHSFSOcooFY2WeR3b+JieaS61aZtQtbS4kGZgzY+mP6mrTxnGTXZh4/aODGVHKXKQAUYqQwn//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-24.png', linkedinUrl: '/in/ashley-johnson-0d0a8f76d0', jobTitle: 'Presenter, broadcasting', }, @@ -10245,7 +10245,7 @@ export const peopleDemo = [ city: 'West Andrea', email: 'susan.stevens@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-25.png', linkedinUrl: '/in/susan-stevens-75236edd7c', jobTitle: 'Psychologist, sport and exercise', }, @@ -10255,7 +10255,7 @@ export const peopleDemo = [ city: 'Stacyhaven', email: 'jennifer.deleon@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-26.png', linkedinUrl: '/in/jennifer-deleon-92f894acba', jobTitle: 'Development worker, community', }, @@ -10265,7 +10265,7 @@ export const peopleDemo = [ city: 'Port Jessica', email: 'kelsey.lopez@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-27.png', linkedinUrl: '/in/kelsey-lopez-90ffaeecdc', jobTitle: 'English as a foreign language teacher', }, @@ -10275,7 +10275,7 @@ export const peopleDemo = [ city: 'Lake Larry', email: 'jill.hammond@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDj2y1IEqXbTHdYomkfgKMmua51WKtzeQWa/vWOT0UDJNZ41h2R3KrGuPlB5JrKnne8vOFZnc4UAZPtXW2Hw31i7gjluTFGTyEJ+YD3xTclFasUYSk/dVzAXXpEcZctH6Ec1o2+ppOSVO5f1FaV/wDDDUUy0UyPx/Fmub/s670meSO4BjdPvAdGHrSU4y2ZThOPxI3kljmXcjhh3x2qVBzXIwXzw3PmIeQeR2YV19u6TwpKn3XGRTehKJSKztalWHSpmYZzgAe+a1TisLxPn+zF9DKM/kalblPYn+HOjpqGuvdzLlbZQyj/AGj0/IV7laxlUBIHtXjHhJUstHuZ3MsqPIMrBnLccCu68P30oeBIoLpI5eRHO2SOvf8ACuetrJs68P7sEjs34Q/KPxryn4k6ROrx39vGTGRhyo+6ff2NbOs3E8k8VzNb3dzETxFBJwnPf8aWXUGYbEspnRgUeGZuOPfkGoj7tpI0kuZOLPFJWBfcBtPf2Ndj4amE+lhccxMVP48/1rnPEFmbPWLiMW7wox3KjHJANa3gksbi6h/h2K3PrnH9a7nZxueak4zszoiKo6vYtf6bJDHjzMhlz3IrQxzS4wKgs1fh/bp/wjyRYKSh2DggdQe+RXXQC3ttR2zzoH8slQxA+uBWD4elDRbRw6HnjrmrmoatpMV6sNzbm4nIIVUj3Ed645Xc2ejSS5FY0rJILws9tcoyk7hsYMp9eafdRx26sxUFscHOar6ZrOm3atFaR+S4bBjaMoc/1qS/GUJY1EtNDVI5G50GPVdaW5uUV49gTbnDDrz+ormfDVqp17UriM5hiJhyP4iMD+mfxrW1rxpLplzNpNjZCS9lACTM/C7vb1FM0SxOmadHbtzKfnkIPVj1rqpKSjdnDXlFvlj8x55zTetSEYOKFhd2CopZj0ArY5i/o9x9muCScBhj8a6WOzjvsS+d5bkdQBXNnTbu1sJLuRNmxlAVvdgCfwBNXZkuYRvt3Kk/w9q5aySlc7cLJ2OiS1jsUyZVYnqxHWsvULwyERRnLHqR2rNjXU7ojz+I/Zq0PsX2eAn+IisHudN7nnNtpF/ceMpb+eAi2EhYM/TA4XH6V1qx/NU+lW13faBNfOh3W9y8DjHUDv8ArTUUnrXc3ojzLQAAAAAAGrP/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-28.png', linkedinUrl: '/in/jill-hammond-4f87a8c4fd', jobTitle: 'Designer, jewellery', }, @@ -10285,7 +10285,7 @@ export const peopleDemo = [ city: 'Pearsonside', email: 'joseph.wu@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1PFNYqilmICgZJPYU+uc8cahNp3hmZrfiSZ1g3f3Q2cn8qG7K4JXdjgfEfxJ1G6mlh0fNvbDKiTaN7++T0rjJ7u8Nq008shlc8ucv+ddBovhyTUIHlLHygSqA9/etX/hB7uWMR/awi9wBXLKom9TtjQlbRHBbdyLPG0R2j94OgJ/pXQeFPiFc6DeeXcvLc2T4DQl8lPda2R8PI4YjuuXdiecDArC1rwiLWB3tCPMT5ue9NVVcJYeVj3eyvbbUbSO6tJVlhkGVZasYryz4R6nMLi/0ediwEa3Ef+zztI/UV6pXSndXOJqzsLXI/EhSfCTN/dnQ/wAx/WuvrnPGyifw9LZbCzT/AHT6Ffm/pSm7RdyqabkkjA8PxJHpsAQdUBFbwYrwRXOvFPb2MH2dJWIjGBGQMcVJoOo39yFW5WRd3IMnUexrgcep60ZLSJsTltmAOD61zWrAGJscnBz70avqWoyPL9mWQxQj5vLxlucYFVVE0uS4lXaMlXx/MUcvUHO/uifC7bL4q1OVE4FsBn0+Yfz5/KvWa8u8BTHSNQmTylZL+5EZbuuN2P1NepV3U2mtDy6sXF69Raz9ZgM2nttXcyHI+nQ/zrQpHUOjKejDBxTkuZWJhLkkpHK2ZXygpA442mh0jW6VUVVPU44pJ4PsWoSxBiVB3Anrg81k3lxY3MimSWJZFzty+Dzwa4Gnex7EWnFNEmmKjXNwhCkhiaTVDHFCwUAEiqFpNaWVw4s5Y3DMThX5o1NmlJA6t0o62BtJFzwdZNPqiTFR5cKl+Om7nBPvyfyr0Gqmm6db6bZpDBEqfKN5HVjjqat13U4cqseTWqe0lcWiimSyxwpvkdUX1Y1Zkc74jPlXUcoHWPk/jWYEjuLdQGVGxwQAagtU1A61qf292kRpswbjn92QCP1JH4Uy8sLlc/Y3UHr5b8D8K4KjvNnq0bxpoZNClud5Klx3xVCGY3Wo26DkGZNx/EcVFc2OpuMXLRxg9lOSaJ7Mw2RjjyrYwGzzmkmk7lSvI9ZPU0lcR8PtW1CfTxb6nI7EswhMp+b5TgjPcdcV3GK9BO6uS1Z2Z//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-29.png', linkedinUrl: '/in/joseph-wu-f673a42110', jobTitle: 'Naval architect', }, @@ -10295,7 +10295,7 @@ export const peopleDemo = [ city: 'Walkerberg', email: 'melissa.walker@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-30.png', linkedinUrl: '/in/melissa-walker-34f194896b', jobTitle: 'Meteorologist', }, @@ -10305,7 +10305,7 @@ export const peopleDemo = [ city: 'North Williamstad', email: 'lisa.mcdaniel@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDt768t9PtJLq5kCRIMk/0HvXm+peLrrVZWWEm3tgcKqnlvqfX2pPH2sve6oumxORb2/MmO7f49q5U3S2wCpxIBx6Rj/Guecm3ZG8I2V2dJAylwJpDu67c8/jVhJCGJt5IkA6tzx+Nc3pwa4uAXLbSeF6lj7+td3aeGZtRRTcytBAPuwx8Z9yaybsbRi2Q2PiS5t7hI5XSeE8bl6g12tpcpdQLInQ1iR+E7K2jdQGyw6k5xVDQL6a08UT6RcHhl3Rk98VpCpd2IqUrK52gWnBaeo4p4FbnOfOmoXrNcyyFsyOxOT6+tU7ceZMEALyMegoksrySE3Sx7hnGAeVFdH4N0zzN9zKmGBwoNczdlc6lFuVjpvC+hLbEXE+GnIwB2Su5twdoFcXd38unhVjhkcscDBwM+5qppl7qz3S3DNKsTMRs3E4wec5rHlb1Om6XunozKSvJritWUx+OtLkQYcxtkj0yaseK77UYLe1js8jzcF3GeAfpTfD2n3F3qMF7eQiNoISoIYkOS3UZ7Y5/GrprVMzqtcrR3CuKcJBVfFLXYcB4poMseoWiWbkebA5kKk43r6/0robGI2UjKFwC2celeXTSy20qzwuVkUnBr0rw/dy6hYwzXDAmVQQQMY4xiuSpG2p30530fQ6+0kiuFCSxg59amuora2hUIi7mPAAqhbxlGG2lvLmxmQRT3axyrzw+GFYK+x0WRqxJHPZW7yLkcjkdPSrdsV8wgDGBWFZPZrb+TDeGZv4dzEmtjT1y8r/QVtRXvmGIdoWL9FAFLius88+aL6P8AdAjp8xrv/CKmTw1aMPvKD/OuSbT5L5oraIHJByfQV6JoFgLLTUgAwFGAK5aktLHbSi+a5pQ3HyjJwRU62sd0wJKceo5FQizMo+WrEdkYlyzHPtWPmdHNYlkiS0jHzByT8uO5rT0xcRMvua5XTpZLu61CaVmKW0hWNT6A12GnBWhVlPDZNdFFanJiJXLQWjbUwTmlLrpOU//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-31.png', linkedinUrl: '/in/lisa-mcdaniel-9ab62dfbef', jobTitle: 'Investment banker, corporate', }, @@ -10315,7 +10315,7 @@ export const peopleDemo = [ city: 'West Sandra', email: 'ruben.robinson@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-32.png', linkedinUrl: '/in/ruben-robinson-0da78d81dc', jobTitle: 'Environmental health practitioner', }, @@ -10325,7 +10325,7 @@ export const peopleDemo = [ city: 'New Benjamin', email: 'david.novak@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1GilpKAOY8Z+KD4etIYrdd15ckiMlcqgHUn+leMXuv395NLNc3MstyfuFmztz6eleg+N1fX/Ftvo9v8ohjDTS9do9vzp0fw0013WRppSe+SMGs5VEnZmsKUpK6PKpNSeQmTaUm24bip49Sa2ZJA0gl6iRSQV49RXsj+BNEMaqbUFlULuz1rKu/AukLE6rGwJ4B3dKj2yL+ryM7wT8T3Dpp+uyeZEeI7vqy+gf1HvXrasroHRgysMgjuK+YdT0uTTdRmhMihVPULya9Z+EevT6lpV5p07FvsTKY2PPytnjP1FbJ3MGrM9GNFKaQnAJwTj0oEcFZWz/APCUa1cSZMjT7Mnso5A/IiuoiX5BzXHeJ5Jobie4gkuYUuX3hYV/eMdoHfp0NJ4X1HVJJRb3LySKULqZFG4fWuSa1bO6k7RUTtG4Xrisu+c+WwXriuO1bUtbW6YwXc5gJOBCgJIz9at2Wq3iv5Vz5023ja6AN+fQ1Djpc05tbHGamiz37u52spbduHX2NdZ8IbZYb7VWQZXy0w2eMEnA/SszxLZ3NzexmC1CNIu0BmGWbPXiuq+HFi+jvdWd3Ir3VwiygouFCrkYB74zXTCSskclSErto740lLSVqYHOXsMZ1KSJgCAAV3c8daitEto7m4kzGpRdoPA+tS6+DFepKP4o+fwrj5/J1Gct5si/LtZYlY5GeQcVySXvtHoU3eCsdNbpbPMIlMZ3DcpGD17VLLbw25JCc+orm7G6g04C2RQilhtBQqQfxroLiYCMEnkgHFQ1Y0uYl6Fn1a2DhtqhmO089MV0nhu0f7S08zF2hTylYnJwT398CuctY7i51NRDtaVnAAboBn/DJ/CvQ7a3jtYRFGOB1J6k+ta0oXafY56tRKLXVklJS0ldRxmJ4pt5pNJe4t13yQAsVHdcc/41y1usl1YwtbTJECARk4yPwr0XgDJ6V5XqEkwuJ7jT1VYFmdTB2XDfw/571hViviOihN7GzPJHBZ7ZWjkYjp2rNm1ErGGZgzEYA7k1hfbJ53MZikVu4HWtXTtJ2uskikY5AJyawdkb3ky5Zal/wj6RaneRGTfKqOAcbQ3yjH0zXpEciyxrIhyrDINee6rYrqFnFZY5kmT8lYMT+ldBbat/ZpMMilos9Qfu10UNrSR//9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-33.png', linkedinUrl: '/in/david-novak-c3c6f0fb18', jobTitle: 'Pharmacologist', }, @@ -10335,7 +10335,7 @@ export const peopleDemo = [ city: 'Faulknerport', email: 'carl.osborne@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDv6RmVFLMQFAySTgAU7FeRfE/xU91MdD06ZjFGf9JKcBm/u57genrUFG5r3xW0/Tp3t9Lt/t7ocNMX2xg+x6muXPxg1qQyNHbWMa5+XKk49uvNUNG+H1/qccbXTLbxMN2B978a6hPhLpwjYG4nLHoRgVm6sUbKhN62I9D+LxuJI4tWsUUE4MkBOfrtP+NemWl5bX9slzaTJNC4yGU5rye7+E8kZL212M4/jWsKxu9b8Ba/C0ryfZXceainKSpnnj1FNVIt2RMqUoq7R73iikikSeGOWM5R1DKfUEZFOxVmY/FfOlpbibxKRI25TcsQMdfmr6NArw7T9N+zfEC5tZeRFcOynHUckH9ambsi6avI9OsNvlKB1HBrWByoxzXC6t54zGFunXBISDj9fWl0E3tpMgZp1ifBIlfcRnt9a41HS56PNrY7eQnbzwK4XxvBDLpMjSRhwhDDPbmpvFE9/I8kcEk+yLlvJ+8fp69ayIopriwurec3DK0J3LNyQcZBFUlb3iJu94naeBJ3uPBtgXYsYw0YJPZWIH6V0WKwfA9tLbeDdPSYYYoXA9iSRW+a7Oh5z3FdN8TJkjcpGRXnM9mtrrVm3UxI0BcnknGa9JrkPF1jJDbi8iUbUmVyc8jPB/nWVaLeqOjDzSvFmjaLFPCAyjI9aq6hcWVtIiPJFHhgMsQoJ9B6ms+z1HdbswOWVC2AetZk8k+pqqzwSKozhRAT+tc0V0O6/Y6MT2MurSRiaJyyjKg5waZqkMMVvII1CllI3CuVjhfS7vzohIMrhlkiIB/Gtqe6a8MMEYzJNgAZ6ZNNx1sS3ZanTeHbVrPQ7eFnL4BIJ9M1pGm28Xk20cXHyqBxTzXalZWPMk7ybHVU1W2W70m6gfo0TfgQMg/nVsVV1S8isdPeWUMVYiMbRn5m4FN7CW55C161lcNCxcSKMMuex/pXTwajFdacU814324DLzgVBq+hx38CTeWPNAxu9q5uS11G0RkTzCB/s54riVmehrFnTi9htLN189p5Oik8CjwRFPqWptdOP9HtONxH33IwB+A5/KuVg0/UrwBSzJFnBYDBPrXpvg+2istOmtogFCOPl/DrWtO3MZVnJxudP//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-34.png', linkedinUrl: '/in/carl-osborne-4aa9f429ec', jobTitle: 'Arts administrator', }, @@ -10345,7 +10345,7 @@ export const peopleDemo = [ city: 'Campbellbury', email: 'jennifer.moore@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwCQrSbakIoxWVzYr3VzDY2zz3DhI1HU9/Ye9cpHr+qahcHyQlvD2GATj3JrE17WptU1OQx5EEZ2xA9h6/U1Lpem3l3g20JkYdXccfhms5yZrCFzqZrq5trQSyXa5x93OSfyqOz8SRKMySEr/EG6j3HrSJ8P9XvVWUyC3fuVYjNUdV8Happ0LyzSCZVHYdayjO27NZU7rY6mC/trnBikDA8g+tWgM1wsUV3pkCREg9wAeRXa6fN9qsYZv7ygn61tCdzCcLFkiqGs3w0zR7m7xlkT5R6seB+prRxxWJ4sQN4butwJGAePrVEo5Lwh4eGs3jtOcxpgnHcnmvY9J0izsYVSGNcivJfD89zaaDJLB5oeWYqBGOScDHNdp4PudXubpIr4y+WyFg0gwR7GuaabdztpNJWO/BUKRmsfWYllsZV7lSRXIeJG1qK8Z7eS6aJegibAIz6etaOl3d/OqwXMM64H/LTn9ahx0uaX1seZ6teyrdkAlShI69a6fwTeSXNndQSc+U4ZfYN2/SuY8WWMtjr1xDtJWQh0wM8Gt/wDHKkl6kisNqoefQ9K6IdDjqX1OxxxUc9tFd20lvMu6ORSrD2NTYpQK0MTO8IWsdlaXGn3KBnSZuo6jjB/LFdB/aFhYXciSyJFshyox+ZrJZWW7V14yMZHemy6lpclxiW1luJY+MxxFsc9M1yST5mj0qVnBWOi066tL+AFJIpVIBDAhgRUt1LDAp2KBism01jTWAt4oJLdy3CvCU5/Kn3alup4qHpoaaHN6hprajrEd4YllRFCmNurDPOPwrR0vS4dMWZYv42/IDoP1qsNaMWvLpEcClpYzJ5xb7oHtWuK6KUXuzjrzVuVEYFLikFOrc5SG5RmhLJ95eRTLa0iuwHN20RI/hrM8Q+IodHjjhQJLcyuqFN33FY43H+lVrpJohuiZhkZwDWFVapnVh5OzOtWCO0g2/afMGOpqhLdtM/lo24nv6Vz9n9uvDtdmK9+a6O0s/Ij5HNYNWOi7ZkWujzf8JXPqkhAhEQijGeTxyf51v4xXCprWq6d40v7e4laTTlYHY38IbGCD7c13AORkHIPeu2KtFHnzd5M/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-35.png', linkedinUrl: '/in/jennifer-moore-0468307bea', jobTitle: 'Water engineer', }, @@ -10355,7 +10355,7 @@ export const peopleDemo = [ city: 'Frederickland', email: 'nicolas.walton@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1aiisLxhrjeHfC95qMe3zkULFu6bzwD+HX8KQyl4k+IGieG5WtpZWuL4D/j3hGSP949BXn+qfGHVZG/0C1trZcY2yfvGz69q5rQfCuo+Lb2W8lumSFnJkuHGWdjycV6FafCTSkQNLcTyEj+LHWspVYp2N40JSVzkZPi14gCoTcwDaMkeQMv8AWu98EfEmy8QQ/ZtRkitb1QNpdwqy/T39qp33wq0OaAKvnIwH3g3WvPPEXgC80W2kuLSXzokO4rjkCkq0W7Dlh5pXPozg8iivNfg/4nk1XSJ9IumJuLHBjJPJjPb8D/OvSq1OcK4D4s4fQdPiZwFa8BZT3AU139cJ8UbIz6Vp8+0lY7nYcdtw4/UUPYcdxfDUCRaZDHGvy4yAK66PGwBWB9q8/vZjYWyRBLpxs+WO1HzMQPXtVnw/c3891FHIbpI252TkFhx7V56XU9W/Q7SfAQgsB+NcxrbAW8gxnKnP0rJ125vxcloxeywxk/u7UgHg+9JBdtORCUuE4yyTr8w/EcGhrS40+hy3gVxZ/E60EZ2rcRyRvjo3ykj+Qr3avDNAsXHxas4YD+5hlaU+y7Scf0r3Ou6DvG55dRWlYK5rxlbzTWcLK58pSdyA8McjH8jXS1S1eD7Rp0gCM7L8yqoySfpRUV4sdGSjNNmHpzRTRbSijH8RNMk1XTdP1aOOeeNMg7AerHHJrNsjIg24OVGSD1pZ9TsJ28mWxmnwNpKQbsfjXBG+x61r7FzS9S0++u5hDOkisx6diOxqbUBBbKQka7iDgisaLVbKOUxx2ktsWwNskJXP41ZvpGZCSecUS00C3cyNL06WfWnmiJWSSaMqy8ZCkZBNepmuV8Lac4C3UsbooyY9w+/nv+X866muuhFqN2ediZptJdAoopR6CtzmOG1qQaVrUqg/JJiQfQ9R+eaeIbS7QbrkqDgjacGofE0kOqam6QAloVMTEj+IE/41yEhvbaQiMOAO2a8+dlN2PUpN8iudnIltZw5SbzOP4qyTcm8u4LVDkyyKpI9CcVhq9zc4EhbB6itOzDaZLFemPcYmDhfXHNTpctttOx6sqLGiogwqjAHoKWq2nXqajpttexghLiMSKD6GrLNekeQf/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-36.png', linkedinUrl: '/in/nicolas-walton-41b1798348', jobTitle: 'Clinical molecular geneticist', }, @@ -10365,7 +10365,7 @@ export const peopleDemo = [ city: 'East Steven', email: 'robert.vega@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDt8UjFVUsxAAGST2pazPEZH/COahltoMDAsTjHFIDjPEvxGQB7LRSfO3bftJAKge3+Nec3V3J5jNPI8kznLOW3ZPrWr4Z8MTa/vkZ/JgRtu7uT6CuwT4YW2zP2uRz7is5VYp2ZtGjKSukebSXB8mMM3zAYyO1WdP8AEN/psyXFpcPE0fUA8N7EdDXoq/DawRH3yMzdscYrkfEfgv8Asu2kuLaQuqHlSOcUlWi3YboTSueo+E/EUXiPSVmyouY+JkHY9iPY1vEV478J7ryPEVxZyOcyW5KDPXBB/lXsZrYwCsDxqxXwdqRUHPlgcfUVv9qr6hFHPpt1FMAY3iYNn0xSY0cb4IgSPw/a46uSxz7mu1SNlUd64C2sjH4csEe3eZvL2gq5AU8n1HNaPhOfUBMIHEyxycgStkr6Z9K4JRu3I9KDslE654yVJJ2iuV8SxCbTpljw5K9uc4qn4pe9nunUJLJHFzsRyN3OOBml06BihQ2rQgDk7sg/r1oUbajbu7HLfDa2a48ZS3CoFW3hYMfXJwK9j7V5/wDD/Sjp+pXs8gYtc7ghHQKrd/ck/pXoJrui01oebOLT1G0MAyFSMgjGDRSimJGVp0UUML2kgBKMQARxjqKtxrFFeRogRcfMTwBUF1AI7pZVz8/X61Qv73STIv2qRfMQkAgnK5GO1cEouMuU9OnJSjcvxrDNdTRtsYk5HQ5puo+Tb25CAZPAArN06+0gMy2TpuZznnBJqxeBZHUM4AJAye2aVtbDk7K5JoVmYBJIRjOAPr3raqOCNIoVRCCAOoqQ13QjyxsebUnzyuNApwqvPeQ2zRI7ZklOEQck+v4D1qtNqAgtZLmQ4jUFvoBVEEHifVbbRtFe8ud2FYBQvUnP+GaoweZexK8MqLxncRXmOs63c+IDLPcOSCxVY88KOwH4V2egXKal4et3SUpcQoI5dp5yBjNYYiFrSOrC1LNo2XhkgVnlljY+oFVJ1Go2s0UhLROjKffIxVFomkuAst3JMpOAuMD8avXd/a6XYNJMwVVGAO7H0Fc2reh0ylfVnEaDNe+F9UuII7tmVXHU8MvoQa9Zs9UWeLMmAc4yOleKNdyX+qNMRtaWQED2z0r0O2uSNCMoPO7+gr0bNJXPNQHZt22P/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-37.png', linkedinUrl: '/in/robert-vega-c9f7c2fc77', jobTitle: 'Engineer, automotive', }, @@ -10375,7 +10375,7 @@ export const peopleDemo = [ city: 'South Sandrafurt', email: 'emily.morrison@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-38.png', linkedinUrl: '/in/emily-morrison-dfcf31f9c8', jobTitle: 'Learning disability nurse', }, @@ -10385,7 +10385,7 @@ export const peopleDemo = [ city: 'Hodgesfort', email: 'michael.johnson@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-39.png', linkedinUrl: '/in/michael-johnson-67b413c0fb', jobTitle: 'Consulting civil engineer', }, @@ -10395,7 +10395,7 @@ export const peopleDemo = [ city: 'Port Brian', email: 'chris.miller@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0TFIzKiFmIVQMknoBTsVxPjTXsxS6VZnMqjdMfQeg9aJPlVwiruxX1DxxPc3bw6ZGBCrFd+3c0nuOwFVNS1WdLVZPtIWbvvIY59xmud0UyxzvLKoDngZrcsvAs+pA3F5PJ+8YkdOBXJKbb1Z1Qp6aIp/8Jre2aqJCBE3DlTkA+o9q6fTPGGPKa4fzbWXA8zHKH39qoy/Di1VQY5ZchSMk5zXOXcTaPBdWXl5xgggY3e5HrTjNphKnoeyAhlBUgg8gikxXE/DrWnv7Ka0mlBeEAohPOO5+ldxiutO6ucrVnYfivA9TuJtQ1+9I3Ru077V3cjk177XhOt2l3D42viYivmXO3gdAx4/Ss6mxVPc7bw74ft0hhkkzLLgEljnmu6gREjCjAx2rgNTuprO3jSNLgjGQIupwKf4fu9Ta/hjlecQykHEpG7muRJ7nfdbHfSbQnXBNcZ4i0uK4SSXlZACQfWq3iW91BLqVYJLryYz8wgA3cdf51FZXs0oEU0VxgjJEo55oa6hdbGF4IYR+Lbdh8pbchAPXivX8V4z4Wtrg+NrWLDIIZySW6Ec8Zr2jFdlPY4Km4tch4v05GvLS8jjzK3yOwHRRzXYVS1S0e7tCsYUyDoCcZ/GnUTcbIKUkpJsydOMM0WxlDEdzTZbvT7HVoEmlijXdwSereg/CqdqHjJUdR1qK71XSZFENxbyTkZGY4C+0nryBXDG+x6SV9jStrzT77UpxDNHKpYggHOG9DT79beBGVYwHI61j2Oq6PGGit4pIMkf66IoT6EE9auXkhmKjq2MCh72BkPhXSMapLqMvLqGCZ9Gx/wDXrsqo6VZta237xNkrfeG7OAOnNX67aaajqedVknLQWlpCQoyeBXCfEU6je6XEmlO2Y5k3BX2hweOfUcitPMzSvoWNUuUtNVnwwEZfOc8c9alS3iuYBtuvKHbb1FZMGlS22jRW8zCWVFw7Y4J71hXV1dWj7U3oBxjOa89tOTZ6UW4pI7GS3SCIh7gTe7U/RWW+1RF4KRAucdyOlcVaT3l7JslchDVy8vrvQr7R57YlUa4EUmBwQw6H9aqFudE1ZNxZ6tiio4JluIEkX+Icj0Pcecf/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-40.png', linkedinUrl: '/in/chris-miller-e5fd1642f6', jobTitle: 'Artist', }, @@ -10405,7 +10405,7 @@ export const peopleDemo = [ city: 'Allisonborough', email: 'ebony.jones@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-41.png', linkedinUrl: '/in/ebony-jones-46514a3944', jobTitle: 'Armed forces training and education officer', }, @@ -10415,7 +10415,7 @@ export const peopleDemo = [ city: 'Rickyshire', email: 'bonnie.mcintyre@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1WgnAyelFUdZvf7O0a8vAiOYYmYI7BQ3HQk0hnm/jX4mwrHeaTYWomR0MZuC5HPfAA6e+cGvJpb6SSPYXZl+95eflB+lWxFNrOpTSO+QzfMQP0FdDZeFrTb86E59TWU6kY7msKUpq6OLWZgxXIVm4OeABWnoOvXmhagL3T5hFIRtYjOGHXBHcV09z4SswCREQcdjXJ6rorWI3oSVz+VEasZOw5UZRVz6F8I+MLPxXZu0SmG6hA86Enpn+JT3H8q6SvmvwH4kbw54jtppCPsz/ALufIJwjEZIx6YBr6TRg6KynKsMg+orUxFrlPiNafa/BN8N4XygJeRwcHpXV1R1nTI9Y0e70+Q4W4iZN390kcH86APn7w9EPL3ZxuPUmu5sLdhHnIYeorihbNptvHbTQeaULqT2yCen5VsaNcTQTRrHwkuCFLZI+uOn0rhqK7cj0aTslE6K9iYQ84UH1Ncfq8HmwuuATg4xVzVbp5riRniaWOL+ENyefT8aqxy/aJCgthFtHJU5H0+tJK3vFN3fKcKoME4O77j8jHSvqvRUWPRLFFl81RAm18Y3DHHFfPen+G5dT8QJCv3HnAAAyTk9fpX0ZaW0dnZwW0ShY4Y1RQOwAxXbGSlsefOLi9SaiigVRB5Fqgtp9cv4xtdDcNgjp1qK3W3W+SLzo4to4DdfyrV8dWH2DXYrqCMJHcJkhRgbgef6Guft7tJHJktmlxkfcJrglB8zR6dOScUy3ALSe5dTJFIrZ5X5sY9aivYYLZCIwB9OlI1/Gr7fJaMNwP3ZGKrXGXwzHjripaa0Lv1Oh8B2An1xLgni3Vnx7ngfz/SvUK53wVHYHw/BNZvHJKV2TOo5DAnKnvxmujrtpx5Ynm1Z80gorGudfRci2Tcf7zcD8qxrzVb2dTG0xAPUKMVTkiFFmp4u0+31DQpRLKsUsIMkTN6gdPxryywZjISlx5LdDxXXuplDIzElgVOT61wUttKVYISk8Z2n6iues9Uzsw91dGpdqIQZpboSv64rMEhuGJBO0VUFpdSuDMzt9TgVpxw+VGFAxWDZ0pNml4E1C60d9QaMh43uCSjdCCB+temaf4htL35ZCIJPRjwfxrzrRLTyrIyYx5zFufToP5VqBApyK64yaSOCcU5M//9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-42.png', linkedinUrl: '/in/bonnie-mcintyre-a8669d6f36', jobTitle: 'Gaffer', }, @@ -10425,7 +10425,7 @@ export const peopleDemo = [ city: 'New Sarah', email: 'tom.dawson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDtyBiol5qdxxXK+MdZk0bQZTbnF1OTFEf7uRy34CoKRT8S/EG00OeSys4xd3q8MM/JGfc9z7CuFufGviu7ZpEvDEo6LHGqj+VdB4b+H6XdhHeX8reZON2Aea6yLwbpVvatB5JZX+8WOTWEq6Wx1wwra1PN7D4n65Yyhb8RXaZ5DKFb8CK9Q0LxJp/iOzM1m5DqB5kTfeT/AOt71haj4A0eZN3ksGA6g1ytxp9x4Nv4tV0ks0cfyzwseHQ0414ydiZ4aUVc9bXk/jUgFVbC5jvbOG6iOY5VDr9CKuVscw5+9cN44hSa6sI35U7jj8q7puRXNa/Zi/uLZ1Qn7LIFkzxw+OnrUVGkjSlFylobenqIrOBAOiD8KmkyT0rE1aS6hjKwNKCFJHlLk8VR8O3uo3Uix3MkvzDd+8Ayo9D6Vw20ueonrY6GYHbjoK4/xIg+wzcZ+U5qTxDqOom4lggMmyIZbyuWP0qmqz3FlNHK0pYxH5ZQMjIoStqKcr3RueB/N/4Re1EhyFZgnsueB/OumxWP4YUR6Hb24TaYFCN7nGSf1rYxzXoRd1c8qaadmPKmqF0jMQwA2Kdzj19P1rSY8VXZdwYA43cGlUhzRsXRqckrsdHEk0WeM981DFBAkrLEg35G4gU2FmRNvdRWZc3VudpjnCSISQQxHPv61wW6Hpxd0RiKI6rMsgGS3BIpNRgjiQ7QAxGKyzKiXjObxZXbsW/lWiqte3EUbEgt1I7UcrvYJSSTbNTSFCafHxhmJJ+taHU1FFGsUaovRRgVLXoRVkkeTOXNJskJ4qNQXfaoJJOABWxFopbmZ8D0X/GtCK1gtWVY4wCRknHNXYg4RpJE1DUoHBBguDH0/h2qQfyNSyFJ7Tbv2DGARXQa9o7/AGk6naR73ZQtxGvVwOjD3HT3H0rlZ4IZlLxztFk9hxn6VwVYuM3c9OhNSgrFG4jSLOGBb1NT6LIj30kRyZVi3r9M4NVJLZUJLT+b9BgVp+ELGWfU77UiuIBGtvET/FgksR+YFFHWaDEP927mlkg8ginqc1pRxB2K7QfUUNpu7mE49j0rvseYf//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-43.png', linkedinUrl: '/in/tom-dawson-f004272b8c', jobTitle: 'Mechanical engineer', }, @@ -10435,7 +10435,7 @@ export const peopleDemo = [ city: 'West Melissa', email: 'sharon.weber@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDalJxVcmrRj3Dkmqt80VlZSzsGO0cAdzWbZSRmXuqsspggjDMv3mY4UVXSQTJvmeSQ9towPw/xrCuLxj+8mbbnkR+p9TTxMZ4wrM7L3B4z9R/SudybOmMbIW+1NxcCG0RFGfmkJBrIaa6fUoXSRJGUnkLgH1rdNoJkSOFdhY/O3Ugf59KbNYx2sJxwYwcH69apNCaZaN/KiY3jOM89Vrf0XUV1CzLYAkjO1wO1cfcXEckaFWw4GVI7nuKveFr3OqC3dsiVCDj1HI/rVRdmRNXR2H25QMCMmsnxBc79OGQQm7LYPNXShB4QkVHc2qXlu0LofVT6HFaNXRnF2Zw62BumE0H73ccA9dv1rcGivHbJEAWmfBIA6AdzUFhLNY6O7Q20j5nZRswMYxya2/Dt7qN5MIrpDhkLAkYI9jXK4s7otD7TRZLa0JIBkJz/APWrP1KxdoXc5JZuaNV1LVobljB5hiT+FAOcVatLyfUYxHJBIh77xRy6XG2r2PO7p3jlMYPzK3StnwdHLceJoJFOFjjZ3z2GMf1qPxJpJg1LenAk5rW8C2ksOsTpKhDGAnkdsj/GtYbo55ppM7TaD24+tPSMd6nFqcdRTxb/AO0a2Ocz4YbaB5IAgCSEuQemT1q3aRwxvM0IUbExwMc1DqFrtiWQE/KcVj3d3p+PKe9NvIR82M5IrnkrSO6k7wRswR285KSKu/rhhRcvDaRnYqjHYVk2V1pix7LW6Dv2Jclj+dWLhS+Nx471DNdDOltvt0gaRQeeMjoK39J06KzV5wo86VFUn0UdB+ua5XUbabUNR060gkmjillImaI4OzuK79IUSNUUYVQFH0Fb0Y9WcdeenKgCCjbUq4qvd30Vsh43v6CtkrnPcWeBZrd4ycbhjPpXKJbi5zsuEVlJUkcgkHBp+oahczu4eTCquQq8Cs6yjWSGeLJV45Sykejc/wA81nWhypSOjDzd7GststtGWkkRm9QKqSXDXD+WrZ9SO1VRZzTufMuWKjqh4q/BCkK4VcGuZs6r3M7WLvV9NgSXR2QOGCyKyBsg8A8+9dTpeqG5hCXDKJx1xwG9xXKX12JLryFb5VOXI7n0qzBn72OW6CuyjF8upw12AAAAC5tD/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-44.png', linkedinUrl: '/in/sharon-weber-793caf2e63', jobTitle: 'Magazine journalist', }, @@ -10445,7 +10445,7 @@ export const peopleDemo = [ city: 'West Jenniferstad', email: 'rodney.lewis@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDvMVg+JvFVn4Zt0Mo8y4lz5cQPX3PoK32ZUUsxwoGSfQV8+eI7u41zxDc3vmbY3fEZ/wBgcL+n86TdhpXNbVviPrl5HJHHIlqP+mI5OfrmuVjupLiR5ZmJbHU9T71t6f4VvNTby7ZMAfelkXitO6+HV+IvmmRZQvACkZHvWbqI2VKT2RlaJ451XRp/JinElv3ikG4Z9q9h8OeJ7DxJZq9vIFuVUebAT8yn+o968Tm8H6nByUXg9qk8M3U/h3xZp810rKnm7W56huD/ADqlNPYiUJLdH0FilxRRVmZHeIZLGdF6tGwH5V4BZxiTUIkkbMbOMg96+gLy6jsrKa6myY4lLMAMk15VZ+HhD4zjjkQiCR3njUjHy9cfh0rKpJLQ3pQk1foekacFWxiRVCgIOQOnFR3iKMkPurC1zV7zTo2itIZ5GA3ExJn9a5/T9c1m+vY7WZMNJg524IB9cdDXNZ2udqaTsdFfWzeQX4+lefeKIgLQSBfnRwQfQ1teIdavNOumtEjZmQ87RuxWXK5vLcfaASElRpBtwdoYZqoqzTIqNNOJ7BpguP7KtPtbK1x5S+YVGATirdRwSJNbRSxghHRWUHsCMipK7DzhtxClzbSQSLlHUqQa5iCzkiuXubp2kuPMOwkn5V6YA7V1grM1a3wqzKzAg8qDwawrQv7x1Yery3g+owmC9tWjlCgdORnNUrD+zY7uaG2ijDR4DSd8ntTD80TbWxkE/SsSeTT3sWt1trmQq2RIkTct65rnWp2aFfW4oT4hlLBSjng9cGqgtVkuUgjGTIwTj3NUJXj+2BS024jGZUIzXReG7AX2qhpGYLABJ8p6nIxVKLbsTOSim2d5HGsUSRIMKihQPYcU6ikrtPLJkUsQBWXdXTTM0LW8kRjfBL4+bjqPauhhtWQZzyaq39sHJEq9P4h1FRUi5RsjSlJRldnDXri3kZCxRH4DelEkay2Ri+1hEA4x1NWNajEabZUDI3fsa42/RoWX7NcMYj/AT92uO1nZnenpdE95GkcgjSXzCfzrvPDmlPpthumH+kTYZx/dHYV5kt6LGWO7lUyLCwkZfUA5xXrtnqNtfwpLBIDvUNtPUZ9q3opPU5sRJ7HKf//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-45.png', linkedinUrl: '/in/rodney-lewis-ec6d41e8de', jobTitle: 'Scientist, research (physical sciences)', }, @@ -10455,7 +10455,7 @@ export const peopleDemo = [ city: 'Rossport', email: 'jordan.norton@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDDbais7MAqjJJ7CuN1DxLdXcjxWbGCEHhgcM349q2fFdy0GlrChwZ2wT7D/IrD8O6Omp6lDA2SvV29KmcrFQjzOxnPbGRGdhvZupPXP171D5U8cZilVjGwyCR0/wA4r3ex8N6RDCEFlH05J5NX38O6S9v9naxhMX+7XMq6Oz6q+587QXE9rKNrtGQeGU4rsvDutSagXt7lwZlGVOMbh3rvdQ8D6HJGXW0AI7g159rGit4c1mC8tBmBm5U84rWFZN2MqmHlFXOj2ZpNlSghgCOh5pQK6DlOf8XxA2VsxHAcj9KPBq7byMJjcx5+lbmq6U+r6W1vAR5wxINw4wDjGexPNJ4J09YLm8V0ImhAQ57GuWtNWaR2UKUk02tzvLfG3H61bPT71cRrx1EIwgjuXVMsoi4x/iaoaCuti9jSWefypFDMHbOwHsfQ1yqOlzu5tbHoFwo8ogkDNefeMBmzIA/iUZ+pxU3jPUdYtrv7HZLIV2gs8fXmsQx3ktk0d08rbJU3GTnow5FXCNrSM6srpxSNeNdqKvoAKlAqMcGpBXonkmpZktbPHESshwpKnB255x79atxRQ2t9LJCuDIVLk9TgY5rKhkeGVZIzhgeDV6OeZ5GlmKnd0CjGK4a9Oz5l1PTw1ZSioPdHRIYbqPBC+4NQMLSCR4YlRX25bHGKrwk7OuOM1k6pd6I0Rgvp7cndk725z+Fc8VfQ69EX9Qht31OMy7GWSMDqOCKzNSSCIiONRgckfSseKfTxeYi1Bbh8cDdyBntVu4dnk+britYxbkkY1JpQbIBTx0pmOalUV6J45YVcmr4gLwsqn5lwwrS0LRP7Vt7pWOxXjMccg6q3XI+lZuj2Ooac81tqpY3ayHcScgjsR7EVz4l2gdWEV5iQXT7dgPzdCD2qee1a5t9sUMRcD+JQRUWoaaZH3wEo/qKw59Z1Cxk8jy3Yj+JRXFFa6HoczjuWJ9PktpTJNFbqwHGxQKhUtIDI3fp9KoXGpXdxG8k+VVRlh3rYCiS1guEB8uaMOn0NddCN5XZx4qo2ku5BtpRT9vNAGK6jhP/Z', + 'https://twentyhq.github.io/placeholder-images/people/image-46.png', linkedinUrl: '/in/jordan-norton-0c59185977', jobTitle: 'Armed forces training and education officer', }, @@ -10465,7 +10465,7 @@ export const peopleDemo = [ city: 'Jonesland', email: 'stephen.kramer@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDX60dOtPUYPNc5481F9O8MyeS5SWdxCCOuD1/QVxpXdjoeiOf8Q+P3humtNHCMq5VrhhkE/wCyP61xNzrF/dSEXF3NNk/NvckUulaReapL5duo2jqx6CuztPhqzxfvbsb29F4re8YaEKE56o4eC/uoJowlzNHsORsbFd3oHjq6W4S31MiWBsL5uMMnufUU2b4WXOC0V0hPuDXP6poF7okiRXHyxk4EgGRmjmjLQfJOGrPY+Dgqcg9DT0HPSub8Faol9pAtWbM1r8p/2lPQ/wBPwrpxWDVnYrdDCO1cN8S2Y6dYQY4eYnP0H/1670gZrjviJCJdGtSCfMSfIUDqMc04/EDV0UPCNktvpalR80hLE139mrMoJ7AV5/PHc2lrbpbvICIwAsY6kCtLw/qurrc29vckkSYYFxggehqZK/vHTCVrRPQrYknAAx05FYHjeCKXQZt0anbgnI96zvEl/rNhOIrNpNo+bMYBJHoM9TVuxhur6zltL8TnzIyGEyjnI7EUJW1HJ30OQ8CHdrF4U4TysEevzV6AAcVx3gbSXtJbyeVSrMBGue4BOT+YrtNuBVTd5HKk0tRpPNYvia0a50s7V3Mhzj68VsHrSTw/aLd4txXcMZHWpKi7MxdPWCZQJFBOO9TCJBrFukajAYZIqk0LWl0YwxO09fWq8kltLfq01wyOv/PPOQfwpHUmrKx3csdvJLtnVd2flzzUsyRww7gecfgK5+yn00RMhlJlcgln3DLeozxWxMu8Bd2Rih9hsoWlr9mi28YySPXBOefzNWD0qZkOBk5OKbt45ppHLOV3cgKc0oXmpAAadtFOxJh66iRvDIGAdsgjPp3qlaosjDdJt54K9RWhr2j3F1c219bZbyEaOWIDllOCCPof51hmNw48qQJnuw4FOUXF6mtKV1odfaRrHbhPO81cfxdaJ7gQQNMxJSPk4HNZmk2twVP2m4GP7sf+Na11p0up2j6daZWSVdu8D/Vjux/zzULV6FyejuSW86zQRTgHZKgdcjqKexU9K3pdFtxaRW6AqIUCoR1AArMk0iZE3xnePyrplSa2OJTTAAAAAAAAAAP/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-47.png', linkedinUrl: '/in/stephen-kramer-3c9febe618', jobTitle: 'Journalist, broadcasting', }, @@ -10475,7 +10475,7 @@ export const peopleDemo = [ city: 'East Stefanie', email: 'hannah.miles@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-48.png', linkedinUrl: '/in/hannah-miles-a7dda4b311', jobTitle: 'Retail manager', }, @@ -10485,7 +10485,7 @@ export const peopleDemo = [ city: 'West Luis', email: 'matthew.gomez@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-49.png', linkedinUrl: '/in/matthew-gomez-138bea0818', jobTitle: 'Landscape architect', }, @@ -10495,7 +10495,7 @@ export const peopleDemo = [ city: 'West Jameshaven', email: 'brian.ashley@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-50.png', linkedinUrl: '/in/brian-ashley-97ba5b196c', jobTitle: 'Clinical psychologist', }, @@ -10505,7 +10505,7 @@ export const peopleDemo = [ city: 'Port Debraburgh', email: 'tyler.silva@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDvcUYpaKQwrE1HxdoWlTGG61CPzhwY4wXYfXHSsDxfqt9qWoDQNHnMQAzeTqcbc9EBH61l23wytSoLXs7E9RgAGs51VF2NoUZTV0dND8RPDU0/lC8kQ5xueFgv54rpILiG6iEtvKksZ6MjAivPp/hfpvlr5dxcIwHJyOapx6dq3g+U3VhdGeBcedCw++BUqtFlSw8krnqOKSqul6lb6vp0V5bNlHHIPVT3B96t1sc4tQ3cxtrKecDcYo2cA98DNT1U1RC+kXqjqYHx/wB8mgDiPDURljNzId89w7SSt6sTXZxLhRzXmjS3UGm2v2c3ALR7gsA+Zj161r+GLrWPtEEN08jRyjcDL95fY1wSje7PUhKyUTt24B5rF1MqsZbg+tc14luNaNzJ9me4MUf8MJ5PPQDvT9Pe7dRDN5/A+ZJsEj6EdaXLpcblrY0vA85F9fW68RlRIAPUHH8iK7WuB8AxMmuasGziP5VJ9C3/ANau/Iruh8J5tT4grN15JZNJkELsrblyV9M8j6VpVHcw+fayxf3lIpyV00KDtJM5XSRbvbxxsgyq4AI6VNcalYabqsEdzKseVJXjqay42ezu5kdDGyMTsIxx1qCW/h1GdTLCWKZwFiL4+tcCTbseqnpob2j31lqfmvDIsg3HqOeD3zUmoCKGNioG7Fc/aaolhKybDh3yA6FWB/GrOq3ReE7Sckc+1DXQL9ybw9at9tgmVsZlaQ7T1BBHNdmax9D017WCKWYAOEAVQeme5962DXXSi1HU8+vNSloIKWkFKSACSQAOprUwOP8AGK/Y7qC8BAEo2t9R/wDWP6VRXZLbhBOIiQDwM8VR1PWrrxBrF9YyxIlnbMEhIHLbhySfyrm5LfWbffHD+8EZxyeQK452c2d9JyjBHazzw21n5fmLK7DGWrNsboX+qW1ip375F8wjnAz0rno7LWrpAbgBIm67Tyf8K0JIZ/DujS3dp8lxD+9BA9Ofx4pKyZTcpJnr+KQ1S0e//tPSoLogB3Ub16YNXU86x//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-51.png', linkedinUrl: '/in/tyler-silva-13e0220240', jobTitle: 'Podiatrist', }, @@ -10515,7 +10515,7 @@ export const peopleDemo = [ city: 'Walterberg', email: 'timothy.neal@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDrQ2Fzzn3FR7Sfm39T0p+WVeeR6VFNMkcTO64VFLNx2pDG3F5BaR75nGOw7msOfxDdzswsLQsi8biM1yer69Le3Dso2p33EAAf0rNTXbtYvKtrqQKM48lOPzPWndLcaTexv3fi/V7OQNJAUTPO+LAP41PY/EmLdsvLXju8R/oa5WXxBqiR7WlEi91miHP41zNxclrln8pUJPKAYFNOL2E01ufQFtqMGo2sdzayCSJxww/kfQ1YGF5yTXl3w+1kW+oLZeYfJuiRsJ+64HGP5flXqAB+6RwetJoCboMkg4FZmuSrBoV3IzlQIzn2zxWkMMpB4FYviqwe+8MajCkmw+UXB/3fmx+lIEeX6Zplx4knkYBltI2wo9T6muxtfCawxKuVI9qpaTBPb+HLN7dJQ0oZwseB3PJP0ArS8Nzapd3SQ3XmCNsnMnUYzXLO8nc9CnaKsh03heF0wxAOPSuM8ReFJLNDNbjeoGcCum1y41QXjrCZmijzxG2C2Dj86mtVmuoxHLHMhxysmDn8aUW46oc0p6NHmejyNBqVvLHn/WKw9QQa+heME9TXha2osvGf2JvlimuF2HsGyK90z8pwPxrrTurnnSVnYlFpuAO5h9Kqazpj3Wh3lskh3yQsFPvW4IW4AXilaFipUpweKGroIuzTOZ8PLF/YNrCyBSkYUqw6GrKSWNteMC8cZCHA7k0wo1pcSrKQoXkhemKwr6403UWDlkVkUqGRCxA75Ncmt7Hpxs1oadibW5lYB45ASeVINS3qQwKdqgfSsCyvLHT3cQeWQTnH3Wz9K0LuXzgGB4bmkxs5R9MNxrMl1gF96+Xlc4Zccn869GAOOTya5Pw7fwalrF3ZrBJus2y7nG0t2xXXheK6KaaWpw15RbSRuKR75oLc45pN4A461Xub63tI/MuJVRffvWpgYHiiRbS6ikDr+9XDJnnAOM/Tmq7xy3NsrW1zHA2B/wDqrAub06r8RrqJ/mgNiVVT0wGH+NQajbalpTF7WTzYscI/Ufj3rmqaSO6g3yo35YJIoi1xJFK2OoFZUtyWkESHcx7DsKwkm1e9uAr4jB6n0robGwFrEqk5Y8lj3rNmt2ze8PaVFYacSu0yXEjTO4AyST0z7VqleMda898HX66VrWtwT3DNaS3JeLkkIe/8/wBK9CjmjmjDxurqehU5rsS0TPNl8TP/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-52.png', linkedinUrl: '/in/timothy-neal-dc5fb8cee9', jobTitle: 'Media buyer', }, @@ -10525,7 +10525,7 @@ export const peopleDemo = [ city: 'Port Jody', email: 'melanie.mora@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDgyc05ULkADmozxWtZwosAd+G7msJz5Vc2jHmdi/onh86g259xjAySvFXjp2hWj+VPHPIW4Vx1q1oGpb5ha2FuX4w0r/0ropPCIvLf98xDkZBXrmsPaSZ0KkjhtW0KC3QS2pbYRnB5rnpojEPm79PevQptD1jTIHiEyTW5BwrpyPxrh7x5JLpraWAo+CyDHf8A+vThVd7MU6VldGaAMcVIKYvA6UoNdDOZbijJIA5JrWvrmaEW1tbFS0mFZiMknvis20iMt7Cu/aCw5rRht3OtWWehl4BrCq9jektT0Tw3psVjbqV5lfl2xXYxFliB6159qFzd2EAjt7Z5mcH5sZAA9BnrVrQ5dWt7iFZt5SZQ3JPyg9Mgng1jFaXOt2vY7C7BliYMoII715z4ksRbgTKeVOAD71q+LL/U45/IthJsQjeUyc+3FYuoC5utHmS4g8uWBgGweGwRyKduontY5fWLZUMN3Hwsw5HowrNra8QiFHtYoVG1Uz1796xxXVH4Tge4/O3kdR0rqdAgW70+CbbmW3dix79Rt/rXMeXkYq3BfXemW8s1o4WQLyGGQRWdRcyNqMuWR67p80E9uIpUDfWp5/JhkjiiUDOCSOMc1gaXIJ7eGdDgSIrY+ozVm/urOUJFPa3ErqdwKRnr6g1zq+x22TNSRYX1O4ik2lThgTWTrItvIa3UBI8bnPsOTUVrdWcbukcV0JnwS8qHn/CsfxHcPHblcjc+Q30qkm3YmdoK7OU1m4juxHIpXcDhscGswCp5owzccYpFT1rp6WPPtrceqk1Zji34BGRVi20+a5mSKGNnkc4VVGSTXf6b8NLqOwW6vMG5DEm2U5+Xtz3PtU6svRPUoaVmDTLcc7QgGfTFa0TW0q/vtxHoDSx2oQPGVxg9MdKhNmd528fSuS+p3rRDLn7LB/x77hnsTXG6jM897M0jEA/IuP4RXXyWuCx6kVDD4fi1SdbY/JLIrGKQDowGcH1BGfoa0pv3jKqrxPPApHWl2n0rsZPD0aS+Vcck8Kw459Kl03wdHfXwtmuhAW+4XTcCfTrXRHU5AAA5ZLlP/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-53.png', linkedinUrl: '/in/melanie-mora-2690667b9b', jobTitle: 'Personal assistant', }, @@ -10535,7 +10535,7 @@ export const peopleDemo = [ city: 'East Lindsay', email: 'michael.gonzalez@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-54.png', linkedinUrl: '/in/michael-gonzalez-06594d52b5', jobTitle: 'Waste management officer', }, @@ -10545,7 +10545,7 @@ export const peopleDemo = [ city: 'Ramosborough', email: 'anthony.moran@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDc20bam21leIdWXRNHlu8BpMhI1PQsen+P4UgKut+J9N0EiO5dnnK7hDGMtj1PYVyl38RbkuWtrGOKLjaZssW/LArnLbRtV8S3Ml5CjzSOx3ys3Bb2rWb4c+I/JANtCxH+1zUOpFaXNVSk1dI07L4jHK/bbKMxnq0Lcj8D1/Oux0jV7LWrXz7NyQOGVlwVPvXmh+G2vbGJiVMc4Bqjpt1q3hTUkBVkb+JG6OO4ojUi9ExSpyirtHs5Wm7KW1njvLSK5iOY5VDKfrUm2tDMn21w/wASomk0qyQNgeeTj1wtd2BxXK+O7FrvTLZkYboZwzDPO0jbnHpkipbshxTbsjW8FWcVpoNqiKASu4nHrXZ9VGMHjtXnGrRXVvDDbW4ufLSP5fs/ByB6/wAhUvhSfVzdxwzSXBik+bMxyRn19D7V59vtHqLS0TurlcREcDIrzTxxZWs1izzRKSCCGxgj8aseKbzWJLqaGFrjyIOS0HU+wHfrWQYLi7tLi2me4ZTEdyz8lTjgg00rNSCTunE3fBTmTw1EmMLE7Rr9B/8ArrodtYfglceGoUbAlBLOvcZPGfwroCtegnoeW1Z6jwOKo6pYLdQPx87LszjOBnP9K0QKHUlCFxnHeoqR5o2Loz5JpsdY+Vc2oWQAccGkN1p9rfRQLJHH8wG5iBuPU4HfFULbeo2qfu5GPcVXnu7e4iEcun3EirkBxDn6kH/CvPinservsWre4srjVbmIyxurOQMEHB96r64ltbW0iRRgFxgmsiG6srGdkt7KeEuRkvCcn6nmpr9nu50iU/MWAwfU02newN2Wpc8PWi29vIw4ztTH+7/+utYim2sH2e3WPjI649akIrvpx5YpHlVZc020PHSlYhVLHoBmmg8HAyB3pYR5hG8YHcVTaISOXt9YF3brqEaOlvcZYL1I5xz+VbANle2oEk5CEdAcVFFp0VpbNp4UDyiQox1UkkGsW+02QKTCxVx3U4/SvNk/edz1YfCrFu9NlYxs0UjHHTcc0zw86317JMTnylyM/wB4/wD1q5x4LlpNkzZPerfh+aWz8QylBuiFt8y5xzu4rWlbnRnWb5Gd/TTVS31O3uOA+1v7rcGrWRiu480//9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-55.png', linkedinUrl: '/in/anthony-moran-1b9585391d', jobTitle: 'Accountant, chartered certified', }, @@ -10555,7 +10555,7 @@ export const peopleDemo = [ city: 'New Anthonyhaven', email: 'kelly.taylor@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-56.png', linkedinUrl: '/in/kelly-taylor-a64148e880', jobTitle: 'Nutritional therapist', }, @@ -10565,7 +10565,7 @@ export const peopleDemo = [ city: 'East Brandy', email: 'jesse.lawson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDHLc0bqQ9aimmS3haWQ4VRk1yHSVNU1yDTFCkGSdvuxg/zPYVz8/inU2wy7IkPZE3H8zUGn6LqHiHUZJYImYuxYv0AGfWun/4VvrLlABCqD0bNaXjHclRnLVIwLXxhfJMEuEjmT2G010+n6tbanEXt5MlfvIeCtVbv4ZX6w+Yk0YkH8PrXJCK98P64m9GQqcP3DL3o92WwOMo7nom6kPJpiNuUMOhGaXNQUNPWsvxAWGkyY6blB/OtU1FdWLahYXMK4BWPfk+xFF7O4JX0R0PgW0jg0OAhQGf5vrXcoSFHHFcA1gbeyt2IunAjAjSF9gGB3Pqa1vD8moQMm+4uBE+G8uc7ivtmsmr+8dcXb3Tobk/IcqK8p+IEKLa+auAxbGa7DxNPeXfmGOS4MMB5S3IVm/x61yGuaW0+kXBha44ZQ6TPvGcjkGqgrNMVR3TVhbLP2C3z18tev0qxSInloqYxtGKcao5RuOa0dEbGpqhAYSKyYPQ8Vn0scjwTLLG211OQaGVB2dz0PSTHJZxxvgkDH41JfAJdQRLjLcnFZGiyTKqfaBtkY7j+PI4qTUbtLm4XzZI49nIGeaztrY7ItNKxas0/4mV3EwGR8wBrL8SGJYUjVBlnGVA645/pTYbkQ3bNayK5YdC3Pv8AWszW7pru7RIwSVG5gD0GP/r00tbCnJRWplD5iT60pBzVuPTblgm1Ad3vVNJFkd0XO5GKn8DjI9q15WcN0SxW0txII4ULuewrqLDQ7a2QNKoknxwzcgH2FY8cZt5MNK0cUgKEocZ9s9q39LlkltjbybvMi5Rm5JXsa1jBLUzlJsivS8dwlygJTyhkDtg81PGsF9AJAyB8cNVuONi2xhnnKe+eorNm0cwzM1pO8KMcmMDIB+nasKsbSuddCppZdCO5FvYQNKWTeo5bpisiC23udQlzmcDavP3T0H9auXGjy3U6JPM0iE5K7cDA7kVsJbfeYDb2A9BV0o9TPETb0ZlyKLWwd4mJk2FVLdc1z3h2xa/mgWTICMWYg84B6fjW7qzfvEgJx649T/8AWBrQ0HTBZ2ss2Mea5ZRjoP8A9ea6LaHLAAAAAAAB1P/Z', + 'https://twentyhq.github.io/placeholder-images/people/image-57.png', linkedinUrl: '/in/jesse-lawson-b8e1d0a3a6', jobTitle: 'Industrial/product designer', }, @@ -10575,7 +10575,7 @@ export const peopleDemo = [ city: 'Bauerburgh', email: 'kaylee.wilson@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-58.png', linkedinUrl: '/in/kaylee-wilson-816a279b72', jobTitle: 'Chartered management accountant', }, @@ -10585,7 +10585,7 @@ export const peopleDemo = [ city: 'New Rileystad', email: 'ernest.benson@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-59.png', linkedinUrl: '/in/ernest-benson-62c7191ff3', jobTitle: 'Data scientist', }, @@ -10595,7 +10595,7 @@ export const peopleDemo = [ city: 'Martinberg', email: 'anthony.garcia@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1PFc5428THwtoJuolR7uVxFAjnjPdiO4A/pXSV89/FDXG1PxhcQ7z9nsj5CL7j7x/E5/IU2xJGJq3iDVNWmlm1O9knYDC7ugHsOAKy7YCVWfKgju3b8KmS0N3iONcucYbrV+LwfrDK0kVsWQDORWTkurNlCT2RHbuqIQrAn1x1roPDPjzUfDN0I2zPYk/PbOeg9VPY1yx0++WQ+ZCwCnntVWdmWUhwaF5CafU+rrS6gv7KG7tnDwTIHRh3BGalryv4LaxPc2eoaXIwMVuVliGeVDZB/DOK9VrVO5k9B1fMXi+Ap451iFhz9sfGfc5/rX07Xi3xA8O+f49hvFiMcU80SSNn77YHI/AfpUzaSLpxcnob3hfwvp9tp9u7wB7jaCWb1rrINNtrcfJFjPfNclrMF5GQsP2soF+RLcheQO5/pUnhm61cTJFcNcNHIN3+kEFlHbPofauG1/ePTTt7tjX1LwzZXgYvCMEHkcEV534m8F2NpZXFzG0mY0JVSc11fii/wBYkmlhtjcLHCMuYCMn2H51lwWk1wkqSvdHdGRKtwQeo6jFON1rcmdnpYzfgqp/4SjUdh+RbP5vc7xivbzXlHwZ0j7G2q3jn944WNR/sgnJ/MV6ua7o7HmSTT1FrnPFNgl0kUrjIjw4453Kcg10dRzwR3MLRSKGUjuOhonHmjYqnPklcxLQxXMIWQA8dxxSmKCK7SGFVDZBYqMVQtgUcqT90kH6iq17cabPInm3KRTRklSHIIP4f1rz0tbHrJpq6L6JE+qXEUoX5myM96rasILaBliUKSMcVlWs1jb3bmG9W4lYjJL5P4VddDf6hBAckO4BHt3/AEp21sTJpJtmx4QsktNJbbGqBnOCBjIH/wBcmt+o7e3itYFhhXbGvQZzUld8Y8sUjyqkuaTYtc9rnjHS9HE0H2gSXqoSsUY3YPbJ6DmvN9S17VtSlPn38wB6LG2wD8BXNTrIvmSoSyhsNnrit1DuZ3O28L30seiJLLIzjzZFZjyV+Yn+RFdSkaXtspSYJxwwANed+EdVjtLt7K5YC3uSCrHor/8A166m7sp4Nxtrhos8jAyv5V5lWLhUaZ6tGd4Jouz2yWoMjyrIw7kCsZ/GMPh7VYZri0a5DxsRtbaR0HH4ZpsUV3ct/pMzOF68YBrh/El4t7rbeW2YocRKfp1/WroLmmZ4ib5D2fRPiD4f12RYobo29wekVyNhP0PQ/nXTgggEHINfLKw/OSOPmrqfD3ivV9ElAt7lpIv4oZSWQ/h2/Cu7lAAAAAAA88//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-60.png', linkedinUrl: '/in/anthony-garcia-1d2ba220ca', jobTitle: 'Brewing technologist', }, @@ -10605,7 +10605,7 @@ export const peopleDemo = [ city: 'South Alexisview', email: 'karen.moody@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-61.png', linkedinUrl: '/in/karen-moody-f6f256a833', jobTitle: 'Conservation officer, nature', }, @@ -10615,7 +10615,7 @@ export const peopleDemo = [ city: 'North Russell', email: 'erin.jimenez@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-62.png', linkedinUrl: '/in/erin-jimenez-0cc5ce0c10', jobTitle: 'Press sub', }, @@ -10625,7 +10625,7 @@ export const peopleDemo = [ city: 'West Ricardo', email: 'daniel.boyd@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDvCoxXPeKvES6BYqYwrXMpwiseg7k10ZGa8F8XXcuo+Ib9nLP+9McY7YBwABSbsOKuXtV8ZXupxLBcSsIwCdqDG70NYy67cwxFfM2qfuex4ya9B8N+B9MTTIWvIvOmdcs7nofQVsS/D7QnjKrCQSODnpXP7ZXOlUJWPJ08RypdwO0zFgwDEHpjgGvWvDfiqPWWMEgxIqjDf3vWqKfDPR44vnDM/r7Vg63or+HtTgv9Od0VR93PG4c/r/SnGsm7ImVCSjdnqWKXFNt2aW2ikddrMgYj0JFS4roOYdXgepqIvGl8MZVLtxj8eK996DNeRX2jm58Z2+qGPZb3827y/wC6w6/njNZ1JJKzNqUHLVHcac37qNcH7o49K24wdg56Vw2tRXYYLE1yIwPuwcEn3zVHw9LqsN/EvmXfkzYJW4bLLz39K4VHS56F9bHpRyVPOK4zxq7Jp6gf89FGcZ68f1qr4su9XivRb2zXIRQu425wcn0qubO5bSnjuJbh1WaNj5/JHzDOD6VUVqmTO7TSPRLGN49Ptkc5ZYlBPqcCp8U2J98EbkbSyg4Hbin16CPMe4A8VxOuW/2C7W7cfLHcJg4+6hyP612orI8T2C33h+8ULmRYiyEHuOf6VnUhzI1o1ORtdwt3hu49hCk45yM5qI21vBdJHEih8gkgdK5/R9TWO23O2QsZfPsBWLfeIhrG02sbxlW3CXzdhz9M8/jXEot6HoKSPRrq3t5b7bMqksAVJHcVXuIo2ZIAB8zgdOOD/wDWrgdO1y+t5ZG1H96Mja/mAlCOg4rv9NcXV4XxkIgbn1PT+tWoNySInUUY3NfGBgdKKWiu48wQVT1PULWygKXEm1pUO1ccnt/OteCwlmwSNi+prE8X+GBeNYaigZxZBg8Y7g4IY+uCP1pTuotl00nJJnnt3bS6eXeLiJwQOPu56irkckjaWn2JbeORE2hZRWldQCa3Axn/AArnrrTrgYFlcDbyCr9V9q4Izvueg04u6NCaaVdJk+1LC8jDAVMGuj8KXUDJc2rOftqFWlQ9lIG3Ht/Wuc0nTHikBuZPNYY/3c1s6BpBl8dG+gDCMWzLcc8MTgL+PH6VrSkueyMqyco3Z1tFXX05iMxt+BqrLbzQ8uhx6tljhP/Z', + 'https://twentyhq.github.io/placeholder-images/people/image-63.png', linkedinUrl: '/in/daniel-boyd-2fa5991fba', jobTitle: 'Telecommunications researcher', }, @@ -10635,7 +10635,7 @@ export const peopleDemo = [ city: 'West Jillianchester', email: 'robert.garrett@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-64.png', linkedinUrl: '/in/robert-garrett-2fade0517f', jobTitle: 'Immigration officer', }, @@ -10645,7 +10645,7 @@ export const peopleDemo = [ city: 'Morrisonchester', email: 'david.vazquez@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDcCcUu2pMcUyeVLa3knkOI41LsfYDNAFPUNQs9MtzPeTpFH0GepPoB3rj774gjzPL06y3j+/Mev/AR/jUcNi/ijUn1PUC3kfdggB4Va6O28K6amJEtwCevOaxnXjF2OinhpSVzmLb4iTJIBe2CbfWIkH9a7PS9Vs9XthNaShh/Ep+8v1FZ9z4V0zBcW/I965nUNMOk3K6hpjPBLEcsqn5WH0ojXi3Yc8NKKueiFM0CP2qtoeoprGlx3QAV/uyKOzDrWkErc5hcVmeJMr4dvSpxlMH6EgGtfFZviHH9hXMRUlpVKL9e38qluyuNJt2RhaKqCyiUcAjIrpYVYINpDY9K4m+hIhhQxTvFtGFhbbk47mp/Dy3Ed3HGizxxSfNslk3EfX0rgcd5Hqxk9InV3YkMTfyrlNW+WGXKk/KQRUGuNeTXkh/0p4YjjbA+0mmWiFlkjJm8sDlZjlgfr3FCjbUJSu+Wxf8Ah5uZdSXGIw6EfXBrt9lch4AWOzhuLaQ/vp5DInuq8f412xFd8WmtDy5RaepXxUF/GJLJwQfwqyBSvGJI2QkgEY4okrpoIS5ZJnPae0MtusMi/MO5q1ClvFfxxKyKV5LcDn0rJuIWsr54gSCr8HHUHkVnXOoWt7teQiMoxCvtOcntmuDkfM0eqprlTRvQRwS308bsh5JUjBziq2qJBBEyx9SOTWHYXcFjK/kMkiu/JwQ278etXL6QyxkDkkj/APVTcbOwue6NHwrAGulbBxFGWX6nj/GuuNUdL0xNNtwoJZ2Ubifar+K7IR5UedVnzyuiMLQ8kcKlpHVFHdjgV5xqHjrVLpGW1WK0T+8o3N+Z/wAK5h765vGaS4nlmcn70jEnFbKHcxudXqWvfbfEN00LBrWFEWNlHXGct781dt4ZnhWS0niQ46tyMfSuU0Jlk1VLeQhROpjDHoG6jP48fjWrPZXtnK0UTMjIcGNuxrjrx5Z3PQw8m4adC/eQmKMyXEsUsnbHQfhWRd6nLZRC8iIZoGV8MOCQRxTDDfSyYl/E1ZnsVmtPsoAJcHj6D/8AVUR1krF1G2m2dTa+P9DuAplklt9w6yJ8oP1Ga6O1vLa9iElrcRTIRkNGwNeBRJ+6A9sEUltLNaTh4ZXiZTwyMQTe4nmH/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-65.png', linkedinUrl: '/in/david-vazquez-852b6ab31b', jobTitle: 'Purchasing manager', }, @@ -10655,7 +10655,7 @@ export const peopleDemo = [ city: 'Michaelchester', email: 'zachary.simmons@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1aiisLxhrjeHfC95qMe3zkULFu6bzwD+HX8KQyl4k+IGieG5WtpZWuL4D/j3hGSP949BXn+qfGHVZG/0C1trZcY2yfvGz69q5rQfCuo+Lb2W8lumSFnJkuHGWdjycV6FafCTSkQNLcTyEj+LHWspVYp2N40JSVzkZPi14gCoTcwDaMkeQMv8AWu98EfEmy8QQ/ZtRkitb1QNpdwqy/T39qp33wq0OaAKvnIwH3g3WvPPEXgC80W2kuLSXzokO4rjkCkq0W7Dlh5pXPozg8iivNfg/4nk1XSJ9IumJuLHBjJPJjPb8D/OvSq1OcK4D4s4fQdPiZwFa8BZT3AU139cJ8UbIz6Vp8+0lY7nYcdtw4/UUPYcdxfDUCRaZDHGvy4yAK66PGwBWB9q8/vZjYWyRBLpxs+WO1HzMQPXtVnw/c3891FHIbpI252TkFhx7V56XU9W/Q7SfAQgsB+NcxrbAW8gxnKnP0rJ125vxcloxeywxk/u7UgHg+9JBdtORCUuE4yyTr8w/EcGhrS40+hy3gVxZ/E60EZ2rcRyRvjo3ykj+Qr3avDNAsXHxas4YD+5hlaU+y7Scf0r3Ou6DvG55dRWlYK5rxlbzTWcLK58pSdyA8McjH8jXS1S1eD7Rp0gCM7L8yqoySfpRUV4sdGSjNNmHpzRTRbSijH8RNMk1XTdP1aOOeeNMg7AerHHJrNsjIg24OVGSD1pZ9TsJ28mWxmnwNpKQbsfjXBG+x61r7FzS9S0++u5hDOkisx6diOxqbUBBbKQka7iDgisaLVbKOUxx2ktsWwNskJXP41ZvpGZCSecUS00C3cyNL06WfWnmiJWSSaMqy8ZCkZBNepmuV8Lac4C3UsbooyY9w+/nv+X866muuhFqN2ediZptJdAoopR6CtzmOG1qQaVrUqg/JJiQfQ9R+eaeIbS7QbrkqDgjacGofE0kOqam6QAloVMTEj+IE/41yEhvbaQiMOAO2a8+dlN2PUpN8iudnIltZw5SbzOP4qyTcm8u4LVDkyyKpI9CcVhq9zc4EhbB6itOzDaZLFemPcYmDhfXHNTpctttOx6sqLGiogwqjAHoKWq2nXqajpttexghLiMSKD6GrLNekeQf/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-66.png', linkedinUrl: '/in/zachary-simmons-3b73fdab08', jobTitle: 'Education officer, museum', }, @@ -10665,7 +10665,7 @@ export const peopleDemo = [ city: 'Tiffanyside', email: 'melissa.wilson@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-67.png', linkedinUrl: '/in/melissa-wilson-8479abddcc', jobTitle: 'General practice doctor', }, @@ -10675,7 +10675,7 @@ export const peopleDemo = [ city: 'Webertown', email: 'michelle.thompson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDvajlkSGJ5XOEQFmPoBT+1c3401q30nQp1mJ3ToUVVByc8f1rA1MPXviZZ2kLx6dGZ5jlfn+XZ715FdXrXtw88szPPITlmOTU9hYXmu6kbeDk/ed26KPeuyh+GEbxZlvG8zrhV4p80Y7lKEpbHnZlMQClgwyCQKGuQx2rnA6V6f/wrTT47cq8kpf8AvZ6VyuueDLnTRvtv30Y6gcEUKpF6A6U0rmp4Q+IFzoLJaair3Nixx1+eL3HqPavbraeG5tYp7d1eGVQ6MvQg9DXyriUNuPAHHJr6D+HF9HfeB7EI5ZoN0L57EEn+RFU9CDqM1ynxA0SLVfD8lw7Mr2atKCvcY5H6CurFNmgS5gkglUNHIpRge4IwagZ5H4Bs0j0+SYDLySnn2FeiRhtuSOnoK8+tLQ6dZS2qi4Jjupo4/Kfb91jz+lb/AIav7x9sVzJKY2UsDL94exrGSu2zspuySOjkDFDlcCue1hPMt5EX7zKRVHW5bq4mknjmuNkYzsjkI3AdsetMs2e5hCmOaN1GSHbIpculym7ux5TqCBLiVCCDu5Hoa9Z+DttcRaJfzs/7iScKiZ/iA5P6ivP/ABLpss3iMxQIWklKlQO5NewfDzTpNN8IRQyBdxlkbK9+ep9+K6E7o4pRabZ1IpRSClFBJx8VnFb3NxbzASHznfkddzE/1qRYo0upBmNAsfTIFXtbt/LvIrhM/ONrfUVgz3Vm8reejPIODtUnFc7TvY9Cm1KKaLthHDOWBCFhg+uRUl7HHbwnaAOOwqrY3toZRFAjRn+6UIqxeqXyW7VLvsVsc9FZA3zXihjMFCg9hg9/zr0PSoPsulwRFdpC5I9Cea5zRLMvNLK+TGCNq9s+tdWr5Uetb04vdnJVqJ+6hfwpRk9AauiDA54HoKkEAI6YrblObmMW/tDeWjRgYccofeuTt4Y5WZZCFYHBPeu+uWS1ged+EjGT7/8A164OeJbiXzRmPc5zjsCawqpJo6sPJ6lnykgAZXB96rzTeaNq856mryaOoXMk7uvp0qIwJGjlFwBwKwOi9zT0ZM2Awv8AG3Nam0hax/DNyzebayDKr86H0yeRXSeXuWuyGqkz/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-68.png', linkedinUrl: '/in/michelle-thompson-bf79635c87', jobTitle: 'Counsellor', }, @@ -10685,7 +10685,7 @@ export const peopleDemo = [ city: 'Rodneyburgh', email: 'donald.stephens@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-69.png', linkedinUrl: '/in/donald-stephens-7f7cf70def', jobTitle: 'Private music teacher', }, @@ -10695,7 +10695,7 @@ export const peopleDemo = [ city: 'Paulachester', email: 'marcus.smith@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-70.png', linkedinUrl: '/in/marcus-smith-3a27ce898a', jobTitle: 'Clinical biochemist', }, @@ -10705,7 +10705,7 @@ export const peopleDemo = [ city: 'Robertbury', email: 'norma.watkins@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-71.png', linkedinUrl: '/in/norma-watkins-61bad82fae', jobTitle: 'Firefighter', }, @@ -10715,7 +10715,7 @@ export const peopleDemo = [ city: 'Rodneyfurt', email: 'jody.morales@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDpsUuQBk9BTsV558QPErRTDRrWQqMBrllPJz0T+p/CpbsNK5u6v4207TlYQg3Trwdhwo/GuZk+KspkURabGqd98hJ/lXLCCbUIoo7eJndzhR6e+K2G+Hl7Faq8kqiRhnYB0/GsnUS3NlSb2R1+kePrG/wt1EbYn+PduX8T2rqwVdA6EMpGQR3rxabRb3Q5FMih43HBFdJ4J8TC3vV0eeQm3lP7gt/yzb+79KqM7kzp2PRMUU8im4rQzItRvE03Tbm9l+5BG0hHrgdK+fri4nvbqS6mJeadyze5PNe0ePpfJ8Faic43KqfXLCvINDg+06pbRkHLODjGeKibLpq7PSfAGhyR2/2y7TDHhA1ehyQB0GUBx0NcjcTtZWeRbTzgr8qJkY4/nVjQbuaDbJKsyI+35HkLEZ6DnvXG9dT0otL3UT+IdCF/p7RIAr9Y2/un/CvFtbgudM1osYmt5QQ+OmGHce1eweJNUuGFxHE06pBjKxD5mzXEeKovtujlxGySQHLeY2efY/SrpuzMqyTXoejaNfrq2j2t6v8Ay1jBYejd/wBau4rmvh7IsnhC2VeqM6t9c5/rXTkV1o897lHXdPGo6NcQ+WsjhSyIRkFgDgVxNp4dSy1NL+NjsCgEMPmyV/pXpQHFcB4l8RyaLrX9m3FmskNy6PFMr4KgnByO+DmsqsW1dG9CUU2pHbacY5bZQV+YAAUmpNBaRCSRo4wDklsAD8araZkRIynrUl7q9pGwjmikkYc7RGT+tca7HppXI4jbzatKEkjkzGGYLzisDxlYxy6RLBbIPMk6D1NaUWqWJvNltE0Lt2KYzUbwtfamidUU5fntVpPmSM6llF8xZ8L6X/ZOg21sQA4Xc2O5Na5pwGBTTXceSSrXD/ELRZb6TTbuGIs0EmHYD+HIP+NdwCAMk4FZV/qXnLLawRE5+UyN059BUzkorUunFyloUoJjZSGJzhc7kNbCpDdJ8zBlbp3qvNYrc2qAgZxis46LfRgiC4KL1Arz09T1VoTX1vb2SM67RjvU2jRM0JuGH+t5HuK528t7tWdbmcybBnFdTo11Bd6TbS25zHsC89QRwQa6aCTdzlxUnaxeNMNPuo4D/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-72.png', linkedinUrl: '/in/jody-morales-9f975a16d2', jobTitle: 'Administrator, education', }, @@ -10725,7 +10725,7 @@ export const peopleDemo = [ city: 'North Barbaraville', email: 'ronald.cox@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-73.png', linkedinUrl: '/in/ronald-cox-f10c08c550', jobTitle: 'Sports coach', }, @@ -10735,7 +10735,7 @@ export const peopleDemo = [ city: 'Flemingmouth', email: 'jennifer.horn@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwBWpu0k1IRTHZYomdyFRRkk9qzNDD1PVFDeTFIMc7mHX8Kxoo/tFwyF87ur55H1qCYvd30q2wLIWOAPSti00TUEVZLeElyPn3965pO7uzqjF20RleUkUkiE5+bBz3pY9KmEqyxHfnoVIyBWjJ4Q1SRmkCCEZyV3ZJpkNpd6XPmaMyDpnuB7UnLsPka3HvcSwJgMCehDDaQa6DQdT+2wGGQYmjHPOciuU1uT7R5clvIuCuCSPyq/4Un2zBJiGkZSFbPI/wARVQ0dyJ6o6srVa9tBd2MsPOWU4we/arRNIOa6DnRzfhTS3S4uluUImQqrKe3Ga9Chh2KBtrh79bu3urma3V8uE2ujYwcEf0FbXhnUdUvWW3u0+doi4Y9eOx9645xd2z0aU1ypHVRRkknaCPesfW9F+1wu0WFfHSsLWtU1y3uSI3l8teSsSjkZx9TW5ptxeTYinilB/vE5BqeV2uU5Jux5XcK8F1LEykFSdy/1FWfDVvJca/axq3yoxds9l710vi/RCNUgnt0y03ytj1qbRtKNnd2rARsZc/OnB6HKn8s1rGSujCVN6vsaBFNApxpK6jiJrcRMzRzKGVxjmtfR7WOK4naJAFVNowKwWzwR1HNSfbrdGZDfeQ5GHXPWuSrG0z0cNJOFux0Mlra3TgSKvmKB1FWMR2sWFAGOgFZtpPprIogvUkfPVpNzH655q5KpI56Vkb6FFx58hLldxPyZqghR9YZoT+5t1YEjo0jdfyA/Wq/itJJtFlitwfNkdY0I6jJ5/TNWbG0WysYbZOka4J9T3Nb0YXfMcmIq2XKupDtpCtSsAqlmOABk1lX2rpBETGOe2a60mzgbsXiyIpMjBV9ScVDaIl258u5QbSRuxnNcTdXs95dNLM5IA4GeB7VJp1wyaza7nYRyBo2APfGR/Ks61O8b9jfD1XGdu56hbWawxZkaF8/xbeaDcmZvKibd2yO1YMSgOEuLiQAds8MK2IbqCFfkAVRXEz0G2zM8Xm5t9BzZOy3KyKU2dTzjH61asUnSxhS4l82cIN7nue9R3En264VifkTkD3qaNtko3dCegruw9NqGp5pz0P/Z', + 'https://twentyhq.github.io/placeholder-images/people/image-74.png', linkedinUrl: '/in/jennifer-horn-7eade4bcb9', jobTitle: 'Product designer', }, @@ -10745,7 +10745,7 @@ export const peopleDemo = [ city: 'Johnside', email: 'joseph.jones@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-75.png', linkedinUrl: '/in/joseph-jones-dcec25d4d9', jobTitle: 'Research scientist (maths)', }, @@ -10755,7 +10755,7 @@ export const peopleDemo = [ city: 'Lake Dean', email: 'cody.blevins@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-76.png', linkedinUrl: '/in/cody-blevins-57df0cb073', jobTitle: 'Clinical psychologist', }, @@ -10765,7 +10765,7 @@ export const peopleDemo = [ city: 'Hamiltonstad', email: 'allison.hickman@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDtqQsqjJIA96O1cB8RdQvbcwW8MzR28iEuFOCx9M+mK5mzdK5c1r4g22nTmO1US7Tgnsa5u6+IOq3tuNzx28ZbrEpDH8a5Wz0ue9IKLlm6Kf4q7fT/AIZ3k8SvdXZjDfwqtQ5Jbs1jBvZD9C+IEsMgh1L54j9185Zfr613FprNneSbIbhJD7GuOuPhZHGpeC9kZscBxnmuM1Fb/wAK6pbMwYeU3yOp4cA8g0ozu7IJU2ldnueQaKz9Gvk1LSre6RgwkQNx/KtCtEzIY77ELYJwOgrxbxVrEuta1JE42xxSbI/pnrXs8oZoHEZAcqdpPr2rwnUrS6h19oLq2MMjyAbRkgn2+v8AWkNHrfh3SbJLK2b7OrOiAKxHNdWpULjPPpXCaheXNjYxwWomxswTEvPAqHQJ9SkvIhPLOI3wT5p5Geg+tc1na53XWx3krfKRuxXnnj+zSfSXkIAeFg6nH4GrHie71GK6kSCSfZF94RDLGs2+luL3QryCYSF1hJ/efnQk00xSaaaJPhrqf+jT6eWBO7zVx+AIr0LNeT/Dq2mTXfNZWRRE2fRs9K9XzXScTEBrlPEuirPqNveRpltwLNnoFBP68V1YFYfim7urLTRJZiIybukgzkew70pK6KpyUZalyxeG4g2Min60pNna3cakxoAQSxIHOeKw9BupLzTra5YBHkTLKvQHvin6nquhqq294jSy7sgLGWIPrmuZJ3sd6s1c1Hexu9VmVXjkV/Qg4NUdYigW2lghXDspHH0rO07UtE3yQWiSRy7hkuhBz25p91MVurdWwzTSrHz6dzSs72CTSV2afhrTE0/TIk6nqDitvNMjTaij0HFOxXWlY86Tu7kqjisHxhZC40V5TcxQmAFx5mPm46DJxn862L3ULLTIPOvbmOCPsXbGfoO9eI+NNePibVWkG5LaMeXCuegz94j1NaxjczcrHoFrNbppsEtk+6024Rx6CrbQSXUKtBconHGQDUei2tqvhezjtDugEICn19fxzmsm8tp4nK28rKP7ua4d5HpQbikaLW726M01wjt2wMD8qm0yxTUbxJzMha2PKZyy5wenbNYttb3DMGuJC2OgzXE6nq19pPja5vLSVo5YyuPRl2jgjuK0ox5pmWIqPlue80hrltG+IGjalCn2mX7FOVyyy8Jn2b/GuqRkkjDxurowyGU5BFY5L3P/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-77.png', linkedinUrl: '/in/allison-hickman-07a1fac3cf', jobTitle: 'Writer', }, @@ -10775,7 +10775,7 @@ export const peopleDemo = [ city: 'West Brendahaven', email: 'david.everett@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDqAtLin44o21AypqWo2ukafJe3bhIk/MnsB71wGq/EudrfbZW8duSMGRzvI+g6U7xtc3WteIItAthlYyDt7FiMlj7AGr9t8MIZVX7TesU6lVXv7VEqiTsbQpOSujhJ/FurXEIifVbkpnnDYyPcCtXRvG+q2duEjuluFTrFONxI9j1rr5vhXpJH7t5VbOTk1gav4C/swtPY7yVBOM81HtEX7CR2mheLdM15UjicxXZHzQOOffB71tMtfPIvZbO7E6O0c0bbgw4IYd69x8Mawde8PW9+6gStlZAP7wOD/jWqdzCSsbGOKUClxxSgc1RJw3huBbvxHq2oNy7zlVJ7DP8AgBXoES4WvOI7eWzbWiiTEfbWEaxnDdBXS+HpbxRDFNI5R035kOWX2Ncc1q2ejSdopHSNkA1l3pwvqawdal1BrpWia4eLdtCxn3q7EJivlEPuQ87uc/Q96m2lzS+tjy3xfDbpqrPFGiM+Qy46n1rsPhW8zaTfpIfkWZdo9Mjn+lYPjbT5X1iJrZGd3XgKuTn2FdX8N9MudO0m9iuovLlacHG4H+EenSumm1ZHDWi7tnZdqBQBS4rU5zMgtY7fUbzeAVuJBKPyAP6irDz2lq8pkljjKxbsHjj1pbtP3sbjryKzru907zv9IUu6/wB2MsR+Vck177R6dDWmrGnp8lreRCSNkcgAgjkEHvT7x0iRiOpFUrPUbKVdtuw3f3Su1vyNSXgBjOetZu60NTCFqs2oLcM5DhSq59zXRabCESaUADzGHA9q56G8KaxbWawl3uSyhgf9WoGSx9u34iurRBHGEUcCtqMXfmOXEVEo8i3YDpSik6U15UiXc7qo9ScV1HCNu0ZoCyDLL8wFZsEcNygctgnqRxU8+rxCJxbku4QlTjjgVz0SXFxb280U2x5kVmI6EkZrmrWumduFk0mjoikVumdyt7kVQvr0FNkZ3O3pVOKzvZw6zyEleoBxU8Nj5QJYcjk1gzpvcs6Fp8X2mS+b5p1XyV5+6Dgn8zj8q3CK5jw+Z01/U92fI2RYPbJ3f4V0xNdlP4UedW+Nn//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-78.png', linkedinUrl: '/in/david-everett-5a8004bbc1', jobTitle: 'Archaeologist', }, @@ -10785,7 +10785,7 @@ export const peopleDemo = [ city: 'Kariport', email: 'james.smith@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-79.png', linkedinUrl: '/in/james-smith-ccd3177ab7', jobTitle: 'Film/video editor', }, @@ -10795,7 +10795,7 @@ export const peopleDemo = [ city: 'South Angela', email: 'chad.stevens@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-80.png', linkedinUrl: '/in/chad-stevens-babda7a962', jobTitle: 'Higher education careers adviser', }, @@ -10805,7 +10805,7 @@ export const peopleDemo = [ city: 'Hillview', email: 'nicole.campbell@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-81.png', linkedinUrl: '/in/nicole-campbell-47b63850d5', jobTitle: 'Plant breeder/geneticist', }, @@ -10815,7 +10815,7 @@ export const peopleDemo = [ city: 'Ochoaberg', email: 'eric.johnson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0c0lLXJ/EHXbjQfDhmtTiaZxErd1yMkj8BQBheIfiitlfT2mmW6SeUSjTSZxuHoB1Febanr1/r1w019eNKQeN52qnso6Ve8PeF7zxAZJzKUhz8zuMlmrpF+FSsG33h55G1azlUinZmsaM5K6PPI7mZbosjkkHKEORj6V3/hv4oXOn7bPVVN3EOBKWxIv1P8X86qy/C+8iYmO6DL24rntc8K6jpP7zY0sS8syDp9RSVWLdrjdGaV2j6F0+/t9UsYry1ffDKMqcYqzXjvwo8TzpqzaJcORbTqXgVv4XHJA+o7e1ex1qYhXnPxdDNpemqCRmdun+7Xo9cf8AEmwa98MqY9vmQzrIAxxkYIOPfB/Sk9hpXZQ8F24g0C3XHzNlvrmuv52jvXEXVrLaWFtbp9pZUiGFt+CSB61P4bnvzMsUjXPlN8wE7ZYexrhav7x6UXa0TrZM7T2rmPEaj+zbgYyTGc1R8RTai11II3uvKj5It2wT7D1pun+a+6GQXG0jJSfk/nU26lN9Dh/BkJf4g6W8cedkx3H22nmvoKvGvBuji0+IrTP8lvDI6ofV2B2j9TXs1d8WmtDzJxaeolZfiC0+26RLDjJPTj8K06ZLH5sTJnGRjNEldNBB2kmY9mkU1uoPXHcZoDWsV6sYKLjqcgZNVow1tK8JPzITnFZt1eaZcOFuAGkTI3BCSuevI6Vw21sepF3V0acD20t5IjOjbmOCMHpT7yKGCMlFGcelYNleaZbzOLYBWduQylST+Nal7IXj69RSatoMp6LYhtYVgCUeTzW9mXpj8K7g1k6Np/2aBZmbLyJnbjG0HmtWuyjFxjqefXmpS06CUtFMmnht4y80qRoP4nYAVqYGF4gT7NIlypwJPlb6iqSos9sNswi44IpdZ1iG/v7WztZElgKO7sB1YYAA/M1jzafeKxNnLx18tjx+FclVWmd9CT5DTMKwoS0iyH1NUXuWmfYpyO5qiltqLswuCFXvznNaFvbeWOn41i2bas7awuoL2whuLZw8LoNpFT15X4X8TSaDJeWksbT2vnuVUHBT5j0/DtXe6d4m0rVFXyblUc/8s5flavRSurnlAAHlvR2P/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-82.png', linkedinUrl: '/in/eric-johnson-be7867ea1f', jobTitle: 'Bookseller', }, @@ -10825,7 +10825,7 @@ export const peopleDemo = [ city: 'Jenniferburgh', email: 'judith.ortiz@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwA3CqeoaraaZAJruUICcKvUsfQCneZnvXnnimaaXXZRI5KIAsfoo+lZstK5du/GF9LPI1swiiydo2gnH+NZFzetKBLPKWkbqc8iqdupmuFBwxz17Vbh0q6vLryYgGlb+EDpWTa6m8U+iEtdTutOffa3DosgwwB+9XU2fjco0YuoFKYAdo+v1xVOH4e6tKxV9oUDPWufvtOk0q5e2uG2svOPX2ojOLdkxypySvJHrVvdQ3Vus8Lho2+6w70/cDXGeHNfthbR2rAx4BJLHiusDg4IrVHOykXIDY644ry6eaa6vXMhJlZjkn616WWznnFee21jJHr32eTBxOFY+uTSlorlQV3Y9H8NeAbCS1S5uZHeZl9cBc+ldppfhbTdLjPlQlmbq7HJNYN7eLY2yosE8wZfkWEkcAVP4fvLsOvmtOsTkELKxYjPSvObk1dnrR5Y6I6wxpGpCrgYxXnPj/w/bXdnLeou24jXdx3Ara8SX91ukWM3Bjj5YQEhjWWs32u0khkhmjBiO9ZCSeR170RvG0kKdpJxPLNGAOrW4KZIcAZ6V6gr9s1wHhyDOsuJ1+aNcpn1B612yuc16SPJkRA80ttpsNzc/aAiieJxIWC8kCo881Lb3MtpN50QUtjGG6EVNSLlFpFUpqE02dxp8cU8Q4GeozTrySys7mFZZIoxuHJwPmPp71Q0qQyW8cicBlB2+hqW51izRtklrJMw5I8rI9+a8xXvY9pJS1RLFNZXWpzpHNFJk845wai1SCCGFlTG8nsKrW+radJKYYrSS2Y/dBjxmotXmeKF5uGZR8oPTNOzvYUkoq7OXfToLG6OzDyDq+OeeSKlU802RzJIzsfmY5NIvWvUirRSPEnLmk2gI5pwQ7GfBIQbmx2FS+QxbAGSavQxGKMxEff6+9Y4iuqUfM1w9B1ZeRHoWrLJaSNCGMaNzkciuhiNjfxgyuCD74IrnfCujmyub5Xcssj/ACD0Xt+PJrUvNFRz8rFPcHGa8+UryuepBcsUuxamSxsY2McnX1OTXK+JNYmh+zBERkfccOcZxj/GttNIiiZAXaRzz8xzgVQ8QaVFqChG+Qxj5GHUHvTjPllcU1zqxl28hubaOfYV3jOD2qReDV6C3UrHEq4VRgj2qX7AshLK20duM1vSx0dqvA//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-83.png', linkedinUrl: '/in/judith-ortiz-d3ecd8a548', jobTitle: 'Publishing rights manager', }, @@ -10835,7 +10835,7 @@ export const peopleDemo = [ city: 'Adamside', email: 'evan.floyd@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDWwKYU56VYMZzWN4q1CTS9DkeE4nlIijPoT1P5Zrl3Z0dDD8Q+N4dLuGsrCNbm6U4difkT29zXHT6tr2ssxe+fy1/hQ7Bn0wOtdn4W8H2E1kJr2LzJZ+SSegro4Ph7ZwEfZ5Ts3bgr81SnFaD9jJq55Vb+Itd0mRdly8iJw0bncP1ruPD/AI1s9YkjtrhTb3jcBT91j7H+lbzfDnTmR3uJXZmzkLxiua8S+DILW3W604mK4gO4En7wFDlFuweymlc65o8mmmKm6HdHVNHt7pgPMZdsg9GHBq+YDU2YiXaK5Dx8m6307rtEzHp7V2fl85Nc74lja6MULKvlxujKT3JOD+hp3tqOMXLRFvRV22cAPDbBXTw5EY5rgdQuNQsm/wBD8zoSqxpuJx9e1WvD2ta3czx295BtL8q5XBx6EVgl1Oy/2TtXZipwe3euY8QuVs5OCflOcVU8Q61rNrcSQ2duX8sZYhd3HsO5qrZTX16JBeGX7nzJKgXBI7Yp26g39k0vCFsY9AQ9nkZx9DW8I91ZXhrcukxQ5+REG3jpnJNbsait1rqcUouLsyBRkVka1AGh3cHaN34g1qAEDrQ0CXEZSRcgjFDjfQIT5XcqWBgubdUkUcDrUwjgj1CGOFVyrAsRWHbmSFigJ3JkEe4qpc3UNzKpMrQzJ0bkVhFdDvurXOqaO3bUJEnC5ZvlJqvqQitoGVAOR1rnbW6htnkL3PnSORksTwfbP9K15g1zPFETncQP8/hQ1rYTaSuzR06PZagD2/lV1cinRwrGgVFCqOwpHU5roUbI4JS5pNlc5HWq+p3psNMnuVALohKA9zjis641aeVtsSrGv97qazJpWuNySMzggg7jnrXZDDvdnO6i6Gdpuo3E2nW99cE7503vkdz3xW7EqXsCsl15LEDDKM1nw2oNgkLdFUL+XFVDaTQuEglKE+vQ15bdpO56sb2TR0LRx20DNLciQgclhXO6lrdxpsdtqEO4qtwitx1UnBz7VY/s65yonnEu70qLXbYNoEsSjklQv1yKcZLmTQppyi7nf2t5DcxJIjr8wztzyKshlNcMIWMChW2yKowR2NXrLU7tDgvux1Vua9SWVO5//9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-84.png', linkedinUrl: '/in/evan-floyd-73bc237c29', jobTitle: 'Chief Operating Officer', }, @@ -10845,7 +10845,7 @@ export const peopleDemo = [ city: 'Cassandraview', email: 'deborah.myers@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDqQtUtV1Wz0Wya6vJNqjhVHLOfQCtELXlPxQ1MnV7ezXI8mPJ+p/8A1VLdikrker+Or2+V44E8hOTsBySO2a4ee+uriUtOXOTzzyataZFPeXSpChdiew6110Xgq8uGLMFVm6kjgCsnNLc1VNy2OOs9RIkEYVlQdFU10+m63PpV3Hd26kHGHibgSD0NX7r4eskHnxF96DPHeuX1F3tD5QXDjg+x+lJSUnoU4OK1PcbG9g1KyjurdgUcZ9wfQ1Y2ivM/hhfXEmoXVszDymj3kc9QccfnXpxFap3MGrMlFeJ/E1/N8ZTxgj5YYxx24/8Ar17aK8b+JWmsnjJZlBxdJHnjjPT+lOQRWps+EdIis7eKVFzKyjJPau9gUiMHivOr67ksLdYY4pm3DgoSAMD+dWPDOo6rNcwW8jTGOQ8eZ1HtmuKzfvHoJpe6ehEkoQD1rhvGPhq2u7OW7VTFOgLZUfeA9aPE97qdpdPHC84WPkiI4z6j3p+k3VxqMDQXEEyZX70hJzke/emk1qDs9DmPhjcyr4sMIUFWgcOcdAMHP54r2QivKPh3aPaeLJiY2CMJIg2OMg5/pXrJFdcXc4Jpp6gtcx430VdSsYblV/ewOOf9nOf5/wA66cUSRJPC8UgyjjBHtTkrqwoS5ZXOQ037PdwLFNGrY7tV6JbS31K3jXaiKwJbpzWde2v9n6nJDECE4KgnPBFUrq6tp3jSa2uHdTlWSM8H1Bris07Hpxakk0dVciyuL6RHKOrsdrcH8KgvDFax+VCgGR26Vj2c9pHCyJaXKuxBMjRHk+ua1LeM3dzFG3fr9KLNuwStFXY/w5psdsZ5wmCzEjI6E8nFbppY4lhiWNBhR0oIrshHlVjzqk+eVwAp1KI3wDjA96uWsAaFXI+Zi2Pw4/xqrq9jOxxHim5T+0ba2WP5zC0nmD2IGP1zWXB9nmO2ctt9Aa6rxLpAkZLlV+eLP4qQAf5A/hXKTWbAjHGfSuOr8Z30H7iNKNbWGMiF2wezGoJ9Wl0IRXYiV42kEbhvQ+h9aLG2CMA2SfU1vw6auoGO2dFZGdWfcMgAEH+gqY3urFTs07msTkA4xmmmtxdP8xJFnCFQf3RTIOPf3rNuLF4HwGyrfdJHWu96LU84/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-85.png', linkedinUrl: '/in/deborah-myers-0014fb575f', jobTitle: 'Engineer, energy', }, @@ -10855,7 +10855,7 @@ export const peopleDemo = [ city: 'Zunigaside', email: 'jonathan.valdez@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0jxFr1p4b0eXUbvLKvypGv3pHPRRXhmofEvxDqck6RXrQpKeEQBVRT2B6n61r/FPW7nU9en0kkfZbOQKg7F8DJPqecVyul6S+o3scEagKv3iRwornlJG8YtkZmuDE8r79z4BYnPPqajLG6RmTcki5BOepH+NejWfgizRVDzzFepGavy+B9LYExRmNiME56/WslUidHsJHH+EvHN74ZiaJAt5aOdxgdiChzzt9D+Yr3HS9UtNYsIry0lV43UEjIyhI+6w7EV5Vc/DyyRzJDJIp9uxrR+Gsd3YeItS02Y7gkQff0DLnj+daRmm7IxqUnFXZ6jiiiitDE+cvGEwuvGepThjj7S4K/Rsf0rS8MvsZCgGXODirHjfw89z4i1TULCTzImuCzJtwQcc49ec1J4Ms4/IkuGJLg7VB/hrCbTTsddOElJJndWxDIAeo4rRJJUd65S5mmjbyws7DrthHJPuTVbTLm+e6DKt1GjdRM+SOccjtWCjodXNrY66VSynjFZuiho/Gtuy9JIJEb3AwRWZ4n1C9tljht1ldWAJaLrWn4BgLalcyyGVpIoiv705IJPJB9DitacdUzGu/daO9xRSmkrpOA4LXLM2utTxlWEUkhmBXqc/5P5Vh6fZx2M05iYlZZS+Ow+ldr48nmsfDx1K3tUnktpFLhu0ZOGP8q4+KR23M2NxbOAOK5KkXF+p6FOopxXdHRW+ydRkckVFcPbWr+WSiueSeAB9TUETui7lz93NUZtQsHZoLiSLeTyrDJJ+lRFXOi6SLspgkht5Gkjbnb94Gtrw2FTUZVQYHlc/mK4Z20+K6SOGUBzkiI5H4gGu48Hwv/pcz8kbYwf1P9K1hG00YV5L2bOoNJS0ldR5o25t4Lu0mt7lVaCVCkgboVPBryu4jMJYxHIQleDkEA4rqfiDbz32g/ZreR4yJVclerAHkflmuds0H2XaRXNXeyOzDR0bJLS8zGnI44OautbxSx/6tGOMDcKwbrT51cyQ5I6kA1Aup6hERGkLuRxnpWSOjmsadxaiBg7JGCvTArv8Aw/ZvaaREJRiWXMrg9ieg/LFefaFqcdxr9pHqifu3YhMHjeORn2r1MOK6aUftHLial/dFNNqpLq1lHKYnl2yA4KkYNSTXkUKhuWzzkDOB6n2rAAAAA1OY/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-86.png', linkedinUrl: '/in/jonathan-valdez-cca544261b', jobTitle: 'Manufacturing engineer', }, @@ -10865,7 +10865,7 @@ export const peopleDemo = [ city: 'Mcculloughborough', email: 'marie.davis@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1bFDMFUsxAAGSTS15x8WPGD6NpY0eyZReXiHzGzzFH/ien50MLXMzxX8YUtrlrPQI45DGxEl1MMqcdlA6/U1x2o/ELWdcZEub828C/wAEIKBvc1X8J+FE14LNMStsjYJA5c+g9q9Pg8CaHLbCNrFOmA3euadZJ2Ounh5SVzz7TfGuu6XKHsdReaIdYZT5in8CePwr1fwf4+sPFI+yuotdSVctAx4cDqUPf6dRXM6p8LtIa2ItkkhkA4dTmvONV0/UvCupQTCUrLE+6C4TjkUQqK9kxVKLSu0fTeKMVzvgnxVD4t0FLsAJdRny7mIfwv6j2PUV0ddJytWGuwRC2M4GcCvmPxfftrXjPUJJiDi4MKgegOK+nXxsbJwMcn0r5Ot1N14pG0s0ct58rMOWG/rUz2Lhue1+HbKG0sYbeFcKijArr7dSI+leb6pdXVnF5cNtLNuUnK5xwO3I5qTwvdaxFdwRzCcW843fvCcpnpkEnFeco6czPWv9k9IkDMhAz0rgPHOmQ3ujXKSLyilwfQijxpearby+Xa+eYUwXMOcn2AHXrVBGvLrTLu3nt5kdIGOXJ+bjPcnmqS2kS2tYnP8Awf1aWw8ZiwDnyL2Iqy/7S8qf5j8a+g6+cfhFDv8AH1uzrzFG+3Prj/8AXX0dXoI8mQ0gEEEcHg143qXhmx0vVN1pGzKl0zhjyUA7fTNeymuE+IcDaXos2rWKIZVcGRJMkEHjj0OSKirFyjoa0JqM7vYk01rW5txFMisO+6pbr7Lb3NvBAEQbgW5A71gaNcfarS3uUOBNGr4HYkVLqNzp1yywzW1zNJGchooidp9Qa89J3sesrNJo6NhaT6lNBN5bqxyuTmoNUFvbW0kcSAAqQMVj6XNpcLNDHDcxTPjMk8bAsR0Oag8Vak2laRcXxAdowAqscAkkAVXK72JlaKuyHwb4Yltdbt7+FtnkHbLjuGByP5flXq9cj8PbmbUPDEF9OAJJSxbHTrxXXV301aJ5FWV5Ow2uf8Z6PPrfhXULK3G+Z4iY19WHI/lXQmgkIpZiFUDJJOAKsg8M8JrqGl6W1jqUMsEkEhCCVSDt6/zzXZ29vDfIC9wU/wB08iqGvaxNq/ii8s3jiFraKq28icmQMMkk/UcVjyfardmSEkMK8+qv3jR6lCT9mmde1tBYxMwuS4PdjzXm3xKv5prCygjY+TJKWb/awOP510lhZ3t0d98xKZ4XPWsLxxaNc6hosKcJ5zK3sMA5/SnS+NBXd4M9L+GYSPwdbQryyffPqTzXY1xHg7XdJt7W5tZNlnNE4DBj8r8cFcDj6V2cU0UyB4pEdW6FTkGu/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-87.png', linkedinUrl: '/in/marie-davis-50223e7489', jobTitle: 'Garment/textile technologist', }, @@ -10875,7 +10875,7 @@ export const peopleDemo = [ city: 'Jacobburgh', email: 'brent.mcpherson@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-88.png', linkedinUrl: '/in/brent-mcpherson-365c1d18d0', jobTitle: 'Data scientist', }, @@ -10885,7 +10885,7 @@ export const peopleDemo = [ city: 'Smithborough', email: 'catherine.kim@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-89.png', linkedinUrl: '/in/catherine-kim-c3dc33b8f1', jobTitle: 'Manufacturing systems engineer', }, @@ -10895,7 +10895,7 @@ export const peopleDemo = [ city: 'Port Matthew', email: 'evan.hanson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDsar3t9babZS3l3KIoIl3Mx/z1qf0rzr4pX5aKz0pW++fOceuOF/rWK3NTP134mT3paLSQ1pb4wZSP3rfT+7/OuKnvZbpjJO8kjs2S0hzXpnhzwHpX9mRPfQmWeUBmJbGM9hXQTeANClt2iW3K7udwPNR7eK0Rt9Wm1c8Qg1S7sJWNpdSxt/CUcr/KvQ/C3xL85orHXAA5+VbocZ9Nw/qK15/hfo7RDDzBwOWz1rkPEXgWCxt3ls5JC0YyQxzkUe2g3YTw9SKuewClxWB4Kvn1DwpZPISZI1MLMe+3jP5YrfqjMdXmnj2MSeKrTeuR5K7ff5jXpYrlPENkt5r2nXBQYhl8o57g/MD+YpSkooqEHJ6G7YALbRqxAIUCtYYMYwc/SuF1q3kMmH+2ugXKR25xkjvn1pfDkl9HcJGrXYhkwdlw+4r/AIfSuVR0ud/NrY7WU4RucDFcX4mci0lMR3MFOcc03xNJezzSRE3Rhh5Zbd8M3+NZFhZnzJGX7Ui7PnS4bPJ75FHKrXBt35TofAMPl+GFfHEszuPpwP6V05rA8GFo9AhtGAxCvB9ckmt811J3Vzz5JxdmFZmpxg7ZSo+Qgg++cVp1DdQie3dec44+tKceZWKpT5ZXHQrFdQKGVSfemiKCK6WOMLuBG4jsaz7aRkXKHjGcVn3t1YXDDzJkjmU5DZOQfwrmSvoehc1ykL6vPHJtw54J7mq2qx29rassagMR1rEgnsradmiuvOkY9Wck/hmr10GuiiEnLkAD60NdAvpc09Bh8qwJIAJIHHfA/wDr1pGkhgS1hWJM7V7nqaca64xsrHmzlzSbEpQMCms2M7Rk1Fuc/eP4CrUTNs5n+0SJpWOI0Mrr7AhiMfpV7ZFcwgrOIzjhlHNJdaciXEyFR5czGRfqeo/P+dYkumXMUhEFwUHYNXFL3ZtM9Km3ypo05LeG3UyPKsj/AN5qqWWsQw6nbPON0bOV3ehwcGs6SxvXYLPMGyeVU5pmoWJVLQJ1jnVh/I/zoi1zIKl3Fno+8NypBHqDRXJ2/mwudkhXHIwa3rC8aQbZeT612tHnH//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-90.png', linkedinUrl: '/in/evan-hanson-93ee351985', jobTitle: 'Art therapist', }, @@ -10905,7 +10905,7 @@ export const peopleDemo = [ city: 'Fritzport', email: 'natalie.cooper@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-91.png', linkedinUrl: '/in/natalie-cooper-043bdf4ec3', jobTitle: 'Land', }, @@ -10915,7 +10915,7 @@ export const peopleDemo = [ city: 'Port Erin', email: 'jacqueline.martin@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDpCtJt56VLtqpqV7FpenTXswykS5wO57CmSUNe8Q2Ph61Wa7JZ3z5cS/ef/wCtXETePtRvroy2Z+zQjpE2P1NcvrmpXOtaxJdzHlj8i54VewFamneF9Zv7b5LXbHJ/Ez4/Gpcki4xb2RrW/wASNQQLE0ETAHHmSdT+WK6TTPHNrdSrHeoId5wJFOUz7+lcje+ANXMWV2HaBjnJrmnhu9LaS3uUKOvOCOCPrSU09mU4Nbo97wrDKkEHoRSbPauC8BeK2uJI9HujvJz5LnqB/dNeibeKtGbJAgxXnXxT1OW1trOyVCIpcuzZ+9joP616OAa8h+Ldz5mtWdujhhFDllB+6xPf8MUMEQ+AtEivfMvp08wq+I1POPevWrSDZGMAHHYV5foAjsfC1q0sc7eduYCIkdz6V1Hhqa6a4SFGm+zyfMPNPzD2rinrJs9GlpFI7Dy228YH1rz7x/4fkvrQXVsB5kWS6/3l9qu+InmS9PnJcyQpziJj6+mRVqycXUZhS3lRMYywIz9fektNUXJc3us8btrl7a4ikjfY8TA7geRivoDRtQj1fSLe9jVlEi8g+o4NfP2rWr2es3VsePLlI/DPFe1fDohvBdqASSruGB7Hd0rtieZJW0OqUE15T8TvDDJcNrFsznzOZUxnGOpzXrSCm3NtBdwPBcRJJE4KsrDIINMRxnhIwP4dsYZIwNsK8MPataK8sbPVo45HSPCkovc+tVH09dMuhBENsSgCMei9hVeS+jlkKGxknxkElP5Z61wNPmaPWptSirGxaX+n6hMypKkqkkBgOhHY1Zu2htoyEUdOMcVkwapCuIZLGWEkjB8vgH6ird0NyqGPTmk9NCjzXxTo6rFqWqSYwdpXI/i4XFdz8OrZ7fwbbF+srNJj6nH9K5K2ll8c+IH0kRCPSrWRmmdDzJgkDJ7V6pa2sVlZQ2sC7YoUCIPQCuykmlqeZWlFy90nXoKUmrg09guXbH0pUs1kkVF78HPWtrGFzm9fWM2scm7EobauO/GSP0rBhWG44kmZSPTrXX69Zl9NkKJl7dxJgDqoyD+hP5Vxd1Zsy+bbnk88Vx4hWlc9DCybiaSLDDFhbhnHoaimeSeB0ib5tpAPvWbZ28zv+9Yg+mK2UMVrbNI3RBmsLrodDTe5H4F8PWWi6KJ7eUzzXY3SykFc4JG0Dtg5rqSeKl0XTXtvC1nbSIEndPMOR90sSx/nTnsbhdv7vJPTBzXotjyXuf/Z', + 'https://twentyhq.github.io/placeholder-images/people/image-92.png', linkedinUrl: '/in/jacqueline-martin-3a858a2278', jobTitle: 'Product manager', }, @@ -10925,7 +10925,7 @@ export const peopleDemo = [ city: 'South Angela', email: 'ashley.harrington@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-93.png', linkedinUrl: '/in/ashley-harrington-cdb4eef042', jobTitle: 'Immunologist', }, @@ -10935,7 +10935,7 @@ export const peopleDemo = [ city: 'West Reginald', email: 'heather.jones@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDvNU1Oz0fT5b69lEUEY5J6k9gB3Jrx3xF8T9S1YmDS4zY24+8+/wCdvx7VJ8VvEUt5rQ0iJsW1pjeB/FIRz+QOPzrgkUDO4fIOeOlRJlxiSXl7NdZluJpJnx1ck/zNVILy5hO6N5FX/ZJxTnjknlPy/L6VrWHhrUNQGVQJF6sP5Couo7lqLlsamifE3XtOiWIyJcxrxicZIH1HNeveFfGFn4ngIVPJukUM8ROQR6qe9eNXnge5tIDNDKWZRzxwaq+FtSudL8QW/luVbzArZ478iqjNPYUqbW59J4pMUo5GQc0GtTE+XNWvmvtUnuZG3M7lmLc5JNV18yVlVASxPCjqaLmxvLUK9xbugf5gx/zxXYeBNFM5a+lAIHCAjvXPKSSudMYtysWfDngl3K3epNjuIs9PrXfw2cMMYWNFwBxisu8uvIPki0aZmyNzjCLWT4duprq7bNu1uhPZjgc9PasHeSuzqjaL5UdRcW4eNgQAMd68s8V2a6ZrdrdwqF3tuIH95SK6/wAW3lxbMYURnQAMQpPOeKx4dNj1/U9Itvs/khbwJNhsqVxkkHvwuKqkrNMis7po9ttm32sT/wB5Af0qWkAAAAGAOlFdh554pc6P9utksGAEguCsremzj9eD+NbHhy3bTrKOA9mb+dM1+6j8O+NXEgL2uofvGHUxueM/Q4q5pl3DqMazW+7y3JKbhg4zXFUTjp0PSpSUrS6nRCNZ4uMe4NUnNtauyYUMAWYkgAD3qwheNDt7CsyfUdMjjZbllkkJ+Ybc8+lZJXN9Au/s1zNbsZI33jHBzV3Sba3Gr2iJEMoxb6EA81zpvdMku18kbJccAjHGe1dR4YDTanJKw4jjOPqTWkI++jKq1yM66kNLTTXceYeD+P2fVNflmi3EKTHtLZ+7x07CtjwqzroNpKvVAUb8CRW9Jocd/c313LCyvICADycev1qp4d0/7Dpf2Nwd8bMHz13ZOa5KstDsorU2o7xJIhggEjFOa2WSLaEU8cGsyWwcZkiJ98VSlu76D5FJ/GsVudNyxc2YhcFgCQeCa7Dw3bGKxa4dcNMcj/dHT+tefveXDhS+N24BR16nFen2c/mQoGwDtHTpXRRV3c5sTN2sW6Q0maAAA10nEf/Z', + 'https://twentyhq.github.io/placeholder-images/people/image-94.png', linkedinUrl: '/in/heather-jones-6accdac7b2', jobTitle: 'Warehouse manager', }, @@ -10945,7 +10945,7 @@ export const peopleDemo = [ city: 'East Davidstad', email: 'corey.martin@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-95.png', linkedinUrl: '/in/corey-martin-e69cbef278', jobTitle: 'Loss adjuster, chartered', }, @@ -10955,7 +10955,7 @@ export const peopleDemo = [ city: 'Jamesberg', email: 'christine.scott@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDb1zXbLQLH7Rdvy3Eca/ec+grybXvGep63KUVza2oPEUbHn6nqTVXxJrUmu61PeEnyl+SBT/Cg9B6nrWTApMq7uBn8qwN0izHG8qF3kYe5FNBMY3Zzjriuz0TwkL+MTXDsIj90ZyTXUr4K0x4lHkEEdyetZe1itDZUZPU4Tw94s1DRZFXzPtNkx+aJjyv+7noa9bsb6DUbOO6t3DRyDINcXqXw9sjE7WzNG/5iqnw+vZdO1i80G5Y55dAexHXH1GD+FVGaexE6bjuejEUYpSKKsyPm9pNoCr95u9b3huzjnvk8395g8A1lDTbj7ILtVDqRnjsK6/wPZYhe5kXDk4X2qJySjob04NyVz0GwVREqjGRxgVsxo23GM1yU+ojTvlaCeYtwEj459z2o0+9vWuY5/wB7HE43GMyltueMEdjXMou1zr5lex1kiEryOK8+udPdPiZpk8A2l0ZpMdwAc/pW94l1G7jFvBbqxEpG5w20DPqe1L4ZtIp5G1A27RyqnlDe5bvyQT64HNaU1rcyrNcrR0WOKSnkU2ug4jyTweYr3S5bN1BljccDglDkj9a6O3hWyfES7U8wnH415TbandaRfrd2km1x8uD0ZfQ16ho99JqtjHcTBRJKA+FGAM1zVYtanbRmmrdUdnaCG5QbgDkdx1pLxLe3ULtAdj8qgdar2sUke0qeoyKdc3OnSAx3jxlsdD1FZrsdFh8UQeKF5AMEY+b1q3aKqvIEGFGKyraXTNwis5AQPupk8fStWyBERJ6k1pTXvGOIdoak7U2nNTa6TgPmK5bdKR2FepeFopV8OWjYw6Lgj2rzxLdmmM20AZ4FeoeD7yG8szDkB1+8np71OIhJQTtob4aS533OjsdRRo0yQGU4IParxtYp8M6Ic8A96xLnSmeYGJ9hbv2NXIbPUrWP57hNg9Rk1yI7L2LLWSWso2KN+eD1rViTYgHfvXBal4tuNI8RW1tLGs0LR5k7EZOAR9P612Gn65p+pjFvOok7xPww/CuqnB25jjxFTmlyl4001IaYaswAAAAAAAAMD//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-96.png', linkedinUrl: '/in/christine-scott-001224382b', jobTitle: 'Historic buildings inspector/conservation officer', }, @@ -10965,7 +10965,7 @@ export const peopleDemo = [ city: 'Lake Brianville', email: 'alicia.ball@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-97.png', linkedinUrl: '/in/alicia-ball-3870ff3969', jobTitle: 'Presenter, broadcasting', }, @@ -10975,7 +10975,7 @@ export const peopleDemo = [ city: 'Port Diane', email: 'antonio.ferguson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDvMVg+JvFVn4Zt0Mo8y4lz5cQPX3PoK32ZUUsxwoGSfQV8+eI7u41zxDc3vmbY3fEZ/wBgcL+n86TdhpXNbVviPrl5HJHHIlqP+mI5OfrmuVjupLiR5ZmJbHU9T71t6f4VvNTby7ZMAfelkXitO6+HV+IvmmRZQvACkZHvWbqI2VKT2RlaJ451XRp/JinElv3ikG4Z9q9h8OeJ7DxJZq9vIFuVUebAT8yn+o968Tm8H6nByUXg9qk8M3U/h3xZp810rKnm7W56huD/ADqlNPYiUJLdH0FilxRRVmZHeIZLGdF6tGwH5V4BZxiTUIkkbMbOMg96+gLy6jsrKa6myY4lLMAMk15VZ+HhD4zjjkQiCR3njUjHy9cfh0rKpJLQ3pQk1foekacFWxiRVCgIOQOnFR3iKMkPurC1zV7zTo2itIZ5GA3ExJn9a5/T9c1m+vY7WZMNJg524IB9cdDXNZ2udqaTsdFfWzeQX4+lefeKIgLQSBfnRwQfQ1teIdavNOumtEjZmQ87RuxWXK5vLcfaASElRpBtwdoYZqoqzTIqNNOJ7BpguP7KtPtbK1x5S+YVGATirdRwSJNbRSxghHRWUHsCMipK7DzhtxClzbSQSLlHUqQa5iCzkiuXubp2kuPMOwkn5V6YA7V1grM1a3wqzKzAg8qDwawrQv7x1Yery3g+owmC9tWjlCgdORnNUrD+zY7uaG2ijDR4DSd8ntTD80TbWxkE/SsSeTT3sWt1trmQq2RIkTct65rnWp2aFfW4oT4hlLBSjng9cGqgtVkuUgjGTIwTj3NUJXj+2BS024jGZUIzXReG7AX2qhpGYLABJ8p6nIxVKLbsTOSim2d5HGsUSRIMKihQPYcU6ikrtPLJkUsQBWXdXTTM0LW8kRjfBL4+bjqPauhhtWQZzyaq39sHJEq9P4h1FRUi5RsjSlJRldnDXri3kZCxRH4DelEkay2Ri+1hEA4x1NWNajEabZUDI3fsa42/RoWX7NcMYj/AT92uO1nZnenpdE95GkcgjSXzCfzrvPDmlPpthumH+kTYZx/dHYV5kt6LGWO7lUyLCwkZfUA5xXrtnqNtfwpLBIDvUNtPUZ9q3opPU5sRJ7HKf//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-98.png', linkedinUrl: '/in/antonio-ferguson-995e342c4b', jobTitle: 'Production assistant, radio', }, @@ -10985,7 +10985,7 @@ export const peopleDemo = [ city: 'Kevinstad', email: 'joseph.baldwin@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDFFUdW1VNKtlcrvlc4RM4z7k1fArzzV737XrFw+8sisVT6Djihght7fXeo3u6VznsinCqPaoWZkmwQwBz8wrpNI8IXmqBZGkERddwyMnFdbY/DqNEInvHbI5CLgVhKrFHRGhN9DzhNRvIdkK3LJgblKnoa6HR/EMlzcpaXcah2HyyKep966PUPhnaNmS3uJEYDgEZrgNY0u60K+WNixAbMbgYz/wDXpxqxk7IU6Moq7O+pCOaraddLe2MU4IJKgN7N3qya2MBkwPkSbc52nGPpXnWl24lu1VsYzg16QRu49eK5e10WfT/EUMFwhkgZtyMn8QGfXHpWc5WRpTg5M9Q0hES1jHAIArdTO0cZriL52MIIW6aNhxHCNrE/WpNCmuLZhIz3YSTHyzybiOeOOxrh5dLnqc2tjsJmIU8VwHji3il05mYcodwI7VoeJbq4uDNGGufLixuWA4Y1z93DLJpV3GpnIMRBWdskN2OaqKs0yakrpxM7wmNulyKTkiUn9BW9Wdo9m1jYrE+N5O5tvTmtDvXoLY8p6MM45rRuYYrhbS7AIaI8enIOazat29y6xC3IBjLhs9waxrQ5lddDfD1FFtPqdTYpFNEMj5gOKL1baJ0RigbIJLYGD2qCxb5VINVr29sJ22XRjJU52ldxBriXY9PQveXC2rSqWQllB6g81Q1i1h8kxKdvmHaSB61Wgn0+C6JtJELnGQcgn6Zp+pzbGEjfNjGBmmk+awpNKLbMNwFkKqcgHAP0pAeabz3pa9JKyseM3d3HKMmoL+6ewmtEKDy7kYDH13Yx+XNakFk8hyBgDrmrd5pcep2KQkDfE6yRH0YdKUthx3VxlndtAfLkcBl5XPcVsKFnj+8qsRgHGayJLBb21G9cSJwR6Gqpi1OBc2rpIi/wk8rXmrfU9e7Wq2NeaBYQWZlZh3IrCu7z7VKVVgwQ849aHXUZpAt2yjjJVfT3rO06OSS71FiPlEwVff5RW9FJzuc2JlLkLBNIOtL1YgA5FJjFdgAAAB2nnn//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-99.png', linkedinUrl: '/in/joseph-baldwin-03fcc63126', jobTitle: 'Heritage manager', }, @@ -10995,7 +10995,7 @@ export const peopleDemo = [ city: 'Fostertown', email: 'devin.lopez@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-100.png', linkedinUrl: '/in/devin-lopez-c9e1d4f2c8', jobTitle: 'Surveyor, insurance', }, @@ -11005,7 +11005,7 @@ export const peopleDemo = [ city: 'Gibsonstad', email: 'victoria.weber@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDoXOUJNZ6sScVpyRHZtPJIrJu5Rp8ZaXAYjI5pSfKrsIrmdkWTdLboBjc3XGcVzepeJWjZvJnXev8ACvNRxzXfiCVrWxzFETh5cckV0Fh4N02zjG+LzHPVmOc1y+0lLc7I0UkYln4i1CWENIo57itKy12K5fypcJJ05702/wDCNqd72rSQMf7jVx16JrK8Czn96h2u6jG4djihVJJ7ilSVtj0WQ56VGoNQeFp01XT9skhM0Xyt7jsa6FdPiXsTXVF8yucklZ2BpYiM5WuB8U3Tz6hLGpwowg/L/wDXXXu2LfbnjNcHqaSz+JI4CMeZcKqr/s5GTWVfVJGtD4juvDunxWWmwhUG4qCxx1Na8grm9VuZbaIxRQ3D/KTmM4AwP51U8PXGoXFxGtxJOYj8wEpyV9jWFtLnYnrY6iThTXHeJ9KW4iNzEMSxgnH94dxTvEN7fpcyC2aYxp1ERwTSWk893C0UqTK23kSHOcj1otpcH2MvwTfLa60q+ZtjkBVg3avTPt9rj/XrXi/hyQx+IBBPwyyMFY/jgV6DmumlscNbc1jDvUKRxWNPZhtdWYxkvDtKkf3cGuoFs/sKx9duk0tDOVUy7CBnoR6U6yvEdCVpmmpjnjxgH6jiqym3huAi7Ux1J45osnElukqn5XUMPoRms2+vNIdwJf3kiE4ZUJ2noTmuRXPQVuhLF5Mt3Kp2t8xwetOu1jhUhQBx2rOtbrTVlYWx2Oxzhhgk0uqXPkWktw3KxoWx0zim+wOyOcfTQuuWbIP3kk7SN7KvOf1rqsCsTwzcTatJcXkyKJMBFRBwq/8A6/5V0YtJmPCN+NdNFe7c8+u7y0OqIX0Ncz4x0h9RsElgUs8bYZR3B/wNbo8xjgfzqK4WZWUmQiMZDqAPm9M+1VUceV3IpxlzKxz2lR3FnpFtBcnEirtPtyePyq3PaG4jGJFQDoRV14FeHYRnise8tbqJQYZCV7A9q40+p6Cdhslv5HVlY+tVpdPbV7eazViCyEgj1HT9aI4LmXJnfA9B3p8izoQbW5e2kX7rqAR9CD1FUmk7sU7yWhZ8LaDc6X5huQoYjHyniulMQrN0jU57zTo5LkKsw4fYPlJHGR7Ve84kcNmuyFraHnzvAAAAAAF9T//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-1.png', linkedinUrl: '/in/victoria-weber-1d629bb105', jobTitle: 'Probation officer', }, @@ -11015,7 +11015,7 @@ export const peopleDemo = [ city: 'Olsontown', email: 'erica.lamb@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-2.png', linkedinUrl: '/in/erica-lamb-ccc3ee1ef0', jobTitle: 'Environmental health practitioner', }, @@ -11025,7 +11025,7 @@ export const peopleDemo = [ city: 'Justinville', email: 'regina.rivera@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDW8Qa3BoWnG4lXfI52xRDqzf4V5Xc61d6ncGS8nLZOdoOEQegFWfHGsvfeI5oo23R258lOeBj7x/PP5VzcdyfMURgMV6MegPrisZO5rFWLWrKr+VHCgBIySzfMfwo06N/LBB2L/skCt3Q/C/8Abc3m5LcfNI3c1q3nwyvIx5lrc/RSMisnNbXNlTk9bGPDdTWjo9tOUmByrOP0DDj8DXomg60mr23zqI7qPAlj/qPY15y+laho7tHewBrc/eKLn8cU7SNXTTNYimR94XjaT95D1H+fSnCVmTOGmp68AKeFGKijYOisOhGRUwrpOY8F8VWwtPFOpW6k7VmY8+hOf61U0mxfUr6OBOAT27V6B418L/2vq11eWhdbhEQSKQNr8du4OMVm/D/SWS7up5lIeI7MEdDXPOaSduh1QpSurrc9G8N6Xb6Zp6W8K8gck9Sa6SJeADXJXFzPZuEEE8iOdoCEKMn1bsKqaPdambzzBFdwwkkFJpd4HOPwrlS0udjetjqtU0aK/gZTGORXivjHw8+gapCN37q4yUA/hIxn+deqeKb/AFCzijW1WdsldxhYA8/UGsC80htavtFluI51jheR5VmfccjHfuCcVrTXvIxq/CzotMaRtLs2lBEhhTcD64FXVNMAxThXacBV1Wy+0bcAbWI3e+Omf89qy4LVLSeaWOLy2lcM4HrjFdKVEkZVuhrlNIjvIopoNRd3uFmdS7cbgD8pHsRiuOtTafMjuoVVJKL3R1VlNHMoDqOnNOv3hhRI1ChmyfQcVTtV245+lQ6neaXInk3wWU45j27sj6Vgux1Wvsa6+U4i3lTuTvzyKgvChCBRjBrP0++0u5do7MbXVcBWGCB1wKtTHMn0FbUV75hiPdg7jM04Uw04V2nmlxcKhYkBR1J6Csm/CT3TPBIr7VHKnIz6V1lvpSSW0kVyoZZlKOvsa5iLQm0J/sJyYh/qpD/GPf39a58S2onVhknMrw3JQDJwQatC2S5wWcf7J7ioLixctmPHPSmWtjfLLtchE7GuJM772L5t1tyCGDE9+9KQSST3qJJI7bU7Kzm3E3bMisezAZq7cW8lu5SRCpH5Gu2glbmOHFTblZlQjmlUU44zThjFdByn/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-3.png', linkedinUrl: '/in/regina-rivera-80ffb29755', jobTitle: 'Psychologist, sport and exercise', }, @@ -11035,7 +11035,7 @@ export const peopleDemo = [ city: 'East Zoeview', email: 'sarah.hernandez@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1PNGaj3Uu6srmlhZJooImlmkWONRksxwBXG618T9K0u4aG2ia8ZerI2Fz7HvXG+NvFFxq+vPpdvIRa277CF/icdT788CubvNDvLaITSx5ViD7D2rKVSzsbwo3Vz0GL4t+ZndpQGOoE3b8q7LQvElh4htfNtJMOPvxMfmX/wCt714RFZTFQ6/KynGD70Q31xpF8k0UjQSociRDjn0NCm7jlSVj6NzSE1znhDxPH4l0cT8LcxHZOo9fUexreLVdzC1iPdWD4x199A8PS3UQHnORFGf7rHv+ABrZ31w3xQikn0CAqCY4ZfMkx0xgj+tS2XFanP8AgrwyNQJv7ht29sqD19yfevTDo1tLZtazIJI2GOa4bQd9v4atGC3G+VC6rEcY6n88V02gXV5mNZpJWjk5Hm/eX2Ncck27s9ODSikindeBIXH7u4Zcfdz1rh/EnhPUYPNYRo8Z+YlT3Hcf4V32tT3c0skiSz+VHnKRHlgO3vVFC95asm24RguWWU5yCP5002tRSSejOM+F15La+Lfs28rFcQsrKT94jkfiMV7YTXg3hF2tviJaLIm0iRo/YEgivdM8V1pnnSWpAHrP13Tl1jRrmzJIMiEAg9+1TCT3p4kGOtTcLGf4dSM6NbQyJh40ClT2PerxeCPUlj3om1ScE4zVFI5I76QggbiSAKr3F3bNKY54ZXdepCGuS2tj1qdpRVjSsHt53cbkY54IOQafqHlQW7BQqkjtWXa3dv5oihikRiehQ4qTUiRE7u33RzSfYbVtzltF8LpN4iOpyOf9aXVV4wP/ANdei76wPC873ujw3skSxGUfKobOFHT862ya6oXS1PMrOLl7plCTAqRXzVQ5qeFGYgKCSewoJFuNyp5q9V5/CnQpDdRqWbBIzkVNe201vps85QEqAAhPqcc1kW1rIXTZO0aN17gGsaiSkdeHk+U03SK2B2tyO9Z1zJ9oUR9YycMfXNW20t9+JLkyD0AxT5dPknUW9pCXPHTgD6ms3vobOVy9FFHBCsUKBI0G1VUYAFK2ah0nwyulh3kneeZicZJ2oD2/+vV9rGQLwwNdSjU//9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-4.png', linkedinUrl: '/in/sarah-hernandez-1e2803fbdb', jobTitle: 'Engineer, water', }, @@ -11045,7 +11045,7 @@ export const peopleDemo = [ city: 'Simonchester', email: 'jessica.graham@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-5.png', linkedinUrl: '/in/jessica-graham-c96b6e62d8', jobTitle: 'Water engineer', }, @@ -11055,7 +11055,7 @@ export const peopleDemo = [ city: 'Lake Scottville', email: 'john.ritter@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-6.png', linkedinUrl: '/in/john-ritter-eb8a8f542a', jobTitle: 'Dancer', }, @@ -11065,7 +11065,7 @@ export const peopleDemo = [ city: 'South Charles', email: 'jessica.bruce@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDdCgiq9/dRadYTXcuNkS5PvUqzLjrXI/EDUWi02C2UcStk/h0qXogSuzkNb8T3+sfLOoWBWJSJP0J9TVKFXWLfIzGJzjOOn1pum2t1qV15dtG8j/7PAH413Ft4H1WRF8y6RVYcqwzisZTS3OiNNvY4HebcnYOoH41FHcHefNY47CvUU+HUUZLyTh2x0C4Ga5DWPCtxYM7gfKDkbeKSqRehTpSWoeGvEUul3YhO1raVgGVyRg+oNerxbSAR0PNeCszNJtK59ya9j0XfbaLZwvIZGWJfmPetYswmupIK57xpGkuiAnAcyqob25rogprP13STqmkSwrnzU/eR/wC8Af8AGqexEdyr4EsI4dJEyr+8kJbOPfFd9GDs5XFcDpb3Fh4YsPJt/NkZCm4yFQp59O9b/h3VNSuGjgvF5cbgSckD0NefKLbcj1ISSSidHyQeDWLrNuk1rJGyAllPBrP8Q3+rwyuLRmKIM7AcbucfUmnadPdXkZS5tBE6dXV9ynjP50uV2uVzK9jx+/UwX00RT7r8Z7V61oas+i2bSA7zCuc/SuZk8Pxah4sumkVWiQhih43ZxXdJGkUYRBhVGAPau2lJM8+tFxKfanqTSBeKcFrYwH6YkEcbWjr8gJKhunPNX4Yo01GJIlAwCTtGKzguJVYdadcXtgk6+bdGGRQfunn8a86pHlm0erRlzwT6mosMU7ukqqWUn7wznmm3jR20BVFA4wABVSwvNNb5be5EkhOfmY7j+dSXxGN7dF7Vm+xraxnWkUJdpQyPKpw2052n0PvVzcDWXocckenkyjEkkjO3HXJzWlXoUockTy61RzkQAcUtSbMCm+WzHAGTWxiOUbhgdahSCKaTbK5Rlz81WhA8cUsh/wCWaFse4FQrEJYFLfNjkn19a4cTKN01ud2E5lcnW3htY9/mq5/vEc1FNvmTec7e2e9SxWMMY3Fi57AnNWWQNEc4rlb1Oxu5lWt/HdiZVjMbwOEkQ9iRkfmKsgg1ctLMJFuZQGmYE5HVQMDNRNZ5J8s7T/dNelCfuhP/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-7.png', linkedinUrl: '/in/jessica-bruce-a0631e1611', jobTitle: 'Community development worker', }, @@ -11075,7 +11075,7 @@ export const peopleDemo = [ city: 'Clintonberg', email: 'sara.larsen@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0isnXvENj4etBNdsS78RQp95z7e3vV+8u4rGymu522xQoXc+wFfP+qa3PrGrzX91J87ngdo17KorBs1irnZXnxC1g5lRIIEJ4Tbn9T1rn73xdq+oXXmyXMkQP3fLcqFx9Ky7XSrvX9QWG3Q4A5Y84rtIPhyws/LlnBZhzxyPpWbkluzaMG9Uivonj/UtOkEd9ML639W4cD2bv+NeoaZqtnq9qtxZyh0PUd1PoR2ryS/8Ah5dW8bGC7MmBwGFZXh3xFc+GdZQyhgiP5dzH6r6/h1FOM77MmdNrdWPfKKZHIssSyRsGRwGUjuD0p9aGJw/xT1A2nhVbdX2tczKpGeqjk/qBXi9splkWOP5pGPHHevT/AIpWlxqusaRp0TogMUkmXOADnkn8hXK+F/D1xF4sS0u02mH5mxyMDpiplJI1hBu3Y9H8H6EmkaUgbDXMnzSN/SukZSPrWDqVxJaRhI7V52bhRu2ovuTWV4Xuby5uWeaKSJW7GQsAPoe9cbTa5md6stEdVOpKHtxXlPj7Skgkj1OMAFm2SAfxe9dZ4ru7qMvHEjOsXzFVYjPtx9a5TxBO194YkxA8LwSKXQtuB7ZB/GrppppkVbNNHp/gy5e68H6ZK/J8kLn1AJA/lW9XN+BEaLwXpqMCCIzkEe5ro66zz3ued/EMtY61o2rEFoomMci9sE8/pmtSK0iF4NRT53lzhx0KnGMflUfxIEZ8MtuA3eam0n8a5Dwz4pmtrXStNmmikSW4eMrzviXHy/hkmsKsW9UdVCaSsz1KFlnh7H2I61BcSW1kmWMcfdmYhQBS2w2oCDxiqWoalYQqRcp5r9dgTca5l2Oy1xrmCbVJVV0cMoJHXmsrXbKK70+Wyt4wXlwgAHTkURatYS3R+zxNE5/vJtzQb0Qatp6lSTcXATIGcADJ/lirinzJE1Pdi7nY2VtHZWsdtCoWONQFA7CrNNXpTq7Dyzzv4pzOLC0gHCM5dj9OleVWs4g1W1mPRLhSfoCK9v8AH2jvqnh13hTfNbnzAo6svcflz+FeOWelvd3YhRAfNYKHI+73J/IUm0tzSN2tD2uOf7KAjthP4WPpUzRRXEZDFSmOMjNLFCrwxK4DDaFOagm0jZuMUzxjsB0rgTPRTsZd1aQW77owufXvXJyaj5/jizY58mBlRMdCepP+fSunmidZHLSGQJxz61wlpeJovigJdozW/mh8r95O4x+eK2o6tmWIbse5x8oD7U6s7S9b07Vog1lcq5/uHhh+FaNdZwAAAAAAHnH/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-8.png', linkedinUrl: '/in/sara-larsen-cc08b21030', jobTitle: 'Computer games developer', }, @@ -11085,7 +11085,7 @@ export const peopleDemo = [ city: 'North Daniellestad', email: 'eric.ellison@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1o9ao6trFjoenS32oTrFDGCeTyx9FHc1czzXzv8QvEB8T+J5PIkIs7b9zErcg4JBYD3P6VIGzqfxj1i5upTpsMNrbKfkDJvcj3PT8q5uLx/4khvDdf2rcl2zwWyD+B4rr/Dvw+0xdPhmvA8k8g3Nk4A9sV1kfgnQ/JCCwhI9cc1i68b2R0rDSauzhtC+L2r293t1RY7yFucYCMPpjj869f0XW7LXrBbyyfch4ZT1U+hrgdQ+GGjz5eEPE3+y1Yvh43fgHxdHbSzu2mXjBPm6Dtk+4J/KqjVjJ2REqMoq7PaqUU0HIyDxRmtDIiuGYW0xT72xtv1xXzLptozX8WULuZc/U19KaheR6fYT3coZo4l3EKOTXiui6cbTxQ6Tx5Cl5Y2HdT0/GonNJM0hBtp9D0G0mRIlWRlXAAJJwK2LeaKWP93KrY9DmuC1OzW5mDTRzzx4OyNG24P8Aj2pmh2BsrhZoVmtomwxR3ycZ6H3rjUVa53czvY9DkcKnzMF9MmuE8dqr6YsuM7JAQw7dqm8VRy3JYbpzFENxERIY+4FZy6VJc6PPaRGZM7G23ByVO4HP5ZqoqzTJm7po9S0ot/ZFlvILGBMkdD8oq4Khto0htIYo87ERVXPoBxUtdh55BeQLdWksDjcrqRivOXtyl39ofJl+ZR/sjjj9K9LrnPEGmRohvUZgS43LxjnvWNaF1dHRQqW919StaeVcR4KjIHfoaLlIY5ViAXP3m6DFUrd2QDH1/Kqd9daXe5iutrFG3HOSQfwrlSvod10dDcQQG8XfsIcDng81BfWyPGbaP5Hl+Xco6Vg28mnRSNtuRLIV2gs5yOcjGa37CJ7u+iDOQUG4nFVZ8yREmkm2dUvyqBnOBilzUZak3Emu655liTtXCeLtRvbTWrS3MrmxvfkVf4Q65JH8j+BrtWlZshRgetUNQ0uHVLIW0ww6tvifHKOOh/z61E9VZGlPR3Zxi3TQnYWAIPf0q1GksseYmRHAwGNQ6nprtuhmXZMvX39x7Vg7tTtZhFH+8A6ZPNca3O+7WqOmNvIqZuXjlNdD4egb7M105BMnyrjsBXFWCXcpZro4x/CDXTeDxPN4cgkdmVpdzr+Zx+la07c1zGu24nTkDNG2q8TSjhuWHBqdX9M//9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-9.png', linkedinUrl: '/in/eric-ellison-d200f0e1b9', jobTitle: 'Farm manager', }, @@ -11095,7 +11095,7 @@ export const peopleDemo = [ city: 'Alvaradomouth', email: 'katrina.butler@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDcOAM9BXPXmtCffHaXKwgZAfbuZ/oOw96PGOpNZaYLeJtstxkceg//AF1zOlShZo42l3uABhF/r/WuWcrHVCNy3Lpl3Pbme6uJCSC2Wk5A+g6VzaqUm8yF3TafvgHNeoWenpqFqYvJznuo6fjUzeA4ZNhZmiA7DqfrWambOmczoGv3fK3R86IDO/duP1rro5EmjWRDlW5BrOl8GrYO08EuW2lQpX5ce4rP0TUJE1KbTLhdj7fMQfowH86uM7uxnOnZXOhOKYacaQDmtDI5nx5YtPHZTIMlSyt9ODVfwpYQqvmzIGmZsYPYVv8AiOH7daCyjZ458ear7cpxxgnt+VZnhLT2S4uTKTviO3B9axqNanRTg9Gz0LT1RYwqLgegrTdkIHPPpXEX11qFuTBBDO2/gbSFH51k6G+uPdq0hukjfkrIT8ozjkHpUpaXNXvY9AuQPKY9jXC3tvAviKykK4kJYAj6VN4xu9YtpBb2KyFF27mj65b0qlo8M1zNDPOJQYQwIkbdlumQfSmo6pkza5WjdIoApT1pwFbnGPuIhJC4+YEqVyvBGfSqSxJY3J8lSBgE5Oc4rVAXad2Md81jXcskeqSBphLBtGzGDjPUE1jVj1OujUuuRnT2tzBeQ+XNGDx3HFPlFrZoI41UO+STwOBWPZ542njtSaxqmh21qYtYljO7+Bhk/lUR10N2kXrpIJ7uPeUZZIxxnPIrPfylnMcK4CisLTtR0h9QdLC4d2VflVv4R6CtaAlvMc92x+VVBe8ZVrKA9TmQ1KKhgGST71P2roRxG5BZLGx8zDA8dO1cqdC+w399bnmORvMi/wB09Py5rt3XepzVK4T7RHnGZYunuPSoqR5kaUpcstTkba+NpN9nlbaynGW7itW4snvrcGORA3YsOPy71ka5arcRtKvDDvWHa6jqEH7sTHaOnOa5k9TuTsbbWM1pKzP5TSscL5a4q+sfkwBepA5PqapaC81+j3c5yfNMafQDB/X+Va8ts7xkp9709a6ILqclefM7FaEYQVNTEXaoFOrRHOf/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-10.png', linkedinUrl: '/in/katrina-butler-3042d9be2a', jobTitle: 'Sales executive', }, @@ -11105,7 +11105,7 @@ export const peopleDemo = [ city: 'North Stefanieton', email: 'michelle.powers@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDNv9TjtiI1+eRuAB1J9BVFp3d1+0jcz/dRTxn09/rWRE/mXJmc8DlnPf8AwFTQar9ovwQAkca/exzj0FcFjuKktqp1CVJrjaqIXKIOAew+tP02fypdrNujPBDLyK1tI0WDXtQl2uQqnBUHoPX8TzWxcfDJw3mQXj49SOV+hpuXQcYN6mPBqkmnXvk3Du0Dfd3D7vuD3FbwkV1DIwZTyCO9c7qukarpNqYLxVuoFPyOBhlqv4Z1UGU2TtlWyYyf5VDjdXRW2jOrBqZDUANSoayGebPOcGEMGP8AEe2ahDsw2Qg7B1I6uagYBEHURjlm9a6jwVoY1e7+0MpW2iPAP8Rrpb5VcyiuZ2Os+GmlXCCa7kQqrYC7hyT3r03yyFwWwfSuZuLxtHiVY4LhkwAFt48n8T2FYmn6jql9rs6xx39vGjEETPvU4649qy31Oi1tDq9W0tb+1dDjcRwfevDNR0+bS/FZtkTbKJFkCDtnn8q9W8X3uq2UEUdnDLJnBcxMFOCfWuPmsZLnXo9SmtHtitsq7JG3Etk85+n86a01JnroaINSKaip6msgOS0zQf7ctYJ4GWRCT5gHWPGM8fyrvPDVn/Zlr5QXCB8qfavHNM16/wBEufN0+4aFWIVxgEOB6g17ho0pmtUWVizf3j1PetasWh0ZxlqlqdTaXMUqbHQHI5NPb7NbuERQXk4GKzYY2HANQX1/o9tG0eo3SB+pUE7vpxzUJm3Knsad15b+U0gUj7pB6iuU8SGI30ZjABEeD+dS2F7pMryW2nySEjlVcH5PYVlX8vm3srNzzgfhQyZrlVioetPjPNMNKnWkYnkb27GQR7CP/r17vYW8iaZazDhxEoYfhWc/w3OrXUWpRfuxFtJt0AzIo7g12FvahLNUYYI4xWtZt2FRsr2KlvefdBODVuWyS8jwHQY6EjkVn3Vq8TEqMio4vtTcDKqO+ayW50p9UFzb/wBmxuxcMw6Eetc42cknvXRfYjfzm2aYrNt3xljw3qD6dqyb7Tbqxk2XERX0PUH6Gr5Xa5hOpzS1M9hTowc07TqRH//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-11.png', linkedinUrl: '/in/michelle-powers-1f5eda1b79', jobTitle: 'Textile designer', }, @@ -11115,7 +11115,7 @@ export const peopleDemo = [ city: 'North Nichole', email: 'jessica.baker@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1zFIRS1l+Idag8P6HdancDKwrlUz99jwB+JoAuXN1b2cJmup44Yx1eRgo/WuWufiZ4Xtrgw/bJJSDgtHESv514zcapqfi7VnnvpJZ5pD+7t0J2IPQAVqR/DzVZxu2eT7Fv6VDmkaRptq6PatI8TaPra5sL6KRv7hO1/yPNa9fPdx4D1qwjEtudzocgK2CD7V2vgb4gzzXkeh6+dt0Tsimfglv7re/oaammKVNx3PTsUYpaKogXNeP/GfUpnutP0mNyIgvnOg/iYnC5+gB/OvXzXiOu28mr/GSe3uG3LC6bR2ChQQP1JqZOyuVBXdjpPBHhiPRNMWeVQ15OoaRyPujsorrCAehBrmdduordGE8VxMm07Y4wcAD6d6oeF3e5uQUgnggPzEOT/nNcj11PRStodZOvyHn6V5z450VZIDqMI8u6hwdy8ZH/wBatTxTcyRXroRcNBH18onP4YqjFOmo6dPbos6nyiCkxJJ4461UdNSZ6+6z1DwtqZ1jwtpt+xy8sCl/94cH9Qa164v4VyO/gK0V/wDlnNKg+gc/412ddR5wteZTWAT4lXmrKCIpm8nDdd6rhiPbpXptcvq1ktvqpvGfCyDCgnjJPP45xWda/LodGHUXLXfoXGWCSD94FIPYjNY91qUNiB5FlI6FwiiFOvqT7CrRBZCu7AAzWXJe6iYCLaxCRqSA8zAZHqBXKtT0Iq+iK0d/bXuqTLLA4Q4HzrwfcGrdzb20KYiRR9KyDd33n4mswytxuiIO2rsm9iiclj2FNoJK25s/D6JrbQJbb/lnHcvs+hwT+pNdZWR4ctFstFiVerkyEeme1a2a7I3tqeVUtzOwpNZPiLTn1XQrm0ifZKwDRt6MCCP1FawUmq2pz/YdNmnAJZV+XAzyTgfqabIRy3mOgVJjhiAGx696tPHBJFiSTC+gPWsLTfM1DRIJZ5nlnIJeRupbJzWbqQvbY4Du6dip5ritqenGWiNy4ht4fmjkOPQms8u8odYmVZCp2lu5x0+tY8MtxOcOz/jVuJ92u6Vap1EjzN9FQ/1Iqor3iakvdZ0vhK41R7dvtEsMpzgttK5NdK9zPCRvtmcHvEd36daz7S3+yW4UcFyCcVqSEqqHPQ11IwAAAA4Xqf/Z', + 'https://twentyhq.github.io/placeholder-images/people/image-12.png', linkedinUrl: '/in/jessica-baker-eeaf05a650', jobTitle: 'Operational researcher', }, @@ -11125,7 +11125,7 @@ export const peopleDemo = [ city: 'Bernardmouth', email: 'cory.cooper@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDt8UjFVUsxAAGST2pazPEZH/COahltoMDAsTjHFIDjPEvxGQB7LRSfO3bftJAKge3+Nec3V3J5jNPI8kznLOW3ZPrWr4Z8MTa/vkZ/JgRtu7uT6CuwT4YW2zP2uRz7is5VYp2ZtGjKSukebSXB8mMM3zAYyO1WdP8AEN/psyXFpcPE0fUA8N7EdDXoq/DawRH3yMzdscYrkfEfgv8Asu2kuLaQuqHlSOcUlWi3YboTSueo+E/EUXiPSVmyouY+JkHY9iPY1vEV478J7ryPEVxZyOcyW5KDPXBB/lXsZrYwCsDxqxXwdqRUHPlgcfUVv9qr6hFHPpt1FMAY3iYNn0xSY0cb4IgSPw/a46uSxz7mu1SNlUd64C2sjH4csEe3eZvL2gq5AU8n1HNaPhOfUBMIHEyxycgStkr6Z9K4JRu3I9KDslE654yVJJ2iuV8SxCbTpljw5K9uc4qn4pe9nunUJLJHFzsRyN3OOBml06BihQ2rQgDk7sg/r1oUbajbu7HLfDa2a48ZS3CoFW3hYMfXJwK9j7V5/wDD/Sjp+pXs8gYtc7ghHQKrd/ck/pXoJrui01oebOLT1G0MAyFSMgjGDRSimJGVp0UUML2kgBKMQARxjqKtxrFFeRogRcfMTwBUF1AI7pZVz8/X61Qv73STIv2qRfMQkAgnK5GO1cEouMuU9OnJSjcvxrDNdTRtsYk5HQ5puo+Tb25CAZPAArN06+0gMy2TpuZznnBJqxeBZHUM4AJAye2aVtbDk7K5JoVmYBJIRjOAPr3raqOCNIoVRCCAOoqQ13QjyxsebUnzyuNApwqvPeQ2zRI7ZklOEQck+v4D1qtNqAgtZLmQ4jUFvoBVEEHifVbbRtFe8ud2FYBQvUnP+GaoweZexK8MqLxncRXmOs63c+IDLPcOSCxVY88KOwH4V2egXKal4et3SUpcQoI5dp5yBjNYYiFrSOrC1LNo2XhkgVnlljY+oFVJ1Go2s0UhLROjKffIxVFomkuAst3JMpOAuMD8avXd/a6XYNJMwVVGAO7H0Fc2reh0ylfVnEaDNe+F9UuII7tmVXHU8MvoQa9Zs9UWeLMmAc4yOleKNdyX+qNMRtaWQED2z0r0O2uSNCMoPO7+gr0bNJXPNQHZt22P/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-13.png', linkedinUrl: '/in/cory-cooper-7be856494d', jobTitle: 'Community development worker', }, @@ -11135,7 +11135,7 @@ export const peopleDemo = [ city: 'New Stephanie', email: 'brittany.williams@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-14.png', linkedinUrl: '/in/brittany-williams-95380b6e0a', jobTitle: 'Engineer, control and instrumentation', }, @@ -11145,7 +11145,7 @@ export const peopleDemo = [ city: 'North Benjamin', email: 'jessica.hinton@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwCKVyRVaWXbhSevapnuYSSKyfO8y+aVjxnCDPSuScuVHXCPMy3qc8lrphKxKm7oSea5pbiS3dFG13fDbiN35c9a3L64/tH/AEKI7pMZZscgVANC/dKkvyNgYFQmramnK+hdtryae0xvSZgPu7djCqsF8Y5mOGwD8yHtTghtFVJOdwwJPf0NVJ3OfMOBIv6j+tS31Q7dGdHFdIQGzwauxXCn+KuYspQ8XyngHpmtGPOeMit4u6uYSWtiu/yRO57CsCW7JuZDH92PgD1NbupZTSp2XqAP51zWiW73eo2kbH5JZDn3/wA4rKorm1I7TwXpDFzcypuZvUVq+KbCRUSeNSVHDY7elJd3D6NbrFFZTTBhwVbAGB607Rby9upBFcJIY5ADtlO7aD7/ANKxcW1c6k0nY5uUFY9s4/dS8rJjoawdSD2svfb1wOhHqK7rxEZbcSW8NqzxJyyoAN3tmskWcGq2Txvp/wBmaEHBDZzx696cU0rkzabsjntJmZL9EzlHBH9RXTJ9K5XQo2fUY0Y8rlh7YyK7GNTW8djknuQSQCaB4nHyupBrH8OQJb6x9mlwJYctGD3wecfhzW8Ac9K5zX7eaK9W6g3rKIyUZeCGwQKJq46crM9WtpYriIRugI96kxFHPHDEoHIJIGKxtHuFvLG3uozkSoGx6HvU9/faWmxLm4aOUHIK5zn8K51e9jvsnqi2wjOpXEUgGCcgkcGqOpeUqtDEgGeOBVazvdPedxb3ZmkJ5LZzUepXEcLI0uSHbbgDOfWna7sTK0Vc5TSbGOG7uJkOVJ2qT3962lGKht7cQJsHarKKe9dKWiPPbu2bqaLLKV+TaD7U+fwmJF8yX51QH5ema9AWzijXgZb1qvPYCR0MjEgMCFHTr3rWSWxnHuec6fB9htTGgIQO2OO2au+UlwN3nbCOM1ekszCZImHKMyn8DVGS3544PqK89u0j04OyViF7ZYG3ebvPriq6Qx32p/Z5OGRA6H8cZH+e9XDCdo7n1qzplmH1ONiOVjYk+2RWlN+8RW1i2ypJ4Zu0PyFZB65xUX9iXqDm3Yj/AGea7yGACMA84pVWKB/mzzXcp5lz/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-15.png', linkedinUrl: '/in/jessica-hinton-fa6b8fd2e2', jobTitle: 'Plant breeder/geneticist', }, @@ -11155,7 +11155,7 @@ export const peopleDemo = [ city: 'West Mark', email: 'natalie.ochoa@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDTBzQcdqbjFcP448STWhOl2h2OygzSZ6A/wioLNLWfHFnppMNiFu7kHBAzsX8e9cnqnj7WLxvLgdLVcciMc++Ca5sM5jL5+oA5NXNP8OalqbKYIBhu7dBRdLcai3sWIfF2sxRrEmoybQcjOM/Tmuz8P+O4LpEttTcRz5wsuMKw9z2NcxeeAdStbUTbVdl5bFc/JC9ucSAbvQ0lJPYbjKO6PeQRjjoaUHiuM8CaybqxNhPNmWL/AFSsckp9fauwzimSNBryDxt8/ia82sSQRkHtxXr+K8k8W2LReMbiPcWE5WQf8C4xSQx/hTQZ9UuVZ4yLaPl3PQn0FewWGnR2kCpHEqqAMba5hpLTSrKOCS1ebKYVAuQABz7Zq94ekAmBhilhhkwSrn1rlm+bU76cVD3TpmjDRkFBt96808aeEVIk1C0YBR8zx/1FdL4kkBnLSwyzxJ/ChP8AKorWS31C2eKO0eAhSrAqQCCPyNKLcdUOcVL3WeZ+F5jF4lsFjJUtMFYn0r2TtXkHh9RD44tI50yEuCvHZuQD+fNexHFdZ55GBXNeJdK+13tleKiloXXPAyfm9fxrq5rWaAZdQR6qc1Sm2lCSu4LztAzn8KmWq0LptKWpdsBDNAoZVY+4zUd7cWtnfW8UjiNWYAHHU+lQWG6MgDOD0BoudTIuNi2bysOpYAL+Z61xrex6aV9i1a3Fnd3kyLIsi7sdOhqxfJFb252gKMdhiqFpf75BE9jJFnoyqCv5jpVm+RpQF5PYD1oa6A9Nzl9F0GGHVZdQkQea0jspI7HGP610jYFaunWkaaZ5ssC+fnBDDOPaq2pWyvB9qt1C7R+8Qdq64OyszzqrTldbFqW3d4zLCTlR86dx/wDWqxNZwXOno8sK/c+b5cE8VrQaekfzMPn/AJVLPbiSIoKSVhbnndxItvdyRIuwJgkZzjPNWbYQTKTLJkHtVvV9HC373qg4kRUlX025wf1/lWHc6fJEd0Ltj0Fc0tJandTfuqxt4hhXMb8elQwTGS9i2fN83A9eMmsy2t5GTMrNiul8P6aXuftTrhFXbEPr1P8AT86cFeWgqkrRdzShUMs0LEKDyPY1QiRlllhYDbtYMPWt82qtk46k81AbFVm83knvXS4vocN0AAAAAAAAAAH/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-16.png', linkedinUrl: '/in/natalie-ochoa-b182dc5873', jobTitle: 'Museum/gallery conservator', }, @@ -11165,7 +11165,7 @@ export const peopleDemo = [ city: 'Clineview', email: 'kristine.warren@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-17.png', linkedinUrl: '/in/kristine-warren-a4821ef1b4', jobTitle: 'Senior tax professional/tax inspector', }, @@ -11175,7 +11175,7 @@ export const peopleDemo = [ city: 'Cynthiaburgh', email: 'lindsey.dalton@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDmHNRGpmGahI+bnpQAxiiANJ0qnL4gUsbdV8tF9O/41algnuzHbQplpZNiD39a6e3+FtoYUea4kMvVj0rKc1F2ZrCm5K6POzq1xHMc4dSeuelV59QkMqhWPlenpXrbfDvSlg2FS/HXNcvrXgVYIXa2cRxqCcEZz+NSq0WW6MkclBqnlxkCQ8E/QV1vhbUzqMUsUhzJFgg46iuAlsnV3QkfL2Fa/hC4Nv4htUlJRXJjz6kjA/XFaoxZ1BFRlQalOKZtHrVEml4YjE2vr8ufLjLL+YGa9HTO1V3815VbCWOSaaFJWYRbP3bYIyw5z6V0fhR9RuWkhuWmKeWzDzj8wxxg1x1o+82dtCXupHXzKxHyt+RrA1jzGtZIlByVOPeuT1RNSS+eVjd3EYOQqyY79hWxYT3Vw3lvbyhV4yW3D8Kz5bK5rzXdjzHW1MVw5ClSeCDTvB1u114r04FS2yXeR7KM/wBK6nxjpYluoTGpLsCDjvSeE/D0+l67bTbmLNExlBGAARxj8RiuqnNNI5J02m2hpfFMElDe9R/StjA6rwa8L3N1FKoYugAB9M812FtBb2kVz5GxTt28YGfoK8z0S5NrqsTA4DHYfxrp7+40cr5N1evFL/HtJy3tXHWT5zuw7ThY3Ugtrt2jkVQ6YOCAaiup4LNCqKMgdqy7S+0pYFjsLhWfP9/LH655qK5JlOWPHesH2N9Co0f2y6DyKG5O0Gi0uIbbUZbWA5EMfz/7JY5C/kP1rJ8SXL2+jXE8EjRyIMIyNggnj+tZnhtWg0tXff5szF3LnJJ7H8q6aELvmOWvUsuXuSSROKhbiti4gIBzTtN8OXmrlnjKxQKcNK/TPoB3rqOQxonIkDA8g5FdbaSTX1uJYHhVu4dc81Zj8Jafp8fmStJcv2DHaCfoO1Qa3BHaJpyR4iEkxVynHVTj8M4rCrqrrodFCTjIeYXtoy85iMh/iWs2bUDM/kxMGY9SO1RXNhLMzRvdyKB2J60/TbBbfcV+b3NcjfU69WOurMzWoh2CQnkK38RFY9lKbuOZ443UQjMgI+7ziuxgtmlljdcBV65rYtNLtkjlVYE/fEmXj7xPHPrXRQcreRzV1FvzP//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-18.png', linkedinUrl: '/in/lindsey-dalton-70af5be384', jobTitle: 'Child psychotherapist', }, @@ -11185,7 +11185,7 @@ export const peopleDemo = [ city: 'Thomasmouth', email: 'jennifer.morgan@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-19.png', linkedinUrl: '/in/jennifer-morgan-ab5acc70fc', jobTitle: 'Quantity surveyor', }, @@ -11195,7 +11195,7 @@ export const peopleDemo = [ city: 'West Andrewhaven', email: 'bryan.harris@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-20.png', linkedinUrl: '/in/bryan-harris-f858052f2c', jobTitle: 'Civil engineer, consulting', }, @@ -11205,7 +11205,7 @@ export const peopleDemo = [ city: 'Elizabethmouth', email: 'norma.adkins@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-21.png', linkedinUrl: '/in/norma-adkins-6297907f60', jobTitle: 'Forest/woodland manager', }, @@ -11215,7 +11215,7 @@ export const peopleDemo = [ city: 'Lake Annview', email: 'kara.perry@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDjhS5CjJPFIBVHVJniiRVZgGPzYFNuyuNK7HS6lukaG3+8pwSw4qrPdx/adksjxBh/rA24A/XsKs6RpkupS7bC3cnozu3yf/Xrej+GN9JJvFykG7kqASKwlUV9Wbxpya0Rzss8dsqNKzMV+8UfIdfUf4VZjv2jw5kM1o33XzyPYj+ldEfhWwVybxuR0C4H5Vz+paNdeH7WWBoneMniRRnH1pKoug3Skldouhgygg5B5BpR1rK0R5TbukpOQeFJ5Fa4Aroi7o52rMrZqncxLLIu5v4TxVs0yW0lljjkVf3ZkEbHPPNKexUE29D0PwzYxWumQrEgBAGSB1966uPOwZ61w95PNYRLHFFcvlcoIiAOBWhoF5qjSRRTmRlkwwMnVc9jivPa6npp/ZOpkJ24xXK+Jwp06fK5BXJpviG/1OJ2S3EpjT73lnk1Stmmu9ySxToQvziVgwOR2NK3UH2OHt/JNwZIhyVxx0NXlqvZadLbQTyPgJ5xVFxyQD1qyor0KbujzKiaepVzWzoapdR3Fmw/eECSPjnIIyP0rFNSW9xJa3Mc8Zw6HIpzjzRsFOfLK56lp/kXNuiyKpOO4qctbxX8USFFwcnkCsHRro3MEUy4G8ZKjsfSn3Oo2LXQhubSaSQZwwjIx9Grztb2PWjZq6NqM28t5NHIVbLHHeoNSMNtbssagHHas2yvrBblreC1nidvmLGMkH3LetO1mTyoXlcjCDp70rO9huyVzC1lYrbTre2QYdmLkHt3P6msNanuZ5buYyynLn8h9KYiZNejTjyxseTVnzzuigaSnbeaTFaGRveHbt4RLHklVwwHpXW26w3qB/N2n1XrXGaDFKL7OAI2jOc9Sc4H9a3jpkxlIgmMTdcDvXnV7Koz08M37NM2JI4rNS5m3HpknmsDV5jcWuedhYYz3q+ukSgg3M7THsvaq+sWJlsmVG2NGN6kdAR6+1ZwklNNmtROUWjnClPjXmrkVi8y71+6QDz709bMo3Jr1Miz3P/Z', + 'https://twentyhq.github.io/placeholder-images/people/image-22.png', linkedinUrl: '/in/kara-perry-3dddc5ee1c', jobTitle: 'Waste management officer', }, @@ -11225,7 +11225,7 @@ export const peopleDemo = [ city: 'South Cynthiaberg', email: 'nicole.kelly@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-23.png', linkedinUrl: '/in/nicole-kelly-793e9bc70f', jobTitle: 'Therapist, music', }, @@ -11235,7 +11235,7 @@ export const peopleDemo = [ city: 'Brucetown', email: 'annette.long@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDXC8Vy2t+N7LS5mtraP7VcKSrfNtRSO2e/4VJ408RHSbQWNt/x+XCE7+0adCfr6V5Mqsz4+8fpk1DZaR1cvjjWLpiBPFAmfuwp0/HmnW3jPU7dvlvjK39yZcg/1FUNH8M6hqjK0MO1O7npXU/8KzuXiJN9l8cKRxWEqsU9zojRk1sW9J8aRahOlvdQCGVsDcrZUn+ldTnNcZN8Np7aATxXh89Rnbjgn61J4V1W8uNRuLS6MjNGNreYckMM1cKik7IzqUnHVnYbc09UyKAKkUVsZHjXjC5a78U34ySUk8tfYKAP51L4W0yOfUU85PMXvnvSeMbR7DxVe5QkTESxnH94c/rmtnwncCGBpRA0sudowcAD61z1m0mdFCN5I9Cs4o4IwqhI0Xj0ArVikidfkmRj7HNefy315NNIJomaJWwqIvGMZ5z3pdMmuom+0xW8kCYLbZOBgevpXHyaXO/n1segTKSnYfjXCzQppnjeOdVAS/Qo2P746Gn+ItRvmZoZYZraJYVkcK24sD6YxWXb3KoYLoxzsLXMkcRQ5JK9z2Hf8K1opqSZjXacWjuRTxUFrMbm0hnMTRGRA5jbquRnBqcV3nnHM3duDM6XSGd5ZztR+VC4689AKbp9lFpcYt4lJTeSc/Wt3UoYIUN5OyrHGMuzDgD1rHhuoLkyNASUV8KT3rzKsXCTTPXpzjUipLc1Yow774EAZgAwIBU028ZbdR9skhjg+85CnnHIB/HsKktBgg5pt/qYhBRbKa6I6hF4z9T/AEqI3eho0hLq8s702jQSxSy7SCjcblP/ANfFRy2guF8gxrEjY34bJI7joKz7PU7eW68p9Lns5H53SIQCfQEitqHc0uX6gVrBNTSMa1vZtljGBSiilAr0Tyhbu0S/sZ7SQfJNG0bfiMVydpbyW1hArD95FGEcepHB/lW7q+qahp/knTrGO63OEk3sR5ef4uO3rUKxlkZiBliSa48VJaI7cHF3bI7e8UIMnGK0I2tplI83CntWHdQEcgcVntIchRuzXIjubOlnt7eFSUmDj0Y5xVi1y8fmMMbun0rnrdfIdJLlyE3KCCfU11YArrw8E3zHFi6j+EQLTgtKdhwH/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-24.png', linkedinUrl: '/in/annette-long-45da6c37e7', jobTitle: 'Community arts worker', }, @@ -11245,7 +11245,7 @@ export const peopleDemo = [ city: 'Deniseport', email: 'john.stewart@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0zNNzRVbUGePTrp422usTFT6HFAGVqWtbXaG2cAKcM45OfauQv70o7yvJulbC/M3A/GpbmVIYViR8Rpxk9WPfNYt1KZBgRgp2+X2qGyrGQ8t1uJDqHIyGBI5NdF4c+Id9ZXMVjrCedAWCC4z8y9ufWufuZirMXjIJbPpWbKUdghGcjg+n1qkJn0MfrQDiuf8ABOoyap4Wt5ZmLTRFoXY99p4P5YroKYhwNU9Y8w6LeiIZk8h9o98VaBqhrt29loN9coGLxwsRt656UmB53MEgI8+YM3RWPJb6D0pPsU0wDx2VwwPcoRV6fS7rTUjuwJZL5lyvlopVTjOMn8qu+Htf1rUZhb3VptYjIbG3j396wc+qOqNJbM5S802eNTvs51GOuzI6CsK4tcOxU5BJAr0DW9f1qC4kgtLVfkBLNt3EgenNZkmlSa9aNIYZIb0DO5owgPsccU4ze7FKitkbXwvlL6bfp0XzFfaexIOf5Cu7NcP8M2WTS75zlZ1mEUqf3So//XXbmtzmG0kiGWJ0I4ZSOamAFLSAxYislubecAlODupbBbYXZW3UYj+8w7nFQaq8Dap9njuEFz5Yd4weQucAkVmXNzbQweXBPLDKMgOEbBPcnjBrjatKx6lOSnFMvMtvLdtHOoDEkgkUXMsNrGyRKMY6isWzubcEiSaaaVmzudWHPt7VehX7VqEMJOdz8/TqaLNuwSaSbZd8IaUun6fc3GD5l7cNO2fyFdBinjgdMClrsWiPMbu7hiqOqavaaTEHuHwzcIg5LGrkBeS2jlkjMbMoJQ9R7V5r42ne115oZsmC6g+X2df/AKxpiM+2cXnj+S+eVg727x9eN4IIH5Z/Kuq8kTRlJLt4GXjjqK8uk1NrSVMZMuQzbeCpH9cV07eN9MvLdEnhm8zAG9VHXH161hVpybujqoVYxVmdHMi2sLM140o9W61nm5+zyLK7+WEzIWJ+6o71yVx4qghZpLZJZ2HTzTgL+Fc7qGqz6i6y3FyzMcgxqNqqM8YpRoye5VSuump3en+OJdP1ue4imubnT5m/1E8pO09yuc4+lekaL4gsNdgL2jkOPvRPwy18+Wod/uoW+ld54M0LW21O1u4opLe3R/nlcYBUYyAO+eldFrI5AAADk3dz/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-25.png', linkedinUrl: '/in/john-stewart-50fd4b2b37', jobTitle: 'Land/geomatics surveyor', }, @@ -11255,7 +11255,7 @@ export const peopleDemo = [ city: 'South Mark', email: 'gregory.larson@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-26.png', linkedinUrl: '/in/gregory-larson-4f52726447', jobTitle: 'Translator', }, @@ -11265,7 +11265,7 @@ export const peopleDemo = [ city: 'North Rhonda', email: 'wanda.herrera@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-27.png', linkedinUrl: '/in/wanda-herrera-10f674edf1', jobTitle: 'Therapeutic radiographer', }, @@ -11275,7 +11275,7 @@ export const peopleDemo = [ city: 'Mcconnellland', email: 'sarah.davis@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-28.png', linkedinUrl: '/in/sarah-davis-c63949c87f', jobTitle: 'Architect', }, @@ -11285,7 +11285,7 @@ export const peopleDemo = [ city: 'East William', email: 'devin.snow@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD06lFGKhvJ/stnJL3Awv17UAcz4j8bRaXM1nYIJ7pSBIxGUj9vc1yN/ruoXMCzTXs67iSuFA2n6VqaboK3HmtISFd2Iwc7vc1rSeEpp4BElwoi9CgrmdW7sdUaDtc4xtauBbiUXRWYfdkQlW/wNa3hv4jTRzJZ61ulRjtW4C4Yf7w71sJ4Isbfl8uep9DWTrOiQMmyGKNXX7px3pe1sy3h7o9KBDKGUggjII70uK5HwRrVxepJYXaqJIFG0g+nB/pXYYrpTurnE1Z2CszxExj0SaQfwlT+tagrL8RDOkspICMwDZ9KJOyY4K8kjLsXQxJyAWUYFbKMfLUE1wGv2VxJOrokzIq5QxclcDsMjk/Wl8L6hrEt0lrMLjY4yrzrgj0Brht1PUXY7q53eUcHAx3rkNWkZCCDkg5rJ8Q6trcl1cW0CziKHl3iXJOPT1rO06O6lmyxuOVy4myPxx2NJxvqO9tDpvAcSz+Ibq8Xg/Z9rj33CvRK8v8ACV1cWfiFY7bDR3MwSYei/Mf516ga7aTTiedWg4y16iCqWrwC502SM9OCfpV0UMquhRwCpGCD3q2rqxnGXLJM5y08m6tRHIBjHOaktUtEvFitgMIfmYeuKzrmF7bUJoEO1FJ2j26isnUJrSVEVXmt51BVJVRxjPXoMGuCzTserFpxTRrQLbSahPDPty7kqT3qHVI7ayhYQrjIPOa5nTpbDTZmxczzyyty8iN/UVf1mZxGS7E/LnFJroVcn8FQebraTYzsDsfYdB/OvR6y9A0mDS9MgCQqlw8SmZu7NjmtSu6lDljY8utU55XEFLXnGu/FqxtUZNHtmupB/wAtZQUQfQdT+leb6t4x13XZi95fyrGekELFIx+A6/jmtDI9K17xCk/iy7trUI8dnDH5joclmJOfyGBWgBFfWiul4YsjIKHmvL/BcmddeMnmWBhj1IIP+NdDeQXMZb7PcGJT09K46ytM9DDyfIdLLDFZxtLJdb8d2ritS1uWQvNAwbyv3gLDgkcgfTiqk51F8xTzb1PG0HrTby18jRrlm6+W38qy6mkpNpnpOl/FfwzfQQG6uXsp3Ub1ljO1W7jcMjGfWuytbu3voFntJ4p4W6PE4ZT+Ir5MVfk2npVnTdSv9Lm32F7PbHPPlSFc/lXonl2P/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-29.png', linkedinUrl: '/in/devin-snow-b8a26f7352', jobTitle: 'Social researcher', }, @@ -11295,7 +11295,7 @@ export const peopleDemo = [ city: 'Nicholeside', email: 'gina.hernandez@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-30.png', linkedinUrl: '/in/gina-hernandez-40ea9940fd', jobTitle: 'Advice worker', }, @@ -11305,7 +11305,7 @@ export const peopleDemo = [ city: 'West Nicholas', email: 'ronnie.watson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDrru5gsrWW5uHEcMSlnY9hXj/iL4j6jqExh0wmytckBh/rH989voK2firqEyXNlpwc/Z3jMjxqcbjnjd7DFcDp2nHUNVt7ZSckjcR0UVjotTWzeiG3M9xegzzTyTTj7xdiTiqzsSgIJHPEY6mvX7P4e6QgBIkJI5+brUlx8N9HnUY81H7MDWaqxN3h5nnfh7xlqegONshntiPmt5XJB/3f7pr2PQ9atNf0yO9s2yrcMhPKN3Brzu9+FzRb2ju/l5wMVJ8Nzdab4gvtLkVcbfmA9ujD8/1qlKMtiJU5R3PUqXAopRTIPJviqudft88f6IMf99HNYfhbEeooV5fcBn1r0Pxh4fHiWVHjfyprIbQWGQ+SCQfSsDwZo62uv3MVxHia1GMHkA+tRKaadjeFKSkr9T0e3OFUHrgVaYkDpWBqDXaLthEuDwfLAyfxPSsXSp9We8DGS7SN8jZMwbbg45GOK51HS5182tjsZ8shPauQ0yAR/EEugPzWbFsD/aGKn8UahqcEsFlZ7gZCoaVP4c5/zmrPhCzlRZ7ud3kkdVRXlHzgDJIP4mtKcdbmVeS5bHTUtBorc4jPu7ci5VggZHbLL6kDj+lZkMKxa3eTiPaZgmT9BXQXkMs1lNHC/lzFDscfwt2NYKqftAcuxZ13cnv3FYVI2fqdlKpzRSe6N2IrInGM45BFQukMUnCKJH9KZbSbRtJ5rO1K5tp1kileIA8Es/P5Vml0OhNFm8gRpIXkUEFcc1a08rskC/dDYrlIZIY7hEjullUDCruzt+ldVpakWKMerEn9a1pr3jDES9yxcNJRRWxxGL4l8W23hdIWuLWefzDhfLxgHsDUJSS606OeMbJQN4U84z2rJ1Jk1rzBdoNj4G3+7jpW5pEoMHkSY8xBg+49aWIg0kzbDNNtFO3vvMYDeFkXhlPatL5ZYdg2A9AcZ5rP1DRPtL+ZAQko6ds/jWSIdbRmA8tYozzJI39BXOrHTdouXsEscixqwediFQAdzXWW8It7aOEHOxQufWvMdU1C/wBOvdOmS4JuHlY5xxgD0/GuotvF7so8+1DbuhjbH6GuilTbV0ctepeVmdSaSseHxPpkpVXlaFz/AAyKRitcMrKGUgg8giraa3MT/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-31.png', linkedinUrl: '/in/ronnie-watson-5e8ffd4706', jobTitle: 'Press sub', }, @@ -11315,7 +11315,7 @@ export const peopleDemo = [ city: 'Davisside', email: 'mark.duran@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDrwBXi/wATfET6prP9lwSf6JZn5gP45O5P06fnXs+CwI9RXzfqcTt4hvYyMv8AaXB5zzupFFWCAsSzA496lW3ZpWVxhcdf5V6Ro3w6tr2zjkurqQF1Bwg6V0cPwx0+O2ZBPLKzLgF8cVj7eJusPO1zxAx4Kqy5GfmI/nSQSSWVzHNHJh1OVIr2qX4ZaR9nZG80yHq4NcV4k8DRabbPLbzOxTnDChV4t2B4aaVz0Twbq8+seHYpro5uY2Mbt/e7g/kRW6elcF8KbuWbRr62kfKwTjYvdcjn+Vd9jjNamA9WxivAryzmPjy+too8ubtzgHsST/KveG5Qj14rgrrQ/svjSG+I+WeEgnOcsMD+WKzqT5TalT59fQ7HRlWOzjjzyvFdDESsYyDivONRhvLSUAPfHILoICMcDOAO5rQ8N6prplWK78x4pMFDKAHTPY4rjS05j0L3fKdlPnbgcVw/i6MXFhNHEcvtOPrU/ijUNY/ew2hkRYhmRogC59lB71z+m2E0s00r/asxrmTznyGyOnHGaEvtCb+zYd8KLWSLSL+5cLiecY9eB/8AXr0EnisLwnp403Q0TvIS/wDhW2eld8XdXPMnHllYByKxNbgZVinQcpLkn2I6VsqeKr6p5a6XO8zoiIu4sxwBilUhzRKpVHCRZszbX9qqyqrgYIzRKkFvcpFAoBBBO0d6x9NYhB5bfKRkUt3eaZM4EtyYZkOQysQQfX/9deeux6ys9TSZIpNUninQENzhqr6p5FtZvDAgUtxhRWXDdWUV07i/NzO2BuZiT+HarTA3N9EpOcsOP1P6U0ruwpyUYtmnax+TaxR4I2rzn1qQ8CnsMUw4xXpJWVjxm7u4i8DJOAO5rz/x9rKXlutpaOXhicNIV5Dn29cV0ni26WPTDDHJglyrKMgnHb6VwDEn5h1HIq1HQm50OnX0llawtNuWMgEH+6e4NdKsUOoRpIJwpI4deuKy9IFtqelnG0nPzof4TVB9Mms3ZIbuW2GeABuX/wCtXlPSVnoz2ISsrx1Ruy20NkrzG43HuzY6VyGt61fW+padJaM6xbyxcDqe2fbrWjDp9zdXAFxctPEvJOMCm67HFDA24DcwCRr+Oaum7TXUzrNyg29Dt9F1CPWdPSfARydrAHgN6f1q3JAyZ3DFcV4Iu/I1Q2cpPlXK4x6MOQf516Wse9Cj8svf1r0WrM8vc//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-32.png', linkedinUrl: '/in/mark-duran-0a02b4a8ee', jobTitle: 'Operational researcher', }, @@ -11325,7 +11325,7 @@ export const peopleDemo = [ city: 'Candiceborough', email: 'shawn.wolfe@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDv6RmVFLMQFAySTgAU7FeRfE/xU91MdD06ZjFGf9JKcBm/u57genrUFG5r3xW0/Tp3t9Lt/t7ocNMX2xg+x6muXPxg1qQyNHbWMa5+XKk49uvNUNG+H1/qccbXTLbxMN2B978a6hPhLpwjYG4nLHoRgVm6sUbKhN62I9D+LxuJI4tWsUUE4MkBOfrtP+NemWl5bX9slzaTJNC4yGU5rye7+E8kZL212M4/jWsKxu9b8Ba/C0ryfZXceainKSpnnj1FNVIt2RMqUoq7R73iikikSeGOWM5R1DKfUEZFOxVmY/FfOlpbibxKRI25TcsQMdfmr6NArw7T9N+zfEC5tZeRFcOynHUckH9ambsi6avI9OsNvlKB1HBrWByoxzXC6t54zGFunXBISDj9fWl0E3tpMgZp1ifBIlfcRnt9a41HS56PNrY7eQnbzwK4XxvBDLpMjSRhwhDDPbmpvFE9/I8kcEk+yLlvJ+8fp69ayIopriwurec3DK0J3LNyQcZBFUlb3iJu94naeBJ3uPBtgXYsYw0YJPZWIH6V0WKwfA9tLbeDdPSYYYoXA9iSRW+a7Oh5z3FdN8TJkjcpGRXnM9mtrrVm3UxI0BcnknGa9JrkPF1jJDbi8iUbUmVyc8jPB/nWVaLeqOjDzSvFmjaLFPCAyjI9aq6hcWVtIiPJFHhgMsQoJ9B6ms+z1HdbswOWVC2AetZk8k+pqqzwSKozhRAT+tc0V0O6/Y6MT2MurSRiaJyyjKg5waZqkMMVvII1CllI3CuVjhfS7vzohIMrhlkiIB/Gtqe6a8MMEYzJNgAZ6ZNNx1sS3ZanTeHbVrPQ7eFnL4BIJ9M1pGm28Xk20cXHyqBxTzXalZWPMk7ybHVU1W2W70m6gfo0TfgQMg/nVsVV1S8isdPeWUMVYiMbRn5m4FN7CW55C161lcNCxcSKMMuex/pXTwajFdacU814324DLzgVBq+hx38CTeWPNAxu9q5uS11G0RkTzCB/s54riVmehrFnTi9htLN189p5Oik8CjwRFPqWptdOP9HtONxH33IwB+A5/KuVg0/UrwBSzJFnBYDBPrXpvg+2istOmtogFCOPl/DrWtO3MZVnJxudP//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-33.png', linkedinUrl: '/in/shawn-wolfe-3b9f538b13', jobTitle: 'Research officer, government', }, @@ -11335,7 +11335,7 @@ export const peopleDemo = [ city: 'Sanchezville', email: 'mark.welch@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-34.png', linkedinUrl: '/in/mark-welch-3a104608c4', jobTitle: 'Chief Marketing Officer', }, @@ -11345,7 +11345,7 @@ export const peopleDemo = [ city: 'Josephbury', email: 'james.holland@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDvsUlLTZGEcbOeigk1zG5geJPE8eiKsMUX2i8kGVjzgKPViK4y51y4vYmlvb1w7D/j3g+6o+n+NY2qajLqGr3U6l2Mj4JPGAOn6VVNvdGLKWUiKeRLEuCaTKSGXT7Fdra6mUsCCjEqT7VDpd/IpdbeV4nHOQSDn65qxDpetXsZPlymP1mHP5Uhszpdk++NvNZiHDc5+lNNbDae53HhTxxJcX0elargSN8sU5IG49g3ufWvQK+bVuZfOWRmKup+VweQR0r6A8O6idW0CzvGOXdMOcfxDg/rTsQamKq6jJ5Gm3UuM7ImOPXirdG0EYI4PWgR5L4f0x9Q1OUuoKKATx3Nd/FYJGqgqMgYziuXsrO+02TWPIDGRJgg2d+v+INaOg3+qXU6RXoI3qWBIwVx2NYzT3Ouk1Y2pLNSMha4/wASaGbiF5FfaF5Iap9Y1fXI77yrUHywwBKpknnFXYZLm+ge3u4zvAIYkdf8amzWpbaeh5LNaN5pTjIO1uOR717V4CtZLbwhaLJ1Ys4PqCa8su9Mu212W1hGZCxHt0617J4YTy/DGnR7gxSEKSM4JHXrXTdPQ4nFrU06UUlApCM8QJFfXJOMTkP+QAP8qIkhWeQoqBlXkgYFSX6fKsg6jisC+uNN4SS/SCZgRnzME9zxWUk72Ouk1yo07dIJnYMF3jnkdaZfeVboSoG7HYYrK0y40yFPKtLqOVge0mWq5d/ONxPQd6zemhsYcWnbdSkvYi5nkK5/uqBwfzrvLOEW9lDEF2hUAx6Gue0K2uJ9QllcD7EiDZkctJn+QGPzrp62pxe7OStNP3UNopskiRIXkdUUdSxwKw7nxho9tK8ZnaRkGWMa5A/GtVFvY52zbmjMsLIOpHH1rnZLUyx4EURZD/EoOD3rKk8dz3YU2VusKE8NJ8zEfyFS6LI2o6GsqSlZkkkR8c5IY9fwIqasHFKTNqFTWyLS2nkqXeKINnqqioJZmnfy1PB6kVDbR3l7PJFcShETqF6mrsVqkJwmcepNczOu9y54d1yyuLq50dMpd2p3MrfxqcHI/OuiryTUZRo3jqLVbc/OY1EqZ4bt/KvRdK8QWGrriCYCYD5oWOGX/GuuK9xM4AAAnpNo/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-35.png', linkedinUrl: '/in/james-holland-a99089ebf7', jobTitle: 'Engineer, building services', }, @@ -11355,7 +11355,7 @@ export const peopleDemo = [ city: 'Lake Denisebury', email: 'jennifer.weber@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-36.png', linkedinUrl: '/in/jennifer-weber-384a97d0de', jobTitle: 'Engineer, maintenance', }, @@ -11365,7 +11365,7 @@ export const peopleDemo = [ city: 'Port April', email: 'beth.hernandez@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-37.png', linkedinUrl: '/in/beth-hernandez-7708149061', jobTitle: 'Runner, broadcasting/film/video', }, @@ -11375,7 +11375,7 @@ export const peopleDemo = [ city: 'Port Tina', email: 'eric.barnes@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDbmRRkis+XFaMuCpOazZ2C5YkAAZJoA4/xP4oOnyyafaAfaCnzS5/1ZPp71wb3MsjvJNMztnJYnJNaVlpcviDVbhw5ERkJMhHJ5rtbLwDZhAGdmHfPes5VYxdmawoymro82MztgqQATyTwT/8AWqa01S5066jnhch423ex9jXo1z8PNPMZwJFP94NXI654Qk05DJEzyKP0qY1ot2KlQnFXO00HX4ddtmZVEc6cSR5z+I9q2lWvJfCt5LYeILcLysp8or65/wDr164pyK2MGXZDhTmsrUA0llconLNEwH1wavytkYqkxweMZ96AW5yXgu226du2/MzGvQbVH2A4rgYQ9hZQoq3I5bHkY4O49Sa2tB1XVZJ44JY3ZX6M+FYD0OK4Jq7cj06bslE6yXeUIA7elcvrqs9nKqKSxHSmaxrGrRXLxxLKI05by1BY/TPem21zNd8SR3K4GSZgP5j+VSk9ym18J55odu58XWqAYImyR6Y5P8q9bUjFcvpGjpbalc3wCmZ5jt3D7qZOce5rp04613U5qSPOqwcN+pJIcrVIn5quFvkINUn+8asyJLD7KZJoZACC2Rn3rRsooRqiLEqhU5zwMmuenzHMki5yeDSNe2ck2ZPMWVRt3oCCPxrgnBqTR6tOalFM6RltTdlLhF+cnDcHNRai1tbW5SJRyMDFZNne6ZBuijUq7nlmU5J+tS3QH3mbgDgVm007Gl9At1UWyZILEnp2qYZxSRptjUe1PAr0acOVWPKq1OeVyWQDZgdapSLzxVonjrUTDJqzMqywedGUzg9j6GqcCuzlftPlSJlSa6PTtNmvJAyr+6BG5j0rn7/SriC8uoWYrNHIxDeoJyP0xXNXSVmdeFk7tFhoxFGWkullY96rgtOpIJKgdTUFtp7s/wDpEjN7dq63QtAbU2UumyzQ/Mem/wBh/U1zJOTsjrlKy5pFazsbibw+uosrbWbKArg7PU/j+lV1NemtBGIhGEGxRjAHAFc9e+GoZPntT5b/AN0/dP8AhXorW9Xof//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-38.png', linkedinUrl: '/in/eric-barnes-332ab94dce', jobTitle: 'Patent attorney', }, @@ -11385,7 +11385,7 @@ export const peopleDemo = [ city: 'Mezaborough', email: 'ryan.richardson@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-39.png', linkedinUrl: '/in/ryan-richardson-36096d0c1f', jobTitle: 'Cartographer', }, @@ -11395,7 +11395,7 @@ export const peopleDemo = [ city: 'Lake Shawn', email: 'brandy.cowan@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDveMUlArF8U6/F4c0SS8baZidkKH+Jz/Qdab0ATXPFWnaGfKlYzXRGRBGeQOxY9hXF3vjfWJ9zo0VpH/CqJub8z/hXERTXOo3MtzNKwd2Ls55d2P1rYtvCWt6nGHSCOGMjh5Th/rxXNOb72OmFPyuWIvH2t28pzeCQA9JIx/gK77R/HWl6jDEs8gguGAyrdM+1cR/wri8CKbi/DEdRgmsXXNCk0IyPGS8Ldz1HtRGr0TCVF2u0e8AqyhlIKnkEUGvPPhl4le/ik0q5fdJEu+Jickr3FehmuhO6OdqzFFeP/FK9km8SxWjsfJt4VKIvdm5JP6V7BXiXxOGzxo/lBixhjZzjoeg/pSnsVDc3/BfhmMW6ahdAPK4yidl/xNd8qFUAC1x4+3Weg2a2qytI0K8JxggdSan8NXms3EiLevIUf5gXGCPY1wSTep6UGlaJ0sqErjGM+tcn4tt0bSJQy5wMmovE11rBllS1eRYovveVyW9v1qvbi5ubGa1ukkV9hHzNuDcdRRGNtQm76HL/AA8nSDxlZnJAcvGR7kHFe6V8/eDlubLxfZ3H2YyRpOEcdwTxkD2zmvoCu6Gx5s9xRXKeKvDdvqEpvwjec0axNjocHgkd8ZNdXUVwu6Bx3xxTnHmi0FOXLJMy9OKParG2DtG0gj0p8pt7e4jRdiEnJ6Cs+wmE26SMjG8ggHOCOtV9T1DRg6JeFJJdx2gKWYHGO1edZ3setGzV0WrY29xezpmN+cjvmmakYYISqAbsYGO1ZWn32jJdOlgQjl8srAhs/jS6rceVbT3T/dijZsH2FO2thNqw3wvpgXU0YrzHI0qk9cEc/rXeGuC+HV3dau17qlyioCFhjVPuqOpwPy5rva7qUbR1PMrSUpaAKCoZSD3pAadmtTI5uSxOku3lBVt2OVAHT1qOS2N3GDE6KR0bGabqevrP4oi0W3CusULSzuOcNwAv881VvrG8WLfYzBDnDKelcFZJVND0cPN8iI3sngdpJZUZvXFY3iG4jl0K6Es3lwttRpAM4ywHTvViSy1B5EW9uQVc/dTvUPiCwim8N3lux2II8g+hByP1qU/eVzSo3JM7HwrotpoukIlpcGeOYCQSHoQR2rczXFfDq+lfw8sMzlkjlZIyew44/D//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-40.png', linkedinUrl: '/in/brandy-cowan-bab6874e38', jobTitle: 'Patent attorney', }, @@ -11405,7 +11405,7 @@ export const peopleDemo = [ city: 'East Sherylstad', email: 'zachary.jensen@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-41.png', linkedinUrl: '/in/zachary-jensen-ad43305058', jobTitle: 'Nurse, adult', }, @@ -11415,7 +11415,7 @@ export const peopleDemo = [ city: 'West Elizabeth', email: 'carrie.taylor@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-42.png', linkedinUrl: '/in/carrie-taylor-c50c9da449', jobTitle: 'Designer, furniture', }, @@ -11425,7 +11425,7 @@ export const peopleDemo = [ city: 'Ronaldfort', email: 'timothy.williams@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-43.png', linkedinUrl: '/in/timothy-williams-0bd12cc799', jobTitle: 'Editor, magazine features', }, @@ -11435,7 +11435,7 @@ export const peopleDemo = [ city: 'South Michaelfurt', email: 'peter.rodgers@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1rFFLSMQoJJwAMkntTENd1jRndgqKMszHAA9TXKal8SfC2msEOoi5c/w2q+Zj8en61yHiDU9X8fX0+naXObXQI22PLjDXDDr/AMB9qrR/CWHbzfuen8IrKVWKdjaNGclc7ex+Jfha+yDfm3Yc4uIyv68iuptriC7t47i2lSWGQZR0OQw9jXkFz8KrcBjb3sqORggjiqlnda78N7mNxMb7SpXxLFn7vuM9DRGrFuwSoTirnt1GKgsL2DUrCC9tmLQzoHQn0NWcVqYi1ieLrr7H4T1KUZyYSgwcfe+X+tbYrmPHzx/8IrPbmTbJMyiNcfewwJH5Um7IcVd2Rg+Holh0+KONQAVB4rpY8lBtbPtmvPdYe4tWW3ikukiWMYFsmWOKb4Wk1Y36wSTXJgchsz9R6fT6V59vtHqX+yehyghDlsH0rlfEiRPp00cyhkKknIrB8T3OqrqpijlufKj6mDkn8O9TWE894n2Wdp5IynzC4TDrn+Yot1BveJ1PwrvXufDM9s5+W1uGSMeikA4/Mmu649a4H4YvHbaVcae2Rc+a0xGOqcKOfwrvK7oyutDzZRs9R4rm/GVmJ9PhmCFniYhQO2Ryf0rpQKqanaG9sZLdZNjMOGxnmicbxaHSlyzTOVtJ7Oa3CzqpBHcZqp/a+kWWqRQl44FzlF24LAdT6VhOzwQzMDl0UkIe5HFUZ7XUdQjH22IoAOAXQVwxV9D079kdJHqmlXeozJ5sUyFiGwMlPr7VZ1BbK3ixAi4x1FcIkeoaTve3ieRSMFRtbP5VsLJLdC3QZDSADb7ntRKOtg5tNTrPBdqqyy3BxuWLZgdgTn+ldlmqOlaZHpdqYlYuxOWcjGav4rspxcY2Z5taanO6H7gBULOCam8iQ4zgCud8R6bPHqEV6kzrAYfL2KTjfknJ/A/pTnPlVxQhzOxwfiFmt7+5JH7p5WZSPr0qCbU9MvbUxXCtIQAQVbbW/fWCXdq8TDJxivPtQ8N3UUzlAH9iSD+lcUZJu7PQlGUVZG3cavplvaNHaEodpGWbOK2PANump6mLh8mO1QMg7bs4B9+9cfpnhuR5d9wg+nX+ddhpF7caFewrbQB4ZpY4ZFA5AJwD+tXFxUkZzU3FnqIIoJqLcVYg8HOKC9dpwWP/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-44.png', linkedinUrl: '/in/peter-rodgers-2b96b2d840', jobTitle: 'Scientific laboratory technician', }, @@ -11445,7 +11445,7 @@ export const peopleDemo = [ city: 'West Christopherview', email: 'julie.taylor@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-45.png', linkedinUrl: '/in/julie-taylor-fa514d063e', jobTitle: 'Careers information officer', }, @@ -11455,7 +11455,7 @@ export const peopleDemo = [ city: 'Amberton', email: 'samuel.ortiz@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDRIz1pu0Zqby8d6QLz0rnOgz769t9Oh824fGfuqOrH2rkNU8W3CyFY3MK/whOSfqah8QXEusa69pB84Q7EC+g6n86i/wCEG1W5T7yrg9zmqTjHcXJKWyKN7q8sxWR53yEG3JOR+HatPS/Fl9bKPLl89E++jcnFRz/D3U4bcYkEjDqBWdJ4Z1GwhaRVYnHO09qOeD6h7Kouh6bpniKx1IxRFvKnkHCN0J9jW4sPFeAR3EkDYaUhgcrjqDXufhfU/wC2fD9vdM26UDy5eMfMOv58H8aHGwlK5Jtz1pGGFJPQAmrAjXFJ5ecggYPapKPPfCcAuL65vD80hwoHoCSf8K9Ftrdwgxg5rzqW1udJutUjtzIF+04j8oc42gj+dbPhfUNYuZltbjcQULhn6j2PpWFRe85HXRlaKidhcRuqYGOe1c7qGY4yu3nBzXPavfa5JfsEa4KIcERnr9Kv2M125+zzLIwHd+fyPeocdLmilrY8+1nasjMqJuV+uOo9D+Nek/CpxLoF4oBytxzkf7IriPEtg8OtFYFLeYoYADvXpfwysGtvDlwZCpke5YnGeMKODXZGScUefODjJs1QM08LSqvHSngEVIGVJFbC/nikUZmw5z64x/SrGnNZ2styfMjXbGVXoOfp2qjr0bRzQXC9MFTj86xpptMvMlw27G1jEGJIHY4rCSfOztpNOCsdBbCzupGjLxOxG4FSGB9qbeG2s1YIoyf4qyLPUdLs4zbW0QiZiMAqVNJeSEltxJI61nJW0NU7me1pHdX5mLMsmNqsD93nOa9E8NwG30Zdww0rtIeMZzxn9K84Ed9d3draadIUluZhGzhQdqdWPtgA161GgRFRfuqABXTRi/iOPEVFbkRkgY7UoU+lSLgClyK0OcoanZNeWMkcf+s6pn1rj4El27ftLW0i/KQOPwr0Ec9BmuY8W2iJFbXCqI5ZmYZA64A61NSGnMbUalnymS7Lbw/PcLMx7kfrWbNcSSgqGLEnrWXN9p8zax4z1FaWnQOSrOeB0Fcz7nYm2Wk1G80I2s1kkbzSyLBiRc53H/GvVLdy6K3fvXF6Ppv27UIZHXMdsfMJI/i/h/xrs7cSJPHsIIZxuBGeO9dmHi3TucGJaQAAABVLI//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-46.png', linkedinUrl: '/in/samuel-ortiz-fd07e1761a', jobTitle: 'Insurance broker', }, @@ -11465,7 +11465,7 @@ export const peopleDemo = [ city: 'West Elizabethfurt', email: 'kevin.lucas@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1GlFFISFBJ4AGSaYjl/GHi8eHUjggiWS7lXcN5+VBnGT615vNrN3qM/nXUst7KxyoJKhD6ADpXQjTxr3iOfU78eYgbbDGegHbj2Fdba6NY5Di1iBBzkL3rmnV1sddOg2rnl9zb3U0Sk2sgnJwGPXPaltNd1vSDHOJZokU4OMlDz/EOhFeuS2y7P8AVrgdOKwNTt45YXWRQVIwRioVZmjw6sa3hjxRB4ht2HyJcxgF0U5DD1Ht/KugrxQrN4a1JbuzchI2zg9gf5jtXsdhdrfadbXajAmjWTHpkZrqjK6OKUeV2J6hulL2U6jqY2A/KpqZNKkFvJLJnYiktgZ4qmJbnD6IuYhjruP866mAELxk1wk0t7Z2ifYldmcuV2jk8n+laPhu81mSZI74na6llLDBX2Irz5LW56UHokdZKSUIJxXP6m2QE7Dk1jate681xM1ozCGLJ2qAS2OOBSWNzfXA8q5ikVyMnePaly6XKvrYztVdXyjj7w2jH+frXpmhQvBoNhE5yywLk/hXnGo2TXF0oRgCcDJ7e9ei6HeLeacoWJo/IPk4bvgDn8a66UlaxxVoPWXQ0aZKglheNhkMpBFPorYwTscvYxxMrwyKMq5wPbOatxJCt4VQKuxCTjjmqt/C1pqrkHIk+cf5/Cse7ksb6Y7rkxTAbS0bHOOuDivPcWpWPUjJSjdG3ZRwXDsjhS3WnXaw2qEqozj8qw9Nm07Tj5VrIoJP8WQT+daF9LuRmPXGcHtUtW0KuY8Eaz3blt4I5Ug4weua7fRYjHpysRhpGLmuW8OWH9o3FyzyFYkwCF6kntmu4VQihVGABgCuqjB/Ezir1E1yoWkpaMV0HKYniG3kNst3Cu5oMlgP7tZMWye3VlkEe4fw1v67qEGl6Hd3dwCY0jIwOpJ4A/WvPLgagJAljtO4Z2t61y1opSudmHm+Wx1DhLeLLOHPq1YF7qm8NHE26VzgDPT61lyp4gmIilRVB6lTzVzS9GaJjJIcnpxWOi1N7tm94Y1rS9MuBpV1ciO9uWBjVlOH49emc5rtq8U1+3VvEdtcI5DQRNwPUnj+tejeF/E0WqWKw3k0aXqHYQzYMg7MK7o2f//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-47.png', linkedinUrl: '/in/kevin-lucas-3789d78a4d', jobTitle: 'Therapist, occupational', }, @@ -11475,7 +11475,7 @@ export const peopleDemo = [ city: 'Jonathanhaven', email: 'alexis.hernandez@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-48.png', linkedinUrl: '/in/alexis-hernandez-9b63f9db08', jobTitle: 'Journalist, magazine', }, @@ -11485,7 +11485,7 @@ export const peopleDemo = [ city: 'Marymouth', email: 'sophia.wood@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDtMcUhwOTwKdXH/EPW5NJ0IQQcS3ZMe7+6v8X+H41m3Y0Suyj4h8czR3JtdFUSbch5yMjP+yO/1rk7jxrrbMyG+k8zPIVRj+VVNC0zUdXkEVrIVLdcKMAe9d9D8NgbNhcXOZXA+ZRXO6mup0RpXWiOXh8Wa0sayreXC7eu8BlNdx4d8Y2mtbLabEN7j7v8L/7p/pXGXvgnVtK3yWtxHIP7jKeRXLXEk9ldrIoaCVTnjqjex9KIzd9wnT01R9A4oxxWN4U1k674fgvJMeeMpLj+8O/48H8a266DnCvLvik7tq2nxt/qlgZl92LYP9K9RFcF8RdK+3XmkOjYfeY2BHG3I5qZuyKppuWhueDNLh0/RYdqjzHUMzY5JNdTI3ygZrj9Uvp9KtxHa21xK23jyztUYHr6+1ReHdQ1W8uEiu/M2sA3z/wjsCa4rNrmPQTV+U6e7XchHHSvK/G+jspN5CvA+8BXSeJdV1K2mkitVkZU5Yp1NZ6TvqdpJbzRTI+z5hI27OR604pr3gk0/dE+FV5IVvrLrENsq+x6H+n5V6RXnnwwsHtkv5HxyQg/M16Ea7I7HnTVmArP1iyF5arwN0bhwT7HP9K0BTJU3xMuSMjqKJx5otBCXLJMgtZo54QjqDx3pHuLO2uUj3JGMjJJAyfSqkSGOUqD09arXd/ZMoSWwnmIJIYRcA+oJrhSd7Hqq0rNC28tvcahcx7kdSxwRz+FQ6j5EKlI0UE8cVnw3trHcOILWaAsc/Mn8zUxje+uFTcVyDlgM7feizvYUmoptmn4XtFtdLOE2l5CT781tE0yGMRQRxr0VQPrTjXfFWVjy5y5pNjh0p2M0iqW4UZqrd2vmvE8rMY0JJQEgH3PriplUjEcYOTsU75SJpHj5HGcVXL2c8WJ2P8Au5xWmyKi4wMHmsjUbNJI9yDnuK4XK7uejBcqSKN0LaIEQE49CasaHc266gYZ5kSWRf3SMcF/XFZ8cGzqMn3rM1eBZfKPIdJUZGHVTn/DNVCVpXFVXNFo9K6DFIawtL1eaSMpcgOU43jgmteK5imHyOPoa7YzjLY85xaP/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-49.png', linkedinUrl: '/in/sophia-wood-e6ff6bda50', jobTitle: 'Database administrator', }, @@ -11495,7 +11495,7 @@ export const peopleDemo = [ city: 'Jeffreyview', email: 'lori.hunt@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDduIQENYVzGdxrprlcKaw7hQWNIDL8o1QutRtrZzHuMko6onb6mtc2st/dx2EDmMyDdLKOqJ7e56CuhtPA+ixIm2Fiy/xM2c1nOoouxpCk5K551Jrcy/csuPUv0/Snwa7byqBMphOcZ6r+deqyeHtLdCrWkbevFczq3gPSpkcwIYnxwc5FR7buaOh2MEMGAKnIPIIpADmsW2ebRdV+wXBLQu20HrtNdIIa3Tujnas7HY3RBQ1hT53Gta4fKVkyctQBZ8PpvubqTHPmBM+wA/xNdbGPlADV5jq11NY20ghiupDLISPIbbg4GefwrU8IXGrS3CWt08pR4/NBkbcQPQ+h9q5JrVs76b91I7xwccHNZd+7LEwA5PQ1wniS41ldRLRNdyxA/cikKjGcYwK1dOvL5pfss9tMAOpL71P0NQ1pc0vrY5XxC26/jLJhg+DkVvxfMiH1Aqv4l0ma81SNbdAxMeSScAYPc1dhjURoEcOAAMjPUcHrXRSknocdaDWvQ15skVUKc1ecZFQ7K2MC1p3kSxvBKinnOGHFXLa40+zu5l8yOIpHwOnXvWMwKTIy8cYOKp3l9o10R5kE0rp8peKMk9eme9cUovnaPRptOCOltZbG9Bj3xScZDKQwNOuJbazjOxV49Kw7PVtJhjFtb28luzNwrQlef5VLcIZW+c8A/nUNNaGhCPMvHZw5icHcjdsA5wfY0SIiyttUDJLHHqeTTo9+52RyFPGPpSrEc5NdFGm0+ZnJXqprkRcbpUZFLuyKkgtprmTZDGzt7DpXSchVuIy9uxQ4ZeRVWO0iu1BN40JAxheDWjqthfWmqWtupUWjwF5nIyWfONo9qxNW0+QOJYJChPB+tctZrmsduHuo3NERRWkJX7V5hPeqJui7eXG271NYlrb3tzcmKSXjvjjNb1vZCDgc+9Ys3u2aVrEFt0+lThAKrabO15BdERlTaT+RJ6ZxkH8qtbuK7o7I82V7u5//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-50.png', linkedinUrl: '/in/lori-hunt-242e73a5d1', jobTitle: 'Financial planner', }, @@ -11505,7 +11505,7 @@ export const peopleDemo = [ city: 'West Alicia', email: 'dennis.stark@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0rFFLRikBm6xrFvo1i9zPyF/gB5NeY638SNSuVf7EfskABGE++fx7fhW94uEup+IItOjjIToZGH5kfSj/AIV3Y3W1jLIMjDDrk1nKok7G9Oi5q6PLm1W9ab7ULh1n5AcyktyPXOa6TQPiHq+jQiG4kW7hx8qzEkr64PWuyX4b6PCvMbuwGCSetUtZ8IWRt9sKbXUfLU+2Rp9WkdD4Z8eaZ4jYQYNvef8APJjkN/unvXVYr5pltrnSruRw3kywtuBA5x2Ne7eCdePiHw1BdSMGnT91MR3Yd/xGDWqdzlasdBQKWgUxHHshl8T3jPy8fyj6dq6KEFV4P5Vy/iAy22tXjwecDKsf+qGW3YNL4Zu9TudyXvmKnlllaRdrfQiuSovebPSoS9xI6iQkKRmsbUT8h2jkCud1GbXBcSSxvPJCgyI48ZbnHFW7Sa9uQFmimTjOJcZ/MVHLpc15tbHEeKijN5jY3MMMMdK6v4RrKtnqW7iMtGQPfB5/LFYniqwZ7mN4wTu4YCuq+Glj/Z1rfwSyM1wxRyCMALjjHrzmumnJWSOCrTldvsd1SikpRWpzmXfLEb3a6jLIDn1wTVYSQJHcHzY12jbjIFSa4pWW3lGcYKn+dcxctpF3O3nsxbgOqKxDY7HHBrlmvfZ6dB3pq250di1rc7oyyFxg4yDxTrxorZDsHOKx7O70qICCzKx5PC7Chz+NW7ojBJ+9jv2qHpobaGDc20dxdI8oZiCQAD611Ph+38sTTEc4EYY9wP8AIrkrm6mhkZ7eMSyqDtQ/xHsPzr0Gwt3t9Pgjlx5oQeZjpu7/AK1pRjd3OXEVEocvcs0YpaWuo4Cjqlo93YukWPNX5kz3Pp+Nc7FB5qqfM8pujKOK68sqqWYgAckntXA+JbqKa+WbS5hllO8qflcg4JFY1YX946sPV5Xys2GVYITmVX9yKxLvUC4KxtvZj1FY2/WZ5RBMhVDxuJ4/Stex0x1dV2mWRuAFFYNanVzXILaVNOljvLlWdY28xwgycLzxXe6Nq9pr2mRX9kzGGToHXDD6iuI8U3MOgac0JZJdRuE2hRyIkPU1h+C/E/8AYV08d0WNlMPnCjJVuzAV10qbjHU4K9RTl7p//9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-51.png', linkedinUrl: '/in/dennis-stark-aac95d0674', jobTitle: 'Quality manager', }, @@ -11515,7 +11515,7 @@ export const peopleDemo = [ city: 'Port Juliamouth', email: 'robert.smith@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDoSKSnGkNIZDPPFawPNM4SNBlmPYVzk/jjTUyIEkk9zhQawPFfiOXUbl9Js0O1ZNrAdZCKq2vgDV7mFWkKRgnO0tkisZ1LG0KTfQ3IPHMzzfNawbD90Bzk10NlrUVxHmdfJbODzkfnXDP4R1qyO0bWi7qDmo4xPp2+3njKsQWUgcHHb61n7WXRmnsV1R6iMEAg5B9KXFcN4a8SbL1LGZy8Mpwhzyjf4Gu7xXRGXMrnNKPK7BUNxIIbaWXONiM2foM1NVPVP+QTeZ6eS+fyqmJHCeCtLFxetqUwzKeQG7E85/L+depQoVQcivLINtno8bEzSK7kgQ8E+g/IV0fhm4uGuFgJnETLvXeeRx3rgmm9T0qbSVjsZEGCSR+Ncr4h01Lu1YptEo5BFZOtyXMk3nMlzPEGOEhYjGDjtU9tceWCiwTpg4KOxb8RU8uly3K7seeuXsdRWRT+9iYHHrivabWdbq0hnT7siBx+IrxrxAgGuXCRqy7hlVYYOetereGCzeF9NLDB8hc12Utjz6u5q1FcQie2lhbpIhU/iKlorUyOc0C2jFjFC67XQY57Grz6hZ6TqDLIrljGSpVSRUP3NRlCEY3dqrXPiRI7sW8OnTXR5y4U7QfrivOs7tHrRtZNF/SZrfUN7oZUD/NtdSpB7jnvVm7EVrESFBbsc5rOstfS5YwvYzW0m7GGjO3PqDip78ZU7j0FJqxWhy91py32ri4ljU/L+7crnD89RXbaWrLpVqHjEbCMAqowBWHpYguruS3V8zR4Zxj7qnp+ddOBxgV1UE92cOJcdEtxtFLxRxXQcpl6urQxi6UcJw+PT1qC3gtbiIN55QHoVOKm8RahBZacsUnMly4hjUdyT1+grj5kurd/3ZbaemDXJWiua53Yeb5TsXEFpDnz9wHc1kXd952I423E9cdqyYYLy5H70kr1wTWnb2nlpux0rB6HRds2NA01bWKa6JJlumDsT2AGAP6/jWziuI8G61ONT1HSL2QkJOxt2Y9jzt/Xiu3Jr0IfCjy535nc/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-52.png', linkedinUrl: '/in/robert-smith-31ba372c60', jobTitle: 'Estate manager/land agent', }, @@ -11525,7 +11525,7 @@ export const peopleDemo = [ city: 'South Linda', email: 'megan.hughes@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-53.png', linkedinUrl: '/in/megan-hughes-d7607985f9', jobTitle: 'Materials engineer', }, @@ -11535,7 +11535,7 @@ export const peopleDemo = [ city: 'Jamesberg', email: 'kristine.osborne@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1eiiimIhu7u3sbWS5upkihjGWdjwK861v4mSPuh0aAIucefMMsfovb8ax/H+vyajrUllHIRaWjFAo6M/c/wBK4xn5O39DyahstI73TvibqcEqrqEENxF/EVGx/wAO36V6FofiLT/ENs0tjI25Dh4nGGT6j096+enbJ/iHsTV3RtavNC1KK+tGbdGfmUnh17qfahMGj6Moqhour22u6VDqFoT5cg5U9UYdVPuK0MVZA+oLucW1lcXB/wCWUbP+QJqesnxQZB4T1cxHEgs5dp/4CaAPG9L0savO91dSEQ7iW5wXOeefSu6stKs4IQLe2g246qoNcdbrHFo1mHhaYPH8qL3OM1taJIbZ4wqmNJMHaT0zXBUbep6VKKjpY2bzT7OWMi5gg2EfxqK4HX/D8Vhm7sWzD1ePOdo9Qa6bWW+1u7+V5yxjO3ucdh71TVlu7Z42gaH5cMhHYilBuOqHUipaM6D4VXvm6VeWmQVjkEiY9GGD+or0CvJPhCZrbVdSs5lYL5WY2PQgN/8AXr1uu6Ox5slZi5qpqloL/SbyzYkCeFo+PcVapM4qhLQ8y06CMILeRctHheR6VZme3TUoIGljjPXnjNN1Szl03VXActvYsGK4yM/rVP8AtC1aUiaAysODhM4rzXF8zR68JJxTRfs2tZ7uZUlif5iAQc8+9GqLDFCdqgH2qouo2yyBI4/LJ7FMfrUWpMRG00rfJGpb9M0mmnYbasze8DWAhmnuI8qu3y2HqSd2f8+tdtXmfw91tNdFzaXDyWdyjLMkUUnEiYIHPU85Jx2xXpS5xycn1r0KatGzPLqyUptodTTTjUc0scETyzOscaDczscAD1NWZmB4vtRJo5uh/rLdgQR6EgH+lcbZKbgArKqkjr6e1ZnjnxgNb1GyhsHkSxtZ9zMTgTHIGceg5xmmPDcIyS2s3lh+uema46/xXO7DN8pvzwm3Xe0isfWsPWrwvpF2QQVWJsk9Dx0qN0uDue+vlMScuR8qgVg6rrQv1NnZRsLUDBc9X/DsKzhFyloa1JpLUtfC1XbxXZ/abUMpJaI7thRgp59SMdq9/FfONlezWM0dzBKUaNgUkU87h6V6t4f+IUN4Vh1aNbV8ACVTlSfcdq7k0QAAAAec0f/Z', + 'https://twentyhq.github.io/placeholder-images/people/image-54.png', linkedinUrl: '/in/kristine-osborne-bb389c0df3', jobTitle: 'Dietitian', }, @@ -11545,7 +11545,7 @@ export const peopleDemo = [ city: 'Lake Marcus', email: 'brandy.thomas@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-55.png', linkedinUrl: '/in/brandy-thomas-9d8f298d17', jobTitle: 'Copy', }, @@ -11555,7 +11555,7 @@ export const peopleDemo = [ city: 'Jorgeton', email: 'brad.long@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-56.png', linkedinUrl: '/in/brad-long-f8d735beb2', jobTitle: 'Personal assistant', }, @@ -11565,7 +11565,7 @@ export const peopleDemo = [ city: 'Davisstad', email: 'caleb.stevens@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDy4tRmkI5qxYwCWclhuVF3kevtQ3ZDSu7E1vZPMod2Ecf95up+gq++nadbqDJcO5PbcBmp9O03UdVUyQx7Y8/xnj8K1pPBU05VnaGI9ymSTXLKtrudcMO2tjBFrp0qM8DycD5lLDKmqV1aS2xBPzRnlXHQ11jeBmRd0dy24Vl6ppc2kWo3sJIGOHBHSnCsm7BPDySvY52npSyRiOQqDuXqD60KOa6TlsRYrT0KATXMqk4GwA/iazsVu+GlX7TNn7xUYH41E/hZUF7yPRbO3SC1iiiUKiLgAelWduR8rA/SsLVi0cQQidwq8Rwjkmo9CebzY4yrpGQGw3UZ7H3rzeXS566lrY6FlO0/Nj61jalHFNE0cgDIeuf51k+Ibi4a6ZEjlkjU/wDLPO41ZtN0kfknzQAMFZeoPse4ppW1FKV9DjtTtRC42nIDFQcdu1UlXmtbU43KH5WOxyGbHQdOazkWvRg/dPKqK0ioa73wzawnQ4JGUM8jEqMDIwTk+voK4R14rqvCOsW1raTWt46psJeFj79QP0qK8W46GuGklPXqj0COBZMHALe461RlvLO0vkjkcR5JAIXgkDJ/CtCA4tw38W2sK9v4nTCwzTKpIxHEW571wxV2emn2H2l1Z3N9Kkciu28ryOh61Zu4EiJYfex0xWRbXUPmfLFLCSw+WWMrk+xrWuZTIq5645oaswvpqc9fxINInU8MoZzz1Bz/AFrk0HNdBrOpwS2Yt7YkszfvDjGMdqwUHNdtCLUdTzsVJSkkuiKZ5p0a4YGn7Kuabp0uoXLxQqSUiaUhRkkAdB9eBWzZyrU9LikYQIu7hlHf1FPkSIQ+UX24GAB6VFDbl9PjjfIZY1Ge/SsrUPtlntyd6dAfSvLuj2Umi/KqpEVDB/TNVZ5gkDqDkhecdgKoB7yThoyA3erclsVtJEUfMyEfpT0B3ZxB5OT35oA5qWSBkWN+SkiB0JGMj6fUf//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-57.png', linkedinUrl: '/in/caleb-stevens-f00c3e5dd3', jobTitle: 'Multimedia specialist', }, @@ -11575,7 +11575,7 @@ export const peopleDemo = [ city: 'Loweryland', email: 'matthew.wall@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-58.png', linkedinUrl: '/in/matthew-wall-90d1a29c8e', jobTitle: 'Chartered legal executive (England and Wales)', }, @@ -11585,7 +11585,7 @@ export const peopleDemo = [ city: 'South Lisa', email: 'cynthia.cook@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-59.png', linkedinUrl: '/in/cynthia-cook-25e7c0ba3c', jobTitle: 'Radiographer, diagnostic', }, @@ -11595,7 +11595,7 @@ export const peopleDemo = [ city: 'North Jasminebury', email: 'lisa.tate@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDtmlU1EzA1VMnvVa+u/sdhcXOC3lIWx61BSK3iLxDZ+H7XzJ23zv8A6uFTy3v7CvK9R+IOt3LMEufJXdlVjGCPxrM1O/udZ1KRy7S3ErYCr/L6Vu2Hw7uHhWW7nMbMM7VHSolUjHc0jSlL4Uc+vizWkmZxqVyHY8kP1rqtC+JV5bSJDq6C4gJ5mUYdfw6Gs+88ASRgmKdmx3Irlr6zmsJmhlBBU8GiNSMtglSnD4kfQljf2mp2SXdpKssL9GFWQyjtXjvw41t7PWfsEsuLa7Bwp6CTtj69Pyr14E+lWZjM1zvjTUPsHhq42nEk/wC5U+mep/Kuh7VznjiyN34Wutq5eICRcex/wpMEYPw78PQG0OpyqWmZiEz0AFdzMOf8K5GFGsPCmnQmG5d2txJmJ9gU4znPrT/DV5d3X7uR59m3ePOIJHtmuKom7yPSpNRtE6KZCVPSuH8U6Mt1A8iD94oyMVY1u8ummkPmXJiQE7IX25ApllL9pG0R3UbADKyvvBBFKKcfeRU2pe6zza3nktbmOZGKvE4dSPUHNfRlpcC5tIZx0kQMPxFeCX+mSnxBNbQR5+fIHbB5r3mzi+z2UEP/ADzjVfyFd6aZ5kotC9qZNGs8EkTjKupU/jUmOKULxQSV4oY/7KhtnwfKQIc+wxVaKO3jWYQqoCjGemTVmdDuJzgEc4rBvLnT3j4EwYZG9FPrz9a8+SfM0evTacUx1rFFLI0cijPbPen3kEVsh2AD6VmWt3ZxOY4PMDE5AZTmrNwxkALH61DXQttGRZ6e0upyOEz9oYIT6AV6HwBgdq4/wgJ57u5upZ90JZkhj2j5eeuevb9a7LFd9KLS1PMr1FJpLoAHFKMCnpG8h2opZj2UZq/DoN7Ly4WJf9o5P5Vq2kYWbMm6iLwEr1FY91bRzwgNMEK9PWui1Kza11A2pclNisM/xZzk/pWHf2UcnzHIPqtcNaScro9HDqUY6mLNElsmFcH1NU5JGaMkZxjr61afTSJsNKXXsKLmEJHtFZG7dzodK0qDToAYUwGAJNaNc9oMl5cXMVpDIRCnzOCMgL/SunlsZ4hnbvGM/L/hXdCpGSPMqU5RZ//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-60.png', linkedinUrl: '/in/lisa-tate-9456c0ae0b', jobTitle: 'Lecturer, higher education', }, @@ -11605,7 +11605,7 @@ export const peopleDemo = [ city: 'South Jeffrey', email: 'gloria.chapman@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDvAKKKyvEOtw+H9Fn1CZS2wYRR/Ex6CqER674o0nw5ErahcYd/uRRjc7fh6e5ribz4wwifZYaRJJGP45pQpP4AH+deZXt3f+ItVluZC81xI2cDnA9B7VpW3g3V54txg8sY6N3rOU0t2XGm5bI6u3+Ml8t1/pelW5gJ+7E7Bh+J4Nd34Z8baV4mj2wSeRdj71tKw3fUHuK8UPhLWgCPsrEDnJIrJAvNIvUfDw3ETBlYcEEUKaezCVNrdH1LikrI8MaymveHrTUFPzOuJB6OOCPzrXqyABrjvie8SeCLjzACzSIsfP8AFnr+Wa68VwnxahaXwpAyn7l0pI9cgik2NLUw/AWkQ2+nC5MYaaQ5yR2rvgoKKQoLVw8jtpumQQolyQYgAIeOg9aXw1PqU18scss/kNz++OSPQV50ru8j1I2SUTsZYx5ZG0A157430+KXT3lKASJyGA5q74lur1b5ljkuPJTr5JwTVZpP7Q02eALOCImBWbkk465pxVrSFPVOJofByfdp+oQGU7kdW8s+/evTia8x+EECx22oyGFg7Ff3h9OeP0r02vQTPMaswFYnizTxqOitGeSrZA9yCP61sg0y4hW5t3hYkBhjI7VM1eLRVOXLJM5vTGgltVimRSeh3DpSyXFhb38cKNFCoPfA3HqcetV7m1NhetEHLDAOTxmqF1qNrIPKbT5Lgpn5th4z1IP+FebZ35T14tSSaLaSWc9/MjtHIrMRxzj61FqUVtBGVhUAngYrNt7y2SUxi0kgLdypOfqa0LO1OoX8cLs2GzkjqBT5XzWJk0k7mj4Ksmtba4cjAO2MAd9uTn6811NQ21vHa26QxjCr+vvUtejCPLGx5dWXPJsQEYp1RL9aUvtUkAscZAHeqbISOc8TEreRkcfu+fzNZIt4ruH57nZ6Y6ir0tzNqciy3CRoxTbtTJA596w72xni3NA3Q/drzZyUpto9SlFxgrkstvHbLhZ9/v3ra8JnzL64JH3Yxj8TXMW1vNJ80xOfStTTtQudLuJWtYo5XdQoRyRuOeBkdKdOSU02KqnKDSO+NJmoopvMRS6lHKgshPQ46U4mvceY0f/Z', + 'https://twentyhq.github.io/placeholder-images/people/image-61.png', linkedinUrl: '/in/gloria-chapman-c537bef76d', jobTitle: 'Building services engineer', }, @@ -11615,7 +11615,7 @@ export const peopleDemo = [ city: 'Victoriaport', email: 'connie.lewis@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDmGBqG4nSzt2nlztHYdSavCPJ6VyGv6i66hLBjdHHwBXHFXZ2yfKh8+vXM/EUflDPQDc1QyX10FBkujz0IyMfhWdb+dnMand2APH/160Y/Det3Ee9bMlWGSCa10RkrvYaNYubWQOXbPQjOQa3LHWo7hdkxWNsZB7GsgeDtXaJne3O1RkDPWseVJ7HMUqGNu+SaGoyBOUdWd/8AeUMDkHuKRV5rK8LyzXFnIsnzRofkb+YrdEfNYvR2NlqrltV9K8815kl1y6dBkbsZz1I4r0VAc1wWp6Lcxa60ez5J5/kb1BP/ANenTeoqqdtDtfB/g6EW8OoXLFnYZEeOBXeNAqIoVR6YrA1G7m0iyWG3guZCEwBDwBgdz/Sqfh/UNXvbtIbln2v82XHIHoSKh3fvHRG0fdOiuE2wnAHPrXmnjewja1M4XDqeTW54k1fUre7aG2EhWM/M0Yyayb+aTU9Luo3SbzEjORJg89eCKIppqQqjUk4mH4Nu2+0SWmR5ZUuB7iuxA5rj/B1i3nzXTKQoXav1712IGKqp8WhjTvy6kyNg1I1gmoeU4UeZBIJN2ecDt+eKhA5qZJ5raOSWD/WBDtGM5OKg0TtudbDcRyxeWyggjvUC3VjBdiJWjjAIyzEDcfQVVsiZrWN+jMgJHocc1TvtV0+CNYDp89y/PziI4B7ndUq7djo0auMSW2l1W4RijqzHBHPPpVXVlhSN4okA3DHFUbXULI3EiQ2ctuxP8SHB/GpJw0suc84NNp3sJtJFewtBZ2SRAYx1qfvT29PSkApmA8VNEMsKIrWWeURxIzuegUZrai8NXcccMszLGCx3rjJA7D6mmk9ybrYhUmG2VhwnfHaklgguYc/aSg7Y61pyWypCUxx6VhahY/JuiJUjqBWd9ToV0jPu4YrckrMZD6nrTbVvN8xvTAFV/IcufMOcVXCzJdRyQyEDeFeM9HUnH5j1qlqyajdrmmcUgNTvYXHVE3j/AGar7HUkMCCOoNW4tbmKkgAAAAAAHsf/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-62.png', linkedinUrl: '/in/connie-lewis-c6b975976f', jobTitle: 'Insurance risk surveyor', }, @@ -11625,7 +11625,7 @@ export const peopleDemo = [ city: 'Dylanberg', email: 'gary.harris@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-63.png', linkedinUrl: '/in/gary-harris-619dfa4ebb', jobTitle: 'Research officer, trade union', }, @@ -11635,7 +11635,7 @@ export const peopleDemo = [ city: 'Lake Daniel', email: 'sharon.berger@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-64.png', linkedinUrl: '/in/sharon-berger-2da41916fd', jobTitle: 'Therapeutic radiographer', }, @@ -11645,7 +11645,7 @@ export const peopleDemo = [ city: 'Steveborough', email: 'michael.russo@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0+kzjk9KWua8cagtn4ekg8xkluv3SlTg46n9OPxqSjM1z4mabpt29pYxm9mTq6tiMHuM98VwupePNZvL5J4tQKBGDpDGuE49Qai07wtPfRGWMDYTwSuM1o/8ACBTP8z3Ko3oFrJ1Yrqbxw82rpEqfFbWLOSJru2tZ4jkMoBQ59c813PhTxtZeKvNiSFre6jXcY2bIZfUGvONQ8CM0ePtG7GCRjrisKzuL/wAIeJLW9jXMcbYcAfeX+JfypxqRlsTOhOCu0fRVLUNpdQ31nDdW7h4ZkDow7g1NWhkOrifHsXny2MbfdIbB98j/AOtXbVy3jG1Fy9iORtLEntg4FTN2RdNNysiHTYY4LWNEAwBxVqRxn7tYmpT3FoMW/mZVcqsabicevtUWi6vqN84iuo1Q4DfdwQPf3rgtpc9WL6GrdH5CAoOa4HxKI41LOo2twa2tb1u/WaS3s4ctFkswGfy9a5u8M2oWs8MuSQmcuu0g/SqgrNMirJNOJ6r4GVB4L03yySnlnGT0+Y8V0NYvhAIvhHTFSPywsIXHuCQT+J5rarvWx5bVnYcKyPEEJkghkAyEY7vpitcVHc2yXUBifOD6HFTOPNGxVOfJJM56OJZY1bjd6VVDQee0cWzfnBPAyfanFZI4pNv3kBGPcVzl0Lu4iyLeVSBlGKj5ff1rgSvoeunpoPURJrs8chUbzwe2fSoNYWCFWRFCs3X3rDuI57XUDNFDKxJG7I5J/OtqKybVdZs7SbcvmMvmAdVGMmq5dUiJTVndHouhwiDQbGNRgCFTj6jP9avUyGFLe3jhjyEjUIuTngDFPrvSsjyZO7uSCsrxFqTaXolxNCwW5KFYcjPz44/KuV1Hx5czSNFp0Kwp/wA9JeWP4dB+tc9c6hcXrmS4neRs/wARouHKamgajc3nh62urppHllTMjHqWzyTWo9zbPAA5BVh0zyPauf0LUYbRmsbhgkbNmJz0BPY1rXul210ufNeKTsVOAa8+acZu56lN3gnEyNWuraKNwowQOPX6Ve8C6npb6tcG7ukjvwgESyEKCp6kE9TxisG50xIpCPNeQryxY5rk74KdTnZewVR7Y/8A11rRs5GOIb5D6SyCMjpSGvnW01jVNMm32d/PERxhXOMfSuw0b4k6pBhNQRLuP+9ja/6Gx//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-65.png', linkedinUrl: '/in/michael-russo-a3ba403e9b', jobTitle: 'Production engineer', }, @@ -11655,7 +11655,7 @@ export const peopleDemo = [ city: 'New Randall', email: 'michael.young@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0rFGKfiuX8a+LE8MacohUS6hcAi3jPQerN7D9aGwWptajq2n6TD52oXkFsh6GVwM/QdT+Fc6fiZ4UEm3+0mPONwgfH8q88j8Kal4kl/tLV9Sd55RnJGcD0HYD2FaEfw8sEj+eaVn/ALwwK53iYI6o4So0ep6ZrGm6zB52nXsNyg6+W2Sv1HUfjV7FeMweEbjRb1b7S9SlguVOVIXj6H1HtXqXh7WRrNgWlVY7yE7LiJeit6j/AGT1FaU6sZ7GVWjOn8RpkUYpxFGK0Mh+K8Z8aOdR8e3SuxKWqJCg9OMn9Sa9nxXker2iy/EG8kBDwzSKysOQ3yDOD9RWVZ2ibUI80zotNVY7eOPHIUVclVsDp9K57U2vFAhto5TuGCyNtA+prD0CbVnvUimadYpCSQ7klRnv6V56jeNz1nO0rHa3ETPEccVQ0G6Nj4rtl5C3QNu49eCyn8CD+dc54nvtTjvntoDN5aYJMZ559K0/DIeXWNO8923Q3GSZDz91u/p0rWirNMwxElKLiepminEUmK9A8oZdRNPZzwoxVpI2UEdiRXnSQqgWMRhBa7UQEck4+Y16WK5zxDpW23mvISiqvzuuDk884rnxFNySa6HZhKyheMupnQyJNFgfK+PTg1UlmsrCUI8kUZOC7uQOSeAKktGTBbqe1Zd3qFncb42tZJ2VssUi3YP16VwpX0PRbsPuDaXeqsI5YnJA4BBI/D3pt1ZrMy2sLbXlITPoc1krc2cVwRHA0DnAG+Pbn6V0fh63mvdZilEe5IiHkJPT0/WtVB8yRnOaUW2egKuxFXOdoAzSU6kr0TxhRWN4h1bT7S1exubhUuLqMrFFgksfw96uT6raQ70EqySr1RDk/j6Vz/2Kz1bXLe8vlzMEkjiPZC2MH8MfrTlF8rHF+8rnN+Y1o2JG2qehqU/Z5YDGbkxrjgJ1q7qGmvDctb3a8r6dCOxHtWBrWktDCstrgAdea8q2tmezfS62GzxwoCqTeYv+1XoXhOw+y6StwxBkuQH47L2H+fWvKoY3RC8jcAd67f4eeIYn0I2t7OsbxyuIy5x8pY8Z9q6qCTkzjxUnyo7ykpAQwBBBB9Zwn//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-66.png', linkedinUrl: '/in/michael-young-800f26276e', jobTitle: 'Charity fundraiser', }, @@ -11665,7 +11665,7 @@ export const peopleDemo = [ city: 'Michelleberg', email: 'devin.ramsey@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDe28VwnxB8Stp1uulWTMt1Ou53Q4KJ6fU/yrviOK8I8YTm58X6kzZ+WXy1A9FGP6UAZI5AyCzk8880shQAKhIbuHGPyrqtH8AahqMSSvIIVYZGRk4rfb4WSmMKL9ix/vJxWLqwT3NlRm1ex5udojLA7WxgqeeaveH/ABBdaJqKyQuxiY/vI88MP8a7+L4TxiP97dncOyrxXI+J/Bc+hJ9oSQSQbsEgcrmmq0G7Jg6E0rtHsFlcR3tnDcxEMkiBgR7irO0YrjvhvqH2zw81uQc2smzPqDyK7MCtTAeeleKa5ZM/jq+i253XOcDvnFe19q4ybSA3j611IqAs6uCh5wyDGfx4rOpNRRrTpubOusUSC0hUlVIAXk98VqRqdowQfpXIaxaoWzcW93cIASqwtjGB9RzR4dM6zpFbrdxwMA4S4fdjPb2PtXDyq1z0uZ3sdg4IUnOB71xnjOMS6JdKq78Lkgc9DT/FE1xuZZo7uSJOqWrYP+eaqafYKJJUQXSxlSHjnbd19DQkl7wpNu8Sv8N7ZI/D80q9ZbhifwAFdlisLwdbCz8OxQBcFWbJ9STmt+vRTuro8uSadmJ2qjcWyC6juyoLIdqn+7nOfz/pV4dKiuEzCx9OfyrOtDmjoa0KnJLXqaMSx3EeSAfYjioyIkuFjiA+UgsQMCqttLtQEHjGaqXdxo87IbiZA6NkEOQQfwrhXY9I0WER1CRJCpVzweoz6Uy+SG2t22gAkY4rKt5tIimfybhXkcjJaTk/nVq7Yzsi5zkgUW1sDdldkttGIoERQAAO1TUgGBS16UVZJHkzlzSbEFcT4+1qW3ihsrSVlYSK0+04yMjC/wBaraz42uJJPJ079xHnBkIBY/4Vy8lw955hndnkY5LMckmqsSmenLcta4WRsIehq+sIuYg0bRqccHGaytHu4tZ0eNmwZUULIp7EVFc2V5EwFpchAf4W6V5Wzsz1lLqjRltVgBkkMTMO4A4rGu/E8WmavYw3CboZ1YmT+7jAz+tPit7uaTbdTBwD0UYFcn4yKSa3bIpy0MRz7ZP/ANatqOtRGNeT5Gz1KOaOVQ0bq6nkFTmn5rxSK7mt2SaGV45E5BU4rqtK8cXS/Leos6f3lG1h/Q0Fd9jzj//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-67.png', linkedinUrl: '/in/devin-ramsey-428f24b810', jobTitle: 'Educational psychologist', }, @@ -11675,7 +11675,7 @@ export const peopleDemo = [ city: 'Keithville', email: 'sara.lee@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-68.png', linkedinUrl: '/in/sara-lee-becddd74f2', jobTitle: 'Equality and diversity officer', }, @@ -11685,7 +11685,7 @@ export const peopleDemo = [ city: 'Port Stephanie', email: 'robin.stark@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDhSKhuLhLOEyvz2Ve7GrmzNcnql79pumKnMafKg9vX8akole6lupA0rE5PEY6V0EJthpm4tHFgc5H+FcjbyFpOenet6wubaTdG5ABHGef8/WsZpm0Gik99Jlo4Lh8A5HGAa0bS6eS2EjHcucEjtTLfQLnUb1vs4yoPLZ/lUtpp82n6hd2VwoB25B7HNHOlsPkb1aJ91APNMj5X6cVKFFbJ3MGrMbrt19h0xsHEsvyJj9TXGA9M89zW94tkJvoIsHCpn8z/APWrBUAjGTSY0KrbVI9eta2haZcarfqkKnaDl27AVVisMoCwcsx+VQMZ/Gu28NvdaYYIRHsinw2MA9fU/wBKyqStHQ3pU7yVzuvD2kxWUQSMbSoyeOT/AJ4rlviNA1q8d4i7S42sw9a1PFF9qelSL9kkmUbQW8oAFse5rM1aSfXvCt350VyktqnmnziG3EehHtniuaKekjrm07xRyVhc+fKy+o3VoAVz+kNi8X3BUj3rowOK7YbHnT3MDxbvXWk3fdEY21l2ERkuEJXKBhmuy8U2lvPpbXLjEsQ+Rv6VwaStBIjI7DkbgD1ptXVgi7O7PW9Eis3jWOSFGI45FX9QSOO9tYo0AG4E9gBmsuyTBilU8EA8VLeXVnPeol1FNI0ZHEanNefuz1ktNDvWitppDHcxxv0KlgDWZ4kkt7fw9fJCmAYGUKB1JGKg02+02RTEsc0Upx88qEFsdOaxPH+qSaboqRxFfOupBGuRnC4yT/Kkk3JRCdoxbZ5dpxddRHoGGa65RxXPaJas0plP3cZrpFAAFejE8mZJr+nXN5phit9pOcsrdx7VwraTJ8hDoSWxtDAkfUCvoO98Nw7G8rIOOSRxXD6/4dELR3lvGAhbbMAPut6/jUSk0roqEU3ZiWB22yoT0AxWna2cN1IDLIVYdx1FZ1vEwQEDoOlaFpa3Mrfu8KPU1wXPUSsb8UEFnF8kxkz3bk145401ubV/EMgHENqxhiX8eT+Jr1tbYwQELy+PvGuXPhdI7E6hDaJLGXdZHC5KsDzn2PXNbYezk2c+Kb5TnNJtjFZK54Z+celXxxUzIF4AwB0ApmK7UrI89u4AAAAAAAO5/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-69.png', linkedinUrl: '/in/robin-stark-868b21526e', jobTitle: 'Production engineer', }, @@ -11695,7 +11695,7 @@ export const peopleDemo = [ city: 'Samanthafort', email: 'sergio.burns@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD07FYfivxLb+FtGe+mTzJGby4Ys43uffsO5rdrxH4oatLqviU6WrP9mscAIvG6QgZP6gVTYI53VfEur6/KJry/diGysSNtRBnoFHH9aziLmYkwjLrnPPavU/DvgTTBp8JuYPMkdQW59e1dJb+CtGtHV4rFVYA85rndZHUsO+p4B5pglVlDq4wSenPrXpvgr4krF9m0rVyzqxCR3W4kjPTfn+ddReeBtFmQ5swCecg1574q8Gixjaewj3BBkoTgjHcURrK9hSw0krnug5ornfAuqTav4PsLm4JM4UxuT3KnGf0roxXQco7FeH+I7JYviRfL13zK4B/2lBr3CvM7uxa98dWuqSR4julyFI+6UGMH8qzqSSVjWlByd1sdppyiKCNABkKBWkWduorktSN1BvaMXLkKWUQ44x9e/tTvD9/qc0ix3Rl2OoYGQDK+xx3rltpc793Y6WbcOMGuU8RgfY5iBkhG/lR4j1LVFmlS0EpjhG5zFgsfYDv1rOhWWYOrfaF+TLJPg9R2IqWupV/sml8LwT4SZs5VrqQr7Dj+ua7SuS+HSNB4ZFsyBTHKzZz13Emuurvi7o8uSadmLXM3lr5WpmVkG1X/AHZ/u5zn+ddLVLUrZZLdpedyDd14OKirDmRpQqcj16iQBJE6An0NQu0QnEUQXcGG7aOhplqSse7PGM1n3U+lyuqySgSRk4Zc5B7nIrkSPQViwmxdVmikwCx4z3pmqRxxQtgAHHas+KXTYbklLvzJXwMuxyfpmp7vdeTxRZPzsF/M0rdC5O2ppeG4hFpzAKA28hsewFbNQWtslpAsUecDuepNTV3QjaKR5NSSlNtDq4/x14ml0WOxsrTYbi8nSN8jO2MsATj1OcfnVHW/ilp1lIYdNhN7IBzITtjB/mf0rzfVNYudU1MalcPul81ZAB0GDkAewq2nYiO6uesC7a1xFKcIT8rH+VaoRLmHAlCccEelZ1qbbWNKimUB43UGqFxpuo28Z+w3AKDoj84rzkz1dtjRuokt1LFwxA6mn6Cv2y7e4YjbDwPdj/gK57yL+fH2yUD/AGUrAvPFN54a8YA2oR4WtFWSJ87T8xweO9aUknNGdeT5GeyUVwuh/E/StRmNvqCGwmHG5m3Rsfr2/Gu3jljmjWSJ1dGGQynII612nmn/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-70.png', linkedinUrl: '/in/sergio-burns-994728d1d7', jobTitle: 'Fitness centre manager', }, @@ -11705,7 +11705,7 @@ export const peopleDemo = [ city: 'Combsfurt', email: 'lisa.haas@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-71.png', linkedinUrl: '/in/lisa-haas-e3c3871c8d', jobTitle: 'Oceanographer', }, @@ -11715,7 +11715,7 @@ export const peopleDemo = [ city: 'East Amandaville', email: 'courtney.donaldson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwBviHxFDpMBjiIe5bjbnhMjqa4iGW9vZTLdzeZGR1bnBqvqNw93N5srq8hYlmbuTWlp9i08SBOrEZbPJ9gK5ZT6nTCn0KF3BFj55QZRjkjOaI5PsACtIHUjdz29q9M03wDYzxxyXiFiedua1JPBGjKrILUHI7nNR7Q19kzy7S/E0lndB0l3REYdG5r0DT9Si1KDzI+GHDLnOKzNW+HenYkktDJExHCg8A1R8JRNbm7tpSRcQybWHt2NbQnfYwqU3FanW4FNxSijtWpgeJi5JlBwgHcda9A8GeXc3iSbSzKOCe1cVP4Z1PT2BuY49meZInV1J+ozzXqngzTorfR45EX95J1buRXHNq2h304u+p2UMo25/XtTpHRujqT7GuZv9QubWQxx2MkqHq5GQP1xXO6Ql5qmrGSK0e2Q/MSTggZ5yMnH0qFtc362O6u4w0RO4DNcdbaeY/Et3dfwtEnIPBPI/kBSeOptSskt4LXzGhdQXZOvXGKXwwC2nu7RNGd+whu+O/vmtqS1uc+Ifu2NnGKSlNJXScJWhs1uEhhUp/Z6xBThcl8jOc+n+NXtOjaxgiiXlYxjPrXnXhrxhJoZTTLyM3EJfyo3U8pzgD3X+VeiafdG7tkMqeXIR8y/3TXnSi46HrqalqjdWWK6i2MgGeoIqs8tnp0ixqqK0nU8AAVHGrA4HWqN1qmk2YlXUJA7kAsuwvgdhQtS7IdqF5p2oW8P+kwS4cj5GDA/jWdd3sGnFY0iyp6YNZEmoaHc6iqWweOSXopXaPYiotRd95X7zR4remmpnNiX7jNiHUoJiBnaT2NXQc9K5BAsse6N9sg6qTWhYapIg8uXnHeutHm3PKrieaO+h3xGNY5FPI9CK9zlDW5SdPuMOcVzsHgWC4sjfXrNJNHMm5TwAM8gj8q7UwI1usbDIArgqO9j0qStcggvA6gowJPfNXBEzQGNNp46n19a5zU9O+ztuiLIfVTWW3iC/szsVt/bkc1EVqa8xrXlhNC+ZNjLnIOOlYF1FdR6pJ5qMgk4wRzjtWjoeo3PiO+lRgyxwSKrMOjHqR+GK7s6bbajbFJ41cBiFJ6r9DXXTg92ceJq87sjyeazdX3B8GnW8mw4wc10niPwrNYIZ7YvJCTz6r9f8a5yZ//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-72.png', linkedinUrl: '/in/courtney-donaldson-dd063d66c2', jobTitle: 'Sports therapist', }, @@ -11725,7 +11725,7 @@ export const peopleDemo = [ city: 'Jeffreyview', email: 'ashley.conrad@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-73.png', linkedinUrl: '/in/ashley-conrad-96b6f83928', jobTitle: 'Manufacturing engineer', }, @@ -11735,7 +11735,7 @@ export const peopleDemo = [ city: 'Bentonland', email: 'tim.levine@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0nNJTc0u6gBayNS8UaLpSsbvUYFdf+WaNuc+2BXK+PddvZ54vD2is5upRuuGj6qvZc9s965KD4dX7qGurxI2P8KDP61nKokawpOWp6jYeMdB1KSKO31GISyfdjk+Vvoc963K8Tufh5PGu+C9ywHRhWp4S8XahomrR6FrrFoJDtimY8oe3PdT+lEaiYTpOOp6zRTQaXNaGQzNZ2u6g2l6HeXqAF4Yiyg9M9B+tXs1geNXK+FLvHIJQH6bhSew47mP4WsfJ09r+5bfeXbebNKx59h9K2TPDL/q5VbBxwc1z99FHFYwRTpNIqRDEcYOM45qHQEWScbIHhj64IwfxrjavqejHTQ37iaGNf3kqrnpk4rj/ABbYw3lg0qgeZH8yMKk1v97dSeZA88Sfwr1NV44I7mymjhjmiBjIMUnbI4oStqEnfQ7rwNq0useFLWed988ZMUhPcr/9bFdGTXn3wodjoF8pUgLdkZ/4CK70muxbHnPcZWH4rie50lYBjY8oMn0HP88VteYKq6iqzWhDdAQTUz+F2LpW51cq+VG8IyBjGORWVPqFtYzonlPhieUXgYGck9hV1nIgZgcgDNY9xdLLHgQzOB6IQK5Urnox10RBZXlvdXU3yt98gh1x+XqKt3qxRJ8oA47VkG4CT/LG8ZY9GXg/jVmeR5tqgEs3GBySaGgbtuaPgG3axsr63HMbTCYH3bOR+grr81jeHrN7KxfzEKNI+4KeoHv+ta+8V1Qvy6nnVbc7sRgUMRHG0jkKijLE9BTsgYBIHua0VsU2NFL86Srtb0xTk7ImKuzj72ZXuHWOQMjHqP1qK4iEsW1pdn0q1L4fmsvOidmli8wtHKB90dgfQ1z9/HeW8n7tvNXt61yrV3Z3J22FnTyQQJA2O9WNAiW81VTnKwDzD9eg/X+Vcw899c3BiwVzwSe1aFppsst3bxoZBGGDPIMjOOetNaO4pvmTPSMUYqtHO2Bu5U8A1OHHGTiuiMk9jicWj//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-74.png', linkedinUrl: '/in/tim-levine-01557d92c6', jobTitle: 'Animal nutritionist', }, @@ -11745,7 +11745,7 @@ export const peopleDemo = [ city: 'Port Erinburgh', email: 'michelle.martinez@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-75.png', linkedinUrl: '/in/michelle-martinez-905bf6439c', jobTitle: 'TEFL teacher', }, @@ -11755,7 +11755,7 @@ export const peopleDemo = [ city: 'New Jean', email: 'jennifer.rose@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDgieaAaQ0ySVIULOwAAJ5oALm+hsot8z49FHU1m/25dSvvhjRYgeh5NZlvDNrGpBArySO3C+g/wrvtO+HU7bXmulReuxF7/Ws5VFHc1hSlLZHJXOu3gkV49oQfwlau2OsxX58sr5cuM7Sev0rfuvhu8SF0vGMnXla4jU9Lm0q7IuOGVuGXjdSjUUthypSjq0dITmkBwaz9N1AXabGI8xevvV+tDEUjNYGsyb7ny8jhcV0OK5bVnWW/JVtu0d+9DGjuvh5o6JA926gyu2AfQCvVraLYg3L+VeZaQyaXoFmZLR7mSRMom7aoOCSfrXTeGby6jdGZ51huACIpJN+zP16fSuKau3I9Km7JROouEyh+QfU15v470uG4sHmWMeYnOR7Vu+KL6aSR5R58kMXWKOQqDz6Dr1rKHl6jbzRpaNbSRr843blYEfXGaUVb3hyd/dPLrPFrqMb5JBA4HvxXTVy8iP8AaCRx5fBGenNdRCD5SbjlsDJ9a7Uea0S1zmtQD7SAQFzjDV0dZWrWT3AV4gGIOSpPX8KbEj1fQY4jp0dtKqs0QC8+1aU6RxX9rFuRM888Vyng7Vn1W3a6aOOOTzNjJH93gDpWxqGsRx3gjltjMyjJG3pXA0+ax7FO00uU0dPSO4uLhSUYhvlPUGo9VEFvZS7EVflPAFVNN1aCa58lYTC5GQMcVH4hlWKwuJ5D8sSFj+VLW9hyXLe549q9nPp+pSmZdol+YcZBU84rbslItowTnA4NZFxfXviG9Wa52IBgIiLhUA7YreiG1APQV3RTtqeRUavoJ2oA5zTtlTWtpNd3CQQRl5XOFUVZBe8NWsmlxyzxK5s2kwWP8LV2tvFaaiivJtbPfuKNP8Ly22j/AGCWc+dLJ5qsB8qsAPlPscVXutHnspSoL2845ZVPB9x2rjrK0rnfhp+7YvvbWthGzRbR7jvXJ+K1vNX01rGwG6SZgDk4yByRn8K3Us2k5mmkdR1BOKkj0G9vr+2lhieG1jbJm6AAdceuRx+NZw+LQ1qv3Xc8sj0W50q6WK6O1gofZ656Grwr1rxDoFle2Ekj26mWOIlHAwwwPX0ry/7Iy13R2AAAPNluf//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-76.png', linkedinUrl: '/in/jennifer-rose-162f9c1d7b', jobTitle: 'Logistics and distribution manager', }, @@ -11765,7 +11765,7 @@ export const peopleDemo = [ city: 'Martinezmouth', email: 'casey.greer@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-77.png', linkedinUrl: '/in/casey-greer-e3d7510c16', jobTitle: 'Editor, commissioning', }, @@ -11775,7 +11775,7 @@ export const peopleDemo = [ city: 'South Sandra', email: 'crystal.mclaughlin@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD06iiigAzXNa5470bQ52t5ZWmuF6xxjOPqegp3jPxKfDWhTXUUfmT7cRg9AegJ/E9K8e0bwtqniVW1G7uWRJ2Ll2GS+T2HYVE5qC1NKdNzeh2eofGSC3l222mu6EcGSQA5+g7Vnp8XtUZi4sbQr12biD+eaYfhzp6RYaSVnA+8TXKat4SbSpxKkhKe9ZKvGWiZs8PKKu0enaL8WNNvpVh1G2ayZjgSbtyfie1egI6yIrowZWGQwOQRXygXaOUo3K5r0DwF46l0i7j0y/uC1hIcRsx/1RP/ALL/ACrVS7mEo9j2/NGaSirIOC+J1u19p+naarYa9vUTI9ACTWpY2iWttFCiqqRqFVfQAVn/ABEHlSaRdukjwxPLuCZzu2cdPxrM8L3TMk26OeOLaWHm5znOO9cWJu2d+EtynQ3EkW4p50e4dV3DNYWuW0d3ZPC67iVOCKxdTWe1vftEWmrPuOQ5YDqavWclzeDL2rxe38P1FYctlc6b30PKdQiEF0UYEHPQ1UL87fTpXW+OtM8uRbpB14bHrXFgsSTgn1rupy5o3POqx5ZNH15RSCitjApasI2tAkihlZwMGuQv7vT7FWjE8UJ3hSDwAfc12GqRGXT5cfeUbx+FcLJqGmRXbbrQzzjhmWPdXDiE+c9LB2cLLc3NPa2ubbdlTtJB7jiqmoXUUAYR4qC21S0ul8q0Qxleq7CuPwqldx+byTxmuV3TszrSRg6jAdUKxt9zfk5rIutOtYNKvZPLVURGw6ng9Rj88YrfupPJIKIXCkEqDgkd/wBK47xd4mF8f7MtI2jhRgZS3G4joAB2raknJ2RhVlGKcnufSAooFLXpHkjWUOpU9CMGuIuNLRZ5IpLjYUbGAcbvc13NZmp6Haam4lkaSKYDHmRnGfqO9Y1qbmtNzfD1vZy12ZyM8iWy7FkGB3xWPeaiFXaDk+gqvqVleRXc0JZmMbEN/jTLPT5GcPKPlzwPWvOas9T1U77AFka3eZhgkcCvMJYnuNaljC5kaXaB75r2G6iJiWKNCztwFUZJNU9K+HN/beJ7XWJ2iihDqzwMNzE/yFdGGlrFR0R//9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-78.png', linkedinUrl: '/in/crystal-mclaughlin-7b67938d55', jobTitle: 'Chiropodist', }, @@ -11785,7 +11785,7 @@ export const peopleDemo = [ city: 'North Joshua', email: 'rachel.floyd@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDtL6+ttNs5Lu6lEcMYyzH+Q9TXmur/ABAvL0uunr9mt+itwXb3z0H4VjeOvEr63rLWkMh+wWjbQB0d+5/pXO/aFEeM5ycADufSuU6oq25an1K7kdpbi6kJ93NTaf4n1XTJfNtbxvL7pIcg/hWZMhaVY1+ZumfQ+1alr4T1HUgGiHlQ/wB49TS0W5oouWx1WhfE+7kuxDqUEbxE4LRjDL74716bDPHcQpNE4aNxlWHQivFLrwFc2Vo00U+6UDPTH4VrfDnxO0Gof2RdOwjl4jDH7j+n40XT2IlBx3PVzSUGk7UiD5kdnKgZ255JNIk207hyRwD6VBKs4RZJI3WN+VYjAat3wzoUmtzg52xIeWxWjsldlRTlKyL/AIU0ibWNSVSp8pMNI3p6CvY4rVLeEIqBVA4AFcjLnw5p4t7Gykk3cZztUHHUmqfh651O8uvMnd1jf5tqyHC84wQawknLU6o2j7p2l5FviYD0rxjVgdK8amSIFcMsox69f6V33jDUdRsp47a1yofbucEjr/IVwd+kmreINPURSJLMFQ723ZwxHB7inTjbUms09Ox77G2+JH/vKDTqai7I1T+6AKdmqOU8Z0zTrfxD4dtCdq7WxL7FRj/69dHoGnppERiRfl3nB9a838PeIJtBveBvt5AA6HoD2b8K9O0XUhqcYlMXlK+GQZzkEdfzzUVIteh20pxlr1OrgaK4h2sozjoahMdrZsFVUV257ACmRIy4xVLUdV0yzjK3xEkr/wDLMLuPtWSvsdFkyTUI7a6khYvG+5ccEGsBNMgm8b6S6JxCjsfwwR+tRR6tYTX6xW9vLC+3Kqwxj6DtWtou2TxBG5/1ixvk/lWkbqRjWSUNTsKKSitDgPmW8RReyqn3Q5A+leoeD43l8L2jrxLECPwBNcRrXh+7j8Vz6dCg8ySQyRZOAUJ4P+fSvUvDenf2dpqWpbcUH3vU9/1orPRI6KEbybLltfKwAYgMOCD2qxJZRXcZV1Rx2J6iqt1piTsWUlW9R61nGLVIGZRKnlr/ABMTmudHWmNudOhsZBIPvDuWzir3hq2ZdQe5fnzAcfp/SuB8TaxP9qtrSWcpFKGLEdD6Z9q9X0xAYIHVkZfLA3Icg8dvatoxdrnLXq8zsaJpOY//2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-79.png', linkedinUrl: '/in/rachel-floyd-554e320b10', jobTitle: 'Therapist, drama', }, @@ -11795,7 +11795,7 @@ export const peopleDemo = [ city: 'South Joy', email: 'shannon.anderson@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDJJ5prt8uKcRzTH6UACKWOBVe+vhbRloyGCHDGtBGigs3kdSxJAAXqfatOz8EPcIs17KU3Hd5QGdoPYmuarValyo6qNFNczMCyluLmESRyRnd/yzyM/wA6jvmvYBuKMCBzlRW/P4AijD/ZbueMdQFbGK5+5tr3SpxaXErz2sgIYPyR7g9jXM5Nu9zp9mktiGz1lJCIbj5W7N2NagGa4+UATsm4Mu75T6VvaJemRjbynP8AcJ/lXVTqvZnJUpdUaZHWomBzirBFRMK6DnNDR4PtWv21s4BigXzsY++3b8uK9AIbGK87juhb+bcRwSyyrbFQsbYJOV7it7wze3s9oBeqVyjMCWJIwcYOa4JxabbPSpNWVjoJEIU81y/iPSxf252tsnXlT6+xrN1eTV21KJrfzHRm6lztxnHQdK0oZbq4JimhdXQ4yG3K3uDWTjZXN7pvlPLbmIW87LMSrKeTirNtLs2TRvu2sDx6Vf8AGtn9l1GO4A+WVcOPcVz9us0G5iG8rON2OK2WsbnNJWlY74imEc1NjmmuuK7jzze8JCJrq4LqCwQBc+hPP8hW5dtDBFIFaNCSBjpXJaFcG31WPniTKH8elb1+2kSuy3ZWT+8p5BPuK4q8XzHpYV3j6GnZCKWEkYyDgio7yVIEY4HSq1ld2Gzy7SWMnrtB5qK//ejB6Vg+x02VznNTtItTw86gohJAIznisLXNPjghtbaKMfaLlwm1R1A74/ECtrWtVOiW7XixrII/4GOMntz2rH0B7nXNVfWrx0AiG2KFOiE1dKDkzGtUjBPubKrlqbKvNWYk5pkyV6J5RUjYxTpIvVWBFdnbxRXtssyOq5H4muc0/R73U5dtpbtJ6t0UfU1vHTW0vVI9LaUmT7N57svTcWxgewrCvHTmOnCzcZWRI0SWvIWPJ7gVQubjK4U7mPYVfm02eUZWbK98jmohp4gxnlupriZ6HNc4vxPp9xqFtb2cQy8soLH0Fa9jZR6fZRWsQAWNQPqe5q3LZXN3q9lDajMjS4b2T+I/gOasanaNZ6hNCRgBsr/u9q68P8JwYv4z/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-80.png', linkedinUrl: '/in/shannon-anderson-7e555790c5', jobTitle: 'Mudlogger', }, @@ -11805,7 +11805,7 @@ export const peopleDemo = [ city: 'Webbstad', email: 'catherine.white@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDtRS8CiuN8d6//AGfZiwhkKyTDMhHUJ6D61i3ZXNkruxc1PxdDDKbfTws0gOGlJ+Rf8a5m/wDiBqNpO0EX2eUgZJUH5a57TrW81KVVgHzt0I6IK7Cy+H1s0LfaZ3eRx8xXiuZ1HfVnTGjdaIh0rxvfTDdL5bn+43Gfoa7TStYttWg3RHbIv34m+8tcNc+Cr7TMy6fdmQD/AJZSjIPtmsmLVptM1BJwhimjOShPUdxTjVd/IJ0dD140YqCyu4r+xhuoTmOVAwqeug5QJAXJOAOTXguv6o+ta3c3AJZS5CA+mcAflXuGqRvJpF5HG212gcKfQ7TXgOlRGXVrO2A5L7m+gqJmlPc9Q8JaYbKwQvgyvyx9PauytwAmM151f3tzpwEKWs024cAEgYx296ueHhqKXcbsJo7eXBKSNnbnpzmuRxfxHoKS+E7mbBQgmvM/HWlNC638P3Sw3ex7GtrxXNexSsYRO8MfURHk/wCc1lPcS6rot7bPbyxOkRJVzkHjIP1pxT+IU2neJtfDi+M+izWrHmCT5R6Ka7SvLPhZd7tRu4T95ogT9Qf/AK9ep12R2POnuBUMpU9Dwa8jGkGw8RPJ954t25j7k4H4AV672ri/GD22lzRXUobbcyBMgfdbpn6c1FVNrQ1oSSbTNHTrmC6hVZY1b6il1W+s9Pe3EskcUZYZJ478AVlWCtG/yng9Kff65p6P5VxZy3LJ1CxE4/HFcaWtj0dzWtr2yvtQuIkljlXuOuD70mo/Z4YHSNFXIxwKybDWtLaQwwWctqSABvjK5/Gp7piZA7hmUc7QMk0NO9gei1I/B2hR2NxJeeXtdk2/TPX+ldjVPTY1SyRlz+8G8596uV3QTUdTyqrTm2hw6VyHxE0ptR8NtJGMyWziQD26GuvFZGo6xYG0uYVcTuAUKqOM/XpVSaS1Jim3ocrbXHl7QTjbg81qrYwXx8wzsp7FTyKyp7ZxAsoHbmstrue3bEZP4GuDc9ROx1h0+Gx3P55kPTc3JqG2knmuQbdA6qDuBBwwPHWsS2+132POZtvfmuq8Oz2xluLNWxcRgOU/2TwCPxBrSkrzMsRN8ht28flW8aH+FQKeadTTXYeef//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-81.png', linkedinUrl: '/in/catherine-white-759d1e61da', jobTitle: 'Barista', }, @@ -11815,7 +11815,7 @@ export const peopleDemo = [ city: 'Port Davidton', email: 'matthew.fisher@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-82.png', linkedinUrl: '/in/matthew-fisher-4f49bc00ee', jobTitle: 'Systems developer', }, @@ -11825,7 +11825,7 @@ export const peopleDemo = [ city: 'Woodsborough', email: 'tracy.leonard@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0A0lFRzyiGB5CQNoJyago5zXfGdno9x9m2mSTHO09K881XxbeX94bg3DRxqf3aIx4+vvWZp2nXvijXLhI3cu7kyytyqDP+eK9Bh+FenLYBhcSNN3LcA/hUOaTszSNNtXRyEPjK+ihdZZnZHxkE5Jq9pfxAl0uUK7m6tW/gyAyfSuwk8A6Q1oI3jLSBcFgcV5v4g8I3OjvJJCS0APVeoFJVItlSpSSuez6TrFlrVkt1YzCSM8EdCp9COxq+K8T+GOtS2fiYae75gu1K7f9sDIP6EV7YK0MRK4b4k6tLZ6QlvAzB5Gwcdx6f59K7muC+KFtFLpllKRtkWbG/HQEd++KGNbifDrT0ttHMyrh523Ma7zcoUAMPpXCwAaVodnG7XBUQjK2/VjjJ5qXRLuSa7jRXufLfJCzHJHeuR63Z3x0SidjMw2/e59BXOa1As9pJG65LA1kavdSea8zm8kjDYCW77cYODUkNyHwqG4wOscxyR+Pepa0uVfWx5NIz6Vriz27lWilDqM8gg9K+i9Lvl1LSrW9VSoniWTae2R0rwHxVZv/AMJFP5MZGTuAx1717d4PieDwpp8b7siIff64PNdkXdJnnzVm0beKyfEWl/2rpMluAC+Mrn1rXpGwFJJ7VTRKdjn9PAFskMqgPGoB9sCnQTWcV8xcohQHbzyTjk1BhzIzKMFifaqV3eWnEbWkkroCN6p09cGuCzTsepG0ldFqzeCS4dUZH3EsCpB5zyKkuo4YxnHPtWZZ3toJCkUTwyE5AZCP1q5dMWUE9aT7FNHPDRTf6vLI2T5qqi4HQg/5/KvRrS3W1tY4FJKxqFGfauG8JavJqOvzxbIkgg3BMfek7ZP/ANavQMV10otLU8+tNSdkHSjBbIAzxWi21WJ2DA6DFN2lgCVGe+K1uZWPP4NbTVGmaO2MD252yLuyQckYP5VOscM8fM2B16VZns4tL1q7tSoWO9Y3EZx1Y8MP5H8azbuzaF90ZwM8iuKo/edzvpaRViSWOOBRhw30GKpX93ss5pOWCKSccZ9qd5bueTVXU7drmweyh5luP3SAepqFuaSejOj8KWWlf2bFqFjblGmUZMhyy47A10VVNK0tdM0yC0UkiGMLkfxEDk1cKMozjIrvAAAR5jR//9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-83.png', linkedinUrl: '/in/tracy-leonard-b9b7beae66', jobTitle: 'Psychologist, sport and exercise', }, @@ -11835,7 +11835,7 @@ export const peopleDemo = [ city: 'South Michaelville', email: 'jenna.moore@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-84.png', linkedinUrl: '/in/jenna-moore-c17c91ef24', jobTitle: 'Senior tax professional/tax inspector', }, @@ -11845,7 +11845,7 @@ export const peopleDemo = [ city: 'West Edwardchester', email: 'alice.edwards@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-85.png', linkedinUrl: '/in/alice-edwards-aefc82ee0c', jobTitle: 'Engineer, water', }, @@ -11855,7 +11855,7 @@ export const peopleDemo = [ city: 'Reynoldsview', email: 'theresa.orozco@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-86.png', linkedinUrl: '/in/theresa-orozco-4a2ec9a601', jobTitle: 'Journalist, magazine', }, @@ -11865,7 +11865,7 @@ export const peopleDemo = [ city: 'Richardberg', email: 'samantha.hicks@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-87.png', linkedinUrl: '/in/samantha-hicks-16b4d5470f', jobTitle: 'Herpetologist', }, @@ -11875,7 +11875,7 @@ export const peopleDemo = [ city: 'Lauriemouth', email: 'brian.finley@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD07FUdZ1W30TSZ9RutxihXO1RyxPAA+pq/XH/E2Xy/BNwo6ySxoOPfP9KG7K4JXdjyrxF401TxHeNu3w2vRYEchVHvj7x9zWFK6xFRKig5DI6nIyD0NdfoHgybVbYTyzmGNumBywreHw2sAMSSMyHnBGK43VV9Tujh5NaHk8ytFdscYwdyEdxWtp/iC80u586zumjmQDBB4b2I7iu5l+HNhjJmlKryo9KwtX8BJbWMlzaSOxTkhu4qo1Iy2JlQnHVnrHg/xCfE3h+O+eMRzqxilVTkbhjJH1zW6RXkvwk1N4dTvdKk3bZk85fTcvB+nFetmupO6OOSsyWuX+IMfmeEZl9Zovw+auormvF8hudPm09IyflWZm9AG7e/BqaklGOppSg5TsiLRYkhsYFVcDy14/CtOYs+0VzeozXlmg+yxzSYXIEajsO5P8qb4e1DVb1tt9G8akbgXxnnscdK8y2lz2E9bGxdLtG3pxWVesW02aIKOcnp14rC1rU9ZlvZ4rWOQxQDlk6nHYe9SadqF05WG6SVQ6jAlUA5+orWmramVV30K3w9s1HjiaZR922f8DlRXrJFeYaRdnw9r+pXzW/mRvhSAcbQSCTXqGQwyOh5rtptNWPMqwad3sx1YuuW5dlZQdrja+OuBk1tdqZPCs8RRiR3BHairDnjYdCp7OakzHs0juLYBiOmfrVd5LVJhHE0ahSd3IGTimKDbySxbuEJArGu5tOuVCyRFmUFAywscZ68gV5iTvY9qLvqhbNraTUpE3owcnoc5Iq3NDBG4CKB9K5pBp9tqIazWSJy+QJEZcn8a1Dct9tO49+la294yk7RaZWe3kvdejgjUlJQqTDPB/CvSwoCgDoBgViaFpFvEqajl2nlUnk8L24rcPSu2lDlu31PNxFVTtFdBaWiitTnOZ1wGC+eQcKygn69KgZFubYKZvL4yCvHFTTanBqmq3ttCjEWjCB3PR2xnj2GcVjaho2otHnT7hVB/hcdPpXm1UvaM9ehJqmiKe3ELfLPk5781nJKXlPzZftWZd2+uW1z5V5tVMcSK2QR6CtGxh8pFduB6mmtAk3Jnpmlrs0q0X0iX+VW68p0L4hGHxlLYXV+sujuAkLbBiJ8Afe/u5zXqqusiB0YMpGQwOQa9COyPJkAAAAJ/Ez/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-88.png', linkedinUrl: '/in/brian-finley-aa52351d68', jobTitle: 'Youth worker', }, @@ -11885,7 +11885,7 @@ export const peopleDemo = [ city: 'Juliebury', email: 'kevin.black@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDv6UUVz3jTWG0Xw3PLDN5V1LiOE4yck8kfQZqCg1rxnpWjXD2jM9xeKMmGIdPqTwK4W6+I+tNOZEe1t03fJDsDHHuTXM6Tod5rly8iFslvmeQ5ye+fWupPwwebDSXoDY6hKzlUSdrm0aMmrpE1t8SNV3L5y2zg9f3R/mDXY6L4w0/VpFtpGWC6YcIx4b6E9/avOk+H+pW0x2urKO44z+FYOsR3GmzeTIpjdDkc0lUu9GOVJpXaPoUikxXKeAvE58RaMUnBF5a7UlJ/jBHDfjg/lXWVsYCV5t8VCHudJgL8ESNs/Fea9Krzf4pWzG80edE5/eRM+egOMDH50nsEdy/4StI4tJgCAAsNxOPWuwiH7sZOa8+uVntrOGBEuWCRjasBwcgc81c8OXGpGeCKV7jy5Tn98csvsfSuFq/vHqxdrRO0f5QeRXG+LdOs7mxka5gVyAdr45X6Go/EdzqQmlEJn8uE8+SfmP0qpCk11aS28gnXMZ3LMcnOOuaEuoSd/dM/4VSGDxDfWsa/uHg3Zz1IYf4mvWzXknwntZY9fv3kQgLCygk/7Qr1s13LY8t7iCua8ZaeLuzhlBG9DtXcOATjn9K6WoL23+1WrxgDd1XPrSmrxsOnLlkmzD06WK5tUR1G4CpvPtLfUYELxoc55IGT6VkwpLbztC3yujEEA1Fe6hpLskV4w80k7cISQfw6VwpO9j1k1a5sQS2lzezp5kb/ADHGDnn0qPVDDbwMIx8xFZlhe6SrPHZuu8kbhtKtn8anvVedliHLsQo+poatoDatcm8H6etrJK6nJ2YLEcnJyP611RqrptkLK22sB5jcvg5/CrJrtpxajqeXWkpTuthaUUVjal4t0HSJTDe6nBHKAT5YJZvyGa0MjO8QsLHVUm6LKmT9Rx/LFV0gFzGskUqrnocZrnbrxXD4m16UW/mCzjgVY1kGCTk7jj8R+VLHFfQgm1kJCnlCf5VxVVabPSoSfImdF9kFsheWRHI74Ao0q5W4122DOoUMcZ/ibBwBWQtvfTRB7l8A9EBzWb4hFxY6bDdWrFJLa4jkB/4Fj+tTF++iqrbgz1w0w1l6RrsGp6PDfviHfGHdWPC9jz6ZBq7FdwXKboJo5V9UYEfpXceWf//Z', + 'https://twentyhq.github.io/placeholder-images/people/image-89.png', linkedinUrl: '/in/kevin-black-ada9f2fada', jobTitle: 'Teacher, adult education', }, @@ -11895,7 +11895,7 @@ export const peopleDemo = [ city: 'Kevinborough', email: 'eric.peterson@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-90.png', linkedinUrl: '/in/eric-peterson-2e15a4a39c', jobTitle: 'Ranger/warden', }, @@ -11905,7 +11905,7 @@ export const peopleDemo = [ city: 'New Ronaldview', email: 'samantha.steele@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDXmnjt4XllYKiDLE9q4bWfFN1KT5Mj28J4RF5kf39qPGOsldRWwDkRxKGZR/Ex9foP51hWtxGbmMPGGDcsX5J9M+3tWM5u9kbU4K12Vrm4EZCkSKr85DZL/U1RkvJzmQhkXoNp6Y7e9dE0llfapGzIzjOxI0GBx3NdFZeAby/+aXZHbk/KMfMKz5jbkvsYnhvXpVjKLKzFeqt0P0rubO/iv7ZZo8+jKeoNYd54DGkeY1qWZmXj61n6HqkNldfZ3JTzWAO7selVCetiKlLS52mc1IuMVGuPSpAe2K6DmPJfEsjnxVfySjDl9qrjsAMfpVGwjmu5lii/1kjbRjr9TXQ+PrOSPWEvFUFZYgnHXI9vpR8PtPNxqk87ciFQBn+8a556XZ001eyOy8KeCIbIrc3DeZN244UV6HCiRxhVOCO1cJqerXmm5ijsrmbPdc4H5d6rWLa4t2jqbhEkUPsZtwQH19D7Vkr7nS7bHoFzEJIm3Y/GvG/iBp621xBJGoV5HbJA69K7TxXqer6f5FtZRSSNKgZnQZxmsCGwm1q9sPtkUuLeR2l85twbA4x2xnH5VUVdomo0os37VCttEJDlwgDH1OKsAY6DpUy2zO2xFyx9KnWDAaIKS2OTius885TxHpS3sTTRxB7goIlz2BPWq3hnT5dEkuI3XKO4ZX9a19UmmttLuLmGITSQp5gRujY5xUWn3p1GzWcw+Usqh0UnJwQOtc1VNP1O6hJSiu6OvtZ4bmMLLEjKex5p88lpbMsMaxqzg+w4rCt/MDgKee1JealpAhe21FZJGPLARM39KyV9jpsma9zJaypbM7xyAjaRkH6VEqwNdCIFYkArmLObSBObe18/JHyB4ioT2BrcsoWuXlhkG5iowfcVcE+czr2VNpm7G9tassbbVD8A+v41SvoVtWZkbZvGMg1nTQSxKYp43MY6EnkfjT71me1iOS6gYDHrXRc84mvPDNzdWBgS8a1nLDLKoYFe68+vrWddaVLYxuvllAhyp7Ee1elSWyuCCKz7uxYxlZE8yM9eKc6fNsVTqchwFrfpkLuAIPOeorbWMXkQCzBR6+lZuueEZGYz6e27/YJwfwPeuaSfULSY25d0deCp4IrmcGnqdkaqex1c1i8GR53mE8L61cj064hKNFKyuOpHOaxNElEqte31xiKFwQ2eMcjn8a7G3ura4x5M8UnGflcE4roo01a7ObEVnJ2RkXGryWz+VdWruh4LbajkWP7OHgYNA/I9vaukkgSRSGAqhcaZCYHRB5eTnI6D8K37GHMf/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-91.png', linkedinUrl: '/in/samantha-steele-a6e15143ce', jobTitle: 'Designer, industrial/product', }, @@ -11915,7 +11915,7 @@ export const peopleDemo = [ city: 'West Brandonville', email: 'tiffany.boyd@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-92.png', linkedinUrl: '/in/tiffany-boyd-5875da90d3', jobTitle: 'Editor, film/video', }, @@ -11925,7 +11925,7 @@ export const peopleDemo = [ city: 'Rochafurt', email: 'larry.johnston@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0vFKKXFGKYg6V5p4m+JVzA80OkxokaMY/PcbmY/7I6D8c132tTm20e5kX75Tan+8eB/OuCfwIlxaxCOY787nDDgms6lRR0NqVJzu0edahq+sapKbi6lmkcjgyH+Q7VntdajxIkkiOnO5XKkflXtCeBtNS3CzK8jY5bdis668J6ZEDiE88ZJrH26Oj6tI5Pwz8VtX0qUQ6rv1C0yAS5/eoPY9/xr2fRdbsPEOmpf6dN5kLEg5GGVh1BHY14HqegJp97KEZjDg4Na/w11ifRfFMVlvP2DUG8plJzh8fKfz4/GuiMro5Jxs7HumKMU40VRBm65CZrBVHaZCfzqO3Rgi54/Ck8UJO2gztbzSRvHiQ+UBuYDsM1geH9Q1O4s2F4rJ8jFWfhhtOPmA9e1ceIXvXPQwkvdaOjk3BCM9awtSJclU7CsFrzxG+pqrNK8DMAuzaAPc8dK0oVvbnc8gYY67lwax5banTzX0OQ8QTIkLJKvOehrF8IxrN4w0iNUIzdK2D2xzn9K6nxHaC5aGFcGRmwM07w5oFtoetWWqF2mdJCp+b5VyMHA9s10wqJJXOOdGUm7HrVFFFdJxFe/4spDjjjP0zWRKqLbyFSoLYGM4rbuE822kTuykVwl9caVLP/ps2zaeUIbk+471y117yPQwb91o6awSCeMuu0spKt7VDfzRwI4TBJ71TsL20VRFZshHonX6mm3zAxsFwSe/pXO+x1HP3AV7iNmTcQ3AxWzpNn5t3bQvGp2DzJB9P/wBYFc5dTn7WnlPtZDuBHbFdj4NsCtjNqUztJPdtjLH7qLwFHpzk/jW1KHNJHPVq8kHbqdNRRRXYeaKK5TUdMMd66rJ5Ycl0bHY9q6pmVFLMQFAySTgCuF8UeMNMZGtbLdcXKAlZkOEQ/X+L6frUVIc60NqFX2c7l7atpbkl13d2rBv9WQRFY2DO54AqstvfavAAl5h9vKY4JHUCpbXQiiCV2+YHBU9c1wtJPU9HmctilFbOIWmfJdup/pXQeB/FYub6Xw/PHHGYEzbyA8y92B9xms/V5o9P02R5DhUXgeprzKO4mF59pjkaOUPvV1OCp9jXRhk2kon/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-93.png', linkedinUrl: '/in/larry-johnston-2639a97c12', jobTitle: 'Horticulturist, amenity', }, @@ -11935,7 +11935,7 @@ export const peopleDemo = [ city: 'Lake Rhonda', email: 'vanessa.villanueva@example.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDusUUGkZgqlj0AyaYivqWo2uk2Et7dyiOGMZJ9fYepryHXviBqeryNFZyNY2nQBT87D3P9BS/E7Xbm+1aPTE3R2sChyM/fc9/wH9a5/SvDN5qSBlBSM/xEcms5Ssawg3sZk9yWlJMpZj1J5NROk6RCRjgOeM9/evQLT4fpFHvlfc47YrH8QaCYWwWOFHHtUKaNHSkkcxFcyZG4lJF+6w4r1DwR8QWdo9N1uXk4WG6bufRv8fzrzaaJI3UA81VzgkZ+X2q0zJo+ou1JiilFaGZ4d4gjOt/E57Qj5Fl2EDsqjn+tekWtitvCqIoAAxgVyPi7SP7G8ZNqiW7TxXkTsFXI2ycA8/jmtPwpeXl2ssM6TIiqWUyHJGO2a5aqdztoNWOk2OFPp9aw9f01buzdVwJSOCfWsTVZLmy1Bpfsc1znncXPrgYGa1rCae/jybSaLHGGOV/A1nayubXu7HkWoRzWt28UylWU4INVd+G5PWu38eaXtKXUa8n5Wrio7K4nVmVDhFLHPtXRGSauck4NSsj6lpRSUtbHOZ2r+WVhWRQwJPUVlK1rbrJseNCTtC9K1tZgaXT3dM74vnGP1ri5LvRjN/pYEjgjcpGRkeorlqp8x6GHs4WR01utrdg5ClkOCDzTbuaO3Q7AAMdqzrbU9LlVYbJ0VuoUDB/Kku0kc7TxWDdtDoSRgatEdRQxkAruyayrqxj07SryaTIg2HAYYyR93H48Vu3R8tdseN3avPvF2r3l5eCykkQQxncI0/qe9XTV3YxqSUVc+ihS4pRRXceaNdA6FG6MMGuLl0l47qWLzljKHGf73pXbis3VNHg1FlmM7wSIMF1xgj3FZ1IOS0N6FX2b1MEQpaR8lCT1IFU7q/AU5bk1lahJdw3UsKS+aisQHA6j1otLSWVw0oIH864nud6dyZImkzKw+lefavpFzeeKI4lwouTgO5wox1ya9VMarBtArIufD0WtLHbSQ78tkKOP19KulK060bxP/9k=', + 'https://twentyhq.github.io/placeholder-images/people/image-94.png', linkedinUrl: '/in/vanessa-villanueva-cf67adba5d', jobTitle: 'Child psychotherapist', }, @@ -11945,7 +11945,7 @@ export const peopleDemo = [ city: 'East Christophermouth', email: 'danielle.gutierrez@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-95.png', linkedinUrl: '/in/danielle-gutierrez-bae65dfff7', jobTitle: 'Technical author', }, @@ -11955,7 +11955,7 @@ export const peopleDemo = [ city: 'Cookland', email: 'pamela.anderson@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-96.png', linkedinUrl: '/in/pamela-anderson-79a31bf795', jobTitle: 'Geoscientist', }, @@ -11965,7 +11965,7 @@ export const peopleDemo = [ city: 'Fryeville', email: 'linda.young@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-97.png', linkedinUrl: '/in/linda-young-912fcbd8df', jobTitle: 'Ship broker', }, @@ -11975,7 +11975,7 @@ export const peopleDemo = [ city: 'Davidmouth', email: 'rodney.orr@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-98.png', linkedinUrl: '/in/rodney-orr-ae717c2f34', jobTitle: 'Best boy', }, @@ -11985,7 +11985,7 @@ export const peopleDemo = [ city: 'Laurenfurt', email: 'ashley.perez@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-99.png', linkedinUrl: '/in/ashley-perez-9375a8f7c7', jobTitle: 'Chemical engineer', }, @@ -11995,7 +11995,7 @@ export const peopleDemo = [ city: 'Travisfurt', email: 'abigail.scott@example.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-100.png', linkedinUrl: '/in/abigail-scott-34179b2995', jobTitle: 'Radiographer, diagnostic', }, diff --git a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/company.ts b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/company.ts index 9899ffd1ca44..6061cef071a6 100644 --- a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/company.ts +++ b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/company.ts @@ -10,7 +10,12 @@ export const companyPrefillData = async ( .into(`${schemaName}.company`, [ 'name', 'domainName', - 'address', + 'addressAddressStreet1', + 'addressAddressStreet2', + 'addressAddressCity', + 'addressAddressState', + 'addressAddressPostcode', + 'addressAddressCountry', 'employees', 'position', ]) @@ -19,35 +24,60 @@ export const companyPrefillData = async ( { name: 'Airbnb', domainName: 'airbnb.com', - address: 'San Francisco', + addressAddressStreet1: '888 Brannan St', + addressAddressStreet2: null, + addressAddressCity: 'San Francisco', + addressAddressState: 'CA', + addressAddressPostcode: '94103', + addressAddressCountry: 'United States', employees: 5000, position: 1, }, { name: 'Qonto', domainName: 'qonto.com', - address: 'San Francisco', + addressAddressStreet1: '18 rue de navarrin', + addressAddressStreet2: null, + addressAddressCity: 'Paris', + addressAddressState: null, + addressAddressPostcode: '75009', + addressAddressCountry: 'France', employees: 800, position: 2, }, { name: 'Stripe', domainName: 'stripe.com', - address: 'San Francisco', + addressAddressStreet1: 'Eutaw Street', + addressAddressStreet2: null, + addressAddressCity: 'Dublin', + addressAddressState: null, + addressAddressPostcode: null, + addressAddressCountry: 'Ireland', employees: 8000, position: 3, }, { name: 'Figma', domainName: 'figma.com', - address: 'San Francisco', + addressAddressStreet1: '760 Market St', + addressAddressStreet2: 'Floor 10', + addressAddressCity: 'San Francisco', + addressAddressState: null, + addressAddressPostcode: '94102', + addressAddressCountry: 'United States', employees: 800, position: 4, }, { name: 'Notion', domainName: 'notion.com', - address: 'San Francisco', + addressAddressStreet1: '2300 Harrison St', + addressAddressStreet2: null, + addressAddressCity: 'San Francisco', + addressAddressState: 'CA', + addressAddressPostcode: '94110', + addressAddressCountry: 'United States', employees: 400, position: 5, }, diff --git a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/person.ts b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/person.ts index 68d82ebb1eb9..5c4a0212bff0 100644 --- a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/person.ts +++ b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/person.ts @@ -23,7 +23,7 @@ export const personPrefillData = async ( city: 'San Francisco', email: 'chesky@airbnb.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-3.png', position: 1, }, { @@ -32,7 +32,7 @@ export const personPrefillData = async ( city: 'Paris', email: 'prot@qonto.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAASABIAAD/4QCMRXhpZgAATU0AKgAAAAgABQESAAMAAAABAAEAAAEaAAUAAAABAAAASgEbAAUAAAABAAAAUgEoAAMAAAABAAIAAIdpAAQAAAABAAAAWgAAAAAAAABIAAAAAQAAAEgAAAABAAOgAQADAAAAAQABAACgAgAEAAAAAQAAADygAwAEAAAAAQAAADwAAAAA/+0AOFBob3Rvc2hvcCAzLjAAOEJJTQQEAAAAAAAAOEJJTQQlAAAAAAAQ1B2M2Y8AsgTpgAmY7PhCfv/AABEIADwAPAMBIgACEQEDEQH/xAAfAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgv/xAC1EAACAQMDAgQDBQUEBAAAAX0BAgMABBEFEiExQQYTUWEHInEUMoGRoQgjQrHBFVLR8CQzYnKCCQoWFxgZGiUmJygpKjQ1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4eLj5OXm5+jp6vHy8/T19vf4+fr/xAAfAQADAQEBAQEBAQEBAAAAAAAAAQIDBAUGBwgJCgv/xAC1EQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2dri4+Tl5ufo6ery8/T19vf4+fr/2wBDAAkGBxAQEBUQEBAVFRUVFRUVFRUVEBAVFRUQFRUWFhUVFRUYHSggGBolGxUVITEhJSkrLi4uFx8zODMtNygtLiv/2wBDAQoKCg4NDhcQEBctHR0dLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS3/3QAEAAT/2gAMAwEAAhEDEQA/APZ6KSitCRc1Sn1e3Q7XmQEdRuHH19K4n4keK3i3WluSHwu9lJBBbkID24GSfevOILa6lO4GSQ4x8qsRjuARUOVjSMLn0RDMrgMpBB7g5FPrwzRdavLaQJ+9jPZXVtjEdsEdcelex6DqQuYFlxgkYYejjqKadxSjY0aKSlpkH//Q9mooFFaEnj2vWQk1xoGUsHfzH5IBTYuB9K9HtkVU2qAABgAYGB7CsrU9Jj+2i5YfOA8ZbJyyPgqPouMD6moF8PokvnAnr1LPnPPv71zvdnbCNkT6xaxSfLKUweBuYDk9CKk+G4xbSLzlJWRg3Xenyn88A575zWVfaPG9zI7qCeDzyQhGML6DK/nXR+FQv78rjBmABB5+WNQc++c0Qeoqyurm/RSZpM1ucZ//0fZaWkqOWZV6n8O9aJXIvYzvEIjEe5iA2RtyeTjkgDucZ/KsOaR2X5QCAOu4gg+orX1aES7XIBKNuXPYEFT+hNc7dCaAkw4Zf7hOCPofT2rOrCzR1YepoZIMvmO7yM4YY5OTnoFUAACvTbWMKijAHAzgY5wMn61wGgXjSXSm5CxhWAVSR80pBK8/h+legbqVKO7JxE7tJEmaM1HmjNanOf/S9blnJ6cD171VI9afu4pjV2xVjmbuMuruOGNnlYBV6k989AAOpPTArnRc74jIFO0jcAww+09Nw7EdxW7cQq+A6hsHIyM4PqKrXVgjAkZU/wCyxGfqOholSU1bqOFZ03focTPpkszoFBGJlkPvwQB+pP4Cu8tLrDmIZ3KqliRwd2eh79OR2rLvrkxRIygE8ZJHXBxzj6VNYpnkscvyxyM8+noKcKajCxNSo5TbOhhnDdxkdcVLmsy3GJQBwNjcfRlq/msJqzNoO6P/2Q==', + 'https://twentyhq.github.io/placeholder-images/people/image-89.png', position: 2, }, { @@ -41,7 +41,7 @@ export const personPrefillData = async ( city: 'San Francisco', email: 'collison@stripe.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-47.png', position: 3, }, { @@ -50,7 +50,7 @@ export const personPrefillData = async ( city: 'San Francisco', email: 'field@figma.com', avatarUrl: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQABLAEsAAD/4QSQRXhpZgAATU0AKgAAAAgADAEOAAIAAADlAAAAngEPAAIAAAAGAAABhAEQAAIAAAANAAABigESAAMAAAABAAEAAAEaAAUAAAABAAABmAEbAAUAAAABAAABoAEoAAMAAAABAAIAAAExAAIAAAAhAAABqAEyAAIAAAAUAAABygE7AAIAAAAPAAAB3oKYAAIAAAASAAAB7odpAAQAAAABAAACAAAAAABTQU4gRlJBTkNJU0NPLCBDQUxJRk9STklBIC0gT0NUT0JFUiAyMDogQ28tZm91bmRlciAmIENFTyBvZsKgRmlnbWEgRHlsYW4gRmllbGQgc3BlYWtzIG9uc3RhZ2UgZHVyaW5nIFRlY2hDcnVuY2ggRGlzcnVwdCAyMDIyIG9uIE9jdG9iZXIgMjAsIDIwMjIgaW4gU2FuIEZyYW5jaXNjbywgQ2FsaWZvcm5pYS4gKFBob3RvIGJ5IEtpbWJlcmx5IFdoaXRlL0dldHR5IEltYWdlcyBmb3IgVGVjaENydW5jaCkAAENhbm9uAENhbm9uIEVPUyBSNQAAAAABLAAAAAEAAAEsAAAAAUFkb2JlIFBob3Rvc2hvcCAyMy41IChNYWNpbnRvc2gpAAAyMDIyOjEwOjIwIDEwOjU2OjU4AEtpbWJlcmx5IFdoaXRlAAAyMDIyIEdldHR5IEltYWdlcwAAI4KaAAUAAAABAAADqoKdAAUAAAABAAADsogiAAMAAAABAAEAAIgnAAMAAAABCcQAAIgwAAMAAAABAAIAAIgyAAQAAAABAAAJxJAAAAcAAAAEMDIzMZADAAIAAAAUAAADupAEAAIAAAAUAAADzpAQAAIAAAAHAAAD4pARAAIAAAAHAAAD6pASAAIAAAAHAAAD8pIBAAoAAAABAAAD+pICAAUAAAABAAAEApIEAAoAAAABAAAECpIFAAUAAAABAAAEEpIHAAMAAAABAAUAAJIJAAMAAAABAAAAAJIKAAUAAAABAAAEGpKQAAIAAAADNzgAAJKRAAIAAAADNzgAAJKSAAIAAAADNzgAAKACAAQAAAABAAAAPKADAAQAAAABAAAAUKIOAAUAAAABAAAEIqIPAAUAAAABAAAEKqIQAAMAAAABAAIAAKQBAAMAAAABAAAAAKQCAAMAAAABAAEAAKQDAAMAAAABAAEAAKQGAAMAAAABAAAAAKQxAAIAAAANAAAEMqQyAAUAAAAEAAAEQKQ0AAIAAAAcAAAEYKQ1AAIAAAALAAAEfAAAAAAAAAABAAAB9AAAAAUAAAABMjAyMjoxMDoyMCAxMjo0ODozMgAyMDIyOjEwOjIwIDEyOjQ4OjMyAC0wNTowMAAALTA1OjAwAAAtMDU6MDAAAAAAdbYAAA0hAAQwyQAA5wMAAAAAAAAAAQAAAAMAAAABAAAAbgAAAAEAFT2AAAAB2QAlDXsAAAM6MDUyMDIxMDA0MTE5AAAAAABGAAAAAQAAAMgAAAABAAAAAAAAAAEAAAAAAAAAAUVGNzAtMjAwbW0gZi8yLjhMIElTIElJIFVTTQAwMDAwNDBjNzVjAAD/4ROOaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJYTVAgQ29yZSA2LjAuMCI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnBob3Rvc2hvcD0iaHR0cDovL25zLmFkb2JlLmNvbS9waG90b3Nob3AvMS4wLyIgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIiB4bWxuczpHZXR0eUltYWdlc0dJRlQ9Imh0dHA6Ly94bXAuZ2V0dHlpbWFnZXMuY29tL2dpZnQvMS4wLyIgeG1sbnM6SXB0YzR4bXBDb3JlPSJodHRwOi8vaXB0Yy5vcmcvc3RkL0lwdGM0eG1wQ29yZS8xLjAveG1sbnMvIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOnBsdXM9Imh0dHA6Ly9ucy51c2VwbHVzLm9yZy9sZGYveG1wLzEuMC8iIHhtbG5zOnhtcFJpZ2h0cz0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3JpZ2h0cy8iIHhtbG5zOklwdGM0eG1wRXh0PSJodHRwOi8vaXB0Yy5vcmcvc3RkL0lwdGM0eG1wRXh0LzIwMDgtMDItMjkvIiBwaG90b3Nob3A6Q2l0eT0iU2FuIEZyYW5jaXNjbyIgcGhvdG9zaG9wOkRhdGVDcmVhdGVkPSIyMDIyLTEwLTIwVDEyOjQ4OjMyLjc4IiBwaG90b3Nob3A6SGVhZGxpbmU9IlRlY2hDcnVuY2ggRGlzcnVwdCAyMDIyIC0gRGF5IDMiIHBob3Rvc2hvcDpDb3VudHJ5PSJVbml0ZWQgU3RhdGVzIiBwaG90b3Nob3A6Q29weXJpZ2h0RmxhZz0idHJ1ZSIgcGhvdG9zaG9wOkNhdGVnb3J5PSJFIiBwaG90b3Nob3A6U291cmNlPSJHZXR0eSBJbWFnZXMgTm9ydGggQW1lcmljYSIgcGhvdG9zaG9wOlVyZ2VuY3k9IjMiIHBob3Rvc2hvcDpBdXRob3JzUG9zaXRpb249IlN0cmluZ2VyIiBwaG90b3Nob3A6VHJhbnNtaXNzaW9uUmVmZXJlbmNlPSI3NzU4ODQzODQiIHBob3Rvc2hvcDpVUkw9Imh0dHBzOi8vd3d3LmdldHR5aW1hZ2VzLmNvbSIgcGhvdG9zaG9wOlN0YXRlPSJDYWxpZm9ybmlhIiBwaG90b3Nob3A6Q3JlZGl0PSJHZXR0eSBJbWFnZXMgZm9yIFRlY2hDcnVuY2giIHBob3Rvc2hvcDpDYXB0aW9uV3JpdGVyPSJFRCAvIEVEIiBkYzpSaWdodHM9IjIwMjIgR2V0dHkgSW1hZ2VzIiBHZXR0eUltYWdlc0dJRlQ6SW1hZ2VSYW5rPSIzIiBHZXR0eUltYWdlc0dJRlQ6RGxyZWY9ImZjNkRiREMzK0ZHWG5PMXpiVzFKYkE9PSIgR2V0dHlJbWFnZXNHSUZUOkFzc2V0SUQ9IjE0MzUwODg1NjciIElwdGM0eG1wQ29yZTpDb3VudHJ5Q29kZT0iVVNBIiBJcHRjNHhtcENvcmU6TG9jYXRpb249Ik1vc2NvbmUgQ2VudGVyIiB4bXA6Q3JlYXRlRGF0ZT0iMjAyMi0xMC0yMFQxMjo0ODozMi43OCIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjMuNSAoTWFjaW50b3NoKSIgeG1wOk1vZGlmeURhdGU9IjIwMjItMTAtMjBUMTA6NTY6NTguNzgiIHBsdXM6SW1hZ2VTdXBwbGllckltYWdlSUQ9IjE0MzUwODg1NjciIHhtcFJpZ2h0czpXZWJTdGF0ZW1lbnQ9Imh0dHBzOi8vd3d3LmdldHR5aW1hZ2VzLmNvbS9ldWxhP3V0bV9tZWRpdW09b3JnYW5pYyZhbXA7dXRtX3NvdXJjZT1nb29nbGUmYW1wO3V0bV9jYW1wYWlnbj1pcHRjdXJsIiBJcHRjNHhtcEV4dDpIZWFkbGluZT0iVGVjaENydW5jaCBEaXNydXB0IDIwMjIgLSBEYXkgMyI+IDxwaG90b3Nob3A6U3VwcGxlbWVudGFsQ2F0ZWdvcmllcz4gPHJkZjpCYWc+IDxyZGY6bGk+QUNFPC9yZGY6bGk+IDxyZGY6bGk+RU5UPC9yZGY6bGk+IDwvcmRmOkJhZz4gPC9waG90b3Nob3A6U3VwcGxlbWVudGFsQ2F0ZWdvcmllcz4gPGRjOnJpZ2h0cz4gPHJkZjpBbHQ+IDxyZGY6bGkgeG1sOmxhbmc9IngtZGVmYXVsdCI+MjAyMiBHZXR0eSBJbWFnZXM8L3JkZjpsaT4gPC9yZGY6QWx0PiA8L2RjOnJpZ2h0cz4gPGRjOnN1YmplY3Q+IDxyZGY6QmFnPiA8cmRmOmxpPmFydHMgY3VsdHVyZSBhbmQgZW50ZXJ0YWlubWVudDwvcmRmOmxpPiA8L3JkZjpCYWc+IDwvZGM6c3ViamVjdD4gPGRjOmNyZWF0b3I+IDxyZGY6U2VxPiA8cmRmOmxpPktpbWJlcmx5IFdoaXRlPC9yZGY6bGk+IDwvcmRmOlNlcT4gPC9kYzpjcmVhdG9yPiA8ZGM6dGl0bGU+IDxyZGY6QWx0PiA8cmRmOmxpIHhtbDpsYW5nPSJ4LWRlZmF1bHQiPjE0MzUwODg1Njc8L3JkZjpsaT4gPC9yZGY6QWx0PiA8L2RjOnRpdGxlPiA8ZGM6ZGVzY3JpcHRpb24+IDxyZGY6QWx0PiA8cmRmOmxpIHhtbDpsYW5nPSJ4LWRlZmF1bHQiPlNBTiBGUkFOQ0lTQ08sIENBTElGT1JOSUEgLSBPQ1RPQkVSIDIwOiBDby1mb3VuZGVyICZhbXA7IENFTyBvZsKgRmlnbWEgRHlsYW4gRmllbGQgc3BlYWtzIG9uc3RhZ2UgZHVyaW5nIFRlY2hDcnVuY2ggRGlzcnVwdCAyMDIyIG9uIE9jdG9iZXIgMjAsIDIwMjIgaW4gU2FuIEZyYW5jaXNjbywgQ2FsaWZvcm5pYS4gKFBob3RvIGJ5IEtpbWJlcmx5IFdoaXRlL0dldHR5IEltYWdlcyBmb3IgVGVjaENydW5jaCk8L3JkZjpsaT4gPC9yZGY6QWx0PiA8L2RjOmRlc2NyaXB0aW9uPiA8cGx1czpMaWNlbnNvcj4gPHJkZjpTZXE+IDxyZGY6bGkgcGx1czpMaWNlbnNvclVSTD0iaHR0cHM6Ly93d3cuZ2V0dHlpbWFnZXMuY29tL2RldGFpbC8xNDM1MDg4NTY3P3V0bV9tZWRpdW09b3JnYW5pYyZhbXA7dXRtX3NvdXJjZT1nb29nbGUmYW1wO3V0bV9jYW1wYWlnbj1pcHRjdXJsIi8+IDwvcmRmOlNlcT4gPC9wbHVzOkxpY2Vuc29yPiA8SXB0YzR4bXBFeHQ6UGVyc29uSW5JbWFnZT4gPHJkZjpCYWc+IDxyZGY6bGk+RHlsYW4gRmllbGQ8L3JkZjpsaT4gPC9yZGY6QmFnPiA8L0lwdGM0eG1wRXh0OlBlcnNvbkluSW1hZ2U+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDw/eHBhY2tldCBlbmQ9InciPz4A/+0CsFBob3Rvc2hvcCAzLjAAOEJJTQQEAAAAAAJ3HAFaAAMbJUccAgAAAgACHAI8AAYxMjQ4MzIcAngA5FNBTiBGUkFOQ0lTQ08sIENBTElGT1JOSUEgLSBPQ1RPQkVSIDIwOiBD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', + 'https://twentyhq.github.io/placeholder-images/people/image-40.png', position: 4, }, { @@ -59,7 +59,7 @@ export const personPrefillData = async ( city: 'San Francisco', email: 'zhao@notion.com', avatarUrl: - 'data:image/jpeg;base64,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', + 'https://twentyhq.github.io/placeholder-images/people/image-68.png', position: 5, }, ]) diff --git a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/view-opportunity-fields.ts b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/view-opportunity-fields.ts index 7e7ed6b59354..baa08a95f7ea 100644 --- a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/view-opportunity-fields.ts +++ b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/view-opportunity-fields.ts @@ -47,16 +47,6 @@ export const viewOpportunityFields = ( isVisible: true, size: 150, }, - { - fieldMetadataId: - objectMetadataMap[STANDARD_OBJECT_IDS.opportunity].fields[ - OPPORTUNITY_STANDARD_FIELD_IDS.probability - ], - viewId: viewId, - position: 4, - isVisible: true, - size: 150, - }, { fieldMetadataId: objectMetadataMap[STANDARD_OBJECT_IDS.opportunity].fields[ diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-cleaner/commands/clean-inactive-workspaces.command.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-cleaner/commands/clean-inactive-workspaces.command.ts index 822fd2e94fd1..79b805c607cf 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-cleaner/commands/clean-inactive-workspaces.command.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-cleaner/commands/clean-inactive-workspaces.command.ts @@ -1,7 +1,6 @@ -import { Inject } from '@nestjs/common'; - import { Command, CommandRunner, Option } from 'nest-commander'; +import { InjectMessageQueue } from 'src/engine/integrations/message-queue/decorators/message-queue.decorator'; import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service'; import { CleanInactiveWorkspaceJob } from 'src/engine/workspace-manager/workspace-cleaner/crons/clean-inactive-workspace.job'; @@ -16,7 +15,7 @@ export type CleanInactiveWorkspacesCommandOptions = { }) export class CleanInactiveWorkspacesCommand extends CommandRunner { constructor( - @Inject(MessageQueue.taskAssignedQueue) + @InjectMessageQueue(MessageQueue.cronQueue) private readonly messageQueueService: MessageQueueService, ) { super(); diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-cleaner/commands/delete-incomplete-workspaces.command.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-cleaner/commands/delete-workspaces.command.ts similarity index 56% rename from packages/twenty-server/src/engine/workspace-manager/workspace-cleaner/commands/delete-incomplete-workspaces.command.ts rename to packages/twenty-server/src/engine/workspace-manager/workspace-cleaner/commands/delete-workspaces.command.ts index 30c980c4e0c1..2bbc17b75878 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-cleaner/commands/delete-incomplete-workspaces.command.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-cleaner/commands/delete-workspaces.command.ts @@ -2,26 +2,29 @@ import { InjectRepository } from '@nestjs/typeorm'; import { Logger } from '@nestjs/common'; import { Command, CommandRunner, Option } from 'nest-commander'; -import { FindOptionsWhere, In, Repository } from 'typeorm'; +import { In, Repository } from 'typeorm'; -import { WorkspaceService } from 'src/engine/core-modules/workspace/services/workspace.service'; import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; -import { getDryRunLogHeader } from 'src/utils/get-dry-run-log-header'; import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; +import { getDryRunLogHeader } from 'src/utils/get-dry-run-log-header'; +import { WorkspaceService } from 'src/engine/core-modules/workspace/services/workspace.service'; +import { LoadServiceWithWorkspaceContext } from 'src/engine/twenty-orm/context/load-service-with-workspace.context'; -type DeleteIncompleteWorkspacesCommandOptions = { +type DeleteWorkspacesCommandOptions = { dryRun?: boolean; - workspaceIds?: string[]; + workspaceIds: string[]; }; @Command({ - name: 'workspace:delete-incomplete', - description: 'Delete incomplete workspaces', + name: 'workspace:delete', + description: 'Delete workspace', }) -export class DeleteIncompleteWorkspacesCommand extends CommandRunner { - private readonly logger = new Logger(DeleteIncompleteWorkspacesCommand.name); +export class DeleteWorkspacesCommand extends CommandRunner { + private readonly logger = new Logger(DeleteWorkspacesCommand.name); + constructor( private readonly workspaceService: WorkspaceService, + private readonly loadServiceWithWorkspaceContext: LoadServiceWithWorkspaceContext, @InjectRepository(Workspace, 'core') private readonly workspaceRepository: Repository<Workspace>, private readonly dataSourceService: DataSourceService, @@ -41,7 +44,7 @@ export class DeleteIncompleteWorkspacesCommand extends CommandRunner { @Option({ flags: '-w, --workspace-ids [workspace_ids]', description: 'comma separated workspace ids', - required: false, + required: true, }) parseWorkspaceIds(value: string): string[] { return value.split(','); @@ -49,41 +52,43 @@ export class DeleteIncompleteWorkspacesCommand extends CommandRunner { async run( _passedParam: string[], - options: DeleteIncompleteWorkspacesCommandOptions, + options: DeleteWorkspacesCommandOptions, ): Promise<void> { - const where: FindOptionsWhere<Workspace> = { - subscriptionStatus: 'incomplete', - }; + const workspaces = await this.workspaceRepository.find({ + where: { id: In(options.workspaceIds) }, + }); - if (options.workspaceIds) { - where.id = In(options.workspaceIds); - } - - const incompleteWorkspaces = await this.workspaceRepository.findBy(where); const dataSources = await this.dataSourceService.getManyDataSourceMetadata(); + const workspaceIdsWithSchema = dataSources.map( (dataSource) => dataSource.workspaceId, ); - const incompleteWorkspacesToDelete = incompleteWorkspaces.filter( - (incompleteWorkspace) => - workspaceIdsWithSchema.includes(incompleteWorkspace.id), + + const workspacesToDelete = workspaces.filter((Workspace) => + workspaceIdsWithSchema.includes(Workspace.id), ); - if (incompleteWorkspacesToDelete.length) { + if (workspacesToDelete.length) { this.logger.log( - `Running Deleting incomplete workspaces on ${incompleteWorkspacesToDelete.length} workspaces`, + `Running Deleting workspaces on ${workspacesToDelete.length} workspaces`, ); } - for (const incompleteWorkspace of incompleteWorkspacesToDelete) { + for (const workspace of workspacesToDelete) { this.logger.log( `${getDryRunLogHeader(options.dryRun)}Deleting workspace ${ - incompleteWorkspace.id - } name: '${incompleteWorkspace.displayName}'`, + workspace.id + } name: '${workspace.displayName}'`, ); + const workspaceServiceInstance = + await this.loadServiceWithWorkspaceContext.load( + this.workspaceService, + workspace.id, + ); + if (!options.dryRun) { - await this.workspaceService.softDeleteWorkspace(incompleteWorkspace.id); + await workspaceServiceInstance.softDeleteWorkspace(workspace.id); } } } diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-cleaner/commands/start-clean-inactive-workspaces.cron.command.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-cleaner/commands/start-clean-inactive-workspaces.cron.command.ts index 62b7f0fa0e4d..daee64136210 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-cleaner/commands/start-clean-inactive-workspaces.cron.command.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-cleaner/commands/start-clean-inactive-workspaces.cron.command.ts @@ -1,7 +1,6 @@ -import { Inject } from '@nestjs/common'; - import { Command, CommandRunner } from 'nest-commander'; +import { InjectMessageQueue } from 'src/engine/integrations/message-queue/decorators/message-queue.decorator'; import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service'; import { cleanInactiveWorkspaceCronPattern } from 'src/engine/workspace-manager/workspace-cleaner/crons/clean-inactive-workspace.cron.pattern'; @@ -13,7 +12,7 @@ import { CleanInactiveWorkspaceJob } from 'src/engine/workspace-manager/workspac }) export class StartCleanInactiveWorkspacesCronCommand extends CommandRunner { constructor( - @Inject(MessageQueue.cronQueue) + @InjectMessageQueue(MessageQueue.cronQueue) private readonly messageQueueService: MessageQueueService, ) { super(); diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-cleaner/commands/stop-clean-inactive-workspaces.cron.command.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-cleaner/commands/stop-clean-inactive-workspaces.cron.command.ts index 1dd6dd85e650..0fa47c6fb59c 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-cleaner/commands/stop-clean-inactive-workspaces.cron.command.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-cleaner/commands/stop-clean-inactive-workspaces.cron.command.ts @@ -1,7 +1,6 @@ -import { Inject } from '@nestjs/common'; - import { Command, CommandRunner } from 'nest-commander'; +import { InjectMessageQueue } from 'src/engine/integrations/message-queue/decorators/message-queue.decorator'; import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service'; import { cleanInactiveWorkspaceCronPattern } from 'src/engine/workspace-manager/workspace-cleaner/crons/clean-inactive-workspace.cron.pattern'; @@ -13,7 +12,7 @@ import { CleanInactiveWorkspaceJob } from 'src/engine/workspace-manager/workspac }) export class StopCleanInactiveWorkspacesCronCommand extends CommandRunner { constructor( - @Inject(MessageQueue.cronQueue) + @InjectMessageQueue(MessageQueue.cronQueue) private readonly messageQueueService: MessageQueueService, ) { super(); diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-cleaner/crons/clean-inactive-workspace.job.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-cleaner/crons/clean-inactive-workspace.job.ts index 7d74648dccf9..95f9fc9a4f17 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-cleaner/crons/clean-inactive-workspace.job.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-cleaner/crons/clean-inactive-workspace.job.ts @@ -1,4 +1,4 @@ -import { Injectable, Logger } from '@nestjs/common'; +import { Logger } from '@nestjs/common'; import { render } from '@react-email/render'; import { In } from 'typeorm'; @@ -7,8 +7,6 @@ import { DeleteInactiveWorkspaceEmail, } from 'twenty-emails'; -import { MessageQueueJob } from 'src/engine/integrations/message-queue/interfaces/message-queue-job.interface'; - import { ObjectMetadataService } from 'src/engine/metadata-modules/object-metadata/object-metadata.service'; import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; import { TypeORMService } from 'src/database/typeorm/typeorm.service'; @@ -20,6 +18,9 @@ import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadat import { computeObjectTargetTable } from 'src/engine/utils/compute-object-target-table.util'; import { CleanInactiveWorkspacesCommandOptions } from 'src/engine/workspace-manager/workspace-cleaner/commands/clean-inactive-workspaces.command'; import { getDryRunLogHeader } from 'src/utils/get-dry-run-log-header'; +import { Processor } from 'src/engine/integrations/message-queue/decorators/processor.decorator'; +import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; +import { Process } from 'src/engine/integrations/message-queue/decorators/process.decorator'; const MILLISECONDS_IN_ONE_DAY = 1000 * 3600 * 24; @@ -28,10 +29,8 @@ type WorkspaceToDeleteData = { daysSinceInactive: number; }; -@Injectable() -export class CleanInactiveWorkspaceJob - implements MessageQueueJob<CleanInactiveWorkspacesCommandOptions> -{ +@Processor(MessageQueue.cronQueue) +export class CleanInactiveWorkspaceJob { private readonly logger = new Logger(CleanInactiveWorkspaceJob.name); private readonly inactiveDaysBeforeDelete; private readonly inactiveDaysBeforeEmail; @@ -193,6 +192,7 @@ export class CleanInactiveWorkspaceJob }); } + @Process(CleanInactiveWorkspaceJob.name) async handle(data: CleanInactiveWorkspacesCommandOptions): Promise<void> { const isDryRun = data.dryRun || false; diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-cleaner/workspace-cleaner.module.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-cleaner/workspace-cleaner.module.ts index 6bf7eb0136ad..681755be16a0 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-cleaner/workspace-cleaner.module.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-cleaner/workspace-cleaner.module.ts @@ -2,12 +2,12 @@ import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; import { WorkspaceModule } from 'src/engine/core-modules/workspace/workspace.module'; -import { DeleteIncompleteWorkspacesCommand } from 'src/engine/workspace-manager/workspace-cleaner/commands/delete-incomplete-workspaces.command'; import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; import { CleanInactiveWorkspacesCommand } from 'src/engine/workspace-manager/workspace-cleaner/commands/clean-inactive-workspaces.command'; import { StartCleanInactiveWorkspacesCronCommand } from 'src/engine/workspace-manager/workspace-cleaner/commands/start-clean-inactive-workspaces.cron.command'; import { StopCleanInactiveWorkspacesCronCommand } from 'src/engine/workspace-manager/workspace-cleaner/commands/stop-clean-inactive-workspaces.cron.command'; import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module'; +import { DeleteWorkspacesCommand } from 'src/engine/workspace-manager/workspace-cleaner/commands/delete-workspaces.command'; @Module({ imports: [ @@ -16,7 +16,7 @@ import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-s DataSourceModule, ], providers: [ - DeleteIncompleteWorkspacesCommand, + DeleteWorkspacesCommand, CleanInactiveWorkspacesCommand, StartCleanInactiveWorkspacesCronCommand, StopCleanInactiveWorkspacesCronCommand, diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-manager.module.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-manager.module.ts index a3afeb00cc42..53bba06ce186 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-manager.module.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-manager.module.ts @@ -4,21 +4,30 @@ import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-s import { ObjectMetadataModule } from 'src/engine/metadata-modules/object-metadata/object-metadata.module'; import { WorkspaceMigrationModule } from 'src/engine/metadata-modules/workspace-migration/workspace-migration.module'; import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; -import { WorkspaceSyncMetadataModule } from 'src/engine/workspace-manager/workspace-sync-metadata/workspace-sync-metadata.module'; import { WorkspaceHealthModule } from 'src/engine/workspace-manager/workspace-health/workspace-health.module'; +import { WorkspaceStatusModule } from 'src/engine/workspace-manager/workspace-status/workspace-manager.module'; +import { + WorkspaceSyncMetadataModule, +} from 'src/engine/workspace-manager/workspace-sync-metadata/workspace-sync-metadata.module'; import { WorkspaceManagerService } from './workspace-manager.service'; +import { FieldMetadataModule } from 'src/engine/metadata-modules/field-metadata/field-metadata.module'; +import { RelationMetadataModule } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.module'; @Module({ imports: [ WorkspaceDataSourceModule, WorkspaceMigrationModule, ObjectMetadataModule, + FieldMetadataModule, + RelationMetadataModule, DataSourceModule, WorkspaceSyncMetadataModule, WorkspaceHealthModule, + WorkspaceStatusModule, ], exports: [WorkspaceManagerService], providers: [WorkspaceManagerService], }) -export class WorkspaceManagerModule {} +export class WorkspaceManagerModule { +} diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-manager.service.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-manager.service.ts index c7d75b6440e8..f49be7866353 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-manager.service.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-manager.service.ts @@ -1,13 +1,23 @@ import { Injectable } from '@nestjs/common'; +import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity'; import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; import { ObjectMetadataService } from 'src/engine/metadata-modules/object-metadata/object-metadata.service'; import { WorkspaceMigrationService } from 'src/engine/metadata-modules/workspace-migration/workspace-migration.service'; -import { standardObjectsPrefillData } from 'src/engine/workspace-manager/standard-objects-prefill-data/standard-objects-prefill-data'; -import { demoObjectsPrefillData } from 'src/engine/workspace-manager/demo-objects-prefill-data/demo-objects-prefill-data'; import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; -import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity'; -import { WorkspaceSyncMetadataService } from 'src/engine/workspace-manager/workspace-sync-metadata/workspace-sync-metadata.service'; +import { + demoObjectsPrefillData, +} from 'src/engine/workspace-manager/demo-objects-prefill-data/demo-objects-prefill-data'; +import { + standardObjectsPrefillData, +} from 'src/engine/workspace-manager/standard-objects-prefill-data/standard-objects-prefill-data'; +import { + WorkspaceSyncMetadataService, +} from 'src/engine/workspace-manager/workspace-sync-metadata/workspace-sync-metadata.service'; +import * as process from 'node:process'; +import { prefillWorkspaceWithFunnelminkFSMObjects } from 'src/funnelmink/funnelmink-objects-prefill-data'; +import { FieldMetadataService } from 'src/engine/metadata-modules/field-metadata/field-metadata.service'; +import { RelationMetadataService } from '../metadata-modules/relation-metadata/relation-metadata.service'; @Injectable() export class WorkspaceManagerService { @@ -17,7 +27,10 @@ export class WorkspaceManagerService { private readonly objectMetadataService: ObjectMetadataService, private readonly dataSourceService: DataSourceService, private readonly workspaceSyncMetadataService: WorkspaceSyncMetadataService, - ) {} + private readonly fieldMetadataService: FieldMetadataService, + private readonly relationMetadataService: RelationMetadataService, + ) { + } /** * Init a workspace by creating a new data source and running all migrations @@ -47,6 +60,17 @@ export class WorkspaceManagerService { dataSourceMetadata, workspaceId, ); + + if (process.env.FUNNELMINK_PREFILL_NEW_WORKSPACES_WITH_FSM_OBJECTS === 'true') { + await prefillWorkspaceWithFunnelminkFSMObjects( + dataSourceMetadata, + workspaceId, + this.workspaceDataSourceService, + this.objectMetadataService, + this.fieldMetadataService, + this.relationMetadataService, + ); + } } /** diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-builder/factories/index.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-builder/factories/index.ts index 50f96d394829..5d5e66ac5310 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-builder/factories/index.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-builder/factories/index.ts @@ -1,3 +1,5 @@ +import { WorkspaceMigrationIndexFactory } from 'src/engine/workspace-manager/workspace-migration-builder/factories/workspace-migration-index.factory'; + import { WorkspaceMigrationObjectFactory } from './workspace-migration-object.factory'; import { WorkspaceMigrationFieldFactory } from './workspace-migration-field.factory'; import { WorkspaceMigrationRelationFactory } from './workspace-migration-relation.factory'; @@ -6,4 +8,5 @@ export const workspaceMigrationBuilderFactories = [ WorkspaceMigrationObjectFactory, WorkspaceMigrationFieldFactory, WorkspaceMigrationRelationFactory, + WorkspaceMigrationIndexFactory, ]; diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-builder/factories/workspace-migration-index.factory.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-builder/factories/workspace-migration-index.factory.ts new file mode 100644 index 000000000000..0392041edc93 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-builder/factories/workspace-migration-index.factory.ts @@ -0,0 +1,156 @@ +import { Injectable } from '@nestjs/common'; + +import { WorkspaceMigrationBuilderAction } from 'src/engine/workspace-manager/workspace-migration-builder/interfaces/workspace-migration-builder-action.interface'; + +import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; +import { + WorkspaceMigrationEntity, + WorkspaceMigrationIndexActionType, + WorkspaceMigrationTableActionType, +} from 'src/engine/metadata-modules/workspace-migration/workspace-migration.entity'; +import { computeObjectTargetTable } from 'src/engine/utils/compute-object-target-table.util'; +import { generateMigrationName } from 'src/engine/metadata-modules/workspace-migration/utils/generate-migration-name.util'; +import { IndexMetadataEntity } from 'src/engine/metadata-modules/index-metadata/index-metadata.entity'; + +@Injectable() +export class WorkspaceMigrationIndexFactory { + constructor() {} + + async create( + originalObjectMetadataCollection: ObjectMetadataEntity[], + indexMetadataCollection: IndexMetadataEntity[], + action: WorkspaceMigrationBuilderAction, + ): Promise<Partial<WorkspaceMigrationEntity>[]> { + const originalObjectMetadataMap = Object.fromEntries( + originalObjectMetadataCollection.map((obj) => [obj.id, obj]), + ); + + const indexMetadataByObjectMetadataMap = new Map< + ObjectMetadataEntity, + IndexMetadataEntity[] + >(); + + indexMetadataCollection.forEach((currentIndexMetadata) => { + const objectMetadata = + originalObjectMetadataMap[currentIndexMetadata.objectMetadataId]; + + if (!objectMetadata) { + throw new Error( + `Object metadata with id ${currentIndexMetadata.objectMetadataId} not found`, + ); + } + + if (!indexMetadataByObjectMetadataMap.has(objectMetadata)) { + indexMetadataByObjectMetadataMap.set(objectMetadata, []); + } + + indexMetadataByObjectMetadataMap + ?.get(objectMetadata) + ?.push(currentIndexMetadata); + }); + + switch (action) { + case WorkspaceMigrationBuilderAction.CREATE: + return this.createIndexMigration(indexMetadataByObjectMetadataMap); + case WorkspaceMigrationBuilderAction.DELETE: + return this.deleteIndexMigration(indexMetadataByObjectMetadataMap); + default: + return []; + } + } + + private async createIndexMigration( + indexMetadataByObjectMetadataMap: Map< + ObjectMetadataEntity, + IndexMetadataEntity[] + >, + ): Promise<Partial<WorkspaceMigrationEntity>[]> { + const workspaceMigrations: Partial<WorkspaceMigrationEntity>[] = []; + + for (const [ + objectMetadata, + indexMetadataCollection, + ] of indexMetadataByObjectMetadataMap) { + const targetTable = computeObjectTargetTable(objectMetadata); + + const fieldsById = Object.fromEntries( + objectMetadata.fields.map((field) => [field.id, field]), + ); + + const indexes = indexMetadataCollection.map((indexMetadata) => ({ + name: indexMetadata.name, + action: WorkspaceMigrationIndexActionType.CREATE, + columns: indexMetadata.indexFieldMetadatas + .sort((a, b) => a.order - b.order) + .map((indexFieldMetadata) => { + const fieldMetadata = + fieldsById[indexFieldMetadata.fieldMetadataId]; + + if (!fieldMetadata) { + throw new Error( + `Field metadata with id ${indexFieldMetadata.fieldMetadataId} not found in object metadata with id ${objectMetadata.id}`, + ); + } + + return fieldMetadata.name; + }), + })); + + workspaceMigrations.push({ + workspaceId: objectMetadata.workspaceId, + name: generateMigrationName( + `create-${objectMetadata.nameSingular}-indexes`, + ), + isCustom: false, + migrations: [ + { + name: targetTable, + action: WorkspaceMigrationTableActionType.ALTER_INDEXES, + indexes, + }, + ], + }); + } + + return workspaceMigrations; + } + + private async deleteIndexMigration( + indexMetadataByObjectMetadataMap: Map< + ObjectMetadataEntity, + IndexMetadataEntity[] + >, + ): Promise<Partial<WorkspaceMigrationEntity>[]> { + const workspaceMigrations: Partial<WorkspaceMigrationEntity>[] = []; + + for (const [ + objectMetadata, + indexMetadataCollection, + ] of indexMetadataByObjectMetadataMap) { + const targetTable = computeObjectTargetTable(objectMetadata); + + const indexes = indexMetadataCollection.map((indexMetadata) => ({ + name: indexMetadata.name, + action: WorkspaceMigrationIndexActionType.DROP, + columns: [], + })); + + workspaceMigrations.push({ + workspaceId: objectMetadata.workspaceId, + name: generateMigrationName( + `delete-${objectMetadata.nameSingular}-indexes`, + ), + isCustom: false, + migrations: [ + { + name: targetTable, + action: WorkspaceMigrationTableActionType.ALTER_INDEXES, + indexes, + }, + ], + }); + } + + return workspaceMigrations; + } +} diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-runner/services/workspace-migration-enum.service.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-runner/services/workspace-migration-enum.service.ts index 05ebc0370482..03dd078fa6a6 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-runner/services/workspace-migration-enum.service.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-runner/services/workspace-migration-enum.service.ts @@ -49,10 +49,6 @@ export class WorkspaceMigrationEnumService { typeof enumValue !== 'string', ); - if (!columnDefinition.isNullable && !columnDefinition.defaultValue) { - columnDefinition.defaultValue = serializeDefaultValue(enumValues[0]); - } - const oldColumnName = `${columnDefinition.columnName}_old_${v4()}`; // Rename old column diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-runner/workspace-migration-runner.service.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-runner/workspace-migration-runner.service.ts index 560d9fff4995..c239462a2dbc 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-runner/workspace-migration-runner.service.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-runner/workspace-migration-runner.service.ts @@ -5,6 +5,7 @@ import { Table, TableColumn, TableForeignKey, + TableIndex, TableUnique, } from 'typeorm'; @@ -20,6 +21,8 @@ import { WorkspaceMigrationColumnDropRelation, WorkspaceMigrationTableActionType, WorkspaceMigrationForeignTable, + WorkspaceMigrationIndexAction, + WorkspaceMigrationIndexActionType, } from 'src/engine/metadata-modules/workspace-migration/workspace-migration.entity'; import { WorkspaceCacheVersionService } from 'src/engine/metadata-modules/workspace-cache-version/workspace-cache-version.service'; import { WorkspaceMigrationEnumService } from 'src/engine/workspace-manager/workspace-migration-runner/services/workspace-migration-enum.service'; @@ -137,6 +140,7 @@ export class WorkspaceMigrationRunnerService { tableMigration.columns, ); } + break; } case WorkspaceMigrationTableActionType.DROP: @@ -163,6 +167,17 @@ export class WorkspaceMigrationRunnerService { tableMigration.columns, ); break; + + case WorkspaceMigrationTableActionType.ALTER_INDEXES: + if (tableMigration.indexes && tableMigration.indexes.length > 0) { + await this.handleIndexesChanges( + queryRunner, + schemaName, + tableMigration.newName ?? tableMigration.name, + tableMigration.indexes, + ); + } + break; default: throw new Error( `Migration table action ${tableMigration.action} not supported`, @@ -170,6 +185,32 @@ export class WorkspaceMigrationRunnerService { } } + private async handleIndexesChanges( + queryRunner: QueryRunner, + schemaName: string, + tableName: string, + indexes: WorkspaceMigrationIndexAction[], + ) { + for (const index of indexes) { + switch (index.action) { + case WorkspaceMigrationIndexActionType.CREATE: + await queryRunner.createIndex( + `${schemaName}.${tableName}`, + new TableIndex({ + name: index.name, + columnNames: index.columns, + }), + ); + break; + case WorkspaceMigrationIndexActionType.DROP: + await queryRunner.dropIndex(`${schemaName}.${tableName}`, index.name); + break; + default: + throw new Error(`Migration index action not supported`); + } + } + } + /** * Creates a table for a given schema and table name * diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-status/services/workspace-status.service.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-status/services/workspace-status.service.ts new file mode 100644 index 000000000000..4792e62edd8f --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-status/services/workspace-status.service.ts @@ -0,0 +1,74 @@ +import { Injectable } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; + +import { Any, Repository } from 'typeorm'; + +import { + BillingSubscription, + SubscriptionStatus, +} from 'src/engine/core-modules/billing/entities/billing-subscription.entity'; +import { + FeatureFlagEntity, + FeatureFlagKeys, +} from 'src/engine/core-modules/feature-flag/feature-flag.entity'; +import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; +import { EnvironmentService } from 'src/engine/integrations/environment/environment.service'; + +@Injectable() +export class WorkspaceStatusService { + constructor( + private readonly environmentService: EnvironmentService, + @InjectRepository(Workspace, 'core') + private readonly workspaceRepository: Repository<Workspace>, + @InjectRepository(BillingSubscription, 'core') + private readonly billingSubscriptionRepository: Repository<BillingSubscription>, + @InjectRepository(FeatureFlagEntity, 'core') + private readonly featureFlagRepository: Repository<FeatureFlagEntity>, + ) {} + + async getActiveWorkspaceIds(): Promise<string[]> { + const workspaces = await this.workspaceRepository.find(); + const workspaceIds = workspaces.map((workspace) => workspace.id); + + if (!this.environmentService.get('IS_BILLING_ENABLED')) { + return workspaceIds; + } + + const billingSubscriptionForWorkspaces = + await this.billingSubscriptionRepository.find({ + where: { + workspaceId: Any(workspaceIds), + status: Any([ + SubscriptionStatus.PastDue, + SubscriptionStatus.Active, + SubscriptionStatus.Trialing, + ]), + }, + }); + + const workspaceIdsWithActiveSubscription = + billingSubscriptionForWorkspaces.map( + (billingSubscription) => billingSubscription.workspaceId, + ); + + const freeAccessEnabledFeatureFlagForWorkspace = + await this.featureFlagRepository.find({ + where: { + workspaceId: Any(workspaceIds), + key: FeatureFlagKeys.IsFreeAccessEnabled, + value: true, + }, + }); + + const workspaceIdsWithFreeAccessEnabled = + freeAccessEnabledFeatureFlagForWorkspace.map( + (featureFlag) => featureFlag.workspaceId, + ); + + return workspaceIds.filter( + (workspaceId) => + workspaceIdsWithActiveSubscription.includes(workspaceId) || + workspaceIdsWithFreeAccessEnabled.includes(workspaceId), + ); + } +} diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-status/workspace-manager.module.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-status/workspace-manager.module.ts new file mode 100644 index 000000000000..ac39a9e0c322 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-status/workspace-manager.module.ts @@ -0,0 +1,21 @@ +import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; + +import { BillingSubscription } from 'src/engine/core-modules/billing/entities/billing-subscription.entity'; +import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity'; +import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; +import { EnvironmentModule } from 'src/engine/integrations/environment/environment.module'; +import { WorkspaceStatusService } from 'src/engine/workspace-manager/workspace-status/services/workspace-status.service'; + +@Module({ + imports: [ + EnvironmentModule, + TypeOrmModule.forFeature( + [Workspace, BillingSubscription, FeatureFlagEntity], + 'core', + ), + ], + exports: [WorkspaceStatusService], + providers: [WorkspaceStatusService], +}) +export class WorkspaceStatusModule {} diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/commands/add-standard-id.command.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/commands/add-standard-id.command.ts index be810ced1e81..f351cfabf54f 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/commands/add-standard-id.command.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/commands/add-standard-id.command.ts @@ -4,13 +4,13 @@ import { InjectDataSource } from '@nestjs/typeorm'; import { Command, CommandRunner, Option } from 'nest-commander'; import { DataSource } from 'typeorm'; -import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; -import { standardObjectMetadataDefinitions } from 'src/engine/workspace-manager/workspace-sync-metadata/standard-objects'; -import { StandardObjectFactory } from 'src/engine/workspace-manager/workspace-sync-metadata/factories/standard-object.factory'; -import { computeStandardObject } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/compute-standard-object.util'; -import { StandardFieldFactory } from 'src/engine/workspace-manager/workspace-sync-metadata/factories/standard-field.factory'; +import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { CustomWorkspaceEntity } from 'src/engine/twenty-orm/custom.workspace-entity'; +import { StandardFieldFactory } from 'src/engine/workspace-manager/workspace-sync-metadata/factories/standard-field.factory'; +import { StandardObjectFactory } from 'src/engine/workspace-manager/workspace-sync-metadata/factories/standard-object.factory'; +import { standardObjectMetadataDefinitions } from 'src/engine/workspace-manager/workspace-sync-metadata/standard-objects'; +import { computeStandardFields } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/compute-standard-fields.util'; interface RunCommandOptions { workspaceId?: string; @@ -58,7 +58,10 @@ export class AddStandardIdCommand extends CommandRunner { IS_AIRTABLE_INTEGRATION_ENABLED: true, IS_POSTGRESQL_INTEGRATION_ENABLED: true, IS_STRIPE_INTEGRATION_ENABLED: false, - IS_CONTACT_CREATION_FOR_SENT_AND_RECEIVED_EMAILS_ENABLED: true, + IS_COPILOT_ENABLED: false, + IS_MESSAGING_ALIAS_FETCHING_ENABLED: true, + IS_GOOGLE_CALENDAR_SYNC_V2_ENABLED: true, + IS_FREE_ACCESS_ENABLED: false, }, ); const standardFieldMetadataCollection = this.standardFieldFactory.create( @@ -73,7 +76,10 @@ export class AddStandardIdCommand extends CommandRunner { IS_AIRTABLE_INTEGRATION_ENABLED: true, IS_POSTGRESQL_INTEGRATION_ENABLED: true, IS_STRIPE_INTEGRATION_ENABLED: false, - IS_CONTACT_CREATION_FOR_SENT_AND_RECEIVED_EMAILS_ENABLED: true, + IS_COPILOT_ENABLED: false, + IS_MESSAGING_ALIAS_FETCHING_ENABLED: true, + IS_GOOGLE_CALENDAR_SYNC_V2_ENABLED: true, + IS_FREE_ACCESS_ENABLED: false, }, ); @@ -117,11 +123,8 @@ export class AddStandardIdCommand extends CommandRunner { continue; } - const computedStandardObjectMetadata = computeStandardObject( - standardObjectMetadata ?? { - ...originalObjectMetadata, - fields: standardFieldMetadataCollection, - }, + const computedStandardFieldMetadataCollection = computeStandardFields( + standardFieldMetadataCollection, originalObjectMetadata, customObjectMetadataCollection, ); @@ -129,13 +132,13 @@ export class AddStandardIdCommand extends CommandRunner { if (!originalObjectMetadata.isCustom) { updateObjectMetadataCollection.push({ id: originalObjectMetadata.id, - standardId: computedStandardObjectMetadata.standardId, + standardId: originalObjectMetadata.standardId, }); } for (const fieldMetadata of originalObjectMetadata.fields) { const standardFieldMetadata = - computedStandardObjectMetadata.fields.find( + computedStandardFieldMetadataCollection.find( (field) => field.name === fieldMetadata.name && !field.isCustom, ); diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/commands/sync-workspace-metadata.command.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/commands/sync-workspace-metadata.command.ts index b6d15d677bd5..46313f69571d 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/commands/sync-workspace-metadata.command.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/commands/sync-workspace-metadata.command.ts @@ -1,19 +1,20 @@ import { Logger } from '@nestjs/common'; +import isEmpty from 'lodash.isempty'; import { Command, CommandRunner, Option } from 'nest-commander'; import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; -import { WorkspaceSyncMetadataService } from 'src/engine/workspace-manager/workspace-sync-metadata/workspace-sync-metadata.service'; import { WorkspaceHealthService } from 'src/engine/workspace-manager/workspace-health/workspace-health.service'; -import { WorkspaceService } from 'src/engine/core-modules/workspace/services/workspace.service'; +import { WorkspaceStatusService } from 'src/engine/workspace-manager/workspace-status/services/workspace-status.service'; +import { WorkspaceSyncMetadataService } from 'src/engine/workspace-manager/workspace-sync-metadata/workspace-sync-metadata.service'; import { SyncWorkspaceLoggerService } from './services/sync-workspace-logger.service'; // TODO: implement dry-run interface RunWorkspaceMigrationsOptions { - workspaceId?: string; dryRun?: boolean; force?: boolean; + workspaceId?: string; } @Command({ @@ -28,7 +29,7 @@ export class SyncWorkspaceMetadataCommand extends CommandRunner { private readonly workspaceHealthService: WorkspaceHealthService, private readonly dataSourceService: DataSourceService, private readonly syncWorkspaceLoggerService: SyncWorkspaceLoggerService, - private readonly workspaceService: WorkspaceService, + private readonly workspaceStatusService: WorkspaceStatusService, ) { super(); } @@ -37,9 +38,20 @@ export class SyncWorkspaceMetadataCommand extends CommandRunner { _passedParam: string[], options: RunWorkspaceMigrationsOptions, ): Promise<void> { - const workspaceIds = options.workspaceId - ? [options.workspaceId] - : await this.workspaceService.getWorkspaceIds(); + // TODO: re-implement load index from workspaceService, this is breaking the logger + let workspaceIds = options.workspaceId ? [options.workspaceId] : []; + + if (isEmpty(workspaceIds)) { + const activeWorkspaceIds = + await this.workspaceStatusService.getActiveWorkspaceIds(); + + workspaceIds = activeWorkspaceIds; + this.logger.log( + `Attempting to sync ${activeWorkspaceIds.length} workspaces.`, + ); + } + + const errorsDuringSync: string[] = []; for (const workspaceId of workspaceIds) { try { @@ -60,7 +72,7 @@ export class SyncWorkspaceMetadataCommand extends CommandRunner { 'Please use `workspace:health` command to check issues and fix them before running this command.', ); - return; + continue; } this.logger.warn( @@ -78,28 +90,46 @@ export class SyncWorkspaceMetadataCommand extends CommandRunner { ); } - const dataSourceMetadata = - await this.dataSourceService.getLastDataSourceMetadataFromWorkspaceIdOrFail( - workspaceId, - ); + try { + const dataSourceMetadata = + await this.dataSourceService.getLastDataSourceMetadataFromWorkspaceIdOrFail( + workspaceId, + ); - const { storage, workspaceMigrations } = - await this.workspaceSyncMetadataService.synchronize( - { + const { storage, workspaceMigrations } = + await this.workspaceSyncMetadataService.synchronize( + { + workspaceId, + dataSourceId: dataSourceMetadata.id, + }, + { applyChanges: !options.dryRun }, + ); + + if (options.dryRun) { + await this.syncWorkspaceLoggerService.saveLogs( workspaceId, - dataSourceId: dataSourceMetadata.id, - }, - { applyChanges: !options.dryRun }, + storage, + workspaceMigrations, + ); + } + } catch (error) { + errorsDuringSync.push( + `Failed to synchronize workspace ${workspaceId}: ${error.message}`, ); - if (options.dryRun) { - await this.syncWorkspaceLoggerService.saveLogs( - workspaceId, - storage, - workspaceMigrations, - ); + continue; } } + + this.logger.log( + `Finished synchronizing all active workspaces (${ + workspaceIds.length + } workspaces). ${ + errorsDuringSync.length > 0 + ? 'Errors during sync:\n' + errorsDuringSync.join('.\n') + : '' + }`, + ); } @Option({ diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/commands/workspace-sync-metadata-commands.module.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/commands/workspace-sync-metadata-commands.module.ts index 8e30f0c418fb..1178966443ab 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/commands/workspace-sync-metadata-commands.module.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/commands/workspace-sync-metadata-commands.module.ts @@ -1,12 +1,15 @@ import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; +import { WorkspaceModule } from 'src/engine/core-modules/workspace/workspace.module'; import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module'; -import { WorkspaceSyncMetadataModule } from 'src/engine/workspace-manager/workspace-sync-metadata/workspace-sync-metadata.module'; +import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; import { WorkspaceHealthModule } from 'src/engine/workspace-manager/workspace-health/workspace-health.module'; -import { WorkspaceModule } from 'src/engine/core-modules/workspace/workspace.module'; +import { WorkspaceStatusModule } from 'src/engine/workspace-manager/workspace-status/workspace-manager.module'; import { AddStandardIdCommand } from 'src/engine/workspace-manager/workspace-sync-metadata/commands/add-standard-id.command'; import { ConvertRecordPositionsToIntegers } from 'src/engine/workspace-manager/workspace-sync-metadata/commands/convert-record-positions-to-integers.command'; -import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; +import { WorkspaceSyncMetadataModule } from 'src/engine/workspace-manager/workspace-sync-metadata/workspace-sync-metadata.module'; import { SyncWorkspaceMetadataCommand } from './sync-workspace-metadata.command'; @@ -19,6 +22,8 @@ import { SyncWorkspaceLoggerService } from './services/sync-workspace-logger.ser WorkspaceModule, DataSourceModule, WorkspaceDataSourceModule, + TypeOrmModule.forFeature([Workspace], 'core'), + WorkspaceStatusModule, ], providers: [ SyncWorkspaceMetadataCommand, diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/comparators/__tests__/workspace-field.comparator.spec.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/comparators/__tests__/workspace-field.comparator.spec.ts index e4deb708c3a6..3df3f57398fe 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/comparators/__tests__/workspace-field.comparator.spec.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/comparators/__tests__/workspace-field.comparator.spec.ts @@ -36,7 +36,7 @@ describe('WorkspaceFieldComparator', () => { ], } as any; - const result = comparator.compare(original, standard); + const result = comparator.compare('', original.fields, standard.fields); expect(result).toEqual([ { @@ -65,7 +65,7 @@ describe('WorkspaceFieldComparator', () => { ], } as any; - const result = comparator.compare(original, standard); + const result = comparator.compare('', original.fields, standard.fields); expect(result).toEqual([ { @@ -88,7 +88,7 @@ describe('WorkspaceFieldComparator', () => { } as any; const standard = { fields: [] } as any; - const result = comparator.compare(original, standard); + const result = comparator.compare('', original.fields, standard.fields); expect(result).toEqual([ { @@ -108,7 +108,7 @@ describe('WorkspaceFieldComparator', () => { fields: [createMockFieldMetadata({ standardId: '1' })], } as any; - const result = comparator.compare(original, standard); + const result = comparator.compare('', original.fields, standard.fields); expect(result).toHaveLength(0); }); diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/comparators/index.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/comparators/index.ts index 3c95f7babe3f..2f29fbf41f5b 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/comparators/index.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/comparators/index.ts @@ -1,3 +1,5 @@ +import { WorkspaceIndexComparator } from 'src/engine/workspace-manager/workspace-sync-metadata/comparators/workspace-index.comparator'; + import { WorkspaceFieldComparator } from './workspace-field.comparator'; import { WorkspaceObjectComparator } from './workspace-object.comparator'; import { WorkspaceRelationComparator } from './workspace-relation.comparator'; @@ -6,4 +8,5 @@ export const workspaceSyncMetadataComparators = [ WorkspaceFieldComparator, WorkspaceObjectComparator, WorkspaceRelationComparator, + WorkspaceIndexComparator, ]; diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/comparators/workspace-field.comparator.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/comparators/workspace-field.comparator.ts index eaf55f33a446..7e51a398f9be 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/comparators/workspace-field.comparator.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/comparators/workspace-field.comparator.ts @@ -7,14 +7,12 @@ import { FieldComparatorResult, } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/comparator.interface'; import { ComputedPartialFieldMetadata } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/partial-field-metadata.interface'; -import { ComputedPartialWorkspaceEntity } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/partial-object-metadata.interface'; -import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; -import { transformMetadataForComparison } from 'src/engine/workspace-manager/workspace-sync-metadata/comparators/utils/transform-metadata-for-comparison.util'; import { FieldMetadataEntity, FieldMetadataType, } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; +import { transformMetadataForComparison } from 'src/engine/workspace-manager/workspace-sync-metadata/comparators/utils/transform-metadata-for-comparison.util'; const commonFieldPropertiesToIgnore = [ 'id', @@ -30,13 +28,20 @@ const commonFieldPropertiesToIgnore = [ const fieldPropertiesToStringify = ['defaultValue'] as const; +const shouldSkipFieldCreation = ( + standardFieldMetadata: ComputedPartialFieldMetadata | undefined, +) => { + return standardFieldMetadata?.isCustom; +}; + @Injectable() export class WorkspaceFieldComparator { constructor() {} public compare( - originalObjectMetadata: ObjectMetadataEntity, - standardObjectMetadata: ComputedPartialWorkspaceEntity, + originalObjectMetadataId: string, + originalFieldMetadataCollection: FieldMetadataEntity[], + standardFieldMetadataCollection: ComputedPartialFieldMetadata[], ): FieldComparatorResult[] { const result: FieldComparatorResult[] = []; const fieldPropertiesToUpdateMap: Record< @@ -46,7 +51,7 @@ export class WorkspaceFieldComparator { // Double security to only compare non-custom fields const filteredOriginalFieldCollection = - originalObjectMetadata.fields.filter((field) => !field.isCustom); + originalFieldMetadataCollection.filter((field) => !field.isCustom); const originalFieldMetadataMap = transformMetadataForComparison( filteredOriginalFieldCollection, { @@ -73,7 +78,7 @@ export class WorkspaceFieldComparator { }, ); const standardFieldMetadataMap = transformMetadataForComparison( - standardObjectMetadata.fields, + standardFieldMetadataCollection, { shouldIgnoreProperty: (property, originalMetadata) => { if (commonFieldPropertiesToIgnore.includes(property)) { @@ -109,20 +114,19 @@ export class WorkspaceFieldComparator { const findField = ( field: ComputedPartialFieldMetadata | FieldMetadataEntity, ) => { - if (field.isCustom) { - return field.name === fieldName; - } - return field.standardId === fieldName; }; // Object shouldn't have thousands of fields, so we can use find here const standardFieldMetadata = - standardObjectMetadata.fields.find(findField); + standardFieldMetadataCollection.find(findField); const originalFieldMetadata = - originalObjectMetadata.fields.find(findField); + originalFieldMetadataCollection.find(findField); switch (difference.type) { case 'CREATE': { + if (shouldSkipFieldCreation(standardFieldMetadata)) { + break; + } if (!standardFieldMetadata) { throw new Error( `Field ${fieldName} not found in standardObjectMetadata`, @@ -133,7 +137,7 @@ export class WorkspaceFieldComparator { action: ComparatorAction.CREATE, object: { ...standardFieldMetadata, - objectMetadataId: originalObjectMetadata.id, + objectMetadataId: originalObjectMetadataId, }, }); break; diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/comparators/workspace-index.comparator.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/comparators/workspace-index.comparator.ts new file mode 100644 index 000000000000..5fbf2ad9756d --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/comparators/workspace-index.comparator.ts @@ -0,0 +1,90 @@ +import { Injectable } from '@nestjs/common'; + +import diff from 'microdiff'; + +import { + IndexComparatorResult, + ComparatorAction, +} from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/comparator.interface'; + +import { IndexMetadataEntity } from 'src/engine/metadata-modules/index-metadata/index-metadata.entity'; +import { transformMetadataForComparison } from 'src/engine/workspace-manager/workspace-sync-metadata/comparators/utils/transform-metadata-for-comparison.util'; + +const propertiesToIgnore = ['createdAt', 'updatedAt', 'indexFieldMetadatas']; + +@Injectable() +export class WorkspaceIndexComparator { + constructor() {} + + compare( + originalIndexMetadataCollection: IndexMetadataEntity[], + standardIndexMetadataCollection: Partial<IndexMetadataEntity>[], + ): IndexComparatorResult[] { + const results: IndexComparatorResult[] = []; + + // Create a map of standard relations + const standardIndexMetadataMap = transformMetadataForComparison( + standardIndexMetadataCollection, + { + keyFactory(indexMetadata) { + return `${indexMetadata.name}`; + }, + }, + ); + + const originalIndexMetadataCollectionWithColumns = + originalIndexMetadataCollection.map((indexMetadata) => { + return { + ...indexMetadata, + columns: indexMetadata.indexFieldMetadatas.map( + (indexFieldMetadata) => indexFieldMetadata.fieldMetadata.name, + ), + indexFieldMetadatas: undefined, + }; + }); + + // Create a filtered map of original relations + // We filter out 'id' later because we need it to remove the relation from DB + const originalIndexMetadataMap = transformMetadataForComparison( + originalIndexMetadataCollectionWithColumns, + { + shouldIgnoreProperty: (property) => + propertiesToIgnore.includes(property), + keyFactory(indexMetadata) { + return `${indexMetadata.name}`; + }, + }, + ); + + // Compare indexes + const indexesDifferences = diff( + originalIndexMetadataMap, + standardIndexMetadataMap, + ); + + for (const difference of indexesDifferences) { + switch (difference.type) { + case 'CREATE': { + results.push({ + action: ComparatorAction.CREATE, + object: difference.value, + }); + break; + } + case 'REMOVE': { + if (difference.path[difference.path.length - 1] !== 'id') { + results.push({ + action: ComparatorAction.DELETE, + object: difference.oldValue, + }); + } + break; + } + default: + break; + } + } + + return results; + } +} diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/comparators/workspace-object.comparator.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/comparators/workspace-object.comparator.ts index 9ab7f2f27f0d..eaa37da7cf84 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/comparators/workspace-object.comparator.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/comparators/workspace-object.comparator.ts @@ -27,8 +27,8 @@ export class WorkspaceObjectComparator { constructor() {} public compare( - originalObjectMetadata: ObjectMetadataEntity | undefined, - standardObjectMetadata: ComputedPartialWorkspaceEntity, + originalObjectMetadata: Omit<ObjectMetadataEntity, 'fields'> | undefined, + standardObjectMetadata: Omit<ComputedPartialWorkspaceEntity, 'fields'>, ): ObjectComparatorResult { // If the object doesn't exist in the original metadata, we need to create it if (!originalObjectMetadata) { diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids.ts index 21910d0a758e..0778c007c325 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids.ts @@ -67,10 +67,14 @@ export const CALENDAR_CHANNEL_STANDARD_FIELD_IDS = { handle: '20202020-1d08-420a-9aa7-22e0f298232d', visibility: '20202020-1b07-4796-9f01-d626bab7ca4d', isContactAutoCreationEnabled: '20202020-50fb-404b-ba28-369911a3793a', + contactAutoCreationPolicy: '20202020-b55d-447d-b4df-226319058775', isSyncEnabled: '20202020-fe19-4818-8854-21f7b1b43395', syncCursor: '20202020-bac2-4852-a5cb-7a7898992b70', calendarChannelEventAssociations: '20202020-afb0-4a9f-979f-2d5087d71d09', throttleFailureCount: '20202020-525c-4b76-b9bd-0dd57fd11d61', + syncStatus: '20202020-7116-41da-8b4b-035975c4eb6a', + syncStage: '20202020-6246-42e6-b5cd-003bd921782c', + syncStageStartedAt: '20202020-a934-46f1-a8e7-9568b1e3a53e', }; export const CALENDAR_EVENT_PARTICIPANT_STANDARD_FIELD_IDS = { @@ -110,7 +114,8 @@ export const COMMENT_STANDARD_FIELD_IDS = { export const COMPANY_STANDARD_FIELD_IDS = { name: '20202020-4d99-4e2e-a84c-4a27837b1ece', domainName: '20202020-0c28-43d8-8ba5-3659924d3489', - address: '20202020-a82a-4ee2-96cc-a18a3259d953', + address_deprecated: '20202020-a82a-4ee2-96cc-a18a3259d953', + address: '20202020-c5ce-4adc-b7b6-9c0979fc55e7', employees: '20202020-8965-464a-8a75-74bafc152a0b', linkedinLink: '20202020-ebeb-4beb-b9ad-6848036fb451', xLink: '20202020-6f64-4fd9-9580-9c1991c7d8c3', @@ -136,6 +141,7 @@ export const CONNECTED_ACCOUNT_STANDARD_FIELD_IDS = { authFailedAt: '20202020-d268-4c6b-baff-400d402b430a', messageChannels: '20202020-24f7-4362-8468-042204d1e445', calendarChannels: '20202020-af4a-47bb-99ec-51911c1d3977', + handleAliases: '20202020-8a3d-46be-814f-6228af16c47b', }; export const EVENT_STANDARD_FIELD_IDS = { @@ -152,6 +158,7 @@ export const AUDIT_LOGS_STANDARD_FIELD_IDS = { properties: '20202020-5d36-470e-8fad-d56ea3ab2fd0', context: '20202020-b9d1-4058-9a75-7469cab5ca8c', objectName: '20202020-76ba-4c47-b7e5-96034005d00a', + objectMetadataId: '20202020-127b-409d-9864-0ec44aa9ed98', recordId: '20202020-c578-4acf-bf94-eb53b035cea2', workspaceMember: '20202020-6e96-4300-b3f5-67a707147385', }; @@ -202,6 +209,9 @@ export const MESSAGE_CHANNEL_STANDARD_FIELD_IDS = { connectedAccount: '20202020-49a2-44a4-b470-282c0440d15d', type: '20202020-ae95-42d9-a3f1-797a2ea22122', isContactAutoCreationEnabled: '20202020-fabd-4f14-b7c6-3310f6d132c6', + contactAutoCreationPolicy: '20202020-fc0e-4ba6-b259-a66ca89cfa38', + excludeNonProfessionalEmails: '20202020-1df5-445d-b4f3-2413ad178431', + excludeGroupEmails: '20202020-45a0-4be4-9164-5820a6a109fb', messageChannelMessageAssociations: '20202020-49b8-4766-88fd-75f1e21b3d5f', isSyncEnabled: '20202020-d9a6-48e9-990b-b97fdf22e8dd', syncCursor: '20202020-79d1-41cf-b738-bcf5ed61e256', @@ -241,7 +251,7 @@ export const OPPORTUNITY_STANDARD_FIELD_IDS = { name: '20202020-8609-4f65-a2d9-44009eb422b5', amount: '20202020-583e-4642-8533-db761d5fa82f', closeDate: '20202020-527e-44d6-b1ac-c4158d307b97', - probability: '20202020-69d4-45f3-9703-690b09fafcf0', + probabilityDeprecated: '20202020-69d4-45f3-9703-690b09fafcf0', stage: '20202020-6f76-477d-8551-28cd65b2b4b9', position: '20202020-806d-493a-bbc6-6313e62958e2', pointOfContact: '20202020-8dfb-42fc-92b6-01afb759ed16', diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/factories/index.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/factories/index.ts index 72185436922b..958bf346cae7 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/factories/index.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/factories/index.ts @@ -1,3 +1,5 @@ +import { StandardIndexFactory } from 'src/engine/workspace-manager/workspace-sync-metadata/factories/standard-index.factory'; + import { FeatureFlagFactory } from './feature-flags.factory'; import { StandardFieldFactory } from './standard-field.factory'; import { StandardObjectFactory } from './standard-object.factory'; @@ -8,4 +10,5 @@ export const workspaceSyncMetadataFactories = [ StandardFieldFactory, StandardObjectFactory, StandardRelationFactory, + StandardIndexFactory, ]; diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/factories/standard-field.factory.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/factories/standard-field.factory.ts index 07bb1ef059d2..eff6dedbdb0f 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/factories/standard-field.factory.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/factories/standard-field.factory.ts @@ -16,6 +16,7 @@ import { metadataArgsStorage } from 'src/engine/twenty-orm/storage/metadata-args import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity'; import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; import { createDeterministicUuid } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/create-deterministic-uuid.util'; +import { getJoinColumn } from 'src/engine/twenty-orm/utils/get-join-column.util'; @Injectable() export class StandardFieldFactory { @@ -23,10 +24,53 @@ export class StandardFieldFactory { target: typeof BaseWorkspaceEntity, context: WorkspaceSyncContext, workspaceFeatureFlagsMap: FeatureFlagMap, - ): Array<PartialFieldMetadata | PartialComputedFieldMetadata> { + ): (PartialFieldMetadata | PartialComputedFieldMetadata)[]; + + create( + targets: (typeof BaseWorkspaceEntity)[], + context: WorkspaceSyncContext, + workspaceFeatureFlagsMap: FeatureFlagMap, // Map of standardId to field metadata + ): Map<string, (PartialFieldMetadata | PartialComputedFieldMetadata)[]>; + + create( + targetOrTargets: + | typeof BaseWorkspaceEntity + | (typeof BaseWorkspaceEntity)[], + context: WorkspaceSyncContext, + workspaceFeatureFlagsMap: FeatureFlagMap, + ): + | (PartialFieldMetadata | PartialComputedFieldMetadata)[] + | Map<string, (PartialFieldMetadata | PartialComputedFieldMetadata)[]> { + if (Array.isArray(targetOrTargets)) { + return targetOrTargets.reduce((acc, target) => { + const workspaceEntityMetadataArgs = + metadataArgsStorage.filterEntities(target); + + if (!workspaceEntityMetadataArgs) { + return acc; + } + + if ( + isGatedAndNotEnabled( + workspaceEntityMetadataArgs.gate, + workspaceFeatureFlagsMap, + ) + ) { + return acc; + } + + acc.set( + workspaceEntityMetadataArgs.standardId, + this.create(target, context, workspaceFeatureFlagsMap), + ); + + return acc; + }, new Map<string, (PartialFieldMetadata | PartialComputedFieldMetadata)[]>()); + } + const workspaceEntityMetadataArgs = - metadataArgsStorage.filterEntities(target); - const metadataCollections = this.collectMetadata(target); + metadataArgsStorage.filterEntities(targetOrTargets); + const metadataCollections = this.collectMetadata(targetOrTargets); return [ ...this.processMetadata( @@ -118,7 +162,7 @@ export class StandardFieldFactory { options: workspaceFieldMetadataArgs.options, workspaceId: context.workspaceId, isNullable: workspaceFieldMetadataArgs.isNullable, - isCustom: false, + isCustom: workspaceFieldMetadataArgs.isDeprecated ? true : false, isSystem: workspaceEntityMetadataArgs?.isSystem || workspaceFieldMetadataArgs.isSystem, @@ -139,6 +183,14 @@ export class StandardFieldFactory { const foreignKeyStandardId = createDeterministicUuid( workspaceRelationMetadataArgs.standardId, ); + const joinColumnMetadataArgsCollection = + metadataArgsStorage.filterJoinColumns( + workspaceRelationMetadataArgs.target, + ); + const joinColumn = getJoinColumn( + joinColumnMetadataArgsCollection, + workspaceRelationMetadataArgs, + ); if ( isGatedAndNotEnabled( @@ -149,11 +201,11 @@ export class StandardFieldFactory { return []; } - if (workspaceRelationMetadataArgs.joinColumn) { + if (joinColumn) { fieldMetadataCollection.push({ type: FieldMetadataType.UUID, standardId: foreignKeyStandardId, - name: workspaceRelationMetadataArgs.joinColumn, + name: joinColumn, label: `${workspaceRelationMetadataArgs.label} id (foreign key)`, description: `${workspaceRelationMetadataArgs.description} id foreign key`, icon: workspaceRelationMetadataArgs.icon, diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/factories/standard-index.factory.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/factories/standard-index.factory.ts new file mode 100644 index 000000000000..83e450cbe90b --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/factories/standard-index.factory.ts @@ -0,0 +1,69 @@ +import { Injectable } from '@nestjs/common'; + +import { FeatureFlagMap } from 'src/engine/core-modules/feature-flag/interfaces/feature-flag-map.interface'; +import { PartialIndexMetadata } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/partial-index-metadata.interface'; +import { WorkspaceSyncContext } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/workspace-sync-context.interface'; + +import { IndexMetadataEntity } from 'src/engine/metadata-modules/index-metadata/index-metadata.entity'; +import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; +import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity'; +import { metadataArgsStorage } from 'src/engine/twenty-orm/storage/metadata-args.storage'; + +@Injectable() +export class StandardIndexFactory { + create( + standardObjectMetadataDefinitions: (typeof BaseWorkspaceEntity)[], + context: WorkspaceSyncContext, + originalObjectMetadataMap: Record<string, ObjectMetadataEntity>, + workspaceFeatureFlagsMap: FeatureFlagMap, + ): Partial<IndexMetadataEntity>[] { + return standardObjectMetadataDefinitions.flatMap((standardObjectMetadata) => + this.createIndexMetadata( + standardObjectMetadata, + context, + originalObjectMetadataMap, + workspaceFeatureFlagsMap, + ), + ); + } + + private createIndexMetadata( + target: typeof BaseWorkspaceEntity, + context: WorkspaceSyncContext, + originalObjectMetadataMap: Record<string, ObjectMetadataEntity>, + _workspaceFeatureFlagsMap: FeatureFlagMap, + ): Partial<IndexMetadataEntity>[] { + const workspaceEntity = metadataArgsStorage.filterEntities(target); + + if (!workspaceEntity) { + throw new Error( + `Object metadata decorator not found, can't parse ${target.name}`, + ); + } + + const workspaceIndexMetadataArgsCollection = + metadataArgsStorage.filterIndexes(target); + + return workspaceIndexMetadataArgsCollection.map( + (workspaceIndexMetadataArgs) => { + const objectMetadata = + originalObjectMetadataMap[workspaceEntity.nameSingular]; + + if (!objectMetadata) { + throw new Error( + `Object metadata not found for ${workspaceEntity.nameSingular}`, + ); + } + + const indexMetadata: PartialIndexMetadata = { + workspaceId: context.workspaceId, + objectMetadataId: objectMetadata.id, + name: workspaceIndexMetadataArgs.name, + columns: workspaceIndexMetadataArgs.columns, + }; + + return indexMetadata; + }, + ); + } +} diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/factories/standard-object.factory.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/factories/standard-object.factory.ts index 9a907f3c3d65..72e29753e992 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/factories/standard-object.factory.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/factories/standard-object.factory.ts @@ -8,17 +8,13 @@ import { isGatedAndNotEnabled } from 'src/engine/workspace-manager/workspace-syn import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity'; import { metadataArgsStorage } from 'src/engine/twenty-orm/storage/metadata-args.storage'; -import { StandardFieldFactory } from './standard-field.factory'; - @Injectable() export class StandardObjectFactory { - constructor(private readonly standardFieldFactory: StandardFieldFactory) {} - create( standardObjectMetadataDefinitions: (typeof BaseWorkspaceEntity)[], context: WorkspaceSyncContext, workspaceFeatureFlagsMap: FeatureFlagMap, - ): PartialWorkspaceEntity[] { + ): Omit<PartialWorkspaceEntity, 'fields'>[] { return standardObjectMetadataDefinitions .map((metadata) => this.createObjectMetadata(metadata, context, workspaceFeatureFlagsMap), @@ -30,7 +26,7 @@ export class StandardObjectFactory { target: typeof BaseWorkspaceEntity, context: WorkspaceSyncContext, workspaceFeatureFlagsMap: FeatureFlagMap, - ): PartialWorkspaceEntity | undefined { + ): Omit<PartialWorkspaceEntity, 'fields'> | undefined { const workspaceEntityMetadataArgs = metadataArgsStorage.filterEntities(target); @@ -49,12 +45,6 @@ export class StandardObjectFactory { return undefined; } - const fields = this.standardFieldFactory.create( - target, - context, - workspaceFeatureFlagsMap, - ); - return { ...workspaceEntityMetadataArgs, // TODO: Remove targetTableName when we remove the old metadata @@ -64,7 +54,6 @@ export class StandardObjectFactory { isCustom: false, isRemote: false, isSystem: workspaceEntityMetadataArgs.isSystem ?? false, - fields, }; } } diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/interfaces/comparator.interface.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/interfaces/comparator.interface.ts index efc061bc73ac..b4279b5d2397 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/interfaces/comparator.interface.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/interfaces/comparator.interface.ts @@ -1,5 +1,6 @@ import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; import { RelationMetadataEntity } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity'; +import { IndexMetadataEntity } from 'src/engine/metadata-modules/index-metadata/index-metadata.entity'; import { ComputedPartialFieldMetadata } from './partial-field-metadata.interface'; import { ComputedPartialWorkspaceEntity } from './partial-object-metadata.interface'; @@ -32,9 +33,9 @@ export interface ComparatorDeleteResult<T> { export type ObjectComparatorResult = | ComparatorSkipResult - | ComparatorCreateResult<ComputedPartialWorkspaceEntity> + | ComparatorCreateResult<Omit<ComputedPartialWorkspaceEntity, 'fields'>> | ComparatorUpdateResult< - Partial<ComputedPartialWorkspaceEntity> & { id: string } + Partial<Omit<ComputedPartialWorkspaceEntity, 'fields'>> & { id: string } >; export type FieldComparatorResult = @@ -49,3 +50,8 @@ export type RelationComparatorResult = | ComparatorCreateResult<Partial<RelationMetadataEntity>> | ComparatorDeleteResult<RelationMetadataEntity> | ComparatorUpdateResult<Partial<RelationMetadataEntity>>; + +export type IndexComparatorResult = + | ComparatorCreateResult<Partial<IndexMetadataEntity>> + | ComparatorUpdateResult<Partial<IndexMetadataEntity>> + | ComparatorDeleteResult<IndexMetadataEntity>; diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/interfaces/partial-index-metadata.interface.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/interfaces/partial-index-metadata.interface.ts new file mode 100644 index 000000000000..26939eaa740a --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/interfaces/partial-index-metadata.interface.ts @@ -0,0 +1,8 @@ +import { IndexMetadataEntity } from 'src/engine/metadata-modules/index-metadata/index-metadata.entity'; + +export type PartialIndexMetadata = Omit< + IndexMetadataEntity, + 'id' | 'objectMetadata' | 'indexFieldMetadatas' | 'createdAt' | 'updatedAt' +> & { + columns: string[]; +}; diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/services/workspace-metadata-updater.service.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/services/workspace-metadata-updater.service.ts index 5ba73cbcc203..1ae597c2d985 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/services/workspace-metadata-updater.service.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/services/workspace-metadata-updater.service.ts @@ -11,6 +11,7 @@ import { v4 as uuidV4 } from 'uuid'; import { DeepPartial } from 'typeorm/common/DeepPartial'; import { PartialFieldMetadata } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/partial-field-metadata.interface'; +import { PartialIndexMetadata } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/partial-index-metadata.interface'; import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { @@ -22,6 +23,7 @@ import { FieldMetadataComplexOption } from 'src/engine/metadata-modules/field-me import { WorkspaceSyncStorage } from 'src/engine/workspace-manager/workspace-sync-metadata/storage/workspace-sync.storage'; import { FieldMetadataUpdate } from 'src/engine/workspace-manager/workspace-migration-builder/factories/workspace-migration-field.factory'; import { ObjectMetadataUpdate } from 'src/engine/workspace-manager/workspace-migration-builder/factories/workspace-migration-object.factory'; +import { IndexMetadataEntity } from 'src/engine/metadata-modules/index-metadata/index-metadata.entity'; @Injectable() export class WorkspaceMetadataUpdaterService { @@ -45,9 +47,6 @@ export class WorkspaceMetadataUpdaterService { storage.objectMetadataCreateCollection.map((objectMetadata) => ({ ...objectMetadata, isActive: true, - fields: objectMetadata.fields.map((field) => - this.prepareFieldMetadataForCreation(field), - ), })) as DeepPartial<ObjectMetadataEntity>[], ); const identifiers = createdPartialObjectMetadataCollection.map( @@ -126,16 +125,6 @@ export class WorkspaceMetadataUpdaterService { updatedFieldMetadataCollection: FieldMetadataUpdate[]; }> { const fieldMetadataRepository = manager.getRepository(FieldMetadataEntity); - - /** - * Create field metadata - */ - const createdFieldMetadataCollection = await fieldMetadataRepository.save( - storage.fieldMetadataCreateCollection.map((field) => - this.prepareFieldMetadataForCreation(field), - ) as DeepPartial<FieldMetadataEntity>[], - ); - /** * Update field metadata */ @@ -146,6 +135,15 @@ export class WorkspaceMetadataUpdaterService { 'workspaceId', ]); + /** + * Create field metadata + */ + const createdFieldMetadataCollection = await fieldMetadataRepository.save( + storage.fieldMetadataCreateCollection.map((field) => + this.prepareFieldMetadataForCreation(field), + ) as DeepPartial<FieldMetadataEntity>[], + ); + /** * Delete field metadata */ @@ -230,6 +228,69 @@ export class WorkspaceMetadataUpdaterService { }; } + async updateIndexMetadata( + manager: EntityManager, + storage: WorkspaceSyncStorage, + originalObjectMetadataCollection: ObjectMetadataEntity[], + ): Promise<{ + createdIndexMetadataCollection: IndexMetadataEntity[]; + }> { + const indexMetadataRepository = manager.getRepository(IndexMetadataEntity); + + const convertIndexMetadataForSaving = ( + indexMetadata: PartialIndexMetadata, + ) => { + const convertIndexFieldMetadataForSaving = ( + column: string, + order: number, + ) => { + const fieldMetadata = originalObjectMetadataCollection + .find((object) => object.id === indexMetadata.objectMetadataId) + ?.fields.find((field) => column === field.name); + + if (!fieldMetadata) { + throw new Error(` + Field metadata not found for column ${column} in object ${indexMetadata.objectMetadataId} + `); + } + + return { + fieldMetadataId: fieldMetadata.id, + order, + }; + }; + + return { + ...indexMetadata, + indexFieldMetadatas: indexMetadata.columns.map((column, index) => + convertIndexFieldMetadataForSaving(column, index), + ), + }; + }; + + /** + * Create index metadata + */ + const createdIndexMetadataCollection = await indexMetadataRepository.save( + storage.indexMetadataCreateCollection.map(convertIndexMetadataForSaving), + ); + + /** + * Delete index metadata + */ + if (storage.indexMetadataDeleteCollection.length > 0) { + await indexMetadataRepository.delete( + storage.indexMetadataDeleteCollection.map( + (indexMetadata) => indexMetadata.id, + ), + ); + } + + return { + createdIndexMetadataCollection, + }; + } + /** * Update entities in the database * @param manager EntityManager diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/services/workspace-sync-field-metadata.service.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/services/workspace-sync-field-metadata.service.ts index 4fe25b628ce2..a926b9525ba9 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/services/workspace-sync-field-metadata.service.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/services/workspace-sync-field-metadata.service.ts @@ -3,7 +3,10 @@ import { Injectable, Logger } from '@nestjs/common'; import { EntityManager } from 'typeorm'; import { WorkspaceSyncContext } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/workspace-sync-context.interface'; -import { ComparatorAction } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/comparator.interface'; +import { + ComparatorAction, + FieldComparatorResult, +} from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/comparator.interface'; import { FeatureFlagMap } from 'src/engine/core-modules/feature-flag/interfaces/feature-flag-map.interface'; import { WorkspaceMigrationBuilderAction } from 'src/engine/workspace-manager/workspace-migration-builder/interfaces/workspace-migration-builder-action.interface'; @@ -15,7 +18,9 @@ import { WorkspaceSyncStorage } from 'src/engine/workspace-manager/workspace-syn import { WorkspaceMigrationFieldFactory } from 'src/engine/workspace-manager/workspace-migration-builder/factories/workspace-migration-field.factory'; import { StandardFieldFactory } from 'src/engine/workspace-manager/workspace-sync-metadata/factories/standard-field.factory'; import { CustomWorkspaceEntity } from 'src/engine/twenty-orm/custom.workspace-entity'; -import { computeStandardObject } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/compute-standard-object.util'; +import { computeStandardFields } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/compute-standard-fields.util'; +import { standardObjectMetadataDefinitions } from 'src/engine/workspace-manager/workspace-sync-metadata/standard-objects'; +import { mapObjectMetadataByUniqueIdentifier } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/sync-metadata.util'; @Injectable() export class WorkspaceSyncFieldMetadataService { @@ -43,60 +48,28 @@ export class WorkspaceSyncFieldMetadataService { where: { workspaceId: context.workspaceId, // We're only interested in standard fields - fields: { isCustom: false }, }, relations: ['dataSource', 'fields'], }); - - // Filter out custom objects const customObjectMetadataCollection = originalObjectMetadataCollection.filter( (objectMetadata) => objectMetadata.isCustom, ); - // Create standard field metadata collection - const standardFieldMetadataCollection = this.standardFieldFactory.create( - CustomWorkspaceEntity, + await this.synchronizeStandardObjectFields( context, + originalObjectMetadataCollection, + customObjectMetadataCollection, + storage, workspaceFeatureFlagsMap, ); - // Loop over all standard objects and compare them with the objects in DB - for (const customObjectMetadata of customObjectMetadataCollection) { - // Also, maybe it's better to refactor a bit and move generation part into a separate module ? - const standardObjectMetadata = computeStandardObject( - { - ...customObjectMetadata, - fields: standardFieldMetadataCollection, - }, - customObjectMetadata, - ); - - /** - * COMPARE FIELD METADATA - */ - const fieldComparatorResults = this.workspaceFieldComparator.compare( - customObjectMetadata, - standardObjectMetadata, - ); - - for (const fieldComparatorResult of fieldComparatorResults) { - switch (fieldComparatorResult.action) { - case ComparatorAction.CREATE: { - storage.addCreateFieldMetadata(fieldComparatorResult.object); - break; - } - case ComparatorAction.UPDATE: { - storage.addUpdateFieldMetadata(fieldComparatorResult.object); - break; - } - case ComparatorAction.DELETE: { - storage.addDeleteFieldMetadata(fieldComparatorResult.object); - break; - } - } - } - } + await this.synchronizeCustomObjectFields( + context, + customObjectMetadataCollection, + storage, + workspaceFeatureFlagsMap, + ); this.logger.log('Updating workspace metadata'); @@ -137,4 +110,110 @@ export class WorkspaceSyncFieldMetadataService { ...deleteFieldWorkspaceMigrations, ]; } + + /** + * This can be optimized to avoid import of standardObjectFactory here. + * We should refactor the logic of the factory, so this one only create the objects and not the fields. + * Then standardFieldFactory should be used to create the fields of standard objects. + */ + private async synchronizeStandardObjectFields( + context: WorkspaceSyncContext, + originalObjectMetadataCollection: ObjectMetadataEntity[], + customObjectMetadataCollection: ObjectMetadataEntity[], + storage: WorkspaceSyncStorage, + workspaceFeatureFlagsMap: FeatureFlagMap, + ): Promise<void> { + // Create standard field metadata map + const standardObjectStandardFieldMetadataMap = + this.standardFieldFactory.create( + standardObjectMetadataDefinitions, + context, + workspaceFeatureFlagsMap, + ); + + // Create map of original and standard object metadata by standard ids + const originalObjectMetadataMap = mapObjectMetadataByUniqueIdentifier( + originalObjectMetadataCollection, + ); + + // Loop over all standard objects and compare them with the objects in DB + for (const [ + standardObjectId, + standardFieldMetadataCollection, + ] of standardObjectStandardFieldMetadataMap) { + const originalObjectMetadata = + originalObjectMetadataMap[standardObjectId]; + const computedStandardFieldMetadataCollection = computeStandardFields( + standardFieldMetadataCollection, + originalObjectMetadata, + // We need to provide this for generated relations with custom objects + customObjectMetadataCollection, + ); + + const fieldComparatorResults = this.workspaceFieldComparator.compare( + originalObjectMetadata.id, + originalObjectMetadata.fields, + computedStandardFieldMetadataCollection, + ); + + this.storeComparatorResults(fieldComparatorResults, storage); + } + } + + private async synchronizeCustomObjectFields( + context: WorkspaceSyncContext, + customObjectMetadataCollection: ObjectMetadataEntity[], + storage: WorkspaceSyncStorage, + workspaceFeatureFlagsMap: FeatureFlagMap, + ): Promise<void> { + // Create standard field metadata collection + const customObjectStandardFieldMetadataCollection = + this.standardFieldFactory.create( + CustomWorkspaceEntity, + context, + workspaceFeatureFlagsMap, + ); + + // Loop over all custom objects from the DB and compare their fields with standard fields + for (const customObjectMetadata of customObjectMetadataCollection) { + // Also, maybe it's better to refactor a bit and move generation part into a separate module ? + const standardFieldMetadataCollection = computeStandardFields( + customObjectStandardFieldMetadataCollection, + customObjectMetadata, + ); + + /** + * COMPARE FIELD METADATA + */ + const fieldComparatorResults = this.workspaceFieldComparator.compare( + customObjectMetadata.id, + customObjectMetadata.fields, + standardFieldMetadataCollection, + ); + + this.storeComparatorResults(fieldComparatorResults, storage); + } + } + + private storeComparatorResults( + fieldComparatorResults: FieldComparatorResult[], + storage: WorkspaceSyncStorage, + ): void { + for (const fieldComparatorResult of fieldComparatorResults) { + switch (fieldComparatorResult.action) { + case ComparatorAction.CREATE: { + storage.addCreateFieldMetadata(fieldComparatorResult.object); + break; + } + case ComparatorAction.UPDATE: { + storage.addUpdateFieldMetadata(fieldComparatorResult.object); + break; + } + case ComparatorAction.DELETE: { + storage.addDeleteFieldMetadata(fieldComparatorResult.object); + break; + } + } + } + } } diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/services/workspace-sync-index-metadata.service.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/services/workspace-sync-index-metadata.service.ts new file mode 100644 index 000000000000..4f7a30ef9d25 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/services/workspace-sync-index-metadata.service.ts @@ -0,0 +1,119 @@ +import { Injectable, Logger } from '@nestjs/common'; + +import { EntityManager } from 'typeorm'; + +import { FeatureFlagMap } from 'src/engine/core-modules/feature-flag/interfaces/feature-flag-map.interface'; +import { WorkspaceSyncContext } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/workspace-sync-context.interface'; +import { ComparatorAction } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/comparator.interface'; +import { WorkspaceMigrationBuilderAction } from 'src/engine/workspace-manager/workspace-migration-builder/interfaces/workspace-migration-builder-action.interface'; + +import { WorkspaceMigrationEntity } from 'src/engine/metadata-modules/workspace-migration/workspace-migration.entity'; +import { WorkspaceSyncStorage } from 'src/engine/workspace-manager/workspace-sync-metadata/storage/workspace-sync.storage'; +import { StandardIndexFactory } from 'src/engine/workspace-manager/workspace-sync-metadata/factories/standard-index.factory'; +import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; +import { mapObjectMetadataByUniqueIdentifier } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/sync-metadata.util'; +import { IndexMetadataEntity } from 'src/engine/metadata-modules/index-metadata/index-metadata.entity'; +import { standardObjectMetadataDefinitions } from 'src/engine/workspace-manager/workspace-sync-metadata/standard-objects'; +import { WorkspaceIndexComparator } from 'src/engine/workspace-manager/workspace-sync-metadata/comparators/workspace-index.comparator'; +import { WorkspaceMetadataUpdaterService } from 'src/engine/workspace-manager/workspace-sync-metadata/services/workspace-metadata-updater.service'; +import { WorkspaceMigrationIndexFactory } from 'src/engine/workspace-manager/workspace-migration-builder/factories/workspace-migration-index.factory'; + +@Injectable() +export class WorkspaceSyncIndexMetadataService { + private readonly logger = new Logger(WorkspaceSyncIndexMetadataService.name); + + constructor( + private readonly standardIndexFactory: StandardIndexFactory, + private readonly workspaceIndexComparator: WorkspaceIndexComparator, + private readonly workspaceMetadataUpdaterService: WorkspaceMetadataUpdaterService, + private readonly workspaceMigrationIndexFactory: WorkspaceMigrationIndexFactory, + ) {} + + async synchronize( + context: WorkspaceSyncContext, + manager: EntityManager, + storage: WorkspaceSyncStorage, + workspaceFeatureFlagsMap: FeatureFlagMap, + ): Promise<Partial<WorkspaceMigrationEntity>[]> { + this.logger.log('Syncing index metadata'); + + const objectMetadataRepository = + manager.getRepository(ObjectMetadataEntity); + + // Retrieve object metadata collection from DB + const originalObjectMetadataCollection = + await objectMetadataRepository.find({ + where: { + workspaceId: context.workspaceId, + // We're only interested in standard fields + fields: { isCustom: false }, + isCustom: false, + }, + relations: ['dataSource', 'fields', 'indexes'], + }); + + // Create map of object metadata & field metadata by unique identifier + const originalObjectMetadataMap = mapObjectMetadataByUniqueIdentifier( + originalObjectMetadataCollection, + // Relation are based on the singular name + (objectMetadata) => objectMetadata.nameSingular, + ); + + const indexMetadataRepository = manager.getRepository(IndexMetadataEntity); + + const originalIndexMetadataCollection = await indexMetadataRepository.find({ + where: { + workspaceId: context.workspaceId, + }, + relations: ['indexFieldMetadatas.fieldMetadata'], + }); + + // Generate index metadata from models + const standardIndexMetadataCollection = this.standardIndexFactory.create( + standardObjectMetadataDefinitions, + context, + originalObjectMetadataMap, + workspaceFeatureFlagsMap, + ); + + const indexComparatorResults = this.workspaceIndexComparator.compare( + originalIndexMetadataCollection, + standardIndexMetadataCollection, + ); + + for (const indexComparatorResult of indexComparatorResults) { + if (indexComparatorResult.action === ComparatorAction.CREATE) { + storage.addCreateIndexMetadata(indexComparatorResult.object); + } else if (indexComparatorResult.action === ComparatorAction.DELETE) { + storage.addDeleteIndexMetadata(indexComparatorResult.object); + } + } + + const metadataIndexUpdaterResult = + await this.workspaceMetadataUpdaterService.updateIndexMetadata( + manager, + storage, + originalObjectMetadataCollection, + ); + + // Create migrations + const createIndexWorkspaceMigrations = + await this.workspaceMigrationIndexFactory.create( + originalObjectMetadataCollection, + metadataIndexUpdaterResult.createdIndexMetadataCollection, + WorkspaceMigrationBuilderAction.CREATE, + ); + + const deleteIndexWorkspaceMigrations = + await this.workspaceMigrationIndexFactory.create( + originalObjectMetadataCollection, + storage.indexMetadataDeleteCollection, + WorkspaceMigrationBuilderAction.DELETE, + ); + + return [ + ...createIndexWorkspaceMigrations, + ...deleteIndexWorkspaceMigrations, + ]; + } +} diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/services/workspace-sync-object-metadata.service.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/services/workspace-sync-object-metadata.service.ts index 147389b18918..34d456d19d95 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/services/workspace-sync-object-metadata.service.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/services/workspace-sync-object-metadata.service.ts @@ -12,11 +12,9 @@ import { mapObjectMetadataByUniqueIdentifier } from 'src/engine/workspace-manage import { WorkspaceMigrationEntity } from 'src/engine/metadata-modules/workspace-migration/workspace-migration.entity'; import { StandardObjectFactory } from 'src/engine/workspace-manager/workspace-sync-metadata/factories/standard-object.factory'; import { WorkspaceObjectComparator } from 'src/engine/workspace-manager/workspace-sync-metadata/comparators/workspace-object.comparator'; -import { WorkspaceFieldComparator } from 'src/engine/workspace-manager/workspace-sync-metadata/comparators/workspace-field.comparator'; import { WorkspaceMetadataUpdaterService } from 'src/engine/workspace-manager/workspace-sync-metadata/services/workspace-metadata-updater.service'; import { WorkspaceSyncStorage } from 'src/engine/workspace-manager/workspace-sync-metadata/storage/workspace-sync.storage'; import { WorkspaceMigrationObjectFactory } from 'src/engine/workspace-manager/workspace-migration-builder/factories/workspace-migration-object.factory'; -import { computeStandardObject } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/compute-standard-object.util'; import { standardObjectMetadataDefinitions } from 'src/engine/workspace-manager/workspace-sync-metadata/standard-objects'; @Injectable() @@ -26,7 +24,6 @@ export class WorkspaceSyncObjectMetadataService { constructor( private readonly standardObjectFactory: StandardObjectFactory, private readonly workspaceObjectComparator: WorkspaceObjectComparator, - private readonly workspaceFieldComparator: WorkspaceFieldComparator, private readonly workspaceMetadataUpdaterService: WorkspaceMetadataUpdaterService, private readonly workspaceMigrationObjectFactory: WorkspaceMigrationObjectFactory, ) {} @@ -49,10 +46,6 @@ export class WorkspaceSyncObjectMetadataService { }, relations: ['dataSource', 'fields'], }); - const customObjectMetadataCollection = - originalObjectMetadataCollection.filter( - (objectMetadata) => objectMetadata.isCustom, - ); // Create standard object metadata collection const standardObjectMetadataCollection = this.standardObjectFactory.create( @@ -87,11 +80,8 @@ export class WorkspaceSyncObjectMetadataService { for (const standardObjectId in standardObjectMetadataMap) { const originalObjectMetadata = originalObjectMetadataMap[standardObjectId]; - const standardObjectMetadata = computeStandardObject( - standardObjectMetadataMap[standardObjectId], - originalObjectMetadata, - customObjectMetadataCollection, - ); + const standardObjectMetadata = + standardObjectMetadataMap[standardObjectId]; /** * COMPARE OBJECT METADATA @@ -109,31 +99,6 @@ export class WorkspaceSyncObjectMetadataService { if (objectComparatorResult.action === ComparatorAction.UPDATE) { storage.addUpdateObjectMetadata(objectComparatorResult.object); } - - /** - * COMPARE FIELD METADATA - */ - const fieldComparatorResults = this.workspaceFieldComparator.compare( - originalObjectMetadata, - standardObjectMetadata, - ); - - for (const fieldComparatorResult of fieldComparatorResults) { - switch (fieldComparatorResult.action) { - case ComparatorAction.CREATE: { - storage.addCreateFieldMetadata(fieldComparatorResult.object); - break; - } - case ComparatorAction.UPDATE: { - storage.addUpdateFieldMetadata(fieldComparatorResult.object); - break; - } - case ComparatorAction.DELETE: { - storage.addDeleteFieldMetadata(fieldComparatorResult.object); - break; - } - } - } } this.logger.log('Updating workspace metadata'); diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/services/workspace-sync-relation-metadata.service.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/services/workspace-sync-relation-metadata.service.ts index 86d46f01a853..ba14f3634e93 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/services/workspace-sync-relation-metadata.service.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/services/workspace-sync-relation-metadata.service.ts @@ -46,7 +46,6 @@ export class WorkspaceSyncRelationMetadataService { await objectMetadataRepository.find({ where: { workspaceId: context.workspaceId, - fields: { isCustom: false }, }, relations: ['dataSource', 'fields'], }); diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/standard-objects/index.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/standard-objects/index.ts index 39ef93760e7f..43d591382253 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/standard-objects/index.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/standard-objects/index.ts @@ -1,33 +1,34 @@ import { ActivityTargetWorkspaceEntity } from 'src/modules/activity/standard-objects/activity-target.workspace-entity'; import { ActivityWorkspaceEntity } from 'src/modules/activity/standard-objects/activity.workspace-entity'; +import { CommentWorkspaceEntity } from 'src/modules/activity/standard-objects/comment.workspace-entity'; import { ApiKeyWorkspaceEntity } from 'src/modules/api-key/standard-objects/api-key.workspace-entity'; import { AttachmentWorkspaceEntity } from 'src/modules/attachment/standard-objects/attachment.workspace-entity'; -import { BlocklistWorkspaceEntity } from 'src/modules/connected-account/standard-objects/blocklist.workspace-entity'; -import { CalendarEventWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-event.workspace-entity'; -import { CalendarChannelWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-channel.workspace-entity'; -import { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-event-participant.workspace-entity'; -import { CommentWorkspaceEntity } from 'src/modules/activity/standard-objects/comment.workspace-entity'; +import { BlocklistWorkspaceEntity } from 'src/modules/blocklist/standard-objects/blocklist.workspace-entity'; +import { CalendarChannelEventAssociationWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-channel-event-association.workspace-entity'; +import { CalendarChannelWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-channel.workspace-entity'; +import { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-event-participant.workspace-entity'; +import { CalendarEventWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-event.workspace-entity'; import { CompanyWorkspaceEntity } from 'src/modules/company/standard-objects/company.workspace-entity'; import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; import { FavoriteWorkspaceEntity } from 'src/modules/favorite/standard-objects/favorite.workspace-entity'; +import { MessageChannelMessageAssociationWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel-message-association.workspace-entity'; +import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity'; +import { MessageParticipantWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-participant.workspace-entity'; +import { MessageThreadWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-thread.workspace-entity'; +import { MessageWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message.workspace-entity'; import { OpportunityWorkspaceEntity } from 'src/modules/opportunity/standard-objects/opportunity.workspace-entity'; import { PersonWorkspaceEntity } from 'src/modules/person/standard-objects/person.workspace-entity'; +import { AuditLogWorkspaceEntity } from 'src/modules/timeline/standard-objects/audit-log.workspace-entity'; +import { BehavioralEventWorkspaceEntity } from 'src/modules/timeline/standard-objects/behavioral-event.workspace-entity'; +import { TimelineActivityWorkspaceEntity } from 'src/modules/timeline/standard-objects/timeline-activity.workspace-entity'; import { ViewFieldWorkspaceEntity } from 'src/modules/view/standard-objects/view-field.workspace-entity'; import { ViewFilterWorkspaceEntity } from 'src/modules/view/standard-objects/view-filter.workspace-entity'; import { ViewSortWorkspaceEntity } from 'src/modules/view/standard-objects/view-sort.workspace-entity'; import { ViewWorkspaceEntity } from 'src/modules/view/standard-objects/view.workspace-entity'; import { WebhookWorkspaceEntity } from 'src/modules/webhook/standard-objects/webhook.workspace-entity'; import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; -import { CalendarChannelEventAssociationWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-channel-event-association.workspace-entity'; -import { AuditLogWorkspaceEntity } from 'src/modules/timeline/standard-objects/audit-log.workspace-entity'; -import { TimelineActivityWorkspaceEntity } from 'src/modules/timeline/standard-objects/timeline-activity.workspace-entity'; -import { BehavioralEventWorkspaceEntity } from 'src/modules/timeline/standard-objects/behavioral-event.workspace-entity'; -import { MessageChannelMessageAssociationWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel-message-association.workspace-entity'; -import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity'; -import { MessageParticipantWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-participant.workspace-entity'; -import { MessageThreadWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-thread.workspace-entity'; -import { MessageWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message.workspace-entity'; +// TODO: Maybe we should automate this with the DiscoverService of Nest.JS export const standardObjectMetadataDefinitions = [ ActivityTargetWorkspaceEntity, ActivityWorkspaceEntity, diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/storage/workspace-sync.storage.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/storage/workspace-sync.storage.ts index 6d0a7a9d39ae..49bc4b176fcd 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/storage/workspace-sync.storage.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/storage/workspace-sync.storage.ts @@ -4,12 +4,17 @@ import { ComputedPartialFieldMetadata } from 'src/engine/workspace-manager/works import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; import { RelationMetadataEntity } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity'; +import { IndexMetadataEntity } from 'src/engine/metadata-modules/index-metadata/index-metadata.entity'; export class WorkspaceSyncStorage { // Object metadata - private readonly _objectMetadataCreateCollection: ComputedPartialWorkspaceEntity[] = - []; - private readonly _objectMetadataUpdateCollection: (Partial<ComputedPartialWorkspaceEntity> & { + private readonly _objectMetadataCreateCollection: Omit< + ComputedPartialWorkspaceEntity, + 'fields' + >[] = []; + private readonly _objectMetadataUpdateCollection: (Partial< + Omit<ComputedPartialWorkspaceEntity, 'fields'> + > & { id: string; })[] = []; private readonly _objectMetadataDeleteCollection: ObjectMetadataEntity[] = []; @@ -25,10 +30,17 @@ export class WorkspaceSyncStorage { // Relation metadata private readonly _relationMetadataCreateCollection: Partial<RelationMetadataEntity>[] = []; + private readonly _relationMetadataUpdateCollection: Partial<RelationMetadataEntity>[] = + []; private readonly _relationMetadataDeleteCollection: RelationMetadataEntity[] = []; - private readonly _relationMetadataUpdateCollection: Partial<RelationMetadataEntity>[] = + + // Index metadata + private readonly _indexMetadataCreateCollection: Partial<IndexMetadataEntity>[] = []; + private readonly _indexMetadataUpdateCollection: Partial<IndexMetadataEntity>[] = + []; + private readonly _indexMetadataDeleteCollection: IndexMetadataEntity[] = []; constructor() {} @@ -68,7 +80,21 @@ export class WorkspaceSyncStorage { return this._relationMetadataDeleteCollection; } - addCreateObjectMetadata(object: ComputedPartialWorkspaceEntity) { + get indexMetadataCreateCollection() { + return this._indexMetadataCreateCollection; + } + + get indexMetadataUpdateCollection() { + return this._indexMetadataUpdateCollection; + } + + get indexMetadataDeleteCollection() { + return this._indexMetadataDeleteCollection; + } + + addCreateObjectMetadata( + object: Omit<ComputedPartialWorkspaceEntity, 'fields'>, + ) { this._objectMetadataCreateCollection.push(object); } @@ -107,4 +133,16 @@ export class WorkspaceSyncStorage { addDeleteRelationMetadata(relation: RelationMetadataEntity) { this._relationMetadataDeleteCollection.push(relation); } + + addCreateIndexMetadata(index: Partial<IndexMetadataEntity>) { + this._indexMetadataCreateCollection.push(index); + } + + addUpdateIndexMetadata(index: Partial<IndexMetadataEntity>) { + this._indexMetadataUpdateCollection.push(index); + } + + addDeleteIndexMetadata(index: IndexMetadataEntity) { + this._indexMetadataDeleteCollection.push(index); + } } diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/types/object-record.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/types/object-record.ts deleted file mode 100644 index d517a6aeda88..000000000000 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/types/object-record.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { ObjectLiteral } from 'typeorm'; - -import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity'; - -export type ObjectRecord<T extends ObjectLiteral> = { - [K in keyof T as T[K] extends BaseWorkspaceEntity - ? `${Extract<K, string>}Id` - : K]: T[K] extends BaseWorkspaceEntity - ? string - : T[K] extends BaseWorkspaceEntity[] - ? string[] - : T[K]; -} & { - [K in keyof T]: T[K] extends BaseWorkspaceEntity - ? ObjectRecord<T[K]> - : T[K] extends BaseWorkspaceEntity[] - ? ObjectRecord<T[K][number]>[] - : T[K]; -}; diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/utils/compute-standard-object.util.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/utils/compute-standard-fields.util.ts similarity index 81% rename from packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/utils/compute-standard-object.util.ts rename to packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/utils/compute-standard-fields.util.ts index c45503534a77..7f1a1247bdce 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/utils/compute-standard-object.util.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/utils/compute-standard-fields.util.ts @@ -1,8 +1,8 @@ import { - ComputedPartialWorkspaceEntity, - PartialWorkspaceEntity, -} from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/partial-object-metadata.interface'; -import { ComputedPartialFieldMetadata } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/partial-field-metadata.interface'; + ComputedPartialFieldMetadata, + PartialComputedFieldMetadata, + PartialFieldMetadata, +} from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/partial-field-metadata.interface'; import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; @@ -11,16 +11,18 @@ import { createRelationDeterministicUuid, } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/create-deterministic-uuid.util'; -export const computeStandardObject = ( - standardObjectMetadata: Omit<PartialWorkspaceEntity, 'standardId'> & { - standardId: string | null; - }, +export const computeStandardFields = ( + standardFieldMetadataCollection: ( + | PartialFieldMetadata + | PartialComputedFieldMetadata + )[], originalObjectMetadata: ObjectMetadataEntity, customObjectMetadataCollection: ObjectMetadataEntity[] = [], -): ComputedPartialWorkspaceEntity => { +): ComputedPartialFieldMetadata[] => { const fields: ComputedPartialFieldMetadata[] = []; - for (const partialFieldMetadata of standardObjectMetadata.fields) { + for (const partialFieldMetadata of standardFieldMetadataCollection) { + // Relation from standard object to custom object if ('argsFactory' in partialFieldMetadata) { // Compute standard fields of custom object for (const customObjectMetadata of customObjectMetadataCollection) { @@ -63,6 +65,7 @@ export const computeStandardObject = ( }); } } else { + // Relation from standard object to standard object const labelText = typeof partialFieldMetadata.label === 'function' ? partialFieldMetadata.label(originalObjectMetadata) @@ -80,8 +83,5 @@ export const computeStandardObject = ( } } - return { - ...standardObjectMetadata, - fields, - }; + return fields; }; diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/workspace-sync-metadata.module.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/workspace-sync-metadata.module.ts index 7e8d046cbe7e..e6f2d15a1858 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/workspace-sync-metadata.module.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/workspace-sync-metadata.module.ts @@ -5,17 +5,18 @@ import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature- import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { RelationMetadataEntity } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity'; +import { WorkspaceCacheVersionModule } from 'src/engine/metadata-modules/workspace-cache-version/workspace-cache-version.module'; import { WorkspaceMigrationEntity } from 'src/engine/metadata-modules/workspace-migration/workspace-migration.entity'; +import { WorkspaceMigrationBuilderModule } from 'src/engine/workspace-manager/workspace-migration-builder/workspace-migration-builder.module'; import { WorkspaceMigrationRunnerModule } from 'src/engine/workspace-manager/workspace-migration-runner/workspace-migration-runner.module'; -import { WorkspaceSyncMetadataService } from 'src/engine/workspace-manager/workspace-sync-metadata/workspace-sync-metadata.service'; -import { workspaceSyncMetadataFactories } from 'src/engine/workspace-manager/workspace-sync-metadata/factories'; import { workspaceSyncMetadataComparators } from 'src/engine/workspace-manager/workspace-sync-metadata/comparators'; +import { workspaceSyncMetadataFactories } from 'src/engine/workspace-manager/workspace-sync-metadata/factories'; import { WorkspaceMetadataUpdaterService } from 'src/engine/workspace-manager/workspace-sync-metadata/services/workspace-metadata-updater.service'; +import { WorkspaceSyncFieldMetadataService } from 'src/engine/workspace-manager/workspace-sync-metadata/services/workspace-sync-field-metadata.service'; +import { WorkspaceSyncIndexMetadataService } from 'src/engine/workspace-manager/workspace-sync-metadata/services/workspace-sync-index-metadata.service'; import { WorkspaceSyncObjectMetadataService } from 'src/engine/workspace-manager/workspace-sync-metadata/services/workspace-sync-object-metadata.service'; import { WorkspaceSyncRelationMetadataService } from 'src/engine/workspace-manager/workspace-sync-metadata/services/workspace-sync-relation-metadata.service'; -import { WorkspaceSyncFieldMetadataService } from 'src/engine/workspace-manager/workspace-sync-metadata/services/workspace-sync-field-metadata.service'; -import { WorkspaceMigrationBuilderModule } from 'src/engine/workspace-manager/workspace-migration-builder/workspace-migration-builder.module'; -import { WorkspaceCacheVersionModule } from 'src/engine/metadata-modules/workspace-cache-version/workspace-cache-version.module'; +import { WorkspaceSyncMetadataService } from 'src/engine/workspace-manager/workspace-sync-metadata/workspace-sync-metadata.service'; @Module({ imports: [ @@ -41,6 +42,7 @@ import { WorkspaceCacheVersionModule } from 'src/engine/metadata-modules/workspa WorkspaceSyncRelationMetadataService, WorkspaceSyncFieldMetadataService, WorkspaceSyncMetadataService, + WorkspaceSyncIndexMetadataService, ], exports: [...workspaceSyncMetadataFactories, WorkspaceSyncMetadataService], }) diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/workspace-sync-metadata.service.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/workspace-sync-metadata.service.ts index 8b4db8d36ae4..b233be4e3747 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/workspace-sync-metadata.service.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/workspace-sync-metadata.service.ts @@ -13,6 +13,7 @@ import { WorkspaceSyncFieldMetadataService } from 'src/engine/workspace-manager/ import { WorkspaceSyncStorage } from 'src/engine/workspace-manager/workspace-sync-metadata/storage/workspace-sync.storage'; import { WorkspaceMigrationEntity } from 'src/engine/metadata-modules/workspace-migration/workspace-migration.entity'; import { WorkspaceCacheVersionService } from 'src/engine/metadata-modules/workspace-cache-version/workspace-cache-version.service'; +import { WorkspaceSyncIndexMetadataService } from 'src/engine/workspace-manager/workspace-sync-metadata/services/workspace-sync-index-metadata.service'; interface SynchronizeOptions { applyChanges?: boolean; @@ -31,6 +32,7 @@ export class WorkspaceSyncMetadataService { private readonly workspaceSyncRelationMetadataService: WorkspaceSyncRelationMetadataService, private readonly workspaceSyncFieldMetadataService: WorkspaceSyncFieldMetadataService, private readonly workspaceCacheVersionService: WorkspaceCacheVersionService, + private readonly workspaceSyncIndexMetadataService: WorkspaceSyncIndexMetadataService, ) {} /** @@ -97,11 +99,21 @@ export class WorkspaceSyncMetadataService { workspaceFeatureFlagsMap, ); + // 4 - Sync standard indexes on standard objects + const workspaceIndexMigrations = + await this.workspaceSyncIndexMetadataService.synchronize( + context, + manager, + storage, + workspaceFeatureFlagsMap, + ); + // Save workspace migrations into the database workspaceMigrations = await workspaceMigrationRepository.save([ ...workspaceObjectMigrations, ...workspaceFieldMigrations, ...workspaceRelationMigrations, + ...workspaceIndexMigrations, ]); // If we're running a dry run, rollback the transaction and do not execute migrations diff --git a/packages/twenty-server/src/funnelmink/funnelmink-constants.ts b/packages/twenty-server/src/funnelmink/funnelmink-constants.ts new file mode 100644 index 000000000000..92fae36f36ed --- /dev/null +++ b/packages/twenty-server/src/funnelmink/funnelmink-constants.ts @@ -0,0 +1,35 @@ +export const FUNNELMINK_ICONS = { + // objects + company: 'IconBuildingSkyscraper', + person: 'IconUser', + crew: 'IconCar', + equipment: 'IconBackhoe', + job: 'IconPlant', + material: 'IconPaperBag', + service: 'IconHeartHandshake', + workorder: 'IconChecklist', + member: 'IconUserCircle', + + // fields + activityTargets: 'IconCheckbox', + address: 'IconMap', + annualRecurringRevenue: 'IconMoneybag', + attachments: 'IconFileImport', + avatarUrl: 'IconFileUpload', + calendarEventParticipants: 'IconCalendar', + createdAt: 'IconCalendar', + description: 'IconInfoCircle', + domainName: 'IconGlobe', + email: 'IconMail', + favorite: 'IconHeart', + idealCustomerProfile: 'IconTarget', + jobTitle: 'IconBriefcase', + linkedinLink: 'IconBrandLinkedin', + name: 'IconArticle', + phone: 'IconPhone', + position: 'IconHierarchy2', + stage: 'IconTargetArrow', + stickyNote: 'IconNote', + timelineActivities: 'IconTimelineEvent', + xLink: 'IconBrandX', +}; diff --git a/packages/twenty-server/src/funnelmink/funnelmink-objects-prefill-data.ts b/packages/twenty-server/src/funnelmink/funnelmink-objects-prefill-data.ts new file mode 100644 index 000000000000..b866a3d78a03 --- /dev/null +++ b/packages/twenty-server/src/funnelmink/funnelmink-objects-prefill-data.ts @@ -0,0 +1,357 @@ +import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; +import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; +import { ObjectMetadataService } from 'src/engine/metadata-modules/object-metadata/object-metadata.service'; +import { FUNNELMINK_ICONS } from 'src/funnelmink/funnelmink-constants'; +import { CreateObjectInput } from 'src/engine/metadata-modules/object-metadata/dtos/create-object.input'; +import { CreateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/create-field.input'; +import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; +import { FieldMetadataService } from 'src/engine/metadata-modules/field-metadata/field-metadata.service'; +import { RelationMetadataService } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.service'; +import { RelationMetadataType } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity'; +import { CreateRelationInput } from 'src/engine/metadata-modules/relation-metadata/dtos/create-relation.input'; + +// fm TODO: this needs to be fault tolerant and reusable +// - in the future, if a user messes with their data model, we can offer to regen missing objects (and/or fields) +// - as this function iterates, it should catch and log errors without breaking out of the loop + +export const prefillWorkspaceWithFunnelminkFSMObjects = async ( + workspaceId: string, + workspaceDataSourceService: WorkspaceDataSourceService, + objectMetadataService: ObjectMetadataService, + fieldMetadataService: FieldMetadataService, + relationMetadataService: RelationMetadataService, +) => { + const workspaceDataSource = + await workspaceDataSourceService.connectToWorkspaceDataSource(workspaceId); + + if (!workspaceDataSource) { + throw new Error('Could not connect to workspace data source'); + } + + // loop through create funnelmink objects and fields + await createFunnelminkObjects( + workspaceId, + objectMetadataService, + fieldMetadataService, + ); + + await createFunnelminkRelations( + workspaceId, + objectMetadataService, + relationMetadataService, + ); + + // fm TODO: prefill data (see `standard-objects-prefill-data.ts`) + + // fm TODO: prefill views (see `standard-objects-prefill-data.ts`) +}; + +const createFunnelminkObjects = async ( + workspaceId: string, + objectMetadataService: ObjectMetadataService, + fieldMetadataService: FieldMetadataService, +) => { + const metadatas: ObjectMetadataEntity[] = []; + + // loop through, create objects, fields and relations + for (const object of fsmObjects) { + const input: CreateObjectInput = { + dataSourceId: '', + workspaceId: workspaceId, + nameSingular: object.nameSingular, + namePlural: object.namePlural, + labelSingular: object.labelSingular, + labelPlural: object.labelPlural, + description: object.description, + icon: object.icon, + isRemote: object.isRemote, + }; + const objectMetadata = await objectMetadataService.createOne(input); + + console.log( + `[fm] Created object ${object.nameSingular} with ID ${objectMetadata.id}`, + ); + for (const field of object.fields) { + const fieldInput: CreateFieldInput = { + workspaceId: workspaceId, + objectMetadataId: objectMetadata.id, + name: field.name, + label: field.label, + type: field.type, + icon: field.icon, + isRemoteCreation: false, + }; + + await fieldMetadataService.createOne(fieldInput); + } + metadatas.push(objectMetadata); + } +}; + +const createFunnelminkRelations = async ( + workspaceId: string, + objectMetadataService: ObjectMetadataService, + relationMetadataService: RelationMetadataService, +) => { + const objectMetadatas = + await objectMetadataService.findManyWithinWorkspace(workspaceId); + + for (const relation of fsmRelationships) { + const parentMetadata = objectMetadatas.find( + (metadata) => metadata.namePlural === relation.fromName, + ); + let toName = relation.toName; + + if (relation.toName === 'crewLead') { + toName = 'workspaceMembers'; + } + const childMetadata = objectMetadatas.find( + (metadata) => metadata.namePlural === toName, + ); + + if (!parentMetadata || !childMetadata) { + throw new Error( + `Could not find object metadata for ${relation.fromName} or ${relation.toName}`, + ); + } + + const input: CreateRelationInput = { + fromDescription: relation.description, + fromIcon: relation.fromIcon, + fromLabel: relation.fromLabel, + fromName: relation.fromName, + fromObjectMetadataId: childMetadata.id, + relationType: relation.type, + toIcon: relation.toIcon, + toLabel: relation.toLabel, + toName: relation.toName, + toObjectMetadataId: parentMetadata.id, + workspaceId: workspaceId, + }; + + console.log( + `[fm] Creating relationship from ${parentMetadata.nameSingular} to ${relation.toName}`, + ); + await relationMetadataService.createOne(input); + console.log( + `[fm] Created relationship from ${parentMetadata.nameSingular} to ${relation.toName}`, + ); + } +}; + +const fsmObjects = [ + { + nameSingular: 'workorder', + namePlural: 'workorders', + labelSingular: 'Work Order', + labelPlural: 'Work Orders', + description: 'A Work Order', + isRemote: false, + icon: FUNNELMINK_ICONS.workorder, + fields: [ + { + name: 'stickyNote', + label: 'Sticky Note', + icon: FUNNELMINK_ICONS.stickyNote, + type: FieldMetadataType.TEXT, + }, + { + name: 'description', + label: 'Description', + icon: FUNNELMINK_ICONS.description, + type: FieldMetadataType.TEXT, + }, + ], + }, + { + nameSingular: 'service', + namePlural: 'services', + labelSingular: 'Service', + labelPlural: 'Services', + description: 'A Service', + isRemote: false, + icon: FUNNELMINK_ICONS.service, + fields: [ + { + name: 'stickyNote', + label: 'Sticky Note', + icon: FUNNELMINK_ICONS.stickyNote, + type: FieldMetadataType.TEXT, + }, + { + name: 'description', + label: 'Description', + icon: FUNNELMINK_ICONS.description, + type: FieldMetadataType.TEXT, + }, + ], + }, + { + nameSingular: 'crew', + namePlural: 'crews', + labelSingular: 'Crew', + labelPlural: 'Crews', + description: 'A Crew', + isRemote: false, + icon: FUNNELMINK_ICONS.crew, + fields: [ + { + name: 'stickyNote', + label: 'Sticky Note', + icon: FUNNELMINK_ICONS.stickyNote, + type: FieldMetadataType.TEXT, + }, + ], + }, + { + nameSingular: 'equipment', + namePlural: 'equipments', + labelSingular: 'Equipment', + labelPlural: 'Equipment', + description: 'Equipment', + isRemote: false, + icon: FUNNELMINK_ICONS.equipment, + fields: [ + { + name: 'stickyNote', + label: 'Sticky Note', + icon: FUNNELMINK_ICONS.stickyNote, + type: FieldMetadataType.TEXT, + }, + ], + }, + { + nameSingular: 'material', + namePlural: 'materials', + labelSingular: 'Material', + labelPlural: 'Materials', + description: 'Material', + isRemote: false, + icon: FUNNELMINK_ICONS.material, + fields: [ + { + name: 'stickyNote', + label: 'Sticky Note', + icon: FUNNELMINK_ICONS.stickyNote, + type: FieldMetadataType.TEXT, + }, + ], + }, + { + nameSingular: 'job', + namePlural: 'jobs', + labelSingular: 'Job', + labelPlural: 'Jobs', + description: 'Job', + isRemote: false, + icon: FUNNELMINK_ICONS.job, + fields: [ + { + name: 'stickyNote', + label: 'Sticky Note', + icon: FUNNELMINK_ICONS.stickyNote, + type: FieldMetadataType.TEXT, + }, + { + name: 'description', + label: 'Description', + icon: FUNNELMINK_ICONS.description, + type: FieldMetadataType.TEXT, + }, + ], + }, +]; + +const fsmRelationships = [ + { + description: 'The Work Orders for this Company', + fromIcon: FUNNELMINK_ICONS.workorder, + fromLabel: 'Work Orders', + fromName: 'workorders', + toIcon: FUNNELMINK_ICONS.company, + toLabel: 'Company', + toName: 'companies', + type: RelationMetadataType.ONE_TO_MANY, + }, + { + description: 'The Work Orders for this Person', + fromIcon: FUNNELMINK_ICONS.workorder, + fromLabel: 'Work Orders', + fromName: 'workorders', + toIcon: FUNNELMINK_ICONS.person, + toLabel: 'Person', + toName: 'people', + type: RelationMetadataType.ONE_TO_MANY, + }, + { + description: 'The Jobs this Work Order represents', + fromIcon: FUNNELMINK_ICONS.job, + fromLabel: 'Jobs', + fromName: 'jobs', + toIcon: FUNNELMINK_ICONS.workorder, + toLabel: 'Work Orders', + toName: 'workorders', + type: RelationMetadataType.ONE_TO_MANY, + }, + // { + // description: 'The Jobs where this Service is performed', + // fromIcon: FUNNELMINK_ICONS.service, + // fromLabel: 'Services', + // fromName: 'services', + // toIcon: FUNNELMINK_ICONS.job, + // toLabel: 'Jobs', + // toName: 'jobs', + // type: RelationMetadataType.MANY_TO_MANY, + // }, + { + description: 'The Jobs this Crew is assigned to', + fromIcon: FUNNELMINK_ICONS.job, + fromLabel: 'Jobs', + fromName: 'jobs', + toIcon: FUNNELMINK_ICONS.crew, + toLabel: 'Crew', + toName: 'crews', + type: RelationMetadataType.ONE_TO_MANY, + }, + { + description: 'The Crew Lead', + fromIcon: FUNNELMINK_ICONS.crew, + fromLabel: 'Crews', + fromName: 'crews', + toIcon: FUNNELMINK_ICONS.member, + toLabel: 'Crew Lead', + toName: 'crewLead', + type: RelationMetadataType.ONE_TO_MANY, + }, + // { + // description: 'The Crew Members', + // fromIcon: FUNNELMINK_ICONS.crew, + // fromLabel: 'Crews', + // fromName: 'crews', + // toIcon: FUNNELMINK_ICONS.member, + // toLabel: 'Crew Members', + // toName: 'crewMembers', + // type: RelationMetadataType.MANY_TO_MANY, + // }, + // { + // description: 'The Jobs this Equipment is used for', + // fromIcon: FUNNELMINK_ICONS.equipment, + // fromLabel: 'Equipment', + // fromName: 'equipments', + // toIcon: FUNNELMINK_ICONS.job, + // toLabel: 'Jobs', + // toName: 'jobs', + // type: RelationMetadataType.MANY_TO_MANY, + // }, + // + // { + // description: 'The Jobs this Material is used for', + // fromIcon: FUNNELMINK_ICONS.material, + // fromLabel: 'Materials', + // fromName: 'materials', + // toIcon: FUNNELMINK_ICONS.job, + // toLabel: 'Jobs', + // toName: 'jobs', + // type: RelationMetadataType.MANY_TO_MANY, + // }, +]; diff --git a/packages/twenty-server/src/modules/activity/repositories/comment.repository.ts b/packages/twenty-server/src/modules/activity/repositories/comment.repository.ts deleted file mode 100644 index e6bf07b2b8a5..000000000000 --- a/packages/twenty-server/src/modules/activity/repositories/comment.repository.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Injectable } from '@nestjs/common'; - -import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; - -@Injectable() -export class CommentRepository { - constructor( - private readonly workspaceDataSourceService: WorkspaceDataSourceService, - ) {} - - async deleteByAuthorId(authorId: string, workspaceId: string): Promise<void> { - const dataSourceSchema = - this.workspaceDataSourceService.getSchemaName(workspaceId); - - await this.workspaceDataSourceService.executeRawQuery( - `DELETE FROM ${dataSourceSchema}."comment" WHERE "authorId" = $1`, - [authorId], - workspaceId, - ); - } -} diff --git a/packages/twenty-server/src/modules/activity/standard-objects/activity-target.workspace-entity.ts b/packages/twenty-server/src/modules/activity/standard-objects/activity-target.workspace-entity.ts index c99325d137f5..dd2ef18cb94e 100644 --- a/packages/twenty-server/src/modules/activity/standard-objects/activity-target.workspace-entity.ts +++ b/packages/twenty-server/src/modules/activity/standard-objects/activity-target.workspace-entity.ts @@ -14,6 +14,7 @@ import { WorkspaceDynamicRelation } from 'src/engine/twenty-orm/decorators/works import { RelationMetadataType } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity'; import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator'; import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity'; +import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator'; @WorkspaceEntity({ standardId: STANDARD_OBJECT_IDS.activityTarget, @@ -31,12 +32,14 @@ export class ActivityTargetWorkspaceEntity extends BaseWorkspaceEntity { label: 'Activity', description: 'ActivityTarget activity', icon: 'IconNotes', - joinColumn: 'activityId', inverseSideTarget: () => ActivityWorkspaceEntity, inverseSideFieldKey: 'activityTargets', }) @WorkspaceIsNullable() - activity: Relation<ActivityWorkspaceEntity>; + activity: Relation<ActivityWorkspaceEntity> | null; + + @WorkspaceJoinColumn('activity') + activityId: string | null; @WorkspaceRelation({ standardId: ACTIVITY_TARGET_STANDARD_FIELD_IDS.person, @@ -44,12 +47,14 @@ export class ActivityTargetWorkspaceEntity extends BaseWorkspaceEntity { label: 'Person', description: 'ActivityTarget person', icon: 'IconUser', - joinColumn: 'personId', inverseSideTarget: () => PersonWorkspaceEntity, inverseSideFieldKey: 'activityTargets', }) @WorkspaceIsNullable() - person: Relation<PersonWorkspaceEntity>; + person: Relation<PersonWorkspaceEntity> | null; + + @WorkspaceJoinColumn('person') + personId: string | null; @WorkspaceRelation({ standardId: ACTIVITY_TARGET_STANDARD_FIELD_IDS.company, @@ -57,12 +62,14 @@ export class ActivityTargetWorkspaceEntity extends BaseWorkspaceEntity { label: 'Company', description: 'ActivityTarget company', icon: 'IconBuildingSkyscraper', - joinColumn: 'companyId', inverseSideTarget: () => CompanyWorkspaceEntity, inverseSideFieldKey: 'activityTargets', }) @WorkspaceIsNullable() - company: Relation<CompanyWorkspaceEntity>; + company: Relation<CompanyWorkspaceEntity> | null; + + @WorkspaceJoinColumn('company') + companyId: string | null; @WorkspaceRelation({ standardId: ACTIVITY_TARGET_STANDARD_FIELD_IDS.opportunity, @@ -70,12 +77,14 @@ export class ActivityTargetWorkspaceEntity extends BaseWorkspaceEntity { label: 'Opportunity', description: 'ActivityTarget opportunity', icon: 'IconTargetArrow', - joinColumn: 'opportunityId', inverseSideTarget: () => OpportunityWorkspaceEntity, inverseSideFieldKey: 'activityTargets', }) @WorkspaceIsNullable() - opportunity: Relation<OpportunityWorkspaceEntity>; + opportunity: Relation<OpportunityWorkspaceEntity> | null; + + @WorkspaceJoinColumn('opportunity') + opportunityId: string | null; @WorkspaceDynamicRelation({ type: RelationMetadataType.MANY_TO_ONE, diff --git a/packages/twenty-server/src/modules/activity/standard-objects/activity.workspace-entity.ts b/packages/twenty-server/src/modules/activity/standard-objects/activity.workspace-entity.ts index 8c6460eb45e3..f8d81dfebca2 100644 --- a/packages/twenty-server/src/modules/activity/standard-objects/activity.workspace-entity.ts +++ b/packages/twenty-server/src/modules/activity/standard-objects/activity.workspace-entity.ts @@ -17,6 +17,7 @@ import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator'; import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator'; import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity'; +import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator'; @WorkspaceEntity({ standardId: STANDARD_OBJECT_IDS.activity, @@ -64,7 +65,7 @@ export class ActivityWorkspaceEntity extends BaseWorkspaceEntity { icon: 'IconCalendarEvent', }) @WorkspaceIsNullable() - reminderAt: Date; + reminderAt: Date | null; @WorkspaceField({ standardId: ACTIVITY_STANDARD_FIELD_IDS.dueAt, @@ -74,7 +75,7 @@ export class ActivityWorkspaceEntity extends BaseWorkspaceEntity { icon: 'IconCalendarEvent', }) @WorkspaceIsNullable() - dueAt: Date; + dueAt: Date | null; @WorkspaceField({ standardId: ACTIVITY_STANDARD_FIELD_IDS.completedAt, @@ -84,7 +85,7 @@ export class ActivityWorkspaceEntity extends BaseWorkspaceEntity { icon: 'IconCheck', }) @WorkspaceIsNullable() - completedAt: Date; + completedAt: Date | null; @WorkspaceRelation({ standardId: ACTIVITY_STANDARD_FIELD_IDS.activityTargets, @@ -131,10 +132,12 @@ export class ActivityWorkspaceEntity extends BaseWorkspaceEntity { inverseSideTarget: () => WorkspaceMemberWorkspaceEntity, inverseSideFieldKey: 'authoredActivities', onDelete: RelationOnDeleteAction.SET_NULL, - joinColumn: 'authorId', }) @WorkspaceIsNullable() - author: Relation<WorkspaceMemberWorkspaceEntity>; + author: Relation<WorkspaceMemberWorkspaceEntity> | null; + + @WorkspaceJoinColumn('author') + authorId: string | null; @WorkspaceRelation({ standardId: ACTIVITY_STANDARD_FIELD_IDS.assignee, @@ -145,8 +148,10 @@ export class ActivityWorkspaceEntity extends BaseWorkspaceEntity { inverseSideTarget: () => WorkspaceMemberWorkspaceEntity, inverseSideFieldKey: 'assignedActivities', onDelete: RelationOnDeleteAction.SET_NULL, - joinColumn: 'assigneeId', }) @WorkspaceIsNullable() - assignee: Relation<WorkspaceMemberWorkspaceEntity>; + assignee: Relation<WorkspaceMemberWorkspaceEntity> | null; + + @WorkspaceJoinColumn('assignee') + assigneeId: string | null; } diff --git a/packages/twenty-server/src/modules/activity/standard-objects/comment.workspace-entity.ts b/packages/twenty-server/src/modules/activity/standard-objects/comment.workspace-entity.ts index b198e36da399..a572f5d074ad 100644 --- a/packages/twenty-server/src/modules/activity/standard-objects/comment.workspace-entity.ts +++ b/packages/twenty-server/src/modules/activity/standard-objects/comment.workspace-entity.ts @@ -11,6 +11,7 @@ import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator'; import { RelationMetadataType } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity'; import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity'; +import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator'; @WorkspaceEntity({ standardId: STANDARD_OBJECT_IDS.comment, @@ -37,21 +38,25 @@ export class CommentWorkspaceEntity extends BaseWorkspaceEntity { label: 'Author', description: 'Comment author', icon: 'IconCircleUser', - joinColumn: 'authorId', inverseSideTarget: () => WorkspaceMemberWorkspaceEntity, inverseSideFieldKey: 'authoredComments', }) author: Relation<WorkspaceMemberWorkspaceEntity>; + @WorkspaceJoinColumn('author') + authorId: string; + @WorkspaceRelation({ standardId: COMMENT_STANDARD_FIELD_IDS.activity, type: RelationMetadataType.MANY_TO_ONE, label: 'Activity', description: 'Comment activity', icon: 'IconNotes', - joinColumn: 'activityId', inverseSideTarget: () => ActivityWorkspaceEntity, inverseSideFieldKey: 'comments', }) activity: Relation<ActivityWorkspaceEntity>; + + @WorkspaceJoinColumn('activity') + activityId: string; } diff --git a/packages/twenty-server/src/modules/api-key/standard-objects/api-key.workspace-entity.ts b/packages/twenty-server/src/modules/api-key/standard-objects/api-key.workspace-entity.ts index 40159e093a85..82ca9d107d6b 100644 --- a/packages/twenty-server/src/modules/api-key/standard-objects/api-key.workspace-entity.ts +++ b/packages/twenty-server/src/modules/api-key/standard-objects/api-key.workspace-entity.ts @@ -45,5 +45,5 @@ export class ApiKeyWorkspaceEntity extends BaseWorkspaceEntity { icon: 'IconCalendar', }) @WorkspaceIsNullable() - revokedAt?: Date; + revokedAt?: Date | null; } diff --git a/packages/twenty-server/src/modules/attachment/repositories/attachment.repository.ts b/packages/twenty-server/src/modules/attachment/repositories/attachment.repository.ts deleted file mode 100644 index 2d340d2cba0d..000000000000 --- a/packages/twenty-server/src/modules/attachment/repositories/attachment.repository.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Injectable } from '@nestjs/common'; - -import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; - -@Injectable() -export class AttachmentRepository { - constructor( - private readonly workspaceDataSourceService: WorkspaceDataSourceService, - ) {} - - async deleteByAuthorId(authorId: string, workspaceId: string): Promise<void> { - const dataSourceSchema = - this.workspaceDataSourceService.getSchemaName(workspaceId); - - await this.workspaceDataSourceService.executeRawQuery( - `DELETE FROM ${dataSourceSchema}."attachment" WHERE "authorId" = $1`, - [authorId], - workspaceId, - ); - } -} diff --git a/packages/twenty-server/src/modules/attachment/standard-objects/attachment.workspace-entity.ts b/packages/twenty-server/src/modules/attachment/standard-objects/attachment.workspace-entity.ts index 42af628b9e03..a4ea0b2e7d14 100644 --- a/packages/twenty-server/src/modules/attachment/standard-objects/attachment.workspace-entity.ts +++ b/packages/twenty-server/src/modules/attachment/standard-objects/attachment.workspace-entity.ts @@ -18,6 +18,7 @@ import { RelationMetadataType } from 'src/engine/metadata-modules/relation-metad import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator'; import { WorkspaceDynamicRelation } from 'src/engine/twenty-orm/decorators/workspace-dynamic-relation.decorator'; import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity'; +import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator'; @WorkspaceEntity({ standardId: STANDARD_OBJECT_IDS.attachment, @@ -63,24 +64,28 @@ export class AttachmentWorkspaceEntity extends BaseWorkspaceEntity { label: 'Author', description: 'Attachment author', icon: 'IconCircleUser', - joinColumn: 'authorId', inverseSideTarget: () => WorkspaceMemberWorkspaceEntity, inverseSideFieldKey: 'authoredAttachments', }) author: Relation<WorkspaceMemberWorkspaceEntity>; + @WorkspaceJoinColumn('author') + authorId: string; + @WorkspaceRelation({ standardId: ATTACHMENT_STANDARD_FIELD_IDS.activity, type: RelationMetadataType.MANY_TO_ONE, label: 'Activity', description: 'Attachment activity', icon: 'IconNotes', - joinColumn: 'activityId', inverseSideTarget: () => ActivityWorkspaceEntity, inverseSideFieldKey: 'attachments', }) @WorkspaceIsNullable() - activity: Relation<ActivityWorkspaceEntity>; + activity: Relation<ActivityWorkspaceEntity> | null; + + @WorkspaceJoinColumn('activity') + activityId: string | null; @WorkspaceRelation({ standardId: ATTACHMENT_STANDARD_FIELD_IDS.person, @@ -88,12 +93,14 @@ export class AttachmentWorkspaceEntity extends BaseWorkspaceEntity { label: 'Person', description: 'Attachment person', icon: 'IconUser', - joinColumn: 'personId', inverseSideTarget: () => PersonWorkspaceEntity, inverseSideFieldKey: 'attachments', }) @WorkspaceIsNullable() - person: Relation<PersonWorkspaceEntity>; + person: Relation<PersonWorkspaceEntity> | null; + + @WorkspaceJoinColumn('person') + personId: string | null; @WorkspaceRelation({ standardId: ATTACHMENT_STANDARD_FIELD_IDS.company, @@ -101,12 +108,14 @@ export class AttachmentWorkspaceEntity extends BaseWorkspaceEntity { label: 'Company', description: 'Attachment company', icon: 'IconBuildingSkyscraper', - joinColumn: 'companyId', inverseSideTarget: () => CompanyWorkspaceEntity, inverseSideFieldKey: 'attachments', }) @WorkspaceIsNullable() - company: Relation<CompanyWorkspaceEntity>; + company: Relation<CompanyWorkspaceEntity> | null; + + @WorkspaceJoinColumn('company') + companyId: string | null; @WorkspaceRelation({ standardId: ATTACHMENT_STANDARD_FIELD_IDS.opportunity, @@ -114,12 +123,14 @@ export class AttachmentWorkspaceEntity extends BaseWorkspaceEntity { label: 'Opportunity', description: 'Attachment opportunity', icon: 'IconBuildingSkyscraper', - joinColumn: 'opportunityId', inverseSideTarget: () => OpportunityWorkspaceEntity, inverseSideFieldKey: 'attachments', }) @WorkspaceIsNullable() - opportunity: Relation<OpportunityWorkspaceEntity>; + opportunity: Relation<OpportunityWorkspaceEntity> | null; + + @WorkspaceJoinColumn('opportunity') + opportunityId: string | null; @WorkspaceDynamicRelation({ type: RelationMetadataType.MANY_TO_ONE, diff --git a/packages/twenty-server/src/modules/connected-account/services/blocklist/blocklist-validation.module.ts b/packages/twenty-server/src/modules/blocklist/blocklist-validation-manager/blocklist-validation-manager.module.ts similarity index 64% rename from packages/twenty-server/src/modules/connected-account/services/blocklist/blocklist-validation.module.ts rename to packages/twenty-server/src/modules/blocklist/blocklist-validation-manager/blocklist-validation-manager.module.ts index a76112fd8fc9..6d4678dc210e 100644 --- a/packages/twenty-server/src/modules/connected-account/services/blocklist/blocklist-validation.module.ts +++ b/packages/twenty-server/src/modules/blocklist/blocklist-validation-manager/blocklist-validation-manager.module.ts @@ -1,8 +1,8 @@ import { Module } from '@nestjs/common'; import { ObjectMetadataRepositoryModule } from 'src/engine/object-metadata-repository/object-metadata-repository.module'; -import { BlocklistValidationService } from 'src/modules/connected-account/services/blocklist/blocklist-validation.service'; -import { BlocklistWorkspaceEntity } from 'src/modules/connected-account/standard-objects/blocklist.workspace-entity'; +import { BlocklistValidationService } from 'src/modules/blocklist/blocklist-validation-manager/services/blocklist-validation.service'; +import { BlocklistWorkspaceEntity } from 'src/modules/blocklist/standard-objects/blocklist.workspace-entity'; import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; @Module({ @@ -15,4 +15,4 @@ import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/sta providers: [BlocklistValidationService], exports: [BlocklistValidationService], }) -export class BlocklistValidationModule {} +export class BlocklistValidationManagerModule {} diff --git a/packages/twenty-server/src/modules/connected-account/services/blocklist/blocklist-validation.service.ts b/packages/twenty-server/src/modules/blocklist/blocklist-validation-manager/services/blocklist-validation.service.ts similarity index 95% rename from packages/twenty-server/src/modules/connected-account/services/blocklist/blocklist-validation.service.ts rename to packages/twenty-server/src/modules/blocklist/blocklist-validation-manager/services/blocklist-validation.service.ts index efa8d727997a..eb518f3f4c99 100644 --- a/packages/twenty-server/src/modules/connected-account/services/blocklist/blocklist-validation.service.ts +++ b/packages/twenty-server/src/modules/blocklist/blocklist-validation-manager/services/blocklist-validation.service.ts @@ -9,8 +9,8 @@ import { import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; import { isDomain } from 'src/engine/utils/is-domain'; -import { BlocklistRepository } from 'src/modules/connected-account/repositories/blocklist.repository'; -import { BlocklistWorkspaceEntity } from 'src/modules/connected-account/standard-objects/blocklist.workspace-entity'; +import { BlocklistRepository } from 'src/modules/blocklist/repositories/blocklist.repository'; +import { BlocklistWorkspaceEntity } from 'src/modules/blocklist/standard-objects/blocklist.workspace-entity'; import { WorkspaceMemberRepository } from 'src/modules/workspace-member/repositories/workspace-member.repository'; import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; diff --git a/packages/twenty-server/src/modules/connected-account/query-hooks/blocklist/blocklist-create-many.pre-query.hook.ts b/packages/twenty-server/src/modules/blocklist/query-hooks/blocklist-create-many.pre-query.hook.ts similarity index 51% rename from packages/twenty-server/src/modules/connected-account/query-hooks/blocklist/blocklist-create-many.pre-query.hook.ts rename to packages/twenty-server/src/modules/blocklist/query-hooks/blocklist-create-many.pre-query.hook.ts index 30e025de1079..b8118ec12aa9 100644 --- a/packages/twenty-server/src/modules/connected-account/query-hooks/blocklist/blocklist-create-many.pre-query.hook.ts +++ b/packages/twenty-server/src/modules/blocklist/query-hooks/blocklist-create-many.pre-query.hook.ts @@ -1,15 +1,16 @@ -import { Injectable } from '@nestjs/common'; - -import { WorkspacePreQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-pre-query-hook/interfaces/workspace-pre-query-hook.interface'; +import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface'; import { CreateManyResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; +import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator'; import { BlocklistItem, BlocklistValidationService, -} from 'src/modules/connected-account/services/blocklist/blocklist-validation.service'; +} from 'src/modules/blocklist/blocklist-validation-manager/services/blocklist-validation.service'; -@Injectable() -export class BlocklistCreateManyPreQueryHook implements WorkspacePreQueryHook { +@WorkspaceQueryHook(`blocklist.createMany`) +export class BlocklistCreateManyPreQueryHook + implements WorkspaceQueryHookInstance +{ constructor( private readonly blocklistValidationService: BlocklistValidationService, ) {} diff --git a/packages/twenty-server/src/modules/blocklist/query-hooks/blocklist-query-hook.module.ts b/packages/twenty-server/src/modules/blocklist/query-hooks/blocklist-query-hook.module.ts new file mode 100644 index 000000000000..3a03459c85ec --- /dev/null +++ b/packages/twenty-server/src/modules/blocklist/query-hooks/blocklist-query-hook.module.ts @@ -0,0 +1,16 @@ +import { Module } from '@nestjs/common'; + +import { BlocklistValidationManagerModule } from 'src/modules/blocklist/blocklist-validation-manager/blocklist-validation-manager.module'; +import { BlocklistCreateManyPreQueryHook } from 'src/modules/blocklist/query-hooks/blocklist-create-many.pre-query.hook'; +import { BlocklistUpdateManyPreQueryHook } from 'src/modules/blocklist/query-hooks/blocklist-update-many.pre-query.hook'; +import { BlocklistUpdateOnePreQueryHook } from 'src/modules/blocklist/query-hooks/blocklist-update-one.pre-query.hook'; + +@Module({ + imports: [BlocklistValidationManagerModule], + providers: [ + BlocklistCreateManyPreQueryHook, + BlocklistUpdateManyPreQueryHook, + BlocklistUpdateOnePreQueryHook, + ], +}) +export class BlocklistQueryHookModule {} diff --git a/packages/twenty-server/src/modules/blocklist/query-hooks/blocklist-update-many.pre-query.hook.ts b/packages/twenty-server/src/modules/blocklist/query-hooks/blocklist-update-many.pre-query.hook.ts new file mode 100644 index 000000000000..28be74cfc6dc --- /dev/null +++ b/packages/twenty-server/src/modules/blocklist/query-hooks/blocklist-update-many.pre-query.hook.ts @@ -0,0 +1,16 @@ +import { MethodNotAllowedException } from '@nestjs/common'; + +import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface'; + +import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator'; + +@WorkspaceQueryHook(`blocklist.updateMany`) +export class BlocklistUpdateManyPreQueryHook + implements WorkspaceQueryHookInstance +{ + constructor() {} + + async execute(): Promise<void> { + throw new MethodNotAllowedException('Method not allowed.'); + } +} diff --git a/packages/twenty-server/src/modules/connected-account/query-hooks/blocklist/blocklist-update-one.pre-query.hook.ts b/packages/twenty-server/src/modules/blocklist/query-hooks/blocklist-update-one.pre-query.hook.ts similarity index 51% rename from packages/twenty-server/src/modules/connected-account/query-hooks/blocklist/blocklist-update-one.pre-query.hook.ts rename to packages/twenty-server/src/modules/blocklist/query-hooks/blocklist-update-one.pre-query.hook.ts index 28c39a43b2e9..b9fdaf247bd7 100644 --- a/packages/twenty-server/src/modules/connected-account/query-hooks/blocklist/blocklist-update-one.pre-query.hook.ts +++ b/packages/twenty-server/src/modules/blocklist/query-hooks/blocklist-update-one.pre-query.hook.ts @@ -1,15 +1,16 @@ -import { Injectable } from '@nestjs/common'; - -import { WorkspacePreQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-pre-query-hook/interfaces/workspace-pre-query-hook.interface'; +import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface'; import { UpdateOneResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; +import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator'; import { BlocklistItem, BlocklistValidationService, -} from 'src/modules/connected-account/services/blocklist/blocklist-validation.service'; +} from 'src/modules/blocklist/blocklist-validation-manager/services/blocklist-validation.service'; -@Injectable() -export class BlocklistUpdateOnePreQueryHook implements WorkspacePreQueryHook { +@WorkspaceQueryHook(`blocklist.updateOne`) +export class BlocklistUpdateOnePreQueryHook + implements WorkspaceQueryHookInstance +{ constructor( private readonly blocklistValidationService: BlocklistValidationService, ) {} diff --git a/packages/twenty-server/src/modules/connected-account/repositories/blocklist.repository.ts b/packages/twenty-server/src/modules/blocklist/repositories/blocklist.repository.ts similarity index 84% rename from packages/twenty-server/src/modules/connected-account/repositories/blocklist.repository.ts rename to packages/twenty-server/src/modules/blocklist/repositories/blocklist.repository.ts index 99ec3ecbb6a1..755997e23ff1 100644 --- a/packages/twenty-server/src/modules/connected-account/repositories/blocklist.repository.ts +++ b/packages/twenty-server/src/modules/blocklist/repositories/blocklist.repository.ts @@ -3,8 +3,7 @@ import { Injectable } from '@nestjs/common'; import { EntityManager } from 'typeorm'; import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; -import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record'; -import { BlocklistWorkspaceEntity } from 'src/modules/connected-account/standard-objects/blocklist.workspace-entity'; +import { BlocklistWorkspaceEntity } from 'src/modules/blocklist/standard-objects/blocklist.workspace-entity'; @Injectable() export class BlocklistRepository { @@ -16,7 +15,7 @@ export class BlocklistRepository { id: string, workspaceId: string, transactionManager?: EntityManager, - ): Promise<ObjectRecord<BlocklistWorkspaceEntity> | null> { + ): Promise<BlocklistWorkspaceEntity | null> { const dataSourceSchema = this.workspaceDataSourceService.getSchemaName(workspaceId); @@ -39,7 +38,7 @@ export class BlocklistRepository { workspaceMemberId: string, workspaceId: string, transactionManager?: EntityManager, - ): Promise<ObjectRecord<BlocklistWorkspaceEntity>[]> { + ): Promise<BlocklistWorkspaceEntity[]> { const dataSourceSchema = this.workspaceDataSourceService.getSchemaName(workspaceId); @@ -56,7 +55,7 @@ export class BlocklistRepository { handle: string, workspaceId: string, transactionManager?: EntityManager, - ): Promise<ObjectRecord<BlocklistWorkspaceEntity>[]> { + ): Promise<BlocklistWorkspaceEntity[]> { const dataSourceSchema = this.workspaceDataSourceService.getSchemaName(workspaceId); diff --git a/packages/twenty-server/src/modules/connected-account/standard-objects/blocklist.workspace-entity.ts b/packages/twenty-server/src/modules/blocklist/standard-objects/blocklist.workspace-entity.ts similarity index 92% rename from packages/twenty-server/src/modules/connected-account/standard-objects/blocklist.workspace-entity.ts rename to packages/twenty-server/src/modules/blocklist/standard-objects/blocklist.workspace-entity.ts index fce1a5eb201d..323f211a5e35 100644 --- a/packages/twenty-server/src/modules/connected-account/standard-objects/blocklist.workspace-entity.ts +++ b/packages/twenty-server/src/modules/blocklist/standard-objects/blocklist.workspace-entity.ts @@ -11,6 +11,7 @@ import { WorkspaceIsNotAuditLogged } from 'src/engine/twenty-orm/decorators/work import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field.decorator'; import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator'; import { RelationMetadataType } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity'; +import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator'; @WorkspaceEntity({ standardId: STANDARD_OBJECT_IDS.blocklist, @@ -38,9 +39,11 @@ export class BlocklistWorkspaceEntity extends BaseWorkspaceEntity { label: 'WorkspaceMember', description: 'WorkspaceMember', icon: 'IconCircleUser', - joinColumn: 'workspaceMemberId', inverseSideTarget: () => WorkspaceMemberWorkspaceEntity, inverseSideFieldKey: 'blocklist', }) workspaceMember: Relation<WorkspaceMemberWorkspaceEntity>; + + @WorkspaceJoinColumn('workspaceMember') + workspaceMemberId: string; } diff --git a/packages/twenty-server/src/modules/calendar-messaging-participant/services/add-person-id-and-workspace-member-id/add-person-id-and-workspace-member-id.service.ts b/packages/twenty-server/src/modules/calendar-messaging-participant-manager/services/add-person-id-and-workspace-member-id/add-person-id-and-workspace-member-id.service.ts similarity index 97% rename from packages/twenty-server/src/modules/calendar-messaging-participant/services/add-person-id-and-workspace-member-id/add-person-id-and-workspace-member-id.service.ts rename to packages/twenty-server/src/modules/calendar-messaging-participant-manager/services/add-person-id-and-workspace-member-id/add-person-id-and-workspace-member-id.service.ts index aa6eb282a977..ef22e2a1cb3a 100644 --- a/packages/twenty-server/src/modules/calendar-messaging-participant/services/add-person-id-and-workspace-member-id/add-person-id-and-workspace-member-id.service.ts +++ b/packages/twenty-server/src/modules/calendar-messaging-participant-manager/services/add-person-id-and-workspace-member-id/add-person-id-and-workspace-member-id.service.ts @@ -7,6 +7,8 @@ import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/work import { PersonRepository } from 'src/modules/person/repositories/person.repository'; import { PersonWorkspaceEntity } from 'src/modules/person/standard-objects/person.workspace-entity'; +// TODO: Move inside person module and workspace-member module + @Injectable() export class AddPersonIdAndWorkspaceMemberIdService { constructor( diff --git a/packages/twenty-server/src/modules/calendar-messaging-participant/utils/__tests__/is-email-blocklisted.util.spec.ts b/packages/twenty-server/src/modules/calendar-messaging-participant-manager/utils/__tests__/is-email-blocklisted.util.spec.ts similarity index 97% rename from packages/twenty-server/src/modules/calendar-messaging-participant/utils/__tests__/is-email-blocklisted.util.spec.ts rename to packages/twenty-server/src/modules/calendar-messaging-participant-manager/utils/__tests__/is-email-blocklisted.util.spec.ts index c7c6af34c30f..4d5cf12553a7 100644 --- a/packages/twenty-server/src/modules/calendar-messaging-participant/utils/__tests__/is-email-blocklisted.util.spec.ts +++ b/packages/twenty-server/src/modules/calendar-messaging-participant-manager/utils/__tests__/is-email-blocklisted.util.spec.ts @@ -1,4 +1,4 @@ -import { isEmailBlocklisted } from 'src/modules/calendar-messaging-participant/utils/is-email-blocklisted.util'; +import { isEmailBlocklisted } from 'src/modules/calendar-messaging-participant-manager/utils/is-email-blocklisted.util'; describe('isEmailBlocklisted', () => { it('should return true if email is blocklisted', () => { diff --git a/packages/twenty-server/src/modules/calendar-messaging-participant/utils/is-email-blocklisted.util.ts b/packages/twenty-server/src/modules/calendar-messaging-participant-manager/utils/is-email-blocklisted.util.ts similarity index 91% rename from packages/twenty-server/src/modules/calendar-messaging-participant/utils/is-email-blocklisted.util.ts rename to packages/twenty-server/src/modules/calendar-messaging-participant-manager/utils/is-email-blocklisted.util.ts index af21bbe1ed96..1ba64ee19fc6 100644 --- a/packages/twenty-server/src/modules/calendar-messaging-participant/utils/is-email-blocklisted.util.ts +++ b/packages/twenty-server/src/modules/calendar-messaging-participant-manager/utils/is-email-blocklisted.util.ts @@ -1,3 +1,5 @@ +// TODO: Move inside blocklist module + export const isEmailBlocklisted = ( channelHandle: string, email: string | null | undefined, diff --git a/packages/twenty-server/src/modules/calendar-messaging-participant/jobs/calendar-messaging-participant-job.module.ts b/packages/twenty-server/src/modules/calendar-messaging-participant/jobs/calendar-messaging-participant-job.module.ts deleted file mode 100644 index a2c338dace65..000000000000 --- a/packages/twenty-server/src/modules/calendar-messaging-participant/jobs/calendar-messaging-participant-job.module.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Module } from '@nestjs/common'; - -import { MatchParticipantJob } from 'src/modules/calendar-messaging-participant/jobs/match-participant.job'; -import { UnmatchParticipantJob } from 'src/modules/calendar-messaging-participant/jobs/unmatch-participant.job'; -import { CalendarEventParticipantModule } from 'src/modules/calendar/services/calendar-event-participant/calendar-event-participant.module'; -import { MessagingCommonModule } from 'src/modules/messaging/common/messaging-common.module'; - -@Module({ - imports: [CalendarEventParticipantModule, MessagingCommonModule], - providers: [ - { - provide: MatchParticipantJob.name, - useClass: MatchParticipantJob, - }, - { - provide: UnmatchParticipantJob.name, - useClass: UnmatchParticipantJob, - }, - ], -}) -export class CalendarMessagingParticipantJobModule {} diff --git a/packages/twenty-server/src/modules/calendar-messaging-participant/jobs/match-participant.job.ts b/packages/twenty-server/src/modules/calendar-messaging-participant/jobs/match-participant.job.ts deleted file mode 100644 index 8f9015bfcd24..000000000000 --- a/packages/twenty-server/src/modules/calendar-messaging-participant/jobs/match-participant.job.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { Injectable } from '@nestjs/common'; - -import { MessageQueueJob } from 'src/engine/integrations/message-queue/interfaces/message-queue-job.interface'; - -import { CalendarEventParticipantService } from 'src/modules/calendar/services/calendar-event-participant/calendar-event-participant.service'; -import { MessagingMessageParticipantService } from 'src/modules/messaging/common/services/messaging-message-participant.service'; - -export type MatchParticipantJobData = { - workspaceId: string; - email: string; - personId?: string; - workspaceMemberId?: string; -}; - -@Injectable() -export class MatchParticipantJob - implements MessageQueueJob<MatchParticipantJobData> -{ - constructor( - private readonly messageParticipantService: MessagingMessageParticipantService, - private readonly calendarEventParticipantService: CalendarEventParticipantService, - ) {} - - async handle(data: MatchParticipantJobData): Promise<void> { - const { workspaceId, email, personId, workspaceMemberId } = data; - - await this.messageParticipantService.matchMessageParticipants( - workspaceId, - email, - personId, - workspaceMemberId, - ); - - await this.calendarEventParticipantService.matchCalendarEventParticipants( - workspaceId, - email, - personId, - workspaceMemberId, - ); - } -} diff --git a/packages/twenty-server/src/modules/calendar-messaging-participant/jobs/unmatch-participant.job.ts b/packages/twenty-server/src/modules/calendar-messaging-participant/jobs/unmatch-participant.job.ts deleted file mode 100644 index 11fee2cda22f..000000000000 --- a/packages/twenty-server/src/modules/calendar-messaging-participant/jobs/unmatch-participant.job.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { Injectable } from '@nestjs/common'; - -import { MessageQueueJob } from 'src/engine/integrations/message-queue/interfaces/message-queue-job.interface'; - -import { CalendarEventParticipantService } from 'src/modules/calendar/services/calendar-event-participant/calendar-event-participant.service'; -import { MessagingMessageParticipantService } from 'src/modules/messaging/common/services/messaging-message-participant.service'; - -export type UnmatchParticipantJobData = { - workspaceId: string; - email: string; - personId?: string; - workspaceMemberId?: string; -}; - -@Injectable() -export class UnmatchParticipantJob - implements MessageQueueJob<UnmatchParticipantJobData> -{ - constructor( - private readonly messageParticipantService: MessagingMessageParticipantService, - private readonly calendarEventParticipantService: CalendarEventParticipantService, - ) {} - - async handle(data: UnmatchParticipantJobData): Promise<void> { - const { workspaceId, email, personId, workspaceMemberId } = data; - - await this.messageParticipantService.unmatchMessageParticipants( - workspaceId, - email, - personId, - workspaceMemberId, - ); - - await this.calendarEventParticipantService.unmatchCalendarEventParticipants( - workspaceId, - email, - personId, - workspaceMemberId, - ); - } -} diff --git a/packages/twenty-server/src/modules/calendar-messaging-participant/services/add-person-id-and-workspace-member-id/add-person-id-and-workspace-member-id.module.ts b/packages/twenty-server/src/modules/calendar-messaging-participant/services/add-person-id-and-workspace-member-id/add-person-id-and-workspace-member-id.module.ts deleted file mode 100644 index eac7dd9c797d..000000000000 --- a/packages/twenty-server/src/modules/calendar-messaging-participant/services/add-person-id-and-workspace-member-id/add-person-id-and-workspace-member-id.module.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Module } from '@nestjs/common'; - -import { ObjectMetadataRepositoryModule } from 'src/engine/object-metadata-repository/object-metadata-repository.module'; -import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; -import { AddPersonIdAndWorkspaceMemberIdService } from 'src/modules/calendar-messaging-participant/services/add-person-id-and-workspace-member-id/add-person-id-and-workspace-member-id.service'; -import { PersonWorkspaceEntity } from 'src/modules/person/standard-objects/person.workspace-entity'; - -@Module({ - imports: [ - WorkspaceDataSourceModule, - ObjectMetadataRepositoryModule.forFeature([PersonWorkspaceEntity]), - ], - providers: [AddPersonIdAndWorkspaceMemberIdService], - exports: [AddPersonIdAndWorkspaceMemberIdService], -}) -export class AddPersonIdAndWorkspaceMemberIdModule {} diff --git a/packages/twenty-server/src/modules/calendar/blocklist-manager/calendar-blocklist-manager.module.ts b/packages/twenty-server/src/modules/calendar/blocklist-manager/calendar-blocklist-manager.module.ts new file mode 100644 index 000000000000..57497f1d279e --- /dev/null +++ b/packages/twenty-server/src/modules/calendar/blocklist-manager/calendar-blocklist-manager.module.ts @@ -0,0 +1,18 @@ +import { Module } from '@nestjs/common'; + +import { BlocklistItemDeleteCalendarEventsJob } from 'src/modules/calendar/blocklist-manager/jobs/blocklist-item-delete-calendar-events.job'; +import { BlocklistReimportCalendarEventsJob } from 'src/modules/calendar/blocklist-manager/jobs/blocklist-reimport-calendar-events.job'; +import { CalendarBlocklistListener } from 'src/modules/calendar/blocklist-manager/listeners/calendar-blocklist.listener'; +import { CalendarEventCleanerModule } from 'src/modules/calendar/calendar-event-cleaner/calendar-event-cleaner.module'; +import { CalendarEventImportManagerModule } from 'src/modules/calendar/calendar-event-import-manager/calendar-event-import-manager.module'; + +@Module({ + imports: [CalendarEventCleanerModule, CalendarEventImportManagerModule], + providers: [ + CalendarBlocklistListener, + BlocklistItemDeleteCalendarEventsJob, + BlocklistReimportCalendarEventsJob, + ], + exports: [], +}) +export class CalendarBlocklistManagerModule {} diff --git a/packages/twenty-server/src/modules/calendar/blocklist-manager/jobs/blocklist-item-delete-calendar-events.job.ts b/packages/twenty-server/src/modules/calendar/blocklist-manager/jobs/blocklist-item-delete-calendar-events.job.ts new file mode 100644 index 000000000000..7091c127a000 --- /dev/null +++ b/packages/twenty-server/src/modules/calendar/blocklist-manager/jobs/blocklist-item-delete-calendar-events.job.ts @@ -0,0 +1,101 @@ +import { Logger, Scope } from '@nestjs/common'; + +import { Any, ILike } from 'typeorm'; + +import { Process } from 'src/engine/integrations/message-queue/decorators/process.decorator'; +import { Processor } from 'src/engine/integrations/message-queue/decorators/processor.decorator'; +import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; +import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; +import { InjectWorkspaceRepository } from 'src/engine/twenty-orm/decorators/inject-workspace-repository.decorator'; +import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository'; +import { BlocklistRepository } from 'src/modules/blocklist/repositories/blocklist.repository'; +import { BlocklistWorkspaceEntity } from 'src/modules/blocklist/standard-objects/blocklist.workspace-entity'; +import { CalendarEventCleanerService } from 'src/modules/calendar/calendar-event-cleaner/services/calendar-event-cleaner.service'; +import { CalendarChannelEventAssociationWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-channel-event-association.workspace-entity'; +import { CalendarChannelWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-channel.workspace-entity'; + +export type BlocklistItemDeleteCalendarEventsJobData = { + workspaceId: string; + blocklistItemId: string; +}; + +@Processor({ + queueName: MessageQueue.calendarQueue, + scope: Scope.REQUEST, +}) +export class BlocklistItemDeleteCalendarEventsJob { + private readonly logger = new Logger( + BlocklistItemDeleteCalendarEventsJob.name, + ); + + constructor( + @InjectWorkspaceRepository(CalendarChannelWorkspaceEntity) + private readonly calendarChannelRepository: WorkspaceRepository<CalendarChannelWorkspaceEntity>, + @InjectWorkspaceRepository(CalendarChannelEventAssociationWorkspaceEntity) + private readonly calendarChannelEventAssociationRepository: WorkspaceRepository<CalendarChannelEventAssociationWorkspaceEntity>, + @InjectObjectMetadataRepository(BlocklistWorkspaceEntity) + private readonly blocklistRepository: BlocklistRepository, + private readonly calendarEventCleanerService: CalendarEventCleanerService, + ) {} + + @Process(BlocklistItemDeleteCalendarEventsJob.name) + async handle(data: BlocklistItemDeleteCalendarEventsJobData): Promise<void> { + const { workspaceId, blocklistItemId } = data; + + const blocklistItem = await this.blocklistRepository.getById( + blocklistItemId, + workspaceId, + ); + + if (!blocklistItem) { + this.logger.log( + `Blocklist item with id ${blocklistItemId} not found in workspace ${workspaceId}`, + ); + + return; + } + + const { handle, workspaceMemberId } = blocklistItem; + + this.logger.log( + `Deleting calendar events from ${handle} in workspace ${workspaceId} for workspace member ${workspaceMemberId}`, + ); + + if (!workspaceMemberId) { + throw new Error( + `Workspace member ID is undefined for blocklist item ${blocklistItemId} in workspace ${workspaceId}`, + ); + } + + const calendarChannels = await this.calendarChannelRepository.find({ + where: { + connectedAccount: { + accountOwnerId: workspaceMemberId, + }, + }, + }); + + const calendarChannelIds = calendarChannels.map(({ id }) => id); + + const isHandleDomain = handle.startsWith('@'); + + await this.calendarChannelEventAssociationRepository.delete({ + calendarEvent: { + calendarEventParticipants: { + handle: isHandleDomain ? ILike(`%${handle}`) : handle, + }, + calendarChannelEventAssociations: { + calendarChannelId: Any(calendarChannelIds), + }, + }, + }); + + await this.calendarEventCleanerService.cleanWorkspaceCalendarEvents( + workspaceId, + ); + + this.logger.log( + `Deleted calendar events from handle ${handle} in workspace ${workspaceId} for workspace member ${workspaceMemberId}`, + ); + } +} diff --git a/packages/twenty-server/src/modules/calendar/blocklist-manager/jobs/blocklist-reimport-calendar-events.job.ts b/packages/twenty-server/src/modules/calendar/blocklist-manager/jobs/blocklist-reimport-calendar-events.job.ts new file mode 100644 index 000000000000..4eef5ecdb1a9 --- /dev/null +++ b/packages/twenty-server/src/modules/calendar/blocklist-manager/jobs/blocklist-reimport-calendar-events.job.ts @@ -0,0 +1,61 @@ +import { Scope } from '@nestjs/common'; + +import { Any } from 'typeorm'; + +import { Processor } from 'src/engine/integrations/message-queue/decorators/processor.decorator'; +import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; +import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; +import { ConnectedAccountRepository } from 'src/modules/connected-account/repositories/connected-account.repository'; +import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; +import { Process } from 'src/engine/integrations/message-queue/decorators/process.decorator'; +import { InjectWorkspaceRepository } from 'src/engine/twenty-orm/decorators/inject-workspace-repository.decorator'; +import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository'; +import { + CalendarChannelSyncStage, + CalendarChannelWorkspaceEntity, +} from 'src/modules/calendar/common/standard-objects/calendar-channel.workspace-entity'; + +export type BlocklistReimportCalendarEventsJobData = { + workspaceId: string; + workspaceMemberId: string; +}; + +@Processor({ + queueName: MessageQueue.calendarQueue, + scope: Scope.REQUEST, +}) +export class BlocklistReimportCalendarEventsJob { + constructor( + @InjectObjectMetadataRepository(ConnectedAccountWorkspaceEntity) + private readonly connectedAccountRepository: ConnectedAccountRepository, + @InjectWorkspaceRepository(CalendarChannelWorkspaceEntity) + private readonly calendarChannelRepository: WorkspaceRepository<CalendarChannelWorkspaceEntity>, + ) {} + + @Process(BlocklistReimportCalendarEventsJob.name) + async handle(data: BlocklistReimportCalendarEventsJobData): Promise<void> { + const { workspaceId, workspaceMemberId } = data; + + const connectedAccounts = + await this.connectedAccountRepository.getAllByWorkspaceMemberId( + workspaceMemberId, + workspaceId, + ); + + if (!connectedAccounts || connectedAccounts.length === 0) { + return; + } + + await this.calendarChannelRepository.update( + { + connectedAccountId: Any( + connectedAccounts.map((connectedAccount) => connectedAccount.id), + ), + }, + { + syncStage: + CalendarChannelSyncStage.FULL_CALENDAR_EVENT_LIST_FETCH_PENDING, + }, + ); + } +} diff --git a/packages/twenty-server/src/modules/calendar/listeners/calendar-blocklist.listener.ts b/packages/twenty-server/src/modules/calendar/blocklist-manager/listeners/calendar-blocklist.listener.ts similarity index 82% rename from packages/twenty-server/src/modules/calendar/listeners/calendar-blocklist.listener.ts rename to packages/twenty-server/src/modules/calendar/blocklist-manager/listeners/calendar-blocklist.listener.ts index c1ed4f2d98eb..9c1c54c5fab3 100644 --- a/packages/twenty-server/src/modules/calendar/listeners/calendar-blocklist.listener.ts +++ b/packages/twenty-server/src/modules/calendar/blocklist-manager/listeners/calendar-blocklist.listener.ts @@ -1,25 +1,26 @@ -import { Inject, Injectable } from '@nestjs/common'; +import { Injectable } from '@nestjs/common'; import { OnEvent } from '@nestjs/event-emitter'; import { ObjectRecordCreateEvent } from 'src/engine/integrations/event-emitter/types/object-record-create.event'; import { ObjectRecordDeleteEvent } from 'src/engine/integrations/event-emitter/types/object-record-delete.event'; import { ObjectRecordUpdateEvent } from 'src/engine/integrations/event-emitter/types/object-record-update.event'; +import { InjectMessageQueue } from 'src/engine/integrations/message-queue/decorators/message-queue.decorator'; import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service'; +import { BlocklistWorkspaceEntity } from 'src/modules/blocklist/standard-objects/blocklist.workspace-entity'; import { - BlocklistItemDeleteCalendarEventsJobData, BlocklistItemDeleteCalendarEventsJob, -} from 'src/modules/calendar/jobs/blocklist-item-delete-calendar-events.job'; + BlocklistItemDeleteCalendarEventsJobData, +} from 'src/modules/calendar/blocklist-manager/jobs/blocklist-item-delete-calendar-events.job'; import { - BlocklistReimportCalendarEventsJobData, BlocklistReimportCalendarEventsJob, -} from 'src/modules/calendar/jobs/blocklist-reimport-calendar-events.job'; -import { BlocklistWorkspaceEntity } from 'src/modules/connected-account/standard-objects/blocklist.workspace-entity'; + BlocklistReimportCalendarEventsJobData, +} from 'src/modules/calendar/blocklist-manager/jobs/blocklist-reimport-calendar-events.job'; @Injectable() export class CalendarBlocklistListener { constructor( - @Inject(MessageQueue.calendarQueue) + @InjectMessageQueue(MessageQueue.calendarQueue) private readonly messageQueueService: MessageQueueService, ) {} @@ -45,7 +46,6 @@ export class CalendarBlocklistListener { { workspaceId: payload.workspaceId, workspaceMemberId: payload.properties.before.workspaceMember.id, - handle: payload.properties.before.handle, }, ); } @@ -67,7 +67,6 @@ export class CalendarBlocklistListener { { workspaceId: payload.workspaceId, workspaceMemberId: payload.properties.after.workspaceMember.id, - handle: payload.properties.before.handle, }, ); } diff --git a/packages/twenty-server/src/modules/calendar/calendar-event-cleaner/calendar-event-cleaner.module.ts b/packages/twenty-server/src/modules/calendar/calendar-event-cleaner/calendar-event-cleaner.module.ts new file mode 100644 index 000000000000..50da2766148f --- /dev/null +++ b/packages/twenty-server/src/modules/calendar/calendar-event-cleaner/calendar-event-cleaner.module.ts @@ -0,0 +1,16 @@ +import { Module } from '@nestjs/common'; + +import { TwentyORMModule } from 'src/engine/twenty-orm/twenty-orm.module'; +import { DeleteConnectedAccountAssociatedCalendarDataJob } from 'src/modules/calendar/calendar-event-cleaner/jobs/delete-connected-account-associated-calendar-data.job'; +import { CalendarEventCleanerService } from 'src/modules/calendar/calendar-event-cleaner/services/calendar-event-cleaner.service'; +import { CalendarEventWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-event.workspace-entity'; + +@Module({ + imports: [TwentyORMModule.forFeature([CalendarEventWorkspaceEntity])], + providers: [ + CalendarEventCleanerService, + DeleteConnectedAccountAssociatedCalendarDataJob, + ], + exports: [CalendarEventCleanerService], +}) +export class CalendarEventCleanerModule {} diff --git a/packages/twenty-server/src/modules/calendar/jobs/delete-connected-account-associated-calendar-data.job.ts b/packages/twenty-server/src/modules/calendar/calendar-event-cleaner/jobs/delete-connected-account-associated-calendar-data.job.ts similarity index 62% rename from packages/twenty-server/src/modules/calendar/jobs/delete-connected-account-associated-calendar-data.job.ts rename to packages/twenty-server/src/modules/calendar/calendar-event-cleaner/jobs/delete-connected-account-associated-calendar-data.job.ts index 2d41ada2fa43..481814595542 100644 --- a/packages/twenty-server/src/modules/calendar/jobs/delete-connected-account-associated-calendar-data.job.ts +++ b/packages/twenty-server/src/modules/calendar/calendar-event-cleaner/jobs/delete-connected-account-associated-calendar-data.job.ts @@ -1,19 +1,17 @@ -import { Injectable, Logger } from '@nestjs/common'; +import { Logger } from '@nestjs/common'; -import { MessageQueueJob } from 'src/engine/integrations/message-queue/interfaces/message-queue-job.interface'; - -import { CalendarEventCleanerService } from 'src/modules/calendar/services/calendar-event-cleaner/calendar-event-cleaner.service'; +import { Process } from 'src/engine/integrations/message-queue/decorators/process.decorator'; +import { Processor } from 'src/engine/integrations/message-queue/decorators/processor.decorator'; +import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; +import { CalendarEventCleanerService } from 'src/modules/calendar/calendar-event-cleaner/services/calendar-event-cleaner.service'; export type DeleteConnectedAccountAssociatedCalendarDataJobData = { workspaceId: string; connectedAccountId: string; }; -@Injectable() -export class DeleteConnectedAccountAssociatedCalendarDataJob - implements - MessageQueueJob<DeleteConnectedAccountAssociatedCalendarDataJobData> -{ +@Processor(MessageQueue.calendarQueue) +export class DeleteConnectedAccountAssociatedCalendarDataJob { private readonly logger = new Logger( DeleteConnectedAccountAssociatedCalendarDataJob.name, ); @@ -22,6 +20,7 @@ export class DeleteConnectedAccountAssociatedCalendarDataJob private readonly calendarEventCleanerService: CalendarEventCleanerService, ) {} + @Process(DeleteConnectedAccountAssociatedCalendarDataJob.name) async handle( data: DeleteConnectedAccountAssociatedCalendarDataJobData, ): Promise<void> { diff --git a/packages/twenty-server/src/modules/calendar/calendar-event-cleaner/services/calendar-event-cleaner.service.ts b/packages/twenty-server/src/modules/calendar/calendar-event-cleaner/services/calendar-event-cleaner.service.ts new file mode 100644 index 000000000000..0248957a612a --- /dev/null +++ b/packages/twenty-server/src/modules/calendar/calendar-event-cleaner/services/calendar-event-cleaner.service.ts @@ -0,0 +1,40 @@ +import { Injectable } from '@nestjs/common'; + +import { Any, IsNull } from 'typeorm'; + +import { InjectWorkspaceRepository } from 'src/engine/twenty-orm/decorators/inject-workspace-repository.decorator'; +import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository'; +import { deleteUsingPagination } from 'src/modules/messaging/message-cleaner/utils/delete-using-pagination.util'; +import { CalendarEventWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-event.workspace-entity'; + +@Injectable() +export class CalendarEventCleanerService { + constructor( + @InjectWorkspaceRepository(CalendarEventWorkspaceEntity) + private readonly calendarEventRepository: WorkspaceRepository<CalendarEventWorkspaceEntity>, + ) {} + + public async cleanWorkspaceCalendarEvents(workspaceId: string) { + await deleteUsingPagination( + workspaceId, + 500, + async (limit, offset) => { + const nonAssociatedCalendarEvents = + await this.calendarEventRepository.find({ + where: { + calendarChannelEventAssociations: { + id: IsNull(), + }, + }, + take: limit, + skip: offset, + }); + + return nonAssociatedCalendarEvents.map(({ id }) => id); + }, + async (ids) => { + await this.calendarEventRepository.delete({ id: Any(ids) }); + }, + ); + } +} diff --git a/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/calendar-event-import-manager.module.ts b/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/calendar-event-import-manager.module.ts new file mode 100644 index 000000000000..cfcee7cad740 --- /dev/null +++ b/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/calendar-event-import-manager.module.ts @@ -0,0 +1,69 @@ +import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; + +import { BillingModule } from 'src/engine/core-modules/billing/billing.module'; +import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity'; +import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity'; +import { ObjectMetadataRepositoryModule } from 'src/engine/object-metadata-repository/object-metadata-repository.module'; +import { TwentyORMModule } from 'src/engine/twenty-orm/twenty-orm.module'; +import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; +import { BlocklistWorkspaceEntity } from 'src/modules/blocklist/standard-objects/blocklist.workspace-entity'; +import { CalendarEventCleanerModule } from 'src/modules/calendar/calendar-event-cleaner/calendar-event-cleaner.module'; +import { CalendarEventListFetchCronCommand } from 'src/modules/calendar/calendar-event-import-manager/crons/commands/calendar-event-list-fetch.cron.command'; +import { CalendarEventListFetchCronJob } from 'src/modules/calendar/calendar-event-import-manager/crons/jobs/calendar-event-list-fetch.cron.job'; +import { GoogleCalendarDriverModule } from 'src/modules/calendar/calendar-event-import-manager/drivers/google-calendar/google-calendar-driver.module'; +import { CalendarEventListFetchJob } from 'src/modules/calendar/calendar-event-import-manager/jobs/calendar-event-list-fetch.job'; +import { CalendarChannelSyncStatusService } from 'src/modules/calendar/calendar-event-import-manager/services/calendar-channel-sync-status.service'; +import { CalendarEventImportErrorHandlerService } from 'src/modules/calendar/calendar-event-import-manager/services/calendar-event-import-error-handling.service'; +import { CalendarEventsImportService } from 'src/modules/calendar/calendar-event-import-manager/services/calendar-events-import.service'; +import { CalendarGetCalendarEventsService } from 'src/modules/calendar/calendar-event-import-manager/services/calendar-get-events.service'; +import { CalendarSaveEventsService } from 'src/modules/calendar/calendar-event-import-manager/services/calendar-save-events.service'; +import { CalendarEventParticipantManagerModule } from 'src/modules/calendar/calendar-event-participant-manager/calendar-event-participant-manager.module'; +import { CalendarCommonModule } from 'src/modules/calendar/common/calendar-common.module'; +import { CalendarChannelEventAssociationWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-channel-event-association.workspace-entity'; +import { CalendarChannelWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-channel.workspace-entity'; +import { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-event-participant.workspace-entity'; +import { CalendarEventWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-event.workspace-entity'; +import { RefreshAccessTokenManagerModule } from 'src/modules/connected-account/refresh-access-token-manager/refresh-access-token-manager.module'; +import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; +import { PersonWorkspaceEntity } from 'src/modules/person/standard-objects/person.workspace-entity'; +import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; + +@Module({ + imports: [ + TwentyORMModule.forFeature([ + CalendarEventWorkspaceEntity, + CalendarChannelWorkspaceEntity, + CalendarChannelEventAssociationWorkspaceEntity, + CalendarEventParticipantWorkspaceEntity, + ]), + ObjectMetadataRepositoryModule.forFeature([ + ConnectedAccountWorkspaceEntity, + BlocklistWorkspaceEntity, + PersonWorkspaceEntity, + WorkspaceMemberWorkspaceEntity, + ]), + CalendarEventParticipantManagerModule, + TypeOrmModule.forFeature([FeatureFlagEntity], 'core'), + TypeOrmModule.forFeature([DataSourceEntity], 'metadata'), + WorkspaceDataSourceModule, + CalendarEventCleanerModule, + GoogleCalendarDriverModule, + BillingModule, + RefreshAccessTokenManagerModule, + CalendarCommonModule, + CalendarEventParticipantManagerModule, + ], + providers: [ + CalendarChannelSyncStatusService, + CalendarEventsImportService, + CalendarEventImportErrorHandlerService, + CalendarGetCalendarEventsService, + CalendarSaveEventsService, + CalendarEventListFetchCronJob, + CalendarEventListFetchCronCommand, + CalendarEventListFetchJob, + ], + exports: [CalendarEventsImportService], +}) +export class CalendarEventImportManagerModule {} diff --git a/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/constants/calendar-throttle-duration.ts b/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/constants/calendar-throttle-duration.ts new file mode 100644 index 000000000000..64028026a9ab --- /dev/null +++ b/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/constants/calendar-throttle-duration.ts @@ -0,0 +1 @@ +export const CALENDAR_THROTTLE_DURATION = 1000 * 60 * 1; // 1 minute diff --git a/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/constants/calendar-throttle-max-attempts.ts b/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/constants/calendar-throttle-max-attempts.ts new file mode 100644 index 000000000000..f6a3866380a0 --- /dev/null +++ b/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/constants/calendar-throttle-max-attempts.ts @@ -0,0 +1 @@ +export const CALENDAR_THROTTLE_MAX_ATTEMPTS = 4; diff --git a/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/crons/commands/calendar-event-list-fetch.cron.command.ts b/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/crons/commands/calendar-event-list-fetch.cron.command.ts new file mode 100644 index 000000000000..87d139aa48d9 --- /dev/null +++ b/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/crons/commands/calendar-event-list-fetch.cron.command.ts @@ -0,0 +1,31 @@ +import { Command, CommandRunner } from 'nest-commander'; + +import { InjectMessageQueue } from 'src/engine/integrations/message-queue/decorators/message-queue.decorator'; +import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; +import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service'; +import { CalendarEventListFetchCronJob } from 'src/modules/calendar/calendar-event-import-manager/crons/jobs/calendar-event-list-fetch.cron.job'; + +const CALENDAR_EVENTS_IMPORT_CRON_PATTERN = '*/5 * * * *'; + +@Command({ + name: 'cron:calendar:calendar-event-list-fetch', + description: 'Starts a cron job to fetch the calendar event list', +}) +export class CalendarEventListFetchCronCommand extends CommandRunner { + constructor( + @InjectMessageQueue(MessageQueue.cronQueue) + private readonly messageQueueService: MessageQueueService, + ) { + super(); + } + + async run(): Promise<void> { + await this.messageQueueService.addCron<undefined>( + CalendarEventListFetchCronJob.name, + undefined, + { + repeat: { pattern: CALENDAR_EVENTS_IMPORT_CRON_PATTERN }, + }, + ); + } +} diff --git a/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/crons/jobs/calendar-event-list-fetch.cron.job.ts b/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/crons/jobs/calendar-event-list-fetch.cron.job.ts new file mode 100644 index 000000000000..30c6fad2e9de --- /dev/null +++ b/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/crons/jobs/calendar-event-list-fetch.cron.job.ts @@ -0,0 +1,78 @@ +import { InjectRepository } from '@nestjs/typeorm'; + +import { Any, In, Repository } from 'typeorm'; + +import { BillingService } from 'src/engine/core-modules/billing/billing.service'; +import { InjectMessageQueue } from 'src/engine/integrations/message-queue/decorators/message-queue.decorator'; +import { Process } from 'src/engine/integrations/message-queue/decorators/process.decorator'; +import { Processor } from 'src/engine/integrations/message-queue/decorators/processor.decorator'; +import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; +import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service'; +import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity'; +import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager'; +import { + CalendarEventListFetchJob, + CalendarEventsImportJobData, +} from 'src/modules/calendar/calendar-event-import-manager/jobs/calendar-event-list-fetch.job'; +import { + CalendarChannelSyncStage, + CalendarChannelWorkspaceEntity, +} from 'src/modules/calendar/common/standard-objects/calendar-channel.workspace-entity'; + +@Processor({ + queueName: MessageQueue.cronQueue, +}) +export class CalendarEventListFetchCronJob { + constructor( + @InjectRepository(DataSourceEntity, 'metadata') + private readonly dataSourceRepository: Repository<DataSourceEntity>, + @InjectMessageQueue(MessageQueue.calendarQueue) + private readonly messageQueueService: MessageQueueService, + private readonly billingService: BillingService, + private readonly twentyORMManager: TwentyORMManager, + ) {} + + @Process(CalendarEventListFetchCronJob.name) + async handle(): Promise<void> { + const workspaceIds = + await this.billingService.getActiveSubscriptionWorkspaceIds(); + + const dataSources = await this.dataSourceRepository.find({ + where: { + workspaceId: In(workspaceIds), + }, + }); + + const workspaceIdsWithDataSources = new Set( + dataSources.map((dataSource) => dataSource.workspaceId), + ); + + for (const workspaceId of workspaceIdsWithDataSources) { + const calendarChannelRepository = + await this.twentyORMManager.getRepositoryForWorkspace( + workspaceId, + CalendarChannelWorkspaceEntity, + ); + + const calendarChannels = await calendarChannelRepository.find({ + where: { + isSyncEnabled: true, + syncStage: Any([ + CalendarChannelSyncStage.FULL_CALENDAR_EVENT_LIST_FETCH_PENDING, + CalendarChannelSyncStage.PARTIAL_CALENDAR_EVENT_LIST_FETCH_PENDING, + ]), + }, + }); + + for (const calendarChannel of calendarChannels) { + await this.messageQueueService.add<CalendarEventsImportJobData>( + CalendarEventListFetchJob.name, + { + calendarChannelId: calendarChannel.id, + workspaceId, + }, + ); + } + } + } +} diff --git a/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/drivers/google-calendar/google-calendar-driver.module.ts b/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/drivers/google-calendar/google-calendar-driver.module.ts new file mode 100644 index 000000000000..46b209ef9af4 --- /dev/null +++ b/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/drivers/google-calendar/google-calendar-driver.module.ts @@ -0,0 +1,13 @@ +import { Module } from '@nestjs/common'; + +import { EnvironmentModule } from 'src/engine/integrations/environment/environment.module'; +import { GoogleCalendarClientProvider } from 'src/modules/calendar/calendar-event-import-manager/drivers/google-calendar/providers/google-calendar.provider'; +import { GoogleCalendarGetEventsService } from 'src/modules/calendar/calendar-event-import-manager/drivers/google-calendar/services/google-calendar-get-events.service'; +import { OAuth2ClientManagerModule } from 'src/modules/connected-account/oauth2-client-manager/oauth2-client-manager.module'; + +@Module({ + imports: [EnvironmentModule, OAuth2ClientManagerModule], + providers: [GoogleCalendarClientProvider, GoogleCalendarGetEventsService], + exports: [GoogleCalendarGetEventsService], +}) +export class GoogleCalendarDriverModule {} diff --git a/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/drivers/google-calendar/providers/google-calendar.provider.ts b/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/drivers/google-calendar/providers/google-calendar.provider.ts new file mode 100644 index 000000000000..e91758494902 --- /dev/null +++ b/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/drivers/google-calendar/providers/google-calendar.provider.ts @@ -0,0 +1,30 @@ +import { Injectable } from '@nestjs/common'; + +import { calendar_v3 as calendarV3, google } from 'googleapis'; + +import { OAuth2ClientManagerService } from 'src/modules/connected-account/oauth2-client-manager/services/oauth2-client-manager.service'; +import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; + +@Injectable() +export class GoogleCalendarClientProvider { + constructor( + private readonly oAuth2ClientManagerService: OAuth2ClientManagerService, + ) {} + + public async getGoogleCalendarClient( + connectedAccount: Pick< + ConnectedAccountWorkspaceEntity, + 'provider' | 'refreshToken' + >, + ): Promise<calendarV3.Calendar> { + const oAuth2Client = + await this.oAuth2ClientManagerService.getOAuth2Client(connectedAccount); + + const googleCalendarClient = google.calendar({ + version: 'v3', + auth: oAuth2Client, + }); + + return googleCalendarClient; + } +} diff --git a/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/drivers/google-calendar/services/google-calendar-get-events.service.ts b/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/drivers/google-calendar/services/google-calendar-get-events.service.ts new file mode 100644 index 000000000000..20f3ec63704d --- /dev/null +++ b/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/drivers/google-calendar/services/google-calendar-get-events.service.ts @@ -0,0 +1,110 @@ +import { Injectable } from '@nestjs/common'; + +import { GaxiosError } from 'gaxios'; +import { calendar_v3 as calendarV3 } from 'googleapis'; + +import { GoogleCalendarClientProvider } from 'src/modules/calendar/calendar-event-import-manager/drivers/google-calendar/providers/google-calendar.provider'; +import { GoogleCalendarError } from 'src/modules/calendar/calendar-event-import-manager/drivers/google-calendar/types/google-calendar-error.type'; +import { formatGoogleCalendarEvents } from 'src/modules/calendar/calendar-event-import-manager/drivers/google-calendar/utils/format-google-calendar-event.util'; +import { parseGaxiosError } from 'src/modules/calendar/calendar-event-import-manager/drivers/google-calendar/utils/parse-gaxios-error.util'; +import { parseGoogleCalendarError } from 'src/modules/calendar/calendar-event-import-manager/drivers/google-calendar/utils/parse-google-calendar-error.util'; +import { GetCalendarEventsResponse } from 'src/modules/calendar/calendar-event-import-manager/services/calendar-get-events.service'; +import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; + +@Injectable() +export class GoogleCalendarGetEventsService { + constructor( + private readonly googleCalendarClientProvider: GoogleCalendarClientProvider, + ) {} + + public async getCalendarEvents( + connectedAccount: Pick< + ConnectedAccountWorkspaceEntity, + 'provider' | 'refreshToken' | 'id' + >, + syncCursor?: string, + ): Promise<GetCalendarEventsResponse> { + const googleCalendarClient = + await this.googleCalendarClientProvider.getGoogleCalendarClient( + connectedAccount, + ); + + let nextSyncToken: string | null | undefined; + let nextPageToken: string | undefined; + const events: calendarV3.Schema$Event[] = []; + + let hasMoreEvents = true; + + while (hasMoreEvents) { + const googleCalendarEvents = await googleCalendarClient.events + .list({ + calendarId: 'primary', + maxResults: 500, + syncToken: syncCursor, + pageToken: nextPageToken, + showDeleted: true, + }) + .catch(async (error: GaxiosError) => { + this.handleError(error); + + return { + data: { + items: [], + nextSyncToken: undefined, + nextPageToken: undefined, + }, + }; + }); + + nextSyncToken = googleCalendarEvents.data.nextSyncToken; + nextPageToken = googleCalendarEvents.data.nextPageToken || undefined; + + const { items } = googleCalendarEvents.data; + + if (!items || items.length === 0) { + break; + } + + events.push(...items); + + if (!nextPageToken) { + hasMoreEvents = false; + } + } + + return { + calendarEvents: formatGoogleCalendarEvents(events), + nextSyncCursor: nextSyncToken || '', + }; + } + + private handleError(error: GaxiosError) { + if ( + error.code && + [ + 'ECONNRESET', + 'ENOTFOUND', + 'ECONNABORTED', + 'ETIMEDOUT', + 'ERR_NETWORK', + ].includes(error.code) + ) { + throw parseGaxiosError(error); + } + if (error.response?.status !== 410) { + const googleCalendarError: GoogleCalendarError = { + code: error.response?.status, + reason: + error.response?.data?.error?.errors?.[0].reason || + error.response?.data?.error || + '', + message: + error.response?.data?.error?.errors?.[0].message || + error.response?.data?.error_description || + '', + }; + + throw parseGoogleCalendarError(googleCalendarError); + } + } +} diff --git a/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/drivers/google-calendar/types/google-calendar-error.type.ts b/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/drivers/google-calendar/types/google-calendar-error.type.ts new file mode 100644 index 000000000000..b007431ad384 --- /dev/null +++ b/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/drivers/google-calendar/types/google-calendar-error.type.ts @@ -0,0 +1,5 @@ +export type GoogleCalendarError = { + code?: number; + reason: string; + message: string; +}; diff --git a/packages/twenty-server/src/modules/calendar/utils/format-google-calendar-event.util.ts b/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/drivers/google-calendar/utils/format-google-calendar-event.util.ts similarity index 82% rename from packages/twenty-server/src/modules/calendar/utils/format-google-calendar-event.util.ts rename to packages/twenty-server/src/modules/calendar/calendar-event-import-manager/drivers/google-calendar/utils/format-google-calendar-event.util.ts index bb8a4523a37d..06f97e3c585c 100644 --- a/packages/twenty-server/src/modules/calendar/utils/format-google-calendar-event.util.ts +++ b/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/drivers/google-calendar/utils/format-google-calendar-event.util.ts @@ -1,16 +1,17 @@ import { calendar_v3 as calendarV3 } from 'googleapis'; -import { v4 } from 'uuid'; -import { CalendarEventParticipantResponseStatus } from 'src/modules/calendar/standard-objects/calendar-event-participant.workspace-entity'; -import { CalendarEventWithParticipants } from 'src/modules/calendar/types/calendar-event'; +import { CalendarEventParticipantResponseStatus } from 'src/modules/calendar/common/standard-objects/calendar-event-participant.workspace-entity'; +import { CalendarEventWithParticipants } from 'src/modules/calendar/common/types/calendar-event'; -export const formatGoogleCalendarEvent = ( +export const formatGoogleCalendarEvents = ( + events: calendarV3.Schema$Event[], +): CalendarEventWithParticipants[] => { + return events.map(formatGoogleCalendarEvent); +}; + +const formatGoogleCalendarEvent = ( event: calendarV3.Schema$Event, - iCalUIDCalendarEventIdMap: Map<string, string>, ): CalendarEventWithParticipants => { - const id = - (event.iCalUID && iCalUIDCalendarEventIdMap.get(event.iCalUID)) ?? v4(); - const formatResponseStatus = (status: string | null | undefined) => { switch (status) { case 'accepted': @@ -25,7 +26,6 @@ export const formatGoogleCalendarEvent = ( }; return { - id, title: event.summary ?? '', isCanceled: event.status === 'cancelled', isFullDay: event.start?.dateTime == null, @@ -44,12 +44,11 @@ export const formatGoogleCalendarEvent = ( recurringEventExternalId: event.recurringEventId ?? '', participants: event.attendees?.map((attendee) => ({ - calendarEventId: id, - iCalUID: event.iCalUID ?? '', handle: attendee.email ?? '', displayName: attendee.displayName ?? '', isOrganizer: attendee.organizer === true, responseStatus: formatResponseStatus(attendee.responseStatus), })) ?? [], + status: event.status ?? '', }; }; diff --git a/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/drivers/google-calendar/utils/parse-gaxios-error.util.ts b/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/drivers/google-calendar/utils/parse-gaxios-error.util.ts new file mode 100644 index 000000000000..4245ff82fe22 --- /dev/null +++ b/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/drivers/google-calendar/utils/parse-gaxios-error.util.ts @@ -0,0 +1,28 @@ +import { GaxiosError } from 'gaxios'; + +import { + CalendarEventError, + CalendarEventErrorCode, +} from 'src/modules/calendar/calendar-event-import-manager/types/calendar-event-error.type'; + +export const parseGaxiosError = (error: GaxiosError): CalendarEventError => { + const { code } = error; + + switch (code) { + case 'ECONNRESET': + case 'ENOTFOUND': + case 'ECONNABORTED': + case 'ETIMEDOUT': + case 'ERR_NETWORK': + return { + code: CalendarEventErrorCode.TEMPORARY_ERROR, + message: error.message, + }; + + default: + return { + code: CalendarEventErrorCode.UNKNOWN, + message: error.message, + }; + } +}; diff --git a/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/drivers/google-calendar/utils/parse-google-calendar-error.util.ts b/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/drivers/google-calendar/utils/parse-google-calendar-error.util.ts new file mode 100644 index 000000000000..9e5667c629ca --- /dev/null +++ b/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/drivers/google-calendar/utils/parse-google-calendar-error.util.ts @@ -0,0 +1,86 @@ +import { GoogleCalendarError } from 'src/modules/calendar/calendar-event-import-manager/drivers/google-calendar/types/google-calendar-error.type'; +import { + CalendarEventError, + CalendarEventErrorCode, +} from 'src/modules/calendar/calendar-event-import-manager/types/calendar-event-error.type'; + +export const parseGoogleCalendarError = ( + error: GoogleCalendarError, +): CalendarEventError => { + const { code, reason, message } = error; + + switch (code) { + case 400: + if (reason === 'invalid_grant') { + return { + code: CalendarEventErrorCode.INSUFFICIENT_PERMISSIONS, + message, + }; + } + if (reason === 'failedPrecondition') { + return { + code: CalendarEventErrorCode.TEMPORARY_ERROR, + message, + }; + } + + return { + code: CalendarEventErrorCode.UNKNOWN, + message, + }; + + case 404: + return { + code: CalendarEventErrorCode.NOT_FOUND, + message, + }; + + case 429: + return { + code: CalendarEventErrorCode.TEMPORARY_ERROR, + message, + }; + + case 403: + if ( + reason === 'rateLimitExceeded' || + reason === 'userRateLimitExceeded' + ) { + return { + code: CalendarEventErrorCode.TEMPORARY_ERROR, + message, + }; + } else { + return { + code: CalendarEventErrorCode.INSUFFICIENT_PERMISSIONS, + message, + }; + } + + case 401: + return { + code: CalendarEventErrorCode.INSUFFICIENT_PERMISSIONS, + message, + }; + case 500: + if (reason === 'backendError') { + return { + code: CalendarEventErrorCode.TEMPORARY_ERROR, + message, + }; + } else { + return { + code: CalendarEventErrorCode.UNKNOWN, + message, + }; + } + + default: + break; + } + + return { + code: CalendarEventErrorCode.UNKNOWN, + message, + }; +}; diff --git a/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/jobs/calendar-event-list-fetch.job.ts b/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/jobs/calendar-event-list-fetch.job.ts new file mode 100644 index 000000000000..34ba97feaef0 --- /dev/null +++ b/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/jobs/calendar-event-list-fetch.job.ts @@ -0,0 +1,92 @@ +import { Scope } from '@nestjs/common'; + +import { Processor } from 'src/engine/integrations/message-queue/decorators/processor.decorator'; +import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; +import { Process } from 'src/engine/integrations/message-queue/decorators/process.decorator'; +import { CalendarEventsImportService } from 'src/modules/calendar/calendar-event-import-manager/services/calendar-events-import.service'; +import { isThrottled } from 'src/modules/connected-account/utils/is-throttled'; +import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; +import { ConnectedAccountRepository } from 'src/modules/connected-account/repositories/connected-account.repository'; +import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; +import { + CalendarChannelSyncStage, + CalendarChannelWorkspaceEntity, +} from 'src/modules/calendar/common/standard-objects/calendar-channel.workspace-entity'; +import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository'; +import { InjectWorkspaceRepository } from 'src/engine/twenty-orm/decorators/inject-workspace-repository.decorator'; + +export type CalendarEventsImportJobData = { + calendarChannelId: string; + workspaceId: string; +}; + +@Processor({ + queueName: MessageQueue.calendarQueue, + scope: Scope.REQUEST, +}) +export class CalendarEventListFetchJob { + constructor( + private readonly calendarEventsImportService: CalendarEventsImportService, + @InjectObjectMetadataRepository(ConnectedAccountWorkspaceEntity) + private readonly connectedAccountRepository: ConnectedAccountRepository, + @InjectWorkspaceRepository(CalendarChannelWorkspaceEntity) + private readonly calendarChannelRepository: WorkspaceRepository<CalendarChannelWorkspaceEntity>, + ) {} + + @Process(CalendarEventListFetchJob.name) + async handle(data: CalendarEventsImportJobData): Promise<void> { + const { workspaceId, calendarChannelId } = data; + + const calendarChannel = await this.calendarChannelRepository.findOne({ + where: { + id: calendarChannelId, + isSyncEnabled: true, + }, + }); + + if (!calendarChannel) { + return; + } + + if ( + isThrottled( + calendarChannel.syncStageStartedAt, + calendarChannel.throttleFailureCount, + ) + ) { + return; + } + + const connectedAccount = + await this.connectedAccountRepository.getConnectedAccountOrThrow( + workspaceId, + calendarChannel.connectedAccountId, + ); + + switch (calendarChannel.syncStage) { + case CalendarChannelSyncStage.FULL_CALENDAR_EVENT_LIST_FETCH_PENDING: + await this.calendarChannelRepository.update(calendarChannelId, { + syncCursor: '', + syncStageStartedAt: null, + }); + + await this.calendarEventsImportService.processCalendarEventsImport( + calendarChannel, + connectedAccount, + workspaceId, + ); + break; + + case CalendarChannelSyncStage.PARTIAL_CALENDAR_EVENT_LIST_FETCH_PENDING: + await this.calendarEventsImportService.processCalendarEventsImport( + calendarChannel, + connectedAccount, + workspaceId, + ); + break; + + default: + break; + } + } +} diff --git a/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/services/calendar-channel-sync-status.service.ts b/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/services/calendar-channel-sync-status.service.ts new file mode 100644 index 000000000000..0d6dd28fcc0c --- /dev/null +++ b/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/services/calendar-channel-sync-status.service.ts @@ -0,0 +1,118 @@ +import { Injectable } from '@nestjs/common'; + +import { CacheStorageService } from 'src/engine/integrations/cache-storage/cache-storage.service'; +import { InjectCacheStorage } from 'src/engine/integrations/cache-storage/decorators/cache-storage.decorator'; +import { CacheStorageNamespace } from 'src/engine/integrations/cache-storage/types/cache-storage-namespace.enum'; +import { InjectWorkspaceRepository } from 'src/engine/twenty-orm/decorators/inject-workspace-repository.decorator'; +import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository'; +import { + CalendarChannelSyncStage, + CalendarChannelSyncStatus, + CalendarChannelWorkspaceEntity, +} from 'src/modules/calendar/common/standard-objects/calendar-channel.workspace-entity'; + +@Injectable() +export class CalendarChannelSyncStatusService { + constructor( + @InjectWorkspaceRepository(CalendarChannelWorkspaceEntity) + private readonly calendarChannelRepository: WorkspaceRepository<CalendarChannelWorkspaceEntity>, + @InjectCacheStorage(CacheStorageNamespace.Calendar) + private readonly cacheStorage: CacheStorageService, + ) {} + + public async scheduleFullCalendarEventListFetch(calendarChannelId: string) { + await this.calendarChannelRepository.update(calendarChannelId, { + syncStage: + CalendarChannelSyncStage.FULL_CALENDAR_EVENT_LIST_FETCH_PENDING, + }); + } + + public async schedulePartialCalendarEventListFetch( + calendarChannelId: string, + ) { + await this.calendarChannelRepository.update(calendarChannelId, { + syncStage: + CalendarChannelSyncStage.PARTIAL_CALENDAR_EVENT_LIST_FETCH_PENDING, + }); + } + + public async markAsCalendarEventListFetchOngoing(calendarChannelId: string) { + await this.calendarChannelRepository.update(calendarChannelId, { + syncStage: CalendarChannelSyncStage.CALENDAR_EVENT_LIST_FETCH_ONGOING, + syncStatus: CalendarChannelSyncStatus.ONGOING, + syncStageStartedAt: new Date().toISOString(), + }); + } + + public async resetAndScheduleFullCalendarEventListFetch( + calendarChannelId: string, + workspaceId: string, + ) { + await this.cacheStorage.del( + `calendar-events-to-import:${workspaceId}:google-calendar:${calendarChannelId}`, + ); + + await this.calendarChannelRepository.update(calendarChannelId, { + syncCursor: '', + syncStageStartedAt: null, + throttleFailureCount: 0, + }); + + await this.scheduleFullCalendarEventListFetch(calendarChannelId); + } + + public async scheduleCalendarEventsImport(calendarChannelId: string) { + await this.calendarChannelRepository.update(calendarChannelId, { + syncStage: CalendarChannelSyncStage.CALENDAR_EVENTS_IMPORT_PENDING, + }); + } + + public async markAsCalendarEventsImportOngoing(calendarChannelId: string) { + await this.calendarChannelRepository.update(calendarChannelId, { + syncStage: CalendarChannelSyncStage.CALENDAR_EVENTS_IMPORT_ONGOING, + syncStatus: CalendarChannelSyncStatus.ONGOING, + }); + } + + public async markAsCompletedAndSchedulePartialMessageListFetch( + calendarChannelId: string, + ) { + await this.calendarChannelRepository.update(calendarChannelId, { + syncStage: + CalendarChannelSyncStage.PARTIAL_CALENDAR_EVENT_LIST_FETCH_PENDING, + syncStatus: CalendarChannelSyncStatus.ACTIVE, + throttleFailureCount: 0, + syncStageStartedAt: null, + }); + + await this.schedulePartialCalendarEventListFetch(calendarChannelId); + } + + public async markAsFailedUnknownAndFlushCalendarEventsToImport( + calendarChannelId: string, + workspaceId: string, + ) { + await this.cacheStorage.del( + `calendar-events-to-import:${workspaceId}:google-calendar:${calendarChannelId}`, + ); + + await this.calendarChannelRepository.update(calendarChannelId, { + syncStatus: CalendarChannelSyncStatus.FAILED_UNKNOWN, + syncStage: CalendarChannelSyncStage.FAILED, + }); + } + + public async markAsFailedInsufficientPermissionsAndFlushCalendarEventsToImport( + calendarChannelId: string, + workspaceId: string, + ) { + await this.cacheStorage.del( + `calendar-events-to-import:${workspaceId}:google-calendar:${calendarChannelId}`, + ); + + await this.calendarChannelRepository.update(calendarChannelId, { + syncStatus: CalendarChannelSyncStatus.FAILED_INSUFFICIENT_PERMISSIONS, + syncStage: CalendarChannelSyncStage.FAILED, + }); + } +} diff --git a/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/services/calendar-event-import-error-handling.service.ts b/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/services/calendar-event-import-error-handling.service.ts new file mode 100644 index 000000000000..93c8b9238f80 --- /dev/null +++ b/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/services/calendar-event-import-error-handling.service.ts @@ -0,0 +1,144 @@ +import { Injectable } from '@nestjs/common'; + +import { InjectWorkspaceRepository } from 'src/engine/twenty-orm/decorators/inject-workspace-repository.decorator'; +import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository'; +import { CALENDAR_THROTTLE_MAX_ATTEMPTS } from 'src/modules/calendar/calendar-event-import-manager/constants/calendar-throttle-max-attempts'; +import { CalendarChannelSyncStatusService } from 'src/modules/calendar/calendar-event-import-manager/services/calendar-channel-sync-status.service'; +import { CalendarEventError } from 'src/modules/calendar/calendar-event-import-manager/types/calendar-event-error.type'; +import { CalendarChannelWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-channel.workspace-entity'; + +export enum CalendarEventImportSyncStep { + FULL_CALENDAR_EVENT_LIST_FETCH = 'FULL_CALENDAR_EVENT_LIST_FETCH', + PARTIAL_CALENDAR_EVENT_LIST_FETCH = 'PARTIAL_CALENDAR_EVENT_LIST_FETCH', + CALENDAR_EVENTS_IMPORT = 'CALENDAR_EVENTS_IMPORT', +} + +@Injectable() +export class CalendarEventImportErrorHandlerService { + constructor( + private readonly calendarChannelSyncStatusService: CalendarChannelSyncStatusService, + @InjectWorkspaceRepository(CalendarChannelWorkspaceEntity) + private readonly calendarChannelRepository: WorkspaceRepository<CalendarChannelWorkspaceEntity>, + ) {} + + public async handleError( + error: CalendarEventError, + syncStep: CalendarEventImportSyncStep, + calendarChannel: Pick< + CalendarChannelWorkspaceEntity, + 'id' | 'throttleFailureCount' + >, + workspaceId: string, + ): Promise<void> { + switch (error.code) { + case 'NOT_FOUND': + await this.handleNotFoundError(syncStep, calendarChannel, workspaceId); + break; + case 'TEMPORARY_ERROR': + await this.handleTemporaryError(syncStep, calendarChannel, workspaceId); + break; + case 'INSUFFICIENT_PERMISSIONS': + await this.handleInsufficientPermissionsError( + calendarChannel, + workspaceId, + ); + break; + case 'UNKNOWN': + await this.handleUnknownError(error, calendarChannel, workspaceId); + break; + } + } + + private async handleTemporaryError( + syncStep: CalendarEventImportSyncStep, + calendarChannel: Pick< + CalendarChannelWorkspaceEntity, + 'id' | 'throttleFailureCount' + >, + workspaceId: string, + ): Promise<void> { + if ( + calendarChannel.throttleFailureCount >= CALENDAR_THROTTLE_MAX_ATTEMPTS + ) { + await this.calendarChannelSyncStatusService.markAsFailedUnknownAndFlushCalendarEventsToImport( + calendarChannel.id, + workspaceId, + ); + + return; + } + + await this.calendarChannelRepository.increment( + { + id: calendarChannel.id, + }, + 'throttleFailureCount', + 1, + ); + + switch (syncStep) { + case CalendarEventImportSyncStep.FULL_CALENDAR_EVENT_LIST_FETCH: + await this.calendarChannelSyncStatusService.scheduleFullCalendarEventListFetch( + calendarChannel.id, + ); + break; + + case CalendarEventImportSyncStep.PARTIAL_CALENDAR_EVENT_LIST_FETCH: + await this.calendarChannelSyncStatusService.schedulePartialCalendarEventListFetch( + calendarChannel.id, + ); + break; + + case CalendarEventImportSyncStep.CALENDAR_EVENTS_IMPORT: + await this.calendarChannelSyncStatusService.scheduleCalendarEventsImport( + calendarChannel.id, + ); + break; + + default: + break; + } + } + + private async handleInsufficientPermissionsError( + calendarChannel: Pick<CalendarChannelWorkspaceEntity, 'id'>, + workspaceId: string, + ): Promise<void> { + await this.calendarChannelSyncStatusService.markAsFailedInsufficientPermissionsAndFlushCalendarEventsToImport( + calendarChannel.id, + workspaceId, + ); + } + + private async handleUnknownError( + error: CalendarEventError, + calendarChannel: Pick<CalendarChannelWorkspaceEntity, 'id'>, + workspaceId: string, + ): Promise<void> { + await this.calendarChannelSyncStatusService.markAsFailedUnknownAndFlushCalendarEventsToImport( + calendarChannel.id, + workspaceId, + ); + + throw new Error( + `Unknown error occurred while importing calendar events for calendar channel ${calendarChannel.id} in workspace ${workspaceId}: ${error.message}`, + ); + } + + private async handleNotFoundError( + syncStep: CalendarEventImportSyncStep, + calendarChannel: Pick<CalendarChannelWorkspaceEntity, 'id'>, + workspaceId: string, + ): Promise<void> { + if ( + syncStep === CalendarEventImportSyncStep.FULL_CALENDAR_EVENT_LIST_FETCH + ) { + return; + } + + await this.calendarChannelSyncStatusService.resetAndScheduleFullCalendarEventListFetch( + calendarChannel.id, + workspaceId, + ); + } +} diff --git a/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/services/calendar-events-import.service.ts b/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/services/calendar-events-import.service.ts new file mode 100644 index 000000000000..da1dfdddb860 --- /dev/null +++ b/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/services/calendar-events-import.service.ts @@ -0,0 +1,144 @@ +import { Injectable } from '@nestjs/common'; + +import { Any } from 'typeorm'; + +import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; +import { InjectWorkspaceRepository } from 'src/engine/twenty-orm/decorators/inject-workspace-repository.decorator'; +import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository'; +import { BlocklistRepository } from 'src/modules/blocklist/repositories/blocklist.repository'; +import { BlocklistWorkspaceEntity } from 'src/modules/blocklist/standard-objects/blocklist.workspace-entity'; +import { CalendarEventCleanerService } from 'src/modules/calendar/calendar-event-cleaner/services/calendar-event-cleaner.service'; +import { CalendarChannelSyncStatusService } from 'src/modules/calendar/calendar-event-import-manager/services/calendar-channel-sync-status.service'; +import { + CalendarEventImportErrorHandlerService, + CalendarEventImportSyncStep, +} from 'src/modules/calendar/calendar-event-import-manager/services/calendar-event-import-error-handling.service'; +import { + CalendarGetCalendarEventsService, + GetCalendarEventsResponse, +} from 'src/modules/calendar/calendar-event-import-manager/services/calendar-get-events.service'; +import { CalendarSaveEventsService } from 'src/modules/calendar/calendar-event-import-manager/services/calendar-save-events.service'; +import { filterEventsAndReturnCancelledEvents } from 'src/modules/calendar/calendar-event-import-manager/utils/filter-events.util'; +import { CalendarChannelEventAssociationWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-channel-event-association.workspace-entity'; +import { + CalendarChannelSyncStage, + CalendarChannelWorkspaceEntity, +} from 'src/modules/calendar/common/standard-objects/calendar-channel.workspace-entity'; +import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; + +@Injectable() +export class CalendarEventsImportService { + constructor( + @InjectWorkspaceRepository(CalendarChannelWorkspaceEntity) + private readonly calendarChannelRepository: WorkspaceRepository<CalendarChannelWorkspaceEntity>, + @InjectWorkspaceRepository(CalendarChannelEventAssociationWorkspaceEntity) + private readonly calendarChannelEventAssociationRepository: WorkspaceRepository<CalendarChannelEventAssociationWorkspaceEntity>, + @InjectObjectMetadataRepository(BlocklistWorkspaceEntity) + private readonly blocklistRepository: BlocklistRepository, + private readonly calendarEventCleanerService: CalendarEventCleanerService, + private readonly calendarChannelSyncStatusService: CalendarChannelSyncStatusService, + private readonly getCalendarEventsService: CalendarGetCalendarEventsService, + private readonly calendarSaveEventsService: CalendarSaveEventsService, + private readonly calendarEventImportErrorHandlerService: CalendarEventImportErrorHandlerService, + ) {} + + public async processCalendarEventsImport( + calendarChannel: CalendarChannelWorkspaceEntity, + connectedAccount: ConnectedAccountWorkspaceEntity, + workspaceId: string, + ): Promise<void> { + const syncStep = + calendarChannel.syncStage === + CalendarChannelSyncStage.FULL_CALENDAR_EVENT_LIST_FETCH_PENDING + ? CalendarEventImportSyncStep.FULL_CALENDAR_EVENT_LIST_FETCH + : CalendarEventImportSyncStep.PARTIAL_CALENDAR_EVENT_LIST_FETCH; + + await this.calendarChannelSyncStatusService.markAsCalendarEventListFetchOngoing( + calendarChannel.id, + ); + let calendarEvents: GetCalendarEventsResponse['calendarEvents'] = []; + let nextSyncCursor: GetCalendarEventsResponse['nextSyncCursor'] = ''; + + try { + const getCalendarEventsResponse = + await this.getCalendarEventsService.getCalendarEvents( + connectedAccount, + calendarChannel.syncCursor, + ); + + calendarEvents = getCalendarEventsResponse.calendarEvents; + nextSyncCursor = getCalendarEventsResponse.nextSyncCursor; + } catch (error) { + await this.calendarEventImportErrorHandlerService.handleError( + error, + syncStep, + calendarChannel, + workspaceId, + ); + + return; + } + + if (!calendarEvents || calendarEvents?.length === 0) { + await this.calendarChannelRepository.update( + { + id: calendarChannel.id, + }, + { + syncCursor: nextSyncCursor, + }, + ); + + await this.calendarChannelSyncStatusService.schedulePartialCalendarEventListFetch( + calendarChannel.id, + ); + } + + const blocklist = await this.blocklistRepository.getByWorkspaceMemberId( + connectedAccount.accountOwnerId, + workspaceId, + ); + + const { filteredEvents, cancelledEvents } = + filterEventsAndReturnCancelledEvents( + calendarChannel, + calendarEvents, + blocklist.map((blocklist) => blocklist.handle), + ); + + const cancelledEventExternalIds = cancelledEvents.map( + (event) => event.externalId, + ); + + await this.calendarSaveEventsService.saveCalendarEventsAndEnqueueContactCreationJob( + filteredEvents, + calendarChannel, + connectedAccount, + workspaceId, + ); + + await this.calendarChannelEventAssociationRepository.delete({ + eventExternalId: Any(cancelledEventExternalIds), + calendarChannel: { + id: calendarChannel.id, + }, + }); + + await this.calendarEventCleanerService.cleanWorkspaceCalendarEvents( + workspaceId, + ); + + await this.calendarChannelRepository.update( + { + id: calendarChannel.id, + }, + { + syncCursor: nextSyncCursor, + }, + ); + + await this.calendarChannelSyncStatusService.markAsCompletedAndSchedulePartialMessageListFetch( + calendarChannel.id, + ); + } +} diff --git a/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/services/calendar-get-events.service.ts b/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/services/calendar-get-events.service.ts new file mode 100644 index 000000000000..d9fa121101c5 --- /dev/null +++ b/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/services/calendar-get-events.service.ts @@ -0,0 +1,37 @@ +import { Injectable } from '@nestjs/common'; + +import { GoogleCalendarGetEventsService as GoogleCalendarGetCalendarEventsService } from 'src/modules/calendar/calendar-event-import-manager/drivers/google-calendar/services/google-calendar-get-events.service'; +import { CalendarEventWithParticipants } from 'src/modules/calendar/common/types/calendar-event'; +import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; + +export type GetCalendarEventsResponse = { + calendarEvents: CalendarEventWithParticipants[]; + nextSyncCursor: string; +}; + +@Injectable() +export class CalendarGetCalendarEventsService { + constructor( + private readonly googleCalendarGetCalendarEventsService: GoogleCalendarGetCalendarEventsService, + ) {} + + public async getCalendarEvents( + connectedAccount: Pick< + ConnectedAccountWorkspaceEntity, + 'provider' | 'refreshToken' | 'id' + >, + syncCursor?: string, + ): Promise<GetCalendarEventsResponse> { + switch (connectedAccount.provider) { + case 'google': + return this.googleCalendarGetCalendarEventsService.getCalendarEvents( + connectedAccount, + syncCursor, + ); + default: + throw new Error( + `Provider ${connectedAccount.provider} is not supported.`, + ); + } + } +} diff --git a/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/services/calendar-save-events.service.ts b/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/services/calendar-save-events.service.ts new file mode 100644 index 000000000000..52ea333888fb --- /dev/null +++ b/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/services/calendar-save-events.service.ts @@ -0,0 +1,159 @@ +import { Injectable } from '@nestjs/common'; +import { EventEmitter2 } from '@nestjs/event-emitter'; + +import { Any } from 'typeorm'; + +import { InjectMessageQueue } from 'src/engine/integrations/message-queue/decorators/message-queue.decorator'; +import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; +import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service'; +import { WorkspaceDataSource } from 'src/engine/twenty-orm/datasource/workspace.datasource'; +import { InjectWorkspaceDatasource } from 'src/engine/twenty-orm/decorators/inject-workspace-datasource.decorator'; +import { InjectWorkspaceRepository } from 'src/engine/twenty-orm/decorators/inject-workspace-repository.decorator'; +import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository'; +import { injectIdsInCalendarEvents } from 'src/modules/calendar/calendar-event-import-manager/utils/inject-ids-in-calendar-events.util'; +import { CalendarEventParticipantService } from 'src/modules/calendar/calendar-event-participant-manager/services/calendar-event-participant.service'; +import { CalendarChannelEventAssociationWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-channel-event-association.workspace-entity'; +import { CalendarChannelWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-channel.workspace-entity'; +import { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-event-participant.workspace-entity'; +import { CalendarEventWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-event.workspace-entity'; +import { CalendarEventWithParticipants } from 'src/modules/calendar/common/types/calendar-event'; +import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; +import { + CreateCompanyAndContactJob, + CreateCompanyAndContactJobData, +} from 'src/modules/contact-creation-manager/jobs/create-company-and-contact.job'; + +@Injectable() +export class CalendarSaveEventsService { + constructor( + @InjectWorkspaceRepository(CalendarEventWorkspaceEntity) + private readonly calendarEventRepository: WorkspaceRepository<CalendarEventWorkspaceEntity>, + @InjectWorkspaceRepository(CalendarChannelEventAssociationWorkspaceEntity) + private readonly calendarChannelEventAssociationRepository: WorkspaceRepository<CalendarChannelEventAssociationWorkspaceEntity>, + @InjectWorkspaceDatasource() + private readonly workspaceDataSource: WorkspaceDataSource, + private readonly calendarEventParticipantService: CalendarEventParticipantService, + @InjectMessageQueue(MessageQueue.contactCreationQueue) + private readonly messageQueueService: MessageQueueService, + private readonly eventEmitter: EventEmitter2, + ) {} + + public async saveCalendarEventsAndEnqueueContactCreationJob( + filteredEvents: CalendarEventWithParticipants[], + calendarChannel: CalendarChannelWorkspaceEntity, + connectedAccount: ConnectedAccountWorkspaceEntity, + workspaceId: string, + ): Promise<void> { + const existingCalendarEvents = await this.calendarEventRepository.find({ + where: { + iCalUID: Any(filteredEvents.map((event) => event.iCalUID as string)), + }, + }); + + const iCalUIDCalendarEventIdMap = new Map( + existingCalendarEvents.map((calendarEvent) => [ + calendarEvent.iCalUID, + calendarEvent.id, + ]), + ); + + const calendarEventsWithIds = injectIdsInCalendarEvents( + filteredEvents, + iCalUIDCalendarEventIdMap, + ); + + // TODO: When we will be able to add unicity contraint on iCalUID, we will do a INSERT ON CONFLICT DO UPDATE + + const existingEventsICalUIDs = existingCalendarEvents.map( + (calendarEvent) => calendarEvent.iCalUID, + ); + + const eventsToSave = calendarEventsWithIds.filter( + (calendarEvent) => + !existingEventsICalUIDs.includes(calendarEvent.iCalUID), + ); + + const eventsToUpdate = calendarEventsWithIds.filter((calendarEvent) => + existingEventsICalUIDs.includes(calendarEvent.iCalUID), + ); + + const existingCalendarChannelEventAssociations = + await this.calendarChannelEventAssociationRepository.find({ + where: { + eventExternalId: Any( + calendarEventsWithIds.map((calendarEvent) => calendarEvent.id), + ), + calendarChannel: { + id: calendarChannel.id, + }, + }, + }); + + const calendarChannelEventAssociationsToSave = calendarEventsWithIds + .filter( + (calendarEvent) => + !existingCalendarChannelEventAssociations.some( + (association) => association.eventExternalId === calendarEvent.id, + ), + ) + .map((calendarEvent) => ({ + calendarEventId: calendarEvent.id, + eventExternalId: calendarEvent.externalId, + calendarChannelId: calendarChannel.id, + })); + + const participantsToSave = eventsToSave.flatMap( + (event) => event.participants, + ); + + const participantsToUpdate = eventsToUpdate.flatMap( + (event) => event.participants, + ); + + const savedCalendarEventParticipantsToEmit: CalendarEventParticipantWorkspaceEntity[] = + []; + + await this.workspaceDataSource?.transaction(async (transactionManager) => { + await this.calendarEventRepository.save( + eventsToSave, + {}, + transactionManager, + ); + + await this.calendarEventRepository.save( + eventsToUpdate, + {}, + transactionManager, + ); + + await this.calendarChannelEventAssociationRepository.save( + calendarChannelEventAssociationsToSave, + {}, + transactionManager, + ); + + await this.calendarEventParticipantService.upsertAndDeleteCalendarEventParticipants( + participantsToSave, + participantsToUpdate, + transactionManager, + ); + }); + + this.eventEmitter.emit(`calendarEventParticipant.matched`, { + workspaceId, + workspaceMemberId: connectedAccount.accountOwnerId, + calendarEventParticipants: savedCalendarEventParticipantsToEmit, + }); + + if (calendarChannel.isContactAutoCreationEnabled) { + await this.messageQueueService.add<CreateCompanyAndContactJobData>( + CreateCompanyAndContactJob.name, + { + workspaceId, + connectedAccount, + contactsToCreate: participantsToSave, + }, + ); + } + } +} diff --git a/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/types/calendar-event-error.type.ts b/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/types/calendar-event-error.type.ts new file mode 100644 index 000000000000..7bf1b56f8d18 --- /dev/null +++ b/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/types/calendar-event-error.type.ts @@ -0,0 +1,11 @@ +export enum CalendarEventErrorCode { + NOT_FOUND = 'NOT_FOUND', + TEMPORARY_ERROR = 'TEMPORARY_ERROR', + INSUFFICIENT_PERMISSIONS = 'INSUFFICIENT_PERMISSIONS', + UNKNOWN = 'UNKNOWN', +} + +export interface CalendarEventError { + message: string; + code: CalendarEventErrorCode; +} diff --git a/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/utils/filter-events.util.ts b/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/utils/filter-events.util.ts new file mode 100644 index 000000000000..b3e7e0d1d221 --- /dev/null +++ b/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/utils/filter-events.util.ts @@ -0,0 +1,40 @@ +import { filterOutBlocklistedEvents } from 'src/modules/calendar/calendar-event-import-manager/utils/filter-out-blocklisted-events.util'; +import { CalendarChannelWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-channel.workspace-entity'; +import { CalendarEventWithParticipants } from 'src/modules/calendar/common/types/calendar-event'; + +export const filterEventsAndReturnCancelledEvents = ( + calendarChannel: Pick<CalendarChannelWorkspaceEntity, 'handle'>, + events: CalendarEventWithParticipants[], + blocklist: string[], +): { + filteredEvents: CalendarEventWithParticipants[]; + cancelledEvents: CalendarEventWithParticipants[]; +} => { + const filteredEvents = filterOutBlocklistedEvents( + calendarChannel.handle, + events, + blocklist, + ); + + return filteredEvents.reduce( + ( + acc: { + filteredEvents: CalendarEventWithParticipants[]; + cancelledEvents: CalendarEventWithParticipants[]; + }, + event, + ) => { + if (event.status === 'cancelled') { + acc.cancelledEvents.push(event); + } else { + acc.filteredEvents.push(event); + } + + return acc; + }, + { + filteredEvents: [], + cancelledEvents: [], + }, + ); +}; diff --git a/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/utils/filter-out-blocklisted-events.util.ts b/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/utils/filter-out-blocklisted-events.util.ts new file mode 100644 index 000000000000..b28f5801c51c --- /dev/null +++ b/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/utils/filter-out-blocklisted-events.util.ts @@ -0,0 +1,19 @@ +import { isEmailBlocklisted } from 'src/modules/calendar-messaging-participant-manager/utils/is-email-blocklisted.util'; +import { CalendarEventWithParticipants } from 'src/modules/calendar/common/types/calendar-event'; + +export const filterOutBlocklistedEvents = ( + calendarChannelHandle: string, + events: CalendarEventWithParticipants[], + blocklist: string[], +) => { + return events.filter((event) => { + if (!event.participants) { + return true; + } + + return event.participants.every( + (attendee) => + !isEmailBlocklisted(calendarChannelHandle, attendee.handle, blocklist), + ); + }); +}; diff --git a/packages/twenty-server/src/modules/calendar/utils/get-flattened-values-and-values-string-for-batch-raw-query.util.ts b/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/utils/get-flattened-values-and-values-string-for-batch-raw-query.util.ts similarity index 100% rename from packages/twenty-server/src/modules/calendar/utils/get-flattened-values-and-values-string-for-batch-raw-query.util.ts rename to packages/twenty-server/src/modules/calendar/calendar-event-import-manager/utils/get-flattened-values-and-values-string-for-batch-raw-query.util.ts diff --git a/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/utils/inject-ids-in-calendar-events.util.ts b/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/utils/inject-ids-in-calendar-events.util.ts new file mode 100644 index 000000000000..b41e329dc0f4 --- /dev/null +++ b/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/utils/inject-ids-in-calendar-events.util.ts @@ -0,0 +1,31 @@ +import { v4 } from 'uuid'; + +import { + CalendarEventWithParticipants, + CalendarEventWithParticipantsAndCalendarEventId, +} from 'src/modules/calendar/common/types/calendar-event'; + +export const injectIdsInCalendarEvents = ( + calendarEvents: CalendarEventWithParticipants[], + iCalUIDCalendarEventIdMap: Map<string, string>, +): CalendarEventWithParticipantsAndCalendarEventId[] => { + return calendarEvents.map((calendarEvent) => { + const id = iCalUIDCalendarEventIdMap.get(calendarEvent.iCalUID) ?? v4(); + + return injectIdInCalendarEvent(calendarEvent, id); + }); +}; + +const injectIdInCalendarEvent = ( + calendarEvent: CalendarEventWithParticipants, + id: string, +): CalendarEventWithParticipantsAndCalendarEventId => { + return { + ...calendarEvent, + id, + participants: calendarEvent.participants.map((participant) => ({ + ...participant, + calendarEventId: id, + })), + }; +}; diff --git a/packages/twenty-server/src/modules/calendar/calendar-event-participant-manager/calendar-event-participant-manager.module.ts b/packages/twenty-server/src/modules/calendar/calendar-event-participant-manager/calendar-event-participant-manager.module.ts new file mode 100644 index 000000000000..609c83429af4 --- /dev/null +++ b/packages/twenty-server/src/modules/calendar/calendar-event-participant-manager/calendar-event-participant-manager.module.ts @@ -0,0 +1,46 @@ +import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; + +import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; +import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; +import { ObjectMetadataRepositoryModule } from 'src/engine/object-metadata-repository/object-metadata-repository.module'; +import { TwentyORMModule } from 'src/engine/twenty-orm/twenty-orm.module'; +import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; +import { AddPersonIdAndWorkspaceMemberIdService } from 'src/modules/calendar-messaging-participant-manager/services/add-person-id-and-workspace-member-id/add-person-id-and-workspace-member-id.service'; +import { CalendarCreateCompanyAndContactAfterSyncJob } from 'src/modules/calendar/calendar-event-participant-manager/jobs/calendar-create-company-and-contact-after-sync.job'; +import { CalendarEventParticipantMatchParticipantJob } from 'src/modules/calendar/calendar-event-participant-manager/jobs/calendar-event-participant-match-participant.job'; +import { CalendarEventParticipantUnmatchParticipantJob } from 'src/modules/calendar/calendar-event-participant-manager/jobs/calendar-event-participant-unmatch-participant.job'; +import { CalendarEventParticipantPersonListener } from 'src/modules/calendar/calendar-event-participant-manager/listeners/calendar-event-participant-person.listener'; +import { CalendarEventParticipantWorkspaceMemberListener } from 'src/modules/calendar/calendar-event-participant-manager/listeners/calendar-event-participant-workspace-member.listener'; +import { CalendarEventParticipantListener } from 'src/modules/calendar/calendar-event-participant-manager/listeners/calendar-event-participant.listener'; +import { CalendarEventParticipantService } from 'src/modules/calendar/calendar-event-participant-manager/services/calendar-event-participant.service'; +import { CalendarCommonModule } from 'src/modules/calendar/common/calendar-common.module'; +import { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-event-participant.workspace-entity'; +import { ContactCreationManagerModule } from 'src/modules/contact-creation-manager/contact-creation-manager.module'; +import { PersonWorkspaceEntity } from 'src/modules/person/standard-objects/person.workspace-entity'; + +@Module({ + imports: [ + WorkspaceDataSourceModule, + TwentyORMModule.forFeature([CalendarEventParticipantWorkspaceEntity]), + ObjectMetadataRepositoryModule.forFeature([PersonWorkspaceEntity]), + TypeOrmModule.forFeature( + [ObjectMetadataEntity, FieldMetadataEntity], + 'metadata', + ), + ContactCreationManagerModule, + CalendarCommonModule, + ], + providers: [ + CalendarEventParticipantService, + CalendarCreateCompanyAndContactAfterSyncJob, + CalendarEventParticipantMatchParticipantJob, + CalendarEventParticipantUnmatchParticipantJob, + CalendarEventParticipantListener, + CalendarEventParticipantPersonListener, + CalendarEventParticipantWorkspaceMemberListener, + AddPersonIdAndWorkspaceMemberIdService, + ], + exports: [CalendarEventParticipantService], +}) +export class CalendarEventParticipantManagerModule {} diff --git a/packages/twenty-server/src/modules/calendar/calendar-event-participant-manager/jobs/calendar-create-company-and-contact-after-sync.job.ts b/packages/twenty-server/src/modules/calendar/calendar-event-participant-manager/jobs/calendar-create-company-and-contact-after-sync.job.ts new file mode 100644 index 000000000000..372dde104575 --- /dev/null +++ b/packages/twenty-server/src/modules/calendar/calendar-event-participant-manager/jobs/calendar-create-company-and-contact-after-sync.job.ts @@ -0,0 +1,99 @@ +import { Logger, Scope } from '@nestjs/common'; + +import { IsNull } from 'typeorm'; + +import { Process } from 'src/engine/integrations/message-queue/decorators/process.decorator'; +import { Processor } from 'src/engine/integrations/message-queue/decorators/processor.decorator'; +import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; +import { InjectWorkspaceRepository } from 'src/engine/twenty-orm/decorators/inject-workspace-repository.decorator'; +import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository'; +import { CalendarChannelWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-channel.workspace-entity'; +import { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-event-participant.workspace-entity'; +import { CreateCompanyAndContactService } from 'src/modules/contact-creation-manager/services/create-company-and-contact.service'; + +export type CalendarCreateCompanyAndContactAfterSyncJobData = { + workspaceId: string; + calendarChannelId: string; +}; + +@Processor({ + queueName: MessageQueue.calendarQueue, + scope: Scope.REQUEST, +}) +export class CalendarCreateCompanyAndContactAfterSyncJob { + private readonly logger = new Logger( + CalendarCreateCompanyAndContactAfterSyncJob.name, + ); + constructor( + private readonly createCompanyAndContactService: CreateCompanyAndContactService, + @InjectWorkspaceRepository(CalendarChannelWorkspaceEntity) + private readonly calendarChannelRepository: WorkspaceRepository<CalendarChannelWorkspaceEntity>, + @InjectWorkspaceRepository(CalendarEventParticipantWorkspaceEntity) + private readonly calendarEventParticipantRepository: WorkspaceRepository<CalendarEventParticipantWorkspaceEntity>, + ) {} + + @Process(CalendarCreateCompanyAndContactAfterSyncJob.name) + async handle( + data: CalendarCreateCompanyAndContactAfterSyncJobData, + ): Promise<void> { + this.logger.log( + `create contacts and companies after sync for workspace ${data.workspaceId} and calendarChannel ${data.calendarChannelId}`, + ); + const { workspaceId, calendarChannelId } = data; + + const calendarChannel = await this.calendarChannelRepository.findOne({ + where: { + id: calendarChannelId, + }, + relations: ['connectedAccount.accountOwner'], + }); + + if (!calendarChannel) { + throw new Error( + `Calendar channel with id ${calendarChannelId} not found in workspace ${workspaceId}`, + ); + } + + const { handle, isContactAutoCreationEnabled, connectedAccount } = + calendarChannel; + + if (!isContactAutoCreationEnabled || !handle) { + return; + } + + if (!connectedAccount) { + throw new Error( + `Connected account not found in workspace ${workspaceId}`, + ); + } + + const calendarEventParticipantsWithoutPersonIdAndWorkspaceMemberId = + await this.calendarEventParticipantRepository.find({ + where: { + calendarEvent: { + calendarChannelEventAssociations: { + calendarChannelId, + }, + calendarEventParticipants: { + person: IsNull(), + workspaceMember: IsNull(), + }, + }, + }, + relations: [ + 'calendarEvent.calendarChannelEventAssociations', + 'calendarEvent.calendarEventParticipants', + ], + }); + + await this.createCompanyAndContactService.createCompaniesAndContactsAndUpdateParticipants( + connectedAccount, + calendarEventParticipantsWithoutPersonIdAndWorkspaceMemberId, + workspaceId, + ); + + this.logger.log( + `create contacts and companies after sync for workspace ${data.workspaceId} and calendarChannel ${data.calendarChannelId} done`, + ); + } +} diff --git a/packages/twenty-server/src/modules/calendar/calendar-event-participant-manager/jobs/calendar-event-participant-match-participant.job.ts b/packages/twenty-server/src/modules/calendar/calendar-event-participant-manager/jobs/calendar-event-participant-match-participant.job.ts new file mode 100644 index 000000000000..e8dc28c0c117 --- /dev/null +++ b/packages/twenty-server/src/modules/calendar/calendar-event-participant-manager/jobs/calendar-event-participant-match-participant.job.ts @@ -0,0 +1,37 @@ +import { Scope } from '@nestjs/common'; + +import { Process } from 'src/engine/integrations/message-queue/decorators/process.decorator'; +import { Processor } from 'src/engine/integrations/message-queue/decorators/processor.decorator'; +import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; +import { CalendarEventParticipantService } from 'src/modules/calendar/calendar-event-participant-manager/services/calendar-event-participant.service'; + +export type CalendarEventParticipantMatchParticipantJobData = { + workspaceId: string; + email: string; + personId?: string; + workspaceMemberId?: string; +}; + +@Processor({ + queueName: MessageQueue.calendarQueue, + scope: Scope.REQUEST, +}) +export class CalendarEventParticipantMatchParticipantJob { + constructor( + private readonly calendarEventParticipantService: CalendarEventParticipantService, + ) {} + + @Process(CalendarEventParticipantMatchParticipantJob.name) + async handle( + data: CalendarEventParticipantMatchParticipantJobData, + ): Promise<void> { + const { workspaceId, email, personId, workspaceMemberId } = data; + + await this.calendarEventParticipantService.matchCalendarEventParticipants( + workspaceId, + email, + personId, + workspaceMemberId, + ); + } +} diff --git a/packages/twenty-server/src/modules/calendar/calendar-event-participant-manager/jobs/calendar-event-participant-unmatch-participant.job.ts b/packages/twenty-server/src/modules/calendar/calendar-event-participant-manager/jobs/calendar-event-participant-unmatch-participant.job.ts new file mode 100644 index 000000000000..9aa9d3e38ec7 --- /dev/null +++ b/packages/twenty-server/src/modules/calendar/calendar-event-participant-manager/jobs/calendar-event-participant-unmatch-participant.job.ts @@ -0,0 +1,37 @@ +import { Scope } from '@nestjs/common'; + +import { Processor } from 'src/engine/integrations/message-queue/decorators/processor.decorator'; +import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; +import { Process } from 'src/engine/integrations/message-queue/decorators/process.decorator'; +import { CalendarEventParticipantService } from 'src/modules/calendar/calendar-event-participant-manager/services/calendar-event-participant.service'; + +export type CalendarEventParticipantUnmatchParticipantJobData = { + workspaceId: string; + email: string; + personId?: string; + workspaceMemberId?: string; +}; + +@Processor({ + queueName: MessageQueue.calendarQueue, + scope: Scope.REQUEST, +}) +export class CalendarEventParticipantUnmatchParticipantJob { + constructor( + private readonly calendarEventParticipantService: CalendarEventParticipantService, + ) {} + + @Process(CalendarEventParticipantUnmatchParticipantJob.name) + async handle( + data: CalendarEventParticipantUnmatchParticipantJobData, + ): Promise<void> { + const { workspaceId, email, personId, workspaceMemberId } = data; + + await this.calendarEventParticipantService.unmatchCalendarEventParticipants( + workspaceId, + email, + personId, + workspaceMemberId, + ); + } +} diff --git a/packages/twenty-server/src/modules/calendar/calendar-event-participant-manager/listeners/calendar-event-participant-person.listener.ts b/packages/twenty-server/src/modules/calendar/calendar-event-participant-manager/listeners/calendar-event-participant-person.listener.ts new file mode 100644 index 000000000000..7b369af572d6 --- /dev/null +++ b/packages/twenty-server/src/modules/calendar/calendar-event-participant-manager/listeners/calendar-event-participant-person.listener.ts @@ -0,0 +1,74 @@ +import { Injectable } from '@nestjs/common'; +import { OnEvent } from '@nestjs/event-emitter'; + +import { ObjectRecordCreateEvent } from 'src/engine/integrations/event-emitter/types/object-record-create.event'; +import { ObjectRecordUpdateEvent } from 'src/engine/integrations/event-emitter/types/object-record-update.event'; +import { objectRecordChangedProperties as objectRecordUpdateEventChangedProperties } from 'src/engine/integrations/event-emitter/utils/object-record-changed-properties.util'; +import { InjectMessageQueue } from 'src/engine/integrations/message-queue/decorators/message-queue.decorator'; +import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; +import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service'; +import { + CalendarEventParticipantMatchParticipantJobData, + CalendarEventParticipantMatchParticipantJob, +} from 'src/modules/calendar/calendar-event-participant-manager/jobs/calendar-event-participant-match-participant.job'; +import { + CalendarEventParticipantUnmatchParticipantJobData, + CalendarEventParticipantUnmatchParticipantJob, +} from 'src/modules/calendar/calendar-event-participant-manager/jobs/calendar-event-participant-unmatch-participant.job'; +import { PersonWorkspaceEntity } from 'src/modules/person/standard-objects/person.workspace-entity'; + +@Injectable() +export class CalendarEventParticipantPersonListener { + constructor( + @InjectMessageQueue(MessageQueue.calendarQueue) + private readonly messageQueueService: MessageQueueService, + ) {} + + @OnEvent('person.created') + async handleCreatedEvent( + payload: ObjectRecordCreateEvent<PersonWorkspaceEntity>, + ) { + if (payload.properties.after.email === null) { + return; + } + + await this.messageQueueService.add<CalendarEventParticipantMatchParticipantJobData>( + CalendarEventParticipantMatchParticipantJob.name, + { + workspaceId: payload.workspaceId, + email: payload.properties.after.email, + personId: payload.recordId, + }, + ); + } + + @OnEvent('person.updated') + async handleUpdatedEvent( + payload: ObjectRecordUpdateEvent<PersonWorkspaceEntity>, + ) { + if ( + objectRecordUpdateEventChangedProperties( + payload.properties.before, + payload.properties.after, + ).includes('email') + ) { + await this.messageQueueService.add<CalendarEventParticipantUnmatchParticipantJobData>( + CalendarEventParticipantUnmatchParticipantJob.name, + { + workspaceId: payload.workspaceId, + email: payload.properties.before.email, + personId: payload.recordId, + }, + ); + + await this.messageQueueService.add<CalendarEventParticipantMatchParticipantJobData>( + CalendarEventParticipantMatchParticipantJob.name, + { + workspaceId: payload.workspaceId, + email: payload.properties.after.email, + personId: payload.recordId, + }, + ); + } + } +} diff --git a/packages/twenty-server/src/modules/calendar/calendar-event-participant-manager/listeners/calendar-event-participant-workspace-member.listener.ts b/packages/twenty-server/src/modules/calendar/calendar-event-participant-manager/listeners/calendar-event-participant-workspace-member.listener.ts new file mode 100644 index 000000000000..1f84fce0dc2f --- /dev/null +++ b/packages/twenty-server/src/modules/calendar/calendar-event-participant-manager/listeners/calendar-event-participant-workspace-member.listener.ts @@ -0,0 +1,74 @@ +import { Injectable } from '@nestjs/common'; +import { OnEvent } from '@nestjs/event-emitter'; + +import { ObjectRecordCreateEvent } from 'src/engine/integrations/event-emitter/types/object-record-create.event'; +import { ObjectRecordUpdateEvent } from 'src/engine/integrations/event-emitter/types/object-record-update.event'; +import { objectRecordChangedProperties as objectRecordUpdateEventChangedProperties } from 'src/engine/integrations/event-emitter/utils/object-record-changed-properties.util'; +import { InjectMessageQueue } from 'src/engine/integrations/message-queue/decorators/message-queue.decorator'; +import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; +import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service'; +import { + CalendarEventParticipantMatchParticipantJob, + CalendarEventParticipantMatchParticipantJobData, +} from 'src/modules/calendar/calendar-event-participant-manager/jobs/calendar-event-participant-match-participant.job'; +import { + CalendarEventParticipantUnmatchParticipantJobData, + CalendarEventParticipantUnmatchParticipantJob, +} from 'src/modules/calendar/calendar-event-participant-manager/jobs/calendar-event-participant-unmatch-participant.job'; +import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; + +@Injectable() +export class CalendarEventParticipantWorkspaceMemberListener { + constructor( + @InjectMessageQueue(MessageQueue.calendarQueue) + private readonly messageQueueService: MessageQueueService, + ) {} + + @OnEvent('workspaceMember.created') + async handleCreatedEvent( + payload: ObjectRecordCreateEvent<WorkspaceMemberWorkspaceEntity>, + ) { + if (payload.properties.after.userEmail === null) { + return; + } + + await this.messageQueueService.add<CalendarEventParticipantMatchParticipantJobData>( + CalendarEventParticipantMatchParticipantJob.name, + { + workspaceId: payload.workspaceId, + email: payload.properties.after.userEmail, + workspaceMemberId: payload.properties.after.id, + }, + ); + } + + @OnEvent('workspaceMember.updated') + async handleUpdatedEvent( + payload: ObjectRecordUpdateEvent<WorkspaceMemberWorkspaceEntity>, + ) { + if ( + objectRecordUpdateEventChangedProperties<WorkspaceMemberWorkspaceEntity>( + payload.properties.before, + payload.properties.after, + ).includes('userEmail') + ) { + await this.messageQueueService.add<CalendarEventParticipantUnmatchParticipantJobData>( + CalendarEventParticipantUnmatchParticipantJob.name, + { + workspaceId: payload.workspaceId, + email: payload.properties.before.userEmail, + personId: payload.recordId, + }, + ); + + await this.messageQueueService.add<CalendarEventParticipantMatchParticipantJobData>( + CalendarEventParticipantMatchParticipantJob.name, + { + workspaceId: payload.workspaceId, + email: payload.properties.after.userEmail, + workspaceMemberId: payload.recordId, + }, + ); + } + } +} diff --git a/packages/twenty-server/src/modules/calendar/listeners/calendar-event-participant.listener.ts b/packages/twenty-server/src/modules/calendar/calendar-event-participant-manager/listeners/calendar-event-participant.listener.ts similarity index 88% rename from packages/twenty-server/src/modules/calendar/listeners/calendar-event-participant.listener.ts rename to packages/twenty-server/src/modules/calendar/calendar-event-participant-manager/listeners/calendar-event-participant.listener.ts index 79025878c586..b28a73033990 100644 --- a/packages/twenty-server/src/modules/calendar/listeners/calendar-event-participant.listener.ts +++ b/packages/twenty-server/src/modules/calendar/calendar-event-participant-manager/listeners/calendar-event-participant.listener.ts @@ -7,10 +7,9 @@ import { Repository } from 'typeorm'; import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; -import { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-event-participant.workspace-entity'; import { TimelineActivityRepository } from 'src/modules/timeline/repositiories/timeline-activity.repository'; import { TimelineActivityWorkspaceEntity } from 'src/modules/timeline/standard-objects/timeline-activity.workspace-entity'; -import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record'; +import { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-event-participant.workspace-entity'; @Injectable() export class CalendarEventParticipantListener { @@ -25,8 +24,8 @@ export class CalendarEventParticipantListener { @OnEvent('calendarEventParticipant.matched') public async handleCalendarEventParticipantMatchedEvent(payload: { workspaceId: string; - userId: string; - calendarEventParticipants: ObjectRecord<CalendarEventParticipantWorkspaceEntity>[]; + workspaceMemberId: string; + calendarEventParticipants: CalendarEventParticipantWorkspaceEntity[]; }): Promise<void> { const calendarEventParticipants = payload.calendarEventParticipants ?? []; @@ -59,7 +58,7 @@ export class CalendarEventParticipantListener { properties: null, objectName: 'calendarEvent', recordId: participant.personId, - workspaceMemberId: payload.userId, + workspaceMemberId: payload.workspaceMemberId, workspaceId: payload.workspaceId, linkedObjectMetadataId: calendarEventObjectMetadata.id, linkedRecordId: participant.calendarEventId, diff --git a/packages/twenty-server/src/modules/calendar/calendar-event-participant-manager/services/calendar-event-participant.service.ts b/packages/twenty-server/src/modules/calendar/calendar-event-participant-manager/services/calendar-event-participant.service.ts new file mode 100644 index 000000000000..346e727d99e2 --- /dev/null +++ b/packages/twenty-server/src/modules/calendar/calendar-event-participant-manager/services/calendar-event-participant.service.ts @@ -0,0 +1,192 @@ +import { Injectable } from '@nestjs/common'; +import { EventEmitter2 } from '@nestjs/event-emitter'; + +import { isDefined } from 'class-validator'; +import differenceWith from 'lodash.differencewith'; +import { Any } from 'typeorm'; + +import { InjectWorkspaceRepository } from 'src/engine/twenty-orm/decorators/inject-workspace-repository.decorator'; +import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository'; +import { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-event-participant.workspace-entity'; +import { CalendarEventParticipantWithCalendarEventId } from 'src/modules/calendar/common/types/calendar-event'; + +@Injectable() +export class CalendarEventParticipantService { + constructor( + @InjectWorkspaceRepository(CalendarEventParticipantWorkspaceEntity) + private readonly calendarEventParticipantRepository: WorkspaceRepository<CalendarEventParticipantWorkspaceEntity>, + private readonly eventEmitter: EventEmitter2, + ) {} + + public async upsertAndDeleteCalendarEventParticipants( + participantsToSave: CalendarEventParticipantWithCalendarEventId[], + participantsToUpdate: CalendarEventParticipantWithCalendarEventId[], + transactionManager?: any, + ): Promise<void> { + const existingCalendarEventParticipants = + await this.calendarEventParticipantRepository.find({ + where: { + calendarEventId: Any( + participantsToUpdate + .map((participant) => participant.calendarEventId) + .filter(isDefined), + ), + }, + }); + + const { calendarEventParticipantsToUpdate, newCalendarEventParticipants } = + participantsToUpdate.reduce( + (acc, calendarEventParticipant) => { + const existingCalendarEventParticipant = + existingCalendarEventParticipants.find( + (existingCalendarEventParticipant) => + existingCalendarEventParticipant.handle === + calendarEventParticipant.handle && + existingCalendarEventParticipant.calendarEventId === + calendarEventParticipant.calendarEventId, + ); + + if (existingCalendarEventParticipant) { + acc.calendarEventParticipantsToUpdate.push( + calendarEventParticipant, + ); + } else { + acc.newCalendarEventParticipants.push(calendarEventParticipant); + } + + return acc; + }, + { + calendarEventParticipantsToUpdate: + [] as CalendarEventParticipantWithCalendarEventId[], + newCalendarEventParticipants: + [] as CalendarEventParticipantWithCalendarEventId[], + }, + ); + + const calendarEventParticipantsToDelete = differenceWith( + existingCalendarEventParticipants, + participantsToUpdate, + (existingCalendarEventParticipant, participantToUpdate) => + existingCalendarEventParticipant.handle === + participantToUpdate.handle && + existingCalendarEventParticipant.calendarEventId === + participantToUpdate.calendarEventId, + ); + + await this.calendarEventParticipantRepository.delete( + { + id: Any( + calendarEventParticipantsToDelete.map( + (calendarEventParticipant) => calendarEventParticipant.id, + ), + ), + }, + transactionManager, + ); + + for (const calendarEventParticipantToUpdate of calendarEventParticipantsToUpdate) { + await this.calendarEventParticipantRepository.update( + { + calendarEventId: calendarEventParticipantToUpdate.calendarEventId, + handle: calendarEventParticipantToUpdate.handle, + }, + { + ...calendarEventParticipantToUpdate, + }, + transactionManager, + ); + } + + participantsToSave.push(...newCalendarEventParticipants); + + await this.calendarEventParticipantRepository.save( + participantsToSave, + {}, + transactionManager, + ); + } + + public async matchCalendarEventParticipants( + workspaceId: string, + email: string, + personId?: string, + workspaceMemberId?: string, + ) { + const calendarEventParticipantsToUpdate = + await this.calendarEventParticipantRepository.find({ + where: { + handle: email, + }, + }); + + const calendarEventParticipantIdsToUpdate = + calendarEventParticipantsToUpdate.map((participant) => participant.id); + + if (personId) { + await this.calendarEventParticipantRepository.update( + { + id: Any(calendarEventParticipantIdsToUpdate), + }, + { + person: { + id: personId, + }, + }, + ); + + const updatedCalendarEventParticipants = + await this.calendarEventParticipantRepository.find({ + where: { + id: Any(calendarEventParticipantIdsToUpdate), + }, + }); + + this.eventEmitter.emit(`calendarEventParticipant.matched`, { + workspaceId, + workspaceMemberId: null, + calendarEventParticipants: updatedCalendarEventParticipants, + }); + } + if (workspaceMemberId) { + await this.calendarEventParticipantRepository.update( + { + id: Any(calendarEventParticipantIdsToUpdate), + }, + { + workspaceMember: { + id: workspaceMemberId, + }, + }, + ); + } + } + + public async unmatchCalendarEventParticipants( + workspaceId: string, + handle: string, + personId?: string, + workspaceMemberId?: string, + ) { + if (personId) { + await this.calendarEventParticipantRepository.update( + { + handle, + }, + { + person: null, + }, + ); + } + if (workspaceMemberId) { + await this.calendarEventParticipantRepository.update( + { + handle, + }, + { + workspaceMember: null, + }, + ); + } + } +} diff --git a/packages/twenty-server/src/modules/calendar/calendar.module.ts b/packages/twenty-server/src/modules/calendar/calendar.module.ts index d6a63b5a206e..de5759c1849c 100644 --- a/packages/twenty-server/src/modules/calendar/calendar.module.ts +++ b/packages/twenty-server/src/modules/calendar/calendar.module.ts @@ -1,27 +1,20 @@ import { Module } from '@nestjs/common'; -import { TypeOrmModule } from '@nestjs/typeorm'; -import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; -import { ObjectMetadataRepositoryModule } from 'src/engine/object-metadata-repository/object-metadata-repository.module'; -import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; -import { CalendarBlocklistListener } from 'src/modules/calendar/listeners/calendar-blocklist.listener'; -import { CalendarChannelListener } from 'src/modules/calendar/listeners/calendar-channel.listener'; -import { CalendarEventParticipantListener } from 'src/modules/calendar/listeners/calendar-event-participant.listener'; -import { TimelineActivityWorkspaceEntity } from 'src/modules/timeline/standard-objects/timeline-activity.workspace-entity'; +import { CalendarBlocklistManagerModule } from 'src/modules/calendar/blocklist-manager/calendar-blocklist-manager.module'; +import { CalendarEventCleanerModule } from 'src/modules/calendar/calendar-event-cleaner/calendar-event-cleaner.module'; +import { CalendarEventImportManagerModule } from 'src/modules/calendar/calendar-event-import-manager/calendar-event-import-manager.module'; +import { CalendarEventParticipantManagerModule } from 'src/modules/calendar/calendar-event-participant-manager/calendar-event-participant-manager.module'; +import { CalendarCommonModule } from 'src/modules/calendar/common/calendar-common.module'; @Module({ imports: [ - WorkspaceDataSourceModule, - ObjectMetadataRepositoryModule.forFeature([ - TimelineActivityWorkspaceEntity, - ]), - TypeOrmModule.forFeature([ObjectMetadataEntity], 'metadata'), - ], - providers: [ - CalendarChannelListener, - CalendarBlocklistListener, - CalendarEventParticipantListener, + CalendarBlocklistManagerModule, + CalendarEventCleanerModule, + CalendarEventImportManagerModule, + CalendarEventParticipantManagerModule, + CalendarCommonModule, ], + providers: [], exports: [], }) export class CalendarModule {} diff --git a/packages/twenty-server/src/modules/calendar/commands/calendar-commands.module.ts b/packages/twenty-server/src/modules/calendar/commands/calendar-commands.module.ts deleted file mode 100644 index 20b187004c8b..000000000000 --- a/packages/twenty-server/src/modules/calendar/commands/calendar-commands.module.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Module } from '@nestjs/common'; - -import { ObjectMetadataRepositoryModule } from 'src/engine/object-metadata-repository/object-metadata-repository.module'; -import { GoogleCalendarSyncCommand } from 'src/modules/calendar/commands/google-calendar-sync.command'; -import { WorkspaceGoogleCalendarSyncModule } from 'src/modules/calendar/services/workspace-google-calendar-sync/workspace-google-calendar-sync.module'; -import { CalendarChannelWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-channel.workspace-entity'; -import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; - -@Module({ - imports: [ - ObjectMetadataRepositoryModule.forFeature([ - ConnectedAccountWorkspaceEntity, - CalendarChannelWorkspaceEntity, - ]), - WorkspaceGoogleCalendarSyncModule, - ], - providers: [GoogleCalendarSyncCommand], -}) -export class CalendarCommandsModule {} diff --git a/packages/twenty-server/src/modules/calendar/commands/google-calendar-sync.command.ts b/packages/twenty-server/src/modules/calendar/commands/google-calendar-sync.command.ts deleted file mode 100644 index f605ad74256c..000000000000 --- a/packages/twenty-server/src/modules/calendar/commands/google-calendar-sync.command.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { Command, CommandRunner, Option } from 'nest-commander'; - -import { WorkspaceGoogleCalendarSyncService } from 'src/modules/calendar/services/workspace-google-calendar-sync/workspace-google-calendar-sync.service'; - -interface GoogleCalendarSyncOptions { - workspaceId: string; -} - -@Command({ - name: 'workspace:google-calendar-sync', - description: - 'Start google calendar sync for all workspaceMembers in a workspace.', -}) -export class GoogleCalendarSyncCommand extends CommandRunner { - constructor( - private readonly workspaceGoogleCalendarSyncService: WorkspaceGoogleCalendarSyncService, - ) { - super(); - } - - @Option({ - flags: '-w, --workspace-id [workspace_id]', - description: 'workspace id', - required: true, - }) - parseWorkspaceId(value: string): string { - return value; - } - - async run( - _passedParam: string[], - options: GoogleCalendarSyncOptions, - ): Promise<void> { - await this.workspaceGoogleCalendarSyncService.startWorkspaceGoogleCalendarSync( - options.workspaceId, - ); - - return; - } -} diff --git a/packages/twenty-server/src/modules/calendar/common/calendar-common.module.ts b/packages/twenty-server/src/modules/calendar/common/calendar-common.module.ts new file mode 100644 index 000000000000..3d3ccecd2d0e --- /dev/null +++ b/packages/twenty-server/src/modules/calendar/common/calendar-common.module.ts @@ -0,0 +1,11 @@ +import { Module } from '@nestjs/common'; + +import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; +import { AddPersonIdAndWorkspaceMemberIdService } from 'src/modules/calendar-messaging-participant-manager/services/add-person-id-and-workspace-member-id/add-person-id-and-workspace-member-id.service'; + +@Module({ + imports: [WorkspaceDataSourceModule], + providers: [AddPersonIdAndWorkspaceMemberIdService], + exports: [], +}) +export class CalendarCommonModule {} diff --git a/packages/twenty-server/src/modules/calendar/common/query-hooks/calendar-event/calendar-event-find-many.pre-query.hook.ts b/packages/twenty-server/src/modules/calendar/common/query-hooks/calendar-event/calendar-event-find-many.pre-query.hook.ts new file mode 100644 index 000000000000..8660401f1248 --- /dev/null +++ b/packages/twenty-server/src/modules/calendar/common/query-hooks/calendar-event/calendar-event-find-many.pre-query.hook.ts @@ -0,0 +1,52 @@ +import { BadRequestException, NotFoundException, Scope } from '@nestjs/common'; + +import { FindManyResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; +import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface'; + +import { InjectWorkspaceRepository } from 'src/engine/twenty-orm/decorators/inject-workspace-repository.decorator'; +import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository'; +import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator'; +import { CanAccessCalendarEventService } from 'src/modules/calendar/common/query-hooks/calendar-event/services/can-access-calendar-event.service'; +import { CalendarChannelEventAssociationWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-channel-event-association.workspace-entity'; + +@WorkspaceQueryHook({ + key: `calendarEvent.findMany`, + scope: Scope.REQUEST, +}) +export class CalendarEventFindManyPreQueryHook + implements WorkspaceQueryHookInstance +{ + constructor( + @InjectWorkspaceRepository(CalendarChannelEventAssociationWorkspaceEntity) + private readonly calendarChannelEventAssociationRepository: WorkspaceRepository<CalendarChannelEventAssociationWorkspaceEntity>, + private readonly canAccessCalendarEventService: CanAccessCalendarEventService, + ) {} + + async execute( + userId: string, + workspaceId: string, + payload: FindManyResolverArgs, + ): Promise<void> { + if (!payload?.filter?.id?.eq) { + throw new BadRequestException('id filter is required'); + } + + const calendarChannelCalendarEventAssociations = + await this.calendarChannelEventAssociationRepository.find({ + where: { + calendarEventId: payload?.filter?.id?.eq, + }, + relations: ['calendarChannel.connectedAccount'], + }); + + if (calendarChannelCalendarEventAssociations.length === 0) { + throw new NotFoundException(); + } + + await this.canAccessCalendarEventService.canAccessCalendarEvent( + userId, + workspaceId, + calendarChannelCalendarEventAssociations, + ); + } +} diff --git a/packages/twenty-server/src/modules/calendar/common/query-hooks/calendar-event/calendar-event-find-one.pre-query-hook.ts b/packages/twenty-server/src/modules/calendar/common/query-hooks/calendar-event/calendar-event-find-one.pre-query-hook.ts new file mode 100644 index 000000000000..add123542be9 --- /dev/null +++ b/packages/twenty-server/src/modules/calendar/common/query-hooks/calendar-event/calendar-event-find-one.pre-query-hook.ts @@ -0,0 +1,53 @@ +import { BadRequestException, NotFoundException, Scope } from '@nestjs/common'; + +import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface'; +import { FindOneResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; + +import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator'; +import { InjectWorkspaceRepository } from 'src/engine/twenty-orm/decorators/inject-workspace-repository.decorator'; +import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository'; +import { CanAccessCalendarEventService } from 'src/modules/calendar/common/query-hooks/calendar-event/services/can-access-calendar-event.service'; +import { CalendarChannelEventAssociationWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-channel-event-association.workspace-entity'; + +@WorkspaceQueryHook({ + key: `calendarEvent.findOne`, + scope: Scope.REQUEST, +}) +export class CalendarEventFindOnePreQueryHook + implements WorkspaceQueryHookInstance +{ + constructor( + @InjectWorkspaceRepository(CalendarChannelEventAssociationWorkspaceEntity) + private readonly calendarChannelEventAssociationRepository: WorkspaceRepository<CalendarChannelEventAssociationWorkspaceEntity>, + private readonly canAccessCalendarEventService: CanAccessCalendarEventService, + ) {} + + async execute( + userId: string, + workspaceId: string, + payload: FindOneResolverArgs, + ): Promise<void> { + if (!payload?.filter?.id?.eq) { + throw new BadRequestException('id filter is required'); + } + + // TODO: Re-implement this using twenty ORM + const calendarChannelCalendarEventAssociations = + await this.calendarChannelEventAssociationRepository.find({ + where: { + calendarEventId: payload?.filter?.id?.eq, + }, + relations: ['calendarChannel.connectedAccount'], + }); + + if (calendarChannelCalendarEventAssociations.length === 0) { + throw new NotFoundException(); + } + + await this.canAccessCalendarEventService.canAccessCalendarEvent( + userId, + workspaceId, + calendarChannelCalendarEventAssociations, + ); + } +} diff --git a/packages/twenty-server/src/modules/calendar/query-hooks/calendar-event/services/can-access-calendar-event.service.ts b/packages/twenty-server/src/modules/calendar/common/query-hooks/calendar-event/services/can-access-calendar-event.service.ts similarity index 72% rename from packages/twenty-server/src/modules/calendar/query-hooks/calendar-event/services/can-access-calendar-event.service.ts rename to packages/twenty-server/src/modules/calendar/common/query-hooks/calendar-event/services/can-access-calendar-event.service.ts index 0a971c32dcbf..fcd05354a713 100644 --- a/packages/twenty-server/src/modules/calendar/query-hooks/calendar-event/services/can-access-calendar-event.service.ts +++ b/packages/twenty-server/src/modules/calendar/common/query-hooks/calendar-event/services/can-access-calendar-event.service.ts @@ -1,25 +1,26 @@ import { ForbiddenException, Injectable } from '@nestjs/common'; import groupBy from 'lodash.groupby'; +import { Any } from 'typeorm'; import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; -import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record'; -import { CalendarChannelRepository } from 'src/modules/calendar/repositories/calendar-channel.repository'; -import { CalendarChannelEventAssociationWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-channel-event-association.workspace-entity'; -import { - CalendarChannelWorkspaceEntity, - CalendarChannelVisibility, -} from 'src/modules/calendar/standard-objects/calendar-channel.workspace-entity'; +import { InjectWorkspaceRepository } from 'src/engine/twenty-orm/decorators/inject-workspace-repository.decorator'; +import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository'; import { ConnectedAccountRepository } from 'src/modules/connected-account/repositories/connected-account.repository'; import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; import { WorkspaceMemberRepository } from 'src/modules/workspace-member/repositories/workspace-member.repository'; import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; +import { CalendarChannelEventAssociationWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-channel-event-association.workspace-entity'; +import { + CalendarChannelWorkspaceEntity, + CalendarChannelVisibility, +} from 'src/modules/calendar/common/standard-objects/calendar-channel.workspace-entity'; @Injectable() export class CanAccessCalendarEventService { constructor( - @InjectObjectMetadataRepository(CalendarChannelWorkspaceEntity) - private readonly calendarChannelRepository: CalendarChannelRepository, + @InjectWorkspaceRepository(CalendarChannelWorkspaceEntity) + private readonly calendarChannelRepository: WorkspaceRepository<CalendarChannelWorkspaceEntity>, @InjectObjectMetadataRepository(ConnectedAccountWorkspaceEntity) private readonly connectedAccountRepository: ConnectedAccountRepository, @InjectObjectMetadataRepository(WorkspaceMemberWorkspaceEntity) @@ -29,14 +30,17 @@ export class CanAccessCalendarEventService { public async canAccessCalendarEvent( userId: string, workspaceId: string, - calendarChannelCalendarEventAssociations: ObjectRecord<CalendarChannelEventAssociationWorkspaceEntity>[], + calendarChannelCalendarEventAssociations: CalendarChannelEventAssociationWorkspaceEntity[], ) { - const calendarChannels = await this.calendarChannelRepository.getByIds( - calendarChannelCalendarEventAssociations.map( - (association) => association.calendarChannelId, - ), - workspaceId, - ); + const calendarChannels = await this.calendarChannelRepository.find({ + where: { + id: Any( + calendarChannelCalendarEventAssociations.map( + (association) => association.calendarChannel.id, + ), + ), + }, + }); const calendarChannelsGroupByVisibility = groupBy( calendarChannels, diff --git a/packages/twenty-server/src/modules/calendar/query-hooks/calendar-query-hook.module.ts b/packages/twenty-server/src/modules/calendar/common/query-hooks/calendar-query-hook.module.ts similarity index 66% rename from packages/twenty-server/src/modules/calendar/query-hooks/calendar-query-hook.module.ts rename to packages/twenty-server/src/modules/calendar/common/query-hooks/calendar-query-hook.module.ts index 0bed2914aa0d..e3a16adf896b 100644 --- a/packages/twenty-server/src/modules/calendar/query-hooks/calendar-query-hook.module.ts +++ b/packages/twenty-server/src/modules/calendar/common/query-hooks/calendar-query-hook.module.ts @@ -3,31 +3,28 @@ import { Module } from '@nestjs/common'; import { ObjectMetadataRepositoryModule } from 'src/engine/object-metadata-repository/object-metadata-repository.module'; import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; -import { CalendarChannelEventAssociationWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-channel-event-association.workspace-entity'; -import { CalendarChannelWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-channel.workspace-entity'; -import { CalendarEventFindManyPreQueryHook } from 'src/modules/calendar/query-hooks/calendar-event/calendar-event-find-many.pre-query.hook'; -import { CalendarEventFindOnePreQueryHook } from 'src/modules/calendar/query-hooks/calendar-event/calendar-event-find-one.pre-query-hook'; -import { CanAccessCalendarEventService } from 'src/modules/calendar/query-hooks/calendar-event/services/can-access-calendar-event.service'; +import { TwentyORMModule } from 'src/engine/twenty-orm/twenty-orm.module'; +import { CalendarEventFindManyPreQueryHook } from 'src/modules/calendar/common/query-hooks/calendar-event/calendar-event-find-many.pre-query.hook'; +import { CalendarEventFindOnePreQueryHook } from 'src/modules/calendar/common/query-hooks/calendar-event/calendar-event-find-one.pre-query-hook'; +import { CanAccessCalendarEventService } from 'src/modules/calendar/common/query-hooks/calendar-event/services/can-access-calendar-event.service'; +import { CalendarChannelEventAssociationWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-channel-event-association.workspace-entity'; +import { CalendarChannelWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-channel.workspace-entity'; @Module({ imports: [ - ObjectMetadataRepositoryModule.forFeature([ + TwentyORMModule.forFeature([ CalendarChannelEventAssociationWorkspaceEntity, CalendarChannelWorkspaceEntity, + ]), + ObjectMetadataRepositoryModule.forFeature([ ConnectedAccountWorkspaceEntity, WorkspaceMemberWorkspaceEntity, ]), ], providers: [ CanAccessCalendarEventService, - { - provide: CalendarEventFindOnePreQueryHook.name, - useClass: CalendarEventFindOnePreQueryHook, - }, - { - provide: CalendarEventFindManyPreQueryHook.name, - useClass: CalendarEventFindManyPreQueryHook, - }, + CalendarEventFindOnePreQueryHook, + CalendarEventFindManyPreQueryHook, ], }) export class CalendarQueryHookModule {} diff --git a/packages/twenty-server/src/modules/calendar/standard-objects/calendar-channel-event-association.workspace-entity.ts b/packages/twenty-server/src/modules/calendar/common/standard-objects/calendar-channel-event-association.workspace-entity.ts similarity index 88% rename from packages/twenty-server/src/modules/calendar/standard-objects/calendar-channel-event-association.workspace-entity.ts rename to packages/twenty-server/src/modules/calendar/common/standard-objects/calendar-channel-event-association.workspace-entity.ts index bf1e82aa7210..f1475da3b012 100644 --- a/packages/twenty-server/src/modules/calendar/standard-objects/calendar-channel-event-association.workspace-entity.ts +++ b/packages/twenty-server/src/modules/calendar/common/standard-objects/calendar-channel-event-association.workspace-entity.ts @@ -3,7 +3,6 @@ import { Relation } from 'src/engine/workspace-manager/workspace-sync-metadata/i import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; import { CALENDAR_CHANNEL_EVENT_ASSOCIATION_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids'; import { STANDARD_OBJECT_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-object-ids'; -import { CalendarEventWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-event.workspace-entity'; import { WorkspaceEntity } from 'src/engine/twenty-orm/decorators/workspace-entity.decorator'; import { WorkspaceIsSystem } from 'src/engine/twenty-orm/decorators/workspace-is-system.decorator'; import { WorkspaceIsNotAuditLogged } from 'src/engine/twenty-orm/decorators/workspace-is-not-audit-logged.decorator'; @@ -11,7 +10,9 @@ import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-re import { RelationMetadataType } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity'; import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field.decorator'; import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity'; -import { CalendarChannelWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-channel.workspace-entity'; +import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator'; +import { CalendarChannelWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-channel.workspace-entity'; +import { CalendarEventWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-event.workspace-entity'; @WorkspaceEntity({ standardId: STANDARD_OBJECT_IDS.calendarChannelEventAssociation, @@ -41,12 +42,14 @@ export class CalendarChannelEventAssociationWorkspaceEntity extends BaseWorkspac label: 'Channel ID', description: 'Channel ID', icon: 'IconCalendar', - joinColumn: 'calendarChannelId', inverseSideTarget: () => CalendarChannelWorkspaceEntity, inverseSideFieldKey: 'calendarChannelEventAssociations', }) calendarChannel: Relation<CalendarChannelWorkspaceEntity>; + @WorkspaceJoinColumn('calendarChannel') + calendarChannelId: string; + @WorkspaceRelation({ standardId: CALENDAR_CHANNEL_EVENT_ASSOCIATION_STANDARD_FIELD_IDS.calendarEvent, @@ -54,9 +57,11 @@ export class CalendarChannelEventAssociationWorkspaceEntity extends BaseWorkspac label: 'Event ID', description: 'Event ID', icon: 'IconCalendar', - joinColumn: 'calendarEventId', inverseSideTarget: () => CalendarEventWorkspaceEntity, inverseSideFieldKey: 'calendarChannelEventAssociations', }) calendarEvent: Relation<CalendarEventWorkspaceEntity>; + + @WorkspaceJoinColumn('calendarEvent') + calendarEventId: string; } diff --git a/packages/twenty-server/src/modules/calendar/common/standard-objects/calendar-channel.workspace-entity.ts b/packages/twenty-server/src/modules/calendar/common/standard-objects/calendar-channel.workspace-entity.ts new file mode 100644 index 000000000000..88a549847726 --- /dev/null +++ b/packages/twenty-server/src/modules/calendar/common/standard-objects/calendar-channel.workspace-entity.ts @@ -0,0 +1,301 @@ +import { Relation } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/relation.interface'; + +import { + RelationMetadataType, + RelationOnDeleteAction, +} from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity'; +import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; +import { CALENDAR_CHANNEL_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids'; +import { STANDARD_OBJECT_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-object-ids'; +import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; +import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity'; +import { WorkspaceEntity } from 'src/engine/twenty-orm/decorators/workspace-entity.decorator'; +import { WorkspaceIsSystem } from 'src/engine/twenty-orm/decorators/workspace-is-system.decorator'; +import { WorkspaceIsNotAuditLogged } from 'src/engine/twenty-orm/decorators/workspace-is-not-audit-logged.decorator'; +import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field.decorator'; +import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator'; +import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator'; +import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator'; +import { CalendarChannelEventAssociationWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-channel-event-association.workspace-entity'; + +export enum CalendarChannelVisibility { + METADATA = 'METADATA', + SHARE_EVERYTHING = 'SHARE_EVERYTHING', +} + +export enum CalendarChannelSyncStatus { + NOT_SYNCED = 'NOT_SYNCED', + ONGOING = 'ONGOING', + ACTIVE = 'ACTIVE', + FAILED_INSUFFICIENT_PERMISSIONS = 'FAILED_INSUFFICIENT_PERMISSIONS', + FAILED_UNKNOWN = 'FAILED_UNKNOWN', +} + +export enum CalendarChannelSyncStage { + FULL_CALENDAR_EVENT_LIST_FETCH_PENDING = 'FULL_CALENDAR_EVENT_LIST_FETCH_PENDING', + PARTIAL_CALENDAR_EVENT_LIST_FETCH_PENDING = 'PARTIAL_CALENDAR_EVENT_LIST_FETCH_PENDING', + CALENDAR_EVENT_LIST_FETCH_ONGOING = 'CALENDAR_EVENT_LIST_FETCH_ONGOING', + CALENDAR_EVENTS_IMPORT_PENDING = 'CALENDAR_EVENTS_IMPORT_PENDING', + CALENDAR_EVENTS_IMPORT_ONGOING = 'CALENDAR_EVENTS_IMPORT_ONGOING', + FAILED = 'FAILED', +} + +export enum CalendarChannelContactAutoCreationPolicy { + AS_PARTICIPANT_AND_ORGANIZER = 'AS_PARTICIPANT_AND_ORGANIZER', + AS_PARTICIPANT = 'AS_PARTICIPANT', + AS_ORGANIZER = 'AS_ORGANIZER', + NONE = 'NONE', +} + +@WorkspaceEntity({ + standardId: STANDARD_OBJECT_IDS.calendarChannel, + namePlural: 'calendarChannels', + labelSingular: 'Calendar Channel', + labelPlural: 'Calendar Channels', + description: 'Calendar Channels', + icon: 'IconCalendar', +}) +@WorkspaceIsSystem() +@WorkspaceIsNotAuditLogged() +export class CalendarChannelWorkspaceEntity extends BaseWorkspaceEntity { + @WorkspaceField({ + standardId: CALENDAR_CHANNEL_STANDARD_FIELD_IDS.handle, + type: FieldMetadataType.TEXT, + label: 'Handle', + description: 'Handle', + icon: 'IconAt', + }) + handle: string; + + @WorkspaceField({ + standardId: CALENDAR_CHANNEL_STANDARD_FIELD_IDS.syncStatus, + type: FieldMetadataType.SELECT, + label: 'Sync status', + description: 'Sync status', + icon: 'IconStatusChange', + options: [ + { + value: CalendarChannelSyncStatus.ONGOING, + label: 'Ongoing', + position: 1, + color: 'yellow', + }, + { + value: CalendarChannelSyncStatus.NOT_SYNCED, + label: 'Not Synced', + position: 2, + color: 'blue', + }, + { + value: CalendarChannelSyncStatus.ACTIVE, + label: 'Active', + position: 3, + color: 'green', + }, + { + value: CalendarChannelSyncStatus.FAILED_INSUFFICIENT_PERMISSIONS, + label: 'Failed Insufficient Permissions', + position: 4, + color: 'red', + }, + { + value: CalendarChannelSyncStatus.FAILED_UNKNOWN, + label: 'Failed Unknown', + position: 5, + color: 'red', + }, + ], + }) + @WorkspaceIsNullable() + syncStatus: CalendarChannelSyncStatus | null; + + @WorkspaceField({ + standardId: CALENDAR_CHANNEL_STANDARD_FIELD_IDS.syncStage, + type: FieldMetadataType.SELECT, + label: 'Sync stage', + description: 'Sync stage', + icon: 'IconStatusChange', + options: [ + { + value: CalendarChannelSyncStage.FULL_CALENDAR_EVENT_LIST_FETCH_PENDING, + label: 'Full calendar event list fetch pending', + position: 0, + color: 'blue', + }, + { + value: + CalendarChannelSyncStage.PARTIAL_CALENDAR_EVENT_LIST_FETCH_PENDING, + label: 'Partial calendar event list fetch pending', + position: 1, + color: 'blue', + }, + { + value: CalendarChannelSyncStage.CALENDAR_EVENT_LIST_FETCH_ONGOING, + label: 'Calendar event list fetch ongoing', + position: 2, + color: 'orange', + }, + { + value: CalendarChannelSyncStage.CALENDAR_EVENTS_IMPORT_PENDING, + label: 'Calendar events import pending', + position: 3, + color: 'blue', + }, + { + value: CalendarChannelSyncStage.CALENDAR_EVENTS_IMPORT_ONGOING, + label: 'Calendar events import ongoing', + position: 4, + color: 'orange', + }, + { + value: CalendarChannelSyncStage.FAILED, + label: 'Failed', + position: 5, + color: 'red', + }, + ], + defaultValue: `'${CalendarChannelSyncStage.FULL_CALENDAR_EVENT_LIST_FETCH_PENDING}'`, + }) + syncStage: CalendarChannelSyncStage; + + @WorkspaceField({ + standardId: CALENDAR_CHANNEL_STANDARD_FIELD_IDS.visibility, + type: FieldMetadataType.SELECT, + label: 'Visibility', + description: 'Visibility', + icon: 'IconEyeglass', + options: [ + { + value: CalendarChannelVisibility.METADATA, + label: 'Metadata', + position: 0, + color: 'green', + }, + { + value: CalendarChannelVisibility.SHARE_EVERYTHING, + label: 'Share Everything', + position: 1, + color: 'orange', + }, + ], + defaultValue: `'${CalendarChannelVisibility.SHARE_EVERYTHING}'`, + }) + visibility: string; + + @WorkspaceField({ + standardId: + CALENDAR_CHANNEL_STANDARD_FIELD_IDS.isContactAutoCreationEnabled, + type: FieldMetadataType.BOOLEAN, + label: 'Is Contact Auto Creation Enabled', + description: 'Is Contact Auto Creation Enabled', + icon: 'IconUserCircle', + defaultValue: true, + }) + isContactAutoCreationEnabled: boolean; + + @WorkspaceField({ + standardId: CALENDAR_CHANNEL_STANDARD_FIELD_IDS.contactAutoCreationPolicy, + type: FieldMetadataType.SELECT, + label: 'Contact auto creation policy', + description: + 'Automatically create records for people you participated with in an event.', + icon: 'IconUserCircle', + options: [ + { + value: + CalendarChannelContactAutoCreationPolicy.AS_PARTICIPANT_AND_ORGANIZER, + label: 'As Participant and Organizer', + color: 'green', + position: 0, + }, + { + value: CalendarChannelContactAutoCreationPolicy.AS_PARTICIPANT, + label: 'As Participant', + color: 'orange', + position: 1, + }, + { + value: CalendarChannelContactAutoCreationPolicy.AS_ORGANIZER, + label: 'As Organizer', + color: 'blue', + position: 2, + }, + { + value: CalendarChannelContactAutoCreationPolicy.NONE, + label: 'None', + color: 'red', + position: 3, + }, + ], + defaultValue: `'${CalendarChannelContactAutoCreationPolicy.AS_PARTICIPANT_AND_ORGANIZER}'`, + }) + contactAutoCreationPolicy: CalendarChannelContactAutoCreationPolicy; + + @WorkspaceField({ + standardId: CALENDAR_CHANNEL_STANDARD_FIELD_IDS.isSyncEnabled, + type: FieldMetadataType.BOOLEAN, + label: 'Is Sync Enabled', + description: 'Is Sync Enabled', + icon: 'IconRefresh', + defaultValue: true, + }) + isSyncEnabled: boolean; + + @WorkspaceField({ + standardId: CALENDAR_CHANNEL_STANDARD_FIELD_IDS.syncCursor, + type: FieldMetadataType.TEXT, + label: 'Sync Cursor', + description: + 'Sync Cursor. Used for syncing events from the calendar provider', + icon: 'IconReload', + }) + syncCursor: string; + + @WorkspaceField({ + standardId: CALENDAR_CHANNEL_STANDARD_FIELD_IDS.syncStageStartedAt, + type: FieldMetadataType.DATE_TIME, + label: 'Sync stage started at', + description: 'Sync stage started at', + icon: 'IconHistory', + }) + @WorkspaceIsNullable() + syncStageStartedAt: string | null; + + @WorkspaceField({ + standardId: CALENDAR_CHANNEL_STANDARD_FIELD_IDS.throttleFailureCount, + type: FieldMetadataType.NUMBER, + label: 'Throttle Failure Count', + description: 'Throttle Failure Count', + icon: 'IconX', + defaultValue: 0, + }) + throttleFailureCount: number; + + @WorkspaceRelation({ + standardId: CALENDAR_CHANNEL_STANDARD_FIELD_IDS.connectedAccount, + type: RelationMetadataType.MANY_TO_ONE, + label: 'Connected Account', + description: 'Connected Account', + icon: 'IconUserCircle', + inverseSideTarget: () => ConnectedAccountWorkspaceEntity, + inverseSideFieldKey: 'calendarChannels', + }) + connectedAccount: Relation<ConnectedAccountWorkspaceEntity>; + + @WorkspaceJoinColumn('connectedAccount') + connectedAccountId: string; + + @WorkspaceRelation({ + standardId: + CALENDAR_CHANNEL_STANDARD_FIELD_IDS.calendarChannelEventAssociations, + type: RelationMetadataType.ONE_TO_MANY, + label: 'Calendar Channel Event Associations', + description: 'Calendar Channel Event Associations', + icon: 'IconCalendar', + inverseSideTarget: () => CalendarChannelEventAssociationWorkspaceEntity, + onDelete: RelationOnDeleteAction.CASCADE, + }) + calendarChannelEventAssociations: Relation< + CalendarChannelEventAssociationWorkspaceEntity[] + >; +} diff --git a/packages/twenty-server/src/modules/calendar/standard-objects/calendar-event-participant.workspace-entity.ts b/packages/twenty-server/src/modules/calendar/common/standard-objects/calendar-event-participant.workspace-entity.ts similarity index 91% rename from packages/twenty-server/src/modules/calendar/standard-objects/calendar-event-participant.workspace-entity.ts rename to packages/twenty-server/src/modules/calendar/common/standard-objects/calendar-event-participant.workspace-entity.ts index ee271b437998..4d8727a50fcf 100644 --- a/packages/twenty-server/src/modules/calendar/standard-objects/calendar-event-participant.workspace-entity.ts +++ b/packages/twenty-server/src/modules/calendar/common/standard-objects/calendar-event-participant.workspace-entity.ts @@ -3,7 +3,6 @@ import { Relation } from 'src/engine/workspace-manager/workspace-sync-metadata/i import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; import { CALENDAR_EVENT_PARTICIPANT_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids'; import { STANDARD_OBJECT_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-object-ids'; -import { CalendarEventWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-event.workspace-entity'; import { PersonWorkspaceEntity } from 'src/modules/person/standard-objects/person.workspace-entity'; import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity'; @@ -14,6 +13,8 @@ import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator'; import { RelationMetadataType } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity'; import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator'; +import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator'; +import { CalendarEventWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-event.workspace-entity'; export enum CalendarEventParticipantResponseStatus { NEEDS_ACTION = 'NEEDS_ACTION', @@ -103,24 +104,28 @@ export class CalendarEventParticipantWorkspaceEntity extends BaseWorkspaceEntity label: 'Event ID', description: 'Event ID', icon: 'IconCalendar', - joinColumn: 'calendarEventId', inverseSideTarget: () => CalendarEventWorkspaceEntity, inverseSideFieldKey: 'calendarEventParticipants', }) calendarEvent: Relation<CalendarEventWorkspaceEntity>; + @WorkspaceJoinColumn('calendarEvent') + calendarEventId: string; + @WorkspaceRelation({ standardId: CALENDAR_EVENT_PARTICIPANT_STANDARD_FIELD_IDS.person, type: RelationMetadataType.MANY_TO_ONE, label: 'Person', description: 'Person', icon: 'IconUser', - joinColumn: 'personId', inverseSideTarget: () => PersonWorkspaceEntity, inverseSideFieldKey: 'calendarEventParticipants', }) @WorkspaceIsNullable() - person: Relation<PersonWorkspaceEntity>; + person: Relation<PersonWorkspaceEntity> | null; + + @WorkspaceJoinColumn('person') + personId: string | null; @WorkspaceRelation({ standardId: CALENDAR_EVENT_PARTICIPANT_STANDARD_FIELD_IDS.workspaceMember, @@ -128,10 +133,12 @@ export class CalendarEventParticipantWorkspaceEntity extends BaseWorkspaceEntity label: 'Workspace Member', description: 'Workspace Member', icon: 'IconUser', - joinColumn: 'workspaceMemberId', inverseSideTarget: () => WorkspaceMemberWorkspaceEntity, inverseSideFieldKey: 'calendarEventParticipants', }) @WorkspaceIsNullable() - workspaceMember: Relation<WorkspaceMemberWorkspaceEntity>; + workspaceMember: Relation<WorkspaceMemberWorkspaceEntity> | null; + + @WorkspaceJoinColumn('workspaceMember') + workspaceMemberId: string | null; } diff --git a/packages/twenty-server/src/modules/calendar/standard-objects/calendar-event.workspace-entity.ts b/packages/twenty-server/src/modules/calendar/common/standard-objects/calendar-event.workspace-entity.ts similarity index 96% rename from packages/twenty-server/src/modules/calendar/standard-objects/calendar-event.workspace-entity.ts rename to packages/twenty-server/src/modules/calendar/common/standard-objects/calendar-event.workspace-entity.ts index d8d9052d27b3..563c85391690 100644 --- a/packages/twenty-server/src/modules/calendar/standard-objects/calendar-event.workspace-entity.ts +++ b/packages/twenty-server/src/modules/calendar/common/standard-objects/calendar-event.workspace-entity.ts @@ -5,8 +5,6 @@ import { RelationMetadataType, RelationOnDeleteAction, } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity'; -import { CalendarChannelEventAssociationWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-channel-event-association.workspace-entity'; -import { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-event-participant.workspace-entity'; import { STANDARD_OBJECT_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-object-ids'; import { CALENDAR_EVENT_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids'; import { LinkMetadata } from 'src/engine/metadata-modules/field-metadata/composite-types/link.composite-type'; @@ -17,6 +15,8 @@ import { WorkspaceIsNotAuditLogged } from 'src/engine/twenty-orm/decorators/work import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field.decorator'; import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator'; import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator'; +import { CalendarChannelEventAssociationWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-channel-event-association.workspace-entity'; +import { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-event-participant.workspace-entity'; @WorkspaceEntity({ standardId: STANDARD_OBJECT_IDS.calendarEvent, @@ -44,6 +44,7 @@ export class CalendarEventWorkspaceEntity extends BaseWorkspaceEntity { label: 'Is canceled', description: 'Is canceled', icon: 'IconCalendarCancel', + defaultValue: false, }) isCanceled: boolean; @@ -53,6 +54,7 @@ export class CalendarEventWorkspaceEntity extends BaseWorkspaceEntity { label: 'Is Full Day', description: 'Is Full Day', icon: 'Icon24Hours', + defaultValue: false, }) isFullDay: boolean; diff --git a/packages/twenty-server/src/modules/calendar/types/calendar-event.ts b/packages/twenty-server/src/modules/calendar/common/types/calendar-event.ts similarity index 54% rename from packages/twenty-server/src/modules/calendar/types/calendar-event.ts rename to packages/twenty-server/src/modules/calendar/common/types/calendar-event.ts index c2d7bd596603..00f4c82ac5c5 100644 --- a/packages/twenty-server/src/modules/calendar/types/calendar-event.ts +++ b/packages/twenty-server/src/modules/calendar/common/types/calendar-event.ts @@ -1,21 +1,21 @@ -import { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-event-participant.workspace-entity'; -import { CalendarEventWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-event.workspace-entity'; -import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record'; +import { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-event-participant.workspace-entity'; +import { CalendarEventWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-event.workspace-entity'; export type CalendarEvent = Omit< - ObjectRecord<CalendarEventWorkspaceEntity>, + CalendarEventWorkspaceEntity, | 'createdAt' | 'updatedAt' | 'calendarChannelEventAssociations' | 'calendarEventParticipants' | 'conferenceLink' + | 'id' > & { conferenceLinkLabel: string; conferenceLinkUrl: string; }; export type CalendarEventParticipant = Omit< - ObjectRecord<CalendarEventParticipantWorkspaceEntity>, + CalendarEventParticipantWorkspaceEntity, | 'id' | 'createdAt' | 'updatedAt' @@ -24,15 +24,23 @@ export type CalendarEventParticipant = Omit< | 'person' | 'workspaceMember' | 'calendarEvent' -> & { - iCalUID: string; -}; + | 'calendarEventId' +>; + +export type CalendarEventParticipantWithCalendarEventId = + CalendarEventParticipant & { + calendarEventId: string; + }; export type CalendarEventWithParticipants = CalendarEvent & { externalId: string; participants: CalendarEventParticipant[]; + status: string; }; -export type CalendarEventParticipantWithId = CalendarEventParticipant & { +export type CalendarEventWithParticipantsAndCalendarEventId = CalendarEvent & { id: string; + externalId: string; + participants: CalendarEventParticipantWithCalendarEventId[]; + status: string; }; diff --git a/packages/twenty-server/src/modules/calendar/crons/commands/calendar-cron-commands.module.ts b/packages/twenty-server/src/modules/calendar/crons/commands/calendar-cron-commands.module.ts deleted file mode 100644 index 30df8fe7daa5..000000000000 --- a/packages/twenty-server/src/modules/calendar/crons/commands/calendar-cron-commands.module.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Module } from '@nestjs/common'; - -import { GoogleCalendarSyncCronCommand } from 'src/modules/calendar/crons/commands/google-calendar-sync.cron.command'; - -@Module({ - providers: [GoogleCalendarSyncCronCommand], -}) -export class CalendarCronCommandsModule {} diff --git a/packages/twenty-server/src/modules/calendar/crons/commands/google-calendar-sync.cron.command.ts b/packages/twenty-server/src/modules/calendar/crons/commands/google-calendar-sync.cron.command.ts deleted file mode 100644 index 90eeed4a0596..000000000000 --- a/packages/twenty-server/src/modules/calendar/crons/commands/google-calendar-sync.cron.command.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { Inject } from '@nestjs/common'; - -import { Command, CommandRunner } from 'nest-commander'; - -import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; -import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service'; -import { GoogleCalendarSyncCronJob } from 'src/modules/calendar/crons/jobs/google-calendar-sync.cron.job'; - -const GOOGLE_CALENDAR_SYNC_CRON_PATTERN = '*/5 * * * *'; - -@Command({ - name: 'cron:calendar:google-calendar-sync', - description: 'Starts a cron job to sync google calendar for all workspaces.', -}) -export class GoogleCalendarSyncCronCommand extends CommandRunner { - constructor( - @Inject(MessageQueue.cronQueue) - private readonly messageQueueService: MessageQueueService, - ) { - super(); - } - - async run(): Promise<void> { - await this.messageQueueService.addCron<undefined>( - GoogleCalendarSyncCronJob.name, - undefined, - { - repeat: { pattern: GOOGLE_CALENDAR_SYNC_CRON_PATTERN }, - }, - ); - } -} diff --git a/packages/twenty-server/src/modules/calendar/crons/jobs/calendar-cron-job.module.ts b/packages/twenty-server/src/modules/calendar/crons/jobs/calendar-cron-job.module.ts deleted file mode 100644 index 04f57299fa88..000000000000 --- a/packages/twenty-server/src/modules/calendar/crons/jobs/calendar-cron-job.module.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Module } from '@nestjs/common'; -import { TypeOrmModule } from '@nestjs/typeorm'; - -import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity'; -import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; -import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity'; -import { GoogleCalendarSyncCronJob } from 'src/modules/calendar/crons/jobs/google-calendar-sync.cron.job'; -import { WorkspaceGoogleCalendarSyncModule } from 'src/modules/calendar/services/workspace-google-calendar-sync/workspace-google-calendar-sync.module'; - -@Module({ - imports: [ - TypeOrmModule.forFeature([Workspace, FeatureFlagEntity], 'core'), - TypeOrmModule.forFeature([DataSourceEntity], 'metadata'), - WorkspaceGoogleCalendarSyncModule, - ], - providers: [ - { - provide: GoogleCalendarSyncCronJob.name, - useClass: GoogleCalendarSyncCronJob, - }, - ], -}) -export class CalendarCronJobModule {} diff --git a/packages/twenty-server/src/modules/calendar/crons/jobs/google-calendar-sync.cron.job.ts b/packages/twenty-server/src/modules/calendar/crons/jobs/google-calendar-sync.cron.job.ts deleted file mode 100644 index 7c2072c41e1c..000000000000 --- a/packages/twenty-server/src/modules/calendar/crons/jobs/google-calendar-sync.cron.job.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { InjectRepository } from '@nestjs/typeorm'; - -import { Repository, In } from 'typeorm'; - -import { MessageQueueJob } from 'src/engine/integrations/message-queue/interfaces/message-queue-job.interface'; - -import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; -import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity'; -import { WorkspaceGoogleCalendarSyncService } from 'src/modules/calendar/services/workspace-google-calendar-sync/workspace-google-calendar-sync.service'; -import { EnvironmentService } from 'src/engine/integrations/environment/environment.service'; - -@Injectable() -export class GoogleCalendarSyncCronJob implements MessageQueueJob<undefined> { - constructor( - @InjectRepository(Workspace, 'core') - private readonly workspaceRepository: Repository<Workspace>, - @InjectRepository(DataSourceEntity, 'metadata') - private readonly dataSourceRepository: Repository<DataSourceEntity>, - private readonly workspaceGoogleCalendarSyncService: WorkspaceGoogleCalendarSyncService, - private readonly environmentService: EnvironmentService, - ) {} - - async handle(): Promise<void> { - const workspaceIds = ( - await this.workspaceRepository.find({ - where: this.environmentService.get('IS_BILLING_ENABLED') - ? { - subscriptionStatus: In(['active', 'trialing', 'past_due']), - } - : {}, - select: ['id'], - }) - ).map((workspace) => workspace.id); - - const dataSources = await this.dataSourceRepository.find({ - where: { - workspaceId: In(workspaceIds), - }, - }); - - const workspaceIdsWithDataSources = new Set( - dataSources.map((dataSource) => dataSource.workspaceId), - ); - - for (const workspaceId of workspaceIdsWithDataSources) { - await this.workspaceGoogleCalendarSyncService.startWorkspaceGoogleCalendarSync( - workspaceId, - ); - } - } -} diff --git a/packages/twenty-server/src/modules/calendar/jobs/blocklist-item-delete-calendar-events.job.ts b/packages/twenty-server/src/modules/calendar/jobs/blocklist-item-delete-calendar-events.job.ts deleted file mode 100644 index a3196a02a45d..000000000000 --- a/packages/twenty-server/src/modules/calendar/jobs/blocklist-item-delete-calendar-events.job.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { Injectable, Logger } from '@nestjs/common'; - -import { MessageQueueJob } from 'src/engine/integrations/message-queue/interfaces/message-queue-job.interface'; - -import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; -import { CalendarChannelEventAssociationRepository } from 'src/modules/calendar/repositories/calendar-channel-event-association.repository'; -import { CalendarChannelRepository } from 'src/modules/calendar/repositories/calendar-channel.repository'; -import { CalendarEventCleanerService } from 'src/modules/calendar/services/calendar-event-cleaner/calendar-event-cleaner.service'; -import { CalendarChannelEventAssociationWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-channel-event-association.workspace-entity'; -import { CalendarChannelWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-channel.workspace-entity'; -import { BlocklistRepository } from 'src/modules/connected-account/repositories/blocklist.repository'; -import { BlocklistWorkspaceEntity } from 'src/modules/connected-account/standard-objects/blocklist.workspace-entity'; - -export type BlocklistItemDeleteCalendarEventsJobData = { - workspaceId: string; - blocklistItemId: string; -}; - -@Injectable() -export class BlocklistItemDeleteCalendarEventsJob - implements MessageQueueJob<BlocklistItemDeleteCalendarEventsJobData> -{ - private readonly logger = new Logger( - BlocklistItemDeleteCalendarEventsJob.name, - ); - - constructor( - @InjectObjectMetadataRepository(CalendarChannelWorkspaceEntity) - private readonly calendarChannelRepository: CalendarChannelRepository, - @InjectObjectMetadataRepository( - CalendarChannelEventAssociationWorkspaceEntity, - ) - private readonly calendarChannelEventAssociationRepository: CalendarChannelEventAssociationRepository, - @InjectObjectMetadataRepository(BlocklistWorkspaceEntity) - private readonly blocklistRepository: BlocklistRepository, - private readonly calendarEventCleanerService: CalendarEventCleanerService, - ) {} - - async handle(data: BlocklistItemDeleteCalendarEventsJobData): Promise<void> { - const { workspaceId, blocklistItemId } = data; - - const blocklistItem = await this.blocklistRepository.getById( - blocklistItemId, - workspaceId, - ); - - if (!blocklistItem) { - this.logger.log( - `Blocklist item with id ${blocklistItemId} not found in workspace ${workspaceId}`, - ); - - return; - } - - const { handle, workspaceMemberId } = blocklistItem; - - this.logger.log( - `Deleting calendar events from ${handle} in workspace ${workspaceId} for workspace member ${workspaceMemberId}`, - ); - - const calendarChannels = - await this.calendarChannelRepository.getIdsByWorkspaceMemberId( - workspaceMemberId, - workspaceId, - ); - - const calendarChannelIds = calendarChannels.map(({ id }) => id); - - await this.calendarChannelEventAssociationRepository.deleteByCalendarEventParticipantHandleAndCalendarChannelIds( - handle, - calendarChannelIds, - workspaceId, - ); - - await this.calendarEventCleanerService.cleanWorkspaceCalendarEvents( - workspaceId, - ); - - this.logger.log( - `Deleted calendar events from handle ${handle} in workspace ${workspaceId} for workspace member ${workspaceMemberId}`, - ); - } -} diff --git a/packages/twenty-server/src/modules/calendar/jobs/blocklist-reimport-calendar-events.job.ts b/packages/twenty-server/src/modules/calendar/jobs/blocklist-reimport-calendar-events.job.ts deleted file mode 100644 index 85660dae7d5a..000000000000 --- a/packages/twenty-server/src/modules/calendar/jobs/blocklist-reimport-calendar-events.job.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { Injectable, Logger } from '@nestjs/common'; - -import { MessageQueueJob } from 'src/engine/integrations/message-queue/interfaces/message-queue-job.interface'; - -import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; -import { GoogleCalendarSyncService } from 'src/modules/calendar/services/google-calendar-sync/google-calendar-sync.service'; -import { ConnectedAccountRepository } from 'src/modules/connected-account/repositories/connected-account.repository'; -import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; - -export type BlocklistReimportCalendarEventsJobData = { - workspaceId: string; - workspaceMemberId: string; - handle: string; -}; - -@Injectable() -export class BlocklistReimportCalendarEventsJob - implements MessageQueueJob<BlocklistReimportCalendarEventsJobData> -{ - private readonly logger = new Logger(BlocklistReimportCalendarEventsJob.name); - - constructor( - @InjectObjectMetadataRepository(ConnectedAccountWorkspaceEntity) - private readonly connectedAccountRepository: ConnectedAccountRepository, - private readonly googleCalendarSyncService: GoogleCalendarSyncService, - ) {} - - async handle(data: BlocklistReimportCalendarEventsJobData): Promise<void> { - const { workspaceId, workspaceMemberId, handle } = data; - - this.logger.log( - `Reimporting calendar events from handle ${handle} in workspace ${workspaceId} for workspace member ${workspaceMemberId}`, - ); - - const connectedAccount = - await this.connectedAccountRepository.getAllByWorkspaceMemberId( - workspaceMemberId, - workspaceId, - ); - - if (!connectedAccount || connectedAccount.length === 0) { - this.logger.error( - `No connected account found for workspace member ${workspaceMemberId} in workspace ${workspaceId}`, - ); - - return; - } - - await this.googleCalendarSyncService.startGoogleCalendarSync( - workspaceId, - connectedAccount[0].id, - handle, - ); - - this.logger.log( - `Reimporting calendar events from ${handle} in workspace ${workspaceId} for workspace member ${workspaceMemberId} done`, - ); - } -} diff --git a/packages/twenty-server/src/modules/calendar/jobs/calendar-create-company-and-contact-after-sync.job.ts b/packages/twenty-server/src/modules/calendar/jobs/calendar-create-company-and-contact-after-sync.job.ts deleted file mode 100644 index 3c1b9046b9a5..000000000000 --- a/packages/twenty-server/src/modules/calendar/jobs/calendar-create-company-and-contact-after-sync.job.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { Injectable, Logger } from '@nestjs/common'; - -import { MessageQueueJob } from 'src/engine/integrations/message-queue/interfaces/message-queue-job.interface'; - -import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; -import { CalendarChannelRepository } from 'src/modules/calendar/repositories/calendar-channel.repository'; -import { CalendarEventParticipantRepository } from 'src/modules/calendar/repositories/calendar-event-participant.repository'; -import { CalendarChannelWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-channel.workspace-entity'; -import { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-event-participant.workspace-entity'; -import { CreateCompanyAndContactService } from 'src/modules/connected-account/auto-companies-and-contacts-creation/services/create-company-and-contact.service'; -import { ConnectedAccountRepository } from 'src/modules/connected-account/repositories/connected-account.repository'; -import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; - -export type CalendarCreateCompanyAndContactAfterSyncJobData = { - workspaceId: string; - calendarChannelId: string; -}; - -@Injectable() -export class CalendarCreateCompanyAndContactAfterSyncJob - implements MessageQueueJob<CalendarCreateCompanyAndContactAfterSyncJobData> -{ - private readonly logger = new Logger( - CalendarCreateCompanyAndContactAfterSyncJob.name, - ); - constructor( - private readonly createCompanyAndContactService: CreateCompanyAndContactService, - @InjectObjectMetadataRepository(CalendarChannelWorkspaceEntity) - private readonly calendarChannelService: CalendarChannelRepository, - @InjectObjectMetadataRepository(CalendarEventParticipantWorkspaceEntity) - private readonly calendarEventParticipantRepository: CalendarEventParticipantRepository, - @InjectObjectMetadataRepository(ConnectedAccountWorkspaceEntity) - private readonly connectedAccountRepository: ConnectedAccountRepository, - ) {} - - async handle( - data: CalendarCreateCompanyAndContactAfterSyncJobData, - ): Promise<void> { - this.logger.log( - `create contacts and companies after sync for workspace ${data.workspaceId} and calendarChannel ${data.calendarChannelId}`, - ); - const { workspaceId, calendarChannelId } = data; - - const calendarChannels = await this.calendarChannelService.getByIds( - [calendarChannelId], - workspaceId, - ); - - if (calendarChannels.length === 0) { - throw new Error( - `Calendar channel with id ${calendarChannelId} not found in workspace ${workspaceId}`, - ); - } - - const { handle, isContactAutoCreationEnabled, connectedAccountId } = - calendarChannels[0]; - - if (!isContactAutoCreationEnabled || !handle) { - return; - } - - const connectedAccount = await this.connectedAccountRepository.getById( - connectedAccountId, - workspaceId, - ); - - if (!connectedAccount) { - throw new Error( - `Connected account with id ${connectedAccountId} not found in workspace ${workspaceId}`, - ); - } - - const calendarEventParticipantsWithoutPersonIdAndWorkspaceMemberId = - await this.calendarEventParticipantRepository.getByCalendarChannelIdWithoutPersonIdAndWorkspaceMemberId( - calendarChannelId, - workspaceId, - ); - - await this.createCompanyAndContactService.createCompaniesAndContactsAndUpdateParticipants( - connectedAccount, - calendarEventParticipantsWithoutPersonIdAndWorkspaceMemberId, - workspaceId, - ); - - this.logger.log( - `create contacts and companies after sync for workspace ${data.workspaceId} and calendarChannel ${data.calendarChannelId} done`, - ); - } -} diff --git a/packages/twenty-server/src/modules/calendar/jobs/calendar-job.module.ts b/packages/twenty-server/src/modules/calendar/jobs/calendar-job.module.ts deleted file mode 100644 index 4888d98fc0f8..000000000000 --- a/packages/twenty-server/src/modules/calendar/jobs/calendar-job.module.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { Module } from '@nestjs/common'; - -import { ObjectMetadataRepositoryModule } from 'src/engine/object-metadata-repository/object-metadata-repository.module'; -import { BlocklistItemDeleteCalendarEventsJob } from 'src/modules/calendar/jobs/blocklist-item-delete-calendar-events.job'; -import { BlocklistReimportCalendarEventsJob } from 'src/modules/calendar/jobs/blocklist-reimport-calendar-events.job'; -import { CalendarCreateCompanyAndContactAfterSyncJob } from 'src/modules/calendar/jobs/calendar-create-company-and-contact-after-sync.job'; -import { DeleteConnectedAccountAssociatedCalendarDataJob } from 'src/modules/calendar/jobs/delete-connected-account-associated-calendar-data.job'; -import { GoogleCalendarSyncJob } from 'src/modules/calendar/jobs/google-calendar-sync.job'; -import { CalendarEventCleanerModule } from 'src/modules/calendar/services/calendar-event-cleaner/calendar-event-cleaner.module'; -import { GoogleCalendarSyncModule } from 'src/modules/calendar/services/google-calendar-sync/google-calendar-sync.module'; -import { CalendarChannelEventAssociationWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-channel-event-association.workspace-entity'; -import { CalendarChannelWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-channel.workspace-entity'; -import { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-event-participant.workspace-entity'; -import { AutoCompaniesAndContactsCreationModule } from 'src/modules/connected-account/auto-companies-and-contacts-creation/auto-companies-and-contacts-creation.module'; -import { GoogleAPIRefreshAccessTokenModule } from 'src/modules/connected-account/services/google-api-refresh-access-token/google-api-refresh-access-token.module'; -import { BlocklistWorkspaceEntity } from 'src/modules/connected-account/standard-objects/blocklist.workspace-entity'; -import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; - -@Module({ - imports: [ - ObjectMetadataRepositoryModule.forFeature([ - CalendarChannelWorkspaceEntity, - CalendarChannelEventAssociationWorkspaceEntity, - CalendarEventParticipantWorkspaceEntity, - ConnectedAccountWorkspaceEntity, - BlocklistWorkspaceEntity, - ]), - CalendarEventCleanerModule, - AutoCompaniesAndContactsCreationModule, - GoogleCalendarSyncModule, - GoogleAPIRefreshAccessTokenModule, - GoogleCalendarSyncModule, - ], - providers: [ - { - provide: BlocklistItemDeleteCalendarEventsJob.name, - useClass: BlocklistItemDeleteCalendarEventsJob, - }, - { - provide: BlocklistReimportCalendarEventsJob.name, - useClass: BlocklistReimportCalendarEventsJob, - }, - { - provide: GoogleCalendarSyncJob.name, - useClass: GoogleCalendarSyncJob, - }, - { - provide: CalendarCreateCompanyAndContactAfterSyncJob.name, - useClass: CalendarCreateCompanyAndContactAfterSyncJob, - }, - { - provide: DeleteConnectedAccountAssociatedCalendarDataJob.name, - useClass: DeleteConnectedAccountAssociatedCalendarDataJob, - }, - ], -}) -export class CalendarJobModule {} diff --git a/packages/twenty-server/src/modules/calendar/jobs/google-calendar-sync.job.ts b/packages/twenty-server/src/modules/calendar/jobs/google-calendar-sync.job.ts deleted file mode 100644 index dd7a3362d3a6..000000000000 --- a/packages/twenty-server/src/modules/calendar/jobs/google-calendar-sync.job.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { Injectable, Logger } from '@nestjs/common'; - -import { MessageQueueJob } from 'src/engine/integrations/message-queue/interfaces/message-queue-job.interface'; - -import { GoogleAPIRefreshAccessTokenService } from 'src/modules/connected-account/services/google-api-refresh-access-token/google-api-refresh-access-token.service'; -import { GoogleCalendarSyncService } from 'src/modules/calendar/services/google-calendar-sync/google-calendar-sync.service'; - -export type GoogleCalendarSyncJobData = { - workspaceId: string; - connectedAccountId: string; -}; - -@Injectable() -export class GoogleCalendarSyncJob - implements MessageQueueJob<GoogleCalendarSyncJobData> -{ - private readonly logger = new Logger(GoogleCalendarSyncJob.name); - - constructor( - private readonly googleAPIsRefreshAccessTokenService: GoogleAPIRefreshAccessTokenService, - private readonly googleCalendarSyncService: GoogleCalendarSyncService, - ) {} - - async handle(data: GoogleCalendarSyncJobData): Promise<void> { - this.logger.log( - `google calendar sync for workspace ${data.workspaceId} and account ${data.connectedAccountId}`, - ); - try { - await this.googleAPIsRefreshAccessTokenService.refreshAndSaveAccessToken( - data.workspaceId, - data.connectedAccountId, - ); - } catch (e) { - this.logger.error( - `Error refreshing access token for connected account ${data.connectedAccountId} in workspace ${data.workspaceId}`, - e, - ); - - return; - } - - await this.googleCalendarSyncService.startGoogleCalendarSync( - data.workspaceId, - data.connectedAccountId, - ); - } -} diff --git a/packages/twenty-server/src/modules/calendar/query-hooks/calendar-event/calendar-event-find-many.pre-query.hook.ts b/packages/twenty-server/src/modules/calendar/query-hooks/calendar-event/calendar-event-find-many.pre-query.hook.ts deleted file mode 100644 index a5c8b06aa649..000000000000 --- a/packages/twenty-server/src/modules/calendar/query-hooks/calendar-event/calendar-event-find-many.pre-query.hook.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { - BadRequestException, - Injectable, - NotFoundException, -} from '@nestjs/common'; - -import { WorkspacePreQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-pre-query-hook/interfaces/workspace-pre-query-hook.interface'; -import { FindManyResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; - -import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; -import { CalendarChannelEventAssociationWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-channel-event-association.workspace-entity'; -import { CalendarChannelEventAssociationRepository } from 'src/modules/calendar/repositories/calendar-channel-event-association.repository'; -import { CanAccessCalendarEventService } from 'src/modules/calendar/query-hooks/calendar-event/services/can-access-calendar-event.service'; - -@Injectable() -export class CalendarEventFindManyPreQueryHook - implements WorkspacePreQueryHook -{ - constructor( - @InjectObjectMetadataRepository( - CalendarChannelEventAssociationWorkspaceEntity, - ) - private readonly calendarChannelEventAssociationRepository: CalendarChannelEventAssociationRepository, - private readonly canAccessCalendarEventService: CanAccessCalendarEventService, - ) {} - - async execute( - userId: string, - workspaceId: string, - payload: FindManyResolverArgs, - ): Promise<void> { - if (!payload?.filter?.id?.eq) { - throw new BadRequestException('id filter is required'); - } - - const calendarChannelCalendarEventAssociations = - await this.calendarChannelEventAssociationRepository.getByCalendarEventIds( - [payload?.filter?.id?.eq], - workspaceId, - ); - - if (calendarChannelCalendarEventAssociations.length === 0) { - throw new NotFoundException(); - } - - await this.canAccessCalendarEventService.canAccessCalendarEvent( - userId, - workspaceId, - calendarChannelCalendarEventAssociations, - ); - } -} diff --git a/packages/twenty-server/src/modules/calendar/query-hooks/calendar-event/calendar-event-find-one.pre-query-hook.ts b/packages/twenty-server/src/modules/calendar/query-hooks/calendar-event/calendar-event-find-one.pre-query-hook.ts deleted file mode 100644 index 082e1b280185..000000000000 --- a/packages/twenty-server/src/modules/calendar/query-hooks/calendar-event/calendar-event-find-one.pre-query-hook.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { - BadRequestException, - Injectable, - NotFoundException, -} from '@nestjs/common'; - -import { WorkspacePreQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-pre-query-hook/interfaces/workspace-pre-query-hook.interface'; -import { FindOneResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; - -import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; -import { CanAccessCalendarEventService } from 'src/modules/calendar/query-hooks/calendar-event/services/can-access-calendar-event.service'; -import { CalendarChannelEventAssociationRepository } from 'src/modules/calendar/repositories/calendar-channel-event-association.repository'; -import { CalendarChannelEventAssociationWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-channel-event-association.workspace-entity'; - -@Injectable() -export class CalendarEventFindOnePreQueryHook implements WorkspacePreQueryHook { - constructor( - @InjectObjectMetadataRepository( - CalendarChannelEventAssociationWorkspaceEntity, - ) - private readonly calendarChannelEventAssociationRepository: CalendarChannelEventAssociationRepository, - private readonly canAccessCalendarEventService: CanAccessCalendarEventService, - ) {} - - async execute( - userId: string, - workspaceId: string, - payload: FindOneResolverArgs, - ): Promise<void> { - if (!payload?.filter?.id?.eq) { - throw new BadRequestException('id filter is required'); - } - - const calendarChannelCalendarEventAssociations = - await this.calendarChannelEventAssociationRepository.getByCalendarEventIds( - [payload?.filter?.id?.eq], - workspaceId, - ); - - if (calendarChannelCalendarEventAssociations.length === 0) { - throw new NotFoundException(); - } - - await this.canAccessCalendarEventService.canAccessCalendarEvent( - userId, - workspaceId, - calendarChannelCalendarEventAssociations, - ); - } -} diff --git a/packages/twenty-server/src/modules/calendar/repositories/calendar-channel-event-association.repository.ts b/packages/twenty-server/src/modules/calendar/repositories/calendar-channel-event-association.repository.ts deleted file mode 100644 index 89a9a28b486f..000000000000 --- a/packages/twenty-server/src/modules/calendar/repositories/calendar-channel-event-association.repository.ts +++ /dev/null @@ -1,205 +0,0 @@ -import { Injectable } from '@nestjs/common'; - -import { EntityManager } from 'typeorm'; - -import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; -import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record'; -import { CalendarChannelEventAssociationWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-channel-event-association.workspace-entity'; -import { getFlattenedValuesAndValuesStringForBatchRawQuery } from 'src/modules/calendar/utils/get-flattened-values-and-values-string-for-batch-raw-query.util'; - -@Injectable() -export class CalendarChannelEventAssociationRepository { - constructor( - private readonly workspaceDataSourceService: WorkspaceDataSourceService, - ) {} - - public async getByEventExternalIdsAndCalendarChannelId( - eventExternalIds: string[], - calendarChannelId: string, - workspaceId: string, - transactionManager?: EntityManager, - ): Promise<ObjectRecord<CalendarChannelEventAssociationWorkspaceEntity>[]> { - if (eventExternalIds.length === 0) { - return []; - } - - const dataSourceSchema = - this.workspaceDataSourceService.getSchemaName(workspaceId); - - return await this.workspaceDataSourceService.executeRawQuery( - `SELECT * FROM ${dataSourceSchema}."calendarChannelEventAssociation" - WHERE "eventExternalId" = ANY($1) AND "calendarChannelId" = $2`, - [eventExternalIds, calendarChannelId], - workspaceId, - transactionManager, - ); - } - - public async deleteByEventExternalIdsAndCalendarChannelId( - eventExternalIds: string[], - calendarChannelId: string, - workspaceId: string, - transactionManager?: EntityManager, - ) { - const dataSourceSchema = - this.workspaceDataSourceService.getSchemaName(workspaceId); - - await this.workspaceDataSourceService.executeRawQuery( - `DELETE FROM ${dataSourceSchema}."calendarChannelEventAssociation" WHERE "eventExternalId" = ANY($1) AND "calendarChannelId" = $2`, - [eventExternalIds, calendarChannelId], - workspaceId, - transactionManager, - ); - } - - public async getByCalendarChannelIds( - calendarChannelIds: string[], - workspaceId: string, - transactionManager?: EntityManager, - ): Promise<ObjectRecord<CalendarChannelEventAssociationWorkspaceEntity>[]> { - if (calendarChannelIds.length === 0) { - return []; - } - - const dataSourceSchema = - this.workspaceDataSourceService.getSchemaName(workspaceId); - - return await this.workspaceDataSourceService.executeRawQuery( - `SELECT * FROM ${dataSourceSchema}."calendarChannelEventAssociation" - WHERE "calendarChannelId" = ANY($1)`, - [calendarChannelIds], - workspaceId, - transactionManager, - ); - } - - public async deleteByCalendarChannelIds( - calendarChannelIds: string[], - workspaceId: string, - transactionManager?: EntityManager, - ) { - if (calendarChannelIds.length === 0) { - return; - } - - const dataSourceSchema = - this.workspaceDataSourceService.getSchemaName(workspaceId); - - await this.workspaceDataSourceService.executeRawQuery( - `DELETE FROM ${dataSourceSchema}."calendarChannelEventAssociation" WHERE "calendarChannelId" = ANY($1)`, - [calendarChannelIds], - workspaceId, - transactionManager, - ); - } - - public async deleteByIds( - ids: string[], - workspaceId: string, - transactionManager?: EntityManager, - ) { - if (ids.length === 0) { - return; - } - - const dataSourceSchema = - this.workspaceDataSourceService.getSchemaName(workspaceId); - - await this.workspaceDataSourceService.executeRawQuery( - `DELETE FROM ${dataSourceSchema}."calendarChannelEventAssociation" WHERE "id" = ANY($1)`, - [ids], - workspaceId, - transactionManager, - ); - } - - public async getByCalendarEventIds( - calendarEventIds: string[], - workspaceId: string, - transactionManager?: EntityManager, - ): Promise<ObjectRecord<CalendarChannelEventAssociationWorkspaceEntity>[]> { - if (calendarEventIds.length === 0) { - return []; - } - - const dataSourceSchema = - this.workspaceDataSourceService.getSchemaName(workspaceId); - - return await this.workspaceDataSourceService.executeRawQuery( - `SELECT * FROM ${dataSourceSchema}."calendarChannelEventAssociation" - WHERE "calendarEventId" = ANY($1)`, - [calendarEventIds], - workspaceId, - transactionManager, - ); - } - - public async saveCalendarChannelEventAssociations( - calendarChannelEventAssociations: Omit< - ObjectRecord<CalendarChannelEventAssociationWorkspaceEntity>, - 'id' | 'createdAt' | 'updatedAt' | 'calendarChannel' | 'calendarEvent' - >[], - workspaceId: string, - transactionManager?: EntityManager, - ) { - if (calendarChannelEventAssociations.length === 0) { - return; - } - - const dataSourceSchema = - this.workspaceDataSourceService.getSchemaName(workspaceId); - - const { - flattenedValues: calendarChannelEventAssociationValues, - valuesString, - } = getFlattenedValuesAndValuesStringForBatchRawQuery( - calendarChannelEventAssociations, - { - calendarChannelId: 'uuid', - calendarEventId: 'uuid', - eventExternalId: 'text', - }, - ); - - await this.workspaceDataSourceService.executeRawQuery( - `INSERT INTO ${dataSourceSchema}."calendarChannelEventAssociation" ("calendarChannelId", "calendarEventId", "eventExternalId") - VALUES ${valuesString}`, - calendarChannelEventAssociationValues, - workspaceId, - transactionManager, - ); - } - - public async deleteByCalendarEventParticipantHandleAndCalendarChannelIds( - calendarEventParticipantHandle: string, - calendarChannelIds: string[], - workspaceId: string, - transactionManager?: EntityManager, - ) { - const dataSourceSchema = - this.workspaceDataSourceService.getSchemaName(workspaceId); - - const isHandleDomain = calendarEventParticipantHandle.startsWith('@'); - - await this.workspaceDataSourceService.executeRawQuery( - `DELETE FROM ${dataSourceSchema}."calendarChannelEventAssociation" - WHERE "id" IN ( - SELECT "calendarChannelEventAssociation"."id" - FROM ${dataSourceSchema}."calendarChannelEventAssociation" "calendarChannelEventAssociation" - JOIN ${dataSourceSchema}."calendarEvent" "calendarEvent" ON "calendarChannelEventAssociation"."calendarEventId" = "calendarEvent"."id" - JOIN ${dataSourceSchema}."calendarEventParticipant" "calendarEventParticipant" ON "calendarEvent"."id" = "calendarEventParticipant"."calendarEventId" - WHERE "calendarEventParticipant"."handle" ${ - isHandleDomain ? 'ILIKE' : '=' - } $1 AND "calendarChannelEventAssociation"."calendarChannelId" = ANY($2) - )`, - [ - isHandleDomain - ? `%${calendarEventParticipantHandle}` - : calendarEventParticipantHandle, - calendarChannelIds, - ], - workspaceId, - transactionManager, - ); - } -} diff --git a/packages/twenty-server/src/modules/calendar/repositories/calendar-channel.repository.ts b/packages/twenty-server/src/modules/calendar/repositories/calendar-channel.repository.ts deleted file mode 100644 index d0cde3ca82fd..000000000000 --- a/packages/twenty-server/src/modules/calendar/repositories/calendar-channel.repository.ts +++ /dev/null @@ -1,135 +0,0 @@ -import { Injectable } from '@nestjs/common'; - -import { EntityManager } from 'typeorm'; - -import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; -import { CalendarChannelWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-channel.workspace-entity'; -import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record'; - -@Injectable() -export class CalendarChannelRepository { - constructor( - private readonly workspaceDataSourceService: WorkspaceDataSourceService, - ) {} - - public async getAll( - workspaceId: string, - transactionManager?: EntityManager, - ): Promise<ObjectRecord<CalendarChannelWorkspaceEntity>[]> { - const dataSourceSchema = - this.workspaceDataSourceService.getSchemaName(workspaceId); - - return await this.workspaceDataSourceService.executeRawQuery( - `SELECT * FROM ${dataSourceSchema}."calendarChannel"`, - [], - workspaceId, - transactionManager, - ); - } - - public async create( - calendarChannel: Pick< - ObjectRecord<CalendarChannelWorkspaceEntity>, - 'id' | 'connectedAccountId' | 'handle' | 'visibility' - >, - workspaceId: string, - transactionManager?: EntityManager, - ): Promise<void> { - const dataSourceSchema = - this.workspaceDataSourceService.getSchemaName(workspaceId); - - await this.workspaceDataSourceService.executeRawQuery( - `INSERT INTO ${dataSourceSchema}."calendarChannel" (id, "connectedAccountId", "handle", "visibility") VALUES ($1, $2, $3, $4)`, - [ - calendarChannel.id, - calendarChannel.connectedAccountId, - calendarChannel.handle, - calendarChannel.visibility, - ], - workspaceId, - transactionManager, - ); - } - - public async getByConnectedAccountId( - connectedAccountId: string, - workspaceId: string, - transactionManager?: EntityManager, - ): Promise<ObjectRecord<CalendarChannelWorkspaceEntity>[]> { - const dataSourceSchema = - this.workspaceDataSourceService.getSchemaName(workspaceId); - - return await this.workspaceDataSourceService.executeRawQuery( - `SELECT * FROM ${dataSourceSchema}."calendarChannel" WHERE "connectedAccountId" = $1 LIMIT 1`, - [connectedAccountId], - workspaceId, - transactionManager, - ); - } - - public async getFirstByConnectedAccountId( - connectedAccountId: string, - workspaceId: string, - ): Promise<ObjectRecord<CalendarChannelWorkspaceEntity> | undefined> { - const calendarChannels = await this.getByConnectedAccountId( - connectedAccountId, - workspaceId, - ); - - return calendarChannels[0]; - } - - public async getByIds( - ids: string[], - workspaceId: string, - transactionManager?: EntityManager, - ): Promise<ObjectRecord<CalendarChannelWorkspaceEntity>[]> { - const dataSourceSchema = - this.workspaceDataSourceService.getSchemaName(workspaceId); - - return await this.workspaceDataSourceService.executeRawQuery( - `SELECT * FROM ${dataSourceSchema}."calendarChannel" WHERE "id" = ANY($1)`, - [ids], - workspaceId, - transactionManager, - ); - } - - public async getIdsByWorkspaceMemberId( - workspaceMemberId: string, - workspaceId: string, - transactionManager?: EntityManager, - ): Promise<ObjectRecord<CalendarChannelWorkspaceEntity>[]> { - const dataSourceSchema = - this.workspaceDataSourceService.getSchemaName(workspaceId); - - const calendarChannelIds = - await this.workspaceDataSourceService.executeRawQuery( - `SELECT "calendarChannel".id FROM ${dataSourceSchema}."calendarChannel" "calendarChannel" - JOIN ${dataSourceSchema}."connectedAccount" ON "calendarChannel"."connectedAccountId" = ${dataSourceSchema}."connectedAccount"."id" - WHERE ${dataSourceSchema}."connectedAccount"."accountOwnerId" = $1`, - [workspaceMemberId], - workspaceId, - transactionManager, - ); - - return calendarChannelIds; - } - - public async updateSyncCursor( - syncCursor: string | null, - calendarChannelId: string, - workspaceId: string, - transactionManager?: EntityManager, - ): Promise<void> { - const dataSourceSchema = - this.workspaceDataSourceService.getSchemaName(workspaceId); - - await this.workspaceDataSourceService.executeRawQuery( - `UPDATE ${dataSourceSchema}."calendarChannel" SET "syncCursor" = $1 WHERE "id" = $2`, - [syncCursor || '', calendarChannelId], - workspaceId, - transactionManager, - ); - } -} diff --git a/packages/twenty-server/src/modules/calendar/repositories/calendar-event-participant.repository.ts b/packages/twenty-server/src/modules/calendar/repositories/calendar-event-participant.repository.ts deleted file mode 100644 index f095e100e7d0..000000000000 --- a/packages/twenty-server/src/modules/calendar/repositories/calendar-event-participant.repository.ts +++ /dev/null @@ -1,305 +0,0 @@ -import { Injectable } from '@nestjs/common'; - -import { EntityManager } from 'typeorm'; -import differenceWith from 'lodash.differencewith'; - -import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; -import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record'; -import { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-event-participant.workspace-entity'; -import { getFlattenedValuesAndValuesStringForBatchRawQuery } from 'src/modules/calendar/utils/get-flattened-values-and-values-string-for-batch-raw-query.util'; -import { - CalendarEventParticipant, - CalendarEventParticipantWithId, -} from 'src/modules/calendar/types/calendar-event'; - -@Injectable() -export class CalendarEventParticipantRepository { - constructor( - private readonly workspaceDataSourceService: WorkspaceDataSourceService, - ) {} - - public async getByHandles( - handles: string[], - workspaceId: string, - transactionManager?: EntityManager, - ): Promise<ObjectRecord<CalendarEventParticipantWorkspaceEntity>[]> { - const dataSourceSchema = - this.workspaceDataSourceService.getSchemaName(workspaceId); - - return await this.workspaceDataSourceService.executeRawQuery( - `SELECT * FROM ${dataSourceSchema}."calendarEventParticipant" WHERE "handle" = ANY($1)`, - [handles], - workspaceId, - transactionManager, - ); - } - - public async updateParticipantsPersonId( - participantIds: string[], - personId: string, - workspaceId: string, - transactionManager?: EntityManager, - ) { - const dataSourceSchema = - this.workspaceDataSourceService.getSchemaName(workspaceId); - - await this.workspaceDataSourceService.executeRawQuery( - `UPDATE ${dataSourceSchema}."calendarEventParticipant" SET "personId" = $1 WHERE "id" = ANY($2)`, - [personId, participantIds], - workspaceId, - transactionManager, - ); - } - - public async updateParticipantsPersonIdAndReturn( - participantIds: string[], - personId: string, - workspaceId: string, - transactionManager?: EntityManager, - ): Promise<ObjectRecord<CalendarEventParticipantWorkspaceEntity>[]> { - const dataSourceSchema = - this.workspaceDataSourceService.getSchemaName(workspaceId); - - return await this.workspaceDataSourceService.executeRawQuery( - `UPDATE ${dataSourceSchema}."calendarEventParticipant" SET "personId" = $1 WHERE "id" = ANY($2) RETURNING *`, - [personId, participantIds], - workspaceId, - transactionManager, - ); - } - - public async updateParticipantsWorkspaceMemberId( - participantIds: string[], - workspaceMemberId: string, - workspaceId: string, - transactionManager?: EntityManager, - ) { - const dataSourceSchema = - this.workspaceDataSourceService.getSchemaName(workspaceId); - - await this.workspaceDataSourceService.executeRawQuery( - `UPDATE ${dataSourceSchema}."calendarEventParticipant" SET "workspaceMemberId" = $1 WHERE "id" = ANY($2)`, - [workspaceMemberId, participantIds], - workspaceId, - transactionManager, - ); - } - - public async removePersonIdByHandle( - handle: string, - workspaceId: string, - transactionManager?: EntityManager, - ) { - const dataSourceSchema = - this.workspaceDataSourceService.getSchemaName(workspaceId); - - await this.workspaceDataSourceService.executeRawQuery( - `UPDATE ${dataSourceSchema}."calendarEventParticipant" SET "personId" = NULL WHERE "handle" = $1`, - [handle], - workspaceId, - transactionManager, - ); - } - - public async removeWorkspaceMemberIdByHandle( - handle: string, - workspaceId: string, - transactionManager?: EntityManager, - ) { - const dataSourceSchema = - this.workspaceDataSourceService.getSchemaName(workspaceId); - - await this.workspaceDataSourceService.executeRawQuery( - `UPDATE ${dataSourceSchema}."calendarEventParticipant" SET "workspaceMemberId" = NULL WHERE "handle" = $1`, - [handle], - workspaceId, - transactionManager, - ); - } - - public async getByIds( - calendarEventParticipantIds: string[], - workspaceId: string, - transactionManager?: EntityManager, - ): Promise<ObjectRecord<CalendarEventParticipantWorkspaceEntity>[]> { - if (calendarEventParticipantIds.length === 0) { - return []; - } - - const dataSourceSchema = - this.workspaceDataSourceService.getSchemaName(workspaceId); - - return await this.workspaceDataSourceService.executeRawQuery( - `SELECT * FROM ${dataSourceSchema}."calendarEventParticipant" WHERE "id" = ANY($1)`, - [calendarEventParticipantIds], - workspaceId, - transactionManager, - ); - } - - public async getByCalendarEventIds( - calendarEventIds: string[], - workspaceId: string, - transactionManager?: EntityManager, - ): Promise<ObjectRecord<CalendarEventParticipantWorkspaceEntity>[]> { - if (calendarEventIds.length === 0) { - return []; - } - - const dataSourceSchema = - this.workspaceDataSourceService.getSchemaName(workspaceId); - - return await this.workspaceDataSourceService.executeRawQuery( - `SELECT * FROM ${dataSourceSchema}."calendarEventParticipant" WHERE "calendarEventId" = ANY($1)`, - [calendarEventIds], - workspaceId, - transactionManager, - ); - } - - public async deleteByIds( - calendarEventParticipantIds: string[], - workspaceId: string, - transactionManager?: EntityManager, - ): Promise<void> { - if (calendarEventParticipantIds.length === 0) { - return; - } - - const dataSourceSchema = - this.workspaceDataSourceService.getSchemaName(workspaceId); - - await this.workspaceDataSourceService.executeRawQuery( - `DELETE FROM ${dataSourceSchema}."calendarEventParticipant" WHERE "id" = ANY($1)`, - [calendarEventParticipantIds], - workspaceId, - transactionManager, - ); - } - - public async updateCalendarEventParticipantsAndReturnNewOnes( - calendarEventParticipants: CalendarEventParticipant[], - workspaceId: string, - transactionManager?: EntityManager, - ): Promise<CalendarEventParticipant[]> { - if (calendarEventParticipants.length === 0) { - return []; - } - - const dataSourceSchema = - this.workspaceDataSourceService.getSchemaName(workspaceId); - - const existingCalendarEventParticipants = await this.getByCalendarEventIds( - calendarEventParticipants.map( - (calendarEventParticipant) => calendarEventParticipant.calendarEventId, - ), - workspaceId, - transactionManager, - ); - - const calendarEventParticipantsToDelete = differenceWith( - existingCalendarEventParticipants, - calendarEventParticipants, - (existingCalendarEventParticipant, calendarEventParticipant) => - existingCalendarEventParticipant.handle === - calendarEventParticipant.handle, - ); - - const newCalendarEventParticipants = differenceWith( - calendarEventParticipants, - existingCalendarEventParticipants, - (calendarEventParticipant, existingCalendarEventParticipant) => - calendarEventParticipant.handle === - existingCalendarEventParticipant.handle, - ); - - await this.deleteByIds( - calendarEventParticipantsToDelete.map( - (calendarEventParticipant) => calendarEventParticipant.id, - ), - workspaceId, - transactionManager, - ); - - const { flattenedValues, valuesString } = - getFlattenedValuesAndValuesStringForBatchRawQuery( - calendarEventParticipants, - { - calendarEventId: 'uuid', - handle: 'text', - displayName: 'text', - isOrganizer: 'boolean', - responseStatus: `${dataSourceSchema}."calendarEventParticipant_responseStatus_enum"`, - }, - ); - - await this.workspaceDataSourceService.executeRawQuery( - `UPDATE ${dataSourceSchema}."calendarEventParticipant" AS "calendarEventParticipant" - SET "displayName" = "newValues"."displayName", - "isOrganizer" = "newValues"."isOrganizer", - "responseStatus" = "newValues"."responseStatus" - FROM (VALUES ${valuesString}) AS "newValues"("calendarEventId", "handle", "displayName", "isOrganizer", "responseStatus") - WHERE "calendarEventParticipant"."handle" = "newValues"."handle" - AND "calendarEventParticipant"."calendarEventId" = "newValues"."calendarEventId"`, - flattenedValues, - workspaceId, - transactionManager, - ); - - return newCalendarEventParticipants; - } - - public async getWithoutPersonIdAndWorkspaceMemberId( - workspaceId: string, - transactionManager?: EntityManager, - ): Promise<CalendarEventParticipantWithId[]> { - if (!workspaceId) { - throw new Error('WorkspaceId is required'); - } - - const dataSourceSchema = - this.workspaceDataSourceService.getSchemaName(workspaceId); - - const calendarEventParticipants: CalendarEventParticipantWithId[] = - await this.workspaceDataSourceService.executeRawQuery( - `SELECT "calendarEventParticipant".* - FROM ${dataSourceSchema}."calendarEventParticipant" AS "calendarEventParticipant" - WHERE "calendarEventParticipant"."personId" IS NULL - AND "calendarEventParticipant"."workspaceMemberId" IS NULL`, - [], - workspaceId, - transactionManager, - ); - - return calendarEventParticipants; - } - - public async getByCalendarChannelIdWithoutPersonIdAndWorkspaceMemberId( - calendarChannelId: string, - workspaceId: string, - transactionManager?: EntityManager, - ): Promise<CalendarEventParticipantWithId[]> { - if (!workspaceId) { - throw new Error('WorkspaceId is required'); - } - - const dataSourceSchema = - this.workspaceDataSourceService.getSchemaName(workspaceId); - - const calendarEventParticipants: CalendarEventParticipantWithId[] = - await this.workspaceDataSourceService.executeRawQuery( - `SELECT "calendarEventParticipant".* - FROM ${dataSourceSchema}."calendarEventParticipant" AS "calendarEventParticipant" - LEFT JOIN ${dataSourceSchema}."calendarEvent" AS "calendarEvent" ON "calendarEventParticipant"."calendarEventId" = "calendarEvent"."id" - LEFT JOIN ${dataSourceSchema}."calendarChannelEventAssociation" AS "calendarChannelEventAssociation" ON "calendarEvent"."id" = "calendarChannelEventAssociation"."calendarEventId" - WHERE "calendarChannelEventAssociation"."calendarChannelId" = $1 - AND "calendarEventParticipant"."personId" IS NULL - AND "calendarEventParticipant"."workspaceMemberId" IS NULL`, - [calendarChannelId], - workspaceId, - transactionManager, - ); - - return calendarEventParticipants; - } -} diff --git a/packages/twenty-server/src/modules/calendar/repositories/calendar-event.repository.ts b/packages/twenty-server/src/modules/calendar/repositories/calendar-event.repository.ts deleted file mode 100644 index f6f28918dd1d..000000000000 --- a/packages/twenty-server/src/modules/calendar/repositories/calendar-event.repository.ts +++ /dev/null @@ -1,227 +0,0 @@ -import { Injectable } from '@nestjs/common'; - -import { EntityManager } from 'typeorm'; - -import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; -import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record'; -import { CalendarEventWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-event.workspace-entity'; -import { getFlattenedValuesAndValuesStringForBatchRawQuery } from 'src/modules/calendar/utils/get-flattened-values-and-values-string-for-batch-raw-query.util'; -import { CalendarEvent } from 'src/modules/calendar/types/calendar-event'; -import { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-event-participant.workspace-entity'; - -@Injectable() -export class CalendarEventRepository { - constructor( - private readonly workspaceDataSourceService: WorkspaceDataSourceService, - ) {} - - public async getByIds( - calendarEventIds: string[], - workspaceId: string, - transactionManager?: EntityManager, - ): Promise<ObjectRecord<CalendarEventWorkspaceEntity>[]> { - if (calendarEventIds.length === 0) { - return []; - } - - const dataSourceSchema = - this.workspaceDataSourceService.getSchemaName(workspaceId); - - return await this.workspaceDataSourceService.executeRawQuery( - `SELECT * FROM ${dataSourceSchema}."calendarEvent" WHERE "id" = ANY($1)`, - [calendarEventIds], - workspaceId, - transactionManager, - ); - } - - public async getByICalUIDs( - iCalUIDs: string[], - workspaceId: string, - transactionManager?: EntityManager, - ): Promise<ObjectRecord<CalendarEventWorkspaceEntity>[]> { - if (iCalUIDs.length === 0) { - return []; - } - - const dataSourceSchema = - this.workspaceDataSourceService.getSchemaName(workspaceId); - - return await this.workspaceDataSourceService.executeRawQuery( - `SELECT * FROM ${dataSourceSchema}."calendarEvent" WHERE "iCalUID" = ANY($1)`, - [iCalUIDs], - workspaceId, - transactionManager, - ); - } - - public async deleteByIds( - calendarEventIds: string[], - workspaceId: string, - transactionManager?: EntityManager, - ): Promise<void> { - if (calendarEventIds.length === 0) { - return; - } - - const dataSourceSchema = - this.workspaceDataSourceService.getSchemaName(workspaceId); - - await this.workspaceDataSourceService.executeRawQuery( - `DELETE FROM ${dataSourceSchema}."calendarEvent" WHERE "id" = ANY($1)`, - [calendarEventIds], - workspaceId, - transactionManager, - ); - } - - public async getNonAssociatedCalendarEventIdsPaginated( - limit: number, - offset: number, - workspaceId: string, - transactionManager?: EntityManager, - ): Promise<ObjectRecord<CalendarEventParticipantWorkspaceEntity>[]> { - const dataSourceSchema = - this.workspaceDataSourceService.getSchemaName(workspaceId); - - const nonAssociatedCalendarEvents = - await this.workspaceDataSourceService.executeRawQuery( - `SELECT m.id FROM ${dataSourceSchema}."calendarEvent" m - LEFT JOIN ${dataSourceSchema}."calendarChannelEventAssociation" ccea - ON m.id = ccea."calendarEventId" - WHERE ccea.id IS NULL - LIMIT $1 OFFSET $2`, - [limit, offset], - workspaceId, - transactionManager, - ); - - return nonAssociatedCalendarEvents.map(({ id }) => id); - } - - public async getICalUIDCalendarEventIdMap( - iCalUIDs: string[], - workspaceId: string, - transactionManager?: EntityManager, - ): Promise<Map<string, string>> { - if (iCalUIDs.length === 0) { - return new Map(); - } - - const dataSourceSchema = - this.workspaceDataSourceService.getSchemaName(workspaceId); - - const calendarEvents: - | { - id: string; - iCalUID: string; - }[] - | undefined = await this.workspaceDataSourceService.executeRawQuery( - `SELECT id, "iCalUID" FROM ${dataSourceSchema}."calendarEvent" WHERE "iCalUID" = ANY($1)`, - [iCalUIDs], - workspaceId, - transactionManager, - ); - - const iCalUIDsCalendarEventIdsMap = new Map<string, string>(); - - calendarEvents?.forEach((calendarEvent) => { - iCalUIDsCalendarEventIdsMap.set(calendarEvent.iCalUID, calendarEvent.id); - }); - - return iCalUIDsCalendarEventIdsMap; - } - - public async saveCalendarEvents( - calendarEvents: CalendarEvent[], - workspaceId: string, - transactionManager?: EntityManager, - ): Promise<void> { - if (calendarEvents.length === 0) { - return; - } - - const dataSourceSchema = - this.workspaceDataSourceService.getSchemaName(workspaceId); - - const { flattenedValues, valuesString } = - getFlattenedValuesAndValuesStringForBatchRawQuery(calendarEvents, { - id: 'uuid', - title: 'text', - isCanceled: 'boolean', - isFullDay: 'boolean', - startsAt: 'timestamptz', - endsAt: 'timestamptz', - externalCreatedAt: 'timestamptz', - externalUpdatedAt: 'timestamptz', - description: 'text', - location: 'text', - iCalUID: 'text', - conferenceSolution: 'text', - conferenceLinkLabel: 'text', - conferenceLinkUrl: 'text', - recurringEventExternalId: 'text', - }); - - await this.workspaceDataSourceService.executeRawQuery( - `INSERT INTO ${dataSourceSchema}."calendarEvent" ("id", "title", "isCanceled", "isFullDay", "startsAt", "endsAt", "externalCreatedAt", "externalUpdatedAt", "description", "location", "iCalUID", "conferenceSolution", "conferenceLinkLabel", "conferenceLinkUrl", "recurringEventExternalId") VALUES ${valuesString}`, - flattenedValues, - workspaceId, - transactionManager, - ); - } - - public async updateCalendarEvents( - calendarEvents: CalendarEvent[], - workspaceId: string, - transactionManager?: EntityManager, - ): Promise<void> { - if (calendarEvents.length === 0) { - return; - } - - const dataSourceSchema = - this.workspaceDataSourceService.getSchemaName(workspaceId); - - const { flattenedValues, valuesString } = - getFlattenedValuesAndValuesStringForBatchRawQuery(calendarEvents, { - title: 'text', - isCanceled: 'boolean', - isFullDay: 'boolean', - startsAt: 'timestamptz', - endsAt: 'timestamptz', - externalCreatedAt: 'timestamptz', - externalUpdatedAt: 'timestamptz', - description: 'text', - location: 'text', - iCalUID: 'text', - conferenceSolution: 'text', - conferenceLinkLabel: 'text', - conferenceLinkUrl: 'text', - recurringEventExternalId: 'text', - }); - - await this.workspaceDataSourceService.executeRawQuery( - `UPDATE ${dataSourceSchema}."calendarEvent" AS "calendarEvent" - SET "title" = "newData"."title", - "isCanceled" = "newData"."isCanceled", - "isFullDay" = "newData"."isFullDay", - "startsAt" = "newData"."startsAt", - "endsAt" = "newData"."endsAt", - "externalCreatedAt" = "newData"."externalCreatedAt", - "externalUpdatedAt" = "newData"."externalUpdatedAt", - "description" = "newData"."description", - "location" = "newData"."location", - "conferenceSolution" = "newData"."conferenceSolution", - "conferenceLinkLabel" = "newData"."conferenceLinkLabel", - "conferenceLinkUrl" = "newData"."conferenceLinkUrl", - "recurringEventExternalId" = "newData"."recurringEventExternalId" - FROM (VALUES ${valuesString}) - AS "newData"("title", "isCanceled", "isFullDay", "startsAt", "endsAt", "externalCreatedAt", "externalUpdatedAt", "description", "location", "iCalUID", "conferenceSolution", "conferenceLinkLabel", "conferenceLinkUrl", "recurringEventExternalId") - WHERE "calendarEvent"."iCalUID" = "newData"."iCalUID"`, - flattenedValues, - workspaceId, - transactionManager, - ); - } -} diff --git a/packages/twenty-server/src/modules/calendar/services/calendar-event-cleaner/calendar-event-cleaner.module.ts b/packages/twenty-server/src/modules/calendar/services/calendar-event-cleaner/calendar-event-cleaner.module.ts deleted file mode 100644 index 644371db16f6..000000000000 --- a/packages/twenty-server/src/modules/calendar/services/calendar-event-cleaner/calendar-event-cleaner.module.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Module } from '@nestjs/common'; - -import { ObjectMetadataRepositoryModule } from 'src/engine/object-metadata-repository/object-metadata-repository.module'; -import { CalendarEventCleanerService } from 'src/modules/calendar/services/calendar-event-cleaner/calendar-event-cleaner.service'; -import { CalendarEventWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-event.workspace-entity'; - -@Module({ - imports: [ - ObjectMetadataRepositoryModule.forFeature([CalendarEventWorkspaceEntity]), - ], - providers: [CalendarEventCleanerService], - exports: [CalendarEventCleanerService], -}) -export class CalendarEventCleanerModule {} diff --git a/packages/twenty-server/src/modules/calendar/services/calendar-event-cleaner/calendar-event-cleaner.service.ts b/packages/twenty-server/src/modules/calendar/services/calendar-event-cleaner/calendar-event-cleaner.service.ts deleted file mode 100644 index 9f3f5d520298..000000000000 --- a/packages/twenty-server/src/modules/calendar/services/calendar-event-cleaner/calendar-event-cleaner.service.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { Injectable } from '@nestjs/common'; - -import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; -import { CalendarEventRepository } from 'src/modules/calendar/repositories/calendar-event.repository'; -import { CalendarEventWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-event.workspace-entity'; -import { deleteUsingPagination } from 'src/modules/messaging/message-cleaner/utils/delete-using-pagination.util'; - -@Injectable() -export class CalendarEventCleanerService { - constructor( - @InjectObjectMetadataRepository(CalendarEventWorkspaceEntity) - private readonly calendarEventRepository: CalendarEventRepository, - ) {} - - public async cleanWorkspaceCalendarEvents(workspaceId: string) { - await deleteUsingPagination( - workspaceId, - 500, - this.calendarEventRepository.getNonAssociatedCalendarEventIdsPaginated.bind( - this.calendarEventRepository, - ), - this.calendarEventRepository.deleteByIds.bind( - this.calendarEventRepository, - ), - ); - } -} diff --git a/packages/twenty-server/src/modules/calendar/services/calendar-event-participant/calendar-event-participant.module.ts b/packages/twenty-server/src/modules/calendar/services/calendar-event-participant/calendar-event-participant.module.ts deleted file mode 100644 index 4eabeedb997a..000000000000 --- a/packages/twenty-server/src/modules/calendar/services/calendar-event-participant/calendar-event-participant.module.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Module } from '@nestjs/common'; - -import { ObjectMetadataRepositoryModule } from 'src/engine/object-metadata-repository/object-metadata-repository.module'; -import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; -import { AddPersonIdAndWorkspaceMemberIdModule } from 'src/modules/calendar-messaging-participant/services/add-person-id-and-workspace-member-id/add-person-id-and-workspace-member-id.module'; -import { CalendarEventParticipantService } from 'src/modules/calendar/services/calendar-event-participant/calendar-event-participant.service'; -import { PersonWorkspaceEntity } from 'src/modules/person/standard-objects/person.workspace-entity'; - -@Module({ - imports: [ - WorkspaceDataSourceModule, - ObjectMetadataRepositoryModule.forFeature([PersonWorkspaceEntity]), - AddPersonIdAndWorkspaceMemberIdModule, - ], - providers: [CalendarEventParticipantService], - exports: [CalendarEventParticipantService], -}) -export class CalendarEventParticipantModule {} diff --git a/packages/twenty-server/src/modules/calendar/services/calendar-event-participant/calendar-event-participant.service.ts b/packages/twenty-server/src/modules/calendar/services/calendar-event-participant/calendar-event-participant.service.ts deleted file mode 100644 index 4b524de0dedc..000000000000 --- a/packages/twenty-server/src/modules/calendar/services/calendar-event-participant/calendar-event-participant.service.ts +++ /dev/null @@ -1,185 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { EventEmitter2 } from '@nestjs/event-emitter'; - -import { EntityManager } from 'typeorm'; - -import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; -import { PersonRepository } from 'src/modules/person/repositories/person.repository'; -import { PersonWorkspaceEntity } from 'src/modules/person/standard-objects/person.workspace-entity'; -import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; -import { getFlattenedValuesAndValuesStringForBatchRawQuery } from 'src/modules/calendar/utils/get-flattened-values-and-values-string-for-batch-raw-query.util'; -import { CalendarEventParticipant } from 'src/modules/calendar/types/calendar-event'; -import { CalendarEventParticipantRepository } from 'src/modules/calendar/repositories/calendar-event-participant.repository'; -import { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-event-participant.workspace-entity'; -import { AddPersonIdAndWorkspaceMemberIdService } from 'src/modules/calendar-messaging-participant/services/add-person-id-and-workspace-member-id/add-person-id-and-workspace-member-id.service'; -import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record'; - -@Injectable() -export class CalendarEventParticipantService { - constructor( - private readonly workspaceDataSourceService: WorkspaceDataSourceService, - @InjectObjectMetadataRepository(CalendarEventParticipantWorkspaceEntity) - private readonly calendarEventParticipantRepository: CalendarEventParticipantRepository, - @InjectObjectMetadataRepository(PersonWorkspaceEntity) - private readonly personRepository: PersonRepository, - private readonly addPersonIdAndWorkspaceMemberIdService: AddPersonIdAndWorkspaceMemberIdService, - private readonly eventEmitter: EventEmitter2, - ) {} - - public async updateCalendarEventParticipantsAfterPeopleCreation( - createdPeople: ObjectRecord<PersonWorkspaceEntity>[], - workspaceId: string, - transactionManager?: EntityManager, - ): Promise<ObjectRecord<CalendarEventParticipantWorkspaceEntity>[]> { - const participants = - await this.calendarEventParticipantRepository.getByHandles( - createdPeople.map((person) => person.email), - workspaceId, - ); - - if (!participants) return []; - - const dataSourceSchema = - this.workspaceDataSourceService.getSchemaName(workspaceId); - - const handles = participants.map((participant) => participant.handle); - - const participantPersonIds = await this.personRepository.getByEmails( - handles, - workspaceId, - transactionManager, - ); - - const calendarEventParticipantsToUpdate = participants.map( - (participant) => ({ - id: participant.id, - personId: participantPersonIds.find( - (e: { id: string; email: string }) => e.email === participant.handle, - )?.id, - }), - ); - - if (calendarEventParticipantsToUpdate.length === 0) return []; - - const { flattenedValues, valuesString } = - getFlattenedValuesAndValuesStringForBatchRawQuery( - calendarEventParticipantsToUpdate, - { - id: 'uuid', - personId: 'uuid', - }, - ); - - return ( - await this.workspaceDataSourceService.executeRawQuery( - `UPDATE ${dataSourceSchema}."calendarEventParticipant" AS "calendarEventParticipant" SET "personId" = "data"."personId" - FROM (VALUES ${valuesString}) AS "data"("id", "personId") - WHERE "calendarEventParticipant"."id" = "data"."id" - RETURNING *`, - flattenedValues, - workspaceId, - transactionManager, - ) - ).flat(); - } - - public async saveCalendarEventParticipants( - calendarEventParticipants: CalendarEventParticipant[], - workspaceId: string, - transactionManager?: EntityManager, - ): Promise<ObjectRecord<CalendarEventParticipantWorkspaceEntity>[]> { - if (calendarEventParticipants.length === 0) { - return []; - } - - const dataSourceSchema = - this.workspaceDataSourceService.getSchemaName(workspaceId); - - const calendarEventParticipantsToSave = - await this.addPersonIdAndWorkspaceMemberIdService.addPersonIdAndWorkspaceMemberId( - calendarEventParticipants, - workspaceId, - transactionManager, - ); - - const { flattenedValues, valuesString } = - getFlattenedValuesAndValuesStringForBatchRawQuery( - calendarEventParticipantsToSave, - { - calendarEventId: 'uuid', - handle: 'text', - displayName: 'text', - isOrganizer: 'boolean', - responseStatus: `${dataSourceSchema}."calendarEventParticipant_responseStatus_enum"`, - personId: 'uuid', - workspaceMemberId: 'uuid', - }, - ); - - return await this.workspaceDataSourceService.executeRawQuery( - `INSERT INTO ${dataSourceSchema}."calendarEventParticipant" ("calendarEventId", "handle", "displayName", "isOrganizer", "responseStatus", "personId", "workspaceMemberId") VALUES ${valuesString} - RETURNING *`, - flattenedValues, - workspaceId, - transactionManager, - ); - } - - public async matchCalendarEventParticipants( - workspaceId: string, - email: string, - personId?: string, - workspaceMemberId?: string, - ) { - const calendarEventParticipantsToUpdate = - await this.calendarEventParticipantRepository.getByHandles( - [email], - workspaceId, - ); - - const calendarEventParticipantIdsToUpdate = - calendarEventParticipantsToUpdate.map((participant) => participant.id); - - if (personId) { - const updatedCalendarEventParticipants = - await this.calendarEventParticipantRepository.updateParticipantsPersonIdAndReturn( - calendarEventParticipantIdsToUpdate, - personId, - workspaceId, - ); - - this.eventEmitter.emit(`calendarEventParticipant.matched`, { - workspaceId, - userId: null, - calendarEventParticipants: updatedCalendarEventParticipants, - }); - } - if (workspaceMemberId) { - await this.calendarEventParticipantRepository.updateParticipantsWorkspaceMemberId( - calendarEventParticipantIdsToUpdate, - workspaceMemberId, - workspaceId, - ); - } - } - - public async unmatchCalendarEventParticipants( - workspaceId: string, - handle: string, - personId?: string, - workspaceMemberId?: string, - ) { - if (personId) { - await this.calendarEventParticipantRepository.removePersonIdByHandle( - handle, - workspaceId, - ); - } - if (workspaceMemberId) { - await this.calendarEventParticipantRepository.removeWorkspaceMemberIdByHandle( - handle, - workspaceId, - ); - } - } -} diff --git a/packages/twenty-server/src/modules/calendar/services/google-calendar-sync/google-calendar-sync.module.ts b/packages/twenty-server/src/modules/calendar/services/google-calendar-sync/google-calendar-sync.module.ts deleted file mode 100644 index fcd5e495ce19..000000000000 --- a/packages/twenty-server/src/modules/calendar/services/google-calendar-sync/google-calendar-sync.module.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { Module } from '@nestjs/common'; -import { TypeOrmModule } from '@nestjs/typeorm'; - -import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity'; -import { ObjectMetadataRepositoryModule } from 'src/engine/object-metadata-repository/object-metadata-repository.module'; -import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; -import { CalendarEventCleanerModule } from 'src/modules/calendar/services/calendar-event-cleaner/calendar-event-cleaner.module'; -import { CalendarEventParticipantModule } from 'src/modules/calendar/services/calendar-event-participant/calendar-event-participant.module'; -import { GoogleCalendarSyncService } from 'src/modules/calendar/services/google-calendar-sync/google-calendar-sync.service'; -import { CalendarProvidersModule } from 'src/modules/calendar/services/providers/calendar-providers.module'; -import { CalendarChannelEventAssociationWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-channel-event-association.workspace-entity'; -import { CalendarChannelWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-channel.workspace-entity'; -import { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-event-participant.workspace-entity'; -import { CalendarEventWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-event.workspace-entity'; -import { BlocklistWorkspaceEntity } from 'src/modules/connected-account/standard-objects/blocklist.workspace-entity'; -import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; -import { PersonWorkspaceEntity } from 'src/modules/person/standard-objects/person.workspace-entity'; -import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; - -@Module({ - imports: [ - CalendarProvidersModule, - ObjectMetadataRepositoryModule.forFeature([ - ConnectedAccountWorkspaceEntity, - CalendarEventWorkspaceEntity, - CalendarChannelWorkspaceEntity, - CalendarChannelEventAssociationWorkspaceEntity, - CalendarEventParticipantWorkspaceEntity, - BlocklistWorkspaceEntity, - PersonWorkspaceEntity, - WorkspaceMemberWorkspaceEntity, - ]), - CalendarEventParticipantModule, - TypeOrmModule.forFeature([FeatureFlagEntity], 'core'), - WorkspaceDataSourceModule, - CalendarEventCleanerModule, - ], - providers: [GoogleCalendarSyncService], - exports: [GoogleCalendarSyncService], -}) -export class GoogleCalendarSyncModule {} diff --git a/packages/twenty-server/src/modules/calendar/services/google-calendar-sync/google-calendar-sync.service.ts b/packages/twenty-server/src/modules/calendar/services/google-calendar-sync/google-calendar-sync.service.ts deleted file mode 100644 index d0c8663d86d4..000000000000 --- a/packages/twenty-server/src/modules/calendar/services/google-calendar-sync/google-calendar-sync.service.ts +++ /dev/null @@ -1,534 +0,0 @@ -import { Injectable, Logger } from '@nestjs/common'; -import { InjectRepository } from '@nestjs/typeorm'; -import { EventEmitter2 } from '@nestjs/event-emitter'; - -import { Repository } from 'typeorm'; -import { calendar_v3 as calendarV3 } from 'googleapis'; -import { GaxiosError } from 'gaxios'; - -import { ConnectedAccountRepository } from 'src/modules/connected-account/repositories/connected-account.repository'; -import { BlocklistRepository } from 'src/modules/connected-account/repositories/blocklist.repository'; -import { - FeatureFlagEntity, - FeatureFlagKeys, -} from 'src/engine/core-modules/feature-flag/feature-flag.entity'; -import { GoogleCalendarClientProvider } from 'src/modules/calendar/services/providers/google-calendar/google-calendar.provider'; -import { CalendarChannelEventAssociationRepository } from 'src/modules/calendar/repositories/calendar-channel-event-association.repository'; -import { CalendarChannelRepository } from 'src/modules/calendar/repositories/calendar-channel.repository'; -import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; -import { CalendarEventRepository } from 'src/modules/calendar/repositories/calendar-event.repository'; -import { formatGoogleCalendarEvent } from 'src/modules/calendar/utils/format-google-calendar-event.util'; -import { CalendarEventParticipantRepository } from 'src/modules/calendar/repositories/calendar-event-participant.repository'; -import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; -import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; -import { CalendarEventWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-event.workspace-entity'; -import { CalendarChannelWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-channel.workspace-entity'; -import { CalendarChannelEventAssociationWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-channel-event-association.workspace-entity'; -import { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-event-participant.workspace-entity'; -import { BlocklistWorkspaceEntity } from 'src/modules/connected-account/standard-objects/blocklist.workspace-entity'; -import { CalendarEventCleanerService } from 'src/modules/calendar/services/calendar-event-cleaner/calendar-event-cleaner.service'; -import { CalendarEventParticipantService } from 'src/modules/calendar/services/calendar-event-participant/calendar-event-participant.service'; -import { CalendarEventWithParticipants } from 'src/modules/calendar/types/calendar-event'; -import { filterOutBlocklistedEvents } from 'src/modules/calendar/utils/filter-out-blocklisted-events.util'; -import { InjectMessageQueue } from 'src/engine/integrations/message-queue/decorators/message-queue.decorator'; -import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; -import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service'; -import { - CreateCompanyAndContactJob, - CreateCompanyAndContactJobData, -} from 'src/modules/connected-account/auto-companies-and-contacts-creation/jobs/create-company-and-contact.job'; -import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record'; - -@Injectable() -export class GoogleCalendarSyncService { - private readonly logger = new Logger(GoogleCalendarSyncService.name); - - constructor( - private readonly googleCalendarClientProvider: GoogleCalendarClientProvider, - @InjectObjectMetadataRepository(ConnectedAccountWorkspaceEntity) - private readonly connectedAccountRepository: ConnectedAccountRepository, - @InjectObjectMetadataRepository(CalendarEventWorkspaceEntity) - private readonly calendarEventRepository: CalendarEventRepository, - @InjectObjectMetadataRepository(CalendarChannelWorkspaceEntity) - private readonly calendarChannelRepository: CalendarChannelRepository, - @InjectObjectMetadataRepository( - CalendarChannelEventAssociationWorkspaceEntity, - ) - private readonly calendarChannelEventAssociationRepository: CalendarChannelEventAssociationRepository, - @InjectObjectMetadataRepository(CalendarEventParticipantWorkspaceEntity) - private readonly calendarEventParticipantsRepository: CalendarEventParticipantRepository, - @InjectObjectMetadataRepository(BlocklistWorkspaceEntity) - private readonly blocklistRepository: BlocklistRepository, - @InjectRepository(FeatureFlagEntity, 'core') - private readonly featureFlagRepository: Repository<FeatureFlagEntity>, - private readonly workspaceDataSourceService: WorkspaceDataSourceService, - private readonly calendarEventCleanerService: CalendarEventCleanerService, - private readonly calendarEventParticipantsService: CalendarEventParticipantService, - @InjectMessageQueue(MessageQueue.emailQueue) - private readonly messageQueueService: MessageQueueService, - private readonly eventEmitter: EventEmitter2, - ) {} - - public async startGoogleCalendarSync( - workspaceId: string, - connectedAccountId: string, - emailOrDomainToReimport?: string, - ): Promise<void> { - const connectedAccount = await this.connectedAccountRepository.getById( - connectedAccountId, - workspaceId, - ); - - if (!connectedAccount) { - return; - } - - const refreshToken = connectedAccount.refreshToken; - const workspaceMemberId = connectedAccount.accountOwnerId; - - if (!refreshToken) { - throw new Error( - `No refresh token found for connected account ${connectedAccountId} in workspace ${workspaceId} during sync`, - ); - } - - const calendarChannel = - await this.calendarChannelRepository.getFirstByConnectedAccountId( - connectedAccountId, - workspaceId, - ); - - const syncToken = calendarChannel?.syncCursor || undefined; - - if (!calendarChannel) { - return; - } - - const calendarChannelId = calendarChannel.id; - - const { events, nextSyncToken } = await this.getEventsFromGoogleCalendar( - refreshToken, - workspaceId, - connectedAccountId, - emailOrDomainToReimport, - syncToken, - ); - - if (!events || events?.length === 0) { - this.logger.log( - `google calendar sync for workspace ${workspaceId} and account ${connectedAccountId} done with nothing to import.`, - ); - - return; - } - - const blocklist = await this.getBlocklist(workspaceMemberId, workspaceId); - - let filteredEvents = filterOutBlocklistedEvents( - calendarChannel.handle, - events, - blocklist, - ).filter((event) => event.status !== 'cancelled'); - - if (emailOrDomainToReimport) { - filteredEvents = filteredEvents.filter( - (event) => - event.attendees?.some( - (attendee) => attendee.email?.endsWith(emailOrDomainToReimport), - ), - ); - } - - const cancelledEventExternalIds = filteredEvents - .filter((event) => event.status === 'cancelled') - .map((event) => event.id as string); - - const iCalUIDCalendarEventIdMap = - await this.calendarEventRepository.getICalUIDCalendarEventIdMap( - filteredEvents.map((calendarEvent) => calendarEvent.iCalUID as string), - workspaceId, - ); - - const formattedEvents = filteredEvents.map((event) => - formatGoogleCalendarEvent(event, iCalUIDCalendarEventIdMap), - ); - - // TODO: When we will be able to add unicity contraint on iCalUID, we will do a INSERT ON CONFLICT DO UPDATE - - let startTime = Date.now(); - - const existingEvents = await this.calendarEventRepository.getByICalUIDs( - formattedEvents.map((event) => event.iCalUID), - workspaceId, - ); - - const existingEventsICalUIDs = existingEvents.map((event) => event.iCalUID); - - let endTime = Date.now(); - - const eventsToSave = formattedEvents.filter( - (event) => !existingEventsICalUIDs.includes(event.iCalUID), - ); - - const eventsToUpdate = formattedEvents.filter((event) => - existingEventsICalUIDs.includes(event.iCalUID), - ); - - startTime = Date.now(); - - const existingCalendarChannelEventAssociations = - await this.calendarChannelEventAssociationRepository.getByEventExternalIdsAndCalendarChannelId( - formattedEvents.map((event) => event.externalId), - calendarChannelId, - workspaceId, - ); - - endTime = Date.now(); - - this.logger.log( - `google calendar sync for workspace ${workspaceId} and account ${connectedAccountId}: getting existing calendar channel event associations in ${ - endTime - startTime - }ms.`, - ); - - const calendarChannelEventAssociationsToSave = formattedEvents - .filter( - (event) => - !existingCalendarChannelEventAssociations.some( - (association) => association.eventExternalId === event.id, - ), - ) - .map((event) => ({ - calendarEventId: event.id, - eventExternalId: event.externalId, - calendarChannelId, - })); - - if (events.length > 0) { - await this.saveGoogleCalendarEvents( - eventsToSave, - eventsToUpdate, - calendarChannelEventAssociationsToSave, - connectedAccount, - calendarChannel, - workspaceId, - ); - - startTime = Date.now(); - - await this.calendarChannelEventAssociationRepository.deleteByEventExternalIdsAndCalendarChannelId( - cancelledEventExternalIds, - calendarChannelId, - workspaceId, - ); - - endTime = Date.now(); - - this.logger.log( - `google calendar sync for workspace ${workspaceId} and account ${connectedAccountId}: deleting calendar channel event associations in ${ - endTime - startTime - }ms.`, - ); - - startTime = Date.now(); - - await this.calendarEventCleanerService.cleanWorkspaceCalendarEvents( - workspaceId, - ); - - endTime = Date.now(); - - this.logger.log( - `google calendar sync for workspace ${workspaceId} and account ${connectedAccountId}: cleaning calendar events in ${ - endTime - startTime - }ms.`, - ); - } else { - this.logger.log( - `google calendar sync for workspace ${workspaceId} and account ${connectedAccountId} done with nothing to import.`, - ); - } - - if (!nextSyncToken) { - throw new Error( - `No next sync token found for connected account ${connectedAccountId} in workspace ${workspaceId} during sync`, - ); - } - - startTime = Date.now(); - - await this.calendarChannelRepository.updateSyncCursor( - nextSyncToken, - calendarChannel.id, - workspaceId, - ); - - endTime = Date.now(); - - this.logger.log( - `google calendar sync for workspace ${workspaceId} and account ${connectedAccountId}: updating sync cursor in ${ - endTime - startTime - }ms.`, - ); - - this.logger.log( - `google calendar sync for workspace ${workspaceId} and account ${connectedAccountId} ${ - syncToken ? `and ${syncToken} syncToken ` : '' - }done.`, - ); - } - - public async getBlocklist(workspaceMemberId: string, workspaceId: string) { - const isBlocklistEnabledFeatureFlag = - await this.featureFlagRepository.findOneBy({ - workspaceId, - key: FeatureFlagKeys.IsBlocklistEnabled, - value: true, - }); - - const isBlocklistEnabled = - isBlocklistEnabledFeatureFlag && isBlocklistEnabledFeatureFlag.value; - - const blocklist = isBlocklistEnabled - ? await this.blocklistRepository.getByWorkspaceMemberId( - workspaceMemberId, - workspaceId, - ) - : []; - - return blocklist.map((blocklist) => blocklist.handle); - } - - public async getEventsFromGoogleCalendar( - refreshToken: string, - workspaceId: string, - connectedAccountId: string, - emailOrDomainToReimport?: string, - syncToken?: string, - ): Promise<{ - events: calendarV3.Schema$Event[]; - nextSyncToken: string | null | undefined; - }> { - const googleCalendarClient = - await this.googleCalendarClientProvider.getGoogleCalendarClient( - refreshToken, - ); - - const startTime = Date.now(); - - let nextSyncToken: string | null | undefined; - let nextPageToken: string | undefined; - const events: calendarV3.Schema$Event[] = []; - - let hasMoreEvents = true; - - while (hasMoreEvents) { - const googleCalendarEvents = await googleCalendarClient.events - .list({ - calendarId: 'primary', - maxResults: 500, - syncToken: emailOrDomainToReimport ? undefined : syncToken, - pageToken: nextPageToken, - q: emailOrDomainToReimport, - showDeleted: true, - }) - .catch(async (error: GaxiosError) => { - if (error.response?.status !== 410) { - throw error; - } - - await this.calendarChannelRepository.updateSyncCursor( - null, - connectedAccountId, - workspaceId, - ); - - this.logger.log( - `Sync token is no longer valid for connected account ${connectedAccountId} in workspace ${workspaceId}, resetting sync cursor.`, - ); - - return { - data: { - items: [], - nextSyncToken: undefined, - nextPageToken: undefined, - }, - }; - }); - - nextSyncToken = googleCalendarEvents.data.nextSyncToken; - nextPageToken = googleCalendarEvents.data.nextPageToken || undefined; - - const { items } = googleCalendarEvents.data; - - if (!items || items.length === 0) { - break; - } - - events.push(...items); - - if (!nextPageToken) { - hasMoreEvents = false; - } - } - - const endTime = Date.now(); - - this.logger.log( - `google calendar sync for workspace ${workspaceId} and account ${connectedAccountId} getting events list in ${ - endTime - startTime - }ms.`, - ); - - return { events, nextSyncToken }; - } - - public async saveGoogleCalendarEvents( - eventsToSave: CalendarEventWithParticipants[], - eventsToUpdate: CalendarEventWithParticipants[], - calendarChannelEventAssociationsToSave: { - calendarEventId: string; - eventExternalId: string; - calendarChannelId: string; - }[], - connectedAccount: ObjectRecord<ConnectedAccountWorkspaceEntity>, - calendarChannel: CalendarChannelWorkspaceEntity, - workspaceId: string, - ): Promise<void> { - const dataSourceMetadata = - await this.workspaceDataSourceService.connectToWorkspaceDataSource( - workspaceId, - ); - - const participantsToSave = eventsToSave.flatMap( - (event) => event.participants, - ); - - const participantsToUpdate = eventsToUpdate.flatMap( - (event) => event.participants, - ); - - let startTime: number; - let endTime: number; - - const savedCalendarEventParticipantsToEmit: ObjectRecord<CalendarEventParticipantWorkspaceEntity>[] = - []; - - try { - await dataSourceMetadata?.transaction(async (transactionManager) => { - startTime = Date.now(); - - await this.calendarEventRepository.saveCalendarEvents( - eventsToSave, - workspaceId, - transactionManager, - ); - - endTime = Date.now(); - - this.logger.log( - `google calendar sync for workspace ${workspaceId} and account ${ - connectedAccount.id - }: saving ${eventsToSave.length} events in ${endTime - startTime}ms.`, - ); - - startTime = Date.now(); - - await this.calendarEventRepository.updateCalendarEvents( - eventsToUpdate, - workspaceId, - transactionManager, - ); - - endTime = Date.now(); - - this.logger.log( - `google calendar sync for workspace ${workspaceId} and account ${ - connectedAccount.id - }: updating ${eventsToUpdate.length} events in ${ - endTime - startTime - }ms.`, - ); - - startTime = Date.now(); - - await this.calendarChannelEventAssociationRepository.saveCalendarChannelEventAssociations( - calendarChannelEventAssociationsToSave, - workspaceId, - transactionManager, - ); - - endTime = Date.now(); - - this.logger.log( - `google calendar sync for workspace ${workspaceId} and account ${ - connectedAccount.id - }: saving calendar channel event associations in ${ - endTime - startTime - }ms.`, - ); - - startTime = Date.now(); - - const newCalendarEventParticipants = - await this.calendarEventParticipantsRepository.updateCalendarEventParticipantsAndReturnNewOnes( - participantsToUpdate, - workspaceId, - transactionManager, - ); - - endTime = Date.now(); - - participantsToSave.push(...newCalendarEventParticipants); - - this.logger.log( - `google calendar sync for workspace ${workspaceId} and account ${ - connectedAccount.id - }: updating participants in ${endTime - startTime}ms.`, - ); - - startTime = Date.now(); - - const savedCalendarEventParticipants = - await this.calendarEventParticipantsService.saveCalendarEventParticipants( - participantsToSave, - workspaceId, - transactionManager, - ); - - savedCalendarEventParticipantsToEmit.push( - ...savedCalendarEventParticipants, - ); - - endTime = Date.now(); - - this.logger.log( - `google calendar sync for workspace ${workspaceId} and account ${ - connectedAccount.id - }: saving participants in ${endTime - startTime}ms.`, - ); - }); - - this.eventEmitter.emit(`calendarEventParticipant.matched`, { - workspaceId, - userId: connectedAccount.accountOwnerId, - calendarEventParticipants: savedCalendarEventParticipantsToEmit, - }); - - if (calendarChannel.isContactAutoCreationEnabled) { - await this.messageQueueService.add<CreateCompanyAndContactJobData>( - CreateCompanyAndContactJob.name, - { - workspaceId, - connectedAccount, - contactsToCreate: participantsToSave, - }, - ); - } - } catch (error) { - this.logger.error( - `Error during google calendar sync for workspace ${workspaceId} and account ${connectedAccount.id}: ${error.message}`, - ); - } - } -} diff --git a/packages/twenty-server/src/modules/calendar/services/providers/calendar-providers.module.ts b/packages/twenty-server/src/modules/calendar/services/providers/calendar-providers.module.ts deleted file mode 100644 index 67f8064f7adf..000000000000 --- a/packages/twenty-server/src/modules/calendar/services/providers/calendar-providers.module.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Module } from '@nestjs/common'; - -import { EnvironmentModule } from 'src/engine/integrations/environment/environment.module'; -import { GoogleCalendarClientProvider } from 'src/modules/calendar/services/providers/google-calendar/google-calendar.provider'; - -@Module({ - imports: [EnvironmentModule], - providers: [GoogleCalendarClientProvider], - exports: [GoogleCalendarClientProvider], -}) -export class CalendarProvidersModule {} diff --git a/packages/twenty-server/src/modules/calendar/services/providers/google-calendar/google-calendar.provider.ts b/packages/twenty-server/src/modules/calendar/services/providers/google-calendar/google-calendar.provider.ts deleted file mode 100644 index 6e2faa04e613..000000000000 --- a/packages/twenty-server/src/modules/calendar/services/providers/google-calendar/google-calendar.provider.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { Injectable } from '@nestjs/common'; - -import { OAuth2Client } from 'google-auth-library'; -import { calendar_v3 as calendarV3, google } from 'googleapis'; - -import { EnvironmentService } from 'src/engine/integrations/environment/environment.service'; - -@Injectable() -export class GoogleCalendarClientProvider { - constructor(private readonly environmentService: EnvironmentService) {} - - public async getGoogleCalendarClient( - refreshToken: string, - ): Promise<calendarV3.Calendar> { - const oAuth2Client = await this.getOAuth2Client(refreshToken); - - const googleCalendarClient = google.calendar({ - version: 'v3', - auth: oAuth2Client, - }); - - return googleCalendarClient; - } - - private async getOAuth2Client(refreshToken: string): Promise<OAuth2Client> { - const googleCalendarClientId = this.environmentService.get( - 'AUTH_GOOGLE_CLIENT_ID', - ); - const googleCalendarClientSecret = this.environmentService.get( - 'AUTH_GOOGLE_CLIENT_SECRET', - ); - - const oAuth2Client = new google.auth.OAuth2( - googleCalendarClientId, - googleCalendarClientSecret, - ); - - oAuth2Client.setCredentials({ - refresh_token: refreshToken, - }); - - return oAuth2Client; - } -} diff --git a/packages/twenty-server/src/modules/calendar/services/workspace-google-calendar-sync/workspace-google-calendar-sync.module.ts b/packages/twenty-server/src/modules/calendar/services/workspace-google-calendar-sync/workspace-google-calendar-sync.module.ts deleted file mode 100644 index 877de36e89d5..000000000000 --- a/packages/twenty-server/src/modules/calendar/services/workspace-google-calendar-sync/workspace-google-calendar-sync.module.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Module } from '@nestjs/common'; - -import { ObjectMetadataRepositoryModule } from 'src/engine/object-metadata-repository/object-metadata-repository.module'; -import { WorkspaceGoogleCalendarSyncService } from 'src/modules/calendar/services/workspace-google-calendar-sync/workspace-google-calendar-sync.service'; -import { CalendarChannelWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-channel.workspace-entity'; - -@Module({ - imports: [ - ObjectMetadataRepositoryModule.forFeature([CalendarChannelWorkspaceEntity]), - ], - providers: [WorkspaceGoogleCalendarSyncService], - exports: [WorkspaceGoogleCalendarSyncService], -}) -export class WorkspaceGoogleCalendarSyncModule {} diff --git a/packages/twenty-server/src/modules/calendar/services/workspace-google-calendar-sync/workspace-google-calendar-sync.service.ts b/packages/twenty-server/src/modules/calendar/services/workspace-google-calendar-sync/workspace-google-calendar-sync.service.ts deleted file mode 100644 index 8d68c01d88c8..000000000000 --- a/packages/twenty-server/src/modules/calendar/services/workspace-google-calendar-sync/workspace-google-calendar-sync.service.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { Injectable } from '@nestjs/common'; - -import { InjectMessageQueue } from 'src/engine/integrations/message-queue/decorators/message-queue.decorator'; -import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; -import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service'; -import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; -import { - GoogleCalendarSyncJobData, - GoogleCalendarSyncJob, -} from 'src/modules/calendar/jobs/google-calendar-sync.job'; -import { CalendarChannelRepository } from 'src/modules/calendar/repositories/calendar-channel.repository'; -import { CalendarChannelWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-channel.workspace-entity'; - -@Injectable() -export class WorkspaceGoogleCalendarSyncService { - constructor( - @InjectObjectMetadataRepository(CalendarChannelWorkspaceEntity) - private readonly calendarChannelRepository: CalendarChannelRepository, - @InjectMessageQueue(MessageQueue.calendarQueue) - private readonly messageQueueService: MessageQueueService, - ) {} - - public async startWorkspaceGoogleCalendarSync( - workspaceId: string, - ): Promise<void> { - const calendarChannels = - await this.calendarChannelRepository.getAll(workspaceId); - - for (const calendarChannel of calendarChannels) { - if (!calendarChannel?.isSyncEnabled) { - continue; - } - - await this.messageQueueService.add<GoogleCalendarSyncJobData>( - GoogleCalendarSyncJob.name, - { - workspaceId, - connectedAccountId: calendarChannel.connectedAccountId, - }, - { - retryLimit: 2, - }, - ); - } - } -} diff --git a/packages/twenty-server/src/modules/calendar/standard-objects/calendar-channel.workspace-entity.ts b/packages/twenty-server/src/modules/calendar/standard-objects/calendar-channel.workspace-entity.ts deleted file mode 100644 index 85aed3b43c9e..000000000000 --- a/packages/twenty-server/src/modules/calendar/standard-objects/calendar-channel.workspace-entity.ts +++ /dev/null @@ -1,134 +0,0 @@ -import { Relation } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/relation.interface'; - -import { - RelationMetadataType, - RelationOnDeleteAction, -} from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity'; -import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; -import { CALENDAR_CHANNEL_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids'; -import { STANDARD_OBJECT_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-object-ids'; -import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; -import { CalendarChannelEventAssociationWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-channel-event-association.workspace-entity'; -import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity'; -import { WorkspaceEntity } from 'src/engine/twenty-orm/decorators/workspace-entity.decorator'; -import { WorkspaceIsSystem } from 'src/engine/twenty-orm/decorators/workspace-is-system.decorator'; -import { WorkspaceIsNotAuditLogged } from 'src/engine/twenty-orm/decorators/workspace-is-not-audit-logged.decorator'; -import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field.decorator'; -import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator'; - -export enum CalendarChannelVisibility { - METADATA = 'METADATA', - SHARE_EVERYTHING = 'SHARE_EVERYTHING', -} - -@WorkspaceEntity({ - standardId: STANDARD_OBJECT_IDS.calendarChannel, - namePlural: 'calendarChannels', - labelSingular: 'Calendar Channel', - labelPlural: 'Calendar Channels', - description: 'Calendar Channels', - icon: 'IconCalendar', -}) -@WorkspaceIsSystem() -@WorkspaceIsNotAuditLogged() -export class CalendarChannelWorkspaceEntity extends BaseWorkspaceEntity { - @WorkspaceField({ - standardId: CALENDAR_CHANNEL_STANDARD_FIELD_IDS.handle, - type: FieldMetadataType.TEXT, - label: 'Handle', - description: 'Handle', - icon: 'IconAt', - }) - handle: string; - - @WorkspaceField({ - standardId: CALENDAR_CHANNEL_STANDARD_FIELD_IDS.visibility, - type: FieldMetadataType.SELECT, - label: 'Visibility', - description: 'Visibility', - icon: 'IconEyeglass', - options: [ - { - value: CalendarChannelVisibility.METADATA, - label: 'Metadata', - position: 0, - color: 'green', - }, - { - value: CalendarChannelVisibility.SHARE_EVERYTHING, - label: 'Share Everything', - position: 1, - color: 'orange', - }, - ], - defaultValue: `'${CalendarChannelVisibility.SHARE_EVERYTHING}'`, - }) - visibility: string; - - @WorkspaceField({ - standardId: - CALENDAR_CHANNEL_STANDARD_FIELD_IDS.isContactAutoCreationEnabled, - type: FieldMetadataType.BOOLEAN, - label: 'Is Contact Auto Creation Enabled', - description: 'Is Contact Auto Creation Enabled', - icon: 'IconUserCircle', - defaultValue: true, - }) - isContactAutoCreationEnabled: boolean; - - @WorkspaceField({ - standardId: CALENDAR_CHANNEL_STANDARD_FIELD_IDS.isSyncEnabled, - type: FieldMetadataType.BOOLEAN, - label: 'Is Sync Enabled', - description: 'Is Sync Enabled', - icon: 'IconRefresh', - defaultValue: true, - }) - isSyncEnabled: boolean; - - @WorkspaceField({ - standardId: CALENDAR_CHANNEL_STANDARD_FIELD_IDS.syncCursor, - type: FieldMetadataType.TEXT, - label: 'Sync Cursor', - description: - 'Sync Cursor. Used for syncing events from the calendar provider', - icon: 'IconReload', - }) - syncCursor: string; - - @WorkspaceField({ - standardId: CALENDAR_CHANNEL_STANDARD_FIELD_IDS.throttleFailureCount, - type: FieldMetadataType.NUMBER, - label: 'Throttle Failure Count', - description: 'Throttle Failure Count', - icon: 'IconX', - defaultValue: 0, - }) - throttleFailureCount: number; - - @WorkspaceRelation({ - standardId: CALENDAR_CHANNEL_STANDARD_FIELD_IDS.connectedAccount, - type: RelationMetadataType.MANY_TO_ONE, - label: 'Connected Account', - description: 'Connected Account', - icon: 'IconUserCircle', - joinColumn: 'connectedAccountId', - inverseSideTarget: () => ConnectedAccountWorkspaceEntity, - inverseSideFieldKey: 'calendarChannels', - }) - connectedAccount: Relation<ConnectedAccountWorkspaceEntity>; - - @WorkspaceRelation({ - standardId: - CALENDAR_CHANNEL_STANDARD_FIELD_IDS.calendarChannelEventAssociations, - type: RelationMetadataType.ONE_TO_MANY, - label: 'Calendar Channel Event Associations', - description: 'Calendar Channel Event Associations', - icon: 'IconCalendar', - inverseSideTarget: () => CalendarChannelEventAssociationWorkspaceEntity, - onDelete: RelationOnDeleteAction.CASCADE, - }) - calendarChannelEventAssociations: Relation< - CalendarChannelEventAssociationWorkspaceEntity[] - >; -} diff --git a/packages/twenty-server/src/modules/calendar/utils/filter-out-blocklisted-events.util.ts b/packages/twenty-server/src/modules/calendar/utils/filter-out-blocklisted-events.util.ts deleted file mode 100644 index 067e49ea5020..000000000000 --- a/packages/twenty-server/src/modules/calendar/utils/filter-out-blocklisted-events.util.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { calendar_v3 as calendarV3 } from 'googleapis'; - -import { isEmailBlocklisted } from 'src/modules/calendar-messaging-participant/utils/is-email-blocklisted.util'; - -export const filterOutBlocklistedEvents = ( - calendarChannelHandle: string, - events: calendarV3.Schema$Event[], - blocklist: string[], -) => { - return events.filter((event) => { - if (!event.attendees) { - return true; - } - - return event.attendees.every( - (attendee) => - !isEmailBlocklisted(calendarChannelHandle, attendee.email, blocklist), - ); - }); -}; diff --git a/packages/twenty-server/src/modules/calendar/utils/google-calendar-search-filter.util.ts b/packages/twenty-server/src/modules/calendar/utils/google-calendar-search-filter.util.ts deleted file mode 100644 index e9dc788d9f92..000000000000 --- a/packages/twenty-server/src/modules/calendar/utils/google-calendar-search-filter.util.ts +++ /dev/null @@ -1,9 +0,0 @@ -export const googleCalendarSearchFilterExcludeEmails = ( - emails: string[], -): string | undefined => { - if (emails.length === 0) { - return undefined; - } - - return `-(${emails.join(', ')})`; -}; diff --git a/packages/twenty-server/src/modules/company/repositories/company.repository.ts b/packages/twenty-server/src/modules/company/repositories/company.repository.ts index 716a7a5bc95e..471db67709ae 100644 --- a/packages/twenty-server/src/modules/company/repositories/company.repository.ts +++ b/packages/twenty-server/src/modules/company/repositories/company.repository.ts @@ -67,7 +67,7 @@ export class CompanyRepository { ); await this.workspaceDataSourceService.executeRawQuery( - `INSERT INTO ${dataSourceSchema}.company (id, "domainName", name, address, position) + `INSERT INTO ${dataSourceSchema}.company (id, "domainName", name, "addressAddressCity", position) VALUES ($1, $2, $3, $4, $5)`, [ companyToCreate.id, diff --git a/packages/twenty-server/src/modules/company/standard-objects/company.workspace-entity.ts b/packages/twenty-server/src/modules/company/standard-objects/company.workspace-entity.ts index 867b11e023e9..8f2d68f5dcee 100644 --- a/packages/twenty-server/src/modules/company/standard-objects/company.workspace-entity.ts +++ b/packages/twenty-server/src/modules/company/standard-objects/company.workspace-entity.ts @@ -1,3 +1,5 @@ +import { Address } from 'nodemailer/lib/mailer'; + import { Relation } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/relation.interface'; import { CurrencyMetadata } from 'src/engine/metadata-modules/field-metadata/composite-types/currency.composite-type'; @@ -7,6 +9,14 @@ import { RelationMetadataType, RelationOnDeleteAction, } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity'; +import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity'; +import { WorkspaceEntity } from 'src/engine/twenty-orm/decorators/workspace-entity.decorator'; +import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field.decorator'; +import { WorkspaceIsDeprecated } from 'src/engine/twenty-orm/decorators/workspace-is-deprecated.decorator'; +import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator'; +import { WorkspaceIsSystem } from 'src/engine/twenty-orm/decorators/workspace-is-system.decorator'; +import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator'; +import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator'; import { COMPANY_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids'; import { STANDARD_OBJECT_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-object-ids'; import { ActivityTargetWorkspaceEntity } from 'src/modules/activity/standard-objects/activity-target.workspace-entity'; @@ -14,14 +24,8 @@ import { AttachmentWorkspaceEntity } from 'src/modules/attachment/standard-objec import { FavoriteWorkspaceEntity } from 'src/modules/favorite/standard-objects/favorite.workspace-entity'; import { OpportunityWorkspaceEntity } from 'src/modules/opportunity/standard-objects/opportunity.workspace-entity'; import { PersonWorkspaceEntity } from 'src/modules/person/standard-objects/person.workspace-entity'; -import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; import { TimelineActivityWorkspaceEntity } from 'src/modules/timeline/standard-objects/timeline-activity.workspace-entity'; -import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity'; -import { WorkspaceEntity } from 'src/engine/twenty-orm/decorators/workspace-entity.decorator'; -import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field.decorator'; -import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator'; -import { WorkspaceIsSystem } from 'src/engine/twenty-orm/decorators/workspace-is-system.decorator'; -import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator'; +import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; @WorkspaceEntity({ standardId: STANDARD_OBJECT_IDS.company, @@ -51,15 +55,6 @@ export class CompanyWorkspaceEntity extends BaseWorkspaceEntity { }) domainName?: string; - @WorkspaceField({ - standardId: COMPANY_STANDARD_FIELD_IDS.address, - type: FieldMetadataType.TEXT, - label: 'Address', - description: 'The company address', - icon: 'IconMap', - }) - address: string; - @WorkspaceField({ standardId: COMPANY_STANDARD_FIELD_IDS.employees, type: FieldMetadataType.NUMBER, @@ -68,7 +63,7 @@ export class CompanyWorkspaceEntity extends BaseWorkspaceEntity { icon: 'IconUsers', }) @WorkspaceIsNullable() - employees: number; + employees: number | null; @WorkspaceField({ standardId: COMPANY_STANDARD_FIELD_IDS.linkedinLink, @@ -78,7 +73,7 @@ export class CompanyWorkspaceEntity extends BaseWorkspaceEntity { icon: 'IconBrandLinkedin', }) @WorkspaceIsNullable() - linkedinLink: LinkMetadata; + linkedinLink: LinkMetadata | null; @WorkspaceField({ standardId: COMPANY_STANDARD_FIELD_IDS.xLink, @@ -88,7 +83,7 @@ export class CompanyWorkspaceEntity extends BaseWorkspaceEntity { icon: 'IconBrandX', }) @WorkspaceIsNullable() - xLink: LinkMetadata; + xLink: LinkMetadata | null; @WorkspaceField({ standardId: COMPANY_STANDARD_FIELD_IDS.annualRecurringRevenue, @@ -99,7 +94,17 @@ export class CompanyWorkspaceEntity extends BaseWorkspaceEntity { icon: 'IconMoneybag', }) @WorkspaceIsNullable() - annualRecurringRevenue: CurrencyMetadata; + annualRecurringRevenue: CurrencyMetadata | null; + + @WorkspaceField({ + standardId: COMPANY_STANDARD_FIELD_IDS.address, + type: FieldMetadataType.ADDRESS, + label: 'Address', + description: 'Address of the company', + icon: 'IconMap', + }) + @WorkspaceIsNullable() + address: Address; @WorkspaceField({ standardId: COMPANY_STANDARD_FIELD_IDS.idealCustomerProfile, @@ -121,7 +126,7 @@ export class CompanyWorkspaceEntity extends BaseWorkspaceEntity { }) @WorkspaceIsSystem() @WorkspaceIsNullable() - position: number; + position: number | null; // Relations @WorkspaceRelation({ @@ -143,13 +148,15 @@ export class CompanyWorkspaceEntity extends BaseWorkspaceEntity { description: 'Your team member responsible for managing the company account', icon: 'IconUserCircle', - joinColumn: 'accountOwnerId', inverseSideTarget: () => WorkspaceMemberWorkspaceEntity, inverseSideFieldKey: 'accountOwnerForCompanies', onDelete: RelationOnDeleteAction.SET_NULL, }) @WorkspaceIsNullable() - accountOwner: Relation<WorkspaceMemberWorkspaceEntity>; + accountOwner: Relation<WorkspaceMemberWorkspaceEntity> | null; + + @WorkspaceJoinColumn('accountOwner') + accountOwnerId: string | null; @WorkspaceRelation({ standardId: COMPANY_STANDARD_FIELD_IDS.activityTargets, @@ -212,4 +219,16 @@ export class CompanyWorkspaceEntity extends BaseWorkspaceEntity { @WorkspaceIsNullable() @WorkspaceIsSystem() timelineActivities: Relation<TimelineActivityWorkspaceEntity[]>; + + @WorkspaceField({ + standardId: COMPANY_STANDARD_FIELD_IDS.address_deprecated, + type: FieldMetadataType.TEXT, + label: 'Address (deprecated) ', + description: + 'Address of the company - deprecated in favor of new address field', + icon: 'IconMap', + }) + @WorkspaceIsDeprecated() + @WorkspaceIsNullable() + addressOld: string; } diff --git a/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/auto-companies-and-contacts-creation.module.ts b/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/auto-companies-and-contacts-creation.module.ts deleted file mode 100644 index 5e6d0fa68a73..000000000000 --- a/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/auto-companies-and-contacts-creation.module.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { Module } from '@nestjs/common'; -import { TypeOrmModule } from '@nestjs/typeorm'; - -import { CreateCompanyAndContactService } from 'src/modules/connected-account/auto-companies-and-contacts-creation/services/create-company-and-contact.service'; -import { CreateCompanyModule } from 'src/modules/connected-account/auto-companies-and-contacts-creation/create-company/create-company.module'; -import { CreateContactModule } from 'src/modules/connected-account/auto-companies-and-contacts-creation/create-contact/create-contact.module'; -import { ObjectMetadataRepositoryModule } from 'src/engine/object-metadata-repository/object-metadata-repository.module'; -import { PersonWorkspaceEntity } from 'src/modules/person/standard-objects/person.workspace-entity'; -import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; -import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; -import { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-event-participant.workspace-entity'; -import { CalendarEventParticipantModule } from 'src/modules/calendar/services/calendar-event-participant/calendar-event-participant.module'; -import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity'; -import { MessagingCommonModule } from 'src/modules/messaging/common/messaging-common.module'; - -@Module({ - imports: [ - CreateContactModule, - CreateCompanyModule, - ObjectMetadataRepositoryModule.forFeature([ - PersonWorkspaceEntity, - WorkspaceMemberWorkspaceEntity, - CalendarEventParticipantWorkspaceEntity, - ]), - MessagingCommonModule, - WorkspaceDataSourceModule, - CalendarEventParticipantModule, - TypeOrmModule.forFeature([FeatureFlagEntity], 'core'), - ], - providers: [CreateCompanyAndContactService], - exports: [CreateCompanyAndContactService], -}) -export class AutoCompaniesAndContactsCreationModule {} diff --git a/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/create-company/create-company.module.ts b/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/create-company/create-company.module.ts deleted file mode 100644 index c93c537ec395..000000000000 --- a/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/create-company/create-company.module.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Module } from '@nestjs/common'; - -import { ObjectMetadataRepositoryModule } from 'src/engine/object-metadata-repository/object-metadata-repository.module'; -import { CompanyWorkspaceEntity } from 'src/modules/company/standard-objects/company.workspace-entity'; -import { CreateCompanyService } from 'src/modules/connected-account/auto-companies-and-contacts-creation/create-company/create-company.service'; - -@Module({ - imports: [ - ObjectMetadataRepositoryModule.forFeature([CompanyWorkspaceEntity]), - ], - providers: [CreateCompanyService], - exports: [CreateCompanyService], -}) -export class CreateCompanyModule {} diff --git a/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/create-contact/create-contact.module.ts b/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/create-contact/create-contact.module.ts deleted file mode 100644 index b24586e3b9ae..000000000000 --- a/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/create-contact/create-contact.module.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Module } from '@nestjs/common'; - -import { ObjectMetadataRepositoryModule } from 'src/engine/object-metadata-repository/object-metadata-repository.module'; -import { CreateContactService } from 'src/modules/connected-account/auto-companies-and-contacts-creation/create-contact/create-contact.service'; -import { PersonWorkspaceEntity } from 'src/modules/person/standard-objects/person.workspace-entity'; - -@Module({ - imports: [ObjectMetadataRepositoryModule.forFeature([PersonWorkspaceEntity])], - providers: [CreateContactService], - exports: [CreateContactService], -}) -export class CreateContactModule {} diff --git a/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/jobs/auto-companies-and-contacts-creation-job.module.ts b/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/jobs/auto-companies-and-contacts-creation-job.module.ts deleted file mode 100644 index f65e1965b7f0..000000000000 --- a/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/jobs/auto-companies-and-contacts-creation-job.module.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Module } from '@nestjs/common'; - -import { AutoCompaniesAndContactsCreationModule } from 'src/modules/connected-account/auto-companies-and-contacts-creation/auto-companies-and-contacts-creation.module'; -import { CreateCompanyAndContactJob } from 'src/modules/connected-account/auto-companies-and-contacts-creation/jobs/create-company-and-contact.job'; - -@Module({ - imports: [AutoCompaniesAndContactsCreationModule], - providers: [ - { - provide: CreateCompanyAndContactJob.name, - useClass: CreateCompanyAndContactJob, - }, - ], -}) -export class AutoCompaniesAndContactsCreationJobModule {} diff --git a/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/services/create-company-and-contact.service.ts b/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/services/create-company-and-contact.service.ts deleted file mode 100644 index 7fd46851031f..000000000000 --- a/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/services/create-company-and-contact.service.ts +++ /dev/null @@ -1,184 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { EventEmitter2 } from '@nestjs/event-emitter'; - -import { EntityManager } from 'typeorm'; -import compact from 'lodash.compact'; - -import { getDomainNameFromHandle } from 'src/modules/calendar-messaging-participant/utils/get-domain-name-from-handle.util'; -import { CreateCompanyService } from 'src/modules/connected-account/auto-companies-and-contacts-creation/create-company/create-company.service'; -import { CreateContactService } from 'src/modules/connected-account/auto-companies-and-contacts-creation/create-contact/create-contact.service'; -import { PersonRepository } from 'src/modules/person/repositories/person.repository'; -import { WorkspaceMemberRepository } from 'src/modules/workspace-member/repositories/workspace-member.repository'; -import { isWorkEmail } from 'src/utils/is-work-email'; -import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; -import { PersonWorkspaceEntity } from 'src/modules/person/standard-objects/person.workspace-entity'; -import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; -import { getUniqueContactsAndHandles } from 'src/modules/connected-account/auto-companies-and-contacts-creation/utils/get-unique-contacts-and-handles.util'; -import { Contacts } from 'src/modules/connected-account/auto-companies-and-contacts-creation/types/contact.type'; -import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; -import { CalendarEventParticipantService } from 'src/modules/calendar/services/calendar-event-participant/calendar-event-participant.service'; -import { filterOutContactsFromCompanyOrWorkspace } from 'src/modules/connected-account/auto-companies-and-contacts-creation/utils/filter-out-contacts-from-company-or-workspace.util'; -import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record'; -import { MessagingMessageParticipantService } from 'src/modules/messaging/common/services/messaging-message-participant.service'; -import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; -import { MessageParticipantWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-participant.workspace-entity'; -import { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-event-participant.workspace-entity'; - -@Injectable() -export class CreateCompanyAndContactService { - constructor( - private readonly createContactService: CreateContactService, - private readonly createCompaniesService: CreateCompanyService, - @InjectObjectMetadataRepository(PersonWorkspaceEntity) - private readonly personRepository: PersonRepository, - @InjectObjectMetadataRepository(WorkspaceMemberWorkspaceEntity) - private readonly workspaceMemberRepository: WorkspaceMemberRepository, - private readonly workspaceDataSourceService: WorkspaceDataSourceService, - private readonly messageParticipantService: MessagingMessageParticipantService, - private readonly calendarEventParticipantService: CalendarEventParticipantService, - private readonly eventEmitter: EventEmitter2, - ) {} - - async createCompaniesAndPeople( - connectedAccountHandle: string, - contactsToCreate: Contacts, - workspaceId: string, - transactionManager?: EntityManager, - ): Promise<ObjectRecord<PersonWorkspaceEntity>[]> { - if (!contactsToCreate || contactsToCreate.length === 0) { - return []; - } - - // TODO: This is a feature that may be implemented in the future - const isContactAutoCreationForNonWorkEmailsEnabled = false; - - const workspaceMembers = - await this.workspaceMemberRepository.getAllByWorkspaceId( - workspaceId, - transactionManager, - ); - - const contactsToCreateFromOtherCompanies = - filterOutContactsFromCompanyOrWorkspace( - contactsToCreate, - connectedAccountHandle, - workspaceMembers, - ); - - const { uniqueContacts, uniqueHandles } = getUniqueContactsAndHandles( - contactsToCreateFromOtherCompanies, - ); - - if (uniqueHandles.length === 0) { - return []; - } - - const alreadyCreatedContacts = await this.personRepository.getByEmails( - uniqueHandles, - workspaceId, - transactionManager, - ); - - const alreadyCreatedContactEmails: string[] = alreadyCreatedContacts?.map( - ({ email }) => email, - ); - - const filteredContactsToCreate = uniqueContacts.filter( - (participant) => - !alreadyCreatedContactEmails.includes(participant.handle) && - participant.handle.includes('@') && - (isContactAutoCreationForNonWorkEmailsEnabled || - isWorkEmail(participant.handle)), - ); - - const filteredContactsToCreateWithCompanyDomainNames = - filteredContactsToCreate?.map((participant) => ({ - handle: participant.handle, - displayName: participant.displayName, - companyDomainName: isWorkEmail(participant.handle) - ? getDomainNameFromHandle(participant.handle) - : undefined, - })); - - const domainNamesToCreate = compact( - filteredContactsToCreateWithCompanyDomainNames.map( - (participant) => participant.companyDomainName, - ), - ); - - const companiesObject = await this.createCompaniesService.createCompanies( - domainNamesToCreate, - workspaceId, - transactionManager, - ); - - const formattedContactsToCreate = - filteredContactsToCreateWithCompanyDomainNames.map((contact) => ({ - handle: contact.handle, - displayName: contact.displayName, - companyId: - contact.companyDomainName && contact.companyDomainName !== '' - ? companiesObject[contact.companyDomainName] - : undefined, - })); - - return await this.createContactService.createPeople( - formattedContactsToCreate, - workspaceId, - transactionManager, - ); - } - - async createCompaniesAndContactsAndUpdateParticipants( - connectedAccount: ObjectRecord<ConnectedAccountWorkspaceEntity>, - contactsToCreate: Contacts, - workspaceId: string, - ) { - const { dataSource: workspaceDataSource } = - await this.workspaceDataSourceService.connectedToWorkspaceDataSourceAndReturnMetadata( - workspaceId, - ); - - let updatedMessageParticipants: ObjectRecord<MessageParticipantWorkspaceEntity>[] = - []; - let updatedCalendarEventParticipants: ObjectRecord<CalendarEventParticipantWorkspaceEntity>[] = - []; - - await workspaceDataSource?.transaction( - async (transactionManager: EntityManager) => { - const createdPeople = await this.createCompaniesAndPeople( - connectedAccount.handle, - contactsToCreate, - workspaceId, - transactionManager, - ); - - updatedMessageParticipants = - await this.messageParticipantService.updateMessageParticipantsAfterPeopleCreation( - createdPeople, - workspaceId, - transactionManager, - ); - - updatedCalendarEventParticipants = - await this.calendarEventParticipantService.updateCalendarEventParticipantsAfterPeopleCreation( - createdPeople, - workspaceId, - transactionManager, - ); - }, - ); - - this.eventEmitter.emit(`messageParticipant.matched`, { - workspaceId, - userId: connectedAccount.accountOwnerId, - messageParticipants: updatedMessageParticipants, - }); - - this.eventEmitter.emit(`calendarEventParticipant.matched`, { - workspaceId, - userId: connectedAccount.accountOwnerId, - calendarEventParticipants: updatedCalendarEventParticipants, - }); - } -} diff --git a/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/utils/filter-out-contacts-from-company-or-workspace.util.ts b/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/utils/filter-out-contacts-from-company-or-workspace.util.ts deleted file mode 100644 index eadb0e9c134b..000000000000 --- a/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/utils/filter-out-contacts-from-company-or-workspace.util.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { getDomainNameFromHandle } from 'src/modules/calendar-messaging-participant/utils/get-domain-name-from-handle.util'; -import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; -import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record'; -import { Contacts } from 'src/modules/connected-account/auto-companies-and-contacts-creation/types/contact.type'; - -export function filterOutContactsFromCompanyOrWorkspace( - contacts: Contacts, - selfHandle: string, - workspaceMembers: ObjectRecord<WorkspaceMemberWorkspaceEntity>[], -): Contacts { - const selfDomainName = getDomainNameFromHandle(selfHandle); - - const workspaceMembersMap = workspaceMembers.reduce( - (map, workspaceMember) => { - map[workspaceMember.userEmail] = true; - - return map; - }, - new Map<string, boolean>(), - ); - - return contacts.filter( - (contact) => - getDomainNameFromHandle(contact.handle) !== selfDomainName && - !workspaceMembersMap[contact.handle], - ); -} diff --git a/packages/twenty-server/src/modules/connected-account/email-alias-manager/drivers/google/google-email-alias-manager.service.ts b/packages/twenty-server/src/modules/connected-account/email-alias-manager/drivers/google/google-email-alias-manager.service.ts new file mode 100644 index 000000000000..5de07e5e1a48 --- /dev/null +++ b/packages/twenty-server/src/modules/connected-account/email-alias-manager/drivers/google/google-email-alias-manager.service.ts @@ -0,0 +1,43 @@ +import { Injectable } from '@nestjs/common'; + +import { google } from 'googleapis'; + +import { OAuth2ClientManagerService } from 'src/modules/connected-account/oauth2-client-manager/services/oauth2-client-manager.service'; +import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; + +@Injectable() +export class GoogleEmailAliasManagerService { + constructor( + private readonly oAuth2ClientManagerService: OAuth2ClientManagerService, + ) {} + + public async getHandleAliases( + connectedAccount: ConnectedAccountWorkspaceEntity, + ) { + const oAuth2Client = + await this.oAuth2ClientManagerService.getOAuth2Client(connectedAccount); + + const people = google.people({ + version: 'v1', + auth: oAuth2Client, + }); + + const emailsResponse = await people.people.get({ + resourceName: 'people/me', + personFields: 'emailAddresses', + }); + + const emailAddresses = emailsResponse.data.emailAddresses; + + const handleAliases = + emailAddresses + ?.filter((emailAddress) => { + return emailAddress.metadata?.primary !== true; + }) + .map((emailAddress) => { + return emailAddress.value || ''; + }) || []; + + return handleAliases; + } +} diff --git a/packages/twenty-server/src/modules/connected-account/email-alias-manager/email-alias-manager.module.ts b/packages/twenty-server/src/modules/connected-account/email-alias-manager/email-alias-manager.module.ts new file mode 100644 index 000000000000..e1678e3d7ab6 --- /dev/null +++ b/packages/twenty-server/src/modules/connected-account/email-alias-manager/email-alias-manager.module.ts @@ -0,0 +1,19 @@ +import { Module } from '@nestjs/common'; + +import { ObjectMetadataRepositoryModule } from 'src/engine/object-metadata-repository/object-metadata-repository.module'; +import { GoogleEmailAliasManagerService } from 'src/modules/connected-account/email-alias-manager/drivers/google/google-email-alias-manager.service'; +import { EmailAliasManagerService } from 'src/modules/connected-account/email-alias-manager/services/email-alias-manager.service'; +import { OAuth2ClientManagerModule } from 'src/modules/connected-account/oauth2-client-manager/oauth2-client-manager.module'; +import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; + +@Module({ + imports: [ + ObjectMetadataRepositoryModule.forFeature([ + ConnectedAccountWorkspaceEntity, + ]), + OAuth2ClientManagerModule, + ], + providers: [EmailAliasManagerService, GoogleEmailAliasManagerService], + exports: [EmailAliasManagerService], +}) +export class EmailAliasManagerModule {} diff --git a/packages/twenty-server/src/modules/connected-account/email-alias-manager/services/email-alias-manager.service.ts b/packages/twenty-server/src/modules/connected-account/email-alias-manager/services/email-alias-manager.service.ts new file mode 100644 index 000000000000..50a855ba31a7 --- /dev/null +++ b/packages/twenty-server/src/modules/connected-account/email-alias-manager/services/email-alias-manager.service.ts @@ -0,0 +1,41 @@ +import { Injectable } from '@nestjs/common'; + +import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; +import { GoogleEmailAliasManagerService } from 'src/modules/connected-account/email-alias-manager/drivers/google/google-email-alias-manager.service'; +import { ConnectedAccountRepository } from 'src/modules/connected-account/repositories/connected-account.repository'; +import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; + +@Injectable() +export class EmailAliasManagerService { + constructor( + @InjectObjectMetadataRepository(ConnectedAccountWorkspaceEntity) + private readonly connectedAccountRepository: ConnectedAccountRepository, + private readonly googleEmailAliasManagerService: GoogleEmailAliasManagerService, + ) {} + + public async refreshHandleAliases( + connectedAccount: ConnectedAccountWorkspaceEntity, + workspaceId: string, + ) { + let handleAliases: string[]; + + switch (connectedAccount.provider) { + case 'google': + handleAliases = + await this.googleEmailAliasManagerService.getHandleAliases( + connectedAccount, + ); + break; + default: + throw new Error( + `Email alias manager for provider ${connectedAccount.provider} is not implemented`, + ); + } + + await this.connectedAccountRepository.updateHandleAliases( + handleAliases, + connectedAccount.id, + workspaceId, + ); + } +} diff --git a/packages/twenty-server/src/modules/connected-account/oauth2-client-manager/drivers/google/google-oauth2-client-manager.service.ts b/packages/twenty-server/src/modules/connected-account/oauth2-client-manager/drivers/google/google-oauth2-client-manager.service.ts new file mode 100644 index 000000000000..ef577eafc702 --- /dev/null +++ b/packages/twenty-server/src/modules/connected-account/oauth2-client-manager/drivers/google/google-oauth2-client-manager.service.ts @@ -0,0 +1,29 @@ +import { Injectable } from '@nestjs/common'; + +import { OAuth2Client } from 'google-auth-library'; +import { google } from 'googleapis'; + +import { EnvironmentService } from 'src/engine/integrations/environment/environment.service'; + +@Injectable() +export class GoogleOAuth2ClientManagerService { + constructor(private readonly environmentService: EnvironmentService) {} + + public async getOAuth2Client(refreshToken: string): Promise<OAuth2Client> { + const gmailClientId = this.environmentService.get('AUTH_GOOGLE_CLIENT_ID'); + const gmailClientSecret = this.environmentService.get( + 'AUTH_GOOGLE_CLIENT_SECRET', + ); + + const oAuth2Client = new google.auth.OAuth2( + gmailClientId, + gmailClientSecret, + ); + + oAuth2Client.setCredentials({ + refresh_token: refreshToken, + }); + + return oAuth2Client; + } +} diff --git a/packages/twenty-server/src/modules/connected-account/oauth2-client-manager/oauth2-client-manager.module.ts b/packages/twenty-server/src/modules/connected-account/oauth2-client-manager/oauth2-client-manager.module.ts new file mode 100644 index 000000000000..23c65eba1157 --- /dev/null +++ b/packages/twenty-server/src/modules/connected-account/oauth2-client-manager/oauth2-client-manager.module.ts @@ -0,0 +1,11 @@ +import { Module } from '@nestjs/common'; + +import { GoogleOAuth2ClientManagerService } from 'src/modules/connected-account/oauth2-client-manager/drivers/google/google-oauth2-client-manager.service'; +import { OAuth2ClientManagerService } from 'src/modules/connected-account/oauth2-client-manager/services/oauth2-client-manager.service'; + +@Module({ + imports: [], + providers: [OAuth2ClientManagerService, GoogleOAuth2ClientManagerService], + exports: [OAuth2ClientManagerService], +}) +export class OAuth2ClientManagerModule {} diff --git a/packages/twenty-server/src/modules/connected-account/oauth2-client-manager/services/oauth2-client-manager.service.ts b/packages/twenty-server/src/modules/connected-account/oauth2-client-manager/services/oauth2-client-manager.service.ts new file mode 100644 index 000000000000..9585ce5a8da6 --- /dev/null +++ b/packages/twenty-server/src/modules/connected-account/oauth2-client-manager/services/oauth2-client-manager.service.ts @@ -0,0 +1,33 @@ +import { Injectable } from '@nestjs/common'; + +import { OAuth2Client } from 'google-auth-library'; + +import { GoogleOAuth2ClientManagerService } from 'src/modules/connected-account/oauth2-client-manager/drivers/google/google-oauth2-client-manager.service'; +import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; + +@Injectable() +export class OAuth2ClientManagerService { + constructor( + private readonly googleOAuth2ClientManagerService: GoogleOAuth2ClientManagerService, + ) {} + + public async getOAuth2Client( + connectedAccount: Pick< + ConnectedAccountWorkspaceEntity, + 'provider' | 'refreshToken' + >, + ): Promise<OAuth2Client> { + const { refreshToken } = connectedAccount; + + switch (connectedAccount.provider) { + case 'google': + return this.googleOAuth2ClientManagerService.getOAuth2Client( + refreshToken, + ); + default: + throw new Error( + `OAuth2 client manager for provider ${connectedAccount.provider} is not implemented`, + ); + } + } +} diff --git a/packages/twenty-server/src/modules/connected-account/query-hooks/blocklist/blocklist-update-many.pre-query.hook.ts b/packages/twenty-server/src/modules/connected-account/query-hooks/blocklist/blocklist-update-many.pre-query.hook.ts deleted file mode 100644 index 1ce12a5350df..000000000000 --- a/packages/twenty-server/src/modules/connected-account/query-hooks/blocklist/blocklist-update-many.pre-query.hook.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Injectable, MethodNotAllowedException } from '@nestjs/common'; - -import { WorkspacePreQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-pre-query-hook/interfaces/workspace-pre-query-hook.interface'; - -@Injectable() -export class BlocklistUpdateManyPreQueryHook implements WorkspacePreQueryHook { - constructor() {} - - async execute(): Promise<void> { - throw new MethodNotAllowedException('Method not allowed.'); - } -} diff --git a/packages/twenty-server/src/modules/connected-account/query-hooks/connected-account-delete-one.pre-query.hook.ts b/packages/twenty-server/src/modules/connected-account/query-hooks/connected-account-delete-one.pre-query.hook.ts new file mode 100644 index 000000000000..9296263df119 --- /dev/null +++ b/packages/twenty-server/src/modules/connected-account/query-hooks/connected-account-delete-one.pre-query.hook.ts @@ -0,0 +1,43 @@ +import { EventEmitter2 } from '@nestjs/event-emitter'; + +import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface'; +import { DeleteOneResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; + +import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator'; +import { InjectWorkspaceRepository } from 'src/engine/twenty-orm/decorators/inject-workspace-repository.decorator'; +import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository'; +import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity'; +import { ObjectRecordDeleteEvent } from 'src/engine/integrations/event-emitter/types/object-record-delete.event'; + +@WorkspaceQueryHook(`connectedAccount.deleteOne`) +export class ConnectedAccountDeleteOnePreQueryHook + implements WorkspaceQueryHookInstance +{ + constructor( + @InjectWorkspaceRepository(MessageChannelWorkspaceEntity) + private readonly messageChannelRepository: WorkspaceRepository<MessageChannelWorkspaceEntity>, + private eventEmitter: EventEmitter2, + ) {} + + async execute( + _userId: string, + workspaceId: string, + payload: DeleteOneResolverArgs, + ): Promise<void> { + const connectedAccountId = payload.id; + + const messageChannels = await this.messageChannelRepository.findBy({ + connectedAccountId, + }); + + messageChannels.forEach((messageChannel) => { + this.eventEmitter.emit('messageChannel.deleted', { + workspaceId, + recordId: messageChannel.id, + } satisfies Pick< + ObjectRecordDeleteEvent<MessageChannelWorkspaceEntity>, + 'workspaceId' | 'recordId' + >); + }); + } +} diff --git a/packages/twenty-server/src/modules/connected-account/query-hooks/connected-account-query-hook.module.ts b/packages/twenty-server/src/modules/connected-account/query-hooks/connected-account-query-hook.module.ts index c711b4b567c8..57aaa6408be0 100644 --- a/packages/twenty-server/src/modules/connected-account/query-hooks/connected-account-query-hook.module.ts +++ b/packages/twenty-server/src/modules/connected-account/query-hooks/connected-account-query-hook.module.ts @@ -1,25 +1,11 @@ import { Module } from '@nestjs/common'; -import { BlocklistCreateManyPreQueryHook } from 'src/modules/connected-account/query-hooks/blocklist/blocklist-create-many.pre-query.hook'; -import { BlocklistUpdateManyPreQueryHook } from 'src/modules/connected-account/query-hooks/blocklist/blocklist-update-many.pre-query.hook'; -import { BlocklistUpdateOnePreQueryHook } from 'src/modules/connected-account/query-hooks/blocklist/blocklist-update-one.pre-query.hook'; -import { BlocklistValidationModule } from 'src/modules/connected-account/services/blocklist/blocklist-validation.module'; +import { TwentyORMModule } from 'src/engine/twenty-orm/twenty-orm.module'; +import { ConnectedAccountDeleteOnePreQueryHook } from 'src/modules/connected-account/query-hooks/connected-account-delete-one.pre-query.hook'; +import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity'; @Module({ - imports: [BlocklistValidationModule], - providers: [ - { - provide: BlocklistCreateManyPreQueryHook.name, - useClass: BlocklistCreateManyPreQueryHook, - }, - { - provide: BlocklistUpdateManyPreQueryHook.name, - useClass: BlocklistUpdateManyPreQueryHook, - }, - { - provide: BlocklistUpdateOnePreQueryHook.name, - useClass: BlocklistUpdateOnePreQueryHook, - }, - ], + imports: [TwentyORMModule.forFeature([MessageChannelWorkspaceEntity])], + providers: [ConnectedAccountDeleteOnePreQueryHook], }) export class ConnectedAccountQueryHookModule {} diff --git a/packages/twenty-server/src/modules/connected-account/services/google-api-refresh-access-token/google-api-refresh-access-token.module.ts b/packages/twenty-server/src/modules/connected-account/refresh-access-token-manager/drivers/google/google-api-refresh-access-token.module.ts similarity index 87% rename from packages/twenty-server/src/modules/connected-account/services/google-api-refresh-access-token/google-api-refresh-access-token.module.ts rename to packages/twenty-server/src/modules/connected-account/refresh-access-token-manager/drivers/google/google-api-refresh-access-token.module.ts index 0c3180c09a77..14529ba0b745 100644 --- a/packages/twenty-server/src/modules/connected-account/services/google-api-refresh-access-token/google-api-refresh-access-token.module.ts +++ b/packages/twenty-server/src/modules/connected-account/refresh-access-token-manager/drivers/google/google-api-refresh-access-token.module.ts @@ -1,7 +1,7 @@ import { Module } from '@nestjs/common'; import { ObjectMetadataRepositoryModule } from 'src/engine/object-metadata-repository/object-metadata-repository.module'; -import { GoogleAPIRefreshAccessTokenService } from 'src/modules/connected-account/services/google-api-refresh-access-token/google-api-refresh-access-token.service'; +import { GoogleAPIRefreshAccessTokenService } from 'src/modules/connected-account/refresh-access-token-manager/drivers/google/services/google-api-refresh-access-token.service'; import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; import { MessagingCommonModule } from 'src/modules/messaging/common/messaging-common.module'; diff --git a/packages/twenty-server/src/modules/connected-account/refresh-access-token-manager/drivers/google/services/google-api-refresh-access-token.service.ts b/packages/twenty-server/src/modules/connected-account/refresh-access-token-manager/drivers/google/services/google-api-refresh-access-token.service.ts new file mode 100644 index 000000000000..3a5d015be990 --- /dev/null +++ b/packages/twenty-server/src/modules/connected-account/refresh-access-token-manager/drivers/google/services/google-api-refresh-access-token.service.ts @@ -0,0 +1,29 @@ +import { Injectable } from '@nestjs/common'; + +import axios from 'axios'; + +import { EnvironmentService } from 'src/engine/integrations/environment/environment.service'; + +@Injectable() +export class GoogleAPIRefreshAccessTokenService { + constructor(private readonly environmentService: EnvironmentService) {} + + async refreshAccessToken(refreshToken: string): Promise<string> { + const response = await axios.post( + 'https://oauth2.googleapis.com/token', + { + client_id: this.environmentService.get('AUTH_GOOGLE_CLIENT_ID'), + client_secret: this.environmentService.get('AUTH_GOOGLE_CLIENT_SECRET'), + refresh_token: refreshToken, + grant_type: 'refresh_token', + }, + { + headers: { + 'Content-Type': 'application/json', + }, + }, + ); + + return response.data.access_token; + } +} diff --git a/packages/twenty-server/src/modules/connected-account/refresh-access-token-manager/refresh-access-token-manager.module.ts b/packages/twenty-server/src/modules/connected-account/refresh-access-token-manager/refresh-access-token-manager.module.ts new file mode 100644 index 000000000000..e8eb170b5d3a --- /dev/null +++ b/packages/twenty-server/src/modules/connected-account/refresh-access-token-manager/refresh-access-token-manager.module.ts @@ -0,0 +1,11 @@ +import { Module } from '@nestjs/common'; + +import { GoogleAPIRefreshAccessTokenModule } from 'src/modules/connected-account/refresh-access-token-manager/drivers/google/google-api-refresh-access-token.module'; +import { RefreshAccessTokenService } from 'src/modules/connected-account/refresh-access-token-manager/services/refresh-access-token.service'; + +@Module({ + imports: [GoogleAPIRefreshAccessTokenModule], + providers: [RefreshAccessTokenService], + exports: [RefreshAccessTokenService], +}) +export class RefreshAccessTokenManagerModule {} diff --git a/packages/twenty-server/src/modules/connected-account/refresh-access-token-manager/services/refresh-access-token.service.ts b/packages/twenty-server/src/modules/connected-account/refresh-access-token-manager/services/refresh-access-token.service.ts new file mode 100644 index 000000000000..7f381750fc51 --- /dev/null +++ b/packages/twenty-server/src/modules/connected-account/refresh-access-token-manager/services/refresh-access-token.service.ts @@ -0,0 +1,62 @@ +import { Injectable } from '@nestjs/common'; + +import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; +import { GoogleAPIRefreshAccessTokenService } from 'src/modules/connected-account/refresh-access-token-manager/drivers/google/services/google-api-refresh-access-token.service'; +import { ConnectedAccountRepository } from 'src/modules/connected-account/repositories/connected-account.repository'; +import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; + +@Injectable() +export class RefreshAccessTokenService { + constructor( + private readonly googleAPIRefreshAccessTokenService: GoogleAPIRefreshAccessTokenService, + @InjectObjectMetadataRepository(ConnectedAccountWorkspaceEntity) + private readonly connectedAccountRepository: ConnectedAccountRepository, + ) {} + + async refreshAndSaveAccessToken( + connectedAccount: ConnectedAccountWorkspaceEntity, + workspaceId: string, + ): Promise<string> { + const refreshToken = connectedAccount.refreshToken; + + if (!refreshToken) { + throw new Error( + `No refresh token found for connected account ${connectedAccount.id} in workspace ${workspaceId}`, + ); + } + const accessToken = await this.refreshAccessToken( + connectedAccount, + refreshToken, + ); + + await this.connectedAccountRepository.updateAccessToken( + accessToken, + connectedAccount.id, + workspaceId, + ); + + await this.connectedAccountRepository.updateAccessToken( + accessToken, + connectedAccount.id, + workspaceId, + ); + + return accessToken; + } + + async refreshAccessToken( + connectedAccount: ConnectedAccountWorkspaceEntity, + refreshToken: string, + ): Promise<string> { + switch (connectedAccount.provider) { + case 'google': + return this.googleAPIRefreshAccessTokenService.refreshAccessToken( + refreshToken, + ); + default: + throw new Error( + `Provider ${connectedAccount.provider} is not supported.`, + ); + } + } +} diff --git a/packages/twenty-server/src/modules/connected-account/repositories/connected-account.repository.ts b/packages/twenty-server/src/modules/connected-account/repositories/connected-account.repository.ts index 1658befee36b..ae68fd68ab0c 100644 --- a/packages/twenty-server/src/modules/connected-account/repositories/connected-account.repository.ts +++ b/packages/twenty-server/src/modules/connected-account/repositories/connected-account.repository.ts @@ -4,7 +4,6 @@ import { EntityManager } from 'typeorm'; import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; -import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record'; @Injectable() export class ConnectedAccountRepository { @@ -15,7 +14,7 @@ export class ConnectedAccountRepository { public async getAll( workspaceId: string, transactionManager?: EntityManager, - ): Promise<ObjectRecord<ConnectedAccountWorkspaceEntity>[]> { + ): Promise<ConnectedAccountWorkspaceEntity[]> { const dataSourceSchema = this.workspaceDataSourceService.getSchemaName(workspaceId); @@ -31,7 +30,7 @@ export class ConnectedAccountRepository { connectedAccountIds: string[], workspaceId: string, transactionManager?: EntityManager, - ): Promise<ObjectRecord<ConnectedAccountWorkspaceEntity>[]> { + ): Promise<ConnectedAccountWorkspaceEntity[]> { const dataSourceSchema = this.workspaceDataSourceService.getSchemaName(workspaceId); @@ -47,7 +46,7 @@ export class ConnectedAccountRepository { workspaceMemberId: string, workspaceId: string, transactionManager?: EntityManager, - ): Promise<ObjectRecord<ConnectedAccountWorkspaceEntity>[] | undefined> { + ): Promise<ConnectedAccountWorkspaceEntity[] | undefined> { const dataSourceSchema = this.workspaceDataSourceService.getSchemaName(workspaceId); @@ -66,7 +65,7 @@ export class ConnectedAccountRepository { userId: string, workspaceId: string, transactionManager?: EntityManager, - ): Promise<ObjectRecord<ConnectedAccountWorkspaceEntity>[] | undefined> { + ): Promise<ConnectedAccountWorkspaceEntity[] | undefined> { const schemaExists = await this.workspaceDataSourceService.checkSchemaExists(workspaceId); @@ -102,7 +101,7 @@ export class ConnectedAccountRepository { workspaceMemberId: string, workspaceId: string, transactionManager?: EntityManager, - ): Promise<ObjectRecord<ConnectedAccountWorkspaceEntity>[] | undefined> { + ): Promise<ConnectedAccountWorkspaceEntity[] | undefined> { const dataSourceSchema = this.workspaceDataSourceService.getSchemaName(workspaceId); @@ -119,7 +118,7 @@ export class ConnectedAccountRepository { public async create( connectedAccount: Pick< - ObjectRecord<ConnectedAccountWorkspaceEntity>, + ConnectedAccountWorkspaceEntity, | 'id' | 'handle' | 'provider' @@ -129,7 +128,7 @@ export class ConnectedAccountRepository { >, workspaceId: string, transactionManager?: EntityManager, - ): Promise<ObjectRecord<ConnectedAccountWorkspaceEntity>> { + ): Promise<ConnectedAccountWorkspaceEntity> { const dataSourceSchema = this.workspaceDataSourceService.getSchemaName(workspaceId); @@ -170,7 +169,7 @@ export class ConnectedAccountRepository { connectedAccountId: string, workspaceId: string, transactionManager?: EntityManager, - ): Promise<ObjectRecord<ConnectedAccountWorkspaceEntity> | undefined> { + ): Promise<ConnectedAccountWorkspaceEntity | undefined> { const dataSourceSchema = this.workspaceDataSourceService.getSchemaName(workspaceId); @@ -189,7 +188,7 @@ export class ConnectedAccountRepository { connectedAccountId: string, workspaceId: string, transactionManager?: EntityManager, - ): Promise<ObjectRecord<ConnectedAccountWorkspaceEntity>> { + ): Promise<ConnectedAccountWorkspaceEntity> { const connectedAccount = await this.getById( connectedAccountId, workspaceId, @@ -293,7 +292,7 @@ export class ConnectedAccountRepository { public async getConnectedAccountOrThrow( workspaceId: string, connectedAccountId: string, - ): Promise<ObjectRecord<ConnectedAccountWorkspaceEntity>> { + ): Promise<ConnectedAccountWorkspaceEntity> { const connectedAccount = await this.getById( connectedAccountId, workspaceId, @@ -307,4 +306,22 @@ export class ConnectedAccountRepository { return connectedAccount; } + + public async updateHandleAliases( + handleAliases: string[], + connectedAccountId: string, + workspaceId: string, + transactionManager?: EntityManager, + ) { + const dataSourceSchema = + this.workspaceDataSourceService.getSchemaName(workspaceId); + + await this.workspaceDataSourceService.executeRawQuery( + `UPDATE ${dataSourceSchema}."connectedAccount" SET "handleAliases" = $1 WHERE "id" = $2`, + // TODO: modify handleAliases to be of fieldmetadatatype array + [handleAliases.join(','), connectedAccountId], + workspaceId, + transactionManager, + ); + } } diff --git a/packages/twenty-server/src/modules/connected-account/services/google-api-refresh-access-token/google-api-refresh-access-token.service.ts b/packages/twenty-server/src/modules/connected-account/services/google-api-refresh-access-token/google-api-refresh-access-token.service.ts deleted file mode 100644 index dc687e1a4c19..000000000000 --- a/packages/twenty-server/src/modules/connected-account/services/google-api-refresh-access-token/google-api-refresh-access-token.service.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { Injectable } from '@nestjs/common'; - -import axios from 'axios'; - -import { EnvironmentService } from 'src/engine/integrations/environment/environment.service'; -import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; -import { ConnectedAccountRepository } from 'src/modules/connected-account/repositories/connected-account.repository'; -import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; -import { MessageChannelRepository } from 'src/modules/messaging/common/repositories/message-channel.repository'; -import { MessagingTelemetryService } from 'src/modules/messaging/common/services/messaging-telemetry.service'; -import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity'; -import { MessagingChannelSyncStatusService } from 'src/modules/messaging/common/services/messaging-channel-sync-status.service'; - -@Injectable() -export class GoogleAPIRefreshAccessTokenService { - constructor( - private readonly environmentService: EnvironmentService, - @InjectObjectMetadataRepository(ConnectedAccountWorkspaceEntity) - private readonly connectedAccountRepository: ConnectedAccountRepository, - @InjectObjectMetadataRepository(MessageChannelWorkspaceEntity) - private readonly messageChannelRepository: MessageChannelRepository, - private readonly messagingTelemetryService: MessagingTelemetryService, - private readonly messagingChannelSyncStatusService: MessagingChannelSyncStatusService, - ) {} - - async refreshAndSaveAccessToken( - workspaceId: string, - connectedAccountId: string, - ): Promise<void> { - const connectedAccount = await this.connectedAccountRepository.getById( - connectedAccountId, - workspaceId, - ); - - if (!connectedAccount) { - throw new Error( - `No connected account found for ${connectedAccountId} in workspace ${workspaceId}`, - ); - } - - const refreshToken = connectedAccount.refreshToken; - - if (!refreshToken) { - throw new Error( - `No refresh token found for connected account ${connectedAccountId} in workspace ${workspaceId}`, - ); - } - - try { - const accessToken = await this.refreshAccessToken(refreshToken); - - await this.connectedAccountRepository.updateAccessToken( - accessToken, - connectedAccountId, - workspaceId, - ); - } catch (error) { - const messageChannel = - await this.messageChannelRepository.getFirstByConnectedAccountId( - connectedAccountId, - workspaceId, - ); - - if (!messageChannel) { - throw new Error( - `No message channel found for connected account ${connectedAccountId} in workspace ${workspaceId}`, - ); - } - - await this.messagingTelemetryService.track({ - eventName: `refresh_token.error.insufficient_permissions`, - workspaceId, - connectedAccountId: messageChannel.connectedAccountId, - messageChannelId: messageChannel.id, - message: `${error.code}: ${error.reason}`, - }); - - await this.messagingChannelSyncStatusService.markAsFailedInsufficientPermissionsAndFlushMessagesToImport( - messageChannel.id, - workspaceId, - ); - - await this.connectedAccountRepository.updateAuthFailedAt( - messageChannel.connectedAccountId, - workspaceId, - ); - } - } - - async refreshAccessToken(refreshToken: string): Promise<string> { - const response = await axios.post( - 'https://oauth2.googleapis.com/token', - { - client_id: this.environmentService.get('AUTH_GOOGLE_CLIENT_ID'), - client_secret: this.environmentService.get('AUTH_GOOGLE_CLIENT_SECRET'), - refresh_token: refreshToken, - grant_type: 'refresh_token', - }, - { - headers: { - 'Content-Type': 'application/json', - }, - }, - ); - - return response.data.access_token; - } -} diff --git a/packages/twenty-server/src/modules/connected-account/standard-objects/connected-account.workspace-entity.ts b/packages/twenty-server/src/modules/connected-account/standard-objects/connected-account.workspace-entity.ts index 481f319703e3..6fb6ad15c407 100644 --- a/packages/twenty-server/src/modules/connected-account/standard-objects/connected-account.workspace-entity.ts +++ b/packages/twenty-server/src/modules/connected-account/standard-objects/connected-account.workspace-entity.ts @@ -5,18 +5,19 @@ import { RelationMetadataType, RelationOnDeleteAction, } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity'; -import { CONNECTED_ACCOUNT_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids'; -import { STANDARD_OBJECT_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-object-ids'; -import { CalendarChannelWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-channel.workspace-entity'; -import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity'; import { WorkspaceEntity } from 'src/engine/twenty-orm/decorators/workspace-entity.decorator'; -import { WorkspaceIsSystem } from 'src/engine/twenty-orm/decorators/workspace-is-system.decorator'; -import { WorkspaceIsNotAuditLogged } from 'src/engine/twenty-orm/decorators/workspace-is-not-audit-logged.decorator'; import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field.decorator'; -import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator'; +import { WorkspaceIsNotAuditLogged } from 'src/engine/twenty-orm/decorators/workspace-is-not-audit-logged.decorator'; import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator'; +import { WorkspaceIsSystem } from 'src/engine/twenty-orm/decorators/workspace-is-system.decorator'; +import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator'; +import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator'; +import { CONNECTED_ACCOUNT_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids'; +import { STANDARD_OBJECT_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-object-ids'; +import { CalendarChannelWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-channel.workspace-entity'; import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity'; +import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; export enum ConnectedAccountProvider { GOOGLE = 'google', @@ -86,7 +87,16 @@ export class ConnectedAccountWorkspaceEntity extends BaseWorkspaceEntity { icon: 'IconX', }) @WorkspaceIsNullable() - authFailedAt: Date; + authFailedAt: Date | null; + + @WorkspaceField({ + standardId: CONNECTED_ACCOUNT_STANDARD_FIELD_IDS.handleAliases, + type: FieldMetadataType.TEXT, + label: 'Handle Aliases', + description: 'Handle Aliases', + icon: 'IconMail', + }) + handleAliases: string; @WorkspaceRelation({ standardId: CONNECTED_ACCOUNT_STANDARD_FIELD_IDS.accountOwner, @@ -94,12 +104,14 @@ export class ConnectedAccountWorkspaceEntity extends BaseWorkspaceEntity { label: 'Account Owner', description: 'Account Owner', icon: 'IconUserCircle', - joinColumn: 'accountOwnerId', inverseSideTarget: () => WorkspaceMemberWorkspaceEntity, inverseSideFieldKey: 'connectedAccounts', }) accountOwner: Relation<WorkspaceMemberWorkspaceEntity>; + @WorkspaceJoinColumn('accountOwner') + accountOwnerId: string; + @WorkspaceRelation({ standardId: CONNECTED_ACCOUNT_STANDARD_FIELD_IDS.messageChannels, type: RelationMetadataType.ONE_TO_MANY, diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/utils/is-throttled.ts b/packages/twenty-server/src/modules/connected-account/utils/is-throttled.ts similarity index 100% rename from packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/utils/is-throttled.ts rename to packages/twenty-server/src/modules/connected-account/utils/is-throttled.ts diff --git a/packages/twenty-server/src/modules/contact-creation-manager/constants/contacts-creation-batch-size.constant.ts b/packages/twenty-server/src/modules/contact-creation-manager/constants/contacts-creation-batch-size.constant.ts new file mode 100644 index 000000000000..3e96e531719f --- /dev/null +++ b/packages/twenty-server/src/modules/contact-creation-manager/constants/contacts-creation-batch-size.constant.ts @@ -0,0 +1 @@ +export const CONTACTS_CREATION_BATCH_SIZE = 100; diff --git a/packages/twenty-server/src/modules/contact-creation-manager/contact-creation-manager.module.ts b/packages/twenty-server/src/modules/contact-creation-manager/contact-creation-manager.module.ts new file mode 100644 index 000000000000..fdb994efa77d --- /dev/null +++ b/packages/twenty-server/src/modules/contact-creation-manager/contact-creation-manager.module.ts @@ -0,0 +1,37 @@ +import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; + +import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity'; +import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; +import { ObjectMetadataRepositoryModule } from 'src/engine/object-metadata-repository/object-metadata-repository.module'; +import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; +import { CompanyWorkspaceEntity } from 'src/modules/company/standard-objects/company.workspace-entity'; +import { AutoCompaniesAndContactsCreationCalendarChannelListener } from 'src/modules/contact-creation-manager/listeners/auto-companies-and-contacts-creation-calendar-channel.listener'; +import { AutoCompaniesAndContactsCreationMessageChannelListener } from 'src/modules/contact-creation-manager/listeners/auto-companies-and-contacts-creation-message-channel.listener'; +import { CreateCompanyAndContactService } from 'src/modules/contact-creation-manager/services/create-company-and-contact.service'; +import { CreateCompanyService } from 'src/modules/contact-creation-manager/services/create-company.service'; +import { CreateContactService } from 'src/modules/contact-creation-manager/services/create-contact.service'; +import { PersonWorkspaceEntity } from 'src/modules/person/standard-objects/person.workspace-entity'; +import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; + +@Module({ + imports: [ + ObjectMetadataRepositoryModule.forFeature([ + PersonWorkspaceEntity, + WorkspaceMemberWorkspaceEntity, + CompanyWorkspaceEntity, + ]), + WorkspaceDataSourceModule, + TypeOrmModule.forFeature([FeatureFlagEntity], 'core'), + TypeOrmModule.forFeature([ObjectMetadataEntity], 'metadata'), + ], + providers: [ + CreateCompanyService, + CreateContactService, + CreateCompanyAndContactService, + AutoCompaniesAndContactsCreationMessageChannelListener, + AutoCompaniesAndContactsCreationCalendarChannelListener, + ], + exports: [CreateCompanyAndContactService], +}) +export class ContactCreationManagerModule {} diff --git a/packages/twenty-server/src/modules/contact-creation-manager/jobs/auto-companies-and-contacts-creation-job.module.ts b/packages/twenty-server/src/modules/contact-creation-manager/jobs/auto-companies-and-contacts-creation-job.module.ts new file mode 100644 index 000000000000..a67a9e498b81 --- /dev/null +++ b/packages/twenty-server/src/modules/contact-creation-manager/jobs/auto-companies-and-contacts-creation-job.module.ts @@ -0,0 +1,10 @@ +import { Module } from '@nestjs/common'; + +import { ContactCreationManagerModule } from 'src/modules/contact-creation-manager/contact-creation-manager.module'; +import { CreateCompanyAndContactJob } from 'src/modules/contact-creation-manager/jobs/create-company-and-contact.job'; + +@Module({ + imports: [ContactCreationManagerModule], + providers: [CreateCompanyAndContactJob], +}) +export class AutoCompaniesAndContactsCreationJobModule {} diff --git a/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/jobs/create-company-and-contact.job.ts b/packages/twenty-server/src/modules/contact-creation-manager/jobs/create-company-and-contact.job.ts similarity index 57% rename from packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/jobs/create-company-and-contact.job.ts rename to packages/twenty-server/src/modules/contact-creation-manager/jobs/create-company-and-contact.job.ts index 7c31e16e81ab..822d14299795 100644 --- a/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/jobs/create-company-and-contact.job.ts +++ b/packages/twenty-server/src/modules/contact-creation-manager/jobs/create-company-and-contact.job.ts @@ -1,28 +1,25 @@ -import { Injectable } from '@nestjs/common'; - -import { MessageQueueJob } from 'src/engine/integrations/message-queue/interfaces/message-queue-job.interface'; - -import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record'; -import { CreateCompanyAndContactService } from 'src/modules/connected-account/auto-companies-and-contacts-creation/services/create-company-and-contact.service'; +import { Process } from 'src/engine/integrations/message-queue/decorators/process.decorator'; +import { Processor } from 'src/engine/integrations/message-queue/decorators/processor.decorator'; +import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; +import { CreateCompanyAndContactService } from 'src/modules/contact-creation-manager/services/create-company-and-contact.service'; export type CreateCompanyAndContactJobData = { workspaceId: string; - connectedAccount: ObjectRecord<ConnectedAccountWorkspaceEntity>; + connectedAccount: ConnectedAccountWorkspaceEntity; contactsToCreate: { displayName: string; handle: string; }[]; }; -@Injectable() -export class CreateCompanyAndContactJob - implements MessageQueueJob<CreateCompanyAndContactJobData> -{ +@Processor(MessageQueue.contactCreationQueue) +export class CreateCompanyAndContactJob { constructor( private readonly createCompanyAndContactService: CreateCompanyAndContactService, ) {} + @Process(CreateCompanyAndContactJob.name) async handle(data: CreateCompanyAndContactJobData): Promise<void> { const { workspaceId, connectedAccount, contactsToCreate } = data; diff --git a/packages/twenty-server/src/modules/calendar/listeners/calendar-channel.listener.ts b/packages/twenty-server/src/modules/contact-creation-manager/listeners/auto-companies-and-contacts-creation-calendar-channel.listener.ts similarity index 78% rename from packages/twenty-server/src/modules/calendar/listeners/calendar-channel.listener.ts rename to packages/twenty-server/src/modules/contact-creation-manager/listeners/auto-companies-and-contacts-creation-calendar-channel.listener.ts index 3d1e28a557ab..51104de273c4 100644 --- a/packages/twenty-server/src/modules/calendar/listeners/calendar-channel.listener.ts +++ b/packages/twenty-server/src/modules/contact-creation-manager/listeners/auto-companies-and-contacts-creation-calendar-channel.listener.ts @@ -1,20 +1,21 @@ -import { Inject, Injectable } from '@nestjs/common'; +import { Injectable } from '@nestjs/common'; import { OnEvent } from '@nestjs/event-emitter'; import { ObjectRecordUpdateEvent } from 'src/engine/integrations/event-emitter/types/object-record-update.event'; import { objectRecordChangedProperties } from 'src/engine/integrations/event-emitter/utils/object-record-changed-properties.util'; +import { InjectMessageQueue } from 'src/engine/integrations/message-queue/decorators/message-queue.decorator'; import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service'; import { CalendarCreateCompanyAndContactAfterSyncJobData, CalendarCreateCompanyAndContactAfterSyncJob, -} from 'src/modules/calendar/jobs/calendar-create-company-and-contact-after-sync.job'; +} from 'src/modules/calendar/calendar-event-participant-manager/jobs/calendar-create-company-and-contact-after-sync.job'; import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity'; @Injectable() -export class CalendarChannelListener { +export class AutoCompaniesAndContactsCreationCalendarChannelListener { constructor( - @Inject(MessageQueue.calendarQueue) + @InjectMessageQueue(MessageQueue.calendarQueue) private readonly messageQueueService: MessageQueueService, ) {} diff --git a/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/listeners/messaging-message-channel.listener.ts b/packages/twenty-server/src/modules/contact-creation-manager/listeners/auto-companies-and-contacts-creation-message-channel.listener.ts similarity index 78% rename from packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/listeners/messaging-message-channel.listener.ts rename to packages/twenty-server/src/modules/contact-creation-manager/listeners/auto-companies-and-contacts-creation-message-channel.listener.ts index 6b3cde3987be..f1d6362d45a9 100644 --- a/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/listeners/messaging-message-channel.listener.ts +++ b/packages/twenty-server/src/modules/contact-creation-manager/listeners/auto-companies-and-contacts-creation-message-channel.listener.ts @@ -1,20 +1,21 @@ -import { Inject, Injectable } from '@nestjs/common'; +import { Injectable } from '@nestjs/common'; import { OnEvent } from '@nestjs/event-emitter'; import { ObjectRecordUpdateEvent } from 'src/engine/integrations/event-emitter/types/object-record-update.event'; import { objectRecordChangedProperties } from 'src/engine/integrations/event-emitter/utils/object-record-changed-properties.util'; +import { InjectMessageQueue } from 'src/engine/integrations/message-queue/decorators/message-queue.decorator'; import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service'; import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity'; import { MessagingCreateCompanyAndContactAfterSyncJobData, MessagingCreateCompanyAndContactAfterSyncJob, -} from 'src/modules/messaging/message-participants-manager/jobs/messaging-create-company-and-contact-after-sync.job'; +} from 'src/modules/messaging/message-participant-manager/jobs/messaging-create-company-and-contact-after-sync.job'; @Injectable() -export class MessagingMessageChannelListener { +export class AutoCompaniesAndContactsCreationMessageChannelListener { constructor( - @Inject(MessageQueue.messagingQueue) + @InjectMessageQueue(MessageQueue.contactCreationQueue) private readonly messageQueueService: MessageQueueService, ) {} diff --git a/packages/twenty-server/src/modules/contact-creation-manager/services/create-company-and-contact.service.ts b/packages/twenty-server/src/modules/contact-creation-manager/services/create-company-and-contact.service.ts new file mode 100644 index 000000000000..14a984cb27d8 --- /dev/null +++ b/packages/twenty-server/src/modules/contact-creation-manager/services/create-company-and-contact.service.ts @@ -0,0 +1,169 @@ +import { Injectable } from '@nestjs/common'; +import { EventEmitter2 } from '@nestjs/event-emitter'; +import { InjectRepository } from '@nestjs/typeorm'; + +import chunk from 'lodash.chunk'; +import compact from 'lodash.compact'; +import { EntityManager, Repository } from 'typeorm'; + +import { ObjectRecordCreateEvent } from 'src/engine/integrations/event-emitter/types/object-record-create.event'; +import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; +import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; +import { STANDARD_OBJECT_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-object-ids'; +import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; +import { CONTACTS_CREATION_BATCH_SIZE } from 'src/modules/contact-creation-manager/constants/contacts-creation-batch-size.constant'; +import { CreateCompanyService } from 'src/modules/contact-creation-manager/services/create-company.service'; +import { CreateContactService } from 'src/modules/contact-creation-manager/services/create-contact.service'; +import { Contact } from 'src/modules/contact-creation-manager/types/contact.type'; +import { filterOutSelfAndContactsFromCompanyOrWorkspace } from 'src/modules/contact-creation-manager/utils/filter-out-contacts-from-company-or-workspace.util'; +import { getDomainNameFromHandle } from 'src/modules/contact-creation-manager/utils/get-domain-name-from-handle.util'; +import { getUniqueContactsAndHandles } from 'src/modules/contact-creation-manager/utils/get-unique-contacts-and-handles.util'; +import { PersonRepository } from 'src/modules/person/repositories/person.repository'; +import { PersonWorkspaceEntity } from 'src/modules/person/standard-objects/person.workspace-entity'; +import { WorkspaceMemberRepository } from 'src/modules/workspace-member/repositories/workspace-member.repository'; +import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; +import { isWorkEmail } from 'src/utils/is-work-email'; + +@Injectable() +export class CreateCompanyAndContactService { + constructor( + private readonly createContactService: CreateContactService, + private readonly createCompaniesService: CreateCompanyService, + @InjectObjectMetadataRepository(PersonWorkspaceEntity) + private readonly personRepository: PersonRepository, + @InjectObjectMetadataRepository(WorkspaceMemberWorkspaceEntity) + private readonly workspaceMemberRepository: WorkspaceMemberRepository, + private readonly eventEmitter: EventEmitter2, + @InjectRepository(ObjectMetadataEntity, 'metadata') + private readonly objectMetadataRepository: Repository<ObjectMetadataEntity>, + ) {} + + private async createCompaniesAndPeople( + connectedAccount: ConnectedAccountWorkspaceEntity, + contactsToCreate: Contact[], + workspaceId: string, + transactionManager?: EntityManager, + ): Promise<PersonWorkspaceEntity[]> { + if (!contactsToCreate || contactsToCreate.length === 0) { + return []; + } + + const workspaceMembers = + await this.workspaceMemberRepository.getAllByWorkspaceId( + workspaceId, + transactionManager, + ); + + const contactsToCreateFromOtherCompanies = + filterOutSelfAndContactsFromCompanyOrWorkspace( + contactsToCreate, + connectedAccount, + workspaceMembers, + ); + + const { uniqueContacts, uniqueHandles } = getUniqueContactsAndHandles( + contactsToCreateFromOtherCompanies, + ); + + if (uniqueHandles.length === 0) { + return []; + } + + const alreadyCreatedContacts = await this.personRepository.getByEmails( + uniqueHandles, + workspaceId, + transactionManager, + ); + + const alreadyCreatedContactEmails: string[] = alreadyCreatedContacts?.map( + ({ email }) => email, + ); + + const filteredContactsToCreate = uniqueContacts.filter( + (participant) => + !alreadyCreatedContactEmails.includes(participant.handle) && + participant.handle.includes('@'), + ); + + const filteredContactsToCreateWithCompanyDomainNames = + filteredContactsToCreate?.map((participant) => ({ + handle: participant.handle, + displayName: participant.displayName, + companyDomainName: isWorkEmail(participant.handle) + ? getDomainNameFromHandle(participant.handle) + : undefined, + })); + + const domainNamesToCreate = compact( + filteredContactsToCreateWithCompanyDomainNames.map( + (participant) => participant.companyDomainName, + ), + ); + + const companiesObject = await this.createCompaniesService.createCompanies( + domainNamesToCreate, + workspaceId, + transactionManager, + ); + + const formattedContactsToCreate = + filteredContactsToCreateWithCompanyDomainNames.map((contact) => ({ + handle: contact.handle, + displayName: contact.displayName, + companyId: + contact.companyDomainName && contact.companyDomainName !== '' + ? companiesObject[contact.companyDomainName] + : undefined, + })); + + return await this.createContactService.createPeople( + formattedContactsToCreate, + workspaceId, + transactionManager, + ); + } + + async createCompaniesAndContactsAndUpdateParticipants( + connectedAccount: ConnectedAccountWorkspaceEntity, + contactsToCreate: Contact[], + workspaceId: string, + ) { + const contactsBatches = chunk( + contactsToCreate, + CONTACTS_CREATION_BATCH_SIZE, + ); + + // TODO: Remove this when events are emitted directly inside TwentyORM + + const objectMetadata = await this.objectMetadataRepository.findOne({ + where: { + standardId: STANDARD_OBJECT_IDS.person, + workspaceId, + }, + }); + + if (!objectMetadata) { + throw new Error('Object metadata not found'); + } + + for (const contactsBatch of contactsBatches) { + const createdPeople = await this.createCompaniesAndPeople( + connectedAccount, + contactsBatch, + workspaceId, + ); + + for (const createdPerson of createdPeople) { + this.eventEmitter.emit('person.created', { + name: 'person.created', + workspaceId, + recordId: createdPerson.id, + objectMetadata, + properties: { + after: createdPerson, + }, + } satisfies ObjectRecordCreateEvent<any>); + } + } + } +} diff --git a/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/create-company/create-company.service.ts b/packages/twenty-server/src/modules/contact-creation-manager/services/create-company.service.ts similarity index 92% rename from packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/create-company/create-company.service.ts rename to packages/twenty-server/src/modules/contact-creation-manager/services/create-company.service.ts index 2721623e948b..266bdad128bd 100644 --- a/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/create-company/create-company.service.ts +++ b/packages/twenty-server/src/modules/contact-creation-manager/services/create-company.service.ts @@ -1,13 +1,13 @@ import { Injectable } from '@nestjs/common'; +import axios, { AxiosInstance } from 'axios'; import { EntityManager } from 'typeorm'; import { v4 } from 'uuid'; -import axios, { AxiosInstance } from 'axios'; -import { CompanyRepository } from 'src/modules/company/repositories/company.repository'; -import { getCompanyNameFromDomainName } from 'src/modules/calendar-messaging-participant/utils/get-company-name-from-domain-name.util'; import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; +import { CompanyRepository } from 'src/modules/company/repositories/company.repository'; import { CompanyWorkspaceEntity } from 'src/modules/company/standard-objects/company.workspace-entity'; +import { getCompanyNameFromDomainName } from 'src/modules/contact-creation-manager/utils/get-company-name-from-domain-name.util'; @Injectable() export class CreateCompanyService { private readonly httpService: AxiosInstance; @@ -76,7 +76,7 @@ export class CreateCompanyService { return companiesObject; } - async createCompany( + private async createCompany( domainName: string, workspaceId: string, transactionManager?: EntityManager, @@ -99,7 +99,7 @@ export class CreateCompanyService { return companyId; } - async getCompanyInfoFromDomainName(domainName: string): Promise<{ + private async getCompanyInfoFromDomainName(domainName: string): Promise<{ name: string; city: string; }> { diff --git a/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/create-contact/create-contact.service.ts b/packages/twenty-server/src/modules/contact-creation-manager/services/create-contact.service.ts similarity index 85% rename from packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/create-contact/create-contact.service.ts rename to packages/twenty-server/src/modules/contact-creation-manager/services/create-contact.service.ts index a8a121526b83..775525c5af77 100644 --- a/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/create-contact/create-contact.service.ts +++ b/packages/twenty-server/src/modules/contact-creation-manager/services/create-contact.service.ts @@ -3,11 +3,10 @@ import { Injectable } from '@nestjs/common'; import { EntityManager } from 'typeorm'; import { v4 } from 'uuid'; -import { PersonRepository } from 'src/modules/person/repositories/person.repository'; -import { getFirstNameAndLastNameFromHandleAndDisplayName } from 'src/modules/calendar-messaging-participant/utils/get-first-name-and-last-name-from-handle-and-display-name.util'; import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; +import { getFirstNameAndLastNameFromHandleAndDisplayName } from 'src/modules/contact-creation-manager/utils/get-first-name-and-last-name-from-handle-and-display-name.util'; +import { PersonRepository } from 'src/modules/person/repositories/person.repository'; import { PersonWorkspaceEntity } from 'src/modules/person/standard-objects/person.workspace-entity'; -import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record'; type ContactToCreate = { handle: string; @@ -30,7 +29,7 @@ export class CreateContactService { private readonly personRepository: PersonRepository, ) {} - public formatContacts( + private formatContacts( contactsToCreate: ContactToCreate[], ): FormattedContactToCreate[] { return contactsToCreate.map((contact) => { @@ -55,7 +54,7 @@ export class CreateContactService { contactsToCreate: ContactToCreate[], workspaceId: string, transactionManager?: EntityManager, - ): Promise<ObjectRecord<PersonWorkspaceEntity>[]> { + ): Promise<PersonWorkspaceEntity[]> { if (contactsToCreate.length === 0) return []; const formattedContacts = this.formatContacts(contactsToCreate); diff --git a/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/types/contact.type.ts b/packages/twenty-server/src/modules/contact-creation-manager/types/contact.type.ts similarity index 66% rename from packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/types/contact.type.ts rename to packages/twenty-server/src/modules/contact-creation-manager/types/contact.type.ts index 0cd41a5b768c..40424311387a 100644 --- a/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/types/contact.type.ts +++ b/packages/twenty-server/src/modules/contact-creation-manager/types/contact.type.ts @@ -2,5 +2,3 @@ export type Contact = { handle: string; displayName: string; }; - -export type Contacts = Contact[]; diff --git a/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/utils/__tests__/get-unique-contacts-and-handles.spec.ts b/packages/twenty-server/src/modules/contact-creation-manager/utils/__tests__/get-unique-contacts-and-handles.spec.ts similarity index 74% rename from packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/utils/__tests__/get-unique-contacts-and-handles.spec.ts rename to packages/twenty-server/src/modules/contact-creation-manager/utils/__tests__/get-unique-contacts-and-handles.spec.ts index 87537a8e88b4..7bafaa4aaddc 100644 --- a/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/utils/__tests__/get-unique-contacts-and-handles.spec.ts +++ b/packages/twenty-server/src/modules/contact-creation-manager/utils/__tests__/get-unique-contacts-and-handles.spec.ts @@ -1,9 +1,9 @@ -import { Contacts } from 'src/modules/connected-account/auto-companies-and-contacts-creation/types/contact.type'; -import { getUniqueContactsAndHandles } from 'src/modules/connected-account/auto-companies-and-contacts-creation/utils/get-unique-contacts-and-handles.util'; +import { Contact } from 'src/modules/contact-creation-manager/types/contact.type'; +import { getUniqueContactsAndHandles } from 'src/modules/contact-creation-manager/utils/get-unique-contacts-and-handles.util'; describe('getUniqueContactsAndHandles', () => { it('should return empty arrays when contacts is empty', () => { - const contacts: Contacts = []; + const contacts: Contact[] = []; const result = getUniqueContactsAndHandles(contacts); expect(result.uniqueContacts).toEqual([]); @@ -11,7 +11,7 @@ describe('getUniqueContactsAndHandles', () => { }); it('should return unique contacts and handles', () => { - const contacts: Contacts = [ + const contacts: Contact[] = [ { handle: 'john@twenty.com', displayName: 'John Doe' }, { handle: 'john@twenty.com', displayName: 'John Doe' }, { handle: 'jane@twenty.com', displayName: 'Jane Smith' }, diff --git a/packages/twenty-server/src/modules/contact-creation-manager/utils/filter-out-contacts-from-company-or-workspace.util.ts b/packages/twenty-server/src/modules/contact-creation-manager/utils/filter-out-contacts-from-company-or-workspace.util.ts new file mode 100644 index 000000000000..42ecfd59d094 --- /dev/null +++ b/packages/twenty-server/src/modules/contact-creation-manager/utils/filter-out-contacts-from-company-or-workspace.util.ts @@ -0,0 +1,30 @@ +import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; +import { Contact } from 'src/modules/contact-creation-manager/types/contact.type'; +import { getDomainNameFromHandle } from 'src/modules/contact-creation-manager/utils/get-domain-name-from-handle.util'; +import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; + +export function filterOutSelfAndContactsFromCompanyOrWorkspace( + contacts: Contact[], + connectedAccount: ConnectedAccountWorkspaceEntity, + workspaceMembers: WorkspaceMemberWorkspaceEntity[], +): Contact[] { + const selfDomainName = getDomainNameFromHandle(connectedAccount.handle); + + const handleAliases = connectedAccount.handleAliases?.split(',') || []; + + const workspaceMembersMap = workspaceMembers.reduce( + (map, workspaceMember) => { + map[workspaceMember.userEmail] = true; + + return map; + }, + new Map<string, boolean>(), + ); + + return contacts.filter( + (contact) => + getDomainNameFromHandle(contact.handle) !== selfDomainName && + !workspaceMembersMap[contact.handle] && + !handleAliases.includes(contact.handle), + ); +} diff --git a/packages/twenty-server/src/modules/calendar-messaging-participant/utils/get-company-name-from-domain-name.util.ts b/packages/twenty-server/src/modules/contact-creation-manager/utils/get-company-name-from-domain-name.util.ts similarity index 100% rename from packages/twenty-server/src/modules/calendar-messaging-participant/utils/get-company-name-from-domain-name.util.ts rename to packages/twenty-server/src/modules/contact-creation-manager/utils/get-company-name-from-domain-name.util.ts diff --git a/packages/twenty-server/src/modules/calendar-messaging-participant/utils/get-domain-name-from-handle.util.ts b/packages/twenty-server/src/modules/contact-creation-manager/utils/get-domain-name-from-handle.util.ts similarity index 100% rename from packages/twenty-server/src/modules/calendar-messaging-participant/utils/get-domain-name-from-handle.util.ts rename to packages/twenty-server/src/modules/contact-creation-manager/utils/get-domain-name-from-handle.util.ts diff --git a/packages/twenty-server/src/modules/calendar-messaging-participant/utils/get-first-name-and-last-name-from-handle-and-display-name.util.ts b/packages/twenty-server/src/modules/contact-creation-manager/utils/get-first-name-and-last-name-from-handle-and-display-name.util.ts similarity index 100% rename from packages/twenty-server/src/modules/calendar-messaging-participant/utils/get-first-name-and-last-name-from-handle-and-display-name.util.ts rename to packages/twenty-server/src/modules/contact-creation-manager/utils/get-first-name-and-last-name-from-handle-and-display-name.util.ts diff --git a/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/utils/get-unique-contacts-and-handles.util.ts b/packages/twenty-server/src/modules/contact-creation-manager/utils/get-unique-contacts-and-handles.util.ts similarity index 64% rename from packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/utils/get-unique-contacts-and-handles.util.ts rename to packages/twenty-server/src/modules/contact-creation-manager/utils/get-unique-contacts-and-handles.util.ts index a6296e3d982a..26cd2e892628 100644 --- a/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/utils/get-unique-contacts-and-handles.util.ts +++ b/packages/twenty-server/src/modules/contact-creation-manager/utils/get-unique-contacts-and-handles.util.ts @@ -1,10 +1,10 @@ import uniq from 'lodash.uniq'; import uniqBy from 'lodash.uniqby'; -import { Contacts } from 'src/modules/connected-account/auto-companies-and-contacts-creation/types/contact.type'; +import { Contact } from 'src/modules/contact-creation-manager/types/contact.type'; -export function getUniqueContactsAndHandles(contacts: Contacts): { - uniqueContacts: Contacts; +export function getUniqueContactsAndHandles(contacts: Contact[]): { + uniqueContacts: Contact[]; uniqueHandles: string[]; } { if (contacts.length === 0) { diff --git a/packages/twenty-server/src/modules/favorite/standard-objects/favorite.workspace-entity.ts b/packages/twenty-server/src/modules/favorite/standard-objects/favorite.workspace-entity.ts index 6c1f81b6b3b3..705c62d32f71 100644 --- a/packages/twenty-server/src/modules/favorite/standard-objects/favorite.workspace-entity.ts +++ b/packages/twenty-server/src/modules/favorite/standard-objects/favorite.workspace-entity.ts @@ -17,6 +17,7 @@ import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-re import { RelationMetadataType } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity'; import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator'; import { WorkspaceDynamicRelation } from 'src/engine/twenty-orm/decorators/workspace-dynamic-relation.decorator'; +import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator'; @WorkspaceEntity({ standardId: STANDARD_OBJECT_IDS.favorite, @@ -46,24 +47,28 @@ export class FavoriteWorkspaceEntity extends BaseWorkspaceEntity { label: 'Workspace Member', description: 'Favorite workspace member', icon: 'IconCircleUser', - joinColumn: 'workspaceMemberId', inverseSideFieldKey: 'favorites', inverseSideTarget: () => WorkspaceMemberWorkspaceEntity, }) workspaceMember: Relation<WorkspaceMemberWorkspaceEntity>; + @WorkspaceJoinColumn('workspaceMember') + workspaceMemberId: string; + @WorkspaceRelation({ standardId: FAVORITE_STANDARD_FIELD_IDS.person, type: RelationMetadataType.MANY_TO_ONE, label: 'Person', description: 'Favorite person', icon: 'IconUser', - joinColumn: 'personId', inverseSideTarget: () => PersonWorkspaceEntity, inverseSideFieldKey: 'favorites', }) @WorkspaceIsNullable() - person: Relation<PersonWorkspaceEntity>; + person: Relation<PersonWorkspaceEntity> | null; + + @WorkspaceJoinColumn('person') + personId: string; @WorkspaceRelation({ standardId: FAVORITE_STANDARD_FIELD_IDS.company, @@ -71,12 +76,14 @@ export class FavoriteWorkspaceEntity extends BaseWorkspaceEntity { label: 'Company', description: 'Favorite company', icon: 'IconBuildingSkyscraper', - joinColumn: 'companyId', inverseSideTarget: () => CompanyWorkspaceEntity, inverseSideFieldKey: 'favorites', }) @WorkspaceIsNullable() - company: Relation<CompanyWorkspaceEntity>; + company: Relation<CompanyWorkspaceEntity> | null; + + @WorkspaceJoinColumn('company') + companyId: string; @WorkspaceRelation({ standardId: FAVORITE_STANDARD_FIELD_IDS.opportunity, @@ -84,12 +91,14 @@ export class FavoriteWorkspaceEntity extends BaseWorkspaceEntity { label: 'Opportunity', description: 'Favorite opportunity', icon: 'IconTargetArrow', - joinColumn: 'opportunityId', inverseSideTarget: () => OpportunityWorkspaceEntity, inverseSideFieldKey: 'favorites', }) @WorkspaceIsNullable() - opportunity: Relation<OpportunityWorkspaceEntity>; + opportunity: Relation<OpportunityWorkspaceEntity> | null; + + @WorkspaceJoinColumn('opportunity') + opportunityId: string; @WorkspaceDynamicRelation({ type: RelationMetadataType.MANY_TO_ONE, diff --git a/packages/twenty-server/src/modules/messaging/blocklist-manager/jobs/messaging-blocklist-item-delete-messages.job.ts b/packages/twenty-server/src/modules/messaging/blocklist-manager/jobs/messaging-blocklist-item-delete-messages.job.ts index 3a52e42deb17..a2941c679d1e 100644 --- a/packages/twenty-server/src/modules/messaging/blocklist-manager/jobs/messaging-blocklist-item-delete-messages.job.ts +++ b/packages/twenty-server/src/modules/messaging/blocklist-manager/jobs/messaging-blocklist-item-delete-messages.job.ts @@ -1,10 +1,11 @@ -import { Injectable, Logger } from '@nestjs/common'; - -import { MessageQueueJob } from 'src/engine/integrations/message-queue/interfaces/message-queue-job.interface'; +import { Logger, Scope } from '@nestjs/common'; +import { Process } from 'src/engine/integrations/message-queue/decorators/process.decorator'; +import { Processor } from 'src/engine/integrations/message-queue/decorators/processor.decorator'; +import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; -import { BlocklistRepository } from 'src/modules/connected-account/repositories/blocklist.repository'; -import { BlocklistWorkspaceEntity } from 'src/modules/connected-account/standard-objects/blocklist.workspace-entity'; +import { BlocklistRepository } from 'src/modules/blocklist/repositories/blocklist.repository'; +import { BlocklistWorkspaceEntity } from 'src/modules/blocklist/standard-objects/blocklist.workspace-entity'; import { MessageChannelMessageAssociationRepository } from 'src/modules/messaging/common/repositories/message-channel-message-association.repository'; import { MessageChannelRepository } from 'src/modules/messaging/common/repositories/message-channel.repository'; import { MessageChannelMessageAssociationWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel-message-association.workspace-entity'; @@ -16,10 +17,11 @@ export type BlocklistItemDeleteMessagesJobData = { blocklistItemId: string; }; -@Injectable() -export class BlocklistItemDeleteMessagesJob - implements MessageQueueJob<BlocklistItemDeleteMessagesJobData> -{ +@Processor({ + queueName: MessageQueue.messagingQueue, + scope: Scope.REQUEST, +}) +export class BlocklistItemDeleteMessagesJob { private readonly logger = new Logger(BlocklistItemDeleteMessagesJob.name); constructor( @@ -34,6 +36,7 @@ export class BlocklistItemDeleteMessagesJob private readonly threadCleanerService: MessagingMessageCleanerService, ) {} + @Process(BlocklistItemDeleteMessagesJob.name) async handle(data: BlocklistItemDeleteMessagesJobData): Promise<void> { const { workspaceId, blocklistItemId } = data; @@ -56,6 +59,12 @@ export class BlocklistItemDeleteMessagesJob `Deleting messages from ${handle} in workspace ${workspaceId} for workspace member ${workspaceMemberId}`, ); + if (!workspaceMemberId) { + throw new Error( + `Workspace member ID is not defined for blocklist item ${blocklistItemId} in workspace ${workspaceId}`, + ); + } + const messageChannels = await this.messageChannelRepository.getIdsByWorkspaceMemberId( workspaceMemberId, diff --git a/packages/twenty-server/src/modules/messaging/blocklist-manager/listeners/messaging-blocklist.listener.ts b/packages/twenty-server/src/modules/messaging/blocklist-manager/listeners/messaging-blocklist.listener.ts index c852bb9edb41..60433a2902fc 100644 --- a/packages/twenty-server/src/modules/messaging/blocklist-manager/listeners/messaging-blocklist.listener.ts +++ b/packages/twenty-server/src/modules/messaging/blocklist-manager/listeners/messaging-blocklist.listener.ts @@ -1,19 +1,20 @@ -import { Inject, Injectable } from '@nestjs/common'; +import { Injectable } from '@nestjs/common'; import { OnEvent } from '@nestjs/event-emitter'; import { ObjectRecordCreateEvent } from 'src/engine/integrations/event-emitter/types/object-record-create.event'; import { ObjectRecordDeleteEvent } from 'src/engine/integrations/event-emitter/types/object-record-delete.event'; +import { ObjectRecordUpdateEvent } from 'src/engine/integrations/event-emitter/types/object-record-update.event'; +import { InjectMessageQueue } from 'src/engine/integrations/message-queue/decorators/message-queue.decorator'; import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service'; -import { BlocklistWorkspaceEntity } from 'src/modules/connected-account/standard-objects/blocklist.workspace-entity'; -import { - BlocklistItemDeleteMessagesJobData, - BlocklistItemDeleteMessagesJob, -} from 'src/modules/messaging/blocklist-manager/jobs/messaging-blocklist-item-delete-messages.job'; -import { ObjectRecordUpdateEvent } from 'src/engine/integrations/event-emitter/types/object-record-update.event'; import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; +import { BlocklistWorkspaceEntity } from 'src/modules/blocklist/standard-objects/blocklist.workspace-entity'; import { ConnectedAccountRepository } from 'src/modules/connected-account/repositories/connected-account.repository'; import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; +import { + BlocklistItemDeleteMessagesJob, + BlocklistItemDeleteMessagesJobData, +} from 'src/modules/messaging/blocklist-manager/jobs/messaging-blocklist-item-delete-messages.job'; import { MessageChannelRepository } from 'src/modules/messaging/common/repositories/message-channel.repository'; import { MessagingChannelSyncStatusService } from 'src/modules/messaging/common/services/messaging-channel-sync-status.service'; import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity'; @@ -21,7 +22,7 @@ import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/stan @Injectable() export class MessagingBlocklistListener { constructor( - @Inject(MessageQueue.messagingQueue) + @InjectMessageQueue(MessageQueue.messagingQueue) private readonly messageQueueService: MessageQueueService, @InjectObjectMetadataRepository(ConnectedAccountWorkspaceEntity) private readonly connectedAccountRepository: ConnectedAccountRepository, diff --git a/packages/twenty-server/src/modules/messaging/common/messaging-common.module.ts b/packages/twenty-server/src/modules/messaging/common/messaging-common.module.ts index f13575d948d3..a700e79a7e6e 100644 --- a/packages/twenty-server/src/modules/messaging/common/messaging-common.module.ts +++ b/packages/twenty-server/src/modules/messaging/common/messaging-common.module.ts @@ -6,14 +6,12 @@ import { AnalyticsModule } from 'src/engine/core-modules/analytics/analytics.mod import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity'; import { ObjectMetadataRepositoryModule } from 'src/engine/object-metadata-repository/object-metadata-repository.module'; import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; -import { AddPersonIdAndWorkspaceMemberIdModule } from 'src/modules/calendar-messaging-participant/services/add-person-id-and-workspace-member-id/add-person-id-and-workspace-member-id.module'; +import { AddPersonIdAndWorkspaceMemberIdService } from 'src/modules/calendar-messaging-participant-manager/services/add-person-id-and-workspace-member-id/add-person-id-and-workspace-member-id.service'; import { MessagingChannelSyncStatusService } from 'src/modules/messaging/common/services/messaging-channel-sync-status.service'; import { MessagingErrorHandlingService } from 'src/modules/messaging/common/services/messaging-error-handling.service'; import { MessagingFetchByBatchesService } from 'src/modules/messaging/common/services/messaging-fetch-by-batch.service'; -import { MessagingMessageParticipantService } from 'src/modules/messaging/common/services/messaging-message-participant.service'; import { MessagingMessageThreadService } from 'src/modules/messaging/common/services/messaging-message-thread.service'; import { MessagingMessageService } from 'src/modules/messaging/common/services/messaging-message.service'; -import { MessagingSaveMessagesAndEnqueueContactCreationService } from 'src/modules/messaging/common/services/messaging-save-messages-and-enqueue-contact-creation.service'; import { MessagingTelemetryService } from 'src/modules/messaging/common/services/messaging-telemetry.service'; import { MessageParticipantWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-participant.workspace-entity'; import { MessageThreadWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-thread.workspace-entity'; @@ -34,26 +32,22 @@ import { PersonWorkspaceEntity } from 'src/modules/person/standard-objects/perso MessageThreadWorkspaceEntity, ]), TypeOrmModule.forFeature([FeatureFlagEntity], 'core'), - AddPersonIdAndWorkspaceMemberIdModule, ], providers: [ MessagingMessageService, MessagingMessageThreadService, - MessagingSaveMessagesAndEnqueueContactCreationService, MessagingErrorHandlingService, MessagingTelemetryService, MessagingChannelSyncStatusService, - MessagingMessageParticipantService, MessagingFetchByBatchesService, + AddPersonIdAndWorkspaceMemberIdService, ], exports: [ MessagingMessageService, MessagingMessageThreadService, - MessagingSaveMessagesAndEnqueueContactCreationService, MessagingErrorHandlingService, MessagingTelemetryService, MessagingChannelSyncStatusService, - MessagingMessageParticipantService, MessagingFetchByBatchesService, ], }) diff --git a/packages/twenty-server/src/modules/messaging/common/query-hooks/message/can-access-message-thread.service.ts b/packages/twenty-server/src/modules/messaging/common/query-hooks/message/can-access-message-thread.service.ts index 095523ee6358..f79c972c6100 100644 --- a/packages/twenty-server/src/modules/messaging/common/query-hooks/message/can-access-message-thread.service.ts +++ b/packages/twenty-server/src/modules/messaging/common/query-hooks/message/can-access-message-thread.service.ts @@ -9,6 +9,7 @@ import { MessageChannelRepository } from 'src/modules/messaging/common/repositor import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity'; import { WorkspaceMemberRepository } from 'src/modules/workspace-member/repositories/workspace-member.repository'; import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; +import { isDefined } from 'src/utils/is-defined'; export class CanAccessMessageThreadService { constructor( @@ -46,7 +47,9 @@ export class CanAccessMessageThreadService { const messageChannelsConnectedAccounts = await this.connectedAccountRepository.getByIds( - messageChannels.map((channel) => channel.connectedAccountId), + messageChannels + .map((channel) => channel.connectedAccountId) + .filter(isDefined), workspaceId, ); diff --git a/packages/twenty-server/src/modules/messaging/common/query-hooks/message/message-find-many.pre-query.hook.ts b/packages/twenty-server/src/modules/messaging/common/query-hooks/message/message-find-many.pre-query.hook.ts index 8e82c578afe2..0e2f2a5d79a7 100644 --- a/packages/twenty-server/src/modules/messaging/common/query-hooks/message/message-find-many.pre-query.hook.ts +++ b/packages/twenty-server/src/modules/messaging/common/query-hooks/message/message-find-many.pre-query.hook.ts @@ -1,19 +1,16 @@ -import { - BadRequestException, - Injectable, - NotFoundException, -} from '@nestjs/common'; +import { BadRequestException, NotFoundException } from '@nestjs/common'; -import { WorkspacePreQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-pre-query-hook/interfaces/workspace-pre-query-hook.interface'; +import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface'; import { FindManyResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; +import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator'; import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; import { CanAccessMessageThreadService } from 'src/modules/messaging/common/query-hooks/message/can-access-message-thread.service'; import { MessageChannelMessageAssociationRepository } from 'src/modules/messaging/common/repositories/message-channel-message-association.repository'; import { MessageChannelMessageAssociationWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel-message-association.workspace-entity'; -@Injectable() -export class MessageFindManyPreQueryHook implements WorkspacePreQueryHook { +@WorkspaceQueryHook(`message.findMany`) +export class MessageFindManyPreQueryHook implements WorkspaceQueryHookInstance { constructor( @InjectObjectMetadataRepository( MessageChannelMessageAssociationWorkspaceEntity, diff --git a/packages/twenty-server/src/modules/messaging/common/query-hooks/message/message-find-one.pre-query-hook.ts b/packages/twenty-server/src/modules/messaging/common/query-hooks/message/message-find-one.pre-query-hook.ts index 2140ac01081a..713e024894f6 100644 --- a/packages/twenty-server/src/modules/messaging/common/query-hooks/message/message-find-one.pre-query-hook.ts +++ b/packages/twenty-server/src/modules/messaging/common/query-hooks/message/message-find-one.pre-query-hook.ts @@ -1,16 +1,17 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ -import { Injectable, NotFoundException } from '@nestjs/common'; +import { NotFoundException } from '@nestjs/common'; -import { WorkspacePreQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-pre-query-hook/interfaces/workspace-pre-query-hook.interface'; +import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface'; import { FindOneResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; +import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator'; import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; import { CanAccessMessageThreadService } from 'src/modules/messaging/common/query-hooks/message/can-access-message-thread.service'; import { MessageChannelMessageAssociationRepository } from 'src/modules/messaging/common/repositories/message-channel-message-association.repository'; import { MessageChannelMessageAssociationWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel-message-association.workspace-entity'; -@Injectable() -export class MessageFindOnePreQueryHook implements WorkspacePreQueryHook { +@WorkspaceQueryHook(`message.findOne`) +export class MessageFindOnePreQueryHook implements WorkspaceQueryHookInstance { constructor( @InjectObjectMetadataRepository( MessageChannelMessageAssociationWorkspaceEntity, diff --git a/packages/twenty-server/src/modules/messaging/common/query-hooks/messaging-query-hook.module.ts b/packages/twenty-server/src/modules/messaging/common/query-hooks/messaging-query-hook.module.ts index f27adf462af7..4268de828017 100644 --- a/packages/twenty-server/src/modules/messaging/common/query-hooks/messaging-query-hook.module.ts +++ b/packages/twenty-server/src/modules/messaging/common/query-hooks/messaging-query-hook.module.ts @@ -20,14 +20,8 @@ import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/stan ], providers: [ CanAccessMessageThreadService, - { - provide: MessageFindOnePreQueryHook.name, - useClass: MessageFindOnePreQueryHook, - }, - { - provide: MessageFindManyPreQueryHook.name, - useClass: MessageFindManyPreQueryHook, - }, + MessageFindOnePreQueryHook, + MessageFindManyPreQueryHook, ], }) export class MessagingQueryHookModule {} diff --git a/packages/twenty-server/src/modules/messaging/common/repositories/message-channel-message-association.repository.ts b/packages/twenty-server/src/modules/messaging/common/repositories/message-channel-message-association.repository.ts index 8699a7670f3a..e9b0ffa0d56a 100644 --- a/packages/twenty-server/src/modules/messaging/common/repositories/message-channel-message-association.repository.ts +++ b/packages/twenty-server/src/modules/messaging/common/repositories/message-channel-message-association.repository.ts @@ -3,7 +3,6 @@ import { Injectable } from '@nestjs/common'; import { EntityManager } from 'typeorm'; import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; -import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record'; import { MessageChannelMessageAssociationWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel-message-association.workspace-entity'; @Injectable() @@ -17,7 +16,7 @@ export class MessageChannelMessageAssociationRepository { messageChannelId: string, workspaceId: string, transactionManager?: EntityManager, - ): Promise<ObjectRecord<MessageChannelMessageAssociationWorkspaceEntity>[]> { + ): Promise<MessageChannelMessageAssociationWorkspaceEntity[]> { const dataSourceSchema = this.workspaceDataSourceService.getSchemaName(workspaceId); @@ -130,7 +129,7 @@ export class MessageChannelMessageAssociationRepository { messageChannelIds: string[], workspaceId: string, transactionManager?: EntityManager, - ): Promise<ObjectRecord<MessageChannelMessageAssociationWorkspaceEntity>[]> { + ): Promise<MessageChannelMessageAssociationWorkspaceEntity[]> { const dataSourceSchema = this.workspaceDataSourceService.getSchemaName(workspaceId); @@ -183,7 +182,7 @@ export class MessageChannelMessageAssociationRepository { messageThreadExternalIds: string[], workspaceId: string, transactionManager?: EntityManager, - ): Promise<ObjectRecord<MessageChannelMessageAssociationWorkspaceEntity>[]> { + ): Promise<MessageChannelMessageAssociationWorkspaceEntity[]> { const dataSourceSchema = this.workspaceDataSourceService.getSchemaName(workspaceId); @@ -200,7 +199,7 @@ export class MessageChannelMessageAssociationRepository { messageThreadExternalId: string, workspaceId: string, transactionManager?: EntityManager, - ): Promise<ObjectRecord<MessageChannelMessageAssociationWorkspaceEntity> | null> { + ): Promise<MessageChannelMessageAssociationWorkspaceEntity | null> { const existingMessageChannelMessageAssociations = await this.getByMessageThreadExternalIds( [messageThreadExternalId], @@ -222,7 +221,7 @@ export class MessageChannelMessageAssociationRepository { messageIds: string[], workspaceId: string, transactionManager?: EntityManager, - ): Promise<ObjectRecord<MessageChannelMessageAssociationWorkspaceEntity>[]> { + ): Promise<MessageChannelMessageAssociationWorkspaceEntity[]> { const dataSourceSchema = this.workspaceDataSourceService.getSchemaName(workspaceId); @@ -239,7 +238,7 @@ export class MessageChannelMessageAssociationRepository { messageThreadId: string, workspaceId: string, transactionManager?: EntityManager, - ): Promise<ObjectRecord<MessageChannelMessageAssociationWorkspaceEntity>[]> { + ): Promise<MessageChannelMessageAssociationWorkspaceEntity[]> { const dataSourceSchema = this.workspaceDataSourceService.getSchemaName(workspaceId); diff --git a/packages/twenty-server/src/modules/messaging/common/repositories/message-channel.repository.ts b/packages/twenty-server/src/modules/messaging/common/repositories/message-channel.repository.ts index a3a8c727ca11..3e46454fb732 100644 --- a/packages/twenty-server/src/modules/messaging/common/repositories/message-channel.repository.ts +++ b/packages/twenty-server/src/modules/messaging/common/repositories/message-channel.repository.ts @@ -3,7 +3,6 @@ import { Injectable } from '@nestjs/common'; import { EntityManager } from 'typeorm'; import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; -import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record'; import { MessageChannelWorkspaceEntity, MessageChannelSyncStatus, @@ -18,7 +17,7 @@ export class MessageChannelRepository { public async create( messageChannel: Pick< - ObjectRecord<MessageChannelWorkspaceEntity>, + MessageChannelWorkspaceEntity, | 'id' | 'connectedAccountId' | 'type' @@ -57,7 +56,11 @@ export class MessageChannelRepository { this.workspaceDataSourceService.getSchemaName(workspaceId); await this.workspaceDataSourceService.executeRawQuery( - `UPDATE ${dataSourceSchema}."messageChannel" SET "syncStatus" = NULL, "syncCursor" = '', "syncStageStartedAt" = NULL + `UPDATE ${dataSourceSchema}."messageChannel" + SET "syncStatus" = NULL, + "syncStage" = '${MessageChannelSyncStage.FULL_MESSAGE_LIST_FETCH_PENDING}', + "syncCursor" = '', + "syncStageStartedAt" = NULL WHERE "connectedAccountId" = $1`, [connectedAccountId], workspaceId, @@ -68,7 +71,7 @@ export class MessageChannelRepository { public async getAll( workspaceId: string, transactionManager?: EntityManager, - ): Promise<ObjectRecord<MessageChannelWorkspaceEntity>[]> { + ): Promise<MessageChannelWorkspaceEntity[]> { const dataSourceSchema = this.workspaceDataSourceService.getSchemaName(workspaceId); @@ -84,7 +87,7 @@ export class MessageChannelRepository { connectedAccountId: string, workspaceId: string, transactionManager?: EntityManager, - ): Promise<ObjectRecord<MessageChannelWorkspaceEntity>[]> { + ): Promise<MessageChannelWorkspaceEntity[]> { const dataSourceSchema = this.workspaceDataSourceService.getSchemaName(workspaceId); @@ -99,7 +102,7 @@ export class MessageChannelRepository { public async getFirstByConnectedAccountIdOrFail( connectedAccountId: string, workspaceId: string, - ): Promise<ObjectRecord<MessageChannelWorkspaceEntity>> { + ): Promise<MessageChannelWorkspaceEntity> { const messageChannel = await this.getFirstByConnectedAccountId( connectedAccountId, workspaceId, @@ -118,7 +121,7 @@ export class MessageChannelRepository { connectedAccountId: string, workspaceId: string, transactionManager?: EntityManager, - ): Promise<ObjectRecord<MessageChannelWorkspaceEntity> | undefined> { + ): Promise<MessageChannelWorkspaceEntity | undefined> { const messageChannels = await this.getByConnectedAccountId( connectedAccountId, workspaceId, @@ -132,7 +135,7 @@ export class MessageChannelRepository { ids: string[], workspaceId: string, transactionManager?: EntityManager, - ): Promise<ObjectRecord<MessageChannelWorkspaceEntity>[]> { + ): Promise<MessageChannelWorkspaceEntity[]> { const dataSourceSchema = this.workspaceDataSourceService.getSchemaName(workspaceId); @@ -148,7 +151,7 @@ export class MessageChannelRepository { id: string, workspaceId: string, transactionManager?: EntityManager, - ): Promise<ObjectRecord<MessageChannelWorkspaceEntity>> { + ): Promise<MessageChannelWorkspaceEntity> { const dataSourceSchema = this.workspaceDataSourceService.getSchemaName(workspaceId); @@ -167,7 +170,7 @@ export class MessageChannelRepository { workspaceMemberId: string, workspaceId: string, transactionManager?: EntityManager, - ): Promise<ObjectRecord<MessageChannelWorkspaceEntity>[]> { + ): Promise<MessageChannelWorkspaceEntity[]> { const dataSourceSchema = this.workspaceDataSourceService.getSchemaName(workspaceId); diff --git a/packages/twenty-server/src/modules/messaging/common/repositories/message-participant.repository.ts b/packages/twenty-server/src/modules/messaging/common/repositories/message-participant.repository.ts index 7d6515ae4a3b..2cb2214f1168 100644 --- a/packages/twenty-server/src/modules/messaging/common/repositories/message-participant.repository.ts +++ b/packages/twenty-server/src/modules/messaging/common/repositories/message-participant.repository.ts @@ -3,7 +3,6 @@ import { Injectable } from '@nestjs/common'; import { EntityManager } from 'typeorm'; import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; -import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record'; import { MessageParticipantWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-participant.workspace-entity'; import { ParticipantWithId } from 'src/modules/messaging/message-import-manager/drivers/gmail/types/gmail-message'; @@ -17,7 +16,7 @@ export class MessageParticipantRepository { handles: string[], workspaceId: string, transactionManager?: EntityManager, - ): Promise<ObjectRecord<MessageParticipantWorkspaceEntity>[]> { + ): Promise<MessageParticipantWorkspaceEntity[]> { const dataSourceSchema = this.workspaceDataSourceService.getSchemaName(workspaceId); diff --git a/packages/twenty-server/src/modules/messaging/common/repositories/message.repository.ts b/packages/twenty-server/src/modules/messaging/common/repositories/message.repository.ts index ed75638c1f01..5f1d3eb25a4c 100644 --- a/packages/twenty-server/src/modules/messaging/common/repositories/message.repository.ts +++ b/packages/twenty-server/src/modules/messaging/common/repositories/message.repository.ts @@ -3,7 +3,6 @@ import { Injectable } from '@nestjs/common'; import { EntityManager } from 'typeorm'; import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; -import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record'; import { MessageWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message.workspace-entity'; @Injectable() @@ -40,7 +39,7 @@ export class MessageRepository { headerMessageId: string, workspaceId: string, transactionManager?: EntityManager, - ): Promise<ObjectRecord<MessageWorkspaceEntity> | null> { + ): Promise<MessageWorkspaceEntity | null> { const dataSourceSchema = this.workspaceDataSourceService.getSchemaName(workspaceId); @@ -62,7 +61,7 @@ export class MessageRepository { messageIds: string[], workspaceId: string, transactionManager?: EntityManager, - ): Promise<ObjectRecord<MessageWorkspaceEntity>[]> { + ): Promise<MessageWorkspaceEntity[]> { const dataSourceSchema = this.workspaceDataSourceService.getSchemaName(workspaceId); @@ -94,7 +93,7 @@ export class MessageRepository { messageThreadIds: string[], workspaceId: string, transactionManager?: EntityManager, - ): Promise<ObjectRecord<MessageWorkspaceEntity>[]> { + ): Promise<MessageWorkspaceEntity[]> { const dataSourceSchema = this.workspaceDataSourceService.getSchemaName(workspaceId); diff --git a/packages/twenty-server/src/modules/messaging/common/services/messaging-channel-sync-status.service.ts b/packages/twenty-server/src/modules/messaging/common/services/messaging-channel-sync-status.service.ts index bf472695a8ec..0e3d3fe179c1 100644 --- a/packages/twenty-server/src/modules/messaging/common/services/messaging-channel-sync-status.service.ts +++ b/packages/twenty-server/src/modules/messaging/common/services/messaging-channel-sync-status.service.ts @@ -57,12 +57,10 @@ export class MessagingChannelSyncStatusService { messageChannelId: string, workspaceId: string, ) { - await this.cacheStorage.setPop( + await this.cacheStorage.del( `messages-to-import:${workspaceId}:gmail:${messageChannelId}`, ); - // TODO: remove nextPageToken from cache - await this.messageChannelRepository.resetSyncCursor( messageChannelId, workspaceId, @@ -126,7 +124,7 @@ export class MessagingChannelSyncStatusService { messageChannelId: string, workspaceId: string, ) { - await this.cacheStorage.setPop( + await this.cacheStorage.del( `messages-to-import:${workspaceId}:gmail:${messageChannelId}`, ); @@ -147,7 +145,7 @@ export class MessagingChannelSyncStatusService { messageChannelId: string, workspaceId: string, ) { - await this.cacheStorage.setPop( + await this.cacheStorage.del( `messages-to-import:${workspaceId}:gmail:${messageChannelId}`, ); diff --git a/packages/twenty-server/src/modules/messaging/common/services/messaging-error-handling.service.ts b/packages/twenty-server/src/modules/messaging/common/services/messaging-error-handling.service.ts index c8cdce1d02a9..2ab9cb8ac185 100644 --- a/packages/twenty-server/src/modules/messaging/common/services/messaging-error-handling.service.ts +++ b/packages/twenty-server/src/modules/messaging/common/services/messaging-error-handling.service.ts @@ -3,7 +3,6 @@ import { Injectable } from '@nestjs/common'; import snakeCase from 'lodash.snakecase'; import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; -import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record'; import { ConnectedAccountRepository } from 'src/modules/connected-account/repositories/connected-account.repository'; import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; import { MessagingTelemetryService } from 'src/modules/messaging/common/services/messaging-telemetry.service'; @@ -36,7 +35,7 @@ export class MessagingErrorHandlingService { public async handleGmailError( error: GmailError, syncStep: SyncStep, - messageChannel: ObjectRecord<MessageChannelWorkspaceEntity>, + messageChannel: MessageChannelWorkspaceEntity, workspaceId: string, ): Promise<void> { const { code, reason } = error; @@ -51,6 +50,21 @@ export class MessagingErrorHandlingService { workspaceId, ); } + if (reason === 'failedPrecondition') { + await this.handleFailedPrecondition( + error, + syncStep, + messageChannel, + workspaceId, + ); + } else { + await this.handleUnknownError( + error, + syncStep, + messageChannel, + workspaceId, + ); + } break; case 404: await this.handleNotFound(error, syncStep, messageChannel, workspaceId); @@ -141,7 +155,7 @@ export class MessagingErrorHandlingService { private async handleRateLimitExceeded( error: GmailError, syncStep: SyncStep, - messageChannel: ObjectRecord<MessageChannelWorkspaceEntity>, + messageChannel: MessageChannelWorkspaceEntity, workspaceId: string, ): Promise<void> { await this.messagingTelemetryService.track({ @@ -152,50 +166,30 @@ export class MessagingErrorHandlingService { message: `${error.code}: ${error.reason}`, }); - if ( - messageChannel.throttleFailureCount >= MESSAGING_THROTTLE_MAX_ATTEMPTS - ) { - await this.messagingChannelSyncStatusService.markAsFailedUnknownAndFlushMessagesToImport( - messageChannel.id, - workspaceId, - ); - - return; - } - - await this.throttle(messageChannel, workspaceId); - - switch (syncStep) { - case 'full-message-list-fetch': - await this.messagingChannelSyncStatusService.scheduleFullMessageListFetch( - messageChannel.id, - workspaceId, - ); - break; - - case 'partial-message-list-fetch': - await this.messagingChannelSyncStatusService.schedulePartialMessageListFetch( - messageChannel.id, - workspaceId, - ); - break; + await this.handleThrottle(syncStep, messageChannel, workspaceId); + } - case 'messages-import': - await this.messagingChannelSyncStatusService.scheduleMessagesImport( - messageChannel.id, - workspaceId, - ); - break; + private async handleFailedPrecondition( + error: GmailError, + syncStep: SyncStep, + messageChannel: MessageChannelWorkspaceEntity, + workspaceId: string, + ): Promise<void> { + await this.messagingTelemetryService.track({ + eventName: `${snakeCase(syncStep)}.error.failed_precondition`, + workspaceId, + connectedAccountId: messageChannel.connectedAccountId, + messageChannelId: messageChannel.id, + message: `${error.code}: ${error.reason}`, + }); - default: - break; - } + await this.handleThrottle(syncStep, messageChannel, workspaceId); } private async handleInsufficientPermissions( error: GmailError, syncStep: SyncStep, - messageChannel: ObjectRecord<MessageChannelWorkspaceEntity>, + messageChannel: MessageChannelWorkspaceEntity, workspaceId: string, ): Promise<void> { await this.messagingTelemetryService.track({ @@ -211,6 +205,12 @@ export class MessagingErrorHandlingService { workspaceId, ); + if (!messageChannel.connectedAccountId) { + throw new Error( + `Connected account ID is not defined for message channel ${messageChannel.id} in workspace ${workspaceId}`, + ); + } + await this.connectedAccountRepository.updateAuthFailedAt( messageChannel.connectedAccountId, workspaceId, @@ -220,7 +220,7 @@ export class MessagingErrorHandlingService { private async handleNotFound( error: GmailError, syncStep: SyncStep, - messageChannel: ObjectRecord<MessageChannelWorkspaceEntity>, + messageChannel: MessageChannelWorkspaceEntity, workspaceId: string, ): Promise<void> { if (syncStep === 'messages-import') { @@ -241,8 +241,53 @@ export class MessagingErrorHandlingService { ); } + private async handleThrottle( + syncStep: SyncStep, + messageChannel: MessageChannelWorkspaceEntity, + workspaceId: string, + ): Promise<void> { + if ( + messageChannel.throttleFailureCount >= MESSAGING_THROTTLE_MAX_ATTEMPTS + ) { + await this.messagingChannelSyncStatusService.markAsFailedUnknownAndFlushMessagesToImport( + messageChannel.id, + workspaceId, + ); + + return; + } + + await this.throttle(messageChannel, workspaceId); + + switch (syncStep) { + case 'full-message-list-fetch': + await this.messagingChannelSyncStatusService.scheduleFullMessageListFetch( + messageChannel.id, + workspaceId, + ); + break; + + case 'partial-message-list-fetch': + await this.messagingChannelSyncStatusService.schedulePartialMessageListFetch( + messageChannel.id, + workspaceId, + ); + break; + + case 'messages-import': + await this.messagingChannelSyncStatusService.scheduleMessagesImport( + messageChannel.id, + workspaceId, + ); + break; + + default: + break; + } + } + private async throttle( - messageChannel: ObjectRecord<MessageChannelWorkspaceEntity>, + messageChannel: MessageChannelWorkspaceEntity, workspaceId: string, ): Promise<void> { await this.messageChannelRepository.incrementThrottleFailureCount( @@ -258,4 +303,28 @@ export class MessagingErrorHandlingService { message: `Increment throttle failure count to ${messageChannel.throttleFailureCount}`, }); } + + private async handleUnknownError( + error: GmailError, + syncStep: SyncStep, + messageChannel: MessageChannelWorkspaceEntity, + workspaceId: string, + ): Promise<void> { + await this.messagingTelemetryService.track({ + eventName: `${snakeCase(syncStep)}.error.unknown`, + workspaceId, + connectedAccountId: messageChannel.connectedAccountId, + messageChannelId: messageChannel.id, + message: `${error.code}: ${error.reason}`, + }); + + await this.messagingChannelSyncStatusService.markAsFailedUnknownAndFlushMessagesToImport( + messageChannel.id, + workspaceId, + ); + + throw new Error( + `Unhandled Gmail error code ${error.code} with reason ${error.reason}`, + ); + } } diff --git a/packages/twenty-server/src/modules/messaging/common/services/messaging-fetch-by-batch.service.ts b/packages/twenty-server/src/modules/messaging/common/services/messaging-fetch-by-batch.service.ts index 354ab92659f0..978850bb9629 100644 --- a/packages/twenty-server/src/modules/messaging/common/services/messaging-fetch-by-batch.service.ts +++ b/packages/twenty-server/src/modules/messaging/common/services/messaging-fetch-by-batch.service.ts @@ -5,25 +5,31 @@ import { AxiosResponse } from 'axios'; import { GmailMessageParsedResponse } from 'src/modules/messaging/message-import-manager/drivers/gmail/types/gmail-message-parsed-response'; import { BatchQueries } from 'src/modules/messaging/message-import-manager/types/batch-queries'; +import { createQueriesFromMessageIds } from 'src/modules/messaging/message-import-manager/utils/create-queries-from-message-ids.util'; @Injectable() export class MessagingFetchByBatchesService { constructor(private readonly httpService: HttpService) {} async fetchAllByBatches( - queries: BatchQueries, + messageIds: string[], accessToken: string, boundary: string, - ): Promise<AxiosResponse<any, any>[]> { - const batchLimit = 50; + ): Promise<{ + messageIdsByBatch: string[][]; + batchResponses: AxiosResponse<any, any>[]; + }> { + const batchLimit = 20; let batchOffset = 0; let batchResponses: AxiosResponse<any, any>[] = []; - while (batchOffset < queries.length) { + const messageIdsByBatch: string[][] = []; + + while (batchOffset < messageIds.length) { const batchResponse = await this.fetchBatch( - queries, + messageIds, accessToken, batchOffset, batchLimit, @@ -32,19 +38,25 @@ export class MessagingFetchByBatchesService { batchResponses = batchResponses.concat(batchResponse); + messageIdsByBatch.push( + messageIds.slice(batchOffset, batchOffset + batchLimit), + ); + batchOffset += batchLimit; } - return batchResponses; + return { messageIdsByBatch, batchResponses }; } async fetchBatch( - queries: BatchQueries, + messageIds: string[], accessToken: string, batchOffset: number, batchLimit: number, boundary: string, ): Promise<AxiosResponse<any, any>> { + const queries = createQueriesFromMessageIds(messageIds); + const limitedQueries = queries.slice(batchOffset, batchOffset + batchLimit); const response = await this.httpService.axiosRef.post( diff --git a/packages/twenty-server/src/modules/messaging/common/services/messaging-message.service.ts b/packages/twenty-server/src/modules/messaging/common/services/messaging-message.service.ts index 4b475d095d7d..e96d2ab3044d 100644 --- a/packages/twenty-server/src/modules/messaging/common/services/messaging-message.service.ts +++ b/packages/twenty-server/src/modules/messaging/common/services/messaging-message.service.ts @@ -1,27 +1,22 @@ -import { Injectable, Logger } from '@nestjs/common'; +import { Injectable } from '@nestjs/common'; -import { DataSource, EntityManager } from 'typeorm'; +import { EntityManager } from 'typeorm'; import { v4 } from 'uuid'; -import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; -import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record'; import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; +import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; import { MessageChannelMessageAssociationRepository } from 'src/modules/messaging/common/repositories/message-channel-message-association.repository'; -import { MessageChannelRepository } from 'src/modules/messaging/common/repositories/message-channel.repository'; import { MessageThreadRepository } from 'src/modules/messaging/common/repositories/message-thread.repository'; import { MessageRepository } from 'src/modules/messaging/common/repositories/message.repository'; +import { MessagingMessageThreadService } from 'src/modules/messaging/common/services/messaging-message-thread.service'; import { MessageChannelMessageAssociationWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel-message-association.workspace-entity'; -import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity'; import { MessageThreadWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-thread.workspace-entity'; import { MessageWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message.workspace-entity'; import { GmailMessage } from 'src/modules/messaging/message-import-manager/drivers/gmail/types/gmail-message'; -import { MessagingMessageThreadService } from 'src/modules/messaging/common/services/messaging-message-thread.service'; @Injectable() export class MessagingMessageService { - private readonly logger = new Logger(MessagingMessageService.name); - constructor( private readonly workspaceDataSourceService: WorkspaceDataSourceService, @InjectObjectMetadataRepository( @@ -30,8 +25,6 @@ export class MessagingMessageService { private readonly messageChannelMessageAssociationRepository: MessageChannelMessageAssociationRepository, @InjectObjectMetadataRepository(MessageWorkspaceEntity) private readonly messageRepository: MessageRepository, - @InjectObjectMetadataRepository(MessageChannelWorkspaceEntity) - private readonly messageChannelRepository: MessageChannelRepository, @InjectObjectMetadataRepository(MessageThreadWorkspaceEntity) private readonly messageThreadRepository: MessageThreadRepository, private readonly messageThreadService: MessagingMessageThreadService, @@ -39,7 +32,7 @@ export class MessagingMessageService { public async saveMessagesWithinTransaction( messages: GmailMessage[], - connectedAccount: ObjectRecord<ConnectedAccountWorkspaceEntity>, + connectedAccount: ConnectedAccountWorkspaceEntity, gmailMessageChannelId: string, workspaceId: string, transactionManager: EntityManager, @@ -68,6 +61,12 @@ export class MessagingMessageService { transactionManager, ); + if (!savedOrExistingMessageThreadId) { + throw new Error( + `No message thread found for message ${message.headerMessageId} in workspace ${workspaceId} in saveMessages`, + ); + } + const savedOrExistingMessageId = await this.saveMessageOrReturnExistingMessage( message, @@ -96,102 +95,10 @@ export class MessagingMessageService { return messageExternalIdsAndIdsMap; } - public async saveMessages( - messages: GmailMessage[], - workspaceDataSource: DataSource, - connectedAccount: ObjectRecord<ConnectedAccountWorkspaceEntity>, - gmailMessageChannelId: string, - workspaceId: string, - ): Promise<Map<string, string>> { - const messageExternalIdsAndIdsMap = new Map<string, string>(); - - try { - let keepImporting = true; - - for (const message of messages) { - if (!keepImporting) { - break; - } - - await workspaceDataSource?.transaction( - async (manager: EntityManager) => { - const gmailMessageChannel = - await this.messageChannelRepository.getByIds( - [gmailMessageChannelId], - workspaceId, - manager, - ); - - if (gmailMessageChannel.length === 0) { - this.logger.error( - `No message channel found for connected account ${connectedAccount.id} in workspace ${workspaceId} in saveMessages`, - ); - - keepImporting = false; - - return; - } - - const existingMessageChannelMessageAssociationsCount = - await this.messageChannelMessageAssociationRepository.countByMessageExternalIdsAndMessageChannelId( - [message.externalId], - gmailMessageChannelId, - workspaceId, - manager, - ); - - if (existingMessageChannelMessageAssociationsCount > 0) { - return; - } - - // TODO: This does not handle all thread merging use cases and might create orphan threads. - const savedOrExistingMessageThreadId = - await this.messageThreadService.saveMessageThreadOrReturnExistingMessageThread( - message.headerMessageId, - message.messageThreadExternalId, - workspaceId, - manager, - ); - - const savedOrExistingMessageId = - await this.saveMessageOrReturnExistingMessage( - message, - savedOrExistingMessageThreadId, - connectedAccount, - workspaceId, - manager, - ); - - messageExternalIdsAndIdsMap.set( - message.externalId, - savedOrExistingMessageId, - ); - - await this.messageChannelMessageAssociationRepository.insert( - gmailMessageChannelId, - savedOrExistingMessageId, - message.externalId, - savedOrExistingMessageThreadId, - message.messageThreadExternalId, - workspaceId, - manager, - ); - }, - ); - } - } catch (error) { - throw new Error( - `Error saving connected account ${connectedAccount.id} messages to workspace ${workspaceId}: ${error.message}`, - ); - } - - return messageExternalIdsAndIdsMap; - } - private async saveMessageOrReturnExistingMessage( message: GmailMessage, messageThreadId: string, - connectedAccount: ObjectRecord<ConnectedAccountWorkspaceEntity>, + connectedAccount: ConnectedAccountWorkspaceEntity, workspaceId: string, manager: EntityManager, ): Promise<string> { @@ -209,7 +116,10 @@ export class MessagingMessageService { const newMessageId = v4(); const messageDirection = - connectedAccount.handle === message.fromHandle ? 'outgoing' : 'incoming'; + connectedAccount.handle === message.fromHandle || + connectedAccount.handleAliases?.includes(message.fromHandle) + ? 'outgoing' + : 'incoming'; const receivedAt = new Date(parseInt(message.internalDate)); diff --git a/packages/twenty-server/src/modules/messaging/common/services/messaging-telemetry.service.ts b/packages/twenty-server/src/modules/messaging/common/services/messaging-telemetry.service.ts index ae9cec0fa136..0234f7fbcb4e 100644 --- a/packages/twenty-server/src/modules/messaging/common/services/messaging-telemetry.service.ts +++ b/packages/twenty-server/src/modules/messaging/common/services/messaging-telemetry.service.ts @@ -5,7 +5,7 @@ import { EnvironmentService } from 'src/engine/integrations/environment/environm type MessagingTelemetryTrackInput = { eventName: string; - workspaceId: string; + workspaceId?: string; userId?: string; connectedAccountId?: string; messageChannelId?: string; diff --git a/packages/twenty-server/src/modules/messaging/common/standard-objects/message-channel-message-association.workspace-entity.ts b/packages/twenty-server/src/modules/messaging/common/standard-objects/message-channel-message-association.workspace-entity.ts index 91e9fa828209..0e0171766c54 100644 --- a/packages/twenty-server/src/modules/messaging/common/standard-objects/message-channel-message-association.workspace-entity.ts +++ b/packages/twenty-server/src/modules/messaging/common/standard-objects/message-channel-message-association.workspace-entity.ts @@ -14,6 +14,7 @@ import { RelationMetadataType } from 'src/engine/metadata-modules/relation-metad import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity'; import { MessageThreadWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-thread.workspace-entity'; import { MessageWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message.workspace-entity'; +import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator'; @WorkspaceEntity({ standardId: STANDARD_OBJECT_IDS.messageChannelMessageAssociation, @@ -35,7 +36,7 @@ export class MessageChannelMessageAssociationWorkspaceEntity extends BaseWorkspa icon: 'IconHash', }) @WorkspaceIsNullable() - messageExternalId: string; + messageExternalId: string | null; @WorkspaceField({ standardId: @@ -46,7 +47,7 @@ export class MessageChannelMessageAssociationWorkspaceEntity extends BaseWorkspa icon: 'IconHash', }) @WorkspaceIsNullable() - messageThreadExternalId: string; + messageThreadExternalId: string | null; @WorkspaceRelation({ standardId: @@ -55,12 +56,14 @@ export class MessageChannelMessageAssociationWorkspaceEntity extends BaseWorkspa label: 'Message Channel Id', description: 'Message Channel Id', icon: 'IconHash', - joinColumn: 'messageChannelId', inverseSideTarget: () => MessageChannelWorkspaceEntity, inverseSideFieldKey: 'messageChannelMessageAssociations', }) @WorkspaceIsNullable() - messageChannel: Relation<MessageChannelWorkspaceEntity>; + messageChannel: Relation<MessageChannelWorkspaceEntity> | null; + + @WorkspaceJoinColumn('messageChannel') + messageChannelId: string; @WorkspaceRelation({ standardId: MESSAGE_CHANNEL_MESSAGE_ASSOCIATION_STANDARD_FIELD_IDS.message, @@ -68,12 +71,14 @@ export class MessageChannelMessageAssociationWorkspaceEntity extends BaseWorkspa label: 'Message Id', description: 'Message Id', icon: 'IconHash', - joinColumn: 'messageId', inverseSideTarget: () => MessageWorkspaceEntity, inverseSideFieldKey: 'messageChannelMessageAssociations', }) @WorkspaceIsNullable() - message: Relation<MessageWorkspaceEntity>; + message: Relation<MessageWorkspaceEntity> | null; + + @WorkspaceJoinColumn('message') + messageId: string; @WorkspaceRelation({ standardId: @@ -82,10 +87,12 @@ export class MessageChannelMessageAssociationWorkspaceEntity extends BaseWorkspa label: 'Message Thread Id', description: 'Message Thread Id', icon: 'IconHash', - joinColumn: 'messageThreadId', inverseSideTarget: () => MessageThreadWorkspaceEntity, inverseSideFieldKey: 'messageChannelMessageAssociations', }) @WorkspaceIsNullable() - messageThread: Relation<MessageThreadWorkspaceEntity>; + messageThread: Relation<MessageThreadWorkspaceEntity> | null; + + @WorkspaceJoinColumn('messageThread') + messageThreadId: string; } diff --git a/packages/twenty-server/src/modules/messaging/common/standard-objects/message-channel.workspace-entity.ts b/packages/twenty-server/src/modules/messaging/common/standard-objects/message-channel.workspace-entity.ts index 92175c6afbf8..565e705095dc 100644 --- a/packages/twenty-server/src/modules/messaging/common/standard-objects/message-channel.workspace-entity.ts +++ b/packages/twenty-server/src/modules/messaging/common/standard-objects/message-channel.workspace-entity.ts @@ -5,25 +5,20 @@ import { RelationMetadataType, RelationOnDeleteAction, } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity'; -import { MESSAGE_CHANNEL_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids'; -import { STANDARD_OBJECT_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-object-ids'; -import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity'; import { WorkspaceEntity } from 'src/engine/twenty-orm/decorators/workspace-entity.decorator'; -import { WorkspaceIsNotAuditLogged } from 'src/engine/twenty-orm/decorators/workspace-is-not-audit-logged.decorator'; -import { WorkspaceIsSystem } from 'src/engine/twenty-orm/decorators/workspace-is-system.decorator'; import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field.decorator'; +import { WorkspaceIsNotAuditLogged } from 'src/engine/twenty-orm/decorators/workspace-is-not-audit-logged.decorator'; import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator'; +import { WorkspaceIsSystem } from 'src/engine/twenty-orm/decorators/workspace-is-system.decorator'; +import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator'; import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator'; +import { MESSAGE_CHANNEL_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids'; +import { STANDARD_OBJECT_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-object-ids'; +import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; import { MessageChannelMessageAssociationWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel-message-association.workspace-entity'; export enum MessageChannelSyncStatus { - // TO BE DEPRECATED - PENDING = 'PENDING', - SUCCEEDED = 'SUCCEEDED', - FAILED = 'FAILED', - - // NEW STATUSES NOT_SYNCED = 'NOT_SYNCED', ONGOING = 'ONGOING', COMPLETED = 'COMPLETED', @@ -51,6 +46,12 @@ export enum MessageChannelType { SMS = 'sms', } +export enum MessageChannelContactAutoCreationPolicy { + SENT_AND_RECEIVED = 'SENT_AND_RECEIVED', + SENT = 'SENT', + NONE = 'NONE', +} + @WorkspaceEntity({ standardId: STANDARD_OBJECT_IDS.messageChannel, namePlural: 'messageChannels', @@ -125,6 +126,7 @@ export class MessageChannelWorkspaceEntity extends BaseWorkspaceEntity { }) type: string; + // TODO: Deprecate this field and migrate data to contactAutoCreationFor @WorkspaceField({ standardId: MESSAGE_CHANNEL_STANDARD_FIELD_IDS.isContactAutoCreationEnabled, type: FieldMetadataType.BOOLEAN, @@ -135,6 +137,57 @@ export class MessageChannelWorkspaceEntity extends BaseWorkspaceEntity { }) isContactAutoCreationEnabled: boolean; + @WorkspaceField({ + standardId: MESSAGE_CHANNEL_STANDARD_FIELD_IDS.contactAutoCreationPolicy, + type: FieldMetadataType.SELECT, + label: 'Contact auto creation policy', + description: + 'Automatically create People records when receiving or sending emails', + icon: 'IconUserCircle', + options: [ + { + value: MessageChannelContactAutoCreationPolicy.SENT_AND_RECEIVED, + label: 'Sent and Received', + position: 0, + color: 'green', + }, + { + value: MessageChannelContactAutoCreationPolicy.SENT, + label: 'Sent', + position: 1, + color: 'blue', + }, + { + value: MessageChannelContactAutoCreationPolicy.NONE, + label: 'None', + position: 2, + color: 'red', + }, + ], + defaultValue: `'${MessageChannelContactAutoCreationPolicy.SENT}'`, + }) + contactAutoCreationPolicy: MessageChannelContactAutoCreationPolicy; + + @WorkspaceField({ + standardId: MESSAGE_CHANNEL_STANDARD_FIELD_IDS.excludeNonProfessionalEmails, + type: FieldMetadataType.BOOLEAN, + label: 'Exclude non professional emails', + description: 'Exclude non professional emails', + icon: 'IconBriefcase', + defaultValue: true, + }) + excludeNonProfessionalEmails: boolean; + + @WorkspaceField({ + standardId: MESSAGE_CHANNEL_STANDARD_FIELD_IDS.excludeGroupEmails, + type: FieldMetadataType.BOOLEAN, + label: 'Exclude group emails', + description: 'Exclude group emails', + icon: 'IconUsersGroup', + defaultValue: true, + }) + excludeGroupEmails: boolean; + @WorkspaceField({ standardId: MESSAGE_CHANNEL_STANDARD_FIELD_IDS.isSyncEnabled, type: FieldMetadataType.BOOLEAN, @@ -162,7 +215,7 @@ export class MessageChannelWorkspaceEntity extends BaseWorkspaceEntity { icon: 'IconHistory', }) @WorkspaceIsNullable() - syncedAt: string; + syncedAt: string | null; @WorkspaceField({ standardId: MESSAGE_CHANNEL_STANDARD_FIELD_IDS.syncStatus, @@ -171,26 +224,6 @@ export class MessageChannelWorkspaceEntity extends BaseWorkspaceEntity { description: 'Sync status', icon: 'IconStatusChange', options: [ - // TO BE DEPRECATED: PENDING, SUCCEEDED, FAILED - { - value: MessageChannelSyncStatus.PENDING, - label: 'Pending', - position: 0, - color: 'blue', - }, - { - value: MessageChannelSyncStatus.SUCCEEDED, - label: 'Succeeded', - position: 2, - color: 'green', - }, - { - value: MessageChannelSyncStatus.FAILED, - label: 'Failed', - position: 3, - color: 'red', - }, - // NEW STATUSES { value: MessageChannelSyncStatus.ONGOING, label: 'Ongoing', @@ -224,7 +257,7 @@ export class MessageChannelWorkspaceEntity extends BaseWorkspaceEntity { ], }) @WorkspaceIsNullable() - syncStatus: MessageChannelSyncStatus; + syncStatus: MessageChannelSyncStatus | null; @WorkspaceField({ standardId: MESSAGE_CHANNEL_STANDARD_FIELD_IDS.syncStage, @@ -282,7 +315,7 @@ export class MessageChannelWorkspaceEntity extends BaseWorkspaceEntity { icon: 'IconHistory', }) @WorkspaceIsNullable() - syncStageStartedAt: string; + syncStageStartedAt: string | null; @WorkspaceField({ standardId: MESSAGE_CHANNEL_STANDARD_FIELD_IDS.throttleFailureCount, @@ -300,12 +333,14 @@ export class MessageChannelWorkspaceEntity extends BaseWorkspaceEntity { label: 'Connected Account', description: 'Connected Account', icon: 'IconUserCircle', - joinColumn: 'connectedAccountId', inverseSideTarget: () => ConnectedAccountWorkspaceEntity, inverseSideFieldKey: 'messageChannels', }) connectedAccount: Relation<ConnectedAccountWorkspaceEntity>; + @WorkspaceJoinColumn('connectedAccount') + connectedAccountId: string; + @WorkspaceRelation({ standardId: MESSAGE_CHANNEL_STANDARD_FIELD_IDS.messageChannelMessageAssociations, diff --git a/packages/twenty-server/src/modules/messaging/common/standard-objects/message-participant.workspace-entity.ts b/packages/twenty-server/src/modules/messaging/common/standard-objects/message-participant.workspace-entity.ts index b8c1e09f6447..0821bf32c012 100644 --- a/packages/twenty-server/src/modules/messaging/common/standard-objects/message-participant.workspace-entity.ts +++ b/packages/twenty-server/src/modules/messaging/common/standard-objects/message-participant.workspace-entity.ts @@ -14,6 +14,7 @@ import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-re import { RelationMetadataType } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity'; import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator'; import { MessageWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message.workspace-entity'; +import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator'; @WorkspaceEntity({ standardId: STANDARD_OBJECT_IDS.messageParticipant, @@ -66,24 +67,28 @@ export class MessageParticipantWorkspaceEntity extends BaseWorkspaceEntity { label: 'Message', description: 'Message', icon: 'IconMessage', - joinColumn: 'messageId', inverseSideTarget: () => MessageWorkspaceEntity, inverseSideFieldKey: 'messageParticipants', }) message: Relation<MessageWorkspaceEntity>; + @WorkspaceJoinColumn('message') + messageId: string; + @WorkspaceRelation({ standardId: MESSAGE_PARTICIPANT_STANDARD_FIELD_IDS.person, type: RelationMetadataType.MANY_TO_ONE, label: 'Person', description: 'Person', icon: 'IconUser', - joinColumn: 'personId', inverseSideTarget: () => PersonWorkspaceEntity, inverseSideFieldKey: 'messageParticipants', }) @WorkspaceIsNullable() - person: Relation<PersonWorkspaceEntity>; + person: Relation<PersonWorkspaceEntity> | null; + + @WorkspaceJoinColumn('person') + personId: string | null; @WorkspaceRelation({ standardId: MESSAGE_PARTICIPANT_STANDARD_FIELD_IDS.workspaceMember, @@ -91,10 +96,12 @@ export class MessageParticipantWorkspaceEntity extends BaseWorkspaceEntity { label: 'Workspace Member', description: 'Workspace member', icon: 'IconCircleUser', - joinColumn: 'workspaceMemberId', inverseSideTarget: () => WorkspaceMemberWorkspaceEntity, inverseSideFieldKey: 'messageParticipants', }) @WorkspaceIsNullable() - workspaceMember: Relation<WorkspaceMemberWorkspaceEntity>; + workspaceMember: Relation<WorkspaceMemberWorkspaceEntity> | null; + + @WorkspaceJoinColumn('workspaceMember') + workspaceMemberId: string | null; } diff --git a/packages/twenty-server/src/modules/messaging/common/standard-objects/message.workspace-entity.ts b/packages/twenty-server/src/modules/messaging/common/standard-objects/message.workspace-entity.ts index a3ad1ea48c8c..a9475a96d6ce 100644 --- a/packages/twenty-server/src/modules/messaging/common/standard-objects/message.workspace-entity.ts +++ b/packages/twenty-server/src/modules/messaging/common/standard-objects/message.workspace-entity.ts @@ -17,6 +17,7 @@ import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-re import { MessageChannelMessageAssociationWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel-message-association.workspace-entity'; import { MessageParticipantWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-participant.workspace-entity'; import { MessageThreadWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-thread.workspace-entity'; +import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator'; @WorkspaceEntity({ standardId: STANDARD_OBJECT_IDS.message, @@ -78,7 +79,7 @@ export class MessageWorkspaceEntity extends BaseWorkspaceEntity { icon: 'IconCalendar', }) @WorkspaceIsNullable() - receivedAt: string; + receivedAt: string | null; @WorkspaceRelation({ standardId: MESSAGE_STANDARD_FIELD_IDS.messageThread, @@ -86,13 +87,15 @@ export class MessageWorkspaceEntity extends BaseWorkspaceEntity { label: 'Message Thread Id', description: 'Message Thread Id', icon: 'IconHash', - joinColumn: 'messageThreadId', inverseSideTarget: () => MessageThreadWorkspaceEntity, inverseSideFieldKey: 'messages', onDelete: RelationOnDeleteAction.CASCADE, }) @WorkspaceIsNullable() - messageThread: Relation<MessageThreadWorkspaceEntity>; + messageThread: Relation<MessageThreadWorkspaceEntity> | null; + + @WorkspaceJoinColumn('messageThread') + messageThreadId: string | null; @WorkspaceRelation({ standardId: MESSAGE_STANDARD_FIELD_IDS.messageParticipants, diff --git a/packages/twenty-server/src/modules/messaging/message-cleaner/jobs/messaging-connected-account-deletion-cleanup.job.ts b/packages/twenty-server/src/modules/messaging/message-cleaner/jobs/messaging-connected-account-deletion-cleanup.job.ts index 5cba9355cb84..c9cc4e9e993e 100644 --- a/packages/twenty-server/src/modules/messaging/message-cleaner/jobs/messaging-connected-account-deletion-cleanup.job.ts +++ b/packages/twenty-server/src/modules/messaging/message-cleaner/jobs/messaging-connected-account-deletion-cleanup.job.ts @@ -1,18 +1,20 @@ -import { Injectable, Logger } from '@nestjs/common'; - -import { MessageQueueJob } from 'src/engine/integrations/message-queue/interfaces/message-queue-job.interface'; +import { Logger, Scope } from '@nestjs/common'; import { MessagingMessageCleanerService } from 'src/modules/messaging/message-cleaner/services/messaging-message-cleaner.service'; +import { Processor } from 'src/engine/integrations/message-queue/decorators/processor.decorator'; +import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; +import { Process } from 'src/engine/integrations/message-queue/decorators/process.decorator'; export type MessagingConnectedAccountDeletionCleanupJobData = { workspaceId: string; connectedAccountId: string; }; -@Injectable() -export class MessagingConnectedAccountDeletionCleanupJob - implements MessageQueueJob<MessagingConnectedAccountDeletionCleanupJobData> -{ +@Processor({ + queueName: MessageQueue.messagingQueue, + scope: Scope.REQUEST, +}) +export class MessagingConnectedAccountDeletionCleanupJob { private readonly logger = new Logger( MessagingConnectedAccountDeletionCleanupJob.name, ); @@ -21,6 +23,7 @@ export class MessagingConnectedAccountDeletionCleanupJob private readonly messageCleanerService: MessagingMessageCleanerService, ) {} + @Process(MessagingConnectedAccountDeletionCleanupJob.name) async handle( data: MessagingConnectedAccountDeletionCleanupJobData, ): Promise<void> { diff --git a/packages/twenty-server/src/modules/messaging/message-cleaner/listeners/messaging-message-cleaner-connected-account.listener.ts b/packages/twenty-server/src/modules/messaging/message-cleaner/listeners/messaging-message-cleaner-connected-account.listener.ts index 24d5deb2974c..8880ad5d10d4 100644 --- a/packages/twenty-server/src/modules/messaging/message-cleaner/listeners/messaging-message-cleaner-connected-account.listener.ts +++ b/packages/twenty-server/src/modules/messaging/message-cleaner/listeners/messaging-message-cleaner-connected-account.listener.ts @@ -1,24 +1,26 @@ -import { Inject } from '@nestjs/common'; +import { Injectable } from '@nestjs/common'; import { OnEvent } from '@nestjs/event-emitter'; import { ObjectRecordDeleteEvent } from 'src/engine/integrations/event-emitter/types/object-record-delete.event'; import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service'; -import { - DeleteConnectedAccountAssociatedCalendarDataJobData, - DeleteConnectedAccountAssociatedCalendarDataJob, -} from 'src/modules/calendar/jobs/delete-connected-account-associated-calendar-data.job'; import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; import { MessagingConnectedAccountDeletionCleanupJob, MessagingConnectedAccountDeletionCleanupJobData, } from 'src/modules/messaging/message-cleaner/jobs/messaging-connected-account-deletion-cleanup.job'; +import { InjectMessageQueue } from 'src/engine/integrations/message-queue/decorators/message-queue.decorator'; +import { + DeleteConnectedAccountAssociatedCalendarDataJobData, + DeleteConnectedAccountAssociatedCalendarDataJob, +} from 'src/modules/calendar/calendar-event-cleaner/jobs/delete-connected-account-associated-calendar-data.job'; +@Injectable() export class MessagingMessageCleanerConnectedAccountListener { constructor( - @Inject(MessageQueue.messagingQueue) + @InjectMessageQueue(MessageQueue.messagingQueue) private readonly messageQueueService: MessageQueueService, - @Inject(MessageQueue.calendarQueue) + @InjectMessageQueue(MessageQueue.calendarQueue) private readonly calendarQueueService: MessageQueueService, ) {} diff --git a/packages/twenty-server/src/modules/messaging/message-cleaner/messaging-message-cleaner.module.ts b/packages/twenty-server/src/modules/messaging/message-cleaner/messaging-message-cleaner.module.ts index 4562bd75bad6..ae4221a85e85 100644 --- a/packages/twenty-server/src/modules/messaging/message-cleaner/messaging-message-cleaner.module.ts +++ b/packages/twenty-server/src/modules/messaging/message-cleaner/messaging-message-cleaner.module.ts @@ -1,6 +1,6 @@ import { Module } from '@nestjs/common'; -import { ObjectMetadataRepositoryModule } from 'src/engine/object-metadata-repository/object-metadata-repository.module'; +import { TwentyORMModule } from 'src/engine/twenty-orm/twenty-orm.module'; import { MessageThreadWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-thread.workspace-entity'; import { MessageWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message.workspace-entity'; import { MessagingConnectedAccountDeletionCleanupJob } from 'src/modules/messaging/message-cleaner/jobs/messaging-connected-account-deletion-cleanup.job'; @@ -9,17 +9,14 @@ import { MessagingMessageCleanerService } from 'src/modules/messaging/message-cl @Module({ imports: [ - ObjectMetadataRepositoryModule.forFeature([ + TwentyORMModule.forFeature([ MessageWorkspaceEntity, MessageThreadWorkspaceEntity, ]), ], providers: [ MessagingMessageCleanerService, - { - provide: MessagingConnectedAccountDeletionCleanupJob.name, - useClass: MessagingConnectedAccountDeletionCleanupJob, - }, + MessagingConnectedAccountDeletionCleanupJob, MessagingMessageCleanerConnectedAccountListener, ], exports: [MessagingMessageCleanerService], diff --git a/packages/twenty-server/src/modules/messaging/message-cleaner/services/messaging-message-cleaner.service.ts b/packages/twenty-server/src/modules/messaging/message-cleaner/services/messaging-message-cleaner.service.ts index 19a9d6b2d185..21b9f5b28185 100644 --- a/packages/twenty-server/src/modules/messaging/message-cleaner/services/messaging-message-cleaner.service.ts +++ b/packages/twenty-server/src/modules/messaging/message-cleaner/services/messaging-message-cleaner.service.ts @@ -1,8 +1,9 @@ import { Injectable } from '@nestjs/common'; -import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; -import { MessageThreadRepository } from 'src/modules/messaging/common/repositories/message-thread.repository'; -import { MessageRepository } from 'src/modules/messaging/common/repositories/message.repository'; +import { EntityManager } from 'typeorm'; + +import { InjectWorkspaceRepository } from 'src/engine/twenty-orm/decorators/inject-workspace-repository.decorator'; +import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository'; import { MessageThreadWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-thread.workspace-entity'; import { MessageWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message.workspace-entity'; import { deleteUsingPagination } from 'src/modules/messaging/message-cleaner/utils/delete-using-pagination.util'; @@ -10,31 +11,74 @@ import { deleteUsingPagination } from 'src/modules/messaging/message-cleaner/uti @Injectable() export class MessagingMessageCleanerService { constructor( - @InjectObjectMetadataRepository(MessageWorkspaceEntity) - private readonly messageRepository: MessageRepository, - @InjectObjectMetadataRepository(MessageThreadWorkspaceEntity) - private readonly messageThreadRepository: MessageThreadRepository, + @InjectWorkspaceRepository(MessageWorkspaceEntity) + private readonly messageRepository: WorkspaceRepository<MessageWorkspaceEntity>, + @InjectWorkspaceRepository(MessageThreadWorkspaceEntity) + private readonly messageThreadRepository: WorkspaceRepository<MessageThreadWorkspaceEntity>, ) {} public async cleanWorkspaceThreads(workspaceId: string) { await deleteUsingPagination( workspaceId, 500, - this.messageRepository.getNonAssociatedMessageIdsPaginated.bind( - this.messageRepository, - ), - this.messageRepository.deleteByIds.bind(this.messageRepository), + async ( + limit: number, + offset: number, + workspaceId: string, + transactionManager?: EntityManager, + ) => { + const nonAssociatedMessages = await this.messageRepository.find( + { + where: { + messageChannelMessageAssociations: [], + }, + take: limit, + skip: offset, + relations: ['messageChannelMessageAssociations'], + }, + transactionManager, + ); + + return nonAssociatedMessages.map(({ id }) => id); + }, + async ( + ids: string[], + workspaceId: string, + transactionManager?: EntityManager, + ) => { + await this.messageRepository.delete(ids, transactionManager); + }, ); await deleteUsingPagination( workspaceId, 500, - this.messageThreadRepository.getOrphanThreadIdsPaginated.bind( - this.messageThreadRepository, - ), - this.messageThreadRepository.deleteByIds.bind( - this.messageThreadRepository, - ), + async ( + limit: number, + offset: number, + workspaceId: string, + transactionManager?: EntityManager, + ) => { + const orphanThreads = await this.messageThreadRepository.find( + { + where: { + messages: [], + }, + take: limit, + skip: offset, + }, + transactionManager, + ); + + return orphanThreads.map(({ id }) => id); + }, + async ( + ids: string[], + workspaceId: string, + transactionManager?: EntityManager, + ) => { + await this.messageThreadRepository.delete(ids, transactionManager); + }, ); } } diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/commands/messaging-single-message-import.command.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/commands/messaging-single-message-import.command.ts new file mode 100644 index 000000000000..c55465f7dedc --- /dev/null +++ b/packages/twenty-server/src/modules/messaging/message-import-manager/commands/messaging-single-message-import.command.ts @@ -0,0 +1,69 @@ +import { Command, CommandRunner, Option } from 'nest-commander'; + +import { InjectMessageQueue } from 'src/engine/integrations/message-queue/decorators/message-queue.decorator'; +import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; +import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service'; +import { + MessagingAddSingleMessageToCacheForImportJob, + MessagingAddSingleMessageToCacheForImportJobData, +} from 'src/modules/messaging/message-import-manager/jobs/messaging-add-single-message-to-cache-for-import.job'; + +type MessagingSingleMessageImportCommandOptions = { + messageExternalId: string; + messageChannelId: string; + workspaceId: string; +}; + +@Command({ + name: 'messaging:single-message-import', + description: 'Enqueue a job to schedule the import of a single message', +}) +export class MessagingSingleMessageImportCommand extends CommandRunner { + constructor( + @InjectMessageQueue(MessageQueue.messagingQueue) + private readonly messageQueueService: MessageQueueService, + ) { + super(); + } + + async run( + _passedParam: string[], + options: MessagingSingleMessageImportCommandOptions, + ): Promise<void> { + await this.messageQueueService.add<MessagingAddSingleMessageToCacheForImportJobData>( + MessagingAddSingleMessageToCacheForImportJob.name, + { + messageExternalId: options.messageExternalId, + messageChannelId: options.messageChannelId, + workspaceId: options.workspaceId, + }, + ); + } + + @Option({ + flags: '-m, --message-external-id [message_external_id]', + description: 'Message external ID', + required: true, + }) + parseMessageId(value: string): string { + return value; + } + + @Option({ + flags: '-M, --message-channel-id [message_channel_id]', + description: 'Message channel ID', + required: true, + }) + parseMessageChannelId(value: string): string { + return value; + } + + @Option({ + flags: '-w, --workspace-id [workspace_id]', + description: 'Workspace ID', + required: true, + }) + parseWorkspaceId(value: string): string { + return value; + } +} diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/crons/commands/messaging-message-list-fetch.cron.command.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/crons/commands/messaging-message-list-fetch.cron.command.ts index 585762d2cb98..d8e2253bd1d1 100644 --- a/packages/twenty-server/src/modules/messaging/message-import-manager/crons/commands/messaging-message-list-fetch.cron.command.ts +++ b/packages/twenty-server/src/modules/messaging/message-import-manager/crons/commands/messaging-message-list-fetch.cron.command.ts @@ -1,7 +1,6 @@ -import { Inject } from '@nestjs/common'; - import { Command, CommandRunner } from 'nest-commander'; +import { InjectMessageQueue } from 'src/engine/integrations/message-queue/decorators/message-queue.decorator'; import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service'; import { MessagingMessageListFetchCronJob } from 'src/modules/messaging/message-import-manager/crons/jobs/messaging-message-list-fetch.cron.job'; @@ -15,7 +14,7 @@ const MESSAGING_MESSAGE_LIST_FETCH_CRON_PATTERN = '*/5 * * * *'; }) export class MessagingMessageListFetchCronCommand extends CommandRunner { constructor( - @Inject(MessageQueue.cronQueue) + @InjectMessageQueue(MessageQueue.cronQueue) private readonly messageQueueService: MessageQueueService, ) { super(); diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/crons/commands/messaging-messages-import.cron.command.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/crons/commands/messaging-messages-import.cron.command.ts index aae9df3723b2..206f2d47815b 100644 --- a/packages/twenty-server/src/modules/messaging/message-import-manager/crons/commands/messaging-messages-import.cron.command.ts +++ b/packages/twenty-server/src/modules/messaging/message-import-manager/crons/commands/messaging-messages-import.cron.command.ts @@ -1,7 +1,6 @@ -import { Inject } from '@nestjs/common'; - import { Command, CommandRunner } from 'nest-commander'; +import { InjectMessageQueue } from 'src/engine/integrations/message-queue/decorators/message-queue.decorator'; import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service'; import { MessagingMessagesImportCronJob } from 'src/modules/messaging/message-import-manager/crons/jobs/messaging-messages-import.cron.job'; @@ -12,7 +11,7 @@ import { MessagingMessagesImportCronJob } from 'src/modules/messaging/message-im }) export class MessagingMessagesImportCronCommand extends CommandRunner { constructor( - @Inject(MessageQueue.cronQueue) + @InjectMessageQueue(MessageQueue.cronQueue) private readonly messageQueueService: MessageQueueService, ) { super(); @@ -24,7 +23,7 @@ export class MessagingMessagesImportCronCommand extends CommandRunner { undefined, { repeat: { - every: 5000, + every: 30000, }, }, ); diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/crons/commands/messaging-ongoing-stale.cron.command.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/crons/commands/messaging-ongoing-stale.cron.command.ts new file mode 100644 index 000000000000..ed77d79555b8 --- /dev/null +++ b/packages/twenty-server/src/modules/messaging/message-import-manager/crons/commands/messaging-ongoing-stale.cron.command.ts @@ -0,0 +1,32 @@ +import { Command, CommandRunner } from 'nest-commander'; + +import { InjectMessageQueue } from 'src/engine/integrations/message-queue/decorators/message-queue.decorator'; +import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; +import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service'; +import { MessagingOngoingStaleCronJob } from 'src/modules/messaging/message-import-manager/crons/jobs/messaging-ongoing-stale.cron.job'; + +const MESSAGING_ONGOING_STALE_CRON_PATTERN = '0 * * * *'; + +@Command({ + name: 'cron:messaging:ongoing-stale', + description: + 'Starts a cron job to check for stale ongoing message imports and put them back to pending', +}) +export class MessagingOngoingStaleCronCommand extends CommandRunner { + constructor( + @InjectMessageQueue(MessageQueue.cronQueue) + private readonly messageQueueService: MessageQueueService, + ) { + super(); + } + + async run(): Promise<void> { + await this.messageQueueService.addCron<undefined>( + MessagingOngoingStaleCronJob.name, + undefined, + { + repeat: { pattern: MESSAGING_ONGOING_STALE_CRON_PATTERN }, + }, + ); + } +} diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/crons/jobs/messaging-message-list-fetch.cron.job.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/crons/jobs/messaging-message-list-fetch.cron.job.ts index 9a2cb54740df..0e8811b6b148 100644 --- a/packages/twenty-server/src/modules/messaging/message-import-manager/crons/jobs/messaging-message-list-fetch.cron.job.ts +++ b/packages/twenty-server/src/modules/messaging/message-import-manager/crons/jobs/messaging-message-list-fetch.cron.job.ts @@ -1,16 +1,12 @@ -import { Inject, Injectable, Logger } from '@nestjs/common'; +import { Logger } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository, In } from 'typeorm'; -import { MessageQueueJob } from 'src/engine/integrations/message-queue/interfaces/message-queue-job.interface'; - -import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity'; import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service'; import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; -import { EnvironmentService } from 'src/engine/integrations/environment/environment.service'; import { MessageChannelRepository } from 'src/modules/messaging/common/repositories/message-channel.repository'; import { MessageChannelSyncStage, @@ -20,36 +16,29 @@ import { MessagingMessageListFetchJobData, MessagingMessageListFetchJob, } from 'src/modules/messaging/message-import-manager/jobs/messaging-message-list-fetch.job'; +import { InjectMessageQueue } from 'src/engine/integrations/message-queue/decorators/message-queue.decorator'; +import { Processor } from 'src/engine/integrations/message-queue/decorators/processor.decorator'; +import { Process } from 'src/engine/integrations/message-queue/decorators/process.decorator'; +import { BillingService } from 'src/engine/core-modules/billing/billing.service'; -@Injectable() -export class MessagingMessageListFetchCronJob - implements MessageQueueJob<undefined> -{ +@Processor(MessageQueue.cronQueue) +export class MessagingMessageListFetchCronJob { private readonly logger = new Logger(MessagingMessageListFetchCronJob.name); constructor( - @InjectRepository(Workspace, 'core') - private readonly workspaceRepository: Repository<Workspace>, @InjectRepository(DataSourceEntity, 'metadata') private readonly dataSourceRepository: Repository<DataSourceEntity>, - @Inject(MessageQueue.messagingQueue) + @InjectMessageQueue(MessageQueue.messagingQueue) private readonly messageQueueService: MessageQueueService, @InjectObjectMetadataRepository(MessageChannelWorkspaceEntity) private readonly messageChannelRepository: MessageChannelRepository, - private readonly environmentService: EnvironmentService, + private readonly billingService: BillingService, ) {} + @Process(MessagingMessageListFetchCronJob.name) async handle(): Promise<void> { - const workspaceIds = ( - await this.workspaceRepository.find({ - where: this.environmentService.get('IS_BILLING_ENABLED') - ? { - subscriptionStatus: In(['active', 'trialing', 'past_due']), - } - : {}, - select: ['id'], - }) - ).map((workspace) => workspace.id); + const workspaceIds = + await this.billingService.getActiveSubscriptionWorkspaceIds(); const dataSources = await this.dataSourceRepository.find({ where: { diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/crons/jobs/messaging-messages-import.cron.job.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/crons/jobs/messaging-messages-import.cron.job.ts index 2faafc14a8c5..4be6ce2e1214 100644 --- a/packages/twenty-server/src/modules/messaging/message-import-manager/crons/jobs/messaging-messages-import.cron.job.ts +++ b/packages/twenty-server/src/modules/messaging/message-import-manager/crons/jobs/messaging-messages-import.cron.job.ts @@ -1,53 +1,44 @@ -import { Inject, Injectable } from '@nestjs/common'; +import { Logger } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository, In } from 'typeorm'; -import { MessageQueueJob } from 'src/engine/integrations/message-queue/interfaces/message-queue-job.interface'; - -import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity'; -import { EnvironmentService } from 'src/engine/integrations/environment/environment.service'; import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service'; import { MessagingMessagesImportJobData, MessagingMessagesImportJob, } from 'src/modules/messaging/message-import-manager/jobs/messaging-messages-import.job'; +import { Processor } from 'src/engine/integrations/message-queue/decorators/processor.decorator'; +import { Process } from 'src/engine/integrations/message-queue/decorators/process.decorator'; +import { InjectMessageQueue } from 'src/engine/integrations/message-queue/decorators/message-queue.decorator'; import { MessageChannelRepository } from 'src/modules/messaging/common/repositories/message-channel.repository'; import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; import { MessageChannelSyncStage, MessageChannelWorkspaceEntity, } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity'; +import { BillingService } from 'src/engine/core-modules/billing/billing.service'; + +@Processor(MessageQueue.cronQueue) +export class MessagingMessagesImportCronJob { + private readonly logger = new Logger(MessagingMessagesImportCronJob.name); -@Injectable() -export class MessagingMessagesImportCronJob - implements MessageQueueJob<undefined> -{ constructor( - @InjectRepository(Workspace, 'core') - private readonly workspaceRepository: Repository<Workspace>, @InjectRepository(DataSourceEntity, 'metadata') private readonly dataSourceRepository: Repository<DataSourceEntity>, - private readonly environmentService: EnvironmentService, - @Inject(MessageQueue.messagingQueue) + @InjectMessageQueue(MessageQueue.messagingQueue) private readonly messageQueueService: MessageQueueService, @InjectObjectMetadataRepository(MessageChannelWorkspaceEntity) private readonly messageChannelRepository: MessageChannelRepository, + private readonly billingService: BillingService, ) {} + @Process(MessagingMessagesImportCronJob.name) async handle(): Promise<void> { - const workspaceIds = ( - await this.workspaceRepository.find({ - where: this.environmentService.get('IS_BILLING_ENABLED') - ? { - subscriptionStatus: In(['active', 'trialing', 'past_due']), - } - : {}, - select: ['id'], - }) - ).map((workspace) => workspace.id); + const workspaceIds = + await this.billingService.getActiveSubscriptionWorkspaceIds(); const dataSources = await this.dataSourceRepository.find({ where: { diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/crons/jobs/messaging-ongoing-stale.cron.job.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/crons/jobs/messaging-ongoing-stale.cron.job.ts new file mode 100644 index 000000000000..bc1bce31ce1e --- /dev/null +++ b/packages/twenty-server/src/modules/messaging/message-import-manager/crons/jobs/messaging-ongoing-stale.cron.job.ts @@ -0,0 +1,51 @@ +import { InjectRepository } from '@nestjs/typeorm'; + +import { Repository, In } from 'typeorm'; + +import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity'; +import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; +import { Processor } from 'src/engine/integrations/message-queue/decorators/processor.decorator'; +import { Process } from 'src/engine/integrations/message-queue/decorators/process.decorator'; +import { InjectMessageQueue } from 'src/engine/integrations/message-queue/decorators/message-queue.decorator'; +import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service'; +import { + MessagingOngoingStaleJobData, + MessagingOngoingStaleJob, +} from 'src/modules/messaging/message-import-manager/jobs/messaging-ongoing-stale.job'; +import { BillingService } from 'src/engine/core-modules/billing/billing.service'; + +@Processor(MessageQueue.cronQueue) +export class MessagingOngoingStaleCronJob { + constructor( + @InjectRepository(DataSourceEntity, 'metadata') + private readonly dataSourceRepository: Repository<DataSourceEntity>, + @InjectMessageQueue(MessageQueue.messagingQueue) + private readonly messageQueueService: MessageQueueService, + private readonly billingService: BillingService, + ) {} + + @Process(MessagingOngoingStaleCronJob.name) + async handle(): Promise<void> { + const workspaceIds = + await this.billingService.getActiveSubscriptionWorkspaceIds(); + + const dataSources = await this.dataSourceRepository.find({ + where: { + workspaceId: In(workspaceIds), + }, + }); + + const workspaceIdsWithDataSources = new Set( + dataSources.map((dataSource) => dataSource.workspaceId), + ); + + for (const workspaceId of workspaceIdsWithDataSources) { + await this.messageQueueService.add<MessagingOngoingStaleJobData>( + MessagingOngoingStaleJob.name, + { + workspaceId, + }, + ); + } + } +} diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/constants/messaging-gmail-users-messages-get-batch-size.constant.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/constants/messaging-gmail-users-messages-get-batch-size.constant.ts index 81255f383742..fdf015b35a78 100644 --- a/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/constants/messaging-gmail-users-messages-get-batch-size.constant.ts +++ b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/constants/messaging-gmail-users-messages-get-batch-size.constant.ts @@ -1 +1 @@ -export const MESSAGING_GMAIL_USERS_MESSAGES_GET_BATCH_SIZE = 20; +export const MESSAGING_GMAIL_USERS_MESSAGES_GET_BATCH_SIZE = 100; diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/messaging-gmail-driver.module.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/messaging-gmail-driver.module.ts index 380e4534efb1..1056c25cc362 100644 --- a/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/messaging-gmail-driver.module.ts +++ b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/messaging-gmail-driver.module.ts @@ -2,10 +2,14 @@ import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity'; +import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module'; import { EnvironmentModule } from 'src/engine/integrations/environment/environment.module'; import { ObjectMetadataRepositoryModule } from 'src/engine/object-metadata-repository/object-metadata-repository.module'; -import { GoogleAPIRefreshAccessTokenModule } from 'src/modules/connected-account/services/google-api-refresh-access-token/google-api-refresh-access-token.module'; -import { BlocklistWorkspaceEntity } from 'src/modules/connected-account/standard-objects/blocklist.workspace-entity'; +import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; +import { BlocklistWorkspaceEntity } from 'src/modules/blocklist/standard-objects/blocklist.workspace-entity'; +import { EmailAliasManagerModule } from 'src/modules/connected-account/email-alias-manager/email-alias-manager.module'; +import { OAuth2ClientManagerModule } from 'src/modules/connected-account/oauth2-client-manager/oauth2-client-manager.module'; +import { RefreshAccessTokenManagerModule } from 'src/modules/connected-account/refresh-access-token-manager/refresh-access-token-manager.module'; import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; import { MessagingCommonModule } from 'src/modules/messaging/common/messaging-common.module'; import { MessageChannelMessageAssociationWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel-message-association.workspace-entity'; @@ -17,10 +21,12 @@ import { MessagingGmailFullMessageListFetchService } from 'src/modules/messaging import { MessagingGmailHistoryService } from 'src/modules/messaging/message-import-manager/drivers/gmail/services/messaging-gmail-history.service'; import { MessagingGmailMessagesImportService } from 'src/modules/messaging/message-import-manager/drivers/gmail/services/messaging-gmail-messages-import.service'; import { MessagingGmailPartialMessageListFetchService } from 'src/modules/messaging/message-import-manager/drivers/gmail/services/messaging-gmail-partial-message-list-fetch.service'; +import { MessagingSaveMessagesAndEnqueueContactCreationService } from 'src/modules/messaging/message-import-manager/drivers/gmail/services/messaging-save-messages-and-enqueue-contact-creation.service'; +import { MessageParticipantManagerModule } from 'src/modules/messaging/message-participant-manager/message-participant-manager.module'; @Module({ imports: [ - GoogleAPIRefreshAccessTokenModule, + RefreshAccessTokenManagerModule, EnvironmentModule, ObjectMetadataRepositoryModule.forFeature([ ConnectedAccountWorkspaceEntity, @@ -30,6 +36,11 @@ import { MessagingGmailPartialMessageListFetchService } from 'src/modules/messag ]), MessagingCommonModule, TypeOrmModule.forFeature([FeatureFlagEntity], 'core'), + OAuth2ClientManagerModule, + EmailAliasManagerModule, + FeatureFlagModule, + WorkspaceDataSourceModule, + MessageParticipantManagerModule, ], providers: [ MessagingGmailClientProvider, @@ -39,6 +50,7 @@ import { MessagingGmailPartialMessageListFetchService } from 'src/modules/messag MessagingGmailFullMessageListFetchService, MessagingGmailMessagesImportService, MessagingGmailFetchMessageIdsToExcludeService, + MessagingSaveMessagesAndEnqueueContactCreationService, ], exports: [ MessagingGmailClientProvider, diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/providers/messaging-gmail-client.provider.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/providers/messaging-gmail-client.provider.ts index 130e335621a1..834fedca46f7 100644 --- a/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/providers/messaging-gmail-client.provider.ts +++ b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/providers/messaging-gmail-client.provider.ts @@ -1,16 +1,24 @@ import { Injectable } from '@nestjs/common'; -import { OAuth2Client } from 'google-auth-library'; import { gmail_v1, google } from 'googleapis'; -import { EnvironmentService } from 'src/engine/integrations/environment/environment.service'; +import { OAuth2ClientManagerService } from 'src/modules/connected-account/oauth2-client-manager/services/oauth2-client-manager.service'; +import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; @Injectable() export class MessagingGmailClientProvider { - constructor(private readonly environmentService: EnvironmentService) {} - - public async getGmailClient(refreshToken: string): Promise<gmail_v1.Gmail> { - const oAuth2Client = await this.getOAuth2Client(refreshToken); + constructor( + private readonly oAuth2ClientManagerService: OAuth2ClientManagerService, + ) {} + + public async getGmailClient( + connectedAccount: Pick< + ConnectedAccountWorkspaceEntity, + 'provider' | 'refreshToken' + >, + ): Promise<gmail_v1.Gmail> { + const oAuth2Client = + await this.oAuth2ClientManagerService.getOAuth2Client(connectedAccount); const gmailClient = google.gmail({ version: 'v1', @@ -19,22 +27,4 @@ export class MessagingGmailClientProvider { return gmailClient; } - - private async getOAuth2Client(refreshToken: string): Promise<OAuth2Client> { - const gmailClientId = this.environmentService.get('AUTH_GOOGLE_CLIENT_ID'); - const gmailClientSecret = this.environmentService.get( - 'AUTH_GOOGLE_CLIENT_SECRET', - ); - - const oAuth2Client = new google.auth.OAuth2( - gmailClientId, - gmailClientSecret, - ); - - oAuth2Client.setCredentials({ - refresh_token: refreshToken, - }); - - return oAuth2Client; - } } diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/services/messaging-gmail-fetch-messages-by-batches.service.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/services/messaging-gmail-fetch-messages-by-batches.service.ts index 1e0c0c6e979c..df3c96bb3e0a 100644 --- a/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/services/messaging-gmail-fetch-messages-by-batches.service.ts +++ b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/services/messaging-gmail-fetch-messages-by-batches.service.ts @@ -7,12 +7,8 @@ import { gmail_v1 } from 'googleapis'; import { assert, assertNotNull } from 'src/utils/assert'; import { GmailMessage } from 'src/modules/messaging/message-import-manager/drivers/gmail/types/gmail-message'; -import { MessageQuery } from 'src/modules/messaging/message-import-manager/types/message-or-thread-query'; import { formatAddressObjectAsParticipants } from 'src/modules/messaging/message-import-manager/utils/format-address-object-as-participants.util'; import { MessagingFetchByBatchesService } from 'src/modules/messaging/common/services/messaging-fetch-by-batch.service'; -import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; -import { ConnectedAccountRepository } from 'src/modules/connected-account/repositories/connected-account.repository'; -import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; @Injectable() export class MessagingGmailFetchMessagesByBatchesService { @@ -22,46 +18,34 @@ export class MessagingGmailFetchMessagesByBatchesService { constructor( private readonly fetchByBatchesService: MessagingFetchByBatchesService, - @InjectObjectMetadataRepository(ConnectedAccountWorkspaceEntity) - private readonly connectedAccountRepository: ConnectedAccountRepository, ) {} async fetchAllMessages( - queries: MessageQuery[], + messageIds: string[], + accessToken: string, connectedAccountId: string, workspaceId: string, ): Promise<GmailMessage[]> { let startTime = Date.now(); - const connectedAccount = await this.connectedAccountRepository.getById( - connectedAccountId, - workspaceId, - ); - - if (!connectedAccount) { - throw new Error( - `Connected account ${connectedAccountId} not found in workspace ${workspaceId}`, + const { messageIdsByBatch, batchResponses } = + await this.fetchByBatchesService.fetchAllByBatches( + messageIds, + accessToken, + 'batch_gmail_messages', ); - } - - const accessToken = connectedAccount.accessToken; - - const batchResponses = await this.fetchByBatchesService.fetchAllByBatches( - queries, - accessToken, - 'batch_gmail_messages', - ); let endTime = Date.now(); this.logger.log( `Messaging import for workspace ${workspaceId} and account ${connectedAccountId} fetching ${ - queries.length + messageIds.length } messages in ${endTime - startTime}ms`, ); startTime = Date.now(); const formattedResponse = this.formatBatchResponsesAsGmailMessages( + messageIdsByBatch, batchResponses, workspaceId, connectedAccountId, @@ -71,7 +55,7 @@ export class MessagingGmailFetchMessagesByBatchesService { this.logger.log( `Messaging import for workspace ${workspaceId} and account ${connectedAccountId} formatting ${ - queries.length + messageIds.length } messages in ${endTime - startTime}ms`, ); @@ -79,6 +63,7 @@ export class MessagingGmailFetchMessagesByBatchesService { } private formatBatchResponseAsGmailMessage( + messageIds: string[], responseCollection: AxiosResponse<any, any>, workspaceId: string, connectedAccountId: string, @@ -90,94 +75,92 @@ export class MessagingGmailFetchMessagesByBatchesService { return str.replace(/\0/g, ''); }; - const formattedResponse = parsedResponses.map( - (response): GmailMessage | null => { - if ('error' in response) { - if (response.error.code === 404) { - return null; - } - - throw response.error; - } - - const { - historyId, - id, - threadId, - internalDate, - subject, - from, - to, - cc, - bcc, - headerMessageId, - text, - attachments, - deliveredTo, - } = this.parseGmailMessage(response); - - if (!from) { - this.logger.log( - `From value is missing while importing message #${id} in workspace ${workspaceId} and account ${connectedAccountId}`, - ); - - return null; - } - - if (!to && !deliveredTo && !bcc && !cc) { - this.logger.log( - `To, Delivered-To, Bcc or Cc value is missing while importing message #${id} in workspace ${workspaceId} and account ${connectedAccountId}`, - ); - - return null; - } - - if (!headerMessageId) { - this.logger.log( - `Message-ID is missing while importing message #${id} in workspace ${workspaceId} and account ${connectedAccountId}`, - ); - + const formattedResponse = parsedResponses.map((response, index) => { + if ('error' in response) { + if (response.error.code === 404) { return null; } - if (!threadId) { - this.logger.log( - `Thread Id is missing while importing message #${id} in workspace ${workspaceId} and account ${connectedAccountId}`, - ); - - return null; - } - - const participants = [ - ...formatAddressObjectAsParticipants(from, 'from'), - ...formatAddressObjectAsParticipants(to ?? deliveredTo, 'to'), - ...formatAddressObjectAsParticipants(cc, 'cc'), - ...formatAddressObjectAsParticipants(bcc, 'bcc'), - ]; - - let textWithoutReplyQuotations = text; - - if (text) { - textWithoutReplyQuotations = planer.extractFrom(text, 'text/plain'); - } - - const messageFromGmail: GmailMessage = { - historyId, - externalId: id, - headerMessageId, - subject: subject || '', - messageThreadExternalId: threadId, - internalDate, - fromHandle: from[0].address || '', - fromDisplayName: from[0].name || '', - participants, - text: sanitizeString(textWithoutReplyQuotations || ''), - attachments, - }; - - return messageFromGmail; - }, - ); + throw { ...response.error, messageId: messageIds[index] }; + } + + const { + historyId, + id, + threadId, + internalDate, + subject, + from, + to, + cc, + bcc, + headerMessageId, + text, + attachments, + deliveredTo, + } = this.parseGmailMessage(response); + + if (!from) { + this.logger.log( + `From value is missing while importing message #${id} in workspace ${workspaceId} and account ${connectedAccountId}`, + ); + + return null; + } + + if (!to && !deliveredTo && !bcc && !cc) { + this.logger.log( + `To, Delivered-To, Bcc or Cc value is missing while importing message #${id} in workspace ${workspaceId} and account ${connectedAccountId}`, + ); + + return null; + } + + if (!headerMessageId) { + this.logger.log( + `Message-ID is missing while importing message #${id} in workspace ${workspaceId} and account ${connectedAccountId}`, + ); + + return null; + } + + if (!threadId) { + this.logger.log( + `Thread Id is missing while importing message #${id} in workspace ${workspaceId} and account ${connectedAccountId}`, + ); + + return null; + } + + const participants = [ + ...formatAddressObjectAsParticipants(from, 'from'), + ...formatAddressObjectAsParticipants(to ?? deliveredTo, 'to'), + ...formatAddressObjectAsParticipants(cc, 'cc'), + ...formatAddressObjectAsParticipants(bcc, 'bcc'), + ]; + + let textWithoutReplyQuotations = text; + + if (text) { + textWithoutReplyQuotations = planer.extractFrom(text, 'text/plain'); + } + + const messageFromGmail: GmailMessage = { + historyId, + externalId: id, + headerMessageId, + subject: subject || '', + messageThreadExternalId: threadId, + internalDate, + fromHandle: from[0].address || '', + fromDisplayName: from[0].name || '', + participants, + text: sanitizeString(textWithoutReplyQuotations || ''), + attachments, + }; + + return messageFromGmail; + }); const filteredMessages = formattedResponse.filter((message) => assertNotNull(message), @@ -187,12 +170,14 @@ export class MessagingGmailFetchMessagesByBatchesService { } private formatBatchResponsesAsGmailMessages( + messageIdsByBatch: string[][], batchResponses: AxiosResponse<any, any>[], workspaceId: string, connectedAccountId: string, ): GmailMessage[] { - const messageBatches = batchResponses.map((response) => { + const messageBatches = batchResponses.map((response, index) => { return this.formatBatchResponseAsGmailMessage( + messageIdsByBatch[index], response, workspaceId, connectedAccountId, diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/services/messaging-gmail-full-message-list-fetch.service.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/services/messaging-gmail-full-message-list-fetch.service.ts index 079baf1ac9cf..12eeda48a37f 100644 --- a/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/services/messaging-gmail-full-message-list-fetch.service.ts +++ b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/services/messaging-gmail-full-message-list-fetch.service.ts @@ -9,7 +9,6 @@ import { InjectCacheStorage } from 'src/engine/integrations/cache-storage/decora import { CacheStorageNamespace } from 'src/engine/integrations/cache-storage/types/cache-storage-namespace.enum'; import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; -import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record'; import { MessageChannelMessageAssociationRepository } from 'src/modules/messaging/common/repositories/message-channel-message-association.repository'; import { MessageChannelRepository } from 'src/modules/messaging/common/repositories/message-channel.repository'; import { MessageChannelMessageAssociationWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel-message-association.workspace-entity'; @@ -23,8 +22,6 @@ import { MessagingChannelSyncStatusService } from 'src/modules/messaging/common/ import { MessagingGmailClientProvider } from 'src/modules/messaging/message-import-manager/drivers/gmail/providers/messaging-gmail-client.provider'; import { MESSAGING_GMAIL_USERS_MESSAGES_LIST_MAX_RESULT } from 'src/modules/messaging/message-import-manager/drivers/gmail/constants/messaging-gmail-users-messages-list-max-result.constant'; import { MESSAGING_GMAIL_EXCLUDED_CATEGORIES } from 'src/modules/messaging/message-import-manager/drivers/gmail/constants/messaging-gmail-excluded-categories'; -import { GoogleAPIRefreshAccessTokenService } from 'src/modules/connected-account/services/google-api-refresh-access-token/google-api-refresh-access-token.service'; -import { ConnectedAccountRepository } from 'src/modules/connected-account/repositories/connected-account.repository'; @Injectable() export class MessagingGmailFullMessageListFetchService { @@ -42,16 +39,13 @@ export class MessagingGmailFullMessageListFetchService { MessageChannelMessageAssociationWorkspaceEntity, ) private readonly messageChannelMessageAssociationRepository: MessageChannelMessageAssociationRepository, - @InjectObjectMetadataRepository(ConnectedAccountWorkspaceEntity) - private readonly connectedAccountRepository: ConnectedAccountRepository, private readonly messagingChannelSyncStatusService: MessagingChannelSyncStatusService, private readonly gmailErrorHandlingService: MessagingErrorHandlingService, - private readonly googleAPIsRefreshAccessTokenService: GoogleAPIRefreshAccessTokenService, ) {} public async processMessageListFetch( - messageChannel: ObjectRecord<MessageChannelWorkspaceEntity>, - connectedAccount: ObjectRecord<ConnectedAccountWorkspaceEntity>, + messageChannel: MessageChannelWorkspaceEntity, + connectedAccount: ConnectedAccountWorkspaceEntity, workspaceId: string, ) { await this.messagingChannelSyncStatusService.markAsMessagesListFetchOngoing( @@ -59,27 +53,8 @@ export class MessagingGmailFullMessageListFetchService { workspaceId, ); - await this.googleAPIsRefreshAccessTokenService.refreshAndSaveAccessToken( - workspaceId, - connectedAccount.id, - ); - - const refreshedConnectedAccount = - await this.connectedAccountRepository.getById( - connectedAccount.id, - workspaceId, - ); - - if (!refreshedConnectedAccount) { - throw new Error( - `Connected account ${connectedAccount.id} not found in workspace ${workspaceId}`, - ); - } - const gmailClient: gmail_v1.Gmail = - await this.gmailClientProvider.getGmailClient( - refreshedConnectedAccount.refreshToken, - ); + await this.gmailClientProvider.getGmailClient(connectedAccount); const { error: gmailError } = await this.fetchAllMessageIdsFromGmailAndStoreInCache( diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/services/messaging-gmail-messages-import.service.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/services/messaging-gmail-messages-import.service.ts index 8b6e462426ac..4d87f09b358d 100644 --- a/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/services/messaging-gmail-messages-import.service.ts +++ b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/services/messaging-gmail-messages-import.service.ts @@ -1,27 +1,29 @@ import { Injectable, Logger } from '@nestjs/common'; -import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; +import { FeatureFlagKeys } from 'src/engine/core-modules/feature-flag/feature-flag.entity'; +import { IsFeatureEnabledService } from 'src/engine/core-modules/feature-flag/services/is-feature-enabled.service'; +import { CacheStorageService } from 'src/engine/integrations/cache-storage/cache-storage.service'; import { InjectCacheStorage } from 'src/engine/integrations/cache-storage/decorators/cache-storage.decorator'; import { CacheStorageNamespace } from 'src/engine/integrations/cache-storage/types/cache-storage-namespace.enum'; -import { CacheStorageService } from 'src/engine/integrations/cache-storage/cache-storage.service'; -import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record'; -import { GoogleAPIRefreshAccessTokenService } from 'src/modules/connected-account/services/google-api-refresh-access-token/google-api-refresh-access-token.service'; -import { BlocklistWorkspaceEntity } from 'src/modules/connected-account/standard-objects/blocklist.workspace-entity'; import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; -import { BlocklistRepository } from 'src/modules/connected-account/repositories/blocklist.repository'; +import { BlocklistRepository } from 'src/modules/blocklist/repositories/blocklist.repository'; +import { BlocklistWorkspaceEntity } from 'src/modules/blocklist/standard-objects/blocklist.workspace-entity'; +import { EmailAliasManagerService } from 'src/modules/connected-account/email-alias-manager/services/email-alias-manager.service'; +import { RefreshAccessTokenService } from 'src/modules/connected-account/refresh-access-token-manager/services/refresh-access-token.service'; +import { ConnectedAccountRepository } from 'src/modules/connected-account/repositories/connected-account.repository'; +import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; +import { MessageChannelRepository } from 'src/modules/messaging/common/repositories/message-channel.repository'; +import { MessagingChannelSyncStatusService } from 'src/modules/messaging/common/services/messaging-channel-sync-status.service'; +import { MessagingErrorHandlingService } from 'src/modules/messaging/common/services/messaging-error-handling.service'; import { MessagingTelemetryService } from 'src/modules/messaging/common/services/messaging-telemetry.service'; import { - MessageChannelWorkspaceEntity, MessageChannelSyncStage, + MessageChannelWorkspaceEntity, } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity'; -import { createQueriesFromMessageIds } from 'src/modules/messaging/message-import-manager/utils/create-queries-from-message-ids.util'; -import { filterEmails } from 'src/modules/messaging/message-import-manager/utils/filter-emails.util'; -import { MessagingChannelSyncStatusService } from 'src/modules/messaging/common/services/messaging-channel-sync-status.service'; import { MESSAGING_GMAIL_USERS_MESSAGES_GET_BATCH_SIZE } from 'src/modules/messaging/message-import-manager/drivers/gmail/constants/messaging-gmail-users-messages-get-batch-size.constant'; import { MessagingGmailFetchMessagesByBatchesService } from 'src/modules/messaging/message-import-manager/drivers/gmail/services/messaging-gmail-fetch-messages-by-batches.service'; -import { MessagingErrorHandlingService } from 'src/modules/messaging/common/services/messaging-error-handling.service'; -import { MessagingSaveMessagesAndEnqueueContactCreationService } from 'src/modules/messaging/common/services/messaging-save-messages-and-enqueue-contact-creation.service'; -import { MessageChannelRepository } from 'src/modules/messaging/common/repositories/message-channel.repository'; +import { MessagingSaveMessagesAndEnqueueContactCreationService } from 'src/modules/messaging/message-import-manager/drivers/gmail/services/messaging-save-messages-and-enqueue-contact-creation.service'; +import { filterEmails } from 'src/modules/messaging/message-import-manager/utils/filter-emails.util'; @Injectable() export class MessagingGmailMessagesImportService { @@ -36,17 +38,21 @@ export class MessagingGmailMessagesImportService { private readonly messagingChannelSyncStatusService: MessagingChannelSyncStatusService, private readonly saveMessagesAndEnqueueContactCreationService: MessagingSaveMessagesAndEnqueueContactCreationService, private readonly gmailErrorHandlingService: MessagingErrorHandlingService, - private readonly googleAPIsRefreshAccessTokenService: GoogleAPIRefreshAccessTokenService, + private readonly refreshAccessTokenService: RefreshAccessTokenService, private readonly messagingTelemetryService: MessagingTelemetryService, @InjectObjectMetadataRepository(BlocklistWorkspaceEntity) private readonly blocklistRepository: BlocklistRepository, @InjectObjectMetadataRepository(MessageChannelWorkspaceEntity) private readonly messageChannelRepository: MessageChannelRepository, + private readonly emailAliasManagerService: EmailAliasManagerService, + private readonly isFeatureEnabledService: IsFeatureEnabledService, + @InjectObjectMetadataRepository(ConnectedAccountWorkspaceEntity) + private readonly connectedAccountRepository: ConnectedAccountRepository, ) {} async processMessageBatchImport( - messageChannel: ObjectRecord<MessageChannelWorkspaceEntity>, - connectedAccount: ObjectRecord<ConnectedAccountWorkspaceEntity>, + messageChannel: MessageChannelWorkspaceEntity, + connectedAccount: ConnectedAccountWorkspaceEntity, workspaceId: string, ) { if ( @@ -72,10 +78,59 @@ export class MessagingGmailMessagesImportService { workspaceId, ); - await this.googleAPIsRefreshAccessTokenService.refreshAndSaveAccessToken( - workspaceId, - connectedAccount.id, - ); + let accessToken: string; + + try { + accessToken = + await this.refreshAccessTokenService.refreshAndSaveAccessToken( + connectedAccount, + workspaceId, + ); + } catch (error) { + await this.messagingTelemetryService.track({ + eventName: `refresh_token.error.insufficient_permissions`, + workspaceId, + connectedAccountId: messageChannel.connectedAccountId, + messageChannelId: messageChannel.id, + message: `${error.code}: ${error.reason}`, + }); + + await this.messagingChannelSyncStatusService.markAsFailedInsufficientPermissionsAndFlushMessagesToImport( + messageChannel.id, + workspaceId, + ); + + await this.connectedAccountRepository.updateAuthFailedAt( + messageChannel.connectedAccountId, + workspaceId, + ); + + return; + } + + if ( + await this.isFeatureEnabledService.isFeatureEnabled( + FeatureFlagKeys.IsMessagingAliasFetchingEnabled, + workspaceId, + ) + ) { + try { + await this.emailAliasManagerService.refreshHandleAliases( + connectedAccount, + workspaceId, + ); + } catch (error) { + await this.gmailErrorHandlingService.handleGmailError( + { + code: error.code, + reason: error.message, + }, + 'messages-import', + messageChannel, + workspaceId, + ); + } + } const messageIdsToFetch = (await this.cacheStorage.setPop( @@ -95,12 +150,11 @@ export class MessagingGmailMessagesImportService { ); } - const messageQueries = createQueriesFromMessageIds(messageIdsToFetch); - try { const allMessages = await this.fetchMessagesByBatchesService.fetchAllMessages( - messageQueries, + messageIdsToFetch, + accessToken, connectedAccount.id, workspaceId, ); @@ -152,6 +206,14 @@ export class MessagingGmailMessagesImportService { workspaceId, ); } catch (error) { + this.logger.log( + `Messaging import for messageId ${ + error.messageId + }, workspace ${workspaceId} and connected account ${ + connectedAccount.id + } failed with error: ${JSON.stringify(error)}`, + ); + await this.cacheStorage.setAdd( `messages-to-import:${workspaceId}:gmail:${messageChannel.id}`, messageIdsToFetch, @@ -180,7 +242,7 @@ export class MessagingGmailMessagesImportService { } private async trackMessageImportCompleted( - messageChannel: ObjectRecord<MessageChannelWorkspaceEntity>, + messageChannel: MessageChannelWorkspaceEntity, workspaceId: string, ) { await this.messagingTelemetryService.track({ diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/services/messaging-gmail-partial-message-list-fetch.service.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/services/messaging-gmail-partial-message-list-fetch.service.ts index 654150d5b1da..069180e5d7e1 100644 --- a/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/services/messaging-gmail-partial-message-list-fetch.service.ts +++ b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/services/messaging-gmail-partial-message-list-fetch.service.ts @@ -7,7 +7,6 @@ import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/s import { CacheStorageService } from 'src/engine/integrations/cache-storage/cache-storage.service'; import { InjectCacheStorage } from 'src/engine/integrations/cache-storage/decorators/cache-storage.decorator'; import { CacheStorageNamespace } from 'src/engine/integrations/cache-storage/types/cache-storage-namespace.enum'; -import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record'; import { MessageChannelMessageAssociationRepository } from 'src/modules/messaging/common/repositories/message-channel-message-association.repository'; import { MessageChannelRepository } from 'src/modules/messaging/common/repositories/message-channel.repository'; import { MessageChannelMessageAssociationWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel-message-association.workspace-entity'; @@ -41,8 +40,8 @@ export class MessagingGmailPartialMessageListFetchService { ) {} public async processMessageListFetch( - messageChannel: ObjectRecord<MessageChannelWorkspaceEntity>, - connectedAccount: ObjectRecord<ConnectedAccountWorkspaceEntity>, + messageChannel: MessageChannelWorkspaceEntity, + connectedAccount: ConnectedAccountWorkspaceEntity, workspaceId: string, ): Promise<void> { await this.messagingChannelSyncStatusService.markAsMessagesListFetchOngoing( @@ -53,9 +52,7 @@ export class MessagingGmailPartialMessageListFetchService { const lastSyncHistoryId = messageChannel.syncCursor; const gmailClient: gmail_v1.Gmail = - await this.gmailClientProvider.getGmailClient( - connectedAccount.refreshToken, - ); + await this.gmailClientProvider.getGmailClient(connectedAccount); const { history, historyId, error } = await this.gmailGetHistoryService.getHistory( diff --git a/packages/twenty-server/src/modules/messaging/common/services/messaging-save-messages-and-enqueue-contact-creation.service.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/services/messaging-save-messages-and-enqueue-contact-creation.service.ts similarity index 57% rename from packages/twenty-server/src/modules/messaging/common/services/messaging-save-messages-and-enqueue-contact-creation.service.ts rename to packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/services/messaging-save-messages-and-enqueue-contact-creation.service.ts index 163c4427b7c4..f408e1c3d548 100644 --- a/packages/twenty-server/src/modules/messaging/common/services/messaging-save-messages-and-enqueue-contact-creation.service.ts +++ b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/services/messaging-save-messages-and-enqueue-contact-creation.service.ts @@ -1,37 +1,39 @@ -import { Injectable, Inject } from '@nestjs/common'; -import { InjectRepository } from '@nestjs/typeorm'; +import { Injectable } from '@nestjs/common'; import { EventEmitter2 } from '@nestjs/event-emitter'; +import { InjectRepository } from '@nestjs/typeorm'; import { EntityManager, Repository } from 'typeorm'; +import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity'; +import { InjectMessageQueue } from 'src/engine/integrations/message-queue/decorators/message-queue.decorator'; import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service'; import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; -import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record'; import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; import { - CreateCompanyAndContactJobData, CreateCompanyAndContactJob, -} from 'src/modules/connected-account/auto-companies-and-contacts-creation/jobs/create-company-and-contact.job'; + CreateCompanyAndContactJobData, +} from 'src/modules/contact-creation-manager/jobs/create-company-and-contact.job'; +import { MessagingMessageService } from 'src/modules/messaging/common/services/messaging-message.service'; import { - FeatureFlagEntity, - FeatureFlagKeys, -} from 'src/engine/core-modules/feature-flag/feature-flag.entity'; -import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity'; + MessageChannelContactAutoCreationPolicy, + MessageChannelWorkspaceEntity, +} from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity'; +import { MessageParticipantWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-participant.workspace-entity'; import { GmailMessage, Participant, ParticipantWithMessageId, } from 'src/modules/messaging/message-import-manager/drivers/gmail/types/gmail-message'; -import { MessagingMessageService } from 'src/modules/messaging/common/services/messaging-message.service'; -import { MessagingMessageParticipantService } from 'src/modules/messaging/common/services/messaging-message-participant.service'; -import { MessageParticipantWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-participant.workspace-entity'; +import { MessagingMessageParticipantService } from 'src/modules/messaging/message-participant-manager/services/messaging-message-participant.service'; +import { isGroupEmail } from 'src/utils/is-group-email'; +import { isWorkEmail } from 'src/utils/is-work-email'; @Injectable() export class MessagingSaveMessagesAndEnqueueContactCreationService { constructor( private readonly workspaceDataSourceService: WorkspaceDataSourceService, - @Inject(MessageQueue.messagingQueue) + @InjectMessageQueue(MessageQueue.contactCreationQueue) private readonly messageQueueService: MessageQueueService, private readonly messageService: MessagingMessageService, private readonly messageParticipantService: MessagingMessageParticipantService, @@ -42,8 +44,8 @@ export class MessagingSaveMessagesAndEnqueueContactCreationService { async saveMessagesAndEnqueueContactCreationJob( messagesToSave: GmailMessage[], - messageChannel: ObjectRecord<MessageChannelWorkspaceEntity>, - connectedAccount: ObjectRecord<ConnectedAccountWorkspaceEntity>, + messageChannel: MessageChannelWorkspaceEntity, + connectedAccount: ConnectedAccountWorkspaceEntity, workspaceId: string, ) { const workspaceDataSource = @@ -51,18 +53,9 @@ export class MessagingSaveMessagesAndEnqueueContactCreationService { workspaceId, ); - const isContactCreationForSentAndReceivedEmailsEnabledFeatureFlag = - await this.featureFlagRepository.findOneBy({ - workspaceId: workspaceId, - key: FeatureFlagKeys.IsContactCreationForSentAndReceivedEmailsEnabled, - value: true, - }); + const handleAliases = connectedAccount.handleAliases?.split(',') || []; - const isContactCreationForSentAndReceivedEmailsEnabled = - isContactCreationForSentAndReceivedEmailsEnabledFeatureFlag?.value; - - let savedMessageParticipants: ObjectRecord<MessageParticipantWorkspaceEntity>[] = - []; + let savedMessageParticipants: MessageParticipantWorkspaceEntity[] = []; const participantsWithMessageId = await workspaceDataSource?.transaction( async (transactionManager: EntityManager) => { @@ -81,15 +74,43 @@ export class MessagingSaveMessagesAndEnqueueContactCreationService { const messageId = messageExternalIdsAndIdsMap.get(message.externalId); return messageId - ? message.participants.map((participant: Participant) => ({ - ...participant, - messageId, - shouldCreateContact: - messageChannel.isContactAutoCreationEnabled && - (isContactCreationForSentAndReceivedEmailsEnabled || - message.participants.find((p) => p.role === 'from') - ?.handle === connectedAccount.handle), - })) + ? message.participants.map((participant: Participant) => { + const fromHandle = + message.participants.find((p) => p.role === 'from')?.handle || + ''; + + const isMessageSentByConnectedAccount = + handleAliases.includes(fromHandle) || + fromHandle === connectedAccount.handle; + + const isParticipantConnectedAccount = + handleAliases.includes(participant.handle) || + participant.handle === connectedAccount.handle; + + const isExcludedByNonProfessionalEmails = + messageChannel.excludeNonProfessionalEmails && + !isWorkEmail(participant.handle); + + const isExcludedByGroupEmails = + messageChannel.excludeGroupEmails && + isGroupEmail(participant.handle); + + const shouldCreateContact = + !isParticipantConnectedAccount && + !isExcludedByNonProfessionalEmails && + !isExcludedByGroupEmails && + (messageChannel.contactAutoCreationPolicy === + MessageChannelContactAutoCreationPolicy.SENT_AND_RECEIVED || + (messageChannel.contactAutoCreationPolicy === + MessageChannelContactAutoCreationPolicy.SENT && + isMessageSentByConnectedAccount)); + + return { + ...participant, + messageId, + shouldCreateContact, + }; + }) : []; }); @@ -106,7 +127,7 @@ export class MessagingSaveMessagesAndEnqueueContactCreationService { this.eventEmitter.emit(`messageParticipant.matched`, { workspaceId, - userId: connectedAccount.accountOwnerId, + workspaceMemberId: connectedAccount.accountOwnerId, messageParticipants: savedMessageParticipants, }); diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/jobs/messaging-add-single-message-to-cache-for-import.job.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/jobs/messaging-add-single-message-to-cache-for-import.job.ts new file mode 100644 index 000000000000..d81bba9cd096 --- /dev/null +++ b/packages/twenty-server/src/modules/messaging/message-import-manager/jobs/messaging-add-single-message-to-cache-for-import.job.ts @@ -0,0 +1,32 @@ +import { CacheStorageService } from 'src/engine/integrations/cache-storage/cache-storage.service'; +import { InjectCacheStorage } from 'src/engine/integrations/cache-storage/decorators/cache-storage.decorator'; +import { CacheStorageNamespace } from 'src/engine/integrations/cache-storage/types/cache-storage-namespace.enum'; +import { Process } from 'src/engine/integrations/message-queue/decorators/process.decorator'; +import { Processor } from 'src/engine/integrations/message-queue/decorators/processor.decorator'; +import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; + +export type MessagingAddSingleMessageToCacheForImportJobData = { + messageExternalId: string; + messageChannelId: string; + workspaceId: string; +}; + +@Processor(MessageQueue.messagingQueue) +export class MessagingAddSingleMessageToCacheForImportJob { + constructor( + @InjectCacheStorage(CacheStorageNamespace.Messaging) + private readonly cacheStorage: CacheStorageService, + ) {} + + @Process(MessagingAddSingleMessageToCacheForImportJob.name) + async handle( + data: MessagingAddSingleMessageToCacheForImportJobData, + ): Promise<void> { + const { messageExternalId, messageChannelId, workspaceId } = data; + + await this.cacheStorage.setAdd( + `messages-to-import:${workspaceId}:gmail:${messageChannelId}`, + [messageExternalId], + ); + } +} diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/jobs/messaging-clean-cache.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/jobs/messaging-clean-cache.ts new file mode 100644 index 000000000000..8c2bc681f240 --- /dev/null +++ b/packages/twenty-server/src/modules/messaging/message-import-manager/jobs/messaging-clean-cache.ts @@ -0,0 +1,38 @@ +import { Logger } from '@nestjs/common'; + +import { Processor } from 'src/engine/integrations/message-queue/decorators/processor.decorator'; +import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; +import { Process } from 'src/engine/integrations/message-queue/decorators/process.decorator'; +import { InjectCacheStorage } from 'src/engine/integrations/cache-storage/decorators/cache-storage.decorator'; +import { CacheStorageNamespace } from 'src/engine/integrations/cache-storage/types/cache-storage-namespace.enum'; +import { CacheStorageService } from 'src/engine/integrations/cache-storage/cache-storage.service'; + +export type MessagingCleanCacheJobData = { + workspaceId: string; + messageChannelId: string; +}; + +@Processor(MessageQueue.messagingQueue) +export class MessagingCleanCacheJob { + private readonly logger = new Logger(MessagingCleanCacheJob.name); + + constructor( + @InjectCacheStorage(CacheStorageNamespace.Messaging) + private readonly cacheStorage: CacheStorageService, + ) {} + + @Process(MessagingCleanCacheJob.name) + async handle(data: MessagingCleanCacheJobData): Promise<void> { + this.logger.log( + `Deleting message channel ${data.messageChannelId} associated cache in workspace ${data.workspaceId}`, + ); + + await this.cacheStorage.del( + `messages-to-import:${data.workspaceId}:gmail:${data.messageChannelId}`, + ); + + this.logger.log( + `Deleted message channel ${data.messageChannelId} associated cache in workspace ${data.workspaceId}`, + ); + } +} diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/jobs/messaging-message-list-fetch.job.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/jobs/messaging-message-list-fetch.job.ts index 4cd4b40e5651..2a468fa493dd 100644 --- a/packages/twenty-server/src/modules/messaging/message-import-manager/jobs/messaging-message-list-fetch.job.ts +++ b/packages/twenty-server/src/modules/messaging/message-import-manager/jobs/messaging-message-list-fetch.job.ts @@ -1,7 +1,8 @@ -import { Injectable, Logger } from '@nestjs/common'; - -import { MessageQueueJob } from 'src/engine/integrations/message-queue/interfaces/message-queue-job.interface'; +import { Logger, Scope } from '@nestjs/common'; +import { Process } from 'src/engine/integrations/message-queue/decorators/process.decorator'; +import { Processor } from 'src/engine/integrations/message-queue/decorators/processor.decorator'; +import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; import { ConnectedAccountRepository } from 'src/modules/connected-account/repositories/connected-account.repository'; import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; @@ -13,17 +14,18 @@ import { } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity'; import { MessagingGmailFullMessageListFetchService } from 'src/modules/messaging/message-import-manager/drivers/gmail/services/messaging-gmail-full-message-list-fetch.service'; import { MessagingGmailPartialMessageListFetchService } from 'src/modules/messaging/message-import-manager/drivers/gmail/services/messaging-gmail-partial-message-list-fetch.service'; -import { isThrottled } from 'src/modules/messaging/message-import-manager/drivers/gmail/utils/is-throttled'; +import { isThrottled } from 'src/modules/connected-account/utils/is-throttled'; export type MessagingMessageListFetchJobData = { messageChannelId: string; workspaceId: string; }; -@Injectable() -export class MessagingMessageListFetchJob - implements MessageQueueJob<MessagingMessageListFetchJobData> -{ +@Processor({ + queueName: MessageQueue.messagingQueue, + scope: Scope.REQUEST, +}) +export class MessagingMessageListFetchJob { private readonly logger = new Logger(MessagingMessageListFetchJob.name); constructor( @@ -36,6 +38,7 @@ export class MessagingMessageListFetchJob private readonly messagingTelemetryService: MessagingTelemetryService, ) {} + @Process(MessagingMessageListFetchJob.name) async handle(data: MessagingMessageListFetchJobData): Promise<void> { const { messageChannelId, workspaceId } = data; diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/jobs/messaging-messages-import.job.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/jobs/messaging-messages-import.job.ts index 246f5f8b1f5e..b4cc6ae0b87d 100644 --- a/packages/twenty-server/src/modules/messaging/message-import-manager/jobs/messaging-messages-import.job.ts +++ b/packages/twenty-server/src/modules/messaging/message-import-manager/jobs/messaging-messages-import.job.ts @@ -1,7 +1,8 @@ -import { Injectable } from '@nestjs/common'; - -import { MessageQueueJob } from 'src/engine/integrations/message-queue/interfaces/message-queue-job.interface'; +import { Scope } from '@nestjs/common'; +import { Process } from 'src/engine/integrations/message-queue/decorators/process.decorator'; +import { Processor } from 'src/engine/integrations/message-queue/decorators/processor.decorator'; +import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; import { ConnectedAccountRepository } from 'src/modules/connected-account/repositories/connected-account.repository'; import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; @@ -12,17 +13,18 @@ import { MessageChannelWorkspaceEntity, } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity'; import { MessagingGmailMessagesImportService } from 'src/modules/messaging/message-import-manager/drivers/gmail/services/messaging-gmail-messages-import.service'; -import { isThrottled } from 'src/modules/messaging/message-import-manager/drivers/gmail/utils/is-throttled'; +import { isThrottled } from 'src/modules/connected-account/utils/is-throttled'; export type MessagingMessagesImportJobData = { messageChannelId: string; workspaceId: string; }; -@Injectable() -export class MessagingMessagesImportJob - implements MessageQueueJob<MessagingMessagesImportJobData> -{ +@Processor({ + queueName: MessageQueue.messagingQueue, + scope: Scope.REQUEST, +}) +export class MessagingMessagesImportJob { constructor( @InjectObjectMetadataRepository(ConnectedAccountWorkspaceEntity) private readonly connectedAccountRepository: ConnectedAccountRepository, @@ -32,6 +34,7 @@ export class MessagingMessagesImportJob private readonly messagingTelemetryService: MessagingTelemetryService, ) {} + @Process(MessagingMessagesImportJob.name) async handle(data: MessagingMessagesImportJobData): Promise<void> { const { messageChannelId, workspaceId } = data; diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/jobs/messaging-ongoing-stale.job.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/jobs/messaging-ongoing-stale.job.ts new file mode 100644 index 000000000000..0eb3c2aa12f8 --- /dev/null +++ b/packages/twenty-server/src/modules/messaging/message-import-manager/jobs/messaging-ongoing-stale.job.ts @@ -0,0 +1,74 @@ +import { Logger, Scope } from '@nestjs/common'; + +import { In } from 'typeorm'; + +import { Process } from 'src/engine/integrations/message-queue/decorators/process.decorator'; +import { Processor } from 'src/engine/integrations/message-queue/decorators/processor.decorator'; +import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; +import { + MessageChannelSyncStage, + MessageChannelWorkspaceEntity, +} from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity'; +import { isSyncStale } from 'src/modules/messaging/message-import-manager/utils/is-sync-stale.util'; +import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository'; +import { InjectWorkspaceRepository } from 'src/engine/twenty-orm/decorators/inject-workspace-repository.decorator'; +import { MessagingChannelSyncStatusService } from 'src/modules/messaging/common/services/messaging-channel-sync-status.service'; + +export type MessagingOngoingStaleJobData = { + workspaceId: string; +}; + +@Processor({ + queueName: MessageQueue.messagingQueue, + scope: Scope.REQUEST, +}) +export class MessagingOngoingStaleJob { + private readonly logger = new Logger(MessagingOngoingStaleJob.name); + constructor( + @InjectWorkspaceRepository(MessageChannelWorkspaceEntity) + private readonly messageChannelRepository: WorkspaceRepository<MessageChannelWorkspaceEntity>, + private readonly messagingChannelSyncStatusService: MessagingChannelSyncStatusService, + ) {} + + @Process(MessagingOngoingStaleJob.name) + async handle(data: MessagingOngoingStaleJobData): Promise<void> { + const { workspaceId } = data; + + const messageChannels = await this.messageChannelRepository.find({ + where: { + syncStage: In([ + MessageChannelSyncStage.MESSAGES_IMPORT_ONGOING, + MessageChannelSyncStage.MESSAGE_LIST_FETCH_ONGOING, + ]), + }, + }); + + for (const messageChannel of messageChannels) { + if ( + messageChannel.syncStageStartedAt && + isSyncStale(messageChannel.syncStageStartedAt) + ) { + this.logger.log( + `Sync for message channel ${messageChannel.id} and workspace ${workspaceId} is stale. Setting sync stage to MESSAGES_IMPORT_PENDING`, + ); + + switch (messageChannel.syncStage) { + case MessageChannelSyncStage.MESSAGE_LIST_FETCH_ONGOING: + await this.messagingChannelSyncStatusService.schedulePartialMessageListFetch( + messageChannel.id, + workspaceId, + ); + break; + case MessageChannelSyncStage.MESSAGES_IMPORT_ONGOING: + await this.messagingChannelSyncStatusService.scheduleMessagesImport( + messageChannel.id, + workspaceId, + ); + break; + default: + break; + } + } + } + } +} diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/listeners/messaging-import-manager-message-channel.listener.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/listeners/messaging-import-manager-message-channel.listener.ts new file mode 100644 index 000000000000..d3f00c95fc42 --- /dev/null +++ b/packages/twenty-server/src/modules/messaging/message-import-manager/listeners/messaging-import-manager-message-channel.listener.ts @@ -0,0 +1,33 @@ +import { Injectable } from '@nestjs/common'; +import { OnEvent } from '@nestjs/event-emitter'; + +import { ObjectRecordDeleteEvent } from 'src/engine/integrations/event-emitter/types/object-record-delete.event'; +import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; +import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service'; +import { InjectMessageQueue } from 'src/engine/integrations/message-queue/decorators/message-queue.decorator'; +import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity'; +import { + MessagingCleanCacheJob, + MessagingCleanCacheJobData, +} from 'src/modules/messaging/message-import-manager/jobs/messaging-clean-cache'; + +@Injectable() +export class MessagingMessageImportManagerMessageChannelListener { + constructor( + @InjectMessageQueue(MessageQueue.messagingQueue) + private readonly messageQueueService: MessageQueueService, + ) {} + + @OnEvent('messageChannel.deleted') + async handleDeletedEvent( + payload: ObjectRecordDeleteEvent<MessageChannelWorkspaceEntity>, + ) { + await this.messageQueueService.add<MessagingCleanCacheJobData>( + MessagingCleanCacheJob.name, + { + workspaceId: payload.workspaceId, + messageChannelId: payload.recordId, + }, + ); + } +} diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/messaging-import-manager.module.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/messaging-import-manager.module.ts index b0b6362c0f35..b2f951bc9789 100644 --- a/packages/twenty-server/src/modules/messaging/message-import-manager/messaging-import-manager.module.ts +++ b/packages/twenty-server/src/modules/messaging/message-import-manager/messaging-import-manager.module.ts @@ -3,41 +3,50 @@ import { TypeOrmModule } from '@nestjs/typeorm'; import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity'; +import { TwentyORMModule } from 'src/engine/twenty-orm/twenty-orm.module'; import { MessagingCommonModule } from 'src/modules/messaging/common/messaging-common.module'; +import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity'; +import { MessagingSingleMessageImportCommand } from 'src/modules/messaging/message-import-manager/commands/messaging-single-message-import.command'; import { MessagingMessageListFetchCronCommand } from 'src/modules/messaging/message-import-manager/crons/commands/messaging-message-list-fetch.cron.command'; import { MessagingMessagesImportCronCommand } from 'src/modules/messaging/message-import-manager/crons/commands/messaging-messages-import.cron.command'; +import { MessagingOngoingStaleCronCommand } from 'src/modules/messaging/message-import-manager/crons/commands/messaging-ongoing-stale.cron.command'; import { MessagingMessageListFetchCronJob } from 'src/modules/messaging/message-import-manager/crons/jobs/messaging-message-list-fetch.cron.job'; import { MessagingMessagesImportCronJob } from 'src/modules/messaging/message-import-manager/crons/jobs/messaging-messages-import.cron.job'; +import { MessagingOngoingStaleCronJob } from 'src/modules/messaging/message-import-manager/crons/jobs/messaging-ongoing-stale.cron.job'; import { MessagingGmailDriverModule } from 'src/modules/messaging/message-import-manager/drivers/gmail/messaging-gmail-driver.module'; +import { MessagingAddSingleMessageToCacheForImportJob } from 'src/modules/messaging/message-import-manager/jobs/messaging-add-single-message-to-cache-for-import.job'; +import { MessagingCleanCacheJob } from 'src/modules/messaging/message-import-manager/jobs/messaging-clean-cache'; import { MessagingMessageListFetchJob } from 'src/modules/messaging/message-import-manager/jobs/messaging-message-list-fetch.job'; import { MessagingMessagesImportJob } from 'src/modules/messaging/message-import-manager/jobs/messaging-messages-import.job'; +import { MessagingOngoingStaleJob } from 'src/modules/messaging/message-import-manager/jobs/messaging-ongoing-stale.job'; +import { MessagingMessageImportManagerMessageChannelListener } from 'src/modules/messaging/message-import-manager/listeners/messaging-import-manager-message-channel.listener'; +import { BillingModule } from 'src/engine/core-modules/billing/billing.module'; +import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; @Module({ imports: [ + WorkspaceDataSourceModule, MessagingGmailDriverModule, MessagingCommonModule, TypeOrmModule.forFeature([Workspace], 'core'), TypeOrmModule.forFeature([DataSourceEntity], 'metadata'), + TwentyORMModule.forFeature([MessageChannelWorkspaceEntity]), + BillingModule, ], providers: [ MessagingMessageListFetchCronCommand, MessagingMessagesImportCronCommand, - { - provide: MessagingMessageListFetchJob.name, - useClass: MessagingMessageListFetchJob, - }, - { - provide: MessagingMessagesImportJob.name, - useClass: MessagingMessagesImportJob, - }, - { - provide: MessagingMessageListFetchCronJob.name, - useClass: MessagingMessageListFetchCronJob, - }, - { - provide: MessagingMessagesImportCronJob.name, - useClass: MessagingMessagesImportCronJob, - }, + MessagingOngoingStaleCronCommand, + MessagingSingleMessageImportCommand, + MessagingMessageListFetchJob, + MessagingMessagesImportJob, + MessagingOngoingStaleJob, + MessagingMessageListFetchCronJob, + MessagingMessagesImportCronJob, + MessagingOngoingStaleCronJob, + MessagingAddSingleMessageToCacheForImportJob, + MessagingMessageImportManagerMessageChannelListener, + MessagingCleanCacheJob, ], exports: [], }) diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/utils/__tests__/is-sync-stale.util.spec.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/utils/__tests__/is-sync-stale.util.spec.ts new file mode 100644 index 000000000000..9935eb610812 --- /dev/null +++ b/packages/twenty-server/src/modules/messaging/message-import-manager/utils/__tests__/is-sync-stale.util.spec.ts @@ -0,0 +1,34 @@ +import { MESSAGING_IMPORT_ONGOING_SYNC_TIMEOUT } from 'src/modules/messaging/message-import-manager/constants/messaging-import-ongoing-sync-timeout.constant'; +import { isSyncStale } from 'src/modules/messaging/message-import-manager/utils/is-sync-stale.util'; + +jest.useFakeTimers().setSystemTime(new Date('2024-01-01')); + +describe('isSyncStale', () => { + it('should return true if sync is stale', () => { + const syncStageStartedAt = new Date( + Date.now() - MESSAGING_IMPORT_ONGOING_SYNC_TIMEOUT - 1, + ).toISOString(); + + const result = isSyncStale(syncStageStartedAt); + + expect(result).toBe(true); + }); + + it('should return false if sync is not stale', () => { + const syncStageStartedAt = new Date( + Date.now() - MESSAGING_IMPORT_ONGOING_SYNC_TIMEOUT + 1, + ).toISOString(); + + const result = isSyncStale(syncStageStartedAt); + + expect(result).toBe(false); + }); + + it('should return false if syncStageStartedAt is invalid', () => { + const syncStageStartedAt = 'invalid-date'; + + expect(() => { + isSyncStale(syncStageStartedAt); + }).toThrow('Invalid date format'); + }); +}); diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/utils/filter-emails.util.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/utils/filter-emails.util.ts index 3bd9819f27d4..b87a36146cb1 100644 --- a/packages/twenty-server/src/modules/messaging/message-import-manager/utils/filter-emails.util.ts +++ b/packages/twenty-server/src/modules/messaging/message-import-manager/utils/filter-emails.util.ts @@ -1,4 +1,4 @@ -import { isEmailBlocklisted } from 'src/modules/calendar-messaging-participant/utils/is-email-blocklisted.util'; +import { isEmailBlocklisted } from 'src/modules/calendar-messaging-participant-manager/utils/is-email-blocklisted.util'; import { GmailMessage } from 'src/modules/messaging/message-import-manager/drivers/gmail/types/gmail-message'; // Todo: refactor this into several utils @@ -9,7 +9,7 @@ export const filterEmails = ( ) => { return filterOutBlocklistedMessages( messageChannelHandle, - filterOutIcsAttachments(filterOutNonPersonalEmails(messages)), + filterOutIcsAttachments(messages), blocklist, ); }; @@ -46,22 +46,3 @@ const filterOutIcsAttachments = (messages: GmailMessage[]) => { ); }); }; - -const isPersonEmail = (email: string): boolean => { - const nonPersonalPattern = - /noreply|no-reply|do_not_reply|no\.reply|^(info@|contact@|hello@|support@|feedback@|service@|help@|invites@|invite@|welcome@|alerts@|team@|notifications@|notification@|news@)/; - - return !nonPersonalPattern.test(email); -}; - -const filterOutNonPersonalEmails = (messages: GmailMessage[]) => { - return messages.filter((message) => { - if (!message.participants) { - return true; - } - - return message.participants.every((participant) => - isPersonEmail(participant.handle), - ); - }); -}; diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/utils/is-sync-stale.util.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/utils/is-sync-stale.util.ts new file mode 100644 index 000000000000..7a1ae5e2029f --- /dev/null +++ b/packages/twenty-server/src/modules/messaging/message-import-manager/utils/is-sync-stale.util.ts @@ -0,0 +1,13 @@ +import { MESSAGING_IMPORT_ONGOING_SYNC_TIMEOUT } from 'src/modules/messaging/message-import-manager/constants/messaging-import-ongoing-sync-timeout.constant'; + +export const isSyncStale = (syncStageStartedAt: string): boolean => { + const syncStageStartedTime = new Date(syncStageStartedAt).getTime(); + + if (isNaN(syncStageStartedTime)) { + throw new Error('Invalid date format'); + } + + return ( + Date.now() - syncStageStartedTime > MESSAGING_IMPORT_ONGOING_SYNC_TIMEOUT + ); +}; diff --git a/packages/twenty-server/src/modules/messaging/message-participant-manager/jobs/message-participant-match-participant.job.ts b/packages/twenty-server/src/modules/messaging/message-participant-manager/jobs/message-participant-match-participant.job.ts new file mode 100644 index 000000000000..a9f486ebf1d3 --- /dev/null +++ b/packages/twenty-server/src/modules/messaging/message-participant-manager/jobs/message-participant-match-participant.job.ts @@ -0,0 +1,35 @@ +import { Scope } from '@nestjs/common'; + +import { Process } from 'src/engine/integrations/message-queue/decorators/process.decorator'; +import { Processor } from 'src/engine/integrations/message-queue/decorators/processor.decorator'; +import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; +import { MessagingMessageParticipantService } from 'src/modules/messaging/message-participant-manager/services/messaging-message-participant.service'; + +export type MessageParticipantMatchParticipantJobData = { + workspaceId: string; + email: string; + personId?: string; + workspaceMemberId?: string; +}; + +@Processor({ + queueName: MessageQueue.messagingQueue, + scope: Scope.REQUEST, +}) +export class MessageParticipantMatchParticipantJob { + constructor( + private readonly messageParticipantService: MessagingMessageParticipantService, + ) {} + + @Process(MessageParticipantMatchParticipantJob.name) + async handle(data: MessageParticipantMatchParticipantJobData): Promise<void> { + const { workspaceId, email, personId, workspaceMemberId } = data; + + await this.messageParticipantService.matchMessageParticipants( + workspaceId, + email, + personId, + workspaceMemberId, + ); + } +} diff --git a/packages/twenty-server/src/modules/messaging/message-participant-manager/jobs/message-participant-unmatch-participant.job.ts b/packages/twenty-server/src/modules/messaging/message-participant-manager/jobs/message-participant-unmatch-participant.job.ts new file mode 100644 index 000000000000..2be146301bff --- /dev/null +++ b/packages/twenty-server/src/modules/messaging/message-participant-manager/jobs/message-participant-unmatch-participant.job.ts @@ -0,0 +1,37 @@ +import { Scope } from '@nestjs/common'; + +import { Processor } from 'src/engine/integrations/message-queue/decorators/processor.decorator'; +import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; +import { MessagingMessageParticipantService } from 'src/modules/messaging/message-participant-manager/services/messaging-message-participant.service'; +import { Process } from 'src/engine/integrations/message-queue/decorators/process.decorator'; + +export type MessageParticipantUnmatchParticipantJobData = { + workspaceId: string; + email: string; + personId?: string; + workspaceMemberId?: string; +}; + +@Processor({ + queueName: MessageQueue.messagingQueue, + scope: Scope.REQUEST, +}) +export class MessageParticipantUnmatchParticipantJob { + constructor( + private readonly messageParticipantService: MessagingMessageParticipantService, + ) {} + + @Process(MessageParticipantUnmatchParticipantJob.name) + async handle( + data: MessageParticipantUnmatchParticipantJobData, + ): Promise<void> { + const { workspaceId, email, personId, workspaceMemberId } = data; + + await this.messageParticipantService.unmatchMessageParticipants( + workspaceId, + email, + personId, + workspaceMemberId, + ); + } +} diff --git a/packages/twenty-server/src/modules/messaging/message-participants-manager/jobs/messaging-create-company-and-contact-after-sync.job.ts b/packages/twenty-server/src/modules/messaging/message-participant-manager/jobs/messaging-create-company-and-contact-after-sync.job.ts similarity index 62% rename from packages/twenty-server/src/modules/messaging/message-participants-manager/jobs/messaging-create-company-and-contact-after-sync.job.ts rename to packages/twenty-server/src/modules/messaging/message-participant-manager/jobs/messaging-create-company-and-contact-after-sync.job.ts index 268fd74ccebf..c22b4b7d3d59 100644 --- a/packages/twenty-server/src/modules/messaging/message-participants-manager/jobs/messaging-create-company-and-contact-after-sync.job.ts +++ b/packages/twenty-server/src/modules/messaging/message-participant-manager/jobs/messaging-create-company-and-contact-after-sync.job.ts @@ -1,32 +1,31 @@ -import { Injectable, Logger } from '@nestjs/common'; +import { Logger } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; -import { MessageQueueJob } from 'src/engine/integrations/message-queue/interfaces/message-queue-job.interface'; - -import { - FeatureFlagEntity, - FeatureFlagKeys, -} from 'src/engine/core-modules/feature-flag/feature-flag.entity'; +import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity'; +import { Process } from 'src/engine/integrations/message-queue/decorators/process.decorator'; +import { Processor } from 'src/engine/integrations/message-queue/decorators/processor.decorator'; +import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; -import { CreateCompanyAndContactService } from 'src/modules/connected-account/auto-companies-and-contacts-creation/services/create-company-and-contact.service'; +import { ConnectedAccountRepository } from 'src/modules/connected-account/repositories/connected-account.repository'; +import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; +import { CreateCompanyAndContactService } from 'src/modules/contact-creation-manager/services/create-company-and-contact.service'; import { MessageChannelRepository } from 'src/modules/messaging/common/repositories/message-channel.repository'; import { MessageParticipantRepository } from 'src/modules/messaging/common/repositories/message-participant.repository'; -import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity'; +import { + MessageChannelContactAutoCreationPolicy, + MessageChannelWorkspaceEntity, +} from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity'; import { MessageParticipantWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-participant.workspace-entity'; -import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; -import { ConnectedAccountRepository } from 'src/modules/connected-account/repositories/connected-account.repository'; export type MessagingCreateCompanyAndContactAfterSyncJobData = { workspaceId: string; messageChannelId: string; }; -@Injectable() -export class MessagingCreateCompanyAndContactAfterSyncJob - implements MessageQueueJob<MessagingCreateCompanyAndContactAfterSyncJobData> -{ +@Processor(MessageQueue.messagingQueue) +export class MessagingCreateCompanyAndContactAfterSyncJob { private readonly logger = new Logger( MessagingCreateCompanyAndContactAfterSyncJob.name, ); @@ -42,6 +41,7 @@ export class MessagingCreateCompanyAndContactAfterSyncJob private readonly connectedAccountRepository: ConnectedAccountRepository, ) {} + @Process(MessagingCreateCompanyAndContactAfterSyncJob.name) async handle( data: MessagingCreateCompanyAndContactAfterSyncJobData, ): Promise<void> { @@ -55,10 +55,11 @@ export class MessagingCreateCompanyAndContactAfterSyncJob workspaceId, ); - const { isContactAutoCreationEnabled, connectedAccountId } = - messageChannel[0]; + const { contactAutoCreationPolicy, connectedAccountId } = messageChannel[0]; - if (!isContactAutoCreationEnabled) { + if ( + contactAutoCreationPolicy === MessageChannelContactAutoCreationPolicy.NONE + ) { return; } @@ -73,25 +74,17 @@ export class MessagingCreateCompanyAndContactAfterSyncJob ); } - const isContactCreationForSentAndReceivedEmailsEnabledFeatureFlag = - await this.featureFlagRepository.findOneBy({ - workspaceId: workspaceId, - key: FeatureFlagKeys.IsContactCreationForSentAndReceivedEmailsEnabled, - value: true, - }); - - const isContactCreationForSentAndReceivedEmailsEnabled = - isContactCreationForSentAndReceivedEmailsEnabledFeatureFlag?.value; - - const contactsToCreate = isContactCreationForSentAndReceivedEmailsEnabled - ? await this.messageParticipantRepository.getByMessageChannelIdWithoutPersonIdAndWorkspaceMemberId( - messageChannelId, - workspaceId, - ) - : await this.messageParticipantRepository.getByMessageChannelIdWithoutPersonIdAndWorkspaceMemberIdAndMessageOutgoing( - messageChannelId, - workspaceId, - ); + const contactsToCreate = + contactAutoCreationPolicy === + MessageChannelContactAutoCreationPolicy.SENT_AND_RECEIVED + ? await this.messageParticipantRepository.getByMessageChannelIdWithoutPersonIdAndWorkspaceMemberId( + messageChannelId, + workspaceId, + ) + : await this.messageParticipantRepository.getByMessageChannelIdWithoutPersonIdAndWorkspaceMemberIdAndMessageOutgoing( + messageChannelId, + workspaceId, + ); await this.createCompanyAndContactService.createCompaniesAndContactsAndUpdateParticipants( connectedAccount, diff --git a/packages/twenty-server/src/modules/calendar-messaging-participant/listeners/participant-person.listener.ts b/packages/twenty-server/src/modules/messaging/message-participant-manager/listeners/message-participant-person.listener.ts similarity index 63% rename from packages/twenty-server/src/modules/calendar-messaging-participant/listeners/participant-person.listener.ts rename to packages/twenty-server/src/modules/messaging/message-participant-manager/listeners/message-participant-person.listener.ts index 67fa7e7dfa86..521c92585054 100644 --- a/packages/twenty-server/src/modules/calendar-messaging-participant/listeners/participant-person.listener.ts +++ b/packages/twenty-server/src/modules/messaging/message-participant-manager/listeners/message-participant-person.listener.ts @@ -1,25 +1,26 @@ -import { Inject, Injectable } from '@nestjs/common'; +import { Injectable } from '@nestjs/common'; import { OnEvent } from '@nestjs/event-emitter'; import { ObjectRecordCreateEvent } from 'src/engine/integrations/event-emitter/types/object-record-create.event'; import { ObjectRecordUpdateEvent } from 'src/engine/integrations/event-emitter/types/object-record-update.event'; import { objectRecordChangedProperties as objectRecordUpdateEventChangedProperties } from 'src/engine/integrations/event-emitter/utils/object-record-changed-properties.util'; +import { InjectMessageQueue } from 'src/engine/integrations/message-queue/decorators/message-queue.decorator'; import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service'; import { - MatchParticipantJobData, - MatchParticipantJob, -} from 'src/modules/calendar-messaging-participant/jobs/match-participant.job'; + MessageParticipantMatchParticipantJobData, + MessageParticipantMatchParticipantJob, +} from 'src/modules/messaging/message-participant-manager/jobs/message-participant-match-participant.job'; import { - UnmatchParticipantJobData, - UnmatchParticipantJob, -} from 'src/modules/calendar-messaging-participant/jobs/unmatch-participant.job'; + MessageParticipantUnmatchParticipantJobData, + MessageParticipantUnmatchParticipantJob, +} from 'src/modules/messaging/message-participant-manager/jobs/message-participant-unmatch-participant.job'; import { PersonWorkspaceEntity } from 'src/modules/person/standard-objects/person.workspace-entity'; @Injectable() -export class ParticipantPersonListener { +export class MessageParticipantPersonListener { constructor( - @Inject(MessageQueue.messagingQueue) + @InjectMessageQueue(MessageQueue.messagingQueue) private readonly messageQueueService: MessageQueueService, ) {} @@ -31,8 +32,8 @@ export class ParticipantPersonListener { return; } - await this.messageQueueService.add<MatchParticipantJobData>( - MatchParticipantJob.name, + await this.messageQueueService.add<MessageParticipantMatchParticipantJobData>( + MessageParticipantMatchParticipantJob.name, { workspaceId: payload.workspaceId, email: payload.properties.after.email, @@ -51,8 +52,8 @@ export class ParticipantPersonListener { payload.properties.after, ).includes('email') ) { - await this.messageQueueService.add<UnmatchParticipantJobData>( - UnmatchParticipantJob.name, + await this.messageQueueService.add<MessageParticipantUnmatchParticipantJobData>( + MessageParticipantUnmatchParticipantJob.name, { workspaceId: payload.workspaceId, email: payload.properties.before.email, @@ -60,8 +61,8 @@ export class ParticipantPersonListener { }, ); - await this.messageQueueService.add<MatchParticipantJobData>( - MatchParticipantJob.name, + await this.messageQueueService.add<MessageParticipantMatchParticipantJobData>( + MessageParticipantMatchParticipantJob.name, { workspaceId: payload.workspaceId, email: payload.properties.after.email, diff --git a/packages/twenty-server/src/modules/calendar-messaging-participant/listeners/participant-workspace-member.listener.ts b/packages/twenty-server/src/modules/messaging/message-participant-manager/listeners/message-participant-workspace-member.listener.ts similarity index 62% rename from packages/twenty-server/src/modules/calendar-messaging-participant/listeners/participant-workspace-member.listener.ts rename to packages/twenty-server/src/modules/messaging/message-participant-manager/listeners/message-participant-workspace-member.listener.ts index 6c8de2e44652..a7dde2e18433 100644 --- a/packages/twenty-server/src/modules/calendar-messaging-participant/listeners/participant-workspace-member.listener.ts +++ b/packages/twenty-server/src/modules/messaging/message-participant-manager/listeners/message-participant-workspace-member.listener.ts @@ -1,25 +1,26 @@ -import { Inject, Injectable } from '@nestjs/common'; +import { Injectable } from '@nestjs/common'; import { OnEvent } from '@nestjs/event-emitter'; import { ObjectRecordCreateEvent } from 'src/engine/integrations/event-emitter/types/object-record-create.event'; import { ObjectRecordUpdateEvent } from 'src/engine/integrations/event-emitter/types/object-record-update.event'; import { objectRecordChangedProperties as objectRecordUpdateEventChangedProperties } from 'src/engine/integrations/event-emitter/utils/object-record-changed-properties.util'; +import { InjectMessageQueue } from 'src/engine/integrations/message-queue/decorators/message-queue.decorator'; import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service'; import { - MatchParticipantJobData, - MatchParticipantJob, -} from 'src/modules/calendar-messaging-participant/jobs/match-participant.job'; + MessageParticipantMatchParticipantJobData, + MessageParticipantMatchParticipantJob, +} from 'src/modules/messaging/message-participant-manager/jobs/message-participant-match-participant.job'; import { - UnmatchParticipantJobData, - UnmatchParticipantJob, -} from 'src/modules/calendar-messaging-participant/jobs/unmatch-participant.job'; + MessageParticipantUnmatchParticipantJobData, + MessageParticipantUnmatchParticipantJob, +} from 'src/modules/messaging/message-participant-manager/jobs/message-participant-unmatch-participant.job'; import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; @Injectable() -export class ParticipantWorkspaceMemberListener { +export class MessageParticipantWorkspaceMemberListener { constructor( - @Inject(MessageQueue.messagingQueue) + @InjectMessageQueue(MessageQueue.messagingQueue) private readonly messageQueueService: MessageQueueService, ) {} @@ -31,8 +32,8 @@ export class ParticipantWorkspaceMemberListener { return; } - await this.messageQueueService.add<MatchParticipantJobData>( - MatchParticipantJob.name, + await this.messageQueueService.add<MessageParticipantMatchParticipantJobData>( + MessageParticipantMatchParticipantJob.name, { workspaceId: payload.workspaceId, email: payload.properties.after.userEmail, @@ -46,13 +47,13 @@ export class ParticipantWorkspaceMemberListener { payload: ObjectRecordUpdateEvent<WorkspaceMemberWorkspaceEntity>, ) { if ( - objectRecordUpdateEventChangedProperties( + objectRecordUpdateEventChangedProperties<WorkspaceMemberWorkspaceEntity>( payload.properties.before, payload.properties.after, ).includes('userEmail') ) { - await this.messageQueueService.add<UnmatchParticipantJobData>( - UnmatchParticipantJob.name, + await this.messageQueueService.add<MessageParticipantUnmatchParticipantJobData>( + MessageParticipantUnmatchParticipantJob.name, { workspaceId: payload.workspaceId, email: payload.properties.before.userEmail, @@ -60,8 +61,8 @@ export class ParticipantWorkspaceMemberListener { }, ); - await this.messageQueueService.add<MatchParticipantJobData>( - MatchParticipantJob.name, + await this.messageQueueService.add<MessageParticipantMatchParticipantJobData>( + MessageParticipantMatchParticipantJob.name, { workspaceId: payload.workspaceId, email: payload.properties.after.userEmail, diff --git a/packages/twenty-server/src/modules/messaging/message-participants-manager/listeners/message-participant.listener.ts b/packages/twenty-server/src/modules/messaging/message-participant-manager/listeners/message-participant.listener.ts similarity index 91% rename from packages/twenty-server/src/modules/messaging/message-participants-manager/listeners/message-participant.listener.ts rename to packages/twenty-server/src/modules/messaging/message-participant-manager/listeners/message-participant.listener.ts index 92853ba5d345..a2fd781c1e07 100644 --- a/packages/twenty-server/src/modules/messaging/message-participants-manager/listeners/message-participant.listener.ts +++ b/packages/twenty-server/src/modules/messaging/message-participant-manager/listeners/message-participant.listener.ts @@ -9,7 +9,6 @@ import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repos import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; import { TimelineActivityRepository } from 'src/modules/timeline/repositiories/timeline-activity.repository'; import { TimelineActivityWorkspaceEntity } from 'src/modules/timeline/standard-objects/timeline-activity.workspace-entity'; -import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record'; import { MessageParticipantWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-participant.workspace-entity'; @Injectable() @@ -25,8 +24,8 @@ export class MessageParticipantListener { @OnEvent('messageParticipant.matched') public async handleMessageParticipantMatched(payload: { workspaceId: string; - userId: string; - messageParticipants: ObjectRecord<MessageParticipantWorkspaceEntity>[]; + workspaceMemberId: string; + messageParticipants: MessageParticipantWorkspaceEntity[]; }): Promise<void> { const messageParticipants = payload.messageParticipants ?? []; @@ -60,7 +59,7 @@ export class MessageParticipantListener { properties: null, objectName: 'message', recordId: participant.personId, - workspaceMemberId: payload.userId, + workspaceMemberId: payload.workspaceMemberId, workspaceId: payload.workspaceId, linkedObjectMetadataId: messageObjectMetadata.id, linkedRecordId: participant.messageId, diff --git a/packages/twenty-server/src/modules/messaging/message-participant-manager/message-participant-manager.module.ts b/packages/twenty-server/src/modules/messaging/message-participant-manager/message-participant-manager.module.ts new file mode 100644 index 000000000000..bbac91a84687 --- /dev/null +++ b/packages/twenty-server/src/modules/messaging/message-participant-manager/message-participant-manager.module.ts @@ -0,0 +1,48 @@ +import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; + +import { AnalyticsModule } from 'src/engine/core-modules/analytics/analytics.module'; +import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity'; +import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; +import { ObjectMetadataRepositoryModule } from 'src/engine/object-metadata-repository/object-metadata-repository.module'; +import { TwentyORMModule } from 'src/engine/twenty-orm/twenty-orm.module'; +import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; +import { AddPersonIdAndWorkspaceMemberIdService } from 'src/modules/calendar-messaging-participant-manager/services/add-person-id-and-workspace-member-id/add-person-id-and-workspace-member-id.service'; +import { CalendarChannelWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-channel.workspace-entity'; +import { ContactCreationManagerModule } from 'src/modules/contact-creation-manager/contact-creation-manager.module'; +import { MessagingCommonModule } from 'src/modules/messaging/common/messaging-common.module'; +import { MessageParticipantMatchParticipantJob } from 'src/modules/messaging/message-participant-manager/jobs/message-participant-match-participant.job'; +import { MessageParticipantUnmatchParticipantJob } from 'src/modules/messaging/message-participant-manager/jobs/message-participant-unmatch-participant.job'; +import { MessagingCreateCompanyAndContactAfterSyncJob } from 'src/modules/messaging/message-participant-manager/jobs/messaging-create-company-and-contact-after-sync.job'; +import { MessageParticipantPersonListener } from 'src/modules/messaging/message-participant-manager/listeners/message-participant-person.listener'; +import { MessageParticipantWorkspaceMemberListener } from 'src/modules/messaging/message-participant-manager/listeners/message-participant-workspace-member.listener'; +import { MessageParticipantListener } from 'src/modules/messaging/message-participant-manager/listeners/message-participant.listener'; +import { MessagingMessageParticipantService } from 'src/modules/messaging/message-participant-manager/services/messaging-message-participant.service'; +import { TimelineActivityWorkspaceEntity } from 'src/modules/timeline/standard-objects/timeline-activity.workspace-entity'; + +@Module({ + imports: [ + TypeOrmModule.forFeature([FeatureFlagEntity], 'core'), + AnalyticsModule, + ContactCreationManagerModule, + WorkspaceDataSourceModule, + ObjectMetadataRepositoryModule.forFeature([ + TimelineActivityWorkspaceEntity, + ]), + TypeOrmModule.forFeature([ObjectMetadataEntity], 'metadata'), + TwentyORMModule.forFeature([CalendarChannelWorkspaceEntity]), + MessagingCommonModule, + ], + providers: [ + MessagingMessageParticipantService, + MessageParticipantMatchParticipantJob, + MessageParticipantUnmatchParticipantJob, + MessagingCreateCompanyAndContactAfterSyncJob, + MessageParticipantListener, + MessageParticipantPersonListener, + MessageParticipantWorkspaceMemberListener, + AddPersonIdAndWorkspaceMemberIdService, + ], + exports: [MessagingMessageParticipantService], +}) +export class MessageParticipantManagerModule {} diff --git a/packages/twenty-server/src/modules/messaging/common/services/messaging-message-participant.service.ts b/packages/twenty-server/src/modules/messaging/message-participant-manager/services/messaging-message-participant.service.ts similarity index 89% rename from packages/twenty-server/src/modules/messaging/common/services/messaging-message-participant.service.ts rename to packages/twenty-server/src/modules/messaging/message-participant-manager/services/messaging-message-participant.service.ts index 78a5623bbaac..24eaec161986 100644 --- a/packages/twenty-server/src/modules/messaging/common/services/messaging-message-participant.service.ts +++ b/packages/twenty-server/src/modules/messaging/message-participant-manager/services/messaging-message-participant.service.ts @@ -7,15 +7,12 @@ import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repos import { PersonRepository } from 'src/modules/person/repositories/person.repository'; import { PersonWorkspaceEntity } from 'src/modules/person/standard-objects/person.workspace-entity'; import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; -import { getFlattenedValuesAndValuesStringForBatchRawQuery } from 'src/modules/calendar/utils/get-flattened-values-and-values-string-for-batch-raw-query.util'; -import { AddPersonIdAndWorkspaceMemberIdService } from 'src/modules/calendar-messaging-participant/services/add-person-id-and-workspace-member-id/add-person-id-and-workspace-member-id.service'; -import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record'; +import { getFlattenedValuesAndValuesStringForBatchRawQuery } from 'src/modules/calendar/calendar-event-import-manager/utils/get-flattened-values-and-values-string-for-batch-raw-query.util'; +import { AddPersonIdAndWorkspaceMemberIdService } from 'src/modules/calendar-messaging-participant-manager/services/add-person-id-and-workspace-member-id/add-person-id-and-workspace-member-id.service'; import { MessageParticipantRepository } from 'src/modules/messaging/common/repositories/message-participant.repository'; import { MessageParticipantWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-participant.workspace-entity'; import { ParticipantWithMessageId } from 'src/modules/messaging/message-import-manager/drivers/gmail/types/gmail-message'; -// Todo: this is not the right place for this file. The code needs to be refactored in term of business modules with a precise scope. -// Putting it here to avoid circular dependencies for now. @Injectable() export class MessagingMessageParticipantService { constructor( @@ -29,10 +26,10 @@ export class MessagingMessageParticipantService { ) {} public async updateMessageParticipantsAfterPeopleCreation( - createdPeople: ObjectRecord<PersonWorkspaceEntity>[], + createdPeople: PersonWorkspaceEntity[], workspaceId: string, transactionManager?: EntityManager, - ): Promise<ObjectRecord<MessageParticipantWorkspaceEntity>[]> { + ): Promise<MessageParticipantWorkspaceEntity[]> { const participants = await this.messageParticipantRepository.getByHandles( createdPeople.map((person) => person.email), workspaceId, @@ -87,7 +84,7 @@ export class MessagingMessageParticipantService { participants: ParticipantWithMessageId[], workspaceId: string, transactionManager?: EntityManager, - ): Promise<ObjectRecord<MessageParticipantWorkspaceEntity>[]> { + ): Promise<MessageParticipantWorkspaceEntity[]> { if (!participants) return []; const dataSourceSchema = @@ -149,7 +146,7 @@ export class MessagingMessageParticipantService { this.eventEmitter.emit(`messageParticipant.matched`, { workspaceId, - userId: null, + workspaceMemberId: null, messageParticipants: updatedMessageParticipants, }); } diff --git a/packages/twenty-server/src/modules/messaging/message-participants-manager/messaging-participants-manager.module.ts b/packages/twenty-server/src/modules/messaging/message-participants-manager/messaging-participants-manager.module.ts deleted file mode 100644 index 589d3eb47794..000000000000 --- a/packages/twenty-server/src/modules/messaging/message-participants-manager/messaging-participants-manager.module.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { Module } from '@nestjs/common'; -import { TypeOrmModule } from '@nestjs/typeorm'; - -import { AnalyticsModule } from 'src/engine/core-modules/analytics/analytics.module'; -import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity'; -import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; -import { ObjectMetadataRepositoryModule } from 'src/engine/object-metadata-repository/object-metadata-repository.module'; -import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; -import { AutoCompaniesAndContactsCreationModule } from 'src/modules/connected-account/auto-companies-and-contacts-creation/auto-companies-and-contacts-creation.module'; -import { MessagingGmailDriverModule } from 'src/modules/messaging/message-import-manager/drivers/gmail/messaging-gmail-driver.module'; -import { MessagingCreateCompanyAndContactAfterSyncJob } from 'src/modules/messaging/message-participants-manager/jobs/messaging-create-company-and-contact-after-sync.job'; -import { MessageParticipantListener } from 'src/modules/messaging/message-participants-manager/listeners/message-participant.listener'; -import { TimelineActivityWorkspaceEntity } from 'src/modules/timeline/standard-objects/timeline-activity.workspace-entity'; - -@Module({ - imports: [ - TypeOrmModule.forFeature([FeatureFlagEntity], 'core'), - AnalyticsModule, - MessagingGmailDriverModule, - AutoCompaniesAndContactsCreationModule, - WorkspaceDataSourceModule, - ObjectMetadataRepositoryModule.forFeature([ - TimelineActivityWorkspaceEntity, - ]), - TypeOrmModule.forFeature([ObjectMetadataEntity], 'metadata'), - ], - providers: [ - { - provide: MessagingCreateCompanyAndContactAfterSyncJob.name, - useClass: MessagingCreateCompanyAndContactAfterSyncJob, - }, - MessageParticipantListener, - ], -}) -export class MessaginParticipantsManagerModule {} diff --git a/packages/twenty-server/src/modules/messaging/messaging.module.ts b/packages/twenty-server/src/modules/messaging/messaging.module.ts index 0797e3853b64..24376567ca96 100644 --- a/packages/twenty-server/src/modules/messaging/messaging.module.ts +++ b/packages/twenty-server/src/modules/messaging/messaging.module.ts @@ -3,14 +3,16 @@ import { Module } from '@nestjs/common'; import { MessagingBlocklistManagerModule } from 'src/modules/messaging/blocklist-manager/messaging-blocklist-manager.module'; import { MessagingMessageCleanerModule } from 'src/modules/messaging/message-cleaner/messaging-message-cleaner.module'; import { MessagingImportManagerModule } from 'src/modules/messaging/message-import-manager/messaging-import-manager.module'; -import { MessaginParticipantsManagerModule } from 'src/modules/messaging/message-participants-manager/messaging-participants-manager.module'; +import { MessageParticipantManagerModule } from 'src/modules/messaging/message-participant-manager/message-participant-manager.module'; +import { MessagingMonitoringModule } from 'src/modules/messaging/monitoring/messaging-monitoring.module'; @Module({ imports: [ MessagingImportManagerModule, MessagingMessageCleanerModule, - MessaginParticipantsManagerModule, + MessageParticipantManagerModule, MessagingBlocklistManagerModule, + MessagingMonitoringModule, ], providers: [], exports: [], diff --git a/packages/twenty-server/src/modules/messaging/monitoring/crons/commands/messaging-message-channel-sync-status-monitoring.cron.command.ts b/packages/twenty-server/src/modules/messaging/monitoring/crons/commands/messaging-message-channel-sync-status-monitoring.cron.command.ts new file mode 100644 index 000000000000..d90fd0b5be45 --- /dev/null +++ b/packages/twenty-server/src/modules/messaging/monitoring/crons/commands/messaging-message-channel-sync-status-monitoring.cron.command.ts @@ -0,0 +1,36 @@ +import { Command, CommandRunner } from 'nest-commander'; + +import { InjectMessageQueue } from 'src/engine/integrations/message-queue/decorators/message-queue.decorator'; +import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; +import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service'; +import { MessagingMessageChannelSyncStatusMonitoringCronJob } from 'src/modules/messaging/monitoring/crons/jobs/messaging-message-channel-sync-status-monitoring.cron'; + +const MESSAGING_MESSAGE_CHANNEL_SYNC_STATUS_MONITORING_CRON_PATTERN = + '2/10 * * * *'; //Every 10 minutes, starting at 2 minutes past the hour + +@Command({ + name: 'cron:messaging:monitoring:message-channel-sync-status', + description: + 'Starts a cron job to monitor the sync status of message channels', +}) +export class MessagingMessageChannelSyncStatusMonitoringCronCommand extends CommandRunner { + constructor( + @InjectMessageQueue(MessageQueue.cronQueue) + private readonly messageQueueService: MessageQueueService, + ) { + super(); + } + + async run(): Promise<void> { + await this.messageQueueService.addCron<undefined>( + MessagingMessageChannelSyncStatusMonitoringCronJob.name, + undefined, + { + repeat: { + pattern: + MESSAGING_MESSAGE_CHANNEL_SYNC_STATUS_MONITORING_CRON_PATTERN, + }, + }, + ); + } +} diff --git a/packages/twenty-server/src/modules/messaging/monitoring/crons/jobs/messaging-message-channel-sync-status-monitoring.cron.ts b/packages/twenty-server/src/modules/messaging/monitoring/crons/jobs/messaging-message-channel-sync-status-monitoring.cron.ts new file mode 100644 index 000000000000..a0384d52829c --- /dev/null +++ b/packages/twenty-server/src/modules/messaging/monitoring/crons/jobs/messaging-message-channel-sync-status-monitoring.cron.ts @@ -0,0 +1,77 @@ +import { Logger } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; + +import { Repository, In } from 'typeorm'; +import snakeCase from 'lodash.snakecase'; + +import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; +import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity'; +import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; +import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; +import { MessageChannelRepository } from 'src/modules/messaging/common/repositories/message-channel.repository'; +import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity'; +import { Processor } from 'src/engine/integrations/message-queue/decorators/processor.decorator'; +import { Process } from 'src/engine/integrations/message-queue/decorators/process.decorator'; +import { MessagingTelemetryService } from 'src/modules/messaging/common/services/messaging-telemetry.service'; +import { BillingService } from 'src/engine/core-modules/billing/billing.service'; + +@Processor(MessageQueue.cronQueue) +export class MessagingMessageChannelSyncStatusMonitoringCronJob { + private readonly logger = new Logger( + MessagingMessageChannelSyncStatusMonitoringCronJob.name, + ); + + constructor( + @InjectRepository(Workspace, 'core') + private readonly workspaceRepository: Repository<Workspace>, + @InjectRepository(DataSourceEntity, 'metadata') + private readonly dataSourceRepository: Repository<DataSourceEntity>, + @InjectObjectMetadataRepository(MessageChannelWorkspaceEntity) + private readonly messageChannelRepository: MessageChannelRepository, + private readonly billingService: BillingService, + private readonly messagingTelemetryService: MessagingTelemetryService, + ) {} + + @Process(MessagingMessageChannelSyncStatusMonitoringCronJob.name) + async handle(): Promise<void> { + this.logger.log('Starting message channel sync status monitoring...'); + + await this.messagingTelemetryService.track({ + eventName: 'message_channel.monitoring.sync_status.start', + message: 'Starting message channel sync status monitoring', + }); + + const workspaceIds = + await this.billingService.getActiveSubscriptionWorkspaceIds(); + + const dataSources = await this.dataSourceRepository.find({ + where: { + workspaceId: In(workspaceIds), + }, + }); + + const workspaceIdsWithDataSources = new Set( + dataSources.map((dataSource) => dataSource.workspaceId), + ); + + for (const workspaceId of workspaceIdsWithDataSources) { + const messageChannels = + await this.messageChannelRepository.getAll(workspaceId); + + for (const messageChannel of messageChannels) { + if (!messageChannel.syncStatus) { + continue; + } + await this.messagingTelemetryService.track({ + eventName: `message_channel.monitoring.sync_status.${snakeCase( + messageChannel.syncStatus, + )}`, + workspaceId, + connectedAccountId: messageChannel.connectedAccountId, + messageChannelId: messageChannel.id, + message: messageChannel.syncStatus, + }); + } + } + } +} diff --git a/packages/twenty-server/src/modules/messaging/monitoring/messaging-monitoring.module.ts b/packages/twenty-server/src/modules/messaging/monitoring/messaging-monitoring.module.ts new file mode 100644 index 000000000000..d41ed75e413e --- /dev/null +++ b/packages/twenty-server/src/modules/messaging/monitoring/messaging-monitoring.module.ts @@ -0,0 +1,24 @@ +import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; + +import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; +import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity'; +import { MessagingCommonModule } from 'src/modules/messaging/common/messaging-common.module'; +import { MessagingMessageChannelSyncStatusMonitoringCronCommand } from 'src/modules/messaging/monitoring/crons/commands/messaging-message-channel-sync-status-monitoring.cron.command'; +import { MessagingMessageChannelSyncStatusMonitoringCronJob } from 'src/modules/messaging/monitoring/crons/jobs/messaging-message-channel-sync-status-monitoring.cron'; +import { BillingModule } from 'src/engine/core-modules/billing/billing.module'; + +@Module({ + imports: [ + MessagingCommonModule, + BillingModule, + TypeOrmModule.forFeature([Workspace], 'core'), + TypeOrmModule.forFeature([DataSourceEntity], 'metadata'), + ], + providers: [ + MessagingMessageChannelSyncStatusMonitoringCronCommand, + MessagingMessageChannelSyncStatusMonitoringCronJob, + ], + exports: [], +}) +export class MessagingMonitoringModule {} diff --git a/packages/twenty-server/src/modules/opportunity/standard-objects/opportunity.workspace-entity.ts b/packages/twenty-server/src/modules/opportunity/standard-objects/opportunity.workspace-entity.ts index 5ec506eb57c9..670ef37a069d 100644 --- a/packages/twenty-server/src/modules/opportunity/standard-objects/opportunity.workspace-entity.ts +++ b/packages/twenty-server/src/modules/opportunity/standard-objects/opportunity.workspace-entity.ts @@ -6,6 +6,15 @@ import { RelationMetadataType, RelationOnDeleteAction, } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity'; +import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity'; +import { WorkspaceEntity } from 'src/engine/twenty-orm/decorators/workspace-entity.decorator'; +import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field.decorator'; +import { WorkspaceIsDeprecated } from 'src/engine/twenty-orm/decorators/workspace-is-deprecated.decorator'; +import { WorkspaceIsNotAuditLogged } from 'src/engine/twenty-orm/decorators/workspace-is-not-audit-logged.decorator'; +import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator'; +import { WorkspaceIsSystem } from 'src/engine/twenty-orm/decorators/workspace-is-system.decorator'; +import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator'; +import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator'; import { OPPORTUNITY_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids'; import { STANDARD_OBJECT_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-object-ids'; import { ActivityTargetWorkspaceEntity } from 'src/modules/activity/standard-objects/activity-target.workspace-entity'; @@ -14,13 +23,6 @@ import { CompanyWorkspaceEntity } from 'src/modules/company/standard-objects/com import { FavoriteWorkspaceEntity } from 'src/modules/favorite/standard-objects/favorite.workspace-entity'; import { PersonWorkspaceEntity } from 'src/modules/person/standard-objects/person.workspace-entity'; import { TimelineActivityWorkspaceEntity } from 'src/modules/timeline/standard-objects/timeline-activity.workspace-entity'; -import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity'; -import { WorkspaceEntity } from 'src/engine/twenty-orm/decorators/workspace-entity.decorator'; -import { WorkspaceIsNotAuditLogged } from 'src/engine/twenty-orm/decorators/workspace-is-not-audit-logged.decorator'; -import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field.decorator'; -import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator'; -import { WorkspaceIsSystem } from 'src/engine/twenty-orm/decorators/workspace-is-system.decorator'; -import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator'; @WorkspaceEntity({ standardId: STANDARD_OBJECT_IDS.opportunity, @@ -49,7 +51,7 @@ export class OpportunityWorkspaceEntity extends BaseWorkspaceEntity { icon: 'IconCurrencyDollar', }) @WorkspaceIsNullable() - amount: CurrencyMetadata; + amount: CurrencyMetadata | null; @WorkspaceField({ standardId: OPPORTUNITY_STANDARD_FIELD_IDS.closeDate, @@ -59,17 +61,7 @@ export class OpportunityWorkspaceEntity extends BaseWorkspaceEntity { icon: 'IconCalendarEvent', }) @WorkspaceIsNullable() - closeDate: Date; - - @WorkspaceField({ - standardId: OPPORTUNITY_STANDARD_FIELD_IDS.probability, - type: FieldMetadataType.TEXT, - label: 'Probability', - description: 'Opportunity probability', - icon: 'IconProgressCheck', - defaultValue: "'0'", - }) - probability: string; + closeDate: Date | null; @WorkspaceField({ standardId: OPPORTUNITY_STANDARD_FIELD_IDS.stage, @@ -102,7 +94,7 @@ export class OpportunityWorkspaceEntity extends BaseWorkspaceEntity { }) @WorkspaceIsSystem() @WorkspaceIsNullable() - position: number; + position: number | null; @WorkspaceRelation({ standardId: OPPORTUNITY_STANDARD_FIELD_IDS.pointOfContact, @@ -110,13 +102,15 @@ export class OpportunityWorkspaceEntity extends BaseWorkspaceEntity { label: 'Point of Contact', description: 'Opportunity point of contact', icon: 'IconUser', - joinColumn: 'pointOfContactId', inverseSideTarget: () => PersonWorkspaceEntity, inverseSideFieldKey: 'pointOfContactForOpportunities', onDelete: RelationOnDeleteAction.SET_NULL, }) @WorkspaceIsNullable() - pointOfContact: Relation<PersonWorkspaceEntity>; + pointOfContact: Relation<PersonWorkspaceEntity> | null; + + @WorkspaceJoinColumn('pointOfContact') + pointOfContactId: string | null; @WorkspaceRelation({ standardId: OPPORTUNITY_STANDARD_FIELD_IDS.company, @@ -124,13 +118,15 @@ export class OpportunityWorkspaceEntity extends BaseWorkspaceEntity { label: 'Company', description: 'Opportunity company', icon: 'IconBuildingSkyscraper', - joinColumn: 'companyId', inverseSideTarget: () => CompanyWorkspaceEntity, inverseSideFieldKey: 'opportunities', onDelete: RelationOnDeleteAction.SET_NULL, }) @WorkspaceIsNullable() - company: Relation<CompanyWorkspaceEntity>; + company: Relation<CompanyWorkspaceEntity> | null; + + @WorkspaceJoinColumn('company') + companyId: string | null; @WorkspaceRelation({ standardId: OPPORTUNITY_STANDARD_FIELD_IDS.favorites, @@ -180,4 +176,15 @@ export class OpportunityWorkspaceEntity extends BaseWorkspaceEntity { }) @WorkspaceIsNullable() timelineActivities: Relation<TimelineActivityWorkspaceEntity[]>; + + @WorkspaceField({ + standardId: OPPORTUNITY_STANDARD_FIELD_IDS.probabilityDeprecated, + type: FieldMetadataType.TEXT, + label: 'Probability', + description: 'Opportunity probability', + icon: 'IconProgressCheck', + defaultValue: "'0'", + }) + @WorkspaceIsDeprecated() + probability: string; } diff --git a/packages/twenty-server/src/modules/person/repositories/person.repository.ts b/packages/twenty-server/src/modules/person/repositories/person.repository.ts index 57e1464fc955..adb40f1cbdb3 100644 --- a/packages/twenty-server/src/modules/person/repositories/person.repository.ts +++ b/packages/twenty-server/src/modules/person/repositories/person.repository.ts @@ -3,9 +3,8 @@ import { Injectable } from '@nestjs/common'; import { EntityManager } from 'typeorm'; import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; -import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record'; import { PersonWorkspaceEntity } from 'src/modules/person/standard-objects/person.workspace-entity'; -import { getFlattenedValuesAndValuesStringForBatchRawQuery } from 'src/modules/calendar/utils/get-flattened-values-and-values-string-for-batch-raw-query.util'; +import { getFlattenedValuesAndValuesStringForBatchRawQuery } from 'src/modules/calendar/calendar-event-import-manager/utils/get-flattened-values-and-values-string-for-batch-raw-query.util'; @Injectable() export class PersonRepository { @@ -17,7 +16,7 @@ export class PersonRepository { emails: string[], workspaceId: string, transactionManager?: EntityManager, - ): Promise<ObjectRecord<PersonWorkspaceEntity>[]> { + ): Promise<PersonWorkspaceEntity[]> { const dataSourceSchema = this.workspaceDataSourceService.getSchemaName(workspaceId); @@ -56,7 +55,7 @@ export class PersonRepository { }[], workspaceId: string, transactionManager?: EntityManager, - ): Promise<ObjectRecord<PersonWorkspaceEntity>[]> { + ): Promise<PersonWorkspaceEntity[]> { const dataSourceSchema = this.workspaceDataSourceService.getSchemaName(workspaceId); diff --git a/packages/twenty-server/src/modules/person/standard-objects/person.workspace-entity.ts b/packages/twenty-server/src/modules/person/standard-objects/person.workspace-entity.ts index 83353993dfb1..0d1704aed68f 100644 --- a/packages/twenty-server/src/modules/person/standard-objects/person.workspace-entity.ts +++ b/packages/twenty-server/src/modules/person/standard-objects/person.workspace-entity.ts @@ -11,7 +11,6 @@ import { PERSON_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspac import { STANDARD_OBJECT_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-object-ids'; import { ActivityTargetWorkspaceEntity } from 'src/modules/activity/standard-objects/activity-target.workspace-entity'; import { AttachmentWorkspaceEntity } from 'src/modules/attachment/standard-objects/attachment.workspace-entity'; -import { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-event-participant.workspace-entity'; import { CompanyWorkspaceEntity } from 'src/modules/company/standard-objects/company.workspace-entity'; import { FavoriteWorkspaceEntity } from 'src/modules/favorite/standard-objects/favorite.workspace-entity'; import { OpportunityWorkspaceEntity } from 'src/modules/opportunity/standard-objects/opportunity.workspace-entity'; @@ -23,6 +22,8 @@ import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace- import { WorkspaceIsSystem } from 'src/engine/twenty-orm/decorators/workspace-is-system.decorator'; import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator'; import { MessageParticipantWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-participant.workspace-entity'; +import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator'; +import { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-event-participant.workspace-entity'; @WorkspaceEntity({ standardId: STANDARD_OBJECT_IDS.person, @@ -41,7 +42,7 @@ export class PersonWorkspaceEntity extends BaseWorkspaceEntity { icon: 'IconUser', }) @WorkspaceIsNullable() - name: FullNameMetadata; + name: FullNameMetadata | null; @WorkspaceField({ standardId: PERSON_STANDARD_FIELD_IDS.email, @@ -60,7 +61,7 @@ export class PersonWorkspaceEntity extends BaseWorkspaceEntity { icon: 'IconBrandLinkedin', }) @WorkspaceIsNullable() - linkedinLink: LinkMetadata; + linkedinLink: LinkMetadata | null; @WorkspaceField({ standardId: PERSON_STANDARD_FIELD_IDS.xLink, @@ -70,7 +71,7 @@ export class PersonWorkspaceEntity extends BaseWorkspaceEntity { icon: 'IconBrandX', }) @WorkspaceIsNullable() - xLink: LinkMetadata; + xLink: LinkMetadata | null; @WorkspaceField({ standardId: PERSON_STANDARD_FIELD_IDS.jobTitle, @@ -118,7 +119,7 @@ export class PersonWorkspaceEntity extends BaseWorkspaceEntity { }) @WorkspaceIsSystem() @WorkspaceIsNullable() - position: number; + position: number | null; // Relations @WorkspaceRelation({ @@ -127,12 +128,14 @@ export class PersonWorkspaceEntity extends BaseWorkspaceEntity { label: 'Company', description: 'Contact’s company', icon: 'IconBuildingSkyscraper', - joinColumn: 'companyId', inverseSideTarget: () => CompanyWorkspaceEntity, inverseSideFieldKey: 'people', }) @WorkspaceIsNullable() - company: Relation<CompanyWorkspaceEntity>; + company: Relation<CompanyWorkspaceEntity> | null; + + @WorkspaceJoinColumn('company') + companyId: string | null; @WorkspaceRelation({ standardId: PERSON_STANDARD_FIELD_IDS.pointOfContactForOpportunities, diff --git a/packages/twenty-server/src/modules/timeline/jobs/create-audit-log-from-internal-event.ts b/packages/twenty-server/src/modules/timeline/jobs/create-audit-log-from-internal-event.ts index 32d8b7637005..edf4c3d9e488 100644 --- a/packages/twenty-server/src/modules/timeline/jobs/create-audit-log-from-internal-event.ts +++ b/packages/twenty-server/src/modules/timeline/jobs/create-audit-log-from-internal-event.ts @@ -1,18 +1,15 @@ -import { Injectable } from '@nestjs/common'; - -import { MessageQueueJob } from 'src/engine/integrations/message-queue/interfaces/message-queue-job.interface'; - import { ObjectRecordBaseEvent } from 'src/engine/integrations/event-emitter/types/object-record.base.event'; import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; import { AuditLogRepository } from 'src/modules/timeline/repositiories/audit-log.repository'; import { AuditLogWorkspaceEntity } from 'src/modules/timeline/standard-objects/audit-log.workspace-entity'; import { WorkspaceMemberRepository } from 'src/modules/workspace-member/repositories/workspace-member.repository'; import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; +import { Processor } from 'src/engine/integrations/message-queue/decorators/processor.decorator'; +import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; +import { Process } from 'src/engine/integrations/message-queue/decorators/process.decorator'; -@Injectable() -export class CreateAuditLogFromInternalEvent - implements MessageQueueJob<ObjectRecordBaseEvent> -{ +@Processor(MessageQueue.entityEventsToDbQueue) +export class CreateAuditLogFromInternalEvent { constructor( @InjectObjectMetadataRepository(WorkspaceMemberWorkspaceEntity) private readonly workspaceMemberService: WorkspaceMemberRepository, @@ -20,6 +17,7 @@ export class CreateAuditLogFromInternalEvent private readonly auditLogRepository: AuditLogRepository, ) {} + @Process(CreateAuditLogFromInternalEvent.name) async handle(data: ObjectRecordBaseEvent): Promise<void> { let workspaceMemberId: string | null = null; diff --git a/packages/twenty-server/src/modules/timeline/jobs/timeline-job.module.ts b/packages/twenty-server/src/modules/timeline/jobs/timeline-job.module.ts index 3fd03709ce2b..416e81aed53f 100644 --- a/packages/twenty-server/src/modules/timeline/jobs/timeline-job.module.ts +++ b/packages/twenty-server/src/modules/timeline/jobs/timeline-job.module.ts @@ -16,14 +16,8 @@ import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/sta TimelineActivityModule, ], providers: [ - { - provide: CreateAuditLogFromInternalEvent.name, - useClass: CreateAuditLogFromInternalEvent, - }, - { - provide: UpsertTimelineActivityFromInternalEvent.name, - useClass: UpsertTimelineActivityFromInternalEvent, - }, + CreateAuditLogFromInternalEvent, + UpsertTimelineActivityFromInternalEvent, ], }) export class TimelineJobModule {} diff --git a/packages/twenty-server/src/modules/timeline/jobs/upsert-timeline-activity-from-internal-event.job.ts b/packages/twenty-server/src/modules/timeline/jobs/upsert-timeline-activity-from-internal-event.job.ts index 2f8490764963..5abcb2e10da6 100644 --- a/packages/twenty-server/src/modules/timeline/jobs/upsert-timeline-activity-from-internal-event.job.ts +++ b/packages/twenty-server/src/modules/timeline/jobs/upsert-timeline-activity-from-internal-event.job.ts @@ -1,23 +1,21 @@ -import { Injectable } from '@nestjs/common'; - -import { MessageQueueJob } from 'src/engine/integrations/message-queue/interfaces/message-queue-job.interface'; - import { ObjectRecordBaseEvent } from 'src/engine/integrations/event-emitter/types/object-record.base.event'; import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; import { WorkspaceMemberRepository } from 'src/modules/workspace-member/repositories/workspace-member.repository'; import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; import { TimelineActivityService } from 'src/modules/timeline/services/timeline-activity.service'; +import { Processor } from 'src/engine/integrations/message-queue/decorators/processor.decorator'; +import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; +import { Process } from 'src/engine/integrations/message-queue/decorators/process.decorator'; -@Injectable() -export class UpsertTimelineActivityFromInternalEvent - implements MessageQueueJob<ObjectRecordBaseEvent> -{ +@Processor(MessageQueue.entityEventsToDbQueue) +export class UpsertTimelineActivityFromInternalEvent { constructor( @InjectObjectMetadataRepository(WorkspaceMemberWorkspaceEntity) private readonly workspaceMemberService: WorkspaceMemberRepository, private readonly timelineActivityService: TimelineActivityService, ) {} + @Process(UpsertTimelineActivityFromInternalEvent.name) async handle(data: ObjectRecordBaseEvent): Promise<void> { if (data.userId) { const workspaceMember = await this.workspaceMemberService.getByIdOrFail( diff --git a/packages/twenty-server/src/modules/timeline/repositiories/timeline-activity.repository.ts b/packages/twenty-server/src/modules/timeline/repositiories/timeline-activity.repository.ts index 8d9a99c7d98e..1ab962ea9cf1 100644 --- a/packages/twenty-server/src/modules/timeline/repositiories/timeline-activity.repository.ts +++ b/packages/twenty-server/src/modules/timeline/repositiories/timeline-activity.repository.ts @@ -2,6 +2,8 @@ import { Injectable } from '@nestjs/common'; import { EntityManager } from 'typeorm'; +import { Record } from 'src/engine/api/graphql/workspace-query-builder/interfaces/record.interface'; + import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; import { objectRecordDiffMerge } from 'src/engine/integrations/event-emitter/utils/object-record-diff-merge'; @@ -13,7 +15,7 @@ export class TimelineActivityRepository { async upsertOne( name: string, - properties: Record<string, any>, + properties: Partial<Record>, objectName: string, recordId: string, workspaceId: string, @@ -103,7 +105,7 @@ export class TimelineActivityRepository { private async updateTimelineActivity( dataSourceSchema: string, id: string, - properties: Record<string, any>, + properties: Partial<Record>, workspaceMemberId: string | undefined, workspaceId: string, ) { @@ -119,7 +121,7 @@ export class TimelineActivityRepository { private async insertTimelineActivity( dataSourceSchema: string, name: string, - properties: Record<string, any>, + properties: Partial<Record>, objectName: string, recordId: string, workspaceMemberId: string | undefined, @@ -149,11 +151,11 @@ export class TimelineActivityRepository { objectName: string, activities: { name: string; - properties: Record<string, any> | null; + properties: Partial<Record> | null; workspaceMemberId: string | undefined; - recordId: string; + recordId: string | null; linkedRecordCachedName: string; - linkedRecordId: string | undefined; + linkedRecordId: string | null | undefined; linkedObjectMetadataId: string | undefined; }[], workspaceId: string, diff --git a/packages/twenty-server/src/modules/timeline/standard-objects/audit-log.workspace-entity.ts b/packages/twenty-server/src/modules/timeline/standard-objects/audit-log.workspace-entity.ts index d7b42a75b089..e6cdc4a77f87 100644 --- a/packages/twenty-server/src/modules/timeline/standard-objects/audit-log.workspace-entity.ts +++ b/packages/twenty-server/src/modules/timeline/standard-objects/audit-log.workspace-entity.ts @@ -1,16 +1,17 @@ import { Relation } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/relation.interface'; import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; -import { AUDIT_LOGS_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids'; -import { STANDARD_OBJECT_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-object-ids'; -import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; +import { RelationMetadataType } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity'; import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity'; import { WorkspaceEntity } from 'src/engine/twenty-orm/decorators/workspace-entity.decorator'; -import { WorkspaceIsSystem } from 'src/engine/twenty-orm/decorators/workspace-is-system.decorator'; import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field.decorator'; import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator'; +import { WorkspaceIsSystem } from 'src/engine/twenty-orm/decorators/workspace-is-system.decorator'; +import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator'; import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator'; -import { RelationMetadataType } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity'; +import { AUDIT_LOGS_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids'; +import { STANDARD_OBJECT_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-object-ids'; +import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; @WorkspaceEntity({ standardId: STANDARD_OBJECT_IDS.auditLog, @@ -39,7 +40,7 @@ export class AuditLogWorkspaceEntity extends BaseWorkspaceEntity { icon: 'IconListDetails', }) @WorkspaceIsNullable() - properties: JSON; + properties: JSON | null; @WorkspaceField({ standardId: AUDIT_LOGS_STANDARD_FIELD_IDS.context, @@ -50,22 +51,22 @@ export class AuditLogWorkspaceEntity extends BaseWorkspaceEntity { icon: 'IconListDetails', }) @WorkspaceIsNullable() - context: JSON; + context: JSON | null; @WorkspaceField({ standardId: AUDIT_LOGS_STANDARD_FIELD_IDS.objectName, type: FieldMetadataType.TEXT, label: 'Object name', - description: 'If the event is related to a particular object', + description: 'Object name', icon: 'IconAbc', }) objectName: string; @WorkspaceField({ - standardId: AUDIT_LOGS_STANDARD_FIELD_IDS.objectName, + standardId: AUDIT_LOGS_STANDARD_FIELD_IDS.objectMetadataId, type: FieldMetadataType.TEXT, - label: 'Object name', - description: 'If the event is related to a particular object', + label: 'Object metadata id', + description: 'Object metadata id', icon: 'IconAbc', }) objectMetadataId: string; @@ -73,12 +74,12 @@ export class AuditLogWorkspaceEntity extends BaseWorkspaceEntity { @WorkspaceField({ standardId: AUDIT_LOGS_STANDARD_FIELD_IDS.recordId, type: FieldMetadataType.UUID, - label: 'Object id', - description: 'Event name/type', + label: 'Record id', + description: 'Record id', icon: 'IconAbc', }) @WorkspaceIsNullable() - recordId: string; + recordId: string | null; @WorkspaceRelation({ standardId: AUDIT_LOGS_STANDARD_FIELD_IDS.workspaceMember, @@ -86,10 +87,12 @@ export class AuditLogWorkspaceEntity extends BaseWorkspaceEntity { label: 'Workspace Member', description: 'Event workspace member', icon: 'IconCircleUser', - joinColumn: 'workspaceMemberId', inverseSideTarget: () => WorkspaceMemberWorkspaceEntity, inverseSideFieldKey: 'auditLogs', }) @WorkspaceIsNullable() - workspaceMember: Relation<WorkspaceMemberWorkspaceEntity>; + workspaceMember: Relation<WorkspaceMemberWorkspaceEntity> | null; + + @WorkspaceJoinColumn('workspaceMember') + workspaceMemberId: string | null; } diff --git a/packages/twenty-server/src/modules/timeline/standard-objects/behavioral-event.workspace-entity.ts b/packages/twenty-server/src/modules/timeline/standard-objects/behavioral-event.workspace-entity.ts index 3460768e4f81..a74069685bbc 100644 --- a/packages/twenty-server/src/modules/timeline/standard-objects/behavioral-event.workspace-entity.ts +++ b/packages/twenty-server/src/modules/timeline/standard-objects/behavioral-event.workspace-entity.ts @@ -56,7 +56,7 @@ export class BehavioralEventWorkspaceEntity extends BaseWorkspaceEntity { icon: 'IconListDetails', }) @WorkspaceIsNullable() - properties: JSON; + properties: JSON | null; @WorkspaceField({ standardId: BEHAVIORAL_EVENT_STANDARD_FIELD_IDS.context, @@ -67,7 +67,7 @@ export class BehavioralEventWorkspaceEntity extends BaseWorkspaceEntity { icon: 'IconListDetails', }) @WorkspaceIsNullable() - context: JSON; + context: JSON | null; @WorkspaceField({ standardId: BEHAVIORAL_EVENT_STANDARD_FIELD_IDS.objectName, @@ -86,5 +86,5 @@ export class BehavioralEventWorkspaceEntity extends BaseWorkspaceEntity { icon: 'IconAbc', }) @WorkspaceIsNullable() - recordId: string; + recordId: string | null; } diff --git a/packages/twenty-server/src/modules/timeline/standard-objects/timeline-activity.workspace-entity.ts b/packages/twenty-server/src/modules/timeline/standard-objects/timeline-activity.workspace-entity.ts index 40cd49307684..c104b5df8931 100644 --- a/packages/twenty-server/src/modules/timeline/standard-objects/timeline-activity.workspace-entity.ts +++ b/packages/twenty-server/src/modules/timeline/standard-objects/timeline-activity.workspace-entity.ts @@ -17,6 +17,7 @@ import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace- import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator'; import { RelationMetadataType } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity'; import { WorkspaceDynamicRelation } from 'src/engine/twenty-orm/decorators/workspace-dynamic-relation.decorator'; +import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator'; @WorkspaceEntity({ standardId: STANDARD_OBJECT_IDS.timelineActivity, @@ -56,7 +57,7 @@ export class TimelineActivityWorkspaceEntity extends BaseWorkspaceEntity { icon: 'IconListDetails', }) @WorkspaceIsNullable() - properties: JSON; + properties: JSON | null; // Special objects that don't have their own timeline and are 'link' to the main object @WorkspaceField({ @@ -76,7 +77,7 @@ export class TimelineActivityWorkspaceEntity extends BaseWorkspaceEntity { icon: 'IconAbc', }) @WorkspaceIsNullable() - linkedRecordId: string; + linkedRecordId: string | null; @WorkspaceField({ standardId: TIMELINE_ACTIVITY_STANDARD_FIELD_IDS.linkedObjectMetadataId, @@ -86,7 +87,7 @@ export class TimelineActivityWorkspaceEntity extends BaseWorkspaceEntity { icon: 'IconAbc', }) @WorkspaceIsNullable() - linkedObjectMetadataId: string; + linkedObjectMetadataId: string | null; // Who made the action @WorkspaceRelation({ @@ -95,12 +96,14 @@ export class TimelineActivityWorkspaceEntity extends BaseWorkspaceEntity { label: 'Workspace Member', description: 'Event workspace member', icon: 'IconCircleUser', - joinColumn: 'workspaceMemberId', inverseSideTarget: () => WorkspaceMemberWorkspaceEntity, inverseSideFieldKey: 'timelineActivities', }) @WorkspaceIsNullable() - workspaceMember: Relation<WorkspaceMemberWorkspaceEntity>; + workspaceMember: Relation<WorkspaceMemberWorkspaceEntity> | null; + + @WorkspaceJoinColumn('workspaceMember') + workspaceMemberId: string | null; @WorkspaceRelation({ standardId: TIMELINE_ACTIVITY_STANDARD_FIELD_IDS.person, @@ -108,12 +111,14 @@ export class TimelineActivityWorkspaceEntity extends BaseWorkspaceEntity { label: 'Person', description: 'Event person', icon: 'IconUser', - joinColumn: 'personId', inverseSideTarget: () => PersonWorkspaceEntity, inverseSideFieldKey: 'timelineActivities', }) @WorkspaceIsNullable() - person: Relation<PersonWorkspaceEntity>; + person: Relation<PersonWorkspaceEntity> | null; + + @WorkspaceJoinColumn('person') + personId: string | null; @WorkspaceRelation({ standardId: TIMELINE_ACTIVITY_STANDARD_FIELD_IDS.company, @@ -121,12 +126,14 @@ export class TimelineActivityWorkspaceEntity extends BaseWorkspaceEntity { label: 'Company', description: 'Event company', icon: 'IconBuildingSkyscraper', - joinColumn: 'companyId', inverseSideTarget: () => CompanyWorkspaceEntity, inverseSideFieldKey: 'timelineActivities', }) @WorkspaceIsNullable() - company: Relation<CompanyWorkspaceEntity>; + company: Relation<CompanyWorkspaceEntity> | null; + + @WorkspaceJoinColumn('company') + companyId: string | null; @WorkspaceRelation({ standardId: TIMELINE_ACTIVITY_STANDARD_FIELD_IDS.opportunity, @@ -134,12 +141,14 @@ export class TimelineActivityWorkspaceEntity extends BaseWorkspaceEntity { label: 'Opportunity', description: 'Event opportunity', icon: 'IconTargetArrow', - joinColumn: 'opportunityId', inverseSideTarget: () => OpportunityWorkspaceEntity, inverseSideFieldKey: 'timelineActivities', }) @WorkspaceIsNullable() - opportunity: Relation<OpportunityWorkspaceEntity>; + opportunity: Relation<OpportunityWorkspaceEntity> | null; + + @WorkspaceJoinColumn('opportunity') + opportunityId: string | null; @WorkspaceDynamicRelation({ type: RelationMetadataType.MANY_TO_ONE, diff --git a/packages/twenty-server/src/modules/view/standard-objects/view-field.workspace-entity.ts b/packages/twenty-server/src/modules/view/standard-objects/view-field.workspace-entity.ts index 424f4299ce5c..e46ee8c0effd 100644 --- a/packages/twenty-server/src/modules/view/standard-objects/view-field.workspace-entity.ts +++ b/packages/twenty-server/src/modules/view/standard-objects/view-field.workspace-entity.ts @@ -10,6 +10,7 @@ import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-re import { VIEW_FIELD_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids'; import { STANDARD_OBJECT_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-object-ids'; import { ViewWorkspaceEntity } from 'src/modules/view/standard-objects/view.workspace-entity'; +import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator'; @WorkspaceEntity({ standardId: STANDARD_OBJECT_IDS.viewField, @@ -69,8 +70,10 @@ export class ViewFieldWorkspaceEntity extends BaseWorkspaceEntity { icon: 'IconLayoutCollage', inverseSideTarget: () => ViewWorkspaceEntity, inverseSideFieldKey: 'viewFields', - joinColumn: 'viewId', }) @WorkspaceIsNullable() - view?: ViewWorkspaceEntity; + view?: ViewWorkspaceEntity | null; + + @WorkspaceJoinColumn('view') + viewId: string | null; } diff --git a/packages/twenty-server/src/modules/view/standard-objects/view-filter.workspace-entity.ts b/packages/twenty-server/src/modules/view/standard-objects/view-filter.workspace-entity.ts index bce3e944aff4..149171e6eb7f 100644 --- a/packages/twenty-server/src/modules/view/standard-objects/view-filter.workspace-entity.ts +++ b/packages/twenty-server/src/modules/view/standard-objects/view-filter.workspace-entity.ts @@ -12,6 +12,7 @@ import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator'; import { RelationMetadataType } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity'; import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator'; +import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator'; @WorkspaceEntity({ standardId: STANDARD_OBJECT_IDS.viewFilter, @@ -63,10 +64,12 @@ export class ViewFilterWorkspaceEntity extends BaseWorkspaceEntity { label: 'View', description: 'View Filter related view', icon: 'IconLayoutCollage', - joinColumn: 'viewId', inverseSideTarget: () => ViewWorkspaceEntity, inverseSideFieldKey: 'viewFilters', }) @WorkspaceIsNullable() - view: Relation<ViewWorkspaceEntity>; + view: Relation<ViewWorkspaceEntity> | null; + + @WorkspaceJoinColumn('view') + viewId: string | null; } diff --git a/packages/twenty-server/src/modules/view/standard-objects/view-sort.workspace-entity.ts b/packages/twenty-server/src/modules/view/standard-objects/view-sort.workspace-entity.ts index 458d4d316881..5abc9848ed7d 100644 --- a/packages/twenty-server/src/modules/view/standard-objects/view-sort.workspace-entity.ts +++ b/packages/twenty-server/src/modules/view/standard-objects/view-sort.workspace-entity.ts @@ -12,6 +12,7 @@ import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator'; import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator'; import { RelationMetadataType } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity'; +import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator'; @WorkspaceEntity({ standardId: STANDARD_OBJECT_IDS.viewSort, @@ -48,10 +49,12 @@ export class ViewSortWorkspaceEntity extends BaseWorkspaceEntity { label: 'View', description: 'View Sort related view', icon: 'IconLayoutCollage', - joinColumn: 'viewId', inverseSideTarget: () => ViewWorkspaceEntity, inverseSideFieldKey: 'viewSorts', }) @WorkspaceIsNullable() - view: Relation<ViewWorkspaceEntity>; + view: Relation<ViewWorkspaceEntity> | null; + + @WorkspaceJoinColumn('view') + viewId: string | null; } diff --git a/packages/twenty-server/src/modules/workspace-member/query-hooks/workspace-member-delete-many.pre-query.hook.ts b/packages/twenty-server/src/modules/workspace-member/query-hooks/workspace-member-delete-many.pre-query.hook.ts index e0650b7e2548..9effd33285b7 100644 --- a/packages/twenty-server/src/modules/workspace-member/query-hooks/workspace-member-delete-many.pre-query.hook.ts +++ b/packages/twenty-server/src/modules/workspace-member/query-hooks/workspace-member-delete-many.pre-query.hook.ts @@ -1,10 +1,12 @@ -import { Injectable, MethodNotAllowedException } from '@nestjs/common'; +import { MethodNotAllowedException } from '@nestjs/common'; -import { WorkspacePreQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-pre-query-hook/interfaces/workspace-pre-query-hook.interface'; +import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface'; -@Injectable() +import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator'; + +@WorkspaceQueryHook(`workspaceMember.deleteMany`) export class WorkspaceMemberDeleteManyPreQueryHook - implements WorkspacePreQueryHook + implements WorkspaceQueryHookInstance { constructor() {} diff --git a/packages/twenty-server/src/modules/workspace-member/query-hooks/workspace-member-delete-one.pre-query.hook.ts b/packages/twenty-server/src/modules/workspace-member/query-hooks/workspace-member-delete-one.pre-query.hook.ts index efa6cd863cc0..e068da436be3 100644 --- a/packages/twenty-server/src/modules/workspace-member/query-hooks/workspace-member-delete-one.pre-query.hook.ts +++ b/packages/twenty-server/src/modules/workspace-member/query-hooks/workspace-member-delete-one.pre-query.hook.ts @@ -1,23 +1,21 @@ -import { Injectable } from '@nestjs/common'; - -import { WorkspacePreQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-pre-query-hook/interfaces/workspace-pre-query-hook.interface'; +import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface'; import { DeleteOneResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; -import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; -import { CommentRepository } from 'src/modules/activity/repositories/comment.repository'; +import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator'; +import { InjectWorkspaceRepository } from 'src/engine/twenty-orm/decorators/inject-workspace-repository.decorator'; +import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository'; import { CommentWorkspaceEntity } from 'src/modules/activity/standard-objects/comment.workspace-entity'; -import { AttachmentRepository } from 'src/modules/attachment/repositories/attachment.repository'; import { AttachmentWorkspaceEntity } from 'src/modules/attachment/standard-objects/attachment.workspace-entity'; -@Injectable() +@WorkspaceQueryHook(`workspaceMember.deleteOne`) export class WorkspaceMemberDeleteOnePreQueryHook - implements WorkspacePreQueryHook + implements WorkspaceQueryHookInstance { constructor( - @InjectObjectMetadataRepository(AttachmentWorkspaceEntity) - private readonly attachmentRepository: AttachmentRepository, - @InjectObjectMetadataRepository(CommentWorkspaceEntity) - private readonly commentRepository: CommentRepository, + @InjectWorkspaceRepository(AttachmentWorkspaceEntity) + private readonly attachmentRepository: WorkspaceRepository<AttachmentWorkspaceEntity>, + @InjectWorkspaceRepository(CommentWorkspaceEntity) + private readonly commentRepository: WorkspaceRepository<CommentWorkspaceEntity>, ) {} // There is no need to validate the user's access to the workspace member since we don't have permission yet. @@ -26,16 +24,14 @@ export class WorkspaceMemberDeleteOnePreQueryHook workspaceId: string, payload: DeleteOneResolverArgs, ): Promise<void> { - const workspaceMemberId = payload.id; + const authorId = payload.id; - await this.attachmentRepository.deleteByAuthorId( - workspaceMemberId, - workspaceId, - ); + await this.attachmentRepository.delete({ + authorId, + }); - await this.commentRepository.deleteByAuthorId( - workspaceMemberId, - workspaceId, - ); + await this.commentRepository.delete({ + authorId, + }); } } diff --git a/packages/twenty-server/src/modules/workspace-member/query-hooks/workspace-member-query-hook.module.ts b/packages/twenty-server/src/modules/workspace-member/query-hooks/workspace-member-query-hook.module.ts index 14c1ef5e5384..051354c6becb 100644 --- a/packages/twenty-server/src/modules/workspace-member/query-hooks/workspace-member-query-hook.module.ts +++ b/packages/twenty-server/src/modules/workspace-member/query-hooks/workspace-member-query-hook.module.ts @@ -1,6 +1,6 @@ import { Module } from '@nestjs/common'; -import { ObjectMetadataRepositoryModule } from 'src/engine/object-metadata-repository/object-metadata-repository.module'; +import { TwentyORMModule } from 'src/engine/twenty-orm/twenty-orm.module'; import { CommentWorkspaceEntity } from 'src/modules/activity/standard-objects/comment.workspace-entity'; import { AttachmentWorkspaceEntity } from 'src/modules/attachment/standard-objects/attachment.workspace-entity'; import { WorkspaceMemberDeleteManyPreQueryHook } from 'src/modules/workspace-member/query-hooks/workspace-member-delete-many.pre-query.hook'; @@ -8,20 +8,14 @@ import { WorkspaceMemberDeleteOnePreQueryHook } from 'src/modules/workspace-memb @Module({ imports: [ - ObjectMetadataRepositoryModule.forFeature([ + TwentyORMModule.forFeature([ AttachmentWorkspaceEntity, CommentWorkspaceEntity, ]), ], providers: [ - { - provide: WorkspaceMemberDeleteOnePreQueryHook.name, - useClass: WorkspaceMemberDeleteOnePreQueryHook, - }, - { - provide: WorkspaceMemberDeleteManyPreQueryHook.name, - useClass: WorkspaceMemberDeleteManyPreQueryHook, - }, + WorkspaceMemberDeleteOnePreQueryHook, + WorkspaceMemberDeleteManyPreQueryHook, ], }) export class WorkspaceMemberQueryHookModule {} diff --git a/packages/twenty-server/src/modules/workspace-member/repositories/workspace-member.repository.ts b/packages/twenty-server/src/modules/workspace-member/repositories/workspace-member.repository.ts index c67c5e66fcec..0d3b5acc3bad 100644 --- a/packages/twenty-server/src/modules/workspace-member/repositories/workspace-member.repository.ts +++ b/packages/twenty-server/src/modules/workspace-member/repositories/workspace-member.repository.ts @@ -4,7 +4,6 @@ import { EntityManager } from 'typeorm'; import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; -import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record'; @Injectable() export class WorkspaceMemberRepository { @@ -12,22 +11,6 @@ export class WorkspaceMemberRepository { private readonly workspaceDataSourceService: WorkspaceDataSourceService, ) {} - public async getByIds( - userIds: string[], - workspaceId: string, - ): Promise<ObjectRecord<WorkspaceMemberWorkspaceEntity>[]> { - const dataSourceSchema = - this.workspaceDataSourceService.getSchemaName(workspaceId); - - const result = await this.workspaceDataSourceService.executeRawQuery( - `SELECT * FROM ${dataSourceSchema}."workspaceMember" WHERE "userId" = ANY($1)`, - [userIds], - workspaceId, - ); - - return result; - } - public async find(workspaceMemberId: string, workspaceId: string) { const dataSourceSchema = this.workspaceDataSourceService.getSchemaName(workspaceId); @@ -45,7 +28,7 @@ export class WorkspaceMemberRepository { public async getByIdOrFail( userId: string, workspaceId: string, - ): Promise<ObjectRecord<WorkspaceMemberWorkspaceEntity>> { + ): Promise<WorkspaceMemberWorkspaceEntity> { const dataSourceSchema = this.workspaceDataSourceService.getSchemaName(workspaceId); @@ -68,7 +51,7 @@ export class WorkspaceMemberRepository { public async getAllByWorkspaceId( workspaceId: string, transactionManager?: EntityManager, - ): Promise<ObjectRecord<WorkspaceMemberWorkspaceEntity>[]> { + ): Promise<WorkspaceMemberWorkspaceEntity[]> { const dataSourceSchema = this.workspaceDataSourceService.getSchemaName(workspaceId); diff --git a/packages/twenty-server/src/modules/workspace-member/standard-objects/workspace-member.workspace-entity.ts b/packages/twenty-server/src/modules/workspace-member/standard-objects/workspace-member.workspace-entity.ts index 17378a598f60..9094a62b0541 100644 --- a/packages/twenty-server/src/modules/workspace-member/standard-objects/workspace-member.workspace-entity.ts +++ b/packages/twenty-server/src/modules/workspace-member/standard-objects/workspace-member.workspace-entity.ts @@ -6,26 +6,26 @@ import { RelationMetadataType, RelationOnDeleteAction, } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity'; +import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity'; +import { WorkspaceEntity } from 'src/engine/twenty-orm/decorators/workspace-entity.decorator'; +import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field.decorator'; +import { WorkspaceIsNotAuditLogged } from 'src/engine/twenty-orm/decorators/workspace-is-not-audit-logged.decorator'; +import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator'; +import { WorkspaceIsSystem } from 'src/engine/twenty-orm/decorators/workspace-is-system.decorator'; +import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator'; import { WORKSPACE_MEMBER_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids'; import { STANDARD_OBJECT_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-object-ids'; import { ActivityWorkspaceEntity } from 'src/modules/activity/standard-objects/activity.workspace-entity'; -import { AttachmentWorkspaceEntity } from 'src/modules/attachment/standard-objects/attachment.workspace-entity'; -import { BlocklistWorkspaceEntity } from 'src/modules/connected-account/standard-objects/blocklist.workspace-entity'; -import { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-event-participant.workspace-entity'; import { CommentWorkspaceEntity } from 'src/modules/activity/standard-objects/comment.workspace-entity'; +import { AttachmentWorkspaceEntity } from 'src/modules/attachment/standard-objects/attachment.workspace-entity'; +import { BlocklistWorkspaceEntity } from 'src/modules/blocklist/standard-objects/blocklist.workspace-entity'; +import { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-event-participant.workspace-entity'; import { CompanyWorkspaceEntity } from 'src/modules/company/standard-objects/company.workspace-entity'; import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; import { FavoriteWorkspaceEntity } from 'src/modules/favorite/standard-objects/favorite.workspace-entity'; -import { TimelineActivityWorkspaceEntity } from 'src/modules/timeline/standard-objects/timeline-activity.workspace-entity'; -import { AuditLogWorkspaceEntity } from 'src/modules/timeline/standard-objects/audit-log.workspace-entity'; -import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity'; -import { WorkspaceEntity } from 'src/engine/twenty-orm/decorators/workspace-entity.decorator'; -import { WorkspaceIsSystem } from 'src/engine/twenty-orm/decorators/workspace-is-system.decorator'; -import { WorkspaceIsNotAuditLogged } from 'src/engine/twenty-orm/decorators/workspace-is-not-audit-logged.decorator'; -import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field.decorator'; -import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator'; -import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator'; import { MessageParticipantWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-participant.workspace-entity'; +import { AuditLogWorkspaceEntity } from 'src/modules/timeline/standard-objects/audit-log.workspace-entity'; +import { TimelineActivityWorkspaceEntity } from 'src/modules/timeline/standard-objects/timeline-activity.workspace-entity'; @WorkspaceEntity({ standardId: STANDARD_OBJECT_IDS.workspaceMember, diff --git a/packages/twenty-server/src/queue-worker/queue-worker.module.ts b/packages/twenty-server/src/queue-worker/queue-worker.module.ts index d6c87b882383..1cf307ffefee 100644 --- a/packages/twenty-server/src/queue-worker/queue-worker.module.ts +++ b/packages/twenty-server/src/queue-worker/queue-worker.module.ts @@ -2,8 +2,17 @@ import { Module } from '@nestjs/common'; import { JobsModule } from 'src/engine/integrations/message-queue/jobs.module'; import { IntegrationsModule } from 'src/engine/integrations/integrations.module'; +import { TwentyORMModule } from 'src/engine/twenty-orm/twenty-orm.module'; +import { MessageQueueModule } from 'src/engine/integrations/message-queue/message-queue.module'; @Module({ - imports: [IntegrationsModule, JobsModule], + imports: [ + TwentyORMModule.register({ + workspaceEntities: ['dist/src/**/*.workspace-entity{.ts,.js}'], + }), + IntegrationsModule, + MessageQueueModule.registerExplorer(), + JobsModule, + ], }) export class QueueWorkerModule {} diff --git a/packages/twenty-server/src/queue-worker/queue-worker.ts b/packages/twenty-server/src/queue-worker/queue-worker.ts index fd62872d47bd..0b2af24eccd6 100644 --- a/packages/twenty-server/src/queue-worker/queue-worker.ts +++ b/packages/twenty-server/src/queue-worker/queue-worker.ts @@ -1,17 +1,8 @@ import { NestFactory } from '@nestjs/core'; -import { - MessageQueueJob, - MessageQueueJobData, -} from 'src/engine/integrations/message-queue/interfaces/message-queue-job.interface'; - import { shouldFilterException } from 'src/engine/utils/global-exception-handler.util'; import { ExceptionHandlerService } from 'src/engine/integrations/exception-handler/exception-handler.service'; import { LoggerService } from 'src/engine/integrations/logger/logger.service'; -import { JobsModule } from 'src/engine/integrations/message-queue/jobs.module'; -import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; -import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service'; -import { getJobClassName } from 'src/engine/integrations/message-queue/utils/get-job-class-name.util'; import { QueueWorkerModule } from 'src/queue-worker/queue-worker.module'; async function bootstrap() { @@ -28,29 +19,6 @@ async function bootstrap() { // Inject our logger app.useLogger(loggerService!); - - for (const queueName of Object.values(MessageQueue)) { - const messageQueueService: MessageQueueService = app.get(queueName); - - await messageQueueService.work(async (jobData: MessageQueueJobData) => { - const jobClassName = getJobClassName(jobData.name); - const job: MessageQueueJob<MessageQueueJobData> = app - .select(JobsModule) - .get(jobClassName, { strict: false }); - - try { - await job.handle(jobData.data); - } catch (err) { - exceptionHandlerService?.captureExceptions([ - new Error( - `Error occurred while processing job ${jobClassName} #${jobData.id}`, - ), - err, - ]); - throw err; - } - }); - } } catch (err) { loggerService?.error(err?.message, err?.name); diff --git a/packages/twenty-server/src/utils/custom-exception.ts b/packages/twenty-server/src/utils/custom-exception.ts new file mode 100644 index 000000000000..e12d8840c7b3 --- /dev/null +++ b/packages/twenty-server/src/utils/custom-exception.ts @@ -0,0 +1,8 @@ +export class CustomException extends Error { + code: string; + + constructor(message: string, code: string) { + super(message); + this.code = code; + } +} diff --git a/packages/twenty-server/src/utils/is-defined.ts b/packages/twenty-server/src/utils/is-defined.ts new file mode 100644 index 000000000000..1be478d76dd0 --- /dev/null +++ b/packages/twenty-server/src/utils/is-defined.ts @@ -0,0 +1,3 @@ +export const isDefined = <T>(value: T | null | undefined): value is T => { + return value !== null && value !== undefined; +}; diff --git a/packages/twenty-server/src/utils/is-group-email.ts b/packages/twenty-server/src/utils/is-group-email.ts new file mode 100644 index 000000000000..748495138b3e --- /dev/null +++ b/packages/twenty-server/src/utils/is-group-email.ts @@ -0,0 +1,6 @@ +export const isGroupEmail = (email: string): boolean => { + const isGroupPattern = + /noreply|no-reply|do_not_reply|no\.reply|^(info@|contact@|hello@|support@|feedback@|service@|help@|invites@|invite@|welcome@|alerts@|team@|notifications@|notification@|news@)/; + + return isGroupPattern.test(email); +}; diff --git a/packages/twenty-server/src/utils/typed-reflect.ts b/packages/twenty-server/src/utils/typed-reflect.ts index 6e9fdb819385..5abec76b8401 100644 --- a/packages/twenty-server/src/utils/typed-reflect.ts +++ b/packages/twenty-server/src/utils/typed-reflect.ts @@ -8,6 +8,7 @@ export interface ReflectMetadataTypeMap { ['workspace:is-system-metadata-args']: true; ['workspace:is-audit-logged-metadata-args']: false; ['workspace:is-primary-field-metadata-args']: true; + ['workspace:is-deprecated-field-metadata-args']: true; } export class TypedReflect { diff --git a/packages/twenty-server/test/company.e2e-spec.ts b/packages/twenty-server/test/company.e2e-spec.ts index 40658d931e3f..1a52998601d8 100644 --- a/packages/twenty-server/test/company.e2e-spec.ts +++ b/packages/twenty-server/test/company.e2e-spec.ts @@ -31,7 +31,9 @@ describe('CompanyResolver (e2e)', () => { id name domainName - address + address { + addressCity + } } } `, @@ -39,7 +41,7 @@ describe('CompanyResolver (e2e)', () => { data: { name: 'New Company', domainName: 'new-company.com', - address: 'New Address', + address: { addressCity: 'Paris' }, }, }, }; @@ -57,7 +59,7 @@ describe('CompanyResolver (e2e)', () => { expect(data).toHaveProperty('id'); expect(data).toHaveProperty('name', 'New Company'); expect(data).toHaveProperty('domainName', 'new-company.com'); - expect(data).toHaveProperty('address', 'New Address'); + expect(data).toHaveProperty('address', { addressCity: 'Paris' }); }); }); @@ -69,7 +71,9 @@ describe('CompanyResolver (e2e)', () => { id name domainName - address + address { + addressCity + } } } `, @@ -92,7 +96,7 @@ describe('CompanyResolver (e2e)', () => { expect(company).toHaveProperty('id'); expect(company).toHaveProperty('name', 'New Company'); expect(company).toHaveProperty('domainName', 'new-company.com'); - expect(company).toHaveProperty('address', 'New Address'); + expect(company).toHaveProperty('address', { addressCity: 'Paris' }); // Check if we have access to ressources outside of our workspace const instagramCompany = data.find((c) => c.name === 'Instagram'); @@ -109,7 +113,9 @@ describe('CompanyResolver (e2e)', () => { id name domainName - address + address { + addressCity + } } } `, @@ -131,7 +137,7 @@ describe('CompanyResolver (e2e)', () => { expect(data).toHaveProperty('id'); expect(data).toHaveProperty('name', 'New Company'); expect(data).toHaveProperty('domainName', 'new-company.com'); - expect(data).toHaveProperty('address', 'New Address'); + expect(data).toHaveProperty('address', { addressCity: 'Paris' }); }); }); @@ -143,7 +149,9 @@ describe('CompanyResolver (e2e)', () => { id name domainName - address + address { + addressCity + } } } `, @@ -175,7 +183,9 @@ describe('CompanyResolver (e2e)', () => { id name domainName - address + address { + addressCity + } } } `, @@ -186,7 +196,7 @@ describe('CompanyResolver (e2e)', () => { data: { name: 'Updated Company', domainName: 'updated-company.com', - address: 'Updated Address', + address: { addressCity: 'Updated City' }, }, }, }; @@ -202,7 +212,7 @@ describe('CompanyResolver (e2e)', () => { expect(data).toHaveProperty('id'); expect(data).toHaveProperty('name', 'Updated Company'); expect(data).toHaveProperty('domainName', 'updated-company.com'); - expect(data).toHaveProperty('address', 'Updated Address'); + expect(data).toHaveProperty('address', { addressCity: 'Updated City' }); }); }); @@ -214,7 +224,9 @@ describe('CompanyResolver (e2e)', () => { id name domainName - address + address { + addressCity + } } } `, diff --git a/packages/twenty-ui/.storybook/main.ts b/packages/twenty-ui/.storybook/main.ts index a27e1bccf947..270259adfdd7 100644 --- a/packages/twenty-ui/.storybook/main.ts +++ b/packages/twenty-ui/.storybook/main.ts @@ -16,15 +16,6 @@ const config: StorybookConfig = { name: '@storybook/react-vite', options: {}, }, - build: { - test: { - disableMDXEntries: true, - disabledAddons: [ - '@storybook/addon-docs', - '@storybook/addon-essentials/docs', - ], - }, - }, }; export default config; diff --git a/packages/twenty-ui/package.json b/packages/twenty-ui/package.json index 06c014e3d64a..a0788e34553f 100644 --- a/packages/twenty-ui/package.json +++ b/packages/twenty-ui/package.json @@ -1,6 +1,6 @@ { "name": "twenty-ui", - "version": "0.20.0", + "version": "0.22.0", "type": "module", "main": "./src/index.ts", "exports": { diff --git a/packages/twenty-ui/project.json b/packages/twenty-ui/project.json index 641a15fae554..951e50cd78cb 100644 --- a/packages/twenty-ui/project.json +++ b/packages/twenty-ui/project.json @@ -43,10 +43,10 @@ "test": {} } }, - "storybook:dev": { + "storybook:serve:dev": { "options": { "port": 6007 } }, - "storybook:static": { + "storybook:serve:static": { "options": { "buildTarget": "twenty-ui:storybook:build", "port": 6007 @@ -59,7 +59,7 @@ "storybook:test": { "options": { "port": 6007 } }, - "storybook:static:test": { + "storybook:serve-and-test:static": { "options": { "port": 6007 } } } diff --git a/packages/twenty-ui/src/display/avatar/components/Avatar.module.css b/packages/twenty-ui/src/display/avatar/components/Avatar.module.css deleted file mode 100644 index ed560dead2b6..000000000000 --- a/packages/twenty-ui/src/display/avatar/components/Avatar.module.css +++ /dev/null @@ -1,23 +0,0 @@ -.avatar { - align-items: center; - border-radius: 2px; - display: flex; - flex-shrink: 0; - justify-content: center; - overflow: hidden; - user-select: none; -} - -.rounded { - border-radius: 50%; -} - -.avatar-on-click:hover { - box-shadow: 0 0 0 4px var(--twentycrm-background-transparent-light); -} - -.avatar-image { - object-fit: cover; - width: 100%; - height: 100%; -} \ No newline at end of file diff --git a/packages/twenty-ui/src/display/avatar/components/Avatar.tsx b/packages/twenty-ui/src/display/avatar/components/Avatar.tsx index d7024b347fd8..b0373b8cb8e5 100644 --- a/packages/twenty-ui/src/display/avatar/components/Avatar.tsx +++ b/packages/twenty-ui/src/display/avatar/components/Avatar.tsx @@ -1,104 +1,112 @@ -import { useState } from 'react'; +import { styled } from '@linaria/react'; import { isNonEmptyString, isUndefined } from '@sniptt/guards'; -import clsx from 'clsx'; +import { useContext } from 'react'; +import { useRecoilState } from 'recoil'; +import { invalidAvatarUrlsState } from '@ui/display/avatar/components/states/isInvalidAvatarUrlState'; +import { AVATAR_PROPERTIES_BY_SIZE } from '@ui/display/avatar/constants/AvatarPropertiesBySize'; +import { AvatarSize } from '@ui/display/avatar/types/AvatarSize'; +import { AvatarType } from '@ui/display/avatar/types/AvatarType'; +import { ThemeContext } from '@ui/theme'; import { Nullable, stringToHslColor } from '@ui/utilities'; -import styles from './Avatar.module.css'; +const StyledAvatar = styled.div<{ + size: AvatarSize; + rounded?: boolean; + clickable?: boolean; + color: string; + backgroundColor: string; + backgroundTransparentLight: string; +}>` + align-items: center; + flex-shrink: 0; + overflow: hidden; + user-select: none; -export type AvatarType = 'squared' | 'rounded'; + border-radius: ${({ rounded }) => (rounded ? '50%' : '2px')}; + display: flex; + font-size: ${({ size }) => AVATAR_PROPERTIES_BY_SIZE[size].fontSize}; + height: ${({ size }) => AVATAR_PROPERTIES_BY_SIZE[size].width}; + justify-content: center; -export type AvatarSize = 'xl' | 'lg' | 'md' | 'sm' | 'xs'; + width: ${({ size }) => AVATAR_PROPERTIES_BY_SIZE[size].width}; + + color: ${({ color }) => color}; + background: ${({ backgroundColor }) => backgroundColor}; + + &:hover { + box-shadow: ${({ clickable, backgroundTransparentLight }) => + clickable ? `0 0 0 4px ${backgroundTransparentLight}` : 'none'}; + } +`; +const StyledImage = styled.img` + height: 100%; + object-fit: cover; + width: 100%; +`; export type AvatarProps = { avatarUrl?: string | null; className?: string; size?: AvatarSize; placeholder: string | undefined; - entityId?: string; + placeholderColorSeed?: string; type?: Nullable<AvatarType>; color?: string; backgroundColor?: string; onClick?: () => void; }; -const propertiesBySize = { - xl: { - fontSize: '16px', - width: '40px', - }, - lg: { - fontSize: '13px', - width: '24px', - }, - md: { - fontSize: '12px', - width: '16px', - }, - sm: { - fontSize: '10px', - width: '14px', - }, - xs: { - fontSize: '8px', - width: '12px', - }, -}; - +// TODO: Remove recoil because we don't want it into twenty-ui and find a solution for invalid avatar urls export const Avatar = ({ avatarUrl, size = 'md', placeholder, - entityId = placeholder, + placeholderColorSeed = placeholder, onClick, type = 'squared', color, backgroundColor, }: AvatarProps) => { - const [isInvalidAvatarUrl, setIsInvalidAvatarUrl] = useState(false); + const { theme } = useContext(ThemeContext); + const [invalidAvatarUrls, setInvalidAvatarUrls] = useRecoilState( + invalidAvatarUrlsState, + ); const noAvatarUrl = !isNonEmptyString(avatarUrl); const placeholderChar = placeholder?.[0]?.toLocaleUpperCase(); - const showPlaceholder = noAvatarUrl || isInvalidAvatarUrl; + const showPlaceholder = noAvatarUrl || invalidAvatarUrls.includes(avatarUrl); const handleImageError = () => { - setIsInvalidAvatarUrl(true); + if (isNonEmptyString(avatarUrl)) { + setInvalidAvatarUrls((prev) => [...prev, avatarUrl]); + } }; - const fixedColor = color ?? stringToHslColor(entityId ?? '', 75, 25); + const fixedColor = + color ?? stringToHslColor(placeholderColorSeed ?? '', 75, 25); const fixedBackgroundColor = - backgroundColor ?? stringToHslColor(entityId ?? '', 75, 85); + backgroundColor ?? stringToHslColor(placeholderColorSeed ?? '', 75, 85); const showBackgroundColor = showPlaceholder; return ( - <div - className={clsx({ - [styles.avatar]: true, - [styles.rounded]: type === 'rounded', - [styles.avatarOnClick]: !isUndefined(onClick), - })} + <StyledAvatar + size={size} + backgroundColor={showBackgroundColor ? fixedBackgroundColor : 'none'} + color={fixedColor} + clickable={!isUndefined(onClick)} + rounded={type === 'rounded'} onClick={onClick} - style={{ - color: fixedColor, - backgroundColor: showBackgroundColor ? fixedBackgroundColor : 'none', - width: propertiesBySize[size].width, - height: propertiesBySize[size].width, - fontSize: propertiesBySize[size].fontSize, - }} + backgroundTransparentLight={theme.background.transparent.light} > {showPlaceholder ? ( placeholderChar ) : ( - <img - src={avatarUrl} - className={styles.avatarImage} - onError={handleImageError} - alt="" - /> + <StyledImage src={avatarUrl} onError={handleImageError} alt="" /> )} - </div> + </StyledAvatar> ); }; diff --git a/packages/twenty-ui/src/display/avatar/components/__stories__/AvatarGroup.stories.tsx b/packages/twenty-ui/src/display/avatar/components/__stories__/AvatarGroup.stories.tsx index 18ad3c3d4d58..e3792988dc5a 100644 --- a/packages/twenty-ui/src/display/avatar/components/__stories__/AvatarGroup.stories.tsx +++ b/packages/twenty-ui/src/display/avatar/components/__stories__/AvatarGroup.stories.tsx @@ -1,11 +1,8 @@ import { Meta, StoryObj } from '@storybook/react'; -import { - Avatar, - AvatarProps, - AvatarSize, - AvatarType, -} from '@ui/display/avatar/components/Avatar'; +import { Avatar, AvatarProps } from '@ui/display/avatar/components/Avatar'; +import { AvatarSize } from '@ui/display/avatar/types/AvatarSize'; +import { AvatarType } from '@ui/display/avatar/types/AvatarType'; import { AVATAR_URL_MOCK, CatalogDecorator, @@ -16,7 +13,7 @@ import { AvatarGroup, AvatarGroupProps } from '../AvatarGroup'; const makeAvatar = (userName: string, props: Partial<AvatarProps> = {}) => ( // eslint-disable-next-line react/jsx-props-no-spreading - <Avatar placeholder={userName} entityId={userName} {...props} /> + <Avatar placeholder={userName} placeholderColorSeed={userName} {...props} /> ); const getAvatars = (commonProps: Partial<AvatarProps> = {}) => [ diff --git a/packages/twenty-ui/src/display/avatar/components/states/isInvalidAvatarUrlState.ts b/packages/twenty-ui/src/display/avatar/components/states/isInvalidAvatarUrlState.ts new file mode 100644 index 000000000000..13d410a6fa4e --- /dev/null +++ b/packages/twenty-ui/src/display/avatar/components/states/isInvalidAvatarUrlState.ts @@ -0,0 +1,6 @@ +import { atom } from 'recoil'; + +export const invalidAvatarUrlsState = atom<string[]>({ + key: 'invalidAvatarUrlsState', + default: [], +}); diff --git a/packages/twenty-ui/src/display/avatar/constants/AvatarPropertiesBySize.ts b/packages/twenty-ui/src/display/avatar/constants/AvatarPropertiesBySize.ts new file mode 100644 index 000000000000..e44c170cc269 --- /dev/null +++ b/packages/twenty-ui/src/display/avatar/constants/AvatarPropertiesBySize.ts @@ -0,0 +1,22 @@ +export const AVATAR_PROPERTIES_BY_SIZE = { + xl: { + fontSize: '16px', + width: '40px', + }, + lg: { + fontSize: '13px', + width: '24px', + }, + md: { + fontSize: '12px', + width: '16px', + }, + sm: { + fontSize: '10px', + width: '14px', + }, + xs: { + fontSize: '8px', + width: '12px', + }, +}; diff --git a/packages/twenty-ui/src/display/avatar/types/AvatarSize.ts b/packages/twenty-ui/src/display/avatar/types/AvatarSize.ts new file mode 100644 index 000000000000..db1915e1718b --- /dev/null +++ b/packages/twenty-ui/src/display/avatar/types/AvatarSize.ts @@ -0,0 +1 @@ +export type AvatarSize = 'xl' | 'lg' | 'md' | 'sm' | 'xs'; diff --git a/packages/twenty-ui/src/display/avatar/types/AvatarType.ts b/packages/twenty-ui/src/display/avatar/types/AvatarType.ts new file mode 100644 index 000000000000..9e9b7dc9589e --- /dev/null +++ b/packages/twenty-ui/src/display/avatar/types/AvatarType.ts @@ -0,0 +1 @@ +export type AvatarType = 'squared' | 'rounded'; diff --git a/packages/twenty-ui/src/display/chip/components/EntityChip.tsx b/packages/twenty-ui/src/display/chip/components/AvatarChip.tsx similarity index 54% rename from packages/twenty-ui/src/display/chip/components/EntityChip.tsx rename to packages/twenty-ui/src/display/chip/components/AvatarChip.tsx index f17ee4108935..89c4bdabef11 100644 --- a/packages/twenty-ui/src/display/chip/components/EntityChip.tsx +++ b/packages/twenty-ui/src/display/chip/components/AvatarChip.tsx @@ -1,55 +1,47 @@ -import * as React from 'react'; -import { useNavigate } from 'react-router-dom'; import { useTheme } from '@emotion/react'; -import { isNonEmptyString } from '@sniptt/guards'; -import { Avatar, AvatarType } from '@ui/display/avatar/components/Avatar'; +import { Avatar } from '@ui/display/avatar/components/Avatar'; +import { AvatarType } from '@ui/display/avatar/types/AvatarType'; import { Chip, ChipVariant } from '@ui/display/chip/components/Chip'; import { IconComponent } from '@ui/display/icon/types/IconComponent'; +import { isDefined } from '@ui/utilities/isDefined'; import { Nullable } from '@ui/utilities/types/Nullable'; +import { MouseEvent } from 'react'; -export type EntityChipProps = { - linkToEntity?: string; - entityId: string; +export type AvatarChipProps = { name: string; avatarUrl?: string; avatarType?: Nullable<AvatarType>; - variant?: EntityChipVariant; + variant?: AvatarChipVariant; LeftIcon?: IconComponent; className?: string; + placeholderColorSeed?: string; + onClick?: (event: MouseEvent) => void; }; -export enum EntityChipVariant { +export enum AvatarChipVariant { Regular = 'regular', Transparent = 'transparent', } -export const EntityChip = ({ - linkToEntity, - entityId, +export const AvatarChip = ({ name, avatarUrl, avatarType = 'rounded', - variant = EntityChipVariant.Regular, + variant = AvatarChipVariant.Regular, LeftIcon, className, -}: EntityChipProps) => { - const navigate = useNavigate(); + placeholderColorSeed, + onClick, +}: AvatarChipProps) => { const theme = useTheme(); - const handleLinkClick = (event: React.MouseEvent<HTMLDivElement>) => { - if (isNonEmptyString(linkToEntity)) { - event.stopPropagation(); - navigate(linkToEntity); - } - }; - return ( <Chip label={name} variant={ - linkToEntity - ? variant === EntityChipVariant.Regular + isDefined(onClick) + ? variant === AvatarChipVariant.Regular ? ChipVariant.Highlighted : ChipVariant.Regular : ChipVariant.Transparent @@ -60,15 +52,15 @@ export const EntityChip = ({ ) : ( <Avatar avatarUrl={avatarUrl} - entityId={entityId} + placeholderColorSeed={placeholderColorSeed} placeholder={name} size="sm" type={avatarType} /> ) } - clickable={!!linkToEntity} - onClick={handleLinkClick} + clickable={isDefined(onClick)} + onClick={onClick} className={className} /> ); diff --git a/packages/twenty-ui/src/display/chip/components/__stories__/EntityChip.stories.tsx b/packages/twenty-ui/src/display/chip/components/__stories__/EntityChip.stories.tsx index 254fceef4018..2682eec0409e 100644 --- a/packages/twenty-ui/src/display/chip/components/__stories__/EntityChip.stories.tsx +++ b/packages/twenty-ui/src/display/chip/components/__stories__/EntityChip.stories.tsx @@ -1,21 +1,19 @@ import { Meta, StoryObj } from '@storybook/react'; +import { AvatarChip } from '@ui/display/chip/components/AvatarChip'; import { ComponentDecorator, RouterDecorator } from '@ui/testing'; -import { EntityChip } from '../EntityChip'; - -const meta: Meta<typeof EntityChip> = { - title: 'UI/Display/Chip/EntityChip', - component: EntityChip, +const meta: Meta<typeof AvatarChip> = { + title: 'UI/Display/Chip/AvatarChip', + component: AvatarChip, decorators: [RouterDecorator, ComponentDecorator], args: { name: 'Entity name', - linkToEntity: '/entity-link', avatarType: 'squared', }, }; export default meta; -type Story = StoryObj<typeof EntityChip>; +type Story = StoryObj<typeof AvatarChip>; export const Default: Story = {}; diff --git a/packages/twenty-ui/src/display/icon/components/IconTwentyStarFilled.tsx b/packages/twenty-ui/src/display/icon/components/IconTwentyStarFilled.tsx index 465483017156..c82ec61041c9 100644 --- a/packages/twenty-ui/src/display/icon/components/IconTwentyStarFilled.tsx +++ b/packages/twenty-ui/src/display/icon/components/IconTwentyStarFilled.tsx @@ -1,14 +1,14 @@ -import { useTheme } from '@emotion/react'; - import IconTwentyStarFilledRaw from '@ui/display/icon/assets/twenty-star-filled.svg?react'; import { IconComponentProps } from '@ui/display/icon/types/IconComponent'; +import { THEME_COMMON } from '@ui/theme'; type IconTwentyStarFilledProps = Pick<IconComponentProps, 'size' | 'stroke'>; +const iconStrokeMd = THEME_COMMON.icon.stroke.md; + export const IconTwentyStarFilled = (props: IconTwentyStarFilledProps) => { - const theme = useTheme(); const size = props.size ?? 24; - const stroke = props.stroke ?? theme.icon.stroke.md; + const stroke = props.stroke ?? iconStrokeMd; return ( <IconTwentyStarFilledRaw height={size} width={size} strokeWidth={stroke} /> diff --git a/packages/twenty-ui/src/display/icon/components/TablerIcons.ts b/packages/twenty-ui/src/display/icon/components/TablerIcons.ts index 2855731a344b..0ba89be2f7e2 100644 --- a/packages/twenty-ui/src/display/icon/components/TablerIcons.ts +++ b/packages/twenty-ui/src/display/icon/components/TablerIcons.ts @@ -33,6 +33,7 @@ export { IconCalendarEvent, IconCalendarTime, IconCalendarX, + IconChartCandle, IconCheck, IconCheckbox, IconChevronDown, @@ -52,6 +53,7 @@ export { IconMessageCircle as IconComment, IconCopy, IconCreditCard, + IconCurrencyBaht, IconCurrencyDirham, IconCurrencyDollar, IconCurrencyEuro, @@ -59,7 +61,9 @@ export { IconCurrencyKroneCzech, IconCurrencyKroneSwedish, IconCurrencyPound, + IconCurrencyReal, IconCurrencyRiyal, + IconCurrencyWon, IconCurrencyYen, IconCurrencyYuan, IconDatabase, @@ -134,10 +138,13 @@ export { IconReload, IconRepeat, IconRocket, + IconRotate, IconSearch, IconSend, IconSettings, IconSortDescending, + IconSparkles, + IconSql, IconSquareRoundedCheck, IconTable, IconTag, diff --git a/packages/twenty-ui/src/display/index.ts b/packages/twenty-ui/src/display/index.ts index 74833f5db945..fa961ff5abf3 100644 --- a/packages/twenty-ui/src/display/index.ts +++ b/packages/twenty-ui/src/display/index.ts @@ -1,9 +1,13 @@ export * from './avatar/components/Avatar'; export * from './avatar/components/AvatarGroup'; +export * from './avatar/components/states/isInvalidAvatarUrlState'; +export * from './avatar/constants/AvatarPropertiesBySize'; +export * from './avatar/types/AvatarSize'; +export * from './avatar/types/AvatarType'; export * from './checkmark/components/AnimatedCheckmark'; export * from './checkmark/components/Checkmark'; +export * from './chip/components/AvatarChip'; export * from './chip/components/Chip'; -export * from './chip/components/EntityChip'; export * from './color/components/ColorSample'; export * from './icon/components/IconAddressBook'; export * from './icon/components/IconGmail'; diff --git a/packages/twenty-ui/src/display/tag/components/Tag.tsx b/packages/twenty-ui/src/display/tag/components/Tag.tsx index 3b2cb67b7354..1ed0dc1dd07f 100644 --- a/packages/twenty-ui/src/display/tag/components/Tag.tsx +++ b/packages/twenty-ui/src/display/tag/components/Tag.tsx @@ -1,5 +1,5 @@ -import { useContext } from 'react'; import { styled } from '@linaria/react'; +import { useContext } from 'react'; import { IconComponent, OverflowingTextWithTooltip } from '@ui/display'; import { @@ -16,14 +16,17 @@ const spacing1 = THEME_COMMON.spacing(1); const StyledTag = styled.h3<{ theme: ThemeType; - color: ThemeColor; + color: TagColor; weight: TagWeight; + variant: TagVariant; preventShrink?: boolean; }>` align-items: center; - background: ${({ color, theme }) => theme.tag.background[color]}; + background: ${({ color, theme }) => + color === 'transparent' ? color : theme.tag.background[color]}; border-radius: ${BORDER_COMMON.radius.sm}; - color: ${({ color, theme }) => theme.tag.text[color]}; + color: ${({ color, theme }) => + color === 'transparent' ? theme.tag.text['gray'] : theme.tag.text[color]}; display: inline-flex; font-size: ${({ theme }) => theme.font.size.md}; font-style: normal; @@ -35,6 +38,8 @@ const StyledTag = styled.h3<{ margin: 0; overflow: hidden; padding: 0 ${spacing2}; + border: ${({ variant, theme }) => + variant === 'outline' ? `2px dashed ${theme.tag.background['gray']}` : ''}; gap: ${spacing1}; @@ -58,14 +63,17 @@ const StyledIconContainer = styled.div` `; type TagWeight = 'regular' | 'medium'; +type TagVariant = 'solid' | 'outline'; +type TagColor = ThemeColor | 'transparent'; type TagProps = { className?: string; - color: ThemeColor; + color: TagColor; text: string; Icon?: IconComponent; onClick?: () => void; weight?: TagWeight; + variant?: TagVariant; preventShrink?: boolean; }; @@ -77,6 +85,7 @@ export const Tag = ({ Icon, onClick, weight = 'regular', + variant = 'solid', preventShrink, }: TagProps) => { const { theme } = useContext(ThemeContext); @@ -88,6 +97,7 @@ export const Tag = ({ color={color} onClick={onClick} weight={weight} + variant={variant} preventShrink={preventShrink} > {!!Icon && ( diff --git a/packages/twenty-ui/src/display/tooltip/AppTooltip.tsx b/packages/twenty-ui/src/display/tooltip/AppTooltip.tsx index e3f126f5a882..e0a00d2750e2 100644 --- a/packages/twenty-ui/src/display/tooltip/AppTooltip.tsx +++ b/packages/twenty-ui/src/display/tooltip/AppTooltip.tsx @@ -10,6 +10,12 @@ export enum TooltipPosition { Bottom = 'bottom', } +export enum TooltipDelay { + noDelay = '0ms', + shortDelay = '300ms', + mediumDelay = '500ms', +} + const StyledAppTooltip = styled(Tooltip)` backdrop-filter: ${({ theme }) => theme.blur.strong}; background-color: ${({ theme }) => RGBA(theme.color.gray80, 0.8)}; @@ -36,38 +42,51 @@ export type AppTooltipProps = { anchorSelect?: string; content?: string; children?: React.ReactNode; - delayHide?: number; offset?: number; noArrow?: boolean; isOpen?: boolean; place?: PlacesType; + delay?: TooltipDelay; positionStrategy?: PositionStrategy; + clickable?: boolean; }; export const AppTooltip = ({ anchorSelect, className, content, - delayHide, isOpen, noArrow, offset, + delay = TooltipDelay.mediumDelay, place, positionStrategy, children, -}: AppTooltipProps) => ( - <StyledAppTooltip - {...{ - anchorSelect, - className, - content, - delayHide, - isOpen, - noArrow, - offset, - place, - positionStrategy, - children, - }} - /> -); + clickable, +}: AppTooltipProps) => { + const delayInMs = + delay === TooltipDelay.noDelay + ? 0 + : delay === TooltipDelay.shortDelay + ? 300 + : 500; + + return ( + <StyledAppTooltip + {...{ + anchorSelect, + className, + content, + delayShow: delayInMs, + delayHide: delayInMs, + isOpen, + noArrow, + offset, + place, + positionStrategy, + children, + clickable, + }} + /> + ); +}; diff --git a/packages/twenty-ui/src/display/tooltip/OverflowingTextWithTooltip.module.css b/packages/twenty-ui/src/display/tooltip/OverflowingTextWithTooltip.module.css deleted file mode 100644 index 2df2dca40bc7..000000000000 --- a/packages/twenty-ui/src/display/tooltip/OverflowingTextWithTooltip.module.css +++ /dev/null @@ -1,20 +0,0 @@ -.main { - font-family: inherit; - font-size: inherit; - - font-weight: inherit; - max-width: 100%; - overflow: hidden; - text-decoration: inherit; - - text-overflow: ellipsis; - white-space: nowrap; -} - -.cursor { - cursor: pointer; -} - -.large { - height: calc(var(--twentycrm-spacing-multiplicator) * 4px); -} \ No newline at end of file diff --git a/packages/twenty-ui/src/display/tooltip/OverflowingTextWithTooltip.tsx b/packages/twenty-ui/src/display/tooltip/OverflowingTextWithTooltip.tsx index 0fbd883f5331..ed0580e9fd65 100644 --- a/packages/twenty-ui/src/display/tooltip/OverflowingTextWithTooltip.tsx +++ b/packages/twenty-ui/src/display/tooltip/OverflowingTextWithTooltip.tsx @@ -4,7 +4,7 @@ import { styled } from '@linaria/react'; import { THEME_COMMON } from '@ui/theme'; -import { AppTooltip } from './AppTooltip'; +import { AppTooltip, TooltipDelay } from './AppTooltip'; const spacing4 = THEME_COMMON.spacing(4); @@ -87,12 +87,12 @@ export const OverflowingTextWithTooltip = ({ <AppTooltip anchorSelect={`#${textElementId}`} content={mutliline ? undefined : text ?? ''} - delayHide={1} offset={5} isOpen noArrow place="bottom" positionStrategy="absolute" + delay={TooltipDelay.mediumDelay} > {mutliline ? <pre>{text}</pre> : ''} </AppTooltip> diff --git a/packages/twenty-ui/src/display/tooltip/__stories__/Tooltip.stories.tsx b/packages/twenty-ui/src/display/tooltip/__stories__/Tooltip.stories.tsx index 7ce9997ab049..3b46a1fc005b 100644 --- a/packages/twenty-ui/src/display/tooltip/__stories__/Tooltip.stories.tsx +++ b/packages/twenty-ui/src/display/tooltip/__stories__/Tooltip.stories.tsx @@ -6,7 +6,11 @@ import { ComponentDecorator, } from '@ui/testing'; -import { AppTooltip as Tooltip, TooltipPosition } from '../AppTooltip'; +import { + AppTooltip as Tooltip, + TooltipDelay, + TooltipPosition, +} from '../AppTooltip'; const meta: Meta<typeof Tooltip> = { title: 'UI/Display/Tooltip', @@ -19,6 +23,7 @@ type Story = StoryObj<typeof Tooltip>; export const Default: Story = { args: { place: TooltipPosition.Bottom, + delay: TooltipDelay.mediumDelay, content: 'Tooltip Test', isOpen: true, anchorSelect: '#hover-text', @@ -28,12 +33,13 @@ export const Default: Story = { anchorSelect, className, content, - delayHide, + delay, isOpen, noArrow, offset, place, positionStrategy, + clickable, }) => ( <> <p id="hover-text" data-testid="tooltip"> @@ -44,12 +50,52 @@ export const Default: Story = { anchorSelect, className, content, - delayHide, + delay, isOpen, noArrow, offset, place, positionStrategy, + clickable, + }} + /> + </> + ), +}; + +export const Hoverable: Story = { + args: { + place: TooltipPosition.Bottom, + delay: TooltipDelay.mediumDelay, + content: 'Tooltip Test', + isOpen: true, + anchorSelect: '#hover-text', + }, + decorators: [ComponentDecorator], + render: ({ + anchorSelect, + className, + content, + delay, + noArrow, + offset, + place, + positionStrategy, + }) => ( + <> + <p id="hover-text" data-testid="tooltip"> + Hover me! + </p> + <Tooltip + {...{ + anchorSelect, + className, + content, + delay, + noArrow, + offset, + place, + positionStrategy, }} /> </> diff --git a/packages/twenty-ui/src/theme/constants/BorderCommon.ts b/packages/twenty-ui/src/theme/constants/BorderCommon.ts index ca10ce0bab5e..a68f017bc44c 100644 --- a/packages/twenty-ui/src/theme/constants/BorderCommon.ts +++ b/packages/twenty-ui/src/theme/constants/BorderCommon.ts @@ -1,7 +1,7 @@ export const BORDER_COMMON = { radius: { xs: '2px', - sm: 'var(--twentycrm-border-radius-sm)', + sm: '4px', md: '8px', xl: '20px', pill: '999px', diff --git a/packages/twenty-ui/src/theme/constants/FontCommon.ts b/packages/twenty-ui/src/theme/constants/FontCommon.ts index 6d14f8d1831d..65556c018d38 100644 --- a/packages/twenty-ui/src/theme/constants/FontCommon.ts +++ b/packages/twenty-ui/src/theme/constants/FontCommon.ts @@ -10,7 +10,7 @@ export const FONT_COMMON = { }, weight: { regular: 400, - medium: 'var(--twentycrm-font-weight-medium)', + medium: 500, semiBold: 600, }, family: 'Inter, sans-serif', diff --git a/packages/twenty-ui/src/theme/provider/ThemeProvider.tsx b/packages/twenty-ui/src/theme/provider/ThemeProvider.tsx index 1282213f8f45..3b513f34e1bf 100644 --- a/packages/twenty-ui/src/theme/provider/ThemeProvider.tsx +++ b/packages/twenty-ui/src/theme/provider/ThemeProvider.tsx @@ -1,23 +1,16 @@ -import { ReactNode, useEffect } from 'react'; +import { ReactNode } from 'react'; import { ThemeProvider as EmotionThemeProvider } from '@emotion/react'; import { ThemeContextProvider } from '@ui/theme/provider/ThemeContextProvider'; import { ThemeType } from '..'; -import './theme.css'; - type ThemeProviderProps = { theme: ThemeType; children: ReactNode; }; const ThemeProvider = ({ theme, children }: ThemeProviderProps) => { - useEffect(() => { - document.documentElement.className = - theme.name === 'dark' ? 'dark' : 'light'; - }, [theme]); - return ( <EmotionThemeProvider theme={theme}> <ThemeContextProvider theme={theme}>{children}</ThemeContextProvider> diff --git a/packages/twenty-ui/src/theme/provider/theme.css b/packages/twenty-ui/src/theme/provider/theme.css deleted file mode 100644 index 076090f6370f..000000000000 --- a/packages/twenty-ui/src/theme/provider/theme.css +++ /dev/null @@ -1,85 +0,0 @@ -:root { - --twentycrm-spacing-multiplicator: 4; - --twentycrm-border-radius-sm: 4px; - --twentycrm-font-weight-medium: 500; - - /* Grays */ - --twentycrm-gray-100: #000000; - --twentycrm-gray-100-4: #0000000A; - --twentycrm-gray-100-10: #00000019; - --twentycrm-gray-100-16: #00000029; - --twentycrm-gray-90: #141414; - --twentycrm-gray-85: #171717; - --twentycrm-gray-85-80: #171717CC; - --twentycrm-gray-80: #1b1b1b; - --twentycrm-gray-80-80: #1b1b1bCC; - --twentycrm-gray-75: #1d1d1d; - --twentycrm-gray-70: #222222; - --twentycrm-gray-65: #292929; - --twentycrm-gray-60: #333333; - --twentycrm-gray-55: #4c4c4c; - --twentycrm-gray-50: #666666; - --twentycrm-gray-45: #818181; - --twentycrm-gray-40: #999999; - --twentycrm-gray-35: #b3b3b3; - --twentycrm-gray-30: #cccccc; - --twentycrm-gray-25: #d6d6d6; - --twentycrm-gray-20: #ebebeb; - --twentycrm-gray-15: #f1f1f1; - --twentycrm-gray-10: #fcfcfc; - --twentycrm-gray-10-80: #fcfcfcCC; - --twentycrm-gray-0: #ffffff; - --twentycrm-gray-0-6: #ffffff0f; - --twentycrm-gray-0-10: #ffffff19; - --twentycrm-gray-0-14: #ffffff23; - - /* Blues */ - --twentycrm-blue-accent-90: #141a25; - --twentycrm-blue-accent-10: #f5f9fd; -} - -:root.dark { - /* Accent color */ - --twentycrm-accent-quaternary: var(--twentycrm-blue-accent-90); - - /* Font color */ - --twentycrm-font-color-secondary: var(--twentycrm-gray-35); - --twentycrm-font-color-primary: var(--twentycrm-gray-20); - --twentycrm-font-color-light: var(--twentycrm-gray-50); - --twentycrm-font-color-extra-light: var(--twentycrm-gray-55); - - /* Background color */ - --twentycrm-background-primary: var(--twentycrm-gray-85); - - /* Background transparent color */ - --twentycrm-background-transparent-secondary: var(--twentycrm-gray-80-80); - --twentycrm-background-transparent-light: var(--twentycrm-gray-0-6); - --twentycrm-background-transparent-medium: var(--twentycrm-gray-0-10); - --twentycrm-background-transparent-strong: var(--twentycrm-gray-0-14); - - /* Border color */ - --twentycrm-border-color-medium: var(--twentycrm-gray-65); -} - -:root.light { - /* Accent color */ - --twentycrm-accent-quaternary: var(--twentycrm-blue-accent-10); - - /* Colors */ - --twentycrm-font-color-primary: var(--twentycrm-gray-60); - --twentycrm-font-color-secondary: var(--twentycrm-gray-50); - --twentycrm-font-color-light: var(--twentycrm-gray-35); - --twentycrm-font-color-extra-light: var(--twentycrm-gray-30); - - /* Background color */ - --twentycrm-background-primary: var(--twentycrm-gray-0); - - /* Background transparent color */ - --twentycrm-background-transparent-secondary: var(--twentycrm-gray-10-80); - --twentycrm-background-transparent-light: var(--twentycrm-gray-100-4); - --twentycrm-background-transparent-medium: var(--twentycrm-gray-100-10); - --twentycrm-background-transparent-strong: var(--twentycrm-gray-100-16); - - /* Border color */ - --twentycrm-border-color-medium: var(--twentycrm-gray-20); -} diff --git a/packages/twenty-ui/src/utilities/index.ts b/packages/twenty-ui/src/utilities/index.ts index 1e20365c2bcf..3d99deafeead 100644 --- a/packages/twenty-ui/src/utilities/index.ts +++ b/packages/twenty-ui/src/utilities/index.ts @@ -1,3 +1,4 @@ export * from './color/utils/stringToHslColor'; +export * from './isDefined'; export * from './state/utils/createState'; export * from './types/Nullable'; diff --git a/packages/twenty-ui/src/utilities/isDefined.ts b/packages/twenty-ui/src/utilities/isDefined.ts new file mode 100644 index 000000000000..81eb67203a03 --- /dev/null +++ b/packages/twenty-ui/src/utilities/isDefined.ts @@ -0,0 +1,4 @@ +import { isNull, isUndefined } from '@sniptt/guards'; + +export const isDefined = <T>(value: T | null | undefined): value is T => + !isUndefined(value) && !isNull(value); diff --git a/packages/twenty-ui/vite.config.ts b/packages/twenty-ui/vite.config.ts index bac435e19c1f..46804e3bee7b 100644 --- a/packages/twenty-ui/vite.config.ts +++ b/packages/twenty-ui/vite.config.ts @@ -33,6 +33,7 @@ export default defineConfig({ '**/OverflowingTextWithTooltip.tsx', '**/Chip.tsx', '**/Tag.tsx', + '**/Avatar.tsx', ], babelOptions: { presets: ['@babel/preset-typescript', '@babel/preset-react'], diff --git a/packages/twenty-website/package.json b/packages/twenty-website/package.json index 7976b89b724c..fd47048b5a4f 100644 --- a/packages/twenty-website/package.json +++ b/packages/twenty-website/package.json @@ -1,6 +1,6 @@ { "name": "twenty-website", - "version": "0.20.0", + "version": "0.22.0", "private": true, "scripts": { "nx": "NX_DEFAULT_PROJECT=twenty-website node ../../node_modules/nx/bin/nx.js", @@ -14,6 +14,7 @@ "database:generate:pg": "npx drizzle-kit generate:pg --config=src/database/drizzle-posgres.config.ts" }, "dependencies": { + "next-runtime-env": "^3.2.2", "postgres": "^3.4.3" } } diff --git a/packages/twenty-website/public/images/releases/0.20/0.20-blocklist.png b/packages/twenty-website/public/images/releases/0.20/0.20-blocklist.png new file mode 100644 index 000000000000..92fbf686bafc Binary files /dev/null and b/packages/twenty-website/public/images/releases/0.20/0.20-blocklist.png differ diff --git a/packages/twenty-website/public/images/releases/0.20/0.20-onboarding.png b/packages/twenty-website/public/images/releases/0.20/0.20-onboarding.png new file mode 100644 index 000000000000..b29133411cc1 Binary files /dev/null and b/packages/twenty-website/public/images/releases/0.20/0.20-onboarding.png differ diff --git a/packages/twenty-website/public/images/releases/0.20/0.20-timeline.png b/packages/twenty-website/public/images/releases/0.20/0.20-timeline.png new file mode 100644 index 000000000000..20fbd8a773e4 Binary files /dev/null and b/packages/twenty-website/public/images/releases/0.20/0.20-timeline.png differ diff --git a/packages/twenty-website/public/images/releases/0.21/0.21-advanced-email-settings.png b/packages/twenty-website/public/images/releases/0.21/0.21-advanced-email-settings.png new file mode 100644 index 000000000000..cc69c0cca7de Binary files /dev/null and b/packages/twenty-website/public/images/releases/0.21/0.21-advanced-email-settings.png differ diff --git a/packages/twenty-website/public/images/releases/0.21/0.21-many-many.png b/packages/twenty-website/public/images/releases/0.21/0.21-many-many.png new file mode 100644 index 000000000000..c76dbdc5eccb Binary files /dev/null and b/packages/twenty-website/public/images/releases/0.21/0.21-many-many.png differ diff --git a/packages/twenty-website/public/images/releases/0.22/0.22-kanban-improvements.png b/packages/twenty-website/public/images/releases/0.22/0.22-kanban-improvements.png new file mode 100644 index 000000000000..e9625df62206 Binary files /dev/null and b/packages/twenty-website/public/images/releases/0.22/0.22-kanban-improvements.png differ diff --git a/packages/twenty-website/public/images/releases/0.22/0.22-mass-deletion.png b/packages/twenty-website/public/images/releases/0.22/0.22-mass-deletion.png new file mode 100644 index 000000000000..f09ab6514800 Binary files /dev/null and b/packages/twenty-website/public/images/releases/0.22/0.22-mass-deletion.png differ diff --git a/packages/twenty-website/public/images/releases/0.22/0.22-navbar.png b/packages/twenty-website/public/images/releases/0.22/0.22-navbar.png new file mode 100644 index 000000000000..6b0bb59762e2 Binary files /dev/null and b/packages/twenty-website/public/images/releases/0.22/0.22-navbar.png differ diff --git a/packages/twenty-website/src/app/_components/contributors/PullRequestItem.tsx b/packages/twenty-website/src/app/_components/contributors/PullRequestItem.tsx index 617ed7c1778b..dd00e056219e 100644 --- a/packages/twenty-website/src/app/_components/contributors/PullRequestItem.tsx +++ b/packages/twenty-website/src/app/_components/contributors/PullRequestItem.tsx @@ -6,6 +6,7 @@ import { PullRequestIcon } from '@/app/_components/ui/icons/SvgIcons'; import { Theme } from '@/app/_components/ui/theme/theme'; import { formatIntoRelativeDate } from '@/shared-utils/formatIntoRelativeDate'; +// TODO: use twenty-ui Tooltip const StyledTooltip = styled(Tooltip)``; const Item = styled.div` diff --git a/packages/twenty-website/src/app/_components/docs/AlgoliaDocSearch.tsx b/packages/twenty-website/src/app/_components/docs/AlgoliaDocSearch.tsx index 17e2e1db6215..cbd4b5b7a1e0 100644 --- a/packages/twenty-website/src/app/_components/docs/AlgoliaDocSearch.tsx +++ b/packages/twenty-website/src/app/_components/docs/AlgoliaDocSearch.tsx @@ -1,5 +1,6 @@ import { DocSearch } from '@docsearch/react'; import { StoredDocSearchHit } from '@docsearch/react/dist/esm/types'; +import { env } from 'next-runtime-env'; interface AlgoliaHit extends StoredDocSearchHit { _snippetResult?: { @@ -47,8 +48,8 @@ export const AlgoliaDocSearch = ({ pathname }: AlgoliaDocSearchProps) => { </a> </section> )} - appId={process.env.NEXT_PUBLIC_ALGOLIA_APP_ID as string} - apiKey={process.env.NEXT_PUBLIC_ALGOLIA_API_KEY as string} + appId={env('NEXT_PUBLIC_ALGOLIA_APP_ID') ?? ''} + apiKey={env('NEXT_PUBLIC_ALGOLIA_API_KEY') ?? ''} indexName={`twenty-${indexName}`} /> ); diff --git a/packages/twenty-website/src/app/_components/docs/DocsCard.tsx b/packages/twenty-website/src/app/_components/docs/DocsCard.tsx index 3c3164e0cfc7..c5eeff85a284 100644 --- a/packages/twenty-website/src/app/_components/docs/DocsCard.tsx +++ b/packages/twenty-website/src/app/_components/docs/DocsCard.tsx @@ -1,12 +1,14 @@ 'use client'; import styled from '@emotion/styled'; -import { usePathname, useRouter } from 'next/navigation'; +import Link from 'next/link'; +import { usePathname } from 'next/navigation'; import { Theme } from '@/app/_components/ui/theme/theme'; import { DocsArticlesProps } from '@/content/user-guide/constants/getDocsArticles'; import { getCardPath } from '@/shared-utils/getCardPath'; -const StyledContainer = styled.div` +const StyledContainer = styled(Link)` + text-decoration: none; color: ${Theme.border.color.plain}; border: 2px solid ${Theme.border.color.plain}; border-radius: ${Theme.border.radius.md}; @@ -58,13 +60,12 @@ export default function DocsCard({ card: DocsArticlesProps; isSection?: boolean; }) { - const router = useRouter(); const pathname = usePathname(); const path = getCardPath(card, pathname, isSection); if (card.title) { return ( - <StyledContainer onClick={() => router.push(path)}> + <StyledContainer href={path}> <StyledImage src={card.image} alt={card.title} /> <StyledHeading>{card.title}</StyledHeading> <StyledSubHeading>{card.info}</StyledSubHeading> diff --git a/packages/twenty-website/src/app/_components/docs/DocsContent.tsx b/packages/twenty-website/src/app/_components/docs/DocsContent.tsx index eb46ee97a439..5d4c6c92603c 100644 --- a/packages/twenty-website/src/app/_components/docs/DocsContent.tsx +++ b/packages/twenty-website/src/app/_components/docs/DocsContent.tsx @@ -149,6 +149,7 @@ export default function DocsContent({ item }: { item: FileContent }) { style={{ objectFit: 'cover' }} onLoad={() => setImageLoaded(true)} loaded={imageLoaded.toString()} + unoptimized /> )} </StyledImageContainer> diff --git a/packages/twenty-website/src/app/_components/playground/rest-api-wrapper.tsx b/packages/twenty-website/src/app/_components/playground/rest-api-wrapper.tsx new file mode 100644 index 000000000000..cd2da8ea8e6d --- /dev/null +++ b/packages/twenty-website/src/app/_components/playground/rest-api-wrapper.tsx @@ -0,0 +1,29 @@ +import React, { useEffect } from 'react'; +// @ts-expect-error Migration loader as text not passing warnings +import { API } from '@stoplight/elements'; + +// @ts-expect-error Migration loader as text not passing warnings +import spotlightTheme from '!css-loader!@stoplight/elements/styles.min.css'; + +export const RestApiWrapper = ({ openApiJson }: { openApiJson: any }) => { + // We load spotlightTheme style using useEffect as it breaks remaining docs style + useEffect(() => { + const styleElement = document.createElement('style'); + styleElement.innerHTML = spotlightTheme.toString(); + document.head.append(styleElement); + + return () => styleElement.remove(); + }, []); + + return ( + <div + style={{ + height: 'calc(100vh - var(--ifm-navbar-height) - 45px)', + width: '100%', + overflow: 'auto', + }} + > + <API apiDescriptionDocument={JSON.stringify(openApiJson)} router="hash" /> + </div> + ); +}; diff --git a/packages/twenty-website/src/app/_components/playground/token-form.tsx b/packages/twenty-website/src/app/_components/playground/token-form.tsx index 398fbad7a525..1a0051c62edd 100644 --- a/packages/twenty-website/src/app/_components/playground/token-form.tsx +++ b/packages/twenty-website/src/app/_components/playground/token-form.tsx @@ -195,7 +195,9 @@ const TokenForm = ({ className="select" onChange={(event) => router.replace( - '/' + pathname.split('/').at(-2) + '/' + event.target.value, + pathname.split('/').slice(0, -1).join('/') + + '/' + + event.target.value, ) } value={pathname.split('/').at(-1)} diff --git a/packages/twenty-website/src/app/_components/ui/layout/PostImage.tsx b/packages/twenty-website/src/app/_components/ui/layout/PostImage.tsx index b5bc150d7cbf..00e215aa7754 100644 --- a/packages/twenty-website/src/app/_components/ui/layout/PostImage.tsx +++ b/packages/twenty-website/src/app/_components/ui/layout/PostImage.tsx @@ -1,5 +1,3 @@ -import Image from 'next/image'; - export const PostImage = ({ sources, style, @@ -7,5 +5,5 @@ export const PostImage = ({ sources: { light: string; dark: string }; style?: React.CSSProperties; }) => { - return <Image src={sources.light} style={style} alt={sources.light} />; + return <img src={sources.light} style={style} alt={sources.light} />; }; diff --git a/packages/twenty-website/src/app/developers/[slug]/page.tsx b/packages/twenty-website/src/app/developers/[slug]/page.tsx index 05cc57264ad3..47efae715865 100644 --- a/packages/twenty-website/src/app/developers/[slug]/page.tsx +++ b/packages/twenty-website/src/app/developers/[slug]/page.tsx @@ -5,8 +5,6 @@ import DocsContent from '@/app/_components/docs/DocsContent'; import { fetchArticleFromSlug } from '@/shared-utils/fetchArticleFromSlug'; import { formatSlug } from '@/shared-utils/formatSlug'; -export const dynamic = 'force-dynamic'; - export async function generateMetadata({ params, }: { diff --git a/packages/twenty-website/src/app/developers/graphql/core/page.tsx b/packages/twenty-website/src/app/developers/graphql/core/page.tsx index e6a0bc9481ed..f2c9e18ff56c 100644 --- a/packages/twenty-website/src/app/developers/graphql/core/page.tsx +++ b/packages/twenty-website/src/app/developers/graphql/core/page.tsx @@ -1,6 +1,11 @@ +'use client'; import React from 'react'; +import dynamic from 'next/dynamic'; -import GraphQlPlayground from '../../../_components/playground/graphql-playground'; +const GraphQlPlayground = dynamic( + () => import('../../../_components/playground/graphql-playground'), + { ssr: false }, +); const CoreGraphql = () => { return <GraphQlPlayground subDoc={'core'} />; diff --git a/packages/twenty-website/src/app/developers/graphql/metadata/page.tsx b/packages/twenty-website/src/app/developers/graphql/metadata/page.tsx index b215e2344458..ebc4490ae132 100644 --- a/packages/twenty-website/src/app/developers/graphql/metadata/page.tsx +++ b/packages/twenty-website/src/app/developers/graphql/metadata/page.tsx @@ -1,6 +1,11 @@ +'use client'; import React from 'react'; +import dynamic from 'next/dynamic'; -import GraphQlPlayground from '../../../_components/playground/graphql-playground'; +const GraphQlPlayground = dynamic( + () => import('../../../_components/playground/graphql-playground'), + { ssr: false }, +); const CoreGraphql = () => { return <GraphQlPlayground subDoc={'metadata'} />; diff --git a/packages/twenty-website/src/app/developers/page.tsx b/packages/twenty-website/src/app/developers/page.tsx index eb425f467bf1..c2de5a6f7adb 100644 --- a/packages/twenty-website/src/app/developers/page.tsx +++ b/packages/twenty-website/src/app/developers/page.tsx @@ -7,8 +7,6 @@ export const metadata = { icons: '/images/core/logo.svg', }; -export const dynamic = 'force-dynamic'; - export default async function DocsHome() { const filePath = 'src/content/developers/'; const docsArticleCards = getDocsArticles(filePath); diff --git a/packages/twenty-website/src/app/developers/rest-api/core/page.tsx b/packages/twenty-website/src/app/developers/rest-api/core/page.tsx index ae245a9959d0..4c211c3ec4d0 100644 --- a/packages/twenty-website/src/app/developers/rest-api/core/page.tsx +++ b/packages/twenty-website/src/app/developers/rest-api/core/page.tsx @@ -1,40 +1,23 @@ 'use client'; -import React, { useEffect, useState } from 'react'; -// @ts-expect-error Migration loader as text not passing warnings -import { API } from '@stoplight/elements'; + +import { useEffect, useState } from 'react'; import Playground from '@/app/_components/playground/playground'; +import { RestApiWrapper } from '@/app/_components/playground/rest-api-wrapper'; -// @ts-expect-error Migration loader as text not passing warnings -import spotlightTheme from '!css-loader!@stoplight/elements/styles.min.css'; +const RestApi = () => { + const [openApiJson, setOpenApiJson] = useState({}); + const [isClient, setIsClient] = useState(false); -const RestApiComponent = ({ openApiJson }: { openApiJson: any }) => { - // We load spotlightTheme style using useEffect as it breaks remaining docs style useEffect(() => { - const styleElement = document.createElement('style'); - styleElement.innerHTML = spotlightTheme.toString(); - document.head.append(styleElement); - - return () => styleElement.remove(); + setIsClient(true); }, []); - return ( - <div - style={{ - height: 'calc(100vh - var(--ifm-navbar-height) - 45px)', - width: '100%', - overflow: 'auto', - }} - > - <API apiDescriptionDocument={JSON.stringify(openApiJson)} router="hash" /> - </div> - ); -}; - -const restApi = () => { - const [openApiJson, setOpenApiJson] = useState({}); + if (!isClient) { + return null; + } - const children = <RestApiComponent openApiJson={openApiJson} />; + const children = <RestApiWrapper openApiJson={openApiJson} />; return ( <div style={{ width: '100vw' }}> @@ -47,4 +30,4 @@ const restApi = () => { ); }; -export default restApi; +export default RestApi; diff --git a/packages/twenty-website/src/app/developers/rest-api/metadata/page.tsx b/packages/twenty-website/src/app/developers/rest-api/metadata/page.tsx index c49726892b99..e76cadc93b77 100644 --- a/packages/twenty-website/src/app/developers/rest-api/metadata/page.tsx +++ b/packages/twenty-website/src/app/developers/rest-api/metadata/page.tsx @@ -1,39 +1,22 @@ 'use client'; import React, { useEffect, useState } from 'react'; -// @ts-expect-error Migration loader as text not passing warnings -import { API } from '@stoplight/elements'; import Playground from '@/app/_components/playground/playground'; +import { RestApiWrapper } from '@/app/_components/playground/rest-api-wrapper'; -// @ts-expect-error Migration loader as text not passing warnings -import spotlightTheme from '!css-loader!@stoplight/elements/styles.min.css'; +const restApi = () => { + const [openApiJson, setOpenApiJson] = useState({}); + const [isClient, setIsClient] = useState(false); -const RestApiComponent = ({ openApiJson }: { openApiJson: any }) => { - // We load spotlightTheme style using useEffect as it breaks remaining docs style useEffect(() => { - const styleElement = document.createElement('style'); - styleElement.innerHTML = spotlightTheme.toString(); - document.head.append(styleElement); - - return () => styleElement.remove(); + setIsClient(true); }, []); - return ( - <div - style={{ - height: 'calc(100vh - var(--ifm-navbar-height) - 45px)', - overflow: 'auto', - }} - > - <API apiDescriptionDocument={JSON.stringify(openApiJson)} router="hash" /> - </div> - ); -}; - -const restApi = () => { - const [openApiJson, setOpenApiJson] = useState({}); + if (!isClient) { + return null; + } - const children = <RestApiComponent openApiJson={openApiJson} />; + const children = <RestApiWrapper openApiJson={openApiJson} />; return ( <Playground diff --git a/packages/twenty-website/src/app/developers/section/[folder]/page.tsx b/packages/twenty-website/src/app/developers/section/[folder]/page.tsx index 5879c5277a29..6e57de3bdc61 100644 --- a/packages/twenty-website/src/app/developers/section/[folder]/page.tsx +++ b/packages/twenty-website/src/app/developers/section/[folder]/page.tsx @@ -6,8 +6,6 @@ import { getDocsArticles } from '@/content/user-guide/constants/getDocsArticles' import { fetchArticleFromSlug } from '@/shared-utils/fetchArticleFromSlug'; import { formatSlug } from '@/shared-utils/formatSlug'; -export const dynamic = 'force-dynamic'; - export async function generateMetadata({ params, }: { diff --git a/packages/twenty-website/src/app/layout.tsx b/packages/twenty-website/src/app/layout.tsx index d82f80c89c07..c302c9e3e51d 100644 --- a/packages/twenty-website/src/app/layout.tsx +++ b/packages/twenty-website/src/app/layout.tsx @@ -1,5 +1,6 @@ import { Metadata } from 'next'; import { Gabarito, Inter } from 'next/font/google'; +import { PublicEnvScript } from 'next-runtime-env'; import { AppHeader } from '@/app/_components/ui/layout/header'; @@ -40,6 +41,7 @@ export default function RootLayout({ return ( <html lang="en" className={`${gabarito.variable} ${inter.variable}`}> <body> + <PublicEnvScript /> <EmotionRootStyleRegistry> <AppHeader /> <div className="container">{children}</div> diff --git a/packages/twenty-website/src/app/user-guide/[slug]/page.tsx b/packages/twenty-website/src/app/user-guide/[slug]/page.tsx index 3c33f6025901..6c919639d5b4 100644 --- a/packages/twenty-website/src/app/user-guide/[slug]/page.tsx +++ b/packages/twenty-website/src/app/user-guide/[slug]/page.tsx @@ -5,8 +5,6 @@ import DocsContent from '@/app/_components/docs/DocsContent'; import { fetchArticleFromSlug } from '@/shared-utils/fetchArticleFromSlug'; import { formatSlug } from '@/shared-utils/formatSlug'; -export const dynamic = 'force-dynamic'; - export async function generateMetadata({ params, }: { diff --git a/packages/twenty-website/src/app/user-guide/page.tsx b/packages/twenty-website/src/app/user-guide/page.tsx index 308bd2fb2be9..e23f4eb87a43 100644 --- a/packages/twenty-website/src/app/user-guide/page.tsx +++ b/packages/twenty-website/src/app/user-guide/page.tsx @@ -8,8 +8,6 @@ export const metadata = { icons: '/images/core/logo.svg', }; -export const dynamic = 'force-dynamic'; - export default async function UserGuideHome() { const filePath = 'src/content/user-guide/'; const docsArticleCards = getDocsArticles(filePath); diff --git a/packages/twenty-website/src/app/user-guide/section/[folder]/[documentation]/page.tsx b/packages/twenty-website/src/app/user-guide/section/[folder]/[documentation]/page.tsx index c331f118e1e0..4804aa7248ca 100644 --- a/packages/twenty-website/src/app/user-guide/section/[folder]/[documentation]/page.tsx +++ b/packages/twenty-website/src/app/user-guide/section/[folder]/[documentation]/page.tsx @@ -5,8 +5,6 @@ import DocsContent from '@/app/_components/docs/DocsContent'; import { fetchArticleFromSlug } from '@/shared-utils/fetchArticleFromSlug'; import { formatSlug } from '@/shared-utils/formatSlug'; -export const dynamic = 'force-dynamic'; - export async function generateMetadata({ params, }: { diff --git a/packages/twenty-website/src/content/developers/frontend-development/frontend-commands.mdx b/packages/twenty-website/src/content/developers/frontend-development/frontend-commands.mdx index 3dfcdd5f6177..56dc4e718a37 100644 --- a/packages/twenty-website/src/content/developers/frontend-development/frontend-commands.mdx +++ b/packages/twenty-website/src/content/developers/frontend-development/frontend-commands.mdx @@ -28,9 +28,9 @@ nx lint twenty-front ```bash nx test twenty-front# run jest tests -nx storybook:dev twenty-front# run storybook -nx storybook:test twenty-front# run tests # (needs yarn storybook:dev to be running) -nx storybook:coverage twenty-front # (needs yarn storybook:dev to be running) +nx storybook:serve:dev twenty-front# run storybook +nx storybook:test twenty-front# run tests # (needs yarn storybook:serve:dev to be running) +nx storybook:coverage twenty-front # (needs yarn storybook:serve:dev to be running) ``` ## Tech Stack diff --git a/packages/twenty-website/src/content/developers/self-hosting/cloud-providers.mdx b/packages/twenty-website/src/content/developers/self-hosting/cloud-providers.mdx index b996568ed657..08e541a21a19 100644 --- a/packages/twenty-website/src/content/developers/self-hosting/cloud-providers.mdx +++ b/packages/twenty-website/src/content/developers/self-hosting/cloud-providers.mdx @@ -6,21 +6,31 @@ image: /images/user-guide/notes/notes_header.png <ArticleWarning> This document is maintained by the community. It might contain issues. -Feel free to join our discord if you need assistance. </ArticleWarning> +## Kubernetes via Terraform and Manifests + +Community-led documentation for Kubernetes deployment is available (here)[https://github.com/twentyhq/twenty/tree/main/packages/twenty-docker/k8s] + ## Render +Community-led, might not be up to date + [![Deploy to Render](https://render.com/images/deploy-to-render-button.svg)](https://render.com/deploy?repo=https://github.com/twentyhq/twenty) -## RepoCloud + +## RepoCloud + +Community-led, might not be up to date [![Deploy on RepoCloud](https://d16t0pc4846x52.cloudfront.net/deploy.png)](https://repocloud.io/details/?app_id=259) ## Azure Container Apps +Community-led, might not be up to date + ### About Hosts Twenty CRM using Azure Container Apps. diff --git a/packages/twenty-website/src/content/developers/self-hosting/self-hosting-var.mdx b/packages/twenty-website/src/content/developers/self-hosting/self-hosting-var.mdx index 9c4937fb3259..f133fde180a3 100644 --- a/packages/twenty-website/src/content/developers/self-hosting/self-hosting-var.mdx +++ b/packages/twenty-website/src/content/developers/self-hosting/self-hosting-var.mdx @@ -13,6 +13,7 @@ Twenty offers integrations with Gmail and Google Calendar. To enable these featu # from your worker container yarn command:prod cron:messaging:messages-import yarn command:prod cron:messaging:message-list-fetch +yarn command:prod cron:calendar:calendar-event-list-fetch ``` # Setup Environment Variables @@ -141,6 +142,8 @@ yarn command:prod cron:messaging:message-list-fetch ['STORAGE_S3_REGION', '', 'Storage Region'], ['STORAGE_S3_NAME', '', 'Bucket Name'], ['STORAGE_S3_ENDPOINT', '', 'Use if a different Endpoint is needed (for example Google)'], + ['STORAGE_S3_ACCESS_KEY_ID', '', 'Optional depending on the authentication method'], + ['STORAGE_S3_SECRET_ACCESS_KEY', '', 'Optional depending on the authentication method'], ['STORAGE_LOCAL_PATH', '.local-storage', 'data path (local storage)'], ]}></ArticleTable> @@ -153,7 +156,7 @@ yarn command:prod cron:messaging:message-list-fetch ### Logging <ArticleTable options={[ - ['LOGGER_DRIVER', 'console', "The logging driver can be: 'console' or 'sentry'"], + ['LOGGER_DRIVER', 'console', "Currently, only supports 'console'"], ['LOGGER_IS_BUFFER_ENABLED', 'true', 'Buffer the logs before sending them to the logging driver'], ['LOG_LEVELS', 'error,warn', "The loglevels which are logged to the logging driver. Can include: 'log', 'warn', 'error'"], ['EXCEPTION_HANDLER_DRIVER', 'sentry', "The exception handler driver can be: 'console' or 'sentry'"], @@ -167,8 +170,13 @@ yarn command:prod cron:messaging:message-list-fetch ### Data enrichment and AI <ArticleTable options={[ - ['OPENROUTER_API_KEY', '', "The API key for openrouter.ai, an abstraction layer over models from Mistral, OpenAI and more"] - ]}></ArticleTable> + ['OPENROUTER_API_KEY', '', "The API key for openrouter.ai, an abstraction layer over models from Mistral, OpenAI and more"], + ['OPENAI_API_KEY', 'sk-proj-abcdabcd...', "OpenAI API key"], + ['LLM_CHAT_MODEL_DRIVER', 'openai', "LLM provider"], + ['LLM_TRACING_DRIVER', 'langfuse', "Where to output LangChain logs. 'langfuse' or 'console'."], + ['LANGFUSE_SECRET_KEY', 'sk-lf-abcdabcd-abcd...', "Langfuse secret key"], + ['LANGFUSE_PUBLIC_KEY', 'pk-lf-abcdabcd-abcd...', "Langfuse public key"], +]}></ArticleTable> ### Support Chat @@ -208,4 +216,4 @@ yarn command:prod cron:messaging:message-list-fetch ['CAPTCHA_SECRET_KEY', '', 'The captcha secret key'], ]}></ArticleTable> -<ArticleEditContent></ArticleEditContent> \ No newline at end of file +<ArticleEditContent></ArticleEditContent> diff --git a/packages/twenty-website/src/content/releases/0.20.0.mdx b/packages/twenty-website/src/content/releases/0.20.0.mdx new file mode 100644 index 000000000000..b80da631407f --- /dev/null +++ b/packages/twenty-website/src/content/releases/0.20.0.mdx @@ -0,0 +1,27 @@ +--- +release: 0.20.0 +Date: June 14th 2024 +--- + +# Enhanced Timeline + +The timeline on every record page has been significantly improved. It now provides detailed updates for: + +- Record creations +- Field updates +- Received emails +- Created calendar events + +![](/images/releases/0.20/0.20-timeline.png) + +# Improved Onboarding Experience + +Our onboarding process has been streamlined to let you import your calendar and emails seamlessly. You can now also configure your privacy settings directly during onboarding, allowing you to choose between sharing content with your team or keeping it hidden. + +![](/images/releases/0.20/0.20-onboarding.png) + +# Email and calendar Blocklist + +To enhance privacy, you can now add specific email addresses to a blocklist within the "Accounts" settings. This feature prevents sensitive content from being synced to the CRM when corresponding with certain individuals. This can be particularly useful when managing sensitive deals. + +![](/images/releases/0.20/0.20-blocklist.png) \ No newline at end of file diff --git a/packages/twenty-website/src/content/releases/0.21.0.mdx b/packages/twenty-website/src/content/releases/0.21.0.mdx new file mode 100644 index 000000000000..2614c981f1a9 --- /dev/null +++ b/packages/twenty-website/src/content/releases/0.21.0.mdx @@ -0,0 +1,24 @@ +--- +release: 0.21.0 +Date: June 28th 2024 +--- + +# Enhanced One-to-Many Relations Editing + +You can now edit one-to-many relations directly from the "many side". This means you can assign people to a company directly from the company list view, instead of having to navigate to each individual person's profile to assign them a company. + +![](/images/releases/0.21/0.21-many-many.png) + + +# Advanced Email and Calendar Settings + +We've introduced advanced settings for email and calendar management: +- **Auto-Create Contact Options:** Choose when an email interaction should automatically create a contact. Options include: + - People I've sent emails to and received emails from + - People I've sent emails to + - Don't auto create contact + +- **Email Exclusions:** Ability to exclude non-professional emails (e.g., Gmail, Outlook) and team emails (e.g., support@, team@) from being synced to the CRM. +- **Calendar Events:** Auto-contact creation settings are now available for calendar events as well. + +![](/images/releases/0.21/0.21-advanced-email-settings.png) \ No newline at end of file diff --git a/packages/twenty-website/src/content/releases/0.22.0.mdx b/packages/twenty-website/src/content/releases/0.22.0.mdx new file mode 100644 index 000000000000..a4b7e856370f --- /dev/null +++ b/packages/twenty-website/src/content/releases/0.22.0.mdx @@ -0,0 +1,26 @@ +--- +release: 0.22.0 +Date: July 11th 2024 +--- + +# Enhanced Kanban Board + +- **Edit Kanban Stages:** You can now edit Kanban stages directly from the app, not just from the settings. This makes it easier to manage and customize your workflow on the fly. +- **"No Value" Column:** Cards that are not assigned to a specific value will now appear in a "No Value" column. This column can be shown or hidden as needed, ensuring no cards are overlooked. + +![](/images/releases/0.22/0.22-kanban-improvements.png) + +# Revamped Navigation Bar + +Navigate more quickly with our revamped record page navbar: +- Navigate directly from one record page to another. +- View the total number of records within a view. +- Easily return to the corresponding index view with a new "Close" button. + +![](/images/releases/0.22/0.22-navbar.png) + +# Bulk Deletion + +You can now delete up to 10,000 records at once. (For when you want to Marie Kondo your database! 🧹) + +![](/images/releases/0.22/0.22-mass-deletion.png) \ No newline at end of file diff --git a/packages/twenty-website/src/content/user-guide/functions/integrations.mdx b/packages/twenty-website/src/content/user-guide/functions/integrations.mdx index 34e4d8b492a8..1cd3713141d3 100644 --- a/packages/twenty-website/src/content/user-guide/functions/integrations.mdx +++ b/packages/twenty-website/src/content/user-guide/functions/integrations.mdx @@ -18,7 +18,8 @@ Sync Twenty with 3000+ apps using <ArticleLink href="https://zapier.com/apps/twe 2. Click on `+ Create Zap` in the left sidebar. 3. Choose the application you want to set as the trigger. A trigger refers to an event that starts the automation. 4. Select Twenty as the action. An action is the event performed whenever an application triggers an automation. <ArticleLink href="https://zapier.com/how-it-works">Learn more about triggers and actions in Zapier.</ArticleLink> -5. Once you choose the Twenty account that you want to use for your automation, you'll have to allow Zapier to access it by adding an API key. You can learn [how to generate your API key here.](/user-guide/api-webhooks) +5. Once you choose the Twenty account that you want to use for your automation, you'll have to allow Zapier to access it by adding an API key. You can learn [how to generate your API key here.](/user-guide/section/functions/api-webhooks) + 6. Enter your API key and click on 'Yes, Continue to Twenty.' @@ -43,4 +44,4 @@ Sync Twenty with 3000+ apps using <ArticleLink href="https://zapier.com/apps/twe You can now continue creating your automation! -<ArticleEditContent></ArticleEditContent> \ No newline at end of file +<ArticleEditContent></ArticleEditContent> diff --git a/packages/twenty-website/src/content/user-guide/getting-started/create-workspace.mdx b/packages/twenty-website/src/content/user-guide/getting-started/create-workspace.mdx index 2639b7b6ff62..c10b7496b7ef 100644 --- a/packages/twenty-website/src/content/user-guide/getting-started/create-workspace.mdx +++ b/packages/twenty-website/src/content/user-guide/getting-started/create-workspace.mdx @@ -7,7 +7,7 @@ sectionInfo: Discover Twenty, an open-source CRM. --- ## Step 1: Registration -1. Navigate to <ArticleLink href="https://app.twenty.com/sign-up">Twenty Sign Up</ArticleLink>. +1. Navigate to <ArticleLink href="https://app.twenty.com">Twenty Sign Up</ArticleLink>. 2. Select your preferred sign-up method: - **Continue with Google** for Google account registration. - Or, **Continue With Email** for email registration. @@ -50,4 +50,4 @@ Post payment approval via Stripe, you're directed to create your workspace and u ## Support For queries or help, connect with the dedicated support team at [contact@twenty.com](mailto:contact@twenty.com) or send a message on <ArticleLink href="https://discord.gg/cx5n4Jzs57">Discord</ArticleLink> -<ArticleEditContent></ArticleEditContent> \ No newline at end of file +<ArticleEditContent></ArticleEditContent> diff --git a/packages/twenty-website/src/content/user-guide/getting-started/what-is-twenty.mdx b/packages/twenty-website/src/content/user-guide/getting-started/what-is-twenty.mdx index 2c18a7fde891..a13746ffe694 100644 --- a/packages/twenty-website/src/content/user-guide/getting-started/what-is-twenty.mdx +++ b/packages/twenty-website/src/content/user-guide/getting-started/what-is-twenty.mdx @@ -12,23 +12,23 @@ Twenty is the leading open-source CRM, crafted by hundreds of contributors to su ### Main Features -**Contact Management:** Efficiently store and manage customer data. [Learn more](/user-guide/objects). +**Contact Management:** Efficiently store and manage customer data. [Learn more](/user-guide/section/objects/standard-objects). -**Custom Objects:** Create and customize objects to fit your business needs. [Details](/user-guide/objects). +**Custom Objects:** Create and customize objects to fit your business needs. [Details](/user-guide/section/objects/standard-objects). -**Custom Fields:** Tailor data fields to capture and organize information specific to your operations. [Understand more](/user-guide/fields). +**Custom Fields:** Tailor data fields to capture and organize information specific to your operations. [Understand more](/user-guide/section/objects/fields). -**Kanban & Table Views:** Optimize your workflow with flexible [Table Views](/user-guide/table-views) and [Kanban Views](/user-guide/kanban-views). +**Kanban & Table Views:** Optimize your workflow with flexible [Table Views](/user-guide/section/objects/table-views) and [Kanban Views](/user-guide/section/objects/kanban-views). -**Pipeline Visualization:** Get a clear view of your processes with customizable views. [Explore views](/user-guide/views-sort-and-filter). +**Pipeline Visualization:** Get a clear view of your processes with customizable views. [Explore views](/user-guide/section/objects/views-sort-filter). -**Email Integration:** View the emails of a specific customer or company within your workspace. [Integrate now](/user-guide/emails). +**Email Integration:** View the emails of a specific customer or company within your workspace. [Integrate now](/user-guide/section/functions/emails). -**Notes:** Create detailed notes for each record to share knowledge more effectively. [Add notes](/user-guide/notes). +**Notes:** Create detailed notes for each record to share knowledge more effectively. [Add notes](/user-guide/section/functions/notes). -**Tasks:** Schedule tasks to track customer interactions. [See how](/user-guide/tasks). +**Tasks:** Schedule tasks to track customer interactions. [See how](/user-guide/section/functions/tasks). -**API & Webhooks:** Connect to other apps and automate workflows with API and Webhooks. [Start integrating](/user-guide/integrations). +**API & Webhooks:** Connect to other apps and automate workflows with API and Webhooks. [Start integrating](/user-guide/section/functions/integrations). ### Benefits @@ -68,4 +68,4 @@ And Open-source is the bedrock of our approach, ensuring that Twenty evolves wit <ArticleLink href="https://app.twenty.com">Register here</ArticleLink> or <ArticleLink href="https://github.com/twentyhq/twenty">become a contributor on GitHub</ArticleLink>. -<ArticleEditContent></ArticleEditContent> \ No newline at end of file +<ArticleEditContent></ArticleEditContent> diff --git a/packages/twenty-website/src/shared-utils/getCardPath.tsx b/packages/twenty-website/src/shared-utils/getCardPath.tsx index f7cadc48ad2f..6bb3d599c894 100644 --- a/packages/twenty-website/src/shared-utils/getCardPath.tsx +++ b/packages/twenty-website/src/shared-utils/getCardPath.tsx @@ -16,7 +16,7 @@ export const getCardPath = ( if (isPlayground.includes(card.fileName)) { const apiType = card.fileName.includes('rest') ? 'rest-api' : 'graphql'; const apiName = card.fileName.includes('core') ? 'core' : 'metadata'; - return `${basePath}/${apiType}/${apiName}`; + return `/developers/${apiType}/${apiName}`; } else if (card.fileName.includes('storybook')) { return 'https://storybook.twenty.com'; } else if (card.fileName.includes('components')) { diff --git a/packages/twenty-zapier/src/test/creates/crud_record.test.ts b/packages/twenty-zapier/src/test/creates/crud_record.test.ts index f1c177233fcc..eb763338b82b 100644 --- a/packages/twenty-zapier/src/test/creates/crud_record.test.ts +++ b/packages/twenty-zapier/src/test/creates/crud_record.test.ts @@ -14,7 +14,7 @@ describe('creates.create_company', () => { nameSingular: 'Company', crudZapierOperation: Operation.create, name: 'Company Name', - address: 'Company Address', + address: { addressCity: 'Paris' }, domainName: 'Company Domain Name', linkedinLink: { url: '/linkedin_url', label: 'Test linkedinUrl' }, xLink: { url: '/x_url', label: 'Test xUrl' }, diff --git a/packages/twenty-zapier/src/test/triggers/trigger_record.test.ts b/packages/twenty-zapier/src/test/triggers/trigger_record.test.ts index 962fe91111e3..9139629da1c2 100644 --- a/packages/twenty-zapier/src/test/triggers/trigger_record.test.ts +++ b/packages/twenty-zapier/src/test/triggers/trigger_record.test.ts @@ -67,7 +67,7 @@ describe('triggers.trigger_record.created', () => { name: '', domainName: '', createdAt: '2023-10-19 10:10:12.490', - address: '', + address: { addressCity: null }, employees: null, linkedinUrl: null, xUrl: null, diff --git a/packages/twenty-zapier/src/test/utils/handleQueryParams.test.ts b/packages/twenty-zapier/src/test/utils/handleQueryParams.test.ts index c407c4a6c9ef..872879900166 100644 --- a/packages/twenty-zapier/src/test/utils/handleQueryParams.test.ts +++ b/packages/twenty-zapier/src/test/utils/handleQueryParams.test.ts @@ -10,7 +10,7 @@ describe('utils.handleQueryParams', () => { test('should format', () => { const inputData = { name: 'Company Name', - address: 'Company Address', + address: { addressCity: 'Paris' }, domainName: 'Company Domain Name', linkedinUrl__url: '/linkedin_url', linkedinUrl__label: 'Test linkedinUrl', @@ -23,7 +23,7 @@ describe('utils.handleQueryParams', () => { const result = handleQueryParams(inputData); const expectedResult = 'name: "Company Name", ' + - 'address: "Company Address", ' + + 'address: { addressCity: "Paris" }, ' + 'domainName: "Company Domain Name", ' + 'linkedinUrl: {url: "/linkedin_url", label: "Test linkedinUrl"}, ' + 'xUrl: {url: "/x_url", label: "Test xUrl"}, ' + diff --git a/packages/twenty-zapier/src/utils/computeInputFields.ts b/packages/twenty-zapier/src/utils/computeInputFields.ts index 7b8afbc58bbc..f2eabc331692 100644 --- a/packages/twenty-zapier/src/utils/computeInputFields.ts +++ b/packages/twenty-zapier/src/utils/computeInputFields.ts @@ -25,7 +25,6 @@ const getTypeFromFieldMetadataType = ( case FieldMetadataType.NUMBER: return 'integer'; case FieldMetadataType.NUMERIC: - case FieldMetadataType.PROBABILITY: return 'number'; default: return undefined; @@ -183,7 +182,6 @@ export const computeInputFields = ( case FieldMetadataType.BOOLEAN: case FieldMetadataType.NUMBER: case FieldMetadataType.NUMERIC: - case FieldMetadataType.PROBABILITY: case FieldMetadataType.RATING: { const nodeFieldType = getTypeFromFieldMetadataType(nodeField.type); if (!nodeFieldType) { diff --git a/packages/twenty-zapier/src/utils/data.types.ts b/packages/twenty-zapier/src/utils/data.types.ts index d7b38d4876c7..ba73ae18e09a 100644 --- a/packages/twenty-zapier/src/utils/data.types.ts +++ b/packages/twenty-zapier/src/utils/data.types.ts @@ -40,7 +40,6 @@ export enum FieldMetadataType { BOOLEAN = 'BOOLEAN', NUMBER = 'NUMBER', NUMERIC = 'NUMERIC', - PROBABILITY = 'PROBABILITY', LINK = 'LINK', CURRENCY = 'CURRENCY', FULL_NAME = 'FULL_NAME', diff --git a/render.yaml b/render.yaml index b0719ea46b63..580cd4a26cfd 100644 --- a/render.yaml +++ b/render.yaml @@ -1,29 +1,58 @@ services: - type: web - name: front + name: server runtime: image - plan: free image: - url: twentycrm/twenty-front:latest + url: twentycrm/twenty:latest + dockerCommand: "sh -c ./scripts/render-run.sh" autoDeploy: false + plan: standard envVars: - - key: REACT_APP_SERVER_BASE_URL + - key: FRONT_BASE_URL fromService: name: server type: web envVarKey: RENDER_EXTERNAL_URL -- type: web - name: server + - key: SERVER_URL + fromService: + name: server + type: web + envVarKey: RENDER_EXTERNAL_URL + - key: ACCESS_TOKEN_SECRET + generateValue: true + - key: LOGIN_TOKEN_SECRET + generateValue: true + - key: REFRESH_TOKEN_SECRET + generateValue: true + - key: FILE_TOKEN_SECRET + generateValue: true + - key: PG_DATABASE_HOST + fromService: + name: twenty_postgres + type: pserv + property: host + - key: PG_DATABASE_PORT + fromService: + name: twenty_postgres + type: pserv + property: port +- type: worker + name: worker runtime: image image: - url: twentycrm/twenty-server:latest - dockerCommand: "sh -c ./scripts/render-run.sh" + url: twentycrm/twenty:latest + dockerCommand: "sh -c ./scripts/render-worker.sh" autoDeploy: false plan: standard envVars: - key: FRONT_BASE_URL fromService: - name: front + name: server + type: web + envVarKey: RENDER_EXTERNAL_URL + - key: SERVER_URL + fromService: + name: server type: web envVarKey: RENDER_EXTERNAL_URL - key: ACCESS_TOKEN_SECRET diff --git a/yarn.lock b/yarn.lock index 7145165f5042..38f5ae31c335 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7695,6 +7695,95 @@ __metadata: languageName: node linkType: hard +"@langchain/core@npm:>0.1.56 <0.3.0, @langchain/core@npm:>=0.2.5 <0.3.0": + version: 0.2.6 + resolution: "@langchain/core@npm:0.2.6" + dependencies: + ansi-styles: "npm:^5.0.0" + camelcase: "npm:6" + decamelize: "npm:1.2.0" + js-tiktoken: "npm:^1.0.12" + langsmith: "npm:~0.1.30" + ml-distance: "npm:^4.0.0" + mustache: "npm:^4.2.0" + p-queue: "npm:^6.6.2" + p-retry: "npm:4" + uuid: "npm:^9.0.0" + zod: "npm:^3.22.4" + zod-to-json-schema: "npm:^3.22.3" + checksum: 4ae46528854f9dfc9e6e91c9351275cecc5cb4d246c8a2ae1326fbe046bb8637e5e26743e1ebd86f06f2ef12dc1741ea3f4480701be1e89ceecc5146b8c873b1 + languageName: node + linkType: hard + +"@langchain/core@npm:>0.2.0 <0.3.0, @langchain/core@npm:>=0.2.8 <0.3.0, @langchain/core@npm:~0.2.0": + version: 0.2.9 + resolution: "@langchain/core@npm:0.2.9" + dependencies: + ansi-styles: "npm:^5.0.0" + camelcase: "npm:6" + decamelize: "npm:1.2.0" + js-tiktoken: "npm:^1.0.12" + langsmith: "npm:~0.1.30" + ml-distance: "npm:^4.0.0" + mustache: "npm:^4.2.0" + p-queue: "npm:^6.6.2" + p-retry: "npm:4" + uuid: "npm:^9.0.0" + zod: "npm:^3.22.4" + zod-to-json-schema: "npm:^3.22.3" + checksum: e336b2c90d4955cc522f3295b1f2b09e89b88d483108ca89af20c88ee41f815b91a307a193d0359e5012fb348022dcafa43a7ed28a195ae74ef4ec6a59678e4d + languageName: node + linkType: hard + +"@langchain/mistralai@npm:^0.0.24": + version: 0.0.24 + resolution: "@langchain/mistralai@npm:0.0.24" + dependencies: + "@langchain/core": "npm:>0.1.56 <0.3.0" + "@mistralai/mistralai": "npm:^0.4.0" + uuid: "npm:^9.0.0" + zod: "npm:^3.22.4" + zod-to-json-schema: "npm:^3.22.4" + checksum: abbc862685dfa48e9f4418ff94843b38d779514f46d5a971dc0c98b55a44d6fe91f3610432ccc0af39496ef075fbffd3e514e4104af5968938e0270e1a07716d + languageName: node + linkType: hard + +"@langchain/openai@npm:>=0.1.0 <0.3.0": + version: 0.2.0 + resolution: "@langchain/openai@npm:0.2.0" + dependencies: + "@langchain/core": "npm:>=0.2.8 <0.3.0" + js-tiktoken: "npm:^1.0.12" + openai: "npm:^4.49.1" + zod: "npm:^3.22.4" + zod-to-json-schema: "npm:^3.22.3" + checksum: a55cf7f42f4df901049b98e592bde9ee3e4a027635b07697110f511d2ccb4118ea562cd9c9d0de0e43efe291ed18425d6f6dea47447b27ba35e756c9b969fba0 + languageName: node + linkType: hard + +"@langchain/openai@npm:^0.1.3": + version: 0.1.3 + resolution: "@langchain/openai@npm:0.1.3" + dependencies: + "@langchain/core": "npm:>=0.2.5 <0.3.0" + js-tiktoken: "npm:^1.0.12" + openai: "npm:^4.49.1" + zod: "npm:^3.22.4" + zod-to-json-schema: "npm:^3.22.3" + checksum: b693bd9d5ec118136f99279c50b531865702d0fa41479cde4ced05bb20b487cc75656761e491b380e69ff191b38b8a41e4573a485b4da42f57061adb7aa692eb + languageName: node + linkType: hard + +"@langchain/textsplitters@npm:~0.0.0": + version: 0.0.3 + resolution: "@langchain/textsplitters@npm:0.0.3" + dependencies: + "@langchain/core": "npm:>0.2.0 <0.3.0" + js-tiktoken: "npm:^1.0.12" + checksum: 3297b48f636a8a6acbd65f1465624741e6d557512ea8020a208cc6b2aa6e8d752cd08511a92ef980a06ed95858b7750a1126a4e6acfbb75fd4733e050651f405 + languageName: node + linkType: hard + "@leichtgewicht/ip-codec@npm:^2.0.1": version: 2.0.4 resolution: "@leichtgewicht/ip-codec@npm:2.0.4" @@ -7991,6 +8080,15 @@ __metadata: languageName: node linkType: hard +"@mistralai/mistralai@npm:^0.4.0": + version: 0.4.0 + resolution: "@mistralai/mistralai@npm:0.4.0" + dependencies: + node-fetch: "npm:^2.6.7" + checksum: 1857ceb56f9119e8248ebb3947f8ee1da6e0731aeced38e1de44823448376ddc733182dd782e50a0e448ddd6b01789bd9dc622e0594e7a354af302a06ced77e7 + languageName: node + linkType: hard + "@mole-inc/bin-wrapper@npm:^8.0.1": version: 8.0.1 resolution: "@mole-inc/bin-wrapper@npm:8.0.1" @@ -8650,6 +8748,13 @@ __metadata: languageName: node linkType: hard +"@next/env@npm:14.2.4": + version: 14.2.4 + resolution: "@next/env@npm:14.2.4" + checksum: cc284e3dd0666df04d8321645d8409c10cb8e325884c226abbb2e7bea20f0a4232f988216aa506a9d0457b46f28b594a61179d1e978c0ca22497cd8cab8196c7 + languageName: node + linkType: hard + "@next/eslint-plugin-next@npm:14.0.4": version: 14.0.4 resolution: "@next/eslint-plugin-next@npm:14.0.4" @@ -8675,6 +8780,13 @@ __metadata: languageName: node linkType: hard +"@next/swc-darwin-arm64@npm:14.2.4": + version: 14.2.4 + resolution: "@next/swc-darwin-arm64@npm:14.2.4" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + "@next/swc-darwin-x64@npm:14.0.4": version: 14.0.4 resolution: "@next/swc-darwin-x64@npm:14.0.4" @@ -8682,6 +8794,13 @@ __metadata: languageName: node linkType: hard +"@next/swc-darwin-x64@npm:14.2.4": + version: 14.2.4 + resolution: "@next/swc-darwin-x64@npm:14.2.4" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + "@next/swc-linux-arm64-gnu@npm:14.0.4": version: 14.0.4 resolution: "@next/swc-linux-arm64-gnu@npm:14.0.4" @@ -8689,6 +8808,13 @@ __metadata: languageName: node linkType: hard +"@next/swc-linux-arm64-gnu@npm:14.2.4": + version: 14.2.4 + resolution: "@next/swc-linux-arm64-gnu@npm:14.2.4" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + "@next/swc-linux-arm64-musl@npm:14.0.4": version: 14.0.4 resolution: "@next/swc-linux-arm64-musl@npm:14.0.4" @@ -8696,6 +8822,13 @@ __metadata: languageName: node linkType: hard +"@next/swc-linux-arm64-musl@npm:14.2.4": + version: 14.2.4 + resolution: "@next/swc-linux-arm64-musl@npm:14.2.4" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + "@next/swc-linux-x64-gnu@npm:14.0.4": version: 14.0.4 resolution: "@next/swc-linux-x64-gnu@npm:14.0.4" @@ -8703,6 +8836,13 @@ __metadata: languageName: node linkType: hard +"@next/swc-linux-x64-gnu@npm:14.2.4": + version: 14.2.4 + resolution: "@next/swc-linux-x64-gnu@npm:14.2.4" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + "@next/swc-linux-x64-musl@npm:14.0.4": version: 14.0.4 resolution: "@next/swc-linux-x64-musl@npm:14.0.4" @@ -8710,6 +8850,13 @@ __metadata: languageName: node linkType: hard +"@next/swc-linux-x64-musl@npm:14.2.4": + version: 14.2.4 + resolution: "@next/swc-linux-x64-musl@npm:14.2.4" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + "@next/swc-win32-arm64-msvc@npm:14.0.4": version: 14.0.4 resolution: "@next/swc-win32-arm64-msvc@npm:14.0.4" @@ -8717,6 +8864,13 @@ __metadata: languageName: node linkType: hard +"@next/swc-win32-arm64-msvc@npm:14.2.4": + version: 14.2.4 + resolution: "@next/swc-win32-arm64-msvc@npm:14.2.4" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + "@next/swc-win32-ia32-msvc@npm:14.0.4": version: 14.0.4 resolution: "@next/swc-win32-ia32-msvc@npm:14.0.4" @@ -8724,6 +8878,13 @@ __metadata: languageName: node linkType: hard +"@next/swc-win32-ia32-msvc@npm:14.2.4": + version: 14.2.4 + resolution: "@next/swc-win32-ia32-msvc@npm:14.2.4" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + "@next/swc-win32-x64-msvc@npm:14.0.4": version: 14.0.4 resolution: "@next/swc-win32-x64-msvc@npm:14.0.4" @@ -8731,6 +8892,13 @@ __metadata: languageName: node linkType: hard +"@next/swc-win32-x64-msvc@npm:14.2.4": + version: 14.2.4 + resolution: "@next/swc-win32-x64-msvc@npm:14.2.4" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + "@nivo/calendar@npm:^0.84.0": version: 0.84.0 resolution: "@nivo/calendar@npm:0.84.0" @@ -15630,6 +15798,16 @@ __metadata: languageName: node linkType: hard +"@swc/helpers@npm:0.5.5": + version: 0.5.5 + resolution: "@swc/helpers@npm:0.5.5" + dependencies: + "@swc/counter": "npm:^0.1.3" + tslib: "npm:^2.4.0" + checksum: 21a9b9cfe7e00865f9c9f3eb4c1cc5b397143464f7abee76a2c5366e591e06b0155b5aac93fe8269ef8d548df253f6fd931e9ddfc0fd12efd405f90f45506e7d + languageName: node + linkType: hard + "@swc/helpers@npm:~0.5.0": version: 0.5.3 resolution: "@swc/helpers@npm:0.5.3" @@ -17265,6 +17443,15 @@ __metadata: languageName: node linkType: hard +"@types/lodash.chunk@npm:^4.2.9": + version: 4.2.9 + resolution: "@types/lodash.chunk@npm:4.2.9" + dependencies: + "@types/lodash": "npm:*" + checksum: 5759b3d969c5db4b0893b70261ae40d4b9a6466c984c16de6fa1d3945b3199cc09f948a444a3b4e6cfa0dd984044cf937cbc8dab5fe0ac8da67244ed74d9e4e4 + languageName: node + linkType: hard + "@types/lodash.compact@npm:^3.0.9": version: 3.0.9 resolution: "@types/lodash.compact@npm:3.0.9" @@ -17382,6 +17569,15 @@ __metadata: languageName: node linkType: hard +"@types/lodash.omitby@npm:^4.6.9": + version: 4.6.9 + resolution: "@types/lodash.omitby@npm:4.6.9" + dependencies: + "@types/lodash": "npm:*" + checksum: e8850219326634c5b531e3398d24701000328e4366504d9315c1660c2fe2a0d4fc9aa2983b8c652ee7239921cd16103b37b1e44efdf25658de2a36f64b76888a + languageName: node + linkType: hard + "@types/lodash.pick@npm:^4.3.7": version: 4.4.9 resolution: "@types/lodash.pick@npm:4.4.9" @@ -17614,6 +17810,15 @@ __metadata: languageName: node linkType: hard +"@types/node@npm:^18.11.18": + version: 18.19.34 + resolution: "@types/node@npm:18.19.34" + dependencies: + undici-types: "npm:~5.26.4" + checksum: e985f50684def801801069e236165ee511f9195fc04ad4a2af7642d86aeaeaf7bfe34c147f894a48618a5c71c15b388ca91341a244792149543a712e38351988 + languageName: node + linkType: hard + "@types/nodemailer@npm:^6.4.14": version: 6.4.14 resolution: "@types/nodemailer@npm:6.4.14" @@ -19171,6 +19376,15 @@ __metadata: languageName: node linkType: hard +"abort-controller@npm:^3.0.0": + version: 3.0.0 + resolution: "abort-controller@npm:3.0.0" + dependencies: + event-target-shim: "npm:^5.0.0" + checksum: 90ccc50f010250152509a344eb2e71977fbf8db0ab8f1061197e3275ddf6c61a41a6edfd7b9409c664513131dd96e962065415325ef23efa5db931b382d24ca5 + languageName: node + linkType: hard + "accepts@npm:^1.3.5, accepts@npm:~1.3.4, accepts@npm:~1.3.5, accepts@npm:~1.3.8": version: 1.3.8 resolution: "accepts@npm:1.3.8" @@ -21495,7 +21709,7 @@ __metadata: languageName: node linkType: hard -"base64-js@npm:^1.0.2, base64-js@npm:^1.3.0, base64-js@npm:^1.3.1": +"base64-js@npm:^1.0.2, base64-js@npm:^1.3.0, base64-js@npm:^1.3.1, base64-js@npm:^1.5.1": version: 1.5.1 resolution: "base64-js@npm:1.5.1" checksum: f23823513b63173a001030fae4f2dabe283b99a9d324ade3ad3d148e218134676f1ee8568c877cd79ec1c53158dcf2d2ba527a97c606618928ba99dd930102bf @@ -21644,6 +21858,20 @@ __metadata: languageName: node linkType: hard +"binary-extensions@npm:^2.2.0": + version: 2.3.0 + resolution: "binary-extensions@npm:2.3.0" + checksum: 75a59cafc10fb12a11d510e77110c6c7ae3f4ca22463d52487709ca7f18f69d886aa387557cc9864fbdb10153d0bdb4caacabf11541f55e89ed6e18d12ece2b5 + languageName: node + linkType: hard + +"binary-search@npm:^1.3.5": + version: 1.3.6 + resolution: "binary-search@npm:1.3.6" + checksum: 786a770e3411cf563c9c7829e2854d79583a207b8faaa5022f93352893e1d06035ae5d80de1b168dcbd9d346fdb0dd2e3d7fcdf309b3a63dc027e92624da32a0 + languageName: node + linkType: hard + "binaryextensions@npm:^4.15.0, binaryextensions@npm:^4.16.0": version: 4.19.0 resolution: "binaryextensions@npm:4.19.0" @@ -22476,6 +22704,13 @@ __metadata: languageName: node linkType: hard +"camelcase@npm:6, camelcase@npm:^6.2.0": + version: 6.3.0 + resolution: "camelcase@npm:6.3.0" + checksum: 0d701658219bd3116d12da3eab31acddb3f9440790c0792e0d398f0a520a6a4058018e546862b6fba89d7ae990efaeb97da71e1913e9ebf5a8b5621a3d55c710 + languageName: node + linkType: hard + "camelcase@npm:^5.0.0, camelcase@npm:^5.3.1": version: 5.3.1 resolution: "camelcase@npm:5.3.1" @@ -22483,13 +22718,6 @@ __metadata: languageName: node linkType: hard -"camelcase@npm:^6.2.0": - version: 6.3.0 - resolution: "camelcase@npm:6.3.0" - checksum: 0d701658219bd3116d12da3eab31acddb3f9440790c0792e0d398f0a520a6a4058018e546862b6fba89d7ae990efaeb97da71e1913e9ebf5a8b5621a3d55c710 - languageName: node - linkType: hard - "camelcase@npm:^7.0.1": version: 7.0.1 resolution: "camelcase@npm:7.0.1" @@ -22518,24 +22746,17 @@ __metadata: languageName: node linkType: hard -"caniuse-lite@npm:^1.0.0, caniuse-lite@npm:^1.0.30001538, caniuse-lite@npm:^1.0.30001565": - version: 1.0.30001568 - resolution: "caniuse-lite@npm:1.0.30001568" - checksum: 13f01e5a2481134bd61cf565ce9fecbd8e107902927a0dcf534230a92191a81f1715792170f5f39719c767c3a96aa6df9917a8d5601f15bbd5e4041a8cfecc99 - languageName: node - linkType: hard - -"caniuse-lite@npm:^1.0.30001406": - version: 1.0.30001571 - resolution: "caniuse-lite@npm:1.0.30001571" - checksum: 632f476e39febbfb5dc91c236981f3d518dc0cf55c42cc2bba431a6b6f4cceae3f9cd74d26312f30e9de65a3cc92ccf80d964ba8de061e25f37b7f0518303dad +"caniuse-lite@npm:^1.0.0, caniuse-lite@npm:^1.0.30001406, caniuse-lite@npm:^1.0.30001538, caniuse-lite@npm:^1.0.30001565, caniuse-lite@npm:^1.0.30001587": + version: 1.0.30001636 + resolution: "caniuse-lite@npm:1.0.30001636" + checksum: e5f965b4da7bae1531fd9f93477d015729ff9e3fa12670ead39a9e6cdc4c43e62c272d47857c5cc332e7b02d697cb3f2f965a1030870ac7476da60c2fc81ee94 languageName: node linkType: hard -"caniuse-lite@npm:^1.0.30001587": - version: 1.0.30001589 - resolution: "caniuse-lite@npm:1.0.30001589" - checksum: 20debfb949413f603011bc7dacaf050010778bc4f8632c86fafd1bd0c43180c95ae7c31f6c82348f6309e5e221934e327c3607a216e3f09640284acf78cd6d4d +"caniuse-lite@npm:^1.0.30001579": + version: 1.0.30001640 + resolution: "caniuse-lite@npm:1.0.30001640" + checksum: d87fce999e52c354029893a23887d2e48ac297e3af55bd14161fcafdd711f97bdb2649c79d2d3049e628603cb59bc4257ca2961644b0b8d206e7b7dd126d37ea languageName: node linkType: hard @@ -23573,7 +23794,7 @@ __metadata: languageName: node linkType: hard -"commander@npm:^10.0.0": +"commander@npm:^10.0.0, commander@npm:^10.0.1": version: 10.0.1 resolution: "commander@npm:10.0.1" checksum: 53f33d8927758a911094adadda4b2cbac111a5b377d8706700587650fd8f45b0bbe336de4b5c3fe47fd61f420a3d9bd452b6e0e6e5600a7e74d7bf0174f6efe3 @@ -25096,7 +25317,7 @@ __metadata: languageName: node linkType: hard -"decamelize@npm:^1.2.0": +"decamelize@npm:1.2.0, decamelize@npm:^1.2.0": version: 1.2.0 resolution: "decamelize@npm:1.2.0" checksum: 85c39fe8fbf0482d4a1e224ef0119db5c1897f8503bcef8b826adff7a1b11414972f6fef2d7dec2ee0b4be3863cf64ac1439137ae9e6af23a3d8dcbe26a5b4b2 @@ -27553,6 +27774,13 @@ __metadata: languageName: node linkType: hard +"event-target-shim@npm:^5.0.0": + version: 5.0.1 + resolution: "event-target-shim@npm:5.0.1" + checksum: 0255d9f936215fd206156fd4caa9e8d35e62075d720dc7d847e89b417e5e62cf1ce6c9b4e0a1633a9256de0efefaf9f8d26924b1f3c8620cffb9db78e7d3076b + languageName: node + linkType: hard + "eventemitter2@npm:6.4.9": version: 6.4.9 resolution: "eventemitter2@npm:6.4.9" @@ -28653,6 +28881,13 @@ __metadata: languageName: node linkType: hard +"form-data-encoder@npm:1.7.2": + version: 1.7.2 + resolution: "form-data-encoder@npm:1.7.2" + checksum: 56553768037b6d55d9de524f97fe70555f0e415e781cb56fc457a68263de3d40fadea2304d4beef2d40b1a851269bd7854e42c362107071892cb5238debe9464 + languageName: node + linkType: hard + "form-data-encoder@npm:^2.1.2": version: 2.1.4 resolution: "form-data-encoder@npm:2.1.4" @@ -28689,7 +28924,7 @@ __metadata: languageName: node linkType: hard -"formdata-node@npm:^4.4.1": +"formdata-node@npm:^4.3.2, formdata-node@npm:^4.4.1": version: 4.4.1 resolution: "formdata-node@npm:4.4.1" dependencies: @@ -29108,6 +29343,7 @@ __metadata: "@types/jest": "npm:^29.5.11" "@types/js-cookie": "npm:^3.0.3" "@types/lodash.camelcase": "npm:^4.3.7" + "@types/lodash.chunk": "npm:^4.2.9" "@types/lodash.compact": "npm:^3.0.9" "@types/lodash.debounce": "npm:^4.0.7" "@types/lodash.groupby": "npm:^4.6.9" @@ -29219,6 +29455,7 @@ __metadata: jsonwebtoken: "npm:^9.0.0" libphonenumber-js: "npm:^1.10.26" lodash.camelcase: "npm:^4.3.0" + lodash.chunk: "npm:^4.2.0" lodash.compact: "npm:^3.0.1" lodash.debounce: "npm:^4.0.8" lodash.groupby: "npm:^4.6.0" @@ -32135,6 +32372,13 @@ __metadata: languageName: node linkType: hard +"is-any-array@npm:^2.0.0": + version: 2.0.1 + resolution: "is-any-array@npm:2.0.1" + checksum: f9807458a51e63ca1ac27fd6f3a3ace8200f077094e00d9b05b24cfbc9d5594d586d6ecf3416271f26939d5cb93fc52ca869cb5744e77318c3f53ec70b08d61f + languageName: node + linkType: hard + "is-arguments@npm:^1.0.4, is-arguments@npm:^1.1.1": version: 1.1.1 resolution: "is-arguments@npm:1.1.1" @@ -33884,6 +34128,15 @@ __metadata: languageName: node linkType: hard +"js-tiktoken@npm:^1.0.12": + version: 1.0.12 + resolution: "js-tiktoken@npm:1.0.12" + dependencies: + base64-js: "npm:^1.5.1" + checksum: 7afb4826e21342386a1884754fbc1c1828f948c4dd0ab093bf778d1323e65343bd5343d15f7cda46af396f1fe4a0297739936149b7c40a0601eefe3fcaef8727 + languageName: node + linkType: hard + "js-tokens@npm:^3.0.0 || ^4.0.0, js-tokens@npm:^4.0.0": version: 4.0.0 resolution: "js-tokens@npm:4.0.0" @@ -34360,7 +34613,7 @@ __metadata: languageName: node linkType: hard -"jsonpointer@npm:^5.0.0": +"jsonpointer@npm:^5.0.0, jsonpointer@npm:^5.0.1": version: 5.0.1 resolution: "jsonpointer@npm:5.0.1" checksum: 89929e58b400fcb96928c0504fcf4fc3f919d81e9543ceb055df125538470ee25290bb4984251e172e6ef8fcc55761eb998c118da763a82051ad89d4cb073fe7 @@ -34560,6 +34813,242 @@ __metadata: languageName: node linkType: hard +"langchain@npm:^0.2.6": + version: 0.2.6 + resolution: "langchain@npm:0.2.6" + dependencies: + "@langchain/core": "npm:~0.2.0" + "@langchain/openai": "npm:>=0.1.0 <0.3.0" + "@langchain/textsplitters": "npm:~0.0.0" + binary-extensions: "npm:^2.2.0" + js-tiktoken: "npm:^1.0.12" + js-yaml: "npm:^4.1.0" + jsonpointer: "npm:^5.0.1" + langchainhub: "npm:~0.0.8" + langsmith: "npm:~0.1.30" + ml-distance: "npm:^4.0.0" + openapi-types: "npm:^12.1.3" + p-retry: "npm:4" + uuid: "npm:^9.0.0" + yaml: "npm:^2.2.1" + zod: "npm:^3.22.4" + zod-to-json-schema: "npm:^3.22.3" + peerDependencies: + "@aws-sdk/client-s3": ^3.310.0 + "@aws-sdk/client-sagemaker-runtime": ^3.310.0 + "@aws-sdk/client-sfn": ^3.310.0 + "@aws-sdk/credential-provider-node": ^3.388.0 + "@azure/storage-blob": ^12.15.0 + "@browserbasehq/sdk": "*" + "@gomomento/sdk": ^1.51.1 + "@gomomento/sdk-core": ^1.51.1 + "@gomomento/sdk-web": ^1.51.1 + "@mendable/firecrawl-js": ^0.0.13 + "@notionhq/client": ^2.2.10 + "@pinecone-database/pinecone": "*" + "@supabase/supabase-js": ^2.10.0 + "@vercel/kv": ^0.2.3 + "@xata.io/client": ^0.28.0 + apify-client: ^2.7.1 + assemblyai: ^4.0.0 + axios: "*" + cheerio: ^1.0.0-rc.12 + chromadb: "*" + convex: ^1.3.1 + couchbase: ^4.3.0 + d3-dsv: ^2.0.0 + epub2: ^3.0.1 + fast-xml-parser: "*" + handlebars: ^4.7.8 + html-to-text: ^9.0.5 + ignore: ^5.2.0 + ioredis: ^5.3.2 + jsdom: "*" + mammoth: ^1.6.0 + mongodb: ">=5.2.0" + node-llama-cpp: "*" + notion-to-md: ^3.1.0 + officeparser: ^4.0.4 + pdf-parse: 1.1.1 + peggy: ^3.0.2 + playwright: ^1.32.1 + puppeteer: ^19.7.2 + pyodide: ^0.24.1 + redis: ^4.6.4 + sonix-speech-recognition: ^2.1.1 + srt-parser-2: ^1.2.3 + typeorm: ^0.3.20 + weaviate-ts-client: "*" + web-auth-library: ^1.0.3 + ws: ^8.14.2 + youtube-transcript: ^1.0.6 + youtubei.js: ^9.1.0 + peerDependenciesMeta: + "@aws-sdk/client-s3": + optional: true + "@aws-sdk/client-sagemaker-runtime": + optional: true + "@aws-sdk/client-sfn": + optional: true + "@aws-sdk/credential-provider-node": + optional: true + "@azure/storage-blob": + optional: true + "@browserbasehq/sdk": + optional: true + "@gomomento/sdk": + optional: true + "@gomomento/sdk-core": + optional: true + "@gomomento/sdk-web": + optional: true + "@mendable/firecrawl-js": + optional: true + "@notionhq/client": + optional: true + "@pinecone-database/pinecone": + optional: true + "@supabase/supabase-js": + optional: true + "@vercel/kv": + optional: true + "@xata.io/client": + optional: true + apify-client: + optional: true + assemblyai: + optional: true + axios: + optional: true + cheerio: + optional: true + chromadb: + optional: true + convex: + optional: true + couchbase: + optional: true + d3-dsv: + optional: true + epub2: + optional: true + faiss-node: + optional: true + fast-xml-parser: + optional: true + handlebars: + optional: true + html-to-text: + optional: true + ignore: + optional: true + ioredis: + optional: true + jsdom: + optional: true + mammoth: + optional: true + mongodb: + optional: true + node-llama-cpp: + optional: true + notion-to-md: + optional: true + officeparser: + optional: true + pdf-parse: + optional: true + peggy: + optional: true + playwright: + optional: true + puppeteer: + optional: true + pyodide: + optional: true + redis: + optional: true + sonix-speech-recognition: + optional: true + srt-parser-2: + optional: true + typeorm: + optional: true + weaviate-ts-client: + optional: true + web-auth-library: + optional: true + ws: + optional: true + youtube-transcript: + optional: true + youtubei.js: + optional: true + checksum: c267d618f20b75eeba0c13b3ee9aaa8e7a57d87d64344c4360d7332bdda82c6976c80c705a81a0be02006f350b2f42142ca98a7b71148ee0aa934a592ddbc47a + languageName: node + linkType: hard + +"langchainhub@npm:~0.0.8": + version: 0.0.11 + resolution: "langchainhub@npm:0.0.11" + checksum: 6ed781b9e8165bfb5cedc822a25bc70df0f3fc02662061d19a5e2044243cfae797857a05d139de8f326539b1f3fe03f2662060eed82669e405181f1f0f435c47 + languageName: node + linkType: hard + +"langfuse-core@npm:^3.11.2": + version: 3.11.2 + resolution: "langfuse-core@npm:3.11.2" + dependencies: + mustache: "npm:^4.2.0" + checksum: 341cddedf16cf0c4b980989c4ee4daa6be0dad7a37349d86ff7b3fcf4e2e35e25318fb9ec6e4c9d27023031c7e780d50d75493f7cf9911938b6581ee2c1728c6 + languageName: node + linkType: hard + +"langfuse-langchain@npm:^3.11.2": + version: 3.11.2 + resolution: "langfuse-langchain@npm:3.11.2" + dependencies: + langfuse: "npm:^3.11.2" + langfuse-core: "npm:^3.11.2" + peerDependencies: + langchain: ">=0.0.157 <0.3.0" + checksum: ec57481128b4b738ee4e146b0f0c42e94d0f75d5a525a031407d7ecd8ffcd50dc9730f580901ed2432694555e544459e032e9181af9d853a156aef42c3ef9b41 + languageName: node + linkType: hard + +"langfuse@npm:^3.11.2": + version: 3.11.2 + resolution: "langfuse@npm:3.11.2" + dependencies: + langfuse-core: "npm:^3.11.2" + checksum: e74053aa5bb3e62a91d3c7a5f95c86f9808342ca9a0dcda5c5a33bf8abf8ace70357f84db7fae36e93d722e9aa383b55ced785e6d6cbf23d47d0252b1fef57b0 + languageName: node + linkType: hard + +"langsmith@npm:~0.1.30": + version: 0.1.30 + resolution: "langsmith@npm:0.1.30" + dependencies: + "@types/uuid": "npm:^9.0.1" + commander: "npm:^10.0.1" + p-queue: "npm:^6.6.2" + p-retry: "npm:4" + uuid: "npm:^9.0.0" + peerDependencies: + "@langchain/core": "*" + langchain: "*" + openai: "*" + peerDependenciesMeta: + "@langchain/core": + optional: true + langchain: + optional: true + openai: + optional: true + checksum: 181719d73bd89918f0ab60768f824449e2bfd5a691242c3540291114053ba6e49ce4670bfa0abd129dd7556f80b3025371ba9cd1884090dc1941fdf39850545c + languageName: node + linkType: hard + "language-subtag-registry@npm:^0.3.20": version: 0.3.22 resolution: "language-subtag-registry@npm:0.3.22" @@ -34867,6 +35356,13 @@ __metadata: languageName: node linkType: hard +"lodash.chunk@npm:^4.2.0": + version: 4.2.0 + resolution: "lodash.chunk@npm:4.2.0" + checksum: f9f99969561ad2f62af1f9a96c5bd0af776f000292b0d8db3126c28eb3b32e210d7c31b49c18d0d7901869bd769057046dc134b60cfa0c2c4ce017823a26bb23 + languageName: node + linkType: hard + "lodash.clonedeep@npm:^4.5.0": version: 4.5.0 resolution: "lodash.clonedeep@npm:4.5.0" @@ -35091,6 +35587,13 @@ __metadata: languageName: node linkType: hard +"lodash.omitby@npm:^4.6.0": + version: 4.6.0 + resolution: "lodash.omitby@npm:4.6.0" + checksum: 4608b1d8c4063b63349a3462852465fbe74781d737fbb26a0a7f00b0e65f6ccbc13fa490a38f9380103d93fc398e3873983038efadfafc67ccafbb25d9bc7bf4 + languageName: node + linkType: hard + "lodash.once@npm:^4.0.0": version: 4.1.1 resolution: "lodash.once@npm:4.1.1" @@ -37936,6 +38439,52 @@ __metadata: languageName: node linkType: hard +"ml-array-mean@npm:^1.1.6": + version: 1.1.6 + resolution: "ml-array-mean@npm:1.1.6" + dependencies: + ml-array-sum: "npm:^1.1.6" + checksum: 41ab68308e3472702f775a49c8ab9ee1e678e01cd59dbc59424c0f1017a37df1bb638e702831305f0e6366300eca48353f526773ab8f4d8d142a64d0461f9944 + languageName: node + linkType: hard + +"ml-array-sum@npm:^1.1.6": + version: 1.1.6 + resolution: "ml-array-sum@npm:1.1.6" + dependencies: + is-any-array: "npm:^2.0.0" + checksum: fb3973ce2bfa19ab4f5e657f722494425b57025547657d332bf5bafe3e4e7e4bd1e082dfb970bcc0bfa87efa345b80a20a596dbb204be7b4802b52c35fd6cf77 + languageName: node + linkType: hard + +"ml-distance-euclidean@npm:^2.0.0": + version: 2.0.0 + resolution: "ml-distance-euclidean@npm:2.0.0" + checksum: 877aef472e134f79be9540b02f889b2a27976ca45d77f5d4ef7d8dd24058a60cf4637365b40a5aba1ab5490348a0fb1b3803143b25af88cdc66137fbfd665442 + languageName: node + linkType: hard + +"ml-distance@npm:^4.0.0": + version: 4.0.1 + resolution: "ml-distance@npm:4.0.1" + dependencies: + ml-array-mean: "npm:^1.1.6" + ml-distance-euclidean: "npm:^2.0.0" + ml-tree-similarity: "npm:^1.0.0" + checksum: 8c2eb077d2ba61437f2414f3b9ca1091c43fcabe2282ecc31d8ebf9e083c1df068e43c67f59a4674e7c8f473201ace4f02779b446427d6169a5d669cae94c816 + languageName: node + linkType: hard + +"ml-tree-similarity@npm:^1.0.0": + version: 1.0.0 + resolution: "ml-tree-similarity@npm:1.0.0" + dependencies: + binary-search: "npm:^1.3.5" + num-sort: "npm:^2.0.0" + checksum: e3ecd07bead5d18bc7b6fed1dfefbe65aea4008d5556181b94b7d70550fba543d2501b224f12a9f5197c1d23d95faef2accc7fd265c5afd15ef55a38190ffc6e + languageName: node + linkType: hard + "mlly@npm:^1.2.0, mlly@npm:^1.4.2": version: 1.6.1 resolution: "mlly@npm:1.6.1" @@ -38162,6 +38711,15 @@ __metadata: languageName: node linkType: hard +"mustache@npm:^4.2.0": + version: 4.2.0 + resolution: "mustache@npm:4.2.0" + bin: + mustache: bin/mustache + checksum: 1f8197e8a19e63645a786581d58c41df7853da26702dbc005193e2437c98ca49b255345c173d50c08fe4b4dbb363e53cb655ecc570791f8deb09887248dd34a2 + languageName: node + linkType: hard + "mute-stream@npm:0.0.8": version: 0.0.8 resolution: "mute-stream@npm:0.0.8" @@ -38305,6 +38863,19 @@ __metadata: languageName: node linkType: hard +"next-runtime-env@npm:^3.2.2": + version: 3.2.2 + resolution: "next-runtime-env@npm:3.2.2" + dependencies: + next: "npm:^14" + react: "npm:^18" + peerDependencies: + next: ^14 + react: ^18 + checksum: 9ac2649fd765b82f340af5d77083f851a4e865acc9e32e9df092ba06cf5f4066b94ee7a3994677ef362d59802457f5becad8d49f3c9a75e77b68179e65c5ecee + languageName: node + linkType: hard + "next-tick@npm:1, next-tick@npm:^1.1.0": version: 1.1.0 resolution: "next-tick@npm:1.1.0" @@ -38368,6 +38939,64 @@ __metadata: languageName: node linkType: hard +"next@npm:^14": + version: 14.2.4 + resolution: "next@npm:14.2.4" + dependencies: + "@next/env": "npm:14.2.4" + "@next/swc-darwin-arm64": "npm:14.2.4" + "@next/swc-darwin-x64": "npm:14.2.4" + "@next/swc-linux-arm64-gnu": "npm:14.2.4" + "@next/swc-linux-arm64-musl": "npm:14.2.4" + "@next/swc-linux-x64-gnu": "npm:14.2.4" + "@next/swc-linux-x64-musl": "npm:14.2.4" + "@next/swc-win32-arm64-msvc": "npm:14.2.4" + "@next/swc-win32-ia32-msvc": "npm:14.2.4" + "@next/swc-win32-x64-msvc": "npm:14.2.4" + "@swc/helpers": "npm:0.5.5" + busboy: "npm:1.6.0" + caniuse-lite: "npm:^1.0.30001579" + graceful-fs: "npm:^4.2.11" + postcss: "npm:8.4.31" + styled-jsx: "npm:5.1.1" + peerDependencies: + "@opentelemetry/api": ^1.1.0 + "@playwright/test": ^1.41.2 + react: ^18.2.0 + react-dom: ^18.2.0 + sass: ^1.3.0 + dependenciesMeta: + "@next/swc-darwin-arm64": + optional: true + "@next/swc-darwin-x64": + optional: true + "@next/swc-linux-arm64-gnu": + optional: true + "@next/swc-linux-arm64-musl": + optional: true + "@next/swc-linux-x64-gnu": + optional: true + "@next/swc-linux-x64-musl": + optional: true + "@next/swc-win32-arm64-msvc": + optional: true + "@next/swc-win32-ia32-msvc": + optional: true + "@next/swc-win32-x64-msvc": + optional: true + peerDependenciesMeta: + "@opentelemetry/api": + optional: true + "@playwright/test": + optional: true + sass: + optional: true + bin: + next: dist/bin/next + checksum: 630c2a197b57c1f29caf4672a0f8fb74dbb048e77e4513f567279467332212f3eebcb68279885f1d525d7aaebbb452f522b02c0b5cd3ca66f385341e4b4eac67 + languageName: node + linkType: hard + "nice-napi@npm:^1.0.2": version: 1.0.2 resolution: "nice-napi@npm:1.0.2" @@ -39029,6 +39658,13 @@ __metadata: languageName: node linkType: hard +"num-sort@npm:^2.0.0": + version: 2.1.0 + resolution: "num-sort@npm:2.1.0" + checksum: cc1d43adbc9adfd5d208a8eb653827277376ff2e6eb75379f96e6a23d481040e317e63505e075b84ce49e19b9d960570646096428a715d12c5ef1381504d5135 + languageName: node + linkType: hard + "number-is-nan@npm:^1.0.0": version: 1.0.1 resolution: "number-is-nan@npm:1.0.1" @@ -39421,6 +40057,24 @@ __metadata: languageName: node linkType: hard +"openai@npm:^4.49.1": + version: 4.51.0 + resolution: "openai@npm:4.51.0" + dependencies: + "@types/node": "npm:^18.11.18" + "@types/node-fetch": "npm:^2.6.4" + abort-controller: "npm:^3.0.0" + agentkeepalive: "npm:^4.2.1" + form-data-encoder: "npm:1.7.2" + formdata-node: "npm:^4.3.2" + node-fetch: "npm:^2.6.7" + web-streams-polyfill: "npm:^3.2.1" + bin: + openai: bin/cli + checksum: c9adcca092aa528fe3556d9e91e022f67515e76c31ee6899d781b5bf17fbfd783e7aca15da4b6dca4bed53d12da021973789f5ae584d2769c5c560976939c45b + languageName: node + linkType: hard + "openapi-types@npm:^12.1.3": version: 12.1.3 resolution: "openapi-types@npm:12.1.3" @@ -39735,7 +40389,7 @@ __metadata: languageName: node linkType: hard -"p-retry@npm:^4.5.0": +"p-retry@npm:4, p-retry@npm:^4.5.0": version: 4.6.2 resolution: "p-retry@npm:4.6.2" dependencies: @@ -47497,6 +48151,8 @@ __metadata: resolution: "twenty-server@workspace:packages/twenty-server" dependencies: "@graphql-yoga/nestjs": "patch:@graphql-yoga/nestjs@2.1.0#./patches/@graphql-yoga-nestjs-npm-2.1.0-cb509e6047.patch" + "@langchain/mistralai": "npm:^0.0.24" + "@langchain/openai": "npm:^0.1.3" "@nestjs/cache-manager": "npm:^2.2.1" "@nestjs/cli": "npm:10.3.0" "@nestjs/devtools-integration": "npm:^0.1.6" @@ -47508,6 +48164,7 @@ __metadata: "@types/lodash.isequal": "npm:^4.5.8" "@types/lodash.isobject": "npm:^3.0.7" "@types/lodash.omit": "npm:^4.5.9" + "@types/lodash.omitby": "npm:^4.6.9" "@types/lodash.snakecase": "npm:^4.1.7" "@types/lodash.uniq": "npm:^4.5.9" "@types/lodash.uniqby": "npm:^4.7.9" @@ -47519,7 +48176,10 @@ __metadata: graphql-middleware: "npm:^6.1.35" jsdom: "npm:~22.1.0" jwt-decode: "npm:^4.0.0" + langchain: "npm:^0.2.6" + langfuse-langchain: "npm:^3.11.2" lodash.differencewith: "npm:^4.5.0" + lodash.omitby: "npm:^4.6.0" lodash.uniq: "npm:^4.5.0" lodash.uniqby: "npm:^4.7.0" passport: "npm:^0.7.0" @@ -47527,6 +48187,7 @@ __metadata: rimraf: "npm:^5.0.5" tsconfig-paths: "npm:^4.2.0" typescript: "npm:5.3.3" + zod-to-json-schema: "npm:^3.23.1" languageName: unknown linkType: soft @@ -47546,6 +48207,7 @@ __metadata: version: 0.0.0-use.local resolution: "twenty-website@workspace:packages/twenty-website" dependencies: + next-runtime-env: "npm:^3.2.2" postgres: "npm:^3.4.3" languageName: unknown linkType: soft @@ -50302,6 +50964,15 @@ __metadata: languageName: node linkType: hard +"yaml@npm:^2.2.1": + version: 2.4.5 + resolution: "yaml@npm:2.4.5" + bin: + yaml: bin.mjs + checksum: e1ee78b381e5c710f715cc4082fd10fc82f7f5c92bd6f075771d20559e175616f56abf1c411f545ea0e9e16e4f84a83a50b42764af5f16ec006328ba9476bb31 + languageName: node + linkType: hard + "yaml@npm:^2.2.2, yaml@npm:^2.3.4": version: 2.3.4 resolution: "yaml@npm:2.3.4" @@ -50634,7 +51305,25 @@ __metadata: languageName: node linkType: hard -"zod@npm:3.23.8": +"zod-to-json-schema@npm:^3.22.3, zod-to-json-schema@npm:^3.22.4": + version: 3.23.0 + resolution: "zod-to-json-schema@npm:3.23.0" + peerDependencies: + zod: ^3.23.3 + checksum: bcd966fa040765d7170a89c0c5f1717575e7d8823b84cbbb606689d494ae308c9eaadd4b71a74752e3170deef64c1f1bb2985f4663c44a0ed2e7854ff6fda724 + languageName: node + linkType: hard + +"zod-to-json-schema@npm:^3.23.1": + version: 3.23.1 + resolution: "zod-to-json-schema@npm:3.23.1" + peerDependencies: + zod: ^3.23.3 + checksum: d48d733f7cba9fdc631ebe3dada3f48b820a16e49f7ded9f363cccafa42461ff95cc7afcf974c27af7cd6d5fa5191212bb7ec15ec203bcb61f829a6d0d3e192f + languageName: node + linkType: hard + +"zod@npm:3.23.8, zod@npm:^3.22.4": version: 3.23.8 resolution: "zod@npm:3.23.8" checksum: 8f14c87d6b1b53c944c25ce7a28616896319d95bc46a9660fe441adc0ed0a81253b02b5abdaeffedbeb23bdd25a0bf1c29d2c12dd919aef6447652dd295e3e69