Compare commits

...
194 Commits
Author SHA1 Message Date
Charles BochetandGitHub 8076ff5b82 Fix broken metadata sync due to index removal (#11706)
Changing strategy regarding disabling index creation with new relation
system
2025-04-23 18:06:19 +02:00
MarieandGitHub 4257f30f12 Permission checks on twentyORM global manager (#11477)
In this PR we are handling permissions when using
twentyORMGlobalManager,
and handling permissions for rest api and api key
2025-04-23 17:57:48 +02:00
Thomas TrompetteandGitHub 28a1354928 Allow webhook only on active versions (#11705)
- webhook call should only be allow on active versions
- fixing exceptions that are wrongly sent to sentry
2025-04-23 17:28:41 +02:00
Charles BochetandGitHub a2d2db441f Improve Filter chip empty state (#11704)
Cases:

<img width="477" alt="image"
src="https://github.com/user-attachments/assets/06da3efc-b878-499f-97de-570317caa9b7"
/>

<img width="477" alt="image"
src="https://github.com/user-attachments/assets/40114c16-2810-489d-a60f-2579e2916691"
/>

<img width="477" alt="image"
src="https://github.com/user-attachments/assets/fa80d7cf-7c2d-4c19-919e-2d4c78a9202b"
/>
2025-04-23 16:54:11 +02:00
Charles BochetandGitHub a4882089b1 Add is relation enabled to default feature flags (#11703) 2025-04-23 16:26:53 +02:00
Paul RastoinandGitHub f2828883ad Fix click outside dropdown content confirmation modal (#11702)
# Introduction
Closes https://github.com/twentyhq/twenty/issues/11674
2025-04-23 14:23:15 +00:00
Thomas TrompetteandGitHub 1333c64d98 Add diff in workflow update events + fix existing (#11700)
Closes https://github.com/twentyhq/twenty/issues/11676.

Diff should be available for objects displaying timeline activities. It
should also fit the existing type.
2025-04-23 15:43:41 +02:00
Félix MalfaitandGitHub e1054b0474 Fix clickhouse migration (#11699)
It looks like Clickhouse Cloud uses a different config var than the docs
2025-04-23 15:09:23 +02:00
Charles BochetandGitHub 457c6ed113 Improve storybook stories (#11694)
## Improvements

### TaskGroups

<img width="1512" alt="image"
src="https://github.com/user-attachments/assets/0dbd71fe-3999-4cf5-870e-565b8e2df1b9"
/>

### EventCardMessage

<img width="1512" alt="image"
src="https://github.com/user-attachments/assets/b41cddc1-3ff2-411f-9ac6-8d4035579e54"
/>

### Blocklist stories

<img width="1512" alt="image"
src="https://github.com/user-attachments/assets/e997a0c1-e7e2-4ea4-9253-f31609ee44df"
/>

### WorkflowEditActionUpdateRecord

<img width="1512" alt="image"
src="https://github.com/user-attachments/assets/275dab17-ad33-4174-8671-31ba455c20a4"
/>
2025-04-23 13:20:13 +02:00
Félix MalfaitandGitHub 93c2ba153b Add clickhouse prod migration command (#11695)
Add a missing command to launch clickhouse migrations the same way we
launch postgres migrations
2025-04-23 13:02:00 +02:00
martmullandGitHub b6e8103df7 Mime encode names in email headers (#11691)
# Before
<img width="618" alt="image"
src="https://github.com/user-attachments/assets/e6d7c0ac-10f8-4d2e-abe4-05bf86a2ea9e"
/>

# After
<img width="504" alt="image"
src="https://github.com/user-attachments/assets/db147cb9-be19-4d08-b357-cb554dc2a4ae"
/>

Fixes also Emojis encoding in Subject ->
<img width="540" alt="image"
src="https://github.com/user-attachments/assets/8c27743f-3a50-46eb-b0f3-492219bbd646"
/>

 Works with microsoft accounts
<img width="360" alt="image"
src="https://github.com/user-attachments/assets/d924440f-c107-4c1c-ad4d-b4b27016f102"
/>


Fixes https://github.com/twentyhq/twenty/issues/9194
2025-04-23 11:37:40 +02:00
EtienneandGitHub ea850f323a Fix inline cell interactions (#11686)
@bosiraphael I've slightly updated [your recent
pr](https://github.com/twentyhq/twenty/pull/11654)
- before
<img width="490" alt="Screenshot 2025-04-22 at 17 48 26"
src="https://github.com/user-attachments/assets/604d65df-5433-4524-bdc5-6f5083b3c045"
/>

- after
<img width="488" alt="Screenshot 2025-04-22 at 17 47 41"
src="https://github.com/user-attachments/assets/21273372-538e-454e-947b-09373d9e0d6d"
/>


closes https://github.com/twentyhq/core-team-issues/issues/831 and
https://github.com/twentyhq/core-team-issues/issues/828
2025-04-23 08:46:10 +00:00
Charles BochetandGitHub fa5f758228 Fix storybook / chromatic tests flakyness and integration tests (#11687)
## Storybook flakyness

### Actor Display image flakyness

<img width="1512" alt="image"
src="https://github.com/user-attachments/assets/875c0738-5e31-4aba-9231-4ba5f78d1355"
/>

**Fix:** stop using a random usage

### Task Groups broken

<img width="1512" alt="image"
src="https://github.com/user-attachments/assets/c67e47a1-a027-43f1-9601-68d61a8052b4"
/>

**Fix:** add missing TabListComponentInstance

## Flaky dates

Add https://github.com/k35o/storybook-addon-mock-date

## Integration tests

Fix broken tests due to relation refactoring
2025-04-23 01:57:36 +02:00
Félix MalfaitandGitHub 8694840b92 Rename webhook and open api urls (#11684)
We want to have fewer base path for routing.

We will have:
- /files
- /webhooks
- /graphql
- /metadata
- /rest
- /auth
- /healthz

I'm moving /open-api under /rest, and centralizing the webhooks
(removing /stripe and /cloudflare)
2025-04-22 22:24:26 +02:00
Paul RastoinandGitHub fba9ae6dfe Fallback undefined recordDataChip record name to empty string (#11685)
# Introduction
Closes #11682 

This seems to always has been quite flaky but this latest
[update](https://github.com/twentyhq/twenty/commit/f0de6d31b7b3b84671c3a5af8fd047ef7432666f#diff-63704155b77d9690a87a1ebd9f364bab7e7bb12afed7cc5a5516561ec3798f29L20)
seems to made the name optional.

As previously `undefined` being transpiles to a string results in
`"undefined"` which not a good thing neither 🙃 but wouldn't throw before
2025-04-22 20:17:44 +02:00
cc29c25176 feat: new relation sync-metadata, twenty-orm, create/update (#10217)
Fix
https://github.com/twentyhq/core-team-issues/issues/330#issue-2827026606
and
https://github.com/twentyhq/core-team-issues/issues/327#issue-2827001814

What this PR does when `isNewRelationEnabled` is set to `true`:
- [x] Drop the creation of the  foreign key as a `FieldMetadata`
- [x] Stop creating `RelationMetadata`
- [x] Properly fill `FieldMetadata` of type `RELATION` during the sync
command
- [x] Use new relation settings in TwentyORM
- [x] Properly create `FieldMetadata` relations when we create a new
object
- [x] Handle `database:reset` with new relations

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
Co-authored-by: Charles Bochet <charlesBochet@users.noreply.github.com>
2025-04-22 19:01:39 +02:00
Paul RastoinandGitHub de1489aabb Time line activity wrong type (#11673)
# Introduction
Closes https://github.com/twentyhq/core-team-issues/issues/874

`TimeLineActivity` fields `` and `` were typed as required whereas in
reality are nullable, resulting in the related sentry error.
Refactored the type then the related components in order to handle
nullable use case
2025-04-22 15:17:08 +00:00
Baptiste DevessierandGitHub efab98a8f8 Get all first depth fields in the table and the board (#11650)
After discussing it with the team, we now want to query all fields in
the table and the board by default. Feeding the cache with exhaustive
data will make the side panel's life easier, as it needs all the record
fields to determine the actions to enable.
2025-04-22 16:45:36 +02:00
Thomas TrompetteandGitHub 0b7024c94a Perform batch update on workflow runs (#11680)
Command times out on workflow versions with too many runs. Performing
batch update instead
2025-04-22 16:07:29 +02:00
EtienneandGitHub 5250d5c8d6 fix subscription item update (#11648)
closes
https://twenty-v7.sentry.io/issues/6550388239/?environment=prod&project=4507072499810304&query=is%3Aunresolved%20issue.priority%3A%5Bhigh%2C%20medium%5D&referrer=issue-stream&stream_index=6
2025-04-22 14:01:36 +02:00
Raphaël BosiandGitHub 87083cb414 834 Design Adjustments for the Record Page Breadcrumb (#11670)
# Design Adjustments for the Record Page Breadcrumb

Closes [834](https://github.com/twentyhq/core-team-issues/issues/834)
and [826](https://github.com/twentyhq/core-team-issues/issues/826)

## Description

- Added the breadcrumb to every object (not just the workflows)
- Fixed spacings
- Changed icon color from primary to tertiary for proper visual
hierarchy
- Displayed pagination information (current/total)
- Close button has been removed to simplify the UI
- Navigate to index page when the breadcrumb is clicked
- Fixed problems when two record title cells were displayed at the same
time (in the header and in the record page)

## Before

<img width="247" alt="Capture d’écran 2025-04-22 à 12 15 34"
src="https://github.com/user-attachments/assets/5ca2aca7-ffb0-49ea-8d3a-4bd621d78f8d"
/>

## After

<img width="233" alt="Capture d’écran 2025-04-22 à 12 15 06"
src="https://github.com/user-attachments/assets/cbcb5dfe-d616-47c9-8017-71dd4d388534"
/>
2025-04-22 13:52:56 +02:00
Raphaël BosiandGitHub 251a7b126b 838 design adjustments on table kanban and inline fields (#11654)
Closes [#838]( https://github.com/twentyhq/core-team-issues/issues/838)
Design adjustments on table kanban and inline fields.

The table row border selection will be done later since it is harder
than initially thought.
2025-04-22 11:15:53 +02:00
Thomas TrompetteandGitHub 33e0794da9 Update workflow statuses in real time (#11653)
Statuses are maintained by an async job. Those are calculations that we
would like to avoid using in both frontend and backend. Using push
updates are an easier way.



https://github.com/user-attachments/assets/31e44a82-08a8-4100-a38e-c965d5c73ee8
2025-04-22 11:03:12 +02:00
Ken LynchandGitHub 3ce3793129 Update glossary.mdx (#11661)
Remove extraneous AI response. :)
2025-04-22 10:17:16 +02:00
Félix MalfaitandGitHub aa2f3438fa Fix email verification (#11660)
Email verification modal had been broken and looked bad

I also added stories to make it more evident if this happens again
2025-04-20 14:18:43 +02:00
Félix MalfaitandGitHub 24873d0c1d Remove versions from package.json (#11658)
Now the source of truth for the version is set during the build process.
We set it as an environment variable from the tags.
We could add it back to the package.json during the build process (from
the git tag), but there is not use for it at the moment since it's not
npm packages.
2025-04-19 23:03:06 +02:00
Antoine MoreauxandGitHub 83434deb22 refactor(auth): optimize work email handling in sign-up flow (#11655)
Extracted isWorkEmail check into a variable for reusability and adjusted
subdomain generation to conditionally include email. This enhances code
readability and maintains logic consistency.
2025-04-19 15:28:41 +02:00
Baptiste DevessierandGitHub 826889715b Fix e2e tests (#11656)
After @bosiraphael's updates on the table, cells are duplicated when
they get the hover/focus. Playwright has a hard time finding which
element to click on.
I dislike my solution because it doesn't mimic how a real user would use
the application, but I couldn't find a better solution that wasn't
flaky.
2025-04-18 18:39:43 +02:00
MarieandGitHub f8b9e4d780 ignoreLock when recomputing rolePermissions when creating datasource (#11657)
[sentry](https://twenty-v7.sentry.io/issues/6545999328/?environment=prod&project=4507072499810304&query=is%3Aunresolved%20issue.priority%3A%5Bhigh%2C%20medium%5D&referrer=issue-stream&sort=date&stream_index=2)

Our workers have failing jobs because they are concurrently creating
datasources on different pods
While the datasources are independent, they read from the same redis
cache, with the same `RolesPermissionsOngoingCachingLock` value in
redis.
<img width="852" alt="Capture d’écran 2025-04-18 à 18 00 20"
src="https://github.com/user-attachments/assets/42ce8479-acc1-462b-af4c-b547cc2bb0b8"
/>
As a consequence they can fail to create a datasource: the first
datasource computes the permissions and sets ongoingCachingLock to true,
then the second arrives, there are still no available permissions in the
cache, but because of the lock it early returns without permissions and
fails. This behavior goes unnoticed on the product and helps
performances, but is annoying for workers as jobs are failing.

Let's remove the cache lock when creating the datasource !
2025-04-18 18:16:34 +02:00
8512904c0a refacto clickoutside componentv2 (#11644)
Switch to ComponentV2

Friday morning refacto & chill with @charles

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2025-04-18 17:48:30 +02:00
Félix MalfaitandGitHub cf5649a1df Deprecate Sentry release (#11651)
Let's deprecate Sentry Release and use APP_VERSION instead. 

It'll make it more clear in the interface to use named version for bug
analysis, than commit sha
2025-04-18 15:48:48 +02:00
martmullandGitHub fba4192d4b Fix rest api integration tests (#11645)
as title
2025-04-18 15:23:36 +02:00
16bd0425e0 i18n - translations (#11647)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2025-04-18 14:22:25 +02:00
MarieandGitHub fd750c7c0e Fix metadata cache flush (#11646)
Attempt to fix
https://twenty-v7.sentry.io/issues/6545999328/?environment=prod&project=4507072499810304&query=is%3Aunresolved%20issue.priority%3A%5Bhigh%2C%20medium%5D&referrer=issue-stream&sort=date&stream_index=2
2025-04-18 12:02:36 +00:00
Thomas TrompetteandGitHub 8112c3aab3 Fix workflow run executed by empty (#11642)
Workflow run executed by should not be empty when the workflow is
unamed. Adding Workflow as fallback

<img width="1072" alt="Capture d’écran 2025-04-17 à 19 17 12"
src="https://github.com/user-attachments/assets/e4cc3360-06e5-47e8-ba05-28a0eafab994"
/>
2025-04-18 09:26:51 +00:00
Antoine MoreauxandGitHub 8a2a004fb5 feat(settings): add domain validation effect and delete functionality (#11643)
Introduced a new effect component to validate custom domain DNS records
on mount, centralizing logic. Added a button to reset the custom domain
field, improving user control and form handling. Refactored related code
for maintainability and enhanced UI structure.

Fix https://github.com/twentyhq/core-team-issues/issues/853
2025-04-18 08:18:36 +00:00
oliverGitHubgreptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>Félix MalfaitFélix Malfait
53042cc9dc Date field format display (#11384)
## Introduction

This PR enables functionality discussed in [Layout Date
Formatting](https://github.com/twentyhq/core-team-issues/issues/97).

### TLDR;
It enables greater control of date formatting at the object's field
level by upgrading all DATE and DATE_TIME fields' settings from:

```ts
{
    displayAsRelativeDate: boolean
}
```

to:

```ts

type FieldDateDisplayFormat = 'full_date' | 'relative_date' | 'date' | 'time' | 'year' | 'custom'

{
    displayFormat: FieldDateDisplayFormat
}
```

PR also includes an upgrade command that will update any existing DATE
and DATE_TIME fields to the new settings value

---------

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: Félix Malfait <felix@twenty.com>
Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
2025-04-18 07:00:02 +00:00
Raphaël BosiandGitHub dd0ea2366f 839 Table focus refactoring (#11629)
# Table Focus Refactoring

This pull request implements the table focus refactoring requested in
[#839](https://github.com/twentyhq/core-team-issues/issues/839),
dissociating hover and focus behaviors in the table component to improve
keyboard navigation.

## Technical Implementation

- Created separate component states to handle focus and hover
independently.
- Updated all relevant hooks and functions to use the new focus
mechanism.
- Removed deprecated states and hooks.
- Introduced dedicated portal components to improve the table
performance (the table cells are much simpler and the more complex logic
is handled via the portals)

## Key Behavior Changes

- Performance improvements
- Focus is now handled exclusively with keyboard navigation
- Clicking on a cell or inline-cell now sets the focus to that cell
- Hover state is managed separately from focus, improving user
experience and accessibility
- The table scrolls when the focused cell changes

## Video



https://github.com/user-attachments/assets/9966beac-3b0f-4433-a87a-299506d83353
2025-04-17 16:40:24 +00:00
Thomas TrompetteandGitHub 18a89b5152 Set error on number field and prevent form from being submitted (#11637)
<img width="943" alt="Capture d’écran 2025-04-17 à 18 14 46"
src="https://github.com/user-attachments/assets/1208075e-937f-4224-886c-be578264d448"
/>
2025-04-17 18:39:18 +02:00
WeikoandGitHub 19da80d2e4 Fix logs in integration tests for unhandled exceptions without removing logger (#11635)
Setting a global exception filter for unhandled exceptions to avoid the
default Nest ExceptionsHandler being called (and logging exceptions)
2025-04-17 18:35:21 +02:00
WeikoandGitHub 3fe12cd8b5 Fix select default value not in options (#11622)
Also fixing a bunch of places where validation exceptions were not
properly handled
2025-04-17 18:34:31 +02:00
EtienneandGitHub dd1ac4deee Fix mismatching stripe subscription metadata plan/planKey (#11634)
for later : https://github.com/twentyhq/core-team-issues/issues/867
2025-04-17 18:21:35 +02:00
martmullandGitHub e4150ff3cb Fix logs in integration tests (#11632)
## Before
<img width="1512" alt="image"
src="https://github.com/user-attachments/assets/3e8be2e0-ac16-4735-8783-69c800bf0aaf"
/>

## After
<img width="1512" alt="image"
src="https://github.com/user-attachments/assets/1a83e7ce-d70a-43c4-a6cd-89dd456d80c1"
/>
2025-04-17 15:05:10 +00:00
Lucas BordeauGitHubgreptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
caf44207fd Implemented filter on FULL_NAME sub-fields (#11628)
This PR implements what's missing to have sub-field filtering.

There is a backend modification to save subFieldName, we just add this
field on view filter workspace entity.

This PR adds subFieldName where missing in frontend, notably in
applyFilter calls, that will be refactored soon.

Also fixes a bug in ViewBar where Add Filter button was at the right
side of the ViewBar, while it should be right after the chips section.

Another bug fixed where we wouldn't delete an empty record filter on
dropdown click outside from the view bar, which was already the case
where using the filter chip dropdown.

<img width="512" alt="image"
src="https://github.com/user-attachments/assets/e9a2f8d2-a66f-4800-853a-4df5c6b627a9"
/>

<img width="495" alt="image"
src="https://github.com/user-attachments/assets/7542697b-0689-4095-9c3c-b5e47875355f"
/>

---------

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2025-04-17 15:03:56 +00:00
Baptiste DevessierandGitHub 1ba0c24071 Set the page hotkey scope only once (#11626)
The `useEffect` in the `PageChangeEffect` component that sets the page's
hotkey scope is run 4-5 times every time the page changes. It should be
executed only once when the location changes. The re-runs are due to
unstable dependencies that shouldn't re-trigger the `useEffect`.

This PR minimizes the re-runs of the `useEffect`. In the following
video, I discuss a more global pattern.

The documentation for the `useEffectEvent` hook:
https://react.dev/learn/separating-events-from-effects#extracting-non-reactive-logic-out-of-effects.


https://github.com/user-attachments/assets/8c0c238b-f1c4-4bbb-b083-0825f7176599
2025-04-17 16:57:49 +02:00
Antoine MoreauxandGitHub 21c3edf8d6 fix(integration-tests): auth with multiworkspace and skip clickhouse … (#11630)
…tests
2025-04-17 14:49:57 +00:00
EtienneandGitHub a7b75c61e8 fix billing command - add workflow subscription item (#11631)
to migrate user with trialing or paused subscription status with trial
end behaviour 'paused'
2025-04-17 16:23:03 +02:00
f40aafb89f fix: reflect on #10521 changes to order-by-input-factory.ts file (#10662)
# This PR

Fixes an error on the FindMany REST API
I was getting the following error:
```
{
  "statusCode": 400,
  "error": "TypeError",
  "messages": [
    "Cannot read properties of undefined (reading 'fields')"
  ]
}
```
Now, it's working as expected
Related to #10521

cc: @Weiko @ijreilly

---------

Co-authored-by: Weiko <corentin@twenty.com>
2025-04-17 16:06:53 +02:00
42e060ac74 Ws poc (#11293)
related to https://github.com/twentyhq/core-team-issues/issues/601

## Done
- add a `onDbEvent` `Subscription` graphql endpoint to listen to
database_event using what we have done with webhooks:
- you can subscribe to any `action` (created, updated, ...) for any
`objectNameSingular` or a specific `recordId`. Parameters are nullable
and treated as wildcards when null.
  - returns events with following shape
```typescript
  @Field(() => String)
  eventId: string;

  @Field()
  emittedAt: string;

  @Field(() => DatabaseEventAction)
  action: DatabaseEventAction;

  @Field(() => String)
  objectNameSingular: string;

  @Field(() => GraphQLJSON)
  record: ObjectRecord;

  @Field(() => [String], { nullable: true })
  updatedFields?: string[];
```
- front provide a componentEffect `<ListenRecordUpdatesEffect />` that
listen for an `objectNameSingular`, a `recordId` and a list of
`listenedFields`. It subscribes to record updates and updates its apollo
cached value for specified `listenedFields`
- subscription is protected with credentials

## Result

Here is an application with `workflowRun`


https://github.com/user-attachments/assets/c964d857-3b54-495f-bf14-587ba26c5a8c

---------

Co-authored-by: prastoin <paul@twenty.com>
2025-04-17 16:03:51 +02:00
Thomas TrompetteandGitHub b112d06f66 Fix onClick on forms (#11624)
As title
2025-04-17 13:53:40 +00:00
Charles BochetandGitHub 56874bf84b Fix aggregate bar (#11620)
Closes https://github.com/twentyhq/twenty/issues/10943

Also adds stories:
<img width="1512" alt="image"
src="https://github.com/user-attachments/assets/377059b1-f6b5-4d8c-b7d1-e74e70448445"
/>
2025-04-17 15:29:20 +02:00
Thomas TrompetteandGitHub d2881bb4a2 Allow workflow field update when custom (#11619)
- Allow workflow field update when custom
- Also handle the case where object name is not defined in actions
2025-04-17 15:01:18 +02:00
GuillimandGitHub 1401f80081 Messaging : better logging (#11621)
Better error logging for messaging import exception handler.

Goal is to have better info on why Unknown errors are thrown and avoid
such messages `Unknown error occurred while importing messages for
message channel XXXXXXXX in workspace YYYYYYYYYY: Unknown error occurred
while importing messages for message channel XXXXXXXX...`
2025-04-17 14:16:05 +02:00
EtienneandGitHub 71dbd1d66b fix: re-init subscription items when user ends his trial period (#11616) 2025-04-17 13:53:37 +02:00
GuillimandGitHub 6e7956b990 logs removal (#11618)
view with Martin, not necessary any longer
2025-04-17 10:01:05 +00:00
martmullandGitHub 0469aba90b Improve from in send email action (#11581)
## Before
<img width="701" alt="image"
src="https://github.com/user-attachments/assets/77184775-5b06-4777-9276-1338cc457070"
/>

## After
<img width="705" alt="image"
src="https://github.com/user-attachments/assets/9528eb0e-54c3-452c-8297-27796ccc75a1"
/>
2025-04-17 11:34:55 +02:00
Antoine MoreauxandGitHub e457ade362 chore(constants): add TrackAnalytics to excluded operations (#11617)
Included TrackAnalytics in the list of excluded middleware operations.
This ensures consistent handling of operations that bypass middleware
processing.
2025-04-17 11:24:45 +02:00
Vaibhav DevereandGitHub 6023bda579 Drop await usage for now-synchronous encodeFileToken() (#11612)
### Remove unnecessary `await` from `encodeFileToken` calls (now
synchronous) #11611

####  Context

In [PR #11385 – commit
26c17f3](https://github.com/twentyhq/twenty/pull/11385/commits/26c17f3205eb0cf4b93dd37cfec97638596ed263),
`FileService.encodeFileToken()` was updated to be a **synchronous**
method. However, several places in the codebase were still calling it
using `await`.

####  Changes 
This PR cleans up those redundant `await` usages to:
- Improve clarity
- Avoid confusion (no longer awaiting a non-Promise)
- Slightly reduce overhead in affected functions
- Removed `await` from calls to `this.fileService.encodeFileToken(...)`
2025-04-17 10:55:54 +02:00
9e9ba73a43 better handling the function argument without touching it (#11614)
leave intact the `input` argument to avoid side effects on the parent
caller

---------

Co-authored-by: Charles Bochet <charlesBochet@users.noreply.github.com>
2025-04-17 08:54:56 +00:00
nitinandGitHub d89474d43b Fix tab icon alignment issue (#11613)
before:
![Screenshot 2025-04-17 at 13 40
00](https://github.com/user-attachments/assets/b29b3e6b-0185-4289-950c-37a24b63cb65)

after:
![Screenshot 2025-04-17 at 13 39
49](https://github.com/user-attachments/assets/af2efe6f-3908-40d6-acde-d2839a5a8ba2)
2025-04-17 10:29:51 +02:00
GuillimandGitHub b5e6600c73 Capitalize labels objectmetadata (#11609)
Capitalize labels singular and plural from objectmetadata

Fixes [#664](https://github.com/twentyhq/core-team-issues/issues/664)
2025-04-16 21:02:12 +00:00
thomasdnGitHubgreptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
3ad110da33 Added support for podman deployment (#11600)
Added files needed to deploy twenty on podman using podman-compose.

---------

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2025-04-16 22:08:14 +02:00
Antoine MoreauxandGitHub 587281a541 feat(analytics): add clickhouse (#11174) 2025-04-16 16:33:10 +00:00
b6901a49bf Fix-inline-height (#11608)
Follow up from inline height #11553 related to PR #11442


we had some issues with hover styles

Fixes
https://github.com/twentyhq/twenty/issues/11442#issuecomment-2805893663

---------

Co-authored-by: etiennejouan <jouan.etienne@gmail.com>
Co-authored-by: Charles Bochet <charles@twenty.com>
2025-04-16 17:49:04 +02:00
e1b99a6f39 Fix Account Owner Dropdown to Display Team Member Profile Pictures #11370 (#11385)
#11370  & #11402
### Changes made:
1. Updated search.service.ts to properly handle workspace member avatar
and Person Avatar URLs with authentication tokens
2. Integrated FileService for token generation
3. Added FileModule to SearchModule for dependency injection

### Implementation details:
- Used getImageUrlWithToken to append authentication tokens to avatar
URLs specifically for workspace members

---------

Co-authored-by: etiennejouan <jouan.etienne@gmail.com>
2025-04-16 17:46:37 +02:00
MarieandGitHub 4d78f5f97f [permissions] Improve performances using a cache for userWorkspaces roles (#11587)
In this PR we are 

- introducing a cached map `{ userworkspaceId: roleId } `to reduce calls
to get a userWorkspace's role (we were having N+1 around that with
combinedFindMany queries and generally having a lot of avoidable
queries)
- using the roles permissions cache (`{ roleId: { objectNameSingular:
{ canRead: bool, canUpdate: bool, ...} } `) in Permissions V1's
userHasObjectPermission, in order to 1) improve performances to avoid
calls to get roles 2) start using our permissions cache
2025-04-16 17:07:43 +02:00
Félix MalfaitandGitHub ab277476a8 Remove Sentry fingerprint (#11602)
As discussed this @ijreilly, Fingerprinting is probably not needed and
Sentry will do a better job by itself
2025-04-16 16:25:40 +02:00
nitinandGitHub c95a84c8e5 update KeyValuePairType enum and add IS_CONFIG_VAR_IN_DB_ENABLED config var (#11596)
closes https://github.com/twentyhq/core-team-issues/issues/758
2025-04-16 16:23:57 +02:00
Thomas TrompetteandGitHub 78e10b2da5 Update next step ids on step update (#11605)
When inserting a new step between step 1 et step 2, then step 1 should
have the new step as next step id, add stop having step 2.

When deleting a step, we link the parent and next steps together. It may
change in the future
2025-04-16 15:30:05 +02:00
bf704bd1bc Improve CSV import sub-field selection (#11601)
This PR adds a better UX for selecting sub-fields when importing CSV
files.

Before : 

<img width="395" alt="image"
src="https://github.com/user-attachments/assets/5a599e7d-ed07-4531-8306-9d70e7cfa37d"
/>

After : 

<img width="298" alt="image"
src="https://github.com/user-attachments/assets/2be8a1df-d089-4341-970e-6db2b269141e"
/>

<img width="296" alt="image"
src="https://github.com/user-attachments/assets/584285f4-4e71-4abd-9adf-11819cab0dc5"
/>

- A util `getSubFieldOptionKey` has been made to be able to reference
the sub field in the `options` object of the spreadsheet import.
- New components have been created :
`MatchColumnSelectFieldSelectDropdownContent`,
`MatchColumnSelectSubFieldSelectDropdownContent` and
`MatchColumnSelectV2`
- Extracted the hard-coded option do not import into a constant
`DO_NOT_IMPORT_OPTION_KEY`
- Passed `availableFieldMetadataItems` to spreadsheet global options so
it's available anywhere in the hierarchy of components.

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
Co-authored-by: Charles Bochet <charlesBochet@users.noreply.github.com>
2025-04-16 15:08:24 +02:00
Baptiste DevessierandGitHub b1c0613514 Fix execution permissions (#11604)
The PR https://github.com/twentyhq/twenty/pull/11400 introduced changes
to the execution permissions of many executable files. These changes
aren't correct and must be reverted.

cc. @charlesBochet
2025-04-16 11:46:37 +02:00
GuillimandGitHub db8a60fe6f more logging to look at calendar errors (#11603)
Adding more logs to look at calendar errors that we have currently

Should help investigation on
https://twenty-v7.sentry.io/issues/5182547220/events/7e8b168887384ede8397e79c15adeb50/?project=4507072499810304
2025-04-16 11:46:02 +02:00
b7cfe89b14 Onboarding doc update (#11599)
Co-authored-by: Weiko <corentin@twenty.com>
2025-04-16 09:55:57 +02:00
madanlal mohanrao nikaljeandGitHub 4c2c9e4273 Refactor webhook event name generation in OpenApiService (#11592)
Fixes - #11589
POT - 
![Screenshot 2025-04-16 at 12 39
11 AM](https://github.com/user-attachments/assets/43802e1a-1ece-4b44-831f-35d70285c5fb)
2025-04-16 08:03:47 +02:00
Charles Bochet 981b1bd767 Fix stories 2025-04-15 23:41:30 +02:00
Charles Bochet 53c6ddb2ad Fix stories 2025-04-15 19:05:14 +02:00
EtienneandGitHub 6f78a51da4 fix query param init before workspace redirection (#11590) 2025-04-15 18:47:26 +02:00
WeikoandGitHub 43af5ceb5e Add object level permission permissions to role page (ReadOnly) (#11568)
## Context
This PR adds the display of object-level permissions. A following PR
will add the ability to update those permissions.
The PR contains the SettingsRoleObjectLevel page but it's not fully
implemented yet (save won't trigger the corresponding mutation)

<img width="616" alt="Screenshot 2025-04-14 at 18 02 40"
src="https://github.com/user-attachments/assets/f8c58193-31f3-468a-a96d-f06a9f2e1423"
/>
2025-04-15 18:46:36 +02:00
Baptiste DevessierandGitHub c23942ce6f Order the workflow run's output properly in the JsonFieldDisplay (#11583)
In this PR:

- Order the workflow run's output in the JsonField Display; the order
should be: error, stepsOutput, flow
- Ensure the special characters are hidden in the JSON visualizer
- Add missing scenarios to Json Tree's stories as it ensures Chromatic
checks them


https://github.com/user-attachments/assets/2ca5ae1d-fdba-4327-bad2-246fd9d23cb9

Closes https://github.com/twentyhq/core-team-issues/issues/804
2025-04-15 18:40:53 +02:00
8bd7b78825 Moved Select Options to External Files (#11400)
This is a minor rework of PR #10738.

I noticed an inconsistency with how Select options are passed as props.
Many files use constants stored in external files to pass options props
to Select objects. This allows for code reusability. Some files are not
passing options in this format.

I modified more files so that they use this method of passing options
props. I made changes to:
- WorkerQueueMetricsSection.tsx 
- SettingsDataModelFieldBooleanForm.tsx 
- SettingsDataModelFieldTextForm.tsx 
- SettingsDataModelFieldNumberForm.tsx 
- PlaygroundSetupForm.tsx 
- ViewPickerContentCreateMode.tsx 

I also noticed that some of these files were incorrectly using
useLingui(), so I fixed the import and usage where needed.

---------

Co-authored-by: Beau Smith <bsmith26@iastate.edu>
Co-authored-by: Charles Bochet <charles@twenty.com>
2025-04-15 18:31:17 +02:00
EtienneandGitHub 797bb0559a create stripe customer before checking out + update on command (#11578)
two distincts fix in this PR

- add billing threshold for current users (in migration command)
- create stripe customer before checking out in order to enable cloud
user to create multiple workspaces (with associated stripe customer -
closes https://github.com/twentyhq/core-team-issues/issues/852)
2025-04-15 18:02:35 +02:00
Charles BochetandGitHub dee779179b Remove user action from waitFor in stories (#11588)
As per title:
- waitFor is a loop that waits for a condition to be filled, it should
be use to expect or in rare case to wait for element to be present in
the page (in most cases, you can use findByXXX)
- user actions should not be in this loop, otherwise they will be
triggered multiple times
2025-04-15 17:34:28 +02:00
Thomas TrompetteGitHubgreptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
c40baf036c Add command to backfill next step id on version and run steps (#11579)
- add next step id on step
- backfill next step id on step, except for the last one
- backfill flow for workflow run, when it exists

---------

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2025-04-15 15:26:58 +00:00
GuillimandGitHub d3922a7f5b removing RecordTableEmptyStateByGroupNoRecordAtAll (#11584)
We found out that `RecordTableEmptyStateByGroupNoRecordAtAll` was used
only when `hasRecordGroups` was true in "RecordTableEmptyState"

However the only parent component is RecordTableEmpty and called
RecordTableEmptyState when `hasRecordGroups` was false

Fixes https://github.com/twentyhq/core-team-issues/issues/833

Meaning never called at all
2025-04-15 16:52:09 +02:00
Charles BochetandGitHub 3c189688d0 Fix stories (#11585)
<img width="1512" alt="image"
src="https://github.com/user-attachments/assets/f77a006c-9538-4734-b80e-b58b9f5e7835"
/>
2025-04-15 16:11:31 +02:00
Lucas BordeauandGitHub aa399ca91e Fix a bug that overwrites currentRecordFilters when using URL filtered view (#11525)
This PR fixes a bug that happened when navigating to a filtered view
from a record show page related record section, clicking on 'All'.

The problem was that the QueryParamsFiltersEffect effect component was
overwriting the currentRecordFilter of a different object metadata item
than the current view.

Which when we navigated back on the original view, had emptied the
filters, while they shouldn't change if we only navigate without
refreshing the app.

Fixes https://github.com/twentyhq/core-team-issues/issues/657
2025-04-15 15:32:41 +02:00
GuillimandGitHub 5c23b52c0d multiline CSS aligned to the top (#11582)
Updating CSS for inline cells so that multilie works fine and are
aligned to the top

Fixes
https://github.com/twentyhq/core-team-issues/issues/757?issue=twentyhq%7Ctwenty%7C11495
2025-04-15 13:15:37 +00:00
Charles BochetandGitHub 7bab6cab41 Fix storybook and chromatic tests and fix Block editor custom slash menu positioning (#11580)
Storybook / Chromatic fixes:
- fix linaria twenty-ui style loading (since twenty-ui prebuild
refactoring)
- update prefetch view mocks
- add ability to disable hotkeys initialization in storybook to avoid
race condition

Custom slash menu positioning fix
2025-04-15 14:57:35 +02:00
Murali SinghandGitHub 9da2a74d9e Fix inline field height #11442 (#11553)
Screenshots:

![Image](https://github.com/user-attachments/assets/998f2a88-53ab-49ef-8bb5-c7bef9158b0d)


![Image](https://github.com/user-attachments/assets/218c8f4b-f8d1-4d49-8029-8f99113f01ec)


![Image](https://github.com/user-attachments/assets/1dfde61a-62bb-403a-af3d-fb99c16ab29e)

@Bonapara Can you confirm is this what you expected ?
2025-04-15 14:42:21 +02:00
Charles BochetandGitHub d6ae4d59f0 Various fixes charles 3 (#11573) 2025-04-15 13:45:04 +02:00
Antoine MoreauxandGitHub f30070c2c9 feat(auth): enhance logo behavior and simplify billing logic (#11574)
Added default domain redirection functionality to the Logo component,
leveraging UndecoratedLink for navigation when default logos are used.
Removed metered product billing feature flag logic in the billing
webhook subscription service to simplify and streamline the codebase.

Fix https://github.com/twentyhq/core-team-issues/issues/783
2025-04-15 13:43:13 +02:00
GuillimandGitHub e1ce98825b Possiblity to reconnect on Failed unkown (#11576)
Possiblity to reconnect you account on Failed Unkown errors.

This PR triggers a similar flow than the Failed errors for unsufficient
permission already existing in twenty.

Allows our users to force the synchro again even though they have a
strange error. It's been asked by some customers since we have had a
couple of issues in messaging lately

Fixes https://github.com/twentyhq/twenty/issues/11411
2025-04-15 13:39:18 +02:00
e8db0176a1 Remove recoil sync (#11569)
Recoil-sync was causing issues with Firefox, replacing it with a simpler
mechanism to hydrate variables on page load

---------

Co-authored-by: etiennejouan <jouan.etienne@gmail.com>
2025-04-15 13:32:12 +02:00
Baptiste DevessierandGitHub 6c2d64dcb2 Fix e2e tests (#11577) 2025-04-15 12:16:38 +02:00
EtienneandGitHub 8b10059e1b fix - remove isMeteredProductBillingEnabled (#11575) 2025-04-15 11:15:02 +02:00
16fb4d406b i18n - translations (#11572)
Created by Github action

Co-authored-by: github-actions <github-actions@twenty.com>
2025-04-14 18:49:45 +02:00
Raphaël BosiandGitHub 8f2dddaa5f Create stories for action display components (#11547)
Create stories for:
- ActionButton
- ActionComponent
- ActionDisplay
- ActionDropdownItem
- ActionListItem
2025-04-14 18:42:49 +02:00
EtienneandGitHub 0249cf3b34 remove feature flag on billing metered product + fixes (#11570)
- remove feature flag
- design fixes
2025-04-14 18:39:19 +02:00
EtienneandGitHub 9a69cd0b61 add billing threshold + specific trial free credits (#11533)
In this PR : 
- set billing thresholds after subscription creation (not possible
during billing checkout)
- add specific free trial workflow credit quantities + set them in
subscription item + check them when receiving stripe alert event

closes : https://github.com/twentyhq/core-team-issues/issues/682
2025-04-14 16:25:07 +00:00
Baptiste DevessierandGitHub 704b18af30 Create FormRichTextField (#11474)
This PR adds a new Form Field for Rich Text V2 fields. The
implementation was relatively simple, thanks to @thomtrp's job on the
back-end side.

## Demo

### Edit mode + insert in database


https://github.com/user-attachments/assets/f44a6442-fad3-4ad9-af50-a7d90e872c90

### Readonly mode


https://github.com/user-attachments/assets/66243ddf-d4a2-4187-894c-356d9c02b2b2

Closes https://github.com/twentyhq/private-issues/issues/229
2025-04-14 18:07:09 +02:00
Baptiste DevessierandGitHub 0be700f376 Fix e2e tests (#11565)
Fixing the e2e tests
2025-04-14 17:47:57 +02:00
GuillimandGitHub 8a3f8ef324 Chip untitled modification (#11498)
Fixes https://github.com/twentyhq/core-team-issues/issues/663
2025-04-14 15:33:41 +00:00
MarieandGitHub d4deca45e8 Read feature flags from cache (#11556)
We are now storing a workspace's feature flag map in our redis cache. 
The cache is invalidated upon feature flag update through the lab
resolver.
2025-04-14 17:31:13 +02:00
Charles BochetandGitHub 15eb96337f Various fixes (#11567)
In this PR:
- Remove SignUpLoading blank screen by an empty dark overlay =>
VerifyEffect
- Add ModalContent from pages themselves instead of using it the Layout.
This allow for empty dark overlay without showing an empty modal with
padding
2025-04-14 17:24:16 +02:00
85d94822b3 Fix the Command menu items right padding #11484 (#11489)
Screenshot:
![Screenshot 2025-04-10 at 1 07
24 AM](https://github.com/user-attachments/assets/1e7ed8e7-594f-4ead-9b04-0c7dab636fbd)

---------

Co-authored-by: guillim <guigloo@msn.com>
Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
2025-04-14 14:12:15 +02:00
Thomas TrompetteandGitHub 69a00eaaf6 Emit message event with actual message object (#11548)
Events were emitted with the wrong object. We were using
messageWithParticipant instead of actual message object
2025-04-14 13:49:19 +02:00
abecdbafc1 Add Edit Rich Text functionality to table view (#11390)
Fixes https://github.com/twentyhq/core-team-issues/issues/729


[recording.webm](https://github.com/user-attachments/assets/ea95d67b-64a3-4fef-91ed-b06318099a78)

---------

Co-authored-by: Félix Malfait <felix@twenty.com>
2025-04-14 11:46:22 +00:00
Charles BochetandGitHub 8f7a82f177 Fix refactor selectableList broke hotkey onEnter behavior (#11562) 2025-04-14 12:25:54 +02:00
4a123a8eac i18n - translations (#11560)
Created by Github action

Co-authored-by: github-actions <github-actions@twenty.com>
2025-04-14 11:11:30 +02:00
ace515eea7 Fix workflow with manual triggers and no selection not appearing in the command menu (#11544)
Fix workflow with manual triggers and no selection not appearing in the
command menu

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2025-04-14 11:03:29 +02:00
Lucas BordeauandGitHub b5a1d1a895 Improving empty filter chip UI (#11537)
This PR is simply removing the : character on the filter chip when the
filter value is empty.

The issue originally was about removing the filter chip when closing the
filter value dropdown with an empty value but it is already the default
behavior.

Fixes https://github.com/twentyhq/core-team-issues/issues/658
2025-04-14 10:43:20 +02:00
EtienneandGitHub 721a34864f create workflow subscription item addition command (#11541)
closes https://github.com/twentyhq/core-team-issues/issues/541
2025-04-14 10:41:37 +02:00
e2b2697fcc refacto dropdown v1>v2 in address input (#11549)
Co-authored-by: Charles Bochet <charles@twenty.com>
2025-04-14 10:37:40 +02:00
0de8140b3a CreateComponentFamilyState -> createComponentFamilyStateV2 (#11546)
Refacto of createComponentFamilyState

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2025-04-14 10:31:30 +02:00
Thomas TrompetteandGitHub 27f542e132 Use transformer in workflows (#11497)
We do not manage rich text properly in workflows. This is because API
has a layer called transformer service. Looks a bit as a duplicate of
format data, but this api layer was already there for position anyway.
Using it in workflow record actions.

I hope at some point we merged formatData util and transformer.
2025-04-11 16:31:45 +00:00
Baptiste DevessierandGitHub 897684f995 JSON Visualizer: ensure labels are 24px tall as all other elements (#11535)
## Before

![CleanShot 2025-04-11 at 14 42
15@2x](https://github.com/user-attachments/assets/a4726342-212a-40b3-829f-40cae7724fec)

## After

![CleanShot 2025-04-11 at 14 42
27@2x](https://github.com/user-attachments/assets/e84a4d81-fdcc-422e-b294-55867a4bc5fb)
2025-04-11 18:25:29 +02:00
MarieandGitHub 162c6bcaa3 [permissions] Implement object-records permissions in query builders (#11458)
In this PR we are

- (if permissionsV2 is enabled) executing permission checks at query
builder level. To do so we want to override the query builders methods
that are performing db calls (.execute(), .getMany(), ... etc.) For now
I have just overriden some of the query builders methods for the poc. To
do so I created custom query builder classes that extend typeorm's query
builder (selectQueryBuilder and updateQueryBuilder, for now and later I
will tackle softDeleteQueryBuilder, etc.).
- adding a notion of roles permissions version and roles permissions
object to datasources. We will now use one datasource per roleId and
rolePermissionVersion. Both rolesPermissionsVersion and rolesPermissions
objects are stored in redis and recomputed at role update or if queried
and found empty. Unlike for metadata version we don't need to store a
version in the db that stands for the source of truth. We also don't
need to destroy and recreate the datasource if the rolesPermissions
version changes, but only to update the value for rolesPermissions and
rolesPermissionsVersions on the existing datasource.

What this PR misses
- computing of roles permissions should take into account
objectPermissions table (for now it only looks at what's on the roles
table)
- pursue extension of query builder classes and overriding of their db
calling-methods
- what should the behaviour be for calls from twentyOrmGlobalManager
that don't have a roleId?
2025-04-11 17:34:02 +02:00
martmullandGitHub 82fa71c2cd Update canary package versions (#11543)
as title
2025-04-11 16:48:41 +02:00
WeikoandGitHub 04f9c5a5de Prepare 0.51 (#11542) 2025-04-11 16:00:24 +02:00
Charles BochetandGitHub 3018e3ac89 Fix date picker month/year dropdown (#11539)
Fixes https://github.com/twentyhq/twenty/issues/11524
2025-04-11 15:22:00 +02:00
GuillimandGitHub 2a8defe262 contact/company creations errors (#11540)
Seeing a couple of issues related to company creations in logs, I
suspect this to be the root cause

This should help a lot in all the support we have to do on email
synchronisation
2025-04-11 15:19:03 +02:00
Charles BochetandGitHub 9da5cca82a Fix dropdown width (#11536)
Fix regressions due to dropdown refactoring
2025-04-11 14:59:57 +02:00
Lucas BordeauandGitHub fe98deef4e Fixed command menu hotkey listener refactor (#11534)
This PR fixes a refactor that was done recently to avoid having
clickoutside listeners on the closed command menu.

The useScopedHotkey hook should have stayed in the command menu
container, because it should always listen.

This has been fixed.
2025-04-11 14:59:48 +02:00
03800ce6d0 i18n - translations (#11532)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2025-04-11 14:42:45 +02:00
martmullandGitHub 1794b3a611 Remove build lambda at creation (#11531)
Remove useless build call (done at first execution)
2025-04-11 14:40:00 +02:00
Baptiste DevessierandGitHub e8488e1da0 Only display Flow for Workflow Runs and display Output tab for triggers (#11520)
> [!WARNING]
> I refactored a bunch of components into utility functions to make it
possible to display the `WorkflowStepHeader` component for **triggers**
in the `CommandMenuWorkflowRunViewStep` component. Previously, we were
asserting that we were displaying the header in `Output` and `Input`
tabs only for **actions**. Handling triggers too required a bunch of
changes. We can think of making a bigger refactor of this part.

In this PR:

- Only display the Flow for Workflow Runs; removed the Code Editor tab
- Allows users to see the Output of trigger nodes
- Prevent impossible states by manually setting the selected tab when
selecting a node

## Demo

### Success, Running and Not Executed steps


https://github.com/user-attachments/assets/c6bebd0f-5da2-4ccc-aef2-d9890eafa59a

### Failed step


https://github.com/user-attachments/assets/e1f4e13a-2f5e-4792-a089-928e4d6b1ac0

Closes https://github.com/twentyhq/core-team-issues/issues/709
2025-04-11 14:31:34 +02:00
Raphaël BosiandGitHub c8011da4d7 Fix title input hotkey scope (#11530)
Before:


https://github.com/user-attachments/assets/e0be8247-6d3e-49d0-8595-76f9547bf354


After:


https://github.com/user-attachments/assets/ae23b01b-3ad7-4b90-b4ae-ce604d984d73
2025-04-11 14:22:31 +02:00
446919bc72 Remove onboarding flashes + close all dropdowns on CommandMenu close (#11483)
## Remove onboarding flashes

Tested:
- sign in with credentials
- sign in with social oAuth
- sign up with credentials
- multidomain
- single domain
- reset password

No more flashes, and code logic simplified!

## Close all dropdowns on CommandMenu close

Before:


https://github.com/user-attachments/assets/244ff935-3d40-47d5-a097-12d4cc3810dd


After:


https://github.com/user-attachments/assets/1de692f8-5032-404a-be74-025ebca67138

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2025-04-11 14:15:14 +02:00
Raphaël BosiandGitHub 637a7f0e64 Fix workflow dropdown hotkey scope (#11518)
The hokey scope was set on focus of the outermost container of the field
inputs. When clicking on a dropdown inside this container, the hokey
scope was set first by the dropdown and then by the focused container.
This led to the previous hotkey scope being overwritten.
The fix consists in moving the hokey scope setter on focus to the inner
container.

Before:


https://github.com/user-attachments/assets/12538c5b-43ab-4b76-a867-7eda6992b1ea


After:


https://github.com/user-attachments/assets/002fedba-010c-41e9-bec6-d5d80cb2dcc5
2025-04-11 09:07:36 +00:00
d34ec7b253 Fix: "Not shared" label not visible due to extra long email subject (#11492)
Closes #11408 

- Added `min-width: 100px` in `EmailThreadNotShared`
- Added `isShared` prop to `StyledSubject` for better subject handling
in shared visibility scenarios

---------

Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
Co-authored-by: Félix Malfait <felix@twenty.com>
2025-04-11 10:13:33 +02:00
Thomas des FrancsandGitHub 04168e720c Update 0.51.0.mdx (#11517) 2025-04-11 10:12:31 +02:00
nitinandGitHub 0cccb80221 revert: transform -> marginLeft in DefaultLayout motion div (#11522) 2025-04-10 22:33:12 +02:00
Félix MalfaitandGitHub e6bb3d4d51 Change required permission for MS (#11519)
Change User.Read.All to User.Read in docs
2025-04-10 18:33:37 +02:00
Thomas des FrancsandGitHub 5a8006f1dd Update src/content/releases/0.51.0 2025-04-10 18:17:08 +02:00
martmullandGitHub b8406820ee Fix wrong filter for get requests (#11512)
- remove wrong exception filter for GET api requests
- remove messageThreadId requirements on messages for requests done with
API key (no user, only workspace)
- doing the same for calendarEvents
2025-04-10 17:29:53 +02:00
3e1b5d23f5 i18n - translations (#11515)
Created by Github action

Co-authored-by: github-actions <github-actions@twenty.com>
2025-04-10 17:10:55 +02:00
bc8f71fab5 wip: api playground fixes (#11345)
# ISSUE 
- closes #10926 

- [x] fix paddings
- [x] fix page change to playground animation
- [x] fixes multiple skeletons issues

---

- Also was showing multiple skeletons on reloading, **before**: 


https://github.com/user-attachments/assets/0cdef639-c121-4cbb-b056-b89e60862c54

---------

Co-authored-by: ehconitin <nitinkoche03@gmail.com>
Co-authored-by: Félix Malfait <felix@twenty.com>
2025-04-10 17:02:55 +02:00
a86317eb71 i18n - translations (#11514)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2025-04-10 17:01:13 +02:00
EtienneandGitHub ee5aa2393d fix billingCheckoutSession query param + enable redirect on workspace… (#11509)
… during onboarding



fixes : https://github.com/twentyhq/core-team-issues/issues/668
2025-04-10 16:47:40 +02:00
WeikoandGitHub d69932c6c4 Fix boolean default value update not updating psql default value when false (#11513)
Fixes https://github.com/twentyhq/twenty/issues/11471

## Context
When sending false as a new defaultValue, this was not going through the
migration creation code due to this condition
```typescript
if (updatableFieldInput.defaultValue)
```
2025-04-10 16:23:16 +02:00
Thomas TrompetteandGitHub 6f5118c677 Remove fixed width for dropdown variables, fix optimistic on file upload (#11507)
As title
2025-04-10 16:07:32 +02:00
Lucas BordeauandGitHub f8f11894e8 Introduce generic way to close any open dropdown on page location change (#11504)
In this PR we introduce a generic way to close any open dropdown
idempotently, with the hook useCloseAnyOpenDropdown.

We also introduce a generic hook useExecuteTasksOnAnyLocationChange that
is called each time the page location changes.

This way we can close any open dropdown when the page location changes,
which fixes the original issue of having advanced filter dropdown
staying open between page changes.

Fixes https://github.com/twentyhq/core-team-issues/issues/659
2025-04-10 16:00:50 +02:00
1844c39a99 i18n - translations (#11511)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2025-04-10 15:47:28 +02:00
WeikoandGitHub 35c6cb4f4a fix chromatic 1 (#11510) 2025-04-10 15:44:12 +02:00
WeikoandGitHub 63a165666a fix error messages margin (#11508)
## Context
Fixing error messages margin in various places
Reset password
<img width="453" alt="Screenshot 2025-04-10 at 15 17 00"
src="https://github.com/user-attachments/assets/7a0fb090-4029-415f-8733-0c9e3aa3c3f2"
/>
Api key
<img width="543" alt="Screenshot 2025-04-10 at 15 16 21"
src="https://github.com/user-attachments/assets/d8f8a348-84d3-44d7-8cea-863c3ddb02fc"
/>

Also setting overflow on api key label in api keys table
<img width="580" alt="Screenshot 2025-04-10 at 15 16 15"
src="https://github.com/user-attachments/assets/207df981-c906-4926-a56d-38167628267f"
/>
2025-04-10 15:36:59 +02:00
Thomas TrompetteandGitHub b8d5f6d4b0 Center empty state on record table (#11506)
as title
2025-04-10 15:05:49 +02:00
martmullandGitHub 4e4c0ddd3c Add command to update serverless layer (#11500)
New command to add packages to serverless -> Run into your terminal
`npx nx run twenty-server:command serverless:add-packages -p
stripe@17.0.0,@slack/web-api,@slack/oauth`

Will create a new layer folder, add packages in it and update the new
last_layer_version

<img width="1468" alt="image"
src="https://github.com/user-attachments/assets/da8ee77f-e512-4ceb-95bc-cfa979f3439c"
/>

Before
<img width="877" alt="image"
src="https://github.com/user-attachments/assets/35f6bb6c-2ebf-46fe-bd15-4e6352901fc8"
/>

After
<img width="938" alt="image"
src="https://github.com/user-attachments/assets/785af132-5e8c-4a9a-bc57-dffdcaaeec02"
/>
2025-04-10 14:53:59 +02:00
WeikoandGitHub 1802c30995 Fix workspace menu width varies (#11505)
Before


https://github.com/user-attachments/assets/cd386034-bddd-4452-bb7f-2b3749ba74d6

After


https://github.com/user-attachments/assets/07ab40b1-0f8d-4b80-b0db-ad1ea8c584f7
2025-04-10 14:47:40 +02:00
Thomas TrompetteandGitHub 5b1091b19e Store trigger output (#11503)
As title. Trigger output is the workflow payload
2025-04-10 14:36:15 +02:00
cc6043be9f i18n - translations (#11502)
Created by Github action

Co-authored-by: github-actions <github-actions@twenty.com>
2025-04-10 14:11:46 +02:00
145ddba721 fix settings container vertical scroll position (#11464)
@charlesBochet is this flex needed here? we don't use flex-specific
properties.

I did check all scrolls seem to be working fine, could u please check
once more? thanks :)


before:
<img width="1512" alt="Screenshot 2025-04-09 at 12 59 25"
src="https://github.com/user-attachments/assets/1b0066e3-c3f7-4bd8-829b-174d2747ee66"
/>

after:
<img width="1512" alt="Screenshot 2025-04-09 at 12 58 13"
src="https://github.com/user-attachments/assets/06b103ed-d72f-4bc3-b530-7ae25542f568"
/>

Co-authored-by: Charles Bochet <charlesBochet@users.noreply.github.com>
2025-04-10 14:11:21 +02:00
db88c93eff Navigation drawer refactor (#11251)
closes #11195
closes #11199

### Context

The yellow dots in the Settings Navigation Drawer (used to indicate
advanced settings) were being hidden due to ScrollWrapper's overflow
handling. This required both a fix for the visibility issue and an
improvement to the component structure.

### Changes
1. Keep scrolling logic of the MainNavigationDrawer and
SettingsNavigationDrawer in one place, and conditionally apply
`<StyledScrollableInnerContainer>` when isSettingsDrawer is true.

2. Fixed Yellow Dots Visibility
Added specific padding in NavigationDrawerScrollableContent to
accommodate yellow dots:
```
  padding-left: ${theme.spacing(5)}; // Space for yellow dots
  padding-right: ${theme.spacing(8)}; // Space for no-padding scroll
  ```
  
  This ensures the yellow dots are visible while maintaining proper scroll behavior

3. Improved Component Composition
Using proper component composition instead of passing components as props
Components are now composed in a more React-idiomatic way:
```
  <NavigationDrawer>
    <NavigationDrawerScrollableContent>
      <SettingsNavigationDrawerItems />
    </NavigationDrawerScrollableContent>
    <NavigationDrawerFixedContent>
      <AdvancedSettingsToggle />
    </NavigationDrawerFixedContent>
  </NavigationDrawer>
  ```

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2025-04-10 14:05:10 +02:00
WeikoandGitHub 41674129c3 Fix sign-in-up sso buttons width (#11499)
## Context
An enforced width was introduced recently for error texts but broke
Microsoft sso placement due to its longer text.
I've replaced it by a min-width and introduced the missing one in global
signin/up.

Before
<img width="456" alt="Screenshot 2025-04-10 at 12 14 51"
src="https://github.com/user-attachments/assets/43f29c63-f257-4c1c-9c16-b0170343c43e"
/>

After
<img width="494" alt="Screenshot 2025-04-10 at 12 14 17"
src="https://github.com/user-attachments/assets/17c4362a-1336-4adc-aeb9-76c6dcd059c6"
/>
2025-04-10 13:51:21 +02:00
Raphaël BosiandGitHub b84a31cb8a Create open side panel page action (#11481)
Closes https://github.com/twentyhq/core-team-issues/issues/697
2025-04-10 11:34:34 +02:00
Raphaël BosiandGitHub 4a4ce9a6fe Fix PageHeaderToggleCommandMenuButton (#11496)
This PR fixes a bug introduced by
https://github.com/twentyhq/twenty/pull/11470

Before:


https://github.com/user-attachments/assets/8c1b8114-591f-4b58-a177-551c4f0dfb98

After:


https://github.com/user-attachments/assets/b93aa498-2ae8-4001-b541-372866d24f54
2025-04-10 11:29:45 +02:00
Charles BochetandGitHub a7e6564017 Make token update synchronous on FE (#11486)
1. Removing tokenPair internal variable of ApolloFactory. We will relay
on cookieStorage
2. setting the cookie explicitely instead of only relaying on recoil
cookieEffect which is too late
2025-04-10 01:39:25 +02:00
WeikoandGitHub 7bd68ad176 Fix event propagation after record creation (#11485)
Fixes https://github.com/twentyhq/twenty/issues/11460
2025-04-10 01:37:26 +02:00
Lucas BordeauandGitHub 2b77f598b2 Fixed (#11482)
This PR fixes many small bugs around the recent hotkey scope refactor.

- Removed unused ActionBar files
- Created components CommandMenuOpenContainer and
KeyboardShortcutMenuOpenContent to avoid mounting listeners when not
needed
- Added DEFAULT_CELL_SCOPE where missing in some field inputs
- Called setHotkeyScopeAndMemorizePreviousScope instead of
setHotkeyScope in new useOpenFieldInputEditMode hook
- Broke down RecordTableBodyUnselectEffect into multiple simpler effect
components that are mounted only when needed to avoid listening for
keyboard and clickoutside event
- Re-implemented recently deleted table cell soft focus component logic
into RecordTableCellDisplayMode
- Created component selector isAtLeastOneTableRowSelectedSelector
- Drill down hotkey scope when opening a dropdown
- Improved debug logs
2025-04-09 18:34:31 +02:00
GuillimandGitHub 9f4e8c046f Messaging-unit-tests (#11467)
# Unit test on the Messaging Module

Initially the issue was to create integration test for the messaging
module but after speaking with the core team, we decided to go for an
easier implementation: unit test only,

We decided to focus our test on three main components of the module :  
- message list
- message import
- message save & create contact

Fixes https://github.com/twentyhq/core-team-issues/issues/56
2025-04-09 17:57:43 +02:00
Charles BochetandGitHub e23688cb41 Fix lint issues (#11475) 2025-04-09 17:35:25 +02:00
b6c079f050 Fixed Navbar padding issue #11438 (#11470)
@Bonapara 
Related Issue: Fixes #11438.

Screenshot:
![Screenshot 2025-04-09 at 4 10
41 PM](https://github.com/user-attachments/assets/4c5346b6-4e1c-4441-bd8a-b88aee139b9b)

---------

Co-authored-by: guillim <guigloo@msn.com>
Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
2025-04-09 17:22:49 +02:00
Thomas TrompetteandGitHub 5d9cd257ae Command menu mobile - Prevent overflow on navigation bar (#11480)
Fix https://github.com/twentyhq/twenty/issues/11413
2025-04-09 17:16:46 +02:00
Thomas TrompetteandGitHub 025e50645d Avoid settings object cover image to be reduced on scroll (#11473)
Fix https://github.com/twentyhq/twenty/issues/11420
2025-04-09 16:43:25 +02:00
Raphaël BosiandGitHub 9e0402e691 Action menu refactoring (#11454)
# Description

Closes [#696](https://github.com/twentyhq/core-team-issues/issues/696)

- `useAction` hooks have been removed for all actions
- Every action can now declare a react component
- Some standard action components have been introduced: `Action`,
`ActionLink` and `ActionModal`
- The `ActionDisplay` component uses the new `displayType` prop of the
`ActionMenuContext` to render the right component for the action
according to its container: `ActionButton`, `ActionDropdownItem` or
`ActionListItem`
- The `ActionDisplayer` wraps the action component inside a context
which gives it all the information about the action
-`actionMenuEntriesComponenState` has been removed and now all actions
are computed directly using `useRegisteredAction`
- This computation is done inside `ActionMenuContextProvider` and the
actions are passed inside a context
- `actionMenuType` gives information about the container of the action,
so the action can know wether or not to close this container upon
execution
2025-04-09 13:12:49 +00:00
Lucas BordeauandGitHub 1834b38d04 Fix show page relation record count (#11459)
This PR fixes the incorrect relation count on a show page relation
section title, when there are more than 60 records.

An aggregate COUNT query has been used to rely on the backend.

A new component RecordDetailRelationSectionDropdown has been created to
abstract a chunk of the parent RecordDetailRelationSection component.

Fixes https://github.com/twentyhq/twenty/issues/11032
2025-04-09 14:41:11 +02:00
nitinandGitHub bd3ec6d5e3 rename core-module environment to twenty-config (#11445)
closes https://github.com/twentyhq/core-team-issues/issues/759
2025-04-09 14:11:26 +02:00
MarieandGitHub fe6d0241a8 [permissions] Allow logo update during sign-up (#11468)
Fixes https://github.com/twentyhq/twenty/issues/11410
2025-04-09 13:58:30 +02:00
c6203d8928 i18n - translations (#11469)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2025-04-09 11:34:35 +02:00
8582bcccf5 remove billing stripe plan product id from env (#11461)
Fixes https://github.com/twentyhq/core-team-issues/issues/661
remove billing stripe plan product id from env

Co-authored-by: Keshav Gupta <keshavgupta@Keshavs-MacBook-Air.local>
2025-04-09 11:31:38 +02:00
EtienneandGitHub 11fb8e0284 add metered products usage (#11452)
- add metered products usage module on settings/billing page
- add new resolver + logic with meter event data fetching from Stripe

<img width="590" alt="Screenshot 2025-04-08 at 16 34 07"
src="https://github.com/user-attachments/assets/34327af1-3482-4d61-91a6-e2dbaeb017ab"
/>
<img width="570" alt="Screenshot 2025-04-08 at 16 31 58"
src="https://github.com/user-attachments/assets/55aa221a-925f-48bf-88c4-f20713c79962"
/>

- bonus : disable subscription switch from yearly to monthly

closes https://github.com/twentyhq/core-team-issues/issues/681
2025-04-09 09:26:49 +00:00
Thomas des FrancsandGitHub b25ee28c12 Update CONTRIBUTING.md (#11465)
Updated the issue assignment policy for good first issues to prioritize
PRs over Issue assignments.
2025-04-09 11:16:13 +02:00
Thomas TrompetteandGitHub 46bbf02431 Emit event on message creation (#11466)
adding event emitting on message creation
2025-04-09 11:04:43 +02:00
GuillimandGitHub c6be260fec datasource TTL fix (#11444)
Comparing the last date a datasource was used instead of a fixed TTL :
should fix workers issues "error: Error: Connection terminated"

FYI was done in pair prog with @Weiko
2025-04-09 10:08:20 +02:00
ccdc2835a2 i18n - translations (#11463)
Created by Github action

Co-authored-by: github-actions <github-actions@twenty.com>
2025-04-09 01:20:17 +02:00
b6e344e7be Various fixes (#11448)
# Scrollbar fix

Fixes https://github.com/twentyhq/twenty/issues/11403

<img width="1512" alt="image"
src="https://github.com/user-attachments/assets/b13fe0f2-8c61-4ea8-9ea1-e61e571a90da"
/>

---------

Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
2025-04-09 01:03:43 +02:00
ab63214efa Added Proper theme color for Favorite Input box (#11434)
#11418  The background color changes based on the theme.
 - If the theme is 'light', the background color will be white.
- Otherwise, it will use the theme's background transparent lighter
color.

---------

Co-authored-by: ehconitin <nitinkoche03@gmail.com>
Co-authored-by: nitin <142569587+ehconitin@users.noreply.github.com>
2025-04-08 20:46:36 +00:00
martmullandGitHub f121c94d4a 701 workflow improve webhook triggers (#11455)
as title

Nota bene: I did not filter execution by http method. A POST webhook
trigger can be triggered by a GET request for more flexibility. Tell me
if you think it is a mistake


https://github.com/user-attachments/assets/1833cbea-51a8-4772-bcd8-088d6a087e79
2025-04-08 19:01:22 +00:00
2f7f28a574 i18n - translations (#11457)
Created by Github action

Co-authored-by: github-actions <github-actions@twenty.com>
2025-04-08 18:37:10 +02:00
Baptiste DevessierandGitHub 6521d19238 Use JSON visualizer for JSON fields (#11428)
- Updates on the JSON field input
  - Previously, we were editing json fields in a textarea 
- Now, we display a JSON visualizer and the user can click on an Edit
button to edit the JSON in Monaco
- The JSON field input has a special behavior for workflow run output.
We want the error to be displayed first in the visualizer. Displaying
the error in red was optional but makes the output clearer in the
context of a workflow run record board.
- Made the code editor transparent in the json field input
- Ensure workflow run's output is not considered readonly in
`packages/twenty-front/src/modules/object-record/record-field/utils/isFieldValueReadOnly.ts`;
we want the json visualizer to always be displayed in this specific case

## Demo

### Failed Workflow Run


https://github.com/user-attachments/assets/7a438d11-53fb-4425-a982-25bbea4ee7a8

### Any JSON field in the record table


https://github.com/user-attachments/assets/b5591abe-3483-4473-bd87-062a45e653e3

Closes https://github.com/twentyhq/core-team-issues/issues/539
2025-04-08 16:18:36 +00:00
EtienneandGitHub c1d421de06 remove default meter driver (#11456)
Remove default meter driver to prevent metric logs from polluting the
console.
2025-04-08 18:17:58 +02:00
Thomas TrompetteandGitHub dd1d9c32c3 Remove task, note and file tabs for workflows (#11453)
Command menu tries to fetch task, file and notes that are not available
for workflow entities. Hiding those tabs
2025-04-08 17:35:41 +02:00
Thomas TrompetteandGitHub a049cd4a25 Update placeholder on record picker object type update (#11451)
- requires a refacto so several fields can be updated at once
- updating object name on record picker will now update placeholder
- add a min-height to label so fields do not get moved when the label is
deleted
2025-04-08 14:20:15 +00:00
6611fbf9ac Fix : Menu shouldn't be displayed on logged out pages (#11437)
#11414 
Conditionally render MobileNavigationBar based on user authentication
status
- Added useIsLogged hook to check if the user is authenticated.
- Updated MobileNavigationBar component to render only when the user is
logged in.
![Screenshot from 2025-04-08
12-33-04](https://github.com/user-attachments/assets/1b58a5ac-e5ff-418f-a903-b952f37db84d)

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2025-04-08 11:54:21 +02:00
Charles BochetandGitHub 17474a0e1e Remove cell hotkey scope (#11435)
Remove FieldContext hotkey scope as:
- each Field should set its own hotkey scope (ex:
emails-field-input-{recordId} or emails-field-input for now)
- while opening a fieldInput, we should synchronously set the
corresponding hotkey scope

To cut this refactoring in half, I'm allowing all input to use
TableHotkeyScope.CellEditMode
2025-04-08 11:18:23 +02:00
3d90eb4eb9 Fix broken dropdown auto resize behavior (#11423)
This PR was originally about fixing advanced filter dropdown auto resize
to avoid breaking the app main container, but the regression is not
limited to advanced filter dropdown, so this PR fixes the regression for
every dropdown in the app.

This PR adds a max dropdown max width to allow resizing dropdowns
horizontally also, which can happen easily for the advanced filter
dropdown.

In this PR we also start removing `fieldMetadataItemUsedInDropdown` in
component `AdvancedFilterDropdownTextInput` because it has no impact
outside of this component which is used only once.

The autoresize behavior determines the right padding-bottom between
mobile and PC.

Mobile : 

<img width="604" alt="Capture d’écran 2025-04-07 à 16 03 12"
src="https://github.com/user-attachments/assets/fbdd8020-1bfc-4e01-8a05-3a9f114cdd40"
/>

PC :

<img width="757" alt="Capture d’écran 2025-04-07 à 16 03 30"
src="https://github.com/user-attachments/assets/f80a5967-8f60-40bb-ae3c-fa9eb4c65707"
/>

Fixes https://github.com/twentyhq/core-team-issues/issues/725
Fixes https://github.com/twentyhq/twenty/issues/11409

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2025-04-08 11:03:10 +02:00
Félix MalfaitandGitHub 89abf3db4f Remove dead code to backfill record positions (#11439)
Fixes https://github.com/twentyhq/core-team-issues/issues/767
2025-04-08 11:02:40 +02:00
8b5c259c36 i18n - translations (#11441)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2025-04-08 11:01:29 +02:00
ea93ac6348 fetch latest version tag from docker hub (#11362)
closes #11352

---------

Co-authored-by: Félix Malfait <felix@twenty.com>
2025-04-08 08:55:03 +00:00
eliasylonenandGitHub 95eba07f6e Share RICH_TEXT_V2 field value override between REST and GraphQL APIs (#10912)
Fixes issue #10606.

This PR makes `RICH_TEXT_V2` field behavior in REST API matche the
current behavior in GraphQL API:

Currently both `markdown` and `blocknote` fields must be included in the
request, one of them can be `null`. The field with a `null` value will
be filled by the converted value of the other field.

In other words, this works:
```
curl http://localhost:3000/rest/notes \
  --request POST \
  --header 'Content-Type: application/json' \
  --header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIyMDIwMjAyMC0xYzI1LTRkMDItYmYyNS02YWVjY2Y3ZWE0MTkiLCJ0eXBlIjoiQVBJX0tFWSIsIndvcmtzcGFjZUlkIjoiMjAyMDIwMjAtMWMyNS00ZDAyLWJmMjUtNmFlY2NmN2VhNDE5IiwiaWF0IjoxNzQxODA1MzQyLCJleHAiOjQ4OTU0MDUzNDEsImp0aSI6ImZlMzU0NTBkLTlhMDMtNGE2ZS04ODVjLTBlNTU3M2Y3YTE0NiJ9.6_g8cwoSE7ZCX1Zzsw44gZIyBdLKNsnDqMOmm1bKik0' \
  --data '{
  "position": 1,
  "title": "a",
  "bodyV2": {    
    "markdown": "test4\n\ntest3\n\n# test1\n",
    "blocknote": null
  },
  "createdBy": {
    "source": "EMAIL"
  }
}'
```

And this does not work:
```
curl http://localhost:3000/rest/notes \
  --request POST \
  --header 'Content-Type: application/json' \
  --header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIyMDIwMjAyMC0xYzI1LTRkMDItYmYyNS02YWVjY2Y3ZWE0MTkiLCJ0eXBlIjoiQVBJX0tFWSIsIndvcmtzcGFjZUlkIjoiMjAyMDIwMjAtMWMyNS00ZDAyLWJmMjUtNmFlY2NmN2VhNDE5IiwiaWF0IjoxNzQxODA1MzQyLCJleHAiOjQ4OTU0MDUzNDEsImp0aSI6ImZlMzU0NTBkLTlhMDMtNGE2ZS04ODVjLTBlNTU3M2Y3YTE0NiJ9.6_g8cwoSE7ZCX1Zzsw44gZIyBdLKNsnDqMOmm1bKik0' \
  --data '{
  "position": 1,
  "title": "",
  "body": "",
  "bodyV2": {    
    "markdown": "test4\n\ntest3\n\n# test1\n"
  },
  "createdBy": {
    "source": "EMAIL"
  }
}'
```

---

It would be nice not to require the null value, maybe let's make that a
separate PR?
2025-04-07 23:30:53 +02:00
6bc18960c9 Show Header in RecordTable on empty state and show groups in Group By views (#11416)
Closes #11298

---------

Co-authored-by: Félix Malfait <felix@twenty.com>
2025-04-07 22:05:59 +02:00
07b25a2aad i18n - translations (#11432)
Created by Github action

Co-authored-by: github-actions <github-actions@twenty.com>
2025-04-07 19:33:05 +02:00
Charles BochetandGitHub 20895f1129 Fix views reordering (#11431)
As per title
2025-04-07 19:18:05 +02:00
Thomas TrompetteandGitHub 17b7e703b4 Refacto form select input (#11426)
- small fixes on form design
- refacto form select input to use the existing select component
2025-04-07 16:56:59 +00:00
WeikoandGitHub ff59658d39 Fix permission check during onboarding (#11429)
## Context
CurrentUser is fetched during onboarding however roles and permissions
are not created yet during that stage so an error was thrown. We only
want to fetch permissions after the onboarding of the workspace.
2025-04-07 18:53:53 +02:00
1666 changed files with 41837 additions and 22080 deletions
+113 -1
View File
@@ -6,8 +6,71 @@ module.exports = {
'plugin:react/recommended',
'plugin:react-hooks/recommended',
'plugin:storybook/recommended',
'plugin:prettier/recommended',
'plugin:lingui/recommended',
'plugin:@nx/typescript'
],
plugins: ['react-hooks', 'react-refresh'],
plugins: ['react-hooks', 'react-refresh', '@nx', 'prefer-arrow', 'import', 'unused-imports', 'unicorn', 'lingui'],
rules: {
'lingui/no-single-variables-to-translate': 'off',
'func-style': ['error', 'declaration', { allowArrowFunctions: true }],
'no-console': ['warn', { allow: ['group', 'groupCollapsed', 'groupEnd'] }],
'no-control-regex': 0,
'no-debugger': 'error',
'no-duplicate-imports': 'error',
'no-undef': 'off',
'no-unused-vars': 'off',
'@nx/enforce-module-boundaries': [
'error',
{
enforceBuildableLibDependency: true,
allow: [],
depConstraints: [
{
sourceTag: 'scope:shared',
onlyDependOnLibsWithTags: ['scope:shared'],
},
{
sourceTag: 'scope:backend',
onlyDependOnLibsWithTags: ['scope:shared', 'scope:backend'],
},
{
sourceTag: 'scope:frontend',
onlyDependOnLibsWithTags: ['scope:shared', 'scope:frontend'],
},
{
sourceTag: 'scope:zapier',
onlyDependOnLibsWithTags: ['scope:shared'],
},
],
},
],
'import/no-relative-packages': 'error',
'import/no-useless-path-segments': 'error',
'import/no-duplicates': ['error', { considerQueryString: true }],
'prefer-arrow/prefer-arrow-functions': [
'error',
{
disallowPrototype: true,
singleReturnOnly: false,
classPropertiesAllowed: false,
},
],
'unused-imports/no-unused-imports': 'warn',
'unused-imports/no-unused-vars': [
'warn',
{
vars: 'all',
varsIgnorePattern: '^_',
args: 'after-used',
argsIgnorePattern: '^_',
},
],
},
overrides: [
{
files: ['**/*.ts', '**/*.tsx'],
@@ -34,6 +97,14 @@ module.exports = {
],
},
],
'@typescript-eslint/no-empty-interface': [
'error',
{
allowSingleExtends: true,
},
],
'@typescript-eslint/no-empty-function': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@nx/workspace-effect-components': 'error',
'@nx/workspace-no-hardcoded-colors': 'error',
'@nx/workspace-matching-state-variable': 'error',
@@ -83,5 +154,46 @@ module.exports = {
],
},
},
{
files: ['*.js', '*.jsx'],
extends: ['plugin:@nx/javascript'],
rules: {},
},
{
files: [
'*.test.@(ts|tsx|js|jsx)',
],
env: {
jest: true,
},
rules: {
'@typescript-eslint/no-non-null-assertion': 'off',
},
},
{
files: ['**/*.constants.ts'],
rules: {
'@typescript-eslint/naming-convention': [
'error',
{
selector: 'variable',
format: ['UPPER_CASE'],
},
],
'unicorn/filename-case': [
'warn',
{
cases: {
pascalCase: true,
},
},
],
'@nx/workspace-max-consts-per-file': ['error', { max: 1 }],
},
},
{
files: ['*.json'],
parser: 'jsonc-eslint-parser',
},
],
};
+3 -7
View File
@@ -13,14 +13,10 @@ Good first issues are a great way to start contributing and get familiar with th
## Issue assignment
Having multiple contributors address the same issue can cause frustration.
To avoid conflicts, we follow these guidelines:
1. If a core team member assigned you the issue within the last three days, your PR takes priority.
2. Otherwise, the first submitted PR is prioritized.
3. For "size: long" PRs, the assignment period extends to one week.
Please ensure you're assigned to an issue before starting work.
1. For `Good First Issue` and `Experienced Contributor` issues without `size: long` labels, we'll merge the first PRs that meet our [code quality standards](https://twenty.com/developers). **We don't assign contributors to these issues**. For `priority: high` issues, our core team will step in within days if no adequate contributions are received.
2. For `size: long` Issues, assigned contributors have one week to submit their first draft PR.
## How to Contribute
@@ -67,4 +63,4 @@ git push origin your-branch-name
## Reporting Issues
If you face any issues or have suggestions, please feel free to (create an issue on Twenty's GitHub repository)[https://github.com/twentyhq/twenty/issues/new]. Please provide as much detail as possible.
If you face any issues or have suggestions, please feel free to (create an issue on Twenty's GitHub repository)[https://github.com/twentyhq/twenty/issues/new]. Please provide as much detail as possible.
+21 -1
View File
@@ -168,9 +168,25 @@ jobs:
image: redis
ports:
- 6379:6379
clickhouse:
image: clickhouse/clickhouse-server:latest
env:
CLICKHOUSE_PASSWORD: clickhousePassword
CLICKHOUSE_URL: "http://default:clickhousePassword@localhost:8123/twenty"
ports:
- 8123:8123
- 9000:9000
options: >-
--health-cmd "clickhouse-client --host=localhost --port=9000 --user=default --password=clickhousePassword --query='SELECT 1'"
--health-interval 10s
--health-timeout 5s
--health-retries 5
env:
NX_REJECT_UNKNOWN_LOCAL_CACHE: 0
NODE_ENV: test
ANALYTICS_ENABLED: true
CLICKHOUSE_URL: "http://default:clickhousePassword@localhost:8123/twenty"
CLICKHOUSE_PASSWORD: clickhousePassword
steps:
- name: Fetch custom Github Actions and base branch history
uses: actions/checkout@v4
@@ -178,7 +194,7 @@ jobs:
fetch-depth: 0
- name: Install dependencies
uses: ./.github/workflows/actions/yarn-install
- name: Update .env.test for billing
- name: Update .env.test for integrations tests
run: |
echo "IS_BILLING_ENABLED=true" >> .env.test
echo "BILLING_STRIPE_API_KEY=test-api-key" >> .env.test
@@ -198,6 +214,10 @@ jobs:
- name: Server / Create Test DB
run: |
PGPASSWORD=postgres psql -h localhost -p 5432 -U postgres -d postgres -c 'CREATE DATABASE "test";'
- name: Run ClickHouse migrations
run: npx nx clickhouse:migrate twenty-server
- name: Run ClickHouse seeds
run: npx nx clickhouse:seed twenty-server
- name: Server / Run Integration Tests
uses: ./.github/workflows/actions/nx-affected
with:
+4 -1
View File
@@ -17,4 +17,7 @@ postgres-on-docker:
-c "CREATE DATABASE \"test\" WITH OWNER postgres;"
redis-on-docker:
docker run -d --name twenty_redis -p 6379:6379 redis/redis-stack-server:latest
docker run -d --name twenty_redis -p 6379:6379 redis/redis-stack-server:latest
clickhouse-on-docker:
docker run -d --name twenty_clickhouse -p 8123:8123 -p 9000:9000 -e CLICKHOUSE_PASSWORD=devPassword clickhouse/clickhouse-server:latest
+5 -1
View File
@@ -99,7 +99,9 @@
"graphql-fields": "^2.0.3",
"graphql-middleware": "^6.1.35",
"graphql-rate-limit": "^3.3.0",
"graphql-redis-subscriptions": "^2.7.0",
"graphql-scalars": "^1.23.0",
"graphql-sse": "^2.5.4",
"graphql-subscriptions": "2.0.0",
"graphql-tag": "^2.12.6",
"graphql-type-json": "^0.3.2",
@@ -181,6 +183,7 @@
"semver": "^7.5.4",
"sharp": "^0.32.1",
"slash": "^5.1.0",
"storybook-addon-mock-date": "^0.6.0",
"stripe": "^17.3.1",
"ts-key-enum": "^2.0.12",
"tslib": "^2.3.0",
@@ -354,7 +357,8 @@
"type-fest": "4.10.1",
"typescript": "5.3.3",
"prosemirror-model": "1.23.0",
"yjs": "13.6.18"
"yjs": "13.6.18",
"graphql-redis-subscriptions/ioredis": "^5.6.0"
},
"version": "0.2.1",
"nx": {},
+3
View File
@@ -1,4 +1,7 @@
# README
DISCLAIMER: The k8s and podman deployments are not maintained by the core team.
These files are provided and maintained by the community. Twenty core team
maintains support for docker deployment.
## Overview
+48
View File
@@ -0,0 +1,48 @@
# How to deploy twenty on podman
DISCLAIMER: The k8s and podman deployments are not maintained by the core team.
These files are provided and maintained by the community. Twenty core team
maintains support for docker deployment.
## How to use
1. Edit `.env` file. At the minimum set `POSTGRES_PASSWORD`, `SERVER_URL`, and `APP_SECRET`.
2. Start twenty by running `podman-compose up -d`.
If you need to stop twenty, you can do so by running `podman-compose down`.
### Install systemd service (optional)
If you want to install a systemd service to run twenty, you can use the provided systemd service.
Edit `twentycrm.service` and change these two variables:
WorkingDirectory=/opt/apps/twenty
EnvironmentFile=/opt/apps/twenty/.env
`WorkingDirectory` should be changed to the path in which `podman-compose.yml` is located.
`EnvironmentFile` should be changed to the path in which your `.env`file is located.
You can run the script `install-systemd-user-service` to install the systemd service under the current user.
./install-systemd-user-service
Note: this script will enable the service and also start it. So it will assume that twenty is not currently running.
If you started it previously, bring it down using:
podman-compose down
## Compatibility
These files should be compatible with podman 4.3+.
I have tested this on Debian GNU/Linux 12 (bookworm) and with the podman that is distributed with the official Debian stable mirrors (podman v4.3.1+ds1-8+deb12u1, podman-compose v1.0.3-3).
+11
View File
@@ -0,0 +1,11 @@
#!/bin/bash
set -e
mkdir -p ~/.config/systemd/user
[ -f twentycrm.service ] || { echo "Error: twentycrm.service not found"; exit 1; }
cp twentycrm.service ~/.config/systemd/user
systemctl --user daemon-reload
systemctl --user enable twentycrm.service
systemctl --user start twentycrm.service
@@ -0,0 +1,71 @@
#!/bin/bash
set -e
if [ ! -f "$(dirname "$0")/.env" ]; then
echo "Error: .env file not found"
exit 1
fi
source "$(dirname "$0")/.env"
## steps to cleanup and start over from scratch - useful when testing
#podman pod stop twenty-pod
#podman pod rm twenty-pod
#podman volume rm twenty-db-data twenty-server-data twenty-redis-data
# end of cleanup
podman volume create twenty-db-data
podman volume create twenty-server-data
podman volume create twenty-redis-data
podman pod create --name twenty-pod -p 127.0.0.1:8080:3000
podman run -d --pod twenty-pod --name twenty-db \
-e POSTGRES_DB=twenty \
-e POSTGRES_USER=twenty \
-e POSTGRES_PASSWORD="$POSTGRES_PASSWORD" \
-v twenty-db-data:/var/lib/postgresql/data:Z \
docker.io/library/postgres:16
podman run -d --pod twenty-pod --name twenty-redis \
-v twenty-redis-data:/data:Z \
docker.io/library/redis:latest
podman run -d --pod twenty-pod --name twenty-server \
-e NODE_PORT=3000 \
-e SERVER_URL="$SERVER_URL" \
-e PG_DATABASE_URL="postgresql://twenty:$POSTGRES_PASSWORD@twenty-db:5432/twenty" \
-e REDIS_URL="redis://twenty-redis:6379" \
-e APP_SECRET="$APP_SECRET" \
-e NODE_ENV=production \
-e LOG_LEVEL=info \
-v twenty-server-data:/app/docker-data:Z \
docker.io/twentycrm/twenty:latest
podman run -d --pod twenty-pod --name twenty-worker \
--init \
-e SERVER_URL="$SERVER_URL" \
-e PG_DATABASE_URL="postgresql://twenty:$POSTGRES_PASSWORD@twenty-db:5432/twenty" \
-e REDIS_URL="redis://twenty-redis:6379" \
-e APP_SECRET="$APP_SECRET" \
-e DISABLE_DB_MIGRATIONS=true \
-e NODE_ENV=production \
-e LOG_LEVEL=info \
-v twenty-server-data:/app/docker-data:Z \
docker.io/twentycrm/twenty:latest \
yarn worker:prod
# wait some time, check status
sleep 30
podman ps --pod -f name=twenty-pod
mkdir -p ~/.config/systemd/user
if [ ! -f "twentycrm.service" ]; then
echo "Error: twentycrm.service file not found"
exit 1
fi
cp twentycrm.service ~/.config/systemd/user
systemctl --user daemon-reload
systemctl --user enable twentycrm.service
systemctl --user start twentycrm.service
@@ -0,0 +1,55 @@
version: "3.8"
services:
db:
container_name: twenty-db
image: postgres:16
environment:
POSTGRES_DB: twenty
POSTGRES_USER: twenty
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- twenty-db-data:/var/lib/postgresql/data:Z
redis:
container_name: twenty-redis
image: redis:latest
volumes:
- twenty-redis-data:/data:Z
server:
container_name: twenty-server
image: twentycrm/twenty:latest
environment:
NODE_PORT: "3000"
SERVER_URL: ${SERVER_URL}
PG_DATABASE_URL: "postgresql://twenty:${POSTGRES_PASSWORD}@twenty-db:5432/twenty"
REDIS_URL: "redis://twenty-redis:6379"
APP_SECRET: ${APP_SECRET}
NODE_ENV: production
LOG_LEVEL: info
volumes:
- twenty-server-data:/app/docker-data:Z
ports:
- 127.0.0.1:8080:3000
worker:
container_name: twenty-worker
image: twentycrm/twenty:latest
command: yarn worker:prod
environment:
SERVER_URL: ${SERVER_URL}
PG_DATABASE_URL: "postgresql://twenty:${POSTGRES_PASSWORD}@twenty-db:5432/twenty"
REDIS_URL: "redis://twenty-redis:6379"
APP_SECRET: ${APP_SECRET}
DISABLE_DB_MIGRATIONS: "true"
NODE_ENV: production
LOG_LEVEL: info
volumes:
- twenty-server-data:/app/docker-data:Z
init: true
volumes:
twenty-db-data:
twenty-server-data:
twenty-redis-data:
@@ -0,0 +1,15 @@
[Unit]
Description=TwentyCRM Container Stack via Podman-Compose
After=network.target
[Service]
Type=simple
WorkingDirectory=/opt/apps/twenty
EnvironmentFile=/opt/apps/twenty/.env
ExecStart=/usr/bin/podman-compose -f podman-compose.yml up -d
ExecStop=/usr/bin/podman-compose -f podman-compose.yml down
RemainAfterExit=yes
[Install]
WantedBy=default.target
-2
View File
@@ -64,8 +64,6 @@ WORKDIR /app/packages/twenty-server
ARG REACT_APP_SERVER_BASE_URL
ENV REACT_APP_SERVER_BASE_URL $REACT_APP_SERVER_BASE_URL
ARG SENTRY_RELEASE
ENV SENTRY_RELEASE $SENTRY_RELEASE
ARG APP_VERSION
ENV APP_VERSION $APP_VERSION
@@ -17,6 +17,7 @@ export class WorkflowVisualizerPage {
readonly deactivateWorkflowButton: Locator;
readonly addTriggerButton: Locator;
readonly commandMenu: Locator;
readonly stepHeaderInCommandMenu: Locator;
readonly workflowNameLabel: Locator;
readonly triggerNode: Locator;
readonly background: Locator;
@@ -68,6 +69,9 @@ export class WorkflowVisualizerPage {
});
this.addTriggerButton = page.getByText('Add a Trigger');
this.commandMenu = page.getByTestId('command-menu');
this.stepHeaderInCommandMenu = this.commandMenu.getByTestId(
'workflow-step-header',
);
this.workflowNameLabel = page
.getByTestId('top-bar-title')
.getByText(this.workflowName);
@@ -114,7 +118,7 @@ export class WorkflowVisualizerPage {
.getByTestId(`row-id-${this.workflowId}`)
.getByRole('link', { name: this.workflowName });
await workflowLink.click();
await workflowLink.click({ force: true });
await this.waitForWorkflowVisualizerLoad();
}
@@ -110,6 +110,10 @@ export class SettingsPage {
await this.releasesLink.click();
}
async logout() {
await this.page.getByText('Logout').click();
}
async toggleAdvancedSettings() {
await this.advancedToggle.click();
}
-1
View File
@@ -1,6 +1,5 @@
{
"name": "twenty-e2e-testing",
"version": "0.51.0-canary",
"description": "",
"author": "",
"private": true,
@@ -10,7 +10,9 @@ test('Create workflow', async ({ page }) => {
const workflowsLink = page.getByRole('link', { name: 'Workflows' });
await workflowsLink.click();
const createWorkflowButton = page.getByRole('button', { name: 'New record' });
const createWorkflowButton = page.getByRole('button', {
name: 'Create new workflow',
});
const [createWorkflowResponse] = await Promise.all([
page.waitForResponse(async (response) => {
@@ -26,7 +28,7 @@ test('Create workflow', async ({ page }) => {
createWorkflowButton.click(),
]);
const recordName = page.getByTestId('top-bar-title').getByTestId('tooltip');
const recordName = page.getByTestId('top-bar-title').getByText('Untitled');
await recordName.click();
const nameInput = page.getByTestId('top-bar-title').getByRole('textbox');
@@ -1,60 +1,58 @@
import { expect } from '@playwright/test';
import { test } from '../lib/fixtures/blank-workflow';
test.fixme(
'The workflow run visualizer shows the executed draft version without the last draft changes',
async ({ workflowVisualizer, page }) => {
await workflowVisualizer.createInitialTrigger('manual');
test('The workflow run visualizer shows the executed draft version without the last draft changes', async ({
workflowVisualizer,
page,
}) => {
await workflowVisualizer.createInitialTrigger('manual');
const manualTriggerAvailabilitySelect = page.getByRole('button', {
name: 'When record(s) are selected',
});
const manualTriggerAvailabilitySelect = page.getByRole('button', {
name: 'When record(s) are selected',
});
await manualTriggerAvailabilitySelect.click();
await manualTriggerAvailabilitySelect.click();
const alwaysAvailableOption = page.getByText(
'When no record(s) are selected',
);
const alwaysAvailableOption = page.getByText(
'When no record(s) are selected',
);
await alwaysAvailableOption.click();
await alwaysAvailableOption.click();
await workflowVisualizer.closeSidePanel();
await workflowVisualizer.closeSidePanel();
const { createdStepId: firstStepId } =
await workflowVisualizer.createStep('create-record');
const { createdStepId: firstStepId } =
await workflowVisualizer.createStep('create-record');
await workflowVisualizer.closeSidePanel();
await workflowVisualizer.closeSidePanel();
const launchTestButton = page.getByLabel('Test Workflow');
const launchTestButton = page.getByLabel(workflowVisualizer.workflowName);
await launchTestButton.click();
await launchTestButton.click();
const goToExecutionPageLink = page.getByRole('link', {
name: 'View execution details',
});
const executionPageUrl = await goToExecutionPageLink.getAttribute('href');
expect(executionPageUrl).not.toBeNull();
const goToExecutionPageLink = page.getByRole('link', {
name: 'View execution details',
});
const executionPageUrl = await goToExecutionPageLink.getAttribute('href');
expect(executionPageUrl).not.toBeNull();
await workflowVisualizer.deleteStep(firstStepId);
await workflowVisualizer.deleteStep(firstStepId);
await page.goto(executionPageUrl!);
await page.goto(executionPageUrl!);
const workflowRunName = page.getByText('Execution of v1');
const workflowRunName = page
.getByText(`#1 - ${workflowVisualizer.workflowName}`)
.nth(1);
await expect(workflowRunName).toBeVisible();
await expect(workflowRunName).toBeVisible();
const flowTab = page.getByText('Flow', { exact: true });
const executedFirstStepNode = workflowVisualizer.getStepNode(firstStepId);
await flowTab.click();
await expect(executedFirstStepNode).toBeVisible();
const executedFirstStepNode = workflowVisualizer.getStepNode(firstStepId);
await executedFirstStepNode.click();
await expect(executedFirstStepNode).toBeVisible();
await executedFirstStepNode.click();
await expect(
workflowVisualizer.commandMenu.getByRole('textbox').first(),
).toHaveValue('Create Record');
},
);
await expect(workflowVisualizer.stepHeaderInCommandMenu).toContainText(
'Create Record',
);
});
@@ -57,7 +57,7 @@ test('Use an old version as draft', async ({ workflowVisualizer, page }) => {
},
);
await linkToFirstWorkflowVersion.click();
await linkToFirstWorkflowVersion.click({ force: true });
await expect(workflowVisualizer.workflowStatus).toHaveText('Archived');
await expect(workflowVisualizer.useAsDraftButton).toBeVisible();
@@ -139,7 +139,7 @@ test('Use an old version as draft while having a pending draft version', async (
},
);
await linkToFirstWorkflowVersion.click();
await linkToFirstWorkflowVersion.click({ force: true });
await expect(workflowVisualizer.workflowStatus).toHaveText('Active');
await expect(workflowVisualizer.useAsDraftButton).toBeVisible();
-1
View File
@@ -1,6 +1,5 @@
{
"name": "twenty-emails",
"version": "0.51.0-canary",
"description": "",
"author": "",
"private": true,
+1
View File
@@ -1,5 +1,6 @@
REACT_APP_SERVER_BASE_URL=http://localhost:3000
VITE_BUILD_SOURCEMAP=false
VITE_DISABLE_ESLINT_CHECKER=true
# ———————— Optional ————————
+6 -65
View File
@@ -1,19 +1,20 @@
const path = require('path');
module.exports = {
extends: ['../../.eslintrc.global.cjs', '../../.eslintrc.react.cjs'],
extends: ['../../.eslintrc.react.cjs'],
ignorePatterns: [
'node_modules',
'mockServiceWorker.js',
'**/generated*/*',
'**/generated/standard-metadata-query-result.ts',
'tsup.config.ts',
'build',
'coverage',
'storybook-static',
'**/*config.js',
'jest.config.ts',
'emotion.d.ts',
'lingui.config.ts',
'vite.config.ts',
'setupTests.ts',
'codegen*',
'tsup.ui.index.tsx',
'__mocks__',
],
overrides: [
@@ -22,66 +23,6 @@ module.exports = {
parserOptions: {
project: ['packages/twenty-front/tsconfig.*.json'],
},
plugins: ['project-structure'],
settings: {
'project-structure/folder-structure-config-path': path.join(
__dirname,
'folderStructure.json',
),
},
rules: {
'project-structure/folder-structure': 'error',
/*
Uncomment this rule when we have a way to work on
'lingui/no-unlocalized-strings': [
'error',
{
ignore: [
'^(?![A-Z])\\S+$',
'^[A-Z0-9_-]+$'
],
ignoreNames: [
{ regex: { pattern: 'className', flags: 'i' } },
{ regex: { pattern: '^[A-Z0-9_-]+$' } },
'styleName',
'src',
'srcSet',
'type',
'id',
'width',
'height',
'displayName',
'Authorization'
],
ignoreFunctions: [
'cva',
'cn',
'track',
'Error',
'console.*',
'*headers.set',
'*.addEventListener',
'*.removeEventListener',
'*.postMessage',
'*.getElementById',
'*.dispatch',
'*.commit',
'*.includes',
'*.indexOf',
'*.endsWith',
'*.startsWith',
'require'
],
useTsTypes: true,
ignoreMethodsOnTypes: [
'Map.get',
'Map.has',
'Set.has'
]
}
]
*/
},
},
],
};
+1
View File
@@ -48,6 +48,7 @@ const config: StorybookConfig = {
'storybook-dark-mode',
'storybook-addon-cookie',
'storybook-addon-pseudo-states',
'storybook-addon-mock-date'
],
framework: {
name: '@storybook/react-vite',
@@ -8,6 +8,7 @@ import { RootDecorator } from '../src/testing/decorators/RootDecorator';
import { mockedUserJWT } from '../src/testing/mock-data/jwt';
import 'react-loading-skeleton/dist/skeleton.css';
import 'twenty-ui/style.css';
import { THEME_DARK, THEME_LIGHT, ThemeContextProvider } from 'twenty-ui/theme';
initialize({
@@ -61,6 +62,7 @@ const preview: Preview = {
date: /Date$/,
},
},
mockingDate: new Date('2024-03-12T09:30:00.000Z'),
options: {
storySort: {
order: ['UI', 'Modules', 'Pages'],
-1
View File
@@ -12,7 +12,6 @@ module.exports = {
'!./src/**/*.test.tsx',
'!./src/**/*.stories.tsx',
'!./src/**/__mocks__/*.ts',
'!./src/modules/users/graphql/queries/getCurrentUserAndViews.ts',
],
overwrite: true,
generates: {
+1 -1
View File
@@ -21,7 +21,7 @@
"moduleFolderRule": {
"name": "{kebab-case}",
"folderRecursionLimit": 6,
"folderRecursionLimit": 4,
"children": [
{ "ruleId": "moduleFolderRule" },
{ "name": "hooks", "ruleId": "hooksLeafFolderRule" },
+1 -1
View File
@@ -60,7 +60,7 @@
}
</script>
</head>
<body style="width: 100%; height: 100vh">
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script
+1
View File
@@ -69,6 +69,7 @@ const jestConfig: JestConfigWithTsJest = {
'config/*',
'graphql/queries/*',
'graphql/mutations/*',
'graphql/subscriptions/*',
'graphql/fragments/*',
'types/*',
'constants/*',
+1 -1
View File
@@ -9,7 +9,7 @@ const globalCoverage = {
const modulesCoverage = {
branches: 25,
statements: 44,
statements: 43,
lines: 44,
functions: 38,
include: ['src/modules/**/*'],
-2
View File
@@ -1,6 +1,5 @@
{
"name": "twenty-front",
"version": "0.51.0-canary",
"private": true,
"type": "module",
"scripts": {
@@ -54,7 +53,6 @@
"buffer": "^6.0.3",
"docx": "^9.1.0",
"file-saver": "^2.0.5",
"recoil-sync": "^0.2.0",
"transliteration": "^2.3.5",
"twenty-shared": "workspace:*",
"twenty-ui": "workspace:*"
@@ -63,6 +63,11 @@ export type Analytics = {
success: Scalars['Boolean']['output'];
};
export enum AnalyticsType {
PAGEVIEW = 'PAGEVIEW',
TRACK = 'TRACK'
}
export type ApiConfig = {
__typename?: 'ApiConfig';
mutationMaximumAffectedRecords: Scalars['Float']['output'];
@@ -145,6 +150,26 @@ export type Billing = {
trialPeriods: Array<BillingTrialPeriodDto>;
};
export type BillingEndTrialPeriodOutput = {
__typename?: 'BillingEndTrialPeriodOutput';
/** Boolean that confirms if a payment method was found */
hasPaymentMethod: Scalars['Boolean']['output'];
/** Updated subscription status */
status?: Maybe<SubscriptionStatus>;
};
export type BillingMeteredProductUsageOutput = {
__typename?: 'BillingMeteredProductUsageOutput';
freeTierQuantity: Scalars['Float']['output'];
freeTrialQuantity: Scalars['Float']['output'];
periodEnd: Scalars['DateTime']['output'];
periodStart: Scalars['DateTime']['output'];
productKey: BillingProductKey;
totalCostCents: Scalars['Float']['output'];
unitPriceCents: Scalars['Float']['output'];
usageQuantity: Scalars['Float']['output'];
};
/** The different billing plans available */
export enum BillingPlanKey {
ENTERPRISE = 'ENTERPRISE',
@@ -153,9 +178,9 @@ export enum BillingPlanKey {
export type BillingPlanOutput = {
__typename?: 'BillingPlanOutput';
baseProduct: BillingProductDto;
meteredProducts: Array<BillingProductDto>;
otherLicensedProducts: Array<BillingProductDto>;
baseProduct: BillingProduct;
meteredProducts: Array<BillingProduct>;
otherLicensedProducts: Array<BillingProduct>;
planKey: BillingPlanKey;
};
@@ -191,13 +216,26 @@ export enum BillingPriceTiersMode {
export type BillingPriceUnionDto = BillingPriceLicensedDto | BillingPriceMeteredDto;
export type BillingProductDto = {
__typename?: 'BillingProductDTO';
export type BillingProduct = {
__typename?: 'BillingProduct';
description: Scalars['String']['output'];
images?: Maybe<Array<Scalars['String']['output']>>;
metadata: BillingProductMetadata;
name: Scalars['String']['output'];
prices: Array<BillingPriceUnionDto>;
type: BillingUsageType;
prices?: Maybe<Array<BillingPriceUnionDto>>;
};
/** The different billing products available */
export enum BillingProductKey {
BASE_PRODUCT = 'BASE_PRODUCT',
WORKFLOW_NODE_EXECUTION = 'WORKFLOW_NODE_EXECUTION'
}
export type BillingProductMetadata = {
__typename?: 'BillingProductMetadata';
planKey: BillingPlanKey;
priceUsageBased: BillingUsageType;
productKey: BillingProductKey;
};
export type BillingSessionOutput = {
@@ -207,11 +245,19 @@ export type BillingSessionOutput = {
export type BillingSubscription = {
__typename?: 'BillingSubscription';
billingSubscriptionItems?: Maybe<Array<BillingSubscriptionItem>>;
id: Scalars['UUID']['output'];
interval?: Maybe<SubscriptionInterval>;
status: SubscriptionStatus;
};
export type BillingSubscriptionItem = {
__typename?: 'BillingSubscriptionItem';
billingProduct?: Maybe<BillingProduct>;
hasReachedCurrentPeriodCap: Scalars['Boolean']['output'];
id: Scalars['UUID']['output'];
};
export type BillingTrialPeriodDto = {
__typename?: 'BillingTrialPeriodDTO';
duration: Scalars['Float']['output'];
@@ -280,6 +326,49 @@ export type ComputeStepOutputSchemaInput = {
step: Scalars['JSON']['input'];
};
export type ConfigVariable = {
__typename?: 'ConfigVariable';
description: Scalars['String']['output'];
isSensitive: Scalars['Boolean']['output'];
name: Scalars['String']['output'];
value: Scalars['String']['output'];
};
export enum ConfigVariablesGroup {
AnalyticsConfig = 'AnalyticsConfig',
BillingConfig = 'BillingConfig',
CaptchaConfig = 'CaptchaConfig',
CloudflareConfig = 'CloudflareConfig',
EmailSettings = 'EmailSettings',
ExceptionHandler = 'ExceptionHandler',
GoogleAuth = 'GoogleAuth',
LLM = 'LLM',
Logging = 'Logging',
Metering = 'Metering',
MicrosoftAuth = 'MicrosoftAuth',
Other = 'Other',
RateLimiting = 'RateLimiting',
SSL = 'SSL',
ServerConfig = 'ServerConfig',
ServerlessConfig = 'ServerlessConfig',
StorageConfig = 'StorageConfig',
SupportChatConfig = 'SupportChatConfig',
TokensDuration = 'TokensDuration'
}
export type ConfigVariablesGroupData = {
__typename?: 'ConfigVariablesGroupData';
description: Scalars['String']['output'];
isHiddenOnLoad: Scalars['Boolean']['output'];
name: ConfigVariablesGroup;
variables: Array<ConfigVariable>;
};
export type ConfigVariablesOutput = {
__typename?: 'ConfigVariablesOutput';
groups: Array<ConfigVariablesGroupData>;
};
export type CreateAppTokenInput = {
expiresAt: Scalars['DateTime']['input'];
};
@@ -391,6 +480,10 @@ export type CreateServerlessFunctionInput = {
};
export type CreateWorkflowVersionStepInput = {
/** Next step ID */
nextStepId?: InputMaybe<Scalars['String']['input']>;
/** Parent step ID */
parentStepId?: InputMaybe<Scalars['String']['input']>;
/** New step type */
stepType: Scalars['String']['input'];
/** Workflow version ID */
@@ -498,49 +591,6 @@ export type EmailPasswordResetLink = {
success: Scalars['Boolean']['output'];
};
export type EnvironmentVariable = {
__typename?: 'EnvironmentVariable';
description: Scalars['String']['output'];
name: Scalars['String']['output'];
sensitive: Scalars['Boolean']['output'];
value: Scalars['String']['output'];
};
export enum EnvironmentVariablesGroup {
AnalyticsConfig = 'AnalyticsConfig',
BillingConfig = 'BillingConfig',
CaptchaConfig = 'CaptchaConfig',
CloudflareConfig = 'CloudflareConfig',
EmailSettings = 'EmailSettings',
ExceptionHandler = 'ExceptionHandler',
GoogleAuth = 'GoogleAuth',
LLM = 'LLM',
Logging = 'Logging',
Metering = 'Metering',
MicrosoftAuth = 'MicrosoftAuth',
Other = 'Other',
RateLimiting = 'RateLimiting',
SSL = 'SSL',
ServerConfig = 'ServerConfig',
ServerlessConfig = 'ServerlessConfig',
StorageConfig = 'StorageConfig',
SupportChatConfig = 'SupportChatConfig',
TokensDuration = 'TokensDuration'
}
export type EnvironmentVariablesGroupData = {
__typename?: 'EnvironmentVariablesGroupData';
description: Scalars['String']['output'];
isHiddenOnLoad: Scalars['Boolean']['output'];
name: EnvironmentVariablesGroup;
variables: Array<EnvironmentVariable>;
};
export type EnvironmentVariablesOutput = {
__typename?: 'EnvironmentVariablesOutput';
groups: Array<EnvironmentVariablesGroupData>;
};
export type ExecuteServerlessFunctionInput = {
/** Id of the serverless function to execute */
id: Scalars['UUID']['input'];
@@ -558,6 +608,12 @@ export type FeatureFlag = {
workspaceId: Scalars['String']['output'];
};
export type FeatureFlagDto = {
__typename?: 'FeatureFlagDTO';
key: FeatureFlagKey;
value: Scalars['Boolean']['output'];
};
export enum FeatureFlagKey {
IsAirtableIntegrationEnabled = 'IsAirtableIntegrationEnabled',
IsAnalyticsV2Enabled = 'IsAnalyticsV2Enabled',
@@ -566,7 +622,6 @@ export enum FeatureFlagKey {
IsCustomDomainEnabled = 'IsCustomDomainEnabled',
IsEventObjectEnabled = 'IsEventObjectEnabled',
IsJsonFilterEnabled = 'IsJsonFilterEnabled',
IsMeteredProductBillingEnabled = 'IsMeteredProductBillingEnabled',
IsNewRelationEnabled = 'IsNewRelationEnabled',
IsPermissionsV2Enabled = 'IsPermissionsV2Enabled',
IsPostgreSQLIntegrationEnabled = 'IsPostgreSQLIntegrationEnabled',
@@ -908,6 +963,7 @@ export type Mutation = {
editSSOIdentityProvider: EditSsoOutput;
emailPasswordResetLink: EmailPasswordResetLink;
enablePostgresProxy: PostgresCredentials;
endSubscriptionTrialPeriod: BillingEndTrialPeriodOutput;
executeOneServerlessFunction: ServerlessFunctionExecutionResult;
generateApiKeyToken: ApiKeyToken;
generateTransientToken: TransientToken;
@@ -926,12 +982,13 @@ export type Mutation = {
signUpInNewWorkspace: SignUpOutput;
skipSyncEmailOnboardingStep: OnboardingStepSuccess;
submitFormStep: Scalars['Boolean']['output'];
switchToYearlyInterval: BillingUpdateOutput;
syncRemoteTable: RemoteTable;
syncRemoteTableSchemaChanges: RemoteTable;
track: Analytics;
trackAnalytics: Analytics;
unsyncRemoteTable: RemoteTable;
updateBillingSubscription: BillingUpdateOutput;
updateLabPublicFeatureFlag: FeatureFlag;
updateLabPublicFeatureFlag: FeatureFlagDto;
updateOneField: Field;
updateOneObject: Object;
updateOneRemoteServer: RemoteServer;
@@ -1212,6 +1269,14 @@ export type MutationTrackArgs = {
};
export type MutationTrackAnalyticsArgs = {
event?: InputMaybe<Scalars['String']['input']>;
name?: InputMaybe<Scalars['String']['input']>;
properties?: InputMaybe<Scalars['JSON']['input']>;
type: AnalyticsType;
};
export type MutationUnsyncRemoteTableArgs = {
input: RemoteTableInput;
};
@@ -1524,8 +1589,9 @@ export type Query = {
findWorkspaceInvitations: Array<WorkspaceInvitation>;
getApprovedAccessDomains: Array<ApprovedAccessDomain>;
getAvailablePackages: Scalars['JSON']['output'];
getEnvironmentVariablesGrouped: EnvironmentVariablesOutput;
getConfigVariablesGrouped: ConfigVariablesOutput;
getIndicatorHealthStatus: AdminPanelHealthServiceData;
getMeteredProductsUsage: Array<BillingMeteredProductUsageOutput>;
getPostgresCredentials?: Maybe<PostgresCredentials>;
getPublicWorkspaceDataByDomain: PublicWorkspaceDataOutput;
getQueueMetrics: QueueMetricsData;
@@ -1545,6 +1611,7 @@ export type Query = {
relationMetadata: RelationMetadataConnection;
search: Array<SearchRecord>;
validatePasswordResetToken: ValidatePasswordResetToken;
versionInfo: VersionInfo;
};
@@ -1849,6 +1916,7 @@ export type Role = {
id: Scalars['String']['output'];
isEditable: Scalars['Boolean']['output'];
label: Scalars['String']['output'];
objectPermissions?: Maybe<Array<ObjectPermission>>;
settingPermissions?: Maybe<Array<SettingPermission>>;
workspaceMembers: Array<WorkspaceMember>;
};
@@ -2369,6 +2437,12 @@ export type ValidatePasswordResetToken = {
id: Scalars['String']['output'];
};
export type VersionInfo = {
__typename?: 'VersionInfo';
currentVersion?: Maybe<Scalars['String']['output']>;
latestVersion: Scalars['String']['output'];
};
export type WorkerQueueMetrics = {
__typename?: 'WorkerQueueMetrics';
active: Scalars['Float']['output'];
@@ -2413,7 +2487,7 @@ export type Workspace = {
defaultRole?: Maybe<Role>;
deletedAt?: Maybe<Scalars['DateTime']['output']>;
displayName?: Maybe<Scalars['String']['output']>;
featureFlags?: Maybe<Array<FeatureFlag>>;
featureFlags?: Maybe<Array<FeatureFlagDto>>;
hasValidEnterpriseKey: Scalars['Boolean']['output'];
id: Scalars['UUID']['output'];
inviteHash?: Maybe<Scalars['String']['output']>;
+351 -88
View File
@@ -55,6 +55,11 @@ export type Analytics = {
success: Scalars['Boolean'];
};
export enum AnalyticsType {
PAGEVIEW = 'PAGEVIEW',
TRACK = 'TRACK'
}
export type ApiConfig = {
__typename?: 'ApiConfig';
mutationMaximumAffectedRecords: Scalars['Float'];
@@ -145,6 +150,18 @@ export type BillingEndTrialPeriodOutput = {
status?: Maybe<SubscriptionStatus>;
};
export type BillingMeteredProductUsageOutput = {
__typename?: 'BillingMeteredProductUsageOutput';
freeTierQuantity: Scalars['Float'];
freeTrialQuantity: Scalars['Float'];
periodEnd: Scalars['DateTime'];
periodStart: Scalars['DateTime'];
productKey: BillingProductKey;
totalCostCents: Scalars['Float'];
unitPriceCents: Scalars['Float'];
usageQuantity: Scalars['Float'];
};
/** The different billing plans available */
export enum BillingPlanKey {
ENTERPRISE = 'ENTERPRISE',
@@ -301,6 +318,49 @@ export type ComputeStepOutputSchemaInput = {
step: Scalars['JSON'];
};
export type ConfigVariable = {
__typename?: 'ConfigVariable';
description: Scalars['String'];
isSensitive: Scalars['Boolean'];
name: Scalars['String'];
value: Scalars['String'];
};
export enum ConfigVariablesGroup {
AnalyticsConfig = 'AnalyticsConfig',
BillingConfig = 'BillingConfig',
CaptchaConfig = 'CaptchaConfig',
CloudflareConfig = 'CloudflareConfig',
EmailSettings = 'EmailSettings',
ExceptionHandler = 'ExceptionHandler',
GoogleAuth = 'GoogleAuth',
LLM = 'LLM',
Logging = 'Logging',
Metering = 'Metering',
MicrosoftAuth = 'MicrosoftAuth',
Other = 'Other',
RateLimiting = 'RateLimiting',
SSL = 'SSL',
ServerConfig = 'ServerConfig',
ServerlessConfig = 'ServerlessConfig',
StorageConfig = 'StorageConfig',
SupportChatConfig = 'SupportChatConfig',
TokensDuration = 'TokensDuration'
}
export type ConfigVariablesGroupData = {
__typename?: 'ConfigVariablesGroupData';
description: Scalars['String'];
isHiddenOnLoad: Scalars['Boolean'];
name: ConfigVariablesGroup;
variables: Array<ConfigVariable>;
};
export type ConfigVariablesOutput = {
__typename?: 'ConfigVariablesOutput';
groups: Array<ConfigVariablesGroupData>;
};
export type CreateApprovedAccessDomainInput = {
domain: Scalars['String'];
email: Scalars['String'];
@@ -356,6 +416,10 @@ export type CreateServerlessFunctionInput = {
};
export type CreateWorkflowVersionStepInput = {
/** Next step ID */
nextStepId?: InputMaybe<Scalars['String']>;
/** Parent step ID */
parentStepId?: InputMaybe<Scalars['String']>;
/** New step type */
stepType: Scalars['String'];
/** Workflow version ID */
@@ -389,6 +453,15 @@ export type CustomDomainValidRecords = {
records: Array<CustomDomainRecord>;
};
/** Database Event Action */
export enum DatabaseEventAction {
CREATED = 'CREATED',
DELETED = 'DELETED',
DESTROYED = 'DESTROYED',
RESTORED = 'RESTORED',
UPDATED = 'UPDATED'
}
export type DateFilter = {
eq?: InputMaybe<Scalars['Date']>;
gt?: InputMaybe<Scalars['Date']>;
@@ -458,49 +531,6 @@ export type EmailPasswordResetLink = {
success: Scalars['Boolean'];
};
export type EnvironmentVariable = {
__typename?: 'EnvironmentVariable';
description: Scalars['String'];
name: Scalars['String'];
sensitive: Scalars['Boolean'];
value: Scalars['String'];
};
export enum EnvironmentVariablesGroup {
AnalyticsConfig = 'AnalyticsConfig',
BillingConfig = 'BillingConfig',
CaptchaConfig = 'CaptchaConfig',
CloudflareConfig = 'CloudflareConfig',
EmailSettings = 'EmailSettings',
ExceptionHandler = 'ExceptionHandler',
GoogleAuth = 'GoogleAuth',
LLM = 'LLM',
Logging = 'Logging',
Metering = 'Metering',
MicrosoftAuth = 'MicrosoftAuth',
Other = 'Other',
RateLimiting = 'RateLimiting',
SSL = 'SSL',
ServerConfig = 'ServerConfig',
ServerlessConfig = 'ServerlessConfig',
StorageConfig = 'StorageConfig',
SupportChatConfig = 'SupportChatConfig',
TokensDuration = 'TokensDuration'
}
export type EnvironmentVariablesGroupData = {
__typename?: 'EnvironmentVariablesGroupData';
description: Scalars['String'];
isHiddenOnLoad: Scalars['Boolean'];
name: EnvironmentVariablesGroup;
variables: Array<EnvironmentVariable>;
};
export type EnvironmentVariablesOutput = {
__typename?: 'EnvironmentVariablesOutput';
groups: Array<EnvironmentVariablesGroupData>;
};
export type ExecuteServerlessFunctionInput = {
/** Id of the serverless function to execute */
id: Scalars['UUID'];
@@ -518,6 +548,12 @@ export type FeatureFlag = {
workspaceId: Scalars['String'];
};
export type FeatureFlagDto = {
__typename?: 'FeatureFlagDTO';
key: FeatureFlagKey;
value: Scalars['Boolean'];
};
export enum FeatureFlagKey {
IsAirtableIntegrationEnabled = 'IsAirtableIntegrationEnabled',
IsAnalyticsV2Enabled = 'IsAnalyticsV2Enabled',
@@ -526,7 +562,6 @@ export enum FeatureFlagKey {
IsCustomDomainEnabled = 'IsCustomDomainEnabled',
IsEventObjectEnabled = 'IsEventObjectEnabled',
IsJsonFilterEnabled = 'IsJsonFilterEnabled',
IsMeteredProductBillingEnabled = 'IsMeteredProductBillingEnabled',
IsNewRelationEnabled = 'IsNewRelationEnabled',
IsPermissionsV2Enabled = 'IsPermissionsV2Enabled',
IsPostgreSQLIntegrationEnabled = 'IsPostgreSQLIntegrationEnabled',
@@ -876,9 +911,10 @@ export type Mutation = {
signUpInNewWorkspace: SignUpOutput;
skipSyncEmailOnboardingStep: OnboardingStepSuccess;
submitFormStep: Scalars['Boolean'];
switchToYearlyInterval: BillingUpdateOutput;
track: Analytics;
updateBillingSubscription: BillingUpdateOutput;
updateLabPublicFeatureFlag: FeatureFlag;
trackAnalytics: Analytics;
updateLabPublicFeatureFlag: FeatureFlagDto;
updateOneField: Field;
updateOneObject: Object;
updateOneRole: Role;
@@ -1118,6 +1154,14 @@ export type MutationTrackArgs = {
};
export type MutationTrackAnalyticsArgs = {
event?: InputMaybe<Scalars['String']>;
name?: InputMaybe<Scalars['String']>;
properties?: InputMaybe<Scalars['JSON']>;
type: AnalyticsType;
};
export type MutationUpdateLabPublicFeatureFlagArgs = {
input: UpdateLabPublicFeatureFlagInput;
};
@@ -1331,6 +1375,21 @@ export type ObjectStandardOverrides = {
translations?: Maybe<Scalars['JSON']>;
};
export type OnDbEventDto = {
__typename?: 'OnDbEventDTO';
action: DatabaseEventAction;
eventDate: Scalars['DateTime'];
objectNameSingular: Scalars['String'];
record: Scalars['JSON'];
updatedFields?: Maybe<Array<Scalars['String']>>;
};
export type OnDbEventInput = {
action?: InputMaybe<DatabaseEventAction>;
objectNameSingular?: InputMaybe<Scalars['String']>;
recordId?: InputMaybe<Scalars['String']>;
};
/** Onboarding status */
export enum OnboardingStatus {
COMPLETED = 'COMPLETED',
@@ -1417,8 +1476,9 @@ export type Query = {
findWorkspaceInvitations: Array<WorkspaceInvitation>;
getApprovedAccessDomains: Array<ApprovedAccessDomain>;
getAvailablePackages: Scalars['JSON'];
getEnvironmentVariablesGrouped: EnvironmentVariablesOutput;
getConfigVariablesGrouped: ConfigVariablesOutput;
getIndicatorHealthStatus: AdminPanelHealthServiceData;
getMeteredProductsUsage: Array<BillingMeteredProductUsageOutput>;
getPostgresCredentials?: Maybe<PostgresCredentials>;
getPublicWorkspaceDataByDomain: PublicWorkspaceDataOutput;
getQueueMetrics: QueueMetricsData;
@@ -1437,6 +1497,7 @@ export type Query = {
plans: Array<BillingPlanOutput>;
search: Array<SearchRecord>;
validatePasswordResetToken: ValidatePasswordResetToken;
versionInfo: VersionInfo;
};
@@ -1674,6 +1735,7 @@ export type Role = {
id: Scalars['String'];
isEditable: Scalars['Boolean'];
label: Scalars['String'];
objectPermissions?: Maybe<Array<ObjectPermission>>;
settingPermissions?: Maybe<Array<SettingPermission>>;
workspaceMembers: Array<WorkspaceMember>;
};
@@ -1847,6 +1909,16 @@ export type SubmitFormStepInput = {
workflowRunId: Scalars['String'];
};
export type Subscription = {
__typename?: 'Subscription';
onDbEvent: OnDbEventDto;
};
export type SubscriptionOnDbEventArgs = {
input: OnDbEventInput;
};
export enum SubscriptionInterval {
Day = 'Day',
Month = 'Month',
@@ -2176,6 +2248,12 @@ export type ValidatePasswordResetToken = {
id: Scalars['String'];
};
export type VersionInfo = {
__typename?: 'VersionInfo';
currentVersion?: Maybe<Scalars['String']>;
latestVersion: Scalars['String'];
};
export type WorkerQueueMetrics = {
__typename?: 'WorkerQueueMetrics';
active: Scalars['Float'];
@@ -2220,7 +2298,7 @@ export type Workspace = {
defaultRole?: Maybe<Role>;
deletedAt?: Maybe<Scalars['DateTime']>;
displayName?: Maybe<Scalars['String']>;
featureFlags?: Maybe<Array<FeatureFlag>>;
featureFlags?: Maybe<Array<FeatureFlagDto>>;
hasValidEnterpriseKey: Scalars['Boolean'];
id: Scalars['UUID'];
inviteHash?: Maybe<Scalars['String']>;
@@ -2373,6 +2451,16 @@ export type GetTimelineThreadsFromPersonIdQueryVariables = Exact<{
export type GetTimelineThreadsFromPersonIdQuery = { __typename?: 'Query', getTimelineThreadsFromPersonId: { __typename?: 'TimelineThreadsWithTotal', totalNumberOfThreads: number, timelineThreads: Array<{ __typename?: 'TimelineThread', id: any, read: boolean, visibility: MessageChannelVisibility, lastMessageReceivedAt: string, lastMessageBody: string, subject: string, numberOfMessagesInThread: number, participantCount: number, firstParticipant: { __typename?: 'TimelineThreadParticipant', personId?: any | null, workspaceMemberId?: any | null, firstName: string, lastName: string, displayName: string, avatarUrl: string, handle: string }, lastTwoParticipants: Array<{ __typename?: 'TimelineThreadParticipant', personId?: any | null, workspaceMemberId?: any | null, firstName: string, lastName: string, displayName: string, avatarUrl: string, handle: string }> }> } };
export type TrackAnalyticsMutationVariables = Exact<{
type: AnalyticsType;
event?: InputMaybe<Scalars['String']>;
name?: InputMaybe<Scalars['String']>;
properties?: InputMaybe<Scalars['JSON']>;
}>;
export type TrackAnalyticsMutation = { __typename?: 'Mutation', trackAnalytics: { __typename?: 'Analytics', success: boolean } };
export type TrackMutationVariables = Exact<{
action: Scalars['String'];
payload: Scalars['JSON'];
@@ -2559,10 +2647,15 @@ export type EndSubscriptionTrialPeriodMutationVariables = Exact<{ [key: string]:
export type EndSubscriptionTrialPeriodMutation = { __typename?: 'Mutation', endSubscriptionTrialPeriod: { __typename?: 'BillingEndTrialPeriodOutput', status?: SubscriptionStatus | null, hasPaymentMethod: boolean } };
export type UpdateBillingSubscriptionMutationVariables = Exact<{ [key: string]: never; }>;
export type GetMeteredProductsUsageQueryVariables = Exact<{ [key: string]: never; }>;
export type UpdateBillingSubscriptionMutation = { __typename?: 'Mutation', updateBillingSubscription: { __typename?: 'BillingUpdateOutput', success: boolean } };
export type GetMeteredProductsUsageQuery = { __typename?: 'Query', getMeteredProductsUsage: Array<{ __typename?: 'BillingMeteredProductUsageOutput', productKey: BillingProductKey, usageQuantity: number, freeTierQuantity: number, freeTrialQuantity: number, unitPriceCents: number, totalCostCents: number }> };
export type SwitchSubscriptionToYearlyIntervalMutationVariables = Exact<{ [key: string]: never; }>;
export type SwitchSubscriptionToYearlyIntervalMutation = { __typename?: 'Mutation', switchToYearlyInterval: { __typename?: 'BillingUpdateOutput', success: boolean } };
export type GetClientConfigQueryVariables = Exact<{ [key: string]: never; }>;
@@ -2601,10 +2694,15 @@ export type UserLookupAdminPanelMutationVariables = Exact<{
export type UserLookupAdminPanelMutation = { __typename?: 'Mutation', userLookupAdminPanel: { __typename?: 'UserLookup', user: { __typename?: 'UserInfo', id: string, email: string, firstName?: string | null, lastName?: string | null }, workspaces: Array<{ __typename?: 'WorkspaceInfo', id: string, name: string, logo?: string | null, totalUsers: number, allowImpersonation: boolean, users: Array<{ __typename?: 'UserInfo', id: string, email: string, firstName?: string | null, lastName?: string | null }>, featureFlags: Array<{ __typename?: 'FeatureFlag', key: FeatureFlagKey, value: boolean }> }> } };
export type GetEnvironmentVariablesGroupedQueryVariables = Exact<{ [key: string]: never; }>;
export type GetConfigVariablesGroupedQueryVariables = Exact<{ [key: string]: never; }>;
export type GetEnvironmentVariablesGroupedQuery = { __typename?: 'Query', getEnvironmentVariablesGrouped: { __typename?: 'EnvironmentVariablesOutput', groups: Array<{ __typename?: 'EnvironmentVariablesGroupData', name: EnvironmentVariablesGroup, description: string, isHiddenOnLoad: boolean, variables: Array<{ __typename?: 'EnvironmentVariable', name: string, description: string, value: string, sensitive: boolean }> }> } };
export type GetConfigVariablesGroupedQuery = { __typename?: 'Query', getConfigVariablesGrouped: { __typename?: 'ConfigVariablesOutput', groups: Array<{ __typename?: 'ConfigVariablesGroupData', name: ConfigVariablesGroup, description: string, isHiddenOnLoad: boolean, variables: Array<{ __typename?: 'ConfigVariable', name: string, description: string, value: string, isSensitive: boolean }> }> } };
export type GetVersionInfoQueryVariables = Exact<{ [key: string]: never; }>;
export type GetVersionInfoQuery = { __typename?: 'Query', versionInfo: { __typename?: 'VersionInfo', currentVersion?: string | null, latestVersion: string } };
export type GetIndicatorHealthStatusQueryVariables = Exact<{
indicatorId: HealthIndicatorId;
@@ -2631,7 +2729,9 @@ export type UpdateLabPublicFeatureFlagMutationVariables = Exact<{
}>;
export type UpdateLabPublicFeatureFlagMutation = { __typename?: 'Mutation', updateLabPublicFeatureFlag: { __typename?: 'FeatureFlag', id: any, key: FeatureFlagKey, value: boolean } };
export type UpdateLabPublicFeatureFlagMutation = { __typename?: 'Mutation', updateLabPublicFeatureFlag: { __typename?: 'FeatureFlagDTO', key: FeatureFlagKey, value: boolean } };
export type ObjectPermissionFragmentFragment = { __typename?: 'ObjectPermission', id: string, objectMetadataId: string, roleId: string, canReadObjectRecords?: boolean | null, canUpdateObjectRecords?: boolean | null, canSoftDeleteObjectRecords?: boolean | null, canDestroyObjectRecords?: boolean | null };
export type RoleFragmentFragment = { __typename?: 'Role', id: string, label: string, description?: string | null, icon?: string | null, canUpdateAllSettings: boolean, isEditable: boolean, canReadAllObjectRecords: boolean, canUpdateAllObjectRecords: boolean, canSoftDeleteAllObjectRecords: boolean, canDestroyAllObjectRecords: boolean };
@@ -2669,7 +2769,7 @@ export type UpsertSettingPermissionsMutation = { __typename?: 'Mutation', upsert
export type GetRolesQueryVariables = Exact<{ [key: string]: never; }>;
export type GetRolesQuery = { __typename?: 'Query', getRoles: Array<{ __typename?: 'Role', id: string, label: string, description?: string | null, icon?: string | null, canUpdateAllSettings: boolean, isEditable: boolean, canReadAllObjectRecords: boolean, canUpdateAllObjectRecords: boolean, canSoftDeleteAllObjectRecords: boolean, canDestroyAllObjectRecords: boolean, workspaceMembers: Array<{ __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale?: string | null, userEmail: string, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } }>, settingPermissions?: Array<{ __typename?: 'SettingPermission', id: string, setting: SettingPermissionType, roleId: string }> | null }> };
export type GetRolesQuery = { __typename?: 'Query', getRoles: Array<{ __typename?: 'Role', id: string, label: string, description?: string | null, icon?: string | null, canUpdateAllSettings: boolean, isEditable: boolean, canReadAllObjectRecords: boolean, canUpdateAllObjectRecords: boolean, canSoftDeleteAllObjectRecords: boolean, canDestroyAllObjectRecords: boolean, workspaceMembers: Array<{ __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale?: string | null, userEmail: string, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } }>, settingPermissions?: Array<{ __typename?: 'SettingPermission', id: string, setting: SettingPermissionType, roleId: string }> | null, objectPermissions?: Array<{ __typename?: 'ObjectPermission', id: string, objectMetadataId: string, roleId: string, canReadObjectRecords?: boolean | null, canUpdateObjectRecords?: boolean | null, canSoftDeleteObjectRecords?: boolean | null, canDestroyObjectRecords?: boolean | null }> | null }> };
export type CreateApprovedAccessDomainMutationVariables = Exact<{
input: CreateApprovedAccessDomainInput;
@@ -2730,7 +2830,14 @@ export type GetSsoIdentityProvidersQueryVariables = Exact<{ [key: string]: never
export type GetSsoIdentityProvidersQuery = { __typename?: 'Query', getSSOIdentityProviders: Array<{ __typename?: 'FindAvailableSSOIDPOutput', type: IdentityProviderType, id: string, name: string, issuer: string, status: SsoIdentityProviderStatus }> };
export type UserQueryFragmentFragment = { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canAccessFullAdminPanel: boolean, canImpersonate: boolean, supportUserHash?: string | null, onboardingStatus?: OnboardingStatus | null, userVars: any, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale?: string | null, userEmail: string, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, workspaceMembers?: Array<{ __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale?: string | null, userEmail: string, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } }> | null, currentUserWorkspace?: { __typename?: 'UserWorkspace', settingsPermissions?: Array<SettingPermissionType> | null, objectRecordsPermissions?: Array<PermissionsOnAllObjectRecords> | null } | null, currentWorkspace?: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, inviteHash?: string | null, allowImpersonation: boolean, activationStatus: WorkspaceActivationStatus, isPublicInviteLinkEnabled: boolean, isGoogleAuthEnabled: boolean, isMicrosoftAuthEnabled: boolean, isPasswordAuthEnabled: boolean, subdomain: string, hasValidEnterpriseKey: boolean, customDomain?: string | null, isCustomDomainEnabled: boolean, metadataVersion: number, workspaceMembersCount?: number | null, workspaceUrls: { __typename?: 'WorkspaceUrls', subdomainUrl: string, customUrl?: string | null }, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: FeatureFlagKey, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, interval?: SubscriptionInterval | null, billingSubscriptionItems?: Array<{ __typename?: 'BillingSubscriptionItem', id: any, hasReachedCurrentPeriodCap: boolean, billingProduct?: { __typename?: 'BillingProduct', name: string, description: string, metadata: { __typename?: 'BillingProductMetadata', planKey: BillingPlanKey, priceUsageBased: BillingUsageType, productKey: BillingProductKey } } | null }> | null } | null, billingSubscriptions: Array<{ __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus }>, defaultRole?: { __typename?: 'Role', id: string, label: string, description?: string | null, icon?: string | null, canUpdateAllSettings: boolean, isEditable: boolean, canReadAllObjectRecords: boolean, canUpdateAllObjectRecords: boolean, canSoftDeleteAllObjectRecords: boolean, canDestroyAllObjectRecords: boolean } | null } | null, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, subdomain: string, customDomain?: string | null, workspaceUrls: { __typename?: 'WorkspaceUrls', subdomainUrl: string, customUrl?: string | null } } | null }> };
export type OnDbEventSubscriptionVariables = Exact<{
input: OnDbEventInput;
}>;
export type OnDbEventSubscription = { __typename?: 'Subscription', onDbEvent: { __typename?: 'OnDbEventDTO', eventDate: string, action: DatabaseEventAction, objectNameSingular: string, updatedFields?: Array<string> | null, record: any } };
export type UserQueryFragmentFragment = { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canAccessFullAdminPanel: boolean, canImpersonate: boolean, supportUserHash?: string | null, onboardingStatus?: OnboardingStatus | null, userVars: any, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale?: string | null, userEmail: string, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, workspaceMembers?: Array<{ __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale?: string | null, userEmail: string, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } }> | null, currentUserWorkspace?: { __typename?: 'UserWorkspace', settingsPermissions?: Array<SettingPermissionType> | null, objectRecordsPermissions?: Array<PermissionsOnAllObjectRecords> | null } | null, currentWorkspace?: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, inviteHash?: string | null, allowImpersonation: boolean, activationStatus: WorkspaceActivationStatus, isPublicInviteLinkEnabled: boolean, isGoogleAuthEnabled: boolean, isMicrosoftAuthEnabled: boolean, isPasswordAuthEnabled: boolean, subdomain: string, hasValidEnterpriseKey: boolean, customDomain?: string | null, isCustomDomainEnabled: boolean, metadataVersion: number, workspaceMembersCount?: number | null, workspaceUrls: { __typename?: 'WorkspaceUrls', subdomainUrl: string, customUrl?: string | null }, featureFlags?: Array<{ __typename?: 'FeatureFlagDTO', key: FeatureFlagKey, value: boolean }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, interval?: SubscriptionInterval | null, billingSubscriptionItems?: Array<{ __typename?: 'BillingSubscriptionItem', id: any, hasReachedCurrentPeriodCap: boolean, billingProduct?: { __typename?: 'BillingProduct', name: string, description: string, metadata: { __typename?: 'BillingProductMetadata', planKey: BillingPlanKey, priceUsageBased: BillingUsageType, productKey: BillingProductKey } } | null }> | null } | null, billingSubscriptions: Array<{ __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus }>, defaultRole?: { __typename?: 'Role', id: string, label: string, description?: string | null, icon?: string | null, canUpdateAllSettings: boolean, isEditable: boolean, canReadAllObjectRecords: boolean, canUpdateAllObjectRecords: boolean, canSoftDeleteAllObjectRecords: boolean, canDestroyAllObjectRecords: boolean } | null } | null, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, subdomain: string, customDomain?: string | null, workspaceUrls: { __typename?: 'WorkspaceUrls', subdomainUrl: string, customUrl?: string | null } } | null }> };
export type DeleteUserAccountMutationVariables = Exact<{ [key: string]: never; }>;
@@ -2747,7 +2854,7 @@ export type UploadProfilePictureMutation = { __typename?: 'Mutation', uploadProf
export type GetCurrentUserQueryVariables = Exact<{ [key: string]: never; }>;
export type GetCurrentUserQuery = { __typename?: 'Query', currentUser: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canAccessFullAdminPanel: boolean, canImpersonate: boolean, supportUserHash?: string | null, onboardingStatus?: OnboardingStatus | null, userVars: any, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale?: string | null, userEmail: string, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, workspaceMembers?: Array<{ __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale?: string | null, userEmail: string, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } }> | null, currentUserWorkspace?: { __typename?: 'UserWorkspace', settingsPermissions?: Array<SettingPermissionType> | null, objectRecordsPermissions?: Array<PermissionsOnAllObjectRecords> | null } | null, currentWorkspace?: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, inviteHash?: string | null, allowImpersonation: boolean, activationStatus: WorkspaceActivationStatus, isPublicInviteLinkEnabled: boolean, isGoogleAuthEnabled: boolean, isMicrosoftAuthEnabled: boolean, isPasswordAuthEnabled: boolean, subdomain: string, hasValidEnterpriseKey: boolean, customDomain?: string | null, isCustomDomainEnabled: boolean, metadataVersion: number, workspaceMembersCount?: number | null, workspaceUrls: { __typename?: 'WorkspaceUrls', subdomainUrl: string, customUrl?: string | null }, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: FeatureFlagKey, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, interval?: SubscriptionInterval | null, billingSubscriptionItems?: Array<{ __typename?: 'BillingSubscriptionItem', id: any, hasReachedCurrentPeriodCap: boolean, billingProduct?: { __typename?: 'BillingProduct', name: string, description: string, metadata: { __typename?: 'BillingProductMetadata', planKey: BillingPlanKey, priceUsageBased: BillingUsageType, productKey: BillingProductKey } } | null }> | null } | null, billingSubscriptions: Array<{ __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus }>, defaultRole?: { __typename?: 'Role', id: string, label: string, description?: string | null, icon?: string | null, canUpdateAllSettings: boolean, isEditable: boolean, canReadAllObjectRecords: boolean, canUpdateAllObjectRecords: boolean, canSoftDeleteAllObjectRecords: boolean, canDestroyAllObjectRecords: boolean } | null } | null, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, subdomain: string, customDomain?: string | null, workspaceUrls: { __typename?: 'WorkspaceUrls', subdomainUrl: string, customUrl?: string | null } } | null }> } };
export type GetCurrentUserQuery = { __typename?: 'Query', currentUser: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canAccessFullAdminPanel: boolean, canImpersonate: boolean, supportUserHash?: string | null, onboardingStatus?: OnboardingStatus | null, userVars: any, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale?: string | null, userEmail: string, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, workspaceMembers?: Array<{ __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale?: string | null, userEmail: string, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } }> | null, currentUserWorkspace?: { __typename?: 'UserWorkspace', settingsPermissions?: Array<SettingPermissionType> | null, objectRecordsPermissions?: Array<PermissionsOnAllObjectRecords> | null } | null, currentWorkspace?: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, inviteHash?: string | null, allowImpersonation: boolean, activationStatus: WorkspaceActivationStatus, isPublicInviteLinkEnabled: boolean, isGoogleAuthEnabled: boolean, isMicrosoftAuthEnabled: boolean, isPasswordAuthEnabled: boolean, subdomain: string, hasValidEnterpriseKey: boolean, customDomain?: string | null, isCustomDomainEnabled: boolean, metadataVersion: number, workspaceMembersCount?: number | null, workspaceUrls: { __typename?: 'WorkspaceUrls', subdomainUrl: string, customUrl?: string | null }, featureFlags?: Array<{ __typename?: 'FeatureFlagDTO', key: FeatureFlagKey, value: boolean }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, interval?: SubscriptionInterval | null, billingSubscriptionItems?: Array<{ __typename?: 'BillingSubscriptionItem', id: any, hasReachedCurrentPeriodCap: boolean, billingProduct?: { __typename?: 'BillingProduct', name: string, description: string, metadata: { __typename?: 'BillingProductMetadata', planKey: BillingPlanKey, priceUsageBased: BillingUsageType, productKey: BillingProductKey } } | null }> | null } | null, billingSubscriptions: Array<{ __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus }>, defaultRole?: { __typename?: 'Role', id: string, label: string, description?: string | null, icon?: string | null, canUpdateAllSettings: boolean, isEditable: boolean, canReadAllObjectRecords: boolean, canUpdateAllObjectRecords: boolean, canSoftDeleteAllObjectRecords: boolean, canDestroyAllObjectRecords: boolean } | null } | null, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, subdomain: string, customDomain?: string | null, workspaceUrls: { __typename?: 'WorkspaceUrls', subdomainUrl: string, customUrl?: string | null } } | null }> } };
export type ActivateWorkflowVersionMutationVariables = Exact<{
workflowVersionId: Scalars['String'];
@@ -2984,6 +3091,17 @@ export const AvailableSsoIdentityProvidersFragmentFragmentDoc = gql`
}
}
`;
export const ObjectPermissionFragmentFragmentDoc = gql`
fragment ObjectPermissionFragment on ObjectPermission {
id
objectMetadataId
roleId
canReadObjectRecords
canUpdateObjectRecords
canSoftDeleteObjectRecords
canDestroyObjectRecords
}
`;
export const SettingPermissionFragmentFragmentDoc = gql`
fragment SettingPermissionFragment on SettingPermission {
id
@@ -3061,10 +3179,8 @@ export const UserQueryFragmentFragmentDoc = gql`
customUrl
}
featureFlags {
id
key
value
workspaceId
}
metadataVersion
currentBillingSubscription {
@@ -3275,6 +3391,42 @@ export function useGetTimelineThreadsFromPersonIdLazyQuery(baseOptions?: Apollo.
export type GetTimelineThreadsFromPersonIdQueryHookResult = ReturnType<typeof useGetTimelineThreadsFromPersonIdQuery>;
export type GetTimelineThreadsFromPersonIdLazyQueryHookResult = ReturnType<typeof useGetTimelineThreadsFromPersonIdLazyQuery>;
export type GetTimelineThreadsFromPersonIdQueryResult = Apollo.QueryResult<GetTimelineThreadsFromPersonIdQuery, GetTimelineThreadsFromPersonIdQueryVariables>;
export const TrackAnalyticsDocument = gql`
mutation TrackAnalytics($type: AnalyticsType!, $event: String, $name: String, $properties: JSON) {
trackAnalytics(type: $type, event: $event, name: $name, properties: $properties) {
success
}
}
`;
export type TrackAnalyticsMutationFn = Apollo.MutationFunction<TrackAnalyticsMutation, TrackAnalyticsMutationVariables>;
/**
* __useTrackAnalyticsMutation__
*
* To run a mutation, you first call `useTrackAnalyticsMutation` within a React component and pass it any options that fit your needs.
* When your component renders, `useTrackAnalyticsMutation` returns a tuple that includes:
* - A mutate function that you can call at any time to execute the mutation
* - An object with fields that represent the current status of the mutation's execution
*
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
*
* @example
* const [trackAnalyticsMutation, { data, loading, error }] = useTrackAnalyticsMutation({
* variables: {
* type: // value for 'type'
* event: // value for 'event'
* name: // value for 'name'
* properties: // value for 'properties'
* },
* });
*/
export function useTrackAnalyticsMutation(baseOptions?: Apollo.MutationHookOptions<TrackAnalyticsMutation, TrackAnalyticsMutationVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useMutation<TrackAnalyticsMutation, TrackAnalyticsMutationVariables>(TrackAnalyticsDocument, options);
}
export type TrackAnalyticsMutationHookResult = ReturnType<typeof useTrackAnalyticsMutation>;
export type TrackAnalyticsMutationResult = Apollo.MutationResult<TrackAnalyticsMutation>;
export type TrackAnalyticsMutationOptions = Apollo.BaseMutationOptions<TrackAnalyticsMutation, TrackAnalyticsMutationVariables>;
export const TrackDocument = gql`
mutation Track($action: String!, $payload: JSON!) {
track(action: $action, payload: $payload) {
@@ -4214,38 +4366,77 @@ export function useEndSubscriptionTrialPeriodMutation(baseOptions?: Apollo.Mutat
export type EndSubscriptionTrialPeriodMutationHookResult = ReturnType<typeof useEndSubscriptionTrialPeriodMutation>;
export type EndSubscriptionTrialPeriodMutationResult = Apollo.MutationResult<EndSubscriptionTrialPeriodMutation>;
export type EndSubscriptionTrialPeriodMutationOptions = Apollo.BaseMutationOptions<EndSubscriptionTrialPeriodMutation, EndSubscriptionTrialPeriodMutationVariables>;
export const UpdateBillingSubscriptionDocument = gql`
mutation UpdateBillingSubscription {
updateBillingSubscription {
export const GetMeteredProductsUsageDocument = gql`
query GetMeteredProductsUsage {
getMeteredProductsUsage {
productKey
usageQuantity
freeTierQuantity
freeTrialQuantity
unitPriceCents
totalCostCents
}
}
`;
/**
* __useGetMeteredProductsUsageQuery__
*
* To run a query within a React component, call `useGetMeteredProductsUsageQuery` and pass it any options that fit your needs.
* When your component renders, `useGetMeteredProductsUsageQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useGetMeteredProductsUsageQuery({
* variables: {
* },
* });
*/
export function useGetMeteredProductsUsageQuery(baseOptions?: Apollo.QueryHookOptions<GetMeteredProductsUsageQuery, GetMeteredProductsUsageQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<GetMeteredProductsUsageQuery, GetMeteredProductsUsageQueryVariables>(GetMeteredProductsUsageDocument, options);
}
export function useGetMeteredProductsUsageLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<GetMeteredProductsUsageQuery, GetMeteredProductsUsageQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<GetMeteredProductsUsageQuery, GetMeteredProductsUsageQueryVariables>(GetMeteredProductsUsageDocument, options);
}
export type GetMeteredProductsUsageQueryHookResult = ReturnType<typeof useGetMeteredProductsUsageQuery>;
export type GetMeteredProductsUsageLazyQueryHookResult = ReturnType<typeof useGetMeteredProductsUsageLazyQuery>;
export type GetMeteredProductsUsageQueryResult = Apollo.QueryResult<GetMeteredProductsUsageQuery, GetMeteredProductsUsageQueryVariables>;
export const SwitchSubscriptionToYearlyIntervalDocument = gql`
mutation SwitchSubscriptionToYearlyInterval {
switchToYearlyInterval {
success
}
}
`;
export type UpdateBillingSubscriptionMutationFn = Apollo.MutationFunction<UpdateBillingSubscriptionMutation, UpdateBillingSubscriptionMutationVariables>;
export type SwitchSubscriptionToYearlyIntervalMutationFn = Apollo.MutationFunction<SwitchSubscriptionToYearlyIntervalMutation, SwitchSubscriptionToYearlyIntervalMutationVariables>;
/**
* __useUpdateBillingSubscriptionMutation__
* __useSwitchSubscriptionToYearlyIntervalMutation__
*
* To run a mutation, you first call `useUpdateBillingSubscriptionMutation` within a React component and pass it any options that fit your needs.
* When your component renders, `useUpdateBillingSubscriptionMutation` returns a tuple that includes:
* To run a mutation, you first call `useSwitchSubscriptionToYearlyIntervalMutation` within a React component and pass it any options that fit your needs.
* When your component renders, `useSwitchSubscriptionToYearlyIntervalMutation` returns a tuple that includes:
* - A mutate function that you can call at any time to execute the mutation
* - An object with fields that represent the current status of the mutation's execution
*
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
*
* @example
* const [updateBillingSubscriptionMutation, { data, loading, error }] = useUpdateBillingSubscriptionMutation({
* const [switchSubscriptionToYearlyIntervalMutation, { data, loading, error }] = useSwitchSubscriptionToYearlyIntervalMutation({
* variables: {
* },
* });
*/
export function useUpdateBillingSubscriptionMutation(baseOptions?: Apollo.MutationHookOptions<UpdateBillingSubscriptionMutation, UpdateBillingSubscriptionMutationVariables>) {
export function useSwitchSubscriptionToYearlyIntervalMutation(baseOptions?: Apollo.MutationHookOptions<SwitchSubscriptionToYearlyIntervalMutation, SwitchSubscriptionToYearlyIntervalMutationVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useMutation<UpdateBillingSubscriptionMutation, UpdateBillingSubscriptionMutationVariables>(UpdateBillingSubscriptionDocument, options);
return Apollo.useMutation<SwitchSubscriptionToYearlyIntervalMutation, SwitchSubscriptionToYearlyIntervalMutationVariables>(SwitchSubscriptionToYearlyIntervalDocument, options);
}
export type UpdateBillingSubscriptionMutationHookResult = ReturnType<typeof useUpdateBillingSubscriptionMutation>;
export type UpdateBillingSubscriptionMutationResult = Apollo.MutationResult<UpdateBillingSubscriptionMutation>;
export type UpdateBillingSubscriptionMutationOptions = Apollo.BaseMutationOptions<UpdateBillingSubscriptionMutation, UpdateBillingSubscriptionMutationVariables>;
export type SwitchSubscriptionToYearlyIntervalMutationHookResult = ReturnType<typeof useSwitchSubscriptionToYearlyIntervalMutation>;
export type SwitchSubscriptionToYearlyIntervalMutationResult = Apollo.MutationResult<SwitchSubscriptionToYearlyIntervalMutation>;
export type SwitchSubscriptionToYearlyIntervalMutationOptions = Apollo.BaseMutationOptions<SwitchSubscriptionToYearlyIntervalMutation, SwitchSubscriptionToYearlyIntervalMutationVariables>;
export const GetClientConfigDocument = gql`
query GetClientConfig {
clientConfig {
@@ -4511,9 +4702,9 @@ export function useUserLookupAdminPanelMutation(baseOptions?: Apollo.MutationHoo
export type UserLookupAdminPanelMutationHookResult = ReturnType<typeof useUserLookupAdminPanelMutation>;
export type UserLookupAdminPanelMutationResult = Apollo.MutationResult<UserLookupAdminPanelMutation>;
export type UserLookupAdminPanelMutationOptions = Apollo.BaseMutationOptions<UserLookupAdminPanelMutation, UserLookupAdminPanelMutationVariables>;
export const GetEnvironmentVariablesGroupedDocument = gql`
query GetEnvironmentVariablesGrouped {
getEnvironmentVariablesGrouped {
export const GetConfigVariablesGroupedDocument = gql`
query GetConfigVariablesGrouped {
getConfigVariablesGrouped {
groups {
name
description
@@ -4522,7 +4713,7 @@ export const GetEnvironmentVariablesGroupedDocument = gql`
name
description
value
sensitive
isSensitive
}
}
}
@@ -4530,31 +4721,66 @@ export const GetEnvironmentVariablesGroupedDocument = gql`
`;
/**
* __useGetEnvironmentVariablesGroupedQuery__
* __useGetConfigVariablesGroupedQuery__
*
* To run a query within a React component, call `useGetEnvironmentVariablesGroupedQuery` and pass it any options that fit your needs.
* When your component renders, `useGetEnvironmentVariablesGroupedQuery` returns an object from Apollo Client that contains loading, error, and data properties
* To run a query within a React component, call `useGetConfigVariablesGroupedQuery` and pass it any options that fit your needs.
* When your component renders, `useGetConfigVariablesGroupedQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useGetEnvironmentVariablesGroupedQuery({
* const { data, loading, error } = useGetConfigVariablesGroupedQuery({
* variables: {
* },
* });
*/
export function useGetEnvironmentVariablesGroupedQuery(baseOptions?: Apollo.QueryHookOptions<GetEnvironmentVariablesGroupedQuery, GetEnvironmentVariablesGroupedQueryVariables>) {
export function useGetConfigVariablesGroupedQuery(baseOptions?: Apollo.QueryHookOptions<GetConfigVariablesGroupedQuery, GetConfigVariablesGroupedQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<GetEnvironmentVariablesGroupedQuery, GetEnvironmentVariablesGroupedQueryVariables>(GetEnvironmentVariablesGroupedDocument, options);
return Apollo.useQuery<GetConfigVariablesGroupedQuery, GetConfigVariablesGroupedQueryVariables>(GetConfigVariablesGroupedDocument, options);
}
export function useGetEnvironmentVariablesGroupedLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<GetEnvironmentVariablesGroupedQuery, GetEnvironmentVariablesGroupedQueryVariables>) {
export function useGetConfigVariablesGroupedLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<GetConfigVariablesGroupedQuery, GetConfigVariablesGroupedQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<GetEnvironmentVariablesGroupedQuery, GetEnvironmentVariablesGroupedQueryVariables>(GetEnvironmentVariablesGroupedDocument, options);
return Apollo.useLazyQuery<GetConfigVariablesGroupedQuery, GetConfigVariablesGroupedQueryVariables>(GetConfigVariablesGroupedDocument, options);
}
export type GetEnvironmentVariablesGroupedQueryHookResult = ReturnType<typeof useGetEnvironmentVariablesGroupedQuery>;
export type GetEnvironmentVariablesGroupedLazyQueryHookResult = ReturnType<typeof useGetEnvironmentVariablesGroupedLazyQuery>;
export type GetEnvironmentVariablesGroupedQueryResult = Apollo.QueryResult<GetEnvironmentVariablesGroupedQuery, GetEnvironmentVariablesGroupedQueryVariables>;
export type GetConfigVariablesGroupedQueryHookResult = ReturnType<typeof useGetConfigVariablesGroupedQuery>;
export type GetConfigVariablesGroupedLazyQueryHookResult = ReturnType<typeof useGetConfigVariablesGroupedLazyQuery>;
export type GetConfigVariablesGroupedQueryResult = Apollo.QueryResult<GetConfigVariablesGroupedQuery, GetConfigVariablesGroupedQueryVariables>;
export const GetVersionInfoDocument = gql`
query GetVersionInfo {
versionInfo {
currentVersion
latestVersion
}
}
`;
/**
* __useGetVersionInfoQuery__
*
* To run a query within a React component, call `useGetVersionInfoQuery` and pass it any options that fit your needs.
* When your component renders, `useGetVersionInfoQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useGetVersionInfoQuery({
* variables: {
* },
* });
*/
export function useGetVersionInfoQuery(baseOptions?: Apollo.QueryHookOptions<GetVersionInfoQuery, GetVersionInfoQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<GetVersionInfoQuery, GetVersionInfoQueryVariables>(GetVersionInfoDocument, options);
}
export function useGetVersionInfoLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<GetVersionInfoQuery, GetVersionInfoQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<GetVersionInfoQuery, GetVersionInfoQueryVariables>(GetVersionInfoDocument, options);
}
export type GetVersionInfoQueryHookResult = ReturnType<typeof useGetVersionInfoQuery>;
export type GetVersionInfoLazyQueryHookResult = ReturnType<typeof useGetVersionInfoLazyQuery>;
export type GetVersionInfoQueryResult = Apollo.QueryResult<GetVersionInfoQuery, GetVersionInfoQueryVariables>;
export const GetIndicatorHealthStatusDocument = gql`
query GetIndicatorHealthStatus($indicatorId: HealthIndicatorId!) {
getIndicatorHealthStatus(indicatorId: $indicatorId) {
@@ -4694,7 +4920,6 @@ export type GetSystemHealthStatusQueryResult = Apollo.QueryResult<GetSystemHealt
export const UpdateLabPublicFeatureFlagDocument = gql`
mutation UpdateLabPublicFeatureFlag($input: UpdateLabPublicFeatureFlagInput!) {
updateLabPublicFeatureFlag(input: $input) {
id
key
value
}
@@ -4878,11 +5103,15 @@ export const GetRolesDocument = gql`
settingPermissions {
...SettingPermissionFragment
}
objectPermissions {
...ObjectPermissionFragment
}
}
}
${RoleFragmentFragmentDoc}
${WorkspaceMemberQueryFragmentFragmentDoc}
${SettingPermissionFragmentFragmentDoc}`;
${SettingPermissionFragmentFragmentDoc}
${ObjectPermissionFragmentFragmentDoc}`;
/**
* __useGetRolesQuery__
@@ -5232,6 +5461,40 @@ export function useGetSsoIdentityProvidersLazyQuery(baseOptions?: Apollo.LazyQue
export type GetSsoIdentityProvidersQueryHookResult = ReturnType<typeof useGetSsoIdentityProvidersQuery>;
export type GetSsoIdentityProvidersLazyQueryHookResult = ReturnType<typeof useGetSsoIdentityProvidersLazyQuery>;
export type GetSsoIdentityProvidersQueryResult = Apollo.QueryResult<GetSsoIdentityProvidersQuery, GetSsoIdentityProvidersQueryVariables>;
export const OnDbEventDocument = gql`
subscription OnDbEvent($input: OnDbEventInput!) {
onDbEvent(input: $input) {
eventDate
action
objectNameSingular
updatedFields
record
}
}
`;
/**
* __useOnDbEventSubscription__
*
* To run a query within a React component, call `useOnDbEventSubscription` and pass it any options that fit your needs.
* When your component renders, `useOnDbEventSubscription` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the subscription, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useOnDbEventSubscription({
* variables: {
* input: // value for 'input'
* },
* });
*/
export function useOnDbEventSubscription(baseOptions: Apollo.SubscriptionHookOptions<OnDbEventSubscription, OnDbEventSubscriptionVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useSubscription<OnDbEventSubscription, OnDbEventSubscriptionVariables>(OnDbEventDocument, options);
}
export type OnDbEventSubscriptionHookResult = ReturnType<typeof useOnDbEventSubscription>;
export type OnDbEventSubscriptionResult = Apollo.SubscriptionResult<OnDbEventSubscription>;
export const DeleteUserAccountDocument = gql`
mutation DeleteUserAccount {
deleteUser {
@@ -91,23 +91,23 @@ const testCases: {
{ loc: AppPath.SignInUp, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam },
{ loc: AppPath.SignInUp, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: defaultHomePagePath },
{ loc: AppPath.Invite, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: undefined },
{ loc: AppPath.Invite, isLoggedIn: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: undefined },
{ loc: AppPath.Invite, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: '/plan-required' },
{ loc: AppPath.Invite, isLoggedIn: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: '/settings/billing' },
{ loc: AppPath.Invite, isLoggedIn: false, isWorkspaceSuspended: false, onboardingStatus: undefined, res: undefined },
{ loc: AppPath.Invite, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: undefined },
{ loc: AppPath.Invite, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: undefined },
{ loc: AppPath.Invite, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: undefined },
{ loc: AppPath.Invite, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: undefined },
{ loc: AppPath.Invite, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: undefined },
{ loc: AppPath.Invite, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: '/create/workspace' },
{ loc: AppPath.Invite, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: '/create/profile' },
{ loc: AppPath.Invite, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: '/sync/emails' },
{ loc: AppPath.Invite, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: '/invite-team' },
{ loc: AppPath.Invite, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: '/objects/companies' },
{ loc: AppPath.ResetPassword, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: undefined },
{ loc: AppPath.ResetPassword, isLoggedIn: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: undefined },
{ loc: AppPath.ResetPassword, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: '/plan-required' },
{ loc: AppPath.ResetPassword, isLoggedIn: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: '/settings/billing' },
{ loc: AppPath.ResetPassword, isLoggedIn: false, isWorkspaceSuspended: false, onboardingStatus: undefined, res: undefined },
{ loc: AppPath.ResetPassword, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: undefined },
{ loc: AppPath.ResetPassword, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: undefined },
{ loc: AppPath.ResetPassword, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: undefined },
{ loc: AppPath.ResetPassword, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: undefined },
{ loc: AppPath.ResetPassword, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: undefined },
{ loc: AppPath.ResetPassword, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: '/create/workspace' },
{ loc: AppPath.ResetPassword, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: '/create/profile' },
{ loc: AppPath.ResetPassword, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: '/sync/emails' },
{ loc: AppPath.ResetPassword, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: '/invite-team' },
{ loc: AppPath.ResetPassword, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: '/objects/companies' },
{ loc: AppPath.VerifyEmail, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: AppPath.PlanRequired },
{ loc: AppPath.VerifyEmail, isLoggedIn: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: '/settings/billing' },
@@ -2,27 +2,31 @@ import { matchPath, useLocation } from 'react-router-dom';
import { AppBasePath } from '@/types/AppBasePath';
import { isNonEmptyString } from '@sniptt/guards';
import { useCallback } from 'react';
import { isDefined } from 'twenty-shared/utils';
const addTrailingSlash = (path: string) =>
path.endsWith('/') ? path : path + '/';
const getConstructedPath = (path: string, basePath?: AppBasePath) => {
if (!isNonEmptyString(basePath)) return path;
return addTrailingSlash(basePath) + path;
};
export const useIsMatchingLocation = () => {
const location = useLocation();
const addTrailingSlash = (path: string) =>
path.endsWith('/') ? path : path + '/';
const getConstructedPath = (path: string, basePath?: AppBasePath) => {
if (!isNonEmptyString(basePath)) return path;
return addTrailingSlash(basePath) + path;
};
const isMatchingLocation = (path: string, basePath?: AppBasePath) => {
const match = matchPath(
getConstructedPath(path, basePath),
location.pathname,
);
return isDefined(match);
};
const isMatchingLocation = useCallback(
(path: string, basePath?: AppBasePath) => {
const match = matchPath(
getConstructedPath(path, basePath),
location.pathname,
);
return isDefined(match);
},
[location.pathname],
);
return {
isMatchingLocation,
@@ -7,10 +7,10 @@ import { SettingsPath } from '@/types/SettingsPath';
import { useIsWorkspaceActivationStatusEqualsTo } from '@/workspace/hooks/useIsWorkspaceActivationStatusEqualsTo';
import { useParams } from 'react-router-dom';
import { useRecoilValue } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
import { WorkspaceActivationStatus } from 'twenty-shared/workspace';
import { OnboardingStatus } from '~/generated/graphql';
import { useIsMatchingLocation } from '~/hooks/useIsMatchingLocation';
import { WorkspaceActivationStatus } from 'twenty-shared/workspace';
import { isDefined } from 'twenty-shared/utils';
export const usePageChangeEffectNavigateLocation = () => {
const { isMatchingLocation } = useIsMatchingLocation();
@@ -47,10 +47,6 @@ export const usePageChangeEffectNavigateLocation = () => {
(objectMetadataItem) => objectMetadataItem.namePlural === objectNamePlural,
);
if (isMatchingOpenRoute) {
return;
}
if (!isLoggedIn && !isMatchingOngoingUserCreationRoute) {
return AppPath.SignInUp;
}
@@ -1,9 +1,11 @@
import styled from '@emotion/styled';
import { useShowAuthModal } from '@/ui/layout/hooks/useShowAuthModal';
import { Modal } from '@/ui/layout/modal/components/Modal';
import { NAV_DRAWER_WIDTHS } from '@/ui/navigation/navigation-drawer/constants/NavDrawerWidths';
import { MOBILE_VIEWPORT } from 'twenty-ui/theme';
import { LeftPanelSkeletonLoader } from '~/loading/components/LeftPanelSkeletonLoader';
import { RightPanelSkeletonLoader } from '~/loading/components/RightPanelSkeletonLoader';
import { MOBILE_VIEWPORT } from 'twenty-ui/theme';
const StyledContainer = styled.div`
background: ${({ theme }) => theme.background.noisy};
@@ -23,8 +25,11 @@ const StyledContainer = styled.div`
`;
export const UserOrMetadataLoader = () => {
const showAuthModal = useShowAuthModal();
return (
<StyledContainer>
{showAuthModal && <Modal.Backdrop modalVariant="primary" />}
<LeftPanelSkeletonLoader />
<RightPanelSkeletonLoader />
</StyledContainer>
@@ -6,6 +6,7 @@ import {
PageDecorator,
PageDecoratorArgs,
} from '~/testing/decorators/PageDecorator';
import { PrefetchLoadingDecorator } from '~/testing/decorators/PrefetchLoadingDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks';
const meta: Meta<PageDecoratorArgs> = {
@@ -19,6 +20,7 @@ const meta: Meta<PageDecoratorArgs> = {
},
parameters: {
msw: graphqlMocks,
prefetchLoadingSetDelay: 1000,
},
};
@@ -29,7 +31,7 @@ export type Story = StoryObj<typeof RecordIndexPage>;
export const Default: Story = {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
decorators: [PageDecorator],
decorators: [PrefetchLoadingDecorator, PageDecorator],
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
Binary file not shown.
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,27 @@
import { ActionDisplay } from '@/action-menu/actions/display/components/ActionDisplay';
import { ActionConfigContext } from '@/action-menu/contexts/ActionConfigContext';
import { useCloseActionMenu } from '@/action-menu/hooks/useCloseActionMenu';
import { useContext } from 'react';
export const Action = ({
onClick,
preventCommandMenuClosing,
}: {
onClick: () => void;
preventCommandMenuClosing?: boolean;
}) => {
const actionConfig = useContext(ActionConfigContext);
const { closeActionMenu } = useCloseActionMenu(preventCommandMenuClosing);
if (!actionConfig) {
return null;
}
const handleClick = () => {
closeActionMenu();
onClick();
};
return <ActionDisplay onClick={handleClick} />;
};
@@ -0,0 +1,21 @@
import { ActionDisplay } from '@/action-menu/actions/display/components/ActionDisplay';
import { useCloseActionMenu } from '@/action-menu/hooks/useCloseActionMenu';
import { AppPath } from '@/types/AppPath';
import { PathParam } from 'react-router-dom';
import { getAppPath } from '~/utils/navigation/getAppPath';
export const ActionLink = <T extends AppPath>({
to,
params,
queryParams,
}: {
to: T;
params?: { [key in PathParam<T>]: string | null };
queryParams?: Record<string, any>;
}) => {
const { closeActionMenu } = useCloseActionMenu();
const path = getAppPath(to, params, queryParams);
return <ActionDisplay onClick={closeActionMenu} to={path} />;
};

Some files were not shown because too many files have changed in this diff Show More