76f69efb437d6d5b658e7a826cc8750a0aee2904
6 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
7258722754 |
security: upgrade @nestjs/graphql 12→13 + @ptc-org/nestjs-query 4→9 (+ @nestjs/config 4) (#21402)
## What Upgrades the NestJS GraphQL stack to clear the High **`ws`** alert (GHSA-3h5v-q93c-6h6q) and modernize off two heavily-patched majors. `@nestjs/graphql@13` pulls `ws@8.20.1` (was 8.16.0). This had to be a **coordinated** upgrade: `@ptc-org/nestjs-query@4.2.0` doesn't support `@nestjs/graphql@13`, so all three move together. | Package | From → To | |---|---| | `@nestjs/config` | 3.3.0 → ^4.0.4 | | `@nestjs/graphql` | 12.1.1 → ^13.4.2 | | `@ptc-org/nestjs-query-{core,graphql,typeorm}` | 4.x → ^9.4.0 | ## The tricky bits - **Re-ported the custom `@nestjs/graphql` patch onto v13.** v13 rewrote the schema builder and added its *own* native multi-schema support (`includeModules`, native `clear()`). Twenty's patch (`resolverSchemaScope` + `computeReachableTypes` — the core/metadata/admin split) is re-merged into v13's new `generate(options, includeModules, reachableTypes)` flow, with a link-preserving `storage.clear()` so cross-schema `resolveType` closures keep working. - **Re-ported the `@ptc-org` patch onto 9.4.0**: removes the `@shareable` federation directive from built-in connection/response types, **and** adds a `.js` extension to its extensionless deep import of `@nestjs/graphql` internals — which v13's new `"exports"` map otherwise rejects at runtime (this was the boot blocker). - **`AppTokenService`**: nestjs-query 9 requires custom services to inject their repo and `super(repo)` it (added an `@InjectRepository` constructor). - **`gridPosition` input fields**: dropped the `deprecationReason` (a *required* input field can't be `@deprecated` under the upgraded graphql) — fields keep their original nullability, so the **schema is unchanged**. - **Service specs**: nestjs-query 9's `TypeOrmQueryService` reads the repo's driver/metadata at construction, so the mocked repos now include `manager`/`metadata`. ## Verification - `nx typecheck twenty-server`: **0 errors**; lint clean - Server boots; **all 3 GraphQL schemas** (`/graphql`, `/metadata`, `/admin-panel`) generate and respond `200` - `graphql:generate` for all 3 schemas is **byte-identical** to before the upgrade (the reachable-types re-port is faithful) - **108 service unit tests pass** (incl. all 6 `TypeOrmQueryService` services) - `ws@8.16.0` gone (now 8.17.1 + 8.18.0); `yarn install --immutable` clean ## Note on lodash `lodash@4.17.21` still remains via `zapier-platform-core` (runtime) and `@stoplight/spectral`, so the lodash alert is **reduced but not fully cleared** by this PR — it needs those separate sources addressed (or a resolution). |
||
|
|
5f604a503a |
backfill widget position from gridPosition (phase 1 of gridPosition removal) (#20032)
## Context
Phase 1 of removing the legacy `gridPosition` field from
`PageLayoutWidget` in favor of the new `position` discriminated union
(`grid` / `vertical-list` / `canvas`). This PR is purely additive —
`gridPosition` is still required and read everywhere; we just guarantee
that every widget now also has a non-null `position` so a follow-up PR
can drop `gridPosition` cleanly.
## Changes
- **Slow instance command**
`BackfillPageLayoutWidgetPositionSlowInstanceCommand` (2.1.0):
for every `core.pageLayoutWidget` row where `position IS NULL`, copies
`gridPosition`
into `position` with `layoutMode: 'GRID'`. Historically only grid
widgets used
`gridPosition`, so a single SQL update covers every existing row.
- **`PageLayoutDuplicationService`**: when duplicating a widget, also
forwards
`originalWidget.position` (was previously only forwarding
`gridPosition`).
- **Frontend default layouts** (10 `Default*PageLayout.ts` files): added
a `position`
sibling to every widget, matching the parent tab's `layoutMode` —
`VERTICAL_LIST` widgets
get `{ layoutMode, index }`, `CANVAS` widgets get `{ layoutMode }`
<img width="338" height="226" alt="Screenshot 2026-04-24 at 16 23 17"
src="https://github.com/user-attachments/assets/c3319318-f1b8-4271-96b4-196b209a1f5e"
/>
|
||
|
|
5c91a96e84 |
Add position to page layout widgets (#17643)
## Context
Introducing a new position column in PageLayoutWidget. This is because
we already have gridPosition but all widgets are not supposed to fit in
a grid (see pageLayoutTab layoutMode (GRID, VERTICAL_LIST, CANVAS...),
position will now support the different layoutMode
## Implementation
- Adding the new column (not renaming to avoid breaking changes in the
dashboards)
- Add proper validation for each layout mode
- Update standard page layout to not always use GRID but rely on the tab
layout mode
<details>
<summary>Graphql Query</summary>
```graphql
{
"data": {
"getPageLayouts": [
{
"tabs": [
{
"title": "Tab 1",
"layoutMode": "GRID",
"widgets": [
{
"title": "Untitled Rich Text",
"position": {
"column": 0,
"columnSpan": 6,
"layoutMode": "GRID",
"row": 0,
"rowSpan": 6
}
},
{
"title": "Deals by Company",
"position": {
"column": 6,
"columnSpan": 6,
"layoutMode": "GRID",
"row": 0,
"rowSpan": 6
}
},
{
"title": "Pipeline Value by Stage",
"position": {
"column": 0,
"columnSpan": 6,
"layoutMode": "GRID",
"row": 6,
"rowSpan": 6
}
},
{
"title": "Revenue Timeline",
"position": {
"column": 6,
"columnSpan": 6,
"layoutMode": "GRID",
"row": 6,
"rowSpan": 6
}
},
{
"title": "Opportunities by Owner",
"position": {
"column": 0,
"columnSpan": 6,
"layoutMode": "GRID",
"row": 12,
"rowSpan": 6
}
},
{
"title": "Stock market (Iframe)",
"position": {
"column": 6,
"columnSpan": 6,
"layoutMode": "GRID",
"row": 12,
"rowSpan": 8
}
},
{
"title": "Deals created this month",
"position": {
"column": 0,
"columnSpan": 3,
"layoutMode": "GRID",
"row": 18,
"rowSpan": 2
}
},
{
"title": "Deal value created this month",
"position": {
"column": 3,
"columnSpan": 3,
"layoutMode": "GRID",
"row": 18,
"rowSpan": 2
}
}
]
}
]
},
{
"tabs": [
{
"title": "Home",
"layoutMode": "VERTICAL_LIST",
"widgets": [
{
"title": "Fields",
"position": {
"layoutMode": "VERTICAL_LIST",
"index": 0
}
}
]
},
{
"title": "Timeline",
"layoutMode": "CANVAS",
"widgets": [
{
"title": "Timeline",
"position": {
"layoutMode": "CANVAS"
}
}
]
},
{
"title": "Tasks",
"layoutMode": "CANVAS",
"widgets": [
{
"title": "Tasks",
"position": {
"layoutMode": "CANVAS"
}
}
]
},
{
"title": "Notes",
"layoutMode": "CANVAS",
"widgets": [
{
"title": "Notes",
"position": {
"layoutMode": "CANVAS"
}
}
]
},
{
"title": "Files",
"layoutMode": "CANVAS",
"widgets": [
{
"title": "Files",
"position": {
"layoutMode": "CANVAS"
}
}
]
},
{
"title": "Emails",
"layoutMode": "CANVAS",
"widgets": [
{
"title": "Emails",
"position": {
"layoutMode": "CANVAS"
}
}
]
},
{
"title": "Calendar",
"layoutMode": "CANVAS",
"widgets": [
{
"title": "Calendar",
"position": {
"layoutMode": "CANVAS"
}
}
]
}
]
},
{
"tabs": [
{
"title": "Home",
"layoutMode": "VERTICAL_LIST",
"widgets": [
{
"title": "Fields",
"position": {
"layoutMode": "VERTICAL_LIST",
"index": 0
}
}
]
},
{
"title": "Timeline",
"layoutMode": "CANVAS",
"widgets": [
{
"title": "Timeline",
"position": {
"layoutMode": "CANVAS"
}
}
]
},
{
"title": "Tasks",
"layoutMode": "CANVAS",
"widgets": [
{
"title": "Tasks",
"position": {
"layoutMode": "CANVAS"
}
}
]
},
{
"title": "Notes",
"layoutMode": "CANVAS",
"widgets": [
{
"title": "Notes",
"position": {
"layoutMode": "CANVAS"
}
}
]
},
{
"title": "Files",
"layoutMode": "CANVAS",
"widgets": [
{
"title": "Files",
"position": {
"layoutMode": "CANVAS"
}
}
]
},
{
"title": "Emails",
"layoutMode": "CANVAS",
"widgets": [
{
"title": "Emails",
"position": {
"layoutMode": "CANVAS"
}
}
]
},
{
"title": "Calendar",
"layoutMode": "CANVAS",
"widgets": [
{
"title": "Calendar",
"position": {
"layoutMode": "CANVAS"
}
}
]
}
]
},
{
"tabs": [
{
"title": "Home",
"layoutMode": "VERTICAL_LIST",
"widgets": [
{
"title": "Fields",
"position": {
"layoutMode": "VERTICAL_LIST",
"index": 0
}
}
]
},
{
"title": "Timeline",
"layoutMode": "CANVAS",
"widgets": [
{
"title": "Timeline",
"position": {
"layoutMode": "CANVAS"
}
}
]
},
{
"title": "Tasks",
"layoutMode": "CANVAS",
"widgets": [
{
"title": "Tasks",
"position": {
"layoutMode": "CANVAS"
}
}
]
},
{
"title": "Notes",
"layoutMode": "CANVAS",
"widgets": [
{
"title": "Notes",
"position": {
"layoutMode": "CANVAS"
}
}
]
},
{
"title": "Files",
"layoutMode": "CANVAS",
"widgets": [
{
"title": "Files",
"position": {
"layoutMode": "CANVAS"
}
}
]
},
{
"title": "Emails",
"layoutMode": "CANVAS",
"widgets": [
{
"title": "Emails",
"position": {
"layoutMode": "CANVAS"
}
}
]
},
{
"title": "Calendar",
"layoutMode": "CANVAS",
"widgets": [
{
"title": "Calendar",
"position": {
"layoutMode": "CANVAS"
}
}
]
}
]
},
{
"tabs": [
{
"title": "Home",
"layoutMode": "VERTICAL_LIST",
"widgets": [
{
"title": "Fields",
"position": {
"layoutMode": "VERTICAL_LIST",
"index": 0
}
},
{
"title": "Note",
"position": {
"layoutMode": "VERTICAL_LIST",
"index": 1
}
}
]
},
{
"title": "Note",
"layoutMode": "CANVAS",
"widgets": [
{
"title": "Note",
"position": {
"layoutMode": "CANVAS"
}
}
]
},
{
"title": "Timeline",
"layoutMode": "CANVAS",
"widgets": [
{
"title": "Timeline",
"position": {
"layoutMode": "CANVAS"
}
}
]
},
{
"title": "Files",
"layoutMode": "CANVAS",
"widgets": [
{
"title": "Files",
"position": {
"layoutMode": "CANVAS"
}
}
]
}
]
},
{
"tabs": [
{
"title": "Home",
"layoutMode": "VERTICAL_LIST",
"widgets": [
{
"title": "Fields",
"position": {
"layoutMode": "VERTICAL_LIST",
"index": 0
}
},
{
"title": "Note",
"position": {
"layoutMode": "VERTICAL_LIST",
"index": 1
}
}
]
},
{
"title": "Note",
"layoutMode": "CANVAS",
"widgets": [
{
"title": "Note",
"position": {
"layoutMode": "CANVAS"
}
}
]
},
{
"title": "Timeline",
"layoutMode": "CANVAS",
"widgets": [
{
"title": "Timeline",
"position": {
"layoutMode": "CANVAS"
}
}
]
},
{
"title": "Files",
"layoutMode": "CANVAS",
"widgets": [
{
"title": "Files",
"position": {
"layoutMode": "CANVAS"
}
}
]
}
]
},
{
"tabs": [
{
"title": "Flow",
"layoutMode": "CANVAS",
"widgets": [
{
"title": "Flow",
"position": {
"layoutMode": "CANVAS"
}
}
]
}
]
},
{
"tabs": [
{
"title": "Home",
"layoutMode": "VERTICAL_LIST",
"widgets": [
{
"title": "Fields",
"position": {
"layoutMode": "VERTICAL_LIST",
"index": 0
}
}
]
},
{
"title": "Flow",
"layoutMode": "CANVAS",
"widgets": [
{
"title": "Flow",
"position": {
"layoutMode": "CANVAS"
}
}
]
}
]
},
{
"tabs": [
{
"title": "Home",
"layoutMode": "VERTICAL_LIST",
"widgets": [
{
"title": "Fields",
"position": {
"layoutMode": "VERTICAL_LIST",
"index": 0
}
}
]
},
{
"title": "Flow",
"layoutMode": "CANVAS",
"widgets": [
{
"title": "Flow",
"position": {
"layoutMode": "CANVAS"
}
}
]
}
]
}
]
}
}
```
</details>
|
||
|
|
4faed25624 |
[PAGE LAYOUTS] Add widgets validation (#16635)
- Add widget validation - Remove 'None' option for primary axis group by - Fix error message parsing by passing the operation type in `useMetadataErrorHandler` |
||
|
|
4135a6473a |
[BREAKING_CHANGE_DASHBOARDS][DASHBOARD_CACHE_FLUSH_REQUIRED] Refactor page layout widget configuration type (#16671)
# Introduction In this pull-request we're refactoring the page layout widget configuration entity to be containing its discriminated key simplifying underlying code and maintainability - Made the configuration and title non nullable - Introduced a generic predicate for the `widgetConfigurationType` - Upgraded command to remove `graphType` and insert new `configurationType` to existing entries - Migrated frontend to new type system --------- Co-authored-by: bosiraphael <raphael.bosi@gmail.com> Co-authored-by: Raphaël Bosi <71827178+bosiraphael@users.noreply.github.com> |
||
|
|
47a8a15598 |
Metadata modules for PageLayoutTab PageLayoutWidget (#16662)
# Introduction Creating dedicated folders and module for both `page-layout-tab` and `page-layout-widget` The addition diff with deletion is due to the module being added |