Skip to content

Commit d908e3e

Browse files
fix(orchestrator): restore status and date filters on workflow runs (#3260)
Filtering workflow runs by status or date failed after query variables were introduced. Use the correct filter types so results load instead of showing an error. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent f03371e commit d908e3e

3 files changed

Lines changed: 60 additions & 11 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@red-hat-developer-hub/backstage-plugin-orchestrator-backend': patch
3+
---
4+
5+
Fix an issue where filtering workflow runs by status or date could show an error instead of results.

workspaces/orchestrator/plugins/orchestrator-backend/src/helpers/filterBuilder.ts

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -111,23 +111,53 @@ function handleNestedFilter(
111111
return filterClause;
112112
}
113113

114-
function handleBetweenOperator(filter: FieldFilter): FilterClause {
114+
function getGraphQLVariableType(
115+
fieldName: string,
116+
fieldDef: IntrospectionField | undefined,
117+
type: ProcessType,
118+
isArray: boolean,
119+
): string {
120+
if (isEnumFilter(fieldName, type)) {
121+
return isArray ? '[ProcessInstanceState!]' : 'ProcessInstanceState';
122+
}
123+
124+
if (fieldDef?.type.name === TypeName.Date) {
125+
return 'DateTime!';
126+
}
127+
128+
if (isArray) {
129+
return '[String!]';
130+
}
131+
132+
return 'String';
133+
}
134+
135+
function handleBetweenOperator(
136+
filter: FieldFilter,
137+
fieldDef: IntrospectionField | undefined,
138+
): FilterClause {
115139
if (!Array.isArray(filter.value) || filter.value.length !== 2) {
116140
throw new Error('Between operator requires an array of two elements');
117141
}
142+
const paramType = getGraphQLVariableType(
143+
filter.field,
144+
fieldDef,
145+
'ProcessInstance',
146+
false,
147+
);
118148
const filterClauseVariableArray: FilterClauseVariable[] = [];
119149
const clauseVariableName1 = `clauseVariable${nonSecureRandomAlphaNumeric()}`;
120150
const filterClauseVariable1: FilterClauseVariable = {
121151
clauseVariableName: clauseVariableName1,
122152
formattedValue: filter.value[0],
123-
clauseVariableType: 'String',
153+
clauseVariableType: paramType,
124154
};
125155

126156
const clauseVariableName2 = `clauseVariable${nonSecureRandomAlphaNumeric()}`;
127157
const filterClauseVariable2: FilterClauseVariable = {
128158
clauseVariableName: clauseVariableName2,
129159
formattedValue: filter.value[1],
130-
clauseVariableType: 'String',
160+
clauseVariableType: paramType,
131161
};
132162

133163
const clause = `${filter.field}: {${getGraphQLOperator(
@@ -193,23 +223,25 @@ function handleBinaryOperator(
193223
}
194224
}
195225
let formattedValue: any;
196-
let paramType: string;
197-
if (Array.isArray(binaryFilter.value)) {
198-
formattedValue = binaryFilter.value.map(v =>
226+
const isArray = Array.isArray(binaryFilter.value);
227+
if (isArray) {
228+
formattedValue = (binaryFilter.value as unknown[]).map((v: unknown) =>
199229
formatValue(binaryFilter.field, v, fieldDef, type),
200230
);
201-
paramType = isEnumFilter(binaryFilter.field, type)
202-
? '[ProcessInstanceState!]'
203-
: '[String!]';
204231
} else {
205232
formattedValue = formatValue(
206233
binaryFilter.field,
207234
binaryFilter.value,
208235
fieldDef,
209236
type,
210237
);
211-
paramType = 'String';
212238
}
239+
const paramType = getGraphQLVariableType(
240+
binaryFilter.field,
241+
fieldDef,
242+
type,
243+
isArray,
244+
);
213245

214246
const clauseVariableName = `clauseVariable${nonSecureRandomAlphaNumeric()}`;
215247
const clause = `${binaryFilter.field}: {${getGraphQLOperator(binaryFilter.operator)}: $${clauseVariableName}}`;
@@ -273,7 +305,7 @@ export function buildFilterCondition(
273305
case FieldFilterOperatorEnum.IsNull:
274306
return handleIsNullOperator(filters);
275307
case FieldFilterOperatorEnum.Between:
276-
return handleBetweenOperator(filters);
308+
return handleBetweenOperator(filters, fieldDef);
277309
case FieldFilterOperatorEnum.Eq:
278310
case FieldFilterOperatorEnum.Like:
279311
case FieldFilterOperatorEnum.In:

workspaces/orchestrator/plugins/orchestrator-backend/src/helpers/filterBuilders.test.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ describe('column filters', () => {
128128
filter: Filter | undefined;
129129
expectedResult: string | FilterClause;
130130
expectedFormattedValue: Array<string | boolean | string[]>;
131+
expectedVariableTypes?: string[];
131132
};
132133
describe('empty filter testcases', () => {
133134
const emptyFilterTestCases: FilterTestCase[] = [
@@ -519,6 +520,7 @@ describe('column filters', () => {
519520
),
520521
expectedResult: `start: {equal: $variable1}`,
521522
expectedFormattedValue: [testDate1],
523+
expectedVariableTypes: ['DateTime!'],
522524
},
523525
{
524526
name: 'returns correct filter for single date field with isNull operator (false as boolean)',
@@ -595,6 +597,7 @@ describe('column filters', () => {
595597
]),
596598
expectedResult: `start: {between: {from: $variable1, to: $variable2}}`,
597599
expectedFormattedValue: [testDate1, testDate2],
600+
expectedVariableTypes: ['DateTime!', 'DateTime!'],
598601
},
599602
{
600603
name: 'returns correct OR filter for multiple id fields with equal, isNull, and GT operators',
@@ -683,6 +686,7 @@ describe('column filters', () => {
683686
filter,
684687
expectedResult,
685688
expectedFormattedValue,
689+
expectedVariableTypes,
686690
}) => {
687691
it(`${name}`, () => {
688692
const result = buildFilterCondition(
@@ -698,6 +702,9 @@ describe('column filters', () => {
698702
`$${item.clauseVariableName}`,
699703
);
700704
expect(item.formattedValue).toEqual(expectedFormattedValue[index]);
705+
expect(item.clauseVariableType).toBe(
706+
expectedVariableTypes?.[index] ?? item.clauseVariableType,
707+
);
701708
});
702709
expect(formattedClause).toBe(result.clause);
703710
});
@@ -718,6 +725,7 @@ describe('column filters', () => {
718725
),
719726
expectedResult: `state: {equal: $variable1}`,
720727
expectedFormattedValue: ['COMPLETED'],
728+
expectedVariableTypes: ['ProcessInstanceState'],
721729
},
722730
];
723731

@@ -728,6 +736,7 @@ describe('column filters', () => {
728736
filter,
729737
expectedResult,
730738
expectedFormattedValue,
739+
expectedVariableTypes,
731740
}) => {
732741
it(`${name}`, () => {
733742
const result = buildFilterCondition(
@@ -743,6 +752,9 @@ describe('column filters', () => {
743752
`$${item.clauseVariableName}`,
744753
);
745754
expect(item.formattedValue).toEqual(expectedFormattedValue[index]);
755+
expect(item.clauseVariableType).toBe(
756+
expectedVariableTypes?.[index] ?? item.clauseVariableType,
757+
);
746758
});
747759
expect(formattedClause).toBe(result.clause);
748760
});

0 commit comments

Comments
 (0)