Closes#16432
Multi-Select and Array fields were exported in an incompatible format:
**Before**: {"0":"VALUE1","1":"VALUE2"} (object with numeric keys)
**After**: ["VALUE1","VALUE2"] (JSON array)
This prevented exported CSV files from being re-imported successfully.
### Changes
Modified useExportProcessRecordsForCSV hook to stringify Multi-Select
and Array fields as JSON arrays before CSV generation
---------
Co-authored-by: Etienne <45695613+etiennejouan@users.noreply.github.com>
# Introduction
In this PR we've introduced the type safe generation tooling for
standard view, view fields, view filters and view groups.
Also generated the ids before such as what was done for object and
fields, it's still temporary as will be replaced by universalIdentifier
mapping afterwards
## Task views
In this PR only implemented the `task` views and view groups, filters
and fields in order to battle test all the generation tools
Will create a dedicated PR that will implement all the remaining views.
- The issue is that the listener is not triggered if they are no change
to the workspaceMember (which happens when name is already filled
through GoogleSSO)
Fixes https://github.com/twentyhq/twenty/issues/16440
This is a known quirk of many Google APIs, including Gmail. Some error
responses use numeric code fields (e.g., 403), while others may return
them as strings (e.g., "403"). This depends on which internal service
returns the error and the language client you’re using.
Changes:
- as we store date in redis as serialized, let's make all flatEntity
dates as string. This requires changing FlatEntity types and making sure
that entity are converted to flatEntity and flatEntity to dtos
# Introduction
Related https://github.com/twentyhq/core-team-issues/issues/1995
In this PR we're introducing the standard index tools for their
declaration
Also adding a common typing in order to have a simily consistency across
standard builders
Will implement remaining standard index builder in an other PR
Issue : #15794
## Context
As shown in the linked issue, slash menu dropdown for rich text editor
at bottom of notes editor screen extended beyond the page container,
causing main page to scroll.
## Changes Made
Added floating UI's `flip()` middleware to the component in
`CustomSlashMenu.tsx` so that the menu automatically flips upward when
detecting not enough space for dropdown. This prevents overflow beyond
the page container.
Additionally, added offset to menu when flipping up to prevent
overlapping of the current line / caret.
## Results
https://github.com/user-attachments/assets/47a79468-779c-4fd7-8e22-2b496456ea92
---------
Co-authored-by: Hyeonjae Park <hyeonjaep@Hyeonjaes-MacBook-Pro.local>
Co-authored-by: Etienne <45695613+etiennejouan@users.noreply.github.com>
Fixes
- Fixes https://github.com/twentyhq/twenty/issues/15640 : we have some
viewGroups that were in the past wrongly migrated; eg deleteing an
enum's option did not lead to deleting the associated viewGroup. We have
not cleaned that (we could do a command), but we can identify them and
choose not to display them - otherwise currently they are shown as a
duplicate of "No value" column
- Fixes buggy edge case introduced by
https://github.com/twentyhq/twenty/pull/16382 : after updating a view
from Table/Calendar to Kanban, then visiting another view, when coming
back to the newly updated kanban view the view groups were empty. This
is due to to the view groups being optimistically created with
on-the-fly computed ids when the view is updated, while we call
refreshCoreViewsByObjectMetadataId() after. The view groups we get from
the refresh obviously have different ids. It is not possible to indicate
the ids of the view group through the update of the view as they are a
side effect of the view update.
# Fireflies
Automatically (with cli util : webhook not working and no cron added)
captures meeting notes with AI-generated summaries and insights from
Fireflies.ai into your Twenty CRM.
## Current Status
- Doesn't work with Fireflies webhook yet due to missing headers
forwarding in twenty serverless func
- Meeting ingestion utility script are available for individual meeting
insertion and historical meetings with filters with yarn meeting:all
- You have to push the secrets as application.config.ts values (despite
env variables in .env in docker compose or container I couldn't push the
secrets with the cli)
## Current Platform Limitation (Headers)
- Twenty serverless route triggers currently do **not forward HTTP
headers** to functions. Fireflies signatures sent in headers are
stripped, so header-based verification does not work in production.
- Workaround: the provided test script also includes the signature
inside the payload; the handler falls back to that payload signature.
Use this only for testing until header forwarding is supported.
## Utilities for meeting insertion (workarounds)
- Ingest a specific Fireflies meeting into Twenty:
`yarn meeting:ingest <meetingId>` or `MEETING_ID=... yarn
meeting:ingest`
- Fetch all/historical Fireflies meetings into Twenty:
`yarn meeting:all [--from 2024-01-01] [--to 2024-02-01] [--organizer
a@x.com] [--participant b@x.com] [--channel <channelId>] [--mine]
[--dry-run]`
- Filters (combine as needed):
- `--from` / `--to`: ISO or date string range filter
- `--organizer` / `--participant`: comma-separated emails
- `--channel`: Fireflies channel id
- `--mine`: only meetings for the current Fireflies user
- Controls:
- `--dry-run`: list and transform without writing to Twenty
- `--page-size`: pagination size (default 50)
- `--max-records`: stop after N transcripts (default 500)
I am closing previous #16378 as this one includes it all
Fixes multiple issues with CRON schedule input validation and execution
time display.
### Issues Fixed
1. **UTC label placement** - Added "UTC" suffix to specific times (e.g.,
"at 09:30 UTC") but not to interval descriptions (e.g., "every hour")
2. **Upcoming execution time calculation** - Fixed incorrect execution
times for malformed CRON expressions by implementing auto-correction
### Changes
- Created `normalizeCronExpression` utility to standardize cron
expressions before parsing
- Updated `formatTime` to support optional UTC suffix
- Enhanced `getHoursDescription` to append UTC to specific times
- Added comprehensive test coverage (102 tests passing)
### Before
- `"1 /3 * * *"` showed daily executions at same time (incorrect)
- `"9 * * *"` showed same time repeated 3 times (incorrect)
- No UTC labels on schedule descriptions (confusing)
### After
- All malformed expressions auto-corrected and show correct execution
times
- UTC labels clearly indicate timezone for specific times
- User-friendly error messages for truly invalid patterns
Closes#15870
Fixes https://github.com/twentyhq/twenty/issues/15925
- update field metadata update logic
- uniformize the way index are named
- command to migrate v1-named unique index
- add integration testing
---------
Co-authored-by: prastoin <paul@twenty.com>
Fixes: #15887
The currency fields were expecting values in micros (multiplied by
10^6), but
this requirement was not indicated anywhere in the workflow UI. Users
had to
manually add a code node to multiply amounts by 10^6 before using the
new
currency value.
This change integrates the micros conversion logic directly into
FormCurrencyFieldInput by using convertCurrencyAmountToCurrencyMicros
and
convertCurrencyMicrosToCurrencyAmount utilities. This allows users to
input
human-readable decimal amounts (e.g., 3.21 for $3.21) in the form, which
are
automatically converted to micros internally for storage and processing.
This eliminates the need for users to add separate code nodes for
conversion
and improves the user experience by making the expected input format
clear.
Updated the 3 hooks - activate, deactivate and discard draft
(deleteVersion) - so those updates the cache.
Removed the update listeners.
Also wrapped a few actions to unsure workflowId is not undefined when
received by useWorkflowWithCurrentVersion hook. Otherwise, useFindRecord
with by performed with skip true, disconnecting tmp from the cache and
making it miss a statuses update.
https://github.com/user-attachments/assets/5fc355e8-cf18-4881-855b-744eb253b79e
Using deepEqual, average over 3 calls:
- version trigger 1.53ms
- version steps 38.3ms
- run state 372.8 ms
Using stringified hash, average over 3 calls:
- version trigger 0.07ms
- version steps 0.74 ms
- run state 0.521ms
Short fastDeepEqual
- version trigger 0.028ms
- version steps 0.197ms
- run state 0.214ms
Lib fastDeepEqual
- version trigger 0.038ms
- version steps 0.187ms
- run state 0.230ms
## Context
Deprecating TwentyORMManager in favor of TwentyORMGlobalManager
(temporarily, as this will simplify the ultimate goal to later replace
all usages with the new TwentyORMGlobalManagerV2 which will have a
similar signature)
This means this PR had to refactor a bit of code to pass down the
workspaceId when not available directly as it is now a requirement,
meaning we also deprecated scopedWorkspaceContextFactory to have a less
obscure way to fetch the workspaceId and have something more
declarative.
Step 3 will be to update TwentyORMGlobalManager to use a featureFlag
toggling and use the new GlobalWorkspaceOrmManager internally using the
new cache service
Step 4 will be to remove the feature flag and pg_pool patch
In this previous work aiming at eliminating the creation of viewGroups
being separated from the views, I removed the creation of viewGroups
from the FE at view creation, but forgot to do it at view update when
the user chooses "change Layout" option (from Table/Kanban/Calendar to
another).
In this PR
- I removed creation, deletion and destroy of viewGroups from
usePersistViewGroupRecords. I left update because it useful for
visibility and position
- since usePersistViewGroups record was also handling optimistic, I
moved optimistic logic to a new hook useViewsSideEffectsOnViewGroups. I
realized that so far we optimistic is only useful for creation. For the
update though we do need to compute the view groups that will be created
to be able to call loadRecordIndexState, so I created a function for
that, but I did not seek to perform real optimistic, with writing and
deleting groups from the cache as it was a bit heavier and not in use
for now and I want to merge this asap as it fixes the creation of
viewGroups.
In this PR:
- add more logs to troubleshoot issues in production
- use messageChannelSyncStatus in messageSync service instead of making
a manual update
There are three identified scenarios.
## First scenario
The user uses a desktop. They click on a company, which is opened in the
side panel. They click on a tab, like "Tasks". The user chooses to open
the record in fullscreen. The "Tasks" tab is opened by default in the
fullscreen record page.
If the user refreshes the page, the default tab is shown: "Timeline".
**This was the behavior on the show pages, and I kept it.** If we wanted
to show the "Tasks" tab here, we would have to put the id of the "Tasks"
tab in the URL hash when we open the record in fullscreen and an active
tab id is already set.
https://github.com/user-attachments/assets/205776ac-9ad7-4e79-af9a-6b44360a5d77
## Second scenario
The user uses a desktop or a mobile device and interacts with a company
record. They click on a tab. If they refresh, the selected tab will be
displayed by default.
### Desktop
https://github.com/user-attachments/assets/d4e1908b-a591-42f6-bb82-5aec592e2778
### Mobile
https://github.com/user-attachments/assets/7bab73cc-a2ff-4ce8-9bc6-325efef2d500
## Third scenario
The user uses a desktop. They click on a dashboard, which is opened in
fullscreen mode by default. They select tabs. If they refresh, the last
selected tab is opened by default.
When the user turns edit mode on, **the url hash is removed**. The last
selected tab remains selected. If the user selects another tab, the url
hash isn't set, but the newly selected tab is displayed correctly. If
the user saves their changes, the selected tab remains selected.
However, if they refresh the page, the default tab replaces the
previously selected tab.
Not setting the url hash when editing a page layout simplifies the code.
I'm okay with this tradeoff as the feature is primarily meant to let
users share specific tabs of their records.
**This behavior will also be used for record page layout once edit mode
is supported.**
https://github.com/user-attachments/assets/869657a1-6895-4ade-816c-972c77aaab9e
Closes https://github.com/twentyhq/core-team-issues/issues/1784