diff options
author | Julius Härtl <jus@bitgrid.net> | 2019-09-02 11:35:33 +0200 |
---|---|---|
committer | Julius Härtl <jus@bitgrid.net> | 2019-09-10 09:01:24 +0200 |
commit | 1742f97acf62df08d2527120200f6e70736f33ec (patch) | |
tree | 3efbdde4e2a167004a70f65910c8e72ad8f2b4aa | |
parent | 69ac169fd9ff3b798e6744a685d2292a1a8a565b (diff) | |
download | nextcloud-server-1742f97acf62df08d2527120200f6e70736f33ec.tar.gz nextcloud-server-1742f97acf62df08d2527120200f6e70736f33ec.zip |
Allow placeholder and validation without custom vue component
Signed-off-by: Julius Härtl <jus@bitgrid.net>
-rw-r--r-- | apps/workflowengine/src/components/Check.vue | 41 | ||||
-rw-r--r-- | apps/workflowengine/src/components/Rule.vue | 4 | ||||
-rw-r--r-- | apps/workflowengine/src/components/Values/FileMimeType.vue | 71 | ||||
-rw-r--r-- | apps/workflowengine/src/components/Values/file.js | 30 | ||||
-rw-r--r-- | apps/workflowengine/src/store.js | 6 | ||||
-rw-r--r-- | apps/workflowengine/src/workflowengine.js | 2 |
6 files changed, 140 insertions, 14 deletions
diff --git a/apps/workflowengine/src/components/Check.vue b/apps/workflowengine/src/components/Check.vue index 8583288016f..bd3c471fc3c 100644 --- a/apps/workflowengine/src/components/Check.vue +++ b/apps/workflowengine/src/components/Check.vue @@ -6,9 +6,9 @@ <Multiselect :disabled="!currentOption" v-model="currentOperator" :options="operators" label="name" track-by="operator" :allow-empty="false" :placeholder="t('workflowengine', 'Select a comparator')" @input="updateCheck" /> - <component :is="currentOption.component" v-if="currentOperator && currentComponent" v-model="check.value" :disabled="!currentOption" /> - <input v-else v-model="check.value" type="text" - @input="updateCheck" :disabled="!currentOption"> + <component :is="currentOption.component" v-if="currentOperator && currentComponent" v-model="check.value" :disabled="!currentOption" :check="check" @valid="valid=true && validate()" @invalid="valid=false && validate()" /> + <input v-else v-model="check.value" type="text" :class="{ invalid: !valid }" + @input="updateCheck" :disabled="!currentOption" :placeholder="valuePlaceholder"> <Actions> <ActionButton v-if="deleteVisible || !currentOption" icon="icon-delete" @click="$emit('remove')" /> </Actions> @@ -34,6 +34,10 @@ export default { check: { type: Object, required: true + }, + rule: { + type: Object, + required: true } }, data() { @@ -41,7 +45,8 @@ export default { deleteVisible: false, currentOption: null, currentOperator: null, - options: [] + options: [], + valid: true, } }, computed: { @@ -56,6 +61,11 @@ export default { if (!this.currentOption) { return [] } const currentComponent = this.Checks[this.currentOption.class].component return currentComponent + }, + valuePlaceholder() { + if (this.currentOption && this.currentOption.placeholder) { + return this.currentOption.placeholder(this.check) + } } }, mounted() { @@ -63,6 +73,11 @@ export default { this.currentOption = this.Checks[this.check.class] this.currentOperator = this.operators.find((operator) => operator.operator === this.check.operator) }, + watch: { + 'check.operator': function () { + this.validate() + } + }, methods: { showDelete() { this.deleteVisible = true @@ -70,12 +85,27 @@ export default { hideDelete() { this.deleteVisible = false }, + validate() { + if (this.currentOption && this.currentOption.validate) { + if(this.currentOption.validate(this.check)) { + this.valid = true + } else { + this.valid = false + } + } + this.$store.dispatch('setValid', { rule: this.rule, valid: this.rule.valid && this.valid }) + return this.valid + }, updateCheck() { if (this.check.class !== this.currentOption.class) { this.currentOperator = this.operators[0] } this.check.class = this.currentOption.class this.check.operator = this.currentOperator.operator + + if (!this.validate()) { + return + } this.$emit('update', this.check) } } @@ -107,4 +137,7 @@ export default { margin-top: -5px; margin-bottom: -5px; } + .invalid { + border: 1px solid var(--color-error) !important; + } </style> diff --git a/apps/workflowengine/src/components/Rule.vue b/apps/workflowengine/src/components/Rule.vue index f1551d985ca..88129525eb3 100644 --- a/apps/workflowengine/src/components/Rule.vue +++ b/apps/workflowengine/src/components/Rule.vue @@ -8,7 +8,7 @@ </p> <p v-for="check in rule.checks"> <span>{{ t('workflowengine', 'and') }}</span> - <Check :check="check" @update="updateRule" @remove="removeCheck(check)" /> + <Check :check="check" :rule="rule" @update="updateRule" @remove="removeCheck(check)" /> </p> <p> <span /> @@ -74,7 +74,7 @@ export default { return this.$store.getters.getOperationForRule(this.rule) }, ruleStatus() { - if (this.error) { + if (this.error || !this.rule.valid) { return { title: t('workflowengine', 'The configuration is invalid'), class: 'icon-close-white invalid', diff --git a/apps/workflowengine/src/components/Values/FileMimeType.vue b/apps/workflowengine/src/components/Values/FileMimeType.vue index 75729af8073..56d8aa6098e 100644 --- a/apps/workflowengine/src/components/Values/FileMimeType.vue +++ b/apps/workflowengine/src/components/Values/FileMimeType.vue @@ -1,47 +1,104 @@ <template> - <input type="text" v-model="test"> + <div> + + <multiselect + :value="currentValue" + placeholder="Select a file type" + label="label" + track-by="pattern" + :options="options" :multiple="false" :tagging="false" @input="setValue"> + <template slot="singleLabel" slot-scope="props"> + <span class="option__icon" :class="props.option.icon"></span> + <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> + <span class="option__title">{{ props.option.label }}</span> + </template> + </multiselect> + <input type="text" :value="currentValue.pattern" @input="updateCustom"/> + </div> </template> <script> import { Multiselect } from 'nextcloud-vue' export default { - name: 'SizeValue', + name: 'FileMimeType', components: { Multiselect }, data() { return { - test: 'test', + value: '', predefinedTypes: [ { icon: 'icon-picture', - label: 'Images', + label: t('workflowengine', 'Images'), pattern: '/image\\/.*/' }, { icon: 'icon-category-office', - label: 'Office documents', + label: t('workflowengine', 'Office documents'), pattern: '/(vnd\\.(ms-|openxmlformats-).*))$/' }, { icon: 'icon-filetype-file', - label: 'PDF documents', + label: t('workflowengine', 'PDF documents'), pattern: 'application/pdf' } ] } }, + computed: { + options() { + return [...this.predefinedTypes, this.customValue] + }, + customValue() { + const matchingPredefined = this.predefinedTypes.find((type) => this.value.pattern === type.pattern) + return { + icon: 'icon-settings-dark', + label: t('workflowengine', 'Custom pattern'), + pattern: '', + } + }, + currentValue() { + const matchingPredefined = this.predefinedTypes.find((type) => this.value === type.pattern) + if (matchingPredefined) { + return matchingPredefined + } + return { + icon: 'icon-settings-dark', + label: t('workflowengine', 'Custom pattern'), + pattern: this.value, + } + } + }, methods: { validateRegex(string) { var regexRegex = /^\/(.*)\/([gui]{0,3})$/ var result = regexRegex.exec(string) return result !== null + }, + setValue (value) { + // TODO: check if value requires a regex and set the check operator according to that + if (value !== null) { + this.value = value.pattern + } + }, + updateCustom (event) { + console.log(event) + this.value = event.target.value } } } </script> <style scoped> - + .multiselect::v-deep .multiselect__single { + display: flex; + } + input, .multiselect { + width: 100%; + } </style> diff --git a/apps/workflowengine/src/components/Values/file.js b/apps/workflowengine/src/components/Values/file.js index 4a473dbc13c..fa6851cc5c2 100644 --- a/apps/workflowengine/src/components/Values/file.js +++ b/apps/workflowengine/src/components/Values/file.js @@ -40,6 +40,36 @@ const FileChecks = Object.values(OCA.WorkflowEngine.Plugins).map((plugin) => { // new way of registering checks + +const validateRegex = function(string) { + var regexRegex = /^\/(.*)\/([gui]{0,3})$/ + var result = regexRegex.exec(string) + return result !== null +} + +FileChecks.push({ + class: 'OCA\\WorkflowEngine\\Check\\FileName', + name: t('workflowengine', 'File name'), + operators: [ + { operator: 'is', name: t('workflowengine', 'is') }, + { operator: '!is', name: t('workflowengine', 'is not') }, + { operator: 'matches', name: t('workflowengine', 'matches') }, + { operator: '!matches', name: t('workflowengine', 'does not match') } + ], + placeholder: (check) => { + if (check.operator === 'matches' || check.operator === '!matches') { + return '/^dummy-.+$/i' + } + return 'filename.txt' + }, + validate: (check) => { + if (check.operator === 'matches' || check.operator === '!matches') { + return validateRegex(check.value) + } + return true + } +}) + FileChecks.push({ class: 'OCA\\WorkflowEngine\\Check\\FileMimeType', name: t('workflowengine', 'File MIME type'), diff --git a/apps/workflowengine/src/store.js b/apps/workflowengine/src/store.js index b38bef0e6ea..a6af51b65d8 100644 --- a/apps/workflowengine/src/store.js +++ b/apps/workflowengine/src/store.js @@ -58,7 +58,7 @@ const store = new Vuex.Store({ }, mutations: { addRule(state, rule) { - state.rules.push(rule) + state.rules.push({ ...rule, valid: true }) }, updateRule(state, rule) { const index = state.rules.findIndex((item) => rule.id === item.id) @@ -129,6 +129,10 @@ const store = new Vuex.Store({ await confirmPassword() await axios.delete(getApiUrl(`/${rule.id}`)) context.commit('removeRule', rule) + }, + setValid (context, { rule, valid }) { + rule.valid = valid + context.commit('updateRule', rule) } }, getters: { diff --git a/apps/workflowengine/src/workflowengine.js b/apps/workflowengine/src/workflowengine.js index cae85c3c24a..6f96f454262 100644 --- a/apps/workflowengine/src/workflowengine.js +++ b/apps/workflowengine/src/workflowengine.js @@ -16,6 +16,8 @@ import {Operators} from './services/Operation'; * The component should handle the v-model directive properly, * so it needs a value property to receive data and emit an input * event once the data has changed + * @property {callable} placeholder - Return a placeholder of no custom component is used + * @property {callable} validate - validate a check if no custom component is used **/ /** |