Commit Graph

81 Commits

Author SHA1 Message Date
c9c2f32922 7154 deleted event is not emitted when calling destroyone (#7159)
Closes #7154
2024-09-27 15:52:04 +02:00
16bb1f22e4 Connect EventTracker to TB endpoint (#7240)
#7091 
EventTrackers send information of events to the TinyBird instance:

In order to test:

1. Set ANALYTICS_ENABLED= true and TELEMETRY_ENABLED=true in
evironment-variables.ts
2. Set the TINYBIRD_TOKEN in environment variables (go to TiniyBird
Tokens)
3. Log in to twenty's TinyBird and go to datasources/analytics_events in
twenty_analytics workspace
4. Run twenty and navigate it
5. New events will be logged in the datasources, containing their
timestamp, sessionId and payload.

<img width="1189" alt="Screenshot 2024-09-24 at 17 23 01"
src="https://github.com/user-attachments/assets/85375897-504d-4e75-98e4-98e6a9671f98">
Example of payload when user is not logged in

```
{"hostName":"localhost",
"pathname":"/welcome",
"locale":"en-US",
"userAgent":"Mozilla/5.0",
"href":"http://localhost:3001/welcome",
"referrer":"",
"timeZone":"Europe/Barcelona"}
```
Example of payload when user is logged in
```
{"userId":"2020202",
"workspaceId":"202",
"workspaceDisplayName":"Apple",
"workspaceDomainName":"apple.dev",
"hostName":"localhost",
"pathname":"/objects/companies",
"locale":"en-US",
"userAgent":"Mozilla/5.0Chrome/128.0.0.0Safari/537.36",
"href":"http://localhost:3001/objects/companies",
"referrer":"",
"timeZone":"Europe/Paris"}
```

---------

Co-authored-by: Félix Malfait <felix@twenty.com>
2024-09-26 10:53:10 +02:00
02618b3e6a Fix graphql query createMany resolver with nested relations (#7061)
Looks like insert() does not return foreign keys. We could eventually
call findMany after but it seems that's what save() is doing so I'm
replacing insert with save.
```typescript
/**
 * Flag to determine whether the entity that is being persisted
 * should be reloaded during the persistence operation.
 *
 * It will work only on databases which does not support RETURNING / OUTPUT statement.
 * Enabled by default.
 */
reload?: boolean;
```

Note: save() also does an upsert by default with no way to configure
that so if we want to keep that behaviour we will need to add a check
before
```typescript
if (args.upsert) {
    const existingRecords = await repository.findBy({
      id: Any(args.data.map((record) => record.id)),
    });
    ...
```

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2024-09-18 18:45:52 +02:00
9c885861a3 Add logs to troubleshoot performances issues 2024-09-18 00:10:35 +02:00
31dea498e9 Remove objectMetadata isSoftDeletable 2024-09-16 13:40:10 +02:00
37d85a716a [flexible-schema] Add createOne/createMany with upsert to graphql query runner (#7041)
## Context
This PR introduces createOne/createMany through the new graphql query
runner.
Trying to use twentyOrm wrapper as much as possible, in this case here
the args are already converted from "metadata-like" structure (including
composite fields) as graphql input to typeorm / raw columns (I had to
introduce a little fix there).

Keep in mind that I'm not using the new graphql query runner parsing
classes here, especially the selected-fields part, because typeorm
already returns all the record columns in the InsertResult object
(including default values such as id, createdAt, ...). That also means
relation objects will be returned as NULL in the gql response but we
don't handle nested creation for the moment so it should be fine.

Note: also removing the feature flag from findOne/findMany
2024-09-16 12:20:04 +02:00
3548751be2 Scaffold empty workflow (#6926)
- Create a workflow version when the user visits an empty workflow.
- If the trigger is not defined yet and the user selects either the
standard object type or the event type first, we automatically select
the first option of the other value. Indeed, every state update is
automatically saved on the backend and we need both standard object and
event types to save the event name.
- Introduces a change in the backend. I removed the assertions that
throw when a workflow version is not complete, that is, when it doesn't
have a defined trigger, which is the case when scaffolding a new
workflow with a first empty workflow version.
- We should keep validating the workflow versions, at least when we
publish them. That should be done in a second step.
2024-09-12 17:01:10 +02:00
3190f4a87b 6658 workflows add a first twenty piece email sender (#6965) 2024-09-12 11:00:25 +02:00
725ee837f9 Refactor graphql query runner + fix nested or (#6986) 2024-09-11 14:22:33 +02:00
1317e1c4f2 [Flexible-schema] Add findOne and fix findMany pagination + soft-delete for graphql-query-runner (#6978) 2024-09-11 11:29:56 +02:00
bc8c961e30 Fix restore event sent to webhooks (#6905)
We were sending the wrong event when restoring a record (delete instead
of create)
2024-09-05 14:21:14 +02:00
cd66ea74a2 6657 Refactor and fix blocklist (#6803)
Closes #6657
- Fix listeners
- Refactor jobs to take array of events
- Fix calendar events and messages deletion

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2024-08-31 16:38:47 +02:00
cd06ae20e8 chore(*): remove unused code (#6781)
The code removed in the PR was flagged as unused by the JetBrains
inspector.

I did a QA on the dev environment but other checks are highly
recommended.

There is one commit by scope to make the review easier.

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2024-08-29 18:16:50 +02:00
f6fd92adcb [POC] add graphql query runner (#6747)
## Context
The goal is to replace pg_graphql with our own ORM wrapper (TwentyORM).
This PR tries to add some parsing logic to convert graphql requests to
send to the ORM to replace pg_graphql implementation.

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2024-08-27 17:06:39 +02:00
da4bd73881 Fix logging error in webhook system 2024-08-21 20:12:14 +02:00
79641327f3 Fix webhook issue (#6711)
Fix
[#web](https://github.com/orgs/twentyhq/projects/1/views/3?pane=issue&itemId=75329194)

This PR does 2 things:
- migrate webhooks to TwentyORM
- Fix inversion between objectNameSingular and operation in webhook
eventName. It is stored as {objectNameSingular}.{operation} and we were
querying {operation}.{objectNameSingular}
2024-08-21 15:33:38 +02:00
091c0f83be 6619 modify event emitter to emit an array of events (#6625)
Closes #6619

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2024-08-20 19:44:29 +02:00
db54469c8a feat: soft delete (#6576)
Implement soft delete on standards and custom objects.
This is a temporary solution, when we drop `pg_graphql` we should rely
on the `softDelete` functions of TypeORM.

---------

Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
2024-08-16 21:20:02 +02:00
f2cc385710 Fix frontend tests (#6585)
Fix a few broken tests
2024-08-09 08:38:01 +02:00
dce5a64ec5 Fix images in note rich text (#6550)
## Before
<img width="439" alt="Screenshot 2024-08-06 at 11 20 06"
src="https://github.com/user-attachments/assets/d2aa9411-cdf4-4457-8997-7cbecb8fe7e3">

## After
<img width="501" alt="Screenshot 2024-08-06 at 11 20 09"
src="https://github.com/user-attachments/assets/a5a68fff-1542-4b62-939c-50070f15b692">
2024-08-07 11:45:17 +02:00
6432ad39b9 feat: add new ACTOR field type and createdBy standard fields (#6324)
This pull request introduces a new `FieldMetadataType` called `ACTOR`.
The primary objective of this new type is to add an extra column to the
following objects: `person`, `company`, `opportunity`, `note`, `task`,
and all custom objects.

This composite type contains three properties:

- `source`
    ```typescript
    export enum FieldActorSource {
      EMAIL = 'EMAIL',
      CALENDAR = 'CALENDAR',
      API = 'API',
      IMPORT = 'IMPORT',
      MANUAL = 'MANUAL',
    }
    ```
- `workspaceMemberId`
- This property can be `undefined` in some cases and refers to the
member who created the record.
- `name`
- Serves as a fallback if the `workspaceMember` is deleted and is used
for other source types like `API`.

### Functionality

The pre-hook system has been updated to allow real-time argument
updates. When a record is created, a pre-hook can now compute and update
the arguments accordingly. This enhancement enables the `createdBy`
field to be populated with the correct values based on the
`authContext`.

The `authContext` now includes:
- An optional User entity
- An optional ApiKey entity
- The workspace entity

This provides access to the necessary data for the `createdBy` field.

In the GraphQL API, only the `source` can be specified in the
`createdBy` input. This allows the front-end to specify the source when
creating records from a CSV file.

### Front-End Handling

On the front-end, `orderBy` and `filter` are only applied to the name
property of the `ACTOR` composite type. Currently, we are unable to
apply these operations to the workspace member relation. This means that
if a workspace member changes their first name or last name, there may
be a mismatch because the name will differ from the new one. The name
displayed on the screen is based on the workspace member entity when
available.

### Missing Components

Currently, this PR does not include a `createdBy` value for the `MAIL`
and `CALENDAR` sources. These records are created in a job, and at
present, we only have access to the workspaceId within the job. To
address this, we should use a function similar to
`loadServiceWithContext`, which was recently removed from `TwentyORM`.
This function would allow us to pass the `authContext` to the jobs
without disrupting existing jobs.
Another PR will be created to handle these cases.

### Related Issues

Fixes issue #5155.

### Additional Notes

This PR doesn't include the migrations of the current records and views.
Everything works properly when the database is reset but this part is
still missing for now. We'll add that in another PR.

- There is a minor issue: front-end tests are broken since this commit:
[80c0fc7ff1).

---------

Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
Co-authored-by: Charles Bochet <charles@twenty.com>
2024-08-03 15:43:31 +02:00
9cf08d912a Fix migration search path (#6520) 2024-08-02 21:34:20 +02:00
5870979bfa Fix missing encoding in workspace-logo, members, person (#6510) 2024-08-02 15:18:48 +02:00
676c902731 Fix timelineActivity updated fields (#6494)
## Context
We recently introduced the new twenty ORM and used it in the update
methods in the query runner.
Initially we were using pg_graphql to fetch the record before updating
it allowing us to compare the before and the after and create a diff.
This diff is then used for the timeline activity creation. Now,
twentyORM is doing the fetch and pg_graphql is still doing the update
and their responses are not exactly the same, which means the diff is
not working as intended (e.g date types were always in the diff due to
one being in Date format and the other as a string)

This PR introduces a updatedFields property to the update event which
comes from the input. This is not ideal as this won't work for API users
that send the whole payload but will be sufficient enough for our FE
that only sends modified fields. We then compare only those fields in
the diff.
2024-08-01 18:41:28 +02:00
a424c63476 file storage workspace id prefix (#6230)
closes https://github.com/twentyhq/twenty/issues/6155

just an idea, i guess this could work well, but im open for discussion

---------

Co-authored-by: Weiko <corentin@twenty.com>
2024-08-01 18:07:22 +02:00
ee14f25996 Add enable workflow trigger endpoint (#6443)
Basic endpoint that only returns a boolean currently and overrides the
previous listener.
2024-07-30 14:00:37 +02:00
3060eb4e1e Handle query runner errors (#6424)
- Throw service error from query runner
- Catch in resolver factories 
- Map to graphql errors

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2024-07-27 12:27:04 +02:00
d0201e17ac Fix: query runner orm (#6397)
Fix WorkspaceQueryRunner events using TwentyORM

Fix #6057

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2024-07-25 13:21:57 +02:00
7c6ca0e841 Fix api timeout (#6401) 2024-07-25 08:38:05 +02:00
11da718482 Refactor connected account module (#6225)
- Refactor connected account module
- Move blocklist into it's own module
- Move contact-creation-manager into it's own module

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2024-07-12 20:15:33 +02:00
1dff5bf957 Fix custom errors thrown as 500 (#6238)
We call convertExceptionToGraphQLError in the exception handler for http
exceptions but we don't take into account those that already are
graphqlErrors and because of that the logic of convertExceptionToGraphql
is to fallback to a 500.
Now if the exception is a BaseGraphqlError (custom graphql error we
throw in the code), we throw them directly.

BEFORE
<img width="957" alt="Screenshot 2024-07-12 at 15 33 03"
src="https://github.com/user-attachments/assets/22ddae13-4996-4ad3-8f86-dd17c2922ca8">


AFTER
<img width="923" alt="Screenshot 2024-07-12 at 15 32 01"
src="https://github.com/user-attachments/assets/d3d6db93-6d28-495c-a4b4-ba4e47d45abd">

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2024-07-12 17:56:21 +02:00
8e25a107fd Add new Address field to views containing deprecated address (#6205)
as per title, following introduction of new Address field, we want to
display the new field next to the deprecated field, for users to notice
the new field.

<img width="983" alt="Capture d’écran 2024-07-10 à 17 44 25"
src="https://github.com/twentyhq/twenty/assets/51697796/7b5309b4-b22d-4f32-8054-68bc7b0f3bb3">
2024-07-11 14:39:38 +02:00
34d13a7b58 Deprecate address standard field (#6087)
Closes #5916

---------

Co-authored-by: Weiko <corentin@twenty.com>
2024-07-10 18:07:18 +02:00
4c642a0bb8 Text-to-SQL proof of concept (#5788)
Added:
- An "Ask AI" command to the command menu.
- A simple GraphQL resolver that converts the user's question into a
relevant SQL query using an LLM, runs the query, and returns the result.

<img width="428" alt="Screenshot 2024-06-09 at 20 53 09"
src="https://github.com/twentyhq/twenty/assets/171685816/57127f37-d4a6-498d-b253-733ffa0d209f">

No security concerns have been addressed, this is only a
proof-of-concept and not intended to be enabled in production.

All changes are behind a feature flag called `IS_ASK_AI_ENABLED`.

---------

Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
2024-07-04 08:57:26 +02:00
f8dd2cc733 Reorganise calendar module (#6089)
Refactor Calendar into functional sub modules
<img width="437" alt="image"
src="https://github.com/twentyhq/twenty/assets/12035771/d9de3285-a226-4fe8-b3ef-2d8a21def2a5">

---------

Co-authored-by: bosiraphael <raphael.bosi@gmail.com>
2024-07-02 13:55:11 +02:00
1eb9c582f3 Rename mutation maximum affected records (#6042)
As per my last comment on https://github.com/twentyhq/twenty/pull/6039,
we decided to rename this var
2024-06-26 18:00:25 +02:00
cf67ed09d0 Upsert endpoint and CSV import upsert (#5970)
This PR introduces an `upsert` parameter (along the existing `data`
param) for `createOne` and `createMany` mutations.

When upsert is set to `true`, the function will look for records with
the same id if an id was passed. If not id was passed, it will leverage
the existing duplicate check mechanism to find a duplicate. If a record
is found, then the function will perform an update instead of a create.

Unfortunately I had to remove some nice tests that existing on the args
factory. Those tests where mostly testing the duplication rule
generation logic but through a GraphQL angle. Since I moved the
duplication rule logic to a dedicated service, if I kept the tests but
mocked the service we wouldn't really be testing anything useful. The
right path would be to create new tests for this service that compare
the JSON output and not the GraphQL output but I chose not to work on
this as it's equivalent to rewriting the tests from scratch and I have
other competing priorities.
2024-06-26 11:39:16 +02:00
7c2e745b45 feat: Dynamic hook registration for WorkspaceQueryHooks (#6008)
#### Overview

This PR introduces a new API for dynamically registering and executing
pre and post query hooks in the Workspace Query Hook system using the
`@WorkspaceQueryHook` decorator. This approach eliminates the need for
manual provider registration, and fix the issue of `undefined` or `null`
repository using `@InjectWorkspaceRepository`.

#### New API

**Define a Hook**

Use the `@WorkspaceQueryHook` decorator to define pre or post hooks:

```typescript
@WorkspaceQueryHook({
  key: `calendarEvent.findMany`,
  scope: Scope.REQUEST,
})
export class CalendarEventFindManyPreQueryHook implements WorkspaceQueryHookInstance {
  async execute(userId: string, workspaceId: string, payload: FindManyResolverArgs): Promise<void> {
    if (!payload?.filter?.id?.eq) {
      throw new BadRequestException('id filter is required');
    }

    // Implement hook logic here
  }
}
```

This API simplifies the registration and execution of query hooks,
providing a more flexible and maintainable approach.

---------

Co-authored-by: Weiko <corentin@twenty.com>
2024-06-25 12:41:46 +02:00
9228667a57 Add the support of Empty and Non-Empty filter (#5773) 2024-06-20 18:18:12 +02:00
d99b9d1d6b feat: Enhancements to MessageQueue Module with Decorators (#5657)
### Overview

This PR introduces significant enhancements to the MessageQueue module
by integrating `@Processor`, `@Process`, and `@InjectMessageQueue`
decorators. These changes streamline the process of defining and
managing queue processors and job handlers, and also allow for
request-scoped handlers, improving compatibility with services that rely
on scoped providers like TwentyORM repositories.

### Key Features

1. **Decorator-based Job Handling**: Use `@Processor` and `@Process`
decorators to define job handlers declaratively.
2. **Request Scope Support**: Job handlers can be scoped per request,
enhancing integration with request-scoped services.

### Usage

#### Defining Processors and Job Handlers

The `@Processor` decorator is used to define a class that processes jobs
for a specific queue. The `@Process` decorator is applied to methods
within this class to define specific job handlers.

##### Example 1: Specific Job Handlers

```typescript
import { Processor, Process, InjectMessageQueue } from 'src/engine/integrations/message-queue';

@Processor('taskQueue')
export class TaskProcessor {

  @Process('taskA')
  async handleTaskA(job: { id: string, data: any }) {
    console.log(`Handling task A with data:`, job.data);
    // Logic for task A
  }

  @Process('taskB')
  async handleTaskB(job: { id: string, data: any }) {
    console.log(`Handling task B with data:`, job.data);
    // Logic for task B
  }
}
```

In the example above, `TaskProcessor` is responsible for processing jobs
in the `taskQueue`. The `handleTaskA` method will only be called for
jobs with the name `taskA`, while `handleTaskB` will be called for
`taskB` jobs.

##### Example 2: General Job Handler

```typescript
import { Processor, Process, InjectMessageQueue } from 'src/engine/integrations/message-queue';

@Processor('generalQueue')
export class GeneralProcessor {

  @Process()
  async handleAnyJob(job: { id: string, name: string, data: any }) {
    console.log(`Handling job ${job.name} with data:`, job.data);
    // Logic for any job
  }
}
```

In this example, `GeneralProcessor` handles all jobs in the
`generalQueue`, regardless of the job name. The `handleAnyJob` method
will be invoked for every job added to the `generalQueue`.

#### Adding Jobs to a Queue

You can use the `@InjectMessageQueue` decorator to inject a queue into a
service and add jobs to it.

##### Example:

```typescript
import { Injectable } from '@nestjs/common';
import { InjectMessageQueue, MessageQueue } from 'src/engine/integrations/message-queue';

@Injectable()
export class TaskService {
  constructor(
    @InjectMessageQueue('taskQueue') private readonly taskQueue: MessageQueue,
  ) {}

  async addTaskA(data: any) {
    await this.taskQueue.add('taskA', data);
  }

  async addTaskB(data: any) {
    await this.taskQueue.add('taskB', data);
  }
}
```

In this example, `TaskService` adds jobs to the `taskQueue`. The
`addTaskA` and `addTaskB` methods add jobs named `taskA` and `taskB`,
respectively, to the queue.

#### Using Scoped Job Handlers

To utilize request-scoped job handlers, specify the scope in the
`@Processor` decorator. This is particularly useful for services that
use scoped repositories like those in TwentyORM.

##### Example:

```typescript
import { Processor, Process, InjectMessageQueue, Scope } from 'src/engine/integrations/message-queue';

@Processor({ name: 'scopedQueue', scope: Scope.REQUEST })
export class ScopedTaskProcessor {

  @Process('scopedTask')
  async handleScopedTask(job: { id: string, data: any }) {
    console.log(`Handling scoped task with data:`, job.data);
    // Logic for scoped task, which might use request-scoped services
  }
}
```

Here, the `ScopedTaskProcessor` is associated with `scopedQueue` and
operates with request scope. This setup is essential when the job
handler relies on services that need to be instantiated per request,
such as scoped repositories.

### Migration Notes

- **Decorators**: Refactor job handlers to use `@Processor` and
`@Process` decorators.
- **Request Scope**: Utilize the scope option in `@Processor` if your
job handlers depend on request-scoped services.

Fix #5628

---------

Co-authored-by: Weiko <corentin@twenty.com>
2024-06-17 09:49:37 +02:00
93c17a8a5b Remove timelineActivity featureFlag (#5856) 2024-06-13 17:39:31 +02:00
374237a988 Refacto rest api, fix graphl playground, improve analytics (#5844)
- Improve the rest api by introducing startingAfter/endingBefore (we
previously had lastCursor), and moving pageInfo/totalCount outside of
the data object.
- Fix broken GraphQL playground on website
- Improve analytics by sending server url
2024-06-12 21:54:33 +02:00
bd22bfce2e Push event for user signup (#5837)
Need to setup Twenty as a CRM for Twenty the Twenty team
2024-06-12 12:35:46 +02:00
be96c68416 POC timeline activity (#5697)
TODO: 
- remove WorkspaceIsNotAuditLogged decorators on activity/activityTarget
to log task/note creations
- handle attachments
-  fix css and remove unnecessary styled components or duplicates
2024-06-11 18:53:28 +02:00
9567103d5f Remove check unique position (#5760)
Currently position can be the same for records displayed in a board
view.
Removing unicity check until we find a new startegy.
2024-06-06 11:00:46 +02:00
25f4e44aec Add backfill position job by workspace (#5725)
- Removing existing listener that was backfilling created records
without position
- Switch to a job that backfill all objects within workspace
- Adapting `FIND_BY_POSITION` so it can fetch objects without position.
Currently we needed to input a number
2024-06-04 14:10:58 +02:00
b1f12d7257 Fix input position backfill (#5731)
Some objects do not have position field so they should not be backfilled
2024-06-04 13:26:40 +02:00
2886664b62 Backfill position when not input (#5696)
- refactor record position factory and record position query factory
- override position if not present during createMany

To avoid overriding the same positions for all data in createMany, the
logic is:
- if inserted last, use last position + arg index + 1
- if inserted first, use first position - arg index - 1
2024-06-03 15:18:01 +02:00
eab8deb211 Rework messaging modules (#5710)
In this PR, I'm refactoring the messaging module into smaller pieces
that have **ONE** responsibility: import messages, clean messages,
handle message participant creation, instead of having ~30 modules (1
per service, jobs, cron, ...). This is mandatory to start introducing
drivers (gmails, office365, ...) IMO. It is too difficult to enforce
common interfaces as we have too many interfaces (30 modules...). All
modules should not be exposed

Right now, we have services that are almost functions:
do-that-and-this.service.ts / do-that-and-this.module.ts
I believe we should have something more organized at a high level and it
does not matter that much if we have a bit of code duplicates.

Note that the proposal is not fully implemented in the current PR that
has only focused on messaging folder (biggest part)

Here is the high level proposal:
- connected-account: token-refresher
- blocklist
- messaging: message-importer, message-cleaner, message-participants,
... (right now I'm keeping a big messaging-common but this will
disappear see below)
- calendar: calendar-importer, calendar-cleaner, ...

Consequences:
1) It's OK to re-implement several times some things. Example:
- error handling in connected-account, messaging, and calendar instead
of trying to unify. They are actually different error handling. The only
things that might be in common is the GmailError => CommonError parsing
and I'm not even sure it makes a lot of sense as these 3 apis might have
different format actually
- auto-creation. Calendar and Messaging could actually have different
rules

2) **We should not have circular dependencies:** 
- I believe this was the reason why we had so many modules, to be able
to cherry pick the one we wanted to avoid circular deps. This is not the
right approach IMO, we need architect the whole messaging by defining
high level blocks that won't have circular dependencies by design. If we
encounter one, we should rethink and break the block in a way that makes
sense.
- ex: connected-account.resolver is not in the same module as
token-refresher. ==> connected-account.resolver => message-importer (as
we trigger full sync job when we connect an account) => token-refresher
(as we refresh token on message import).

connected-account.resolver and token-refresher both in connected-account
folder but should be in different modules. Otherwise it's a circular
dependency. It does not mean that we should create 1 module per service
as it was done before

In a nutshell: The code needs to be thought in term of reponsibilities
and in a way that enforce high level interfaces (and avoid circular
dependencies)

Bonus: As you can see, this code is also removing a lot of code because
of the removal of many .module.ts (also because I'm removing the sync
scripts v2 feature flag end removing old code)
Bonus: I have prefixed services name with Messaging to improve dev xp.
GmailErrorHandler could be different between MessagingGmailErrorHandler
and CalendarGmailErrorHandler for instance
2024-06-03 11:16:05 +02:00
fbd8714c76 Make positions possibly negatives (#5690)
Closes https://github.com/twentyhq/twenty/issues/5427
2024-05-31 14:17:49 +02:00