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:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user