Fixes#8591
1. Summary
We disabled hide/dnd(drag-and-drop) options for `No value` view group
intentionally in the first implementation. We want to change it to
behave like normal view groups, so enable hide/dnd for `No value` view
group as well.
2. Solution
I have removed the code that filters the `No value` group out of view
groups, so `No value` is stored in the same array as other view groups.
I have removed the `No value` flag check for `Hide` button on the
hamburger menu of the Kanban header. I had to update the code in
`packages/twenty-front/src/modules/views/utils/mapViewGroupsToRecordGroupDefinitions.ts`
because it was ignoring the visibility flag of the `No value` view group
and set it always to true. Also, it was always putting the `No value`
group last ignoring the previous position.
>**_I am not 100% confident in the changes I made in
`packages/twenty-front/src/modules/views/utils/mapViewGroupsToRecordGroupDefinitions.ts`.
I'd like to have a review from someone more familiar with that part._**
3. Recording
https://github.com/user-attachments/assets/e135e22e-6e3a-4f94-a898-aafc03bba060
Currently when renaming an object, we execute
```
await this.fieldMetadataRepository
.findOneByOrFail({
name: existingObjectMetadata.nameSingular,
label: existingObjectMetadata.labelSingular,
objectMetadataId: relatedObject.id,
workspaceId: workspaceId,
})
```
to find the standard relation fields.
This would throw an error if the label solely was update beforehand
without updating the name too: in that case we will not have migrated
the label of the standard relation fields (which is maybe a mistake?
@Weiko wdyt?).
Let's remove it.
## Context
Some mutations are not working properly, workspaceMember soft deletion
for example. workspaceMember being a camelCase table name, it's probably
not propagated properly to pgql (which needs double quote for the table
name to keep it as camelCase)
I didn't have time to dig too much but if the `where` is before
`softDelete`, the query is `WHERE workspaceMember.id = $1` while if it's
after, the query becomes `WHERE id = $1`.
Probably due to the fact that once you call delete/softDelete/update,
the standard builder (SelectQueryBuilder) becomes a
DeleteQueryBuilder/etc... and filters are not handled the same way.
## Context
We recently added a command to ensure uniqueness on the viewId column in
the viewField table. This created some issues for some old workspaces
that had viewFields with an empty viewId.
This command should get rid of those and set the column as non-nullable.
Also updating the onDelete action accordingly and set one missing for
FavoriteFolder
In this PR
1. Add integration tests for /metadata (master issue:
https://github.com/twentyhq/twenty/issues/8719)
2. Fix relation deletion: index on "from" object was not deleted,
impeding creation of a new relation between the same two objects A and B
after relation between A and B was deleted
### Readme ideas for better getting started
Website update proposal to give an easier way to get started on the
Local Setup
---------
Co-authored-by: guillim <guillaume@twenty.com>
## Issue
Some users were facing issues while updating SELECT or MULTISELECT
options:
```
Error executing migration QueryFailedError: column "undefined" does not exist
at PostgresQueryRunner.query (/app/node_modules/typeorm/driver/postgres/PostgresQueryRunner.js:219:19)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async WorkspaceMigrationEnumService.migrateEnumValues (/app/packages/twenty-server/dist/src/engine/workspace-manager/workspace-migration-runner/services/workspace-migration-enum.service.js:101:13)
at async WorkspaceMigrationEnumService.alterEnum (/app/packages/twenty-server/dist/src/engine/workspace-manager/workspace-migration-runner/services/workspace-migration-enum.service.js:54:9)
at async WorkspaceMigrationRunnerService.alterColumn (/app/packages/twenty-server/dist/src/engine/workspace-manager/workspace-migration-runner/workspace-migration-runner.service.js:254:13)
at async WorkspaceMigrationRunnerService.handleColumnChanges (/app/packages/twenty-server/dist/src/engine/workspace-manager/workspace-migration-runner/workspace-migration-runner.service.js:202:21)
at async WorkspaceMigrationRunnerService.handleTableChanges (/app/packages/twenty-server/dist/src/engine/workspace-manager/workspace-migration-runner/workspace-migration-runner.service.js:94:25)
at async WorkspaceMigrationRunnerService.executeMigrationFromPendingMigrations (/app/packages/twenty-server/dist/src/engine/workspace-manager/workspace-migration-runner/workspace-migration-runner.service.js:60:17)
at async WorkspaceExecutePendingMigrationsCommand.run (/app/packages/twenty-server/dist/src/engine/workspace-manager/workspace-migration-runner/commands/workspace-execute-pending-migrations.command.js:24:9)
at async Command.<anonymous> (/app/node_modules/nest-commander/src/command-runner.service.js:162:24) {
query: '\n' +
' UPDATE "workspace_7i7bwawp7keh3gel1g69jropc"."_funnelInProductsRu"\n' +
' SET "reasonForStageTransition" = undefined\n' +
" WHERE id='2af8db61-5f75-46de-8b1a-97e312937e06'\n" +
' ',
parameters: undefined,
driverError: error: column "undefined" does not exist
```
## Root cause
Internally, while migrating enum values, we are doing:
```
const values = await queryRunner.query(
`SELECT id, "${oldColumnName}" FROM "${schemaName}"."${tableName}"`,
);
let val = value[oldColumnName];
```
oldColumnName being: `${columnDefinition.columnName}_old_${v4()}`;
However, TypeORM only supports 63 bits identifiers:
https://github.com/typeorm/typeorm/issues/3118, but silently truncate
the identifer so if oldColumnName gets larger than 63 characters,
`value[oldColumnName]` is undefined.
## Fix
We only need a temporary and unique temporary name, no need to take into
account the previous columnName here
Closes#8578
There was no case to handle a FieldMetadataType.Array and thus an error
was thrown every time the edit button was clicked on an Array type.
It has been added now with an explicit break statement.
…RKSPACE_ID
The Pull Request modifies seed data by replacing
SEED_TWENTY_WORKSPACE_ID with SEED_ACME_WORKSPACE_ID across several
files.
- Updated SEED_TWENTY_WORKSPACE_ID to SEED_ACME_WORKSPACE_ID.
- Modified relevant import paths and seeds involving workspace data.
- Changes affect seeding processes for workspace members, user
workspaces, and general workspace details.
**TLDR**
Added Billing Entitlement table, based on stripe
customer.ActiveEntitlements webhook event. In this table it has a key
value pair with each key being the stripe feature lookup key and the
value a boolean. We use this table in order to see if SSO or other
feaures are enabled by workspace.
**In order to test: twenty-server**
Billing:
- Set IS_BILLING_ENABLED to true
- Add your BILLING_STRIPE_SECRET and BILLING_STRIPE_API_KEY
- Add your BILLING_STRIPE_BASE_PLAN_PRODUCT_ID (use the one in testMode
> Base Plan)
Auth:
- Set AUTH_SSO_ENABLED to true
- Set your ACCESS_TOKEN_SECRET, LOGIN_TOKEN_SECRET, REFRESH_TOKEN_SECRET
and FILE_TOKEN_SECRET
- Set IS_SSO_ENABLED feature flag to true
Stripe Webhook:
- Authenticate with your account in the stripe CLI
- Run the command: stripe listen --forward-to
http://localhost:3000/billing/webhooks
Migration:
- npx nx typeorm -- migration:run -d
src/database/typeorm/core/core.datasource.ts
**In order to test: twenty site**
- Buy a subscription (you can use the card 4242...42 with expiration
date later in the future)
- Go to SSO and create an OICD subscription
- Change the value in the entitlement table in order to put it in false
- An error should occur saying that the current workspace has no
entitlement
**Considerations**
The data from the Entitlement table is updated based on the stripe
webhook responses, and we use the customerActiveEntitlemet response to
update the info on the table, however this event doesnt have the
metadata containing the workspaceId. Because we cannot control at wich
order the webhook send events, we force a server error if the
entitlements are updated before the BillingSubscription. Stripe resends
the event based on a exponential backoff (for more info see
https://docs.stripe.com/webhooks#retries ) because we are in test mode
Stripe retries three times over a few hours. So if the
BillingEntitlement is not updated it is completely normal and it will be
updated when stripe resends the event.
---------
Co-authored-by: Félix Malfait <felix@twenty.com>
Fixes: #8487#5027
1. Summary
The purpose of these changes is to elevate the dev/user experience when
the initial config load call fails for whatever reason by displaying a
fallback component.
2. Solution
I ended up making more changes than I initially planned. I had to update
the order of the contexts a bit because `GenericErrorFallback` is
dependent on `AppThemeProvider` for styling and `AppThemeProvider` is
dependent on `ObjectMetadataItemsProvider` for
[`useObjectMetadataItem`](ae2f193d68/packages/twenty-front/src/modules/object-metadata/hooks/useObjectMetadataItem.ts (L22))
hook (`AppThemeProvider` -> `useColorScheme` -> `useUpdateOneRecord` ->
`useObjectMetadataItem`). I had to create a wrapper component for
`AppThemeProvider` and stylize it in a way that it looks responsive on
both mobile and desktop devices. Finally, I had to introduce the
`isErrored` flag to differentiate the loading and error states.
There are some improvements we can make later -
- Display a loading state for the initial config load
- Implement a refetch logic for the initial config loading failure
3. Recording
https://github.com/user-attachments/assets/c2f43573-8006-4118-8e18-8576099d78fdhttps://github.com/user-attachments/assets/9c5853d3-539b-4880-aa38-c416c3e13594
---------
Co-authored-by: Félix Malfait <felix@twenty.com>
## Context
Now that each operation has its own resolver, we need to make sure they
all map to query arg getters. CreateOne was not properly mapped to the
position getter which made record creation fail because "position:
first" was not properly converted to a float.
Also fixing queries with custom object where we were wrongly using the
table name instead of entity name
Fixes https://github.com/twentyhq/twenty/issues/8300
## Context
API events were created too late and were already formatted as Gql
responses (including nesting with edges/node/type + formatting that
should not exist in an event payload). This PR moves the emit logic to
the resolver where we actually do the DB query
Note: Also added RESTORED events
## Context
- Fixing folder structure where 0.33 was inside 0.32.
- Updating the command so it runs enforce uniqueness on all tables
- Updating workspaces entities so the sync metadata adds the index
Refactoring update of standard relations when a custom object is
renamed, after observing occasional issues.
---------
Co-authored-by: Weiko <corentin@twenty.com>