Handle operator registration properly

Signed-off-by: Julius Härtl <jus@bitgrid.net>
This commit is contained in:
Julius Härtl 2019-08-31 11:53:15 +02:00
parent ae55829989
commit 28a7721b2b
No known key found for this signature in database
GPG Key ID: 4C614C6ED2CDE6DF
8 changed files with 78 additions and 49 deletions

View File

@ -89,11 +89,12 @@ export default {
width: 100%; width: 100%;
padding-right: 20px; padding-right: 20px;
& > *:not(.icon-delete) { & > *:not(.icon-delete) {
width: 200px; width: 180px;
} }
& > .multiselect, & > .multiselect,
& > input[type=text] { & > input[type=text] {
margin-right: 5px; margin-right: 5px;
margin-bottom: 5px;
} }
} }
input[type=text] { input[type=text] {

View File

@ -1,6 +1,6 @@
<template> <template>
<div> <div>
<div v-if="operation.isComplex && operation.fixedEntity !== ''"> <div v-if="operation.isComplex && operation.fixedEntity !== ''" class="isComplex">
<img class="option__icon" :src="entity.icon"> <img class="option__icon" :src="entity.icon">
<span class="option__title option__title_single">{{ operation.triggerHint }}</span> <span class="option__title option__title_single">{{ operation.triggerHint }}</span>
</div> </div>
@ -60,7 +60,19 @@ export default {
} }
</script> </script>
<style scoped> <style scoped lang="scss">
.isComplex {
img {
vertical-align: top;
padding-top: 4px;
padding-bottom: 4px;
padding-left: 4px;
}
span {
padding-top: 2px;
display: inline-block;
}
}
.multiselect::v-deep .multiselect__single { .multiselect::v-deep .multiselect__single {
display: flex; display: flex;
} }

View File

@ -59,6 +59,7 @@ export default {
} }
.colored { .colored {
background-color: var(--color-primary-element);
* { * {
color: var(--color-primary-text) color: var(--color-primary-text)
} }

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="section rule" :style="{ borderLeftColor: operation.color }"> <div class="section rule" :style="{ borderLeftColor: operation.color }">
<!-- TODO: icon-confirm --> <!-- TODO: icon-confirm -->
<div class="trigger icon-confirm"> <div class="trigger">
<p> <p>
<span>{{ t('workflowengine', 'When') }}</span> <span>{{ t('workflowengine', 'When') }}</span>
<Event :rule="rule" @update="updateRule" /> <Event :rule="rule" @update="updateRule" />
@ -12,10 +12,11 @@
</p> </p>
<p> <p>
<span /> <span />
<di<input v-if="lastCheckComplete" type="button" class="check--add" <input v-if="lastCheckComplete" type="button" class="check--add"
value="Add a new filter" @click="rule.checks.push({class: null, operator: null, value: null})"> value="Add a new filter" @click="rule.checks.push({class: null, operator: null, value: null})">
</p> </p>
</div> </div>
<div class="flow-icon icon-confirm"></div>
<div class="action"> <div class="action">
<div class="buttons"> <div class="buttons">
<Actions> <Actions>
@ -26,15 +27,15 @@
Remove rule Remove rule
</ActionButton> </ActionButton>
</Actions> </Actions>
<button v-tooltip="ruleStatus.tooltip" class="status-button icon" :class="ruleStatus.class"
@click="saveRule">
{{ ruleStatus.title }}
</button>
</div> </div>
<Operation :operation="operation" :colored="false"> <Operation :operation="operation" :colored="false">
<component :is="operation.options" v-if="operation.options" v-model="rule.operation" <component :is="operation.options" v-if="operation.options" v-model="rule.operation"
@input="updateOperation" /> @input="updateOperation" />
</Operation> </Operation>
<button v-tooltip="ruleStatus.tooltip" class="status-button icon" :class="ruleStatus.class"
@click="saveRule">
{{ ruleStatus.title }}
</button>
</div> </div>
</div> </div>
</template> </template>
@ -152,6 +153,8 @@ export default {
.status-button { .status-button {
transition: 0.5s ease all; transition: 0.5s ease all;
display: block;
margin: auto;
} }
.status-button.primary { .status-button.primary {
padding-left: 32px; padding-left: 32px;
@ -166,15 +169,19 @@ export default {
border: none; border: none;
} }
.flow-icon {
width: 44px;
}
.rule { .rule {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
border-left: 5px solid #fff; border-left: 5px solid var(--color-primary-element);
.trigger, .action { .trigger, .action {
flex-grow: 1; flex-grow: 1;
min-height: 100px; min-height: 100px;
max-width: 900px; max-width: 700px;
} }
.action { .action {
max-width: 400px; max-width: 400px;
@ -214,10 +221,24 @@ export default {
background-color: transparent; background-color: transparent;
padding-left: 6px; padding-left: 6px;
margin: 0; margin: 0;
width: 200px; width: 180px;
border-radius: var(--border-radius); border-radius: var(--border-radius);
font-weight: normal; font-weight: normal;
text-align: left; text-align: left;
font-size: 1em; font-size: 1em;
} }
@media (max-width:1400px) {
.rule {
&, .trigger, .action {
width: 100%;
max-width: 100%;
}
.flow-icon {
display: none;
}
}
}
</style> </style>

View File

@ -1,6 +1,6 @@
<template> <template>
<input v-model="newValue" type="text" placeholder="1 MB" <input v-model="newValue" type="text" placeholder="1 MB"
@input="$emit('input', newValue)"> @input="update">
</template> </template>
<script> <script>
@ -8,11 +8,13 @@ export default {
name: 'SizeValue', name: 'SizeValue',
props: { props: {
value: { value: {
type: String type: String,
default: '1 MB'
} }
}, },
data() { data() {
return { return {
valid: false,
newValue: this.value newValue: this.value
} }
}, },
@ -20,6 +22,19 @@ export default {
value() { value() {
this.newValue = this.value this.newValue = this.value
} }
},
methods: {
validate() {
return this.newValue.match(/^[0-9]+[ ]?[kmgt]?b$/i) !== null
},
update() {
if (this.validate()) {
this.$emit('input', this.newValue)
this.valid = false
} else {
this.valid = false
}
}
} }
} }
</script> </script>

View File

@ -1,6 +1,3 @@
import ConvertToPdf from './../components/Operations/ConvertToPdf'
import Tag from './../components/Operations/Tag'
const ALL_CHECKS = [ const ALL_CHECKS = [
'OCA\\WorkflowEngine\\Check\\FileMimeType', 'OCA\\WorkflowEngine\\Check\\FileMimeType',
'OCA\\WorkflowEngine\\Check\\FileName', 'OCA\\WorkflowEngine\\Check\\FileName',
@ -13,27 +10,10 @@ const ALL_CHECKS = [
'OCA\\WorkflowEngine\\Check\\UserGroupMembership' 'OCA\\WorkflowEngine\\Check\\UserGroupMembership'
] ]
const Operators = OCP.InitialState.loadState('workflowengine', 'operators') const Operators = {}
/** /**
* Extend operators for testing * Extend operators for testing
*/ */
Operators['OCA\\FilesAccessControl\\Operation'] = {
...Operators['OCA\\FilesAccessControl\\Operation'],
color: 'var(--color-error)',
entities: [
'OCA\\WorkflowEngine\\Entity\\File'
],
operation: 'deny'
}
Operators['OCA\\WorkflowPDFConverter\\Operation'] = {
id: 'OCA\\WorkflowPDFConverter\\Operation',
name: 'Convert to PDF',
description: 'Generate a PDF file',
color: '#dc5047',
iconClass: 'icon-convert-pdf',
options: ConvertToPdf
}
Operators['OCA\\TestExample\\Operation1'] = { Operators['OCA\\TestExample\\Operation1'] = {
id: 'OCA\\TestExample\\Operation1', id: 'OCA\\TestExample\\Operation1',
@ -51,14 +31,6 @@ Operators['OCA\\TestExample\\Operation2'] = {
color: 'var(--color-warning)', color: 'var(--color-warning)',
operation: 'deny' operation: 'deny'
} }
Operators['OCA\\FilesAutomatedTagging\\Operation'] = {
id: 'OCA\\FilesAutomatedTagging\\Operation',
name: 'Tag a file',
description: 'Assign a tag to a file',
iconClass: 'icon-tag-white',
color: 'var(--color-primary)',
options: Tag
}
export { export {
Operators, Operators,

View File

@ -24,7 +24,7 @@ import Vue from 'vue'
import Vuex from 'vuex' import Vuex from 'vuex'
import axios from 'nextcloud-axios' import axios from 'nextcloud-axios'
import { getApiUrl } from './helpers/api' import { getApiUrl } from './helpers/api'
import { ALL_CHECKS, Operators } from './services/Operation' import { ALL_CHECKS } from './services/Operation'
import confirmPassword from 'nextcloud-password-confirmation' import confirmPassword from 'nextcloud-password-confirmation'
Vue.use(Vuex) Vue.use(Vuex)
@ -33,8 +33,7 @@ const store = new Vuex.Store({
state: { state: {
rules: [], rules: [],
scope: OCP.InitialState.loadState('workflowengine', 'scope'), scope: OCP.InitialState.loadState('workflowengine', 'scope'),
// TODO: move to backend data operations: OCP.InitialState.loadState('workflowengine', 'operators'),
operations: Operators,
plugins: Vue.observable({ plugins: Vue.observable({
checks: {}, checks: {},
@ -74,7 +73,10 @@ const store = new Vuex.Store({
Vue.set(state.plugins.checks, plugin.class, plugin) Vue.set(state.plugins.checks, plugin.class, plugin)
}, },
addPluginOperator(state, plugin) { addPluginOperator(state, plugin) {
Vue.set(state.plugins.operators, plugin.class, plugin) plugin = Object.assign(
{ color: 'var(--color-primary-element)' },
plugin, state.operations[plugin.id] || {})
Vue.set(state.operations, plugin.id, plugin)
} }
}, },
actions: { actions: {
@ -88,7 +90,8 @@ const store = new Vuex.Store({
let entity = null let entity = null
let events = [] let events = []
if (rule.isComplex === false && rule.fixedEntity === '') { if (rule.isComplex === false && rule.fixedEntity === '') {
entity = context.state.entities.find((item) => rule.entities[0] === item.id) entity = context.state.entities.find((item) => rule.entities && rule.entities[0] === item.id)
entity = entity ? entity : Object.values(context.state.entities)[0]
events = [entity.events[0].eventName] events = [entity.events[0].eventName]
} }

View File

@ -4,6 +4,7 @@ import store from './store'
import Settings from './components/Workflow' import Settings from './components/Workflow'
import FileValues from './components/Values/file' import FileValues from './components/Values/file'
import {Operators} from './services/Operation';
/** /**
* A plugin for displaying a custom value field for checks * A plugin for displaying a custom value field for checks
@ -21,7 +22,7 @@ import FileValues from './components/Values/file'
* A plugin for extending the admin page repesentation of a operator * A plugin for extending the admin page repesentation of a operator
* *
* @typedef {Object} OperatorPlugin * @typedef {Object} OperatorPlugin
* @property {string} class - The PHP class name of the check * @property {string} id - The PHP class name of the check
* @property {string} operation - Default value for the operation field * @property {string} operation - Default value for the operation field
* @property {string} color - Custom color code to be applied for the operator selector * @property {string} color - Custom color code to be applied for the operator selector
* @property {Vue} component - A vue component to handle the rendering of options * @property {Vue} component - A vue component to handle the rendering of options
@ -40,6 +41,8 @@ import FileValues from './components/Values/file'
* Public javascript api for apps to register custom plugins * Public javascript api for apps to register custom plugins
*/ */
window.OCA.WorkflowEngine = Object.assign({}, OCA.WorkflowEngine, { window.OCA.WorkflowEngine = Object.assign({}, OCA.WorkflowEngine, {
/** /**
* *
* @param {CheckPlugin} Plugin * @param {CheckPlugin} Plugin
@ -58,6 +61,7 @@ window.OCA.WorkflowEngine = Object.assign({}, OCA.WorkflowEngine, {
// Register shipped checks for file entity // Register shipped checks for file entity
FileValues.forEach((checkPlugin) => window.OCA.WorkflowEngine.registerCheck(checkPlugin)) FileValues.forEach((checkPlugin) => window.OCA.WorkflowEngine.registerCheck(checkPlugin))
Object.values(Operators).forEach((operatorPlugin) => window.OCA.WorkflowEngine.registerOperator(operatorPlugin))
Vue.use(Vuex) Vue.use(Vuex)
Vue.prototype.t = t Vue.prototype.t = t