Commit 669ad482 authored by MARCO Jonathan's avatar MARCO Jonathan
Browse files

ūüĒÄ Merge branch 'release/3.0.25'

parents 3bbbdab1 480fc0d4
Pipeline #64723 passed with stage
in 13 seconds
{
"name": "@vue-unistra/formbuilder",
"version": "3.0.24",
"version": "3.0.25",
"main": "dist/index.js",
"files": [
"dist/*",
......
<template>
<v-text-field
v-if="editorMode || exist"
v-show="editorMode || visible"
:id="field.id"
:key="key"
v-model="value"
:class="editorMode ? 'mx-2' : ''"
:type="field.type"
:label="label"
:placeholder="translated(fieldId, 'placeholder')"
:hint="translated(fieldId, 'hint')"
:persistent-hint="field.persistentHint"
:prefix="translated(fieldId, 'prefix')"
:suffix="translated(fieldId, 'suffix')"
:prepend-icon="field.prependIcon"
:append-icon="field.appendIcon"
:filled="field.filled"
:outlined="field.outlined"
:rounded="field.rounded"
:shaped="field.shaped"
:clearable="field.clearable"
:rules="rules"
:disabled="fieldOnReadOnly"
v-if="editorMode || exist"
v-show="editorMode || visible"
:id="field.id"
:key="key"
v-model="value"
:class="editorMode ? 'mx-2' : ''"
:type="field.type"
:label="label"
:placeholder="translated(fieldId, 'placeholder')"
:hint="translated(fieldId, 'hint')"
:persistent-hint="field.persistentHint"
:prefix="translated(fieldId, 'prefix')"
:suffix="translated(fieldId, 'suffix')"
:prepend-icon="field.prependIcon"
:append-icon="field.appendIcon"
:filled="field.filled"
:outlined="field.outlined"
:rounded="field.rounded"
:shaped="field.shaped"
:clearable="field.clearable"
:rules="rules"
:disabled="fieldOnReadOnly"
>
<template #append-outer>
<v-icon
v-if="field.repeatable"
@click="repeat"
v-if="field.repeatable"
@click="repeat"
>
mdi-plus
</v-icon>
......@@ -35,7 +35,7 @@
</template>
<script lang="ts">
import { usfFieldMixin, usfHandleConditional, usfDefaultTokenMixin } from '@form-plugin/mixins';
import {usfFieldMixin, usfHandleConditional, usfDefaultTokenMixin} from '@form-plugin/mixins';
import Vue from 'vue';
export default Vue.extend({
......@@ -68,13 +68,13 @@ export default Vue.extend({
},
minErrorMessage(): string {
return this.field.type === 'number'
? `${this.field.label} doit être supérieur ou égal à ${this.field.min}`
: `${this.field.label} doit comporter ${this.field.min} caractères ou plus`;
? `${this.field.label} doit être supérieur ou égal à ${this.field.min}`
: `${this.field.label} doit comporter ${this.field.min} caractères ou plus`;
},
maxErrorMessage(): string {
return this.field.type === 'number'
? `${this.field.label} doit être inférieur ou égal à ${this.field.max}`
: `${this.field.label} doit comporter ${this.field.max} caractères ou moins`;
? `${this.field.label} doit être inférieur ou égal à ${this.field.max}`
: `${this.field.label} doit comporter ${this.field.max} caractères ou moins`;
},
},
......@@ -87,35 +87,38 @@ export default Vue.extend({
methods: {
handleMin(): boolean | string {
const test = this.field.type === 'number'
? (!!this.value && parseFloat(this.value) >= parseFloat(this.field.min))
: (!!this.value && this.value.length >= this.field.min);
? (!!this.value && parseFloat(this.value) >= parseFloat(this.field.min))
: (!!this.value && this.value.length >= this.field.min);
return this.editorMode
|| !this.field.min
|| !this.value
|| test
|| this.minErrorMessage;
|| !this.field.min
|| !this.value
|| test
|| this.minErrorMessage;
},
handleMax(): boolean | string {
const test = this.field.type === 'number'
? (!!this.value && parseFloat(this.value) <= parseFloat(this.field.max))
: (!!this.value && this.value.length <= this.field.max);
? (!!this.value && parseFloat(this.value) <= parseFloat(this.field.max))
: (!!this.value && this.value.length <= this.field.max);
return this.editorMode
|| !this.field.max
|| !this.value
|| test
|| this.maxErrorMessage;
|| !this.field.max
|| !this.value
|| test
|| this.maxErrorMessage;
},
handleEmail(): boolean | string {
return this.editorMode
|| !this.value
|| /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(this.value) // eslint-disable-line no-useless-escape
|| 'Veuillez saisir une adresse électronique valide';
|| !this.value
|| /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(this.value) // eslint-disable-line no-useless-escape
|| 'Veuillez saisir une adresse électronique valide';
},
numberTypeError(): boolean | string {
return this.value === undefined || !isNaN(parseFloat(this.value)) || 'La valeur doit être un nombre';
return this.value === undefined
|| this.value === null
|| !isNaN(parseFloat(this.value))
|| 'La valeur doit être un nombre';
},
},
});
......
<template>
<v-dialog
persistent
max-width="900"
:value="displayed"
@input="$emit('update:displayed', $event)"
persistent
max-width="900"
:value="displayed"
@input="$emit('update:displayed', $event)"
>
<v-card>
<v-toolbar color="primary" flat :dark="primaryIsDark">
......@@ -12,11 +12,11 @@
<v-card-text>
<header>
<v-select
v-model="typeSelected"
:items="types"
:label="_uct('builder.tabs.conditional.types.label')"
:error-messages="typeErrorMessage"
@change="typeErrorMessage = null"
v-model="typeSelected"
:items="types"
:label="_uct('builder.tabs.conditional.types.label')"
:error-messages="typeErrorMessage"
@change="typeErrorMessage = null"
/>
<v-btn @click="onAddItem('&&')" color="primary" outlined>ET</v-btn>
......@@ -26,11 +26,11 @@
<v-tooltip bottom>
<template v-slot:activator="{on, attrs}">
<v-btn
@click="onEmptyConditions"
color="primary"
outlined
v-on="on"
v-bind="attrs"
@click="onEmptyConditions"
color="primary"
outlined
v-on="on"
v-bind="attrs"
>
<v-icon>mdi-delete-empty-outline</v-icon>
</v-btn>
......@@ -39,16 +39,16 @@
</v-tooltip>
<usf-tab-conditional-basic-select
:field="field"
property="exist"
:other-inputs="conditionalBasicItems"
@add="onAddItemLinked"
:field="field"
property="exist"
:other-inputs="conditionalBasicItems"
@add="onAddItemLinked"
/>
</header>
<usf-tab-conditional-draggable-container :items="items" @move-item="onMoveItem" />
<usf-tab-conditional-draggable-container :items="items" @move-item="onMoveItem"/>
</v-card-text>
<v-card-actions>
<v-spacer />
<v-spacer/>
<v-btn @click="onCloseDialog" color="primary" outlined>
{{ _uct('builder.tabs.conditional.actions.cancel') }}
</v-btn>
......@@ -61,16 +61,16 @@
</template>
<script lang="ts">
import Vue, { PropType } from 'vue';
import { UsfTabConditionalBasicSelect } from '../UsfTabConditionalBasicSelect';
import { InputSelectionItem } from '@form-plugin/components/formbuilder/settings/tabs/conditional/UsfTabConditionalBasicSelect';
import { Field, FieldCondition } from '#form-plugin/models/form';
import { mapGetters } from 'vuex';
import { UsfTabConditionalDraggableContainer } from '../UsfTabConditionalDraggableContainer';
import { idGenerator } from '@form-plugin/store/modules/form/actions';
import { vueDraggableChangeEvent } from '#form-plugin/utils/vueDraggable';
import Vue, {PropType} from 'vue';
import {UsfTabConditionalBasicSelect} from '../UsfTabConditionalBasicSelect';
import {InputSelectionItem} from '@form-plugin/components/formbuilder/settings/tabs/conditional/UsfTabConditionalBasicSelect';
import {Field, FieldCondition} from '#form-plugin/models/form';
import {mapActions, mapGetters} from 'vuex';
import {UsfTabConditionalDraggableContainer} from '../UsfTabConditionalDraggableContainer';
import {idGenerator} from '@form-plugin/store/modules/form/actions';
import {vueDraggableChangeEvent} from '#form-plugin/utils/vueDraggable';
import ConditionService from '@form-plugin/services/ConditionService';
import { Control } from '#form-plugin/models/control';
import {Control} from '#form-plugin/models/control';
interface ComponentData {
items: FieldCondition[];
......@@ -111,7 +111,7 @@ export default Vue.extend({
},
},
data: function(): ComponentData {
data: function (): ComponentData {
return {
items: [],
types: [
......@@ -150,30 +150,30 @@ export default Vue.extend({
const templatesNames: string[] = this.templatesNames;
return templatesNames
.map<InputSelectionItem[]>((template) => {
return [
{ header: this._uct(`builder.tabs.conditional.fieldSelection.${template}`) },
...this.templateAttributes(template),
];
})
.reduce(
(acc: InputSelectionItem[], current: InputSelectionItem[]) => acc.concat(current),
[],
)
.concat([{ divider: true }]);
.map<InputSelectionItem[]>((template) => {
return [
{header: this._uct(`builder.tabs.conditional.fieldSelection.${template}`)},
...this.templateAttributes(template),
];
})
.reduce(
(acc: InputSelectionItem[], current: InputSelectionItem[]) => acc.concat(current),
[],
)
.concat([{divider: true}]);
},
otherInputs(): InputSelectionItem[] {
const fieldsArray: Field[] = this.getFieldsArray;
return [
{ header: this._uct('builder.tabs.conditional.fieldSelection.otherFields') },
{header: this._uct('builder.tabs.conditional.fieldSelection.otherFields')},
...fieldsArray
.filter((field: Field) => {
if (field.id === this.field.id) return false;
.filter((field: Field) => {
if (field.id === this.field.id) return false;
return this.getControlById(field.component).usfType === 'input';
})
.map<InputSelectionItem>(({ name, id }: Field) => ({ name: name || id, id })),
return this.getControlById(field.component).usfType === 'input';
})
.map<InputSelectionItem>(({name, id}: Field) => ({name: name || id, id})),
];
},
conditionalBasicItems(): InputSelectionItem[] {
......@@ -185,13 +185,12 @@ export default Vue.extend({
},
watch: {
displayed: function() {
displayed: function () {
if (this.displayed && this.type) {
this.typeSelected = this.type;
this.items.splice(0, this.items.length);
const conditions = ConditionService.getConditions(this.field.conditional.basic[this.type]);
console.log(conditions);
if (conditions) {
conditions.forEach((condition) => {
this.items.push(condition);
......@@ -202,6 +201,7 @@ export default Vue.extend({
},
methods: {
...mapActions('form', ['updateField', 'getFieldById']),
/**
* Add an chip item in the text area container.
*
......@@ -222,7 +222,18 @@ export default Vue.extend({
* Empty the list of the items.
*/
onEmptyConditions(): void {
// TODO: vider la liste
this.updateField({
id: this.tabContext.fieldId,
attribute: 'conditional',
value: {
basic: {
...this.getFieldById(this.tabContext.fieldId)?.conditional?.basic,
[this.type]: [],
},
},
});
this.items.splice(0, this.items.length)
},
/**
* Used when user clicks on the "Valid" button.
......@@ -257,7 +268,7 @@ export default Vue.extend({
* @param {number} newIndex
* @param {any} element
*/
onMoveItem({ moved: { oldIndex, newIndex, element } }: vueDraggableChangeEvent) {
onMoveItem({moved: {oldIndex, newIndex, element}}: vueDraggableChangeEvent) {
this.items.splice(oldIndex, 1);
this.items.splice(newIndex, 0, element);
},
......@@ -269,30 +280,30 @@ export default Vue.extend({
* @param {string | null} operatorSelected
*/
onAddItemLinked(
{
itemLinked,
valueSelected,
operatorSelected,
}: { itemLinked: string, valueSelected: string | string[], operatorSelected: null | string },
{
itemLinked,
valueSelected,
operatorSelected,
}: { itemLinked: string, valueSelected: string | string[], operatorSelected: null | string },
): void {
if (typeof valueSelected === 'string') {
this.onAddItem(
valueSelected,
itemLinked.startsWith('user.') ? 'token' : 'field',
itemLinked,
valueSelected,
itemLinked.startsWith('user.') ? 'token' : 'field',
itemLinked,
);
} else if (Array.isArray(valueSelected)) {
valueSelected.forEach((value: string, index: number) => {
this.onAddItem(
value,
'field',
itemLinked,
value,
'field',
itemLinked,
);
if (index !== valueSelected.length - 1) {
this.onAddItem(
operatorSelected || '||',
'item',
operatorSelected || '||',
'item',
);
}
});
......
......@@ -131,7 +131,7 @@
<template v-slot:item.displayedBy="{ item }">
<v-edit-dialog :return-value="item.displayedBy">
<span v-if="Array.isArray(item.displayedBy) && item.displayedBy.length">
{{ getOption(item.displayedBy[0]).label }}
{{ getLabelOption(item.displayedBy[0]) || item.displayedBy[0] }}
<span v-if="item.displayedBy.length > 1" class="grey--text caption">
{{ `(+${item.displayedBy.length - 1} others)` }}
</span>
......@@ -346,9 +346,12 @@ export default Vue.extend({
return itemLabel.toLowerCase().includes(search)
},
getOption(id) {
getOption(id): Option {
return this.$store.getters['form/getOptionByIdOrValue'](id);
},
getLabelOption(id): undefined | string {
return this.getOption(id)?.label
},
onUpdateDefaultOption(newValue, item) {
this.updateDefaultOption({
newDefaultOptionId: item.id,
......
import {ConditionItemTranslated, ConditionTranslated} from '#form-plugin/models/form';
import {isPlainObject, isString} from 'lodash/fp';
import {isPlainObject, isString, isArray} from 'lodash/fp';
import store from '@form-plugin/store';
export const check = (conditions: ConditionTranslated[] | undefined): boolean => {
......@@ -58,7 +58,7 @@ export const check = (conditions: ConditionTranslated[] | undefined): boolean =>
return conditionsVerified;
}
return false
return false;
};
/**
......@@ -84,13 +84,34 @@ export function fieldCheck(condition: ConditionItemTranslated, conditions: Condi
} else {
const linkedInputValue = store.getters['submission/getValue'](store.getters['form/getFieldById'](condition.id).name);
if (isString(condition.value) && isPlainObject(linkedInputValue) && isString(linkedInputValue.value)) {
if (isArray(condition?.value) && isPlainObject(linkedInputValue) && isArray(linkedInputValue?.value)) {
return linkedInputValue.value.some((value: string) => {
return condition.value.includes(value);
});
}
if (isArray(condition?.value) && isPlainObject(linkedInputValue) && isString(linkedInputValue?.value)) {
return condition.value.includes(linkedInputValue.value);
}
if (isArray(condition?.value) && isString(linkedInputValue)) {
return condition.value.includes(linkedInputValue);
}
if (isString(condition?.value) && isPlainObject(linkedInputValue) && isArray(linkedInputValue?.value)) {
return linkedInputValue.value.some((value: string) => {
return condition.value === value;
});
}
if (isString(condition?.value) && isPlainObject(linkedInputValue) && isString(linkedInputValue?.value)) {
return condition.value === linkedInputValue.value;
}
if (isString(condition.value)) {
if (isString(condition?.value)) {
return condition.value === String(linkedInputValue);
}
}
return false
return false;
}
......@@ -76,6 +76,30 @@ const insertTranslation = (
return i;
};
const conditionsCheckOneByOne = (
conditions: FieldCondition[],
i: number,
parentArray: ConditionTranslated[],
) => {
if (conditions[i].type === 'item' && conditions[i].value === '(') {
i = subConditionInsert(conditions, i, parentArray);
} else if (conditionTest(conditions, i)) {
i = insertTranslation(conditions, i, parentArray);
} else if (conditionWithSubConditionAfter(conditions, i)) {
const subConditionArray: ConditionTranslated[] = [];
const subConditionIFinal = subConditionInsert(conditions, i + 2, subConditionArray);
parentArray.push({
fieldA: {id: <string>conditions[i].id, value: <string>conditions[i].value},
operator: <'&&' | '||'>conditions[i + 1].value,
fieldB: {id: <string>subConditionArray[0]?.child?.id, value: 'child'},
});
parentArray.push(subConditionArray[0]);
i = subConditionIFinal;
}
return i;
};
/**
* Translates the sub condition and returns this with the index.
*
......@@ -96,21 +120,7 @@ function translateSubCondition(
break;
}
if (conditions[i].type === 'item' && conditions[i].value === '(') {
i = subConditionInsert(conditions, i, subConditions);
} else if (conditionTest(conditions, i)) {
i = insertTranslation(conditions, i, subConditions);
} else if (conditionWithSubConditionAfter(conditions, i)) {
const subConditionArray: ConditionTranslated[] = [];
const subConditionIFinal = subConditionInsert(conditions, i + 2, subConditionArray);
subConditions.push({
fieldA: {id: <string>conditions[i].id, value: <string>conditions[i].value},
operator: <'&&' | '||'>conditions[i + 1].value,
fieldB: {id: <string>subConditionArray[0]?.child?.id, value: 'child'},
});
subConditions.push(subConditionArray[0])
i = subConditionIFinal
}
i = conditionsCheckOneByOne(conditions, i, subConditions);
}
return {subConditions, i: finalIndex};
......@@ -191,11 +201,7 @@ class ConditionService {
});
} else {
for (let i = 0; i < conditions.length; i++) {
if (conditions[i].type === 'item' && conditions[i].value === '(') {
i = subConditionInsert(conditions, i, translation);
} else if (conditionTest(conditions, i)) {
i = insertTranslation(conditions, i, translation);
}
i = conditionsCheckOneByOne(conditions, i, translation,);
}
}
......
......@@ -68,7 +68,7 @@ const formField = new schema.Entity('fields', {}, {
}
const oldConditionTranslated = ({ id, value }: OldCondition): ConditionTranslated[] => {
if (Array.isArray(value)) {
if (Array.isArray(value) && value.length > 1) {
const conditionsTranslated: ConditionTranslated[] = [];
value.reduce<ConditionTranslated[]>(((conditions, condition, i) => {
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment