Signed-off-by: Julius Härtl <jus@bitgrid.net>tags/v18.0.0beta1
@@ -89,11 +89,12 @@ export default { | |||
width: 100%; | |||
padding-right: 20px; | |||
& > *:not(.icon-delete) { | |||
width: 200px; | |||
width: 180px; | |||
} | |||
& > .multiselect, | |||
& > input[type=text] { | |||
margin-right: 5px; | |||
margin-bottom: 5px; | |||
} | |||
} | |||
input[type=text] { |
@@ -1,6 +1,6 @@ | |||
<template> | |||
<div> | |||
<div v-if="operation.isComplex && operation.fixedEntity !== ''"> | |||
<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> | |||
</div> | |||
@@ -60,7 +60,19 @@ export default { | |||
} | |||
</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 { | |||
display: flex; | |||
} |
@@ -59,6 +59,7 @@ export default { | |||
} | |||
.colored { | |||
background-color: var(--color-primary-element); | |||
* { | |||
color: var(--color-primary-text) | |||
} |
@@ -1,7 +1,7 @@ | |||
<template> | |||
<div class="section rule" :style="{ borderLeftColor: operation.color }"> | |||
<!-- TODO: icon-confirm --> | |||
<div class="trigger icon-confirm"> | |||
<div class="trigger"> | |||
<p> | |||
<span>{{ t('workflowengine', 'When') }}</span> | |||
<Event :rule="rule" @update="updateRule" /> | |||
@@ -12,10 +12,11 @@ | |||
</p> | |||
<p> | |||
<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})"> | |||
</p> | |||
</div> | |||
<div class="flow-icon icon-confirm"></div> | |||
<div class="action"> | |||
<div class="buttons"> | |||
<Actions> | |||
@@ -26,15 +27,15 @@ | |||
Remove rule | |||
</ActionButton> | |||
</Actions> | |||
<button v-tooltip="ruleStatus.tooltip" class="status-button icon" :class="ruleStatus.class" | |||
@click="saveRule"> | |||
{{ ruleStatus.title }} | |||
</button> | |||
</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> | |||
</div> | |||
</template> | |||
@@ -152,6 +153,8 @@ export default { | |||
.status-button { | |||
transition: 0.5s ease all; | |||
display: block; | |||
margin: auto; | |||
} | |||
.status-button.primary { | |||
padding-left: 32px; | |||
@@ -166,15 +169,19 @@ export default { | |||
border: none; | |||
} | |||
.flow-icon { | |||
width: 44px; | |||
} | |||
.rule { | |||
display: flex; | |||
flex-wrap: wrap; | |||
border-left: 5px solid #fff; | |||
border-left: 5px solid var(--color-primary-element); | |||
.trigger, .action { | |||
flex-grow: 1; | |||
min-height: 100px; | |||
max-width: 900px; | |||
max-width: 700px; | |||
} | |||
.action { | |||
max-width: 400px; | |||
@@ -214,10 +221,24 @@ export default { | |||
background-color: transparent; | |||
padding-left: 6px; | |||
margin: 0; | |||
width: 200px; | |||
width: 180px; | |||
border-radius: var(--border-radius); | |||
font-weight: normal; | |||
text-align: left; | |||
font-size: 1em; | |||
} | |||
@media (max-width:1400px) { | |||
.rule { | |||
&, .trigger, .action { | |||
width: 100%; | |||
max-width: 100%; | |||
} | |||
.flow-icon { | |||
display: none; | |||
} | |||
} | |||
} | |||
</style> |
@@ -1,6 +1,6 @@ | |||
<template> | |||
<input v-model="newValue" type="text" placeholder="1 MB" | |||
@input="$emit('input', newValue)"> | |||
@input="update"> | |||
</template> | |||
<script> | |||
@@ -8,11 +8,13 @@ export default { | |||
name: 'SizeValue', | |||
props: { | |||
value: { | |||
type: String | |||
type: String, | |||
default: '1 MB' | |||
} | |||
}, | |||
data() { | |||
return { | |||
valid: false, | |||
newValue: this.value | |||
} | |||
}, | |||
@@ -20,6 +22,19 @@ export default { | |||
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> |
@@ -1,6 +1,3 @@ | |||
import ConvertToPdf from './../components/Operations/ConvertToPdf' | |||
import Tag from './../components/Operations/Tag' | |||
const ALL_CHECKS = [ | |||
'OCA\\WorkflowEngine\\Check\\FileMimeType', | |||
'OCA\\WorkflowEngine\\Check\\FileName', | |||
@@ -13,27 +10,10 @@ const ALL_CHECKS = [ | |||
'OCA\\WorkflowEngine\\Check\\UserGroupMembership' | |||
] | |||
const Operators = OCP.InitialState.loadState('workflowengine', 'operators') | |||
const Operators = {} | |||
/** | |||
* 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'] = { | |||
id: 'OCA\\TestExample\\Operation1', | |||
@@ -51,14 +31,6 @@ Operators['OCA\\TestExample\\Operation2'] = { | |||
color: 'var(--color-warning)', | |||
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 { | |||
Operators, |
@@ -24,7 +24,7 @@ import Vue from 'vue' | |||
import Vuex from 'vuex' | |||
import axios from 'nextcloud-axios' | |||
import { getApiUrl } from './helpers/api' | |||
import { ALL_CHECKS, Operators } from './services/Operation' | |||
import { ALL_CHECKS } from './services/Operation' | |||
import confirmPassword from 'nextcloud-password-confirmation' | |||
Vue.use(Vuex) | |||
@@ -33,8 +33,7 @@ const store = new Vuex.Store({ | |||
state: { | |||
rules: [], | |||
scope: OCP.InitialState.loadState('workflowengine', 'scope'), | |||
// TODO: move to backend data | |||
operations: Operators, | |||
operations: OCP.InitialState.loadState('workflowengine', 'operators'), | |||
plugins: Vue.observable({ | |||
checks: {}, | |||
@@ -74,7 +73,10 @@ const store = new Vuex.Store({ | |||
Vue.set(state.plugins.checks, plugin.class, 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: { | |||
@@ -88,7 +90,8 @@ const store = new Vuex.Store({ | |||
let entity = null | |||
let events = [] | |||
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] | |||
} | |||
@@ -4,6 +4,7 @@ import store from './store' | |||
import Settings from './components/Workflow' | |||
import FileValues from './components/Values/file' | |||
import {Operators} from './services/Operation'; | |||
/** | |||
* 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 | |||
* | |||
* @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} color - Custom color code to be applied for the operator selector | |||
* @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 | |||
*/ | |||
window.OCA.WorkflowEngine = Object.assign({}, OCA.WorkflowEngine, { | |||
/** | |||
* | |||
* @param {CheckPlugin} Plugin | |||
@@ -58,6 +61,7 @@ window.OCA.WorkflowEngine = Object.assign({}, OCA.WorkflowEngine, { | |||
// Register shipped checks for file entity | |||
FileValues.forEach((checkPlugin) => window.OCA.WorkflowEngine.registerCheck(checkPlugin)) | |||
Object.values(Operators).forEach((operatorPlugin) => window.OCA.WorkflowEngine.registerOperator(operatorPlugin)) | |||
Vue.use(Vuex) | |||
Vue.prototype.t = t |