diff options
Diffstat (limited to 'apps/workflowengine/src')
15 files changed, 273 insertions, 147 deletions
diff --git a/apps/workflowengine/src/components/Check.vue b/apps/workflowengine/src/components/Check.vue index 4f68e394495..10828c1dd8a 100644 --- a/apps/workflowengine/src/components/Check.vue +++ b/apps/workflowengine/src/components/Check.vue @@ -11,6 +11,7 @@ <Multiselect v-model="currentOperator" :disabled="!currentOption" :options="operators" + class="comparator" label="name" track-by="operator" :allow-empty="false" @@ -21,6 +22,7 @@ v-model="check.value" :disabled="!currentOption" :check="check" + class="option" @input="updateCheck" @valid="(valid=true) && validate()" @invalid="(valid=false) && validate()" /> @@ -30,9 +32,10 @@ :class="{ invalid: !valid }" :disabled="!currentOption" :placeholder="valuePlaceholder" + class="option" @input="updateCheck"> <Actions v-if="deleteVisible || !currentOption"> - <ActionButton icon="icon-delete" @click="$emit('remove')" /> + <ActionButton icon="icon-close" @click="$emit('remove')" /> </Actions> </div> </template> @@ -73,17 +76,16 @@ export default { } }, computed: { - Checks() { + checks() { return this.$store.getters.getChecksForEntity(this.rule.entity) }, operators() { if (!this.currentOption) { return [] } - return this.Checks[this.currentOption.class].operators + return this.checks[this.currentOption.class].operators }, currentComponent() { if (!this.currentOption) { return [] } - const currentComponent = this.Checks[this.currentOption.class].component - return currentComponent + return this.checks[this.currentOption.class].component }, valuePlaceholder() { if (this.currentOption && this.currentOption.placeholder) { @@ -98,8 +100,8 @@ export default { } }, mounted() { - this.options = Object.values(this.Checks) - this.currentOption = this.Checks[this.check.class] + this.options = Object.values(this.checks) + this.currentOption = this.checks[this.check.class] this.currentOperator = this.operators.find((operator) => operator.operator === this.check.operator) }, methods: { @@ -111,13 +113,8 @@ export default { }, validate() { if (this.currentOption && this.currentOption.validate) { - if (this.currentOption.validate(this.check)) { - this.valid = true - } else { - this.valid = false - } + this.valid = !!this.currentOption.validate(this.check) } - this.$store.dispatch('setValid', { rule: this.rule, valid: this.rule.valid && this.valid }) return this.valid }, updateCheck() { @@ -128,7 +125,7 @@ export default { this.check.operator = this.currentOperator.operator if (!this.validate()) { - return + this.check.invalid = !this.valid } this.$emit('update', this.check) } @@ -142,14 +139,30 @@ export default { flex-wrap: wrap; width: 100%; padding-right: 20px; - & > *:not(.icon-delete) { + & > *:not(.close) { width: 180px; } + & > .comparator { + min-width: 130px; + width: 130px; + } + & > .option { + min-width: 230px; + width: 230px; + } & > .multiselect, & > input[type=text] { margin-right: 5px; margin-bottom: 5px; } + + .multiselect::v-deep .multiselect__content-wrapper li>span, + .multiselect::v-deep .multiselect__single { + display: block; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } } input[type=text] { margin: 0; @@ -157,14 +170,12 @@ export default { ::placeholder { font-size: 10px; } - .icon-delete { + button.action-item.action-item--single.icon-close { + height: 44px; + width: 44px; margin-top: -5px; margin-bottom: -5px; } - button.action-item.action-item--single.icon-delete { - height: 34px; - width: 34px; - } .invalid { border: 1px solid var(--color-error) !important; } diff --git a/apps/workflowengine/src/components/Checks/FileMimeType.vue b/apps/workflowengine/src/components/Checks/FileMimeType.vue index 2f2487c9adf..e91636f5130 100644 --- a/apps/workflowengine/src/components/Checks/FileMimeType.vue +++ b/apps/workflowengine/src/components/Checks/FileMimeType.vue @@ -32,17 +32,20 @@ :tagging="false" @input="setValue"> <template slot="singleLabel" slot-scope="props"> - <span class="option__icon" :class="props.option.icon" /> + <span v-if="props.option.icon" class="option__icon" :class="props.option.icon" /> + <img v-else :src="props.option.iconUrl"> <span class="option__title option__title_single">{{ props.option.label }}</span> </template> <template slot="option" slot-scope="props"> - <span class="option__icon" :class="props.option.icon" /> + <span v-if="props.option.icon" class="option__icon" :class="props.option.icon" /> + <img v-else :src="props.option.iconUrl"> <span class="option__title">{{ props.option.label }}</span> </template> </Multiselect> <input v-if="!isPredefined" type="text" :value="currentValue.pattern" + :placeholder="t('workflowengine', 'e.g. httpd/unix-directory')" @input="updateCustom"> </div> </template> @@ -68,12 +71,12 @@ export default { pattern: '/image\\/.*/' }, { - icon: 'icon-category-office', + iconUrl: OC.imagePath('core', 'filetypes/x-office-document'), label: t('workflowengine', 'Office documents'), pattern: '/(vnd\\.(ms-|openxmlformats-).*))$/' }, { - icon: 'icon-filetype-file', + iconUrl: OC.imagePath('core', 'filetypes/application-pdf'), label: t('workflowengine', 'PDF documents'), pattern: 'application/pdf' } @@ -130,3 +133,15 @@ export default { } } </script> +<style scoped> + .multiselect, input[type='text'] { + width: 100%; + } + .multiselect >>> .multiselect__content-wrapper li>span, + .multiselect >>> .multiselect__single { + display: flex; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } +</style> diff --git a/apps/workflowengine/src/components/Checks/FileSystemTag.vue b/apps/workflowengine/src/components/Checks/FileSystemTag.vue index d3fd440f1b1..268f8c4e33f 100644 --- a/apps/workflowengine/src/components/Checks/FileSystemTag.vue +++ b/apps/workflowengine/src/components/Checks/FileSystemTag.vue @@ -23,7 +23,7 @@ <template> <MultiselectTag v-model="newValue" :multiple="false" - label="Select a tag" + :label="t('workflowengine', 'Select a tag')" @input="update" /> </template> diff --git a/apps/workflowengine/src/components/Checks/MultiselectTag/MultiselectTag.vue b/apps/workflowengine/src/components/Checks/MultiselectTag/MultiselectTag.vue index c58f53c8e97..804025dc0e5 100644 --- a/apps/workflowengine/src/components/Checks/MultiselectTag/MultiselectTag.vue +++ b/apps/workflowengine/src/components/Checks/MultiselectTag/MultiselectTag.vue @@ -56,10 +56,8 @@ export default { required: true }, value: { - type: Array, - default() { - return [] - } + type: [String, Array], + default: null }, disabled: { type: Boolean, @@ -67,7 +65,7 @@ export default { }, multiple: { type: Boolean, - default: true + default: false } }, data() { diff --git a/apps/workflowengine/src/components/Checks/RequestTime.vue b/apps/workflowengine/src/components/Checks/RequestTime.vue index 1d7950f64f8..26a4907fd18 100644 --- a/apps/workflowengine/src/components/Checks/RequestTime.vue +++ b/apps/workflowengine/src/components/Checks/RequestTime.vue @@ -1,15 +1,21 @@ <template> <div class="timeslot"> - <Multiselect v-model="newValue.timezone" :options="timezones" @input="update" /> <input v-model="newValue.startTime" type="text" class="timeslot--start" - placeholder="08:00" + placeholder="e.g. 08:00" @input="update"> <input v-model="newValue.endTime" type="text" - placeholder="18:00" + placeholder="e.g. 18:00" @input="update"> + <p v-if="!valid" class="invalid-hint"> + {{ t('workflowengine', 'Please enter a valid time span') }} + </p> + <Multiselect v-show="valid" + v-model="newValue.timezone" + :options="timezones" + @input="update" /> </div> </template> @@ -30,7 +36,7 @@ export default { props: { value: { type: String, - default: '1 MB' + default: '' } }, data() { @@ -46,14 +52,17 @@ export default { }, methods: { updateInternalValue(value) { - var data = JSON.parse(value) - var startTime = data[0].split(' ', 2)[0] - var endTime = data[1].split(' ', 2)[0] - var timezone = data[0].split(' ', 2)[1] - this.newValue = { - startTime: startTime, - endTime: endTime, - timezone: timezone + try { + const data = JSON.parse(value) + if (data.length === 2) { + this.newValue = { + startTime: data[0].split(' ', 2)[0], + endTime: data[1].split(' ', 2)[0], + timezone: data[0].split(' ', 2)[1] + } + } + } catch (e) { + // ignore invalid values } }, validate() { @@ -86,14 +95,23 @@ export default { margin-bottom: 5px; } + .multiselect::v-deep .multiselect__tags:not(:hover):not(:focus):not(:active) { + border: 1px solid transparent; + } + input[type=text] { width: 50%; margin: 0; margin-bottom: 5px; + &.timeslot--start { margin-right: 5px; width: calc(50% - 5px); } } + + .invalid-hint { + color: var(--color-text-maxcontrast); + } } </style> diff --git a/apps/workflowengine/src/components/Checks/RequestURL.vue b/apps/workflowengine/src/components/Checks/RequestURL.vue index 5f337a669bd..f63f7d29114 100644 --- a/apps/workflowengine/src/components/Checks/RequestURL.vue +++ b/apps/workflowengine/src/components/Checks/RequestURL.vue @@ -137,3 +137,8 @@ export default { } } </script> +<style scoped> + .multiselect, input[type='text'] { + width: 100%; + } +</style> diff --git a/apps/workflowengine/src/components/Checks/RequestUserAgent.vue b/apps/workflowengine/src/components/Checks/RequestUserAgent.vue index f06aac2e8f7..4e0edb6bf49 100644 --- a/apps/workflowengine/src/components/Checks/RequestUserAgent.vue +++ b/apps/workflowengine/src/components/Checks/RequestUserAgent.vue @@ -27,19 +27,22 @@ :placeholder="t('workflowengine', 'Select a user agent')" label="label" track-by="pattern" - group-values="children" - group-label="label" :options="options" :multiple="false" :tagging="false" @input="setValue"> <template slot="singleLabel" slot-scope="props"> <span class="option__icon" :class="props.option.icon" /> - <span class="option__title option__title_single">{{ props.option.label }}</span> + <!-- v-html can be used here as t() always passes our translated strings though DOMPurify.sanitize --> + <!-- eslint-disable-next-line vue/no-v-html --> + <span class="option__title option__title_single" v-html="props.option.label" /> </template> <template slot="option" slot-scope="props"> <span class="option__icon" :class="props.option.icon" /> - <span class="option__title">{{ props.option.label }} {{ props.option.$groupLabel }}</span> + <!-- eslint-disable-next-line vue/no-v-html --> + <span v-if="props.option.$groupLabel" class="option__title" v-html="props.option.$groupLabel" /> + <!-- eslint-disable-next-line vue/no-v-html --> + <span v-else class="option__title" v-html="props.option.label" /> </template> </Multiselect> <input v-if="!isPredefined" @@ -65,15 +68,10 @@ export default { return { newValue: '', predefinedTypes: [ - { - label: t('workflowengine', 'Sync clients'), - children: [ - { pattern: 'android', label: t('workflowengine', 'Android client'), icon: 'icon-phone' }, - { pattern: 'ios', label: t('workflowengine', 'iOS client'), icon: 'icon-phone' }, - { pattern: 'desktop', label: t('workflowengine', 'Desktop client'), icon: 'icon-desktop' }, - { pattern: 'mail', label: t('workflowengine', 'Thunderbird & Outlook addons'), icon: 'icon-mail' } - ] - } + { pattern: 'android', label: t('workflowengine', 'Android client'), icon: 'icon-phone' }, + { pattern: 'ios', label: t('workflowengine', 'iOS client'), icon: 'icon-phone' }, + { pattern: 'desktop', label: t('workflowengine', 'Desktop client'), icon: 'icon-desktop' }, + { pattern: 'mail', label: t('workflowengine', 'Thunderbird & Outlook addons'), icon: 'icon-mail' } ] } }, @@ -83,8 +81,6 @@ export default { }, matchingPredefined() { return this.predefinedTypes - .map(groups => groups.children) - .flat() .find((type) => this.newValue === type.pattern) }, isPredefined() { @@ -92,14 +88,9 @@ export default { }, customValue() { return { - label: t('workflowengine', 'Others'), - children: [ - { - icon: 'icon-settings-dark', - label: t('workflowengine', 'Custom user agent'), - pattern: '' - } - ] + icon: 'icon-settings-dark', + label: t('workflowengine', 'Custom user agent'), + pattern: '' } }, currentValue() { @@ -115,8 +106,8 @@ export default { }, methods: { validateRegex(string) { - var regexRegex = /^\/(.*)\/([gui]{0,3})$/ - var result = regexRegex.exec(string) + const regexRegex = /^\/(.*)\/([gui]{0,3})$/ + const result = regexRegex.exec(string) return result !== null }, setValue(value) { @@ -133,3 +124,32 @@ export default { } } </script> +<style scoped> + .multiselect, input[type='text'] { + width: 100%; + } + + .multiselect .multiselect__content-wrapper li>span { + display: flex; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + .multiselect::v-deep .multiselect__single { + width: 100%; + display: flex; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + .option__icon { + display: inline-block; + min-width: 30px; + background-position: left; + } + .option__title { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } +</style> diff --git a/apps/workflowengine/src/components/Checks/RequestUserGroup.vue b/apps/workflowengine/src/components/Checks/RequestUserGroup.vue index 1ab06d9b84d..f254a5185f6 100644 --- a/apps/workflowengine/src/components/Checks/RequestUserGroup.vue +++ b/apps/workflowengine/src/components/Checks/RequestUserGroup.vue @@ -22,56 +22,91 @@ <template> <div> - <Multiselect v-model="newValue" - :class="{'icon-loading-small': groups.length === 0}" + <Multiselect :value="currentValue" + :loading="status.isLoading && groups.length === 0" :options="groups" :multiple="false" label="displayname" track-by="id" - @input="setValue" /> + @search-change="searchAsync" + @input="(value) => $emit('input', value.id)" /> </div> </template> <script> import { Multiselect } from 'nextcloud-vue/dist/Components/Multiselect' -import valueMixin from '../../mixins/valueMixin' import axios from '@nextcloud/axios' + +const groups = [] +const status = { + isLoading: false +} + export default { name: 'RequestUserGroup', components: { Multiselect }, - mixins: [ - valueMixin - ], + props: { + value: { + type: String, + default: '' + }, + check: { + type: Object, + default: () => { return {} } + } + }, data() { return { - groups: [] + groups: groups, + status: status } }, - beforeMount() { - axios.get(OC.linkToOCS('cloud', 2) + 'groups').then((response) => { - this.groups = response.data.ocs.data.groups.reduce((obj, item) => { - obj.push({ - id: item, - displayname: item - }) - return obj - }, []) - this.updateInternalValue(this.value) - }, (error) => { - console.error('Error while loading group list', error.response) - }) + computed: { + currentValue() { + return this.groups.find(group => group.id === this.value) || null + } + }, + async mounted() { + if (this.groups.length === 0) { + await this.searchAsync('') + } + if (this.currentValue === null) { + await this.searchAsync(this.value) + } }, methods: { - updateInternalValue() { - this.newValue = this.groups.find(group => group.id === this.value) || null + searchAsync(searchQuery) { + if (this.status.isLoading) { + return + } + + this.status.isLoading = true + return axios.get(OC.linkToOCS('cloud', 2) + 'groups?limit=20&search=' + encodeURI(searchQuery)).then((response) => { + response.data.ocs.data.groups.reduce((obj, item) => { + obj.push({ + id: item, + displayname: item + }) + return obj + }, []).forEach((group) => this.addGroup(group)) + this.status.isLoading = false + }, (error) => { + console.error('Error while loading group list', error.response) + }) }, - setValue(value) { - if (value !== null) { - this.$emit('input', this.newValue.id) + addGroup(group) { + const index = this.groups.findIndex((item) => item.id === group.id) + if (index === -1) { + this.groups.push(group) } } } } </script> +<style scoped> + .multiselect { + width: 100%; + } +</style> diff --git a/apps/workflowengine/src/components/Checks/file.js b/apps/workflowengine/src/components/Checks/file.js index 76f998da007..0cc49c2d4c1 100644 --- a/apps/workflowengine/src/components/Checks/file.js +++ b/apps/workflowengine/src/components/Checks/file.js @@ -65,7 +65,7 @@ const FileChecks = [ { operator: 'greater', name: t('workflowengine', 'greater') } ], placeholder: (check) => '5 MB', - validate: (check) => check.value.match(/^[0-9]+[ ]?[kmgt]?b$/i) !== null + validate: (check) => check.value ? check.value.match(/^[0-9]+[ ]?[kmgt]?b$/i) !== null : false }, { diff --git a/apps/workflowengine/src/components/Event.vue b/apps/workflowengine/src/components/Event.vue index a06835f5f82..97608fde062 100644 --- a/apps/workflowengine/src/components/Event.vue +++ b/apps/workflowengine/src/components/Event.vue @@ -1,5 +1,5 @@ <template> - <div> + <div class="event"> <div v-if="operation.isComplex && operation.fixedEntity !== ''" class="isComplex"> <img class="option__icon" :src="entity.icon"> <span class="option__title option__title_single">{{ operation.triggerHint }}</span> @@ -7,14 +7,16 @@ <Multiselect v-else :value="currentEvent" :options="allEvents" - label="eventName" track-by="id" - :allow-empty="false" + :multiple="true" + :auto-limit="false" :disabled="allEvents.length <= 1" @input="updateEvent"> - <template slot="singleLabel" slot-scope="props"> - <img class="option__icon" :src="props.option.entity.icon"> - <span class="option__title option__title_single">{{ props.option.displayName }}</span> + <template slot="selection" slot-scope="{ values, search, isOpen }"> + <div v-if="values.length && !isOpen" class="eventlist"> + <img class="option__icon" :src="values[0].entity.icon"> + <span v-for="(value, index) in values" :key="value.id" class="text option__title option__title_single">{{ value.displayName }} <span v-if="index+1 < values.length">, </span></span> + </div> </template> <template slot="option" slot-scope="props"> <img class="option__icon" :src="props.option.entity.icon"> @@ -49,23 +51,22 @@ export default { return this.$store.getters.getEventsForOperation(this.operation) }, currentEvent() { - if (!this.rule.events) { - return this.allEvents.length > 0 ? this.allEvents[0] : null - } - return this.allEvents.find(event => event.entity.id === this.rule.entity && this.rule.events.indexOf(event.eventName) !== -1) + return this.allEvents.filter(event => event.entity.id === this.rule.entity && this.rule.events.indexOf(event.eventName) !== -1) } }, methods: { - updateEvent(event) { - this.$set(this.rule, 'entity', event.entity.id) - this.$set(this.rule, 'events', [event.eventName]) - this.$store.dispatch('updateRule', this.rule) + updateEvent(events) { + this.$set(this.rule, 'events', events.map(event => event.eventName)) + this.$emit('update', this.rule) } } } </script> <style scoped lang="scss"> + .event { + margin-bottom: 5px; + } .isComplex { img { vertical-align: top; @@ -78,6 +79,11 @@ export default { display: inline-block; } } + .multiselect { + width: 100%; + max-width: 550px; + margin-top: 4px; + } .multiselect::v-deep .multiselect__single { display: flex; } @@ -86,8 +92,10 @@ export default { border: 1px solid transparent; } - .multiselect::v-deep .multiselect__tags .multiselect__single { + .multiselect::v-deep .multiselect__tags { background-color: var(--color-main-background) !important; + height: auto; + min-height: 34px; } .multiselect:not(.multiselect--disabled)::v-deep .multiselect__tags .multiselect__single { @@ -107,4 +115,9 @@ export default { .option__title_single { font-weight: 900; } + + .eventlist img, + .eventlist .text { + vertical-align: middle; + } </style> diff --git a/apps/workflowengine/src/components/Operation.vue b/apps/workflowengine/src/components/Operation.vue index ad44d376934..ae0a67ae53d 100644 --- a/apps/workflowengine/src/components/Operation.vue +++ b/apps/workflowengine/src/components/Operation.vue @@ -55,6 +55,7 @@ export default { .actions__item_options { width: 100%; margin-top: 10px; + padding-left: 60px; } h3, small { padding: 6px; @@ -63,7 +64,7 @@ export default { h3 { margin: 0; padding: 0; - font-weight: 500; + font-weight: 600; } small { font-size: 10pt; @@ -82,6 +83,7 @@ export default { .actions__item__description { padding-top: 5px; text-align: left; + width: calc(100% - 105px); small { padding: 0; } diff --git a/apps/workflowengine/src/components/Rule.vue b/apps/workflowengine/src/components/Rule.vue index 2be9b0fc5e5..703b7832afa 100644 --- a/apps/workflowengine/src/components/Rule.vue +++ b/apps/workflowengine/src/components/Rule.vue @@ -1,5 +1,5 @@ <template> - <div class="section rule" :style="{ borderLeftColor: operation.color || '' }"> + <div v-if="operation" class="section rule" :style="{ borderLeftColor: operation.color || '' }"> <div class="trigger"> <p> <span>{{ t('workflowengine', 'When') }}</span> @@ -23,28 +23,26 @@ </div> <div class="flow-icon icon-confirm" /> <div class="action"> - <div class="buttons"> - <Actions> - <ActionButton v-if="rule.id < -1" icon="icon-close" @click="cancelRule"> - {{ t('workflowengine', 'Cancel rule creation') }} - </ActionButton> - <ActionButton v-else icon="icon-close" @click="deleteRule"> - {{ t('workflowengine', 'Remove rule') }} - </ActionButton> - </Actions> - </div> <Operation :operation="operation" :colored="false"> <component :is="operation.options" v-if="operation.options" v-model="rule.operation" @input="updateOperation" /> </Operation> - <button v-tooltip="ruleStatus.tooltip" - class="status-button icon" - :class="ruleStatus.class" - @click="saveRule"> - {{ ruleStatus.title }} - </button> + <div class="buttons"> + <button v-tooltip="ruleStatus.tooltip" + class="status-button icon" + :class="ruleStatus.class" + @click="saveRule"> + {{ ruleStatus.title }} + </button> + <button v-if="rule.id < -1" @click="cancelRule"> + {{ t('workflowengine', 'Cancel') }} + </button> + <button v-else @click="deleteRule"> + {{ t('workflowengine', 'Delete') }} + </button> + </div> </div> </div> </template> @@ -85,7 +83,7 @@ export default { return this.$store.getters.getOperationForRule(this.rule) }, ruleStatus() { - if (this.error || !this.rule.valid) { + if (this.error || !this.rule.valid || this.rule.checks.some((check) => check.invalid === true)) { return { title: t('workflowengine', 'The configuration is invalid'), class: 'icon-close-white invalid', @@ -163,11 +161,18 @@ export default { background-position: 10px center; } + .buttons { + display: block; + button { + float: right; + height: 34px; + } + } + .status-button { transition: 0.5s ease all; display: block; - margin: auto; - margin-right: 0; + margin: 3px 10px 3px auto; } .status-button.primary { padding-left: 32px; @@ -199,12 +204,6 @@ export default { .action { max-width: 400px; position: relative; - .buttons { - position: absolute; - right: 0; - display: flex; - z-index: 1; - } } .icon-confirm { background-position: right 27px; @@ -238,6 +237,7 @@ export default { margin: 0; width: 180px; border-radius: var(--border-radius); + color: var(--color-text-maxcontrast); font-weight: normal; text-align: left; font-size: 1em; diff --git a/apps/workflowengine/src/helpers/api.js b/apps/workflowengine/src/helpers/api.js index 2b2bb40a7e2..76861d3bb35 100644 --- a/apps/workflowengine/src/helpers/api.js +++ b/apps/workflowengine/src/helpers/api.js @@ -22,8 +22,9 @@ import { loadState } from '@nextcloud/initial-state' +const scopeValue = loadState('workflowengine', 'scope') === 0 ? 'global' : 'user' + const getApiUrl = (url) => { - const scopeValue = loadState('workflowengine', 'scope') === 0 ? 'global' : 'user' return OC.linkToOCS('apps/workflowengine/api/v1/workflows', 2) + scopeValue + url + '?format=json' } diff --git a/apps/workflowengine/src/helpers/validators.js b/apps/workflowengine/src/helpers/validators.js index 68ced4ae6fa..d64adfa1385 100644 --- a/apps/workflowengine/src/helpers/validators.js +++ b/apps/workflowengine/src/helpers/validators.js @@ -19,23 +19,29 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ +const regexRegex = /^\/(.*)\/([gui]{0,3})$/ +const regexIPv4 = /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\/(3[0-2]|[1-2][0-9]|[1-9])$/ +const regexIPv6 = /^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\/(1([01][0-9]|2[0-8])|[1-9][0-9]|[0-9])$/ const validateRegex = function(string) { - var regexRegex = /^\/(.*)\/([gui]{0,3})$/ - var result = regexRegex.exec(string) - return result !== null + if (!string) { + return false + } + return regexRegex.exec(string) !== null } const validateIPv4 = function(string) { - var regexRegex = /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\/(3[0-2]|[1-2][0-9]|[1-9])$/ - var result = regexRegex.exec(string) - return result !== null + if (!string) { + return false + } + return regexIPv4.exec(string) !== null } const validateIPv6 = function(string) { - var regexRegex = /^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\/(1([01][0-9]|2[0-8])|[1-9][0-9]|[0-9])$/ - var result = regexRegex.exec(string) - return result !== null + if (!string) { + return false + } + return regexIPv6.exec(string) !== null } const stringValidator = (check) => { diff --git a/apps/workflowengine/src/store.js b/apps/workflowengine/src/store.js index cbd9b29c81c..a18540f8035 100644 --- a/apps/workflowengine/src/store.js +++ b/apps/workflowengine/src/store.js @@ -71,7 +71,9 @@ const store = new Vuex.Store({ plugin = Object.assign( { color: 'var(--color-primary-element)' }, plugin, state.operations[plugin.id] || {}) - Vue.set(state.operations, plugin.id, plugin) + if (typeof state.operations[plugin.id] !== 'undefined') { + Vue.set(state.operations, plugin.id, plugin) + } } }, actions: { |