Skip to content

Commit eb9a748

Browse files
committed
Validate group existence in Advanced Query view
1 parent ecfb3f5 commit eb9a748

File tree

5 files changed

+58
-2
lines changed

5 files changed

+58
-2
lines changed

UI/web-app/src/components/AdvancedQuery/AdvancedQuery.base.tsx

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ import {
2424
setIsAdvancedQueryValid,
2525
} from '../../store/manageMembership.slice';
2626
import { removeUnusedProperties } from '../../utils/sourcePartUtils';
27+
import { SourcePartType } from '../../models/SourcePartType';
28+
import { SourcePartQuery } from '../../models/SourcePartQuery';
29+
import { validateGroup } from '../../store/groups.api';
2730

2831
const getClassNames = classNamesFunction<
2932
IAdvancedQueryStyleProps,
@@ -110,15 +113,32 @@ export const AdvancedQueryBase: React.FunctionComponent<IAdvancedQueryProps> = (
110113
onQueryChange(event, newValue);
111114
};
112115

113-
const onValidateQuery = () => {
116+
const onValidateQuery = async () => {
114117
try {
115118
const parsedQuery = JSON.parse(localQuery || '[]');
116119
const validate = ajv.compile(schema);
117120
const isValid = validate(parsedQuery);
118121

119122
if (isValid) {
123+
const validationResults = await Promise.all(
124+
(parsedQuery as Array<SourcePartQuery>).map(async (part) => {
125+
if (part.type === SourcePartType.GroupMembership && part.source) {
126+
const result = await dispatch(validateGroup(part.source)).unwrap();
127+
return result;
128+
}
129+
return { groupId: part.source, isValid: true };
130+
})
131+
);
132+
133+
const invalidGroups = validationResults.filter(result => !result.isValid);
134+
if (invalidGroups.length > 0) {
135+
const invalidGroupIds = invalidGroups.map(result => result.groupId).join(', ');
136+
setValidationMessage(`${strings.ManageMembership.labels.invalidGroups} ${invalidGroupIds}`);
137+
} else {
138+
setValidationMessage(strings.ManageMembership.labels.validQuery);
139+
}
140+
120141
dispatch(setAdvancedViewQuery(localQuery || '[]'));
121-
setValidationMessage(strings.ManageMembership.labels.validQuery);
122142
} else {
123143
const errorsFromAjv = validate.errors;
124144
const formattedErrors = formatErrors(errorsFromAjv as ExtendedErrorObject[] | null | undefined);

UI/web-app/src/services/localization/IStrings.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,7 @@ export type IStrings = {
288288
query: string;
289289
validQuery: string;
290290
invalidQuery: string;
291+
invalidGroups: string;
291292
step3title: string;
292293
step3description: string;
293294
selectStartDate: string;

UI/web-app/src/services/localization/i18n/locales/en/translations.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,7 @@ export const strings: IStrings = {
293293
query: 'Query',
294294
validQuery: 'Query is valid.',
295295
invalidQuery: 'Failed to parse query. Ensure it is valid JSON.',
296+
invalidGroups: 'Invalid group IDs:',
296297
step3title: 'Step 3: Membership Configuration',
297298
step3description: 'Define the source membership for the destination.',
298299
selectStartDate: 'Select an option to start managing the membership',

UI/web-app/src/services/localization/i18n/locales/es/translations.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,7 @@ export const strings: IStrings = {
297297
query: 'Consulta',
298298
validQuery: 'Consulta válida.',
299299
invalidQuery: 'Error al analizar la consulta. Asegúrese de que sea JSON válido.',
300+
invalidGroups: 'Grupos inválido:',
300301
step3title: 'Paso 3: Configuración de Membresía',
301302
step3description: 'Defina la fuente de la membresía para el destino.',
302303
selectStartDate: 'Selecciona una opción para comenzar a administrar la membresía',

UI/web-app/src/store/groups.api.tsx

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ import { TokenType } from '../services/auth';
88
import { Destination } from '../models';
99
import { IPersonaProps } from '@fluentui/react';
1010

11+
interface ValidateGroupResponse {
12+
groupId: string;
13+
isValid: boolean;
14+
}
1115

1216
export const searchGroups = createAsyncThunk<IPersonaProps[], string, ThunkConfig>(
1317
'destinations/searchDestinations',
@@ -42,3 +46,32 @@ export const searchGroups = createAsyncThunk<IPersonaProps[], string, ThunkConfi
4246
}
4347
);
4448

49+
50+
export const validateGroup = createAsyncThunk<ValidateGroupResponse, string, ThunkConfig>(
51+
'destinations/searchDestinations',
52+
async (groupId: string, { extra }) => {
53+
const { authenticationService } = extra.services;
54+
const token = await authenticationService.getTokenAsync(TokenType.GMM);
55+
const headers = new Headers();
56+
const bearer = `Bearer ${token}`;
57+
headers.append('Authorization', bearer);
58+
59+
const options = {
60+
method: 'GET',
61+
headers,
62+
};
63+
64+
try {
65+
const response = await fetch(`${config.searchDestinations}/${encodeURIComponent(groupId)}`, options);
66+
if (!response.ok) {
67+
console.error('Group is not valid!', response.statusText);
68+
return { groupId, isValid: false };
69+
}
70+
return { groupId, isValid: true };
71+
} catch (error) {
72+
console.error('Failed to validate group!', error);
73+
throw new Error('Failed to validate group!');
74+
}
75+
}
76+
);
77+

0 commit comments

Comments
 (0)