").text(res.text).html())
- );
- return $ret;
- },
- };
- }
- },
- watch: {
- placeholder: function (val) {
- $(this.$el).empty().select2(this.opts());
- this.build();
- },
- required: function (val) {
- $(this.$el).empty().select2(this.opts());
- this.build();
- },
- url: function (val) {
- $(this.$el).empty().select2(this.opts());
- this.build();
- },
- },
- destroyed: function () {
- $(this.$el)
- .off()
- .select2("destroy");
- }
- });
-
- Vue.component('checkin-rule', {
- template: ('
'
- + '
'
- + ''
- + ' '
- + ''
- + ''
- + '
'
- + '
'
- + '
'
- + '
'
- + '
'
- + '
'
- + '
'
- + '
'
- + '
'
- + '
'
- + '
'
- + ''
- + '
'
- + '
'
- + '
'
- + '
'
- ),
- computed: {
- variable: function () {
- var op = this.operator;
- if (op === "and" || op === "or") {
- return op;
- } else if (this.rule[op] && this.rule[op][0]) {
- return this.rule[op][0]["var"];
- } else {
- return null;
- }
- },
- rightoperand: function () {
- var op = this.operator;
- if (op === "and" || op === "or") {
- return null;
- } else if (this.rule[op] && typeof this.rule[op][1] !== "undefined") {
- return this.rule[op][1];
- } else {
- return null;
- }
- },
- operator: function () {
- return Object.keys(this.rule)[0];
- },
- operands: function () {
- return this.rule[this.operator];
- },
- classObject: function () {
- var c = {
- 'checkin-rule': true
- };
- c['checkin-rule-' + this.variable] = true;
- return c;
- },
- vartype: function () {
- if (this.variable && VARS[this.variable]) {
- return VARS[this.variable]['type'];
- }
- },
- timeType: function () {
- if (this.rightoperand && this.rightoperand['buildTime']) {
- return this.rightoperand['buildTime'][0];
- }
- },
- timeTolerance: function () {
- var op = this.operator;
- if ((op === "isBefore" || op === "isAfter") && this.rule[op] && typeof this.rule[op][2] !== "undefined") {
- return this.rule[op][2];
- } else {
- return null;
- }
- },
- timeValue: function () {
- if (this.rightoperand && this.rightoperand['buildTime']) {
- return this.rightoperand['buildTime'][1];
- }
- },
- cardinality: function () {
- if (this.vartype && TYPEOPS[this.vartype] && TYPEOPS[this.vartype][this.operator]) {
- return TYPEOPS[this.vartype][this.operator]['cardinality'];
- }
- },
- operators: function () {
- return TYPEOPS[this.vartype];
- },
- productSelectURL: function () {
- return $("#product-select2").text();
- },
- variationSelectURL: function () {
- return $("#variations-select2").text();
- },
- vars: function () {
- return VARS;
- },
- },
- methods: {
- setVariable: function (event) {
- var current_op = Object.keys(this.rule)[0];
- var current_val = this.rule[current_op];
-
- if (event.target.value === "and" || event.target.value === "or") {
- if (current_val[0] && current_val[0]["var"]) {
- current_val = [];
- }
- this.$set(this.rule, event.target.value, current_val);
- this.$delete(this.rule, current_op);
- } else {
- if (current_val !== "and" && current_val !== "or" && current_val[0] && VARS[event.target.value]['type'] === this.vartype) {
- this.$set(this.rule[current_op][0], "var", event.target.value);
- } else {
- this.$delete(this.rule, current_op);
- this.$set(this.rule, "!!", [{"var": event.target.value}]);
- }
- }
- },
- setOperator: function (event) {
- var current_op = Object.keys(this.rule)[0];
- var current_val = this.rule[current_op];
- this.$delete(this.rule, current_op);
- this.$set(this.rule, event.target.value, current_val);
- },
- setRightOperandNumber: function (event) {
- if (this.rule[this.operator].length === 1) {
- this.rule[this.operator].push(parseInt(event.target.value));
- } else {
- this.$set(this.rule[this.operator], 1, parseInt(event.target.value));
- }
- },
- setTimeTolerance: function (event) {
- if (this.rule[this.operator].length === 2) {
- this.rule[this.operator].push(parseInt(event.target.value));
- } else {
- this.$set(this.rule[this.operator], 2, parseInt(event.target.value));
- }
- },
- setTimeType: function (event) {
- var time = {
- "buildTime": [event.target.value]
- };
- if (this.rule[this.operator].length === 1) {
- this.rule[this.operator].push(time);
- } else {
- this.$set(this.rule[this.operator], 1, time);
- }
- if (event.target.value === "custom") {
- this.$set(this.rule[this.operator], 2, 0);
- }
- },
- setTimeValue: function (val) {
- console.log(val);
- this.$set(this.rule[this.operator][1]["buildTime"], 1, val);
- },
- setRightOperandProductList: function (val) {
- var products = {
- "objectList": []
- };
- for (var i = 0; i < val.length; i++) {
- products["objectList"].push({
- "lookup": [
- "product",
- val[i].id,
- val[i].text
- ]
- });
- }
- if (this.rule[this.operator].length === 1) {
- this.rule[this.operator].push(products);
- } else {
- this.$set(this.rule[this.operator], 1, products);
- }
- },
- setRightOperandVariationList: function (val) {
- var products = {
- "objectList": []
- };
- for (var i = 0; i < val.length; i++) {
- products["objectList"].push({
- "lookup": [
- "variation",
- val[i].id,
- val[i].text
- ]
- });
- }
- if (this.rule[this.operator].length === 1) {
- this.rule[this.operator].push(products);
- } else {
- this.$set(this.rule[this.operator], 1, products);
- }
- },
- addOperand: function () {
- this.rule[this.operator].push({"": []});
- },
- wrapWithOR: function () {
- var r = JSON.parse(JSON.stringify(this.rule));
- this.$delete(this.rule, this.operator);
- this.$set(this.rule, "or", [r]);
- },
- wrapWithAND: function () {
- var r = JSON.parse(JSON.stringify(this.rule));
- this.$delete(this.rule, this.operator);
- this.$set(this.rule, "and", [r]);
- },
- cutOut: function () {
- var cop = Object.keys(this.operands[0])[0];
- var r = this.operands[0][cop];
- this.$delete(this.rule, this.operator);
- this.$set(this.rule, cop, r);
- },
- remove: function () {
- this.$parent.rule[this.$parent.operator].splice(this.index, 1);
- },
- },
- props: {
- rule: Object,
- level: Number,
- index: Number,
- }
- });
-
- Vue.component('checkin-rules-editor', {
- template: ('
'
- + ''
- + ''
- + '
'
- ),
- computed: {
- hasRules: function () {
- return hasRules = !!Object.keys(this.$root.rules).length;
- }
- },
- methods: {
- addRule: function () {
- this.$set(this.$root.rules, "and", []);
- },
- },
- });
-
- var app = new Vue({
- el: '#rules-editor',
- data: function () {
- return {
- rules: {},
- hasRules: false,
- };
- },
- created: function () {
- this.rules = JSON.parse($("#id_rules").val());
- },
- watch: {
- rules: {
- deep: true,
- handler: function (newval) {
- $("#id_rules").val(JSON.stringify(newval));
- }
- },
- }
- })
-});
+ },
+ }
+ })
+});
\ No newline at end of file
diff --git a/src/pretix/static/pretixcontrol/js/ui/checkinrules/checkin-rule.vue b/src/pretix/static/pretixcontrol/js/ui/checkinrules/checkin-rule.vue
new file mode 100644
index 0000000000..44176683e2
--- /dev/null
+++ b/src/pretix/static/pretixcontrol/js/ui/checkinrules/checkin-rule.vue
@@ -0,0 +1,261 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pretix/static/pretixcontrol/js/ui/checkinrules/checkin-rules-editor.vue b/src/pretix/static/pretixcontrol/js/ui/checkinrules/checkin-rules-editor.vue
new file mode 100644
index 0000000000..1efb1f27c7
--- /dev/null
+++ b/src/pretix/static/pretixcontrol/js/ui/checkinrules/checkin-rules-editor.vue
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
diff --git a/src/pretix/static/pretixcontrol/js/ui/checkinrules/checkin-rules-visualization.vue b/src/pretix/static/pretixcontrol/js/ui/checkinrules/checkin-rules-visualization.vue
new file mode 100644
index 0000000000..728df5946d
--- /dev/null
+++ b/src/pretix/static/pretixcontrol/js/ui/checkinrules/checkin-rules-visualization.vue
@@ -0,0 +1,268 @@
+
+
+
+
diff --git a/src/pretix/static/pretixcontrol/js/ui/checkinrules/datetimefield.vue b/src/pretix/static/pretixcontrol/js/ui/checkinrules/datetimefield.vue
new file mode 100644
index 0000000000..3676f458ab
--- /dev/null
+++ b/src/pretix/static/pretixcontrol/js/ui/checkinrules/datetimefield.vue
@@ -0,0 +1,55 @@
+
+
+
+
diff --git a/src/pretix/static/pretixcontrol/js/ui/checkinrules/lookup-select2.vue b/src/pretix/static/pretixcontrol/js/ui/checkinrules/lookup-select2.vue
new file mode 100644
index 0000000000..2726e7bb2e
--- /dev/null
+++ b/src/pretix/static/pretixcontrol/js/ui/checkinrules/lookup-select2.vue
@@ -0,0 +1,81 @@
+
+
+
+
diff --git a/src/pretix/static/pretixcontrol/js/ui/checkinrules/viz-node.vue b/src/pretix/static/pretixcontrol/js/ui/checkinrules/viz-node.vue
new file mode 100644
index 0000000000..546783821e
--- /dev/null
+++ b/src/pretix/static/pretixcontrol/js/ui/checkinrules/viz-node.vue
@@ -0,0 +1,145 @@
+
+
+
+
+
+
+
+
+
+
+
+ {{ vardata.label }}
+
+
+ {{ op.label }} {{ rightoperand }}
+
+
+
+ {{ vardata.label }}
+
+ {{ op.label }}
+
+ {{ df(rightoperand.buildTime[1]) }}
+
+
+ {{ this.$root.texts[rightoperand.buildTime[0]] }}
+
+
+ +
+ -
+ {{ operands[2] }}
+ {{ this.$root.texts.minutes }}
+
+
+
+
+ {{ vardata.label }}
+
+ {{ rightoperand.objectList.map((o) => o.lookup[2]).join(", ") }}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pretix/static/pretixcontrol/scss/_forms.scss b/src/pretix/static/pretixcontrol/scss/_forms.scss
index 1bde313c0f..74aeed6855 100644
--- a/src/pretix/static/pretixcontrol/scss/_forms.scss
+++ b/src/pretix/static/pretixcontrol/scss/_forms.scss
@@ -642,18 +642,81 @@ table td > .checkbox input[type="checkbox"] {
#rules-editor {
.checkin-rule {
- border-left: 4px solid $brand-primary;
+ border-left: 4px solid transparentize($brand-primary, .5);
background: rgba(0, 0, 0, 0.05);
padding: 5px 15px 5px 15px;
margin: 5px 0;
position: relative;
+ &:hover {
+ border-left-color: $brand-primary;
+ }
}
.checkin-rule-and {
- border-left: 4px solid $brand-danger;
+ border-left: 4px solid transparentize($brand-danger, .5);
+ &:hover {
+ border-left-color: $brand-danger;
+ }
}
.checkin-rule-or {
- border-left: 4px solid $brand-success;
+ border-left: 4px solid transparentize($brand-success, .5);
+ &:hover {
+ border-left-color: $brand-success;
+ }
+ }
+}
+
+.checkin-rules-visualization {
+ svg {
+ width: 100%;
+ height: auto;
+ .node {
+ stroke: $gray-light;
+ stroke-width: 2px;
+ fill: #fff;
+ &:hover {
+ stroke: $brand-primary;
+ }
+ }
+ .edge {
+ stroke: $gray-light;
+ stroke-width: 2px;
+ fill: none;
+ }
+ .check {
+ fill: $brand-success;
+ }
+ .text {
+ font-size: 12px;
+ width: 100%;
+ height: 100%;
+ overflow-y: auto;
+ cursor: default;
+ text-align: center;
+ }
+ }
+
+ position: relative;
+ .tools {
+ position: absolute;
+ top: 10px;
+ right: 10px;
+ }
+
+ &.maximized {
+ background: white;
+ position: fixed;
+ top: 51px;
+ left: 0;
+ width: 100vw;
+ max-height: none;
+ height: 100vh;
+ height: calc(100vh - 51px);
+ z-index: 90000;
+
+ svg {
+ height: 100%
+ }
}
}