diff --git a/.github/workflows/ci-front.yaml b/.github/workflows/ci-front.yaml
index aa6955723796..b61506709f93 100644
--- a/.github/workflows/ci-front.yaml
+++ b/.github/workflows/ci-front.yaml
@@ -31,6 +31,8 @@ jobs:
uses: actions/checkout@v4
- name: Install dependencies
uses: ./.github/workflows/actions/yarn-install
+ - name: Diagnostic disk space issue
+ run: df -h
- name: Front / Restore Storybook Task Cache
uses: ./.github/workflows/actions/task-cache
with:
diff --git a/.github/workflows/ci-server.yaml b/.github/workflows/ci-server.yaml
index 857dec2fc863..074d63fdda40 100644
--- a/.github/workflows/ci-server.yaml
+++ b/.github/workflows/ci-server.yaml
@@ -54,7 +54,7 @@ jobs:
- name: Server / Write .env
run: npx nx reset:env twenty-server
- name: Worker / Run
- run: MESSAGE_QUEUE_TYPE=sync npx nx worker twenty-server
+ run: npx nx run twenty-server:worker:ci
server-test:
runs-on: ubuntu-latest
diff --git a/oss-gg/twenty-content-challenges/1-create-youtube-video-about-20.md b/oss-gg/twenty-content-challenges/1-create-youtube-video-about-20.md
new file mode 100644
index 000000000000..455b5e35bae3
--- /dev/null
+++ b/oss-gg/twenty-content-challenges/1-create-youtube-video-about-20.md
@@ -0,0 +1,21 @@
+**Side Quest**: Create a YouTube Video about Twenty showcasing a specific way to use Twenty effectively.
+**Points**: 750 Points
+**Proof**: Add your oss handle and YouTube video link to the list below.
+
+Please follow the following schema:
+
+---
+
+» 05-April-2024 by YOUR oss.gg HANDLE » YouTube Link: https://link.to/content
+
+---
+
+////////////////////////////
+
+Your turn 👇
+
+////////////////////////////
+
+» 02-October-2024 by [yourhandle](https://oss.gg/yourhandle) YouTube Link: [YouTube](https://twenty.com/)
+
+---
\ No newline at end of file
diff --git a/oss-gg/twenty-content-challenges/2-write-blog-post-about-20.md b/oss-gg/twenty-content-challenges/2-write-blog-post-about-20.md
new file mode 100644
index 000000000000..a4c4e6bee944
--- /dev/null
+++ b/oss-gg/twenty-content-challenges/2-write-blog-post-about-20.md
@@ -0,0 +1,21 @@
+**Side Quest**: Write a blog post about sharing your experience using Twenty in a detailed format on any platform.
+**Points**: 750 Points
+**Proof**: Add your oss handle and blog link to the list below.
+
+Please follow the following schema:
+
+---
+
+» 05-April-2024 by YOUR oss.gg HANDLE » blog Link: https://link.to/content
+
+---
+
+////////////////////////////
+
+Your turn 👇
+
+////////////////////////////
+
+» 02-October-2024 by [yourhandle](https://oss.gg/yourhandle) blog Link: [blog](https://twenty.com/)
+
+---
\ No newline at end of file
diff --git a/oss-gg/twenty-content-challenges/3-write-selfthost-guide-blog-post-20.md b/oss-gg/twenty-content-challenges/3-write-selfthost-guide-blog-post-20.md
new file mode 100644
index 000000000000..c7352ec430fc
--- /dev/null
+++ b/oss-gg/twenty-content-challenges/3-write-selfthost-guide-blog-post-20.md
@@ -0,0 +1,21 @@
+**Side Quest**: Write a blog post about self-hosting Twenty in a detailed format on any platform.
+**Points**: 750 Points
+**Proof**: Add your oss handle and blog link to the list below.
+
+Please follow the following schema:
+
+---
+
+» 05-April-2024 by YOUR oss.gg HANDLE » blog Link: https://link.to/content
+
+---
+
+////////////////////////////
+
+Your turn 👇
+
+////////////////////////////
+
+» 02-October-2024 by [yourhandle](https://oss.gg/yourhandle) blog Link: [blog](https://twenty.com/)
+
+---
\ No newline at end of file
diff --git a/oss-gg/twenty-content-challenges/4-create-promotional-video-20-share.md b/oss-gg/twenty-content-challenges/4-create-promotional-video-20-share.md
new file mode 100644
index 000000000000..e52cb43a4247
--- /dev/null
+++ b/oss-gg/twenty-content-challenges/4-create-promotional-video-20-share.md
@@ -0,0 +1,21 @@
+**Side Quest**: Create a promotional video for Twenty and share it on social media.
+**Points**: 750 Points
+**Proof**: Add your oss handle and video link to the list below.
+
+Please follow the following schema:
+
+---
+
+» 05-April-2024 by YOUR oss.gg HANDLE » video Link: https://link.to/content
+
+---
+
+////////////////////////////
+
+Your turn 👇
+
+////////////////////////////
+
+» 02-October-2024 by [yourhandle](https://oss.gg/yourhandle) video Link: [video](https://twenty.com/)
+
+---
\ No newline at end of file
diff --git a/oss-gg/twenty-design-challenges/1-design-promotional-poster-20-share.md b/oss-gg/twenty-design-challenges/1-design-promotional-poster-20-share.md
new file mode 100644
index 000000000000..b995788bc3f1
--- /dev/null
+++ b/oss-gg/twenty-design-challenges/1-design-promotional-poster-20-share.md
@@ -0,0 +1,21 @@
+**Side Quest**: Design a promotional poster of Twenty and share it on social media.
+**Points**: 300 Points
+**Proof**: Add your oss handle and poster link to the list below.
+
+Please follow the following schema:
+
+---
+
+» 05-April-2024 by YOUR oss.gg HANDLE » poster Link: https://link.to/content
+
+---
+
+////////////////////////////
+
+Your turn 👇
+
+////////////////////////////
+
+» 02-October-2024 by [yourhandle](https://oss.gg/yourhandle) poster Link: [poster](https://twenty.com/)
+
+---
\ No newline at end of file
diff --git a/oss-gg/twenty-design-challenges/2-design-new-logo-twenty.md b/oss-gg/twenty-design-challenges/2-design-new-logo-twenty.md
new file mode 100644
index 000000000000..e8e70ca913cb
--- /dev/null
+++ b/oss-gg/twenty-design-challenges/2-design-new-logo-twenty.md
@@ -0,0 +1,21 @@
+**Side Quest**: Design/Create new Twenty logo, tweet your design, and mention @twentycrm.
+**Points**: 300 Points
+**Proof**: Create a logo uploade it on any of the platform and add your oss handle and logo link to the list below.
+
+Please follow the following schema:
+
+---
+
+» 05-April-2024 by YOUR oss.gg HANDLE » Logo Link: https://link.to/content » tweet Link: https://link.to/content
+
+---
+
+////////////////////////////
+
+Your turn 👇
+
+////////////////////////////
+
+» 02-October-2024 by [yourhandle](https://oss.gg/yourhandle) Logo Link: [logo](https://twenty.com/) tweet Link: [tweet](https://x.com)
+
+---
\ No newline at end of file
diff --git a/oss-gg/twenty-design-challenges/3-create-custom-interfact-theme-20.md b/oss-gg/twenty-design-challenges/3-create-custom-interfact-theme-20.md
new file mode 100644
index 000000000000..e51945ea9988
--- /dev/null
+++ b/oss-gg/twenty-design-challenges/3-create-custom-interfact-theme-20.md
@@ -0,0 +1,21 @@
+**Side Quest**: Duplicate the Figma file from the main repo and customize the variables to create a unique interface theme for Twenty.
+**Points**: 750 Points
+**Proof**: Add your oss handle and Figma link to the list below.
+
+Please follow the following schema:
+
+---
+
+» 05-April-2024 by YOUR oss.gg HANDLE » Figma Link: https://link.to/content
+
+---
+
+////////////////////////////
+
+Your turn 👇
+
+////////////////////////////
+
+» 02-October-2024 by [yourhandle](https://oss.gg/yourhandle) Figma Link: [Figma](https://twenty.com/)
+
+---
\ No newline at end of file
diff --git a/oss-gg/twenty-dev-challenges/1-write-migration-script-other-crm-to-20.md b/oss-gg/twenty-dev-challenges/1-write-migration-script-other-crm-to-20.md
new file mode 100644
index 000000000000..249d8e158cfa
--- /dev/null
+++ b/oss-gg/twenty-dev-challenges/1-write-migration-script-other-crm-to-20.md
@@ -0,0 +1,21 @@
+**Side Quest**: Develop a script to facilitate the migration of data from another CRM to Twenty.
+**Points**: 750 Points
+**Proof**: Add your oss handle and record video and share link to the list below. In video show the working proof of your created script.
+
+Please follow the following schema:
+
+---
+
+» 05-April-2024 by YOUR oss.gg HANDLE » video Link: https://link.to/content
+
+---
+
+////////////////////////////
+
+Your turn 👇
+
+////////////////////////////
+
+» 02-October-2024 by [yourhandle](https://oss.gg/yourhandle) video Link: [video](https://twenty.com/)
+
+---
\ No newline at end of file
diff --git a/oss-gg/twenty-dev-challenges/2-create-raycast-integration-for-20.md b/oss-gg/twenty-dev-challenges/2-create-raycast-integration-for-20.md
new file mode 100644
index 000000000000..e4793c40d66f
--- /dev/null
+++ b/oss-gg/twenty-dev-challenges/2-create-raycast-integration-for-20.md
@@ -0,0 +1,21 @@
+**Side Quest**: Develop an integration for Raycast that enables users to create records on any object within Twenty directly from Raycast.
+**Points**: 1500 Points
+**Proof**: Add your oss handle and record video and share link to the list below. In video show the workflow of the your integration created and perform some task.
+
+Please follow the following schema:
+
+---
+
+» 05-April-2024 by YOUR oss.gg HANDLE » video Link: https://link.to/content
+
+---
+
+////////////////////////////
+
+Your turn 👇
+
+////////////////////////////
+
+» 02-October-2024 by [yourhandle](https://oss.gg/yourhandle) video Link: [video](https://twenty.com/)
+
+---
\ No newline at end of file
diff --git a/oss-gg/twenty-no-code-challenges/1-create-n8n-template-integrate-20-API.md b/oss-gg/twenty-no-code-challenges/1-create-n8n-template-integrate-20-API.md
new file mode 100644
index 000000000000..6786e5a94553
--- /dev/null
+++ b/oss-gg/twenty-no-code-challenges/1-create-n8n-template-integrate-20-API.md
@@ -0,0 +1,21 @@
+**Side Quest**: Create an n8n workflow that empowers Twenty by connecting it to another tool.
+**Points**: 750 Points
+**Proof**: Add your oss handle and template link to the list below.
+
+Please follow the following schema:
+
+---
+
+» 05-April-2024 by YOUR oss.gg HANDLE » template Link: https://link.to/content
+
+---
+
+////////////////////////////
+
+Your turn 👇
+
+////////////////////////////
+
+» 02-October-2024 by [yourhandle](https://oss.gg/yourhandle) template Link: [template](https://twenty.com/)
+
+---
\ No newline at end of file
diff --git a/oss-gg/twenty-no-code-challenges/2-write-selfthost-guide-blog-post-20.md b/oss-gg/twenty-no-code-challenges/2-write-selfthost-guide-blog-post-20.md
new file mode 100644
index 000000000000..58fa6de4d8d6
--- /dev/null
+++ b/oss-gg/twenty-no-code-challenges/2-write-selfthost-guide-blog-post-20.md
@@ -0,0 +1,21 @@
+**Side Quest**: Write a comprehensive guide on how to integrate Twenty with marketing automation tool (n8n, Zapier). Include a concrete use case and explain how to leverage AI to write API requests for non-developers and share it.
+**Points**: 1500 Points
+**Proof**: Add your oss handle and guide link to the list below.
+
+Please follow the following schema:
+
+---
+
+» 05-April-2024 by YOUR oss.gg HANDLE » guide Link: https://link.to/content
+
+---
+
+////////////////////////////
+
+Your turn 👇
+
+////////////////////////////
+
+» 02-October-2024 by [yourhandle](https://oss.gg/yourhandle) guide Link: [guide](https://twenty.com/)
+
+---
\ No newline at end of file
diff --git a/oss-gg/twenty-side-quest/1-quote-tweet-20-oss-gg-launch.md b/oss-gg/twenty-side-quest/1-quote-tweet-20-oss-gg-launch.md
new file mode 100644
index 000000000000..0a33e2287146
--- /dev/null
+++ b/oss-gg/twenty-side-quest/1-quote-tweet-20-oss-gg-launch.md
@@ -0,0 +1,23 @@
+**Side Quest**: Meme Magic - Craft a meme where a brick plays a role. Tweet it, and tag us @papermarkio to submit.
+**Points**: 150 Points
+**Proof**: Add a screenshot of meme to the PR description. Add a link to your tweet in the list below.
+
+Please follow the following schema:
+
+---
+
+» 05-April-2024 by YOUR NAME
+» Link to Tweet: https://x.com/...
+
+---
+
+////////////////////////////
+
+Your turn 👇
+
+////////////////////////////
+
+» 01-October-2024 by YOUR NAME
+» Link to Tweet: https://x.com/...
+
+---
diff --git a/oss-gg/twenty-side-quest/2-tweet-about-fav-twenty-feature.md b/oss-gg/twenty-side-quest/2-tweet-about-fav-twenty-feature.md
new file mode 100644
index 000000000000..0a33e2287146
--- /dev/null
+++ b/oss-gg/twenty-side-quest/2-tweet-about-fav-twenty-feature.md
@@ -0,0 +1,23 @@
+**Side Quest**: Meme Magic - Craft a meme where a brick plays a role. Tweet it, and tag us @papermarkio to submit.
+**Points**: 150 Points
+**Proof**: Add a screenshot of meme to the PR description. Add a link to your tweet in the list below.
+
+Please follow the following schema:
+
+---
+
+» 05-April-2024 by YOUR NAME
+» Link to Tweet: https://x.com/...
+
+---
+
+////////////////////////////
+
+Your turn 👇
+
+////////////////////////////
+
+» 01-October-2024 by YOUR NAME
+» Link to Tweet: https://x.com/...
+
+---
diff --git a/oss-gg/twenty-side-quest/3-meme-magic.md b/oss-gg/twenty-side-quest/3-meme-magic.md
new file mode 100644
index 000000000000..0a33e2287146
--- /dev/null
+++ b/oss-gg/twenty-side-quest/3-meme-magic.md
@@ -0,0 +1,23 @@
+**Side Quest**: Meme Magic - Craft a meme where a brick plays a role. Tweet it, and tag us @papermarkio to submit.
+**Points**: 150 Points
+**Proof**: Add a screenshot of meme to the PR description. Add a link to your tweet in the list below.
+
+Please follow the following schema:
+
+---
+
+» 05-April-2024 by YOUR NAME
+» Link to Tweet: https://x.com/...
+
+---
+
+////////////////////////////
+
+Your turn 👇
+
+////////////////////////////
+
+» 01-October-2024 by YOUR NAME
+» Link to Tweet: https://x.com/...
+
+---
diff --git a/oss-gg/twenty-side-quest/4-gif-magic.md b/oss-gg/twenty-side-quest/4-gif-magic.md
new file mode 100644
index 000000000000..0e38ace584d6
--- /dev/null
+++ b/oss-gg/twenty-side-quest/4-gif-magic.md
@@ -0,0 +1,23 @@
+**Side Quest**: GIF Magic - Craft a GIF where a brick plays a role. Upload it to GIPHY with tags 'open source', 'foss', 'papermarkio'.
+**Points**: 150 Points
+**Proof**: Add a screenshot of GIF on Giphy to the PR description. Add a link to your GIPHY in the list below.
+
+Please follow the following schema:
+
+---
+
+» 05-April-2024 by YOUR NAME
+» Link to Tweet: https://giphy.com/...
+
+---
+
+////////////////////////////
+
+Your turn 👇
+
+////////////////////////////
+
+» 01-October-2024 by YOUR NAME
+» Link to Tweet: https://x.com/...
+
+---
diff --git a/oss-gg/twenty-side-quest/5-quest-wizard.md b/oss-gg/twenty-side-quest/5-quest-wizard.md
new file mode 100644
index 000000000000..2dfe4bd9c86b
--- /dev/null
+++ b/oss-gg/twenty-side-quest/5-quest-wizard.md
@@ -0,0 +1,19 @@
+**Side Quest**: Complete all papermarkio side quests
+**Points**: 300 Points
+**Proof**: Add screenshots for each side quest to the PR description. Add your name to the list below.
+
+Please follow the following schema:
+
+---
+
+ » 05-April-2024 by YOUR NAME
+
+////////////////////////////
+
+Your turn 👇
+
+////////////////////////////
+
+» 01-October-2024 by X
+
+---
diff --git a/packages/twenty-emails/package.json b/packages/twenty-emails/package.json
index a792a42a373a..1f20fbe7eb64 100644
--- a/packages/twenty-emails/package.json
+++ b/packages/twenty-emails/package.json
@@ -1,6 +1,6 @@
{
"name": "twenty-emails",
- "version": "0.31.canary",
+ "version": "0.31.0-canary",
"description": "",
"author": "",
"private": true,
diff --git a/packages/twenty-front/.storybook/preview.tsx b/packages/twenty-front/.storybook/preview.tsx
index f49ed56c58b9..1d67634e2a54 100644
--- a/packages/twenty-front/.storybook/preview.tsx
+++ b/packages/twenty-front/.storybook/preview.tsx
@@ -1,7 +1,7 @@
-import { useEffect } from 'react';
import { ThemeProvider } from '@emotion/react';
import { Preview } from '@storybook/react';
import { initialize, mswDecorator } from 'msw-storybook-addon';
+import { useEffect } from 'react';
import { useDarkMode } from 'storybook-dark-mode';
import { THEME_DARK, THEME_LIGHT, ThemeContextProvider } from 'twenty-ui';
@@ -13,12 +13,16 @@ import 'react-loading-skeleton/dist/skeleton.css';
initialize({
onUnhandledRequest: async (request: Request) => {
const fileExtensionsToIgnore =
- /\.(ts|tsx|js|jsx|svg|css|png)(\?v=[a-zA-Z0-9]+)?/;
+ /\.(ts|tsx|js|jsx|svg|css|png|woff2)(\?v=[a-zA-Z0-9]+)?/;
if (fileExtensionsToIgnore.test(request.url)) {
return;
}
+ if (request.url.startsWith('http://localhost:3000/files/data:image')) {
+ return;
+ }
+
const requestBody = await request.json();
// eslint-disable-next-line no-console
console.warn(`Unhandled ${request.method} request to ${request.url}
diff --git a/packages/twenty-front/jest.config.ts b/packages/twenty-front/jest.config.ts
index c71df7b77aff..8ed7f398db4e 100644
--- a/packages/twenty-front/jest.config.ts
+++ b/packages/twenty-front/jest.config.ts
@@ -2,6 +2,7 @@ import { JestConfigWithTsJest, pathsToModuleNameMapper } from 'ts-jest';
// eslint-disable-next-line @typescript-eslint/no-var-requires
const tsConfig = require('./tsconfig.json');
+process.env.TZ = 'GMT';
const jestConfig: JestConfigWithTsJest = {
// to enable logs, comment out the following line
@@ -25,7 +26,7 @@ const jestConfig: JestConfigWithTsJest = {
coverageThreshold: {
global: {
statements: 60,
- lines: 60,
+ lines: 55,
functions: 50,
},
},
diff --git a/packages/twenty-front/nyc.config.cjs b/packages/twenty-front/nyc.config.cjs
index 3fbf2dfd6204..8ae501c6910f 100644
--- a/packages/twenty-front/nyc.config.cjs
+++ b/packages/twenty-front/nyc.config.cjs
@@ -16,7 +16,7 @@ const modulesCoverage = {
};
const pagesCoverage = {
- branches: 40,
+ branches: 35,
statements: 60,
lines: 60,
functions: 45,
diff --git a/packages/twenty-front/package.json b/packages/twenty-front/package.json
index 96e6442a3f56..9370f2460b92 100644
--- a/packages/twenty-front/package.json
+++ b/packages/twenty-front/package.json
@@ -1,6 +1,6 @@
{
"name": "twenty-front",
- "version": "0.31.canary",
+ "version": "0.31.0-canary",
"private": true,
"type": "module",
"scripts": {
diff --git a/packages/twenty-front/src/App.tsx b/packages/twenty-front/src/App.tsx
index 1c6adcfdf60e..e8757d1b9913 100644
--- a/packages/twenty-front/src/App.tsx
+++ b/packages/twenty-front/src/App.tsx
@@ -58,43 +58,41 @@ const ProvidersThatNeedRouterContext = () => {
const pageTitle = getPageTitleFromPath(pathname);
return (
- <>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
);
};
diff --git a/packages/twenty-front/src/generated-metadata/graphql.ts b/packages/twenty-front/src/generated-metadata/graphql.ts
index 4f48fe60c424..64d5248023f6 100644
--- a/packages/twenty-front/src/generated-metadata/graphql.ts
+++ b/packages/twenty-front/src/generated-metadata/graphql.ts
@@ -992,6 +992,7 @@ export type RelationDefinition = {
/** Relation definition type */
export enum RelationDefinitionType {
+ ManyToMany = 'MANY_TO_MANY',
ManyToOne = 'MANY_TO_ONE',
OneToMany = 'ONE_TO_MANY',
OneToOne = 'ONE_TO_ONE'
@@ -999,6 +1000,7 @@ export enum RelationDefinitionType {
/** Type of the relation */
export enum RelationMetadataType {
+ ManyToMany = 'MANY_TO_MANY',
ManyToOne = 'MANY_TO_ONE',
OneToMany = 'ONE_TO_MANY',
OneToOne = 'ONE_TO_ONE'
diff --git a/packages/twenty-front/src/loading/components/LeftPanelSkeletonLoader.tsx b/packages/twenty-front/src/loading/components/LeftPanelSkeletonLoader.tsx
index 38803c9efecf..c8de2f64c46a 100644
--- a/packages/twenty-front/src/loading/components/LeftPanelSkeletonLoader.tsx
+++ b/packages/twenty-front/src/loading/components/LeftPanelSkeletonLoader.tsx
@@ -3,6 +3,7 @@ import { motion } from 'framer-motion';
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
import { ANIMATION, BACKGROUND_LIGHT, GRAY_SCALE } from 'twenty-ui';
+import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader';
import { DESKTOP_NAV_DRAWER_WIDTHS } from '@/ui/navigation/navigation-drawer/constants/DesktopNavDrawerWidths';
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
import { MainNavigationDrawerItemsSkeletonLoader } from '~/loading/components/MainNavigationDrawerItemsSkeletonLoader';
@@ -67,7 +68,10 @@ export const LeftPanelSkeletonLoader = () => {
highlightColor={BACKGROUND_LIGHT.transparent.lighter}
borderRadius={4}
>
-
+
diff --git a/packages/twenty-front/src/loading/components/MainNavigationDrawerItemsSkeletonLoader.tsx b/packages/twenty-front/src/loading/components/MainNavigationDrawerItemsSkeletonLoader.tsx
index 2d660dfda236..bfa360a98070 100644
--- a/packages/twenty-front/src/loading/components/MainNavigationDrawerItemsSkeletonLoader.tsx
+++ b/packages/twenty-front/src/loading/components/MainNavigationDrawerItemsSkeletonLoader.tsx
@@ -1,3 +1,4 @@
+import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader';
import styled from '@emotion/styled';
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
import { BACKGROUND_LIGHT, GRAY_SCALE } from 'twenty-ui';
@@ -26,9 +27,18 @@ export const MainNavigationDrawerItemsSkeletonLoader = ({
highlightColor={BACKGROUND_LIGHT.transparent.lighter}
borderRadius={4}
>
- {title && }
+ {title && (
+
+ )}
{Array.from({ length }).map((_, index) => (
-
+
))}
diff --git a/packages/twenty-front/src/loading/components/RightPanelSkeletonLoader.tsx b/packages/twenty-front/src/loading/components/RightPanelSkeletonLoader.tsx
index 1c47a6cdcb6c..9e98594369ab 100644
--- a/packages/twenty-front/src/loading/components/RightPanelSkeletonLoader.tsx
+++ b/packages/twenty-front/src/loading/components/RightPanelSkeletonLoader.tsx
@@ -1,3 +1,4 @@
+import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader';
import styled from '@emotion/styled';
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
import {
@@ -60,7 +61,10 @@ const StyledSkeletonHeaderLoader = () => {
highlightColor={BACKGROUND_LIGHT.transparent.lighter}
borderRadius={4}
>
-
+
);
@@ -73,7 +77,7 @@ const StyledSkeletonAddLoader = () => {
highlightColor={BACKGROUND_LIGHT.transparent.lighter}
borderRadius={4}
>
-
+
);
};
diff --git a/packages/twenty-front/src/modules/activities/components/SkeletonLoader.tsx b/packages/twenty-front/src/modules/activities/components/SkeletonLoader.tsx
index 21478ed73c32..0b65ab1143c3 100644
--- a/packages/twenty-front/src/modules/activities/components/SkeletonLoader.tsx
+++ b/packages/twenty-front/src/modules/activities/components/SkeletonLoader.tsx
@@ -1,6 +1,6 @@
-import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
+import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
const StyledSkeletonContainer = styled.div`
align-items: center;
@@ -25,6 +25,21 @@ const StyledSkeletonSubSectionContent = styled.div`
justify-content: center;
`;
+export const SKELETON_LOADER_HEIGHT_SIZES = {
+ standard: {
+ xs: 13,
+ s: 16,
+ m: 24,
+ l: 32,
+ xl: 40,
+ },
+ columns: {
+ s: 84,
+ m: 120,
+ xxl: 542,
+ },
+};
+
const SkeletonColumnLoader = ({ height }: { height: number }) => {
const theme = useTheme();
return (
@@ -55,15 +70,35 @@ export const SkeletonLoader = ({
borderRadius={4}
>
-
+
{withSubSections &&
skeletonItems.map(({ id }, index) => (
-
+
-
-
- {index === 1 && }
+
+
+ {index === 1 && (
+
+ )}
))}
diff --git a/packages/twenty-front/src/modules/activities/emails/right-drawer/hooks/__tests__/useRightDrawerEmailThread.test.tsx b/packages/twenty-front/src/modules/activities/emails/right-drawer/hooks/__tests__/useRightDrawerEmailThread.test.tsx
index f88c7b79a1b5..0af5cec8224a 100644
--- a/packages/twenty-front/src/modules/activities/emails/right-drawer/hooks/__tests__/useRightDrawerEmailThread.test.tsx
+++ b/packages/twenty-front/src/modules/activities/emails/right-drawer/hooks/__tests__/useRightDrawerEmailThread.test.tsx
@@ -1,56 +1,410 @@
-import { MockedProvider } from '@apollo/client/testing';
-import { renderHook } from '@testing-library/react';
-import { RecoilRoot } from 'recoil';
-
-import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
-import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord';
+import { renderHook, waitFor } from '@testing-library/react';
+import { viewableRecordIdState } from '@/object-record/record-right-drawer/states/viewableRecordIdState';
+import gql from 'graphql-tag';
+import { generateEmptyJestRecordNode } from '~/testing/jest/generateEmptyJestRecordNode';
+import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
import { useRightDrawerEmailThread } from '../useRightDrawerEmailThread';
-jest.mock('@/object-record/hooks/useFindOneRecord', () => ({
- __esModule: true,
- useFindOneRecord: jest.fn(),
-}));
+const mocks = [
+ {
+ request: {
+ query: gql`
+ query FindOneMessageThread($objectRecordId: ID!) {
+ messageThread(filter: { id: { eq: $objectRecordId } }) {
+ __typename
+ id
+ }
+ }
+ `,
+ variables: { objectRecordId: '1' },
+ },
+ result: jest.fn(() => ({
+ data: {
+ messageThread: {
+ id: '1',
+ __typename: 'MessageThread',
+ },
+ },
+ })),
+ },
+ {
+ request: {
+ query: gql`
+ query FindManyMessages(
+ $filter: MessageFilterInput
+ $orderBy: [MessageOrderByInput]
+ $lastCursor: String
+ $limit: Int
+ ) {
+ messages(
+ filter: $filter
+ orderBy: $orderBy
+ first: $limit
+ after: $lastCursor
+ ) {
+ edges {
+ node {
+ __typename
+ createdAt
+ headerMessageId
+ id
+ messageParticipants {
+ edges {
+ node {
+ __typename
+ displayName
+ handle
+ id
+ person {
+ __typename
+ avatarUrl
+ city
+ companyId
+ createdAt
+ createdBy {
+ source
+ workspaceMemberId
+ name
+ }
+ deletedAt
+ emails {
+ primaryEmail
+ additionalEmails
+ }
+ id
+ intro
+ jobTitle
+ linkedinLink {
+ primaryLinkUrl
+ primaryLinkLabel
+ secondaryLinks
+ }
+ name {
+ firstName
+ lastName
+ }
+ performanceRating
+ phones {
+ primaryPhoneNumber
+ primaryPhoneCountryCode
+ additionalPhones
+ }
+ position
+ updatedAt
+ whatsapp {
+ primaryPhoneNumber
+ primaryPhoneCountryCode
+ additionalPhones
+ }
+ workPreference
+ xLink {
+ primaryLinkUrl
+ primaryLinkLabel
+ secondaryLinks
+ }
+ }
+ role
+ workspaceMember {
+ __typename
+ avatarUrl
+ colorScheme
+ createdAt
+ dateFormat
+ deletedAt
+ id
+ locale
+ name {
+ firstName
+ lastName
+ }
+ timeFormat
+ timeZone
+ updatedAt
+ userEmail
+ userId
+ }
+ }
+ }
+ }
+ messageThread {
+ __typename
+ id
+ }
+ receivedAt
+ subject
+ text
+ }
+ cursor
+ }
+ pageInfo {
+ hasNextPage
+ hasPreviousPage
+ startCursor
+ endCursor
+ }
+ totalCount
+ }
+ }
+ `,
+ variables: {
+ filter: { messageThreadId: { eq: '1' } },
+ orderBy: [{ receivedAt: 'AscNullsLast' }],
+ lastCursor: undefined,
+ limit: 10,
+ },
+ },
+ result: jest.fn(() => ({
+ data: {
+ messages: {
+ edges: [
+ {
+ node: generateEmptyJestRecordNode({
+ objectNameSingular: 'message',
+ input: {
+ id: '1',
+ text: 'Message 1',
+ createdAt: '2024-10-03T10:20:10.145Z',
+ },
+ }),
+ cursor: '1',
+ },
+ {
+ node: generateEmptyJestRecordNode({
+ objectNameSingular: 'message',
+ input: {
+ id: '2',
+ text: 'Message 2',
+ createdAt: '2024-10-03T10:20:10.145Z',
+ },
+ }),
+ cursor: '2',
+ },
+ ],
+ totalCount: 2,
+ pageInfo: {
+ hasNextPage: false,
+ hasPreviousPage: false,
+ startCursor: '1',
+ endCursor: '2',
+ },
+ },
+ },
+ })),
+ },
+ {
+ request: {
+ query: gql`
+ query FindManyMessageParticipants(
+ $filter: MessageParticipantFilterInput
+ $orderBy: [MessageParticipantOrderByInput]
+ $lastCursor: String
+ $limit: Int
+ ) {
+ messageParticipants(
+ filter: $filter
+ orderBy: $orderBy
+ first: $limit
+ after: $lastCursor
+ ) {
+ edges {
+ node {
+ __typename
+ displayName
+ handle
+ id
+ messageId
+ person {
+ __typename
+ avatarUrl
+ city
+ companyId
+ createdAt
+ createdBy {
+ source
+ workspaceMemberId
+ name
+ }
+ deletedAt
+ emails {
+ primaryEmail
+ additionalEmails
+ }
+ id
+ intro
+ jobTitle
+ linkedinLink {
+ primaryLinkUrl
+ primaryLinkLabel
+ secondaryLinks
+ }
+ name {
+ firstName
+ lastName
+ }
+ performanceRating
+ phones {
+ primaryPhoneNumber
+ primaryPhoneCountryCode
+ additionalPhones
+ }
+ position
+ updatedAt
+ whatsapp {
+ primaryPhoneNumber
+ primaryPhoneCountryCode
+ additionalPhones
+ }
+ workPreference
+ xLink {
+ primaryLinkUrl
+ primaryLinkLabel
+ secondaryLinks
+ }
+ }
+ role
+ workspaceMember {
+ __typename
+ avatarUrl
+ colorScheme
+ createdAt
+ dateFormat
+ deletedAt
+ id
+ locale
+ name {
+ firstName
+ lastName
+ }
+ timeFormat
+ timeZone
+ updatedAt
+ userEmail
+ userId
+ }
+ }
+ cursor
+ }
+ pageInfo {
+ hasNextPage
+ hasPreviousPage
+ startCursor
+ endCursor
+ }
+ totalCount
+ }
+ }
+ `,
+ variables: {
+ filter: { messageId: { in: ['1', '2'] }, role: { eq: 'from' } },
+ orderBy: undefined,
+ lastCursor: undefined,
+ limit: undefined,
+ },
+ },
+ result: jest.fn(() => ({
+ data: {
+ messageParticipants: {
+ edges: [
+ {
+ node: generateEmptyJestRecordNode({
+ objectNameSingular: 'messageParticipant',
+ input: {
+ id: 'messageParticipant-1',
+ role: 'from',
+ messageId: '1',
+ },
+ }),
+ cursor: '1',
+ },
+ {
+ node: generateEmptyJestRecordNode({
+ objectNameSingular: 'messageParticipant',
+ input: {
+ id: 'messageParticipant-2',
+ role: 'from',
+ messageId: '2',
+ },
+ }),
+ cursor: '2',
+ },
+ ],
+ totalCount: 2,
+ pageInfo: {
+ hasNextPage: false,
+ hasPreviousPage: false,
+ startCursor: '1',
+ endCursor: '2',
+ },
+ },
+ },
+ })),
+ },
+];
-jest.mock('@/object-record/hooks/useFindManyRecords', () => ({
- __esModule: true,
- useFindManyRecords: jest.fn(),
-}));
+const Wrapper = getJestMetadataAndApolloMocksWrapper({
+ apolloMocks: mocks,
+ onInitializeRecoilSnapshot: ({ set }) => {
+ set(viewableRecordIdState, '1');
+ },
+});
describe('useRightDrawerEmailThread', () => {
it('should return correct values', async () => {
- const mockThread = { id: '1' };
-
const mockMessages = [
- { id: '1', text: 'Message 1' },
- { id: '2', text: 'Message 2' },
+ {
+ __typename: 'Message',
+ createdAt: '2024-10-03T10:20:10.145Z',
+ headerMessageId: '',
+ id: '1',
+ messageParticipants: [],
+ messageThread: null,
+ receivedAt: null,
+ sender: {
+ __typename: 'MessageParticipant',
+ displayName: '',
+ handle: '',
+ id: 'messageParticipant-1',
+ messageId: '1',
+ person: null,
+ role: 'from',
+ workspaceMember: null,
+ },
+ subject: '',
+ text: 'Message 1',
+ },
+ {
+ __typename: 'Message',
+ createdAt: '2024-10-03T10:20:10.145Z',
+ headerMessageId: '',
+ id: '2',
+ messageParticipants: [],
+ messageThread: null,
+ receivedAt: null,
+ sender: {
+ __typename: 'MessageParticipant',
+ displayName: '',
+ handle: '',
+ id: 'messageParticipant-2',
+ messageId: '2',
+ person: null,
+ role: 'from',
+ workspaceMember: null,
+ },
+ subject: '',
+ text: 'Message 2',
+ },
];
- const mockFetchMoreRecords = jest.fn();
-
- (useFindOneRecord as jest.Mock).mockReturnValue({
- record: mockThread,
- loading: false,
- fetchMoreRecords: mockFetchMoreRecords,
- });
-
- (useFindManyRecords as jest.Mock).mockReturnValue({
- records: mockMessages,
- loading: false,
- fetchMoreRecords: mockFetchMoreRecords,
- });
-
const { result } = renderHook(() => useRightDrawerEmailThread(), {
- wrapper: ({ children }) => (
-
- {children}
-
- ),
+ wrapper: Wrapper,
});
- expect(result.current.thread).toBeDefined();
- expect(result.current.messages).toEqual(mockMessages);
- expect(result.current.threadLoading).toBeFalsy();
- expect(result.current.fetchMoreMessages).toBeInstanceOf(Function);
+ await waitFor(() => {
+ expect(result.current.thread).toBeDefined();
+ expect(result.current.messages).toEqual(mockMessages);
+ expect(result.current.threadLoading).toBeFalsy();
+ expect(result.current.fetchMoreMessages).toBeInstanceOf(Function);
+ });
});
});
diff --git a/packages/twenty-front/src/modules/activities/hooks/__tests__/useActivityTargetObjectRecords.test.tsx b/packages/twenty-front/src/modules/activities/hooks/__tests__/useActivityTargetObjectRecords.test.tsx
index 260e931a3ae2..7d1426f4cb75 100644
--- a/packages/twenty-front/src/modules/activities/hooks/__tests__/useActivityTargetObjectRecords.test.tsx
+++ b/packages/twenty-front/src/modules/activities/hooks/__tests__/useActivityTargetObjectRecords.test.tsx
@@ -9,7 +9,7 @@ import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMembe
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarProviderScope';
import { JestObjectMetadataItemSetter } from '~/testing/jest/JestObjectMetadataItemSetter';
-import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
+import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
import { mockWorkspaceMembers } from '~/testing/mock-data/workspace-members';
const cache = new InMemoryCache();
diff --git a/packages/twenty-front/src/modules/activities/hooks/__tests__/useCreateActivityInDB.test.tsx b/packages/twenty-front/src/modules/activities/hooks/__tests__/useCreateActivityInDB.test.tsx
index 1b56bc49d5da..baddb1029bda 100644
--- a/packages/twenty-front/src/modules/activities/hooks/__tests__/useCreateActivityInDB.test.tsx
+++ b/packages/twenty-front/src/modules/activities/hooks/__tests__/useCreateActivityInDB.test.tsx
@@ -1,13 +1,11 @@
-import { MockedProvider, MockedResponse } from '@apollo/client/testing';
+import { MockedResponse } from '@apollo/client/testing';
import { act, renderHook } from '@testing-library/react';
import gql from 'graphql-tag';
import pick from 'lodash.pick';
-import { ReactNode } from 'react';
-import { RecoilRoot } from 'recoil';
import { useCreateActivityInDB } from '@/activities/hooks/useCreateActivityInDB';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
-import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarProviderScope';
+import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
import { mockedTasks } from '~/testing/mock-data/tasks';
const mockedDate = '2024-03-15T12:00:00.000Z';
@@ -26,14 +24,44 @@ const mocks: MockedResponse[] = [
mutation CreateOneTask($input: TaskCreateInput!) {
createTask(data: $input) {
__typename
- updatedAt
+ assignee {
+ __typename
+ id
+ name {
+ firstName
+ lastName
+ }
+ }
+ assigneeId
+ attachments {
+ edges {
+ node {
+ __typename
+ activityId
+ authorId
+ companyId
+ createdAt
+ deletedAt
+ fullPath
+ id
+ name
+ noteId
+ opportunityId
+ personId
+ rocketId
+ taskId
+ type
+ updatedAt
+ }
+ }
+ }
+ body
createdAt
dueAt
id
status
- body
- assigneeId
title
+ updatedAt
}
}
`,
@@ -56,15 +84,9 @@ const mocks: MockedResponse[] = [
},
];
-const Wrapper = ({ children }: { children: ReactNode }) => (
-
-
-
- {children}
-
-
-
-);
+const Wrapper = getJestMetadataAndApolloMocksWrapper({
+ apolloMocks: mocks,
+});
describe('useCreateActivityInDB', () => {
it('Should create activity in DB', async () => {
diff --git a/packages/twenty-front/src/modules/activities/hooks/__tests__/useOpenCreateActivityDrawer.test.tsx b/packages/twenty-front/src/modules/activities/hooks/__tests__/useOpenCreateActivityDrawer.test.tsx
index 665702704d1b..855c0b55bd29 100644
--- a/packages/twenty-front/src/modules/activities/hooks/__tests__/useOpenCreateActivityDrawer.test.tsx
+++ b/packages/twenty-front/src/modules/activities/hooks/__tests__/useOpenCreateActivityDrawer.test.tsx
@@ -1,7 +1,6 @@
-import { MockedProvider, MockedResponse } from '@apollo/client/testing';
+import { MockedResponse } from '@apollo/client/testing';
import { act, renderHook } from '@testing-library/react';
-import { ReactNode } from 'react';
-import { RecoilRoot, useRecoilValue, useSetRecoilState } from 'recoil';
+import { useRecoilValue, useSetRecoilState } from 'recoil';
import { useOpenCreateActivityDrawer } from '@/activities/hooks/useOpenCreateActivityDrawer';
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
@@ -9,7 +8,8 @@ import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSi
import { viewableRecordIdState } from '@/object-record/record-right-drawer/states/viewableRecordIdState';
import gql from 'graphql-tag';
import pick from 'lodash.pick';
-import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
+import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
+import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
import { mockedTasks } from '~/testing/mock-data/tasks';
const mockedDate = '2024-03-15T12:00:00.000Z';
@@ -61,13 +61,9 @@ const mocks: MockedResponse[] = [
},
];
-const Wrapper = ({ children }: { children: ReactNode }) => (
-
-
- {children}
-
-
-);
+const Wrapper = getJestMetadataAndApolloMocksWrapper({
+ apolloMocks: mocks,
+});
const mockObjectMetadataItems = generatedMockObjectMetadataItems;
diff --git a/packages/twenty-front/src/modules/activities/hooks/useOpenCreateActivityDrawer.ts b/packages/twenty-front/src/modules/activities/hooks/useOpenCreateActivityDrawer.ts
index 400c1f398a95..c35d27837121 100644
--- a/packages/twenty-front/src/modules/activities/hooks/useOpenCreateActivityDrawer.ts
+++ b/packages/twenty-front/src/modules/activities/hooks/useOpenCreateActivityDrawer.ts
@@ -15,6 +15,7 @@ import { Task } from '@/activities/types/Task';
import { TaskTarget } from '@/activities/types/TaskTarget';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord';
+import { isNewViewableRecordLoadingState } from '@/object-record/record-right-drawer/states/isNewViewableRecordLoading';
import { viewableRecordNameSingularState } from '@/object-record/record-right-drawer/states/viewableRecordNameSingularState';
import { ActivityTargetableObject } from '../types/ActivityTargetableEntity';
@@ -52,7 +53,9 @@ export const useOpenCreateActivityDrawer = ({
const setViewableRecordNameSingular = useSetRecoilState(
viewableRecordNameSingularState,
);
-
+ const setIsNewViewableRecordLoading = useSetRecoilState(
+ isNewViewableRecordLoadingState,
+ );
const setIsUpsertingActivityInDB = useSetRecoilState(
isUpsertingActivityInDBState,
);
@@ -64,6 +67,11 @@ export const useOpenCreateActivityDrawer = ({
targetableObjects: ActivityTargetableObject[];
customAssignee?: WorkspaceMember;
}) => {
+ openRightDrawer(RightDrawerPages.ViewRecord);
+ setIsNewViewableRecordLoading(true);
+ setViewableRecordId(null);
+ setViewableRecordNameSingular(activityObjectNameSingular);
+
const activity = await createOneActivity({
assigneeId: customAssignee?.id,
});
@@ -101,10 +109,9 @@ export const useOpenCreateActivityDrawer = ({
setHotkeyScope(RightDrawerHotkeyScope.RightDrawer, { goto: false });
setViewableRecordId(activity.id);
- setViewableRecordNameSingular(activityObjectNameSingular);
- openRightDrawer(RightDrawerPages.ViewRecord);
setIsUpsertingActivityInDB(false);
+ setIsNewViewableRecordLoading(false);
};
return openCreateActivityDrawer;
diff --git a/packages/twenty-front/src/modules/activities/tasks/__stories__/TaskGroups.stories.tsx b/packages/twenty-front/src/modules/activities/tasks/__stories__/TaskGroups.stories.tsx
index 444049cc1844..aefa6f2ed59a 100644
--- a/packages/twenty-front/src/modules/activities/tasks/__stories__/TaskGroups.stories.tsx
+++ b/packages/twenty-front/src/modules/activities/tasks/__stories__/TaskGroups.stories.tsx
@@ -42,5 +42,8 @@ export const WithTasks: Story = {
},
parameters: {
msw: graphqlMocks,
+ container: {
+ width: '500px',
+ },
},
};
diff --git a/packages/twenty-front/src/modules/activities/tasks/__stories__/TaskList.stories.tsx b/packages/twenty-front/src/modules/activities/tasks/__stories__/TaskList.stories.tsx
index 1113febb6223..c2a65b772be9 100644
--- a/packages/twenty-front/src/modules/activities/tasks/__stories__/TaskList.stories.tsx
+++ b/packages/twenty-front/src/modules/activities/tasks/__stories__/TaskList.stories.tsx
@@ -3,6 +3,7 @@ import { ComponentDecorator } from 'twenty-ui';
import { TaskList } from '@/activities/tasks/components/TaskList';
import { MemoryRouterDecorator } from '~/testing/decorators/MemoryRouterDecorator';
+import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator';
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks';
import { mockedTasks } from '~/testing/mock-data/tasks';
@@ -10,13 +11,21 @@ import { mockedTasks } from '~/testing/mock-data/tasks';
const meta: Meta = {
title: 'Modules/Activity/TaskList',
component: TaskList,
- decorators: [MemoryRouterDecorator, ComponentDecorator, SnackBarDecorator],
+ decorators: [
+ ComponentDecorator,
+ MemoryRouterDecorator,
+ ObjectMetadataItemsDecorator,
+ SnackBarDecorator,
+ ],
args: {
title: 'Tasks',
tasks: mockedTasks,
},
parameters: {
msw: graphqlMocks,
+ container: {
+ width: '500px',
+ },
},
};
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 ae484382ffcc..16ebbec0f38a 100644
--- a/packages/twenty-front/src/modules/activities/tasks/components/TaskGroups.tsx
+++ b/packages/twenty-front/src/modules/activities/tasks/components/TaskGroups.tsx
@@ -27,6 +27,7 @@ import { TaskList } from './TaskList';
const StyledContainer = styled.div`
display: flex;
flex-direction: column;
+ width: 100%;
`;
type TaskGroupsProps = {
diff --git a/packages/twenty-front/src/modules/activities/tasks/components/TaskList.tsx b/packages/twenty-front/src/modules/activities/tasks/components/TaskList.tsx
index 04e56c8d65ed..10e7982ca04f 100644
--- a/packages/twenty-front/src/modules/activities/tasks/components/TaskList.tsx
+++ b/packages/twenty-front/src/modules/activities/tasks/components/TaskList.tsx
@@ -12,6 +12,7 @@ type TaskListProps = {
const StyledContainer = styled.div`
align-items: flex-start;
+ width: 100%;
align-self: stretch;
display: flex;
flex-direction: column;
diff --git a/packages/twenty-front/src/modules/activities/tasks/hooks/__tests__/useCompleteTask.test.tsx b/packages/twenty-front/src/modules/activities/tasks/hooks/__tests__/useCompleteTask.test.tsx
index ba3e2ac53482..814b72fb6ce1 100644
--- a/packages/twenty-front/src/modules/activities/tasks/hooks/__tests__/useCompleteTask.test.tsx
+++ b/packages/twenty-front/src/modules/activities/tasks/hooks/__tests__/useCompleteTask.test.tsx
@@ -1,11 +1,10 @@
-import { MockedProvider, MockedResponse } from '@apollo/client/testing';
+import { MockedResponse } from '@apollo/client/testing';
import { act, renderHook } from '@testing-library/react';
import gql from 'graphql-tag';
-import { ReactNode } from 'react';
-import { RecoilRoot } from 'recoil';
import { useCompleteTask } from '@/activities/tasks/hooks/useCompleteTask';
import { Task } from '@/activities/types/Task';
+import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
const task: Task = {
id: '123',
@@ -28,21 +27,123 @@ const mocks: MockedResponse[] = [
mutation UpdateOneTask($idToUpdate: ID!, $input: TaskUpdateInput!) {
updateTask(id: $idToUpdate, data: $input) {
__typename
- updatedAt
- createdAt
- deletedAt
- dueAt
- id
- status
+ assignee {
+ __typename
+ avatarUrl
+ colorScheme
+ createdAt
+ dateFormat
+ deletedAt
+ id
+ locale
+ name {
+ firstName
+ lastName
+ }
+ timeFormat
+ timeZone
+ updatedAt
+ userEmail
+ userId
+ }
+ assigneeId
+ attachments {
+ edges {
+ node {
+ __typename
+ activityId
+ authorId
+ companyId
+ createdAt
+ deletedAt
+ fullPath
+ id
+ name
+ noteId
+ opportunityId
+ personId
+ rocketId
+ taskId
+ type
+ updatedAt
+ }
+ }
+ }
body
+ createdAt
createdBy {
source
workspaceMemberId
name
}
- assigneeId
+ deletedAt
+ dueAt
+ favorites {
+ edges {
+ node {
+ __typename
+ companyId
+ createdAt
+ deletedAt
+ id
+ noteId
+ opportunityId
+ personId
+ position
+ rocketId
+ taskId
+ updatedAt
+ viewId
+ workflowId
+ workspaceMemberId
+ }
+ }
+ }
+ id
position
+ status
+ taskTargets {
+ edges {
+ node {
+ __typename
+ companyId
+ createdAt
+ deletedAt
+ id
+ opportunityId
+ personId
+ rocketId
+ taskId
+ updatedAt
+ }
+ }
+ }
+ timelineActivities {
+ edges {
+ node {
+ __typename
+ companyId
+ createdAt
+ deletedAt
+ happensAt
+ id
+ linkedObjectMetadataId
+ linkedRecordCachedName
+ linkedRecordId
+ name
+ noteId
+ opportunityId
+ personId
+ properties
+ rocketId
+ taskId
+ updatedAt
+ workspaceMemberId
+ }
+ }
+ }
title
+ updatedAt
}
}
`,
@@ -72,13 +173,9 @@ const mocks: MockedResponse[] = [
},
];
-const Wrapper = ({ children }: { children: ReactNode }) => (
-
-
- {children}
-
-
-);
+const Wrapper = getJestMetadataAndApolloMocksWrapper({
+ apolloMocks: mocks,
+});
describe('useCompleteTask', () => {
it('should complete task', async () => {
diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/hooks/__tests__/useTimelineActivities.test.tsx b/packages/twenty-front/src/modules/activities/timelineActivities/hooks/__tests__/useTimelineActivities.test.tsx
index 894d541c888b..2d1989cc68ea 100644
--- a/packages/twenty-front/src/modules/activities/timelineActivities/hooks/__tests__/useTimelineActivities.test.tsx
+++ b/packages/twenty-front/src/modules/activities/timelineActivities/hooks/__tests__/useTimelineActivities.test.tsx
@@ -1,21 +1,16 @@
import { renderHook } from '@testing-library/react';
import { useTimelineActivities } from '@/activities/timelineActivities/hooks/useTimelineActivities';
-import { ReactNode } from 'react';
-import { getJestHookWrapper } from '~/testing/jest/getJestHookWrapper';
+import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
jest.mock('@/object-record/hooks/useFindManyRecords', () => ({
useFindManyRecords: jest.fn(),
}));
-const Wrappers = getJestHookWrapper({
+const Wrapper = getJestMetadataAndApolloMocksWrapper({
apolloMocks: [],
});
-const Wrapper = ({ children }: { children: ReactNode }) => (
- {children}
-);
-
describe('useTimelineActivities', () => {
afterEach(() => {
jest.clearAllMocks();
diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/rows/main-object/components/__stories__/EventRowMainObjectUpdated.stories.tsx b/packages/twenty-front/src/modules/activities/timelineActivities/rows/main-object/components/__stories__/EventRowMainObjectUpdated.stories.tsx
index 0cb945bdc4b2..224438b853cf 100644
--- a/packages/twenty-front/src/modules/activities/timelineActivities/rows/main-object/components/__stories__/EventRowMainObjectUpdated.stories.tsx
+++ b/packages/twenty-front/src/modules/activities/timelineActivities/rows/main-object/components/__stories__/EventRowMainObjectUpdated.stories.tsx
@@ -5,7 +5,7 @@ import { EventRowMainObjectUpdated } from '@/activities/timelineActivities/rows/
import { TimelineActivity } from '@/activities/timelineActivities/types/TimelineActivity';
import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator';
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
-import { mockedPersonObjectMetadataItem } from '~/testing/mock-data/metadata';
+import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
const meta: Meta = {
title: 'Modules/TimelineActivities/Rows/MainObject/EventRowMainObjectUpdated',
@@ -35,7 +35,9 @@ const meta: Meta = {
},
},
} as TimelineActivity,
- mainObjectMetadataItem: mockedPersonObjectMetadataItem,
+ mainObjectMetadataItem: generatedMockObjectMetadataItems.find(
+ (item) => item.namePlural === 'person',
+ ),
},
decorators: [
ComponentDecorator,
diff --git a/packages/twenty-front/src/modules/chrome-extension-sidecar/components/ChromeExtensionSidecarProvider.tsx b/packages/twenty-front/src/modules/chrome-extension-sidecar/components/ChromeExtensionSidecarProvider.tsx
index 3c4d8556a4bf..9409540ead23 100644
--- a/packages/twenty-front/src/modules/chrome-extension-sidecar/components/ChromeExtensionSidecarProvider.tsx
+++ b/packages/twenty-front/src/modules/chrome-extension-sidecar/components/ChromeExtensionSidecarProvider.tsx
@@ -1,56 +1,46 @@
-import styled from '@emotion/styled';
-import { useRecoilValue } from 'recoil';
-
-import { isLoadingTokensFromExtensionState } from '@/chrome-extension-sidecar/states/isLoadingTokensFromExtensionState';
-import { chromeExtensionIdState } from '@/client-config/states/chromeExtensionIdState';
-import { isDefined } from '~/utils/isDefined';
-import { isInFrame } from '~/utils/isInIframe';
-
-const StyledContainer = styled.div`
- align-items: center;
- display: flex;
- flex-direction: column;
- height: 100vh;
- justify-content: center;
-`;
-
-const AppInaccessible = ({ message }: { message: string }) => {
- return (
-
-
- {message}
-
- );
-};
+// const StyledContainer = styled.div`
+// align-items: center;
+// display: flex;
+// flex-direction: column;
+// height: 100vh;
+// justify-content: center;
+// `;
+
+// const AppInaccessible = ({ message }: { message: string }) => {
+// return (
+//
+//
+// {message}
+//
+// );
+// };
export const ChromeExtensionSidecarProvider: React.FC<
React.PropsWithChildren
> = ({ children }) => {
- const isLoadingTokensFromExtension = useRecoilValue(
- isLoadingTokensFromExtensionState,
- );
- const chromeExtensionId = useRecoilValue(chromeExtensionIdState);
-
- if (!isInFrame()) return <>{children}>;
-
- if (!isDefined(chromeExtensionId))
- return (
-
- );
-
- if (isDefined(isLoadingTokensFromExtension) && !isLoadingTokensFromExtension)
- return (
-
- );
-
- return isLoadingTokensFromExtension && <>{children}>;
+ return <>{children}>;
+
+ // TODO: this is conflictting with storybook tests
+ // if (!isInFrame()) return <>{children}>;
+
+ // if (!isDefined(chromeExtensionId))
+ // return (
+ //
+ // );
+
+ // if (isDefined(isLoadingTokensFromExtension) && !isLoadingTokensFromExtension)
+ // return (
+ //
+ // );
+
+ // return isLoadingTokensFromExtension && <>{children}>;
};
diff --git a/packages/twenty-front/src/modules/favorites/components/FavoritesSkeletonLoader.tsx b/packages/twenty-front/src/modules/favorites/components/FavoritesSkeletonLoader.tsx
index 3822a12bc9b6..5e5d1ea7f8ec 100644
--- a/packages/twenty-front/src/modules/favorites/components/FavoritesSkeletonLoader.tsx
+++ b/packages/twenty-front/src/modules/favorites/components/FavoritesSkeletonLoader.tsx
@@ -1,6 +1,7 @@
-import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
+import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
+import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
const StyledSkeletonContainer = styled.div`
display: flex;
@@ -25,10 +26,19 @@ export const FavoritesSkeletonLoader = () => {
borderRadius={4}
>
-
+
-
-
+
+
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 98813ad384c7..cf0fe8e888b1 100644
--- a/packages/twenty-front/src/modules/favorites/hooks/__mocks__/useFavorites.ts
+++ b/packages/twenty-front/src/modules/favorites/hooks/__mocks__/useFavorites.ts
@@ -87,262 +87,264 @@ export const mocks = [
mutation CreateOneFavorite($input: FavoriteCreateInput!) {
createFavorite(data: $input) {
__typename
- noteId
- taskId
- person {
+ company {
__typename
- name {
- firstName
- lastName
+ accountOwnerId
+ address {
+ addressStreet1
+ addressStreet2
+ addressCity
+ addressState
+ addressCountry
+ addressPostcode
+ addressLat
+ addressLng
+ }
+ annualRecurringRevenue {
+ amountMicros
+ currencyCode
+ }
+ createdAt
+ createdBy {
+ source
+ workspaceMemberId
+ name
+ }
+ deletedAt
+ domainName {
+ primaryLinkUrl
+ primaryLinkLabel
+ secondaryLinks
+ }
+ employees
+ id
+ idealCustomerProfile
+ introVideo {
+ primaryLinkUrl
+ primaryLinkLabel
+ secondaryLinks
}
linkedinLink {
primaryLinkUrl
primaryLinkLabel
secondaryLinks
}
- deletedAt
- createdAt
+ name
+ position
+ tagline
updatedAt
- jobTitle
- intro
- workPrefereance
- performanceRating
+ visaSponsorship
+ workPolicy
xLink {
primaryLinkUrl
primaryLinkLabel
secondaryLinks
}
- city
- companyId
- phones {
- primaryPhoneNumber
- primaryPhoneCountryCode
- additionalPhones
+ }
+ companyId
+ createdAt
+ deletedAt
+ id
+ note {
+ __typename
+ body
+ createdAt
+ createdBy {
+ source
+ workspaceMemberId
+ name
+ }
+ deletedAt
+ id
+ position
+ title
+ updatedAt
+ }
+ noteId
+ opportunity {
+ __typename
+ amount {
+ amountMicros
+ currencyCode
}
+ closeDate
+ companyId
+ createdAt
createdBy {
source
workspaceMemberId
name
}
+ deletedAt
id
+ name
+ pointOfContactId
position
+ stage
+ updatedAt
+ }
+ opportunityId
+ person {
+ __typename
+ avatarUrl
+ city
+ companyId
+ createdAt
+ createdBy {
+ source
+ workspaceMemberId
+ name
+ }
+ deletedAt
emails {
primaryEmail
additionalEmails
}
- avatarUrl
+ id
+ intro
+ jobTitle
+ linkedinLink {
+ primaryLinkUrl
+ primaryLinkLabel
+ secondaryLinks
+ }
+ name {
+ firstName
+ lastName
+ }
+ performanceRating
+ phones {
+ primaryPhoneNumber
+ primaryPhoneCountryCode
+ additionalPhones
+ }
+ position
+ updatedAt
whatsapp {
primaryPhoneNumber
primaryPhoneCountryCode
additionalPhones
}
+ workPreference
+ xLink {
+ primaryLinkUrl
+ primaryLinkLabel
+ secondaryLinks
+ }
}
- task {
+ personId
+ position
+ rocket {
__typename
- updatedAt
createdAt
- deletedAt
- dueAt
- id
- status
- body
createdBy {
source
workspaceMemberId
name
}
- assigneeId
- position
- title
- }
- rocketId
- viewId
- updatedAt
- workflowId
- personId
- workspaceMemberId
- note {
- __typename
deletedAt
id
+ name
position
updatedAt
+ }
+ rocketId
+ task {
+ __typename
+ assigneeId
+ body
+ createdAt
createdBy {
source
workspaceMemberId
name
}
- body
+ deletedAt
+ dueAt
+ id
+ position
+ status
title
- createdAt
+ updatedAt
}
- createdAt
+ taskId
+ updatedAt
view {
__typename
- id
- type
+ createdAt
+ deletedAt
icon
- key
+ id
isCompact
kanbanFieldMetadataId
+ key
+ name
objectMetadataId
position
- createdAt
- deletedAt
+ type
updatedAt
- name
}
- opportunityId
- position
- deletedAt
- id
- companyId
+ viewId
workflow {
__typename
- deletedAt
- lastPublishedVersionId
createdAt
+ deletedAt
id
- statuses
+ lastPublishedVersionId
name
position
+ statuses
updatedAt
}
+ workflowId
workspaceMember {
__typename
+ avatarUrl
+ colorScheme
+ createdAt
+ dateFormat
+ deletedAt
+ id
+ locale
name {
firstName
lastName
}
- avatarUrl
- userId
- createdAt
- timeZone
- id
timeFormat
+ timeZone
updatedAt
- locale
userEmail
- deletedAt
- colorScheme
- dateFormat
+ userId
}
- company {
- __typename
- updatedAt
- domainName {
- primaryLinkUrl
- primaryLinkLabel
- secondaryLinks
- }
- visaSponsorship
- address {
- addressStreet1
- addressStreet2
- addressCity
- addressState
- addressCountry
- addressPostcode
- addressLat
- addressLng
- }
- position
- employees
- deletedAt
- accountOwnerId
- annualRecurringRevenue {
- amountMicros
- currencyCode
- }
- id
- name
- xLink {
- primaryLinkUrl
- primaryLinkLabel
- secondaryLinks
- }
- createdAt
- createdBy {
- source
- workspaceMemberId
- name
- }
- workPolicy
- introVideo {
- primaryLinkUrl
- primaryLinkLabel
- secondaryLinks
- }
- linkedinLink {
- primaryLinkUrl
- primaryLinkLabel
- secondaryLinks
- }
- tagline
- idealCustomerProfile
- }
- rocket {
- __typename
- createdBy {
- source
- workspaceMemberId
- name
- }
- updatedAt
- name
- position
- createdAt
- id
- deletedAt
- }
- opportunity {
- __typename
- createdBy {
- source
- workspaceMemberId
- name
- }
- amount {
- amountMicros
- currencyCode
- }
- stage
- position
- closeDate
- id
- name
- pointOfContactId
- companyId
- updatedAt
- deletedAt
- createdAt
- }
- }
- }
- `,
- variables: {
- input: {
- id: mockId,
- personId: favoriteTargetObjectId,
- position: 4,
- workspaceMemberId: '1',
- },
- },
- },
- result: jest.fn(() => ({
- data: {
- createFavorite: {
- id: favoriteId,
- },
- },
- })),
- },
- {
- request: {
- query: gql`
- mutation DeleteOneFavorite($idToDelete: ID!) {
- deleteFavorite(id: $idToDelete) {
- id
+ workspaceMemberId
+ }
+ }
+ `,
+ variables: {
+ input: {
+ id: mockId,
+ personId: favoriteTargetObjectId,
+ position: 4,
+ workspaceMemberId: '1',
+ },
+ },
+ },
+ result: jest.fn(() => ({
+ data: {
+ createFavorite: {
+ id: favoriteId,
+ },
+ },
+ })),
+ },
+ {
+ request: {
+ query: gql`
+ mutation DeleteOneFavorite($idToDelete: ID!) {
+ deleteFavorite(id: $idToDelete) {
+ __typename
+ deletedAt
+ id
}
}
`,
@@ -365,236 +367,236 @@ export const mocks = [
) {
updateFavorite(id: $idToUpdate, data: $input) {
__typename
- noteId
- taskId
- person {
- __typename
- name {
- firstName
- lastName
- }
- linkedinLink {
- primaryLinkUrl
- primaryLinkLabel
- secondaryLinks
- }
- deletedAt
- createdAt
- updatedAt
- jobTitle
- intro
- workPrefereance
- performanceRating
- xLink {
- primaryLinkUrl
- primaryLinkLabel
- secondaryLinks
- }
- city
- companyId
- phones {
- primaryPhoneNumber
- primaryPhoneCountryCode
- additionalPhones
- }
- createdBy {
- source
- workspaceMemberId
- name
- }
- id
- position
- emails {
- primaryEmail
- additionalEmails
- }
- avatarUrl
- whatsapp {
- primaryPhoneNumber
- primaryPhoneCountryCode
- additionalPhones
- }
- }
- task {
- __typename
- updatedAt
- createdAt
- deletedAt
- dueAt
- id
- status
- body
- createdBy {
- source
- workspaceMemberId
- name
- }
- assigneeId
- position
- title
- }
- rocketId
- viewId
- updatedAt
- workflowId
- personId
- workspaceMemberId
- note {
- __typename
- deletedAt
- id
- position
- updatedAt
- createdBy {
- source
- workspaceMemberId
- name
- }
- body
- title
- createdAt
- }
- createdAt
- view {
- __typename
- id
- type
- icon
- key
- isCompact
- kanbanFieldMetadataId
- objectMetadataId
- position
- createdAt
- deletedAt
- updatedAt
- name
- }
- opportunityId
- position
- deletedAt
- id
- companyId
- workflow {
- __typename
- deletedAt
- lastPublishedVersionId
- createdAt
- id
- statuses
- name
- position
- updatedAt
- }
- workspaceMember {
- __typename
- name {
- firstName
- lastName
- }
- avatarUrl
- userId
- createdAt
- timeZone
- id
- timeFormat
- updatedAt
- locale
- userEmail
- deletedAt
- colorScheme
- dateFormat
- }
- company {
- __typename
- updatedAt
- domainName {
- primaryLinkUrl
- primaryLinkLabel
- secondaryLinks
- }
- visaSponsorship
- address {
- addressStreet1
- addressStreet2
- addressCity
- addressState
- addressCountry
- addressPostcode
- addressLat
- addressLng
- }
- position
- employees
- deletedAt
- accountOwnerId
- annualRecurringRevenue {
- amountMicros
- currencyCode
- }
- id
- name
- xLink {
- primaryLinkUrl
- primaryLinkLabel
- secondaryLinks
- }
- createdAt
- createdBy {
- source
- workspaceMemberId
- name
- }
- workPolicy
- introVideo {
- primaryLinkUrl
- primaryLinkLabel
- secondaryLinks
- }
- linkedinLink {
- primaryLinkUrl
- primaryLinkLabel
- secondaryLinks
- }
- tagline
- idealCustomerProfile
- }
- rocket {
- __typename
- createdBy {
- source
- workspaceMemberId
- name
- }
- updatedAt
- name
- position
- createdAt
- id
- deletedAt
- }
- opportunity {
- __typename
- createdBy {
- source
+ company {
+ __typename
+ accountOwnerId
+ address {
+ addressStreet1
+ addressStreet2
+ addressCity
+ addressState
+ addressCountry
+ addressPostcode
+ addressLat
+ addressLng
+ }
+ annualRecurringRevenue {
+ amountMicros
+ currencyCode
+ }
+ createdAt
+ createdBy {
+ source
+ workspaceMemberId
+ name
+ }
+ deletedAt
+ domainName {
+ primaryLinkUrl
+ primaryLinkLabel
+ secondaryLinks
+ }
+ employees
+ id
+ idealCustomerProfile
+ introVideo {
+ primaryLinkUrl
+ primaryLinkLabel
+ secondaryLinks
+ }
+ linkedinLink {
+ primaryLinkUrl
+ primaryLinkLabel
+ secondaryLinks
+ }
+ name
+ position
+ tagline
+ updatedAt
+ visaSponsorship
+ workPolicy
+ xLink {
+ primaryLinkUrl
+ primaryLinkLabel
+ secondaryLinks
+ }
+ }
+ companyId
+ createdAt
+ deletedAt
+ id
+ note {
+ __typename
+ body
+ createdAt
+ createdBy {
+ source
+ workspaceMemberId
+ name
+ }
+ deletedAt
+ id
+ position
+ title
+ updatedAt
+ }
+ noteId
+ opportunity {
+ __typename
+ amount {
+ amountMicros
+ currencyCode
+ }
+ closeDate
+ companyId
+ createdAt
+ createdBy {
+ source
+ workspaceMemberId
+ name
+ }
+ deletedAt
+ id
+ name
+ pointOfContactId
+ position
+ stage
+ updatedAt
+ }
+ opportunityId
+ person {
+ __typename
+ avatarUrl
+ city
+ companyId
+ createdAt
+ createdBy {
+ source
+ workspaceMemberId
+ name
+ }
+ deletedAt
+ emails {
+ primaryEmail
+ additionalEmails
+ }
+ id
+ intro
+ jobTitle
+ linkedinLink {
+ primaryLinkUrl
+ primaryLinkLabel
+ secondaryLinks
+ }
+ name {
+ firstName
+ lastName
+ }
+ performanceRating
+ phones {
+ primaryPhoneNumber
+ primaryPhoneCountryCode
+ additionalPhones
+ }
+ position
+ updatedAt
+ whatsapp {
+ primaryPhoneNumber
+ primaryPhoneCountryCode
+ additionalPhones
+ }
+ workPreference
+ xLink {
+ primaryLinkUrl
+ primaryLinkLabel
+ secondaryLinks
+ }
+ }
+ personId
+ position
+ rocket {
+ __typename
+ createdAt
+ createdBy {
+ source
+ workspaceMemberId
+ name
+ }
+ deletedAt
+ id
+ name
+ position
+ updatedAt
+ }
+ rocketId
+ task {
+ __typename
+ assigneeId
+ body
+ createdAt
+ createdBy {
+ source
+ workspaceMemberId
+ name
+ }
+ deletedAt
+ dueAt
+ id
+ position
+ status
+ title
+ updatedAt
+ }
+ taskId
+ updatedAt
+ view {
+ __typename
+ createdAt
+ deletedAt
+ icon
+ id
+ isCompact
+ kanbanFieldMetadataId
+ key
+ name
+ objectMetadataId
+ position
+ type
+ updatedAt
+ }
+ viewId
+ workflow {
+ __typename
+ createdAt
+ deletedAt
+ id
+ lastPublishedVersionId
+ name
+ position
+ statuses
+ updatedAt
+ }
+ workflowId
+ workspaceMember {
+ __typename
+ avatarUrl
+ colorScheme
+ createdAt
+ dateFormat
+ deletedAt
+ id
+ locale
+ name {
+ firstName
+ lastName
+ }
+ timeFormat
+ timeZone
+ updatedAt
+ userEmail
+ userId
+ }
workspaceMemberId
- name
- }
- amount {
- amountMicros
- currencyCode
- }
- stage
- position
- closeDate
- id
- name
- pointOfContactId
- companyId
- updatedAt
- deletedAt
- createdAt
- }
}
}
`,
diff --git a/packages/twenty-front/src/modules/favorites/hooks/__tests__/useFavorites.test.tsx b/packages/twenty-front/src/modules/favorites/hooks/__tests__/useFavorites.test.tsx
index 3a30077ea285..9c984ececa94 100644
--- a/packages/twenty-front/src/modules/favorites/hooks/__tests__/useFavorites.test.tsx
+++ b/packages/twenty-front/src/modules/favorites/hooks/__tests__/useFavorites.test.tsx
@@ -1,16 +1,14 @@
-import { MockedProvider } from '@apollo/client/testing';
import { DropResult, ResponderProvided } from '@hello-pangea/dnd';
import { act, renderHook, waitFor } from '@testing-library/react';
-import { ReactNode } from 'react';
-import { RecoilRoot, useSetRecoilState } from 'recoil';
+import { useSetRecoilState } from 'recoil';
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
import { useFavorites } from '@/favorites/hooks/useFavorites';
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
-import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarProviderScope';
-import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
+import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
+import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
import {
favoriteId,
favoriteTargetObjectRecord,
@@ -29,15 +27,9 @@ jest.mock('@/object-record/hooks/useFindManyRecords', () => ({
useFindManyRecords: () => ({ records: initialFavorites }),
}));
-const Wrapper = ({ children }: { children: ReactNode }) => (
-
-
-
- {children}
-
-
-
-);
+const Wrapper = getJestMetadataAndApolloMocksWrapper({
+ apolloMocks: mocks,
+});
describe('useFavorites', () => {
it('should fetch favorites successfully', async () => {
diff --git a/packages/twenty-front/src/modules/navigation/hooks/__tests__/useDefaultHomePagePath.test.ts b/packages/twenty-front/src/modules/navigation/hooks/__tests__/useDefaultHomePagePath.test.ts
index 1ec02c2fd071..a7fb3b4e51ed 100644
--- a/packages/twenty-front/src/modules/navigation/hooks/__tests__/useDefaultHomePagePath.test.ts
+++ b/packages/twenty-front/src/modules/navigation/hooks/__tests__/useDefaultHomePagePath.test.ts
@@ -6,7 +6,7 @@ import { useDefaultHomePagePath } from '@/navigation/hooks/useDefaultHomePagePat
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
import { AppPath } from '@/types/AppPath';
-import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
+import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
import { mockedUserData } from '~/testing/mock-data/users';
jest.mock('@/prefetch/hooks/usePrefetchedData');
diff --git a/packages/twenty-front/src/modules/object-metadata/components/NavigationDrawerSectionForObjectMetadataItemsSkeletonLoader.tsx b/packages/twenty-front/src/modules/object-metadata/components/NavigationDrawerSectionForObjectMetadataItemsSkeletonLoader.tsx
index 70e00d717330..70b965b1827f 100644
--- a/packages/twenty-front/src/modules/object-metadata/components/NavigationDrawerSectionForObjectMetadataItemsSkeletonLoader.tsx
+++ b/packages/twenty-front/src/modules/object-metadata/components/NavigationDrawerSectionForObjectMetadataItemsSkeletonLoader.tsx
@@ -1,3 +1,4 @@
+import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
@@ -20,9 +21,18 @@ export const NavigationDrawerSectionForObjectMetadataItemsSkeletonLoader: React.
borderRadius={4}
>
-
-
-
+
+
+
);
diff --git a/packages/twenty-front/src/modules/object-metadata/components/ObjectMetadataItemsLoadEffect.tsx b/packages/twenty-front/src/modules/object-metadata/components/ObjectMetadataItemsLoadEffect.tsx
index dd1971790bb1..c8659e1689c8 100644
--- a/packages/twenty-front/src/modules/object-metadata/components/ObjectMetadataItemsLoadEffect.tsx
+++ b/packages/twenty-front/src/modules/object-metadata/components/ObjectMetadataItemsLoadEffect.tsx
@@ -9,7 +9,7 @@ import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadat
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { FieldMetadataType } from '~/generated-metadata/graphql';
import { WorkspaceActivationStatus } from '~/generated/graphql';
-import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
+import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
diff --git a/packages/twenty-front/src/modules/object-metadata/hooks/__mocks__/ApolloMetadataClientProvider.tsx b/packages/twenty-front/src/modules/object-metadata/hooks/__mocks__/ApolloMetadataClientMockedProvider.tsx
similarity index 100%
rename from packages/twenty-front/src/modules/object-metadata/hooks/__mocks__/ApolloMetadataClientProvider.tsx
rename to packages/twenty-front/src/modules/object-metadata/hooks/__mocks__/ApolloMetadataClientMockedProvider.tsx
diff --git a/packages/twenty-front/src/modules/object-metadata/hooks/__mocks__/useFieldMetadataItem.ts b/packages/twenty-front/src/modules/object-metadata/hooks/__mocks__/useFieldMetadataItem.ts
index f3c3e93f1b2c..0e7470a10359 100644
--- a/packages/twenty-front/src/modules/object-metadata/hooks/__mocks__/useFieldMetadataItem.ts
+++ b/packages/twenty-front/src/modules/object-metadata/hooks/__mocks__/useFieldMetadataItem.ts
@@ -48,7 +48,18 @@ export const queries = {
createMetadataField: gql`
mutation CreateOneFieldMetadataItem($input: CreateOneFieldMetadataInput!) {
createOneField(input: $input) {
- ${baseFields}
+ id
+ type
+ name
+ label
+ description
+ icon
+ isCustom
+ isActive
+ isNullable
+ createdAt
+ updatedAt
+ settings
defaultValue
options
}
diff --git a/packages/twenty-front/src/modules/object-metadata/hooks/__tests__/useColumnDefinitionsFromFieldMetadata.test.ts b/packages/twenty-front/src/modules/object-metadata/hooks/__tests__/useColumnDefinitionsFromFieldMetadata.test.ts
index 558d2ff3034c..05c87497dcc6 100644
--- a/packages/twenty-front/src/modules/object-metadata/hooks/__tests__/useColumnDefinitionsFromFieldMetadata.test.ts
+++ b/packages/twenty-front/src/modules/object-metadata/hooks/__tests__/useColumnDefinitionsFromFieldMetadata.test.ts
@@ -3,7 +3,7 @@ import { Nullable } from 'twenty-ui';
import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata';
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
-import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
+import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
describe('useColumnDefinitionsFromFieldMetadata', () => {
it('should return empty definitions if no object is passed', () => {
diff --git a/packages/twenty-front/src/modules/object-metadata/hooks/__tests__/useCreateOneObjectMetadataItem.test.tsx b/packages/twenty-front/src/modules/object-metadata/hooks/__tests__/useCreateOneObjectMetadataItem.test.tsx
index 03443712d9de..cc92f241e31c 100644
--- a/packages/twenty-front/src/modules/object-metadata/hooks/__tests__/useCreateOneObjectMetadataItem.test.tsx
+++ b/packages/twenty-front/src/modules/object-metadata/hooks/__tests__/useCreateOneObjectMetadataItem.test.tsx
@@ -1,10 +1,8 @@
-import { ReactNode } from 'react';
-import { MockedProvider } from '@apollo/client/testing';
import { act, renderHook } from '@testing-library/react';
-import { RecoilRoot } from 'recoil';
import { useCreateOneObjectMetadataItem } from '@/object-metadata/hooks/useCreateOneObjectMetadataItem';
+import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
import {
findManyViewsQuery,
query,
@@ -47,13 +45,9 @@ const mocks = [
},
];
-const Wrapper = ({ children }: { children: ReactNode }) => (
-
-
- {children}
-
-
-);
+const Wrapper = getJestMetadataAndApolloMocksWrapper({
+ apolloMocks: mocks,
+});
describe('useCreateOneObjectMetadataItem', () => {
it('should work as expected', async () => {
diff --git a/packages/twenty-front/src/modules/object-metadata/hooks/__tests__/useFieldMetadataItem.test.tsx b/packages/twenty-front/src/modules/object-metadata/hooks/__tests__/useFieldMetadataItem.test.tsx
index 47b1a6c18c88..6795897e3cfd 100644
--- a/packages/twenty-front/src/modules/object-metadata/hooks/__tests__/useFieldMetadataItem.test.tsx
+++ b/packages/twenty-front/src/modules/object-metadata/hooks/__tests__/useFieldMetadataItem.test.tsx
@@ -1,6 +1,6 @@
-import { ReactNode } from 'react';
import { MockedProvider } from '@apollo/client/testing';
-import { act, renderHook } from '@testing-library/react';
+import { renderHook } from '@testing-library/react';
+import { act, ReactNode } from 'react';
import { RecoilRoot } from 'recoil';
import { useFieldMetadataItem } from '@/object-metadata/hooks/useFieldMetadataItem';
diff --git a/packages/twenty-front/src/modules/object-metadata/hooks/__tests__/useFilteredObjectMetadataItems.test.tsx b/packages/twenty-front/src/modules/object-metadata/hooks/__tests__/useFilteredObjectMetadataItems.test.tsx
index 4d16bb6d8af9..02e39712fe57 100644
--- a/packages/twenty-front/src/modules/object-metadata/hooks/__tests__/useFilteredObjectMetadataItems.test.tsx
+++ b/packages/twenty-front/src/modules/object-metadata/hooks/__tests__/useFilteredObjectMetadataItems.test.tsx
@@ -10,7 +10,7 @@ import {
} from '@/object-metadata/hooks/__mocks__/useFilteredObjectMetadataItems';
import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems';
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
-import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
+import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
const mocks = [
{
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 21ec56ad60b4..41220e695b94 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
@@ -1,15 +1,11 @@
-import { ReactNode } from 'react';
-import { MockedProvider } from '@apollo/client/testing';
import { renderHook } from '@testing-library/react';
-import { RecoilRoot } from 'recoil';
import { useGetObjectOrderByField } from '@/object-metadata/hooks/useGetObjectOrderByField';
+import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
-const Wrapper = ({ children }: { children: ReactNode }) => (
-
- {children}
-
-);
+const Wrapper = getJestMetadataAndApolloMocksWrapper({
+ apolloMocks: [],
+});
describe('useGetObjectOrderByField', () => {
it('should work as expected', () => {
diff --git a/packages/twenty-front/src/modules/object-metadata/hooks/__tests__/useGetObjectRecordIdentifierByNameSingular.test.tsx b/packages/twenty-front/src/modules/object-metadata/hooks/__tests__/useGetObjectRecordIdentifierByNameSingular.test.tsx
index a457bd27eff7..938796b78714 100644
--- a/packages/twenty-front/src/modules/object-metadata/hooks/__tests__/useGetObjectRecordIdentifierByNameSingular.test.tsx
+++ b/packages/twenty-front/src/modules/object-metadata/hooks/__tests__/useGetObjectRecordIdentifierByNameSingular.test.tsx
@@ -3,7 +3,7 @@ import { RecoilRoot, useSetRecoilState } from 'recoil';
import { useGetObjectRecordIdentifierByNameSingular } from '@/object-metadata/hooks/useGetObjectRecordIdentifierByNameSingular';
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
-import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
+import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
describe('useGetObjectRecordIdentifierByNameSingular', () => {
it('should work as expected', async () => {
diff --git a/packages/twenty-front/src/modules/object-metadata/hooks/__tests__/useGetRelationMetadata.test.tsx b/packages/twenty-front/src/modules/object-metadata/hooks/__tests__/useGetRelationMetadata.test.tsx
index 12ef572b6adf..7455088f27bc 100644
--- a/packages/twenty-front/src/modules/object-metadata/hooks/__tests__/useGetRelationMetadata.test.tsx
+++ b/packages/twenty-front/src/modules/object-metadata/hooks/__tests__/useGetRelationMetadata.test.tsx
@@ -5,7 +5,7 @@ import { RecoilRoot, useSetRecoilState } from 'recoil';
import { useGetRelationMetadata } from '@/object-metadata/hooks/useGetRelationMetadata';
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
-import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
+import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
const Wrapper = ({ children }: { children: ReactNode }) => (
diff --git a/packages/twenty-front/src/modules/object-metadata/hooks/__tests__/useMapToObjectRecordIdentifier.test.tsx b/packages/twenty-front/src/modules/object-metadata/hooks/__tests__/useMapToObjectRecordIdentifier.test.tsx
index d0157678c04a..8792fb31299a 100644
--- a/packages/twenty-front/src/modules/object-metadata/hooks/__tests__/useMapToObjectRecordIdentifier.test.tsx
+++ b/packages/twenty-front/src/modules/object-metadata/hooks/__tests__/useMapToObjectRecordIdentifier.test.tsx
@@ -1,7 +1,11 @@
import { renderHook } from '@testing-library/react';
-import { RecoilRoot } from 'recoil';
import { useMapToObjectRecordIdentifier } from '@/object-metadata/hooks/useMapToObjectRecordIdentifier';
+import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
+
+const Wrapper = getJestMetadataAndApolloMocksWrapper({
+ apolloMocks: [],
+});
describe('useMapToObjectRecordIdentifier', () => {
it('should work as expected', async () => {
@@ -18,7 +22,7 @@ describe('useMapToObjectRecordIdentifier', () => {
});
},
{
- wrapper: RecoilRoot,
+ wrapper: Wrapper,
},
);
diff --git a/packages/twenty-front/src/modules/object-metadata/hooks/__tests__/useObjectMetadataItem.test.tsx b/packages/twenty-front/src/modules/object-metadata/hooks/__tests__/useObjectMetadataItem.test.tsx
index ee757d7ff7b2..876846f2bd4b 100644
--- a/packages/twenty-front/src/modules/object-metadata/hooks/__tests__/useObjectMetadataItem.test.tsx
+++ b/packages/twenty-front/src/modules/object-metadata/hooks/__tests__/useObjectMetadataItem.test.tsx
@@ -1,16 +1,12 @@
-import { MockedProvider } from '@apollo/client/testing';
import { renderHook } from '@testing-library/react';
-import { ReactNode } from 'react';
-import { RecoilRoot } from 'recoil';
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
-import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
+import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
+import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
-const Wrapper = ({ children }: { children: ReactNode }) => (
-
- {children}
-
-);
+const Wrapper = getJestMetadataAndApolloMocksWrapper({
+ apolloMocks: [],
+});
// Split into tests for each new hook
describe('useObjectMetadataItem', () => {
diff --git a/packages/twenty-front/src/modules/object-metadata/hooks/useObjectNamePluralFromSingular.ts b/packages/twenty-front/src/modules/object-metadata/hooks/useObjectNamePluralFromSingular.ts
index 25208307eabd..88ac0baab21d 100644
--- a/packages/twenty-front/src/modules/object-metadata/hooks/useObjectNamePluralFromSingular.ts
+++ b/packages/twenty-front/src/modules/object-metadata/hooks/useObjectNamePluralFromSingular.ts
@@ -3,7 +3,7 @@ import { useRecoilValue } from 'recoil';
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
import { objectMetadataItemFamilySelector } from '@/object-metadata/states/objectMetadataItemFamilySelector';
import { WorkspaceActivationStatus } from '~/generated/graphql';
-import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
+import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
import { isDefined } from '~/utils/isDefined';
export const useObjectNamePluralFromSingular = ({
diff --git a/packages/twenty-front/src/modules/object-metadata/hooks/useObjectNameSingularFromPlural.ts b/packages/twenty-front/src/modules/object-metadata/hooks/useObjectNameSingularFromPlural.ts
index 5a94a5191b9f..2e5127d8fcd9 100644
--- a/packages/twenty-front/src/modules/object-metadata/hooks/useObjectNameSingularFromPlural.ts
+++ b/packages/twenty-front/src/modules/object-metadata/hooks/useObjectNameSingularFromPlural.ts
@@ -3,7 +3,7 @@ import { useRecoilValue } from 'recoil';
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
import { objectMetadataItemFamilySelector } from '@/object-metadata/states/objectMetadataItemFamilySelector';
import { WorkspaceActivationStatus } from '~/generated/graphql';
-import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
+import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
import { isDefined } from '~/utils/isDefined';
export const useObjectNameSingularFromPlural = ({
diff --git a/packages/twenty-front/src/modules/object-metadata/types/FieldMetadataItem.ts b/packages/twenty-front/src/modules/object-metadata/types/FieldMetadataItem.ts
index 61ce60263dfc..8a403a55a379 100644
--- a/packages/twenty-front/src/modules/object-metadata/types/FieldMetadataItem.ts
+++ b/packages/twenty-front/src/modules/object-metadata/types/FieldMetadataItem.ts
@@ -17,7 +17,7 @@ export type FieldMetadataItemOption = {
export type FieldMetadataItem = Omit<
Field,
- '__typename' | 'defaultValue' | 'options' | 'settings' | 'relationDefinition'
+ '__typename' | 'defaultValue' | 'options' | 'relationDefinition'
> & {
__typename?: string;
defaultValue?: any;
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
index ea2f1d5eee19..92a7e414b822 100644
--- 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
@@ -1,5 +1,5 @@
import { getObjectMetadataItemByNameSingular } from '@/object-metadata/utils/getObjectMetadataItemBySingularName';
-import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
+import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
describe('getObjectMetadataItemBySingularName', () => {
it('should work as expected', () => {
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 78c0e7047a4a..cc5691412fd3 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
@@ -1,5 +1,5 @@
import { getOrderByFieldForObjectMetadataItem } from '@/object-metadata/utils/getObjectOrderByField';
-import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
+import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
describe('getObjectOrderByField', () => {
it('should work as expected', () => {
diff --git a/packages/twenty-front/src/modules/object-metadata/utils/__tests__/getObjectSlug.test.ts b/packages/twenty-front/src/modules/object-metadata/utils/__tests__/getObjectSlug.test.ts
index c43c9d039e7c..526c6fe47635 100644
--- a/packages/twenty-front/src/modules/object-metadata/utils/__tests__/getObjectSlug.test.ts
+++ b/packages/twenty-front/src/modules/object-metadata/utils/__tests__/getObjectSlug.test.ts
@@ -1,5 +1,5 @@
import { getObjectSlug } from '@/object-metadata/utils/getObjectSlug';
-import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
+import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
describe('getObjectSlug', () => {
it('should work as expected', () => {
diff --git a/packages/twenty-front/src/modules/object-metadata/utils/__tests__/isObjectMetadataAvailableForRelation.test.ts b/packages/twenty-front/src/modules/object-metadata/utils/__tests__/isObjectMetadataAvailableForRelation.test.ts
index caefb7feed45..ece3ae39de06 100644
--- a/packages/twenty-front/src/modules/object-metadata/utils/__tests__/isObjectMetadataAvailableForRelation.test.ts
+++ b/packages/twenty-front/src/modules/object-metadata/utils/__tests__/isObjectMetadataAvailableForRelation.test.ts
@@ -1,5 +1,5 @@
import { isObjectMetadataAvailableForRelation } from '@/object-metadata/utils/isObjectMetadataAvailableForRelation';
-import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
+import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
describe('isObjectMetadataAvailableForRelation', () => {
it('should work as expected', () => {
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 755ce29ac677..7208246e7e49 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
@@ -1,5 +1,5 @@
import { mapFieldMetadataToGraphQLQuery } from '@/object-metadata/utils/mapFieldMetadataToGraphQLQuery';
-import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
+import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
import { normalizeGQLField } from '~/utils/normalizeGQLField';
const personObjectMetadataItem = generatedMockObjectMetadataItems.find(
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 c47eae446715..d2650b69807f 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
@@ -1,5 +1,5 @@
import { mapObjectMetadataToGraphQLQuery } from '@/object-metadata/utils/mapObjectMetadataToGraphQLQuery';
-import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
+import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
import { normalizeGQLQuery } from '~/utils/normalizeGQLQuery';
const personObjectMetadataItem = generatedMockObjectMetadataItems.find(
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 8ba9ebe23315..f372cd2eb3ac 100644
--- a/packages/twenty-front/src/modules/object-metadata/utils/formatFieldMetadataItemAsFieldDefinition.ts
+++ b/packages/twenty-front/src/modules/object-metadata/utils/formatFieldMetadataItemAsFieldDefinition.ts
@@ -54,5 +54,6 @@ export const formatFieldMetadataItemAsFieldDefinition = ({
metadata: fieldDefintionMetadata,
type: field.type,
}),
+ settings: field.settings,
};
};
diff --git a/packages/twenty-front/src/modules/object-metadata/utils/mapObjectMetadataToGraphQLQuery.ts b/packages/twenty-front/src/modules/object-metadata/utils/mapObjectMetadataToGraphQLQuery.ts
index f9e248815d99..9e705d428ced 100644
--- a/packages/twenty-front/src/modules/object-metadata/utils/mapObjectMetadataToGraphQLQuery.ts
+++ b/packages/twenty-front/src/modules/object-metadata/utils/mapObjectMetadataToGraphQLQuery.ts
@@ -18,6 +18,7 @@ export const mapObjectMetadataToGraphQLQuery = ({
const fieldsThatShouldBeQueried =
objectMetadataItem?.fields
.filter((field) => field.isActive)
+ .sort((fieldA, fieldB) => fieldA.name.localeCompare(fieldB.name))
.filter((field) =>
shouldFieldBeQueried({
field,
diff --git a/packages/twenty-front/src/modules/object-metadata/validation-schemas/__tests__/objectMetadataItemSchema.test.ts b/packages/twenty-front/src/modules/object-metadata/validation-schemas/__tests__/objectMetadataItemSchema.test.ts
index 0e8d60c66fb9..cbb1b2c46b3d 100644
--- a/packages/twenty-front/src/modules/object-metadata/validation-schemas/__tests__/objectMetadataItemSchema.test.ts
+++ b/packages/twenty-front/src/modules/object-metadata/validation-schemas/__tests__/objectMetadataItemSchema.test.ts
@@ -1,11 +1,12 @@
-import { mockedCompanyObjectMetadataItem } from '~/testing/mock-data/metadata';
-
+import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
import { objectMetadataItemSchema } from '../objectMetadataItemSchema';
describe('objectMetadataItemSchema', () => {
it('validates a valid object metadata item', () => {
// Given
- const validObjectMetadataItem = mockedCompanyObjectMetadataItem;
+ const validObjectMetadataItem = generatedMockObjectMetadataItems.find(
+ (item) => item.nameSingular === 'company',
+ );
// When
const result = objectMetadataItemSchema.parse(validObjectMetadataItem);
diff --git a/packages/twenty-front/src/modules/object-record/cache/utils/__tests__/getRecordNodeFromRecord.test.ts b/packages/twenty-front/src/modules/object-record/cache/utils/__tests__/getRecordNodeFromRecord.test.ts
index 219d05f854e5..4641974a0632 100644
--- a/packages/twenty-front/src/modules/object-record/cache/utils/__tests__/getRecordNodeFromRecord.test.ts
+++ b/packages/twenty-front/src/modules/object-record/cache/utils/__tests__/getRecordNodeFromRecord.test.ts
@@ -1,10 +1,8 @@
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
-import {
- mockedObjectMetadataItems,
- mockedPersonObjectMetadataItem,
-} from '~/testing/mock-data/metadata';
+
import { getPeopleMock } from '~/testing/mock-data/people';
+import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
import { getRecordNodeFromRecord } from '../getRecordNodeFromRecord';
const peopleMock = getPeopleMock();
@@ -12,11 +10,18 @@ const peopleMock = getPeopleMock();
describe('getRecordNodeFromRecord', () => {
it('computes relation records cache references by default', () => {
// Given
- const objectMetadataItems: ObjectMetadataItem[] = mockedObjectMetadataItems;
- const objectMetadataItem: Pick<
- ObjectMetadataItem,
- 'fields' | 'namePlural' | 'nameSingular'
- > = mockedPersonObjectMetadataItem;
+ const objectMetadataItems: ObjectMetadataItem[] =
+ generatedMockObjectMetadataItems;
+ const objectMetadataItem:
+ | Pick
+ | undefined = generatedMockObjectMetadataItems.find(
+ (item) => item.nameSingular === 'person',
+ );
+
+ if (!objectMetadataItem) {
+ throw new Error('Object metadata item not found');
+ }
+
const recordGqlFields = {
name: true,
company: true,
@@ -47,11 +52,18 @@ describe('getRecordNodeFromRecord', () => {
it('does not compute relation records cache references when `computeReferences` is false', () => {
// Given
- const objectMetadataItems: ObjectMetadataItem[] = mockedObjectMetadataItems;
- const objectMetadataItem: Pick<
- ObjectMetadataItem,
- 'fields' | 'namePlural' | 'nameSingular'
- > = mockedPersonObjectMetadataItem;
+ const objectMetadataItems: ObjectMetadataItem[] =
+ generatedMockObjectMetadataItems;
+ const objectMetadataItem:
+ | Pick
+ | undefined = generatedMockObjectMetadataItems.find(
+ (item) => item.nameSingular === 'person',
+ );
+
+ if (!objectMetadataItem) {
+ throw new Error('Object metadata item not found');
+ }
+
const recordGqlFields = {
name: true,
company: true,
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 d7faf5a77f29..2ab3b25344fa 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
@@ -65,7 +65,9 @@ export const getRecordNodeFromRecord = ({
RelationDefinitionType.OneToMany
) {
const oneToManyObjectMetadataItem = objectMetadataItems.find(
- (item) => item.namePlural === fieldName,
+ (item) =>
+ item.namePlural ===
+ field.relationDefinition?.targetObjectMetadata.namePlural,
);
if (!oneToManyObjectMetadataItem) {
diff --git a/packages/twenty-front/src/modules/object-record/hooks/__mocks__/personFragment.ts b/packages/twenty-front/src/modules/object-record/hooks/__mocks__/personFragment.ts
deleted file mode 100644
index 8a2b3f08567d..000000000000
--- a/packages/twenty-front/src/modules/object-record/hooks/__mocks__/personFragment.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-export const PERSON_FRAGMENT = `
- __typename
- name {
- firstName
- lastName
- }
- linkedinLink {
- primaryLinkUrl
- primaryLinkLabel
- secondaryLinks
- }
- deletedAt
- createdAt
- updatedAt
- jobTitle
- intro
- workPrefereance
- performanceRating
- xLink {
- primaryLinkUrl
- primaryLinkLabel
- secondaryLinks
- }
- city
- companyId
- phones {
- primaryPhoneNumber
- primaryPhoneCountryCode
- additionalPhones
- }
- createdBy {
- source
- workspaceMemberId
- name
- }
- id
- position
- emails {
- primaryEmail
- additionalEmails
- }
- avatarUrl
- whatsapp {
- primaryPhoneNumber
- primaryPhoneCountryCode
- additionalPhones
- }
-`
diff --git a/packages/twenty-front/src/modules/object-record/hooks/__mocks__/personFragments.ts b/packages/twenty-front/src/modules/object-record/hooks/__mocks__/personFragments.ts
new file mode 100644
index 000000000000..21cf8b2848b2
--- /dev/null
+++ b/packages/twenty-front/src/modules/object-record/hooks/__mocks__/personFragments.ts
@@ -0,0 +1,327 @@
+export const PERSON_FRAGMENT_WITH_DEPTH_ZERO_RELATIONS = `
+ __typename
+ avatarUrl
+ city
+ companyId
+ createdAt
+ createdBy {
+ source
+ workspaceMemberId
+ name
+ }
+ deletedAt
+ emails {
+ primaryEmail
+ additionalEmails
+ }
+ id
+ intro
+ jobTitle
+ linkedinLink{
+ primaryLinkUrl
+ primaryLinkLabel
+ secondaryLinks
+ }
+ name {
+ firstName
+ lastName
+ }
+ performanceRating
+ phones {
+ primaryPhoneNumber
+ primaryPhoneCountryCode
+ additionalPhones
+ }
+ position
+ updatedAt
+ whatsapp {
+ primaryPhoneNumber
+ primaryPhoneCountryCode
+ additionalPhones
+ }
+ workPreference
+ xLink {
+ primaryLinkUrl
+ primaryLinkLabel
+ secondaryLinks
+ }
+`
+
+export const PERSON_FRAGMENT_WITH_DEPTH_ONE_RELATIONS = `
+ __typename
+ activityTargets {
+ edges {
+ node {
+ __typename
+ activityId
+ companyId
+ createdAt
+ deletedAt
+ id
+ opportunityId
+ personId
+ rocketId
+ updatedAt
+ }
+ }
+ }
+ attachments {
+ edges {
+ node {
+ __typename
+ activityId
+ authorId
+ companyId
+ createdAt
+ deletedAt
+ fullPath
+ id
+ name
+ noteId
+ opportunityId
+ personId
+ rocketId
+ taskId
+ type
+ updatedAt
+ }
+ }
+ }
+ avatarUrl
+ calendarEventParticipants {
+ edges {
+ node {
+ __typename
+ calendarEventId
+ createdAt
+ deletedAt
+ displayName
+ handle
+ id
+ isOrganizer
+ personId
+ responseStatus
+ updatedAt
+ workspaceMemberId
+ }
+ }
+ }
+ city
+ company {
+ __typename
+ accountOwnerId
+ address {
+ addressStreet1
+ addressStreet2
+ addressCity
+ addressState
+ addressCountry
+ addressPostcode
+ addressLat
+ addressLng
+ }
+ annualRecurringRevenue {
+ amountMicros
+ currencyCode
+ }
+ createdAt
+ createdBy {
+ source
+ workspaceMemberId
+ name
+ }
+ deletedAt
+ domainName {
+ primaryLinkUrl
+ primaryLinkLabel
+ secondaryLinks
+ }
+ employees
+ id
+ idealCustomerProfile
+ introVideo {
+ primaryLinkUrl
+ primaryLinkLabel
+ secondaryLinks
+ }
+ linkedinLink {
+ primaryLinkUrl
+ primaryLinkLabel
+ secondaryLinks
+ }
+ name
+ position
+ tagline
+ updatedAt
+ visaSponsorship
+ workPolicy
+ xLink {
+ primaryLinkUrl
+ primaryLinkLabel
+ secondaryLinks
+ }
+ }
+ companyId
+ createdAt
+ createdBy {
+ source
+ workspaceMemberId
+ name
+ }
+ deletedAt
+ emails {
+ primaryEmail
+ additionalEmails
+ }
+ favorites {
+ edges {
+ node {
+ __typename
+ companyId
+ createdAt
+ deletedAt
+ id
+ noteId
+ opportunityId
+ personId
+ position
+ rocketId
+ taskId
+ updatedAt
+ viewId
+ workflowId
+ workspaceMemberId
+ }
+ }
+ }
+ id
+ intro
+ jobTitle
+ linkedinLink {
+ primaryLinkUrl
+ primaryLinkLabel
+ secondaryLinks
+ }
+ messageParticipants {
+ edges {
+ node {
+ __typename
+ createdAt
+ deletedAt
+ displayName
+ handle
+ id
+ messageId
+ personId
+ role
+ updatedAt
+ workspaceMemberId
+ }
+ }
+ }
+ name {
+ firstName
+ lastName
+ }
+ noteTargets {
+ edges {
+ node {
+ __typename
+ companyId
+ createdAt
+ deletedAt
+ id
+ noteId
+ opportunityId
+ personId
+ rocketId
+ updatedAt
+ }
+ }
+ }
+ performanceRating
+ phones {
+ primaryPhoneNumber
+ primaryPhoneCountryCode
+ additionalPhones
+ }
+ pointOfContactForOpportunities {
+ edges {
+ node {
+ __typename
+ amount {
+ amountMicros
+ currencyCode
+ }
+ closeDate
+ companyId
+ createdAt
+ createdBy {
+ source
+ workspaceMemberId
+ name
+ }
+ deletedAt
+ id
+ name
+ pointOfContactId
+ position
+ stage
+ updatedAt
+ }
+ }
+ }
+ position
+ taskTargets {
+ edges {
+ node {
+ __typename
+ companyId
+ createdAt
+ deletedAt
+ id
+ opportunityId
+ personId
+ rocketId
+ taskId
+ updatedAt
+ }
+ }
+ }
+ timelineActivities {
+ edges {
+ node {
+ __typename
+ companyId
+ createdAt
+ deletedAt
+ happensAt
+ id
+ linkedObjectMetadataId
+ linkedRecordCachedName
+ linkedRecordId
+ name
+ noteId
+ opportunityId
+ personId
+ properties
+ rocketId
+ taskId
+ updatedAt
+ workspaceMemberId
+ }
+ }
+ }
+ updatedAt
+ whatsapp {
+ primaryPhoneNumber
+ primaryPhoneCountryCode
+ additionalPhones
+ }
+ workPreference
+ xLink {
+ primaryLinkUrl
+ primaryLinkLabel
+ secondaryLinks
+ }
+`
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 fd28307168b5..b9d5b32b8b36 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
@@ -1,12 +1,12 @@
import { gql } from '@apollo/client';
-import { PERSON_FRAGMENT } from '@/object-record/hooks/__mocks__/personFragment';
+import { PERSON_FRAGMENT_WITH_DEPTH_ONE_RELATIONS } from '@/object-record/hooks/__mocks__/personFragments';
import { Person } from '@/people/types/Person';
export const query = gql`
mutation CreatePeople($data: [PersonCreateInput!]!, $upsert: Boolean) {
createPeople(data: $data, upsert: $upsert) {
- ${PERSON_FRAGMENT}
+ ${PERSON_FRAGMENT_WITH_DEPTH_ONE_RELATIONS}
}
}
`;
diff --git a/packages/twenty-front/src/modules/object-record/hooks/__mocks__/useCreateOneRecord.ts b/packages/twenty-front/src/modules/object-record/hooks/__mocks__/useCreateOneRecord.ts
index 6804a92c3525..6a0261794f3c 100644
--- a/packages/twenty-front/src/modules/object-record/hooks/__mocks__/useCreateOneRecord.ts
+++ b/packages/twenty-front/src/modules/object-record/hooks/__mocks__/useCreateOneRecord.ts
@@ -1,10 +1,10 @@
-import { PERSON_FRAGMENT } from '@/object-record/hooks/__mocks__/personFragment';
+import { PERSON_FRAGMENT_WITH_DEPTH_ONE_RELATIONS } from '@/object-record/hooks/__mocks__/personFragments';
import { gql } from '@apollo/client';
export const query = gql`
mutation CreateOnePerson($input: PersonCreateInput!) {
createPerson(data: $input) {
- ${PERSON_FRAGMENT}
+ ${PERSON_FRAGMENT_WITH_DEPTH_ONE_RELATIONS}
}
}
`;
diff --git a/packages/twenty-front/src/modules/object-record/hooks/__mocks__/useDeleteOneRecord.ts b/packages/twenty-front/src/modules/object-record/hooks/__mocks__/useDeleteOneRecord.ts
index f31b210e089b..2e7ce9bc5320 100644
--- a/packages/twenty-front/src/modules/object-record/hooks/__mocks__/useDeleteOneRecord.ts
+++ b/packages/twenty-front/src/modules/object-record/hooks/__mocks__/useDeleteOneRecord.ts
@@ -3,6 +3,8 @@ import { gql } from '@apollo/client';
export const query = gql`
mutation DeleteOnePerson($idToDelete: ID!) {
deletePerson(id: $idToDelete) {
+ __typename
+ deletedAt
id
}
}
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 2e50e02aac84..784e178fc785 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
@@ -1,4 +1,4 @@
-import { PERSON_FRAGMENT } from '@/object-record/hooks/__mocks__/personFragment';
+import { PERSON_FRAGMENT_WITH_DEPTH_ZERO_RELATIONS } from '@/object-record/hooks/__mocks__/personFragments';
import { gql } from '@apollo/client';
import { getPeopleMock } from '~/testing/mock-data/people';
@@ -9,7 +9,7 @@ export const query = gql`
personDuplicates(ids: $ids) {
edges {
node {
- ${PERSON_FRAGMENT}
+ ${PERSON_FRAGMENT_WITH_DEPTH_ZERO_RELATIONS}
}
cursor
}
diff --git a/packages/twenty-front/src/modules/object-record/hooks/__mocks__/useFindOneRecord.ts b/packages/twenty-front/src/modules/object-record/hooks/__mocks__/useFindOneRecord.ts
index 26ac2981aa37..075dabb052f5 100644
--- a/packages/twenty-front/src/modules/object-record/hooks/__mocks__/useFindOneRecord.ts
+++ b/packages/twenty-front/src/modules/object-record/hooks/__mocks__/useFindOneRecord.ts
@@ -1,12 +1,12 @@
import { gql } from '@apollo/client';
-import { PERSON_FRAGMENT } from '@/object-record/hooks/__mocks__/personFragment';
+import { PERSON_FRAGMENT_WITH_DEPTH_ONE_RELATIONS } from '@/object-record/hooks/__mocks__/personFragments';
import { responseData as person } from './useUpdateOneRecord';
export const query = gql`
query FindOnePerson($objectRecordId: ID!) {
person(filter: { id: { eq: $objectRecordId } }) {
- ${PERSON_FRAGMENT}
+ ${PERSON_FRAGMENT_WITH_DEPTH_ONE_RELATIONS}
}
}
`;
diff --git a/packages/twenty-front/src/modules/object-record/hooks/__mocks__/useUpdateOneRecord.ts b/packages/twenty-front/src/modules/object-record/hooks/__mocks__/useUpdateOneRecord.ts
index 15bb27bc76b1..1c109b9e3ed4 100644
--- a/packages/twenty-front/src/modules/object-record/hooks/__mocks__/useUpdateOneRecord.ts
+++ b/packages/twenty-front/src/modules/object-record/hooks/__mocks__/useUpdateOneRecord.ts
@@ -1,10 +1,10 @@
-import { PERSON_FRAGMENT } from '@/object-record/hooks/__mocks__/personFragment';
+import { PERSON_FRAGMENT_WITH_DEPTH_ONE_RELATIONS } from '@/object-record/hooks/__mocks__/personFragments';
import { gql } from '@apollo/client';
export const query = gql`
mutation UpdateOnePerson($idToUpdate: ID!, $input: PersonUpdateInput!) {
updatePerson(id: $idToUpdate, data: $input) {
- ${PERSON_FRAGMENT}
+ ${PERSON_FRAGMENT_WITH_DEPTH_ONE_RELATIONS}
}
}
`;
diff --git a/packages/twenty-front/src/modules/object-record/hooks/__tests__/useCreateManyRecords.test.tsx b/packages/twenty-front/src/modules/object-record/hooks/__tests__/useCreateManyRecords.test.tsx
index 9eb14eadd799..761680c43081 100644
--- a/packages/twenty-front/src/modules/object-record/hooks/__tests__/useCreateManyRecords.test.tsx
+++ b/packages/twenty-front/src/modules/object-record/hooks/__tests__/useCreateManyRecords.test.tsx
@@ -1,8 +1,5 @@
-import { ReactNode } from 'react';
-import { MockedProvider } from '@apollo/client/testing';
import { mocked } from '@storybook/test';
import { act, renderHook } from '@testing-library/react';
-import { RecoilRoot } from 'recoil';
import { v4 } from 'uuid';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
@@ -12,6 +9,7 @@ import {
variables,
} from '@/object-record/hooks/__mocks__/useCreateManyRecords';
import { useCreateManyRecords } from '@/object-record/hooks/useCreateManyRecords';
+import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
jest.mock('uuid', () => ({
v4: jest.fn(),
@@ -37,13 +35,9 @@ const mocks = [
},
];
-const Wrapper = ({ children }: { children: ReactNode }) => (
-
-
- {children}
-
-
-);
+const Wrapper = getJestMetadataAndApolloMocksWrapper({
+ apolloMocks: mocks,
+});
describe('useCreateManyRecords', () => {
it('works as expected', async () => {
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 3b4d1ad42d4c..a5ab3efec117 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
@@ -1,18 +1,22 @@
import { renderHook } from '@testing-library/react';
import { print } from 'graphql';
-import { RecoilRoot } from 'recoil';
-import { PERSON_FRAGMENT } from '@/object-record/hooks/__mocks__/personFragment';
+import { PERSON_FRAGMENT_WITH_DEPTH_ZERO_RELATIONS } from '@/object-record/hooks/__mocks__/personFragments';
import { useCreateManyRecordsMutation } from '@/object-record/hooks/useCreateManyRecordsMutation';
+import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
const expectedQueryTemplate = `
mutation CreatePeople($data: [PersonCreateInput!]!, $upsert: Boolean) {
createPeople(data: $data, upsert: $upsert) {
- ${PERSON_FRAGMENT}
+ ${PERSON_FRAGMENT_WITH_DEPTH_ZERO_RELATIONS}
}
}
`.replace(/\s/g, '');
+const Wrapper = getJestMetadataAndApolloMocksWrapper({
+ apolloMocks: [],
+});
+
describe('useCreateManyRecordsMutation', () => {
it('should return a valid createManyRecordsMutation', () => {
const objectNameSingular = 'person';
@@ -23,7 +27,7 @@ describe('useCreateManyRecordsMutation', () => {
objectNameSingular,
}),
{
- wrapper: RecoilRoot,
+ wrapper: Wrapper,
},
);
diff --git a/packages/twenty-front/src/modules/object-record/hooks/__tests__/useCreateOneRecord.test.tsx b/packages/twenty-front/src/modules/object-record/hooks/__tests__/useCreateOneRecord.test.tsx
index 837af4dd2bf6..db26b860517a 100644
--- a/packages/twenty-front/src/modules/object-record/hooks/__tests__/useCreateOneRecord.test.tsx
+++ b/packages/twenty-front/src/modules/object-record/hooks/__tests__/useCreateOneRecord.test.tsx
@@ -1,7 +1,4 @@
-import { ReactNode } from 'react';
-import { MockedProvider } from '@apollo/client/testing';
import { act, renderHook } from '@testing-library/react';
-import { RecoilRoot } from 'recoil';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import {
@@ -9,6 +6,7 @@ import {
responseData,
} from '@/object-record/hooks/__mocks__/useCreateOneRecord';
import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord';
+import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
const personId = 'a7286b9a-c039-4a89-9567-2dfa7953cda9';
const input = { name: { firstName: 'John', lastName: 'Doe' } };
@@ -31,13 +29,9 @@ const mocks = [
},
];
-const Wrapper = ({ children }: { children: ReactNode }) => (
-
-
- {children}
-
-
-);
+const Wrapper = getJestMetadataAndApolloMocksWrapper({
+ apolloMocks: mocks,
+});
describe('useCreateOneRecord', () => {
it('works as expected', async () => {
diff --git a/packages/twenty-front/src/modules/object-record/hooks/__tests__/useCreateOneRecordMutation.test.tsx b/packages/twenty-front/src/modules/object-record/hooks/__tests__/useCreateOneRecordMutation.test.tsx
index 18db35f815b0..376a085cde7c 100644
--- a/packages/twenty-front/src/modules/object-record/hooks/__tests__/useCreateOneRecordMutation.test.tsx
+++ b/packages/twenty-front/src/modules/object-record/hooks/__tests__/useCreateOneRecordMutation.test.tsx
@@ -1,18 +1,22 @@
import { renderHook } from '@testing-library/react';
import { print } from 'graphql';
-import { RecoilRoot } from 'recoil';
-import { PERSON_FRAGMENT } from '@/object-record/hooks/__mocks__/personFragment';
+import { PERSON_FRAGMENT_WITH_DEPTH_ONE_RELATIONS } from '@/object-record/hooks/__mocks__/personFragments';
import { useCreateOneRecordMutation } from '@/object-record/hooks/useCreateOneRecordMutation';
+import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
const expectedQueryTemplate = `
mutation CreateOnePerson($input: PersonCreateInput!) {
createPerson(data: $input) {
- ${PERSON_FRAGMENT}
+ ${PERSON_FRAGMENT_WITH_DEPTH_ONE_RELATIONS}
}
}
`.replace(/\s/g, '');
+const Wrapper = getJestMetadataAndApolloMocksWrapper({
+ apolloMocks: [],
+});
+
describe('useCreateOneRecordMutation', () => {
it('should return a valid createOneRecordMutation', () => {
const objectNameSingular = 'person';
@@ -23,7 +27,7 @@ describe('useCreateOneRecordMutation', () => {
objectNameSingular,
}),
{
- wrapper: RecoilRoot,
+ wrapper: Wrapper,
},
);
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 1c7dd33d33e6..ada53864a7a6 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,7 +1,4 @@
-import { MockedProvider } from '@apollo/client/testing';
import { act, renderHook } from '@testing-library/react';
-import { ReactNode } from 'react';
-import { RecoilRoot } from 'recoil';
import {
query,
@@ -9,6 +6,7 @@ import {
variables,
} from '@/object-record/hooks/__mocks__/useDeleteManyRecords';
import { useDeleteManyRecords } from '@/object-record/hooks/useDeleteManyRecords';
+import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
const people = [
'a7286b9a-c039-4a89-9567-2dfa7953cda9',
@@ -29,13 +27,9 @@ const mocks = [
},
];
-const Wrapper = ({ children }: { children: ReactNode }) => (
-
-
- {children}
-
-
-);
+const Wrapper = getJestMetadataAndApolloMocksWrapper({
+ apolloMocks: mocks,
+});
describe('useDeleteManyRecords', () => {
it('works as expected', async () => {
diff --git a/packages/twenty-front/src/modules/object-record/hooks/__tests__/useDeleteManyRecordsMutation.test.tsx b/packages/twenty-front/src/modules/object-record/hooks/__tests__/useDeleteManyRecordsMutation.test.tsx
index 7f96b1be6114..cc5b85d6b664 100644
--- a/packages/twenty-front/src/modules/object-record/hooks/__tests__/useDeleteManyRecordsMutation.test.tsx
+++ b/packages/twenty-front/src/modules/object-record/hooks/__tests__/useDeleteManyRecordsMutation.test.tsx
@@ -1,8 +1,8 @@
import { renderHook } from '@testing-library/react';
import { print } from 'graphql';
-import { RecoilRoot } from 'recoil';
import { useDeleteManyRecordsMutation } from '@/object-record/hooks/useDeleteManyRecordsMutation';
+import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
const expectedQueryTemplate = `
mutation DeleteManyPeople($filter: PersonFilterInput!) {
@@ -12,6 +12,10 @@ const expectedQueryTemplate = `
}
`.replace(/\s/g, '');
+const Wrapper = getJestMetadataAndApolloMocksWrapper({
+ apolloMocks: [],
+});
+
describe('useDeleteManyRecordsMutation', () => {
it('should return a valid deleteManyRecordsMutation', () => {
const objectNameSingular = 'person';
@@ -22,7 +26,7 @@ describe('useDeleteManyRecordsMutation', () => {
objectNameSingular,
}),
{
- wrapper: RecoilRoot,
+ wrapper: Wrapper,
},
);
diff --git a/packages/twenty-front/src/modules/object-record/hooks/__tests__/useDeleteOneRecord.test.tsx b/packages/twenty-front/src/modules/object-record/hooks/__tests__/useDeleteOneRecord.test.tsx
index 731a468a2835..0c347d309520 100644
--- a/packages/twenty-front/src/modules/object-record/hooks/__tests__/useDeleteOneRecord.test.tsx
+++ b/packages/twenty-front/src/modules/object-record/hooks/__tests__/useDeleteOneRecord.test.tsx
@@ -1,7 +1,5 @@
-import { ReactNode } from 'react';
-import { MockedProvider } from '@apollo/client/testing';
-import { act, renderHook } from '@testing-library/react';
-import { RecoilRoot } from 'recoil';
+import { renderHook } from '@testing-library/react';
+import { act } from 'react';
import {
query,
@@ -9,6 +7,7 @@ import {
variables,
} from '@/object-record/hooks/__mocks__/useDeleteOneRecord';
import { useDeleteOneRecord } from '@/object-record/hooks/useDeleteOneRecord';
+import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
const personId = 'a7286b9a-c039-4a89-9567-2dfa7953cda9';
@@ -26,13 +25,9 @@ const mocks = [
},
];
-const Wrapper = ({ children }: { children: ReactNode }) => (
-
-
- {children}
-
-
-);
+const Wrapper = getJestMetadataAndApolloMocksWrapper({
+ apolloMocks: mocks,
+});
describe('useDeleteOneRecord', () => {
it('works as expected', async () => {
diff --git a/packages/twenty-front/src/modules/object-record/hooks/__tests__/useDeleteOneRecordMutation.test.tsx b/packages/twenty-front/src/modules/object-record/hooks/__tests__/useDeleteOneRecordMutation.test.tsx
index 3bbc51f65a85..859355818ae8 100644
--- a/packages/twenty-front/src/modules/object-record/hooks/__tests__/useDeleteOneRecordMutation.test.tsx
+++ b/packages/twenty-front/src/modules/object-record/hooks/__tests__/useDeleteOneRecordMutation.test.tsx
@@ -1,17 +1,23 @@
import { renderHook } from '@testing-library/react';
import { print } from 'graphql';
-import { RecoilRoot } from 'recoil';
import { useDeleteOneRecordMutation } from '@/object-record/hooks/useDeleteOneRecordMutation';
+import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
const expectedQueryTemplate = `
mutation DeleteOnePerson($idToDelete: ID!) {
deletePerson(id: $idToDelete) {
+ __typename
+ deletedAt
id
}
}
`.replace(/\s/g, '');
+const Wrapper = getJestMetadataAndApolloMocksWrapper({
+ apolloMocks: [],
+});
+
describe('useDeleteOneRecordMutation', () => {
it('should return a valid deleteOneRecordMutation', () => {
const objectNameSingular = 'person';
@@ -22,7 +28,7 @@ describe('useDeleteOneRecordMutation', () => {
objectNameSingular,
}),
{
- wrapper: RecoilRoot,
+ wrapper: Wrapper,
},
);
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
index 02095502e9ed..80b57d7dc5bd 100644
--- 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
@@ -1,7 +1,6 @@
-import { MockedProvider } from '@apollo/client/testing';
import { act, renderHook } from '@testing-library/react';
-import { ReactNode, useEffect } from 'react';
-import { RecoilRoot, useRecoilState } from 'recoil';
+import { useEffect } from 'react';
+import { useRecoilState } from 'recoil';
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
import {
@@ -16,8 +15,8 @@ import {
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';
-import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
+import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
+import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
const mocks = [
{
@@ -52,22 +51,12 @@ const mocks = [
},
];
+const Wrapper = getJestMetadataAndApolloMocksWrapper({
+ apolloMocks: mocks,
+});
+
describe('useFetchAllRecordIds', () => {
it('fetches all record ids with fetch more synchronous loop', async () => {
- const Wrapper = ({ children }: { children: ReactNode }) => (
-
-
-
- {children}
-
-
-
- );
-
const { result } = renderHook(
() => {
const [, setObjectMetadataItems] = useRecoilState(
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 e8616d1da1a7..61cd950ff76f 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
@@ -1,11 +1,8 @@
-import { ReactNode } from 'react';
-import { MockedProvider } from '@apollo/client/testing';
import { renderHook, waitFor } from '@testing-library/react';
-import { RecoilRoot } from 'recoil';
import { useFindDuplicateRecords } from '@/object-record/hooks/useFindDuplicateRecords';
-import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarProviderScope';
+import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
import {
query,
responseData,
@@ -24,15 +21,9 @@ const mocks = [
},
];
-const Wrapper = ({ children }: { children: ReactNode }) => (
-
-
-
- {children}
-
-
-
-);
+const Wrapper = getJestMetadataAndApolloMocksWrapper({
+ apolloMocks: mocks,
+});
describe('useFindDuplicateRecords', () => {
it('should fetch duplicate records and return the correct data', async () => {
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 e7d0ad73348f..10cb78a400d3 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
@@ -1,16 +1,16 @@
import { renderHook } from '@testing-library/react';
import { print } from 'graphql';
-import { RecoilRoot } from 'recoil';
-import { PERSON_FRAGMENT } from '@/object-record/hooks/__mocks__/personFragment';
+import { PERSON_FRAGMENT_WITH_DEPTH_ZERO_RELATIONS } from '@/object-record/hooks/__mocks__/personFragments';
import { useFindDuplicateRecordsQuery } from '@/object-record/hooks/useFindDuplicatesRecordsQuery';
+import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
const expectedQueryTemplate = `
query FindDuplicatePerson($ids: [ID!]!) {
personDuplicates(ids: $ids) {
edges {
node {
- ${PERSON_FRAGMENT}
+ ${PERSON_FRAGMENT_WITH_DEPTH_ZERO_RELATIONS}
}
cursor
}
@@ -23,6 +23,10 @@ const expectedQueryTemplate = `
}
`.replace(/\s/g, '');
+const Wrapper = getJestMetadataAndApolloMocksWrapper({
+ apolloMocks: [],
+});
+
describe('useFindDuplicateRecordsQuery', () => {
it('should return a valid findDuplicateRecordsQuery', () => {
const objectNameSingular = 'person';
@@ -33,7 +37,7 @@ describe('useFindDuplicateRecordsQuery', () => {
objectNameSingular,
}),
{
- wrapper: RecoilRoot,
+ wrapper: Wrapper,
},
);
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 d86769f1d219..5d85b80c98da 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,7 +1,5 @@
-import { MockedProvider } from '@apollo/client/testing';
import { renderHook } from '@testing-library/react';
-import { ReactNode } from 'react';
-import { RecoilRoot, useSetRecoilState } from 'recoil';
+import { useSetRecoilState } from 'recoil';
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
@@ -11,8 +9,8 @@ import {
variables,
} from '@/object-record/hooks/__mocks__/useFindManyRecords';
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
-import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarProviderScope';
-import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
+import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
+import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
const mocks = [
{
@@ -28,29 +26,10 @@ const mocks = [
},
];
-const Wrapper = ({ children }: { children: ReactNode }) => (
-
-
-
- {children}
-
-
-
-);
-
+const Wrapper = getJestMetadataAndApolloMocksWrapper({
+ apolloMocks: mocks,
+});
describe('useFindManyRecords', () => {
- it('should skip fetch if currentWorkspaceMember is undefined', async () => {
- const { result } = renderHook(
- () => useFindManyRecords({ objectNameSingular: 'person' }),
- {
- wrapper: Wrapper,
- },
- );
-
- expect(result.current.loading).toBe(false);
- expect(result.current.error).toBeUndefined();
- });
-
it('should work as expected', async () => {
const onCompleted = jest.fn();
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 3d2213a589f4..0c7fd0afbeb2 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
@@ -1,16 +1,16 @@
import { renderHook } from '@testing-library/react';
import { print } from 'graphql';
-import { RecoilRoot } from 'recoil';
-import { PERSON_FRAGMENT } from '@/object-record/hooks/__mocks__/personFragment';
+import { PERSON_FRAGMENT_WITH_DEPTH_ZERO_RELATIONS } from '@/object-record/hooks/__mocks__/personFragments';
import { useFindManyRecordsQuery } from '@/object-record/hooks/useFindManyRecordsQuery';
+import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
const expectedQueryTemplate = `
query FindManyPeople($filter: PersonFilterInput, $orderBy: [PersonOrderByInput], $lastCursor: String, $limit: Int) {
people(filter: $filter, orderBy: $orderBy, first: $limit, after: $lastCursor) {
edges {
node {
- ${PERSON_FRAGMENT}
+ ${PERSON_FRAGMENT_WITH_DEPTH_ZERO_RELATIONS}
}
cursor
}
@@ -25,6 +25,10 @@ const expectedQueryTemplate = `
}
`.replace(/\s/g, '');
+const Wrapper = getJestMetadataAndApolloMocksWrapper({
+ apolloMocks: [],
+});
+
describe('useFindManyRecordsQuery', () => {
it('should return a valid findManyRecordsQuery', () => {
const objectNameSingular = 'person';
@@ -37,7 +41,7 @@ describe('useFindManyRecordsQuery', () => {
computeReferences,
}),
{
- wrapper: RecoilRoot,
+ wrapper: Wrapper,
},
);
diff --git a/packages/twenty-front/src/modules/object-record/hooks/__tests__/useFindOneRecord.test.tsx b/packages/twenty-front/src/modules/object-record/hooks/__tests__/useFindOneRecord.test.tsx
index 62e11efe51dd..e7249d9caf4b 100644
--- a/packages/twenty-front/src/modules/object-record/hooks/__tests__/useFindOneRecord.test.tsx
+++ b/packages/twenty-front/src/modules/object-record/hooks/__tests__/useFindOneRecord.test.tsx
@@ -1,15 +1,12 @@
-import { ReactNode } from 'react';
-import { MockedProvider } from '@apollo/client/testing';
import { renderHook, waitFor } from '@testing-library/react';
-import { RecoilRoot } from 'recoil';
import {
query,
- responseData,
variables,
} from '@/object-record/hooks/__mocks__/useFindOneRecord';
import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord';
-import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarProviderScope';
+import { generateEmptyJestRecordNode } from '~/testing/jest/generateEmptyJestRecordNode';
+import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
const mocks = [
{
@@ -19,21 +16,19 @@ const mocks = [
},
result: jest.fn(() => ({
data: {
- person: responseData,
+ person: generateEmptyJestRecordNode({
+ objectNameSingular: 'person',
+ input: { id: '6205681e-7c11-40b4-9e32-f523dbe54590' },
+ withDepthOneRelation: true,
+ }),
},
})),
},
];
-const Wrapper = ({ children }: { children: ReactNode }) => (
-
-
-
- {children}
-
-
-
-);
+const Wrapper = getJestMetadataAndApolloMocksWrapper({
+ apolloMocks: mocks,
+});
const objectRecordId = '6205681e-7c11-40b4-9e32-f523dbe54590';
diff --git a/packages/twenty-front/src/modules/object-record/hooks/__tests__/useFindOneRecordQuery.test.tsx b/packages/twenty-front/src/modules/object-record/hooks/__tests__/useFindOneRecordQuery.test.tsx
index 386e0d55f84f..32b2a169139d 100644
--- a/packages/twenty-front/src/modules/object-record/hooks/__tests__/useFindOneRecordQuery.test.tsx
+++ b/packages/twenty-front/src/modules/object-record/hooks/__tests__/useFindOneRecordQuery.test.tsx
@@ -1,18 +1,22 @@
import { renderHook } from '@testing-library/react';
import { print } from 'graphql';
-import { RecoilRoot } from 'recoil';
-import { PERSON_FRAGMENT } from '@/object-record/hooks/__mocks__/personFragment';
+import { PERSON_FRAGMENT_WITH_DEPTH_ZERO_RELATIONS } from '@/object-record/hooks/__mocks__/personFragments';
import { useFindOneRecordQuery } from '@/object-record/hooks/useFindOneRecordQuery';
+import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
const expectedQueryTemplate = `
query FindOnePerson($objectRecordId: ID!) {
person(filter: { id: { eq: $objectRecordId } }) {
- ${PERSON_FRAGMENT}
+ ${PERSON_FRAGMENT_WITH_DEPTH_ZERO_RELATIONS}
}
}
`.replace(/\s/g, '');
+const Wrapper = getJestMetadataAndApolloMocksWrapper({
+ apolloMocks: [],
+});
+
describe('useFindOneRecordQuery', () => {
it('should return a valid findOneRecordQuery', () => {
const objectNameSingular = 'person';
@@ -23,7 +27,7 @@ describe('useFindOneRecordQuery', () => {
objectNameSingular,
}),
{
- wrapper: RecoilRoot,
+ wrapper: Wrapper,
},
);
diff --git a/packages/twenty-front/src/modules/object-record/hooks/__tests__/useGenerateFindManyRecordsForMultipleMetadataItemsQuery.test.tsx b/packages/twenty-front/src/modules/object-record/hooks/__tests__/useGenerateFindManyRecordsForMultipleMetadataItemsQuery.test.tsx
index feb33c81b30a..2cdf074ad1d5 100644
--- a/packages/twenty-front/src/modules/object-record/hooks/__tests__/useGenerateFindManyRecordsForMultipleMetadataItemsQuery.test.tsx
+++ b/packages/twenty-front/src/modules/object-record/hooks/__tests__/useGenerateFindManyRecordsForMultipleMetadataItemsQuery.test.tsx
@@ -5,7 +5,7 @@ import { RecoilRoot } from 'recoil';
import { useGenerateCombinedFindManyRecordsQuery } from '@/object-record/multiple-objects/hooks/useGenerateCombinedFindManyRecordsQuery';
import { JestObjectMetadataItemSetter } from '~/testing/jest/JestObjectMetadataItemSetter';
-import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
+import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
const Wrapper = ({ children }: { children: ReactNode }) => (
diff --git a/packages/twenty-front/src/modules/object-record/hooks/__tests__/useLazyFindOneRecord.test.tsx b/packages/twenty-front/src/modules/object-record/hooks/__tests__/useLazyFindOneRecord.test.tsx
index 013889b934cd..77833552d8db 100644
--- a/packages/twenty-front/src/modules/object-record/hooks/__tests__/useLazyFindOneRecord.test.tsx
+++ b/packages/twenty-front/src/modules/object-record/hooks/__tests__/useLazyFindOneRecord.test.tsx
@@ -1,7 +1,4 @@
-import { ReactNode } from 'react';
-import { MockedProvider } from '@apollo/client/testing';
import { act, renderHook, waitFor } from '@testing-library/react';
-import { RecoilRoot } from 'recoil';
import {
query,
@@ -9,7 +6,7 @@ import {
variables,
} from '@/object-record/hooks/__mocks__/useFindOneRecord';
import { useLazyFindOneRecord } from '@/object-record/hooks/useLazyFindOneRecord';
-import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarProviderScope';
+import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
const mocks = [
{
@@ -25,15 +22,9 @@ const mocks = [
},
];
-const Wrapper = ({ children }: { children: ReactNode }) => (
-
-
-
- {children}
-
-
-
-);
+const Wrapper = getJestMetadataAndApolloMocksWrapper({
+ apolloMocks: mocks,
+});
const objectRecordId = '6205681e-7c11-40b4-9e32-f523dbe54590';
diff --git a/packages/twenty-front/src/modules/object-record/hooks/__tests__/useObjectRecordTable.test.tsx b/packages/twenty-front/src/modules/object-record/hooks/__tests__/useObjectRecordTable.test.tsx
index 627991b7f41d..4cd4cdbffc11 100644
--- a/packages/twenty-front/src/modules/object-record/hooks/__tests__/useObjectRecordTable.test.tsx
+++ b/packages/twenty-front/src/modules/object-record/hooks/__tests__/useObjectRecordTable.test.tsx
@@ -1,13 +1,12 @@
-import { ReactNode } from 'react';
-import { MockedProvider } from '@apollo/client/testing';
import { expect } from '@storybook/test';
import { renderHook } from '@testing-library/react';
-import { RecoilRoot } from 'recoil';
+import { ReactNode } from 'react';
+import { mocks } from '@/auth/hooks/__mocks__/useAuth';
import { useLoadRecordIndexTable } from '@/object-record/record-index/hooks/useLoadRecordIndexTable';
import { RecordTableScope } from '@/object-record/record-table/scopes/RecordTableScope';
-import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarProviderScope';
import { getScopeIdFromComponentId } from '@/ui/utilities/recoil-scope/utils/getScopeIdFromComponentId';
+import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
const recordTableId = 'people';
const objectNameSingular = 'person';
@@ -17,20 +16,22 @@ const ObjectNamePluralSetter = ({ children }: { children: ReactNode }) => {
return <>{children}>;
};
+const HookMockWrapper = getJestMetadataAndApolloMocksWrapper({
+ apolloMocks: mocks,
+});
+
const Wrapper = ({ children }: { children: ReactNode }) => {
return (
-
+
-
- {children}
-
+ {children}
-
+
);
};
diff --git a/packages/twenty-front/src/modules/object-record/hooks/__tests__/useUpdateOneRecord.test.tsx b/packages/twenty-front/src/modules/object-record/hooks/__tests__/useUpdateOneRecord.test.tsx
index eb6e7048d316..d32ef37508b1 100644
--- a/packages/twenty-front/src/modules/object-record/hooks/__tests__/useUpdateOneRecord.test.tsx
+++ b/packages/twenty-front/src/modules/object-record/hooks/__tests__/useUpdateOneRecord.test.tsx
@@ -1,7 +1,4 @@
-import { MockedProvider } from '@apollo/client/testing';
import { act, renderHook } from '@testing-library/react';
-import { ReactNode } from 'react';
-import { RecoilRoot } from 'recoil';
import {
query,
@@ -9,6 +6,7 @@ import {
variables,
} from '@/object-record/hooks/__mocks__/useUpdateOneRecord';
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
+import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
const person = { id: '36abbb63-34ed-4a16-89f5-f549ac55d0f9' };
const update = {
@@ -37,13 +35,9 @@ const mocks = [
},
];
-const Wrapper = ({ children }: { children: ReactNode }) => (
-
-
- {children}
-
-
-);
+const Wrapper = getJestMetadataAndApolloMocksWrapper({
+ apolloMocks: mocks,
+});
const idToUpdate = '36abbb63-34ed-4a16-89f5-f549ac55d0f9';
diff --git a/packages/twenty-front/src/modules/object-record/hooks/__tests__/useUpdateOneRecordMutation.test.tsx b/packages/twenty-front/src/modules/object-record/hooks/__tests__/useUpdateOneRecordMutation.test.tsx
index 7581e1612582..be862743e9b8 100644
--- a/packages/twenty-front/src/modules/object-record/hooks/__tests__/useUpdateOneRecordMutation.test.tsx
+++ b/packages/twenty-front/src/modules/object-record/hooks/__tests__/useUpdateOneRecordMutation.test.tsx
@@ -1,18 +1,22 @@
import { renderHook } from '@testing-library/react';
import { print } from 'graphql';
-import { RecoilRoot } from 'recoil';
-import { PERSON_FRAGMENT } from '@/object-record/hooks/__mocks__/personFragment';
+import { PERSON_FRAGMENT_WITH_DEPTH_ZERO_RELATIONS } from '@/object-record/hooks/__mocks__/personFragments';
import { useUpdateOneRecordMutation } from '@/object-record/hooks/useUpdateOneRecordMutation';
+import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
import { normalizeGQLQuery } from '~/utils/normalizeGQLQuery';
const expectedQueryTemplate = `
mutation UpdateOnePerson($idToUpdate: ID!, $input: PersonUpdateInput!) {
updatePerson(id: $idToUpdate, data: $input) {
- ${PERSON_FRAGMENT}
+ ${PERSON_FRAGMENT_WITH_DEPTH_ZERO_RELATIONS}
}
}`;
+const Wrapper = getJestMetadataAndApolloMocksWrapper({
+ apolloMocks: [],
+});
+
describe('useUpdateOneRecordMutation', () => {
it('should return a valid createManyRecordsMutation', () => {
const objectNameSingular = 'person';
@@ -23,7 +27,7 @@ describe('useUpdateOneRecordMutation', () => {
objectNameSingular,
}),
{
- wrapper: RecoilRoot,
+ wrapper: Wrapper,
},
);
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 bd75db4a75a4..7b73f918fd74 100644
--- a/packages/twenty-front/src/modules/object-record/hooks/useFindDuplicateRecords.ts
+++ b/packages/twenty-front/src/modules/object-record/hooks/useFindDuplicateRecords.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/useFindManyRecords.ts b/packages/twenty-front/src/modules/object-record/hooks/useFindManyRecords.ts
index c5f22c9f640e..0dac0caa6d68 100644
--- a/packages/twenty-front/src/modules/object-record/hooks/useFindManyRecords.ts
+++ b/packages/twenty-front/src/modules/object-record/hooks/useFindManyRecords.ts
@@ -1,7 +1,5 @@
import { useQuery, WatchQueryFetchPolicy } from '@apollo/client';
-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 { RecordGqlOperationFindManyResult } from '@/object-record/graphql/types/RecordGqlOperationFindManyResult';
@@ -36,7 +34,6 @@ export const useFindManyRecords = ({
onCompleted,
cursorFilter,
}: UseFindManyRecordsParams) => {
- const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState);
const { objectMetadataItem } = useObjectMetadataItem({
objectNameSingular,
});
@@ -66,7 +63,7 @@ export const useFindManyRecords = ({
const { data, loading, error, fetchMore } =
useQuery(findManyRecordsQuery, {
- skip: skip || !objectMetadataItem || !currentWorkspaceMember,
+ skip: skip || !objectMetadataItem,
variables: {
filter,
orderBy,
diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/getSourceEnumOptions.ts b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/getSourceEnumOptions.ts
index ee886da633e0..7006bb1ed8f1 100644
--- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/getSourceEnumOptions.ts
+++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/getSourceEnumOptions.ts
@@ -4,6 +4,7 @@ import {
IconCsv,
IconGmail,
IconGoogleCalendar,
+ IconRobot,
IconSettingsAutomation,
IconUserCircle,
} from 'twenty-ui';
@@ -52,5 +53,12 @@ export const getSourceEnumOptions = (
AvatarIcon: IconSettingsAutomation,
isIconInverted: true,
},
+ {
+ id: 'SYSTEM',
+ name: 'System',
+ isSelected: selectedItemIds.includes('SYSTEM'),
+ AvatarIcon: IconRobot,
+ isIconInverted: true,
+ },
];
};
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 346987c009c0..d336467e8db3 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
@@ -339,6 +339,7 @@ export const RecordBoardCard = ({
metadata: fieldDefinition.metadata,
type: fieldDefinition.type,
}),
+ settings: fieldDefinition.settings,
},
useUpdateRecord: useUpdateOneRecordHook,
hotkeyScope: InlineCellHotkeyScope.InlineCell,
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
index 4aeafd96f1fd..afaf8e9d78f4 100644
--- 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
@@ -1,7 +1,8 @@
-import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
+import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
+import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader';
import {
StyledBoardCardBody,
StyledBoardCardHeader,
@@ -43,7 +44,10 @@ export const RecordBoardColumnCardContainerSkeletonLoader = ({
>
-
+
@@ -51,8 +55,14 @@ export const RecordBoardColumnCardContainerSkeletonLoader = ({
skeletonItems.map(({ 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 d0d7e93de02c..e0ae827280d9 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
@@ -93,7 +93,6 @@ export const RecordBoardColumnHeader = () => {
newRecord,
handleNewButtonClick,
handleCreateSuccess,
-
handleEntitySelect,
} = useColumnNewCardActions(columnDefinition.id);
const { isOpportunitiesCompanyFieldDisabled } =
diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/hooks/useAddNewCard.ts b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/hooks/useAddNewCard.ts
index f0921f82f380..97cb8c5d6052 100644
--- a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/hooks/useAddNewCard.ts
+++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/hooks/useAddNewCard.ts
@@ -1,6 +1,7 @@
import { RecordBoardContext } from '@/object-record/record-board/contexts/RecordBoardContext';
import { RecordBoardColumnContext } from '@/object-record/record-board/record-board-column/contexts/RecordBoardColumnContext';
import { recordBoardNewRecordByColumnIdSelector } from '@/object-record/record-board/states/selectors/recordBoardNewRecordByColumnIdSelector';
+import { useEntitySelectSearch } from '@/object-record/relation-picker/hooks/useEntitySelectSearch';
import { EntityForSelect } from '@/object-record/relation-picker/types/EntityForSelect';
import { RelationPickerHotkeyScope } from '@/object-record/relation-picker/types/RelationPickerHotkeyScope';
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
@@ -17,6 +18,9 @@ export const useAddNewCard = () => {
const columnContext = useContext(RecordBoardColumnContext);
const { createOneRecord, selectFieldMetadataItem } =
useContext(RecordBoardContext);
+ const { resetSearchFilter } = useEntitySelectSearch({
+ relationPickerScopeId: 'relation-picker',
+ });
const {
goBackToPreviousHotkeyScope,
@@ -132,11 +136,12 @@ export const useAddNewCard = () => {
company: null,
},
);
+ resetSearchFilter();
if (isOpportunity === true) {
goBackToPreviousHotkeyScope();
}
},
- [getColumnDefinitionId, goBackToPreviousHotkeyScope],
+ [getColumnDefinitionId, goBackToPreviousHotkeyScope, resetSearchFilter],
);
const handleCreate = (
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 e688a2a64544..90cd7f176e26 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
@@ -9,10 +9,8 @@ import {
FieldTextMetadata
} from '@/object-record/record-field/types/FieldMetadata';
import { FieldMetadataType } from '~/generated-metadata/graphql';
-import {
- mockedCompanyObjectMetadataItem,
- mockedPersonObjectMetadataItem,
-} from '~/testing/mock-data/metadata';
+import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
+
export const fieldMetadataId = 'fieldMetadataId';
export const textfieldDefinition: FieldDefinition = {
@@ -24,7 +22,16 @@ export const textfieldDefinition: FieldDefinition = {
metadata: { placeHolder: 'John Doe', fieldName: 'userName' },
};
-const relationFieldMetadataItem = mockedPersonObjectMetadataItem.fields?.find(
+const mockedPersonObjectMetadataItem = generatedMockObjectMetadataItems.find(
+ ({ nameSingular }) => nameSingular === 'person',
+);
+
+if (!mockedPersonObjectMetadataItem) {
+ throw new Error('Person object metadata item not found');
+}
+
+
+const relationFieldMetadataItem = mockedPersonObjectMetadataItem?.fields?.find(
({ name }) => name === 'company',
);
@@ -91,7 +98,15 @@ export const ratingFieldDefinition: FieldDefinition = {
},
};
-const booleanFieldMetadataItem = mockedCompanyObjectMetadataItem.fields?.find(
+const mockedCompanyObjectMetadataItem = generatedMockObjectMetadataItems.find(
+ (item) => item.nameSingular === 'company',
+);
+
+if (!mockedCompanyObjectMetadataItem) {
+ throw new Error('Company object metadata item not found');
+}
+
+const booleanFieldMetadataItem = mockedCompanyObjectMetadataItem?.fields?.find(
({ name }) => name === 'idealCustomerProfile',
);
export const booleanFieldDefinition = formatFieldMetadataItemAsFieldDefinition({
diff --git a/packages/twenty-front/src/modules/object-record/record-field/hooks/__tests__/usePersistField.test.tsx b/packages/twenty-front/src/modules/object-record/record-field/hooks/__tests__/usePersistField.test.tsx
index 2e8756c2e8f0..4eea3aae834f 100644
--- a/packages/twenty-front/src/modules/object-record/record-field/hooks/__tests__/usePersistField.test.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-field/hooks/__tests__/usePersistField.test.tsx
@@ -1,11 +1,11 @@
import { gql } from '@apollo/client';
-import { MockedProvider, MockedResponse } from '@apollo/client/testing';
+import { MockedResponse } from '@apollo/client/testing';
import { act, renderHook, waitFor } from '@testing-library/react';
import { ReactNode } from 'react';
-import { RecoilRoot, useRecoilValue } from 'recoil';
+import { useRecoilValue } from 'recoil';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
-import { PERSON_FRAGMENT } from '@/object-record/hooks/__mocks__/personFragment';
+import { PERSON_FRAGMENT_WITH_DEPTH_ONE_RELATIONS } from '@/object-record/hooks/__mocks__/personFragments';
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
import {
phonesFieldDefinition,
@@ -20,11 +20,12 @@ import { usePersistField } from '@/object-record/record-field/hooks/usePersistFi
import { FieldDefinition } from '@/object-record/record-field/types/FieldDefinition';
import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata';
import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector';
+import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
const query = gql`
mutation UpdateOnePerson($idToUpdate: ID!, $input: PersonUpdateInput!) {
updatePerson(id: $idToUpdate, data: $input) {
- ${PERSON_FRAGMENT}
+ ${PERSON_FRAGMENT_WITH_DEPTH_ONE_RELATIONS}
}
}
`;
@@ -72,6 +73,10 @@ const mocks: MockedResponse[] = [
const recordId = 'recordId';
+const JestMetadataAndApolloMocksWrapper = getJestMetadataAndApolloMocksWrapper({
+ apolloMocks: mocks,
+});
+
const getWrapper =
(fieldDefinition: FieldDefinition) =>
({ children }: { children: ReactNode }) => {
@@ -91,7 +96,7 @@ const getWrapper =
};
return (
-
+
- {children}
+ {children}
-
+
);
};
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 86a2037c5d2c..5ec442483de4 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
@@ -1,8 +1,7 @@
import { gql } from '@apollo/client';
-import { MockedProvider, MockedResponse } from '@apollo/client/testing';
-import { act, renderHook, waitFor } from '@testing-library/react';
-import { ReactNode } from 'react';
-import { RecoilRoot } from 'recoil';
+import { MockedResponse } from '@apollo/client/testing';
+import { renderHook, waitFor } from '@testing-library/react';
+import { ReactNode, act } from 'react';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
@@ -13,6 +12,8 @@ import {
RecordUpdateHookParams,
} from '@/object-record/record-field/contexts/FieldContext';
import { useToggleEditOnlyInput } from '@/object-record/record-field/hooks/useToggleEditOnlyInput';
+import { generateEmptyJestRecordNode } from '~/testing/jest/generateEmptyJestRecordNode';
+import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
const recordId = 'recordId';
@@ -26,13 +27,42 @@ const mocks: MockedResponse[] = [
) {
updateCompany(id: $idToUpdate, data: $input) {
__typename
- updatedAt
- domainName {
- primaryLinkUrl
- primaryLinkLabel
- secondaryLinks
+ accountOwner {
+ __typename
+ avatarUrl
+ colorScheme
+ createdAt
+ dateFormat
+ deletedAt
+ id
+ locale
+ name {
+ firstName
+ lastName
+ }
+ timeFormat
+ timeZone
+ updatedAt
+ userEmail
+ userId
+ }
+ accountOwnerId
+ activityTargets {
+ edges {
+ node {
+ __typename
+ activityId
+ companyId
+ createdAt
+ deletedAt
+ id
+ opportunityId
+ personId
+ rocketId
+ updatedAt
+ }
+ }
}
- visaSponsorship
address {
addressStreet1
addressStreet2
@@ -43,20 +73,31 @@ const mocks: MockedResponse[] = [
addressLat
addressLng
}
- position
- employees
- deletedAt
- accountOwnerId
annualRecurringRevenue {
amountMicros
currencyCode
}
- id
- name
- xLink {
- primaryLinkUrl
- primaryLinkLabel
- secondaryLinks
+ attachments {
+ edges {
+ node {
+ __typename
+ activityId
+ authorId
+ companyId
+ createdAt
+ deletedAt
+ fullPath
+ id
+ name
+ noteId
+ opportunityId
+ personId
+ rocketId
+ taskId
+ type
+ updatedAt
+ }
+ }
}
createdAt
createdBy {
@@ -64,7 +105,36 @@ const mocks: MockedResponse[] = [
workspaceMemberId
name
}
- workPolicy
+ deletedAt
+ domainName {
+ primaryLinkUrl
+ primaryLinkLabel
+ secondaryLinks
+ }
+ employees
+ favorites {
+ edges {
+ node {
+ __typename
+ companyId
+ createdAt
+ deletedAt
+ id
+ noteId
+ opportunityId
+ personId
+ position
+ rocketId
+ taskId
+ updatedAt
+ viewId
+ workflowId
+ workspaceMemberId
+ }
+ }
+ }
+ id
+ idealCustomerProfile
introVideo {
primaryLinkUrl
primaryLinkLabel
@@ -75,8 +145,151 @@ const mocks: MockedResponse[] = [
primaryLinkLabel
secondaryLinks
}
+ name
+ noteTargets {
+ edges {
+ node {
+ __typename
+ companyId
+ createdAt
+ deletedAt
+ id
+ noteId
+ opportunityId
+ personId
+ rocketId
+ updatedAt
+ }
+ }
+ }
+ opportunities {
+ edges {
+ node {
+ __typename
+ amount {
+ amountMicros
+ currencyCode
+ }
+ closeDate
+ companyId
+ createdAt
+ createdBy {
+ source
+ workspaceMemberId
+ name
+ }
+ deletedAt
+ id
+ name
+ pointOfContactId
+ position
+ stage
+ updatedAt
+ }
+ }
+ }
+ people {
+ edges {
+ node {
+ __typename
+ avatarUrl
+ city
+ companyId
+ createdAt
+ createdBy {
+ source
+ workspaceMemberId
+ name
+ }
+ deletedAt
+ emails {
+ primaryEmail
+ additionalEmails
+ }
+ id
+ intro
+ jobTitle
+ linkedinLink {
+ primaryLinkUrl
+ primaryLinkLabel
+ secondaryLinks
+ }
+ name {
+ firstName
+ lastName
+ }
+ performanceRating
+ phones {
+ primaryPhoneNumber
+ primaryPhoneCountryCode
+ additionalPhones
+ }
+ position
+ updatedAt
+ whatsapp {
+ primaryPhoneNumber
+ primaryPhoneCountryCode
+ additionalPhones
+ }
+ workPreference
+ xLink {
+ primaryLinkUrl
+ primaryLinkLabel
+ secondaryLinks
+ }
+ }
+ }
+ }
+ position
tagline
- idealCustomerProfile
+ taskTargets {
+ edges {
+ node {
+ __typename
+ companyId
+ createdAt
+ deletedAt
+ id
+ opportunityId
+ personId
+ rocketId
+ taskId
+ updatedAt
+ }
+ }
+ }
+ timelineActivities {
+ edges {
+ node {
+ __typename
+ companyId
+ createdAt
+ deletedAt
+ happensAt
+ id
+ linkedObjectMetadataId
+ linkedRecordCachedName
+ linkedRecordId
+ name
+ noteId
+ opportunityId
+ personId
+ properties
+ rocketId
+ taskId
+ updatedAt
+ workspaceMemberId
+ }
+ }
+ }
+ updatedAt
+ visaSponsorship
+ workPolicy
+ xLink {
+ primaryLinkUrl
+ primaryLinkLabel
+ secondaryLinks
+ }
}
}
`,
@@ -87,8 +300,12 @@ const mocks: MockedResponse[] = [
},
result: jest.fn(() => ({
data: {
- updateWorkspaceMember: {
- id: 'recordId',
+ updateCompany: {
+ ...generateEmptyJestRecordNode({
+ objectNameSingular: CoreObjectNameSingular.Company,
+ input: { id: recordId },
+ withDepthOneRelation: true,
+ }),
},
},
})),
@@ -111,8 +328,13 @@ const Wrapper = ({ children }: { children: ReactNode }) => {
return [updateEntity, { loading: false }];
};
+ const JestMetadataAndApolloMocksWrapper =
+ getJestMetadataAndApolloMocksWrapper({
+ apolloMocks: mocks,
+ });
+
return (
-
+
{
useUpdateRecord: useUpdateOneRecordMutation,
}}
>
- {children}
+ {children}
-
+
);
};
diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/NumberFieldDisplay.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/NumberFieldDisplay.tsx
index 087a4117c47b..cb30dbed3776 100644
--- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/NumberFieldDisplay.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/NumberFieldDisplay.tsx
@@ -2,7 +2,11 @@ import { useNumberFieldDisplay } from '@/object-record/record-field/meta-types/h
import { NumberDisplay } from '@/ui/field/display/components/NumberDisplay';
export const NumberFieldDisplay = () => {
- const { fieldValue } = useNumberFieldDisplay();
-
- return ;
+ const { fieldValue, fieldDefinition } = useNumberFieldDisplay();
+ return (
+
+ );
};
diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/DateTimeFieldDisplay.perf.stories.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/DateTimeFieldDisplay.perf.stories.tsx
index 079b84520e91..9e2cb6b78622 100644
--- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/DateTimeFieldDisplay.perf.stories.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/DateTimeFieldDisplay.perf.stories.tsx
@@ -51,6 +51,6 @@ export const Elipsis: Story = {
export const Performance = getProfilingStory({
componentName: 'DateTimeFieldDisplay',
averageThresholdInMs: 0.1,
- numberOfRuns: 50,
- numberOfTestsPerRun: 100,
+ numberOfRuns: 30,
+ numberOfTestsPerRun: 30,
});
diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/EmailFieldDisplay.perf.stories.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/EmailsFieldDisplay.perf.stories.tsx
similarity index 55%
rename from packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/EmailFieldDisplay.perf.stories.tsx
rename to packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/EmailsFieldDisplay.perf.stories.tsx
index b901caa9c1cd..283224dd88a5 100644
--- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/EmailFieldDisplay.perf.stories.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/EmailsFieldDisplay.perf.stories.tsx
@@ -1,19 +1,22 @@
import { Meta, StoryObj } from '@storybook/react';
import { ComponentDecorator } from 'twenty-ui';
-import { EmailFieldDisplay } from '@/object-record/record-field/meta-types/display/components/EmailFieldDisplay';
+import { EmailsFieldDisplay } from '@/object-record/record-field/meta-types/display/components/EmailsFieldDisplay';
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/EmailFieldDisplay',
+ title: 'UI/Data/Field/Display/EmailsFieldDisplay',
decorators: [
MemoryRouterDecorator,
- getFieldDecorator('person', 'email'),
+ getFieldDecorator('person', 'emails', {
+ primaryEmail: 'test@test.com',
+ additionalEmails: ['toto@test.com'],
+ }),
ComponentDecorator,
],
- component: EmailFieldDisplay,
+ component: EmailsFieldDisplay,
args: {},
parameters: {
chromatic: { disableSnapshot: true },
@@ -22,25 +25,25 @@ const meta: Meta = {
export default meta;
-type Story = StoryObj;
+type Story = StoryObj;
export const Default: Story = {};
export const Elipsis: Story = {
parameters: {
- container: { width: 50 },
+ container: { width: 100 },
},
decorators: [
- getFieldDecorator(
- 'person',
- 'email',
- 'asdasdasdaksjdhkajshdkajhasmdkamskdsd@asdkjhaksjdhaksjd.com',
- ),
+ getFieldDecorator('person', 'emails', {
+ primaryEmail:
+ 'asdasdasdaksjdhkajshdkajhasmdkamskdsd@asdkjhaksjdhaksjd.com',
+ additionalEmails: [],
+ }),
],
};
export const Performance = getProfilingStory({
- componentName: 'EmailFieldDisplay',
+ componentName: 'EmailsFieldDisplay',
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/JsonFieldDisplay.perf.stories.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/JsonFieldDisplay.perf.stories.tsx
deleted file mode 100644
index be1567d863b0..000000000000
--- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/JsonFieldDisplay.perf.stories.tsx
+++ /dev/null
@@ -1,43 +0,0 @@
-import { Meta, StoryObj } from '@storybook/react';
-import { ComponentDecorator } from 'twenty-ui';
-
-import { JsonFieldDisplay } from '@/object-record/record-field/meta-types/display/components/JsonFieldDisplay';
-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/JsonFieldDisplay',
- decorators: [
- MemoryRouterDecorator,
- getFieldDecorator('company', 'testRawJson', {
- key1: 'value1',
- key2: 'value2',
- }),
- ComponentDecorator,
- ],
- component: JsonFieldDisplay,
- args: {},
- parameters: {
- chromatic: { disableSnapshot: true },
- },
-};
-
-export default meta;
-
-type Story = StoryObj;
-
-export const Default: Story = {};
-
-export const Elipsis: Story = {
- parameters: {
- container: { width: 50 },
- },
-};
-
-export const Performance = getProfilingStory({
- componentName: 'JsonFieldDisplay',
- averageThresholdInMs: 0.1,
- numberOfRuns: 50,
- numberOfTestsPerRun: 100,
-});
diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/MultiSelectFieldDisplay.perf.stories.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/MultiSelectFieldDisplay.perf.stories.tsx
index ec9a8291d2c5..0eae95f09db0 100644
--- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/MultiSelectFieldDisplay.perf.stories.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/MultiSelectFieldDisplay.perf.stories.tsx
@@ -23,7 +23,7 @@ const meta: Meta = {
title: 'UI/Data/Field/Display/MultiSelectFieldDisplay',
decorators: [
MemoryRouterDecorator,
- getFieldDecorator('company', 'testMultiSelect', [
+ getFieldDecorator('company', 'workPolicy', [
'Option 1',
'Option 2',
'Option 3',
diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/PhoneFieldDisplay.perf.stories.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/PhonesFieldDisplay.perf.stories.tsx
similarity index 61%
rename from packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/PhoneFieldDisplay.perf.stories.tsx
rename to packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/PhonesFieldDisplay.perf.stories.tsx
index fed4bbe247a3..94f37ee5cfb6 100644
--- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/PhoneFieldDisplay.perf.stories.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/PhonesFieldDisplay.perf.stories.tsx
@@ -1,19 +1,19 @@
import { Meta, StoryObj } from '@storybook/react';
import { ComponentDecorator } from 'twenty-ui';
-import { PhoneFieldDisplay } from '@/object-record/record-field/meta-types/display/components/PhoneFieldDisplay';
+import { PhonesFieldDisplay } from '@/object-record/record-field/meta-types/display/components/PhonesFieldDisplay';
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/PhoneFieldDisplay',
+ title: 'UI/Data/Field/Display/PhonesFieldDisplay',
decorators: [
MemoryRouterDecorator,
- getFieldDecorator('person', 'phone'),
+ getFieldDecorator('person', 'phones'),
ComponentDecorator,
],
- component: PhoneFieldDisplay,
+ component: PhonesFieldDisplay,
args: {},
parameters: {
chromatic: { disableSnapshot: true },
@@ -22,7 +22,7 @@ const meta: Meta = {
export default meta;
-type Story = StoryObj;
+type Story = StoryObj;
export const Default: Story = {};
@@ -33,11 +33,17 @@ export const Elipsis: Story = {
};
export const WrongNumber: Story = {
- decorators: [getFieldDecorator('person', 'phone', 'sdklaskdj')],
+ decorators: [
+ getFieldDecorator('person', 'phones', {
+ primaryPhoneNumber: '123-456-7890',
+ primaryPhoneCountryCode: '+1',
+ additionalPhones: null,
+ }),
+ ],
};
export const Performance = getProfilingStory({
- componentName: 'PhoneFieldDisplay',
+ componentName: 'PhonesFieldDisplay',
averageThresholdInMs: 0.5,
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
index 3c31dc6d5682..3d4b5950aea0 100644
--- 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
@@ -10,7 +10,7 @@ const meta: Meta = {
title: 'UI/Data/Field/Display/RatingFieldDisplay',
decorators: [
MemoryRouterDecorator,
- getFieldDecorator('company', 'testRating'),
+ getFieldDecorator('person', 'performanceRating'),
ComponentDecorator,
],
component: RatingFieldDisplay,
@@ -30,5 +30,5 @@ export const Performance = getProfilingStory({
componentName: 'RatingFieldDisplay',
averageThresholdInMs: 0.5,
numberOfRuns: 30,
- numberOfTestsPerRun: 50,
+ numberOfTestsPerRun: 30,
});
diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/RelationToOneFieldDisplay.perf.stories.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/RelationToOneFieldDisplay.perf.stories.tsx
index 49a076d80a47..989de5e7439f 100644
--- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/RelationToOneFieldDisplay.perf.stories.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/RelationToOneFieldDisplay.perf.stories.tsx
@@ -30,7 +30,7 @@ export const Default: Story = {};
export const Performance = getProfilingStory({
componentName: 'RelationFieldDisplay',
- averageThresholdInMs: 0.2,
+ averageThresholdInMs: 0.22,
numberOfRuns: 20,
numberOfTestsPerRun: 100,
});
diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useNumberField.ts b/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useNumberField.ts
index 5bdceda11e73..097bcb8beef5 100644
--- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useNumberField.ts
+++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useNumberField.ts
@@ -5,10 +5,11 @@ import { useRecordFieldInput } from '@/object-record/record-field/hooks/useRecor
import { FieldNumberValue } from '@/object-record/record-field/types/FieldMetadata';
import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector';
import { FieldMetadataType } from '~/generated-metadata/graphql';
+
import {
- canBeCastAsIntegerOrNull,
- castAsIntegerOrNull,
-} from '~/utils/cast-as-integer-or-null';
+ canBeCastAsNumberOrNull,
+ castAsNumberOrNull,
+} from '~/utils/cast-as-number-or-null';
import { FieldContext } from '../../contexts/FieldContext';
import { usePersistField } from '../../hooks/usePersistField';
@@ -32,11 +33,11 @@ export const useNumberField = () => {
const persistField = usePersistField();
const persistNumberField = (newValue: string) => {
- if (!canBeCastAsIntegerOrNull(newValue)) {
+ if (!canBeCastAsNumberOrNull(newValue)) {
return;
}
- const castedValue = castAsIntegerOrNull(newValue);
+ const castedValue = castAsNumberOrNull(newValue);
persistField(castedValue);
};
diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/EmailsFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/EmailsFieldInput.tsx
index 32418cebc607..d933aeabcd06 100644
--- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/EmailsFieldInput.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/EmailsFieldInput.tsx
@@ -1,6 +1,7 @@
import { useEmailsField } from '@/object-record/record-field/meta-types/hooks/useEmailsField';
import { EmailsFieldMenuItem } from '@/object-record/record-field/meta-types/input/components/EmailsFieldMenuItem';
-import { useMemo } from 'react';
+import { emailSchema } from '@/object-record/record-field/validation-schemas/emailSchema';
+import { useCallback, useMemo } from 'react';
import { isDefined } from 'twenty-ui';
import { FieldMetadataType } from '~/generated-metadata/graphql';
import { MultiItemFieldInput } from './MultiItemFieldInput';
@@ -29,6 +30,14 @@ export const EmailsFieldInput = ({ onCancel }: EmailsFieldInputProps) => {
});
};
+ const validateInput = useCallback(
+ (input: string) => ({
+ isValid: emailSchema.safeParse(input).success,
+ errorMessage: '',
+ }),
+ [],
+ );
+
const isPrimaryEmail = (index: number) => index === 0 && emails?.length > 1;
return (
@@ -38,6 +47,7 @@ export const EmailsFieldInput = ({ onCancel }: EmailsFieldInputProps) => {
onCancel={onCancel}
placeholder="Email"
fieldMetadataType={FieldMetadataType.Emails}
+ validateInput={validateInput}
renderItem={({
value: email,
index,
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 97bc9578c97c..e52cc95c041f 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
@@ -51,7 +51,10 @@ export const LinksFieldInput = ({ onCancel }: LinksFieldInputProps) => {
onCancel={onCancel}
placeholder="URL"
fieldMetadataType={FieldMetadataType.Links}
- validateInput={(input) => absoluteUrlSchema.safeParse(input).success}
+ validateInput={(input) => ({
+ isValid: absoluteUrlSchema.safeParse(input).success,
+ errorMessage: '',
+ })}
formatInput={(input) => ({ url: input, label: '' })}
renderItem={({
value: link,
diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/MultiItemFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/MultiItemFieldInput.tsx
index a73e49498805..7e3e93ec2c48 100644
--- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/MultiItemFieldInput.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/MultiItemFieldInput.tsx
@@ -30,7 +30,7 @@ type MultiItemFieldInputProps = {
onPersist: (updatedItems: T[]) => void;
onCancel?: () => void;
placeholder: string;
- validateInput?: (input: string) => boolean;
+ validateInput?: (input: string) => { isValid: boolean; errorMessage: string };
formatInput?: (input: string) => T;
renderItem: (props: {
value: T;
@@ -74,8 +74,21 @@ export const MultiItemFieldInput = ({
const [isInputDisplayed, setIsInputDisplayed] = useState(false);
const [inputValue, setInputValue] = useState('');
const [itemToEditIndex, setItemToEditIndex] = useState(-1);
+ const [errorData, setErrorData] = useState({
+ isValid: true,
+ errorMessage: '',
+ });
const isAddingNewItem = itemToEditIndex === -1;
+ const handleOnChange = (value: string) => {
+ setInputValue(value);
+ if (!validateInput) return;
+
+ if (errorData.isValid) {
+ setErrorData(errorData);
+ }
+ };
+
const handleAddButtonClick = () => {
setItemToEditIndex(-1);
setIsInputDisplayed(true);
@@ -105,7 +118,13 @@ export const MultiItemFieldInput = ({
};
const handleSubmitInput = () => {
- if (validateInput !== undefined && !validateInput(inputValue)) return;
+ if (validateInput !== undefined) {
+ const validationData = validateInput(inputValue) ?? { isValid: true };
+ if (!validationData.isValid) {
+ setErrorData(validationData);
+ return;
+ }
+ }
const newItem = formatInput
? formatInput(inputValue)
@@ -160,6 +179,7 @@ export const MultiItemFieldInput = ({
placeholder={placeholder}
value={inputValue}
hotkeyScope={hotkeyScope}
+ hasError={!errorData.isValid}
renderInput={
renderInput
? (props) =>
@@ -170,7 +190,7 @@ export const MultiItemFieldInput = ({
})
: undefined
}
- onChange={(event) => setInputValue(event.target.value)}
+ onChange={(event) => handleOnChange(event.target.value)}
onEnter={handleSubmitInput}
rightComponent={
= {
infoTooltipContent?: string;
defaultValue?: any;
editButtonIcon?: IconComponent;
+ settings?: {
+ decimals?: number;
+ };
};
diff --git a/packages/twenty-front/src/modules/object-record/record-field/validation-schemas/emailSchema.ts b/packages/twenty-front/src/modules/object-record/record-field/validation-schemas/emailSchema.ts
new file mode 100644
index 000000000000..fae5812b3ad7
--- /dev/null
+++ b/packages/twenty-front/src/modules/object-record/record-field/validation-schemas/emailSchema.ts
@@ -0,0 +1,3 @@
+import { z } from 'zod';
+
+export const emailSchema = z.string().email();
diff --git a/packages/twenty-front/src/modules/object-record/record-field/validation-schemas/numberFieldDefaultValueSchema.ts b/packages/twenty-front/src/modules/object-record/record-field/validation-schemas/numberFieldDefaultValueSchema.ts
new file mode 100644
index 000000000000..48981e4a5a34
--- /dev/null
+++ b/packages/twenty-front/src/modules/object-record/record-field/validation-schemas/numberFieldDefaultValueSchema.ts
@@ -0,0 +1,5 @@
+import { z } from 'zod';
+
+export const numberFieldDefaultValueSchema = z.object({
+ decimals: z.number().nullable(),
+});
diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingBooleanFilter.spec.ts b/packages/twenty-front/src/modules/object-record/record-filter/utils/__tests__/isMatchingBooleanFilter.test.ts
similarity index 100%
rename from packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingBooleanFilter.spec.ts
rename to packages/twenty-front/src/modules/object-record/record-filter/utils/__tests__/isMatchingBooleanFilter.test.ts
diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingCurrencyFilter.spec.ts b/packages/twenty-front/src/modules/object-record/record-filter/utils/__tests__/isMatchingCurrencyFilter.test.ts
similarity index 100%
rename from packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingCurrencyFilter.spec.ts
rename to packages/twenty-front/src/modules/object-record/record-filter/utils/__tests__/isMatchingCurrencyFilter.test.ts
diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingDateFilter.spec.ts b/packages/twenty-front/src/modules/object-record/record-filter/utils/__tests__/isMatchingDateFilter.test.ts
similarity index 100%
rename from packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingDateFilter.spec.ts
rename to packages/twenty-front/src/modules/object-record/record-filter/utils/__tests__/isMatchingDateFilter.test.ts
diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingFloatFilter.spec.ts b/packages/twenty-front/src/modules/object-record/record-filter/utils/__tests__/isMatchingFloatFilter.test.ts
similarity index 100%
rename from packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingFloatFilter.spec.ts
rename to packages/twenty-front/src/modules/object-record/record-filter/utils/__tests__/isMatchingFloatFilter.test.ts
diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingStringFilter.spec.ts b/packages/twenty-front/src/modules/object-record/record-filter/utils/__tests__/isMatchingStringFilter.test.ts
similarity index 100%
rename from packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingStringFilter.spec.ts
rename to packages/twenty-front/src/modules/object-record/record-filter/utils/__tests__/isMatchingStringFilter.test.ts
diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingUUIDFilter.spec.ts b/packages/twenty-front/src/modules/object-record/record-filter/utils/__tests__/isMatchingUUIDFilter.test.ts
similarity index 100%
rename from packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingUUIDFilter.spec.ts
rename to packages/twenty-front/src/modules/object-record/record-filter/utils/__tests__/isMatchingUUIDFilter.test.ts
diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/isRecordMatchingFilter.spec.ts b/packages/twenty-front/src/modules/object-record/record-filter/utils/__tests__/isRecordMatchingFilter.test.ts
similarity index 98%
rename from packages/twenty-front/src/modules/object-record/record-filter/utils/isRecordMatchingFilter.spec.ts
rename to packages/twenty-front/src/modules/object-record/record-filter/utils/__tests__/isRecordMatchingFilter.test.ts
index ed0b22070777..1c5e1d2b4f46 100644
--- a/packages/twenty-front/src/modules/object-record/record-filter/utils/isRecordMatchingFilter.spec.ts
+++ b/packages/twenty-front/src/modules/object-record/record-filter/utils/__tests__/isRecordMatchingFilter.test.ts
@@ -1,10 +1,11 @@
import { RecordGqlOperationFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter';
import { getCompaniesMock } from '~/testing/mock-data/companies';
-import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
+import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
import { Company } from '@/companies/types/Company';
import { getCompanyDomainName } from '@/object-metadata/utils/getCompanyDomainName';
-import { isRecordMatchingFilter } from './isRecordMatchingFilter';
+import { isRecordMatchingFilter } from '@/object-record/record-filter/utils/isRecordMatchingFilter';
+import { expect } from '@storybook/test';
const companiesMock = getCompaniesMock();
diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/__tests__/turnObjectDropdownFilterIntoQueryFilter.test.ts b/packages/twenty-front/src/modules/object-record/record-filter/utils/__tests__/turnObjectDropdownFilterIntoQueryFilter.test.ts
new file mode 100644
index 000000000000..6486ca29b92e
--- /dev/null
+++ b/packages/twenty-front/src/modules/object-record/record-filter/utils/__tests__/turnObjectDropdownFilterIntoQueryFilter.test.ts
@@ -0,0 +1,1063 @@
+import { Filter } from '@/object-record/object-filter-dropdown/types/Filter';
+import { turnObjectDropdownFilterIntoQueryFilter } from '@/object-record/record-filter/utils/turnObjectDropdownFilterIntoQueryFilter';
+import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
+import { getCompaniesMock } from '~/testing/mock-data/companies';
+import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
+
+const companiesMock = getCompaniesMock();
+
+const companyMockObjectMetadataItem = generatedMockObjectMetadataItems.find(
+ (item) => item.nameSingular === 'company',
+)!;
+
+const personMockObjectMetadataItem = generatedMockObjectMetadataItems.find(
+ (item) => item.nameSingular === 'person',
+)!;
+
+jest.useFakeTimers().setSystemTime(new Date('2020-01-01'));
+
+describe('turnObjectDropdownFilterIntoQueryFilter', () => {
+ it('should work as expected for single filter', () => {
+ const companyMockNameFieldMetadataId =
+ companyMockObjectMetadataItem.fields.find(
+ (field) => field.name === 'name',
+ );
+
+ const nameFilter: Filter = {
+ id: 'company-name-filter',
+ value: companiesMock[0].name,
+ fieldMetadataId: companyMockNameFieldMetadataId?.id,
+ displayValue: companiesMock[0].name,
+ operand: ViewFilterOperand.Contains,
+ definition: {
+ type: 'TEXT',
+ fieldMetadataId: companyMockNameFieldMetadataId?.id,
+ label: 'Name',
+ iconName: 'text',
+ },
+ };
+
+ const result = turnObjectDropdownFilterIntoQueryFilter(
+ [nameFilter],
+ companyMockObjectMetadataItem.fields,
+ );
+
+ expect(result).toEqual({
+ name: {
+ ilike: '%Linkedin%',
+ },
+ });
+ });
+
+ it('should work as expected for multiple filters', () => {
+ const companyMockNameFieldMetadataId =
+ companyMockObjectMetadataItem.fields.find(
+ (field) => field.name === 'name',
+ );
+
+ const companyMockEmployeesFieldMetadataId =
+ companyMockObjectMetadataItem.fields.find(
+ (field) => field.name === 'employees',
+ );
+
+ const nameFilter: Filter = {
+ id: 'company-name-filter',
+ value: companiesMock[0].name,
+ fieldMetadataId: companyMockNameFieldMetadataId?.id,
+ displayValue: companiesMock[0].name,
+ operand: ViewFilterOperand.Contains,
+ definition: {
+ type: 'TEXT',
+ fieldMetadataId: companyMockNameFieldMetadataId?.id,
+ label: 'Name',
+ iconName: 'text',
+ },
+ };
+
+ const employeesFilter: Filter = {
+ id: 'company-employees-filter',
+ value: '1000',
+ fieldMetadataId: companyMockEmployeesFieldMetadataId?.id,
+ displayValue: '1000',
+ operand: ViewFilterOperand.GreaterThan,
+ definition: {
+ type: 'NUMBER',
+ fieldMetadataId: companyMockEmployeesFieldMetadataId?.id,
+ label: 'Employees',
+ iconName: 'number',
+ },
+ };
+
+ const result = turnObjectDropdownFilterIntoQueryFilter(
+ [nameFilter, employeesFilter],
+ companyMockObjectMetadataItem.fields,
+ );
+
+ expect(result).toEqual({
+ and: [
+ {
+ name: {
+ ilike: '%Linkedin%',
+ },
+ },
+ {
+ employees: {
+ gte: 1000,
+ },
+ },
+ ],
+ });
+ });
+});
+
+describe('should work as expected for the different field types', () => {
+ it('address field type', () => {
+ const companyMockAddressFieldMetadataId =
+ companyMockObjectMetadataItem.fields.find(
+ (field) => field.name === 'address',
+ );
+
+ const addressFilterContains: Filter = {
+ id: 'company-address-filter-contains',
+ value: '123 Main St',
+ fieldMetadataId: companyMockAddressFieldMetadataId?.id,
+ displayValue: '123 Main St',
+ operand: ViewFilterOperand.Contains,
+ definition: {
+ type: 'ADDRESS',
+ fieldMetadataId: companyMockAddressFieldMetadataId?.id,
+ label: 'Address',
+ iconName: 'address',
+ },
+ };
+
+ const addressFilterDoesNotContain: Filter = {
+ id: 'company-address-filter-does-not-contain',
+ value: '123 Main St',
+ fieldMetadataId: companyMockAddressFieldMetadataId?.id,
+ displayValue: '123 Main St',
+ operand: ViewFilterOperand.DoesNotContain,
+ definition: {
+ type: 'ADDRESS',
+ fieldMetadataId: companyMockAddressFieldMetadataId?.id,
+ label: 'Address',
+ iconName: 'address',
+ },
+ };
+
+ const addressFilterIsEmpty: Filter = {
+ id: 'company-address-filter-is-empty',
+ value: '',
+ fieldMetadataId: companyMockAddressFieldMetadataId?.id,
+ displayValue: '',
+ operand: ViewFilterOperand.IsEmpty,
+ definition: {
+ type: 'ADDRESS',
+ fieldMetadataId: companyMockAddressFieldMetadataId?.id,
+ label: 'Address',
+ iconName: 'address',
+ },
+ };
+
+ const addressFilterIsNotEmpty: Filter = {
+ id: 'company-address-filter-is-not-empty',
+ value: '',
+ fieldMetadataId: companyMockAddressFieldMetadataId?.id,
+ displayValue: '',
+ operand: ViewFilterOperand.IsNotEmpty,
+ definition: {
+ type: 'ADDRESS',
+ fieldMetadataId: companyMockAddressFieldMetadataId?.id,
+ label: 'Address',
+ iconName: 'address',
+ },
+ };
+
+ const result = turnObjectDropdownFilterIntoQueryFilter(
+ [
+ addressFilterContains,
+ addressFilterDoesNotContain,
+ addressFilterIsEmpty,
+ addressFilterIsNotEmpty,
+ ],
+ companyMockObjectMetadataItem.fields,
+ );
+
+ expect(result).toEqual({
+ and: [
+ {
+ or: [
+ {
+ address: {
+ addressStreet1: {
+ ilike: '%123 Main St%',
+ },
+ },
+ },
+ {
+ address: {
+ addressStreet2: {
+ ilike: '%123 Main St%',
+ },
+ },
+ },
+ {
+ address: {
+ addressCity: {
+ ilike: '%123 Main St%',
+ },
+ },
+ },
+ {
+ address: {
+ addressState: {
+ ilike: '%123 Main St%',
+ },
+ },
+ },
+ {
+ address: {
+ addressCountry: {
+ ilike: '%123 Main St%',
+ },
+ },
+ },
+ {
+ address: {
+ addressPostcode: {
+ ilike: '%123 Main St%',
+ },
+ },
+ },
+ ],
+ },
+ {
+ and: [
+ {
+ not: {
+ address: {
+ addressStreet1: {
+ ilike: '%123 Main St%',
+ },
+ },
+ },
+ },
+ {
+ not: {
+ address: {
+ addressStreet2: {
+ ilike: '%123 Main St%',
+ },
+ },
+ },
+ },
+ {
+ not: {
+ address: {
+ addressCity: {
+ ilike: '%123 Main St%',
+ },
+ },
+ },
+ },
+ ],
+ },
+ {
+ and: [
+ {
+ or: [
+ {
+ address: {
+ addressStreet1: {
+ ilike: '',
+ },
+ },
+ },
+ {
+ address: {
+ addressStreet1: {
+ is: 'NULL',
+ },
+ },
+ },
+ ],
+ },
+ {
+ or: [
+ {
+ address: {
+ addressStreet2: {
+ ilike: '',
+ },
+ },
+ },
+ {
+ address: {
+ addressStreet2: {
+ is: 'NULL',
+ },
+ },
+ },
+ ],
+ },
+ {
+ or: [
+ {
+ address: {
+ addressCity: {
+ ilike: '',
+ },
+ },
+ },
+ {
+ address: {
+ addressCity: {
+ is: 'NULL',
+ },
+ },
+ },
+ ],
+ },
+ {
+ or: [
+ {
+ address: {
+ addressState: {
+ ilike: '',
+ },
+ },
+ },
+ {
+ address: {
+ addressState: {
+ is: 'NULL',
+ },
+ },
+ },
+ ],
+ },
+ {
+ or: [
+ {
+ address: {
+ addressCountry: {
+ ilike: '',
+ },
+ },
+ },
+ {
+ address: {
+ addressCountry: {
+ is: 'NULL',
+ },
+ },
+ },
+ ],
+ },
+ {
+ or: [
+ {
+ address: {
+ addressPostcode: {
+ ilike: '',
+ },
+ },
+ },
+ {
+ address: {
+ addressPostcode: {
+ is: 'NULL',
+ },
+ },
+ },
+ ],
+ },
+ ],
+ },
+ {
+ not: {
+ and: [
+ {
+ or: [
+ {
+ address: {
+ addressStreet1: {
+ ilike: '',
+ },
+ },
+ },
+ {
+ address: {
+ addressStreet1: {
+ is: 'NULL',
+ },
+ },
+ },
+ ],
+ },
+ {
+ or: [
+ {
+ address: {
+ addressStreet2: {
+ ilike: '',
+ },
+ },
+ },
+ {
+ address: {
+ addressStreet2: {
+ is: 'NULL',
+ },
+ },
+ },
+ ],
+ },
+ {
+ or: [
+ {
+ address: {
+ addressCity: {
+ ilike: '',
+ },
+ },
+ },
+ {
+ address: {
+ addressCity: {
+ is: 'NULL',
+ },
+ },
+ },
+ ],
+ },
+ {
+ or: [
+ {
+ address: {
+ addressState: {
+ ilike: '',
+ },
+ },
+ },
+ {
+ address: {
+ addressState: {
+ is: 'NULL',
+ },
+ },
+ },
+ ],
+ },
+ {
+ or: [
+ {
+ address: {
+ addressCountry: {
+ ilike: '',
+ },
+ },
+ },
+ {
+ address: {
+ addressCountry: {
+ is: 'NULL',
+ },
+ },
+ },
+ ],
+ },
+ {
+ or: [
+ {
+ address: {
+ addressPostcode: {
+ ilike: '',
+ },
+ },
+ },
+ {
+ address: {
+ addressPostcode: {
+ is: 'NULL',
+ },
+ },
+ },
+ ],
+ },
+ ],
+ },
+ },
+ ],
+ });
+ });
+
+ it('phones field type', () => {
+ const personMockPhonesFieldMetadataId =
+ personMockObjectMetadataItem.fields.find(
+ (field) => field.name === 'phones',
+ );
+
+ const phonesFilterContains: Filter = {
+ id: 'person-phones-filter-contains',
+ value: '1234567890',
+ fieldMetadataId: personMockPhonesFieldMetadataId?.id,
+ displayValue: '1234567890',
+ operand: ViewFilterOperand.Contains,
+ definition: {
+ type: 'PHONES',
+ fieldMetadataId: personMockPhonesFieldMetadataId?.id,
+ label: 'Phones',
+ iconName: 'phone',
+ },
+ };
+
+ const phonesFilterDoesNotContain: Filter = {
+ id: 'person-phones-filter-does-not-contain',
+ value: '1234567890',
+ fieldMetadataId: personMockPhonesFieldMetadataId?.id,
+ displayValue: '1234567890',
+ operand: ViewFilterOperand.DoesNotContain,
+ definition: {
+ type: 'PHONES',
+ fieldMetadataId: personMockPhonesFieldMetadataId?.id,
+ label: 'Phones',
+ iconName: 'phone',
+ },
+ };
+
+ const phonesFilterIsEmpty: Filter = {
+ id: 'person-phones-filter-is-empty',
+ value: '',
+ fieldMetadataId: personMockPhonesFieldMetadataId?.id,
+ displayValue: '',
+ operand: ViewFilterOperand.IsEmpty,
+ definition: {
+ type: 'PHONES',
+ fieldMetadataId: personMockPhonesFieldMetadataId?.id,
+ label: 'Phones',
+ iconName: 'phone',
+ },
+ };
+
+ const phonesFilterIsNotEmpty: Filter = {
+ id: 'person-phones-filter-is-not-empty',
+ value: '',
+ fieldMetadataId: personMockPhonesFieldMetadataId?.id,
+ displayValue: '',
+ operand: ViewFilterOperand.IsNotEmpty,
+ definition: {
+ type: 'PHONES',
+ fieldMetadataId: personMockPhonesFieldMetadataId?.id,
+ label: 'Phones',
+ iconName: 'phone',
+ },
+ };
+
+ const result = turnObjectDropdownFilterIntoQueryFilter(
+ [
+ phonesFilterContains,
+ phonesFilterDoesNotContain,
+ phonesFilterIsEmpty,
+ phonesFilterIsNotEmpty,
+ ],
+ personMockObjectMetadataItem.fields,
+ );
+
+ expect(result).toEqual({
+ and: [
+ {
+ or: [
+ {
+ phones: {
+ primaryPhoneNumber: {
+ ilike: '%1234567890%',
+ },
+ },
+ },
+ {
+ phones: {
+ primaryPhoneCountryCode: {
+ ilike: '%1234567890%',
+ },
+ },
+ },
+ ],
+ },
+ {
+ and: [
+ {
+ not: {
+ phones: {
+ primaryPhoneNumber: {
+ ilike: '%1234567890%',
+ },
+ },
+ },
+ },
+ {
+ not: {
+ phones: {
+ primaryPhoneCountryCode: {
+ ilike: '%1234567890%',
+ },
+ },
+ },
+ },
+ ],
+ },
+ {
+ and: [
+ {
+ or: [
+ {
+ phones: {
+ primaryPhoneNumber: {
+ is: 'NULL',
+ },
+ },
+ },
+ {
+ phones: {
+ primaryPhoneNumber: {
+ ilike: '',
+ },
+ },
+ },
+ ],
+ },
+ {
+ or: [
+ {
+ phones: {
+ primaryPhoneCountryCode: {
+ is: 'NULL',
+ },
+ },
+ },
+ {
+ phones: {
+ primaryPhoneCountryCode: {
+ ilike: '',
+ },
+ },
+ },
+ ],
+ },
+ ],
+ },
+ {
+ not: {
+ and: [
+ {
+ or: [
+ {
+ phones: {
+ primaryPhoneNumber: {
+ is: 'NULL',
+ },
+ },
+ },
+ {
+ phones: {
+ primaryPhoneNumber: {
+ ilike: '',
+ },
+ },
+ },
+ ],
+ },
+ {
+ or: [
+ {
+ phones: {
+ primaryPhoneCountryCode: {
+ is: 'NULL',
+ },
+ },
+ },
+ {
+ phones: {
+ primaryPhoneCountryCode: {
+ ilike: '',
+ },
+ },
+ },
+ ],
+ },
+ ],
+ },
+ },
+ ],
+ });
+ });
+
+ it('emails field type', () => {
+ const personMockEmailFieldMetadataId =
+ personMockObjectMetadataItem.fields.find(
+ (field) => field.name === 'emails',
+ );
+
+ const emailsFilterContains: Filter = {
+ id: 'person-emails-filter-contains',
+ value: 'test@test.com',
+ fieldMetadataId: personMockEmailFieldMetadataId?.id,
+ displayValue: 'test@test.com',
+ operand: ViewFilterOperand.Contains,
+ definition: {
+ type: 'EMAILS',
+ fieldMetadataId: personMockEmailFieldMetadataId?.id,
+ iconName: 'email',
+ label: 'Emails',
+ },
+ };
+
+ const emailsFilterDoesNotContain: Filter = {
+ id: 'person-emails-filter-does-not-contain',
+ value: 'test@test.com',
+ fieldMetadataId: personMockEmailFieldMetadataId?.id,
+ displayValue: 'test@test.com',
+ operand: ViewFilterOperand.DoesNotContain,
+ definition: {
+ type: 'EMAILS',
+ fieldMetadataId: personMockEmailFieldMetadataId?.id,
+ label: 'Emails',
+ iconName: 'email',
+ },
+ };
+
+ const emailsFilterIsEmpty: Filter = {
+ id: 'person-emails-filter-is-empty',
+ value: '',
+ fieldMetadataId: personMockEmailFieldMetadataId?.id,
+ displayValue: '',
+ operand: ViewFilterOperand.IsEmpty,
+ definition: {
+ type: 'EMAILS',
+ label: 'Emails',
+ iconName: 'email',
+ fieldMetadataId: personMockEmailFieldMetadataId?.id,
+ },
+ };
+
+ const emailsFilterIsNotEmpty: Filter = {
+ id: 'person-emails-filter-is-not-empty',
+ value: '',
+ fieldMetadataId: personMockEmailFieldMetadataId?.id,
+ displayValue: '',
+ operand: ViewFilterOperand.IsNotEmpty,
+ definition: {
+ type: 'EMAILS',
+ label: 'Emails',
+ iconName: 'email',
+ fieldMetadataId: personMockEmailFieldMetadataId?.id,
+ },
+ };
+
+ const result = turnObjectDropdownFilterIntoQueryFilter(
+ [
+ emailsFilterContains,
+ emailsFilterDoesNotContain,
+ emailsFilterIsEmpty,
+ emailsFilterIsNotEmpty,
+ ],
+ personMockObjectMetadataItem.fields,
+ );
+
+ expect(result).toEqual({
+ and: [
+ {
+ or: [
+ {
+ emails: {
+ primaryEmail: {
+ ilike: '%test@test.com%',
+ },
+ },
+ },
+ ],
+ },
+ {
+ and: [
+ {
+ not: {
+ emails: {
+ primaryEmail: {
+ ilike: '%test@test.com%',
+ },
+ },
+ },
+ },
+ ],
+ },
+ {
+ or: [
+ {
+ emails: {
+ primaryEmail: {
+ ilike: '',
+ },
+ },
+ },
+ {
+ emails: {
+ primaryEmail: {
+ is: 'NULL',
+ },
+ },
+ },
+ ],
+ },
+ {
+ not: {
+ or: [
+ {
+ emails: {
+ primaryEmail: {
+ ilike: '',
+ },
+ },
+ },
+ {
+ emails: {
+ primaryEmail: {
+ is: 'NULL',
+ },
+ },
+ },
+ ],
+ },
+ },
+ ],
+ });
+ });
+
+ it('date field type', () => {
+ const companyMockDateFieldMetadataId =
+ companyMockObjectMetadataItem.fields.find(
+ (field) => field.name === 'createdAt',
+ );
+
+ const dateFilterIsAfter: Filter = {
+ id: 'company-date-filter-is-after',
+ value: '2024-09-17T20:46:58.922Z',
+ fieldMetadataId: companyMockDateFieldMetadataId?.id,
+ displayValue: '2024-09-17T20:46:58.922Z',
+ operand: ViewFilterOperand.IsAfter,
+ definition: {
+ type: 'DATE_TIME',
+ fieldMetadataId: companyMockDateFieldMetadataId?.id,
+ label: 'Created At',
+ iconName: 'date',
+ },
+ };
+
+ const dateFilterIsBefore: Filter = {
+ id: 'company-date-filter-is-before',
+ value: '2024-09-17T20:46:58.922Z',
+ fieldMetadataId: companyMockDateFieldMetadataId?.id,
+ displayValue: '2024-09-17T20:46:58.922Z',
+ operand: ViewFilterOperand.IsBefore,
+ definition: {
+ type: 'DATE_TIME',
+ fieldMetadataId: companyMockDateFieldMetadataId?.id,
+ label: 'Created At',
+ iconName: 'date',
+ },
+ };
+
+ const dateFilterIs: Filter = {
+ id: 'company-date-filter-is',
+ value: '2024-09-17T20:46:58.922Z',
+ fieldMetadataId: companyMockDateFieldMetadataId?.id,
+ displayValue: '2024-09-17T20:46:58.922Z',
+ operand: ViewFilterOperand.Is,
+ definition: {
+ type: 'DATE_TIME',
+ fieldMetadataId: companyMockDateFieldMetadataId?.id,
+ label: 'Created At',
+ iconName: 'date',
+ },
+ };
+
+ const dateFilterIsEmpty: Filter = {
+ id: 'company-date-filter-is-empty',
+ value: '',
+ fieldMetadataId: companyMockDateFieldMetadataId?.id,
+ displayValue: '',
+ operand: ViewFilterOperand.IsEmpty,
+ definition: {
+ type: 'DATE_TIME',
+ fieldMetadataId: companyMockDateFieldMetadataId?.id,
+ label: 'Created At',
+ iconName: 'date',
+ },
+ };
+
+ const dateFilterIsNotEmpty: Filter = {
+ id: 'company-date-filter-is-not-empty',
+ value: '',
+ fieldMetadataId: companyMockDateFieldMetadataId?.id,
+ displayValue: '',
+ operand: ViewFilterOperand.IsNotEmpty,
+ definition: {
+ type: 'DATE_TIME',
+ fieldMetadataId: companyMockDateFieldMetadataId?.id,
+ label: 'Created At',
+ iconName: 'date',
+ },
+ };
+
+ const result = turnObjectDropdownFilterIntoQueryFilter(
+ [
+ dateFilterIsAfter,
+ dateFilterIsBefore,
+ dateFilterIs,
+ dateFilterIsEmpty,
+ dateFilterIsNotEmpty,
+ ],
+ companyMockObjectMetadataItem.fields,
+ );
+
+ expect(result).toEqual({
+ and: [
+ {
+ createdAt: {
+ gt: '2024-09-17T20:46:58.922Z',
+ },
+ },
+ {
+ createdAt: {
+ lt: '2024-09-17T20:46:58.922Z',
+ },
+ },
+ {
+ and: [
+ {
+ createdAt: {
+ lte: '2024-09-17T23:59:59.999Z',
+ },
+ },
+ {
+ createdAt: {
+ gte: '2024-09-17T00:00:00.000Z',
+ },
+ },
+ ],
+ },
+ {
+ createdAt: {
+ is: 'NULL',
+ },
+ },
+ {
+ not: {
+ createdAt: {
+ is: 'NULL',
+ },
+ },
+ },
+ ],
+ });
+ });
+
+ it('number field type', () => {
+ const companyMockEmployeesFieldMetadataId =
+ companyMockObjectMetadataItem.fields.find(
+ (field) => field.name === 'employees',
+ );
+
+ const employeesFilterIsGreaterThan: Filter = {
+ id: 'company-employees-filter-is-greater-than',
+ value: '1000',
+ fieldMetadataId: companyMockEmployeesFieldMetadataId?.id,
+ displayValue: '1000',
+ operand: ViewFilterOperand.GreaterThan,
+ definition: {
+ type: 'NUMBER',
+ fieldMetadataId: companyMockEmployeesFieldMetadataId?.id,
+ label: 'Employees',
+ iconName: 'number',
+ },
+ };
+
+ const employeesFilterIsLessThan: Filter = {
+ id: 'company-employees-filter-is-less-than',
+ value: '1000',
+ fieldMetadataId: companyMockEmployeesFieldMetadataId?.id,
+ displayValue: '1000',
+ operand: ViewFilterOperand.LessThan,
+ definition: {
+ type: 'NUMBER',
+ fieldMetadataId: companyMockEmployeesFieldMetadataId?.id,
+ label: 'Employees',
+ iconName: 'number',
+ },
+ };
+
+ const employeesFilterIsEmpty: Filter = {
+ id: 'company-employees-filter-is-empty',
+ value: '',
+ fieldMetadataId: companyMockEmployeesFieldMetadataId?.id,
+ displayValue: '',
+ operand: ViewFilterOperand.IsEmpty,
+ definition: {
+ type: 'NUMBER',
+ fieldMetadataId: companyMockEmployeesFieldMetadataId?.id,
+ label: 'Employees',
+ iconName: 'number',
+ },
+ };
+
+ const employeesFilterIsNotEmpty: Filter = {
+ id: 'company-employees-filter-is-not-empty',
+ value: '',
+ fieldMetadataId: companyMockEmployeesFieldMetadataId?.id,
+ displayValue: '',
+ operand: ViewFilterOperand.IsNotEmpty,
+ definition: {
+ type: 'NUMBER',
+ fieldMetadataId: companyMockEmployeesFieldMetadataId?.id,
+ label: 'Employees',
+ iconName: 'number',
+ },
+ };
+
+ const result = turnObjectDropdownFilterIntoQueryFilter(
+ [
+ employeesFilterIsGreaterThan,
+ employeesFilterIsLessThan,
+ employeesFilterIsEmpty,
+ employeesFilterIsNotEmpty,
+ ],
+ companyMockObjectMetadataItem.fields,
+ );
+
+ expect(result).toEqual({
+ and: [
+ {
+ employees: {
+ gte: 1000,
+ },
+ },
+ {
+ employees: {
+ lte: 1000,
+ },
+ },
+ {
+ employees: {
+ is: 'NULL',
+ },
+ },
+ {
+ not: {
+ employees: {
+ is: 'NULL',
+ },
+ },
+ },
+ ],
+ });
+ });
+});
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 14584485370e..323e36e2985a 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
@@ -10,7 +10,6 @@ import {
RecordGqlOperationFilter,
RelationFilter,
StringFilter,
- URLFilter,
UUIDFilter,
} from '@/object-record/graphql/types/RecordGqlOperationFilter';
import { FilterType } from '@/object-record/object-filter-dropdown/types/FilterType';
@@ -40,8 +39,6 @@ const applyEmptyFilters = (
switch (filterType) {
case 'TEXT':
- case 'EMAIL':
- case 'PHONE':
emptyRecordFilter = {
or: [
{ [correspondingField.name]: { ilike: '' } as StringFilter },
@@ -86,16 +83,6 @@ const applyEmptyFilters = (
};
break;
}
- case 'LINK':
- emptyRecordFilter = {
- or: [
- { [correspondingField.name]: { url: { ilike: '' } } as URLFilter },
- {
- [correspondingField.name]: { url: { is: 'NULL' } } as URLFilter,
- },
- ],
- };
- break;
case 'LINKS': {
const linksFilters = generateILikeFiltersForCompositeFields(
'',
@@ -305,8 +292,6 @@ export const turnObjectDropdownFilterIntoQueryFilter = (
}
switch (rawUIFilter.definition.type) {
- case 'EMAIL':
- case 'PHONE':
case 'TEXT':
switch (rawUIFilter.operand) {
case ViewFilterOperand.Contains:
@@ -627,43 +612,6 @@ export const turnObjectDropdownFilterIntoQueryFilter = (
);
}
break;
- case 'LINK':
- switch (rawUIFilter.operand) {
- case ViewFilterOperand.Contains:
- objectRecordFilters.push({
- [correspondingField.name]: {
- url: {
- ilike: `%${rawUIFilter.value}%`,
- },
- } as URLFilter,
- });
- break;
- case ViewFilterOperand.DoesNotContain:
- objectRecordFilters.push({
- not: {
- [correspondingField.name]: {
- url: {
- ilike: `%${rawUIFilter.value}%`,
- },
- } as URLFilter,
- },
- });
- 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`,
- );
- }
- break;
case 'LINKS': {
const linksFilters = generateILikeFiltersForCompositeFields(
rawUIFilter.value,
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 36947097459e..df178df4c4fd 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,5 +1,6 @@
import { useRecoilValue } from 'recoil';
+import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
@@ -9,6 +10,7 @@ import { useRecordTableRecordGqlFields } from '@/object-record/record-index/hook
import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates';
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
import { SIGN_IN_BACKGROUND_MOCK_COMPANIES } from '@/sign-in-background-mock/constants/SignInBackgroundMockCompanies';
+import { isNull } from '@sniptt/guards';
import { WorkspaceActivationStatus } from '~/generated/graphql';
export const useFindManyParams = (
@@ -43,6 +45,7 @@ export const useLoadRecordIndexTable = (objectNameSingular: string) => {
const { setRecordTableData, setIsRecordTableInitialLoading } =
useRecordTable();
const currentWorkspace = useRecoilValue(currentWorkspaceState);
+ const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState);
const params = useFindManyParams(objectNameSingular);
const recordGqlFields = useRecordTableRecordGqlFields({ objectMetadataItem });
@@ -63,6 +66,7 @@ export const useLoadRecordIndexTable = (objectNameSingular: string) => {
onError: () => {
setIsRecordTableInitialLoading(false);
},
+ skip: isNull(currentWorkspaceMember),
});
return {
diff --git a/packages/twenty-front/src/modules/object-record/record-index/options/hooks/__tests__/useTableData.test.tsx b/packages/twenty-front/src/modules/object-record/record-index/options/hooks/__tests__/useTableData.test.tsx
index 752deafc8e7f..d670b908cb22 100644
--- a/packages/twenty-front/src/modules/object-record/record-index/options/hooks/__tests__/useTableData.test.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-index/options/hooks/__tests__/useTableData.test.tsx
@@ -1,18 +1,18 @@
-import { act, renderHook, waitFor } from '@testing-library/react';
-import { ReactNode } from 'react';
+import { renderHook, waitFor } from '@testing-library/react';
+import { act } from 'react';
import { percentage, sleep, useTableData } from '../useTableData';
+import { PERSON_FRAGMENT_WITH_DEPTH_ZERO_RELATIONS } from '@/object-record/hooks/__mocks__/personFragments';
import { useRecordBoard } from '@/object-record/record-board/hooks/useRecordBoard';
import { recordBoardKanbanFieldMetadataNameComponentState } from '@/object-record/record-board/states/recordBoardKanbanFieldMetadataNameComponentState';
import { useRecordIndexOptionsForBoard } from '@/object-record/record-index/options/hooks/useRecordIndexOptionsForBoard';
-import { SnackBarManagerScopeInternalContext } from '@/ui/feedback/snack-bar-manager/scopes/scope-internal-context/SnackBarManagerScopeInternalContext';
import { extractComponentState } from '@/ui/utilities/state/component-state/utils/extractComponentState';
import { ViewType } from '@/views/types/ViewType';
-import { MockedProvider, MockedResponse } from '@apollo/client/testing';
+import { MockedResponse } from '@apollo/client/testing';
import gql from 'graphql-tag';
-import { BrowserRouter as Router } from 'react-router-dom';
-import { RecoilRoot, useRecoilValue } from 'recoil';
-import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
+import { useRecoilValue } from 'recoil';
+import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
+import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
const defaultResponseData = {
pageInfo: {
@@ -23,10 +23,10 @@ const defaultResponseData = {
},
totalCount: 1,
};
+
const mockPerson = {
__typename: 'Person',
updatedAt: '2021-08-03T19:20:06.000Z',
- myCustomObjectId: '123',
whatsapp: {
primaryPhoneNumber: '+1',
primaryPhoneCountryCode: '234-567-890',
@@ -41,7 +41,10 @@ const mockPerson = {
firstName: 'firstName',
lastName: 'lastName',
},
- email: 'email',
+ emails: {
+ primaryEmail: 'email',
+ additionalEmails: [],
+ },
position: 'position',
createdBy: {
source: 'source',
@@ -57,7 +60,7 @@ const mockPerson = {
},
performanceRating: 1,
createdAt: '2021-08-03T19:20:06.000Z',
- phone: {
+ phones: {
primaryPhoneNumber: '+1',
primaryPhoneCountryCode: '234-567-890',
additionalPhones: [],
@@ -66,8 +69,10 @@ const mockPerson = {
city: 'city',
companyId: '1',
intro: 'intro',
- workPreference: 'workPrefereance',
+ deletedAt: null,
+ workPreference: 'workPreference',
};
+
const mocks: MockedResponse[] = [
{
request: {
@@ -86,52 +91,7 @@ const mocks: MockedResponse[] = [
) {
edges {
node {
- __typename
- name {
- firstName
- lastName
- }
- linkedinLink {
- primaryLinkUrl
- primaryLinkLabel
- secondaryLinks
- }
- deletedAt
- createdAt
- updatedAt
- jobTitle
- intro
- workPrefereance
- performanceRating
- xLink {
- primaryLinkUrl
- primaryLinkLabel
- secondaryLinks
- }
- city
- companyId
- phones {
- primaryPhoneNumber
- primaryPhoneCountryCode
- additionalPhones
- }
- createdBy {
- source
- workspaceMemberId
- name
- }
- id
- position
- emails {
- primaryEmail
- additionalEmails
- }
- avatarUrl
- whatsapp {
- primaryPhoneNumber
- primaryPhoneCountryCode
- additionalPhones
- }
+ ${PERSON_FRAGMENT_WITH_DEPTH_ZERO_RELATIONS}
}
cursor
}
@@ -167,21 +127,9 @@ const mocks: MockedResponse[] = [
},
];
-const Wrapper = ({ children }: { children: ReactNode }) => (
-
-
-
-
- {children}
-
-
-
-
-);
+const WrapperWithResponse = getJestMetadataAndApolloMocksWrapper({
+ apolloMocks: mocks,
+});
const graphqlEmptyResponse = [
{
@@ -197,21 +145,9 @@ const graphqlEmptyResponse = [
},
];
-const WrapperWithEmptyResponse = ({ children }: { children: ReactNode }) => (
-
-
-
-
- {children}
-
-
-
-
-);
+const WrapperWithEmptyResponse = getJestMetadataAndApolloMocksWrapper({
+ apolloMocks: graphqlEmptyResponse,
+});
describe('useTableData', () => {
const recordIndexId = 'people';
@@ -225,6 +161,7 @@ describe('useTableData', () => {
useTableData({
recordIndexId,
objectNameSingular,
+ pageSize: 30,
callback,
delayMs: 0,
viewType: ViewType.Kanban,
@@ -249,10 +186,11 @@ describe('useTableData', () => {
recordIndexId,
objectNameSingular,
callback,
+ pageSize: 30,
delayMs: 0,
}),
- { wrapper: Wrapper },
+ { wrapper: WrapperWithResponse },
);
await act(async () => {
@@ -292,7 +230,7 @@ describe('useTableData', () => {
};
},
{
- wrapper: Wrapper,
+ wrapper: WrapperWithResponse,
},
);
@@ -340,8 +278,10 @@ describe('useTableData', () => {
relationObjectMetadataNameSingular: '',
relationType: undefined,
targetFieldMetadataName: '',
+ settings: {},
},
position: 7,
+ settings: {},
showLabel: undefined,
size: 100,
type: 'DATE_TIME',
@@ -379,7 +319,7 @@ describe('useTableData', () => {
};
},
{
- wrapper: Wrapper,
+ wrapper: WrapperWithResponse,
},
);
diff --git a/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCellSkeletonLoader.tsx b/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCellSkeletonLoader.tsx
index 2e673478dbd5..bd912d7b55bd 100644
--- a/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCellSkeletonLoader.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCellSkeletonLoader.tsx
@@ -1,6 +1,7 @@
-import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
import { useTheme } from '@emotion/react';
+import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
+import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader';
import { StyledSkeletonDiv } from './RecordInlineCellContainer';
export const RecordInlineCellSkeletonLoader = () => {
@@ -13,7 +14,10 @@ export const RecordInlineCellSkeletonLoader = () => {
borderRadius={4}
>
-
+
);
diff --git a/packages/twenty-front/src/modules/object-record/record-inline-cell/property-box/components/PropertyBoxSkeletonLoader.tsx b/packages/twenty-front/src/modules/object-record/record-inline-cell/property-box/components/PropertyBoxSkeletonLoader.tsx
index 38ee35d74787..88a499952c1f 100644
--- a/packages/twenty-front/src/modules/object-record/record-inline-cell/property-box/components/PropertyBoxSkeletonLoader.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-inline-cell/property-box/components/PropertyBoxSkeletonLoader.tsx
@@ -1,6 +1,7 @@
-import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
+import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
+import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
const StyledSkeletonDiv = styled.div`
align-items: center;
@@ -22,8 +23,14 @@ export const PropertyBoxSkeletonLoader = () => {
>
{skeletonItems.map(({ id }) => (
-
-
+
+
))}
diff --git a/packages/twenty-front/src/modules/object-record/record-right-drawer/components/RightDrawerRecord.tsx b/packages/twenty-front/src/modules/object-record/record-right-drawer/components/RightDrawerRecord.tsx
index e68ce3883ef0..6a76206e6e75 100644
--- a/packages/twenty-front/src/modules/object-record/record-right-drawer/components/RightDrawerRecord.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-right-drawer/components/RightDrawerRecord.tsx
@@ -19,15 +19,6 @@ export const RightDrawerRecord = () => {
viewableRecordNameSingularState,
);
const viewableRecordId = useRecoilValue(viewableRecordIdState);
-
- if (!viewableRecordNameSingular) {
- throw new Error(`Object name is not defined`);
- }
-
- if (!viewableRecordId) {
- throw new Error(`Record id is not defined`);
- }
-
const { objectNameSingular, objectRecordId } = useRecordShowPage(
viewableRecordNameSingular ?? '',
viewableRecordId ?? '',
diff --git a/packages/twenty-front/src/modules/object-record/record-right-drawer/states/isNewViewableRecordLoading.ts b/packages/twenty-front/src/modules/object-record/record-right-drawer/states/isNewViewableRecordLoading.ts
new file mode 100644
index 000000000000..904677204cc6
--- /dev/null
+++ b/packages/twenty-front/src/modules/object-record/record-right-drawer/states/isNewViewableRecordLoading.ts
@@ -0,0 +1,6 @@
+import { createState } from 'twenty-ui';
+
+export const isNewViewableRecordLoadingState = createState({
+ key: 'activities/is-new-viewable-record-loading',
+ defaultValue: false,
+});
diff --git a/packages/twenty-front/src/modules/object-record/record-show/components/RecordShowContainer.tsx b/packages/twenty-front/src/modules/object-record/record-show/components/RecordShowContainer.tsx
index 5f23472fe180..e72df975f22f 100644
--- a/packages/twenty-front/src/modules/object-record/record-show/components/RecordShowContainer.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-show/components/RecordShowContainer.tsx
@@ -21,6 +21,7 @@ import { RecordInlineCell } from '@/object-record/record-inline-cell/components/
import { PropertyBox } from '@/object-record/record-inline-cell/property-box/components/PropertyBox';
import { PropertyBoxSkeletonLoader } from '@/object-record/record-inline-cell/property-box/components/PropertyBoxSkeletonLoader';
import { InlineCellHotkeyScope } from '@/object-record/record-inline-cell/types/InlineCellHotkeyScope';
+import { isNewViewableRecordLoadingState } from '@/object-record/record-right-drawer/states/isNewViewableRecordLoading';
import { RecordDetailDuplicatesSection } from '@/object-record/record-show/record-detail-section/components/RecordDetailDuplicatesSection';
import { RecordDetailRelationSection } from '@/object-record/record-show/record-detail-section/components/RecordDetailRelationSection';
import { recordLoadingFamilyState } from '@/object-record/record-store/states/recordLoadingFamilyState';
@@ -33,6 +34,7 @@ import { ShowPageContainer } from '@/ui/layout/page/ShowPageContainer';
import { ShowPageLeftContainer } from '@/ui/layout/show-page/components/ShowPageLeftContainer';
import { ShowPageRightContainer } from '@/ui/layout/show-page/components/ShowPageRightContainer';
import { ShowPageSummaryCard } from '@/ui/layout/show-page/components/ShowPageSummaryCard';
+import { ShowPageSummaryCardSkeletonLoader } from '@/ui/layout/show-page/components/ShowPageSummaryCardSkeletonLoader';
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
import {
FieldMetadataType,
@@ -80,7 +82,9 @@ export const RecordShowContainer = ({
recordId: objectRecordId,
}),
);
-
+ const isNewViewableRecordLoading = useRecoilValue(
+ isNewViewableRecordLoadingState,
+ );
const [uploadImage] = useUploadImageMutation();
const { updateOneRecord } = useUpdateOneRecord({ objectNameSingular });
@@ -162,53 +166,56 @@ export const RecordShowContainer = ({
const isReadOnly = objectMetadataItem.isRemote;
const isMobile = useIsMobile() || isInRightDrawer;
const isPrefetchLoading = useIsPrefetchLoading();
+ const isNewRightDrawerItemLoading =
+ isInRightDrawer && isNewViewableRecordLoading;
- const summaryCard = isDefined(recordFromStore) ? (
-
-
-
- }
- avatarType={recordIdentifier?.avatarType ?? 'rounded'}
- onUploadPicture={
- objectNameSingular === 'person' ? onUploadPicture : undefined
- }
- />
- ) : (
- <>>
- );
+ useUpdateRecord: useUpdateOneObjectRecordMutation,
+ hotkeyScope: InlineCellHotkeyScope.InlineCell,
+ isCentered: true,
+ }}
+ >
+
+
+ }
+ avatarType={recordIdentifier?.avatarType ?? 'rounded'}
+ onUploadPicture={
+ objectNameSingular === 'person' ? onUploadPicture : undefined
+ }
+ />
+ ) : (
+
+ );
const fieldsBox = (
<>
diff --git a/packages/twenty-front/src/modules/object-record/record-show/record-detail-section/components/__stories__/RecordDetailRelationSection.stories.tsx b/packages/twenty-front/src/modules/object-record/record-show/record-detail-section/components/__stories__/RecordDetailRelationSection.stories.tsx
index 06cb79025bc5..aca53588e1be 100644
--- a/packages/twenty-front/src/modules/object-record/record-show/record-detail-section/components/__stories__/RecordDetailRelationSection.stories.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-show/record-detail-section/components/__stories__/RecordDetailRelationSection.stories.tsx
@@ -9,15 +9,23 @@ import { RecordStoreDecorator } from '~/testing/decorators/RecordStoreDecorator'
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks';
import { getCompaniesMock } from '~/testing/mock-data/companies';
-import { mockedCompanyObjectMetadataItem } from '~/testing/mock-data/metadata';
import { getPeopleMock } from '~/testing/mock-data/people';
+import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
import { RecordDetailRelationSection } from '../RecordDetailRelationSection';
const companiesMock = getCompaniesMock();
const peopleMock = getPeopleMock();
+const mockedCompanyObjectMetadataItem = generatedMockObjectMetadataItems.find(
+ (item) => item.nameSingular === 'company',
+);
+
+if (!mockedCompanyObjectMetadataItem) {
+ throw new Error('Company object metadata item not found');
+}
+
const meta: Meta = {
title:
'Modules/ObjectRecord/RecordShow/RecordDetailSection/RecordDetailRelationSection',
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 9b68416e8192..b866e344842f 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
@@ -21,7 +21,7 @@ import { MemoryRouterDecorator } from '~/testing/decorators/MemoryRouterDecorato
import { getProfilingStory } from '~/testing/profiling/utils/getProfilingStory';
import { RecordTableCellFieldContextWrapper } from '@/object-record/record-table/record-table-cell/components/RecordTableCellFieldContextWrapper';
-import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
+import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
import { mockPerformance } from './mock';
const RelationFieldValueSetterEffect = () => {
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
index b010bdaecd6d..f62018d33388 100644
--- 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
@@ -1,6 +1,7 @@
-import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
+import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
+import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
const StyledSkeletonContainer = styled.div`
padding-left: ${({ theme }) => theme.spacing(2)};
@@ -15,7 +16,10 @@ const StyledRecordTableCellLoader = ({ width }: { width?: number }) => {
highlightColor={theme.background.transparent.lighter}
borderRadius={4}
>
-
+
);
};
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 e592107c5a1b..cf18193570e2 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
@@ -10,7 +10,7 @@ import { textfieldDefinition } from '@/object-record/record-field/__mocks__/fiel
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';
-import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
+import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
const draftValue = 'updated Name';
diff --git a/packages/twenty-front/src/modules/object-record/relation-picker/hooks/__tests__/useMultiObjectRecordsQueryResultFormattedAsObjectRecordForSelectArray.test.tsx b/packages/twenty-front/src/modules/object-record/relation-picker/hooks/__tests__/useMultiObjectRecordsQueryResultFormattedAsObjectRecordForSelectArray.test.tsx
index 9eb2e7b3642e..0aeca9fcb3aa 100644
--- a/packages/twenty-front/src/modules/object-record/relation-picker/hooks/__tests__/useMultiObjectRecordsQueryResultFormattedAsObjectRecordForSelectArray.test.tsx
+++ b/packages/twenty-front/src/modules/object-record/relation-picker/hooks/__tests__/useMultiObjectRecordsQueryResultFormattedAsObjectRecordForSelectArray.test.tsx
@@ -4,7 +4,7 @@ import { RecoilRoot, useSetRecoilState } from 'recoil';
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
import { useMultiObjectRecordsQueryResultFormattedAsObjectRecordForSelectArray } from '@/object-record/relation-picker/hooks/useMultiObjectRecordsQueryResultFormattedAsObjectRecordForSelectArray';
import { RelationPickerScopeInternalContext } from '@/object-record/relation-picker/scopes/scope-internal-context/RelationPickerScopeInternalContext';
-import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
+import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
const scopeId = 'scopeId';
const Wrapper = ({ children }: { children: React.ReactNode }) => (
diff --git a/packages/twenty-front/src/modules/object-record/spreadsheet-import/__tests__/useOpenObjectRecordsSpreasheetImportDialog.test.tsx b/packages/twenty-front/src/modules/object-record/spreadsheet-import/__tests__/useOpenObjectRecordsSpreasheetImportDialog.test.tsx
index da745581eb75..a7e47f8ba713 100644
--- a/packages/twenty-front/src/modules/object-record/spreadsheet-import/__tests__/useOpenObjectRecordsSpreasheetImportDialog.test.tsx
+++ b/packages/twenty-front/src/modules/object-record/spreadsheet-import/__tests__/useOpenObjectRecordsSpreasheetImportDialog.test.tsx
@@ -1,13 +1,12 @@
import { gql } from '@apollo/client';
-import { MockedProvider } from '@apollo/client/testing';
-import { act, renderHook, waitFor } from '@testing-library/react';
-import { ReactNode } from 'react';
-import { RecoilRoot, useRecoilValue } from 'recoil';
+import { renderHook, waitFor } from '@testing-library/react';
+import { act } from 'react';
+import { useRecoilValue } from 'recoil';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { spreadsheetImportDialogState } from '@/spreadsheet-import/states/spreadsheetImportDialogState';
-import { SnackBarManagerScopeInternalContext } from '@/ui/feedback/snack-bar-manager/scopes/scope-internal-context/SnackBarManagerScopeInternalContext';
+import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
import { useOpenObjectRecordsSpreasheetImportDialog } from '../hooks/useOpenObjectRecordsSpreasheetImportDialog';
const companyId = 'cb2e9f4b-20c3-4759-9315-4ffeecfaf71a';
@@ -26,13 +25,42 @@ const companyMocks = [
) {
createCompanies(data: $data, upsert: $upsert) {
__typename
- updatedAt
- domainName {
- primaryLinkUrl
- primaryLinkLabel
- secondaryLinks
+ accountOwner {
+ __typename
+ avatarUrl
+ colorScheme
+ createdAt
+ dateFormat
+ deletedAt
+ id
+ locale
+ name {
+ firstName
+ lastName
+ }
+ timeFormat
+ timeZone
+ updatedAt
+ userEmail
+ userId
+ }
+ accountOwnerId
+ activityTargets {
+ edges {
+ node {
+ __typename
+ activityId
+ companyId
+ createdAt
+ deletedAt
+ id
+ opportunityId
+ personId
+ rocketId
+ updatedAt
+ }
+ }
}
- visaSponsorship
address {
addressStreet1
addressStreet2
@@ -43,20 +71,31 @@ const companyMocks = [
addressLat
addressLng
}
- position
- employees
- deletedAt
- accountOwnerId
annualRecurringRevenue {
amountMicros
currencyCode
}
- id
- name
- xLink {
- primaryLinkUrl
- primaryLinkLabel
- secondaryLinks
+ attachments {
+ edges {
+ node {
+ __typename
+ activityId
+ authorId
+ companyId
+ createdAt
+ deletedAt
+ fullPath
+ id
+ name
+ noteId
+ opportunityId
+ personId
+ rocketId
+ taskId
+ type
+ updatedAt
+ }
+ }
}
createdAt
createdBy {
@@ -64,7 +103,36 @@ const companyMocks = [
workspaceMemberId
name
}
- workPolicy
+ deletedAt
+ domainName {
+ primaryLinkUrl
+ primaryLinkLabel
+ secondaryLinks
+ }
+ employees
+ favorites {
+ edges {
+ node {
+ __typename
+ companyId
+ createdAt
+ deletedAt
+ id
+ noteId
+ opportunityId
+ personId
+ position
+ rocketId
+ taskId
+ updatedAt
+ viewId
+ workflowId
+ workspaceMemberId
+ }
+ }
+ }
+ id
+ idealCustomerProfile
introVideo {
primaryLinkUrl
primaryLinkLabel
@@ -75,8 +143,151 @@ const companyMocks = [
primaryLinkLabel
secondaryLinks
}
+ name
+ noteTargets {
+ edges {
+ node {
+ __typename
+ companyId
+ createdAt
+ deletedAt
+ id
+ noteId
+ opportunityId
+ personId
+ rocketId
+ updatedAt
+ }
+ }
+ }
+ opportunities {
+ edges {
+ node {
+ __typename
+ amount {
+ amountMicros
+ currencyCode
+ }
+ closeDate
+ companyId
+ createdAt
+ createdBy {
+ source
+ workspaceMemberId
+ name
+ }
+ deletedAt
+ id
+ name
+ pointOfContactId
+ position
+ stage
+ updatedAt
+ }
+ }
+ }
+ people {
+ edges {
+ node {
+ __typename
+ avatarUrl
+ city
+ companyId
+ createdAt
+ createdBy {
+ source
+ workspaceMemberId
+ name
+ }
+ deletedAt
+ emails {
+ primaryEmail
+ additionalEmails
+ }
+ id
+ intro
+ jobTitle
+ linkedinLink {
+ primaryLinkUrl
+ primaryLinkLabel
+ secondaryLinks
+ }
+ name {
+ firstName
+ lastName
+ }
+ performanceRating
+ phones {
+ primaryPhoneNumber
+ primaryPhoneCountryCode
+ additionalPhones
+ }
+ position
+ updatedAt
+ whatsapp {
+ primaryPhoneNumber
+ primaryPhoneCountryCode
+ additionalPhones
+ }
+ workPreference
+ xLink {
+ primaryLinkUrl
+ primaryLinkLabel
+ secondaryLinks
+ }
+ }
+ }
+ }
+ position
tagline
- idealCustomerProfile
+ taskTargets {
+ edges {
+ node {
+ __typename
+ companyId
+ createdAt
+ deletedAt
+ id
+ opportunityId
+ personId
+ rocketId
+ taskId
+ updatedAt
+ }
+ }
+ }
+ timelineActivities {
+ edges {
+ node {
+ __typename
+ companyId
+ createdAt
+ deletedAt
+ happensAt
+ id
+ linkedObjectMetadataId
+ linkedRecordCachedName
+ linkedRecordId
+ name
+ noteId
+ opportunityId
+ personId
+ properties
+ rocketId
+ taskId
+ updatedAt
+ workspaceMemberId
+ }
+ }
+ }
+ updatedAt
+ visaSponsorship
+ workPolicy
+ xLink {
+ primaryLinkUrl
+ primaryLinkLabel
+ secondaryLinks
+ }
}
}
`,
@@ -99,6 +310,9 @@ const companyMocks = [
createCompanies: [
{
id: companyId,
+ favorites: {
+ edges: [],
+ },
},
],
},
@@ -112,17 +326,9 @@ const fakeCsv = () => {
return new File([blob], 'fakeData.csv', { type: 'text/csv' });
};
-const Wrapper = ({ children }: { children: ReactNode }) => (
-
-
-
- {children}
-
-
-
-);
+const Wrapper = getJestMetadataAndApolloMocksWrapper({
+ apolloMocks: companyMocks,
+});
// TODO: improve object metadata item seeds to have more field types to add tests on composite fields here
describe('useSpreadsheetCompanyImport', () => {
diff --git a/packages/twenty-front/src/modules/search/hooks/__tests__/useFilteredSearchEntityQuery.test.tsx b/packages/twenty-front/src/modules/search/hooks/__tests__/useFilteredSearchEntityQuery.test.tsx
index 83fa74e7b864..263b70decf0f 100644
--- a/packages/twenty-front/src/modules/search/hooks/__tests__/useFilteredSearchEntityQuery.test.tsx
+++ b/packages/twenty-front/src/modules/search/hooks/__tests__/useFilteredSearchEntityQuery.test.tsx
@@ -8,7 +8,7 @@ import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadat
import { EntitiesForMultipleEntitySelect } from '@/object-record/relation-picker/types/EntitiesForMultipleEntitySelect';
import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarProviderScope';
-import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
+import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
import {
query,
responseData,
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
index 5ef756baf4c6..a4e9f5294e83 100644
--- 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
@@ -3,12 +3,18 @@ import { ComponentDecorator } from 'twenty-ui';
import { SettingsAccountsCalendarChannelDetails } from '@/settings/accounts/components/SettingsAccountsCalendarChannelDetails';
import { CalendarChannelVisibility } from '~/generated/graphql';
+import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator';
+import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
const meta: Meta = {
title:
'Modules/Settings/Accounts/CalendarChannels/SettingsAccountsCalendarChannelDetails',
component: SettingsAccountsCalendarChannelDetails,
- decorators: [ComponentDecorator],
+ decorators: [
+ ComponentDecorator,
+ ObjectMetadataItemsDecorator,
+ SnackBarDecorator,
+ ],
args: {
calendarChannel: {
id: '20202020-ef5a-4822-9e08-ce6e6a4dcb6a',
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
index 49f279316908..83c05df92b98 100644
--- 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
@@ -2,12 +2,18 @@ import { Meta, StoryObj } from '@storybook/react';
import { ComponentDecorator } from 'twenty-ui';
import { SettingsAccountsCalendarChannelsGeneral } from '@/settings/accounts/components/SettingsAccountsCalendarChannelsGeneral';
+import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator';
+import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
const meta: Meta = {
title:
'Modules/Settings/Accounts/CalendarChannels/SettingsAccountsCalendarChannelsGeneral',
component: SettingsAccountsCalendarChannelsGeneral,
- decorators: [ComponentDecorator],
+ decorators: [
+ ComponentDecorator,
+ ObjectMetadataItemsDecorator,
+ SnackBarDecorator,
+ ],
};
export default meta;
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
index 02264d8e66fe..a951150c94f3 100644
--- 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
@@ -4,12 +4,18 @@ import { ComponentDecorator } from 'twenty-ui';
import { MessageChannelContactAutoCreationPolicy } from '@/accounts/types/MessageChannel';
import { SettingsAccountsMessageChannelDetails } from '@/settings/accounts/components/SettingsAccountsMessageChannelDetails';
import { MessageChannelVisibility } from '~/generated/graphql';
+import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator';
+import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
const meta: Meta = {
title:
'Modules/Settings/Accounts/MessageChannels/SettingsAccountsMessageChannelDetails',
component: SettingsAccountsMessageChannelDetails,
- decorators: [ComponentDecorator],
+ decorators: [
+ ComponentDecorator,
+ ObjectMetadataItemsDecorator,
+ SnackBarDecorator,
+ ],
args: {
messageChannel: {
id: '20202020-ef5a-4822-9e08-ce6e6a4dcb6a',
diff --git a/packages/twenty-front/src/modules/settings/data-model/constants/RelationTypes.ts b/packages/twenty-front/src/modules/settings/data-model/constants/RelationTypes.ts
index da5e9b8b9617..179f60fe8979 100644
--- a/packages/twenty-front/src/modules/settings/data-model/constants/RelationTypes.ts
+++ b/packages/twenty-front/src/modules/settings/data-model/constants/RelationTypes.ts
@@ -1,5 +1,6 @@
import {
IconComponent,
+ IllustrationIconManyToMany,
IllustrationIconOneToMany,
IllustrationIconOneToOne,
} from 'twenty-ui';
@@ -34,4 +35,11 @@ export const RELATION_TYPES: Record<
imageSrc: OneToManySvg,
isImageFlipped: true,
},
+ // Not supported yet
+ [RelationDefinitionType.ManyToMany]: {
+ label: 'Belongs to many',
+ Icon: IllustrationIconManyToMany,
+ imageSrc: OneToManySvg,
+ isImageFlipped: true,
+ },
};
diff --git a/packages/twenty-front/src/modules/settings/data-model/fields/forms/components/SettingsDataModelFieldSettingsFormCard.tsx b/packages/twenty-front/src/modules/settings/data-model/fields/forms/components/SettingsDataModelFieldSettingsFormCard.tsx
index a71cc1654bcf..882b57f7d1c1 100644
--- a/packages/twenty-front/src/modules/settings/data-model/fields/forms/components/SettingsDataModelFieldSettingsFormCard.tsx
+++ b/packages/twenty-front/src/modules/settings/data-model/fields/forms/components/SettingsDataModelFieldSettingsFormCard.tsx
@@ -11,6 +11,8 @@ import { settingsDataModelFieldCurrencyFormSchema } from '@/settings/data-model/
import { SettingsDataModelFieldCurrencySettingsFormCard } from '@/settings/data-model/fields/forms/currency/components/SettingsDataModelFieldCurrencySettingsFormCard';
import { settingsDataModelFieldDateFormSchema } from '@/settings/data-model/fields/forms/date/components/SettingsDataModelFieldDateForm';
import { SettingsDataModelFieldDateSettingsFormCard } from '@/settings/data-model/fields/forms/date/components/SettingsDataModelFieldDateSettingsFormCard';
+import { settingsDataModelFieldNumberFormSchema } from '@/settings/data-model/fields/forms/number/components/SettingsDataModelFieldNumberForm';
+import { SettingsDataModelFieldNumberSettingsFormCard } from '@/settings/data-model/fields/forms/number/components/SettingsDataModelFieldNumberSettingsFormCard';
import { settingsDataModelFieldRelationFormSchema } from '@/settings/data-model/fields/forms/relation/components/SettingsDataModelFieldRelationForm';
import { SettingsDataModelFieldRelationSettingsFormCard } from '@/settings/data-model/fields/forms/relation/components/SettingsDataModelFieldRelationSettingsFormCard';
import {
@@ -52,6 +54,10 @@ const multiSelectFieldFormSchema = z
.object({ type: z.literal(FieldMetadataType.MultiSelect) })
.merge(settingsDataModelFieldMultiSelectFormSchema);
+const numberFieldFormSchema = z
+ .object({ type: z.literal(FieldMetadataType.Number) })
+ .merge(settingsDataModelFieldNumberFormSchema);
+
const otherFieldsFormSchema = z.object({
type: z.enum(
Object.keys(
@@ -63,6 +69,7 @@ const otherFieldsFormSchema = z.object({
FieldMetadataType.MultiSelect,
FieldMetadataType.Date,
FieldMetadataType.DateTime,
+ FieldMetadataType.Number,
]),
) as [FieldMetadataType, ...FieldMetadataType[]],
),
@@ -78,13 +85,17 @@ export const settingsDataModelFieldSettingsFormSchema = z.discriminatedUnion(
relationFieldFormSchema,
selectFieldFormSchema,
multiSelectFieldFormSchema,
+ numberFieldFormSchema,
otherFieldsFormSchema,
],
);
type SettingsDataModelFieldSettingsFormCardProps = {
isCreatingField?: boolean;
- fieldMetadataItem: Pick &
+ fieldMetadataItem: Pick<
+ FieldMetadataItem,
+ 'icon' | 'label' | 'type' | 'isCustom'
+ > &
Partial>;
} & Pick;
@@ -163,6 +174,16 @@ export const SettingsDataModelFieldSettingsFormCard = ({
);
}
+ if (fieldMetadataItem.type === FieldMetadataType.Number) {
+ return (
+
+ );
+ }
+
if (
fieldMetadataItem.type === FieldMetadataType.Select ||
fieldMetadataItem.type === FieldMetadataType.MultiSelect
diff --git a/packages/twenty-front/src/modules/settings/data-model/fields/forms/components/__stories__/SettingsDataModelFieldDescriptionForm.stories.tsx b/packages/twenty-front/src/modules/settings/data-model/fields/forms/components/__stories__/SettingsDataModelFieldDescriptionForm.stories.tsx
index 7499adea0338..58f33bf2210f 100644
--- a/packages/twenty-front/src/modules/settings/data-model/fields/forms/components/__stories__/SettingsDataModelFieldDescriptionForm.stories.tsx
+++ b/packages/twenty-front/src/modules/settings/data-model/fields/forms/components/__stories__/SettingsDataModelFieldDescriptionForm.stories.tsx
@@ -3,7 +3,7 @@ import { ComponentDecorator } from 'twenty-ui';
import { FormProviderDecorator } from '~/testing/decorators/FormProviderDecorator';
-import { mockedPersonObjectMetadataItem } from '~/testing/mock-data/metadata';
+import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
import { SettingsDataModelFieldDescriptionForm } from '../SettingsDataModelFieldDescriptionForm';
const meta: Meta = {
@@ -25,11 +25,15 @@ type Story = StoryObj;
export const Default: Story = {};
+const mockedPersonObjectMetadataItem = generatedMockObjectMetadataItems.find(
+ (item) => item.namePlural === 'person',
+);
+
export const WithFieldMetadataItem: Story = {
args: {
- fieldMetadataItem: mockedPersonObjectMetadataItem.fields.find(
+ fieldMetadataItem: mockedPersonObjectMetadataItem?.fields.find(
({ description }) => description === 'description',
- )!,
+ ),
},
};
diff --git a/packages/twenty-front/src/modules/settings/data-model/fields/forms/components/__stories__/SettingsDataModelFieldIconLabelForm.stories.tsx b/packages/twenty-front/src/modules/settings/data-model/fields/forms/components/__stories__/SettingsDataModelFieldIconLabelForm.stories.tsx
index 150efdc46683..555db1bc92d1 100644
--- a/packages/twenty-front/src/modules/settings/data-model/fields/forms/components/__stories__/SettingsDataModelFieldIconLabelForm.stories.tsx
+++ b/packages/twenty-front/src/modules/settings/data-model/fields/forms/components/__stories__/SettingsDataModelFieldIconLabelForm.stories.tsx
@@ -5,7 +5,7 @@ import { ComponentDecorator } from 'twenty-ui';
import { FormProviderDecorator } from '~/testing/decorators/FormProviderDecorator';
import { IconsProviderDecorator } from '~/testing/decorators/IconsProviderDecorator';
-import { mockedPersonObjectMetadataItem } from '~/testing/mock-data/metadata';
+import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
import { SettingsDataModelFieldIconLabelForm } from '../SettingsDataModelFieldIconLabelForm';
const StyledContainer = styled.div`
@@ -32,11 +32,15 @@ type Story = StoryObj;
export const Default: Story = {};
+const mockedPersonObjectMetadataItem = generatedMockObjectMetadataItems.find(
+ (item) => item.namePlural === 'person',
+);
+
export const WithFieldMetadataItem: Story = {
args: {
- fieldMetadataItem: mockedPersonObjectMetadataItem.fields.find(
+ fieldMetadataItem: mockedPersonObjectMetadataItem?.fields.find(
({ name }) => name === 'name',
- )!,
+ ),
},
};
diff --git a/packages/twenty-front/src/modules/settings/data-model/fields/forms/components/__stories__/SettingsDataModelFieldSettingsFormCard.stories.tsx b/packages/twenty-front/src/modules/settings/data-model/fields/forms/components/__stories__/SettingsDataModelFieldSettingsFormCard.stories.tsx
index aff46aa2da0e..09aaf60c282c 100644
--- a/packages/twenty-front/src/modules/settings/data-model/fields/forms/components/__stories__/SettingsDataModelFieldSettingsFormCard.stories.tsx
+++ b/packages/twenty-front/src/modules/settings/data-model/fields/forms/components/__stories__/SettingsDataModelFieldSettingsFormCard.stories.tsx
@@ -7,10 +7,18 @@ import { MemoryRouterDecorator } from '~/testing/decorators/MemoryRouterDecorato
import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator';
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks';
-import { mockedCompanyObjectMetadataItem } from '~/testing/mock-data/metadata';
+import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
import { SettingsDataModelFieldSettingsFormCard } from '../SettingsDataModelFieldSettingsFormCard';
+const mockedCompanyObjectMetadataItem = generatedMockObjectMetadataItems.find(
+ (item) => item.nameSingular === 'company',
+);
+
+if (!mockedCompanyObjectMetadataItem) {
+ throw new Error('Company object metadata item not found');
+}
+
const fieldMetadataItem = mockedCompanyObjectMetadataItem.fields.find(
({ type }) => type === FieldMetadataType.Text,
)!;
diff --git a/packages/twenty-front/src/modules/settings/data-model/fields/forms/number/components/SettingsDataModelFieldNumberDecimalInput.tsx b/packages/twenty-front/src/modules/settings/data-model/fields/forms/number/components/SettingsDataModelFieldNumberDecimalInput.tsx
new file mode 100644
index 000000000000..706bcea37154
--- /dev/null
+++ b/packages/twenty-front/src/modules/settings/data-model/fields/forms/number/components/SettingsDataModelFieldNumberDecimalInput.tsx
@@ -0,0 +1,168 @@
+import styled from '@emotion/styled';
+
+import { Button } from '@/ui/input/button/components/Button';
+import { TextInput } from '@/ui/input/components/TextInput';
+import { IconInfoCircle, IconMinus, IconPlus } from 'twenty-ui';
+import { castAsNumberOrNull } from '~/utils/cast-as-number-or-null';
+
+type SettingsDataModelFieldNumberDecimalsInputProps = {
+ value: number;
+ onChange: (value: number) => void;
+ disabled?: boolean;
+};
+
+const StyledCounterContainer = styled.div`
+ align-items: center;
+ background: ${({ theme }) => theme.background.noisy};
+ border: 1px solid ${({ theme }) => theme.border.color.medium};
+ border-radius: 4px;
+ display: flex;
+ flex-direction: column;
+ flex: 1;
+ gap: ${({ theme }) => theme.spacing(1)};
+ justify-content: center;
+`;
+
+const StyledExampleText = styled.div`
+ color: ${({ theme }) => theme.font.color.primary};
+ width: 100%;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ font-weight: ${({ theme }) => theme.font.weight.regular};
+`;
+
+const StyledCounterControlsIcons = styled.div`
+ align-items: center;
+ display: flex;
+ gap: ${({ theme }) => theme.spacing(2)};
+`;
+
+const StyledCounterInnerContainer = styled.div`
+ align-items: center;
+ align-self: stretch;
+ display: flex;
+ gap: ${({ theme }) => theme.spacing(1)};
+ padding: ${({ theme }) => theme.spacing(2)};
+ height: 24px;
+`;
+
+const StyledTextInput = styled(TextInput)`
+ width: ${({ theme }) => theme.spacing(16)};
+ input {
+ width: ${({ theme }) => theme.spacing(16)};
+ height: ${({ theme }) => theme.spacing(6)};
+ text-align: center;
+ font-weight: ${({ theme }) => theme.font.weight.medium};
+ background: ${({ theme }) => theme.background.noisy};
+ }
+ input ~ div {
+ padding-right: ${({ theme }) => theme.spacing(0)};
+ border-radius: ${({ theme }) => theme.spacing(1)};
+ background: ${({ theme }) => theme.background.noisy};
+ }
+`;
+
+const StyledTitle = styled.div`
+ color: ${({ theme }) => theme.font.color.light};
+ font-size: ${({ theme }) => theme.font.size.xs};
+ font-weight: ${({ theme }) => theme.font.weight.semiBold};
+ margin-bottom: ${({ theme }) => theme.spacing(1)};
+`;
+
+const StyledControlButton = styled(Button)`
+ height: ${({ theme }) => theme.spacing(6)};
+ width: ${({ theme }) => theme.spacing(6)};
+ padding: 0;
+ justify-content: center;
+ svg {
+ height: ${({ theme }) => theme.spacing(4)};
+ width: ${({ theme }) => theme.spacing(4)};
+ }
+`;
+
+const StyledInfoButton = styled(Button)`
+ height: ${({ theme }) => theme.spacing(6)};
+ width: ${({ theme }) => theme.spacing(6)};
+ padding: 0;
+ justify-content: center;
+ svg {
+ color: ${({ theme }) => theme.font.color.extraLight};
+ height: ${({ theme }) => theme.spacing(4)};
+ width: ${({ theme }) => theme.spacing(4)};
+ }
+`;
+
+const MIN_VALUE = 0;
+const MAX_VALUE = 100;
+export const SettingsDataModelFieldNumberDecimalsInput = ({
+ value,
+ onChange,
+ disabled,
+}: SettingsDataModelFieldNumberDecimalsInputProps) => {
+ const exampleValue = (1000).toFixed(value);
+
+ const handleIncrementCounter = () => {
+ if (value < MAX_VALUE) {
+ const newValue = value + 1;
+ onChange(newValue);
+ }
+ };
+
+ const handleDecrementCounter = () => {
+ if (value > MIN_VALUE) {
+ const newValue = value - 1;
+ onChange(newValue);
+ }
+ };
+
+ const handleTextInputChange = (value: string) => {
+ const castedNumber = castAsNumberOrNull(value);
+ if (castedNumber === null) {
+ onChange(MIN_VALUE);
+ return;
+ }
+
+ if (castedNumber < MIN_VALUE) {
+ return;
+ }
+
+ if (castedNumber > MAX_VALUE) {
+ onChange(MAX_VALUE);
+ return;
+ }
+ onChange(castedNumber);
+ };
+ return (
+ <>
+ Number of decimals
+
+
+ Example: {exampleValue}
+
+
+
+ handleTextInputChange(value)}
+ disabled={disabled}
+ />
+
+
+
+
+ >
+ );
+};
diff --git a/packages/twenty-front/src/modules/settings/data-model/fields/forms/number/components/SettingsDataModelFieldNumberForm.tsx b/packages/twenty-front/src/modules/settings/data-model/fields/forms/number/components/SettingsDataModelFieldNumberForm.tsx
new file mode 100644
index 000000000000..3a80bf0e6104
--- /dev/null
+++ b/packages/twenty-front/src/modules/settings/data-model/fields/forms/number/components/SettingsDataModelFieldNumberForm.tsx
@@ -0,0 +1,55 @@
+import { Controller, useFormContext } from 'react-hook-form';
+import { z } from 'zod';
+
+import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
+import { numberFieldDefaultValueSchema } from '@/object-record/record-field/validation-schemas/numberFieldDefaultValueSchema';
+import { SettingsDataModelFieldNumberDecimalsInput } from '@/settings/data-model/fields/forms/number/components/SettingsDataModelFieldNumberDecimalInput';
+import { CardContent } from '@/ui/layout/card/components/CardContent';
+import { DEFAULT_DECIMAL_VALUE } from '~/utils/format/number';
+
+export const settingsDataModelFieldNumberFormSchema = z.object({
+ settings: numberFieldDefaultValueSchema,
+});
+
+export type SettingsDataModelFieldNumberFormValues = z.infer<
+ typeof settingsDataModelFieldNumberFormSchema
+>;
+
+type SettingsDataModelFieldNumberFormProps = {
+ disabled?: boolean;
+ fieldMetadataItem: Pick<
+ FieldMetadataItem,
+ 'icon' | 'label' | 'type' | 'defaultValue' | 'settings'
+ >;
+};
+
+export const SettingsDataModelFieldNumberForm = ({
+ disabled,
+ fieldMetadataItem,
+}: SettingsDataModelFieldNumberFormProps) => {
+ const { control } = useFormContext();
+
+ return (
+
+ {
+ const count = value?.decimals ?? 0;
+
+ return (
+ onChange({ decimals: value })}
+ disabled={disabled}
+ >
+ );
+ }}
+ />
+
+ );
+};
diff --git a/packages/twenty-front/src/modules/settings/data-model/fields/forms/number/components/SettingsDataModelFieldNumberSettingsFormCard.tsx b/packages/twenty-front/src/modules/settings/data-model/fields/forms/number/components/SettingsDataModelFieldNumberSettingsFormCard.tsx
new file mode 100644
index 000000000000..edea86760fbf
--- /dev/null
+++ b/packages/twenty-front/src/modules/settings/data-model/fields/forms/number/components/SettingsDataModelFieldNumberSettingsFormCard.tsx
@@ -0,0 +1,45 @@
+import styled from '@emotion/styled';
+
+import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
+import { SettingsDataModelPreviewFormCard } from '@/settings/data-model/components/SettingsDataModelPreviewFormCard';
+import { SettingsDataModelFieldNumberForm } from '@/settings/data-model/fields/forms/number/components/SettingsDataModelFieldNumberForm';
+import {
+ SettingsDataModelFieldPreviewCard,
+ SettingsDataModelFieldPreviewCardProps,
+} from '@/settings/data-model/fields/preview/components/SettingsDataModelFieldPreviewCard';
+
+type SettingsDataModelFieldNumberSettingsFormCardProps = {
+ disabled?: boolean;
+ fieldMetadataItem: Pick<
+ FieldMetadataItem,
+ 'icon' | 'label' | 'type' | 'defaultValue'
+ >;
+} & Pick;
+
+const StyledFieldPreviewCard = styled(SettingsDataModelFieldPreviewCard)`
+ display: grid;
+ flex: 1 1 100%;
+`;
+
+export const SettingsDataModelFieldNumberSettingsFormCard = ({
+ disabled,
+ fieldMetadataItem,
+ objectMetadataItem,
+}: SettingsDataModelFieldNumberSettingsFormCardProps) => {
+ return (
+
+ }
+ form={
+
+ }
+ />
+ );
+};
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 63305b53d04d..d6f3fe48be10 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
@@ -14,6 +14,7 @@ import { RelationType } from '@/settings/data-model/types/RelationType';
import { IconPicker } from '@/ui/input/components/IconPicker';
import { Select } from '@/ui/input/components/Select';
import { TextInput } from '@/ui/input/components/TextInput';
+import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
import { RelationDefinitionType } from '~/generated-metadata/graphql';
export const settingsDataModelFieldRelationFormSchema = z.object({
@@ -44,13 +45,12 @@ const StyledContainer = styled.div`
padding: ${({ theme }) => theme.spacing(4)};
`;
-const StyledSelectsContainer = styled.div`
+const StyledSelectsContainer = styled.div<{ isMobile: boolean }>`
display: grid;
gap: ${({ theme }) => theme.spacing(4)};
- grid-template-columns: 1fr 1fr;
+ grid-template-columns: ${({ isMobile }) => (isMobile ? '1fr' : '1fr 1fr')};
margin-bottom: ${({ theme }) => theme.spacing(4)};
`;
-
const StyledInputsLabel = styled.span`
color: ${({ theme }) => theme.font.color.light};
display: block;
@@ -66,7 +66,11 @@ const StyledInputsContainer = styled.div`
`;
const RELATION_TYPE_OPTIONS = Object.entries(RELATION_TYPES)
- .filter(([value]) => 'ONE_TO_ONE' !== value && 'MANY_TO_MANY' !== value)
+ .filter(
+ ([value]) =>
+ RelationDefinitionType.OneToOne !== value &&
+ RelationDefinitionType.ManyToMany !== value,
+ )
.map(([value, { label, Icon }]) => ({
label,
value: value as RelationType,
@@ -94,9 +98,11 @@ export const SettingsDataModelFieldRelationForm = ({
watchFormValue('relation.objectMetadataId'),
);
+ const isMobile = useIsMobile();
+
return (
-
+
&
Partial>;
@@ -27,14 +27,23 @@ const StyledFieldPreviewCard = styled(SettingsDataModelFieldPreviewCard)`
flex: 1 1 100%;
`;
-const StyledPreviewContent = styled.div`
+const StyledPreviewContent = styled.div<{ isMobile: boolean }>`
display: flex;
- flex-direction: column;
gap: 6px;
+ flex-direction: ${({ isMobile }) => (isMobile ? 'column' : 'row')};
`;
-const StyledRelationImage = styled.img<{ flip?: boolean }>`
- transform: ${({ flip }) => (flip ? 'scaleX(-1) rotate(270deg)' : 'none')};
+const StyledRelationImage = styled.img<{ flip?: boolean; isMobile: boolean }>`
+ transform: ${({ flip, isMobile }) => {
+ let transform = '';
+ if (isMobile) {
+ transform += 'rotate(90deg) ';
+ }
+ if (flip === true) {
+ transform += 'scaleX(-1)';
+ }
+ return transform.trim();
+ }};
margin: auto;
width: 54px;
`;
@@ -46,7 +55,7 @@ export const SettingsDataModelFieldRelationSettingsFormCard = ({
const { watch: watchFormValue } =
useFormContext();
const { findObjectMetadataItemById } = useFilteredObjectMetadataItems();
-
+ const isMobile = useIsMobile();
const {
initialRelationObjectMetadataItem,
initialRelationType,
@@ -69,7 +78,7 @@ export const SettingsDataModelFieldRelationSettingsFormCard = ({
return (
+
item.nameSingular === 'company',
+);
+
+const mockedOpportunityObjectMetadataItem =
+ generatedMockObjectMetadataItems.find(
+ (item) => item.nameSingular === 'opportunity',
+ );
+
+const mockedPersonObjectMetadataItem = generatedMockObjectMetadataItems.find(
+ (item) => item.nameSingular === 'person',
+);
+
const meta: Meta = {
title:
'Modules/Settings/DataModel/Fields/Preview/SettingsDataModelFieldPreviewCard',
@@ -38,7 +47,7 @@ type Story = StoryObj;
export const LabelIdentifier: Story = {
args: {
- fieldMetadataItem: mockedPersonObjectMetadataItem.fields.find(
+ fieldMetadataItem: mockedPersonObjectMetadataItem?.fields.find(
({ name, type }) =>
name === 'name' && type === FieldMetadataType.FullName,
),
@@ -47,7 +56,7 @@ export const LabelIdentifier: Story = {
export const Text: Story = {
args: {
- fieldMetadataItem: mockedPersonObjectMetadataItem.fields.find(
+ fieldMetadataItem: mockedPersonObjectMetadataItem?.fields.find(
({ name, type }) => name === 'city' && type === FieldMetadataType.Text,
),
},
@@ -55,7 +64,7 @@ export const Text: Story = {
export const Boolean: Story = {
args: {
- fieldMetadataItem: mockedCompanyObjectMetadataItem.fields.find(
+ fieldMetadataItem: mockedCompanyObjectMetadataItem?.fields.find(
({ name, type }) =>
name === 'idealCustomerProfile' && type === FieldMetadataType.Boolean,
),
@@ -65,7 +74,7 @@ export const Boolean: Story = {
export const Currency: Story = {
args: {
- fieldMetadataItem: mockedCompanyObjectMetadataItem.fields.find(
+ fieldMetadataItem: mockedCompanyObjectMetadataItem?.fields.find(
({ name, type }) =>
name === 'annualRecurringRevenue' &&
type === FieldMetadataType.Currency,
@@ -76,7 +85,7 @@ export const Currency: Story = {
export const Date: Story = {
args: {
- fieldMetadataItem: mockedCompanyObjectMetadataItem.fields.find(
+ fieldMetadataItem: mockedCompanyObjectMetadataItem?.fields.find(
({ type }) => type === FieldMetadataType.DateTime,
),
objectMetadataItem: mockedCompanyObjectMetadataItem,
@@ -85,7 +94,7 @@ export const Date: Story = {
export const Links: Story = {
args: {
- fieldMetadataItem: mockedCompanyObjectMetadataItem.fields.find(
+ fieldMetadataItem: mockedCompanyObjectMetadataItem?.fields.find(
({ name, type }) =>
name === 'linkedinLink' && type === FieldMetadataType.Links,
),
@@ -95,7 +104,7 @@ export const Links: Story = {
export const Number: Story = {
args: {
- fieldMetadataItem: mockedCompanyObjectMetadataItem.fields.find(
+ fieldMetadataItem: mockedCompanyObjectMetadataItem?.fields.find(
({ type }) => type === FieldMetadataType.Number,
),
objectMetadataItem: mockedCompanyObjectMetadataItem,
@@ -114,7 +123,7 @@ export const Rating: Story = {
export const Relation: Story = {
args: {
- fieldMetadataItem: mockedPersonObjectMetadataItem.fields.find(
+ fieldMetadataItem: mockedPersonObjectMetadataItem?.fields.find(
({ name }) => name === 'company',
),
relationObjectMetadataItem: mockedCompanyObjectMetadataItem,
@@ -123,7 +132,7 @@ export const Relation: Story = {
export const Select: Story = {
args: {
- fieldMetadataItem: mockedOpportunityObjectMetadataItem.fields.find(
+ fieldMetadataItem: mockedOpportunityObjectMetadataItem?.fields.find(
({ name, type }) => name === 'stage' && type === FieldMetadataType.Select,
),
objectMetadataItem: mockedOpportunityObjectMetadataItem,
diff --git a/packages/twenty-front/src/modules/settings/data-model/fields/preview/hooks/__tests__/useFieldPreviewValue.test.tsx b/packages/twenty-front/src/modules/settings/data-model/fields/preview/hooks/__tests__/useFieldPreviewValue.test.tsx
index a3fbadbf1a24..c9c6b0d4367b 100644
--- a/packages/twenty-front/src/modules/settings/data-model/fields/preview/hooks/__tests__/useFieldPreviewValue.test.tsx
+++ b/packages/twenty-front/src/modules/settings/data-model/fields/preview/hooks/__tests__/useFieldPreviewValue.test.tsx
@@ -1,35 +1,34 @@
-import { ReactNode } from 'react';
-import { MockedProvider } from '@apollo/client/testing';
import { renderHook } from '@testing-library/react';
-import { RecoilRoot } from 'recoil';
-import { ObjectMetadataItemsProvider } from '@/object-metadata/components/ObjectMetadataItemsProvider';
import { FieldMetadataItemOption } from '@/object-metadata/types/FieldMetadataItem';
-import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarProviderScope';
import { FieldMetadataType } from '~/generated/graphql';
-import {
- mockedCompanyObjectMetadataItem,
- mockedOpportunityObjectMetadataItem,
- mockedPersonObjectMetadataItem,
-} from '~/testing/mock-data/metadata';
+import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
+import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
import { useFieldPreviewValue } from '../useFieldPreviewValue';
-const Wrapper = ({ children }: { children: ReactNode }) => (
-
-
-
- {children}
-
-
-
+const mockedCompanyObjectMetadataItem = generatedMockObjectMetadataItems.find(
+ (item) => item.nameSingular === 'company',
);
+const mockedOpportunityObjectMetadataItem =
+ generatedMockObjectMetadataItems.find(
+ (item) => item.nameSingular === 'opportunity',
+ );
+
+const mockedPersonObjectMetadataItem = generatedMockObjectMetadataItems.find(
+ (item) => item.nameSingular === 'person',
+);
+
+const Wrapper = getJestMetadataAndApolloMocksWrapper({
+ apolloMocks: [],
+});
+
describe('useFieldPreviewValue', () => {
it('returns null if skip is true', () => {
// Given
const fieldName = 'amount';
- const fieldMetadataItem = mockedOpportunityObjectMetadataItem.fields.find(
+ const fieldMetadataItem = mockedOpportunityObjectMetadataItem?.fields.find(
({ name, type }) =>
name === fieldName && type === FieldMetadataType.Currency,
);
@@ -52,7 +51,7 @@ describe('useFieldPreviewValue', () => {
it("returns the field's preview value for a Currency field", () => {
// Given
const fieldName = 'amount';
- const fieldMetadataItem = mockedOpportunityObjectMetadataItem.fields.find(
+ const fieldMetadataItem = mockedOpportunityObjectMetadataItem?.fields.find(
({ name, type }) =>
name === fieldName && type === FieldMetadataType.Currency,
);
@@ -106,7 +105,7 @@ describe('useFieldPreviewValue', () => {
it("returns the field's preview value for a Select field", () => {
// Given
const fieldName = 'stage';
- const fieldMetadataItem = mockedOpportunityObjectMetadataItem.fields.find(
+ const fieldMetadataItem = mockedOpportunityObjectMetadataItem?.fields.find(
({ name, type }) =>
name === fieldName && type === FieldMetadataType.Select,
);
@@ -169,7 +168,7 @@ describe('useFieldPreviewValue', () => {
it("returns the field's preview value for other field types", () => {
// Given
const fieldName = 'employees';
- const fieldMetadataItem = mockedCompanyObjectMetadataItem.fields.find(
+ const fieldMetadataItem = mockedCompanyObjectMetadataItem?.fields.find(
({ name }) => name === fieldName,
);
diff --git a/packages/twenty-front/src/modules/settings/data-model/fields/preview/utils/__tests__/getCurrencyFieldPreviewValue.test.ts b/packages/twenty-front/src/modules/settings/data-model/fields/preview/utils/__tests__/getCurrencyFieldPreviewValue.test.ts
index a8d9b9a4af7e..8eeda74fbb79 100644
--- a/packages/twenty-front/src/modules/settings/data-model/fields/preview/utils/__tests__/getCurrencyFieldPreviewValue.test.ts
+++ b/packages/twenty-front/src/modules/settings/data-model/fields/preview/utils/__tests__/getCurrencyFieldPreviewValue.test.ts
@@ -1,16 +1,22 @@
import { CurrencyCode } from '@/object-record/record-field/types/CurrencyCode';
import { FieldMetadataType } from '~/generated-metadata/graphql';
-import {
- mockedCompanyObjectMetadataItem,
- mockedOpportunityObjectMetadataItem,
-} from '~/testing/mock-data/metadata';
+import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
import { getCurrencyFieldPreviewValue } from '../getCurrencyFieldPreviewValue';
+const mockedCompanyObjectMetadataItem = generatedMockObjectMetadataItems.find(
+ (item) => item.nameSingular === 'company',
+);
+
+const mockedOpportunityObjectMetadataItem =
+ generatedMockObjectMetadataItems.find(
+ (item) => item.nameSingular === 'opportunity',
+ );
+
describe('getCurrencyFieldPreviewValue', () => {
it('returns null if the field is not a Currency field', () => {
// Given
- const fieldMetadataItem = mockedCompanyObjectMetadataItem.fields.find(
+ const fieldMetadataItem = mockedCompanyObjectMetadataItem?.fields.find(
({ type }) => type !== FieldMetadataType.Currency,
);
@@ -26,7 +32,7 @@ describe('getCurrencyFieldPreviewValue', () => {
});
const fieldName = 'amount';
- const fieldMetadataItem = mockedOpportunityObjectMetadataItem.fields.find(
+ const fieldMetadataItem = mockedOpportunityObjectMetadataItem?.fields.find(
({ name, type }) =>
name === fieldName && type === FieldMetadataType.Currency,
);
diff --git a/packages/twenty-front/src/modules/settings/data-model/fields/preview/utils/__tests__/getFieldPreviewValue.test.ts b/packages/twenty-front/src/modules/settings/data-model/fields/preview/utils/__tests__/getFieldPreviewValue.test.ts
index 7acf2b0cfe4c..c3a649dbad77 100644
--- a/packages/twenty-front/src/modules/settings/data-model/fields/preview/utils/__tests__/getFieldPreviewValue.test.ts
+++ b/packages/twenty-front/src/modules/settings/data-model/fields/preview/utils/__tests__/getFieldPreviewValue.test.ts
@@ -1,17 +1,21 @@
import { getFieldPreviewValue } from '@/settings/data-model/fields/preview/utils/getFieldPreviewValue';
import { getSettingsFieldTypeConfig } from '@/settings/data-model/utils/getSettingsFieldTypeConfig';
import { FieldMetadataType } from '~/generated-metadata/graphql';
-import {
- mockedCompanyObjectMetadataItem,
- mockedCustomObjectMetadataItem,
- mockedPersonObjectMetadataItem,
-} from '~/testing/mock-data/metadata';
+import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
+
+const mockedCompanyObjectMetadataItem = generatedMockObjectMetadataItems.find(
+ (item) => item.nameSingular === 'company',
+);
+
+const mockedPersonObjectMetadataItem = generatedMockObjectMetadataItems.find(
+ (item) => item.nameSingular === 'person',
+);
describe('getFieldPreviewValue', () => {
it("returns the field's defaultValue from metadata if it exists", () => {
// Given
const fieldName = 'idealCustomerProfile';
- const fieldMetadataItem = mockedCompanyObjectMetadataItem.fields.find(
+ const fieldMetadataItem = mockedCompanyObjectMetadataItem?.fields.find(
({ name }) => name === fieldName,
);
@@ -29,7 +33,7 @@ describe('getFieldPreviewValue', () => {
it('returns a placeholder defaultValue if the field metadata does not have a defaultValue', () => {
// Given
const fieldName = 'employees';
- const fieldMetadataItem = mockedCompanyObjectMetadataItem.fields.find(
+ const fieldMetadataItem = mockedCompanyObjectMetadataItem?.fields.find(
({ name }) => name === fieldName,
);
@@ -50,25 +54,7 @@ describe('getFieldPreviewValue', () => {
it('returns null if the field is supported in Settings but has no pre-configured placeholder defaultValue', () => {
// Given
const fieldName = 'company';
- const fieldMetadataItem = mockedPersonObjectMetadataItem.fields.find(
- ({ name }) => name === fieldName,
- );
-
- if (!fieldMetadataItem) {
- throw new Error(`Field '${fieldName}' not found`);
- }
-
- // When
- const result = getFieldPreviewValue({ fieldMetadataItem });
-
- // Then
- expect(result).toBeNull();
- });
-
- it('returns null if the field is not supported in Settings', () => {
- // Given
- const fieldName = 'position';
- const fieldMetadataItem = mockedCustomObjectMetadataItem.fields.find(
+ const fieldMetadataItem = mockedPersonObjectMetadataItem?.fields.find(
({ name }) => name === fieldName,
);
diff --git a/packages/twenty-front/src/modules/settings/data-model/fields/preview/utils/__tests__/getMultiSelectFieldPreviewValue.test.ts b/packages/twenty-front/src/modules/settings/data-model/fields/preview/utils/__tests__/getMultiSelectFieldPreviewValue.test.ts
index 824d6e820167..2737a829ee91 100644
--- a/packages/twenty-front/src/modules/settings/data-model/fields/preview/utils/__tests__/getMultiSelectFieldPreviewValue.test.ts
+++ b/packages/twenty-front/src/modules/settings/data-model/fields/preview/utils/__tests__/getMultiSelectFieldPreviewValue.test.ts
@@ -1,15 +1,20 @@
import { FieldMetadataType } from '~/generated-metadata/graphql';
-import {
- mockedCompanyObjectMetadataItem,
- mockedCustomObjectMetadataItem,
-} from '~/testing/mock-data/metadata';
-
+import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
import { getMultiSelectFieldPreviewValue } from '../getMultiSelectFieldPreviewValue';
+const mockedCompanyObjectMetadataItem = generatedMockObjectMetadataItems.find(
+ (item) => item.nameSingular === 'company',
+);
+
+const mockedOpportunityObjectMetadataItem =
+ generatedMockObjectMetadataItems.find(
+ (item) => item.nameSingular === 'opportunity',
+ );
+
describe('getMultiSelectFieldPreviewValue', () => {
it('returns null if the field is not a Multi-Select field', () => {
// Given
- const fieldMetadataItem = mockedCompanyObjectMetadataItem.fields.find(
+ const fieldMetadataItem = mockedCompanyObjectMetadataItem?.fields.find(
({ type }) => type !== FieldMetadataType.MultiSelect,
);
@@ -24,10 +29,11 @@ describe('getMultiSelectFieldPreviewValue', () => {
expect(previewValue).toBeNull();
});
- const fieldName = 'priority';
- const selectFieldMetadataItem = mockedCustomObjectMetadataItem.fields.find(
- ({ name, type }) => name === fieldName && type === FieldMetadataType.Select,
- );
+ const fieldName = 'stage';
+ const selectFieldMetadataItem =
+ mockedOpportunityObjectMetadataItem?.fields.find(
+ ({ name }) => name === fieldName,
+ );
if (!selectFieldMetadataItem) {
throw new Error(`Field '${fieldName}' not found`);
@@ -52,7 +58,13 @@ describe('getMultiSelectFieldPreviewValue', () => {
});
// Then
- expect(previewValue).toEqual(['MEDIUM', 'LOW']);
+ expect(previewValue).toEqual([
+ 'NEW',
+ 'SCREENING',
+ 'MEETING',
+ 'PROPOSAL',
+ 'CUSTOMER',
+ ]);
});
it("returns all option values if no defaultValue was found in the field's metadata", () => {
@@ -69,7 +81,13 @@ describe('getMultiSelectFieldPreviewValue', () => {
});
// Then
- expect(previewValue).toEqual(['LOW', 'MEDIUM', 'HIGH']);
+ expect(previewValue).toEqual([
+ 'NEW',
+ 'SCREENING',
+ 'MEETING',
+ 'PROPOSAL',
+ 'CUSTOMER',
+ ]);
expect(previewValue).toEqual(
fieldMetadataItemWithDefaultValue.options?.map(({ value }) => value),
);
@@ -89,7 +107,13 @@ describe('getMultiSelectFieldPreviewValue', () => {
});
// Then
- expect(previewValue).toEqual(['LOW', 'MEDIUM', 'HIGH']);
+ expect(previewValue).toEqual([
+ 'NEW',
+ 'SCREENING',
+ 'MEETING',
+ 'PROPOSAL',
+ 'CUSTOMER',
+ ]);
expect(previewValue).toEqual(
fieldMetadataItemWithDefaultValue.options?.map(({ value }) => value),
);
diff --git a/packages/twenty-front/src/modules/settings/data-model/fields/preview/utils/__tests__/getSelectFieldPreviewValue.test.ts b/packages/twenty-front/src/modules/settings/data-model/fields/preview/utils/__tests__/getSelectFieldPreviewValue.test.ts
index 3572d58d9007..109feefb3ab1 100644
--- a/packages/twenty-front/src/modules/settings/data-model/fields/preview/utils/__tests__/getSelectFieldPreviewValue.test.ts
+++ b/packages/twenty-front/src/modules/settings/data-model/fields/preview/utils/__tests__/getSelectFieldPreviewValue.test.ts
@@ -1,15 +1,21 @@
import { FieldMetadataType } from '~/generated-metadata/graphql';
-import {
- mockedCompanyObjectMetadataItem,
- mockedCustomObjectMetadataItem,
-} from '~/testing/mock-data/metadata';
+import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
import { getSelectFieldPreviewValue } from '../getSelectFieldPreviewValue';
+const mockedCompanyObjectMetadataItem = generatedMockObjectMetadataItems.find(
+ (item) => item.nameSingular === 'company',
+);
+
+const mockedOpportunityObjectMetadataItem =
+ generatedMockObjectMetadataItems.find(
+ (item) => item.nameSingular === 'opportunity',
+ );
+
describe('getSelectFieldPreviewValue', () => {
it('returns null if the field is not a Select field', () => {
// Given
- const fieldMetadataItem = mockedCompanyObjectMetadataItem.fields.find(
+ const fieldMetadataItem = mockedCompanyObjectMetadataItem?.fields.find(
({ type }) => type !== FieldMetadataType.Select,
);
@@ -24,9 +30,9 @@ describe('getSelectFieldPreviewValue', () => {
expect(previewValue).toBeNull();
});
- const fieldName = 'priority';
- const fieldMetadataItem = mockedCustomObjectMetadataItem.fields.find(
- ({ name, type }) => name === fieldName && type === FieldMetadataType.Select,
+ const fieldName = 'stage';
+ const fieldMetadataItem = mockedOpportunityObjectMetadataItem?.fields.find(
+ ({ name }) => name === fieldName,
);
if (!fieldMetadataItem) {
@@ -35,7 +41,7 @@ describe('getSelectFieldPreviewValue', () => {
it("returns the defaultValue as an option value if a valid defaultValue is found in the field's metadata", () => {
// Given
- const defaultValue = "'MEDIUM'";
+ const defaultValue = "'NEW'";
const fieldMetadataItemWithDefaultValue = {
...fieldMetadataItem,
defaultValue,
@@ -47,7 +53,7 @@ describe('getSelectFieldPreviewValue', () => {
});
// Then
- expect(previewValue).toBe('MEDIUM');
+ expect(previewValue).toBe('NEW');
});
it("returns the first option value if no defaultValue was found in the field's metadata", () => {
@@ -64,7 +70,7 @@ describe('getSelectFieldPreviewValue', () => {
});
// Then
- expect(previewValue).toBe('LOW');
+ expect(previewValue).toBe('NEW');
expect(previewValue).toBe(
fieldMetadataItemWithDefaultValue.options?.[0]?.value,
);
@@ -84,7 +90,7 @@ describe('getSelectFieldPreviewValue', () => {
});
// Then
- expect(previewValue).toBe('LOW');
+ expect(previewValue).toBe('NEW');
expect(previewValue).toBe(
fieldMetadataItemWithDefaultValue.options?.[0]?.value,
);
diff --git a/packages/twenty-front/src/modules/settings/data-model/objects/forms/components/__stories__/SettingsDataModelObjectAboutForm.stories.tsx b/packages/twenty-front/src/modules/settings/data-model/objects/forms/components/__stories__/SettingsDataModelObjectAboutForm.stories.tsx
index 4345f59229e9..173106174fdf 100644
--- a/packages/twenty-front/src/modules/settings/data-model/objects/forms/components/__stories__/SettingsDataModelObjectAboutForm.stories.tsx
+++ b/packages/twenty-front/src/modules/settings/data-model/objects/forms/components/__stories__/SettingsDataModelObjectAboutForm.stories.tsx
@@ -4,9 +4,12 @@ import { ComponentDecorator } from 'twenty-ui';
import { FormProviderDecorator } from '~/testing/decorators/FormProviderDecorator';
import { IconsProviderDecorator } from '~/testing/decorators/IconsProviderDecorator';
-import { mockedCompanyObjectMetadataItem } from '~/testing/mock-data/metadata';
+import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
import { SettingsDataModelObjectAboutForm } from '../SettingsDataModelObjectAboutForm';
+const mockedCompanyObjectMetadataItem = generatedMockObjectMetadataItems.find(
+ (item) => item.nameSingular === 'company',
+);
const StyledContainer = styled.div`
flex: 1;
diff --git a/packages/twenty-front/src/modules/settings/data-model/utils/__tests__/getFieldPreviewValueFromRecord.test.ts b/packages/twenty-front/src/modules/settings/data-model/utils/__tests__/getFieldPreviewValueFromRecord.test.ts
index 95b0aac275e1..750604ef1515 100644
--- a/packages/twenty-front/src/modules/settings/data-model/utils/__tests__/getFieldPreviewValueFromRecord.test.ts
+++ b/packages/twenty-front/src/modules/settings/data-model/utils/__tests__/getFieldPreviewValueFromRecord.test.ts
@@ -1,10 +1,14 @@
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
-import {
- mockedCompanyObjectMetadataItem,
- mockedPersonObjectMetadataItem,
-} from '~/testing/mock-data/metadata';
+import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
import { getFieldPreviewValueFromRecord } from '../getFieldPreviewValueFromRecord';
+const mockedCompanyObjectMetadataItem = generatedMockObjectMetadataItems.find(
+ (item) => item.nameSingular === 'company',
+);
+
+const mockedPersonObjectMetadataItem = generatedMockObjectMetadataItems.find(
+ (item) => item.nameSingular === 'person',
+);
describe('getFieldPreviewValueFromRecord', () => {
describe('RELATION field', () => {
@@ -21,9 +25,13 @@ describe('getFieldPreviewValueFromRecord', () => {
},
__typename: 'Opportunity',
};
- const fieldMetadataItem = mockedCompanyObjectMetadataItem.fields.find(
+ const fieldMetadataItem = mockedCompanyObjectMetadataItem?.fields.find(
({ name }) => name === 'people',
- )!;
+ );
+
+ if (!fieldMetadataItem) {
+ throw new Error('Field not found');
+ }
// When
const result = getFieldPreviewValueFromRecord({
@@ -43,9 +51,13 @@ describe('getFieldPreviewValueFromRecord', () => {
company: relationRecord,
__typename: 'Opportunity',
};
- const fieldMetadataItem = mockedPersonObjectMetadataItem.fields.find(
+ const fieldMetadataItem = mockedPersonObjectMetadataItem?.fields.find(
({ name }) => name === 'company',
- )!;
+ );
+
+ if (!fieldMetadataItem) {
+ throw new Error('Field not found');
+ }
// When
const result = getFieldPreviewValueFromRecord({
@@ -62,9 +74,13 @@ describe('getFieldPreviewValueFromRecord', () => {
it('returns the record field value', () => {
// Given
const record = { id: '', name: 'Twenty', __typename: 'Opportunity' };
- const fieldMetadataItem = mockedCompanyObjectMetadataItem.fields.find(
+ const fieldMetadataItem = mockedCompanyObjectMetadataItem?.fields.find(
({ name }) => name === 'name',
- )!;
+ );
+
+ if (!fieldMetadataItem) {
+ throw new Error('Field not found');
+ }
// When
const result = getFieldPreviewValueFromRecord({
diff --git a/packages/twenty-front/src/modules/settings/profile/components/ProfilePictureUploader.tsx b/packages/twenty-front/src/modules/settings/profile/components/ProfilePictureUploader.tsx
index dcfcfaf5e7e1..6d9bf03e00e2 100644
--- a/packages/twenty-front/src/modules/settings/profile/components/ProfilePictureUploader.tsx
+++ b/packages/twenty-front/src/modules/settings/profile/components/ProfilePictureUploader.tsx
@@ -71,7 +71,7 @@ export const ProfilePictureUploader = () => {
return result;
} catch (error) {
- setErrorMessage('An error occured while uploading the picture.');
+ setErrorMessage('An error occurred while uploading the picture.');
}
};
@@ -97,7 +97,7 @@ export const ProfilePictureUploader = () => {
setCurrentWorkspaceMember({ ...currentWorkspaceMember, avatarUrl: null });
} catch (error) {
- setErrorMessage('An error occured while removing the picture.');
+ setErrorMessage('An error occurred while removing the picture.');
}
};
diff --git a/packages/twenty-front/src/modules/settings/serverless-functions/components/SettingsServerlessFunctionsTable.tsx b/packages/twenty-front/src/modules/settings/serverless-functions/components/SettingsServerlessFunctionsTable.tsx
index 93785116af7e..286a90faadca 100644
--- a/packages/twenty-front/src/modules/settings/serverless-functions/components/SettingsServerlessFunctionsTable.tsx
+++ b/packages/twenty-front/src/modules/settings/serverless-functions/components/SettingsServerlessFunctionsTable.tsx
@@ -1,3 +1,4 @@
+import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
import { SettingsServerlessFunctionsFieldItemTableRow } from '@/settings/serverless-functions/components/SettingsServerlessFunctionsFieldItemTableRow';
import { SettingsServerlessFunctionsTableEmpty } from '@/settings/serverless-functions/components/SettingsServerlessFunctionsTableEmpty';
import { useGetManyServerlessFunctions } from '@/settings/serverless-functions/hooks/useGetManyServerlessFunctions';
@@ -24,26 +25,28 @@ export const SettingsServerlessFunctionsTable = () => {
return (
<>
{serverlessFunctions.length ? (
-
-
- Name
- Runtime
-
-
-
- {serverlessFunctions.map(
- (serverlessFunction: ServerlessFunction) => (
-
- ),
- )}
-
-
+
+
+
+ Name
+ Runtime
+
+
+
+ {serverlessFunctions.map(
+ (serverlessFunction: ServerlessFunction) => (
+
+ ),
+ )}
+
+
+
) : (
)}
diff --git a/packages/twenty-front/src/modules/settings/serverless-functions/hooks/__tests__/useServerlessFunctionUpdateFormState.test.ts b/packages/twenty-front/src/modules/settings/serverless-functions/hooks/__tests__/useServerlessFunctionUpdateFormState.test.ts
index e0799f13ac2e..36de554158df 100644
--- a/packages/twenty-front/src/modules/settings/serverless-functions/hooks/__tests__/useServerlessFunctionUpdateFormState.test.ts
+++ b/packages/twenty-front/src/modules/settings/serverless-functions/hooks/__tests__/useServerlessFunctionUpdateFormState.test.ts
@@ -1,5 +1,5 @@
-import { renderHook } from '@testing-library/react';
import { useServerlessFunctionUpdateFormState } from '@/settings/serverless-functions/hooks/useServerlessFunctionUpdateFormState';
+import { renderHook } from '@testing-library/react';
import { RecoilRoot } from 'recoil';
jest.mock(
@@ -44,6 +44,6 @@ describe('useServerlessFunctionUpdateFormState', () => {
const { formValues } = result.current;
- expect(formValues).toEqual({ name: '', description: '', code: '' });
+ expect(formValues).toEqual({ name: '', description: '', code: undefined });
});
});
diff --git a/packages/twenty-front/src/modules/settings/serverless-functions/hooks/useServerlessFunctionUpdateFormState.ts b/packages/twenty-front/src/modules/settings/serverless-functions/hooks/useServerlessFunctionUpdateFormState.ts
index 367710df7137..9e8a13483810 100644
--- a/packages/twenty-front/src/modules/settings/serverless-functions/hooks/useServerlessFunctionUpdateFormState.ts
+++ b/packages/twenty-front/src/modules/settings/serverless-functions/hooks/useServerlessFunctionUpdateFormState.ts
@@ -1,6 +1,6 @@
-import { Dispatch, SetStateAction, useState } from 'react';
import { useGetOneServerlessFunction } from '@/settings/serverless-functions/hooks/useGetOneServerlessFunction';
import { useGetOneServerlessFunctionSourceCode } from '@/settings/serverless-functions/hooks/useGetOneServerlessFunctionSourceCode';
+import { Dispatch, SetStateAction, useState } from 'react';
import { FindOneServerlessFunctionSourceCodeQuery } from '~/generated-metadata/graphql';
export type ServerlessFunctionNewFormValues = {
diff --git a/packages/twenty-front/src/modules/support/components/SupportButtonSkeletonLoader.tsx b/packages/twenty-front/src/modules/support/components/SupportButtonSkeletonLoader.tsx
index 86d4d1b93231..78440fe021d2 100644
--- a/packages/twenty-front/src/modules/support/components/SupportButtonSkeletonLoader.tsx
+++ b/packages/twenty-front/src/modules/support/components/SupportButtonSkeletonLoader.tsx
@@ -1,5 +1,6 @@
-import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
+import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader';
import { useTheme } from '@emotion/react';
+import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
export const SupportButtonSkeletonLoader = () => {
const theme = useTheme();
@@ -9,7 +10,7 @@ export const SupportButtonSkeletonLoader = () => {
highlightColor={theme.background.transparent.lighter}
borderRadius={4}
>
-
+
);
};
diff --git a/packages/twenty-front/src/modules/ui/field/display/components/ActorDisplay.tsx b/packages/twenty-front/src/modules/ui/field/display/components/ActorDisplay.tsx
index ba107aa612f0..b5111d245a0a 100644
--- a/packages/twenty-front/src/modules/ui/field/display/components/ActorDisplay.tsx
+++ b/packages/twenty-front/src/modules/ui/field/display/components/ActorDisplay.tsx
@@ -7,6 +7,7 @@ import {
IconCalendar,
IconCsv,
IconGmail,
+ IconRobot,
} from 'twenty-ui';
type ActorDisplayProps = Partial & {
@@ -29,12 +30,15 @@ export const ActorDisplay = ({
return IconGmail;
case 'CALENDAR':
return IconCalendar;
+ case 'SYSTEM':
+ return IconRobot;
default:
return undefined;
}
}, [source]);
- const isIconInverted = source === 'API' || source === 'IMPORT';
+ const isIconInverted =
+ source === 'API' || source === 'IMPORT' || source === 'SYSTEM';
return (
(
- {value && formatNumber(Number(value))}
+export const NumberDisplay = ({ value, decimals }: NumberDisplayProps) => (
+
+ {value && formatNumber(Number(value), decimals)}
+
);
diff --git a/packages/twenty-front/src/modules/ui/input/relation-picker/components/skeletons/DropdownMenuSkeletonItem.tsx b/packages/twenty-front/src/modules/ui/input/relation-picker/components/skeletons/DropdownMenuSkeletonItem.tsx
index f4853bc48c69..820831f7c77b 100644
--- a/packages/twenty-front/src/modules/ui/input/relation-picker/components/skeletons/DropdownMenuSkeletonItem.tsx
+++ b/packages/twenty-front/src/modules/ui/input/relation-picker/components/skeletons/DropdownMenuSkeletonItem.tsx
@@ -1,6 +1,7 @@
-import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
+import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
+import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
const StyledDropdownMenuSkeletonContainer = styled.div`
--horizontal-padding: ${({ theme }) => theme.spacing(1)};
@@ -21,7 +22,7 @@ export const DropdownMenuSkeletonItem = () => {
baseColor={theme.background.quaternary}
highlightColor={theme.background.secondary}
>
-
+
);
diff --git a/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenuInput.tsx b/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenuInput.tsx
index 5a123105c153..145da879ad11 100644
--- a/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenuInput.tsx
+++ b/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenuInput.tsx
@@ -7,10 +7,14 @@ import { RGBA, TEXT_INPUT_STYLE } from 'twenty-ui';
import { useRegisterInputEvents } from '@/object-record/record-field/meta-types/input/hooks/useRegisterInputEvents';
import { useCombinedRefs } from '~/hooks/useCombinedRefs';
-const StyledInput = styled.input<{ withRightComponent?: boolean }>`
+const StyledInput = styled.input<{
+ withRightComponent?: boolean;
+ hasError?: boolean;
+}>`
${TEXT_INPUT_STYLE}
- border: 1px solid ${({ theme }) => theme.border.color.medium};
+ border: 1px solid ${({ theme, hasError }) =>
+ hasError ? theme.border.color.danger : theme.border.color.medium};
border-radius: ${({ theme }) => theme.border.radius.sm};
box-sizing: border-box;
font-weight: ${({ theme }) => theme.font.weight.medium};
@@ -19,8 +23,10 @@ const StyledInput = styled.input<{ withRightComponent?: boolean }>`
width: 100%;
&:focus {
- border-color: ${({ theme }) => theme.color.blue};
- box-shadow: 0px 0px 0px 3px ${({ theme }) => RGBA(theme.color.blue, 0.1)};
+ ${({ theme, hasError = false }) => {
+ if (hasError) return '';
+ return `box-shadow: 0px 0px 0px 3px ${RGBA(theme.color.blue, 0.1)}`;
+ }};
}
${({ withRightComponent }) =>
@@ -44,6 +50,12 @@ const StyledRightContainer = styled.div`
transform: translateY(-50%);
`;
+const StyledErrorDiv = styled.div`
+ color: ${({ theme }) => theme.color.red};
+ padding: 0 ${({ theme }) => theme.spacing(2)}
+ ${({ theme }) => theme.spacing(1)};
+`;
+
type HTMLInputProps = InputHTMLAttributes;
export type DropdownMenuInputProps = HTMLInputProps & {
@@ -60,6 +72,8 @@ export type DropdownMenuInputProps = HTMLInputProps & {
autoFocus: HTMLInputProps['autoFocus'];
placeholder: HTMLInputProps['placeholder'];
}) => React.ReactNode;
+ error?: string | null;
+ hasError?: boolean;
};
export const DropdownMenuInput = forwardRef<
@@ -81,6 +95,8 @@ export const DropdownMenuInput = forwardRef<
onTab,
rightComponent,
renderInput,
+ error = '',
+ hasError = false,
},
ref,
) => {
@@ -99,28 +115,32 @@ export const DropdownMenuInput = forwardRef<
});
return (
-
- {renderInput ? (
- renderInput({
- value,
- onChange,
- autoFocus,
- placeholder,
- })
- ) : (
-
- )}
- {!!rightComponent && (
- {rightComponent}
- )}
-
+ <>
+
+ {renderInput ? (
+ renderInput({
+ value,
+ onChange,
+ autoFocus,
+ placeholder,
+ })
+ ) : (
+
+ )}
+ {!!rightComponent && (
+ {rightComponent}
+ )}
+
+ {error && {error}}
+ >
);
},
);
diff --git a/packages/twenty-front/src/modules/ui/layout/right-drawer/components/RightDrawerTopBar.tsx b/packages/twenty-front/src/modules/ui/layout/right-drawer/components/RightDrawerTopBar.tsx
index 9176af20340a..b80b943e1730 100644
--- a/packages/twenty-front/src/modules/ui/layout/right-drawer/components/RightDrawerTopBar.tsx
+++ b/packages/twenty-front/src/modules/ui/layout/right-drawer/components/RightDrawerTopBar.tsx
@@ -5,6 +5,7 @@ import { Chip, ChipAccent, ChipSize, useIcons } from 'twenty-ui';
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
import { getBasePathToShowPage } from '@/object-metadata/utils/getBasePathToShowPage';
+import { isNewViewableRecordLoadingState } from '@/object-record/record-right-drawer/states/isNewViewableRecordLoading';
import { viewableRecordIdState } from '@/object-record/record-right-drawer/states/viewableRecordIdState';
import { viewableRecordNameSingularState } from '@/object-record/record-right-drawer/states/viewableRecordNameSingularState';
import { RightDrawerTopBarCloseButton } from '@/ui/layout/right-drawer/components/RightDrawerTopBarCloseButton';
@@ -66,6 +67,10 @@ export const RightDrawerTopBar = () => {
viewableRecordNameSingularState,
);
+ const isNewViewableRecordLoading = useRecoilValue(
+ isNewViewableRecordLoadingState,
+ );
+
const viewableRecordId = useRecoilValue(viewableRecordIdState);
const { objectMetadataItem } = useObjectMetadataItem({
@@ -95,6 +100,7 @@ export const RightDrawerTopBar = () => {
>
{!isRightDrawerMinimized && (
}
size={ChipSize.Large}
diff --git a/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageActivityContainer.tsx b/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageActivityContainer.tsx
index a69f54528cba..2e38456c4fb9 100644
--- a/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageActivityContainer.tsx
+++ b/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageActivityContainer.tsx
@@ -1,8 +1,10 @@
import { RichTextEditor } from '@/activities/components/RichTextEditor';
import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
+import { isNewViewableRecordLoadingState } from '@/object-record/record-right-drawer/states/isNewViewableRecordLoading';
import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper';
import styled from '@emotion/styled';
+import { useRecoilValue } from 'recoil';
const StyledShowPageActivityContainer = styled.div`
margin-top: ${({ theme }) => theme.spacing(6)};
@@ -16,7 +18,11 @@ export const ShowPageActivityContainer = ({
'targetObjectNameSingular' | 'id'
>;
}) => {
- return (
+ const isNewViewableRecordLoading = useRecoilValue(
+ isNewViewableRecordLoadingState,
+ );
+
+ return !isNewViewableRecordLoading ? (
+ ) : (
+ <>>
);
};
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 c06129296187..dab0a2104e12 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
@@ -7,6 +7,7 @@ import { TimelineActivities } from '@/activities/timelineActivities/components/T
import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { useDeleteOneRecord } from '@/object-record/hooks/useDeleteOneRecord';
+import { isNewViewableRecordLoadingState } from '@/object-record/record-right-drawer/states/isNewViewableRecordLoading';
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
import { Button } from '@/ui/input/button/components/Button';
@@ -135,6 +136,10 @@ export const ShowPageRightContainer = ({
const isMobile = useIsMobile();
+ const isNewViewableRecordLoading = useRecoilValue(
+ isNewViewableRecordLoadingState,
+ );
+
const tabs = [
{
id: 'richText',
@@ -272,7 +277,7 @@ export const ShowPageRightContainer = ({
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 9627be5d7e61..dca1b2cea957 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,3 +1,4 @@
+import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { ChangeEvent, ReactNode, useRef } from 'react';
@@ -88,9 +89,9 @@ const StyledShowPageSummaryCardSkeletonLoader = () => {
highlightColor={theme.background.transparent.lighter}
borderRadius={4}
>
-
+
-
+
);
diff --git a/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageSummaryCardSkeletonLoader.tsx b/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageSummaryCardSkeletonLoader.tsx
new file mode 100644
index 000000000000..51b15f506c67
--- /dev/null
+++ b/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageSummaryCardSkeletonLoader.tsx
@@ -0,0 +1,36 @@
+import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader';
+import { useTheme } from '@emotion/react';
+import styled from '@emotion/styled';
+import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
+
+const StyledContainer = styled.div`
+ display: flex;
+ gap: ${({ theme }) => theme.spacing(4)};
+ height: ${({ theme }) => theme.spacing(19)};
+ margin: ${({ theme }) => theme.spacing(4)};
+`;
+
+const StyledRectangularSkeleton = styled(Skeleton)`
+ height: ${({ theme }) => theme.spacing(4)};
+ width: ${({ theme }) => theme.spacing(24)};
+ margin: ${({ theme }) => theme.spacing(1)};
+ border-radius: ${({ theme }) => theme.border.radius.sm};
+`;
+
+export const ShowPageSummaryCardSkeletonLoader = () => {
+ const theme = useTheme();
+ return (
+
+
+
+
+
+
+ );
+};
diff --git a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerSectionTitleSkeletonLoader.tsx b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerSectionTitleSkeletonLoader.tsx
index fcd3ffe20eaa..5391ea3e320d 100644
--- a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerSectionTitleSkeletonLoader.tsx
+++ b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerSectionTitleSkeletonLoader.tsx
@@ -1,6 +1,7 @@
-import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
+import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
+import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
const StyledSkeletonTitle = styled.div`
margin-bottom: ${(props) => props.theme.spacing(2)};
@@ -16,7 +17,10 @@ export const NavigationDrawerSectionTitleSkeletonLoader = () => {
borderRadius={4}
>
-
+
);
diff --git a/packages/twenty-front/src/modules/views/components/ViewBarSkeletonLoader.tsx b/packages/twenty-front/src/modules/views/components/ViewBarSkeletonLoader.tsx
index a7d0c1b247c1..a82565afa813 100644
--- a/packages/twenty-front/src/modules/views/components/ViewBarSkeletonLoader.tsx
+++ b/packages/twenty-front/src/modules/views/components/ViewBarSkeletonLoader.tsx
@@ -1,5 +1,6 @@
-import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
+import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader';
import { useTheme } from '@emotion/react';
+import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
export const ViewBarSkeletonLoader = () => {
const theme = useTheme();
@@ -9,7 +10,7 @@ export const ViewBarSkeletonLoader = () => {
highlightColor={theme.background.transparent.lighter}
borderRadius={4}
>
-
+
);
};
diff --git a/packages/twenty-front/src/modules/views/utils/mapViewFieldsToColumnDefinitions.ts b/packages/twenty-front/src/modules/views/utils/mapViewFieldsToColumnDefinitions.ts
index 139ac042751f..cbf5f19b35ae 100644
--- a/packages/twenty-front/src/modules/views/utils/mapViewFieldsToColumnDefinitions.ts
+++ b/packages/twenty-front/src/modules/views/utils/mapViewFieldsToColumnDefinitions.ts
@@ -50,6 +50,7 @@ export const mapViewFieldsToColumnDefinitions = ({
isSortable: correspondingColumnDefinition.isSortable,
isFilterable: correspondingColumnDefinition.isFilterable,
defaultValue: correspondingColumnDefinition.defaultValue,
+ settings: correspondingColumnDefinition.settings,
} as ColumnDefinition;
})
.filter(isDefined);
diff --git a/packages/twenty-front/src/pages/auth/PasswordReset.tsx b/packages/twenty-front/src/pages/auth/PasswordReset.tsx
index 79ea7074021d..11cf5d016b42 100644
--- a/packages/twenty-front/src/pages/auth/PasswordReset.tsx
+++ b/packages/twenty-front/src/pages/auth/PasswordReset.tsx
@@ -10,6 +10,7 @@ import { useNavigate, useParams } from 'react-router-dom';
import { useSetRecoilState } from 'recoil';
import { z } from 'zod';
+import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader';
import { Logo } from '@/auth/components/Logo';
import { Title } from '@/auth/components/Title';
import { useAuth } from '@/auth/hooks/useAuth';
@@ -174,7 +175,7 @@ export const PasswordReset = () => {
highlightColor={theme.background.secondary}
>
= {
},
});
}),
- graphql.query('FindManyViews', () => {
- return HttpResponse.json({
- data: {
- views: viewQueryResultMock,
- },
- });
- }),
graphqlMocks.handlers,
],
},
diff --git a/packages/twenty-front/src/pages/settings/__stories__/SettingsAppearance.stories.tsx b/packages/twenty-front/src/pages/settings/__stories__/SettingsAppearance.stories.tsx
index 1aa66449abcc..2b7ab8f8e528 100644
--- a/packages/twenty-front/src/pages/settings/__stories__/SettingsAppearance.stories.tsx
+++ b/packages/twenty-front/src/pages/settings/__stories__/SettingsAppearance.stories.tsx
@@ -38,6 +38,24 @@ export const Default: Story = {
},
};
+export const DateTimeSettingsTimeFormat: Story = {
+ play: async () => {
+ const canvas = within(document.body);
+
+ await canvas.findByText('Date and time');
+
+ const timeFormatSelect = await canvas.findByText('24h (08:33)');
+
+ userEvent.click(timeFormatSelect);
+
+ const timeFormatOptions = await canvas.findByText('12h (8:33 AM)');
+
+ userEvent.click(timeFormatOptions);
+
+ await canvas.findByText('12h (8:33 AM)');
+ },
+};
+
export const DateTimeSettingsTimezone: Story = {
play: async () => {
const canvas = within(document.body);
@@ -77,21 +95,3 @@ export const DateTimeSettingsDateFormat: Story = {
await canvas.findByText('Jun 13, 2022');
},
};
-
-export const DateTimeSettingsTimeFormat: Story = {
- play: async () => {
- const canvas = within(document.body);
-
- await canvas.findByText('Date and time');
-
- const timeFormatSelect = await canvas.findByText('24h (08:33)');
-
- userEvent.click(timeFormatSelect);
-
- const timeFormatOptions = await canvas.findByText('12h (8:33 AM)');
-
- userEvent.click(timeFormatOptions);
-
- await canvas.findByText('12h (8:33 AM)');
- },
-};
diff --git a/packages/twenty-front/src/pages/settings/integrations/__stories__/SettingsIntegrationDatabase.stories.tsx b/packages/twenty-front/src/pages/settings/integrations/__stories__/SettingsIntegrationDatabase.stories.tsx
index e828bfa766e8..fc7cecd82dee 100644
--- a/packages/twenty-front/src/pages/settings/integrations/__stories__/SettingsIntegrationDatabase.stories.tsx
+++ b/packages/twenty-front/src/pages/settings/integrations/__stories__/SettingsIntegrationDatabase.stories.tsx
@@ -1,3 +1,4 @@
+import { expect } from '@storybook/jest';
import { Meta, StoryObj } from '@storybook/react';
import { within } from '@storybook/test';
@@ -33,6 +34,6 @@ export const Default: Story = {
const canvas = within(canvasElement);
sleep(1000);
- await canvas.findByText('PostgreSQL database');
+ expect(await canvas.findByText('PostgreSQL database')).toBeInTheDocument();
},
};
diff --git a/packages/twenty-front/src/pages/settings/serverless-functions/SettingsServerlessFunctions.tsx b/packages/twenty-front/src/pages/settings/serverless-functions/SettingsServerlessFunctions.tsx
index 00dcabb77bdc..5f9e58ce7e2a 100644
--- a/packages/twenty-front/src/pages/settings/serverless-functions/SettingsServerlessFunctions.tsx
+++ b/packages/twenty-front/src/pages/settings/serverless-functions/SettingsServerlessFunctions.tsx
@@ -1,4 +1,3 @@
-import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
import { SettingsServerlessFunctionsTable } from '@/settings/serverless-functions/components/SettingsServerlessFunctionsTable';
import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath';
import { SettingsPath } from '@/types/SettingsPath';
@@ -35,11 +34,9 @@ export const SettingsServerlessFunctions = () => {
},
]}
>
-
-
-
+
);
};
diff --git a/packages/twenty-front/src/testing/decorators/ChipGeneratorsDecorator.tsx b/packages/twenty-front/src/testing/decorators/ChipGeneratorsDecorator.tsx
index 283e7046e0ab..c107d5466387 100644
--- a/packages/twenty-front/src/testing/decorators/ChipGeneratorsDecorator.tsx
+++ b/packages/twenty-front/src/testing/decorators/ChipGeneratorsDecorator.tsx
@@ -3,7 +3,7 @@ import { useMemo } from 'react';
import { PreComputedChipGeneratorsContext } from '@/object-metadata/context/PreComputedChipGeneratorsContext';
import { getRecordChipGenerators } from '@/object-record/utils/getRecordChipGenerators';
-import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
+import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
export const ChipGeneratorsDecorator: Decorator = (Story) => {
const { chipGeneratorPerObjectPerField, identifierChipGeneratorPerObject } =
diff --git a/packages/twenty-front/src/testing/decorators/PageDecorator.tsx b/packages/twenty-front/src/testing/decorators/PageDecorator.tsx
index 7125e4326dc6..244772c809e6 100644
--- a/packages/twenty-front/src/testing/decorators/PageDecorator.tsx
+++ b/packages/twenty-front/src/testing/decorators/PageDecorator.tsx
@@ -12,7 +12,7 @@ import {
import { RecoilRoot } from 'recoil';
import { ClientConfigProviderEffect } from '@/client-config/components/ClientConfigProviderEffect';
-import { ApolloMetadataClientMockedProvider } from '@/object-metadata/hooks/__mocks__/ApolloMetadataClientProvider';
+import { ApolloMetadataClientMockedProvider } from '@/object-metadata/hooks/__mocks__/ApolloMetadataClientMockedProvider';
import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarProviderScope';
import { UserProviderEffect } from '@/users/components/UserProviderEffect';
import { ClientConfigProvider } from '~/modules/client-config/components/ClientConfigProvider';
@@ -21,6 +21,7 @@ import { UserProvider } from '~/modules/users/components/UserProvider';
import { mockedApolloClient } from '~/testing/mockedApolloClient';
import { RecoilDebugObserverEffect } from '@/debug/components/RecoilDebugObserver';
+import { ObjectMetadataItemsProvider } from '@/object-metadata/components/ObjectMetadataItemsProvider';
import { PrefetchDataProvider } from '@/prefetch/components/PrefetchDataProvider';
import { IconsProvider } from 'twenty-ui';
import { FullHeightStorybookLayout } from '../FullHeightStorybookLayout';
@@ -64,29 +65,33 @@ const ApolloStorybookDevLogEffect = () => {
const Providers = () => {
return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
);
};
diff --git a/packages/twenty-front/src/testing/decorators/RootDecorator.tsx b/packages/twenty-front/src/testing/decorators/RootDecorator.tsx
index 9c2633037b5b..5808791d1ae2 100644
--- a/packages/twenty-front/src/testing/decorators/RootDecorator.tsx
+++ b/packages/twenty-front/src/testing/decorators/RootDecorator.tsx
@@ -2,7 +2,7 @@ import { ApolloProvider } from '@apollo/client';
import { Decorator } from '@storybook/react';
import { RecoilRoot } from 'recoil';
-import { ApolloMetadataClientMockedProvider } from '@/object-metadata/hooks/__mocks__/ApolloMetadataClientProvider';
+import { ApolloMetadataClientMockedProvider } from '@/object-metadata/hooks/__mocks__/ApolloMetadataClientMockedProvider';
import { InitializeHotkeyStorybookHookEffect } from '../InitializeHotkeyStorybookHook';
import { mockedApolloClient } from '../mockedApolloClient';
diff --git a/packages/twenty-front/src/testing/decorators/getFieldDecorator.tsx b/packages/twenty-front/src/testing/decorators/getFieldDecorator.tsx
index 62cee6f5077b..e61885ed9a0d 100644
--- a/packages/twenty-front/src/testing/decorators/getFieldDecorator.tsx
+++ b/packages/twenty-front/src/testing/decorators/getFieldDecorator.tsx
@@ -12,7 +12,7 @@ import {
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
import { getCompaniesMock } from '~/testing/mock-data/companies';
-import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
+import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
import { getPeopleMock } from '~/testing/mock-data/people';
import { mockedTasks } from '~/testing/mock-data/tasks';
import { isDefined } from '~/utils/isDefined';
@@ -56,7 +56,7 @@ const RecordMockSetterEffect = ({
export const getFieldDecorator =
(
- objectNameSingular: 'company' | 'person' | 'task',
+ objectNameSingular: 'company' | 'person' | 'task' | 'workflowVersions',
fieldName: string,
fieldValue?: any,
): Decorator =>
diff --git a/packages/twenty-front/src/testing/graphqlMocks.ts b/packages/twenty-front/src/testing/graphqlMocks.ts
index c5d319b460b7..a69d6c17c660 100644
--- a/packages/twenty-front/src/testing/graphqlMocks.ts
+++ b/packages/twenty-front/src/testing/graphqlMocks.ts
@@ -11,7 +11,6 @@ import {
getCompanyDuplicateMock,
} from '~/testing/mock-data/companies';
import { mockedClientConfig } from '~/testing/mock-data/config';
-import { mockedObjectMetadataItemsQueryResult } from '~/testing/mock-data/metadata';
import { mockedNotes } from '~/testing/mock-data/notes';
import { getPeopleMock } from '~/testing/mock-data/people';
import { mockedRemoteTables } from '~/testing/mock-data/remote-tables';
@@ -19,6 +18,7 @@ import { mockedUserData } from '~/testing/mock-data/users';
import { mockedViewsData } from '~/testing/mock-data/views';
import { mockWorkspaceMembers } from '~/testing/mock-data/workspace-members';
+import { mockedStandardObjectMetadataQueryResult } from '~/testing/mock-data/generated/mock-metadata-query-result';
import { mockedTasks } from '~/testing/mock-data/tasks';
import { mockedRemoteServers } from './mock-data/remote-servers';
import { mockedViewFieldsData } from './mock-data/view-fields';
@@ -58,7 +58,7 @@ export const graphqlMocks = {
getOperationName(FIND_MANY_OBJECT_METADATA_ITEMS) ?? '',
() => {
return HttpResponse.json({
- data: mockedObjectMetadataItemsQueryResult,
+ data: mockedStandardObjectMetadataQueryResult,
});
},
),
@@ -297,7 +297,7 @@ export const graphqlMocks = {
graphql.query('FindManyTasks', () => {
return HttpResponse.json({
data: {
- activities: {
+ tasks: {
edges: mockedTasks.map(({ taskTargets, ...rest }) => ({
node: {
...rest,
@@ -320,6 +320,26 @@ export const graphqlMocks = {
},
});
}),
+ graphql.query('FindManyTaskTargets', () => {
+ return HttpResponse.json({
+ data: {
+ taskTargets: {
+ edges: mockedTasks.flatMap((task) =>
+ task.taskTargets.map((target) => ({
+ node: target,
+ cursor: null,
+ })),
+ ),
+ pageInfo: {
+ hasNextPage: false,
+ hasPreviousPage: false,
+ startCursor: null,
+ endCursor: null,
+ },
+ },
+ },
+ });
+ }),
graphql.query('FindManyFavorites', () => {
return HttpResponse.json({
data: {
diff --git a/packages/twenty-front/src/testing/jest/JestObjectMetadataItemSetter.tsx b/packages/twenty-front/src/testing/jest/JestObjectMetadataItemSetter.tsx
index abd11cab1832..98e83cb833a5 100644
--- a/packages/twenty-front/src/testing/jest/JestObjectMetadataItemSetter.tsx
+++ b/packages/twenty-front/src/testing/jest/JestObjectMetadataItemSetter.tsx
@@ -2,7 +2,7 @@ import { ReactNode, useEffect, useState } from 'react';
import { useSetRecoilState } from 'recoil';
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
-import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
+import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
export const JestObjectMetadataItemSetter = ({
children,
diff --git a/packages/twenty-front/src/testing/jest/generateEmptyJestRecordNode.ts b/packages/twenty-front/src/testing/jest/generateEmptyJestRecordNode.ts
new file mode 100644
index 000000000000..f27e4f3a3cd8
--- /dev/null
+++ b/packages/twenty-front/src/testing/jest/generateEmptyJestRecordNode.ts
@@ -0,0 +1,37 @@
+import { getRecordNodeFromRecord } from '@/object-record/cache/utils/getRecordNodeFromRecord';
+import { generateDepthOneRecordGqlFields } from '@/object-record/graphql/utils/generateDepthOneRecordGqlFields';
+import { prefillRecord } from '@/object-record/utils/prefillRecord';
+import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
+
+export const generateEmptyJestRecordNode = ({
+ objectNameSingular,
+ input,
+ withDepthOneRelation = false,
+}: {
+ objectNameSingular: string;
+ input: Record;
+ withDepthOneRelation?: boolean;
+}) => {
+ const objectMetadataItem = generatedMockObjectMetadataItems.find(
+ (item) => item.nameSingular === objectNameSingular,
+ );
+
+ if (!objectMetadataItem) {
+ throw new Error(
+ `ObjectMetadataItem not found for objectNameSingular: ${objectNameSingular} while generating empty Jest record node`,
+ );
+ }
+
+ const prefilledRecord = prefillRecord({ objectMetadataItem, input });
+
+ return getRecordNodeFromRecord({
+ record: prefilledRecord,
+ objectMetadataItem,
+ objectMetadataItems: generatedMockObjectMetadataItems,
+ recordGqlFields: withDepthOneRelation
+ ? generateDepthOneRecordGqlFields({
+ objectMetadataItem,
+ })
+ : undefined,
+ });
+};
diff --git a/packages/twenty-front/src/testing/jest/getJestHookWrapper.tsx b/packages/twenty-front/src/testing/jest/getJestMetadataAndApolloMocksWrapper.tsx
similarity index 94%
rename from packages/twenty-front/src/testing/jest/getJestHookWrapper.tsx
rename to packages/twenty-front/src/testing/jest/getJestMetadataAndApolloMocksWrapper.tsx
index 3c8f21553323..ea0e6528f0bc 100644
--- a/packages/twenty-front/src/testing/jest/getJestHookWrapper.tsx
+++ b/packages/twenty-front/src/testing/jest/getJestMetadataAndApolloMocksWrapper.tsx
@@ -5,7 +5,7 @@ import { MutableSnapshot, RecoilRoot } from 'recoil';
import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarProviderScope';
import { JestObjectMetadataItemSetter } from '~/testing/jest/JestObjectMetadataItemSetter';
-export const getJestHookWrapper = ({
+export const getJestMetadataAndApolloMocksWrapper = ({
apolloMocks,
onInitializeRecoilSnapshot,
}: {
diff --git a/packages/twenty-front/src/testing/mock-data/generated/mock-metadata-query-result.ts b/packages/twenty-front/src/testing/mock-data/generated/mock-metadata-query-result.ts
index c30b74ec2344..6832293415c8 100644
--- a/packages/twenty-front/src/testing/mock-data/generated/mock-metadata-query-result.ts
+++ b/packages/twenty-front/src/testing/mock-data/generated/mock-metadata-query-result.ts
@@ -51,6 +51,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'ed0dfa31-8e2f-4b23-87e4-8fa55eb16729',
type: 'TEXT',
name: 'operation',
@@ -72,6 +73,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '814795ef-6f2d-4798-a6f9-4e1c87c68d43',
type: 'DATE_TIME',
name: 'deletedAt',
@@ -93,6 +95,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '1c802ccf-c0ae-4b04-8c1e-f77417e6c3f8',
type: 'DATE_TIME',
name: 'updatedAt',
@@ -114,6 +117,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '6f210155-9cdc-48c6-9803-e20f63512024',
type: 'DATE_TIME',
name: 'createdAt',
@@ -135,6 +139,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '5fa54f64-3363-4a21-89ca-30d4816d8c77',
type: 'UUID',
name: 'id',
@@ -156,6 +161,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'a8876650-a7b6-4a9f-95b4-9ec1d6c232cc',
type: 'TEXT',
name: 'targetUrl',
@@ -177,6 +183,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'afae3f60-bfeb-4faf-a899-b0eb0fefac51',
type: 'TEXT',
name: 'description',
@@ -233,6 +240,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'ad82920a-857a-4357-8e4a-ed70961ba5d8',
type: 'DATE_TIME',
name: 'updatedAt',
@@ -254,6 +262,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '89662f00-b57c-49f6-aa48-d1c84f5fd7c7',
type: 'UUID',
name: 'personId',
@@ -275,6 +284,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '19270b1d-73b4-4aa9-8106-c1c81351ec53',
type: 'UUID',
name: 'rocketId',
@@ -296,6 +306,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '0c796ac5-0592-455f-9a0a-66ad53c6e4cf',
type: 'UUID',
name: 'companyId',
@@ -317,6 +328,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'dadac630-f64e-4d3d-9923-78ca579373f3',
type: 'RELATION',
name: 'rocket',
@@ -364,6 +376,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '0fcdebbb-a332-45ec-ab46-c30d5d7f9ef0',
type: 'DATE_TIME',
name: 'createdAt',
@@ -385,6 +398,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '37882bc2-c8d8-4cc5-bc13-4b820cc05b83',
type: 'UUID',
name: 'taskId',
@@ -406,6 +420,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'da63ddb4-7c19-49f0-bf90-ac2cc9486ae7',
type: 'DATE_TIME',
name: 'deletedAt',
@@ -427,6 +442,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '26cc6ba3-cff7-4b84-bf78-71823187a824',
type: 'RELATION',
name: 'person',
@@ -474,6 +490,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'e4414119-6f9c-465a-9ee2-95d1fc5eec01',
type: 'UUID',
name: 'opportunityId',
@@ -495,6 +512,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '598688a1-9766-439d-abd3-c0a47c8f36a3',
type: 'RELATION',
name: 'opportunity',
@@ -542,6 +560,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'cd7f57e8-a67f-4be9-a971-b5609cb0fb83',
type: 'RELATION',
name: 'company',
@@ -589,6 +608,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '400c9e53-283b-42d8-a69f-5010fb75d977',
type: 'UUID',
name: 'id',
@@ -610,6 +630,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'ec532542-a4dc-4722-99c3-fca6366db597',
type: 'RELATION',
name: 'task',
@@ -692,6 +713,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '26c57af1-5c70-4a9d-974f-e54c6a77a2b4',
type: 'RELATION',
name: 'rocket',
@@ -739,6 +761,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '434d1fd2-e6e0-4de7-9b15-706398e34d2d',
type: 'DATE_TIME',
name: 'deletedAt',
@@ -760,6 +783,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '06fcb5e2-b2f7-4118-a9f0-34558429b72c',
type: 'DATE_TIME',
name: 'updatedAt',
@@ -781,6 +805,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '4b6aaf36-4247-4bbb-b26d-64987b02f805',
type: 'RELATION',
name: 'company',
@@ -828,6 +853,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'c9bbd140-d9ab-4557-bd77-b446cd80774b',
type: 'UUID',
name: 'personId',
@@ -849,6 +875,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'b86fd021-b648-4a1e-b02e-080f0b280303',
type: 'UUID',
name: 'rocketId',
@@ -870,6 +897,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'cd3a9c3d-a29e-4b27-9fdb-0e8959f21f10',
type: 'UUID',
name: 'opportunityId',
@@ -891,6 +919,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'e6a5a8b1-ebef-4e01-ba22-a5f86d894eb5',
type: 'UUID',
name: 'id',
@@ -912,6 +941,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '9d568132-6cbc-4e87-95e8-7c2509549391',
type: 'RELATION',
name: 'note',
@@ -959,6 +989,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '6f80afcd-8ed7-4bf9-a987-9de3d1cddc81',
type: 'RELATION',
name: 'opportunity',
@@ -1006,6 +1037,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'dc63ee78-06ac-4312-b223-1d41a7ea2af4',
type: 'UUID',
name: 'noteId',
@@ -1027,6 +1059,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '646f3b4b-0fad-495a-a90d-136593464c7f',
type: 'UUID',
name: 'companyId',
@@ -1048,6 +1081,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '2b9481a9-c605-45d0-8aad-801a19c4b92c',
type: 'DATE_TIME',
name: 'createdAt',
@@ -1069,6 +1103,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '77508442-f0de-4809-b690-3c998edfc0b5',
type: 'RELATION',
name: 'person',
@@ -1151,6 +1186,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '27e79204-ba19-4791-8110-ec2bdc523e07',
type: 'TEXT',
name: 'messageThreadExternalId',
@@ -1172,6 +1208,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '1d9f0c85-c16f-41e9-9241-2acd90781cdd',
type: 'RELATION',
name: 'message',
@@ -1219,6 +1256,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '72a85b74-9803-4279-9f74-dafb833847fb',
type: 'DATE_TIME',
name: 'createdAt',
@@ -1240,6 +1278,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '6cb121b9-32d1-44fe-af26-324d73ffe0ac',
type: 'DATE_TIME',
name: 'deletedAt',
@@ -1261,6 +1300,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '9491ddd2-aea5-47fe-bd93-09fb6969b20c',
type: 'TEXT',
name: 'messageExternalId',
@@ -1282,6 +1322,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'f3eafb28-947a-4c7a-9464-24fa5549fb03',
type: 'UUID',
name: 'id',
@@ -1303,6 +1344,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'dbfff493-11a0-4866-9ef6-e4e8418a661a',
type: 'UUID',
name: 'messageChannelId',
@@ -1324,6 +1366,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '95488a9d-6473-47e8-aa62-a04d49238a2f',
type: 'UUID',
name: 'messageId',
@@ -1345,6 +1388,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'f4582d66-df12-4499-8ede-ab347427241b',
type: 'RELATION',
name: 'messageChannel',
@@ -1392,6 +1436,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '7bf79a5a-f5b7-495e-a336-4ddf85a5b2f7',
type: 'SELECT',
name: 'direction',
@@ -1428,6 +1473,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'a18edc4a-1b58-4a78-8de4-9564479b09cc',
type: 'DATE_TIME',
name: 'updatedAt',
@@ -1484,6 +1530,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'ea62fcb2-2161-47db-9151-19011419ac66',
type: 'DATE_TIME',
name: 'createdAt',
@@ -1505,6 +1552,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'e2f2b624-93bf-4d16-8517-bf66e43cabc4',
type: 'RELATION',
name: 'message',
@@ -1552,6 +1600,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'b92e3ff7-e5e0-4fec-b36e-cb496e2b57ae',
type: 'UUID',
name: 'id',
@@ -1573,6 +1622,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'ef5a67e6-88dd-4c92-a9be-7ab0605804e7',
type: 'DATE_TIME',
name: 'deletedAt',
@@ -1594,6 +1644,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'f3db188f-7329-40bc-9978-e30e5c07d962',
type: 'RELATION',
name: 'person',
@@ -1641,6 +1692,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '26c81156-529d-4bec-b5fb-f92e991907b5',
type: 'UUID',
name: 'messageId',
@@ -1662,6 +1714,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'aa502069-91c1-4eeb-bc8e-b22240564fe1',
type: 'TEXT',
name: 'displayName',
@@ -1683,6 +1736,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'd205df4f-f9de-4f61-9a85-40f340a4de23',
type: 'RELATION',
name: 'workspaceMember',
@@ -1730,6 +1784,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '0cf35f0a-eb64-47ef-88a4-55b92ca57c64',
type: 'UUID',
name: 'personId',
@@ -1751,6 +1806,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'e8550477-6034-45f4-8370-5a1cd75f7a55',
type: 'UUID',
name: 'workspaceMemberId',
@@ -1772,6 +1828,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '8dcde658-c38a-4659-8546-89c60465d36e',
type: 'TEXT',
name: 'handle',
@@ -1793,6 +1850,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '56ff0ed7-7916-4610-834c-a7c0657fa9e7',
type: 'DATE_TIME',
name: 'updatedAt',
@@ -1814,6 +1872,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '7a8597e3-bbce-4ff5-9f6e-9bf3c7fd43fa',
type: 'SELECT',
name: 'role',
@@ -1899,6 +1958,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '9061081a-eed9-49b8-99ab-9a7b8ce7a355',
type: 'BOOLEAN',
name: 'isContactAutoCreationEnabled',
@@ -1920,6 +1980,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'df104a7c-39e5-491d-8bde-6e3f75a3156b',
type: 'DATE_TIME',
name: 'syncedAt',
@@ -1941,6 +2002,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '751ef307-be5e-4451-9434-e2bae8861873',
type: 'BOOLEAN',
name: 'excludeNonProfessionalEmails',
@@ -1962,6 +2024,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '9a8520ed-6577-46b0-a732-1a08aafb0160',
type: 'SELECT',
name: 'visibility',
@@ -2005,6 +2068,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '2f7f7ea2-c5d0-47bc-bb0e-e3afc6d82b91',
type: 'DATE_TIME',
name: 'updatedAt',
@@ -2026,6 +2090,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'dafc931d-0466-4c83-91b3-72be3fdee12f',
type: 'DATE_TIME',
name: 'createdAt',
@@ -2047,6 +2112,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '97ba10a8-da33-4d1f-a9c6-964f814f5fd7',
type: 'DATE_TIME',
name: 'deletedAt',
@@ -2068,6 +2134,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'a3c22a32-9c6c-4294-abc4-7b3f9b6d8816',
type: 'RELATION',
name: 'messageChannelMessageAssociations',
@@ -2115,6 +2182,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'c1686e5a-1af6-45d9-a9f8-d2ecaef71526',
type: 'RELATION',
name: 'connectedAccount',
@@ -2162,6 +2230,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '7eaa0427-04b4-4cf8-9676-4e28c88a0fa8',
type: 'DATE_TIME',
name: 'syncStageStartedAt',
@@ -2183,6 +2252,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '290318a3-e994-4dee-8dd1-6bebe92043af',
type: 'SELECT',
name: 'syncStatus',
@@ -2240,6 +2310,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '7238d6c1-c54c-4787-aa4f-79294220acdc',
type: 'BOOLEAN',
name: 'isSyncEnabled',
@@ -2261,6 +2332,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '9416f68a-84cb-4b1f-805b-e58fb009cc44',
type: 'TEXT',
name: 'syncCursor',
@@ -2282,6 +2354,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '09ec080b-c8fe-432f-aff1-c151861c3ec7',
type: 'SELECT',
name: 'contactAutoCreationPolicy',
@@ -2326,6 +2399,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'd30ddf0c-769a-4480-a9cf-fea5867f9eea',
type: 'BOOLEAN',
name: 'excludeGroupEmails',
@@ -2347,6 +2421,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '839a7a90-3b1a-4f76-8207-5a0779ca909d',
type: 'SELECT',
name: 'type',
@@ -2383,6 +2458,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'b0026844-d54e-4fe2-af36-ed7ac7be1833',
type: 'UUID',
name: 'connectedAccountId',
@@ -2404,6 +2480,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '7ca7d194-3cdc-4ff9-a90f-6bfaedba8280',
type: 'TEXT',
name: 'handle',
@@ -2425,6 +2502,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '5f87d969-7dae-4a25-8b11-9577aa11285e',
type: 'UUID',
name: 'id',
@@ -2446,6 +2524,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'aafcc52e-d761-4b6a-97a6-1bc097e2ccd2',
type: 'SELECT',
name: 'syncStage',
@@ -2510,6 +2589,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '33180dbd-4124-43eb-84c3-17e32b4848e4',
type: 'NUMBER',
name: 'throttleFailureCount',
@@ -2566,6 +2646,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '8ca32bd7-4999-4562-9e41-698a458944ea',
type: 'DATE_TIME',
name: 'deletedAt',
@@ -2587,6 +2668,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '236195db-49d1-4386-99b9-4518ab7586f2',
type: 'RELATION',
name: 'accountOwner',
@@ -2634,6 +2716,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '919dadd4-8dda-479f-a8a7-b4ed89eafae5',
type: 'RELATION',
name: 'calendarChannels',
@@ -2681,6 +2764,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '75c78041-39ca-4b46-bcff-6ed0af05248e',
type: 'TEXT',
name: 'handleAliases',
@@ -2702,6 +2786,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'd3f821eb-c8b1-48a5-aebb-1bfe23c4128e',
type: 'DATE_TIME',
name: 'updatedAt',
@@ -2723,6 +2808,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '6f74d250-76f0-4eff-8e27-d1a12782517d',
type: 'TEXT',
name: 'lastSyncHistoryId',
@@ -2744,6 +2830,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'fd6c04f4-8dba-47ac-a597-90300eb1a079',
type: 'UUID',
name: 'id',
@@ -2765,6 +2852,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '8f7d7528-83a8-442e-b0b6-958f52a1de5e',
type: 'DATE_TIME',
name: 'authFailedAt',
@@ -2786,6 +2874,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '762d59c0-f7e9-410f-b5dc-df66d764de0d',
type: 'TEXT',
name: 'handle',
@@ -2808,6 +2897,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'f45f5e44-f88a-490c-b112-df2465b612a3',
type: 'TEXT',
name: 'refreshToken',
@@ -2829,6 +2919,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '2aa282f3-5542-47e8-adf3-4384e9ce5d10',
type: 'UUID',
name: 'accountOwnerId',
@@ -2850,6 +2941,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '5f411e82-b626-4456-896c-d5a326e5e02a',
type: 'TEXT',
name: 'accessToken',
@@ -2871,6 +2963,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'c21734fd-6539-410f-bc1a-e91a3177b9c9',
type: 'DATE_TIME',
name: 'createdAt',
@@ -2892,6 +2985,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '5b0a8a38-9d02-4e06-8f07-2f76f0ab70eb',
type: 'TEXT',
name: 'provider',
@@ -2913,6 +3007,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '178f1e8a-cbbf-448e-95f3-d1262d9ff33d',
type: 'RELATION',
name: 'messageChannels',
@@ -2995,6 +3090,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '9e7b7d2f-02fb-426b-8e3e-392225f5b6b3',
type: 'RELATION',
name: 'taskTargets',
@@ -3042,6 +3138,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '78f1d502-397e-4cce-b096-a525b2d373e2',
type: 'RELATION',
name: 'noteTargets',
@@ -3089,6 +3186,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'c692555c-020e-46a4-b537-c9c4c7d3cd32',
type: 'ACTOR',
name: 'createdBy',
@@ -3113,6 +3211,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '6d32aa8b-28c0-4e35-b45e-9643fd8e1c33',
type: 'CURRENCY',
name: 'amount',
@@ -3137,6 +3236,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'c859b99c-2554-483d-8ffe-4d29cb9c8459',
type: 'RELATION',
name: 'company',
@@ -3184,6 +3284,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '7ad6853d-d1e9-46a8-a77a-38eeae27e1d6',
type: 'RELATION',
name: 'pointOfContact',
@@ -3231,6 +3332,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'f6c45230-619b-4432-82fd-e5bed0c4e8f4',
type: 'SELECT',
name: 'stage',
@@ -3288,6 +3390,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '5d3ca5b4-9468-4061-8c6b-ef03a9b123df',
type: 'RELATION',
name: 'favorites',
@@ -3335,6 +3438,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '3bc37e42-10f2-4501-94e4-760a7c3fa38e',
type: 'POSITION',
name: 'position',
@@ -3356,6 +3460,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '9019bf90-efbc-4499-a87b-0624bda5a559',
type: 'RELATION',
name: 'timelineActivities',
@@ -3404,6 +3509,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'c7472787-44e9-4641-9901-cc4909ca031d',
type: 'DATE_TIME',
name: 'closeDate',
@@ -3425,6 +3531,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '01e75534-627f-4a49-bc28-c08170a71085',
type: 'UUID',
name: 'id',
@@ -3446,6 +3553,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '6d5401c0-d456-42c4-85d4-9666900615ef',
type: 'TEXT',
name: 'name',
@@ -3467,6 +3575,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'aa651efa-1576-4edc-9599-070666a76dda',
type: 'RELATION',
name: 'attachments',
@@ -3514,6 +3623,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'b8eb99bd-3485-44bb-8483-f0c600af4e92',
type: 'UUID',
name: 'pointOfContactId',
@@ -3535,6 +3645,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '55fd22aa-80df-4c0b-b5ee-f19163d10a82',
type: 'UUID',
name: 'companyId',
@@ -3556,6 +3667,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'd487fe61-e181-4077-ba4e-9c7b466085ad',
type: 'DATE_TIME',
name: 'updatedAt',
@@ -3577,6 +3689,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'bf11e668-6598-42ee-8c81-563641403ba9',
type: 'DATE_TIME',
name: 'deletedAt',
@@ -3598,6 +3711,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '2e77023d-fdeb-454d-9368-ab638a68a0bb',
type: 'DATE_TIME',
name: 'createdAt',
@@ -3619,6 +3733,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'ac708d8f-abd4-436f-aec7-9a8c4ec2cd28',
type: 'RELATION',
name: 'activityTargets',
@@ -3701,6 +3816,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '4a2da98e-6880-47be-8673-165e1d77a910',
type: 'RELATION',
name: 'rocket',
@@ -3748,6 +3864,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '03aab98d-e16c-48fb-91e7-bffc2300402d',
type: 'UUID',
name: 'opportunityId',
@@ -3769,6 +3886,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'e1d06322-0658-4c45-9c9b-8a42750c8751',
type: 'RELATION',
name: 'company',
@@ -3816,6 +3934,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'ca812263-7b62-4e7f-8f31-bed3de2d4a94',
type: 'DATE_TIME',
name: 'updatedAt',
@@ -3837,6 +3956,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '984d38ae-335d-41fb-ac29-9029ff43c4c6',
type: 'UUID',
name: 'companyId',
@@ -3858,6 +3978,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'b2531e1e-39ad-46c8-af56-853fe1cc7dd6',
type: 'RELATION',
name: 'activity',
@@ -3905,6 +4026,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '26d681d7-4ef2-40eb-bd0c-7e0b7d6d6cb0',
type: 'UUID',
name: 'personId',
@@ -3926,6 +4048,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'dc9c8fec-55d2-40b6-9fcd-d441024be60f',
type: 'DATE_TIME',
name: 'createdAt',
@@ -3947,6 +4070,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '08806161-5d03-4777-8825-b5cff93de042',
type: 'UUID',
name: 'activityId',
@@ -3968,6 +4092,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '9ff04b9e-f87c-44df-82ed-518748ca0d81',
type: 'UUID',
name: 'rocketId',
@@ -3989,6 +4114,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '86438a20-0beb-4e73-93d9-cf91bfe9ac3f',
type: 'UUID',
name: 'id',
@@ -4010,6 +4136,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '2f2ed506-e96e-48d3-8225-45a9c0b55e76',
type: 'DATE_TIME',
name: 'deletedAt',
@@ -4031,6 +4158,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '867aff40-ddf5-4af8-a3f5-6359ab91eb2c',
type: 'RELATION',
name: 'person',
@@ -4078,6 +4206,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'c2708db4-5c1e-482b-bdd4-bd620612c15f',
type: 'RELATION',
name: 'opportunity',
@@ -4160,6 +4289,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'eb926345-9d3c-4815-a044-bf1085b31cdc',
type: 'UUID',
name: 'assigneeId',
@@ -4181,6 +4311,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '7314a7d0-f318-4aa0-b8f3-db1953139d3f',
type: 'TEXT',
name: 'title',
@@ -4202,6 +4333,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '3e63dfad-08ba-422f-88e5-0c1ebffd6496',
type: 'RELATION',
name: 'author',
@@ -4249,6 +4381,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '5ceb1884-c3ff-4a31-9629-3ef599b1a461',
type: 'DATE_TIME',
name: 'updatedAt',
@@ -4270,6 +4403,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'ffdb396b-200a-4dc5-a3aa-e2c23b180ac0',
type: 'TEXT',
name: 'body',
@@ -4291,6 +4425,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '0f1cfe74-f960-44f9-91f3-fc9d25a4b96b',
type: 'RELATION',
name: 'comments',
@@ -4338,6 +4473,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '248b356d-5a70-458d-a10b-92d70512497b',
type: 'DATE_TIME',
name: 'createdAt',
@@ -4359,6 +4495,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '2f1f7b1a-2c98-42ca-8f6c-784406d7bad8',
type: 'UUID',
name: 'authorId',
@@ -4380,6 +4517,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '799c1e27-3fa5-4411-bfa2-a1f494d2434a',
type: 'DATE_TIME',
name: 'reminderAt',
@@ -4401,6 +4539,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'dd5354bb-dd0a-4426-ac75-87e9ab171dc4',
type: 'RELATION',
name: 'assignee',
@@ -4448,6 +4587,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'd7b4584a-d0ed-49f8-b14c-198036b60fe8',
type: 'DATE_TIME',
name: 'dueAt',
@@ -4469,6 +4609,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '9b8808d3-be01-4595-9b20-ebb9553cd7db',
type: 'DATE_TIME',
name: 'completedAt',
@@ -4490,6 +4631,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'd0341ced-bdb0-4629-a816-d402df827bd7',
type: 'TEXT',
name: 'type',
@@ -4511,6 +4653,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '1dc0b9af-181a-4f2c-bd01-9c4bf355b9de',
type: 'RELATION',
name: 'activityTargets',
@@ -4558,6 +4701,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'b31fdd11-115b-4405-8265-c03329338f0c',
type: 'DATE_TIME',
name: 'deletedAt',
@@ -4579,6 +4723,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'bfa2ab3d-a55b-41ca-906b-9d497aee7ba8',
type: 'RELATION',
name: 'attachments',
@@ -4626,6 +4771,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '33b0ccb9-19fc-42d6-b7af-87bc4411692e',
type: 'UUID',
name: 'id',
@@ -4682,6 +4828,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'e166c79b-99c1-4fb4-9575-5cf7e7f4811f',
type: 'BOOLEAN',
name: 'isOrganizer',
@@ -4703,6 +4850,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '34f2ac5d-bb7e-446c-ab52-18e722345a24',
type: 'UUID',
name: 'workspaceMemberId',
@@ -4724,6 +4872,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '0c215138-fc5b-4be2-8c37-0acc7cb4e5a1',
type: 'SELECT',
name: 'responseStatus',
@@ -4774,6 +4923,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '16b867dd-9fb1-43ab-8254-2478004b30b3',
type: 'UUID',
name: 'id',
@@ -4795,6 +4945,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'fdfea59a-624c-4af3-9901-1f86d1972b23',
type: 'TEXT',
name: 'displayName',
@@ -4816,6 +4967,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '2f77bc8e-26dc-40b1-964a-f0748feb193a',
type: 'RELATION',
name: 'person',
@@ -4863,6 +5015,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '597d153f-8724-4d61-8863-8bfae905721f',
type: 'RELATION',
name: 'calendarEvent',
@@ -4910,6 +5063,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '83d94e19-f9f3-47bb-a277-6935af6ae69d',
type: 'UUID',
name: 'personId',
@@ -4931,6 +5085,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'cc27c5b5-44cc-4f19-a56e-8ce172e2ab37',
type: 'DATE_TIME',
name: 'updatedAt',
@@ -4952,6 +5107,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '22c34bd1-550b-4b5c-a2a4-fbb475a4420b',
type: 'DATE_TIME',
name: 'createdAt',
@@ -4973,6 +5129,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '7b7792da-246d-4015-855a-ea029f0b8a02',
type: 'DATE_TIME',
name: 'deletedAt',
@@ -4994,6 +5151,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '7794c913-c52f-4c06-921e-2b391b63e51e',
type: 'UUID',
name: 'calendarEventId',
@@ -5015,6 +5173,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '30fd4e8a-2089-4443-ac06-5cd53d9a3fcf',
type: 'RELATION',
name: 'workspaceMember',
@@ -5062,6 +5221,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'c97d9e28-d807-4fff-ba2c-c72f99087f89',
type: 'TEXT',
name: 'handle',
@@ -5118,6 +5278,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'e8a5a86c-b1ce-4db1-8d51-d5b01d2b361b',
type: 'DATE_TIME',
name: 'updatedAt',
@@ -5139,6 +5300,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '09a753b7-a5f9-4810-ae2f-389982f593c3',
type: 'DATE_TIME',
name: 'createdAt',
@@ -5160,6 +5322,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '7881aa82-a7ed-4090-923d-f1c0cf16a486',
type: 'DATE_TIME',
name: 'deletedAt',
@@ -5181,6 +5344,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '7f1d2847-9f16-457f-a57c-de36c401286a',
type: 'UUID',
name: 'recordId',
@@ -5202,6 +5366,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '1db6f800-bb46-45a2-a324-cfe52362ed9a',
type: 'UUID',
name: 'id',
@@ -5223,6 +5388,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '785dc6cb-77dc-4bdd-be44-60ad8f1f45da',
type: 'UUID',
name: 'workspaceMemberId',
@@ -5244,6 +5410,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '3d6dc314-877d-4aaa-88bd-364dc50f780b',
type: 'RELATION',
name: 'workspaceMember',
@@ -5291,6 +5458,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '80fe2b13-5cb0-48a0-9341-aec08481628f',
type: 'RAW_JSON',
name: 'context',
@@ -5313,6 +5481,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '0383ac8e-6138-4e06-a828-bfc391e53d01',
type: 'TEXT',
name: 'name',
@@ -5334,6 +5503,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'f4f0343a-8241-492a-8156-18d40c75f46a',
type: 'RAW_JSON',
name: 'properties',
@@ -5355,6 +5525,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'a8282a28-724f-487b-a9fa-f0d10c919237',
type: 'TEXT',
name: 'objectName',
@@ -5376,6 +5547,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'd85abbad-9616-456f-978c-4cced740490c',
type: 'TEXT',
name: 'objectMetadataId',
@@ -5432,6 +5604,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '818ec7cd-9181-4c72-ad99-c19b00fde065',
type: 'TEXT',
name: 'syncCursor',
@@ -5454,6 +5627,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '93658b38-cb56-4d2b-93f8-3a4c7714f7c4',
type: 'TEXT',
name: 'handle',
@@ -5475,6 +5649,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'af61423d-0891-4e91-b6d3-2f7ed6363916',
type: 'UUID',
name: 'connectedAccountId',
@@ -5496,6 +5671,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'e921674b-2e9f-4f19-a067-920685cf9164',
type: 'SELECT',
name: 'visibility',
@@ -5532,6 +5708,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '0abc3baf-2797-4f88-8565-a3ffa4468b55',
type: 'DATE_TIME',
name: 'deletedAt',
@@ -5553,6 +5730,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'e567e960-f3c8-4ef0-b810-d8a4bc6a4f7d',
type: 'BOOLEAN',
name: 'isSyncEnabled',
@@ -5574,6 +5752,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'bb3531fe-a008-4505-820b-0cb2c365b05d',
type: 'DATE_TIME',
name: 'createdAt',
@@ -5595,6 +5774,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'd9a353c7-25ba-403f-8157-0d8bee911cec',
type: 'UUID',
name: 'id',
@@ -5616,6 +5796,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'd1596020-b595-4bf9-b3c1-782f9b49f41b',
type: 'RELATION',
name: 'calendarChannelEventAssociations',
@@ -5663,6 +5844,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'd757fd20-3568-411f-a2ba-ec2f7b30dc55',
type: 'SELECT',
name: 'syncStatus',
@@ -5720,6 +5902,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '529b36bb-42d1-4361-ac0a-e683557cc879',
type: 'DATE_TIME',
name: 'updatedAt',
@@ -5741,6 +5924,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '8d7cb56f-29f1-40ad-90cf-4497bee669a1',
type: 'SELECT',
name: 'contactAutoCreationPolicy',
@@ -5792,6 +5976,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'c933e11e-7820-42e4-a589-389c2f314add',
type: 'RELATION',
name: 'connectedAccount',
@@ -5839,6 +6024,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '01e23a9d-d8b7-47c6-a1f8-7e012ae9f54a',
type: 'DATE_TIME',
name: 'syncStageStartedAt',
@@ -5860,6 +6046,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '9c5f7d31-5b5e-4af1-9918-859ce66b6c08',
type: 'SELECT',
name: 'syncStage',
@@ -5924,6 +6111,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '0c81da27-4ff4-4bf4-8937-9a8ee627e46c',
type: 'NUMBER',
name: 'throttleFailureCount',
@@ -5945,6 +6133,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '5c73b1cc-ddda-46a8-a517-f0bb5f0c5f60',
type: 'BOOLEAN',
name: 'isContactAutoCreationEnabled',
@@ -6001,6 +6190,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '0cc37cbd-c7ce-4898-b34d-5da7736e7b54',
type: 'DATE_TIME',
name: 'updatedAt',
@@ -6022,6 +6212,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '537e956c-58bb-4ed4-8127-beb0f2d04dd2',
type: 'RELATION',
name: 'messages',
@@ -6069,6 +6260,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '728f4580-9220-4130-9a25-c56669ad0e43',
type: 'DATE_TIME',
name: 'deletedAt',
@@ -6090,6 +6282,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'fe0508ef-6e8e-4422-b822-67899af4aa58',
type: 'DATE_TIME',
name: 'createdAt',
@@ -6111,6 +6304,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '823a20db-9431-422c-b0a1-4f559b992651',
type: 'UUID',
name: 'id',
@@ -6167,6 +6361,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '7011922c-2271-4960-81eb-b9f9ae3ae00c',
type: 'DATE_TIME',
name: 'updatedAt',
@@ -6188,6 +6383,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '37abc2ae-9f44-4bc0-8277-e3ddfd54738c',
type: 'RELATION',
name: 'people',
@@ -6235,6 +6431,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'c264b8c8-1260-410b-aa34-d69b14bba19b',
type: 'LINKS',
name: 'domainName',
@@ -6261,6 +6458,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '73c7c0bc-a328-488f-b357-fd9dc332ab75',
type: 'BOOLEAN',
name: 'visaSponsorship',
@@ -6282,6 +6480,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'b08a8600-2c4f-4e8a-8f32-6ffe7041e569',
type: 'ADDRESS',
name: 'address',
@@ -6312,6 +6511,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '107fd869-fa4a-4ca5-b6b1-a918ec78851e',
type: 'POSITION',
name: 'position',
@@ -6333,6 +6533,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '2f0ab2d8-3cdf-49d1-a8be-ef204e871968',
type: 'NUMBER',
name: 'employees',
@@ -6354,6 +6555,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '9677b321-e8fc-4d1b-9d7f-145a5dea0001',
type: 'RELATION',
name: 'favorites',
@@ -6401,6 +6603,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '8a21fcb9-5ee7-498c-a09d-1d3137be0540',
type: 'DATE_TIME',
name: 'deletedAt',
@@ -6422,6 +6625,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '300545a5-6ca7-487a-8374-a662bab5d717',
type: 'UUID',
name: 'accountOwnerId',
@@ -6444,6 +6648,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'e41f22fd-ecd5-4b28-a2ed-a04d2a017c19',
type: 'CURRENCY',
name: 'annualRecurringRevenue',
@@ -6469,6 +6674,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '24cc7f7b-e8d3-4c12-a3c5-caa5ccf61523',
type: 'UUID',
name: 'id',
@@ -6490,6 +6696,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '8421d3d3-d5ac-4065-a431-95780fda2ce7',
type: 'RELATION',
name: 'opportunities',
@@ -6537,6 +6744,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '2395970c-d0a2-43df-9f55-58299e930b34',
type: 'RELATION',
name: 'attachments',
@@ -6584,6 +6792,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '3b52848e-e419-4361-8fbc-3d4ed19f1956',
type: 'TEXT',
name: 'name',
@@ -6605,6 +6814,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '5f23c37a-9971-4060-a861-19f030848b90',
type: 'LINKS',
name: 'xLink',
@@ -6630,6 +6840,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'c5103301-686a-4c1f-86d1-69e32a4a34ae',
type: 'DATE_TIME',
name: 'createdAt',
@@ -6651,6 +6862,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '81907e01-90e3-412a-9aa5-9ae8352b679d',
type: 'ACTOR',
name: 'createdBy',
@@ -6675,6 +6887,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'f8393bb6-05c2-44d7-bff8-4a7671b43f15',
type: 'RELATION',
name: 'timelineActivities',
@@ -6722,6 +6935,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '4882e808-7cd2-487f-911f-ab2d9353e60d',
type: 'RELATION',
name: 'accountOwner',
@@ -6770,6 +6984,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'a8cf3568-4d04-43cf-b8c2-2070a7eb0e4e',
type: 'MULTI_SELECT',
name: 'workPolicy',
@@ -6813,6 +7028,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'd69eb854-c043-43d9-a40e-65a0649fd1a9',
type: 'RELATION',
name: 'taskTargets',
@@ -6860,6 +7076,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '531c4b2e-94a0-46f4-9395-277c3239413d',
type: 'RELATION',
name: 'noteTargets',
@@ -6907,6 +7124,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'de10d71e-4cfa-4322-b967-761871e69bc0',
type: 'LINKS',
name: 'introVideo',
@@ -6932,6 +7150,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'e2e632fe-1c08-4c12-9aba-88f8595bf5be',
type: 'RELATION',
name: 'activityTargets',
@@ -6979,6 +7198,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '16838104-8adf-45a3-93bf-e97551240b66',
type: 'LINKS',
name: 'linkedinLink',
@@ -7004,6 +7224,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '195db745-305e-40f0-b740-d071c5c19214',
type: 'TEXT',
name: 'tagline',
@@ -7025,6 +7246,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '2d8e886a-3ebf-474c-8c7a-909e9d7fcc6f',
type: 'BOOLEAN',
name: 'idealCustomerProfile',
@@ -7082,6 +7304,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'c496110c-239a-4dd4-bdbd-022ca4fdc62c',
type: 'RELATION',
name: 'calendarEvent',
@@ -7129,6 +7352,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '8505bc8b-e978-401a-8983-f1f1e64aa26d',
type: 'UUID',
name: 'id',
@@ -7150,6 +7374,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '18e21e78-56c2-492a-8082-f1e8ceb72e14',
type: 'UUID',
name: 'calendarChannelId',
@@ -7171,6 +7396,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'b61d8723-b739-42b6-b23d-b82e09b34669',
type: 'DATE_TIME',
name: 'deletedAt',
@@ -7192,6 +7418,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '97a0be23-ba2e-4af3-8503-d4c27c293a37',
type: 'DATE_TIME',
name: 'createdAt',
@@ -7213,6 +7440,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '906e35f2-e2d1-45d5-8326-cb7712a19e60',
type: 'RELATION',
name: 'calendarChannel',
@@ -7260,6 +7488,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'aa298945-e331-40de-a6db-855b58b99d05',
type: 'TEXT',
name: 'eventExternalId',
@@ -7281,6 +7510,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '0ec16ef5-2331-4a1e-b429-0e4fc3d9576f',
type: 'DATE_TIME',
name: 'updatedAt',
@@ -7302,6 +7532,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '2c765e90-ce86-4f6b-a528-94e38b5aaf54',
type: 'UUID',
name: 'calendarEventId',
@@ -7358,6 +7589,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '78eec6b7-ab9c-4dee-ac64-2b9e40b467f6',
type: 'TEXT',
name: 'name',
@@ -7379,6 +7611,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'd2653ce4-585b-4a38-9e09-4ae8e2afae51',
type: 'DATE_TIME',
name: 'expiresAt',
@@ -7400,6 +7633,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '9e5cd8cb-e800-4b25-a9e6-cfb6d51623c6',
type: 'DATE_TIME',
name: 'updatedAt',
@@ -7421,6 +7655,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '68704d45-b248-4e41-a07b-21d5874663bb',
type: 'DATE_TIME',
name: 'revokedAt',
@@ -7442,6 +7677,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '77ef9f04-627b-4708-b400-076629ed9f20',
type: 'DATE_TIME',
name: 'createdAt',
@@ -7463,6 +7699,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'dc4892f0-a890-4a49-90ae-5a7999665785',
type: 'UUID',
name: 'id',
@@ -7484,6 +7721,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'bbe022a1-426f-40c2-ad1d-8294ef127c0b',
type: 'DATE_TIME',
name: 'deletedAt',
@@ -7540,6 +7778,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '9d2499b3-403c-473f-b61f-61bbea97afeb',
type: 'UUID',
name: 'noteId',
@@ -7561,6 +7800,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '0d232853-5ae9-43f3-ac4a-248c50e2a64e',
type: 'UUID',
name: 'taskId',
@@ -7582,6 +7822,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '8e506212-1b66-4981-95d6-f0ac83f5d869',
type: 'RELATION',
name: 'person',
@@ -7629,6 +7870,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'dc005581-351b-4fa0-9b39-da5bbe2554b7',
type: 'RELATION',
name: 'task',
@@ -7676,6 +7918,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '86e97af0-ec16-4937-b5b6-e4531027be82',
type: 'UUID',
name: 'rocketId',
@@ -7697,6 +7940,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'c33a0768-3f55-4c7b-aa1a-07aeacf3fb85',
type: 'UUID',
name: 'viewId',
@@ -7718,6 +7962,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'afc385d4-22d1-4f83-a67a-46450df368e9',
type: 'DATE_TIME',
name: 'updatedAt',
@@ -7739,6 +7984,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '90a28b04-0214-424f-afad-172b7cd28073',
type: 'UUID',
name: 'workflowId',
@@ -7760,6 +8006,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '6a245087-243d-450b-9f00-c951d417d4ef',
type: 'UUID',
name: 'personId',
@@ -7781,6 +8028,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '14e0bf40-d4eb-4893-a5f2-3df3ce749996',
type: 'UUID',
name: 'workspaceMemberId',
@@ -7802,6 +8050,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '0ecb3679-5ff7-4b55-9ed3-9927bc9e184b',
type: 'RELATION',
name: 'note',
@@ -7849,6 +8098,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '3a561744-45bd-45a6-af94-bfb4d4f508fe',
type: 'DATE_TIME',
name: 'createdAt',
@@ -7870,6 +8120,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '46ff8942-360f-4837-9a83-007739c8ba05',
type: 'RELATION',
name: 'view',
@@ -7917,6 +8168,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '6e104959-9dfb-42a7-80da-0ddb0dab12f9',
type: 'UUID',
name: 'opportunityId',
@@ -7938,6 +8190,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'f112f2a8-4f21-454d-b3a7-fcd85f0eab72',
type: 'NUMBER',
name: 'position',
@@ -7959,6 +8212,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'e4102fb0-c6e3-47e8-a810-71e0b6453705',
type: 'DATE_TIME',
name: 'deletedAt',
@@ -7980,6 +8234,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'a1555234-ff28-4a04-871c-31008b39e442',
type: 'UUID',
name: 'id',
@@ -8001,6 +8256,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '10509b5e-71c0-49e8-9cb8-d0ff7ee8691b',
type: 'UUID',
name: 'companyId',
@@ -8022,6 +8278,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'eed525bd-edf3-4030-9f09-8ff68226a6a0',
type: 'RELATION',
name: 'workflow',
@@ -8069,6 +8326,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '5b559e4c-eb75-4a1e-b904-a486d2328b24',
type: 'RELATION',
name: 'workspaceMember',
@@ -8116,6 +8374,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '7155582f-4bbc-4643-be0c-38165b8a282f',
type: 'RELATION',
name: 'company',
@@ -8163,6 +8422,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '11e6c0a0-e1fa-4931-a705-8725a79afe24',
type: 'RELATION',
name: 'rocket',
@@ -8210,6 +8470,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '1d3858e1-e4aa-484f-b422-8bbefa9409c8',
type: 'RELATION',
name: 'opportunity',
@@ -8292,6 +8553,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '974ab999-a946-409f-820c-aa2e2c21f3ce',
type: 'DATE_TIME',
name: 'updatedAt',
@@ -8313,6 +8575,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '70a9b04f-0d11-41a1-bce8-e7ac8bb0ed5d',
type: 'DATE_TIME',
name: 'createdAt',
@@ -8334,6 +8597,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'da1dda8a-b7b6-4166-b11b-740a8414706b',
type: 'UUID',
name: 'authorId',
@@ -8355,6 +8619,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '3b07941b-15b6-4468-8e2f-52abf7ff36b3',
type: 'TEXT',
name: 'body',
@@ -8376,6 +8641,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '8f985123-68d4-4e8a-b75b-85a75f0f071e',
type: 'UUID',
name: 'id',
@@ -8397,6 +8663,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'e48bc6a2-211c-46aa-9f22-1859aedac28e',
type: 'RELATION',
name: 'activity',
@@ -8444,6 +8711,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'c39eb95c-2e9f-4fd3-abc3-103986dd21bb',
type: 'UUID',
name: 'activityId',
@@ -8465,6 +8733,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '571e3b8c-0c80-4292-93b1-c73b4d976b05',
type: 'DATE_TIME',
name: 'deletedAt',
@@ -8486,6 +8755,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'b1ead0df-5b1c-4c00-b0c5-05a67ec37327',
type: 'RELATION',
name: 'author',
@@ -8568,6 +8838,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '0c1f5af5-c2d5-4f38-9fd4-6ce854e693d3',
type: 'DATE_TIME',
name: 'updatedAt',
@@ -8589,6 +8860,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'f06f5946-e54f-458d-9c77-47d6d8fbd995',
type: 'DATE_TIME',
name: 'endsAt',
@@ -8610,6 +8882,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'bc8be6a6-4707-498a-9e79-8ffb86e92a43',
type: 'RELATION',
name: 'calendarEventParticipants',
@@ -8657,6 +8930,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '6bfac067-9c6c-4b4d-bdaf-ecf7737b2599',
type: 'TEXT',
name: 'iCalUID',
@@ -8678,6 +8952,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '45bd7c28-f450-4487-a556-1fd85be68beb',
type: 'TEXT',
name: 'title',
@@ -8699,6 +8974,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '52d1ed74-b3d5-4339-b408-6f4c8dbc3969',
type: 'DATE_TIME',
name: 'createdAt',
@@ -8720,6 +8996,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '4078641f-c8b4-418c-9e7a-0bfdc411c4d9',
type: 'DATE_TIME',
name: 'externalUpdatedAt',
@@ -8741,6 +9018,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'ae4f8ff1-47f1-4b84-b61b-c519c939a409',
type: 'TEXT',
name: 'conferenceSolution',
@@ -8762,6 +9040,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'a77794e2-adea-40cb-a0f9-a91a6d4494ed',
type: 'DATE_TIME',
name: 'startsAt',
@@ -8783,6 +9062,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '62d6a06b-0083-4702-be85-edd6ca882816',
type: 'TEXT',
name: 'location',
@@ -8804,6 +9084,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '567c7852-6dc5-4c6e-826d-e4b253614e60',
type: 'TEXT',
name: 'recurringEventExternalId',
@@ -8825,6 +9106,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'c0ed400f-b0cf-4fe1-a929-89698dc020a5',
type: 'DATE_TIME',
name: 'externalCreatedAt',
@@ -8846,6 +9128,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'da0d1cc9-be28-4b41-9ddf-48041702024b',
type: 'TEXT',
name: 'description',
@@ -8867,6 +9150,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '52db308a-e428-4efd-95ed-2b0e19cbdc92',
type: 'RELATION',
name: 'calendarChannelEventAssociations',
@@ -8914,6 +9198,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '63904769-6145-4230-b294-c4554c36a273',
type: 'BOOLEAN',
name: 'isCanceled',
@@ -8935,6 +9220,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '48fac512-a780-4c44-b1dc-f178bd8ab3f8',
type: 'DATE_TIME',
name: 'deletedAt',
@@ -8956,6 +9242,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '1ba833a8-68ca-4396-b3ed-9a7411e1dc4f',
type: 'UUID',
name: 'id',
@@ -8977,6 +9264,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '3050381d-7191-4d18-be27-9a92cbefb57a',
type: 'LINKS',
name: 'conferenceLink',
@@ -9002,6 +9290,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'b6cf9c5d-e923-4026-9316-c3a513ce7c12',
type: 'BOOLEAN',
name: 'isFullDay',
@@ -9058,6 +9347,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'ac76a0ff-f5c1-4127-b354-0b3ce2b3696b',
type: 'RELATION',
name: 'favorites',
@@ -9105,6 +9395,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'e32f7a81-d208-4c14-afb4-a4befc938670',
type: 'RELATION',
name: 'assignedActivities',
@@ -9152,6 +9443,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '85df4525-aed1-4e46-b718-b5bc963da41d',
type: 'RELATION',
name: 'auditLogs',
@@ -9199,6 +9491,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'a1ffe54a-6b76-47fa-bd25-df479a31eee2',
type: 'FULL_NAME',
name: 'name',
@@ -9223,6 +9516,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '7370da8c-294f-4671-91e5-7f87f4dccc1e',
type: 'RELATION',
name: 'calendarEventParticipants',
@@ -9270,6 +9564,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '13531c23-42ca-4b1e-a6e3-3fcfad74a3e9',
type: 'RELATION',
name: 'connectedAccounts',
@@ -9317,6 +9612,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'a5fc2711-0e3d-40ac-938a-8beafeac1f57',
type: 'RELATION',
name: 'timelineActivities',
@@ -9364,6 +9660,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'bb548a08-0706-4021-833d-e527c23e2a48',
type: 'RELATION',
name: 'accountOwnerForCompanies',
@@ -9411,6 +9708,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'fc4f41c0-01ea-428d-9e0c-e2496acc765b',
type: 'TEXT',
name: 'avatarUrl',
@@ -9432,6 +9730,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'f74a56bf-9230-4452-b6a0-099ba9f7de0d',
type: 'RELATION',
name: 'authoredComments',
@@ -9479,6 +9778,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'e2895a0d-0e4f-4673-a778-2b99cac1ab20',
type: 'UUID',
name: 'userId',
@@ -9500,6 +9800,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '4cceec11-98cc-41c6-b08c-b04887a0ac22',
type: 'DATE_TIME',
name: 'createdAt',
@@ -9521,6 +9822,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '1dc4eef9-d576-4106-b19e-2fc91777470d',
type: 'TEXT',
name: 'timeZone',
@@ -9542,6 +9844,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '2f548d63-6cf6-4116-ae5a-03fcc35ffd1d',
type: 'UUID',
name: 'id',
@@ -9563,6 +9866,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '6cc143e8-f88a-4d75-a52c-d5c7f7419d97',
type: 'SELECT',
name: 'timeFormat',
@@ -9606,6 +9910,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'b9f4e812-721f-4c83-9f1e-42b79042d905',
type: 'DATE_TIME',
name: 'updatedAt',
@@ -9627,6 +9932,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '12e6ccfa-23ef-4b68-a043-6012bc7b9c67',
type: 'TEXT',
name: 'locale',
@@ -9648,6 +9954,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'b75d64ca-eb86-439d-ad61-3f23efec07e4',
type: 'TEXT',
name: 'userEmail',
@@ -9669,6 +9976,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'dd63010d-24f1-4e62-9b49-b4728bb3bd81',
type: 'DATE_TIME',
name: 'deletedAt',
@@ -9690,6 +9998,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'f173a8e9-af79-4377-9b21-5cb1ca27bc87',
type: 'TEXT',
name: 'colorScheme',
@@ -9711,6 +10020,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'f76b3faa-0bc6-45ed-9654-0421171a1f1a',
type: 'RELATION',
name: 'authoredActivities',
@@ -9758,6 +10068,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'c5df2d21-5db8-4e72-82bf-aeb3ec984ca9',
type: 'RELATION',
name: 'authoredAttachments',
@@ -9805,6 +10116,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'd82db237-ca6d-4bee-8d69-dfa0f753707b',
type: 'RELATION',
name: 'messageParticipants',
@@ -9852,6 +10164,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'e64fef03-fda1-4b5c-8894-d1bee725e7e2',
type: 'RELATION',
name: 'blocklist',
@@ -9899,6 +10212,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '3653df1b-5687-45c1-a2bf-afc261fe85a8',
type: 'RELATION',
name: 'assignedTasks',
@@ -9946,6 +10260,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '18a0276f-ce5e-4fc7-81fc-c32f6dd844f3',
type: 'SELECT',
name: 'dateFormat',
@@ -10031,6 +10346,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'f58f100f-8ee9-4a0c-8f35-8bdcb561d586',
type: 'DATE_TIME',
name: 'createdAt',
@@ -10052,6 +10368,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'a3740f53-215a-477d-82be-b57265731d83',
type: 'DATE_TIME',
name: 'deletedAt',
@@ -10073,6 +10390,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '67dbcf4d-f15b-4703-ba84-4bc2b9903579',
type: 'UUID',
name: 'id',
@@ -10094,6 +10412,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'd26efc67-251a-4bdd-a585-177717e298a6',
type: 'TEXT',
name: 'eventName',
@@ -10115,6 +10434,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'c8d7ed48-3d0e-47fa-a4af-5a62e578c128',
type: 'UUID',
name: 'workflowId',
@@ -10137,6 +10457,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'a424fba4-d3f4-41b1-bf9a-4b809ad628a9',
type: 'RELATION',
name: 'workflow',
@@ -10184,6 +10505,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'aabd6970-7bf9-488b-8411-5bc654574d58',
type: 'DATE_TIME',
name: 'updatedAt',
@@ -10240,6 +10562,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'ee4d98d0-37a4-42cc-8794-653099d4df54',
type: 'BOOLEAN',
name: 'isVisible',
@@ -10261,6 +10584,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '643509ce-5666-4264-8b09-f095e23a1624',
type: 'NUMBER',
name: 'position',
@@ -10282,6 +10606,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'c672e744-21f3-4d23-abd8-fcc03fad503a',
type: 'UUID',
name: 'viewId',
@@ -10303,6 +10628,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '49e8ada7-3a80-49c7-869a-3ebfdae35387',
type: 'NUMBER',
name: 'size',
@@ -10324,6 +10650,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'dd7510e1-4f22-4376-8436-19d7d631ea77',
type: 'DATE_TIME',
name: 'createdAt',
@@ -10345,6 +10672,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'f74ba2c1-22ab-4827-85ad-d2dbbe2a9b51',
type: 'RELATION',
name: 'view',
@@ -10392,6 +10720,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '959d36dc-493b-4e08-ae3d-38680bab1d0d',
type: 'UUID',
name: 'id',
@@ -10413,6 +10742,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '300b7bf6-e1fa-4cd2-a601-7a125b7bf1b8',
type: 'DATE_TIME',
name: 'deletedAt',
@@ -10434,6 +10764,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '0f7acd2a-ccd1-437e-b80a-bf4555a7c034',
type: 'UUID',
name: 'fieldMetadataId',
@@ -10455,6 +10786,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '217be100-e82e-4aae-9566-b091823a5466',
type: 'DATE_TIME',
name: 'updatedAt',
@@ -10511,6 +10843,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '330a6b96-c7eb-41ae-962e-eb528dc16aaf',
type: 'DATE_TIME',
name: 'updatedAt',
@@ -10532,6 +10865,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '45fe30a3-141f-4908-be8b-b826f84edb75',
type: 'UUID',
name: 'viewId',
@@ -10553,6 +10887,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '7924f4d6-c92b-436f-a86d-26b2dcc521aa',
type: 'TEXT',
name: 'direction',
@@ -10574,6 +10909,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'fc34ddd1-7f8a-4f23-a2b6-9a6d3165cc0a',
type: 'DATE_TIME',
name: 'deletedAt',
@@ -10595,6 +10931,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'e4f8f882-dec2-4d6b-a141-936e87d3fd27',
type: 'UUID',
name: 'id',
@@ -10616,6 +10953,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '25ae0938-795a-491a-b029-e4672412e85f',
type: 'RELATION',
name: 'view',
@@ -10663,6 +11001,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '540715e7-6531-4746-b567-b0a7fcda60ef',
type: 'UUID',
name: 'fieldMetadataId',
@@ -10684,6 +11023,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '26889121-d2d9-49dc-86ac-51c64d123197',
type: 'DATE_TIME',
name: 'createdAt',
@@ -10739,6 +11079,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '9aed4be2-3434-489f-a8a3-384311ee585e',
type: 'RELATION',
name: 'activityTargets',
@@ -10786,6 +11127,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '13794481-6a3a-48cb-80c2-109b7558f7b3',
type: 'RELATION',
name: 'attachments',
@@ -10833,6 +11175,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '79da64bc-eea3-476e-801b-f08c86a8c337',
type: 'RELATION',
name: 'favorites',
@@ -10880,6 +11223,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '0a688ec2-f55c-4485-a7a9-9438c19bcbe3',
type: 'ACTOR',
name: 'createdBy',
@@ -10904,6 +11248,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '17cbb6ed-1acc-43e9-a802-96a2b373a067',
type: 'DATE_TIME',
name: 'updatedAt',
@@ -10925,6 +11270,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'ba68ee30-5dc6-47db-bf6f-db25d829feb5',
type: 'TEXT',
name: 'name',
@@ -10946,6 +11292,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'ff73fd8a-9b60-4480-82d0-7b96c3c3aab6',
type: 'POSITION',
name: 'position',
@@ -10967,6 +11314,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '83515891-eb29-472e-9cde-4a1d42b6855d',
type: 'RELATION',
name: 'taskTargets',
@@ -11014,6 +11362,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '73428c65-a426-4c59-b50b-0dea5ffe9bf0',
type: 'DATE_TIME',
name: 'createdAt',
@@ -11035,6 +11384,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '6c65c781-9def-4c6c-98d4-25d3c0c085b8',
type: 'UUID',
name: 'id',
@@ -11056,6 +11406,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'b2643f4a-319e-49d4-a7b7-cbfff4712bf7',
type: 'DATE_TIME',
name: 'deletedAt',
@@ -11077,6 +11428,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '75f64c23-e9a5-4ada-8dc6-3c2c2ea27280',
type: 'RELATION',
name: 'noteTargets',
@@ -11124,6 +11476,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'aeefa434-6843-4b47-92f6-3ce6d8e93860',
type: 'RELATION',
name: 'timelineActivities',
@@ -11206,6 +11559,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'fa957d80-c61a-4298-aab9-54e8fba2110d',
type: 'UUID',
name: 'id',
@@ -11227,6 +11581,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'f966b379-0438-4b9c-8696-3edf18c197f7',
type: 'RELATION',
name: 'workspaceMember',
@@ -11274,6 +11629,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '37f7671b-aa7c-4fed-b50c-9b7cc7f59aa8',
type: 'TEXT',
name: 'handle',
@@ -11295,6 +11651,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '862261a3-5473-4e16-9220-16444ee99243',
type: 'DATE_TIME',
name: 'updatedAt',
@@ -11316,6 +11673,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '1233f40e-cc97-4281-a8a8-c23de8961693',
type: 'DATE_TIME',
name: 'createdAt',
@@ -11337,6 +11695,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'a75f6045-cf57-4b05-960b-5719ce2037c9',
type: 'DATE_TIME',
name: 'deletedAt',
@@ -11358,6 +11717,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'c30e3bff-ce4e-4e64-80e3-bf417ceefa25',
type: 'UUID',
name: 'workspaceMemberId',
@@ -11414,6 +11774,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '2d00a390-5ae4-40d9-8d6c-6abbcdc0bc75',
type: 'DATE_TIME',
name: 'updatedAt',
@@ -11435,6 +11796,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '2aab6f08-2cab-4beb-8775-1ad8b89c3313',
type: 'ACTOR',
name: 'createdBy',
@@ -11459,6 +11821,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'f40e2edc-c0dd-46d8-9a01-a0afd33a00db',
type: 'UUID',
name: 'id',
@@ -11480,6 +11843,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '421de2e5-36a1-4fb2-ae00-4e2f62dd67e6',
type: 'UUID',
name: 'workflowVersionId',
@@ -11502,6 +11866,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'c9e837bb-4516-43ad-8756-7a9c2ad33ca9',
type: 'DATE_TIME',
name: 'createdAt',
@@ -11523,6 +11888,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'aec86cc0-1fb6-4ff0-b1df-85b74ee6a974',
type: 'UUID',
name: 'workflowId',
@@ -11544,6 +11910,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'b38c3f7d-d455-4f1c-b674-66b86c0d56cc',
type: 'RELATION',
name: 'workflowVersion',
@@ -11591,6 +11958,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '446d4c37-71ac-4a61-8b65-16d70250cbc5',
type: 'SELECT',
name: 'status',
@@ -11641,6 +12009,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '0ed4a200-4d2e-4d4d-81b2-45240ae9e1b8',
type: 'DATE_TIME',
name: 'endedAt',
@@ -11662,6 +12031,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'a5444b51-1ad5-46ae-b9d9-ef5f1def9232',
type: 'RELATION',
name: 'workflow',
@@ -11709,6 +12079,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'b388b202-371a-4663-9299-afc6be461a8c',
type: 'DATE_TIME',
name: 'deletedAt',
@@ -11730,6 +12101,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '2e84a165-18af-492f-8662-14fbd5852b0c',
type: 'DATE_TIME',
name: 'startedAt',
@@ -11786,6 +12158,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '6f41b722-fbc4-44d9-9315-51498900e157',
type: 'DATE_TIME',
name: 'updatedAt',
@@ -11807,6 +12180,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '1d53ad9c-bdf4-4660-b4b6-e79162d13c39',
type: 'RELATION',
name: 'favorites',
@@ -11854,6 +12228,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'e7df66e0-50cc-4047-9b91-8f5ee1ff7246',
type: 'DATE_TIME',
name: 'createdAt',
@@ -11875,6 +12250,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '34ec585e-b42e-4e63-8e4b-7f9bf6a4e79b',
type: 'DATE_TIME',
name: 'deletedAt',
@@ -11896,6 +12272,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '22b735aa-95d7-44fe-a4a6-965171e3f7b7',
type: 'DATE_TIME',
name: 'dueAt',
@@ -11917,6 +12294,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'fea3a2f3-73ca-4142-8d15-3b8877b68cee',
type: 'UUID',
name: 'id',
@@ -11938,6 +12316,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '4f82dbad-cf61-4dd1-ad90-4cec71b288be',
type: 'RELATION',
name: 'attachments',
@@ -11985,6 +12364,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'b52cbdab-0c97-4601-b5ad-de766ec9f940',
type: 'SELECT',
name: 'status',
@@ -12028,6 +12408,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '1eea9af9-53a3-4085-9391-4a2fad697eb7',
type: 'RELATION',
name: 'timelineActivities',
@@ -12075,6 +12456,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '78360243-9830-4f40-a515-59cd8faf88b1',
type: 'RICH_TEXT',
name: 'body',
@@ -12096,6 +12478,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '33d7eb92-8231-417c-8efe-eb837c6ccadf',
type: 'ACTOR',
name: 'createdBy',
@@ -12120,6 +12503,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '5f9a8761-e5e6-492c-87ab-401c7b0e25cd',
type: 'UUID',
name: 'assigneeId',
@@ -12141,6 +12525,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '7a062a59-07da-4d2d-a0e8-f79f87e2e5e3',
type: 'RELATION',
name: 'assignee',
@@ -12188,6 +12573,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '80932806-6350-4941-a291-4d1430275d65',
type: 'RELATION',
name: 'taskTargets',
@@ -12235,6 +12621,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'daf389ba-49e6-4753-8a5a-a0330c5ab154',
type: 'POSITION',
name: 'position',
@@ -12256,6 +12643,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '0413dccd-00a6-4abd-967a-45233e8cf666',
type: 'TEXT',
name: 'title',
@@ -12312,6 +12700,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '38f5127c-ab53-45bc-90b9-a3883d697eb9',
type: 'DATE_TIME',
name: 'deletedAt',
@@ -12333,6 +12722,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'b2a7002e-19f2-4f16-8b5b-ea452aeb7104',
type: 'TEXT',
name: 'lastPublishedVersionId',
@@ -12354,6 +12744,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'd6fb9120-9aa5-4fdf-a84a-2805bb359855',
type: 'RELATION',
name: 'versions',
@@ -12401,6 +12792,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '99d7e7e6-ac6a-4b74-9129-d4a9759bc928',
type: 'DATE_TIME',
name: 'createdAt',
@@ -12422,6 +12814,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '06a5a424-930c-4465-9943-2a9c486f2038',
type: 'UUID',
name: 'id',
@@ -12443,6 +12836,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '650b02ef-32b5-4b10-bdab-a49f4e3b7a9b',
type: 'MULTI_SELECT',
name: 'statuses',
@@ -12484,6 +12878,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'b14865e9-26a6-4ae8-930d-d22c21c7696c',
type: 'RELATION',
name: 'eventListeners',
@@ -12532,6 +12927,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '4f32f14b-5009-4624-8b19-e65084368349',
type: 'RELATION',
name: 'runs',
@@ -12579,6 +12975,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'bab376b1-a7d9-48b8-88b7-f302bc6d483d',
type: 'TEXT',
name: 'name',
@@ -12600,6 +12997,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '141281c7-5b28-41d4-99bd-31c1e4c88e9b',
type: 'RELATION',
name: 'favorites',
@@ -12647,6 +13045,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'f21077b2-283f-4362-98fd-e5ea5f87d621',
type: 'POSITION',
name: 'position',
@@ -12668,6 +13067,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'b063853c-a442-4b52-8f89-f750c44a2e04',
type: 'DATE_TIME',
name: 'updatedAt',
@@ -12725,6 +13125,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '6615546f-8744-4b36-83d5-59c1ef72e845',
type: 'UUID',
name: 'id',
@@ -12746,6 +13147,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '299c9bdc-5137-4d2b-8225-ddb81a720bfe',
type: 'UUID',
name: 'rocketId',
@@ -12767,6 +13169,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '8626f50f-1d39-40e7-a05b-528c42fe4313',
type: 'RELATION',
name: 'task',
@@ -12814,6 +13217,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'f2f27d9e-c959-4dee-aed4-f87c64229c3f',
type: 'RELATION',
name: 'rocket',
@@ -12861,6 +13265,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '62e278a5-d719-4b49-a820-fc5ed358311e',
type: 'DATE_TIME',
name: 'happensAt',
@@ -12882,6 +13287,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '145c8790-abd1-49fb-9857-650da78c6717',
type: 'RELATION',
name: 'company',
@@ -12929,6 +13335,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '08dd3999-ca07-43cf-b872-a2bed317aa6a',
type: 'TEXT',
name: 'name',
@@ -12950,6 +13357,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'bbdf103a-60cb-4c39-a982-1704e26f6735',
type: 'UUID',
name: 'noteId',
@@ -12971,6 +13379,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '9e9d4989-fdf2-4e71-90af-aae2ef0b4923',
type: 'RELATION',
name: 'person',
@@ -13018,6 +13427,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '1b496b65-948d-4614-889f-2a9e0a6292f3',
type: 'UUID',
name: 'linkedObjectMetadataId',
@@ -13039,6 +13449,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'cd22914c-60d6-4e45-9936-9ff345d3a5bb',
type: 'DATE_TIME',
name: 'updatedAt',
@@ -13060,6 +13471,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '77f9059d-33f5-4fa1-8641-4976d38eaeb7',
type: 'TEXT',
name: 'linkedRecordCachedName',
@@ -13081,6 +13493,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '137a88ef-9c08-414c-adcc-2d450624acf8',
type: 'RELATION',
name: 'workspaceMember',
@@ -13128,6 +13541,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'b2df9370-1560-47f6-89b6-88293de46572',
type: 'UUID',
name: 'personId',
@@ -13149,6 +13563,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '9cb24716-07e8-4c54-a0c8-7005a619314e',
type: 'RAW_JSON',
name: 'properties',
@@ -13170,6 +13585,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'bc5277df-a1ec-4ae2-affe-e42aed88f0b9',
type: 'UUID',
name: 'taskId',
@@ -13191,6 +13607,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'cda06c7c-9c62-4579-b3ba-2e8275c604b1',
type: 'DATE_TIME',
name: 'createdAt',
@@ -13212,6 +13629,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '95fa7d72-fd85-4a32-a489-a5d03199debb',
type: 'UUID',
name: 'workspaceMemberId',
@@ -13233,6 +13651,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '1d16560a-4a8f-448c-8289-70e3e98ad3b4',
type: 'UUID',
name: 'linkedRecordId',
@@ -13254,6 +13673,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'c646eaf5-2754-4924-a212-c5747b0d1d41',
type: 'UUID',
name: 'companyId',
@@ -13275,6 +13695,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '88a829b3-6d66-4e53-b1ad-ed02e544e4d2',
type: 'RELATION',
name: 'opportunity',
@@ -13322,6 +13743,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'db7ab4e8-9d93-4f45-bbbf-f68eb31776cb',
type: 'RELATION',
name: 'note',
@@ -13369,6 +13791,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '1ee1c4bc-7281-4eff-bc32-6afaff324477',
type: 'DATE_TIME',
name: 'deletedAt',
@@ -13390,6 +13813,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '225d1acc-2ccc-458d-acd5-06f7d8647a38',
type: 'UUID',
name: 'opportunityId',
@@ -13447,6 +13871,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'f926708e-cc19-4e5f-8684-d14a1a1bc7df',
type: 'RELATION',
name: 'pointOfContactForOpportunities',
@@ -13495,6 +13920,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '5a063961-bffe-4d68-a0c8-e86b6b26f85e',
type: 'FULL_NAME',
name: 'name',
@@ -13519,6 +13945,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'd02d52c8-379b-476d-84d6-1222c2179db7',
type: 'LINKS',
name: 'linkedinLink',
@@ -13544,6 +13971,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '504f7e23-1476-422b-ac1d-5d86d3d33022',
type: 'RELATION',
name: 'company',
@@ -13591,6 +14019,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'daab9749-7d39-44cb-9557-23e0e257aaad',
type: 'RELATION',
name: 'attachments',
@@ -13638,6 +14067,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '6e46c199-d4f9-4c60-b9bb-19da859991b4',
type: 'RELATION',
name: 'timelineActivities',
@@ -13685,6 +14115,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'aa5e7931-e042-45d5-af4a-e4c22979a3b7',
type: 'RELATION',
name: 'calendarEventParticipants',
@@ -13732,6 +14163,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'a8a3d68a-a1b1-4912-aa13-51f088c6a754',
type: 'DATE_TIME',
name: 'deletedAt',
@@ -13753,6 +14185,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'e442f814-f8a6-44e9-b60c-d736afec87dd',
type: 'DATE_TIME',
name: 'createdAt',
@@ -13774,6 +14207,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'a91e4125-7885-4b3c-9672-0f6d2fc49c07',
type: 'DATE_TIME',
name: 'updatedAt',
@@ -13795,6 +14229,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '4a9a6c3e-633d-47d6-99bc-b8e6e9b6aad9',
type: 'TEXT',
name: 'jobTitle',
@@ -13816,6 +14251,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'b801b0d2-2a24-42be-b878-ef439ef7ea78',
type: 'TEXT',
name: 'intro',
@@ -13837,6 +14273,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'c188f5b7-2259-4207-87d2-5232ec775029',
type: 'RELATION',
name: 'favorites',
@@ -13884,9 +14321,10 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '5cdf5de5-6c7f-4787-b47d-de5e3787e670',
type: 'MULTI_SELECT',
- name: 'workPrefereance',
+ name: 'workPreference',
label: 'Work Preference',
description: "Person's Work Preference",
icon: 'IconHome',
@@ -13927,6 +14365,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '1315ca79-3abd-4b7f-917e-8949db3e01f3',
type: 'RATING',
name: 'performanceRating',
@@ -13979,6 +14418,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '749e13b2-5430-4993-83db-635c6ff11d1a',
type: 'LINKS',
name: 'xLink',
@@ -14004,6 +14444,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '0f7b1621-5da6-439a-927f-948fd2dd6f29',
type: 'RELATION',
name: 'noteTargets',
@@ -14051,6 +14492,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '759da4e9-e9c6-4827-9802-5b7b4021448f',
type: 'TEXT',
name: 'city',
@@ -14072,6 +14514,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '48f76fc3-3c82-463d-afa7-977011eed7c8',
type: 'UUID',
name: 'companyId',
@@ -14093,6 +14536,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '23c64ee1-4935-4a25-b401-afc08a0967fd',
type: 'RELATION',
name: 'activityTargets',
@@ -14140,6 +14584,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'd4a5fecc-285b-42d7-8eb4-96fc2a6838c4',
type: 'PHONES',
name: 'phones',
@@ -14165,6 +14610,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'bb5900a5-29ff-46bb-8bbb-7dbedd844e29',
type: 'ACTOR',
name: 'createdBy',
@@ -14189,6 +14635,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '54fbea0f-ce3f-4d28-8fa4-abcfe1ae3d54',
type: 'UUID',
name: 'id',
@@ -14210,6 +14657,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '718ee8a6-a294-4609-91d4-7ab0e83d996f',
type: 'POSITION',
name: 'position',
@@ -14231,6 +14679,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '779bdf5a-a28d-48be-8d02-b6ca93851829',
type: 'RELATION',
name: 'messageParticipants',
@@ -14278,6 +14727,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '7f8249b8-5919-4fee-81cf-b4dfdb89cf4d',
type: 'EMAILS',
name: 'emails',
@@ -14302,6 +14752,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'b328a712-5dc3-457a-aa56-8631f1b57248',
type: 'RELATION',
name: 'taskTargets',
@@ -14349,6 +14800,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '377efd0d-9798-4522-b9db-73c19bf55e26',
type: 'TEXT',
name: 'avatarUrl',
@@ -14370,6 +14822,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '3a34e81d-d5b1-417d-9831-a355040a6f44',
type: 'PHONES',
name: 'whatsapp',
@@ -14430,6 +14883,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'f115229b-f5b3-4623-ac80-f8bf3df5e077',
type: 'RELATION',
name: 'favorites',
@@ -14477,6 +14931,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'ed46299b-4006-45b4-aaa4-2dc7c0c25613',
type: 'DATE_TIME',
name: 'deletedAt',
@@ -14498,6 +14953,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '54952f24-63cc-475e-ab4c-b0f3ad6400bc',
type: 'UUID',
name: 'id',
@@ -14519,6 +14975,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'bef43ac8-834a-4a86-8bfb-5bed6cd94a57',
type: 'RELATION',
name: 'noteTargets',
@@ -14566,6 +15023,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '210b544b-46f7-422d-84e7-328ef270f081',
type: 'RELATION',
name: 'timelineActivities',
@@ -14613,6 +15071,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'd80706c2-3c5d-491f-9759-b05b25004799',
type: 'POSITION',
name: 'position',
@@ -14634,6 +15093,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '2238e043-a33f-4e8d-99d6-386cd0d2ea3b',
type: 'DATE_TIME',
name: 'updatedAt',
@@ -14655,6 +15115,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'c996b13e-a787-44f7-ad7a-2ba22afd46bc',
type: 'ACTOR',
name: 'createdBy',
@@ -14679,6 +15140,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '61375724-caaa-46b1-8e50-4b2f23afac71',
type: 'RICH_TEXT',
name: 'body',
@@ -14700,6 +15162,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '7ffc4d21-aa5d-4f0f-bc91-61c72660f2ba',
type: 'TEXT',
name: 'title',
@@ -14721,6 +15184,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '27b7400b-e754-4db9-b895-0a9252a015bf',
type: 'DATE_TIME',
name: 'createdAt',
@@ -14742,6 +15206,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '80479763-1c19-4465-a62f-cd5e37c9165a',
type: 'RELATION',
name: 'attachments',
@@ -14824,6 +15289,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '4e4f0f26-89bd-41eb-bc00-a591e041ca7d',
type: 'DATE_TIME',
name: 'updatedAt',
@@ -14845,6 +15311,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '362cb4b7-dda1-4136-9385-4f5402b4f700',
type: 'UUID',
name: 'id',
@@ -14866,6 +15333,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'd13848d4-b41e-43b0-87ca-ab40c00fd739',
type: 'DATE_TIME',
name: 'createdAt',
@@ -14887,6 +15355,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '81685712-ecaa-4d04-a8d9-e6c93a6bfe7a',
type: 'TEXT',
name: 'displayValue',
@@ -14908,6 +15377,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'f72701d1-8337-4640-84b7-4570cfbe96aa',
type: 'UUID',
name: 'viewId',
@@ -14929,6 +15399,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'e323bb1b-8018-4b6f-b065-37c979caf7fc',
type: 'DATE_TIME',
name: 'deletedAt',
@@ -14950,6 +15421,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '646c0bfc-071d-44f3-b8d4-428061106500',
type: 'UUID',
name: 'fieldMetadataId',
@@ -14971,6 +15443,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '016a2312-ac04-4d46-b7c7-2d6e24e363c8',
type: 'TEXT',
name: 'value',
@@ -14992,6 +15465,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'e09cc7ab-2750-4cd9-86e1-c257dac8b390',
type: 'TEXT',
name: 'operand',
@@ -15013,6 +15487,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'd1829b60-e886-4dac-8cf3-0d3b84da093d',
type: 'RELATION',
name: 'view',
@@ -15095,6 +15570,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'dd208a4e-3e5e-4192-83a1-adbc5b9123a1',
type: 'RAW_JSON',
name: 'steps',
@@ -15116,6 +15592,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'fe28de2e-8979-4cfd-9b66-03e67e93406b',
type: 'UUID',
name: 'id',
@@ -15137,6 +15614,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'dcdf9413-04c8-44f7-ace7-a11950ce3019',
type: 'SELECT',
name: 'status',
@@ -15187,6 +15665,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'ef3d8797-2f17-4f31-9970-697fc230df7f',
type: 'RELATION',
name: 'runs',
@@ -15234,6 +15713,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'ebe58c33-17d2-418b-b33f-f5c3907e97d7',
type: 'DATE_TIME',
name: 'deletedAt',
@@ -15255,6 +15735,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '1b223e47-9228-41c4-a420-ff6ed516393e',
type: 'DATE_TIME',
name: 'createdAt',
@@ -15276,6 +15757,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '54cde78b-4bd4-436b-b10b-e6de37494161',
type: 'RELATION',
name: 'workflow',
@@ -15323,6 +15805,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '4ebb0eb9-9ad6-4e5b-b01b-837b0e2c0718',
type: 'RAW_JSON',
name: 'trigger',
@@ -15344,6 +15827,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'ef2dd597-faaa-4b1d-96b7-5953cd8c8539',
type: 'TEXT',
name: 'name',
@@ -15365,6 +15849,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'd9f1d5c8-ce95-48c3-a4f3-0909aea7e322',
type: 'DATE_TIME',
name: 'updatedAt',
@@ -15386,6 +15871,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '182c0466-9e03-4500-8cf7-22673e05b299',
type: 'UUID',
name: 'workflowId',
@@ -15442,6 +15928,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '426142c4-5a52-4105-a880-387b6dba6362',
type: 'DATE_TIME',
name: 'deletedAt',
@@ -15463,6 +15950,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '4d459669-2ffd-4fd0-b28b-57d8a1eb9434',
type: 'UUID',
name: 'personId',
@@ -15484,6 +15972,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '1a6dd2bf-3da7-492d-80de-a8891c5307b7',
type: 'UUID',
name: 'opportunityId',
@@ -15505,6 +15994,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '3669c8b2-ba73-4e9b-be61-10a2023955fd',
type: 'RELATION',
name: 'activity',
@@ -15552,6 +16042,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '023f376c-023a-4cae-89e8-961add0b3743',
type: 'UUID',
name: 'id',
@@ -15573,6 +16064,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '6a5833a9-0741-44f0-948d-424a60d3264e',
type: 'RELATION',
name: 'note',
@@ -15620,6 +16112,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '1d3d2f23-c3e6-4ee0-b62e-7668e4f8147d',
type: 'TEXT',
name: 'fullPath',
@@ -15641,6 +16134,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'd9a80298-6f72-4b2f-a859-2bd355d36735',
type: 'RELATION',
name: 'author',
@@ -15688,6 +16182,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '42dbb8d7-320b-460d-a25e-943222ae2a9b',
type: 'TEXT',
name: 'type',
@@ -15709,6 +16204,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'a7971798-8b85-477e-8a1e-9b2f2fb5da6d',
type: 'UUID',
name: 'rocketId',
@@ -15730,6 +16226,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '610633e7-0221-4838-adaf-71943d18a5ca',
type: 'RELATION',
name: 'person',
@@ -15777,6 +16274,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '26668e62-39e7-4842-a198-a657f44206f8',
type: 'RELATION',
name: 'task',
@@ -15824,6 +16322,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '1433d739-29ed-450c-8216-6afea26d21fb',
type: 'RELATION',
name: 'company',
@@ -15871,6 +16370,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '1a8466d6-8be7-458a-a7ea-cdf11b4fe31d',
type: 'DATE_TIME',
name: 'updatedAt',
@@ -15892,6 +16392,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '7dc968df-7127-4e05-b63e-f2e9809324ee',
type: 'UUID',
name: 'noteId',
@@ -15913,6 +16414,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '7ffec116-99d2-402d-adea-68b731be4c74',
type: 'UUID',
name: 'taskId',
@@ -15934,6 +16436,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'd76c9b48-5a3e-445f-be15-948de8ba2fc2',
type: 'TEXT',
name: 'name',
@@ -15955,6 +16458,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'fa9d964c-3d30-4d8b-bc57-9b382053e9e3',
type: 'RELATION',
name: 'opportunity',
@@ -16002,6 +16506,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '133dcd8e-aa07-4c9e-a337-92dabd5f7d03',
type: 'UUID',
name: 'activityId',
@@ -16023,6 +16528,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'd10c5485-159b-4700-a709-37d3049a8778',
type: 'DATE_TIME',
name: 'createdAt',
@@ -16044,6 +16550,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '60f8c4fb-1ab9-44a7-a5bd-e89a0349feb7',
type: 'RELATION',
name: 'rocket',
@@ -16091,6 +16598,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'adaa359c-c834-44bb-8639-44ef1affce2f',
type: 'UUID',
name: 'authorId',
@@ -16112,6 +16620,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '3486e0e2-053c-4e27-9d5d-c27b5dd739ea',
type: 'UUID',
name: 'companyId',
@@ -16168,6 +16677,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '827beccf-c3ca-4f24-a349-5d7c8690ac95',
type: 'TEXT',
name: 'headerMessageId',
@@ -16189,6 +16699,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'f51b5646-06b0-45e4-960f-5f8eaeb18c83',
type: 'DATE_TIME',
name: 'deletedAt',
@@ -16210,6 +16721,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'f32d4ef7-cadd-4ce5-84ce-a95fd76fde05',
type: 'DATE_TIME',
name: 'updatedAt',
@@ -16231,6 +16743,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'c36f257c-2318-4b61-9c63-666e1fc0810c',
type: 'DATE_TIME',
name: 'receivedAt',
@@ -16252,6 +16765,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '86a6dca6-5ad5-4576-b8f4-4be343e573de',
type: 'RELATION',
name: 'messageChannelMessageAssociations',
@@ -16299,6 +16813,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '606cef74-d9c3-4abc-b6ae-bb778f518e49',
type: 'RELATION',
name: 'messageParticipants',
@@ -16346,6 +16861,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '21c34ce8-7505-4d6c-9fc8-218dd8532a25',
type: 'UUID',
name: 'id',
@@ -16367,6 +16883,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '48f20f05-700d-4609-965b-8a954bf07e8d',
type: 'UUID',
name: 'messageThreadId',
@@ -16388,6 +16905,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '11f38fa4-e7b8-4275-b0b2-59688cb2eed8',
type: 'RELATION',
name: 'messageThread',
@@ -16435,6 +16953,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '2697ab29-9991-4188-9569-8bc6fc079ec6',
type: 'TEXT',
name: 'subject',
@@ -16456,6 +16975,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'f6a75fcf-f8a3-41dd-b1d0-efce8358e2d2',
type: 'TEXT',
name: 'text',
@@ -16477,6 +16997,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '29f11f81-aab0-4b96-971f-24d84c81f1bf',
type: 'DATE_TIME',
name: 'createdAt',
@@ -16533,6 +17054,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '61fe3c78-ab04-4a83-9a40-8560f7285abe',
type: 'RELATION',
name: 'favorites',
@@ -16580,6 +17102,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '027418ee-6028-456f-a570-0b032d35b07f',
type: 'RELATION',
name: 'viewFields',
@@ -16627,6 +17150,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '4385a72b-bb9d-4ac6-9c08-d9853c468726',
type: 'UUID',
name: 'id',
@@ -16648,6 +17172,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '421bf244-013a-4962-970a-37150cf38057',
type: 'TEXT',
name: 'type',
@@ -16669,6 +17194,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '8ee5c1d6-718a-4e43-b468-91563270ae35',
type: 'TEXT',
name: 'icon',
@@ -16690,6 +17216,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '073a7e52-0c68-4853-a500-5470b026c914',
type: 'SELECT',
name: 'key',
@@ -16719,6 +17246,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'ed944e8e-e84d-40ef-aa44-b423453c23f9',
type: 'BOOLEAN',
name: 'isCompact',
@@ -16740,6 +17268,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '5454b125-73c2-438b-991b-eb361bcd6295',
type: 'TEXT',
name: 'kanbanFieldMetadataId',
@@ -16761,6 +17290,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '7974ab3b-7d05-4738-a05b-b76840f98328',
type: 'RELATION',
name: 'viewFilters',
@@ -16808,6 +17338,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '23b99490-be92-4edc-a939-07e0f64f13eb',
type: 'RELATION',
name: 'viewSorts',
@@ -16855,6 +17386,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '36f1f251-121a-461c-aef5-aba2c9fa39a6',
type: 'UUID',
name: 'objectMetadataId',
@@ -16876,6 +17408,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: '2fcf2221-da1f-4c19-acdc-adfb089ea219',
type: 'POSITION',
name: 'position',
@@ -16897,6 +17430,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'a0e02b0d-6681-41da-a8a8-48c0bc5ba690',
type: 'DATE_TIME',
name: 'createdAt',
@@ -16918,6 +17452,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'dbc64e7b-2b59-4e9e-9e1e-bcd9e9f5a57a',
type: 'DATE_TIME',
name: 'deletedAt',
@@ -16939,6 +17474,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'f5c9b9fc-87fd-4a74-af09-28a330a53bec',
type: 'DATE_TIME',
name: 'updatedAt',
@@ -16960,6 +17496,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
__typename: 'fieldEdge',
node: {
__typename: 'field',
+ settings: {},
id: 'a24df79d-a05a-45e7-8791-b71957dff236',
type: 'TEXT',
name: 'name',
diff --git a/packages/twenty-front/src/testing/mock-data/objectMetadataItems.ts b/packages/twenty-front/src/testing/mock-data/generatedMockObjectMetadataItems.ts
similarity index 100%
rename from packages/twenty-front/src/testing/mock-data/objectMetadataItems.ts
rename to packages/twenty-front/src/testing/mock-data/generatedMockObjectMetadataItems.ts
diff --git a/packages/twenty-front/src/testing/mock-data/metadata.ts b/packages/twenty-front/src/testing/mock-data/metadata.ts
deleted file mode 100644
index f739afd46647..000000000000
--- a/packages/twenty-front/src/testing/mock-data/metadata.ts
+++ /dev/null
@@ -1,290 +0,0 @@
-import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
-import { mapPaginatedObjectMetadataItemsToObjectMetadataItems } from '@/object-metadata/utils/mapPaginatedObjectMetadataItemsToObjectMetadataItems';
-import {
- FieldMetadataType,
- ObjectEdge,
- ObjectMetadataItemsQuery,
-} from '~/generated-metadata/graphql';
-import { mockedStandardObjectMetadataQueryResult } from '~/testing/mock-data/generated/mock-metadata-query-result';
-
-// TODO: replace with new mock
-const customObjectMetadataItemEdge: ObjectEdge = {
- __typename: 'objectEdge',
- node: {
- __typename: 'object',
- id: 'efa1addc-a9cb-4789-b99e-a060fa84f982',
- dataSourceId: 'd36e6a2d-28bc-459d-afd5-fe18e4405729',
- nameSingular: 'myCustom',
- namePlural: 'myCustoms',
- labelSingular: 'My Custom',
- labelPlural: 'My Customs',
- description: 'A custom object example',
- icon: 'IconLayoutCollage',
- isCustom: true,
- isRemote: false,
- isActive: true,
- isSystem: false,
- createdAt: '2024-04-08T12:48:49.538Z',
- updatedAt: '2024-04-08T12:48:49.538Z',
- labelIdentifierFieldMetadataId: null,
- imageIdentifierFieldMetadataId: null,
- fields: {
- __typename: 'ObjectFieldsConnection',
- pageInfo: {
- __typename: 'PageInfo',
- hasNextPage: false,
- hasPreviousPage: false,
- startCursor: 'YXJyYXljb25uZWN0aW9uOjA=',
- endCursor: 'YXJyYXljb25uZWN0aW9uOjEz',
- },
- edges: [
- {
- __typename: 'fieldEdge',
- node: {
- __typename: 'field',
- id: 'ea83af89-be10-49af-a605-10c3392ae007',
- type: 'RELATION',
- name: 'companies',
- label: 'Companies',
- description: 'A custom Relation example',
- icon: 'IconTag',
- isCustom: false,
- isActive: true,
- isSystem: true,
- options: null,
- isNullable: true,
- createdAt: '2024-04-08T12:48:49.538Z',
- updatedAt: '2024-04-08T12:48:49.538Z',
- defaultValue: null,
- relationDefinition: {
- relationId: '1ec22b36-9e3c-4f24-8cf6-6c387ec3f243',
- __typename: 'RelationDefinition',
- direction: 'ONE_TO_MANY',
- sourceObjectMetadata: {
- __typename: 'object',
- id: 'efa1addc-a9cb-4789-b99e-a060fa84f982',
- nameSingular: 'myCustom',
- namePlural: 'myCustoms',
- },
- sourceFieldMetadata: {
- __typename: 'field',
- id: 'ea83af89-be10-49af-a605-10c3392ae007',
- name: 'companies',
- },
- targetObjectMetadata: {
- __typename: 'object',
- id: 'dba899da-7d88-41ac-b70e-5ea612ab4b2e',
- nameSingular: 'company',
- namePlural: 'companies',
- },
- targetFieldMetadata: {
- __typename: 'field',
- id: 'c9607ed7-168d-4743-a56a-689ffcfffe98',
- name: 'myCustom',
- },
- },
- },
- },
- {
- __typename: 'fieldEdge',
- node: {
- __typename: 'field',
- id: 'c5384d2a-9ec3-4e1b-b93f-86f53f122169',
- type: 'UUID',
- name: 'objectMetadataId',
- label: 'Object Metadata Id',
- description: 'View target object',
- icon: null,
- isCustom: false,
- isActive: true,
- isSystem: true,
- options: null,
- isNullable: false,
- createdAt: '2024-04-08T12:48:49.538Z',
- updatedAt: '2024-04-08T12:48:49.538Z',
- defaultValue: null,
- relationDefinition: null,
- },
- },
- {
- __typename: 'fieldEdge',
- node: {
- __typename: 'field',
- id: 'bb4d96be-e4d9-47a9-812d-fcdfb063ebf3',
- type: 'POSITION',
- name: 'position',
- label: 'Position',
- description: 'View position',
- icon: null,
- isCustom: false,
- isActive: true,
- isSystem: true,
- options: null,
- isNullable: true,
- createdAt: '2024-04-08T12:48:49.538Z',
- updatedAt: '2024-04-08T12:48:49.538Z',
- defaultValue: null,
- relationDefinition: null,
- },
- },
- {
- __typename: 'fieldEdge',
- node: {
- __typename: 'field',
- id: 'f20c68aa-3930-41c4-9f79-45dceda506df',
- type: 'TEXT',
- name: 'name',
- label: 'Name',
- description: 'Custom name',
- icon: null,
- isCustom: false,
- isActive: true,
- isSystem: true,
- options: null,
- isNullable: false,
- createdAt: '2024-04-08T12:48:49.538Z',
- updatedAt: '2024-04-08T12:48:49.538Z',
- defaultValue: "''",
- relationDefinition: null,
- },
- },
- {
- __typename: 'fieldEdge',
- node: {
- __typename: 'field',
- id: 'a3ef848d-660a-4aef-9cd4-5baf25ce36ed',
- type: 'DATE_TIME',
- name: 'createdAt',
- label: 'Creation date',
- description: 'Creation date',
- icon: 'IconCalendar',
- isCustom: false,
- isActive: true,
- isSystem: true,
- options: null,
- isNullable: false,
- createdAt: '2024-04-08T12:48:49.538Z',
- updatedAt: '2024-04-08T12:48:49.538Z',
- defaultValue: 'now',
- relationDefinition: null,
- },
- },
- {
- __typename: 'fieldEdge',
- node: {
- __typename: 'field',
- id: '92f3e27c-041d-45b2-b2bd-46db2b1aec3f',
- type: 'DATE_TIME',
- name: 'updatedAt',
- label: 'Update date',
- description: 'Update date',
- icon: 'IconCalendar',
- isCustom: false,
- isActive: true,
- isSystem: true,
- options: null,
- isNullable: false,
- createdAt: '2024-04-08T12:48:49.538Z',
- updatedAt: '2024-04-08T12:48:49.538Z',
- defaultValue: 'now',
- relationDefinition: null,
- },
- },
- {
- __typename: 'fieldEdge',
- node: {
- __typename: 'field',
- id: '8d7987eb-99e8-4e54-a86c-86b3bd07d2be',
- type: 'UUID',
- name: 'id',
- label: 'Id',
- description: 'Id',
- icon: 'Icon123',
- isCustom: false,
- isActive: true,
- isSystem: true,
- options: null,
- isNullable: false,
- createdAt: '2024-04-08T12:48:49.538Z',
- updatedAt: '2024-04-08T12:48:49.538Z',
- defaultValue: 'uuid',
- relationDefinition: null,
- },
- },
- {
- __typename: 'fieldEdge',
- node: {
- __typename: 'field',
- id: 'e07fcc3f-beec-4d91-8488-9d1d2cfa5f99',
- type: FieldMetadataType.Select,
- name: 'priority',
- label: 'Priority',
- description: 'A custom Select example',
- icon: 'IconWarning',
- isCustom: true,
- isActive: true,
- isSystem: false,
- options: [
- {
- id: '2b98dc02-0d99-4f3e-890e-e2e6b8f3196c',
- value: 'LOW',
- label: 'Low',
- color: 'turquoise',
- },
- {
- id: 'd925a8de-d8ec-4b59-a079-64f4012e3311',
- value: 'MEDIUM',
- label: 'Medium',
- color: 'yellow',
- },
- {
- id: '6f6e1421-8a42-4d4a-bf76-465b5f84b6d2',
- value: 'HIGH',
- label: 'High',
- color: 'red',
- },
- ],
- isNullable: true,
- createdAt: '2024-04-08T12:48:49.538Z',
- updatedAt: '2024-04-08T12:48:49.538Z',
- defaultValue: null,
- relationDefinition: null,
- },
- },
- ],
- },
- },
-} as ObjectEdge;
-
-export const mockedObjectMetadataItemsQueryResult = {
- ...mockedStandardObjectMetadataQueryResult,
- objects: {
- ...mockedStandardObjectMetadataQueryResult.objects,
- edges: [
- ...mockedStandardObjectMetadataQueryResult.objects.edges,
- customObjectMetadataItemEdge,
- ],
- },
-} as ObjectMetadataItemsQuery;
-
-export const mockedObjectMetadataItems =
- mapPaginatedObjectMetadataItemsToObjectMetadataItems({
- pagedObjectMetadataItems: mockedObjectMetadataItemsQueryResult,
- });
-
-export const mockedCompanyObjectMetadataItem = mockedObjectMetadataItems?.find(
- (object) => object.nameSingular === 'company',
-) as ObjectMetadataItem;
-
-export const mockedPersonObjectMetadataItem = mockedObjectMetadataItems?.find(
- (object) => object.nameSingular === 'person',
-) as ObjectMetadataItem;
-
-export const mockedCustomObjectMetadataItem = mockedObjectMetadataItems?.find(
- (object) => object.nameSingular === 'myCustom',
-) as ObjectMetadataItem;
-
-export const mockedOpportunityObjectMetadataItem =
- mockedObjectMetadataItems?.find(
- (object) => object.nameSingular === 'opportunity',
- ) as ObjectMetadataItem;
diff --git a/packages/twenty-front/src/testing/mock-data/users.ts b/packages/twenty-front/src/testing/mock-data/users.ts
index f7a4c2727e22..cc483bd1e570 100644
--- a/packages/twenty-front/src/testing/mock-data/users.ts
+++ b/packages/twenty-front/src/testing/mock-data/users.ts
@@ -26,6 +26,7 @@ type MockedUser = Pick<
locale: string;
defaultWorkspace: Workspace;
workspaces: Array<{ workspace: Workspace }>;
+ workspaceMembers: WorkspaceMember[];
};
export const avatarUrl =
@@ -107,6 +108,7 @@ export const mockedUserData: MockedUser = {
defaultWorkspace: mockDefaultWorkspace,
locale: 'en',
workspaces: [{ workspace: mockDefaultWorkspace }],
+ workspaceMembers: [mockedWorkspaceMemberData],
onboardingStatus: OnboardingStatus.Completed,
userVars: {},
};
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 b68cfb706a27..325e3610ccd7 100644
--- a/packages/twenty-front/src/testing/mock-data/view-fields.ts
+++ b/packages/twenty-front/src/testing/mock-data/view-fields.ts
@@ -1,240 +1,416 @@
+import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
import { mockedViewsData } from './views';
+const companyObjectMetadata = generatedMockObjectMetadataItems.find(
+ (item) => item.nameSingular === 'company',
+);
+
+const personObjectMetadata = generatedMockObjectMetadataItems.find(
+ (item) => item.nameSingular === 'person',
+);
+
+const opportunityObjectMetadata = generatedMockObjectMetadataItems.find(
+ (item) => item.nameSingular === 'opportunity',
+);
+
export const mockedViewFieldsData = [
// Companies
{
id: '79035310-e955-4986-a4a4-73f9d9949c6a',
- fieldMetadataId: '9e123592-cd2b-471c-8143-3cc0b46089ef',
+ fieldMetadataId: companyObjectMetadata?.fields.find(
+ (field) => field.name === 'name',
+ )?.id,
viewId: mockedViewsData[0].id,
position: 0,
isVisible: true,
size: 180,
createdAt: '2021-09-01T00:00:00.000Z',
updatedAt: '2021-09-01T00:00:00.000Z',
+ deletedAt: null,
__typename: 'ViewField',
},
{
id: '2a96bbc8-d86d-439a-8e50-4b07ebd27750',
- fieldMetadataId: 'domainName',
+ fieldMetadataId: companyObjectMetadata?.fields.find(
+ (field) => field.name === 'domainName',
+ )?.id,
viewId: mockedViewsData[0].id,
position: 1,
isVisible: true,
size: 100,
createdAt: '2021-09-01T00:00:00.000Z',
updatedAt: '2021-09-01T00:00:00.000Z',
+ deletedAt: null,
__typename: 'ViewField',
},
{
id: '0c1b4c7b-6a3d-4fb0-bf2b-5d7c8fb844ed',
- fieldMetadataId: 'accountOwner',
+ fieldMetadataId: companyObjectMetadata?.fields.find(
+ (field) => field.name === 'accountOwner',
+ )?.id,
viewId: mockedViewsData[0].id,
position: 2,
isVisible: true,
size: 150,
createdAt: '2021-09-01T00:00:00.000Z',
updatedAt: '2021-09-01T00:00:00.000Z',
+ deletedAt: null,
__typename: 'ViewField',
},
{
id: 'cc7f9560-32b5-4b82-8fd9-b05fe77c8cf7',
- fieldMetadataId: 'createdAt',
+ fieldMetadataId: companyObjectMetadata?.fields.find(
+ (field) => field.name === 'createdAt',
+ )?.id,
viewId: mockedViewsData[0].id,
position: 3,
isVisible: true,
size: 150,
createdAt: '2021-09-01T00:00:00.000Z',
updatedAt: '2021-09-01T00:00:00.000Z',
+ deletedAt: null,
__typename: 'ViewField',
},
{
id: '3de4d078-3396-4480-be2d-6f3b1a228b0d',
- fieldMetadataId: 'employees',
+ fieldMetadataId: companyObjectMetadata?.fields.find(
+ (field) => field.name === 'employees',
+ )?.id,
viewId: mockedViewsData[0].id,
position: 4,
isVisible: true,
size: 150,
createdAt: '2021-09-01T00:00:00.000Z',
updatedAt: '2021-09-01T00:00:00.000Z',
+ deletedAt: null,
__typename: 'ViewField',
},
{
id: '4650c8fb-0f1e-4342-88dc-adedae1445f9',
- fieldMetadataId: 'linkedin',
+ fieldMetadataId: companyObjectMetadata?.fields.find(
+ (field) => field.name === 'linkedinLink',
+ )?.id,
viewId: mockedViewsData[0].id,
position: 5,
isVisible: true,
size: 170,
createdAt: '2021-09-01T00:00:00.000Z',
updatedAt: '2021-09-01T00:00:00.000Z',
+ deletedAt: null,
__typename: 'ViewField',
},
{
id: '727430bf-6ff8-4c85-9828-cbe72ac0fc27',
- fieldMetadataId: 'address',
+ fieldMetadataId: companyObjectMetadata?.fields.find(
+ (field) => field.name === 'address',
+ )?.id,
viewId: mockedViewsData[0].id,
position: 6,
isVisible: true,
size: 170,
createdAt: '2021-09-01T00:00:00.000Z',
updatedAt: '2021-09-01T00:00:00.000Z',
+ deletedAt: null,
+ __typename: 'ViewField',
+ },
+
+ // Companies v2
+ {
+ id: '79035310-e955-4986-a4a4-73f9d9949c6a',
+ fieldMetadataId: companyObjectMetadata?.fields.find(
+ (field) => field.name === 'name',
+ )?.id,
+ viewId: mockedViewsData[3].id,
+ position: 0,
+ isVisible: true,
+ size: 180,
+ createdAt: '2021-09-01T00:00:00.000Z',
+ updatedAt: '2021-09-01T00:00:00.000Z',
+ deletedAt: null,
+ __typename: 'ViewField',
+ },
+ {
+ id: '2a96bbc8-d86d-439a-8e50-4b07ebd27750',
+ fieldMetadataId: companyObjectMetadata?.fields.find(
+ (field) => field.name === 'domainName',
+ )?.id,
+ viewId: mockedViewsData[3].id,
+ position: 1,
+ isVisible: true,
+ size: 100,
+ createdAt: '2021-09-01T00:00:00.000Z',
+ updatedAt: '2021-09-01T00:00:00.000Z',
+ deletedAt: null,
+ __typename: 'ViewField',
+ },
+ {
+ id: '0c1b4c7b-6a3d-4fb0-bf2b-5d7c8fb844ed',
+ fieldMetadataId: companyObjectMetadata?.fields.find(
+ (field) => field.name === 'accountOwner',
+ )?.id,
+ viewId: mockedViewsData[3].id,
+ position: 2,
+ isVisible: true,
+ size: 150,
+ createdAt: '2021-09-01T00:00:00.000Z',
+ updatedAt: '2021-09-01T00:00:00.000Z',
+ deletedAt: null,
+ __typename: 'ViewField',
+ },
+ {
+ id: 'cc7f9560-32b5-4b82-8fd9-b05fe77c8cf7',
+ fieldMetadataId: companyObjectMetadata?.fields.find(
+ (field) => field.name === 'createdAt',
+ )?.id,
+ viewId: mockedViewsData[3].id,
+ position: 3,
+ isVisible: true,
+ size: 150,
+ createdAt: '2021-09-01T00:00:00.000Z',
+ updatedAt: '2021-09-01T00:00:00.000Z',
+ deletedAt: null,
+ __typename: 'ViewField',
+ },
+ {
+ id: '3de4d078-3396-4480-be2d-6f3b1a228b0d',
+ fieldMetadataId: companyObjectMetadata?.fields.find(
+ (field) => field.name === 'employees',
+ )?.id,
+ viewId: mockedViewsData[3].id,
+ position: 4,
+ isVisible: true,
+ size: 150,
+ createdAt: '2021-09-01T00:00:00.000Z',
+ updatedAt: '2021-09-01T00:00:00.000Z',
+ deletedAt: null,
+ __typename: 'ViewField',
+ },
+ {
+ id: '4650c8fb-0f1e-4342-88dc-adedae1445f9',
+ fieldMetadataId: companyObjectMetadata?.fields.find(
+ (field) => field.name === 'linkedinLink',
+ )?.id,
+ viewId: mockedViewsData[3].id,
+ position: 5,
+ isVisible: true,
+ size: 170,
+ createdAt: '2021-09-01T00:00:00.000Z',
+ updatedAt: '2021-09-01T00:00:00.000Z',
+ deletedAt: null,
+ __typename: 'ViewField',
+ },
+ {
+ id: '727430bf-6ff8-4c85-9828-cbe72ac0fc27',
+ fieldMetadataId: companyObjectMetadata?.fields.find(
+ (field) => field.name === 'address',
+ )?.id,
+ viewId: mockedViewsData[3].id,
+ position: 6,
+ isVisible: true,
+ size: 170,
+ createdAt: '2021-09-01T00:00:00.000Z',
+ updatedAt: '2021-09-01T00:00:00.000Z',
+ deletedAt: null,
__typename: 'ViewField',
},
// People
{
id: '28894146-4fde-4a16-a9ca-1a31b5b788b4',
- fieldMetadataId: 'displayName',
+ fieldMetadataId: personObjectMetadata?.fields.find(
+ (field) => field.name === 'name',
+ )?.id,
viewId: mockedViewsData[1].id,
position: 0,
isVisible: true,
size: 210,
createdAt: '2021-09-01T00:00:00.000Z',
updatedAt: '2021-09-01T00:00:00.000Z',
+ deletedAt: null,
__typename: 'ViewField',
},
{
id: 'e1e24864-8601-4cd8-8a63-09c1285f2e39',
- fieldMetadataId: 'email',
+ fieldMetadataId: personObjectMetadata?.fields.find(
+ (field) => field.name === 'emails',
+ )?.id,
viewId: mockedViewsData[1].id,
position: 1,
isVisible: true,
size: 150,
createdAt: '2021-09-01T00:00:00.000Z',
updatedAt: '2021-09-01T00:00:00.000Z',
+ deletedAt: null,
__typename: 'ViewField',
},
{
id: '5a1df716-7211-445a-9f16-9783a00998a7',
- fieldMetadataId: 'company',
+ fieldMetadataId: personObjectMetadata?.fields.find(
+ (field) => field.name === 'company',
+ )?.id,
viewId: mockedViewsData[1].id,
position: 2,
isVisible: true,
size: 150,
createdAt: '2021-09-01T00:00:00.000Z',
updatedAt: '2021-09-01T00:00:00.000Z',
+ deletedAt: null,
__typename: 'ViewField',
},
{
id: 'a6e1197a-7e84-4d92-ace2-367c0bc46c49',
- fieldMetadataId: 'phone',
+ fieldMetadataId: personObjectMetadata?.fields.find(
+ (field) => field.name === 'phones',
+ )?.id,
viewId: mockedViewsData[1].id,
position: 3,
isVisible: true,
size: 150,
createdAt: '2021-09-01T00:00:00.000Z',
updatedAt: '2021-09-01T00:00:00.000Z',
+ deletedAt: null,
__typename: 'ViewField',
},
{
id: 'c9343097-d14b-4559-a5fa-626c1527d39f',
- fieldMetadataId: 'createdAt',
+ fieldMetadataId: personObjectMetadata?.fields.find(
+ (field) => field.name === 'createdAt',
+ )?.id,
viewId: mockedViewsData[1].id,
position: 4,
isVisible: true,
size: 150,
createdAt: '2021-09-01T00:00:00.000Z',
updatedAt: '2021-09-01T00:00:00.000Z',
+ deletedAt: null,
__typename: 'ViewField',
},
{
id: 'a873e5f0-fed6-47e9-a712-6854eab3ec77',
- fieldMetadataId: 'city',
+ fieldMetadataId: personObjectMetadata?.fields.find(
+ (field) => field.name === 'city',
+ )?.id,
viewId: mockedViewsData[1].id,
position: 5,
isVisible: true,
size: 150,
createdAt: '2021-09-01T00:00:00.000Z',
updatedAt: '2021-09-01T00:00:00.000Z',
+ deletedAt: null,
__typename: 'ViewField',
},
{
id: '66f134b8-5329-422f-b88e-83e6bb707eb5',
- fieldMetadataId: 'jobTitle',
+ fieldMetadataId: personObjectMetadata?.fields.find(
+ (field) => field.name === 'jobTitle',
+ )?.id,
viewId: mockedViewsData[1].id,
position: 6,
isVisible: true,
size: 150,
createdAt: '2021-09-01T00:00:00.000Z',
updatedAt: '2021-09-01T00:00:00.000Z',
+ deletedAt: null,
__typename: 'ViewField',
},
{
id: '648faa24-cabb-482a-8578-ba3f09906017',
- fieldMetadataId: 'linkedin',
+ fieldMetadataId: personObjectMetadata?.fields.find(
+ (field) => field.name === 'linkedinLink',
+ )?.id,
viewId: mockedViewsData[1].id,
position: 7,
isVisible: true,
size: 150,
createdAt: '2021-09-01T00:00:00.000Z',
updatedAt: '2021-09-01T00:00:00.000Z',
+ deletedAt: null,
__typename: 'ViewField',
},
{
id: '3a9e7f0d-a4ce-4ad5-aac7-3a24eb1a412d',
- fieldMetadataId: 'x',
+ fieldMetadataId: personObjectMetadata?.fields.find(
+ (field) => field.name === 'xLink',
+ )?.id,
viewId: mockedViewsData[1].id,
position: 8,
isVisible: true,
size: 150,
createdAt: '2021-09-01T00:00:00.000Z',
updatedAt: '2021-09-01T00:00:00.000Z',
+ deletedAt: null,
__typename: 'ViewField',
},
// Opportunities
{
id: '35a42e2d-83dd-4b57-ada6-f90616da706d',
- fieldMetadataId: 'amount',
+ fieldMetadataId: opportunityObjectMetadata?.fields.find(
+ (field) => field.name === 'name',
+ )?.id,
viewId: mockedViewsData[2].id,
position: 0,
isVisible: true,
size: 180,
createdAt: '2021-09-01T00:00:00.000Z',
updatedAt: '2021-09-01T00:00:00.000Z',
+ deletedAt: null,
__typename: 'ViewField',
},
{
id: '3159acd8-463f-458d-bf9a-af8ac6f57dc0',
- fieldMetadataId: 'closeDate',
+ fieldMetadataId: opportunityObjectMetadata?.fields.find(
+ (field) => field.name === 'closeDate',
+ )?.id,
viewId: mockedViewsData[2].id,
position: 2,
isVisible: true,
size: 100,
createdAt: '2021-09-01T00:00:00.000Z',
updatedAt: '2021-09-01T00:00:00.000Z',
+ deletedAt: null,
__typename: 'ViewField',
},
{
id: 'afc0819d-b694-4e3c-a2e6-25261aa3ed2c',
- fieldMetadataId: 'company',
+ fieldMetadataId: opportunityObjectMetadata?.fields.find(
+ (field) => field.name === 'company',
+ )?.id,
viewId: mockedViewsData[2].id,
position: 3,
isVisible: true,
size: 150,
createdAt: '2021-09-01T00:00:00.000Z',
updatedAt: '2021-09-01T00:00:00.000Z',
+ deletedAt: null,
__typename: 'ViewField',
},
{
id: 'ec0507bb-aedc-4695-ba96-d81bdeb9db83',
- fieldMetadataId: 'createdAt',
+ fieldMetadataId: opportunityObjectMetadata?.fields.find(
+ (field) => field.name === 'createdAt',
+ )?.id,
viewId: mockedViewsData[2].id,
position: 4,
isVisible: true,
size: 150,
createdAt: '2021-09-01T00:00:00.000Z',
updatedAt: '2021-09-01T00:00:00.000Z',
+ deletedAt: null,
__typename: 'ViewField',
},
{
id: '3f1585f6-44f6-45c5-b840-bc05af5d0008',
- fieldMetadataId: 'pointOfContact',
+ fieldMetadataId: opportunityObjectMetadata?.fields.find(
+ (field) => field.name === 'pointOfContact',
+ )?.id,
viewId: mockedViewsData[2].id,
position: 5,
isVisible: true,
size: 150,
createdAt: '2021-09-01T00:00:00.000Z',
updatedAt: '2021-09-01T00:00:00.000Z',
+ deletedAt: null,
__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 d13c0dc3fdfb..3318e158b4f6 100644
--- a/packages/twenty-front/src/testing/mock-data/views.ts
+++ b/packages/twenty-front/src/testing/mock-data/views.ts
@@ -1,813 +1,22 @@
-import { RecordGqlConnection } from '@/object-record/graphql/types/RecordGqlConnection';
-import { ViewType } from '@/views/types/ViewType';
+import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
-export const viewQueryResultMock: RecordGqlConnection = {
- __typename: 'ViewConnection',
- totalCount: 6,
- pageInfo: {
- __typename: 'PageInfo',
- hasNextPage: false,
- hasPreviousPage: false,
- startCursor: 'WyIyY2M5MGJjZC0wNzkzLTRkMzctYWZlOS1kZTVlY2NmYmFlNzEiXQ==',
- endCursor: 'WyJmZjhlZGQyMi02NjVhLTQ5NWYtODljYy03MGFiOGZkNWMxYTYiXQ==',
- },
- edges: [
- {
- __typename: 'ViewEdge',
- cursor: 'WyIyY2M5MGJjZC0wNzkzLTRkMzctYWZlOS1kZTVlY2NmYmFlNzEiXQ==',
- node: {
- __typename: 'View',
- position: 1,
- updatedAt: '2024-07-11T10:21:33.304Z',
- key: null,
- id: '2cc90bcd-0793-4d37-afe9-de5eccfbae71',
- objectMetadataId: '9c293c05-f461-456a-b5a2-2710b5b30447',
- createdAt: '2024-07-11T10:21:33.304Z',
- icon: 'IconLayoutKanban',
- isCompact: false,
- name: 'By Stage',
- type: 'kanban' as ViewType,
- kanbanFieldMetadataId: 'f74de381-4392-4662-a890-5ed3b5bd847d',
- viewSorts: {
- __typename: 'ViewSortConnection',
- edges: [],
- },
- viewFilters: {
- __typename: 'ViewFilterConnection',
- edges: [],
- },
- viewFields: {
- __typename: 'ViewFieldConnection',
- edges: [
- {
- __typename: 'ViewFieldEdge',
- node: {
- __typename: 'ViewField',
- updatedAt: '2024-07-11T10:21:33.304Z',
- position: 2,
- id: '05ffd5e0-69b0-4774-843a-fbae12231e7d',
- viewId: '2cc90bcd-0793-4d37-afe9-de5eccfbae71',
- createdAt: '2024-07-11T10:21:33.304Z',
- isVisible: true,
- size: 150,
- fieldMetadataId: 'c4e1b90f-bf9a-4a04-b67a-0f88263d8706',
- },
- },
- {
- __typename: 'ViewFieldEdge',
- node: {
- __typename: 'ViewField',
- updatedAt: '2024-07-11T10:21:33.304Z',
- position: 4,
- id: '573ae123-1eed-4671-8fff-d9ac9455b1b4',
- viewId: '2cc90bcd-0793-4d37-afe9-de5eccfbae71',
- createdAt: '2024-07-11T10:21:33.304Z',
- isVisible: true,
- size: 150,
- fieldMetadataId: '6e073ac2-034c-43ab-b0c6-206b1dd1174b',
- },
- },
- {
- __typename: 'ViewFieldEdge',
- node: {
- __typename: 'ViewField',
- updatedAt: '2024-07-11T10:21:33.304Z',
- position: 0,
- id: 'ae4f318f-5059-41ba-b365-22daa0b3cb0e',
- viewId: '2cc90bcd-0793-4d37-afe9-de5eccfbae71',
- createdAt: '2024-07-11T10:21:33.304Z',
- isVisible: true,
- size: 150,
- fieldMetadataId: '4ee7183a-f1f6-42a6-94e5-79f741357760',
- },
- },
- {
- __typename: 'ViewFieldEdge',
- node: {
- __typename: 'ViewField',
- updatedAt: '2024-07-11T10:21:33.304Z',
- position: 1,
- id: 'b5ac37dc-9f64-412f-a598-611bdb5d27f8',
- viewId: '2cc90bcd-0793-4d37-afe9-de5eccfbae71',
- createdAt: '2024-07-11T10:21:33.304Z',
- isVisible: true,
- size: 150,
- fieldMetadataId: '37593700-f3ac-43a2-9ce2-1b811fa3fbfc',
- },
- },
- {
- __typename: 'ViewFieldEdge',
- node: {
- __typename: 'ViewField',
- updatedAt: '2024-07-11T10:21:33.304Z',
- position: 5,
- id: 'bda12277-2962-4b35-a549-665cbbe53483',
- viewId: '2cc90bcd-0793-4d37-afe9-de5eccfbae71',
- createdAt: '2024-07-11T10:21:33.304Z',
- isVisible: true,
- size: 150,
- fieldMetadataId: '031bc747-1787-4e46-9320-562a8b75f3ff',
- },
- },
- {
- __typename: 'ViewFieldEdge',
- node: {
- __typename: 'ViewField',
- updatedAt: '2024-07-11T10:21:33.304Z',
- position: 3,
- id: 'f43e660f-bbf8-4a2f-aeb1-54890ac40f4b',
- viewId: '2cc90bcd-0793-4d37-afe9-de5eccfbae71',
- createdAt: '2024-07-11T10:21:33.304Z',
- isVisible: true,
- size: 150,
- fieldMetadataId: '2cc0fa2b-dbea-4fd0-b7f5-11fa54cd0242',
- },
- },
- ],
- },
- },
- },
- {
- __typename: 'ViewEdge',
- cursor: 'WyI1N2FkYTUyMy0zZDgzLTQzOTEtYThiOS0wZTkxOGUyNGE1MTkiXQ==',
- node: {
- __typename: 'View',
- position: null,
- updatedAt: '2024-07-12T09:52:15.595Z',
- key: 'INDEX',
- id: '57ada523-3d83-4391-a8b9-0e918e24a519',
- objectMetadataId: '3561dbe5-39a2-40fa-a111-4af924e39908',
- createdAt: '2024-07-12T09:52:15.595Z',
- icon: 'IconListNumbers',
- isCompact: false,
- name: 'All Tests',
- type: 'table',
- kanbanFieldMetadataId: '',
- viewSorts: {
- __typename: 'ViewSortConnection',
- edges: [],
- },
- viewFilters: {
- __typename: 'ViewFilterConnection',
- edges: [],
- },
- viewFields: {
- __typename: 'ViewFieldConnection',
- edges: [
- {
- __typename: 'ViewFieldEdge',
- node: {
- __typename: 'ViewField',
- updatedAt: '2024-07-16T12:58:56.823Z',
- position: 2,
- id: '39a026d9-8362-4a4c-9b35-3d23218122a7',
- viewId: '57ada523-3d83-4391-a8b9-0e918e24a519',
- createdAt: '2024-07-16T12:58:56.823Z',
- isVisible: true,
- size: 100,
- fieldMetadataId: '9918f304-99d9-4d5b-8351-c6b6f7cc38bb',
- },
- },
- {
- __typename: 'ViewFieldEdge',
- node: {
- __typename: 'ViewField',
- updatedAt: '2024-07-12T09:52:15.598Z',
- position: 0,
- id: '3ab70930-e60a-4bfd-830a-57355121d889',
- viewId: '57ada523-3d83-4391-a8b9-0e918e24a519',
- createdAt: '2024-07-12T09:52:15.598Z',
- isVisible: true,
- size: 180,
- fieldMetadataId: 'f7f485fc-0c14-4b70-a180-0508699a5c14',
- },
- },
- {
- __typename: 'ViewFieldEdge',
- node: {
- __typename: 'ViewField',
- updatedAt: '2024-07-12T09:52:15.604Z',
- position: 1,
- id: '43ec0b2c-d94f-4eaf-a4bc-f00d409661b5',
- viewId: '57ada523-3d83-4391-a8b9-0e918e24a519',
- createdAt: '2024-07-12T09:52:15.604Z',
- isVisible: true,
- size: 180,
- fieldMetadataId: '66645848-4100-4649-bc0e-d50281df2fd6',
- },
- },
- {
- __typename: 'ViewFieldEdge',
- node: {
- __typename: 'ViewField',
- updatedAt: '2024-07-12T09:52:15.604Z',
- position: 2,
- id: '53f01c19-7042-4551-97d8-d36b6ae28602',
- viewId: '57ada523-3d83-4391-a8b9-0e918e24a519',
- createdAt: '2024-07-12T09:52:15.604Z',
- isVisible: true,
- size: 180,
- fieldMetadataId: '1b3caa7a-343a-4b4b-8c2e-3371cd1dd237',
- },
- },
- {
- __typename: 'ViewFieldEdge',
- node: {
- __typename: 'ViewField',
- updatedAt: '2024-07-16T12:59:52.966Z',
- position: 3,
- id: 'ecbc275e-f937-4d00-b035-6225e6f87c90',
- viewId: '57ada523-3d83-4391-a8b9-0e918e24a519',
- createdAt: '2024-07-16T12:59:46.864Z',
- isVisible: true,
- size: 209,
- fieldMetadataId: '9e3e6ed9-7889-4979-bc15-c7803bf437f1',
- },
- },
- {
- __typename: 'ViewFieldEdge',
- node: {
- __typename: 'ViewField',
- updatedAt: '2024-07-12T09:52:15.605Z',
- position: 3,
- id: 'ed9f32e7-cd08-4bcf-b78f-838371cd282a',
- viewId: '57ada523-3d83-4391-a8b9-0e918e24a519',
- createdAt: '2024-07-12T09:52:15.605Z',
- isVisible: true,
- size: 180,
- fieldMetadataId: 'ffa953c4-d8e0-49af-b2ef-f16e238f4687',
- },
- },
- ],
- },
- },
- },
- {
- __typename: 'ViewEdge',
- cursor: 'WyI1ODJmMjI0Yy0zYzNmLTQxMjctYjFlZC0yOTcxZDI3ZTU0YTQiXQ==',
- node: {
- __typename: 'View',
- position: 0,
- updatedAt: '2024-07-11T10:21:33.304Z',
- key: 'INDEX',
- id: '582f224c-3c3f-4127-b1ed-2971d27e54a4',
- objectMetadataId: '9c293c05-f461-456a-b5a2-2710b5b30447',
- createdAt: '2024-07-11T10:21:33.304Z',
- icon: 'IconTargetArrow',
- isCompact: false,
- name: 'All Opportunities',
- type: 'table',
- kanbanFieldMetadataId: '',
- viewSorts: {
- __typename: 'ViewSortConnection',
- edges: [],
- },
- viewFilters: {
- __typename: 'ViewFilterConnection',
- edges: [],
- },
- viewFields: {
- __typename: 'ViewFieldConnection',
- edges: [
- {
- __typename: 'ViewFieldEdge',
- node: {
- __typename: 'ViewField',
- updatedAt: '2024-07-11T10:21:33.304Z',
- position: 2,
- id: '0f0cacad-7f1d-4667-a0e8-466cddad3e65',
- viewId: '582f224c-3c3f-4127-b1ed-2971d27e54a4',
- createdAt: '2024-07-11T10:21:33.304Z',
- isVisible: true,
- size: 150,
- fieldMetadataId: 'c4e1b90f-bf9a-4a04-b67a-0f88263d8706',
- },
- },
- {
- __typename: 'ViewFieldEdge',
- node: {
- __typename: 'ViewField',
- updatedAt: '2024-07-11T10:21:33.304Z',
- position: 1,
- id: '19d0d674-9825-492d-bbd0-c1de494201dc',
- viewId: '582f224c-3c3f-4127-b1ed-2971d27e54a4',
- createdAt: '2024-07-11T10:21:33.304Z',
- isVisible: true,
- size: 150,
- fieldMetadataId: '37593700-f3ac-43a2-9ce2-1b811fa3fbfc',
- },
- },
- {
- __typename: 'ViewFieldEdge',
- node: {
- __typename: 'ViewField',
- updatedAt: '2024-07-11T10:21:33.304Z',
- position: 5,
- id: '77d6a102-7b8e-40c0-9d53-33e9a8d0df0f',
- viewId: '582f224c-3c3f-4127-b1ed-2971d27e54a4',
- createdAt: '2024-07-11T10:21:33.304Z',
- isVisible: true,
- size: 150,
- fieldMetadataId: '031bc747-1787-4e46-9320-562a8b75f3ff',
- },
- },
- {
- __typename: 'ViewFieldEdge',
- node: {
- __typename: 'ViewField',
- updatedAt: '2024-07-11T10:21:33.304Z',
- position: 4,
- id: '8d1da76d-4056-4675-b2e5-907021c1b482',
- viewId: '582f224c-3c3f-4127-b1ed-2971d27e54a4',
- createdAt: '2024-07-11T10:21:33.304Z',
- isVisible: true,
- size: 150,
- fieldMetadataId: '6e073ac2-034c-43ab-b0c6-206b1dd1174b',
- },
- },
- {
- __typename: 'ViewFieldEdge',
- node: {
- __typename: 'ViewField',
- updatedAt: '2024-07-11T10:21:33.304Z',
- position: 3,
- id: 'a5556adc-e4a0-4f71-aee3-2ff2a4e53b31',
- viewId: '582f224c-3c3f-4127-b1ed-2971d27e54a4',
- createdAt: '2024-07-11T10:21:33.304Z',
- isVisible: true,
- size: 150,
- fieldMetadataId: '2cc0fa2b-dbea-4fd0-b7f5-11fa54cd0242',
- },
- },
- {
- __typename: 'ViewFieldEdge',
- node: {
- __typename: 'ViewField',
- updatedAt: '2024-07-11T10:21:33.304Z',
- position: 0,
- id: 'fa8cdb32-24f0-483d-a9f6-bc92f2704452',
- viewId: '582f224c-3c3f-4127-b1ed-2971d27e54a4',
- createdAt: '2024-07-11T10:21:33.304Z',
- isVisible: true,
- size: 150,
- fieldMetadataId: '4ee7183a-f1f6-42a6-94e5-79f741357760',
- },
- },
- ],
- },
- },
- },
- {
- __typename: 'ViewEdge',
- cursor: 'WyI2NTM3M2UxZS0xNmU1LTRlNWYtOWJjMS1jMDlkOTAxNTZmMjciXQ==',
- node: {
- __typename: 'View',
- position: null,
- updatedAt: '2024-07-11T15:41:08.076Z',
- key: null,
- id: '65373e1e-16e5-4e5f-9bc1-c09d90156f27',
- objectMetadataId: 'b8115dc1-5304-4d22-b300-0b4efda42ebc',
- createdAt: '2024-07-11T15:41:08.076Z',
- icon: 'IconBuildingSkyscraper',
- isCompact: false,
- name: 'All Companies L',
- type: 'kanban',
- kanbanFieldMetadataId: '4ba829d2-c34a-40d0-9ae6-a65d11d2ff5a',
- viewSorts: {
- __typename: 'ViewSortConnection',
- edges: [],
- },
- viewFilters: {
- __typename: 'ViewFilterConnection',
- edges: [],
- },
- viewFields: {
- __typename: 'ViewFieldConnection',
- edges: [
- {
- __typename: 'ViewFieldEdge',
- node: {
- __typename: 'ViewField',
- updatedAt: '2024-07-11T15:41:09.141Z',
- position: 5,
- id: '00bf00d5-f257-4ed0-9a80-ce6d7fa2eace',
- viewId: '65373e1e-16e5-4e5f-9bc1-c09d90156f27',
- createdAt: '2024-07-11T15:41:09.141Z',
- isVisible: true,
- size: 170,
- fieldMetadataId: 'f50611a0-d4b2-49a3-8110-1ca1282ad9c2',
- },
- },
- {
- __typename: 'ViewFieldEdge',
- node: {
- __typename: 'ViewField',
- updatedAt: '2024-07-11T15:41:09.082Z',
- position: 4,
- id: '08ccb08d-d279-4738-bdc0-32a0f9b01390',
- viewId: '65373e1e-16e5-4e5f-9bc1-c09d90156f27',
- createdAt: '2024-07-11T15:41:09.082Z',
- isVisible: true,
- size: 150,
- fieldMetadataId: '2334adb8-a0c5-408e-a449-6730f010aff1',
- },
- },
- {
- __typename: 'ViewFieldEdge',
- node: {
- __typename: 'ViewField',
- updatedAt: '2024-07-11T15:41:09.115Z',
- position: 2,
- id: '478c93ae-1dcc-4d79-b821-b53431348abe',
- viewId: '65373e1e-16e5-4e5f-9bc1-c09d90156f27',
- createdAt: '2024-07-11T15:41:09.115Z',
- isVisible: true,
- size: 150,
- fieldMetadataId: 'be572271-de80-4d55-ae25-6141ec48e1a7',
- },
- },
- {
- __typename: 'ViewFieldEdge',
- node: {
- __typename: 'ViewField',
- updatedAt: '2024-07-11T15:41:09.083Z',
- position: 7,
- id: '4b28e7c9-f97b-4e86-80bf-ca7a1cc49f64',
- viewId: '65373e1e-16e5-4e5f-9bc1-c09d90156f27',
- createdAt: '2024-07-11T15:41:09.083Z',
- isVisible: true,
- size: 180,
- fieldMetadataId: '4ba829d2-c34a-40d0-9ae6-a65d11d2ff5a',
- },
- },
- {
- __typename: 'ViewFieldEdge',
- node: {
- __typename: 'ViewField',
- updatedAt: '2024-07-11T15:41:09.076Z',
- position: 3,
- id: '6402a5db-dc6f-433c-9de3-af19a6d71a28',
- viewId: '65373e1e-16e5-4e5f-9bc1-c09d90156f27',
- createdAt: '2024-07-11T15:41:09.076Z',
- isVisible: true,
- size: 150,
- fieldMetadataId: '04f98129-3433-43f6-a5fa-5ede5314fafd',
- },
- },
- {
- __typename: 'ViewFieldEdge',
- node: {
- __typename: 'ViewField',
- updatedAt: '2024-07-11T15:41:09.141Z',
- position: 1,
- id: '97938fb7-d3a2-42a1-8c04-7ff59d18e41c',
- viewId: '65373e1e-16e5-4e5f-9bc1-c09d90156f27',
- createdAt: '2024-07-11T15:41:09.141Z',
- isVisible: true,
- size: 100,
- fieldMetadataId: '7b76bf52-04ff-4624-9dd5-26ef59be0d88',
- },
- },
- {
- __typename: 'ViewFieldEdge',
- node: {
- __typename: 'ViewField',
- updatedAt: '2024-07-11T15:41:09.129Z',
- position: 0,
- id: 'c7429772-5214-49ee-9d96-c4c9ea929888',
- viewId: '65373e1e-16e5-4e5f-9bc1-c09d90156f27',
- createdAt: '2024-07-11T15:41:09.129Z',
- isVisible: true,
- size: 180,
- fieldMetadataId: '716b202a-7f2f-4d7a-a78a-666db003d94f',
- },
- },
- {
- __typename: 'ViewFieldEdge',
- node: {
- __typename: 'ViewField',
- updatedAt: '2024-07-11T15:41:09.083Z',
- position: 6,
- id: 'ec211171-6676-40d2-acc2-5fa13f11ed00',
- viewId: '65373e1e-16e5-4e5f-9bc1-c09d90156f27',
- createdAt: '2024-07-11T15:41:09.083Z',
- isVisible: true,
- size: 170,
- fieldMetadataId: '479e7d9f-cd8a-4064-b009-65cb89a16c36',
- },
- },
- ],
- },
- },
- },
- {
- __typename: 'ViewEdge',
- cursor: 'WyJiZWU2NWJjNC05YmNiLTQ5YTgtOGVhNS0xYmQ5MjQxYjA5YzMiXQ==',
- node: {
- __typename: 'View',
- position: 0,
- updatedAt: '2024-07-11T10:21:33.304Z',
- key: 'INDEX',
- id: 'bee65bc4-9bcb-49a8-8ea5-1bd9241b09c3',
- objectMetadataId: '48824ee2-367d-481f-b80b-ca1eeb85c4ab',
- createdAt: '2024-07-11T10:21:33.304Z',
- icon: 'IconUser',
- isCompact: false,
- name: 'All People',
- type: 'table',
- kanbanFieldMetadataId: '',
- viewSorts: {
- __typename: 'ViewSortConnection',
- edges: [],
- },
- viewFilters: {
- __typename: 'ViewFilterConnection',
- edges: [],
- },
- viewFields: {
- __typename: 'ViewFieldConnection',
- edges: [
- {
- __typename: 'ViewFieldEdge',
- node: {
- __typename: 'ViewField',
- updatedAt: '2024-07-11T10:21:33.304Z',
- position: 3,
- id: '2dc48490-3ee8-4ade-a979-d5326da33d43',
- viewId: 'bee65bc4-9bcb-49a8-8ea5-1bd9241b09c3',
- createdAt: '2024-07-11T10:21:33.304Z',
- isVisible: true,
- size: 150,
- fieldMetadataId: '34ed07ad-067a-4f5f-bdee-21a37616f96b',
- },
- },
- {
- __typename: 'ViewFieldEdge',
- node: {
- __typename: 'ViewField',
- updatedAt: '2024-07-11T10:21:33.304Z',
- position: 0,
- id: '67af4225-56e0-4ef9-bcfc-4a551d676c2b',
- viewId: 'bee65bc4-9bcb-49a8-8ea5-1bd9241b09c3',
- createdAt: '2024-07-11T10:21:33.304Z',
- isVisible: true,
- size: 210,
- fieldMetadataId: 'c485ed46-3f8a-4ee6-af70-628b9f18ad47',
- },
- },
- {
- __typename: 'ViewFieldEdge',
- node: {
- __typename: 'ViewField',
- updatedAt: '2024-07-11T10:21:33.304Z',
- position: 5,
- id: '796bdd63-cc83-4f8c-b538-9f8e9dfb1937',
- viewId: 'bee65bc4-9bcb-49a8-8ea5-1bd9241b09c3',
- createdAt: '2024-07-11T10:21:33.304Z',
- isVisible: true,
- size: 150,
- fieldMetadataId: '4aadffed-1df4-4732-bb99-559f31a464af',
- },
- },
- {
- __typename: 'ViewFieldEdge',
- node: {
- __typename: 'ViewField',
- updatedAt: '2024-07-11T10:21:33.304Z',
- position: 7,
- id: '80cb1229-5e05-45d4-89da-b2ec850ffb2f',
- viewId: 'bee65bc4-9bcb-49a8-8ea5-1bd9241b09c3',
- createdAt: '2024-07-11T10:21:33.304Z',
- isVisible: true,
- size: 150,
- fieldMetadataId: 'a8298361-b7c8-4b6c-be6c-d33885e00237',
- },
- },
- {
- __typename: 'ViewFieldEdge',
- node: {
- __typename: 'ViewField',
- updatedAt: '2024-07-11T10:21:33.304Z',
- position: 8,
- id: '835b104c-b9fc-4c9f-b659-3dc4bb54d9ef',
- viewId: 'bee65bc4-9bcb-49a8-8ea5-1bd9241b09c3',
- createdAt: '2024-07-11T10:21:33.304Z',
- isVisible: true,
- size: 150,
- fieldMetadataId: '125cbc00-7efb-473d-b0a6-581d3cf868dd',
- },
- },
- {
- __typename: 'ViewFieldEdge',
- node: {
- __typename: 'ViewField',
- updatedAt: '2024-07-11T10:21:33.304Z',
- position: 6,
- id: '8f494c43-6b63-4033-b303-0110698cf19c',
- viewId: 'bee65bc4-9bcb-49a8-8ea5-1bd9241b09c3',
- createdAt: '2024-07-11T10:21:33.304Z',
- isVisible: true,
- size: 150,
- fieldMetadataId: '22566388-8ece-43dc-8205-371e662716d4',
- },
- },
- {
- __typename: 'ViewFieldEdge',
- node: {
- __typename: 'ViewField',
- updatedAt: '2024-07-11T10:21:33.304Z',
- position: 4,
- id: 'b2d72e77-a323-4e2e-acef-598b6da04712',
- viewId: 'bee65bc4-9bcb-49a8-8ea5-1bd9241b09c3',
- createdAt: '2024-07-11T10:21:33.304Z',
- isVisible: true,
- size: 150,
- fieldMetadataId: 'b328512c-ff13-431b-9c94-1018ef0bd53c',
- },
- },
- {
- __typename: 'ViewFieldEdge',
- node: {
- __typename: 'ViewField',
- updatedAt: '2024-07-11T10:21:33.304Z',
- position: 1,
- id: 'c7e1a253-9af8-498a-b579-adab742acf2d',
- viewId: 'bee65bc4-9bcb-49a8-8ea5-1bd9241b09c3',
- createdAt: '2024-07-11T10:21:33.304Z',
- isVisible: true,
- size: 150,
- fieldMetadataId: '2eb50615-376c-45e8-b99b-440a92a912d3',
- },
- },
- {
- __typename: 'ViewFieldEdge',
- node: {
- __typename: 'ViewField',
- updatedAt: '2024-07-11T10:21:33.304Z',
- position: 2,
- id: 'cceae812-2687-49b5-a0c8-eb59956865e8',
- viewId: 'bee65bc4-9bcb-49a8-8ea5-1bd9241b09c3',
- createdAt: '2024-07-11T10:21:33.304Z',
- isVisible: true,
- size: 150,
- fieldMetadataId: 'f34c04f8-ce2f-4c92-8dbc-9166c6e0d49f',
- },
- },
- ],
- },
- },
- },
- {
- __typename: 'ViewEdge',
- cursor: 'WyJmZjhlZGQyMi02NjVhLTQ5NWYtODljYy03MGFiOGZkNWMxYTYiXQ==',
- node: {
- __typename: 'View',
- position: 0,
- updatedAt: '2024-07-11T10:21:33.304Z',
- key: 'INDEX',
- id: 'ff8edd22-665a-495f-89cc-70ab8fd5c1a6',
- objectMetadataId: 'b8115dc1-5304-4d22-b300-0b4efda42ebc',
- createdAt: '2024-07-11T10:21:33.304Z',
- icon: 'IconBuildingSkyscraper',
- isCompact: false,
- name: 'All Companies',
- type: 'table',
- kanbanFieldMetadataId: '',
- viewSorts: {
- __typename: 'ViewSortConnection',
- edges: [],
- },
- viewFilters: {
- __typename: 'ViewFilterConnection',
- edges: [],
- },
- viewFields: {
- __typename: 'ViewFieldConnection',
- edges: [
- {
- __typename: 'ViewFieldEdge',
- node: {
- __typename: 'ViewField',
- updatedAt: '2024-07-11T10:21:33.304Z',
- position: 3,
- id: '1cb6aeed-8011-495f-9371-20bace45814a',
- viewId: 'ff8edd22-665a-495f-89cc-70ab8fd5c1a6',
- createdAt: '2024-07-11T10:21:33.304Z',
- isVisible: true,
- size: 150,
- fieldMetadataId: '04f98129-3433-43f6-a5fa-5ede5314fafd',
- },
- },
- {
- __typename: 'ViewFieldEdge',
- node: {
- __typename: 'ViewField',
- updatedAt: '2024-07-11T10:21:33.304Z',
- position: 6,
- id: '3beb2130-bdc5-48d1-8cd0-22c5d0010ad2',
- viewId: 'ff8edd22-665a-495f-89cc-70ab8fd5c1a6',
- createdAt: '2024-07-11T10:21:33.304Z',
- isVisible: true,
- size: 170,
- fieldMetadataId: '479e7d9f-cd8a-4064-b009-65cb89a16c36',
- },
- },
- {
- __typename: 'ViewFieldEdge',
- node: {
- __typename: 'ViewField',
- updatedAt: '2024-07-11T10:21:33.304Z',
- position: 4,
- id: '5f73729b-9592-473a-8742-8e52b693c780',
- viewId: 'ff8edd22-665a-495f-89cc-70ab8fd5c1a6',
- createdAt: '2024-07-11T10:21:33.304Z',
- isVisible: true,
- size: 150,
- fieldMetadataId: '2334adb8-a0c5-408e-a449-6730f010aff1',
- },
- },
- {
- __typename: 'ViewFieldEdge',
- node: {
- __typename: 'ViewField',
- updatedAt: '2024-07-11T15:41:03.814Z',
- position: 7,
- id: '788627cb-0d3a-4659-ab4b-69deabf02f27',
- viewId: 'ff8edd22-665a-495f-89cc-70ab8fd5c1a6',
- createdAt: '2024-07-11T15:41:03.814Z',
- isVisible: true,
- size: 180,
- fieldMetadataId: '4ba829d2-c34a-40d0-9ae6-a65d11d2ff5a',
- },
- },
- {
- __typename: 'ViewFieldEdge',
- node: {
- __typename: 'ViewField',
- updatedAt: '2024-07-11T10:21:33.304Z',
- position: 2,
- id: 'ac5797a1-2d29-42d2-b9fb-d679a945eec5',
- viewId: 'ff8edd22-665a-495f-89cc-70ab8fd5c1a6',
- createdAt: '2024-07-11T10:21:33.304Z',
- isVisible: true,
- size: 150,
- fieldMetadataId: 'be572271-de80-4d55-ae25-6141ec48e1a7',
- },
- },
- {
- __typename: 'ViewFieldEdge',
- node: {
- __typename: 'ViewField',
- updatedAt: '2024-07-11T10:21:33.304Z',
- position: 0,
- id: 'ae98037e-38f7-4fbf-8ae1-c0b6754c6311',
- viewId: 'ff8edd22-665a-495f-89cc-70ab8fd5c1a6',
- createdAt: '2024-07-11T10:21:33.304Z',
- isVisible: true,
- size: 180,
- fieldMetadataId: '716b202a-7f2f-4d7a-a78a-666db003d94f',
- },
- },
- {
- __typename: 'ViewFieldEdge',
- node: {
- __typename: 'ViewField',
- updatedAt: '2024-07-11T10:21:33.304Z',
- position: 5,
- id: 'b4d9f94e-0c4b-4422-839a-f2ceb293fde1',
- viewId: 'ff8edd22-665a-495f-89cc-70ab8fd5c1a6',
- createdAt: '2024-07-11T10:21:33.304Z',
- isVisible: true,
- size: 170,
- fieldMetadataId: 'f50611a0-d4b2-49a3-8110-1ca1282ad9c2',
- },
- },
- {
- __typename: 'ViewFieldEdge',
- node: {
- __typename: 'ViewField',
- updatedAt: '2024-07-11T10:21:33.304Z',
- position: 1,
- id: 'd45b1412-ff6b-41e5-86df-0fb778033bb3',
- viewId: 'ff8edd22-665a-495f-89cc-70ab8fd5c1a6',
- createdAt: '2024-07-11T10:21:33.304Z',
- isVisible: true,
- size: 100,
- fieldMetadataId: '7b76bf52-04ff-4624-9dd5-26ef59be0d88',
- },
- },
- ],
- },
- },
- },
- ],
-};
+const companyObjectMetadata = generatedMockObjectMetadataItems.find(
+ (item) => item.nameSingular === 'company',
+);
+
+const personObjectMetadata = generatedMockObjectMetadataItems.find(
+ (item) => item.nameSingular === 'person',
+);
+
+const opportunityObjectMetadata = generatedMockObjectMetadataItems.find(
+ (item) => item.nameSingular === 'opportunity',
+);
export const mockedViewsData = [
{
id: '37a8a866-eb17-4e76-9382-03143a2f6a80',
name: 'All companies',
- objectMetadataId: '701aecf9-eb1c-4d84-9d94-b954b231b64b',
+ objectMetadataId: companyObjectMetadata?.id,
type: 'table',
icon: 'IconSkyline',
key: 'INDEX',
@@ -822,7 +31,7 @@ export const mockedViewsData = [
{
id: '6095799e-b48f-4e00-b071-10818083593a',
name: 'All people',
- objectMetadataId: 'person',
+ objectMetadataId: personObjectMetadata?.id,
type: 'table',
icon: 'IconPerson',
key: 'INDEX',
@@ -836,7 +45,7 @@ export const mockedViewsData = [
{
id: 'e26f66b7-f890-4a5c-b4d2-ec09987b5308',
name: 'All opportunities',
- objectMetadataId: 'company',
+ objectMetadataId: opportunityObjectMetadata?.id,
type: 'kanban',
icon: 'IconOpportunity',
key: 'INDEX',
@@ -850,7 +59,7 @@ export const mockedViewsData = [
{
id: '5c307222-1dd5-4ff3-ab06-8d990e9b3c74',
name: 'All companies (v2)',
- objectMetadataId: '701aecf9-eb1c-4d84-9d94-b954b231b64b',
+ objectMetadataId: companyObjectMetadata?.id,
type: 'table',
icon: 'IconSkyline',
key: 'INDEX',
diff --git a/packages/twenty-front/src/utils/__tests__/cast-as-integer-or-null.test.ts b/packages/twenty-front/src/utils/__tests__/cast-as-integer-or-null.test.ts
deleted file mode 100644
index cc077afdb27c..000000000000
--- a/packages/twenty-front/src/utils/__tests__/cast-as-integer-or-null.test.ts
+++ /dev/null
@@ -1,72 +0,0 @@
-import {
- canBeCastAsIntegerOrNull,
- castAsIntegerOrNull,
-} from '../cast-as-integer-or-null';
-
-describe('canBeCastAsIntegerOrNull', () => {
- it(`should return true if null`, () => {
- expect(canBeCastAsIntegerOrNull(null)).toBeTruthy();
- });
-
- it(`should return true if number`, () => {
- expect(canBeCastAsIntegerOrNull(9)).toBeTruthy();
- });
-
- it(`should return true if empty string`, () => {
- expect(canBeCastAsIntegerOrNull('')).toBeTruthy();
- });
-
- it(`should return true if integer string`, () => {
- expect(canBeCastAsIntegerOrNull('9')).toBeTruthy();
- });
-
- it(`should return false if undefined`, () => {
- expect(canBeCastAsIntegerOrNull(undefined)).toBeFalsy();
- });
-
- it(`should return false if non numeric string`, () => {
- expect(canBeCastAsIntegerOrNull('9a')).toBeFalsy();
- });
-
- it(`should return false if non numeric string #2`, () => {
- expect(canBeCastAsIntegerOrNull('a9a')).toBeFalsy();
- });
-
- it(`should return false if float`, () => {
- expect(canBeCastAsIntegerOrNull(0.9)).toBeFalsy();
- });
-
- it(`should return false if float string`, () => {
- expect(canBeCastAsIntegerOrNull('0.9')).toBeFalsy();
- });
-});
-
-describe('castAsIntegerOrNull', () => {
- it(`should cast null to null`, () => {
- expect(castAsIntegerOrNull(null)).toBe(null);
- });
-
- it(`should cast empty string to null`, () => {
- expect(castAsIntegerOrNull('')).toBe(null);
- });
-
- it(`should cast an integer to an integer`, () => {
- expect(castAsIntegerOrNull(9)).toBe(9);
- });
-
- it(`should cast an integer string to an integer`, () => {
- expect(castAsIntegerOrNull('9')).toBe(9);
- });
-
- it(`should throw if trying to cast a float string to an integer`, () => {
- expect(() => castAsIntegerOrNull('9.9')).toThrow(Error);
- });
-
- it(`should throw if trying to cast a non numeric string to an integer`, () => {
- expect(() => castAsIntegerOrNull('9.9a')).toThrow(Error);
- });
-
- it(`should throw if trying to cast an undefined to an integer`, () => {
- expect(() => castAsIntegerOrNull(undefined)).toThrow(Error);
- });
-});
diff --git a/packages/twenty-front/src/utils/__tests__/cast-as-number-or-null.test.ts b/packages/twenty-front/src/utils/__tests__/cast-as-number-or-null.test.ts
new file mode 100644
index 000000000000..082527de7ec7
--- /dev/null
+++ b/packages/twenty-front/src/utils/__tests__/cast-as-number-or-null.test.ts
@@ -0,0 +1,72 @@
+import {
+ canBeCastAsNumberOrNull,
+ castAsNumberOrNull,
+} from '../cast-as-number-or-null';
+
+describe('canBeCastAsNumberOrNull', () => {
+ it(`should return true if null`, () => {
+ expect(canBeCastAsNumberOrNull(null)).toBeTruthy();
+ });
+
+ it(`should return true if number`, () => {
+ expect(canBeCastAsNumberOrNull(9)).toBeTruthy();
+ });
+
+ it(`should return true if empty string`, () => {
+ expect(canBeCastAsNumberOrNull('')).toBeTruthy();
+ });
+
+ it(`should return true if integer string`, () => {
+ expect(canBeCastAsNumberOrNull('9')).toBeTruthy();
+ });
+
+ it(`should return false if undefined`, () => {
+ expect(canBeCastAsNumberOrNull(undefined)).toBeFalsy();
+ });
+
+ it(`should return false if non numeric string`, () => {
+ expect(canBeCastAsNumberOrNull('9a')).toBeFalsy();
+ });
+
+ it(`should return false if non numeric string #2`, () => {
+ expect(canBeCastAsNumberOrNull('a9a')).toBeFalsy();
+ });
+
+ it(`should return true if float`, () => {
+ expect(canBeCastAsNumberOrNull(0.9)).toBeTruthy();
+ });
+
+ it(`should return true if float string`, () => {
+ expect(canBeCastAsNumberOrNull('0.9')).toBeTruthy();
+ });
+});
+
+describe('castAsNumberOrNull', () => {
+ it(`should cast null to null`, () => {
+ expect(castAsNumberOrNull(null)).toBe(null);
+ });
+
+ it(`should cast empty string to null`, () => {
+ expect(castAsNumberOrNull('')).toBe(null);
+ });
+
+ it(`should cast an integer to an integer`, () => {
+ expect(castAsNumberOrNull(9)).toBe(9);
+ });
+
+ it(`should cast an integer string to an integer`, () => {
+ expect(castAsNumberOrNull('9')).toBe(9);
+ });
+
+ it(`should throw if trying to cast a float string to an integer`, () => {
+ expect(castAsNumberOrNull('9.9')).toBe(9.9);
+ });
+
+ it(`should throw if trying to cast a non numeric string to an integer`, () => {
+ expect(() => castAsNumberOrNull('9.9a')).toThrow(Error);
+ });
+
+ it(`should throw if trying to cast an undefined to an integer`, () => {
+ expect(() => castAsNumberOrNull(undefined)).toThrow(Error);
+ });
+});
diff --git a/packages/twenty-front/src/utils/cast-as-integer-or-null.ts b/packages/twenty-front/src/utils/cast-as-number-or-null.ts
similarity index 82%
rename from packages/twenty-front/src/utils/cast-as-integer-or-null.ts
rename to packages/twenty-front/src/utils/cast-as-number-or-null.ts
index 5cca0021dead..ef06e5b5a33e 100644
--- a/packages/twenty-front/src/utils/cast-as-integer-or-null.ts
+++ b/packages/twenty-front/src/utils/cast-as-number-or-null.ts
@@ -4,7 +4,7 @@ import { logError } from './logError';
const DEBUG_MODE = false;
-export const canBeCastAsIntegerOrNull = (
+export const canBeCastAsNumberOrNull = (
probableNumberOrNull: string | undefined | number | null,
): probableNumberOrNull is number | null => {
if (probableNumberOrNull === undefined) {
@@ -16,7 +16,7 @@ export const canBeCastAsIntegerOrNull = (
if (isNumber(probableNumberOrNull)) {
if (DEBUG_MODE) logError('typeof probableNumberOrNull === "number"');
- return Number.isInteger(probableNumberOrNull);
+ return true;
}
if (isNull(probableNumberOrNull)) {
@@ -39,8 +39,8 @@ export const canBeCastAsIntegerOrNull = (
return false;
}
- if (Number.isInteger(stringAsNumber)) {
- if (DEBUG_MODE) logError('Number.isInteger(stringAsNumber)');
+ if (isNumber(stringAsNumber)) {
+ if (DEBUG_MODE) logError('isNumber(stringAsNumber)');
return true;
}
@@ -49,10 +49,10 @@ export const canBeCastAsIntegerOrNull = (
return false;
};
-export const castAsIntegerOrNull = (
+export const castAsNumberOrNull = (
probableNumberOrNull: string | undefined | number | null,
): number | null => {
- if (canBeCastAsIntegerOrNull(probableNumberOrNull) === false) {
+ if (canBeCastAsNumberOrNull(probableNumberOrNull) === false) {
throw new Error('Cannot cast to number or null');
}
diff --git a/packages/twenty-front/src/utils/format/__tests__/number.test.ts b/packages/twenty-front/src/utils/format/__tests__/number.test.ts
index 37237e03dd53..8b2f6687f8f1 100644
--- a/packages/twenty-front/src/utils/format/__tests__/number.test.ts
+++ b/packages/twenty-front/src/utils/format/__tests__/number.test.ts
@@ -6,12 +6,15 @@ describe('formatNumber', () => {
expect(formatNumber(123)).toEqual('123');
});
it(`Should format decimal numbers correctly`, () => {
- expect(formatNumber(123.92)).toEqual('123.92');
+ expect(formatNumber(123.92, 2)).toEqual('123.92');
});
it(`Should format large numbers correctly`, () => {
expect(formatNumber(1234567)).toEqual('1,234,567');
});
it(`Should format large numbers with a decimal point correctly`, () => {
- expect(formatNumber(7654321.89)).toEqual('7,654,321.89');
+ expect(formatNumber(7654321.89, 2)).toEqual('7,654,321.89');
+ });
+ it('should format apply decimals correctly', () => {
+ expect(formatNumber(123.456, 2)).toEqual('123.46');
});
});
diff --git a/packages/twenty-front/src/utils/format/number.ts b/packages/twenty-front/src/utils/format/number.ts
index 4937372d0cbd..a36cb6fffad8 100644
--- a/packages/twenty-front/src/utils/format/number.ts
+++ b/packages/twenty-front/src/utils/format/number.ts
@@ -1,2 +1,8 @@
-export const formatNumber = (value: number): string =>
- value.toLocaleString('en-US');
+export const DEFAULT_DECIMAL_VALUE = 0;
+
+export const formatNumber = (value: number, decimals?: number): string => {
+ return value.toLocaleString('en-US', {
+ minimumFractionDigits: decimals ?? DEFAULT_DECIMAL_VALUE,
+ maximumFractionDigits: decimals ?? DEFAULT_DECIMAL_VALUE,
+ });
+};
diff --git a/packages/twenty-server/jest.config.ts b/packages/twenty-server/jest.config.ts
index 00c1b6f06fdb..f25c9e66dcca 100644
--- a/packages/twenty-server/jest.config.ts
+++ b/packages/twenty-server/jest.config.ts
@@ -7,7 +7,7 @@ const jestConfig: JestConfigWithTsJest = {
displayName: 'twenty-server',
rootDir: './',
testEnvironment: 'node',
- transformIgnorePatterns: ['../../node_modules/'],
+ transformIgnorePatterns: ['/node_modules/'],
testRegex: '.*\\.spec\\.ts$',
transform: {
'^.+\\.(t|j)s$': 'ts-jest',
diff --git a/packages/twenty-server/package.json b/packages/twenty-server/package.json
index dde92f42a8da..d5c8f91b9c69 100644
--- a/packages/twenty-server/package.json
+++ b/packages/twenty-server/package.json
@@ -1,6 +1,6 @@
{
"name": "twenty-server",
- "version": "0.31.canary",
+ "version": "0.31.0-canary",
"description": "",
"author": "",
"private": true,
diff --git a/packages/twenty-server/project.json b/packages/twenty-server/project.json
index a31ff4fb101f..ed8ad716b6e0 100644
--- a/packages/twenty-server/project.json
+++ b/packages/twenty-server/project.json
@@ -77,6 +77,14 @@
"options": {
"cwd": "packages/twenty-server",
"command": "node dist/src/queue-worker/queue-worker.js"
+ },
+ "configurations": {
+ "ci": {
+ "env": {
+ "MESSAGE_QUEUE_TYPE": "sync",
+ "CACHE_STORAGE_TYPE": "memory"
+ }
+ }
}
},
"typeorm": {
diff --git a/packages/twenty-server/src/constants/assets-path.ts b/packages/twenty-server/src/constants/assets-path.ts
index 44c7724db0b8..04766287433a 100644
--- a/packages/twenty-server/src/constants/assets-path.ts
+++ b/packages/twenty-server/src/constants/assets-path.ts
@@ -1,3 +1,8 @@
import path from 'path';
-export const ASSET_PATH = path.resolve(__dirname, `../../assets`);
+// If the code is built through the testing module, assets are not output to the dist/assets directory.
+const IS_BUILT_THROUGH_TESTING_MODULE = !__dirname.includes('/dist/');
+
+export const ASSET_PATH = IS_BUILT_THROUGH_TESTING_MODULE
+ ? path.resolve(__dirname, `../`)
+ : path.resolve(__dirname, `../../assets`);
diff --git a/packages/twenty-server/src/database/typeorm-seeds/metadata/fieldsMetadata.ts b/packages/twenty-server/src/database/typeorm-seeds/metadata/fieldsMetadata.ts
index 330975f00d02..cf605a51244e 100644
--- a/packages/twenty-server/src/database/typeorm-seeds/metadata/fieldsMetadata.ts
+++ b/packages/twenty-server/src/database/typeorm-seeds/metadata/fieldsMetadata.ts
@@ -104,7 +104,7 @@ export const getDevSeedPeopleCustomFields = (
{
workspaceId,
type: FieldMetadataType.MULTI_SELECT,
- name: 'workPrefereance',
+ name: 'workPreference',
label: 'Work Preference',
description: "Person's Work Preference",
icon: 'IconHome',
diff --git a/packages/twenty-server/src/database/typeorm/metadata/migrations/1726848397026-addTypeOrmMetadata.ts b/packages/twenty-server/src/database/typeorm/core/migrations/1726848397026-addTypeOrmMetadata.ts
similarity index 100%
rename from packages/twenty-server/src/database/typeorm/metadata/migrations/1726848397026-addTypeOrmMetadata.ts
rename to packages/twenty-server/src/database/typeorm/core/migrations/1726848397026-addTypeOrmMetadata.ts
diff --git a/packages/twenty-server/src/database/typeorm/metadata/migrations/1725893697807-addIndexType.ts b/packages/twenty-server/src/database/typeorm/metadata/migrations/1725893697807-addIndexType.ts
index 41edac1a5990..59a1828627ea 100644
--- a/packages/twenty-server/src/database/typeorm/metadata/migrations/1725893697807-addIndexType.ts
+++ b/packages/twenty-server/src/database/typeorm/metadata/migrations/1725893697807-addIndexType.ts
@@ -5,12 +5,12 @@ export class AddIndexType1725893697807 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise {
await queryRunner.query(
- `CREATE TYPE metadata."indextype_enum" AS ENUM ('BTREE', 'GIN')`,
+ `CREATE TYPE "metadata"."indexMetadata_indextype_enum" AS ENUM('BTREE', 'GIN')`,
);
await queryRunner.query(`
ALTER TABLE metadata."indexMetadata"
- ADD COLUMN "indexType" metadata."indextype_enum" NOT NULL DEFAULT 'BTREE';
+ ADD COLUMN "indexType" metadata."indexMetadata_indextype_enum" NOT NULL DEFAULT 'BTREE';
`);
}
@@ -19,6 +19,8 @@ export class AddIndexType1725893697807 implements MigrationInterface {
ALTER TABLE metadata."indexMetadata" DROP COLUMN "indexType"
`);
- await queryRunner.query(`DROP TYPE metadata."indextype_enum"`);
+ await queryRunner.query(
+ `DROP TYPE metadata."indexMetadata_indextype_enum"`,
+ );
}
}
diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/factories/graphql-query-resolver.factory.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/factories/graphql-query-resolver.factory.ts
new file mode 100644
index 000000000000..ca2506d18aa9
--- /dev/null
+++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/factories/graphql-query-resolver.factory.ts
@@ -0,0 +1,51 @@
+import { Injectable } from '@nestjs/common';
+import { ModuleRef } from '@nestjs/core';
+
+import { ResolverService } from 'src/engine/api/graphql/graphql-query-runner/interfaces/resolver-service.interface';
+import {
+ ResolverArgs,
+ WorkspaceResolverBuilderMethodNames,
+} from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
+
+import { GraphqlQueryCreateManyResolverService } from 'src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-create-many-resolver.service';
+import { GraphqlQueryDestroyOneResolverService } from 'src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-destroy-one-resolver.service';
+import { GraphqlQueryFindDuplicatesResolverService } from 'src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-find-duplicates-resolver.service';
+import { GraphqlQueryFindManyResolverService } from 'src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-find-many-resolver.service';
+import { GraphqlQueryFindOneResolverService } from 'src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-find-one-resolver.service';
+import { GraphqlQuerySearchResolverService } from 'src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-search-resolver.service';
+import { GraphqlQueryUpdateManyResolverService } from 'src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-update-many-resolver.service';
+import { GraphqlQueryUpdateOneResolverService } from 'src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-update-one-resolver.service';
+
+@Injectable()
+export class GraphqlQueryResolverFactory {
+ constructor(private moduleRef: ModuleRef) {}
+
+ public getResolver(
+ operationName: WorkspaceResolverBuilderMethodNames,
+ ): ResolverService {
+ switch (operationName) {
+ case 'findOne':
+ return this.moduleRef.get(GraphqlQueryFindOneResolverService);
+ case 'findMany':
+ return this.moduleRef.get(GraphqlQueryFindManyResolverService);
+ case 'findDuplicates':
+ return this.moduleRef.get(GraphqlQueryFindDuplicatesResolverService);
+ case 'search':
+ return this.moduleRef.get(GraphqlQuerySearchResolverService);
+ case 'createOne':
+ case 'createMany':
+ return this.moduleRef.get(GraphqlQueryCreateManyResolverService);
+ case 'destroyOne':
+ return this.moduleRef.get(GraphqlQueryDestroyOneResolverService);
+ case 'updateOne':
+ case 'deleteOne':
+ return this.moduleRef.get(GraphqlQueryUpdateOneResolverService);
+ case 'updateMany':
+ case 'deleteMany':
+ case 'restoreMany':
+ return this.moduleRef.get(GraphqlQueryUpdateManyResolverService);
+ default:
+ throw new Error(`Unsupported operation: ${operationName}`);
+ }
+ }
+}
diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query-filter/graphql-query-filter-condition.parser.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query-filter/graphql-query-filter-condition.parser.ts
index 093364db8479..21f9bdbdccb0 100644
--- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query-filter/graphql-query-filter-condition.parser.ts
+++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query-filter/graphql-query-filter-condition.parser.ts
@@ -25,7 +25,7 @@ export class GraphqlQueryFilterConditionParser {
public parse(
queryBuilder: SelectQueryBuilder,
objectNameSingular: string,
- filter: RecordFilter,
+ filter: Partial,
): SelectQueryBuilder {
if (!filter || Object.keys(filter).length === 0) {
return queryBuilder;
diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query-filter/graphql-query-filter-field.parser.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query-filter/graphql-query-filter-field.parser.ts
index fe37c4d445da..920fa01c56d6 100644
--- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query-filter/graphql-query-filter-field.parser.ts
+++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query-filter/graphql-query-filter-field.parser.ts
@@ -58,7 +58,6 @@ export class GraphqlQueryFilterFieldParser {
}
const { sql, params } = this.computeWhereConditionParts(
- fieldMetadata,
operator,
objectNameSingular,
key,
@@ -73,7 +72,6 @@ export class GraphqlQueryFilterFieldParser {
}
private computeWhereConditionParts(
- fieldMetadata: FieldMetadataInterface,
operator: string,
objectNameSingular: string,
key: string,
@@ -185,7 +183,6 @@ export class GraphqlQueryFilterFieldParser {
);
const { sql, params } = this.computeWhereConditionParts(
- fieldMetadata,
operator,
objectNameSingular,
fullFieldName,
diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query.parser.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query.parser.ts
index d83667211bd0..0aa047fc31f7 100644
--- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query.parser.ts
+++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query.parser.ts
@@ -9,7 +9,6 @@ import {
RecordFilter,
RecordOrderBy,
} from 'src/engine/api/graphql/workspace-query-builder/interfaces/record.interface';
-import { ObjectMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/object-metadata.interface';
import { GraphqlQueryFilterConditionParser } from 'src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query-filter/graphql-query-filter-condition.parser';
import { GraphqlQueryOrderFieldParser } from 'src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query-order/graphql-query-order.parser';
@@ -17,6 +16,7 @@ import { GraphqlQuerySelectedFieldsParser } from 'src/engine/api/graphql/graphql
import {
FieldMetadataMap,
ObjectMetadataMap,
+ ObjectMetadataMapItem,
} from 'src/engine/metadata-modules/utils/generate-object-metadata-map.util';
export class GraphqlQueryParser {
@@ -39,10 +39,10 @@ export class GraphqlQueryParser {
);
}
- applyFilterToBuilder(
+ public applyFilterToBuilder(
queryBuilder: SelectQueryBuilder,
objectNameSingular: string,
- recordFilter: RecordFilter,
+ recordFilter: Partial,
): SelectQueryBuilder {
return this.filterConditionParser.parse(
queryBuilder,
@@ -51,7 +51,7 @@ export class GraphqlQueryParser {
);
}
- applyDeletedAtToBuilder(
+ public applyDeletedAtToBuilder(
queryBuilder: SelectQueryBuilder,
recordFilter: RecordFilter,
): SelectQueryBuilder {
@@ -88,7 +88,7 @@ export class GraphqlQueryParser {
return false;
};
- applyOrderToBuilder(
+ public applyOrderToBuilder(
queryBuilder: SelectQueryBuilder,
orderBy: RecordOrderBy,
objectNameSingular: string,
@@ -103,8 +103,8 @@ export class GraphqlQueryParser {
return queryBuilder.orderBy(parsedOrderBys as OrderByCondition);
}
- parseSelectedFields(
- parentObjectMetadata: ObjectMetadataInterface,
+ public parseSelectedFields(
+ parentObjectMetadata: ObjectMetadataMapItem,
graphqlSelectedFields: Partial>,
): { select: Record; relations: Record } {
const parentFields =
diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/graphql-query-runner.module.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/graphql-query-runner.module.ts
index 28cb362ca3f0..8c689ff8a979 100644
--- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/graphql-query-runner.module.ts
+++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/graphql-query-runner.module.ts
@@ -1,16 +1,43 @@
import { Module } from '@nestjs/common';
+import { GraphqlQueryResolverFactory } from 'src/engine/api/graphql/graphql-query-runner/factories/graphql-query-resolver.factory';
import { GraphqlQueryRunnerService } from 'src/engine/api/graphql/graphql-query-runner/graphql-query-runner.service';
+import { GraphqlQueryCreateManyResolverService } from 'src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-create-many-resolver.service';
+import { GraphqlQueryDestroyOneResolverService } from 'src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-destroy-one-resolver.service';
+import { GraphqlQueryFindDuplicatesResolverService } from 'src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-find-duplicates-resolver.service';
+import { GraphqlQueryFindManyResolverService } from 'src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-find-many-resolver.service';
+import { GraphqlQueryFindOneResolverService } from 'src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-find-one-resolver.service';
+import { GraphqlQuerySearchResolverService } from 'src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-search-resolver.service';
+import { GraphqlQueryUpdateManyResolverService } from 'src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-update-many-resolver.service';
+import { GraphqlQueryUpdateOneResolverService } from 'src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-update-one-resolver.service';
+import { ApiEventEmitterService } from 'src/engine/api/graphql/graphql-query-runner/services/api-event-emitter.service';
import { WorkspaceQueryHookModule } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook.module';
import { WorkspaceQueryRunnerModule } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-runner.module';
import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module';
+
+const graphqlQueryResolvers = [
+ GraphqlQueryFindOneResolverService,
+ GraphqlQueryFindManyResolverService,
+ GraphqlQueryFindDuplicatesResolverService,
+ GraphqlQueryCreateManyResolverService,
+ GraphqlQueryDestroyOneResolverService,
+ GraphqlQueryUpdateOneResolverService,
+ GraphqlQueryUpdateManyResolverService,
+ GraphqlQuerySearchResolverService,
+];
+
@Module({
imports: [
WorkspaceQueryHookModule,
WorkspaceQueryRunnerModule,
FeatureFlagModule,
],
- providers: [GraphqlQueryRunnerService],
+ providers: [
+ GraphqlQueryRunnerService,
+ GraphqlQueryResolverFactory,
+ ApiEventEmitterService,
+ ...graphqlQueryResolvers,
+ ],
exports: [GraphqlQueryRunnerService],
})
export class GraphqlQueryRunnerModule {}
diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/graphql-query-runner.service.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/graphql-query-runner.service.ts
index 8c866695b6ad..4e3475927ecd 100644
--- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/graphql-query-runner.service.ts
+++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/graphql-query-runner.service.ts
@@ -6,285 +6,377 @@ import {
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 { IEdge } from 'src/engine/api/graphql/workspace-query-runner/interfaces/edge.interface';
import { WorkspaceQueryRunnerOptions } from 'src/engine/api/graphql/workspace-query-runner/interfaces/query-runner-option.interface';
import {
CreateManyResolverArgs,
CreateOneResolverArgs,
+ DeleteManyResolverArgs,
+ DeleteOneResolverArgs,
DestroyOneResolverArgs,
+ FindDuplicatesResolverArgs,
FindManyResolverArgs,
FindOneResolverArgs,
+ ResolverArgs,
ResolverArgsType,
+ RestoreManyResolverArgs,
SearchResolverArgs,
+ UpdateManyResolverArgs,
+ UpdateOneResolverArgs,
+ WorkspaceResolverBuilderMethodNames,
} 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 { GraphqlQueryCreateManyResolverService } from 'src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-create-many-resolver.service';
-import { GraphqlQueryDestroyOneResolverService } from 'src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-destroy-one-resolver.service';
-import { GraphqlQueryFindManyResolverService } from 'src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-find-many-resolver.service';
-import { GraphqlQueryFindOneResolverService } from 'src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-find-one-resolver.service';
-import { GraphqlQuerySearchResolverService } from 'src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-search-resolver.service';
+import { GraphqlQueryResolverFactory } from 'src/engine/api/graphql/graphql-query-runner/factories/graphql-query-resolver.factory';
+import { ApiEventEmitterService } from 'src/engine/api/graphql/graphql-query-runner/services/api-event-emitter.service';
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 { WorkspaceQueryHookService } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook.service';
-import {
- WorkspaceQueryRunnerException,
- WorkspaceQueryRunnerExceptionCode,
-} from 'src/engine/api/graphql/workspace-query-runner/workspace-query-runner.exception';
-import { AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type';
-import { ObjectRecordCreateEvent } from 'src/engine/core-modules/event-emitter/types/object-record-create.event';
-import { ObjectRecordDeleteEvent } from 'src/engine/core-modules/event-emitter/types/object-record-delete.event';
-import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
import { InjectMessageQueue } from 'src/engine/core-modules/message-queue/decorators/message-queue.decorator';
import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants';
import { MessageQueueService } from 'src/engine/core-modules/message-queue/services/message-queue.service';
import { LogExecutionTime } from 'src/engine/decorators/observability/log-execution-time.decorator';
-import { assertMutationNotOnRemoteObject } from 'src/engine/metadata-modules/object-metadata/utils/assert-mutation-not-on-remote-object.util';
-import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
-import { WorkspaceEventEmitter } from 'src/engine/workspace-event-emitter/workspace-event-emitter';
+import { capitalize } from 'src/utils/capitalize';
@Injectable()
export class GraphqlQueryRunnerService {
constructor(
- private readonly twentyORMGlobalManager: TwentyORMGlobalManager,
- private readonly featureFlagService: FeatureFlagService,
private readonly workspaceQueryHookService: WorkspaceQueryHookService,
private readonly queryRunnerArgsFactory: QueryRunnerArgsFactory,
- private readonly workspaceEventEmitter: WorkspaceEventEmitter,
@InjectMessageQueue(MessageQueue.webhookQueue)
private readonly messageQueueService: MessageQueueService,
+ private readonly graphqlQueryResolverFactory: GraphqlQueryResolverFactory,
+ private readonly apiEventEmitterService: ApiEventEmitterService,
) {}
+ /** QUERIES */
+
@LogExecutionTime()
- async findOne<
- ObjectRecord extends IRecord = IRecord,
- Filter extends RecordFilter = RecordFilter,
- >(
+ async findOne(
args: FindOneResolverArgs,
options: WorkspaceQueryRunnerOptions,
- ): Promise {
- const graphqlQueryFindOneResolverService =
- new GraphqlQueryFindOneResolverService(this.twentyORMGlobalManager);
-
- const { authContext, objectMetadataItem } = options;
-
- if (!args.filter || Object.keys(args.filter).length === 0) {
- throw new WorkspaceQueryRunnerException(
- 'Missing filter argument',
- WorkspaceQueryRunnerExceptionCode.INVALID_QUERY_INPUT,
- );
- }
-
- const hookedArgs =
- await this.workspaceQueryHookService.executePreQueryHooks(
- authContext,
- objectMetadataItem.nameSingular,
- 'findOne',
- args,
- );
-
- const computedArgs = (await this.queryRunnerArgsFactory.create(
- hookedArgs,
+ ): Promise {
+ return this.executeQuery, ObjectRecord>(
+ 'findOne',
+ args,
options,
- ResolverArgsType.FindOne,
- )) as FindOneResolverArgs;
-
- return graphqlQueryFindOneResolverService.findOne(computedArgs, options);
+ );
}
@LogExecutionTime()
async findMany<
- ObjectRecord extends IRecord = IRecord,
- Filter extends RecordFilter = RecordFilter,
- OrderBy extends RecordOrderBy = RecordOrderBy,
+ ObjectRecord extends IRecord,
+ Filter extends RecordFilter,
+ OrderBy extends RecordOrderBy,
>(
args: FindManyResolverArgs,
options: WorkspaceQueryRunnerOptions,
+ ): Promise>> {
+ return this.executeQuery<
+ FindManyResolverArgs,
+ IConnection>
+ >('findMany', args, options);
+ }
+
+ @LogExecutionTime()
+ async findDuplicates(
+ args: FindDuplicatesResolverArgs>,
+ options: WorkspaceQueryRunnerOptions,
+ ): Promise[]> {
+ return this.executeQuery<
+ FindDuplicatesResolverArgs>,
+ IConnection[]
+ >('findDuplicates', args, options);
+ }
+
+ @LogExecutionTime()
+ async search(
+ args: SearchResolverArgs,
+ options: WorkspaceQueryRunnerOptions,
): Promise> {
- const graphqlQueryFindManyResolverService =
- new GraphqlQueryFindManyResolverService(this.twentyORMGlobalManager);
+ return this.executeQuery>(
+ 'search',
+ args,
+ options,
+ );
+ }
- const { authContext, objectMetadataItem } = options;
+ /** MUTATIONS */
- const hookedArgs =
- await this.workspaceQueryHookService.executePreQueryHooks(
- authContext,
- objectMetadataItem.nameSingular,
- 'findMany',
- args,
+ @LogExecutionTime()
+ async createOne(
+ args: CreateOneResolverArgs>,
+ options: WorkspaceQueryRunnerOptions,
+ ): Promise {
+ const results = await this.executeQuery<
+ CreateManyResolverArgs>,
+ ObjectRecord[]
+ >('createMany', { data: [args.data], upsert: args.upsert }, options);
+
+ // TODO: emitCreateEvents should be moved to the ORM layer
+ if (results) {
+ this.apiEventEmitterService.emitCreateEvents(
+ results,
+ options.authContext,
+ options.objectMetadataItem,
);
+ }
- const computedArgs = (await this.queryRunnerArgsFactory.create(
- hookedArgs,
- options,
- ResolverArgsType.FindMany,
- )) as FindManyResolverArgs;
-
- return graphqlQueryFindManyResolverService.findMany(computedArgs, options);
+ return results[0];
}
@LogExecutionTime()
- async createOne(
- args: CreateOneResolverArgs>,
+ async createMany(
+ args: CreateManyResolverArgs>,
options: WorkspaceQueryRunnerOptions,
- ): Promise {
- const graphqlQueryCreateManyResolverService =
- new GraphqlQueryCreateManyResolverService(this.twentyORMGlobalManager);
+ ): Promise {
+ const results = await this.executeQuery<
+ CreateManyResolverArgs>,
+ ObjectRecord[]
+ >('createMany', args, options);
+
+ if (results) {
+ this.apiEventEmitterService.emitCreateEvents(
+ results,
+ options.authContext,
+ options.objectMetadataItem,
+ );
+ }
- const { authContext, objectMetadataItem } = options;
+ return results;
+ }
- assertMutationNotOnRemoteObject(objectMetadataItem);
+ @LogExecutionTime()
+ public async updateOne(
+ args: UpdateOneResolverArgs>,
+ options: WorkspaceQueryRunnerOptions,
+ ): Promise {
+ const existingRecord = await this.executeQuery<
+ FindOneResolverArgs,
+ ObjectRecord
+ >(
+ 'findOne',
+ {
+ filter: { id: { eq: args.id } },
+ },
+ options,
+ );
- if (args.data.id) {
- assertIsValidUuid(args.data.id);
- }
+ const result = await this.executeQuery<
+ UpdateOneResolverArgs>,
+ ObjectRecord
+ >('updateOne', args, options);
- const createManyArgs = {
- data: [args.data],
- upsert: args.upsert,
- } as CreateManyResolverArgs;
+ this.apiEventEmitterService.emitUpdateEvents(
+ [existingRecord],
+ [result],
+ Object.keys(args.data),
+ options.authContext,
+ options.objectMetadataItem,
+ );
- const hookedArgs =
- await this.workspaceQueryHookService.executePreQueryHooks(
- authContext,
- objectMetadataItem.nameSingular,
- 'createMany',
- createManyArgs,
- );
+ return result;
+ }
- const computedArgs = (await this.queryRunnerArgsFactory.create(
- hookedArgs,
+ @LogExecutionTime()
+ public async updateMany(
+ args: UpdateManyResolverArgs>,
+ options: WorkspaceQueryRunnerOptions,
+ ): Promise {
+ const existingRecords = await this.executeQuery<
+ FindManyResolverArgs,
+ IConnection>
+ >(
+ 'findMany',
+ {
+ filter: args.filter,
+ },
options,
- ResolverArgsType.CreateMany,
- )) as CreateManyResolverArgs;
+ );
+
+ const result = await this.executeQuery<
+ UpdateManyResolverArgs>,
+ ObjectRecord[]
+ >('updateMany', args, options);
+
+ this.apiEventEmitterService.emitUpdateEvents(
+ existingRecords.edges.map((edge) => edge.node),
+ result,
+ Object.keys(args.data),
+ options.authContext,
+ options.objectMetadataItem,
+ );
- const results = (await graphqlQueryCreateManyResolverService.createMany(
- computedArgs,
+ return result;
+ }
+
+ @LogExecutionTime()
+ public async deleteOne(
+ args: DeleteOneResolverArgs,
+ options: WorkspaceQueryRunnerOptions,
+ ): Promise {
+ const result = await this.executeQuery<
+ UpdateOneResolverArgs>,
+ ObjectRecord
+ >(
+ 'deleteOne',
+ {
+ id: args.id,
+ data: { deletedAt: new Date() } as Partial,
+ },
options,
- )) as ObjectRecord[];
+ );
+
+ this.apiEventEmitterService.emitDeletedEvents(
+ [result],
+ options.authContext,
+ options.objectMetadataItem,
+ );
- await this.triggerWebhooks(
- results,
- CallWebhookJobsJobOperation.create,
+ return result;
+ }
+
+ @LogExecutionTime()
+ public async deleteMany(
+ args: DeleteManyResolverArgs,
+ options: WorkspaceQueryRunnerOptions,
+ ): Promise {
+ const result = await this.executeQuery<
+ UpdateManyResolverArgs>,
+ ObjectRecord[]
+ >(
+ 'deleteMany',
+ {
+ filter: args.filter,
+
+ data: { deletedAt: new Date() } as Partial,
+ },
options,
);
- this.emitCreateEvents(
- results,
- authContext,
- objectMetadataItem,
+ this.apiEventEmitterService.emitDeletedEvents(
+ result,
+ options.authContext,
+ options.objectMetadataItem,
);
- return results?.[0] as ObjectRecord;
+ return result;
}
@LogExecutionTime()
- async search(
- args: SearchResolverArgs,
+ async destroyOne(
+ args: DestroyOneResolverArgs,
options: WorkspaceQueryRunnerOptions,
- ): Promise> {
- const graphqlQuerySearchResolverService =
- new GraphqlQuerySearchResolverService(
- this.twentyORMGlobalManager,
- this.featureFlagService,
- );
+ ): Promise {
+ const result = await this.executeQuery<
+ DestroyOneResolverArgs,
+ ObjectRecord
+ >('destroyOne', args, options);
+
+ this.apiEventEmitterService.emitDestroyEvents(
+ [result],
+ options.authContext,
+ options.objectMetadataItem,
+ );
- return graphqlQuerySearchResolverService.search(args, options);
+ return result;
}
@LogExecutionTime()
- async createMany(
- args: CreateManyResolverArgs>,
+ public async restoreMany(
+ args: RestoreManyResolverArgs,
options: WorkspaceQueryRunnerOptions,
- ): Promise {
- const graphqlQueryCreateManyResolverService =
- new GraphqlQueryCreateManyResolverService(this.twentyORMGlobalManager);
+ ): Promise {
+ const result = await this.executeQuery<
+ UpdateManyResolverArgs>,
+ ObjectRecord
+ >(
+ 'restoreMany',
+ {
+ filter: args.filter,
+ data: { deletedAt: null } as Partial,
+ },
+ options,
+ );
+
+ return result;
+ }
+ private async executeQuery(
+ operationName: WorkspaceResolverBuilderMethodNames,
+ args: Input,
+ options: WorkspaceQueryRunnerOptions,
+ ): Promise {
const { authContext, objectMetadataItem } = options;
- assertMutationNotOnRemoteObject(objectMetadataItem);
+ const resolver =
+ this.graphqlQueryResolverFactory.getResolver(operationName);
- args.data.forEach((record) => {
- if (record?.id) {
- assertIsValidUuid(record.id);
- }
- });
+ await resolver.validate(args, options);
const hookedArgs =
await this.workspaceQueryHookService.executePreQueryHooks(
authContext,
objectMetadataItem.nameSingular,
- 'createMany',
+ operationName,
args,
);
- const computedArgs = (await this.queryRunnerArgsFactory.create(
+ const computedArgs = await this.queryRunnerArgsFactory.create(
hookedArgs,
options,
- ResolverArgsType.CreateMany,
- )) as CreateManyResolverArgs;
+ ResolverArgsType[capitalize(operationName)],
+ );
- const results = (await graphqlQueryCreateManyResolverService.createMany(
- computedArgs,
- options,
- )) as ObjectRecord[];
+ const results = await resolver.resolve(computedArgs as Input, options);
await this.workspaceQueryHookService.executePostQueryHooks(
authContext,
objectMetadataItem.nameSingular,
- 'createMany',
- results,
+ operationName,
+ Array.isArray(results) ? results : [results],
);
- await this.triggerWebhooks(
- results,
- CallWebhookJobsJobOperation.create,
- options,
- );
+ const jobOperation = this.operationNameToJobOperation(operationName);
- this.emitCreateEvents(
- results,
- authContext,
- objectMetadataItem,
- );
+ if (jobOperation) {
+ await this.triggerWebhooks(results, jobOperation, options);
+ }
return results;
}
- private emitCreateEvents(
- records: BaseRecord[],
- authContext: AuthContext,
- objectMetadataItem: ObjectMetadataInterface,
- ) {
- this.workspaceEventEmitter.emit(
- `${objectMetadataItem.nameSingular}.created`,
- records.map(
- (record) =>
- ({
- userId: authContext.user?.id,
- recordId: record.id,
- objectMetadata: objectMetadataItem,
- properties: {
- after: record,
- },
- }) satisfies ObjectRecordCreateEvent,
- ),
- authContext.workspace.id,
- );
+ private operationNameToJobOperation(
+ operationName: WorkspaceResolverBuilderMethodNames,
+ ): CallWebhookJobsJobOperation | undefined {
+ switch (operationName) {
+ case 'createOne':
+ case 'createMany':
+ return CallWebhookJobsJobOperation.create;
+ case 'updateOne':
+ case 'updateMany':
+ case 'restoreMany':
+ return CallWebhookJobsJobOperation.update;
+ case 'deleteOne':
+ case 'deleteMany':
+ return CallWebhookJobsJobOperation.delete;
+ case 'destroyOne':
+ return CallWebhookJobsJobOperation.destroy;
+ default:
+ return undefined;
+ }
}
- private async triggerWebhooks(
- jobsData: Record[] | undefined,
+ private async triggerWebhooks(
+ jobsData: T[] | undefined,
operation: CallWebhookJobsJobOperation,
options: WorkspaceQueryRunnerOptions,
- ) {
- if (!Array.isArray(jobsData)) {
- return;
- }
+ ): Promise {
+ if (!jobsData || !Array.isArray(jobsData)) return;
+
jobsData.forEach((jobData) => {
this.messageQueueService.add(
CallWebhookJobsJob.name,
@@ -298,99 +390,4 @@ export class GraphqlQueryRunnerService {
);
});
}
-
- @LogExecutionTime()
- async destroyOne(
- args: DestroyOneResolverArgs,
- options: WorkspaceQueryRunnerOptions,
- ): Promise {
- const graphqlQueryDestroyOneResolverService =
- new GraphqlQueryDestroyOneResolverService(this.twentyORMGlobalManager);
-
- const { authContext, objectMetadataItem } = options;
-
- assertMutationNotOnRemoteObject(objectMetadataItem);
- assertIsValidUuid(args.id);
-
- const hookedArgs =
- await this.workspaceQueryHookService.executePreQueryHooks(
- authContext,
- objectMetadataItem.nameSingular,
- 'destroyOne',
- args,
- );
-
- const computedArgs = (await this.queryRunnerArgsFactory.create(
- hookedArgs,
- options,
- ResolverArgsType.DestroyOne,
- )) as DestroyOneResolverArgs;
-
- const result = (await graphqlQueryDestroyOneResolverService.destroyOne(
- computedArgs,
- options,
- )) as ObjectRecord;
-
- await this.workspaceQueryHookService.executePostQueryHooks(
- authContext,
- objectMetadataItem.nameSingular,
- 'destroyOne',
- [result],
- );
-
- await this.triggerWebhooks(
- [result],
- CallWebhookJobsJobOperation.destroy,
- options,
- );
-
- this.emitDestroyEvents([result], authContext, objectMetadataItem);
-
- return result;
- }
-
- private emitDestroyEvents(
- records: BaseRecord[],
- authContext: AuthContext,
- objectMetadataItem: ObjectMetadataInterface,
- ) {
- this.workspaceEventEmitter.emit(
- `${objectMetadataItem.nameSingular}.destroyed`,
- records.map((record) => {
- return {
- userId: authContext.user?.id,
- recordId: record.id,
- objectMetadata: objectMetadataItem,
- properties: {
- before: this.removeNestedProperties(record),
- },
- } satisfies ObjectRecordDeleteEvent;
- }),
- authContext.workspace.id,
- );
- }
-
- private removeNestedProperties(
- record: Record,
- ) {
- if (!record) {
- return;
- }
-
- const sanitizedRecord = {};
-
- for (const [key, value] of Object.entries(record)) {
- if (value && typeof value === 'object' && value['edges']) {
- continue;
- }
-
- if (key === '__typename') {
- continue;
- }
-
- sanitizedRecord[key] = value;
- }
-
- return sanitizedRecord;
- }
}
diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/orm-mappers/object-records-to-graphql-connection.mapper.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper.ts
similarity index 99%
rename from packages/twenty-server/src/engine/api/graphql/graphql-query-runner/orm-mappers/object-records-to-graphql-connection.mapper.ts
rename to packages/twenty-server/src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper.ts
index b9a81ef245dc..5ccff3af114d 100644
--- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/orm-mappers/object-records-to-graphql-connection.mapper.ts
+++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper.ts
@@ -20,7 +20,7 @@ import { CompositeFieldMetadataType } from 'src/engine/metadata-modules/workspac
import { isRelationFieldMetadataType } from 'src/engine/utils/is-relation-field-metadata-type.util';
import { isPlainObject } from 'src/utils/is-plain-object';
-export class ObjectRecordsToGraphqlConnectionMapper {
+export class ObjectRecordsToGraphqlConnectionHelper {
private objectMetadataMap: ObjectMetadataMap;
constructor(objectMetadataMap: ObjectMetadataMap) {
diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/helpers/process-nested-relations.helper.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/helpers/process-nested-relations.helper.ts
index f19c7cf06eb3..dd3e5abd4020 100644
--- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/helpers/process-nested-relations.helper.ts
+++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/helpers/process-nested-relations.helper.ts
@@ -4,6 +4,7 @@ import {
FindOptionsRelations,
In,
ObjectLiteral,
+ Repository,
} from 'typeorm';
import { Record as IRecord } from 'src/engine/api/graphql/workspace-query-builder/interfaces/record.interface';
@@ -16,17 +17,38 @@ import {
ObjectMetadataMap,
ObjectMetadataMapItem,
} from 'src/engine/metadata-modules/utils/generate-object-metadata-map.util';
-import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
import { deduceRelationDirection } from 'src/engine/utils/deduce-relation-direction.util';
export class ProcessNestedRelationsHelper {
- private readonly twentyORMGlobalManager: TwentyORMGlobalManager;
+ constructor() {}
- constructor(twentyORMGlobalManager: TwentyORMGlobalManager) {
- this.twentyORMGlobalManager = twentyORMGlobalManager;
+ public async processNestedRelations(
+ objectMetadataMap: ObjectMetadataMap,
+ parentObjectMetadataItem: ObjectMetadataMapItem,
+ parentObjectRecords: ObjectRecord[],
+ relations: Record>,
+ limit: number,
+ authContext: any,
+ dataSource: DataSource,
+ ): Promise {
+ const processRelationTasks = Object.entries(relations).map(
+ ([relationName, nestedRelations]) =>
+ this.processRelation(
+ objectMetadataMap,
+ parentObjectMetadataItem,
+ parentObjectRecords,
+ relationName,
+ nestedRelations,
+ limit,
+ authContext,
+ dataSource,
+ ),
+ );
+
+ await Promise.all(processRelationTasks);
}
- private async processFromRelation(
+ private async processRelation(
objectMetadataMap: ObjectMetadataMap,
parentObjectMetadataItem: ObjectMetadataMapItem,
parentObjectRecords: ObjectRecord[],
@@ -35,49 +57,71 @@ export class ProcessNestedRelationsHelper {
limit: number,
authContext: any,
dataSource: DataSource,
- ) {
+ ): Promise {
const relationFieldMetadata = parentObjectMetadataItem.fields[relationName];
const relationMetadata = getRelationMetadata(relationFieldMetadata);
-
- const inverseRelationName =
- objectMetadataMap[relationMetadata.toObjectMetadataId]?.fields[
- relationMetadata.toFieldMetadataId
- ]?.name;
-
- const referenceObjectMetadata = getRelationObjectMetadata(
+ const relationDirection = deduceRelationDirection(
relationFieldMetadata,
- objectMetadataMap,
+ relationMetadata,
);
- const referenceObjectMetadataName = referenceObjectMetadata.nameSingular;
+ const processor =
+ relationDirection === 'to'
+ ? this.processToRelation
+ : this.processFromRelation;
- const relationRepository = await dataSource.getRepository(
- referenceObjectMetadataName,
+ await processor.call(
+ this,
+ objectMetadataMap,
+ parentObjectMetadataItem,
+ parentObjectRecords,
+ relationName,
+ nestedRelations,
+ limit,
+ authContext,
+ dataSource,
);
+ }
- const relationIds = parentObjectRecords.map((item) => item.id);
-
- const uniqueRelationIds = [...new Set(relationIds)];
-
- const relationFindOptions: FindManyOptions = {
- where: {
- [`${inverseRelationName}Id`]: In(uniqueRelationIds),
- },
- take: limit * parentObjectRecords.length,
- };
+ private async processFromRelation(
+ objectMetadataMap: ObjectMetadataMap,
+ parentObjectMetadataItem: ObjectMetadataMapItem,
+ parentObjectRecords: ObjectRecord[],
+ relationName: string,
+ nestedRelations: any,
+ limit: number,
+ authContext: any,
+ dataSource: DataSource,
+ ): Promise {
+ const { inverseRelationName, referenceObjectMetadata } =
+ this.getRelationMetadata(
+ objectMetadataMap,
+ parentObjectMetadataItem,
+ relationName,
+ );
+ const relationRepository = dataSource.getRepository(
+ referenceObjectMetadata.nameSingular,
+ );
- const relationResults = await relationRepository.find(relationFindOptions);
+ const relationIds = this.getUniqueIds(parentObjectRecords, 'id');
+ const relationResults = await this.findRelations(
+ relationRepository,
+ inverseRelationName,
+ relationIds,
+ limit * parentObjectRecords.length,
+ );
- parentObjectRecords.forEach((item) => {
- (item as any)[relationName] = relationResults.filter(
- (rel) => rel[`${inverseRelationName}Id`] === item.id,
- );
- });
+ this.assignRelationResults(
+ parentObjectRecords,
+ relationResults,
+ relationName,
+ `${inverseRelationName}Id`,
+ );
if (Object.keys(nestedRelations).length > 0) {
await this.processNestedRelations(
objectMetadataMap,
- objectMetadataMap[referenceObjectMetadataName],
+ objectMetadataMap[referenceObjectMetadata.nameSingular],
relationResults as ObjectRecord[],
nestedRelations as Record>,
limit,
@@ -96,48 +140,37 @@ export class ProcessNestedRelationsHelper {
limit: number,
authContext: any,
dataSource: DataSource,
- ) {
- const relationFieldMetadata = parentObjectMetadataItem.fields[relationName];
-
- const referenceObjectMetadata = getRelationObjectMetadata(
- relationFieldMetadata,
+ ): Promise {
+ const { referenceObjectMetadata } = this.getRelationMetadata(
objectMetadataMap,
+ parentObjectMetadataItem,
+ relationName,
);
-
- const referenceObjectMetadataName = referenceObjectMetadata.nameSingular;
-
const relationRepository = dataSource.getRepository(
- referenceObjectMetadataName,
+ referenceObjectMetadata.nameSingular,
);
- const relationIds = parentObjectRecords.map(
- (item) => item[`${relationName}Id`],
+ const relationIds = this.getUniqueIds(
+ parentObjectRecords,
+ `${relationName}Id`,
+ );
+ const relationResults = await this.findRelations(
+ relationRepository,
+ 'id',
+ relationIds,
+ limit,
);
- const uniqueRelationIds = [...new Set(relationIds)];
-
- const relationFindOptions: FindManyOptions = {
- where: {
- id: In(uniqueRelationIds),
- },
- take: limit,
- };
-
- const relationResults = await relationRepository.find(relationFindOptions);
-
- parentObjectRecords.forEach((item) => {
- if (relationResults.length === 0) {
- (item as any)[`${relationName}Id`] = null;
- }
- (item as any)[relationName] = relationResults.filter(
- (rel) => rel.id === item[`${relationName}Id`],
- )[0];
- });
+ this.assignToRelationResults(
+ parentObjectRecords,
+ relationResults,
+ relationName,
+ );
if (Object.keys(nestedRelations).length > 0) {
await this.processNestedRelations(
objectMetadataMap,
- objectMetadataMap[referenceObjectMetadataName],
+ objectMetadataMap[referenceObjectMetadata.nameSingular],
relationResults as ObjectRecord[],
nestedRelations as Record>,
limit,
@@ -147,48 +180,71 @@ export class ProcessNestedRelationsHelper {
}
}
- public async processNestedRelations(
+ private getRelationMetadata(
objectMetadataMap: ObjectMetadataMap,
parentObjectMetadataItem: ObjectMetadataMapItem,
- parentObjectRecords: ObjectRecord[],
- relations: Record>,
- limit: number,
- authContext: any,
- dataSource: DataSource,
+ relationName: string,
) {
- for (const [relationName, nestedRelations] of Object.entries(relations)) {
- const relationFieldMetadata =
- parentObjectMetadataItem.fields[relationName];
- const relationMetadata = getRelationMetadata(relationFieldMetadata);
-
- const relationDirection = deduceRelationDirection(
- relationFieldMetadata,
- relationMetadata,
+ const relationFieldMetadata = parentObjectMetadataItem.fields[relationName];
+ const relationMetadata = getRelationMetadata(relationFieldMetadata);
+ const referenceObjectMetadata = getRelationObjectMetadata(
+ relationFieldMetadata,
+ objectMetadataMap,
+ );
+ const inverseRelationName =
+ objectMetadataMap[relationMetadata.toObjectMetadataId]?.fields[
+ relationMetadata.toFieldMetadataId
+ ]?.name;
+
+ return { inverseRelationName, referenceObjectMetadata };
+ }
+
+ private getUniqueIds(records: IRecord[], idField: string): any[] {
+ return [...new Set(records.map((item) => item[idField]))];
+ }
+
+ private async findRelations(
+ repository: Repository,
+ field: string,
+ ids: any[],
+ limit: number,
+ ): Promise {
+ if (ids.length === 0) {
+ return [];
+ }
+ const findOptions: FindManyOptions = {
+ where: { [field]: In(ids) },
+ take: limit,
+ };
+
+ return repository.find(findOptions);
+ }
+
+ private assignRelationResults(
+ parentRecords: IRecord[],
+ relationResults: any[],
+ relationName: string,
+ joinField: string,
+ ): void {
+ parentRecords.forEach((item) => {
+ (item as any)[relationName] = relationResults.filter(
+ (rel) => rel[joinField] === item.id,
);
+ });
+ }
- if (relationDirection === 'to') {
- await this.processToRelation(
- objectMetadataMap,
- parentObjectMetadataItem,
- parentObjectRecords,
- relationName,
- nestedRelations,
- limit,
- authContext,
- dataSource,
- );
- } else {
- await this.processFromRelation(
- objectMetadataMap,
- parentObjectMetadataItem,
- parentObjectRecords,
- relationName,
- nestedRelations,
- limit,
- authContext,
- dataSource,
- );
+ private assignToRelationResults(
+ parentRecords: IRecord[],
+ relationResults: any[],
+ relationName: string,
+ ): void {
+ parentRecords.forEach((item) => {
+ if (relationResults.length === 0) {
+ (item as any)[`${relationName}Id`] = null;
}
- }
+ (item as any)[relationName] =
+ relationResults.find((rel) => rel.id === item[`${relationName}Id`]) ??
+ null;
+ });
}
}
diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/interfaces/resolver-service.interface.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/interfaces/resolver-service.interface.ts
new file mode 100644
index 000000000000..f88691647425
--- /dev/null
+++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/interfaces/resolver-service.interface.ts
@@ -0,0 +1,12 @@
+import { WorkspaceQueryRunnerOptions } from 'src/engine/api/graphql/workspace-query-runner/interfaces/query-runner-option.interface';
+
+export interface ResolverService {
+ resolve: (
+ args: ResolverArgs,
+ options: WorkspaceQueryRunnerOptions,
+ ) => Promise;
+ validate: (
+ args: ResolverArgs,
+ options: WorkspaceQueryRunnerOptions,
+ ) => Promise;
+}
diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-create-many-resolver.service.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-create-many-resolver.service.ts
index f66497a6812a..aa8a81ce85a6 100644
--- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-create-many-resolver.service.ts
+++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-create-many-resolver.service.ts
@@ -1,51 +1,53 @@
+import { Injectable } from '@nestjs/common';
+
import graphqlFields from 'graphql-fields';
import { In, InsertResult } from 'typeorm';
+import { ResolverService } from 'src/engine/api/graphql/graphql-query-runner/interfaces/resolver-service.interface';
import { Record as IRecord } from 'src/engine/api/graphql/workspace-query-builder/interfaces/record.interface';
import { WorkspaceQueryRunnerOptions } from 'src/engine/api/graphql/workspace-query-runner/interfaces/query-runner-option.interface';
import { CreateManyResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
+import { QUERY_MAX_RECORDS } from 'src/engine/api/graphql/graphql-query-runner/constants/query-max-records.constant';
import { GraphqlQueryParser } from 'src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query.parser';
-import { ObjectRecordsToGraphqlConnectionMapper } from 'src/engine/api/graphql/graphql-query-runner/orm-mappers/object-records-to-graphql-connection.mapper';
-import { getObjectMetadataOrThrow } from 'src/engine/api/graphql/graphql-query-runner/utils/get-object-metadata-or-throw.util';
-import { generateObjectMetadataMap } from 'src/engine/metadata-modules/utils/generate-object-metadata-map.util';
+import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper';
+import { ProcessNestedRelationsHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/process-nested-relations.helper';
+import { assertIsValidUuid } from 'src/engine/api/graphql/workspace-query-runner/utils/assert-is-valid-uuid.util';
+import { assertMutationNotOnRemoteObject } from 'src/engine/metadata-modules/object-metadata/utils/assert-mutation-not-on-remote-object.util';
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
+import { formatResult } from 'src/engine/twenty-orm/utils/format-result.util';
-export class GraphqlQueryCreateManyResolverService {
- private twentyORMGlobalManager: TwentyORMGlobalManager;
-
- constructor(twentyORMGlobalManager: TwentyORMGlobalManager) {
- this.twentyORMGlobalManager = twentyORMGlobalManager;
- }
+@Injectable()
+export class GraphqlQueryCreateManyResolverService
+ implements ResolverService
+{
+ constructor(
+ private readonly twentyORMGlobalManager: TwentyORMGlobalManager,
+ ) {}
- async createMany(
+ async resolve(
args: CreateManyResolverArgs>,
options: WorkspaceQueryRunnerOptions,
- ): Promise {
- const { authContext, objectMetadataItem, objectMetadataCollection, info } =
+ ): Promise {
+ const { authContext, info, objectMetadataMap, objectMetadataMapItem } =
options;
- const repository =
- await this.twentyORMGlobalManager.getRepositoryForWorkspace(
+ const dataSource =
+ await this.twentyORMGlobalManager.getDataSourceForWorkspace(
authContext.workspace.id,
- objectMetadataItem.nameSingular,
);
-
- const objectMetadataMap = generateObjectMetadataMap(
- objectMetadataCollection,
- );
- const objectMetadata = getObjectMetadataOrThrow(
- objectMetadataMap,
- objectMetadataItem.nameSingular,
+ const repository = dataSource.getRepository(
+ objectMetadataMapItem.nameSingular,
);
+
const graphqlQueryParser = new GraphqlQueryParser(
- objectMetadata.fields,
+ objectMetadataMapItem.fields,
objectMetadataMap,
);
const selectedFields = graphqlFields(info);
- const { select, relations } = graphqlQueryParser.parseSelectedFields(
- objectMetadataItem,
+ const { relations } = graphqlQueryParser.parseSelectedFields(
+ objectMetadataMapItem,
selectedFields,
);
@@ -56,24 +58,59 @@ export class GraphqlQueryCreateManyResolverService {
skipUpdateIfNoValuesChanged: true,
});
- const upsertedRecords = await repository.find({
- where: {
+ const queryBuilder = repository.createQueryBuilder(
+ objectMetadataMapItem.nameSingular,
+ );
+
+ const nonFormattedUpsertedRecords = (await queryBuilder
+ .where({
id: In(objectRecords.generatedMaps.map((record) => record.id)),
- },
- select,
- relations,
- });
+ })
+ .take(QUERY_MAX_RECORDS)
+ .getMany()) as ObjectRecord[];
+
+ const upsertedRecords = formatResult(
+ nonFormattedUpsertedRecords,
+ objectMetadataMapItem,
+ objectMetadataMap,
+ );
+
+ const processNestedRelationsHelper = new ProcessNestedRelationsHelper();
+
+ if (relations) {
+ await processNestedRelationsHelper.processNestedRelations(
+ objectMetadataMap,
+ objectMetadataMapItem,
+ upsertedRecords,
+ relations,
+ QUERY_MAX_RECORDS,
+ authContext,
+ dataSource,
+ );
+ }
const typeORMObjectRecordsParser =
- new ObjectRecordsToGraphqlConnectionMapper(objectMetadataMap);
+ new ObjectRecordsToGraphqlConnectionHelper(objectMetadataMap);
return upsertedRecords.map((record: ObjectRecord) =>
typeORMObjectRecordsParser.processRecord(
record,
- objectMetadataItem.nameSingular,
+ objectMetadataMapItem.nameSingular,
1,
1,
),
);
}
+
+ async validate(
+ args: CreateManyResolverArgs>,
+ options: WorkspaceQueryRunnerOptions,
+ ): Promise {
+ assertMutationNotOnRemoteObject(options.objectMetadataItem);
+ args.data.forEach((record) => {
+ if (record?.id) {
+ assertIsValidUuid(record.id);
+ }
+ });
+ }
}
diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-destroy-one-resolver.service.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-destroy-one-resolver.service.ts
index 53dad3eddd0b..3540dcbf9559 100644
--- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-destroy-one-resolver.service.ts
+++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-destroy-one-resolver.service.ts
@@ -1,33 +1,68 @@
+import { Injectable } from '@nestjs/common';
+
+import { ResolverService } from 'src/engine/api/graphql/graphql-query-runner/interfaces/resolver-service.interface';
import { Record as IRecord } from 'src/engine/api/graphql/workspace-query-builder/interfaces/record.interface';
import { WorkspaceQueryRunnerOptions } from 'src/engine/api/graphql/workspace-query-runner/interfaces/query-runner-option.interface';
import { DestroyOneResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
+import {
+ GraphqlQueryRunnerException,
+ GraphqlQueryRunnerExceptionCode,
+} from 'src/engine/api/graphql/graphql-query-runner/errors/graphql-query-runner.exception';
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
+import { formatResult } from 'src/engine/twenty-orm/utils/format-result.util';
-export class GraphqlQueryDestroyOneResolverService {
- private twentyORMGlobalManager: TwentyORMGlobalManager;
-
- constructor(twentyORMGlobalManager: TwentyORMGlobalManager) {
- this.twentyORMGlobalManager = twentyORMGlobalManager;
- }
+@Injectable()
+export class GraphqlQueryDestroyOneResolverService
+ implements ResolverService
+{
+ constructor(
+ private readonly twentyORMGlobalManager: TwentyORMGlobalManager,
+ ) {}
- async destroyOne(
+ async resolve(
args: DestroyOneResolverArgs,
options: WorkspaceQueryRunnerOptions,
): Promise {
- const { authContext, objectMetadataItem } = options;
+ const { authContext, objectMetadataMapItem, objectMetadataMap } = options;
const repository =
await this.twentyORMGlobalManager.getRepositoryForWorkspace(
authContext.workspace.id,
- objectMetadataItem.nameSingular,
+ objectMetadataMapItem.nameSingular,
);
- const record = await repository.findOne({
+ const nonFormattedRecordBeforeDeletion = await repository.findOne({
where: { id: args.id },
+ withDeleted: true,
});
+ if (!nonFormattedRecordBeforeDeletion) {
+ throw new GraphqlQueryRunnerException(
+ 'Record not found',
+ GraphqlQueryRunnerExceptionCode.RECORD_NOT_FOUND,
+ );
+ }
+
+ const recordBeforeDeletion = formatResult(
+ [nonFormattedRecordBeforeDeletion],
+ objectMetadataMapItem,
+ objectMetadataMap,
+ )[0];
+
await repository.delete(args.id);
- return record as ObjectRecord;
+ return recordBeforeDeletion as ObjectRecord;
+ }
+
+ async validate(
+ args: DestroyOneResolverArgs,
+ _options: WorkspaceQueryRunnerOptions,
+ ): Promise {
+ if (!args.id) {
+ throw new GraphqlQueryRunnerException(
+ 'Missing id',
+ GraphqlQueryRunnerExceptionCode.INVALID_QUERY_INPUT,
+ );
+ }
}
}
diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-find-duplicates-resolver.service.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-find-duplicates-resolver.service.ts
new file mode 100644
index 000000000000..00561933043d
--- /dev/null
+++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-find-duplicates-resolver.service.ts
@@ -0,0 +1,214 @@
+import { Injectable } from '@nestjs/common';
+
+import isEmpty from 'lodash.isempty';
+import { In } from 'typeorm';
+
+import { ResolverService } from 'src/engine/api/graphql/graphql-query-runner/interfaces/resolver-service.interface';
+import {
+ Record as IRecord,
+ OrderByDirection,
+ RecordFilter,
+} 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 { WorkspaceQueryRunnerOptions } from 'src/engine/api/graphql/workspace-query-runner/interfaces/query-runner-option.interface';
+import { FindDuplicatesResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
+
+import {
+ GraphqlQueryRunnerException,
+ GraphqlQueryRunnerExceptionCode,
+} from 'src/engine/api/graphql/graphql-query-runner/errors/graphql-query-runner.exception';
+import { GraphqlQueryParser } from 'src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query.parser';
+import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper';
+import { settings } from 'src/engine/constants/settings';
+import { DUPLICATE_CRITERIA_COLLECTION } from 'src/engine/core-modules/duplicate/constants/duplicate-criteria.constants';
+import { ObjectMetadataMapItem } from 'src/engine/metadata-modules/utils/generate-object-metadata-map.util';
+import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
+import { formatData } from 'src/engine/twenty-orm/utils/format-data.util';
+import { formatResult } from 'src/engine/twenty-orm/utils/format-result.util';
+
+@Injectable()
+export class GraphqlQueryFindDuplicatesResolverService
+ implements
+ ResolverService[]>
+{
+ constructor(
+ private readonly twentyORMGlobalManager: TwentyORMGlobalManager,
+ ) {}
+
+ async resolve(
+ args: FindDuplicatesResolverArgs>,
+ options: WorkspaceQueryRunnerOptions,
+ ): Promise[]> {
+ const { authContext, objectMetadataMapItem, objectMetadataMap } = options;
+
+ const dataSource =
+ await this.twentyORMGlobalManager.getDataSourceForWorkspace(
+ authContext.workspace.id,
+ );
+ const repository = dataSource.getRepository(
+ objectMetadataMapItem.nameSingular,
+ );
+ const existingRecordsQueryBuilder = repository.createQueryBuilder(
+ objectMetadataMapItem.nameSingular,
+ );
+ const duplicateRecordsQueryBuilder = repository.createQueryBuilder(
+ objectMetadataMapItem.nameSingular,
+ );
+
+ const graphqlQueryParser = new GraphqlQueryParser(
+ objectMetadataMap[objectMetadataMapItem.nameSingular].fields,
+ objectMetadataMap,
+ );
+
+ const typeORMObjectRecordsParser =
+ new ObjectRecordsToGraphqlConnectionHelper(objectMetadataMap);
+
+ let objectRecords: Partial[] = [];
+
+ if (args.ids) {
+ const nonFormattedObjectRecords = (await existingRecordsQueryBuilder
+ .where({ id: In(args.ids) })
+ .getMany()) as ObjectRecord[];
+
+ objectRecords = formatResult(
+ nonFormattedObjectRecords,
+ objectMetadataMapItem,
+ objectMetadataMap,
+ );
+ } else if (args.data && !isEmpty(args.data)) {
+ objectRecords = formatData(args.data, objectMetadataMapItem);
+ }
+
+ const duplicateConnections: IConnection[] = await Promise.all(
+ objectRecords.map(async (record) => {
+ const duplicateConditions = this.buildDuplicateConditions(
+ objectMetadataMapItem,
+ [record],
+ record.id,
+ );
+
+ if (isEmpty(duplicateConditions)) {
+ return typeORMObjectRecordsParser.createConnection(
+ [],
+ objectMetadataMapItem.nameSingular,
+ 0,
+ 0,
+ [{ id: OrderByDirection.AscNullsFirst }],
+ false,
+ false,
+ );
+ }
+
+ const withFilterQueryBuilder = graphqlQueryParser.applyFilterToBuilder(
+ duplicateRecordsQueryBuilder,
+ objectMetadataMapItem.nameSingular,
+ duplicateConditions,
+ );
+
+ const nonFormattedDuplicates =
+ (await withFilterQueryBuilder.getMany()) as ObjectRecord[];
+
+ const duplicates = formatResult(
+ nonFormattedDuplicates,
+ objectMetadataMapItem,
+ objectMetadataMap,
+ );
+
+ return typeORMObjectRecordsParser.createConnection(
+ duplicates,
+ objectMetadataMapItem.nameSingular,
+ duplicates.length,
+ duplicates.length,
+ [{ id: OrderByDirection.AscNullsFirst }],
+ false,
+ false,
+ );
+ }),
+ );
+
+ return duplicateConnections;
+ }
+
+ private buildDuplicateConditions(
+ objectMetadataMapItem: ObjectMetadataMapItem,
+ records?: Partial[] | undefined,
+ filteringByExistingRecordId?: string,
+ ): Partial {
+ if (!records || records.length === 0) {
+ return {};
+ }
+
+ const criteriaCollection = this.getApplicableDuplicateCriteriaCollection(
+ objectMetadataMapItem,
+ );
+
+ const conditions = records.flatMap((record) => {
+ const criteriaWithMatchingArgs = criteriaCollection.filter((criteria) =>
+ criteria.columnNames.every((columnName) => {
+ const value = record[columnName] as string | undefined;
+
+ return (
+ value && value.length >= settings.minLengthOfStringForDuplicateCheck
+ );
+ }),
+ );
+
+ return criteriaWithMatchingArgs.map((criteria) => {
+ const condition = {};
+
+ criteria.columnNames.forEach((columnName) => {
+ condition[columnName] = { eq: record[columnName] };
+ });
+
+ return condition;
+ });
+ });
+
+ const filter: Partial = {};
+
+ if (conditions && !isEmpty(conditions)) {
+ filter.or = conditions;
+
+ if (filteringByExistingRecordId) {
+ filter.id = { neq: filteringByExistingRecordId };
+ }
+ }
+
+ return filter;
+ }
+
+ private getApplicableDuplicateCriteriaCollection(
+ objectMetadataMapItem: ObjectMetadataMapItem,
+ ) {
+ return DUPLICATE_CRITERIA_COLLECTION.filter(
+ (duplicateCriteria) =>
+ duplicateCriteria.objectName === objectMetadataMapItem.nameSingular,
+ );
+ }
+
+ async validate(
+ args: FindDuplicatesResolverArgs,
+ _options: WorkspaceQueryRunnerOptions,
+ ): Promise {
+ if (!args.data && !args.ids) {
+ throw new GraphqlQueryRunnerException(
+ 'You have to provide either "data" or "ids" argument',
+ GraphqlQueryRunnerExceptionCode.INVALID_QUERY_INPUT,
+ );
+ }
+
+ if (args.data && args.ids) {
+ throw new GraphqlQueryRunnerException(
+ 'You cannot provide both "data" and "ids" arguments',
+ GraphqlQueryRunnerExceptionCode.INVALID_QUERY_INPUT,
+ );
+ }
+
+ if (!args.ids && isEmpty(args.data)) {
+ throw new GraphqlQueryRunnerException(
+ 'The "data" condition can not be empty when "ids" input not provided',
+ GraphqlQueryRunnerExceptionCode.INVALID_QUERY_INPUT,
+ );
+ }
+ }
+}
diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-find-many-resolver.service.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-find-many-resolver.service.ts
index 5caa30e4e51e..85fdd3948274 100644
--- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-find-many-resolver.service.ts
+++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-find-many-resolver.service.ts
@@ -1,6 +1,9 @@
+import { Injectable } from '@nestjs/common';
+
import { isDefined } from 'class-validator';
import graphqlFields from 'graphql-fields';
+import { ResolverService } from 'src/engine/api/graphql/graphql-query-runner/interfaces/resolver-service.interface';
import {
Record as IRecord,
OrderByDirection,
@@ -17,26 +20,25 @@ import {
GraphqlQueryRunnerExceptionCode,
} from 'src/engine/api/graphql/graphql-query-runner/errors/graphql-query-runner.exception';
import { GraphqlQueryParser } from 'src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query.parser';
+import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper';
import { ProcessNestedRelationsHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/process-nested-relations.helper';
-import { ObjectRecordsToGraphqlConnectionMapper } from 'src/engine/api/graphql/graphql-query-runner/orm-mappers/object-records-to-graphql-connection.mapper';
import { computeCursorArgFilter } from 'src/engine/api/graphql/graphql-query-runner/utils/compute-cursor-arg-filter';
-import { decodeCursor } from 'src/engine/api/graphql/graphql-query-runner/utils/cursors.util';
-import { getObjectMetadataOrThrow } from 'src/engine/api/graphql/graphql-query-runner/utils/get-object-metadata-or-throw.util';
import {
- ObjectMetadataMapItem,
- generateObjectMetadataMap,
-} from 'src/engine/metadata-modules/utils/generate-object-metadata-map.util';
+ getCursor,
+ getPaginationInfo,
+} from 'src/engine/api/graphql/graphql-query-runner/utils/cursors.util';
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
import { formatResult } from 'src/engine/twenty-orm/utils/format-result.util';
-export class GraphqlQueryFindManyResolverService {
- private twentyORMGlobalManager: TwentyORMGlobalManager;
-
- constructor(twentyORMGlobalManager: TwentyORMGlobalManager) {
- this.twentyORMGlobalManager = twentyORMGlobalManager;
- }
+@Injectable()
+export class GraphqlQueryFindManyResolverService
+ implements ResolverService>
+{
+ constructor(
+ private readonly twentyORMGlobalManager: TwentyORMGlobalManager,
+ ) {}
- async findMany<
+ async resolve<
ObjectRecord extends IRecord = IRecord,
Filter extends RecordFilter = RecordFilter,
OrderBy extends RecordOrderBy = RecordOrderBy,
@@ -44,51 +46,41 @@ export class GraphqlQueryFindManyResolverService {
args: FindManyResolverArgs,
options: WorkspaceQueryRunnerOptions,
): Promise> {
- const { authContext, objectMetadataItem, info, objectMetadataCollection } =
+ const { authContext, objectMetadataMapItem, info, objectMetadataMap } =
options;
- this.validateArgsOrThrow(args);
-
const dataSource =
await this.twentyORMGlobalManager.getDataSourceForWorkspace(
authContext.workspace.id,
);
const repository = dataSource.getRepository(
- objectMetadataItem.nameSingular,
+ objectMetadataMapItem.nameSingular,
);
const queryBuilder = repository.createQueryBuilder(
- objectMetadataItem.nameSingular,
+ objectMetadataMapItem.nameSingular,
);
const countQueryBuilder = repository.createQueryBuilder(
- objectMetadataItem.nameSingular,
- );
-
- const objectMetadataMap = generateObjectMetadataMap(
- objectMetadataCollection,
+ objectMetadataMapItem.nameSingular,
);
- const objectMetadata = getObjectMetadataOrThrow(
- objectMetadataMap,
- objectMetadataItem.nameSingular,
- );
const graphqlQueryParser = new GraphqlQueryParser(
- objectMetadata.fields,
+ objectMetadataMapItem.fields,
objectMetadataMap,
);
const withFilterCountQueryBuilder = graphqlQueryParser.applyFilterToBuilder(
countQueryBuilder,
- objectMetadataItem.nameSingular,
+ objectMetadataMapItem.nameSingular,
args.filter ?? ({} as Filter),
);
const selectedFields = graphqlFields(info);
const { relations } = graphqlQueryParser.parseSelectedFields(
- objectMetadataItem,
+ objectMetadataMapItem,
selectedFields,
);
const isForwardPagination = !isDefined(args.before);
@@ -105,7 +97,7 @@ export class GraphqlQueryFindManyResolverService {
? await withDeletedCountQueryBuilder.getCount()
: 0;
- const cursor = this.getCursor(args);
+ const cursor = getCursor(args);
let appliedFilters = args.filter ?? ({} as Filter);
@@ -118,7 +110,7 @@ export class GraphqlQueryFindManyResolverService {
const cursorArgFilter = computeCursorArgFilter(
cursor,
orderByWithIdCondition,
- objectMetadata.fields,
+ objectMetadataMapItem.fields,
isForwardPagination,
);
@@ -131,14 +123,14 @@ export class GraphqlQueryFindManyResolverService {
const withFilterQueryBuilder = graphqlQueryParser.applyFilterToBuilder(
queryBuilder,
- objectMetadataItem.nameSingular,
+ objectMetadataMapItem.nameSingular,
appliedFilters,
);
const withOrderByQueryBuilder = graphqlQueryParser.applyOrderToBuilder(
withFilterQueryBuilder,
orderByWithIdCondition,
- objectMetadataItem.nameSingular,
+ objectMetadataMapItem.nameSingular,
isForwardPagination,
);
@@ -153,11 +145,11 @@ export class GraphqlQueryFindManyResolverService {
const objectRecords = formatResult(
nonFormattedObjectRecords,
- objectMetadata,
+ objectMetadataMapItem,
objectMetadataMap,
);
- const { hasNextPage, hasPreviousPage } = this.getPaginationInfo(
+ const { hasNextPage, hasPreviousPage } = getPaginationInfo(
objectRecords,
limit,
isForwardPagination,
@@ -167,14 +159,12 @@ export class GraphqlQueryFindManyResolverService {
objectRecords.pop();
}
- const processNestedRelationsHelper = new ProcessNestedRelationsHelper(
- this.twentyORMGlobalManager,
- );
+ const processNestedRelationsHelper = new ProcessNestedRelationsHelper();
if (relations) {
await processNestedRelationsHelper.processNestedRelations(
objectMetadataMap,
- objectMetadata,
+ objectMetadataMapItem,
objectRecords,
relations,
limit,
@@ -184,20 +174,25 @@ export class GraphqlQueryFindManyResolverService {
}
const typeORMObjectRecordsParser =
- new ObjectRecordsToGraphqlConnectionMapper(objectMetadataMap);
+ new ObjectRecordsToGraphqlConnectionHelper(objectMetadataMap);
- return typeORMObjectRecordsParser.createConnection(
+ const result = typeORMObjectRecordsParser.createConnection(
objectRecords,
- objectMetadataItem.nameSingular,
+ objectMetadataMapItem.nameSingular,
limit,
totalCount,
orderByWithIdCondition,
hasNextPage,
hasPreviousPage,
);
+
+ return result;
}
- private validateArgsOrThrow(args: FindManyResolverArgs) {
+ async validate(
+ args: FindManyResolverArgs,
+ _options: WorkspaceQueryRunnerOptions,
+ ): Promise {
if (args.first && args.last) {
throw new GraphqlQueryRunnerException(
'Cannot provide both first and last',
@@ -235,49 +230,4 @@ export class GraphqlQueryFindManyResolverService {
);
}
}
-
- private getCursor(
- args: FindManyResolverArgs,
- ): Record | undefined {
- if (args.after) return decodeCursor(args.after);
- if (args.before) return decodeCursor(args.before);
-
- return undefined;
- }
-
- private addOrderByColumnsToSelect(
- order: Record,
- select: Record,
- ) {
- for (const column of Object.keys(order || {})) {
- if (!select[column]) {
- select[column] = true;
- }
- }
- }
-
- private addForeingKeyColumnsToSelect(
- relations: Record,
- select: Record,
- objectMetadata: ObjectMetadataMapItem,
- ) {
- for (const column of Object.keys(relations || {})) {
- if (!select[`${column}Id`] && objectMetadata.fields[`${column}Id`]) {
- select[`${column}Id`] = true;
- }
- }
- }
-
- private getPaginationInfo(
- objectRecords: any[],
- limit: number,
- isForwardPagination: boolean,
- ) {
- const hasMoreRecords = objectRecords.length > limit;
-
- return {
- hasNextPage: isForwardPagination && hasMoreRecords,
- hasPreviousPage: !isForwardPagination && hasMoreRecords,
- };
- }
}
diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-find-one-resolver.service.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-find-one-resolver.service.ts
index b9e86e420cc9..164f30b68664 100644
--- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-find-one-resolver.service.ts
+++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-find-one-resolver.service.ts
@@ -1,5 +1,8 @@
+import { Injectable } from '@nestjs/common';
+
import graphqlFields from 'graphql-fields';
+import { ResolverService } from 'src/engine/api/graphql/graphql-query-runner/interfaces/resolver-service.interface';
import {
Record as IRecord,
RecordFilter,
@@ -13,28 +16,31 @@ import {
GraphqlQueryRunnerExceptionCode,
} from 'src/engine/api/graphql/graphql-query-runner/errors/graphql-query-runner.exception';
import { GraphqlQueryParser } from 'src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query.parser';
+import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper';
import { ProcessNestedRelationsHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/process-nested-relations.helper';
-import { ObjectRecordsToGraphqlConnectionMapper } from 'src/engine/api/graphql/graphql-query-runner/orm-mappers/object-records-to-graphql-connection.mapper';
-import { getObjectMetadataOrThrow } from 'src/engine/api/graphql/graphql-query-runner/utils/get-object-metadata-or-throw.util';
-import { generateObjectMetadataMap } from 'src/engine/metadata-modules/utils/generate-object-metadata-map.util';
+import {
+ WorkspaceQueryRunnerException,
+ WorkspaceQueryRunnerExceptionCode,
+} from 'src/engine/api/graphql/workspace-query-runner/workspace-query-runner.exception';
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
import { formatResult } from 'src/engine/twenty-orm/utils/format-result.util';
-export class GraphqlQueryFindOneResolverService {
- private twentyORMGlobalManager: TwentyORMGlobalManager;
-
- constructor(twentyORMGlobalManager: TwentyORMGlobalManager) {
- this.twentyORMGlobalManager = twentyORMGlobalManager;
- }
+@Injectable()
+export class GraphqlQueryFindOneResolverService
+ implements ResolverService
+{
+ constructor(
+ private readonly twentyORMGlobalManager: TwentyORMGlobalManager,
+ ) {}
- async findOne<
+ async resolve<
ObjectRecord extends IRecord = IRecord,
Filter extends RecordFilter = RecordFilter,
>(
args: FindOneResolverArgs,
options: WorkspaceQueryRunnerOptions,
- ): Promise {
- const { authContext, objectMetadataItem, info, objectMetadataCollection } =
+ ): Promise {
+ const { authContext, objectMetadataMapItem, info, objectMetadataMap } =
options;
const dataSource =
@@ -43,37 +49,28 @@ export class GraphqlQueryFindOneResolverService {
);
const repository = dataSource.getRepository(
- objectMetadataItem.nameSingular,
+ objectMetadataMapItem.nameSingular,
);
const queryBuilder = repository.createQueryBuilder(
- objectMetadataItem.nameSingular,
- );
-
- const objectMetadataMap = generateObjectMetadataMap(
- objectMetadataCollection,
- );
-
- const objectMetadata = getObjectMetadataOrThrow(
- objectMetadataMap,
- objectMetadataItem.nameSingular,
+ objectMetadataMapItem.nameSingular,
);
const graphqlQueryParser = new GraphqlQueryParser(
- objectMetadata.fields,
+ objectMetadataMapItem.fields,
objectMetadataMap,
);
const selectedFields = graphqlFields(info);
const { relations } = graphqlQueryParser.parseSelectedFields(
- objectMetadataItem,
+ objectMetadataMapItem,
selectedFields,
);
const withFilterQueryBuilder = graphqlQueryParser.applyFilterToBuilder(
queryBuilder,
- objectMetadataItem.nameSingular,
+ objectMetadataMapItem.nameSingular,
args.filter ?? ({} as Filter),
);
@@ -86,12 +83,10 @@ export class GraphqlQueryFindOneResolverService {
const objectRecord = formatResult(
nonFormattedObjectRecord,
- objectMetadata,
+ objectMetadataMapItem,
objectMetadataMap,
);
- const limit = QUERY_MAX_RECORDS;
-
if (!objectRecord) {
throw new GraphqlQueryRunnerException(
'Record not found',
@@ -99,32 +94,42 @@ export class GraphqlQueryFindOneResolverService {
);
}
- const processNestedRelationsHelper = new ProcessNestedRelationsHelper(
- this.twentyORMGlobalManager,
- );
+ const processNestedRelationsHelper = new ProcessNestedRelationsHelper();
const objectRecords = [objectRecord];
if (relations) {
await processNestedRelationsHelper.processNestedRelations(
objectMetadataMap,
- objectMetadata,
+ objectMetadataMapItem,
objectRecords,
relations,
- limit,
+ QUERY_MAX_RECORDS,
authContext,
dataSource,
);
}
const typeORMObjectRecordsParser =
- new ObjectRecordsToGraphqlConnectionMapper(objectMetadataMap);
+ new ObjectRecordsToGraphqlConnectionHelper(objectMetadataMap);
return typeORMObjectRecordsParser.processRecord(
objectRecords[0],
- objectMetadataItem.nameSingular,
+ objectMetadataMapItem.nameSingular,
1,
1,
) as ObjectRecord;
}
+
+ async validate(
+ args: FindOneResolverArgs,
+ _options: WorkspaceQueryRunnerOptions,
+ ): Promise {
+ if (!args.filter || Object.keys(args.filter).length === 0) {
+ throw new WorkspaceQueryRunnerException(
+ 'Missing filter argument',
+ WorkspaceQueryRunnerExceptionCode.INVALID_QUERY_INPUT,
+ );
+ }
+ }
}
diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-search-resolver.service.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-search-resolver.service.ts
index c8d1892bbd2b..fe9d86f6cd84 100644
--- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-search-resolver.service.ts
+++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-search-resolver.service.ts
@@ -1,3 +1,6 @@
+import { Injectable } from '@nestjs/common';
+
+import { ResolverService } from 'src/engine/api/graphql/graphql-query-runner/interfaces/resolver-service.interface';
import {
Record as IRecord,
OrderByDirection,
@@ -11,47 +14,25 @@ import {
GraphqlQueryRunnerException,
GraphqlQueryRunnerExceptionCode,
} from 'src/engine/api/graphql/graphql-query-runner/errors/graphql-query-runner.exception';
-import { ObjectRecordsToGraphqlConnectionMapper } from 'src/engine/api/graphql/graphql-query-runner/orm-mappers/object-records-to-graphql-connection.mapper';
+import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper';
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
import { SEARCH_VECTOR_FIELD } from 'src/engine/metadata-modules/constants/search-vector-field.constants';
-import { generateObjectMetadataMap } from 'src/engine/metadata-modules/utils/generate-object-metadata-map.util';
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
-export class GraphqlQuerySearchResolverService {
- private twentyORMGlobalManager: TwentyORMGlobalManager;
- private featureFlagService: FeatureFlagService;
-
+@Injectable()
+export class GraphqlQuerySearchResolverService
+ implements ResolverService>
+{
constructor(
- twentyORMGlobalManager: TwentyORMGlobalManager,
- featureFlagService: FeatureFlagService,
- ) {
- this.twentyORMGlobalManager = twentyORMGlobalManager;
- this.featureFlagService = featureFlagService;
- }
+ private readonly twentyORMGlobalManager: TwentyORMGlobalManager,
+ private readonly featureFlagService: FeatureFlagService,
+ ) {}
- async search(
+ async resolve(
args: SearchResolverArgs,
options: WorkspaceQueryRunnerOptions,
): Promise> {
- const { authContext, objectMetadataItem, objectMetadataCollection } =
- options;
-
- const featureFlagsForWorkspace =
- await this.featureFlagService.getWorkspaceFeatureFlags(
- authContext.workspace.id,
- );
-
- const isQueryRunnerTwentyORMEnabled =
- featureFlagsForWorkspace.IS_QUERY_RUNNER_TWENTY_ORM_ENABLED;
-
- const isSearchEnabled = featureFlagsForWorkspace.IS_SEARCH_ENABLED;
-
- if (!isQueryRunnerTwentyORMEnabled || !isSearchEnabled) {
- throw new GraphqlQueryRunnerException(
- 'This endpoint is not available yet, please use findMany instead.',
- GraphqlQueryRunnerExceptionCode.INVALID_QUERY_INPUT,
- );
- }
+ const { authContext, objectMetadataItem, objectMetadataMap } = options;
const repository =
await this.twentyORMGlobalManager.getRepositoryForWorkspace(
@@ -59,21 +40,8 @@ export class GraphqlQuerySearchResolverService {
objectMetadataItem.nameSingular,
);
- const objectMetadataMap = generateObjectMetadataMap(
- objectMetadataCollection,
- );
-
- const objectMetadata = objectMetadataMap[objectMetadataItem.nameSingular];
-
- if (!objectMetadata) {
- throw new GraphqlQueryRunnerException(
- `Object metadata not found for ${objectMetadataItem.nameSingular}`,
- GraphqlQueryRunnerExceptionCode.OBJECT_METADATA_NOT_FOUND,
- );
- }
-
const typeORMObjectRecordsParser =
- new ObjectRecordsToGraphqlConnectionMapper(objectMetadataMap);
+ new ObjectRecordsToGraphqlConnectionHelper(objectMetadataMap);
if (!args.searchInput) {
return typeORMObjectRecordsParser.createConnection(
@@ -100,7 +68,7 @@ export class GraphqlQuerySearchResolverService {
'DESC',
)
.setParameter('searchTerms', searchTerms)
- .limit(limit)
+ .take(limit)
.getMany()) as ObjectRecord[];
const objectRecords = await repository.formatResult(resultsWithTsVector);
@@ -129,4 +97,26 @@ export class GraphqlQuerySearchResolverService {
return formattedWords.join(' | ');
}
+
+ async validate(
+ _args: SearchResolverArgs,
+ options: WorkspaceQueryRunnerOptions,
+ ): Promise {
+ const featureFlagsForWorkspace =
+ await this.featureFlagService.getWorkspaceFeatureFlags(
+ options.authContext.workspace.id,
+ );
+
+ const isQueryRunnerTwentyORMEnabled =
+ featureFlagsForWorkspace.IS_QUERY_RUNNER_TWENTY_ORM_ENABLED;
+
+ const isSearchEnabled = featureFlagsForWorkspace.IS_SEARCH_ENABLED;
+
+ if (!isQueryRunnerTwentyORMEnabled || !isSearchEnabled) {
+ throw new GraphqlQueryRunnerException(
+ 'This endpoint is not available yet, please use findMany instead.',
+ GraphqlQueryRunnerExceptionCode.INVALID_QUERY_INPUT,
+ );
+ }
+ }
}
diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-update-many-resolver.service.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-update-many-resolver.service.ts
new file mode 100644
index 000000000000..d8854223794b
--- /dev/null
+++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-update-many-resolver.service.ts
@@ -0,0 +1,115 @@
+import { Injectable } from '@nestjs/common';
+
+import graphqlFields from 'graphql-fields';
+
+import { ResolverService } from 'src/engine/api/graphql/graphql-query-runner/interfaces/resolver-service.interface';
+import { Record as IRecord } from 'src/engine/api/graphql/workspace-query-builder/interfaces/record.interface';
+import { WorkspaceQueryRunnerOptions } from 'src/engine/api/graphql/workspace-query-runner/interfaces/query-runner-option.interface';
+import { UpdateManyResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
+
+import { QUERY_MAX_RECORDS } from 'src/engine/api/graphql/graphql-query-runner/constants/query-max-records.constant';
+import { GraphqlQueryParser } from 'src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query.parser';
+import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper';
+import { ProcessNestedRelationsHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/process-nested-relations.helper';
+import { assertIsValidUuid } from 'src/engine/api/graphql/workspace-query-runner/utils/assert-is-valid-uuid.util';
+import { assertMutationNotOnRemoteObject } from 'src/engine/metadata-modules/object-metadata/utils/assert-mutation-not-on-remote-object.util';
+import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
+import { formatData } from 'src/engine/twenty-orm/utils/format-data.util';
+import { formatResult } from 'src/engine/twenty-orm/utils/format-result.util';
+
+@Injectable()
+export class GraphqlQueryUpdateManyResolverService
+ implements ResolverService
+{
+ constructor(
+ private readonly twentyORMGlobalManager: TwentyORMGlobalManager,
+ ) {}
+
+ async resolve(
+ args: UpdateManyResolverArgs>,
+ options: WorkspaceQueryRunnerOptions,
+ ): Promise {
+ const { authContext, objectMetadataMapItem, objectMetadataMap, info } =
+ options;
+
+ const dataSource =
+ await this.twentyORMGlobalManager.getDataSourceForWorkspace(
+ authContext.workspace.id,
+ );
+
+ const repository = dataSource.getRepository(
+ objectMetadataMapItem.nameSingular,
+ );
+
+ const graphqlQueryParser = new GraphqlQueryParser(
+ objectMetadataMapItem.fields,
+ objectMetadataMap,
+ );
+
+ const selectedFields = graphqlFields(info);
+
+ const { relations } = graphqlQueryParser.parseSelectedFields(
+ objectMetadataMapItem,
+ selectedFields,
+ );
+
+ const queryBuilder = repository.createQueryBuilder(
+ objectMetadataMapItem.nameSingular,
+ );
+
+ const withFilterQueryBuilder = graphqlQueryParser.applyFilterToBuilder(
+ queryBuilder,
+ objectMetadataMapItem.nameSingular,
+ args.filter,
+ );
+
+ const data = formatData(args.data, objectMetadataMapItem);
+
+ const result = await withFilterQueryBuilder
+ .update(data)
+ .returning('*')
+ .execute();
+
+ const nonFormattedUpdatedObjectRecords = result.raw;
+
+ const updatedRecords = formatResult(
+ nonFormattedUpdatedObjectRecords,
+ objectMetadataMapItem,
+ objectMetadataMap,
+ );
+
+ const processNestedRelationsHelper = new ProcessNestedRelationsHelper();
+
+ if (relations) {
+ await processNestedRelationsHelper.processNestedRelations(
+ objectMetadataMap,
+ objectMetadataMapItem,
+ updatedRecords,
+ relations,
+ QUERY_MAX_RECORDS,
+ authContext,
+ dataSource,
+ );
+ }
+
+ const typeORMObjectRecordsParser =
+ new ObjectRecordsToGraphqlConnectionHelper(objectMetadataMap);
+
+ return updatedRecords.map((record: ObjectRecord) =>
+ typeORMObjectRecordsParser.processRecord(
+ record,
+ objectMetadataMapItem.nameSingular,
+ 1,
+ 1,
+ ),
+ );
+ }
+
+ async validate(
+ args: UpdateManyResolverArgs>,
+ options: WorkspaceQueryRunnerOptions,
+ ): Promise {
+ assertMutationNotOnRemoteObject(options.objectMetadataMapItem);
+ args.filter?.id?.in?.forEach((id: string) => assertIsValidUuid(id));
+ }
+}
diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-update-one-resolver.service.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-update-one-resolver.service.ts
new file mode 100644
index 000000000000..6fc4e1a72c58
--- /dev/null
+++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-update-one-resolver.service.ts
@@ -0,0 +1,121 @@
+import { Injectable } from '@nestjs/common';
+
+import graphqlFields from 'graphql-fields';
+
+import { ResolverService } from 'src/engine/api/graphql/graphql-query-runner/interfaces/resolver-service.interface';
+import { Record as IRecord } from 'src/engine/api/graphql/workspace-query-builder/interfaces/record.interface';
+import { WorkspaceQueryRunnerOptions } from 'src/engine/api/graphql/workspace-query-runner/interfaces/query-runner-option.interface';
+import { UpdateOneResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
+
+import { QUERY_MAX_RECORDS } from 'src/engine/api/graphql/graphql-query-runner/constants/query-max-records.constant';
+import {
+ GraphqlQueryRunnerException,
+ GraphqlQueryRunnerExceptionCode,
+} from 'src/engine/api/graphql/graphql-query-runner/errors/graphql-query-runner.exception';
+import { GraphqlQueryParser } from 'src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query.parser';
+import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper';
+import { ProcessNestedRelationsHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/process-nested-relations.helper';
+import { assertIsValidUuid } from 'src/engine/api/graphql/workspace-query-runner/utils/assert-is-valid-uuid.util';
+import { assertMutationNotOnRemoteObject } from 'src/engine/metadata-modules/object-metadata/utils/assert-mutation-not-on-remote-object.util';
+import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
+import { formatData } from 'src/engine/twenty-orm/utils/format-data.util';
+import { formatResult } from 'src/engine/twenty-orm/utils/format-result.util';
+
+@Injectable()
+export class GraphqlQueryUpdateOneResolverService
+ implements ResolverService
+{
+ constructor(
+ private readonly twentyORMGlobalManager: TwentyORMGlobalManager,
+ ) {}
+
+ async resolve(
+ args: UpdateOneResolverArgs>,
+ options: WorkspaceQueryRunnerOptions,
+ ): Promise {
+ const { authContext, objectMetadataMapItem, objectMetadataMap, info } =
+ options;
+
+ const dataSource =
+ await this.twentyORMGlobalManager.getDataSourceForWorkspace(
+ authContext.workspace.id,
+ );
+
+ const repository = dataSource.getRepository(
+ objectMetadataMapItem.nameSingular,
+ );
+
+ const graphqlQueryParser = new GraphqlQueryParser(
+ objectMetadataMapItem.fields,
+ objectMetadataMap,
+ );
+
+ const selectedFields = graphqlFields(info);
+
+ const { relations } = graphqlQueryParser.parseSelectedFields(
+ objectMetadataMapItem,
+ selectedFields,
+ );
+
+ const queryBuilder = repository.createQueryBuilder(
+ objectMetadataMapItem.nameSingular,
+ );
+
+ const data = formatData(args.data, objectMetadataMapItem);
+
+ const result = await queryBuilder
+ .update(data)
+ .where({ id: args.id })
+ .returning('*')
+ .execute();
+
+ const nonFormattedUpdatedObjectRecords = result.raw;
+
+ const updatedRecords = formatResult(
+ nonFormattedUpdatedObjectRecords,
+ objectMetadataMapItem,
+ objectMetadataMap,
+ );
+
+ if (updatedRecords.length === 0) {
+ throw new GraphqlQueryRunnerException(
+ 'Record not found',
+ GraphqlQueryRunnerExceptionCode.RECORD_NOT_FOUND,
+ );
+ }
+
+ const updatedRecord = updatedRecords[0] as ObjectRecord;
+
+ const processNestedRelationsHelper = new ProcessNestedRelationsHelper();
+
+ if (relations) {
+ await processNestedRelationsHelper.processNestedRelations(
+ objectMetadataMap,
+ objectMetadataMapItem,
+ [updatedRecord],
+ relations,
+ QUERY_MAX_RECORDS,
+ authContext,
+ dataSource,
+ );
+ }
+
+ const typeORMObjectRecordsParser =
+ new ObjectRecordsToGraphqlConnectionHelper(objectMetadataMap);
+
+ return typeORMObjectRecordsParser.processRecord(
+ updatedRecord,
+ objectMetadataMapItem.nameSingular,
+ 1,
+ 1,
+ );
+ }
+
+ async validate(
+ args: UpdateOneResolverArgs>,
+ options: WorkspaceQueryRunnerOptions,
+ ): Promise {
+ assertMutationNotOnRemoteObject(options.objectMetadataMapItem);
+ assertIsValidUuid(args.id);
+ }
+}
diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/services/api-event-emitter.service.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/services/api-event-emitter.service.ts
new file mode 100644
index 000000000000..8cb2c9cc7a04
--- /dev/null
+++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/services/api-event-emitter.service.ts
@@ -0,0 +1,137 @@
+import { Injectable } from '@nestjs/common';
+
+import { Record as IRecord } from 'src/engine/api/graphql/workspace-query-builder/interfaces/record.interface';
+import { ObjectMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/object-metadata.interface';
+
+import { AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type';
+import { WorkspaceEventEmitter } from 'src/engine/workspace-event-emitter/workspace-event-emitter';
+
+@Injectable()
+export class ApiEventEmitterService {
+ constructor(private readonly workspaceEventEmitter: WorkspaceEventEmitter) {}
+
+ public emitCreateEvents(
+ records: T[],
+ authContext: AuthContext,
+ objectMetadataItem: ObjectMetadataInterface,
+ ): void {
+ this.workspaceEventEmitter.emit(
+ `${objectMetadataItem.nameSingular}.created`,
+ records.map((record) => ({
+ userId: authContext.user?.id,
+ recordId: record.id,
+ objectMetadata: objectMetadataItem,
+ properties: {
+ before: null,
+ after: this.removeGraphQLAndNestedProperties(record),
+ },
+ })),
+ authContext.workspace.id,
+ );
+ }
+
+ public emitUpdateEvents(
+ existingRecords: T[],
+ records: T[],
+ updatedFields: string[],
+ authContext: AuthContext,
+ objectMetadataItem: ObjectMetadataInterface,
+ ): void {
+ const mappedExistingRecords = existingRecords.reduce(
+ (acc, { id, ...record }) => ({
+ ...acc,
+ [id]: record,
+ }),
+ {},
+ );
+
+ this.workspaceEventEmitter.emit(
+ `${objectMetadataItem.nameSingular}.updated`,
+ records.map((record) => {
+ return {
+ userId: authContext.user?.id,
+ recordId: record.id,
+ objectMetadata: objectMetadataItem,
+ properties: {
+ before: mappedExistingRecords[record.id]
+ ? this.removeGraphQLAndNestedProperties(
+ mappedExistingRecords[record.id],
+ )
+ : undefined,
+ after: this.removeGraphQLAndNestedProperties(record),
+ updatedFields,
+ },
+ };
+ }),
+ authContext.workspace.id,
+ );
+ }
+
+ public emitDeletedEvents(
+ records: T[],
+ authContext: AuthContext,
+ objectMetadataItem: ObjectMetadataInterface,
+ ): void {
+ this.workspaceEventEmitter.emit(
+ `${objectMetadataItem.nameSingular}.deleted`,
+ records.map((record) => {
+ return {
+ userId: authContext.user?.id,
+ recordId: record.id,
+ objectMetadata: objectMetadataItem,
+ properties: {
+ before: this.removeGraphQLAndNestedProperties(record),
+ after: null,
+ },
+ };
+ }),
+ authContext.workspace.id,
+ );
+ }
+
+ public emitDestroyEvents(
+ records: T[],
+ authContext: AuthContext,
+ objectMetadataItem: ObjectMetadataInterface,
+ ): void {
+ this.workspaceEventEmitter.emit(
+ `${objectMetadataItem.nameSingular}.destroyed`,
+ records.map((record) => {
+ return {
+ userId: authContext.user?.id,
+ recordId: record.id,
+ objectMetadata: objectMetadataItem,
+ properties: {
+ before: this.removeGraphQLAndNestedProperties(record),
+ after: null,
+ },
+ };
+ }),
+ authContext.workspace.id,
+ );
+ }
+
+ private removeGraphQLAndNestedProperties(
+ record: ObjectRecord,
+ ) {
+ if (!record) {
+ return {};
+ }
+
+ const sanitizedRecord = {};
+
+ for (const [key, value] of Object.entries(record)) {
+ if (value && typeof value === 'object' && value['edges']) {
+ continue;
+ }
+
+ if (key === '__typename') {
+ continue;
+ }
+
+ sanitizedRecord[key] = value;
+ }
+
+ return sanitizedRecord;
+ }
+}
diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/utils/cursors.util.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/utils/cursors.util.ts
index bf8eb52d0a57..bd27522ce1b2 100644
--- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/utils/cursors.util.ts
+++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/utils/cursors.util.ts
@@ -2,6 +2,7 @@ import {
Record as IRecord,
RecordOrderBy,
} from 'src/engine/api/graphql/workspace-query-builder/interfaces/record.interface';
+import { FindManyResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
import {
GraphqlQueryRunnerException,
@@ -44,3 +45,25 @@ export const encodeCursor = (
return Buffer.from(JSON.stringify(cursorData)).toString('base64');
};
+
+export const getCursor = (
+ args: FindManyResolverArgs,
+): Record | undefined => {
+ if (args.after) return decodeCursor(args.after);
+ if (args.before) return decodeCursor(args.before);
+
+ return undefined;
+};
+
+export const getPaginationInfo = (
+ objectRecords: any[],
+ limit: number,
+ isForwardPagination: boolean,
+) => {
+ const hasMoreRecords = objectRecords.length > limit;
+
+ return {
+ hasNextPage: isForwardPagination && hasMoreRecords,
+ hasPreviousPage: !isForwardPagination && hasMoreRecords,
+ };
+};
diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/interfaces/query-runner-option.interface.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/interfaces/query-runner-option.interface.ts
index 45883f99ddf3..d960c3d45a7f 100644
--- a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/interfaces/query-runner-option.interface.ts
+++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/interfaces/query-runner-option.interface.ts
@@ -4,6 +4,10 @@ import { FieldMetadataInterface } from 'src/engine/metadata-modules/field-metada
import { ObjectMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/object-metadata.interface';
import { AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type';
+import {
+ ObjectMetadataMap,
+ ObjectMetadataMapItem,
+} from 'src/engine/metadata-modules/utils/generate-object-metadata-map.util';
export interface WorkspaceQueryRunnerOptions {
authContext: AuthContext;
@@ -11,4 +15,6 @@ export interface WorkspaceQueryRunnerOptions {
objectMetadataItem: ObjectMetadataInterface;
fieldMetadataCollection: FieldMetadataInterface[];
objectMetadataCollection: ObjectMetadataInterface[];
+ objectMetadataMap: ObjectMetadataMap;
+ objectMetadataMapItem: ObjectMetadataMapItem;
}
diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-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
index b75c939d1ac7..034c73bda552 100644
--- a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-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
@@ -9,6 +9,7 @@ import {
FindManyResolverArgs,
FindOneResolverArgs,
RestoreManyResolverArgs,
+ SearchResolverArgs,
UpdateManyResolverArgs,
UpdateOneResolverArgs,
} from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
@@ -42,4 +43,6 @@ export type WorkspacePreQueryHookPayload = T extends 'createMany'
? DestroyManyResolverArgs
: T extends 'destroyOne'
? DestroyOneResolverArgs
- : never;
+ : T extends 'search'
+ ? SearchResolverArgs
+ : never;
diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/create-many-resolver.factory.ts b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/create-many-resolver.factory.ts
index 872ab7906fca..06a8d5507b2d 100644
--- a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/create-many-resolver.factory.ts
+++ b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/create-many-resolver.factory.ts
@@ -1,5 +1,6 @@
import { Injectable } from '@nestjs/common';
+import { WorkspaceQueryRunnerOptions } from 'src/engine/api/graphql/workspace-query-runner/interfaces/query-runner-option.interface';
import { WorkspaceResolverBuilderFactoryInterface } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolver-builder-factory.interface';
import {
CreateManyResolverArgs,
@@ -32,12 +33,14 @@ export class CreateManyResolverFactory
return async (_source, args, _context, info) => {
try {
- const options = {
+ const options: WorkspaceQueryRunnerOptions = {
authContext: internalContext.authContext,
objectMetadataItem: internalContext.objectMetadataItem,
info,
fieldMetadataCollection: internalContext.fieldMetadataCollection,
objectMetadataCollection: internalContext.objectMetadataCollection,
+ objectMetadataMap: internalContext.objectMetadataMap,
+ objectMetadataMapItem: internalContext.objectMetadataMapItem,
};
const isQueryRunnerTwentyORMEnabled =
diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/create-one-resolver.factory.ts b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/create-one-resolver.factory.ts
index edf9206a1cde..5922d05550d6 100644
--- a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/create-one-resolver.factory.ts
+++ b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/create-one-resolver.factory.ts
@@ -1,5 +1,6 @@
import { Injectable } from '@nestjs/common';
+import { WorkspaceQueryRunnerOptions } from 'src/engine/api/graphql/workspace-query-runner/interfaces/query-runner-option.interface';
import { WorkspaceResolverBuilderFactoryInterface } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolver-builder-factory.interface';
import {
CreateOneResolverArgs,
@@ -32,12 +33,14 @@ export class CreateOneResolverFactory
return async (_source, args, _context, info) => {
try {
- const options = {
+ const options: WorkspaceQueryRunnerOptions = {
authContext: internalContext.authContext,
objectMetadataItem: internalContext.objectMetadataItem,
info,
fieldMetadataCollection: internalContext.fieldMetadataCollection,
objectMetadataCollection: internalContext.objectMetadataCollection,
+ objectMetadataMap: internalContext.objectMetadataMap,
+ objectMetadataMapItem: internalContext.objectMetadataMapItem,
};
const isQueryRunnerTwentyORMEnabled =
@@ -50,13 +53,7 @@ export class CreateOneResolverFactory
return await this.graphqlQueryRunnerService.createOne(args, options);
}
- return await this.workspaceQueryRunnerService.createOne(args, {
- authContext: internalContext.authContext,
- objectMetadataItem: internalContext.objectMetadataItem,
- info,
- fieldMetadataCollection: internalContext.fieldMetadataCollection,
- objectMetadataCollection: internalContext.objectMetadataCollection,
- });
+ return await this.workspaceQueryRunnerService.createOne(args, options);
} catch (error) {
workspaceQueryRunnerGraphqlApiExceptionHandler(error);
}
diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/delete-many-resolver.factory.ts b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/delete-many-resolver.factory.ts
index a8d36f3e4900..4a32ad5ea1c5 100644
--- a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/delete-many-resolver.factory.ts
+++ b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/delete-many-resolver.factory.ts
@@ -1,5 +1,6 @@
import { Injectable } from '@nestjs/common';
+import { WorkspaceQueryRunnerOptions } from 'src/engine/api/graphql/workspace-query-runner/interfaces/query-runner-option.interface';
import { WorkspaceResolverBuilderFactoryInterface } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolver-builder-factory.interface';
import {
DeleteManyResolverArgs,
@@ -7,8 +8,11 @@ import {
} from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
import { WorkspaceSchemaBuilderContext } from 'src/engine/api/graphql/workspace-schema-builder/interfaces/workspace-schema-builder-context.interface';
+import { GraphqlQueryRunnerService } from 'src/engine/api/graphql/graphql-query-runner/graphql-query-runner.service';
import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util';
import { WorkspaceQueryRunnerService } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-runner.service';
+import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
+import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
@Injectable()
export class DeleteManyResolverFactory
@@ -18,6 +22,8 @@ export class DeleteManyResolverFactory
constructor(
private readonly workspaceQueryRunnerService: WorkspaceQueryRunnerService,
+ private readonly featureFlagService: FeatureFlagService,
+ private readonly graphqlQueryRunnerService: GraphqlQueryRunnerService,
) {}
create(
@@ -27,13 +33,27 @@ export class DeleteManyResolverFactory
return async (_source, args, context, info) => {
try {
- return await this.workspaceQueryRunnerService.deleteMany(args, {
+ const options: WorkspaceQueryRunnerOptions = {
authContext: internalContext.authContext,
objectMetadataItem: internalContext.objectMetadataItem,
info,
fieldMetadataCollection: internalContext.fieldMetadataCollection,
objectMetadataCollection: internalContext.objectMetadataCollection,
- });
+ objectMetadataMap: internalContext.objectMetadataMap,
+ objectMetadataMapItem: internalContext.objectMetadataMapItem,
+ };
+
+ const isQueryRunnerTwentyORMEnabled =
+ await this.featureFlagService.isFeatureEnabled(
+ FeatureFlagKey.IsQueryRunnerTwentyORMEnabled,
+ internalContext.authContext.workspace.id,
+ );
+
+ if (isQueryRunnerTwentyORMEnabled) {
+ return await this.graphqlQueryRunnerService.deleteMany(args, options);
+ }
+
+ return await this.workspaceQueryRunnerService.deleteMany(args, options);
} catch (error) {
workspaceQueryRunnerGraphqlApiExceptionHandler(error);
}
diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/delete-one-resolver.factory.ts b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/delete-one-resolver.factory.ts
index 93f249cdd6ac..d58ebe02fd56 100644
--- a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/delete-one-resolver.factory.ts
+++ b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/delete-one-resolver.factory.ts
@@ -1,5 +1,6 @@
import { Injectable } from '@nestjs/common';
+import { WorkspaceQueryRunnerOptions } from 'src/engine/api/graphql/workspace-query-runner/interfaces/query-runner-option.interface';
import { WorkspaceResolverBuilderFactoryInterface } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolver-builder-factory.interface';
import {
DeleteOneResolverArgs,
@@ -7,8 +8,11 @@ import {
} from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
import { WorkspaceSchemaBuilderContext } from 'src/engine/api/graphql/workspace-schema-builder/interfaces/workspace-schema-builder-context.interface';
+import { GraphqlQueryRunnerService } from 'src/engine/api/graphql/graphql-query-runner/graphql-query-runner.service';
import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util';
import { WorkspaceQueryRunnerService } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-runner.service';
+import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
+import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
@Injectable()
export class DeleteOneResolverFactory
@@ -18,6 +22,8 @@ export class DeleteOneResolverFactory
constructor(
private readonly workspaceQueryRunnerService: WorkspaceQueryRunnerService,
+ private readonly featureFlagService: FeatureFlagService,
+ private readonly graphqlQueryRunnerService: GraphqlQueryRunnerService,
) {}
create(
@@ -27,13 +33,27 @@ export class DeleteOneResolverFactory
return async (_source, args, context, info) => {
try {
- return await this.workspaceQueryRunnerService.deleteOne(args, {
+ const options: WorkspaceQueryRunnerOptions = {
authContext: internalContext.authContext,
objectMetadataItem: internalContext.objectMetadataItem,
info,
fieldMetadataCollection: internalContext.fieldMetadataCollection,
objectMetadataCollection: internalContext.objectMetadataCollection,
- });
+ objectMetadataMap: internalContext.objectMetadataMap,
+ objectMetadataMapItem: internalContext.objectMetadataMapItem,
+ };
+
+ const isQueryRunnerTwentyORMEnabled =
+ await this.featureFlagService.isFeatureEnabled(
+ FeatureFlagKey.IsQueryRunnerTwentyORMEnabled,
+ internalContext.authContext.workspace.id,
+ );
+
+ if (isQueryRunnerTwentyORMEnabled) {
+ return await this.graphqlQueryRunnerService.deleteOne(args, options);
+ }
+
+ return await this.workspaceQueryRunnerService.deleteOne(args, options);
} catch (error) {
workspaceQueryRunnerGraphqlApiExceptionHandler(error);
}
diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/destroy-many-resolver.factory.ts b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/destroy-many-resolver.factory.ts
index 4a064a406b9b..2e6cf835effa 100644
--- a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/destroy-many-resolver.factory.ts
+++ b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/destroy-many-resolver.factory.ts
@@ -1,5 +1,6 @@
import { Injectable } from '@nestjs/common';
+import { WorkspaceQueryRunnerOptions } from 'src/engine/api/graphql/workspace-query-runner/interfaces/query-runner-option.interface';
import { WorkspaceResolverBuilderFactoryInterface } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolver-builder-factory.interface';
import {
DestroyManyResolverArgs,
@@ -27,13 +28,20 @@ export class DestroyManyResolverFactory
return async (_source, args, context, info) => {
try {
- return await this.workspaceQueryRunnerService.destroyMany(args, {
+ const options: WorkspaceQueryRunnerOptions = {
authContext: internalContext.authContext,
objectMetadataItem: internalContext.objectMetadataItem,
info,
fieldMetadataCollection: internalContext.fieldMetadataCollection,
objectMetadataCollection: internalContext.objectMetadataCollection,
- });
+ objectMetadataMap: internalContext.objectMetadataMap,
+ objectMetadataMapItem: internalContext.objectMetadataMapItem,
+ };
+
+ return await this.workspaceQueryRunnerService.destroyMany(
+ args,
+ options,
+ );
} catch (error) {
workspaceQueryRunnerGraphqlApiExceptionHandler(error);
}
diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/destroy-one-resolver.factory.ts b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/destroy-one-resolver.factory.ts
index 4c204d6e8c0c..bb1e2aaaa9ba 100644
--- a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/destroy-one-resolver.factory.ts
+++ b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/destroy-one-resolver.factory.ts
@@ -1,5 +1,6 @@
import { Injectable } from '@nestjs/common';
+import { WorkspaceQueryRunnerOptions } from 'src/engine/api/graphql/workspace-query-runner/interfaces/query-runner-option.interface';
import { WorkspaceResolverBuilderFactoryInterface } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolver-builder-factory.interface';
import {
DestroyOneResolverArgs,
@@ -27,13 +28,17 @@ export class DestroyOneResolverFactory
return async (_source, args, context, info) => {
try {
- return await this.graphQLQueryRunnerService.destroyOne(args, {
+ const options: WorkspaceQueryRunnerOptions = {
authContext: internalContext.authContext,
objectMetadataItem: internalContext.objectMetadataItem,
info,
fieldMetadataCollection: internalContext.fieldMetadataCollection,
objectMetadataCollection: internalContext.objectMetadataCollection,
- });
+ objectMetadataMap: internalContext.objectMetadataMap,
+ objectMetadataMapItem: internalContext.objectMetadataMapItem,
+ };
+
+ return await this.graphQLQueryRunnerService.destroyOne(args, options);
} catch (error) {
workspaceQueryRunnerGraphqlApiExceptionHandler(error);
}
diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/find-duplicates-resolver.factory.ts b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/find-duplicates-resolver.factory.ts
index 0a1494efb666..f8b57ad22cca 100644
--- a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/find-duplicates-resolver.factory.ts
+++ b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/find-duplicates-resolver.factory.ts
@@ -1,5 +1,6 @@
import { Injectable } from '@nestjs/common';
+import { WorkspaceQueryRunnerOptions } from 'src/engine/api/graphql/workspace-query-runner/interfaces/query-runner-option.interface';
import { WorkspaceResolverBuilderFactoryInterface } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolver-builder-factory.interface';
import {
FindDuplicatesResolverArgs,
@@ -7,8 +8,11 @@ import {
} from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
import { WorkspaceSchemaBuilderContext } from 'src/engine/api/graphql/workspace-schema-builder/interfaces/workspace-schema-builder-context.interface';
+import { GraphqlQueryRunnerService } from 'src/engine/api/graphql/graphql-query-runner/graphql-query-runner.service';
import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util';
import { WorkspaceQueryRunnerService } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-runner.service';
+import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
+import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
@Injectable()
export class FindDuplicatesResolverFactory
@@ -18,6 +22,8 @@ export class FindDuplicatesResolverFactory
constructor(
private readonly workspaceQueryRunnerService: WorkspaceQueryRunnerService,
+ private readonly featureFlagService: FeatureFlagService,
+ private readonly graphqlQueryRunnerService: GraphqlQueryRunnerService,
) {}
create(
@@ -27,13 +33,33 @@ export class FindDuplicatesResolverFactory
return async (_source, args, context, info) => {
try {
- return await this.workspaceQueryRunnerService.findDuplicates(args, {
+ const options: WorkspaceQueryRunnerOptions = {
authContext: internalContext.authContext,
objectMetadataItem: internalContext.objectMetadataItem,
info,
fieldMetadataCollection: internalContext.fieldMetadataCollection,
objectMetadataCollection: internalContext.objectMetadataCollection,
- });
+ objectMetadataMap: internalContext.objectMetadataMap,
+ objectMetadataMapItem: internalContext.objectMetadataMapItem,
+ };
+
+ const isQueryRunnerTwentyORMEnabled =
+ await this.featureFlagService.isFeatureEnabled(
+ FeatureFlagKey.IsQueryRunnerTwentyORMEnabled,
+ internalContext.authContext.workspace.id,
+ );
+
+ if (isQueryRunnerTwentyORMEnabled) {
+ return await this.graphqlQueryRunnerService.findDuplicates(
+ args,
+ options,
+ );
+ }
+
+ return await this.workspaceQueryRunnerService.findDuplicates(
+ args,
+ options,
+ );
} catch (error) {
workspaceQueryRunnerGraphqlApiExceptionHandler(error);
}
diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/find-many-resolver.factory.ts b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/find-many-resolver.factory.ts
index 2dd452a2976c..c695079e2f62 100644
--- a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/find-many-resolver.factory.ts
+++ b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/find-many-resolver.factory.ts
@@ -1,5 +1,6 @@
import { Injectable } from '@nestjs/common';
+import { WorkspaceQueryRunnerOptions } from 'src/engine/api/graphql/workspace-query-runner/interfaces/query-runner-option.interface';
import { WorkspaceResolverBuilderFactoryInterface } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolver-builder-factory.interface';
import {
FindManyResolverArgs,
@@ -27,12 +28,14 @@ export class FindManyResolverFactory
return async (_source, args, _context, info) => {
try {
- const options = {
+ const options: WorkspaceQueryRunnerOptions = {
authContext: internalContext.authContext,
objectMetadataItem: internalContext.objectMetadataItem,
info,
fieldMetadataCollection: internalContext.fieldMetadataCollection,
objectMetadataCollection: internalContext.objectMetadataCollection,
+ objectMetadataMap: internalContext.objectMetadataMap,
+ objectMetadataMapItem: internalContext.objectMetadataMapItem,
};
return await this.graphqlQueryRunnerService.findMany(args, options);
diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/find-one-resolver.factory.ts b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/find-one-resolver.factory.ts
index 3dbbc2330d06..00845e841710 100644
--- a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/find-one-resolver.factory.ts
+++ b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/find-one-resolver.factory.ts
@@ -1,5 +1,6 @@
import { Injectable } from '@nestjs/common';
+import { WorkspaceQueryRunnerOptions } from 'src/engine/api/graphql/workspace-query-runner/interfaces/query-runner-option.interface';
import { WorkspaceResolverBuilderFactoryInterface } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolver-builder-factory.interface';
import {
FindOneResolverArgs,
@@ -27,12 +28,14 @@ export class FindOneResolverFactory
return async (_source, args, _context, info) => {
try {
- const options = {
+ const options: WorkspaceQueryRunnerOptions = {
authContext: internalContext.authContext,
objectMetadataItem: internalContext.objectMetadataItem,
info,
fieldMetadataCollection: internalContext.fieldMetadataCollection,
objectMetadataCollection: internalContext.objectMetadataCollection,
+ objectMetadataMap: internalContext.objectMetadataMap,
+ objectMetadataMapItem: internalContext.objectMetadataMapItem,
};
return await this.graphqlQueryRunnerService.findOne(args, options);
diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/restore-many-resolver.factory.ts b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/restore-many-resolver.factory.ts
index ceba95306aed..d92210040535 100644
--- a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/restore-many-resolver.factory.ts
+++ b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/restore-many-resolver.factory.ts
@@ -1,5 +1,6 @@
import { Injectable } from '@nestjs/common';
+import { WorkspaceQueryRunnerOptions } from 'src/engine/api/graphql/workspace-query-runner/interfaces/query-runner-option.interface';
import { WorkspaceResolverBuilderFactoryInterface } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolver-builder-factory.interface';
import {
Resolver,
@@ -7,8 +8,11 @@ import {
} from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
import { WorkspaceSchemaBuilderContext } from 'src/engine/api/graphql/workspace-schema-builder/interfaces/workspace-schema-builder-context.interface';
+import { GraphqlQueryRunnerService } from 'src/engine/api/graphql/graphql-query-runner/graphql-query-runner.service';
import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util';
import { WorkspaceQueryRunnerService } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-runner.service';
+import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
+import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
@Injectable()
export class RestoreManyResolverFactory
@@ -18,6 +22,8 @@ export class RestoreManyResolverFactory
constructor(
private readonly workspaceQueryRunnerService: WorkspaceQueryRunnerService,
+ private readonly featureFlagService: FeatureFlagService,
+ private readonly graphqlQueryRunnerService: GraphqlQueryRunnerService,
) {}
create(
@@ -27,13 +33,33 @@ export class RestoreManyResolverFactory
return async (_source, args, context, info) => {
try {
- return await this.workspaceQueryRunnerService.restoreMany(args, {
+ const options: WorkspaceQueryRunnerOptions = {
authContext: internalContext.authContext,
objectMetadataItem: internalContext.objectMetadataItem,
info,
fieldMetadataCollection: internalContext.fieldMetadataCollection,
objectMetadataCollection: internalContext.objectMetadataCollection,
- });
+ objectMetadataMap: internalContext.objectMetadataMap,
+ objectMetadataMapItem: internalContext.objectMetadataMapItem,
+ };
+
+ const isQueryRunnerTwentyORMEnabled =
+ await this.featureFlagService.isFeatureEnabled(
+ FeatureFlagKey.IsQueryRunnerTwentyORMEnabled,
+ internalContext.authContext.workspace.id,
+ );
+
+ if (isQueryRunnerTwentyORMEnabled) {
+ return await this.graphqlQueryRunnerService.restoreMany(
+ args,
+ options,
+ );
+ }
+
+ return await this.workspaceQueryRunnerService.restoreMany(
+ args,
+ options,
+ );
} catch (error) {
workspaceQueryRunnerGraphqlApiExceptionHandler(error);
}
diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/search-resolver-factory.ts b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/search-resolver-factory.ts
index 5b32d527960f..9d559b656194 100644
--- a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/search-resolver-factory.ts
+++ b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/search-resolver-factory.ts
@@ -1,5 +1,6 @@
import { Injectable } from '@nestjs/common';
+import { WorkspaceQueryRunnerOptions } from 'src/engine/api/graphql/workspace-query-runner/interfaces/query-runner-option.interface';
import { WorkspaceResolverBuilderFactoryInterface } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolver-builder-factory.interface';
import {
Resolver,
@@ -25,13 +26,17 @@ export class SearchResolverFactory
return async (_source, args, _context, info) => {
try {
- return await this.graphqlQueryRunnerService.search(args, {
+ const options: WorkspaceQueryRunnerOptions = {
authContext: internalContext.authContext,
objectMetadataItem: internalContext.objectMetadataItem,
info,
fieldMetadataCollection: internalContext.fieldMetadataCollection,
objectMetadataCollection: internalContext.objectMetadataCollection,
- });
+ objectMetadataMap: internalContext.objectMetadataMap,
+ objectMetadataMapItem: internalContext.objectMetadataMapItem,
+ };
+
+ return await this.graphqlQueryRunnerService.search(args, options);
} catch (error) {
workspaceQueryRunnerGraphqlApiExceptionHandler(error);
}
diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/update-many-resolver.factory.ts b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/update-many-resolver.factory.ts
index c2328d12ba05..11027e4cc4fd 100644
--- a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/update-many-resolver.factory.ts
+++ b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/update-many-resolver.factory.ts
@@ -1,5 +1,6 @@
import { Injectable } from '@nestjs/common';
+import { WorkspaceQueryRunnerOptions } from 'src/engine/api/graphql/workspace-query-runner/interfaces/query-runner-option.interface';
import { WorkspaceResolverBuilderFactoryInterface } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolver-builder-factory.interface';
import {
Resolver,
@@ -7,8 +8,11 @@ import {
} from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
import { WorkspaceSchemaBuilderContext } from 'src/engine/api/graphql/workspace-schema-builder/interfaces/workspace-schema-builder-context.interface';
+import { GraphqlQueryRunnerService } from 'src/engine/api/graphql/graphql-query-runner/graphql-query-runner.service';
import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util';
import { WorkspaceQueryRunnerService } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-runner.service';
+import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
+import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
@Injectable()
export class UpdateManyResolverFactory
@@ -18,6 +22,8 @@ export class UpdateManyResolverFactory
constructor(
private readonly workspaceQueryRunnerService: WorkspaceQueryRunnerService,
+ private readonly featureFlagService: FeatureFlagService,
+ private readonly graphqlQueryRunnerService: GraphqlQueryRunnerService,
) {}
create(
@@ -27,13 +33,27 @@ export class UpdateManyResolverFactory
return async (_source, args, context, info) => {
try {
- return await this.workspaceQueryRunnerService.updateMany(args, {
+ const options: WorkspaceQueryRunnerOptions = {
authContext: internalContext.authContext,
objectMetadataItem: internalContext.objectMetadataItem,
info,
fieldMetadataCollection: internalContext.fieldMetadataCollection,
objectMetadataCollection: internalContext.objectMetadataCollection,
- });
+ objectMetadataMap: internalContext.objectMetadataMap,
+ objectMetadataMapItem: internalContext.objectMetadataMapItem,
+ };
+
+ const isQueryRunnerTwentyORMEnabled =
+ await this.featureFlagService.isFeatureEnabled(
+ FeatureFlagKey.IsQueryRunnerTwentyORMEnabled,
+ internalContext.authContext.workspace.id,
+ );
+
+ if (isQueryRunnerTwentyORMEnabled) {
+ return await this.graphqlQueryRunnerService.updateMany(args, options);
+ }
+
+ return await this.workspaceQueryRunnerService.updateMany(args, options);
} catch (error) {
workspaceQueryRunnerGraphqlApiExceptionHandler(error);
}
diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/update-one-resolver.factory.ts b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/update-one-resolver.factory.ts
index c7a7dc6bacd6..13a2e4f714d1 100644
--- a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/update-one-resolver.factory.ts
+++ b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/update-one-resolver.factory.ts
@@ -1,5 +1,6 @@
import { Injectable } from '@nestjs/common';
+import { WorkspaceQueryRunnerOptions } from 'src/engine/api/graphql/workspace-query-runner/interfaces/query-runner-option.interface';
import { WorkspaceResolverBuilderFactoryInterface } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolver-builder-factory.interface';
import {
Resolver,
@@ -7,8 +8,11 @@ import {
} from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
import { WorkspaceSchemaBuilderContext } from 'src/engine/api/graphql/workspace-schema-builder/interfaces/workspace-schema-builder-context.interface';
+import { GraphqlQueryRunnerService } from 'src/engine/api/graphql/graphql-query-runner/graphql-query-runner.service';
import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util';
import { WorkspaceQueryRunnerService } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-runner.service';
+import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
+import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
@Injectable()
export class UpdateOneResolverFactory
@@ -18,6 +22,8 @@ export class UpdateOneResolverFactory
constructor(
private readonly workspaceQueryRunnerService: WorkspaceQueryRunnerService,
+ private readonly featureFlagService: FeatureFlagService,
+ private readonly graphqlQueryRunnerService: GraphqlQueryRunnerService,
) {}
create(
@@ -27,13 +33,27 @@ export class UpdateOneResolverFactory
return async (_source, args, context, info) => {
try {
- return await this.workspaceQueryRunnerService.updateOne(args, {
+ const options: WorkspaceQueryRunnerOptions = {
authContext: internalContext.authContext,
objectMetadataItem: internalContext.objectMetadataItem,
info,
fieldMetadataCollection: internalContext.fieldMetadataCollection,
objectMetadataCollection: internalContext.objectMetadataCollection,
- });
+ objectMetadataMap: internalContext.objectMetadataMap,
+ objectMetadataMapItem: internalContext.objectMetadataMapItem,
+ };
+
+ const isQueryRunnerTwentyORMEnabled =
+ await this.featureFlagService.isFeatureEnabled(
+ FeatureFlagKey.IsQueryRunnerTwentyORMEnabled,
+ internalContext.authContext.workspace.id,
+ );
+
+ if (isQueryRunnerTwentyORMEnabled) {
+ return await this.graphqlQueryRunnerService.updateOne(args, options);
+ }
+
+ return await this.workspaceQueryRunnerService.updateOne(args, options);
} catch (error) {
workspaceQueryRunnerGraphqlApiExceptionHandler(error);
}
diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/workspace-resolver.factory.ts b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/workspace-resolver.factory.ts
index 616c734581df..a652e3065c81 100644
--- a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/workspace-resolver.factory.ts
+++ b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/workspace-resolver.factory.ts
@@ -11,6 +11,7 @@ import { RestoreManyResolverFactory } from 'src/engine/api/graphql/workspace-res
import { SearchResolverFactory } from 'src/engine/api/graphql/workspace-resolver-builder/factories/search-resolver-factory';
import { UpdateManyResolverFactory } from 'src/engine/api/graphql/workspace-resolver-builder/factories/update-many-resolver.factory';
import { AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type';
+import { ObjectMetadataMap } from 'src/engine/metadata-modules/utils/generate-object-metadata-map.util';
import { getResolverName } from 'src/engine/utils/get-resolver-name.util';
import { CreateManyResolverFactory } from './factories/create-many-resolver.factory';
@@ -49,6 +50,7 @@ export class WorkspaceResolverFactory {
async create(
authContext: AuthContext,
objectMetadataCollection: ObjectMetadataInterface[],
+ objectMetadataMap: ObjectMetadataMap,
workspaceResolverBuilderMethods: WorkspaceResolverBuilderMethods,
): Promise {
const factories = new Map<
@@ -94,7 +96,9 @@ export class WorkspaceResolverFactory {
authContext,
objectMetadataItem: objectMetadata,
fieldMetadataCollection: objectMetadata.fields,
- objectMetadataCollection: objectMetadataCollection,
+ objectMetadataCollection,
+ objectMetadataMap,
+ objectMetadataMapItem: objectMetadataMap[objectMetadata.nameSingular],
});
}
@@ -117,7 +121,9 @@ export class WorkspaceResolverFactory {
authContext,
objectMetadataItem: objectMetadata,
fieldMetadataCollection: objectMetadata.fields,
- objectMetadataCollection: objectMetadataCollection,
+ objectMetadataCollection,
+ objectMetadataMap,
+ objectMetadataMapItem: objectMetadataMap[objectMetadata.nameSingular],
});
}
}
diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/interfaces/workspace-schema-builder-context.interface.ts b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/interfaces/workspace-schema-builder-context.interface.ts
index f5a6aec8b1a2..d0ab66983309 100644
--- a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/interfaces/workspace-schema-builder-context.interface.ts
+++ b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/interfaces/workspace-schema-builder-context.interface.ts
@@ -2,10 +2,16 @@ import { FieldMetadataInterface } from 'src/engine/metadata-modules/field-metada
import { ObjectMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/object-metadata.interface';
import { AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type';
+import {
+ ObjectMetadataMap,
+ ObjectMetadataMapItem,
+} from 'src/engine/metadata-modules/utils/generate-object-metadata-map.util';
export interface WorkspaceSchemaBuilderContext {
authContext: AuthContext;
- objectMetadataItem: ObjectMetadataInterface;
fieldMetadataCollection: FieldMetadataInterface[];
objectMetadataCollection: ObjectMetadataInterface[];
+ objectMetadataItem: ObjectMetadataInterface;
+ objectMetadataMap: ObjectMetadataMap;
+ objectMetadataMapItem: ObjectMetadataMapItem;
}
diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-schema.factory.ts b/packages/twenty-server/src/engine/api/graphql/workspace-schema.factory.ts
index 336fa825f81c..32a44ad4d26e 100644
--- a/packages/twenty-server/src/engine/api/graphql/workspace-schema.factory.ts
+++ b/packages/twenty-server/src/engine/api/graphql/workspace-schema.factory.ts
@@ -117,6 +117,7 @@ export class WorkspaceSchemaFactory {
const autoGeneratedResolvers = await this.workspaceResolverFactory.create(
authContext,
objectMetadataCollection,
+ objectMetadataMap,
workspaceResolverBuilderMethodNames,
);
const scalarsResolvers =
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
index 4fec6c7ab443..625da7f23b07 100644
--- 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
@@ -31,6 +31,9 @@ describe('mapFieldMetadataToGraphqlQuery', () => {
});
describe('should handle all field metadata types', () => {
Object.values(FieldMetadataType).forEach((fieldMetadataType) => {
+ if (fieldMetadataType === FieldMetadataType.TS_VECTOR) {
+ return;
+ }
it(`with field type ${fieldMetadataType}`, () => {
const field = {
type: fieldMetadataType,
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
index d7ed6f87bd85..48d021b5e689 100644
--- a/packages/twenty-server/src/engine/core-modules/duplicate/duplicate.service.ts
+++ b/packages/twenty-server/src/engine/core-modules/duplicate/duplicate.service.ts
@@ -1,15 +1,15 @@
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 { ObjectMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/object-metadata.interface';
import { settings } from 'src/engine/constants/settings';
+import { DUPLICATE_CRITERIA_COLLECTION } from 'src/engine/core-modules/duplicate/constants/duplicate-criteria.constants';
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 {
@@ -94,80 +94,4 @@ export class DuplicateService {
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,
- 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,
- ) {
- 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/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 5c885c312dfc..5f10e3be0d75 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
@@ -10,7 +10,8 @@ describe('computeSchemaComponents', () => {
it('should test all non-deprecated field types', () => {
expect(fields.map((field) => field.type)).toEqual(
Object.keys(FieldMetadataType).filter(
- (key) => key !== FieldMetadataType.LINK,
+ (key) =>
+ key !== FieldMetadataType.LINK && key !== FieldMetadataType.TS_VECTOR,
),
);
});
@@ -21,6 +22,7 @@ describe('computeSchemaComponents', () => {
] as ObjectMetadataEntity[]),
).toEqual({
ObjectName: {
+ description: undefined,
type: 'object',
properties: {
fieldUuid: {
@@ -195,6 +197,7 @@ describe('computeSchemaComponents', () => {
'API',
'IMPORT',
'MANUAL',
+ 'SYSTEM',
],
},
},
@@ -203,6 +206,7 @@ describe('computeSchemaComponents', () => {
required: ['fieldNumber'],
},
'ObjectName for Update': {
+ description: undefined,
type: 'object',
properties: {
fieldUuid: {
@@ -377,6 +381,7 @@ describe('computeSchemaComponents', () => {
'API',
'IMPORT',
'MANUAL',
+ 'SYSTEM',
],
},
},
@@ -384,6 +389,7 @@ describe('computeSchemaComponents', () => {
},
},
'ObjectName for Response': {
+ description: undefined,
type: 'object',
properties: {
fieldUuid: {
@@ -558,6 +564,7 @@ describe('computeSchemaComponents', () => {
'API',
'IMPORT',
'MANUAL',
+ 'SYSTEM',
],
},
workspaceMemberId: {
diff --git a/packages/twenty-server/src/engine/core-modules/serverless/drivers/utils/get-base-typescript-project-files.ts b/packages/twenty-server/src/engine/core-modules/serverless/drivers/utils/get-base-typescript-project-files.ts
index 8fed171beec6..3d3a8c2a8952 100644
--- a/packages/twenty-server/src/engine/core-modules/serverless/drivers/utils/get-base-typescript-project-files.ts
+++ b/packages/twenty-server/src/engine/core-modules/serverless/drivers/utils/get-base-typescript-project-files.ts
@@ -1,5 +1,5 @@
-import path, { join } from 'path';
import fs from 'fs/promises';
+import path, { join } from 'path';
import { ASSET_PATH } from 'src/constants/assets-path';
diff --git a/packages/twenty-server/src/engine/metadata-modules/field-metadata/composite-types/actor.composite-type.ts b/packages/twenty-server/src/engine/metadata-modules/field-metadata/composite-types/actor.composite-type.ts
index 1efa0eeffff5..80f4689aef74 100644
--- a/packages/twenty-server/src/engine/metadata-modules/field-metadata/composite-types/actor.composite-type.ts
+++ b/packages/twenty-server/src/engine/metadata-modules/field-metadata/composite-types/actor.composite-type.ts
@@ -12,6 +12,7 @@ export enum FieldActorSource {
API = 'API',
IMPORT = 'IMPORT',
MANUAL = 'MANUAL',
+ SYSTEM = 'SYSTEM',
}
export const actorCompositeType: CompositeType = {
diff --git a/packages/twenty-server/src/engine/metadata-modules/field-metadata/field-metadata-validation.service.ts b/packages/twenty-server/src/engine/metadata-modules/field-metadata/field-metadata-validation.service.ts
new file mode 100644
index 000000000000..81ede4ec4faa
--- /dev/null
+++ b/packages/twenty-server/src/engine/metadata-modules/field-metadata/field-metadata-validation.service.ts
@@ -0,0 +1,48 @@
+import { Injectable } from '@nestjs/common';
+
+import { FieldMetadataSettings } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata-settings.interface';
+
+import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
+import {
+ FieldMetadataException,
+ FieldMetadataExceptionCode,
+} from 'src/engine/metadata-modules/field-metadata/field-metadata.exception';
+
+@Injectable()
+export class FieldMetadataValidationService<
+ T extends FieldMetadataType | 'default' = 'default',
+> {
+ constructor() {}
+
+ validateSettingsOrThrow({
+ fieldType,
+ settings,
+ }: {
+ fieldType: FieldMetadataType;
+ settings: FieldMetadataSettings;
+ }) {
+ switch (fieldType) {
+ case FieldMetadataType.NUMBER:
+ this.validateNumberSettings(settings);
+ break;
+ default:
+ break;
+ }
+ }
+
+ private validateNumberSettings(settings: FieldMetadataSettings) {
+ if ('decimals' in settings) {
+ const { decimals } = settings;
+
+ if (
+ decimals !== undefined &&
+ (decimals < 0 || !Number.isInteger(decimals))
+ ) {
+ throw new FieldMetadataException(
+ `Decimals value "${decimals}" must be a positive integer`,
+ FieldMetadataExceptionCode.INVALID_FIELD_INPUT,
+ );
+ }
+ }
+ }
+}
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 377575ba9bfd..b6cb8e8ed1d7 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
@@ -12,6 +12,7 @@ import { ActorModule } from 'src/engine/core-modules/actor/actor.module';
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module';
import { FieldMetadataDTO } from 'src/engine/metadata-modules/field-metadata/dtos/field-metadata.dto';
+import { FieldMetadataValidationService } from 'src/engine/metadata-modules/field-metadata/field-metadata-validation.service';
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';
@@ -44,7 +45,11 @@ import { UpdateFieldInput } from './dtos/update-field.input';
TypeORMModule,
ActorModule,
],
- services: [IsFieldMetadataDefaultValue, FieldMetadataService],
+ services: [
+ IsFieldMetadataDefaultValue,
+ FieldMetadataService,
+ FieldMetadataValidationService,
+ ],
resolvers: [
{
EntityClass: FieldMetadataEntity,
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 ac2c5b1d438d..019cfcea7bdf 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
@@ -56,6 +56,7 @@ import { computeObjectTargetTable } from 'src/engine/utils/compute-object-target
import { WorkspaceMigrationRunnerService } from 'src/engine/workspace-manager/workspace-migration-runner/workspace-migration-runner.service';
import { ViewFieldWorkspaceEntity } from 'src/modules/view/standard-objects/view-field.workspace-entity';
+import { FieldMetadataValidationService } from './field-metadata-validation.service';
import {
FieldMetadataEntity,
FieldMetadataType,
@@ -82,6 +83,7 @@ export class FieldMetadataService extends TypeOrmQueryService(
+ fieldMetadataInput.type,
fieldMetadataInput,
objectMetadata,
);
@@ -391,6 +394,7 @@ export class FieldMetadataService extends TypeOrmQueryService(
+ existingFieldMetadata.type,
fieldMetadataInput,
objectMetadata,
);
@@ -707,7 +711,11 @@ export class FieldMetadataService extends TypeOrmQueryService(fieldMetadataInput: T, objectMetadata: ObjectMetadataEntity): T {
+ >(
+ fieldMetadataType: FieldMetadataType,
+ fieldMetadataInput: T,
+ objectMetadata: ObjectMetadataEntity,
+ ): T {
if (fieldMetadataInput.name) {
try {
validateFieldNameValidityOrThrow(fieldMetadataInput.name);
@@ -748,6 +756,13 @@ export class FieldMetadataService extends TypeOrmQueryService [
- {
- name: computeObjectTargetTable(createdObjectMetadata),
- action: WorkspaceMigrationTableActionType.CREATE,
- } satisfies WorkspaceMigrationTableAction,
// Add activity target relation
{
name: computeObjectTargetTable(activityTargetObjectMetadata),
diff --git a/packages/twenty-server/src/engine/twenty-orm/base.workspace-entity.ts b/packages/twenty-server/src/engine/twenty-orm/base.workspace-entity.ts
index d9a19a689301..53355304c346 100644
--- a/packages/twenty-server/src/engine/twenty-orm/base.workspace-entity.ts
+++ b/packages/twenty-server/src/engine/twenty-orm/base.workspace-entity.ts
@@ -55,5 +55,5 @@ export abstract class BaseWorkspaceEntity {
},
})
@WorkspaceIsNullable()
- deletedAt?: string | null;
+ deletedAt: string | null;
}
diff --git a/packages/twenty-server/src/engine/twenty-orm/utils/format-data.util.ts b/packages/twenty-server/src/engine/twenty-orm/utils/format-data.util.ts
index f6f31f32c9db..cd3851393678 100644
--- a/packages/twenty-server/src/engine/twenty-orm/utils/format-data.util.ts
+++ b/packages/twenty-server/src/engine/twenty-orm/utils/format-data.util.ts
@@ -1,9 +1,11 @@
-import { isPlainObject } from '@nestjs/common/utils/shared.utils';
+import { FieldMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata.interface';
import { compositeTypeDefinitions } from 'src/engine/metadata-modules/field-metadata/composite-types';
-import { computeCompositeColumnName } from 'src/engine/metadata-modules/field-metadata/utils/compute-column-name.util';
+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 { ObjectMetadataMapItem } from 'src/engine/metadata-modules/utils/generate-object-metadata-map.util';
-import { getCompositeFieldMetadataCollection } from 'src/engine/twenty-orm/utils/get-composite-field-metadata-collection';
+import { CompositeFieldMetadataType } from 'src/engine/metadata-modules/workspace-migration/factories/composite-column-action.factory';
+import { capitalize } from 'src/utils/capitalize';
export function formatData