diff --git a/cspell.json b/cspell.json
index 3acbbe0ee1..b484a24da7 100644
--- a/cspell.json
+++ b/cspell.json
@@ -129,7 +129,8 @@
"uploadfileform",
"processwithstarteventform",
"processstring",
- "typeahed"
+ "typeahed",
+ "minmax"
],
"dictionaries": [
"html",
diff --git a/lib/core/card-view/components/card-view-textitem/card-view-textitem.component.html b/lib/core/card-view/components/card-view-textitem/card-view-textitem.component.html
index 8c476f1ceb..b14e0dec4e 100644
--- a/lib/core/card-view/components/card-view-textitem/card-view-textitem.component.html
+++ b/lib/core/card-view/components/card-view-textitem/card-view-textitem.component.html
@@ -55,7 +55,7 @@
class="adf-textitem-editable-error"
*ngIf="hasErrors">
- - {{ errorMessage | translate }}
+ - {{ error.message | translate: error }}
diff --git a/lib/core/card-view/components/card-view-textitem/card-view-textitem.component.spec.ts b/lib/core/card-view/components/card-view-textitem/card-view-textitem.component.spec.ts
index c35e7c2495..4f55503887 100644
--- a/lib/core/card-view/components/card-view-textitem/card-view-textitem.component.spec.ts
+++ b/lib/core/card-view/components/card-view-textitem/card-view-textitem.component.spec.ts
@@ -27,6 +27,7 @@ import { MatChipsModule } from '@angular/material/chips';
import { ClipboardService } from '../../../clipboard/clipboard.service';
import { DebugElement } from '@angular/core';
import { TranslateModule } from '@ngx-translate/core';
+import { CardViewItemValidator } from '../../interfaces/card-view-item-validator.interface';
describe('CardViewTextItemComponent', () => {
@@ -441,7 +442,7 @@ describe('CardViewTextItemComponent', () => {
});
it('should set the errorMessages properly if the editedValue is invalid', async () => {
- const expectedErrorMessages = ['Something went wrong'];
+ const expectedErrorMessages = [{ message: 'Something went wrong' } as CardViewItemValidator];
component.property.isValid = () => false;
component.property.getValidationErrors = () => expectedErrorMessages;
@@ -450,7 +451,7 @@ describe('CardViewTextItemComponent', () => {
await fixture.whenStable();
updateTextField(component.property.key, 'updated-value');
- expect(component.errorMessages).toBe(expectedErrorMessages);
+ expect(component.errors).toBe(expectedErrorMessages);
});
it('should update the property value after a successful update attempt', async () => {
diff --git a/lib/core/card-view/components/card-view-textitem/card-view-textitem.component.ts b/lib/core/card-view/components/card-view-textitem/card-view-textitem.component.ts
index 081148cc09..f77c018468 100644
--- a/lib/core/card-view/components/card-view-textitem/card-view-textitem.component.ts
+++ b/lib/core/card-view/components/card-view-textitem/card-view-textitem.component.ts
@@ -22,6 +22,7 @@ import { BaseCardView } from '../base-card-view';
import { MatChipInputEvent } from '@angular/material/chips';
import { ClipboardService } from '../../../clipboard/clipboard.service';
import { TranslationService } from '../../../services/translation.service';
+import { CardViewItemValidator } from '../../interfaces/card-view-item-validator.interface';
export const DEFAULT_SEPARATOR = ', ';
const templateTypes = {
@@ -55,7 +56,7 @@ export class CardViewTextItemComponent extends BaseCardView 0;
+ return (!!this.errors?.length) ?? false;
}
get isChipViewEnabled(): boolean {
diff --git a/lib/core/card-view/models/card-view-baseitem.model.spec.ts b/lib/core/card-view/models/card-view-baseitem.model.spec.ts
index f1b6f7daf3..39036f2fc9 100644
--- a/lib/core/card-view/models/card-view-baseitem.model.spec.ts
+++ b/lib/core/card-view/models/card-view-baseitem.model.spec.ts
@@ -91,7 +91,7 @@ describe('CardViewBaseItemModel', () => {
const isValid = itemModel.isValid('test-against-this');
expect(isValid).toBe(false);
- expect(itemModel.getValidationErrors('test-against-this')).toEqual(['validator 1', 'validator 3']);
+ expect(itemModel.getValidationErrors('test-against-this')).toEqual([validator1, validator3 ]);
});
});
});
diff --git a/lib/core/card-view/models/card-view-baseitem.model.ts b/lib/core/card-view/models/card-view-baseitem.model.ts
index 5c09e0a217..87eccf25f2 100644
--- a/lib/core/card-view/models/card-view-baseitem.model.ts
+++ b/lib/core/card-view/models/card-view-baseitem.model.ts
@@ -16,6 +16,7 @@
*/
import { CardViewItemProperties, CardViewItemValidator } from '../interfaces/card-view.interfaces';
+import validatorsMap from '../validators/validators.map';
export abstract class CardViewBaseItemModel {
label: string;
@@ -38,6 +39,14 @@ export abstract class CardViewBaseItemModel {
this.icon = cardViewItemProperties.icon || '';
this.validators = cardViewItemProperties.validators || [];
this.data = cardViewItemProperties.data || null;
+
+ if (cardViewItemProperties?.constraints?.length ?? 0) {
+ for (const constraint of cardViewItemProperties.constraints) {
+ if (constraint.type !== 'LIST') {
+ this.validators.push(validatorsMap[constraint.type.toLowerCase()](constraint.parameters));
+ }
+ }
+ }
}
isEmpty(): boolean {
@@ -54,11 +63,11 @@ export abstract class CardViewBaseItemModel {
.reduce((isValidUntilNow, isValid) => isValidUntilNow && isValid, true);
}
- getValidationErrors(value): string[] {
+ getValidationErrors(value): CardViewItemValidator[] {
if (!this.validators.length) {
return [];
}
- return this.validators.filter((validator) => !validator.isValid(value)).map((validator) => validator.message);
+ return this.validators.filter((validator) => !validator.isValid(value)).map((validator) => validator);
}
}
diff --git a/lib/core/card-view/models/card-view-floatitem.model.spec.ts b/lib/core/card-view/models/card-view-floatitem.model.spec.ts
index 47fbe1acc2..b18a9534c4 100644
--- a/lib/core/card-view/models/card-view-floatitem.model.spec.ts
+++ b/lib/core/card-view/models/card-view-floatitem.model.spec.ts
@@ -56,4 +56,24 @@ describe('CardViewFloatItemModel', () => {
expect(itemModel.isValid('42.3')).toBe(true, 'For "42.3" it should be true');
expect(itemModel.isValid('test')).toBe(false, 'For "test" it should be false');
});
+
+ it('should validate based on defined constraints', () => {
+ const constrainedProperties = {
+ label: 'Tribe',
+ value: '42.42',
+ key: 'tribe',
+ dataType: 'd:float',
+ constraints: [{
+ id: 'constraint-id',
+ type: 'MINMAX',
+ parameters: { minValue: 10, maxValue: 40 }
+ }]
+ };
+
+ const itemModel = new CardViewFloatItemModel(constrainedProperties);
+ expect(itemModel.isValid(itemModel.value)).toBe(false, '42.42 is bigger than maximum allowed');
+
+ itemModel.value = '9.1';
+ expect(itemModel.isValid(itemModel.value)).toBe(false, '9.1 is less than minimum allowed');
+ });
});
diff --git a/lib/core/card-view/models/card-view-intitem.model.spec.ts b/lib/core/card-view/models/card-view-intitem.model.spec.ts
index 1e92e5e965..e49eb4ae45 100644
--- a/lib/core/card-view/models/card-view-intitem.model.spec.ts
+++ b/lib/core/card-view/models/card-view-intitem.model.spec.ts
@@ -56,4 +56,24 @@ describe('CardViewIntItemModel', () => {
expect(itemModel.isValid('42.3')).toBe(false, 'For "42.3" it should be false');
expect(itemModel.isValid('test')).toBe(false, 'For "test" it should be false');
});
+
+ it('should validate based on defined constraints', () => {
+ const constrainedProperties = {
+ label: 'Tribe',
+ value: '20',
+ key: 'tribe',
+ dataType: 'd:float',
+ constraints: [{
+ id: 'constraint-id',
+ type: 'MINMAX',
+ parameters: { minValue: 10, maxValue: 15 }
+ }]
+ };
+
+ const itemModel = new CardViewIntItemModel(constrainedProperties);
+ expect(itemModel.isValid(itemModel.value)).toBe(false, '20 is bigger than maximum allowed');
+
+ itemModel.value = '5';
+ expect(itemModel.isValid(itemModel.value)).toBe(false, '5 is less than minimum allowed');
+ });
});
diff --git a/lib/core/card-view/models/card-view-textitem.model.spec.ts b/lib/core/card-view/models/card-view-textitem.model.spec.ts
index a8126efc93..f3f97c20d8 100644
--- a/lib/core/card-view/models/card-view-textitem.model.spec.ts
+++ b/lib/core/card-view/models/card-view-textitem.model.spec.ts
@@ -85,4 +85,24 @@ describe('CardViewTextItemModel', () => {
expect(itemModel.displayValue).toBe('testpiped-testpiped-testpiped-Banuk-1-2-3');
});
});
+
+ it('should validate based on defined constraints', () => {
+ const constrainedProperties = {
+ label: 'Tribe',
+ value: 'test',
+ key: 'tribe',
+ dataType: 'd:text',
+ constraints: [{
+ id: 'constraint-id',
+ type: 'REGEX',
+ parameters: { expression: '^(?=.*test).*' }
+ }]
+ };
+
+ const itemModel = new CardViewTextItemModel(constrainedProperties);
+ expect(itemModel.isValid(itemModel.value)).toBe(true);
+
+ itemModel.value = 'dummy';
+ expect(itemModel.isValid(itemModel.value)).toBe(false, '`dummy` is not a constraint expression pattern');
+ });
});
diff --git a/lib/core/card-view/validators/card-view-item-length.valiator.ts b/lib/core/card-view/validators/card-view-item-length.valiator.ts
new file mode 100644
index 0000000000..a1f77d6f4c
--- /dev/null
+++ b/lib/core/card-view/validators/card-view-item-length.valiator.ts
@@ -0,0 +1,34 @@
+/*!
+ * @license
+ * Copyright 2019 Alfresco Software, Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { CardViewItemValidator } from '../interfaces/card-view.interfaces';
+
+export interface LengthValidatorParams {
+ minLength: number;
+ maxLength: number;
+}
+
+export class CardViewItemLengthValidator implements CardViewItemValidator {
+ message = 'CORE.CARDVIEW.VALIDATORS.LENGTH_VALIDATION_ERROR';
+
+ constructor(private minLength: number, private maxLength: number) {}
+
+ isValid(value: string = ''): boolean {
+ const stringLength = value.length;
+ return stringLength >= this.minLength && stringLength <= this.maxLength;
+ }
+}
diff --git a/lib/core/card-view/validators/card-view-item-match.valiator.ts b/lib/core/card-view/validators/card-view-item-match.valiator.ts
new file mode 100644
index 0000000000..7c148833a5
--- /dev/null
+++ b/lib/core/card-view/validators/card-view-item-match.valiator.ts
@@ -0,0 +1,34 @@
+/*!
+ * @license
+ * Copyright 2019 Alfresco Software, Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { CardViewItemValidator } from '../interfaces/card-view.interfaces';
+
+export interface MatchValidatorParams {
+ expression: string;
+ flags?: string;
+}
+
+export class CardViewItemMatchValidator implements CardViewItemValidator {
+ message = 'CORE.CARDVIEW.VALIDATORS.MATCH_VALIDATION_ERROR';
+
+ constructor(private expression: string, private flags?: string) {}
+
+ isValid(value: string): boolean {
+ const regex = new RegExp(this.expression, this.flags);
+ return value === '' || regex.test(value);
+ }
+}
diff --git a/lib/core/card-view/validators/card-view-item-minmax.valiator.ts b/lib/core/card-view/validators/card-view-item-minmax.valiator.ts
new file mode 100644
index 0000000000..e3d63f08ba
--- /dev/null
+++ b/lib/core/card-view/validators/card-view-item-minmax.valiator.ts
@@ -0,0 +1,37 @@
+/*!
+ * @license
+ * Copyright 2019 Alfresco Software, Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { CardViewItemValidator } from '../interfaces/card-view.interfaces';
+import { CardViewItemIntValidator } from './card-view-item-int.validator';
+
+export interface MinMaxValidatorParams {
+ minValue: number;
+ maxValue: number;
+}
+
+export class CardViewItemMinMaxValidator implements CardViewItemValidator {
+ message = 'CORE.CARDVIEW.VALIDATORS.MINMAX_VALIDATION_ERROR';
+ private intValidator: CardViewItemIntValidator;
+
+ constructor(private minValue: number, private maxValue: number) {
+ this.intValidator = new CardViewItemIntValidator();
+ }
+
+ isValid(value: number): boolean {
+ return this.intValidator.isValid(value) && (value >= this.minValue && value <= this.maxValue);
+ }
+}
diff --git a/lib/core/card-view/validators/card-view.validators.ts b/lib/core/card-view/validators/card-view.validators.ts
index 4b8e6d355f..b05b5e4999 100644
--- a/lib/core/card-view/validators/card-view.validators.ts
+++ b/lib/core/card-view/validators/card-view.validators.ts
@@ -17,3 +17,7 @@
export * from './card-view-item-int.validator';
export * from './card-view-item-float.validator';
+export * from './card-view-item-match.valiator';
+export * from './card-view-item-minmax.valiator';
+export * from './card-view-item-length.valiator';
+export * from './validators.map';
diff --git a/lib/core/card-view/validators/validators.map.ts b/lib/core/card-view/validators/validators.map.ts
new file mode 100644
index 0000000000..a916d53da2
--- /dev/null
+++ b/lib/core/card-view/validators/validators.map.ts
@@ -0,0 +1,27 @@
+/*!
+ * @license
+ * Copyright 2019 Alfresco Software, Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { CardViewItemMatchValidator, MatchValidatorParams } from './card-view-item-match.valiator';
+import { CardViewItemMinMaxValidator, MinMaxValidatorParams } from './card-view-item-minmax.valiator';
+import { CardViewItemLengthValidator, LengthValidatorParams } from './card-view-item-length.valiator';
+
+const validators = {
+ minmax: (parameters: MinMaxValidatorParams) => new CardViewItemMinMaxValidator(parameters.minValue, parameters.maxValue),
+ regex: (parameters: MatchValidatorParams) => new CardViewItemMatchValidator(parameters.expression),
+ length: (parameters: LengthValidatorParams) => new CardViewItemLengthValidator(parameters.minLength, parameters.maxLength)
+};
+export default validators;
diff --git a/lib/core/i18n/en.json b/lib/core/i18n/en.json
index da509c57a9..34745a1ec6 100644
--- a/lib/core/i18n/en.json
+++ b/lib/core/i18n/en.json
@@ -175,7 +175,10 @@
"NONE": "None",
"VALIDATORS": {
"FLOAT_VALIDATION_ERROR": "Use a number format",
- "INT_VALIDATION_ERROR": "Use an integer format"
+ "INT_VALIDATION_ERROR": "Use an integer format",
+ "LENGTH_VALIDATION_ERROR": "Value should be minimum {{ minLength }} and maximum {{ maxLength }} in length",
+ "MATCH_VALIDATION_ERROR": "Value doesn't match pattern: {{ expression }}",
+ "MINMAX_VALIDATION_ERROR": "Value should be between minimum {{ minValue }} and maximum {{ maxValue }}"
},
"MORE": "More"
},