functional editor
This commit is contained in:
		@@ -5,8 +5,6 @@
 | 
				
			|||||||
 * Created by Timo Hocker <timo@scode.ovh>, July 2020
 | 
					 * Created by Timo Hocker <timo@scode.ovh>, July 2020
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module.exports = {
 | 
					'use strict';
 | 
				
			||||||
  presets: [
 | 
					
 | 
				
			||||||
    '@vue/cli-plugin-babel/preset'
 | 
					module.exports = { presets: [ '@vue/cli-plugin-babel/preset' ] };
 | 
				
			||||||
  ]
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								index.js
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								index.js
									
									
									
									
									
								
							@@ -38,7 +38,7 @@ const user = {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  app.use (api);
 | 
					  app.use (api);
 | 
				
			||||||
  app.use (history_fallback ());
 | 
					  app.use (history_fallback ());
 | 
				
			||||||
  app.use (http_proxy ('localhost:8081'));
 | 
					  app.use (http_proxy ('localhost:8080'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  app.listen (3000, () => {
 | 
					  app.listen (3000, () => {
 | 
				
			||||||
    console.log ('listening on 3000');
 | 
					    console.log ('listening on 3000');
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										11
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								package.json
									
									
									
									
									
								
							@@ -15,6 +15,7 @@
 | 
				
			|||||||
    "@sapphirecode/crypto-helper": "^1.1.57",
 | 
					    "@sapphirecode/crypto-helper": "^1.1.57",
 | 
				
			||||||
    "@sapphirecode/password-helper": "^1.0.47",
 | 
					    "@sapphirecode/password-helper": "^1.0.47",
 | 
				
			||||||
    "@sapphirecode/ui-modules": "^0.1.1",
 | 
					    "@sapphirecode/ui-modules": "^0.1.1",
 | 
				
			||||||
 | 
					    "@sapphirecode/utilities": "^1.8.5",
 | 
				
			||||||
    "body-parser": "^1.19.0",
 | 
					    "body-parser": "^1.19.0",
 | 
				
			||||||
    "chart.js": "^2.9.3",
 | 
					    "chart.js": "^2.9.3",
 | 
				
			||||||
    "connect-history-api-fallback": "^1.6.0",
 | 
					    "connect-history-api-fallback": "^1.6.0",
 | 
				
			||||||
@@ -35,11 +36,11 @@
 | 
				
			|||||||
  "devDependencies": {
 | 
					  "devDependencies": {
 | 
				
			||||||
    "@sapphirecode/eslint-config": "^2.1.16",
 | 
					    "@sapphirecode/eslint-config": "^2.1.16",
 | 
				
			||||||
    "@sapphirecode/eslint-config-vue": "^1.1.16",
 | 
					    "@sapphirecode/eslint-config-vue": "^1.1.16",
 | 
				
			||||||
    "@vue/cli-plugin-babel": "~4.4.0",
 | 
					    "@vue/cli-plugin-babel": "^4.4.0",
 | 
				
			||||||
    "@vue/cli-plugin-eslint": "~4.4.0",
 | 
					    "@vue/cli-plugin-eslint": "^4.4.0",
 | 
				
			||||||
    "@vue/cli-plugin-router": "~4.4.0",
 | 
					    "@vue/cli-plugin-router": "^4.4.0",
 | 
				
			||||||
    "@vue/cli-plugin-vuex": "~4.4.0",
 | 
					    "@vue/cli-plugin-vuex": "^4.4.0",
 | 
				
			||||||
    "@vue/cli-service": "~4.4.0",
 | 
					    "@vue/cli-service": "^4.4.0",
 | 
				
			||||||
    "babel-eslint": "^10.1.0",
 | 
					    "babel-eslint": "^10.1.0",
 | 
				
			||||||
    "eslint": "^7.5.0",
 | 
					    "eslint": "^7.5.0",
 | 
				
			||||||
    "eslint-plugin-vue": "^6.2.2",
 | 
					    "eslint-plugin-vue": "^6.2.2",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,6 +18,7 @@ function create_log (index, simplex) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async function seed (knex) {
 | 
					async function seed (knex) {
 | 
				
			||||||
 | 
					  // eslint-disable-next-line no-console
 | 
				
			||||||
  console.log ('creating seeds');
 | 
					  console.log ('creating seeds');
 | 
				
			||||||
  const simplex = (new sn);
 | 
					  const simplex = (new sn);
 | 
				
			||||||
  const log = (Array (20))
 | 
					  const log = (Array (20))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,10 @@
 | 
				
			|||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <div class="config-editor">
 | 
					  <div
 | 
				
			||||||
 | 
					    v-if="enabled"
 | 
				
			||||||
 | 
					    class="config-editor"
 | 
				
			||||||
 | 
					  >
 | 
				
			||||||
    <p
 | 
					    <p
 | 
				
			||||||
      clasS="label"
 | 
					      class="label"
 | 
				
			||||||
      v-text="template.name"
 | 
					      v-text="template.name"
 | 
				
			||||||
    />
 | 
					    />
 | 
				
			||||||
    <!-- editor -->
 | 
					    <!-- editor -->
 | 
				
			||||||
@@ -12,8 +15,9 @@
 | 
				
			|||||||
      <ConfigEditor
 | 
					      <ConfigEditor
 | 
				
			||||||
        v-for="(prop,key) of template.properties"
 | 
					        v-for="(prop,key) of template.properties"
 | 
				
			||||||
        :key="key"
 | 
					        :key="key"
 | 
				
			||||||
 | 
					        v-model="config[prop.name]"
 | 
				
			||||||
        :template="prop"
 | 
					        :template="prop"
 | 
				
			||||||
        :config="config[prop.name]"
 | 
					        :enabled="is_enabled(prop.if)"
 | 
				
			||||||
      />
 | 
					      />
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
    <div
 | 
					    <div
 | 
				
			||||||
@@ -23,12 +27,13 @@
 | 
				
			|||||||
      <ConfigEditor
 | 
					      <ConfigEditor
 | 
				
			||||||
        v-for="(child,key) of config"
 | 
					        v-for="(child,key) of config"
 | 
				
			||||||
        :key="key"
 | 
					        :key="key"
 | 
				
			||||||
        :config="child"
 | 
					        v-model="config[key]"
 | 
				
			||||||
        :template="template.child"
 | 
					        :template="template.child"
 | 
				
			||||||
 | 
					        :enabled="is_enabled(template.child.if)"
 | 
				
			||||||
      />
 | 
					      />
 | 
				
			||||||
      <button
 | 
					      <button
 | 
				
			||||||
        type="button"
 | 
					        type="button"
 | 
				
			||||||
        @click="config.push(create_default(template.child))"
 | 
					        @click="add_item"
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
        add
 | 
					        add
 | 
				
			||||||
      </button>
 | 
					      </button>
 | 
				
			||||||
@@ -37,7 +42,18 @@
 | 
				
			|||||||
      v-else-if="template.type === 'string'"
 | 
					      v-else-if="template.type === 'string'"
 | 
				
			||||||
      class="editor"
 | 
					      class="editor"
 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
 | 
					      <select
 | 
				
			||||||
 | 
					        v-if="Array.isArray(template.choices)"
 | 
				
			||||||
 | 
					        v-model="config"
 | 
				
			||||||
 | 
					      >
 | 
				
			||||||
 | 
					        <option
 | 
				
			||||||
 | 
					          v-for="(opt,optkey) in template.choices"
 | 
				
			||||||
 | 
					          :key="optkey"
 | 
				
			||||||
 | 
					          v-text="opt"
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					      </select>
 | 
				
			||||||
      <input
 | 
					      <input
 | 
				
			||||||
 | 
					        v-else
 | 
				
			||||||
        v-model="config"
 | 
					        v-model="config"
 | 
				
			||||||
        type="text"
 | 
					        type="text"
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
@@ -67,17 +83,60 @@
 | 
				
			|||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script>
 | 
					<script>
 | 
				
			||||||
 | 
					import { resolve_data } from '../helper';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default {
 | 
					export default {
 | 
				
			||||||
  name:  'ConfigEditor',
 | 
					  name:  'ConfigEditor',
 | 
				
			||||||
  props: {
 | 
					  props: {
 | 
				
			||||||
    // eslint-disable-next-line vue/require-prop-types
 | 
					    // eslint-disable-next-line vue/require-prop-types
 | 
				
			||||||
    config:   { required: true },
 | 
					    value:    { required: true },
 | 
				
			||||||
    template: {
 | 
					    template: {
 | 
				
			||||||
      type:     Object,
 | 
					      type:     Object,
 | 
				
			||||||
      required: true
 | 
					      required: true,
 | 
				
			||||||
 | 
					      enabled:  { type: Boolean, default: true }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    enabled: {
 | 
				
			||||||
 | 
					      type:    Boolean,
 | 
				
			||||||
 | 
					      default: true
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  data () {
 | 
				
			||||||
 | 
					    return { temp: this.value };
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  computed: {
 | 
				
			||||||
 | 
					    config: {
 | 
				
			||||||
 | 
					      get () {
 | 
				
			||||||
 | 
					        return this.temp;
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      set (val) {
 | 
				
			||||||
 | 
					        this.$emit ('input', val);
 | 
				
			||||||
 | 
					        this.temp = val;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  methods: {
 | 
					  methods: {
 | 
				
			||||||
 | 
					    is_enabled (condition) {
 | 
				
			||||||
 | 
					      if (typeof condition === 'undefined')
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					      switch (condition.op) {
 | 
				
			||||||
 | 
					        case '=':
 | 
				
			||||||
 | 
					          return resolve_data (this.config, condition.prop) === condition.val;
 | 
				
			||||||
 | 
					        case '<':
 | 
				
			||||||
 | 
					          return resolve_data (this.config, condition.prop) < condition.val;
 | 
				
			||||||
 | 
					        case '>':
 | 
				
			||||||
 | 
					          return resolve_data (this.config, condition.prop) > condition.val;
 | 
				
			||||||
 | 
					        default:
 | 
				
			||||||
 | 
					          return false;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    add_item () {
 | 
				
			||||||
 | 
					      if (
 | 
				
			||||||
 | 
					        typeof this.config === 'undefined'
 | 
				
			||||||
 | 
					        || !Array.isArray (this.config)
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					        this.config = [];
 | 
				
			||||||
 | 
					      this.config.push (this.create_default (this.template.child));
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    create_default (template) {
 | 
					    create_default (template) {
 | 
				
			||||||
      if (typeof template.default !== 'undefined')
 | 
					      if (typeof template.default !== 'undefined')
 | 
				
			||||||
        return template.default;
 | 
					        return template.default;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,21 +4,28 @@ export default {
 | 
				
			|||||||
    type:       'object',
 | 
					    type:       'object',
 | 
				
			||||||
    properties: [
 | 
					    properties: [
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        type: 'string',
 | 
					        type:    'string',
 | 
				
			||||||
        name: 'type'
 | 
					        name:    'type',
 | 
				
			||||||
 | 
					        choices: [
 | 
				
			||||||
 | 
					          'table',
 | 
				
			||||||
 | 
					          'chart'
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        name:  'columns',
 | 
					        name:  'columns',
 | 
				
			||||||
        type:  'array',
 | 
					        type:  'array',
 | 
				
			||||||
        child: { type: 'string' }
 | 
					        child: { type: 'string' },
 | 
				
			||||||
 | 
					        if:    { prop: 'type', op: '=', val: 'table' }
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        name: 'x',
 | 
					        name: 'x',
 | 
				
			||||||
        type: 'string'
 | 
					        type: 'string',
 | 
				
			||||||
 | 
					        if:    { prop: 'type', op: '=', val: 'chart' }
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        name:  'y',
 | 
					        name:  'y',
 | 
				
			||||||
        type:  'array',
 | 
					        type:  'array',
 | 
				
			||||||
 | 
					        if:    { prop: 'type', op: '=', val: 'chart' },
 | 
				
			||||||
        child: {
 | 
					        child: {
 | 
				
			||||||
          type:       'object',
 | 
					          type:       'object',
 | 
				
			||||||
          properties: [
 | 
					          properties: [
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,11 +3,11 @@
 | 
				
			|||||||
    class="grid"
 | 
					    class="grid"
 | 
				
			||||||
  >
 | 
					  >
 | 
				
			||||||
    <ConfigEditor
 | 
					    <ConfigEditor
 | 
				
			||||||
      :config="config"
 | 
					      v-model="config"
 | 
				
			||||||
      :template="template"
 | 
					      :template="template"
 | 
				
			||||||
    />
 | 
					    />
 | 
				
			||||||
    <ViewComponent
 | 
					    <ViewComponent
 | 
				
			||||||
      v-for="(item,key) of config"
 | 
					      v-for="(item,key) of saved_config"
 | 
				
			||||||
      :key="key"
 | 
					      :key="key"
 | 
				
			||||||
      :config="item"
 | 
					      :config="item"
 | 
				
			||||||
      :data="parsed_log"
 | 
					      :data="parsed_log"
 | 
				
			||||||
@@ -17,6 +17,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
<script>
 | 
					<script>
 | 
				
			||||||
import Vuex from 'vuex';
 | 
					import Vuex from 'vuex';
 | 
				
			||||||
 | 
					import { copy_object } from '@sapphirecode/utilities';
 | 
				
			||||||
import ViewComponent from '../components/ViewComponent.vue';
 | 
					import ViewComponent from '../components/ViewComponent.vue';
 | 
				
			||||||
import ConfigEditor from '../components/ConfigEditor.vue';
 | 
					import ConfigEditor from '../components/ConfigEditor.vue';
 | 
				
			||||||
import default_config from '../default';
 | 
					import default_config from '../default';
 | 
				
			||||||
@@ -26,8 +27,9 @@ export default {
 | 
				
			|||||||
  components: { ViewComponent, ConfigEditor },
 | 
					  components: { ViewComponent, ConfigEditor },
 | 
				
			||||||
  data () {
 | 
					  data () {
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
      config:   default_config,
 | 
					      config:       copy_object (default_config),
 | 
				
			||||||
      template: default_template
 | 
					      saved_config: copy_object (default_config),
 | 
				
			||||||
 | 
					      template:     default_template
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  computed:   {
 | 
					  computed:   {
 | 
				
			||||||
@@ -41,8 +43,25 @@ export default {
 | 
				
			|||||||
  },
 | 
					  },
 | 
				
			||||||
  mounted () {
 | 
					  mounted () {
 | 
				
			||||||
    this.get_log ();
 | 
					    this.get_log ();
 | 
				
			||||||
 | 
					    document.body.addEventListener ('keydown', (ev) => {
 | 
				
			||||||
 | 
					      if (ev.key === 's' && ev.ctrlKey) {
 | 
				
			||||||
 | 
					        this.save_config ();
 | 
				
			||||||
 | 
					        ev.preventDefault ();
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  methods: { ...Vuex.mapActions ({ get_log: 'get_log' }) }
 | 
					  methods: {
 | 
				
			||||||
 | 
					    save_config () {
 | 
				
			||||||
 | 
					      fetch ('config', {
 | 
				
			||||||
 | 
					        method: 'POST',
 | 
				
			||||||
 | 
					        body:   JSON.stringify (this.config)
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      this.saved_config = copy_object (this.config);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    ...Vuex.mapActions ({ get_log: 'get_log' })
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user