diff --git a/backend/src/main/resources/i18n/messages.properties b/backend/src/main/resources/i18n/messages.properties
index 3f23fc105..2cb49fb3d 100644
--- a/backend/src/main/resources/i18n/messages.properties
+++ b/backend/src/main/resources/i18n/messages.properties
@@ -741,3 +741,4 @@ value.algorithm-cbc-256=CBC (256) - http://www.w3.org/2001/04/xmlenc#aes256-cbc
value.algorithm-cbc-192=CBC (192) - http://www.w3.org/2001/04/xmlenc#aes192-cbc
value.algorithm-cbc-128=CBC (128) - http://www.w3.org/2001/04/xmlenc#aes128-cbc
value.algorithm-cbc-tripledes=CBC (TRIPLEDES) - http://www.w3.org/2001/04/xmlenc#tripledes-cbc
+message.algorithms-unique=Each algorithm may only be used once.
\ No newline at end of file
diff --git a/ui/src/app/core/components/ProtectRoute.js b/ui/src/app/core/components/ProtectRoute.js
index 68420b3b9..77133d9e7 100644
--- a/ui/src/app/core/components/ProtectRoute.js
+++ b/ui/src/app/core/components/ProtectRoute.js
@@ -7,7 +7,7 @@ import { useCurrentUser, useIsAdmin } from '../user/UserContext';
export function ProtectRoute({ children, redirectTo, ...rest }) {
const user = useCurrentUser();
const isAdmin = useIsAdmin();
- if (isUndefined(user.role)) {
+ if (isUndefined(user?.role)) {
return <>>
}
return isAdmin ? children : ;
diff --git a/ui/src/app/core/components/ProtectRoute.test.js b/ui/src/app/core/components/ProtectRoute.test.js
index 0edd7662e..477707774 100644
--- a/ui/src/app/core/components/ProtectRoute.test.js
+++ b/ui/src/app/core/components/ProtectRoute.test.js
@@ -6,7 +6,8 @@ import { ProtectRoute } from './ProtectRoute';
const mockIsAdmin = jest.fn();
jest.mock('../user/UserContext', () => ({
- useIsAdmin: () => mockIsAdmin()
+ useIsAdmin: () => mockIsAdmin(),
+ useCurrentUser: () => ({role: 'ROLE_ADMIN'}),
}));
const renderWithRouter = (ui, { route = '/' } = {}) => {
diff --git a/ui/src/app/form/component/widgets/SelectWidget.js b/ui/src/app/form/component/widgets/SelectWidget.js
index 2bf62bb2d..57f18b532 100644
--- a/ui/src/app/form/component/widgets/SelectWidget.js
+++ b/ui/src/app/form/component/widgets/SelectWidget.js
@@ -61,6 +61,7 @@ const SelectWidget = ({
onFocus,
placeholder,
rawErrors = [],
+ uiSchema,
}) => {
const { enumOptions, enumDisabled } = options;
@@ -120,6 +121,9 @@ const SelectWidget = ({
onChange={(event) => {
const newValue = getValue(event, multiple);
onChange(processValue(schema, newValue));
+ if (uiSchema.checkOnChange) {
+ setTouched(true);
+ }
}}>
{!multiple && schema.default === undefined && (
diff --git a/ui/src/app/metadata/domain/filter/definition/AlgorithmFilterDefinition.js b/ui/src/app/metadata/domain/filter/definition/AlgorithmFilterDefinition.js
index 51e3fa846..5d19288fb 100644
--- a/ui/src/app/metadata/domain/filter/definition/AlgorithmFilterDefinition.js
+++ b/ui/src/app/metadata/domain/filter/definition/AlgorithmFilterDefinition.js
@@ -11,7 +11,10 @@ export const AlgorithmFilterWizard = {
},
algorithms: {
"ui:options": {
- orderable: false
+ orderable: false,
+ },
+ items: {
+ checkOnChange: true
}
}
}, BaseFilterDefinition.uiSchema),
@@ -21,7 +24,24 @@ export const AlgorithmFilterWizard = {
// schema: `${BASE_PATH}assets/schema/filter/algorithm.schema.json`,
steps: [],
validator: (data = [], current = { resourceId: null }, group) => {
- return BaseFilterDefinition.validator(data, current, group, 'algorithmFilterTarget', 'algorithmFilterTargetType')
+ const base = BaseFilterDefinition.validator(data, current, group, 'algorithmFilterTarget', 'algorithmFilterTargetType');
+
+ return (formData, errors) => {
+ const errorList = base(formData, errors);
+ const { algorithms } = formData;
+
+ const dupes = algorithms.filter((item, index) => index !== algorithms.indexOf(item));
+
+ if (dupes.length) {
+ algorithms.forEach((value, index) => {
+ if (dupes.indexOf(value) > -1) {
+ errors.algorithms[index].addError('message.algorithms-unique');
+ }
+ });
+ }
+
+ return errorList;
+ }
},
formatter: (changes) => ({
...changes,