fix(server): preserve kanban/calendar fields in view manifest sync (#19946)
## Summary The `fromViewManifestToUniversalFlatView` converter hardcoded five view fields to `null` instead of reading them from the manifest: - `mainGroupByFieldMetadataUniversalIdentifier` - `kanbanAggregateOperation` - `kanbanAggregateOperationFieldMetadataUniversalIdentifier` - `calendarLayout` - `calendarFieldMetadataUniversalIdentifier` As a result **any** Kanban view in an app manifest is rejected by `validateFlatViewCreation` with `"Kanban view must have a main group by field"`, and any Calendar view would trip the `view.entity.ts` check constraint requiring `calendarLayout` + `calendarFieldMetadataId` to be non-null. Discovered while trying to install [`twenty-crm-meeting-baas`](https://github.com/Meeting-BaaS/twenty-crm-meeting-baas) which ships a Kanban view. ## Changes - **Server converter**: read all five fields from the manifest (with `?? null` fallback). - **`ViewManifest` type** (`twenty-shared`): add the five fields so SDK users can set them type-safely. - **Move `ViewCalendarLayout`** from `twenty-server` to `twenty-shared` so the manifest type can reference it. Seven import sites updated; the front-end imports via generated GraphQL types and is unaffected. - **Unit tests**: extend `from-view-manifest-to-universal-flat-view.util.spec.ts` with preservation + null-default cases for both Kanban and Calendar (5 tests total). - **Regression coverage**: add a Kanban view (`post-cards-by-status.view.ts`) to the `rich-app` fixture grouped by the existing `status` SELECT field. The existing `applications-install-delete-reinstall` e2e test now exercises the Kanban path end-to-end — a future regression here would fail CI. Note: `expected-manifest.ts` and the `views.length` assertion in `manifest.tests.ts` were updated to reflect the new fixture view. ## Test plan - [x] `nx test twenty-server -- from-view-manifest-to-universal-flat-view` → 5/5 pass - [x] `nx typecheck twenty-shared` / `twenty-sdk` / `twenty-server` → no new errors (one pre-existing unrelated error in `admin-panel.module-factory.ts`) - [x] `nx lint twenty-shared` / `twenty-sdk` → clean - [x] Manual install of the Meeting BaaS app on a dev workspace succeeds with the Kanban view after this fix - [ ] CI: SDK e2e `applications-install-delete-reinstall` passes against the new fixture view - [ ] CI: integration test `calendar-field-deactivation-deletes-views` still passes after the enum move 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
This commit is contained in:
+67
@@ -1,4 +1,6 @@
|
||||
import {
|
||||
AggregateOperations,
|
||||
ViewCalendarLayout,
|
||||
ViewOpenRecordIn,
|
||||
ViewType,
|
||||
ViewVisibility,
|
||||
@@ -65,4 +67,69 @@ describe('fromViewManifestToUniversalFlatView', () => {
|
||||
expect(result.visibility).toBe(ViewVisibility.UNLISTED);
|
||||
expect(result.openRecordIn).toBe(ViewOpenRecordIn.RECORD_PAGE);
|
||||
});
|
||||
|
||||
it('should preserve kanban fields from the manifest', () => {
|
||||
const result = fromViewManifestToUniversalFlatView({
|
||||
viewManifest: {
|
||||
universalIdentifier: 'view-uuid-3',
|
||||
name: 'Kanban Board',
|
||||
objectUniversalIdentifier: 'object-uuid-1',
|
||||
type: ViewType.KANBAN,
|
||||
mainGroupByFieldMetadataUniversalIdentifier: 'field-uuid-status',
|
||||
kanbanAggregateOperation: AggregateOperations.COUNT,
|
||||
kanbanAggregateOperationFieldMetadataUniversalIdentifier:
|
||||
'field-uuid-amount',
|
||||
},
|
||||
applicationUniversalIdentifier,
|
||||
now,
|
||||
});
|
||||
|
||||
expect(result.mainGroupByFieldMetadataUniversalIdentifier).toBe(
|
||||
'field-uuid-status',
|
||||
);
|
||||
expect(result.kanbanAggregateOperation).toBe(AggregateOperations.COUNT);
|
||||
expect(
|
||||
result.kanbanAggregateOperationFieldMetadataUniversalIdentifier,
|
||||
).toBe('field-uuid-amount');
|
||||
});
|
||||
|
||||
it('should default kanban and calendar fields to null when omitted', () => {
|
||||
const result = fromViewManifestToUniversalFlatView({
|
||||
viewManifest: {
|
||||
universalIdentifier: 'view-uuid-4',
|
||||
name: 'All Records',
|
||||
objectUniversalIdentifier: 'object-uuid-1',
|
||||
},
|
||||
applicationUniversalIdentifier,
|
||||
now,
|
||||
});
|
||||
|
||||
expect(result.mainGroupByFieldMetadataUniversalIdentifier).toBeNull();
|
||||
expect(result.kanbanAggregateOperation).toBeNull();
|
||||
expect(
|
||||
result.kanbanAggregateOperationFieldMetadataUniversalIdentifier,
|
||||
).toBeNull();
|
||||
expect(result.calendarLayout).toBeNull();
|
||||
expect(result.calendarFieldMetadataUniversalIdentifier).toBeNull();
|
||||
});
|
||||
|
||||
it('should preserve calendar fields from the manifest', () => {
|
||||
const result = fromViewManifestToUniversalFlatView({
|
||||
viewManifest: {
|
||||
universalIdentifier: 'view-uuid-5',
|
||||
name: 'Calendar View',
|
||||
objectUniversalIdentifier: 'object-uuid-1',
|
||||
type: ViewType.CALENDAR,
|
||||
calendarLayout: ViewCalendarLayout.WEEK,
|
||||
calendarFieldMetadataUniversalIdentifier: 'field-uuid-date',
|
||||
},
|
||||
applicationUniversalIdentifier,
|
||||
now,
|
||||
});
|
||||
|
||||
expect(result.calendarLayout).toBe(ViewCalendarLayout.WEEK);
|
||||
expect(result.calendarFieldMetadataUniversalIdentifier).toBe(
|
||||
'field-uuid-date',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
+9
-5
@@ -29,11 +29,15 @@ export const fromViewManifestToUniversalFlatView = ({
|
||||
visibility: viewManifest.visibility ?? ViewVisibility.WORKSPACE,
|
||||
openRecordIn: viewManifest.openRecordIn ?? ViewOpenRecordIn.SIDE_PANEL,
|
||||
key: viewManifest.key ?? null,
|
||||
kanbanAggregateOperation: null,
|
||||
kanbanAggregateOperationFieldMetadataUniversalIdentifier: null,
|
||||
calendarLayout: null,
|
||||
calendarFieldMetadataUniversalIdentifier: null,
|
||||
mainGroupByFieldMetadataUniversalIdentifier: null,
|
||||
kanbanAggregateOperation: viewManifest.kanbanAggregateOperation ?? null,
|
||||
kanbanAggregateOperationFieldMetadataUniversalIdentifier:
|
||||
viewManifest.kanbanAggregateOperationFieldMetadataUniversalIdentifier ??
|
||||
null,
|
||||
calendarLayout: viewManifest.calendarLayout ?? null,
|
||||
calendarFieldMetadataUniversalIdentifier:
|
||||
viewManifest.calendarFieldMetadataUniversalIdentifier ?? null,
|
||||
mainGroupByFieldMetadataUniversalIdentifier:
|
||||
viewManifest.mainGroupByFieldMetadataUniversalIdentifier ?? null,
|
||||
shouldHideEmptyGroups: false,
|
||||
anyFieldFilterValue: null,
|
||||
createdByUserWorkspaceId: null,
|
||||
|
||||
Reference in New Issue
Block a user