add view related schema definitions to computeMetadataSchemaComponents (#13971)

### The Issue

Every PR is currently failing the REST API breaking changes check with
errors like:
```
  Could not find /components/schemas/ViewForResponse
  Could not find /components/schemas/View
  Could not find /components/schemas/ViewForUpdate
  ...
  ```

  This is happening because the View REST endpoints were added to main `(/rest/metadata/views, /rest/metadata/viewFields, etc.)` but the corresponding OpenAPI schema definitions were missing from components.utils.ts.

 ### The Fix

  Added the missing schema definitions for all View-related entities:
  - view, viewField, viewFilter, viewSort, viewGroup, viewFilterGroup
  - Each entity includes 3 schema variants: base, ForUpdate, and ForResponse

  This ensures the OpenAPI spec properly documents what's already exposed.

 ### Note about CI

  This PR will still show the error in CI since it's comparing against the current main branch. Once merged, this should
  resolve the issue for future PRs.

###  Open Question

  Should the View REST endpoints be gated behind the IS_CORE_VIEW_ENABLED feature flag? Currently they're always exposed
  while the GraphQL resolvers do check this flag. Happy to add that in a follow-up if needed.
This commit is contained in:
nitin
2025-08-19 18:31:45 +05:30
committed by GitHub
parent e60e2bd342
commit 9d90a2e67f
@@ -503,6 +503,493 @@ export const computeMetadataSchemaComponents = (
},
};
return schemas;
}
case 'view': {
schemas[`${capitalize(item.nameSingular)}`] = {
type: 'object',
description: `A view`,
properties: {
name: { type: 'string' },
objectMetadataId: { type: 'string', format: 'uuid' },
type: {
type: 'string',
enum: ['TABLE', 'KANBAN'],
default: 'TABLE',
},
key: { type: 'string', default: 'INDEX' },
icon: { type: 'string' },
position: { type: 'number', default: 0 },
isCompact: { type: 'boolean', default: false },
openRecordIn: {
type: 'string',
enum: ['SIDE_PANEL', 'RECORD_PAGE'],
default: 'SIDE_PANEL',
},
kanbanAggregateOperation: {
type: 'string',
enum: ['AVG', 'COUNT', 'MAX', 'MIN', 'SUM'],
},
kanbanAggregateOperationFieldMetadataId: {
type: 'string',
format: 'uuid',
},
anyFieldFilterValue: { type: 'string' },
},
required: ['name', 'objectMetadataId', 'icon'],
};
schemas[`${capitalize(item.namePlural)}`] = {
type: 'array',
description: `A list of ${item.namePlural}`,
items: {
$ref: `#/components/schemas/${capitalize(item.nameSingular)}`,
},
};
schemas[`${capitalize(item.nameSingular)}ForUpdate`] = {
type: 'object',
description: `A view for update`,
properties: {
name: { type: 'string' },
type: {
type: 'string',
enum: ['TABLE', 'KANBAN'],
},
key: { type: 'string' },
icon: { type: 'string' },
position: { type: 'number' },
isCompact: { type: 'boolean' },
openRecordIn: {
type: 'string',
enum: ['SIDE_PANEL', 'RECORD_PAGE'],
},
kanbanAggregateOperation: {
type: 'string',
enum: ['AVG', 'COUNT', 'MAX', 'MIN', 'SUM'],
},
kanbanAggregateOperationFieldMetadataId: {
type: 'string',
format: 'uuid',
},
anyFieldFilterValue: { type: 'string' },
},
};
schemas[`${capitalize(item.nameSingular)}ForResponse`] = {
type: 'object',
description: `A view`,
properties: {
id: { type: 'string', format: 'uuid' },
name: { type: 'string' },
objectMetadataId: { type: 'string', format: 'uuid' },
type: {
type: 'string',
enum: ['TABLE', 'KANBAN'],
},
key: { type: 'string' },
icon: { type: 'string' },
position: { type: 'number' },
isCompact: { type: 'boolean' },
openRecordIn: {
type: 'string',
enum: ['SIDE_PANEL', 'RECORD_PAGE'],
},
kanbanAggregateOperation: {
type: 'string',
enum: ['AVG', 'COUNT', 'MAX', 'MIN', 'SUM'],
},
kanbanAggregateOperationFieldMetadataId: {
type: 'string',
format: 'uuid',
},
anyFieldFilterValue: { type: 'string' },
workspaceId: { type: 'string', format: 'uuid' },
createdAt: { type: 'string', format: 'date-time' },
updatedAt: { type: 'string', format: 'date-time' },
deletedAt: { type: 'string', format: 'date-time' },
},
};
schemas[`${capitalize(item.namePlural)}ForResponse`] = {
type: 'array',
description: `A list of ${item.namePlural}`,
items: {
$ref: `#/components/schemas/${capitalize(item.nameSingular)}ForResponse`,
},
};
return schemas;
}
case 'viewField': {
schemas[`${capitalize(item.nameSingular)}`] = {
type: 'object',
description: `A view field`,
properties: {
fieldMetadataId: { type: 'string', format: 'uuid' },
viewId: { type: 'string', format: 'uuid' },
isVisible: { type: 'boolean', default: true },
size: { type: 'number', default: 0 },
position: { type: 'number', default: 0 },
aggregateOperation: {
type: 'string',
enum: ['AVG', 'COUNT', 'MAX', 'MIN', 'SUM'],
},
},
required: ['fieldMetadataId', 'viewId'],
};
schemas[`${capitalize(item.namePlural)}`] = {
type: 'array',
description: `A list of ${item.namePlural}`,
items: {
$ref: `#/components/schemas/${capitalize(item.nameSingular)}`,
},
};
schemas[`${capitalize(item.nameSingular)}ForUpdate`] = {
type: 'object',
description: `A view field for update`,
properties: {
isVisible: { type: 'boolean' },
size: { type: 'number' },
position: { type: 'number' },
aggregateOperation: {
type: 'string',
enum: ['AVG', 'COUNT', 'MAX', 'MIN', 'SUM'],
},
},
};
schemas[`${capitalize(item.nameSingular)}ForResponse`] = {
type: 'object',
description: `A view field`,
properties: {
id: { type: 'string', format: 'uuid' },
fieldMetadataId: { type: 'string', format: 'uuid' },
viewId: { type: 'string', format: 'uuid' },
isVisible: { type: 'boolean' },
size: { type: 'number' },
position: { type: 'number' },
aggregateOperation: {
type: 'string',
enum: ['AVG', 'COUNT', 'MAX', 'MIN', 'SUM'],
},
workspaceId: { type: 'string', format: 'uuid' },
createdAt: { type: 'string', format: 'date-time' },
updatedAt: { type: 'string', format: 'date-time' },
deletedAt: { type: 'string', format: 'date-time' },
},
};
schemas[`${capitalize(item.namePlural)}ForResponse`] = {
type: 'array',
description: `A list of ${item.namePlural}`,
items: {
$ref: `#/components/schemas/${capitalize(item.nameSingular)}ForResponse`,
},
};
return schemas;
}
case 'viewFilter': {
schemas[`${capitalize(item.nameSingular)}`] = {
type: 'object',
description: `A view filter`,
properties: {
fieldMetadataId: { type: 'string', format: 'uuid' },
viewId: { type: 'string', format: 'uuid' },
operand: {
type: 'string',
enum: [
'IS',
'IS_NOT_NULL',
'IS_NOT',
'LESS_THAN_OR_EQUAL',
'GREATER_THAN_OR_EQUAL',
'IS_BEFORE',
'IS_AFTER',
'CONTAINS',
'DOES_NOT_CONTAIN',
'IS_EMPTY',
'IS_NOT_EMPTY',
'IS_RELATIVE',
'IS_IN_PAST',
'IS_IN_FUTURE',
'IS_TODAY',
'VECTOR_SEARCH',
],
default: 'CONTAINS',
},
value: {
type: 'object',
description: 'Filter value (JSON format)',
},
viewFilterGroupId: { type: 'string', format: 'uuid' },
positionInViewFilterGroup: { type: 'number' },
subFieldName: { type: 'string' },
},
required: ['fieldMetadataId', 'viewId', 'value'],
};
schemas[`${capitalize(item.namePlural)}`] = {
type: 'array',
description: `A list of ${item.namePlural}`,
items: {
$ref: `#/components/schemas/${capitalize(item.nameSingular)}`,
},
};
schemas[`${capitalize(item.nameSingular)}ForUpdate`] = {
type: 'object',
description: `A view filter for update`,
properties: {
operand: {
type: 'string',
enum: [
'IS',
'IS_NOT_NULL',
'IS_NOT',
'LESS_THAN_OR_EQUAL',
'GREATER_THAN_OR_EQUAL',
'IS_BEFORE',
'IS_AFTER',
'CONTAINS',
'DOES_NOT_CONTAIN',
'IS_EMPTY',
'IS_NOT_EMPTY',
'IS_RELATIVE',
'IS_IN_PAST',
'IS_IN_FUTURE',
'IS_TODAY',
'VECTOR_SEARCH',
],
},
value: {
type: 'object',
description: 'Filter value (JSON format)',
},
viewFilterGroupId: { type: 'string', format: 'uuid' },
positionInViewFilterGroup: { type: 'number' },
subFieldName: { type: 'string' },
},
};
schemas[`${capitalize(item.nameSingular)}ForResponse`] = {
type: 'object',
description: `A view filter`,
properties: {
id: { type: 'string', format: 'uuid' },
fieldMetadataId: { type: 'string', format: 'uuid' },
viewId: { type: 'string', format: 'uuid' },
operand: {
type: 'string',
enum: [
'IS',
'IS_NOT_NULL',
'IS_NOT',
'LESS_THAN_OR_EQUAL',
'GREATER_THAN_OR_EQUAL',
'IS_BEFORE',
'IS_AFTER',
'CONTAINS',
'DOES_NOT_CONTAIN',
'IS_EMPTY',
'IS_NOT_EMPTY',
'IS_RELATIVE',
'IS_IN_PAST',
'IS_IN_FUTURE',
'IS_TODAY',
'VECTOR_SEARCH',
],
},
value: {
type: 'object',
description: 'Filter value (JSON format)',
},
viewFilterGroupId: { type: 'string', format: 'uuid' },
positionInViewFilterGroup: { type: 'number' },
subFieldName: { type: 'string' },
workspaceId: { type: 'string', format: 'uuid' },
createdAt: { type: 'string', format: 'date-time' },
updatedAt: { type: 'string', format: 'date-time' },
deletedAt: { type: 'string', format: 'date-time' },
},
};
schemas[`${capitalize(item.namePlural)}ForResponse`] = {
type: 'array',
description: `A list of ${item.namePlural}`,
items: {
$ref: `#/components/schemas/${capitalize(item.nameSingular)}ForResponse`,
},
};
return schemas;
}
case 'viewSort': {
schemas[`${capitalize(item.nameSingular)}`] = {
type: 'object',
description: `A view sort`,
properties: {
fieldMetadataId: { type: 'string', format: 'uuid' },
viewId: { type: 'string', format: 'uuid' },
direction: {
type: 'string',
enum: ['ASC', 'DESC'],
default: 'ASC',
},
},
required: ['fieldMetadataId', 'viewId'],
};
schemas[`${capitalize(item.namePlural)}`] = {
type: 'array',
description: `A list of ${item.namePlural}`,
items: {
$ref: `#/components/schemas/${capitalize(item.nameSingular)}`,
},
};
schemas[`${capitalize(item.nameSingular)}ForUpdate`] = {
type: 'object',
description: `A view sort for update`,
properties: {
direction: {
type: 'string',
enum: ['ASC', 'DESC'],
},
},
};
schemas[`${capitalize(item.nameSingular)}ForResponse`] = {
type: 'object',
description: `A view sort`,
properties: {
id: { type: 'string', format: 'uuid' },
fieldMetadataId: { type: 'string', format: 'uuid' },
viewId: { type: 'string', format: 'uuid' },
direction: {
type: 'string',
enum: ['ASC', 'DESC'],
},
workspaceId: { type: 'string', format: 'uuid' },
createdAt: { type: 'string', format: 'date-time' },
updatedAt: { type: 'string', format: 'date-time' },
deletedAt: { type: 'string', format: 'date-time' },
},
};
schemas[`${capitalize(item.namePlural)}ForResponse`] = {
type: 'array',
description: `A list of ${item.namePlural}`,
items: {
$ref: `#/components/schemas/${capitalize(item.nameSingular)}ForResponse`,
},
};
return schemas;
}
case 'viewGroup': {
schemas[`${capitalize(item.nameSingular)}`] = {
type: 'object',
description: `A view group`,
properties: {
fieldMetadataId: { type: 'string', format: 'uuid' },
viewId: { type: 'string', format: 'uuid' },
fieldValue: { type: 'string' },
isVisible: { type: 'boolean', default: true },
position: { type: 'number', default: 0 },
},
required: ['fieldMetadataId', 'viewId', 'fieldValue'],
};
schemas[`${capitalize(item.namePlural)}`] = {
type: 'array',
description: `A list of ${item.namePlural}`,
items: {
$ref: `#/components/schemas/${capitalize(item.nameSingular)}`,
},
};
schemas[`${capitalize(item.nameSingular)}ForUpdate`] = {
type: 'object',
description: `A view group for update`,
properties: {
fieldValue: { type: 'string' },
isVisible: { type: 'boolean' },
position: { type: 'number' },
},
};
schemas[`${capitalize(item.nameSingular)}ForResponse`] = {
type: 'object',
description: `A view group`,
properties: {
id: { type: 'string', format: 'uuid' },
fieldMetadataId: { type: 'string', format: 'uuid' },
viewId: { type: 'string', format: 'uuid' },
fieldValue: { type: 'string' },
isVisible: { type: 'boolean' },
position: { type: 'number' },
workspaceId: { type: 'string', format: 'uuid' },
createdAt: { type: 'string', format: 'date-time' },
updatedAt: { type: 'string', format: 'date-time' },
deletedAt: { type: 'string', format: 'date-time' },
},
};
schemas[`${capitalize(item.namePlural)}ForResponse`] = {
type: 'array',
description: `A list of ${item.namePlural}`,
items: {
$ref: `#/components/schemas/${capitalize(item.nameSingular)}ForResponse`,
},
};
return schemas;
}
case 'viewFilterGroup': {
schemas[`${capitalize(item.nameSingular)}`] = {
type: 'object',
description: `A view filter group`,
properties: {
viewId: { type: 'string', format: 'uuid' },
parentViewFilterGroupId: { type: 'string', format: 'uuid' },
logicalOperator: {
type: 'string',
enum: ['AND', 'OR', 'NOT'],
default: 'AND',
},
positionInViewFilterGroup: { type: 'number' },
},
required: ['viewId'],
};
schemas[`${capitalize(item.namePlural)}`] = {
type: 'array',
description: `A list of ${item.namePlural}`,
items: {
$ref: `#/components/schemas/${capitalize(item.nameSingular)}`,
},
};
schemas[`${capitalize(item.nameSingular)}ForUpdate`] = {
type: 'object',
description: `A view filter group for update`,
properties: {
parentViewFilterGroupId: { type: 'string', format: 'uuid' },
logicalOperator: {
type: 'string',
enum: ['AND', 'OR', 'NOT'],
},
positionInViewFilterGroup: { type: 'number' },
},
};
schemas[`${capitalize(item.nameSingular)}ForResponse`] = {
type: 'object',
description: `A view filter group`,
properties: {
id: { type: 'string', format: 'uuid' },
viewId: { type: 'string', format: 'uuid' },
parentViewFilterGroupId: { type: 'string', format: 'uuid' },
logicalOperator: {
type: 'string',
enum: ['AND', 'OR', 'NOT'],
},
positionInViewFilterGroup: { type: 'number' },
workspaceId: { type: 'string', format: 'uuid' },
createdAt: { type: 'string', format: 'date-time' },
updatedAt: { type: 'string', format: 'date-time' },
deletedAt: { type: 'string', format: 'date-time' },
},
};
schemas[`${capitalize(item.namePlural)}ForResponse`] = {
type: 'array',
description: `A list of ${item.namePlural}`,
items: {
$ref: `#/components/schemas/${capitalize(item.nameSingular)}ForResponse`,
},
};
return schemas;
}
}