Browse Source

Allow placeholder and validation without custom vue component

Signed-off-by: Julius Härtl <jus@bitgrid.net>
tags/v18.0.0beta1
Julius Härtl 4 years ago
parent
commit
1742f97acf
No account linked to committer's email address

+ 37
- 4
apps/workflowengine/src/components/Check.vue View File

@@ -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>

+ 2
- 2
apps/workflowengine/src/components/Rule.vue View File

@@ -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',

+ 64
- 7
apps/workflowengine/src/components/Values/FileMimeType.vue View File

@@ -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>

+ 30
- 0
apps/workflowengine/src/components/Values/file.js View File

@@ -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'),

+ 5
- 1
apps/workflowengine/src/store.js View File

@@ -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: {

+ 2
- 0
apps/workflowengine/src/workflowengine.js View File

@@ -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
**/

/**

Loading…
Cancel
Save