Move to vuex store

Signed-off-by: Julius Härtl <jus@bitgrid.net>
This commit is contained in:
Julius Härtl 2019-08-29 16:50:33 +02:00
parent aa00f401b3
commit bd281daa47
No known key found for this signature in database
GPG Key ID: 4C614C6ED2CDE6DF
25 changed files with 753 additions and 1302 deletions

View File

@ -1,385 +0,0 @@
/**
* @copyright Copyright (c) 2016 Morris Jobke <hey@morrisjobke.de>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
import OperationTemplate from './templates/operation.handlebars';
import OperationsTemplate from './templates/operations.handlebars';
(function() {
OCA.WorkflowEngine = _.extend(OCA.WorkflowEngine || {}, {
availablePlugins: [],
availableChecks: [],
getCheckByClass: function(className) {
var length = OCA.WorkflowEngine.availableChecks.length;
for (var i = 0; i < length; i++) {
if (OCA.WorkflowEngine.availableChecks[i]['class'] === className) {
return OCA.WorkflowEngine.availableChecks[i];
}
}
return undefined;
}
});
/**
* 888b d888 888 888
* 8888b d8888 888 888
* 88888b.d88888 888 888
* 888Y88888P888 .d88b. .d88888 .d88b. 888 .d8888b
* 888 Y888P 888 d88""88b d88" 888 d8P Y8b 888 88K
* 888 Y8P 888 888 888 888 888 88888888 888 "Y8888b.
* 888 " 888 Y88..88P Y88b 888 Y8b. 888 X88
* 888 888 "Y88P" "Y88888 "Y8888 888 88888P'
*/
/**
* @class OCA.WorkflowEngine.Operation
*/
OCA.WorkflowEngine.Operation =
OC.Backbone.Model.extend({
defaults: {
'class': 'OCA\\WorkflowEngine\\Operation',
'name': '',
'checks': [],
'operation': ''
}
});
/**
* .d8888b. 888 888 888 d8b
* d88P Y88b 888 888 888 Y8P
* 888 888 888 888 888
* 888 .d88b. 888 888 .d88b. .d8888b 888888 888 .d88b. 88888b. .d8888b
* 888 d88""88b 888 888 d8P Y8b d88P" 888 888 d88""88b 888 "88b 88K
* 888 888 888 888 888 888 88888888 888 888 888 888 888 888 888 "Y8888b.
* Y88b d88P Y88..88P 888 888 Y8b. Y88b. Y88b. 888 Y88..88P 888 888 X88
* "Y8888P" "Y88P" 888 888 "Y8888 "Y8888P "Y888 888 "Y88P" 888 888 88888P'
*/
/**
* @class OCA.WorkflowEngine.OperationsCollection
*
* collection for all configurated operations
*/
OCA.WorkflowEngine.OperationsCollection =
OC.Backbone.Collection.extend({
model: OCA.WorkflowEngine.Operation,
url: OC.generateUrl('apps/workflowengine/operations')
});
/**
* 888 888 d8b
* 888 888 Y8P
* 888 888
* Y88b d88P 888 .d88b. 888 888 888 .d8888b
* Y88b d88P 888 d8P Y8b 888 888 888 88K
* Y88o88P 888 88888888 888 888 888 "Y8888b.
* Y888P 888 Y8b. Y88b 888 d88P X88
* Y8P 888 "Y8888 "Y8888888P" 88888P'
*/
/**
* @class OCA.WorkflowEngine.OperationView
*
* this creates the view for a single operation
*/
OCA.WorkflowEngine.OperationView =
OC.Backbone.View.extend({
templateId: '#operation-template',
events: {
'change .check-class': 'checkChanged',
'change .check-operator': 'checkChanged',
'change .check-value': 'checkChanged',
'change .operation-name': 'operationChanged',
'change .operation-operation': 'operationChanged',
'click .button-reset': 'reset',
'click .button-save': 'save',
'click .button-add': 'add',
'click .button-delete': 'delete',
'click .button-delete-check': 'deleteCheck'
},
originalModel: null,
hasChanged: false,
message: '',
errorMessage: '',
saving: false,
groups: [],
template: function(vars) {
return OperationTemplate(_.extend(
{
shortRuleDescTXT: t('workflowengine', 'Short rule description'),
addRuleTXT: t('workflowengine', 'Add rule'),
resetTXT: t('workflowengine', 'Reset'),
saveTXT: t('workflowengine', 'Save'),
savingTXT: t('workflowengine', 'Saving…')
},
vars
));
},
initialize: function() {
// this creates a new copy of the object to definitely have a new reference and being able to reset the model
this.originalModel = JSON.parse(JSON.stringify(this.model));
this.model.on('change', function() {
console.log('model changed');
this.hasChanged = true;
this.render();
}, this);
if (this.model.get('id') === undefined) {
this.hasChanged = true;
}
var self = this;
$.ajax({
url: OC.linkToOCS('cloud/groups', 2) + 'details',
dataType: 'json',
quietMillis: 100,
}).success(function(data) {
if (data.ocs.data.groups && data.ocs.data.groups.length > 0) {
data.ocs.data.groups.forEach(function(group) {
self.groups.push({ id: group.id, displayname: group.displayname });
});
self.render();
} else {
OC.Notification.error(t('workflowengine', 'Group list is empty'), { type: 'error' });
console.log(data);
}
}).error(function(data) {
OC.Notification.error(t('workflowengine', 'Unable to retrieve the group list'), { type: 'error' });
console.log(data);
});
},
delete: function() {
if (OC.PasswordConfirmation.requiresPasswordConfirmation()) {
OC.PasswordConfirmation.requirePasswordConfirmation(_.bind(this.delete, this));
return;
}
this.model.destroy();
this.remove();
},
reset: function() {
this.hasChanged = false;
// silent is need to not trigger the change event which resets the hasChanged attribute
this.model.set(this.originalModel, { silent: true });
this.render();
},
save: function() {
if (OC.PasswordConfirmation.requiresPasswordConfirmation()) {
OC.PasswordConfirmation.requirePasswordConfirmation(_.bind(this.save, this));
return;
}
var success = function(model, response, options) {
this.saving = false;
this.originalModel = JSON.parse(JSON.stringify(this.model));
this.message = t('workflowengine', 'Saved');
this.errorMessage = '';
this.render();
};
var error = function(model, response, options) {
this.saving = false;
this.hasChanged = true;
this.message = t('workflowengine', 'Saving failed:');
this.errorMessage = response.responseText;
this.render();
};
this.hasChanged = false;
this.saving = true;
this.render();
this.model.save(null, { success: success, error: error, context: this });
},
add: function() {
var checks = _.clone(this.model.get('checks')),
classname = OCA.WorkflowEngine.availableChecks[0]['class'],
operators = OCA.WorkflowEngine.availableChecks[0]['operators'];
checks.push({
'class': classname,
'operator': operators[0]['operator'],
'value': ''
});
this.model.set({ 'checks': checks });
},
checkChanged: function(event) {
var value = event.target.value,
id = $(event.target.parentElement).data('id'),
// this creates a new copy of the object to definitely have a new reference
checks = JSON.parse(JSON.stringify(this.model.get('checks'))),
key = null;
for (var i = 0; i < event.target.classList.length; i++) {
var className = event.target.classList[i];
if (className.substr(0, 'check-'.length) === 'check-') {
key = className.substr('check-'.length);
break;
}
}
if (key === null) {
console.warn('checkChanged triggered but element doesn\'t have any "check-" class');
return;
}
if (!_.has(checks[id], key)) {
console.warn('key "' + key + '" is not available in check', check);
return;
}
checks[id][key] = value;
// if the class is changed most likely also the operators have changed
// with this we set the operator to the first possible operator
if (key === 'class') {
var check = OCA.WorkflowEngine.getCheckByClass(value);
if (!_.isUndefined(check)) {
checks[id]['operator'] = check['operators'][0]['operator'];
checks[id]['value'] = '';
}
}
// model change will trigger render
this.model.set({ 'checks': checks });
},
deleteCheck: function(event) {
console.log(arguments);
var id = $(event.target.parentElement).data('id'),
checks = JSON.parse(JSON.stringify(this.model.get('checks')));
// splice removes 1 element at index `id`
checks.splice(id, 1);
// model change will trigger render
this.model.set({ 'checks': checks });
},
operationChanged: function(event) {
var value = event.target.value,
key = null;
for (var i = 0; i < event.target.classList.length; i++) {
var className = event.target.classList[i];
if (className.substr(0, 'operation-'.length) === 'operation-') {
key = className.substr('operation-'.length);
break;
}
}
if (key === null) {
console.warn('operationChanged triggered but element doesn\'t have any "operation-" class');
return;
}
if (key !== 'name' && key !== 'operation') {
console.warn('key "' + key + '" is no valid attribute');
return;
}
// model change will trigger render
this.model.set(key, value);
},
render: function() {
this.$el.html(this.template({
operation: this.model.toJSON(),
classes: OCA.WorkflowEngine.availableChecks,
hasChanged: this.hasChanged,
message: this.message,
errorMessage: this.errorMessage,
saving: this.saving
}));
var checks = this.model.get('checks');
_.each(this.$el.find('.check'), function(element) {
var $element = $(element),
id = $element.data('id'),
check = checks[id],
valueElement = $element.find('.check-value').first();
var self = this;
_.each(OCA.WorkflowEngine.availablePlugins, function(plugin) {
if (_.isFunction(plugin.render)) {
plugin.render(valueElement, check, self.groups);
}
});
}, this);
if (this.message !== '') {
// hide success messages after some time
_.delay(function(elements) {
$(elements).css('opacity', 0);
}, 7000, this.$el.find('.msg.success'));
this.message = '';
}
return this.$el;
}
});
/**
* @class OCA.WorkflowEngine.OperationsView
*
* this creates the view for configured operations
*/
OCA.WorkflowEngine.OperationsView =
OC.Backbone.View.extend({
templateId: '#operations-template',
collection: null,
$el: null,
events: {
'click .button-add-operation': 'add'
},
template: function(vars) {
return OperationsTemplate(_.extend(
{
addRuleGroupTXT: t('workflowengine', 'Add rule group')
},
vars
));
},
initialize: function(classname) {
if (!OCA.WorkflowEngine.availablePlugins.length) {
OCA.WorkflowEngine.availablePlugins = OC.Plugins.getPlugins('OCA.WorkflowEngine.CheckPlugins');
_.each(OCA.WorkflowEngine.availablePlugins, function(plugin) {
if (_.isFunction(plugin.getCheck)) {
OCA.WorkflowEngine.availableChecks.push(plugin.getCheck(classname));
}
});
}
this.collection.fetch({
data: {
'class': classname
}
});
this.collection.once('sync', this.render, this);
},
add: function() {
var operation = this.collection.create();
this.renderOperation(operation);
},
renderOperation: function(subView) {
var operationsElement = this.$el.find('.operations');
operationsElement.append(subView.$el);
subView.render();
},
render: function() {
this.$el.html(this.template());
this.collection.each(this.renderOperation, this);
}
});
})();

View File

@ -1,86 +1,82 @@
<template>
<div class="check" @click="showDelete" v-click-outside="hideDelete">
<Multiselect v-model="currentOption" :options="options" label="name"
track-by="class" :allow-empty="false" :placeholder="t('workflowengine', 'Select a filter')"
@input="updateCheck" ref="checkSelector"></Multiselect>
<Multiselect v-if="currentOption" v-model="currentOperator" @input="updateCheck"
:options="operators" label="name" track-by="operator"
:allow-empty="false" :placeholder="t('workflowengine', 'Select a comparator')"></Multiselect>
<component v-if="currentOperator && currentComponent" :is="currentOption.component()" v-model="check.value" />
<input v-else-if="currentOperator" type="text" v-model="check.value" @input="updateCheck" />
<div v-click-outside="hideDelete" class="check" @click="showDelete">
<Multiselect ref="checkSelector" v-model="currentOption" :options="options"
label="name" track-by="class" :allow-empty="false"
:placeholder="t('workflowengine', 'Select a filter')" @input="updateCheck" />
<Multiselect v-if="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" />
<input v-else-if="currentOperator" v-model="check.value" type="text"
@input="updateCheck">
<Actions>
<ActionButton icon="icon-delete" v-if="deleteVisible || !currentOption" @click="$emit('remove')" />
<ActionButton v-if="deleteVisible || !currentOption" icon="icon-delete" @click="$emit('remove')" />
</Actions>
</div>
</template>
<script>
import { Checks } from '../services/Operation';
import { Multiselect, Actions, ActionButton } from 'nextcloud-vue'
import ClickOutside from 'vue-click-outside';
import { Checks } from '../services/Operation'
import { Multiselect, Actions, ActionButton } from 'nextcloud-vue'
import ClickOutside from 'vue-click-outside'
export default {
name: 'Check',
components: {
ActionButton,
Actions,
Multiselect
export default {
name: 'Check',
components: {
ActionButton,
Actions,
Multiselect
},
directives: {
ClickOutside
},
props: {
check: {
type: Object,
required: true
}
},
data() {
return {
deleteVisible: false,
currentOption: null,
currentOperator: null,
options: []
}
},
computed: {
operators() {
if (!this.currentOption) { return [] }
return Checks[this.currentOption.class].operators
},
directives: {
ClickOutside
currentComponent() {
if (!this.currentOption) { return [] }
const currentComponent = Checks[this.currentOption.class].component
return currentComponent && currentComponent()
}
},
mounted() {
this.options = Object.values(Checks)
this.currentOption = Checks[this.check.class]
this.currentOperator = this.operators.find((operator) => operator.operator === this.check.operator)
},
methods: {
showDelete() {
this.deleteVisible = true
},
props: {
check: {
type: Object,
required: true
}
},
data() {
return {
deleteVisible: false,
currentOption: null,
currentOperator: null,
options: [],
}
},
mounted() {
this.options = Object.values(Checks)
this.currentOption = Checks[this.check.class]
this.currentOperator = this.operators.find((operator) => operator.operator === this.check.operator)
this.$nextTick(() => {
//this.$refs.checkSelector.$el.focus()
})
},
computed: {
operators() {
if (!this.currentOption)
return []
return Checks[this.currentOption.class].operators
},
currentComponent() {
if (!this.currentOption)
return []
let currentComponent = Checks[this.currentOption.class].component
return currentComponent && currentComponent()
}
},
methods: {
showDelete() {
this.deleteVisible = true
},
hideDelete() {
this.deleteVisible = false
},
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
this.$emit('update', this.check)
hideDelete() {
this.deleteVisible = false
},
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
this.$emit('update', this.check)
}
}
}
</script>
<style scoped lang="scss">

View File

@ -1,74 +1,63 @@
<template>
<div>
<Multiselect :value="currentEvent" :options="allEvents" label="name" track-by="id" :allow-empty="false" :disabled="allEvents.length <= 1" @input="updateEvent">
<template slot="singleLabel" slot-scope="props">
<img class="option__icon" :src="props.option.icon" />
<span class="option__title option__title_single">{{ props.option.name }}</span>
</template>
<template slot="option" slot-scope="props">
<img class="option__icon" :src="props.option.icon" />
<span class="option__title">{{ props.option.name }}</span>
</template>
</Multiselect>
<div v-if="operation.isComplex && operation.fixedEntity !== ''">
<img class="option__icon" :src="entity.icon">
<span class="option__title option__title_single">{{ entity.name }}</span>
</div>
<Multiselect v-else :value="currentEvent" :options="allEvents"
label="eventName" track-by="id" :allow-empty="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>
<template slot="option" slot-scope="props">
<img class="option__icon" :src="props.option.entity.icon">
<span class="option__title">{{ props.option.displayName }}</span>
</template>
</Multiselect>
</div>
</template>
<script>
import { Multiselect } from 'nextcloud-vue'
import { Entities, operationService } from '../services/Operation'
import { Multiselect } from 'nextcloud-vue'
export default {
name: "Event",
components: {
Multiselect
export default {
name: 'Event',
components: {
Multiselect
},
props: {
rule: {
type: Object,
required: true
}
},
computed: {
entity() {
return this.$store.getters.getEntityForOperation(this.operation)
},
props: {
rule: {
type: Object,
required: true
}
},
mounted() {
this.updateEvent(this.currentEvent)
},
computed: {
currentEvent() {
if (!this.rule.event) {
return this.allEvents.length > 0 ? this.allEvents[0] : null
}
return this.allEvents.find(event => event.entity === this.rule.entity && event.event === this.rule.event)
},
allEvents() {
return this.operation.events.map((entityEventName) => {
const parts = entityEventName.split('::')
const entityId = parts[0]
const eventName = parts[1]
const Entity = Entities.find((entity) => entity.id === entityId)
const Event = Entity.events.find((event) => event.eventName === eventName)
return {
entity: entityId,
id: entityEventName,
events: eventName,
name: Event.displayName,
icon: Entity.icon,
checks: Entity.checks,
}
})
},
operation() {
return operationService.get(this.rule.class)
}
},
methods: {
updateEvent(event) {
if (this.rule.entity !== event.entity || this.rule.events !== '["' + event.event + '"]') {
this.$set(this.rule, 'entity', event.entity)
this.$set(this.rule, 'event', event.event)
this.$emit('update', this.rule)
}
operation() {
return this.$store.getters.getOperationForRule(this.rule)
},
allEvents() {
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)
}
},
methods: {
updateEvent(event) {
this.$set(this.rule, 'entity', event.entity.id)
this.$set(this.rule, 'events', [event.eventName])
this.$store.dispatch('updateRule', this.rule)
}
}
}
</script>
<style scoped>

View File

@ -1,34 +1,26 @@
<template>
<div class="actions__item" :class="{'colored': !!color}" :style="{ backgroundColor: color }">
<div class="icon" :class="icon"></div>
<h3>{{ title }}</h3>
<small>{{ description }}</small>
<div class="actions__item" :class="{'colored': colored}" :style="{ backgroundColor: colored ? operation.color : 'transparent' }">
<div class="icon" :class="operation.iconClass" :style="{ backgroundImage: operation.iconClass ? '' : `url(${operation.icon})` }" />
<h3>{{ operation.name }}</h3>
<small>{{ operation.description }}</small>
<slot />
</div>
</template>
<script>
export default {
name: "Operation",
props: {
icon: {
type: String,
required: true
},
title: {
type: String,
required: true
},
description: {
type: String,
required: true
},
color: {
type: String,
required: false
},
export default {
name: 'Operation',
props: {
operation: {
type: Object,
required: true
},
colored: {
type: Boolean,
default: true
}
}
}
</script>
<style scoped lang="scss">
@ -50,6 +42,7 @@
background-position: center center;
margin-top: 10px;
margin-bottom: 20px;
background-repeat: no-repeat;
}
h3, small {
padding: 6px;

View File

@ -1,38 +1,39 @@
<template>
<multiselect :options="options" track-by="id" label="text" v-model="value"></multiselect>
<Multiselect v-model="value" :options="options" track-by="id"
label="text" @input="$emit('input', value.id)" />
</template>
<script>
const pdfConvertOptions = [
{
id: 'keep;preserve',
text: t('workflow_pdf_converter', 'Keep original, preserve existing PDFs'),
},
{
id: 'keep;overwrite',
text: t('workflow_pdf_converter', 'Keep original, overwrite existing PDF'),
},
{
id: 'delete;preserve',
text: t('workflow_pdf_converter', 'Delete original, preserve existing PDFs'),
},
{
id: 'delete;overwrite',
text: t('workflow_pdf_converter', 'Delete original, overwrite existing PDF'),
},
]
import { Multiselect } from 'nextcloud-vue'
import { Multiselect } from 'nextcloud-vue'
export default {
name: "ConvertToPdf",
components: {Multiselect},
data() {
return {
options: pdfConvertOptions,
value: pdfConvertOptions[0]
}
const pdfConvertOptions = [
{
id: 'keep;preserve',
text: t('workflow_pdf_converter', 'Keep original, preserve existing PDFs')
},
{
id: 'keep;overwrite',
text: t('workflow_pdf_converter', 'Keep original, overwrite existing PDF')
},
{
id: 'delete;preserve',
text: t('workflow_pdf_converter', 'Delete original, preserve existing PDFs')
},
{
id: 'delete;overwrite',
text: t('workflow_pdf_converter', 'Delete original, overwrite existing PDF')
}
]
export default {
name: 'ConvertToPdf',
components: { Multiselect },
data() {
return {
options: pdfConvertOptions,
value: pdfConvertOptions[0]
}
}
}
</script>
<style scoped>
@ -42,4 +43,4 @@
margin: auto;
text-align: center;
}
</style>
</style>

View File

@ -1,22 +1,24 @@
<template>
<multiselect :options="options" v-model="value" track-by="id" label="title" :multiple="true" :tagging="true" @input="$emit('input', value.map(item => item.id))"></multiselect>
<Multiselect v-model="value" :options="options" track-by="id"
label="title" :multiple="true" :tagging="true"
@input="$emit('input', value.map(item => item.id))" />
</template>
<script>
// TODO: fetch tags from endpoint
const tags = [{id: 3, title: 'foo'}, {id: 4, title: 'bar'}]
// TODO: fetch tags from endpoint
import { Multiselect } from 'nextcloud-vue'
import { Multiselect } from 'nextcloud-vue'
export default {
name: "Tag",
components: {Multiselect},
data() {
return {
options: tags,
value: null
}
const tags = [{ id: 3, title: 'foo' }, { id: 4, title: 'bar' }]
export default {
name: 'Tag',
components: { Multiselect },
data() {
return {
options: tags,
value: null
}
}
}
</script>
<style scoped>
@ -26,4 +28,4 @@
margin: auto;
text-align: center;
}
</style>
</style>

View File

@ -4,143 +4,144 @@
<div class="trigger icon-confirm">
<p>
<span>{{ t('workflowengine', 'When') }}</span>
<Event :rule="rule" @update="updateRule"></Event>
<Event :rule="rule" @update="updateRule" />
</p>
<p v-for="check in rule.checks">
<span>{{ t('workflowengine', 'and') }}</span>
<Check :check="check" @update="updateRule" @remove="removeCheck(check)"></Check>
<Check :check="check" @update="updateRule" @remove="removeCheck(check)" />
</p>
<p>
<span> </span>
<input v-if="lastCheckComplete" type="button" class="check--add" @click="rule.checks.push({class: null, operator: null, value: null})" value="Add a new filter"/>
<span />
<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="action">
<div class="buttons">
<Actions>
<ActionButton v-if="rule.id === -1" icon="icon-close" @click="$emit('cancel')">Cancel rule creation</ActionButton>
<ActionButton v-else icon="icon-close" @click="deleteRule">Remove rule</ActionButton>
<ActionButton v-if="rule.id < -1" icon="icon-close" @click="cancelRule">
Cancel rule creation
</ActionButton>
<ActionButton v-else icon="icon-close" @click="deleteRule">
Remove rule
</ActionButton>
</Actions>
<button class="status-button icon" :class="ruleStatus.class" v-tooltip="ruleStatus.tooltip" @click="saveRule">{{ ruleStatus.title }}</button>
<button v-tooltip="ruleStatus.tooltip" class="status-button icon" :class="ruleStatus.class"
@click="saveRule">
{{ ruleStatus.title }}
</button>
</div>
<Operation :icon="operation.icon" :title="operation.title" :description="operation.description">
<component v-if="operation.options" :is="operation.options" v-model="operation.operation" @input="updateOperation" />
<Operation :operation="operation" :colored="false">
<component :is="operation.options" v-if="operation.options" v-model="rule.operation"
@input="updateOperation" />
</Operation>
</div>
</div>
</template>
<script>
import { Actions, ActionButton, Tooltip } from 'nextcloud-vue'
import Event from './Event'
import Check from './Check'
import Operation from './Operation'
import { operationService } from '../services/Operation'
import axios from 'nextcloud-axios'
import confirmPassword from 'nextcloud-password-confirmation'
import {getApiUrl} from '../helpers/api';
import { Actions, ActionButton, Tooltip } from 'nextcloud-vue'
import Event from './Event'
import Check from './Check'
import Operation from './Operation'
export default {
name: 'Rule',
components: {
Operation, Check, Event, Actions, ActionButton
export default {
name: 'Rule',
components: {
Operation, Check, Event, Actions, ActionButton
},
directives: {
Tooltip
},
props: {
rule: {
type: Object,
required: true
}
},
data() {
return {
editing: false,
checks: [],
error: null,
dirty: this.rule.id < 0,
checking: false
}
},
computed: {
operation() {
return this.$store.getters.getOperationForRule(this.rule)
},
directives: {
Tooltip
ruleStatus() {
if (this.error) {
return {
title: t('workflowengine', 'The configuration is invalid'),
class: 'icon-close-white invalid',
tooltip: { placement: 'bottom', show: true, content: this.error }
}
}
if (!this.dirty || this.checking) {
return { title: 'Active', class: 'icon icon-checkmark' }
}
return { title: 'Save', class: 'icon-confirm-white primary' }
},
props: {
rule: {
type: Object,
required: true,
lastCheckComplete() {
const lastCheck = this.rule.checks[this.rule.checks.length - 1]
return typeof lastCheck === 'undefined' || lastCheck.class !== null
}
},
methods: {
async updateOperation(operation) {
this.$set(this.rule, 'operation', operation)
await this.updateRule()
},
async updateRule() {
this.checking = true
if (!this.dirty) {
this.dirty = true
}
try {
// TODO: add new verify endpoint
// let result = await axios.post(OC.generateUrl(`/apps/workflowengine/operations/test`), this.rule)
this.error = null
this.checking = false
this.$store.dispatch('updateRule', this.rule)
} catch (e) {
console.error('Failed to update operation', e)
this.error = e.response.ocs.meta.message
this.checking = false
}
},
data () {
return {
editing: false,
operationService,
checks: [],
error: null,
dirty: this.rule.id === -1,
checking: false
async saveRule() {
try {
await this.$store.dispatch('pushUpdateRule', this.rule)
this.dirty = false
this.error = null
} catch (e) {
console.error('Failed to save operation')
this.error = e.response.data.ocs.meta.message
}
},
computed: {
operation() {
return this.operationService.get(this.rule.class)
},
ruleStatus() {
if (this.error) {
return { title: 'Invalid', class: 'icon-close-white invalid', tooltip: { placement: 'bottom', show: true, content: escapeHTML(this.error) } }
}
if (!this.dirty || this.checking) {
return { title: 'Active', class: 'icon icon-checkmark' }
}
return { title: 'Save', class: 'icon-confirm-white primary' }
},
lastCheckComplete() {
const lastCheck = this.rule.checks[this.rule.checks.length-1]
return typeof lastCheck === 'undefined' || lastCheck.class !== null
async deleteRule() {
try {
await this.$store.dispatch('deleteRule', this.rule)
} catch (e) {
console.error('Failed to delete operation')
this.error = e.response.data.ocs.meta.message
}
},
methods: {
updateOperation(operation) {
this.$set(this.rule, 'operation', operation)
},
async updateRule() {
this.checking = true
if (!this.dirty) {
this.dirty = true
}
try {
// TODO: add new verify endpoint
//let result = await axios.post(OC.generateUrl(`/apps/workflowengine/operations/test`), this.rule)
this.error = null
this.checking = false
} catch (e) {
console.error('Failed to update operation', e)
this.error = e.response.ocs.meta.message
this.checking = false
}
},
async saveRule() {
try {
await confirmPassword()
let result
if (this.rule.id === -1) {
result = await axios.post(getApiUrl(''), {...this.rule, events: [this.rule.event]})
this.rule.id = result.data.ocs.data.id
} else {
result = await axios.put(getApiUrl(`/${this.rule.id}`), {...this.rule, events: [this.rule.event]})
}
this.$emit('update', this.rule)
this.dirty = false
this.error = null
} catch (e) {
console.log(e.response.data.ocs.meta.message)
console.error('Failed to update operation', e)
this.error = e.response.data.ocs.meta.message
}
},
async deleteRule() {
try {
await confirmPassword()
await axios.delete(getApiUrl(`/${this.rule.id}`))
this.$emit('delete')
} catch (e) {
console.error('Failed to delete operation')
this.error = e.response
}
},
removeCheck(check) {
const index = this.rule.checks.findIndex(item => item === check)
if (index !== -1) {
this.rule.checks.splice(index, 1)
}
cancelRule() {
this.$store.dispatch('removeRule', this.rule)
},
removeCheck(check) {
const index = this.rule.checks.findIndex(item => item === check)
if (index < 0) {
this.rule.checks.splice(index, 1)
}
}
}
}
</script>
<style scoped lang="scss">
@ -162,6 +163,7 @@
.status-button.invalid {
background-color: var(--color-warning);
color: #fff;
border: none;
}
.rule {

View File

@ -1,39 +1,39 @@
<template>
<input type="text" />
<input type="text">
</template>
<script>
import { Multiselect } from 'nextcloud-vue'
import { Multiselect } from 'nextcloud-vue'
export default {
name: 'SizeValue',
components: {
Multiselect
},
data() {
return {
predefinedTypes: [
{
icon: 'icon-picture',
label: 'Images',
pattern: '/image\\/.*/'
},
{
icon: 'icon-category-office',
label: 'Office documents',
pattern: '/(vnd\\.(ms-|openxmlformats-).*))$/'
},
{
icon: 'icon-filetype-file',
label: 'PDF documents',
pattern: 'application/pdf'
}
]
}
export default {
name: 'SizeValue',
components: {
Multiselect
},
data() {
return {
predefinedTypes: [
{
icon: 'icon-picture',
label: 'Images',
pattern: '/image\\/.*/'
},
{
icon: 'icon-category-office',
label: 'Office documents',
pattern: '/(vnd\\.(ms-|openxmlformats-).*))$/'
},
{
icon: 'icon-filetype-file',
label: 'PDF documents',
pattern: 'application/pdf'
}
]
}
}
}
</script>
<style scoped>
</style>
</style>

View File

@ -1,28 +1,29 @@
<template>
<input type="text" placeholder="1 MB" @input="$emit('input', newValue)" v-model="newValue">
<input v-model="newValue" type="text" placeholder="1 MB"
@input="$emit('input', newValue)">
</template>
<script>
export default {
name: "SizeValue",
props: {
value: {
type: String
}
},
data() {
return {
newValue: this.value
}
},
watch: {
value() {
this.newValue = this.value
}
export default {
name: 'SizeValue',
props: {
value: {
type: String
}
},
data() {
return {
newValue: this.value
}
},
watch: {
value() {
this.newValue = this.value
}
}
}
</script>
<style scoped>
</style>
</style>

View File

@ -4,93 +4,68 @@
<h2>{{ t('workflowengine', 'Workflows') }}</h2>
<transition-group name="slide" tag="div" class="actions">
<Operation v-for="operation in getMainOperations" :key="operation.class"
:icon="operation.icon" :title="operation.title" :description="operation.description" :color="operation.color"
@click.native="createNewRule(operation)"></Operation>
<Operation v-for="operation in getMainOperations" :key="operation.id" :operation="operation"
@click.native="createNewRule(operation)" />
</transition-group>
<div class="actions__more" v-if="hasMoreOperations">
<div v-if="hasMoreOperations" class="actions__more">
<button class="icon" :class="showMoreOperations ? 'icon-triangle-n' : 'icon-triangle-s'"
@click="showMoreOperations=!showMoreOperations">
@click="showMoreOperations=!showMoreOperations">
{{ showMoreOperations ? t('workflowengine', 'Show less') : t('workflowengine', 'Show more') }}
</button>
</div>
</div>
<transition-group name="slide" v-if="rules.length > 0">
<Rule v-for="rule in rules" :key="rule.id" :rule="rule" @delete="removeRule(rule)" @cancel="removeRule(rule)" @update="updateRule"></Rule>
<transition-group v-if="rules.length > 0" name="slide">
<Rule v-for="rule in rules" :key="rule.id" :rule="rule" />
</transition-group>
</div>
</template>
<script>
import Rule from './Rule'
import Operation from './Operation'
import { operationService } from '../services/Operation'
import axios from 'nextcloud-axios'
import { getApiUrl } from '../helpers/api';
import Rule from './Rule'
import Operation from './Operation'
import { mapGetters, mapState } from 'vuex'
const ACTION_LIMIT = 3
const ACTION_LIMIT = 3
export default {
name: 'Workflow',
components: {
Operation,
Rule
export default {
name: 'Workflow',
components: {
Operation,
Rule
},
data() {
return {
showMoreOperations: false
}
},
computed: {
...mapGetters({
rules: 'getRules'
}),
...mapState({
operations: 'operations'
}),
hasMoreOperations() {
return Object.keys(this.operations).length > ACTION_LIMIT
},
async mounted() {
const { data } = await axios.get(getApiUrl(''))
this.rules = Object.values(data.ocs.data).flat()
},
data() {
return {
scope: OCP.InitialState.loadState('workflowengine', 'scope'),
operations: operationService,
showMoreOperations: false,
rules: []
}
},
computed: {
hasMoreOperations() {
return Object.keys(this.operations.getAll()).length > ACTION_LIMIT
},
getMainOperations() {
if (this.showMoreOperations) {
return Object.values(this.operations.getAll())
}
return Object.values(this.operations.getAll()).slice(0, ACTION_LIMIT)
},
getMoreOperations() {
return Object.values(this.operations.getAll()).slice(ACTION_LIMIT)
}
},
methods: {
updateRule(rule) {
let index = this.rules.findIndex((item) => rule === item)
this.$set(this.rules, index, rule)
},
removeRule(rule) {
let index = this.rules.findIndex((item) => rule === item)
this.rules.splice(index, 1)
},
showAllOperations() {
},
createNewRule(operation) {
this.rules.unshift({
id: -1,
class: operation.class,
entity: undefined,
event: undefined,
name: '', // unused in the new ui, there for legacy reasons
checks: [],
operation: operation.operation || ''
})
getMainOperations() {
if (this.showMoreOperations) {
return Object.values(this.operations)
}
return Object.values(this.operations).slice(0, ACTION_LIMIT)
}
},
mounted() {
this.$store.dispatch('fetchRules')
},
methods: {
createNewRule(operation) {
this.$store.dispatch('createNewRule', operation)
}
}
}
</script>
<style scoped lang="scss">
@ -119,7 +94,6 @@
background-position: 10px center;
}
.slide-enter-active {
-moz-transition-duration: 0.3s;
-webkit-transition-duration: 0.3s;

View File

@ -1,7 +0,0 @@
module.exports = function(classname) {
var check = OCA.WorkflowEngine.getCheckByClass(classname);
if (!_.isUndefined(check)) {
return check['operators'];
}
return [];
}

View File

@ -1,7 +0,0 @@
module.exports = function(currentValue, itemValue) {
if (currentValue === itemValue) {
return 'selected="selected"';
}
return "";
}

View File

@ -17,61 +17,61 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
import FileMimeType from './components/Values/FileMimeType'
import FileMimeType from './../components/Values/FileMimeType'
(function() {
OCA.WorkflowEngine = OCA.WorkflowEngine || {};
OCA.WorkflowEngine.Plugins = OCA.WorkflowEngine.Plugins || {};
OCA.WorkflowEngine = OCA.WorkflowEngine || {}
OCA.WorkflowEngine.Plugins = OCA.WorkflowEngine.Plugins || {}
OCA.WorkflowEngine.Plugins.FileMimeTypePlugin = {
getCheck: function() {
return {
'class': 'OCA\\WorkflowEngine\\Check\\FileMimeType',
'name': t('workflowengine', 'File MIME type'),
'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')}
class: 'OCA\\WorkflowEngine\\Check\\FileMimeType',
name: t('workflowengine', 'File MIME type'),
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') }
]
};
}
},
render: function(element, check) {
if (check['class'] !== 'OCA\\WorkflowEngine\\Check\\FileMimeType') {
return;
if (check.class !== 'OCA\\WorkflowEngine\\Check\\FileMimeType') {
return
}
var placeholder = 'text/plain';
if (check['operator'] === 'matches' || check['operator'] === '!matches') {
placeholder = '/^text\\/(plain|html)$/i';
var placeholder = 'text/plain'
if (check.operator === 'matches' || check.operator === '!matches') {
placeholder = '/^text\\/(plain|html)$/i'
if (this._validateRegex(check['value'])) {
$(element).removeClass('invalid-input');
if (this._validateRegex(check.value)) {
$(element).removeClass('invalid-input')
} else {
$(element).addClass('invalid-input');
$(element).addClass('invalid-input')
}
}
$(element).css('width', '250px')
.attr('placeholder', placeholder)
.attr('title', t('workflowengine', 'Example: {placeholder}', {placeholder: placeholder}))
.attr('title', t('workflowengine', 'Example: {placeholder}', { placeholder: placeholder }))
.addClass('has-tooltip')
.tooltip({
placement: 'bottom'
});
})
},
_validateRegex: function(string) {
var regexRegex = /^\/(.*)\/([gui]{0,3})$/,
result = regexRegex.exec(string);
return result !== null;
var regexRegex = /^\/(.*)\/([gui]{0,3})$/
var result = regexRegex.exec(string)
return result !== null
},
component: function () {
component: function() {
return FileMimeType
}
};
})();
}
})()
OC.Plugins.register('OCA.WorkflowEngine.CheckPlugins', OCA.WorkflowEngine.Plugins.FileMimeTypePlugin);
OC.Plugins.register('OCA.WorkflowEngine.CheckPlugins', OCA.WorkflowEngine.Plugins.FileMimeTypePlugin)

View File

@ -18,61 +18,61 @@
*
*/
(function () {
(function() {
OCA.WorkflowEngine = OCA.WorkflowEngine || {};
OCA.WorkflowEngine.Plugins = OCA.WorkflowEngine.Plugins || {};
OCA.WorkflowEngine = OCA.WorkflowEngine || {}
OCA.WorkflowEngine.Plugins = OCA.WorkflowEngine.Plugins || {}
OCA.WorkflowEngine.Plugins.FileNamePlugin = {
getCheck: function () {
getCheck: function() {
return {
'class': 'OCA\\WorkflowEngine\\Check\\FileName',
'name': t('workflowengine', 'File name'),
'operators': [
{'operator': 'is', 'name': t('workflowengine', 'is')},
{'operator': '!is', 'name': t('workflowengine', 'is not')},
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', 'matches')
},
{
'operator': '!matches',
'name': t('workflowengine', 'does not match')
operator: '!matches',
name: t('workflowengine', 'does not match')
}
]
};
}
},
render: function (element, check) {
if (check['class'] !== 'OCA\\WorkflowEngine\\Check\\FileName') {
return;
render: function(element, check) {
if (check.class !== 'OCA\\WorkflowEngine\\Check\\FileName') {
return
}
var placeholder = 'dummy.jpg';
if (check['operator'] === 'matches' || check['operator'] === '!matches') {
placeholder = '/^dummy-.+$/i';
var placeholder = 'dummy.jpg'
if (check.operator === 'matches' || check.operator === '!matches') {
placeholder = '/^dummy-.+$/i'
if (this._validateRegex(check['value'])) {
$(element).removeClass('invalid-input');
if (this._validateRegex(check.value)) {
$(element).removeClass('invalid-input')
} else {
$(element).addClass('invalid-input');
$(element).addClass('invalid-input')
}
}
$(element).css('width', '250px')
.attr('placeholder', placeholder)
.attr('title', t('workflowengine', 'Example: {placeholder}', {placeholder: placeholder}))
.attr('title', t('workflowengine', 'Example: {placeholder}', { placeholder: placeholder }))
.addClass('has-tooltip')
.tooltip({
placement: 'bottom'
});
})
},
_validateRegex: function (string) {
var regexRegex = /^\/(.*)\/([gui]{0,3})$/,
result = regexRegex.exec(string);
return result !== null;
_validateRegex: function(string) {
var regexRegex = /^\/(.*)\/([gui]{0,3})$/
var result = regexRegex.exec(string)
return result !== null
}
};
})();
}
})()
OC.Plugins.register('OCA.WorkflowEngine.CheckPlugins', OCA.WorkflowEngine.Plugins.FileNamePlugin);
OC.Plugins.register('OCA.WorkflowEngine.CheckPlugins', OCA.WorkflowEngine.Plugins.FileNamePlugin)

View File

@ -17,43 +17,43 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
import SizeValue from './components/Values/SizeValue'
import SizeValue from './../components/Values/SizeValue'
(function() {
OCA.WorkflowEngine = OCA.WorkflowEngine || {};
OCA.WorkflowEngine.Plugins = OCA.WorkflowEngine.Plugins || {};
OCA.WorkflowEngine = OCA.WorkflowEngine || {}
OCA.WorkflowEngine.Plugins = OCA.WorkflowEngine.Plugins || {}
OCA.WorkflowEngine.Plugins.FileSizePlugin = {
getCheck: function() {
return {
'class': 'OCA\\WorkflowEngine\\Check\\FileSize',
'name': t('workflowengine', 'File size (upload)'),
'operators': [
{'operator': 'less', 'name': t('workflowengine', 'less')},
{'operator': '!greater', 'name': t('workflowengine', 'less or equals')},
{'operator': '!less', 'name': t('workflowengine', 'greater or equals')},
{'operator': 'greater', 'name': t('workflowengine', 'greater')}
class: 'OCA\\WorkflowEngine\\Check\\FileSize',
name: t('workflowengine', 'File size (upload)'),
operators: [
{ operator: 'less', name: t('workflowengine', 'less') },
{ operator: '!greater', name: t('workflowengine', 'less or equals') },
{ operator: '!less', name: t('workflowengine', 'greater or equals') },
{ operator: 'greater', name: t('workflowengine', 'greater') }
]
};
}
},
render: function(element, check) {
if (check['class'] !== 'OCA\\WorkflowEngine\\Check\\FileSize') {
return;
if (check.class !== 'OCA\\WorkflowEngine\\Check\\FileSize') {
return
}
var placeholder = '12 MB'; // Do not translate!!!
var placeholder = '12 MB' // Do not translate!!!
$(element).css('width', '250px')
.attr('placeholder', placeholder)
.attr('title', t('workflowengine', 'Example: {placeholder}', {placeholder: placeholder}))
.attr('title', t('workflowengine', 'Example: {placeholder}', { placeholder: placeholder }))
.addClass('has-tooltip')
.tooltip({
placement: 'bottom'
});
})
},
component: function () {
component: function() {
return SizeValue
}
};
})();
}
})()
OC.Plugins.register('OCA.WorkflowEngine.CheckPlugins', OCA.WorkflowEngine.Plugins.FileSizePlugin);
OC.Plugins.register('OCA.WorkflowEngine.CheckPlugins', OCA.WorkflowEngine.Plugins.FileSizePlugin)

View File

@ -20,28 +20,28 @@
(function() {
OCA.WorkflowEngine = OCA.WorkflowEngine || {};
OCA.WorkflowEngine.Plugins = OCA.WorkflowEngine.Plugins || {};
OCA.WorkflowEngine = OCA.WorkflowEngine || {}
OCA.WorkflowEngine.Plugins = OCA.WorkflowEngine.Plugins || {}
OCA.WorkflowEngine.Plugins.FileSystemTagsPlugin = {
getCheck: function() {
this.collection = OC.SystemTags.collection;
this.collection = OC.SystemTags.collection
return {
'class': 'OCA\\WorkflowEngine\\Check\\FileSystemTags',
'name': t('workflowengine', 'File system tag'),
'operators': [
{'operator': 'is', 'name': t('workflowengine', 'is tagged with')},
{'operator': '!is', 'name': t('workflowengine', 'is not tagged with')}
class: 'OCA\\WorkflowEngine\\Check\\FileSystemTags',
name: t('workflowengine', 'File system tag'),
operators: [
{ operator: 'is', name: t('workflowengine', 'is tagged with') },
{ operator: '!is', name: t('workflowengine', 'is not tagged with') }
]
};
}
},
render: function(element, check) {
if (check['class'] !== 'OCA\\WorkflowEngine\\Check\\FileSystemTags') {
return;
if (check.class !== 'OCA\\WorkflowEngine\\Check\\FileSystemTags') {
return
}
$(element).css('width', '400px');
$(element).css('width', '400px')
$(element).select2({
allowClear: false,
@ -50,29 +50,29 @@
query: _.debounce(function(query) {
query.callback({
results: OC.SystemTags.collection.filterByName(query.term)
});
})
}, 100, true),
id: function(element) {
return element.get('id');
return element.get('id')
},
initSelection: function(element, callback) {
callback($(element).val());
callback($(element).val())
},
formatResult: function (tag) {
return OC.SystemTags.getDescriptiveTag(tag);
formatResult: function(tag) {
return OC.SystemTags.getDescriptiveTag(tag)
},
formatSelection: function (tagId) {
var tag = OC.SystemTags.collection.get(tagId);
formatSelection: function(tagId) {
var tag = OC.SystemTags.collection.get(tagId)
if (!_.isUndefined(tag)) {
return OC.SystemTags.getDescriptiveTag(tag);
return OC.SystemTags.getDescriptiveTag(tag)
}
},
escapeMarkup: function(m) {
return m;
return m
}
});
})
}
};
})();
}
})()
OC.Plugins.register('OCA.WorkflowEngine.CheckPlugins', OCA.WorkflowEngine.Plugins.FileSystemTagsPlugin);
OC.Plugins.register('OCA.WorkflowEngine.CheckPlugins', OCA.WorkflowEngine.Plugins.FileSystemTagsPlugin)

View File

@ -20,64 +20,64 @@
(function() {
OCA.WorkflowEngine = OCA.WorkflowEngine || {};
OCA.WorkflowEngine.Plugins = OCA.WorkflowEngine.Plugins || {};
OCA.WorkflowEngine = OCA.WorkflowEngine || {}
OCA.WorkflowEngine.Plugins = OCA.WorkflowEngine.Plugins || {}
OCA.WorkflowEngine.Plugins.RequestRemoteAddressPlugin = {
getCheck: function() {
return {
'class': 'OCA\\WorkflowEngine\\Check\\RequestRemoteAddress',
'name': t('workflowengine', 'Request remote address'),
'operators': [
{'operator': 'matchesIPv4', 'name': t('workflowengine', 'matches IPv4')},
{'operator': '!matchesIPv4', 'name': t('workflowengine', 'does not match IPv4')},
{'operator': 'matchesIPv6', 'name': t('workflowengine', 'matches IPv6')},
{'operator': '!matchesIPv6', 'name': t('workflowengine', 'does not match IPv6')}
class: 'OCA\\WorkflowEngine\\Check\\RequestRemoteAddress',
name: t('workflowengine', 'Request remote address'),
operators: [
{ operator: 'matchesIPv4', name: t('workflowengine', 'matches IPv4') },
{ operator: '!matchesIPv4', name: t('workflowengine', 'does not match IPv4') },
{ operator: 'matchesIPv6', name: t('workflowengine', 'matches IPv6') },
{ operator: '!matchesIPv6', name: t('workflowengine', 'does not match IPv6') }
]
};
}
},
render: function(element, check) {
if (check['class'] !== 'OCA\\WorkflowEngine\\Check\\RequestRemoteAddress') {
return;
if (check.class !== 'OCA\\WorkflowEngine\\Check\\RequestRemoteAddress') {
return
}
var placeholder = '127.0.0.1/32'; // Do not translate!!!
if (check['operator'] === 'matchesIPv6' || check['operator'] === '!matchesIPv6') {
placeholder = '::1/128'; // Do not translate!!!
if (this._validateIPv6(check['value'])) {
$(element).removeClass('invalid-input');
var placeholder = '127.0.0.1/32' // Do not translate!!!
if (check.operator === 'matchesIPv6' || check.operator === '!matchesIPv6') {
placeholder = '::1/128' // Do not translate!!!
if (this._validateIPv6(check.value)) {
$(element).removeClass('invalid-input')
} else {
$(element).addClass('invalid-input');
$(element).addClass('invalid-input')
}
} else {
if (this._validateIPv4(check['value'])) {
$(element).removeClass('invalid-input');
if (this._validateIPv4(check.value)) {
$(element).removeClass('invalid-input')
} else {
$(element).addClass('invalid-input');
$(element).addClass('invalid-input')
}
}
$(element).css('width', '300px')
.attr('placeholder', placeholder)
.attr('title', t('workflowengine', 'Example: {placeholder}', {placeholder: placeholder}))
.attr('title', t('workflowengine', 'Example: {placeholder}', { placeholder: placeholder }))
.addClass('has-tooltip')
.tooltip({
placement: 'bottom'
});
})
},
_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])$/,
result = regexRegex.exec(string);
return result !== null;
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
},
_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])$/,
result = regexRegex.exec(string);
return result !== null;
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
}
};
})();
}
})()
OC.Plugins.register('OCA.WorkflowEngine.CheckPlugins', OCA.WorkflowEngine.Plugins.RequestRemoteAddressPlugin);
OC.Plugins.register('OCA.WorkflowEngine.CheckPlugins', OCA.WorkflowEngine.Plugins.RequestRemoteAddressPlugin)

View File

@ -20,81 +20,81 @@
(function() {
OCA.WorkflowEngine = OCA.WorkflowEngine || {};
OCA.WorkflowEngine.Plugins = OCA.WorkflowEngine.Plugins || {};
OCA.WorkflowEngine = OCA.WorkflowEngine || {}
OCA.WorkflowEngine.Plugins = OCA.WorkflowEngine.Plugins || {}
OCA.WorkflowEngine.Plugins.RequestTimePlugin = {
timezones: [
"Europe/Berlin",
"Europe/London"
'Europe/Berlin',
'Europe/London'
],
_$element: null,
getCheck: function() {
return {
'class': 'OCA\\WorkflowEngine\\Check\\RequestTime',
'name': t('workflowengine', 'Request time'),
'operators': [
{'operator': 'in', 'name': t('workflowengine', 'between')},
{'operator': '!in', 'name': t('workflowengine', 'not between')}
class: 'OCA\\WorkflowEngine\\Check\\RequestTime',
name: t('workflowengine', 'Request time'),
operators: [
{ operator: 'in', name: t('workflowengine', 'between') },
{ operator: '!in', name: t('workflowengine', 'not between') }
]
};
}
},
render: function(element, check) {
if (check['class'] !== 'OCA\\WorkflowEngine\\Check\\RequestTime') {
return;
if (check.class !== 'OCA\\WorkflowEngine\\Check\\RequestTime') {
return
}
var startTime = '09:00',
endTime = '18:00',
timezone = jstz.determine().name(),
$element = $(element);
var startTime = '09:00'
var endTime = '18:00'
var timezone = jstz.determine().name()
var $element = $(element)
if (_.isString(check['value']) && check['value'] !== '') {
var value = JSON.parse(check['value']),
splittedStart = value[0].split(' ', 2),
splittedEnd = value[1].split(' ', 2);
if (_.isString(check.value) && check.value !== '') {
var value = JSON.parse(check.value)
var splittedStart = value[0].split(' ', 2)
var splittedEnd = value[1].split(' ', 2)
startTime = splittedStart[0];
endTime = splittedEnd[0];
timezone = splittedStart[1];
startTime = splittedStart[0]
endTime = splittedEnd[0]
timezone = splittedStart[1]
}
var valueJSON = JSON.stringify([startTime + ' ' + timezone, endTime + ' ' + timezone]);
if (check['value'] !== valueJSON) {
check['value'] = valueJSON;
$element.val(valueJSON);
var valueJSON = JSON.stringify([startTime + ' ' + timezone, endTime + ' ' + timezone])
if (check.value !== valueJSON) {
check.value = valueJSON
$element.val(valueJSON)
}
$element.css('display', 'none');
$element.css('display', 'none')
$('<input>')
.attr('type', 'text')
.attr('placeholder', t('workflowengine', 'Start'))
.attr('title', t('workflowengine', 'Example: {placeholder}', {placeholder: '16:00'}))
.attr('title', t('workflowengine', 'Example: {placeholder}', { placeholder: '16:00' }))
.addClass('has-tooltip')
.tooltip({
placement: 'bottom'
})
.addClass('start')
.val(startTime)
.insertBefore($element);
.insertBefore($element)
$('<input>')
.attr('type', 'text')
.attr('placeholder', t('workflowengine', 'End'))
.attr('title', t('workflowengine', 'Example: {placeholder}', {placeholder: '16:00'}))
.attr('title', t('workflowengine', 'Example: {placeholder}', { placeholder: '16:00' }))
.addClass('has-tooltip')
.tooltip({
placement: 'bottom'
})
.addClass('end')
.val(endTime)
.insertBefore($element);
.insertBefore($element)
var timezoneInput = $('<input>')
.attr('type', 'hidden')
.css('width', '250px')
.insertBefore($element)
.val(timezone);
.val(timezone)
timezoneInput.select2({
allowClear: false,
@ -104,93 +104,93 @@
url: OC.generateUrl('apps/workflowengine/timezones'),
dataType: 'json',
quietMillis: 100,
data: function (term) {
data: function(term) {
if (term === '') {
// Default search in the same continent...
term = jstz.determine().name().split('/');
term = term[0];
term = jstz.determine().name().split('/')
term = term[0]
}
return {
search: term
};
}
},
results: function (response) {
var results = [];
results: function(response) {
var results = []
$.each(response, function(timezone) {
results.push({ id: timezone });
});
results.push({ id: timezone })
})
return {
results: results,
more: false
};
}
}
},
initSelection: function (element, callback) {
callback(element.val());
initSelection: function(element, callback) {
callback(element.val())
},
formatResult: function (element) {
return '<span>' + element.id + '</span>';
formatResult: function(element) {
return '<span>' + element.id + '</span>'
},
formatSelection: function (element) {
formatSelection: function(element) {
if (!_.isUndefined(element.id)) {
element = element.id;
element = element.id
}
return '<span>' + element + '</span>';
return '<span>' + element + '</span>'
}
});
})
// Has to be added after select2 for `event.target.classList`
timezoneInput.addClass('timezone');
timezoneInput.addClass('timezone')
$element.parent()
.on('change', '.start', _.bind(this.update, this))
.on('change', '.end', _.bind(this.update, this))
.on('change', '.timezone', _.bind(this.update, this));
.on('change', '.timezone', _.bind(this.update, this))
this._$element = $element;
this._$element = $element
},
update: function(event) {
var value = event.target.value,
key = null;
var value = event.target.value
var key = null
for (var i = 0; i < event.target.classList.length; i++) {
key = event.target.classList[i];
key = event.target.classList[i]
}
if (key === null) {
console.warn('update triggered but element doesn\'t have any class');
return;
console.warn('update triggered but element doesn\'t have any class')
return
}
var data = JSON.parse(this._$element.val()),
startTime = moment(data[0].split(' ', 2)[0], 'H:m Z'),
endTime = moment(data[1].split(' ', 2)[0], 'H:m Z'),
timezone = data[0].split(' ', 2)[1];
var data = JSON.parse(this._$element.val())
var startTime = moment(data[0].split(' ', 2)[0], 'H:m Z')
var endTime = moment(data[1].split(' ', 2)[0], 'H:m Z')
var timezone = data[0].split(' ', 2)[1]
if (key === 'start' || key === 'end') {
var parsedDate = moment(value, ['H:m', 'h:m a'], true).format('HH:mm');
var parsedDate = moment(value, ['H:m', 'h:m a'], true).format('HH:mm')
if (parsedDate === 'Invalid date') {
return;
return
}
var indexValue = 0;
var indexValue = 0
if (key === 'end') {
indexValue = 1;
indexValue = 1
}
data[indexValue] = parsedDate + ' ' + timezone;
data[indexValue] = parsedDate + ' ' + timezone
}
if (key === 'timezone') {
data[0] = startTime.format('HH:mm') + ' ' + value;
data[1] = endTime.format('HH:mm') + ' ' + value;
data[0] = startTime.format('HH:mm') + ' ' + value
data[1] = endTime.format('HH:mm') + ' ' + value
}
this._$element.val(JSON.stringify(data));
this._$element.trigger('change');
this._$element.val(JSON.stringify(data))
this._$element.trigger('change')
}
};
})();
}
})()
OC.Plugins.register('OCA.WorkflowEngine.CheckPlugins', OCA.WorkflowEngine.Plugins.RequestTimePlugin);
OC.Plugins.register('OCA.WorkflowEngine.CheckPlugins', OCA.WorkflowEngine.Plugins.RequestTimePlugin)

View File

@ -20,98 +20,97 @@
(function() {
OCA.WorkflowEngine = OCA.WorkflowEngine || {};
OCA.WorkflowEngine.Plugins = OCA.WorkflowEngine.Plugins || {};
OCA.WorkflowEngine = OCA.WorkflowEngine || {}
OCA.WorkflowEngine.Plugins = OCA.WorkflowEngine.Plugins || {}
OCA.WorkflowEngine.Plugins.RequestURLPlugin = {
predefinedValues: ['webdav'],
getCheck: function() {
return {
'class': 'OCA\\WorkflowEngine\\Check\\RequestURL',
'name': t('workflowengine', 'Request URL'),
'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')}
class: 'OCA\\WorkflowEngine\\Check\\RequestURL',
name: t('workflowengine', 'Request URL'),
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') }
]
};
}
},
render: function(element, check) {
if (check['class'] !== 'OCA\\WorkflowEngine\\Check\\RequestURL') {
return;
if (check.class !== 'OCA\\WorkflowEngine\\Check\\RequestURL') {
return
}
var placeholder = 'https://localhost/index.php';
var placeholder = 'https://localhost/index.php'
if (check['operator'] === 'matches' || check['operator'] === '!matches') {
placeholder = '/^https\\:\\/\\/localhost\\/index\\.php$/i';
if (check.operator === 'matches' || check.operator === '!matches') {
placeholder = '/^https\\:\\/\\/localhost\\/index\\.php$/i'
}
$(element).css('width', '250px')
.attr('placeholder', placeholder)
.attr('title', t('workflowengine', 'Example: {placeholder}', {placeholder: placeholder}))
.attr('title', t('workflowengine', 'Example: {placeholder}', { placeholder: placeholder }))
.addClass('has-tooltip')
.tooltip({
placement: 'bottom'
});
})
if (check['operator'] === 'matches' || check['operator'] === '!matches') {
if (this._validateRegex(check['value'])) {
$(element).removeClass('invalid-input');
if (check.operator === 'matches' || check.operator === '!matches') {
if (this._validateRegex(check.value)) {
$(element).removeClass('invalid-input')
} else {
$(element).addClass('invalid-input');
$(element).addClass('invalid-input')
}
} else {
var self = this,
data = [
var self = this
var data = [
{
text: t('workflowengine', 'Predefined URLs'),
children: [
{id: 'webdav', text: t('workflowengine', 'Files WebDAV')}
{ id: 'webdav', text: t('workflowengine', 'Files WebDAV') }
]
}
];
if (this.predefinedValues.indexOf(check['value']) === -1) {
]
if (this.predefinedValues.indexOf(check.value) === -1) {
data.unshift({
id: check['value'],
text: check['value']
id: check.value,
text: check.value
})
}
$(element).select2({
data: data,
createSearchChoice: function(term) {
if (self.predefinedValues.indexOf(check['value']) === -1) {
if (self.predefinedValues.indexOf(check.value) === -1) {
return {
id: term,
text: term
};
}
}
},
id: function(element) {
return element.id;
return element.id
},
formatResult: function (tag) {
return tag.text;
formatResult: function(tag) {
return tag.text
},
formatSelection: function (tag) {
return tag.text;
formatSelection: function(tag) {
return tag.text
},
escapeMarkup: function(m) {
return m;
return m
}
})
}
},
_validateRegex: function(string) {
var regexRegex = /^\/(.*)\/([gui]{0,3})$/,
result = regexRegex.exec(string);
return result !== null;
var regexRegex = /^\/(.*)\/([gui]{0,3})$/
var result = regexRegex.exec(string)
return result !== null
}
};
})();
}
})()
OC.Plugins.register('OCA.WorkflowEngine.CheckPlugins', OCA.WorkflowEngine.Plugins.RequestURLPlugin);
OC.Plugins.register('OCA.WorkflowEngine.CheckPlugins', OCA.WorkflowEngine.Plugins.RequestURLPlugin)

View File

@ -20,66 +20,66 @@
(function() {
OCA.WorkflowEngine = OCA.WorkflowEngine || {};
OCA.WorkflowEngine.Plugins = OCA.WorkflowEngine.Plugins || {};
OCA.WorkflowEngine = OCA.WorkflowEngine || {}
OCA.WorkflowEngine.Plugins = OCA.WorkflowEngine.Plugins || {}
OCA.WorkflowEngine.Plugins.RequestUserAgentPlugin = {
predefinedValues: ['android', 'ios', 'desktop'],
getCheck: function() {
return {
'class': 'OCA\\WorkflowEngine\\Check\\RequestUserAgent',
'name': t('workflowengine', 'Request user agent'),
'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')}
class: 'OCA\\WorkflowEngine\\Check\\RequestUserAgent',
name: t('workflowengine', 'Request user agent'),
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') }
]
};
}
},
render: function(element, check) {
if (check['class'] !== 'OCA\\WorkflowEngine\\Check\\RequestUserAgent') {
return;
if (check.class !== 'OCA\\WorkflowEngine\\Check\\RequestUserAgent') {
return
}
var placeholder = 'Mozilla/5.0 User Agent';
var placeholder = 'Mozilla/5.0 User Agent'
if (check.operator === 'matches' || check.operator === '!matches') {
placeholder = '/^Mozilla\\/5\\.0 (.*)$/i';
placeholder = '/^Mozilla\\/5\\.0 (.*)$/i'
}
$(element).css('width', '250px')
.attr('placeholder', placeholder)
.attr('title', t('workflowengine', 'Example: {placeholder}', {placeholder: placeholder}))
.attr('title', t('workflowengine', 'Example: {placeholder}', { placeholder: placeholder }))
.addClass('has-tooltip')
.tooltip({
placement: 'bottom'
});
})
if (check.operator === 'matches' || check.operator === '!matches') {
if (this._validateRegex(check.value)) {
$(element).removeClass('invalid-input');
$(element).removeClass('invalid-input')
} else {
$(element).addClass('invalid-input');
$(element).addClass('invalid-input')
}
} else {
var self = this,
data = [
var self = this
var data = [
{
text: t('workflowengine', 'Sync clients'),
children: [
{id: 'android', text: t('workflowengine', 'Android client')},
{id: 'ios', text: t('workflowengine', 'iOS client')},
{id: 'desktop', text: t('workflowengine', 'Desktop client')},
{id: 'mail', text: t('workflowengine', 'Thunderbird & Outlook addons')}
{ id: 'android', text: t('workflowengine', 'Android client') },
{ id: 'ios', text: t('workflowengine', 'iOS client') },
{ id: 'desktop', text: t('workflowengine', 'Desktop client') },
{ id: 'mail', text: t('workflowengine', 'Thunderbird & Outlook addons') }
]
}
];
]
if (this.predefinedValues.indexOf(check.value) === -1) {
data.unshift({
id: check.value,
text: check.value
});
})
}
$(element).select2({
@ -89,31 +89,31 @@
return {
id: term,
text: term
};
}
}
},
id: function(element) {
return element.id;
return element.id
},
formatResult: function (tag) {
return tag.text;
formatResult: function(tag) {
return tag.text
},
formatSelection: function (tag) {
return tag.text;
formatSelection: function(tag) {
return tag.text
},
escapeMarkup: function(m) {
return m;
return m
}
})
}
},
_validateRegex: function(string) {
var regexRegex = /^\/(.*)\/([gui]{0,3})$/,
result = regexRegex.exec(string);
return result !== null;
var regexRegex = /^\/(.*)\/([gui]{0,3})$/
var result = regexRegex.exec(string)
return result !== null
}
};
})();
}
})()
OC.Plugins.register('OCA.WorkflowEngine.CheckPlugins', OCA.WorkflowEngine.Plugins.RequestUserAgentPlugin);
OC.Plugins.register('OCA.WorkflowEngine.CheckPlugins', OCA.WorkflowEngine.Plugins.RequestUserAgentPlugin)

View File

@ -20,56 +20,56 @@
(function() {
OCA.WorkflowEngine = OCA.WorkflowEngine || {};
OCA.WorkflowEngine.Plugins = OCA.WorkflowEngine.Plugins || {};
OCA.WorkflowEngine = OCA.WorkflowEngine || {}
OCA.WorkflowEngine.Plugins = OCA.WorkflowEngine.Plugins || {}
OCA.WorkflowEngine.Plugins.UserGroupMembershipPlugin = {
getCheck: function() {
return {
'class': 'OCA\\WorkflowEngine\\Check\\UserGroupMembership',
'name': t('workflowengine', 'User group membership'),
'operators': [
{'operator': 'is', 'name': t('workflowengine', 'is member of')},
{'operator': '!is', 'name': t('workflowengine', 'is not member of')}
class: 'OCA\\WorkflowEngine\\Check\\UserGroupMembership',
name: t('workflowengine', 'User group membership'),
operators: [
{ operator: 'is', name: t('workflowengine', 'is member of') },
{ operator: '!is', name: t('workflowengine', 'is not member of') }
]
};
}
},
render: function(element, check, groups) {
if (check['class'] !== 'OCA\\WorkflowEngine\\Check\\UserGroupMembership') {
return;
if (check.class !== 'OCA\\WorkflowEngine\\Check\\UserGroupMembership') {
return
}
$(element).css('width', '400px');
$(element).css('width', '400px')
$(element).select2({
data: { results: groups, text: 'displayname' },
initSelection: function (element, callback) {
var groupId = element.val();
initSelection: function(element, callback) {
var groupId = element.val()
if (groupId && groups.length > 0) {
callback({
id: groupId,
displayname: groups.find(function (group) {
return group.id === groupId;
displayname: groups.find(function(group) {
return group.id === groupId
}).displayname
});
})
} else if (groupId) {
callback({
id: groupId,
displayname: groupId
});
})
} else {
callback();
callback()
}
},
formatResult: function (element) {
return '<span>' + escapeHTML(element.displayname) + '</span>';
formatResult: function(element) {
return '<span>' + escapeHTML(element.displayname) + '</span>'
},
formatSelection: function (element) {
return '<span title="'+escapeHTML(element.id)+'">'+escapeHTML(element.displayname)+'</span>';
formatSelection: function(element) {
return '<span title="' + escapeHTML(element.id) + '">' + escapeHTML(element.displayname) + '</span>'
}
});
})
}
};
})();
}
})()
OC.Plugins.register('OCA.WorkflowEngine.CheckPlugins', OCA.WorkflowEngine.Plugins.UserGroupMembershipPlugin);
OC.Plugins.register('OCA.WorkflowEngine.CheckPlugins', OCA.WorkflowEngine.Plugins.UserGroupMembershipPlugin)

View File

@ -13,17 +13,9 @@ const ALL_CHECKS = [
'OCA\\WorkflowEngine\\Check\\UserGroupMembership'
]
const Entities = OCP.InitialState.loadState('workflowengine', 'entities').map(entity => {
return {
...entity,
// TODO: see if we should have this defined in the backend as well
checks: [...ALL_CHECKS]
}
})
const Checks = Object.values(OCA.WorkflowEngine.Plugins).map((plugin) => {
if (plugin.component) {
return {...plugin.getCheck(), component: plugin.component}
return { ...plugin.getCheck(), component: plugin.component }
}
return plugin.getCheck()
}).reduce((obj, item) => {
@ -31,113 +23,55 @@ const Checks = Object.values(OCA.WorkflowEngine.Plugins).map((plugin) => {
return obj
}, {})
const Operators = OCP.InitialState.loadState('workflowengine', 'operators')
/**
* Register operations
* TODO: should be provided by the backend
* Extend operators for testing
*/
class OperationService {
constructor() {
this.operations = {}
}
registerOperation (operation) {
this.operations[operation.class] = Object.assign({
color: 'var(--color-primary)'
}, operation)
}
getAll() {
return this.operations
}
get(className) {
return this.operations[className]
}
}
const operationService = new OperationService()
operationService.registerOperation({
class: 'OCA\\FilesAccessControl\\Operation',
title: 'Block access',
description: 'Deny access to files when they are accessed',
icon: 'icon-block',
Operators['OCA\\FilesAccessControl\\Operation'] = {
...Operators['OCA\\FilesAccessControl\\Operation'],
color: 'var(--color-error)',
entites: [
entities: [
'OCA\\WorkflowEngine\\Entity\\File'
],
events: [
// TODO: this is probably handled differently since there is no regular event for files access control
'OCA\\WorkflowEngine\\Entity\\File::postTouch'
],
operation: 'deny'
})
operationService.registerOperation({
class: 'OCA\\TestExample\\Operation1',
title: 'Rename file',
description: '🚧 For UI mocking only',
icon: 'icon-address-white',
color: 'var(--color-success)',
entites: [],
events: [],
operation: 'deny'
})
operationService.registerOperation({
class: 'OCA\\TestExample\\Operation2',
title: 'Notify me',
description: '🚧 For UI mocking only',
icon: 'icon-comment-white',
color: 'var(--color-warning)',
entites: [],
events: [],
operation: 'deny'
})
operationService.registerOperation({
class: 'OCA\\TestExample\\Operation3',
title: 'Call a web hook',
description: '🚧 For UI mocking only',
icon: 'icon-category-integration icon-invert',
color: 'var(--color-primary)',
entites: [],
events: [],
operation: 'deny'
})
operationService.registerOperation({
class: 'OCA\\FilesAutomatedTagging\\Operation',
title: 'Tag a file',
description: 'Assign a tag to a file',
icon: 'icon-tag-white',
events: [
'WorkflowEngine_Entity_File::postWrite',
//'WorkflowEngine_Entity_File::postTagged',
],
options: Tag
})
operationService.registerOperation({
class: 'OCA\\WorkflowPDFConverter\\Operation',
title: 'Convert to PDF',
}
Operators['OCA\\WorkflowPDFConverter\\Operation'] = {
id: 'OCA\\WorkflowPDFConverter\\Operation',
name: 'Convert to PDF',
description: 'Generate a PDF file',
color: '#dc5047',
icon: 'icon-convert-pdf',
events: [
'WorkflowEngine_Entity_File::postWrite',
//EVENT_FILE_TAGGED
],
iconClass: 'icon-convert-pdf',
options: ConvertToPdf
})
console.debug('[InitialState] Entities', Entities)
console.debug('[WorkflowEngine] Checks', Checks)
console.debug('[WorkflowEngine] Operations', operationService.operations)
}
Operators['OCA\\TestExample\\Operation1'] = {
id: 'OCA\\TestExample\\Operation1',
name: 'Rename file',
description: '🚧 For UI mocking only',
iconClass: 'icon-address-white',
color: 'var(--color-success)',
operation: 'deny'
}
Operators['OCA\\TestExample\\Operation2'] = {
id: 'OCA\\TestExample\\Operation2',
name: 'Notify me',
description: '🚧 For UI mocking only',
iconClass: 'icon-comment-white',
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 {
Entities,
Checks,
operationService
Operators,
ALL_CHECKS
}

View File

@ -1,45 +0,0 @@
<div class="operation{{#if hasChanged}} modified{{/if}}">
<div class="operation-header">
<input type="text" class="operation-name" placeholder="{{shortRuleDescTXT}}" value="{{operation.name}}" />
<input type="text" class="operation-operation" value="{{operation.operation}}" />
{{! delete only makes sense if the operation is already saved }}
{{#if operation.id}}
<span class="button-delete icon-delete"></span>
{{/if}}
</div>
<div class="checks">
{{#each operation.checks}}
<div class="check" data-id="{{@index}}">
<select class="check-class">
{{#each ../classes}}
<option value="{{class}}" {{{selectItem class ../class}}}>{{name}}</option>
{{/each}}
</select>
<select class="check-operator">
{{#each (getOperators class)}}
<option value="{{operator}}" {{{selectItem operator ../operator}}}>{{name}}</option>
{{/each}}
</select>
<input type="text" class="check-value" value="{{value}}">
<span class="button-delete-check icon-delete"></span>
</div>
{{/each}}
</div>
<button class="button-add">{{addRuleTXT}}</button>
{{#if hasChanged}}
{{! reset only makes sense if the operation is already saved }}
{{#if operation.id}}
<button class="button-reset pull-right">{{resetTXT}}</button>
{{/if}}
<button class="button-save pull-right">{{saveTXT}}</button>
{{/if}}
{{#if saving}}
<span class="icon-loading-small pull-right"></span>
<span class="pull-right">{{savingTXT}}</span>
{{else}}{{#if message}}
<span class="msg pull-right {{#if errorMessage}}error{{else}}success{{/if}}">
{{message}}{{#if errorMessage}} {{errorMessage}}{{/if}}
</span>
{{/if}}{{/if}}
</div>

View File

@ -1,2 +0,0 @@
<div class="operations"></div>
<button class="button-add-operation">{{addRuleGroupTXT}}</button>

View File

@ -1,19 +1,25 @@
import './filemimetypeplugin'
import './filenameplugin'
import './filesizeplugin'
import './filesystemtagsplugin'
import './requestremoteaddressplugin'
import './requesttimeplugin'
import './requesturlplugin'
import './requestuseragentplugin'
import './usergroupmembershipplugin'
import './legacy/filemimetypeplugin'
import './legacy/filenameplugin'
import './legacy/filesizeplugin'
import './legacy/filesystemtagsplugin'
import './legacy/requestremoteaddressplugin'
import './legacy/requesttimeplugin'
import './legacy/requesturlplugin'
import './legacy/requestuseragentplugin'
import './legacy/usergroupmembershipplugin'
import Vue from 'vue'
import Vuex from 'vuex'
import store from './store'
import Settings from './components/Workflow'
window.OCA.WorkflowEngine = OCA.WorkflowEngine
Vue.use(Vuex)
import Vue from 'vue';
Vue.prototype.t = t;
import Settings from './components/Workflow';
Vue.prototype.t = t
const View = Vue.extend(Settings)
new View({}).$mount('#workflowengine')
new View({
store
}).$mount('#workflowengine')