Write node forms using Vue 3 and JSON Schema

Soon you will be able to test my framework for writting node forms using Vue 3 and JSON Schema. This will enable the creation of more complex config forms and write code in an modern way.

Directory structure

.
├── src/
│   └── nodes/
│       └── node-1/
│           ├── schemas/
│           │   ├── config.js
│           │   ├── iput.js
│           │   ├── output-1.js
│           │   ├── output-2.js
│           │   ├── ...
│           │   └── output-n.js
│           ├── client/
│           │   ├── locales/
│           │   │   ├── docs/
│           │   │   │   ├── en-US.md
│           │   │   │   ├── de.md
│           │   │   │   └── ...
│           │   │   └── labels/
│           │   │       ├── en-US.json
│           │   │       ├── de.json
│           │   │       └── ...
│           │   ├── assets/
│           │   │   └── icons/
│           │   │       └── vue.svg
│           │   ├── form.vue
│           │   └── index.js
│           └── server/
│               └── index.js
└── package.json

src/nodes/node-1/client/index.js

import MyComponentForm from "./form.vue";
import MyComponentFormSchema from "../schemas/config.js";
import { defineNode } from "@nrg/core/client";

export default defineNode({
  category: "function",
  color: "#FFFFFF",
  inputs: 1,
  outputs: 1,
  icon: "vue.png", // TODO: check if I can load base64 asset
  form: {
    component: MyComponentForm,
    schema: MyComponentFormSchema,
  },
});

src/nodes/node-1/client/form.vue

<template>
  <div>
    <div class="form-row">
      <label><i class="fa fa-tag"></i> Username</label>
      <NodeRedCredentialInput
        v-model:value="node.credentials.username"
        :error="errors['node.credentials.username']"
      />
    </div>
    <div class="form-row">
      <label><i class="fa fa-tag"></i> Password</label>
      <NodeRedCredentialInput
        v-model:value="node.credentials.password"
        type="password"
        :error="errors['node.credentials.password']"
      />
    </div>
    <div class="form-row">
      <label>Typed Input</label>
      <NodeRedTypedInput
        v-model:value="node.myProperty"
        :types="types"
        :error="errors['node.myProperty']"
      />
    </div>
    <div class="form-row">
      <label>Typed Input 2</label>
      <NodeRedTypedInput
        v-model:value="node.myProperty2"
        :error="errors['node.myProperty2']"
      />
    </div>
    <div class="form-row">
      <label>Config Input</label>
      <NodeRedConfigInput
        v-model:value="node.remoteServer"
        type="remote-server"
        :error="errors['node.remoteServer']"
      />
    </div>
    <div class="form-row">
      <label>Select Input</label>
      <NodeRedSelectInput
        v-model:value="node.country"
        :options="countries"
        :error="errors['node.country']"
      />
    </div>
    <div class="form-row">
      <label>MultiSelect Input</label>
      <NodeRedSelectInput
        v-model:value="node.fruit"
        :options="fruits"
        multiple
        :error="errors['node.fruit']"
      />
    </div>
    <div class="form-row">
      <label>Select Input</label>
      <NodeRedSelectInput
        v-model:value="node.number"
        :options="numbers"
        :error="errors['node.number']"
      />
    </div>
    <div class="form-row">
      <label>Select Input</label>
      <NodeRedSelectInput
        v-model:value="node.object"
        :options="objects"
        multiple
        :error="errors['node.object']"
      />
    </div>
    <div class="form-row">
      <label>Select Input</label>
      <NodeRedSelectInput
        v-model:value="node.array"
        :options="arrays"
        :error="errors['node.array']"
      />
    </div>
    <div class="form-row">
      <label>Editor with default height 200px and JSON</label>
      <NodeRedEditorInput
        v-model:value="node.jsontest"
        :error="errors['node.jsontest']"
      />
    </div>
    <div class="form-row">
      <label>Editor with custom height and CSS</label>
      <NodeRedEditorInput
        v-model:value="node.csstest"
        language="css"
        style="height: 100px"
        :error="errors['node.csstest']"
      />
    </div>
  </div>
</template>

<script>
export default {
  props: {
    node: {
      type: Object,
      required: true,
    },
    errors: {
      type: Object,
      default: () => ({}),
    },
  },
  data() {
    return {
      types: ["str", "msg"],
      countries: [
        { value: "usa", label: "usa" },
        { value: "argentina", label: "argentina" },
        { value: "brasil", label: "brasil" },
      ],
      fruits: [
        { value: "apple", label: "apple" },
        { value: "melon", label: "melon" },
        { value: "raspberry", label: "raspberry" },
      ],
      numbers: [
        { value: "1", label: "1" },
        { value: "2", label: "2" },
        { value: "3", label: "3" },
      ],
      objects: [
        { value: JSON.stringify({ test: "a" }), label: "a" },
        { value: JSON.stringify({ test: "b" }), label: "b" },
        { value: JSON.stringify({ test: "c" }), label: "c" },
      ],
      arrays: [
        { value: JSON.stringify(["a"]), label: "a" },
        { value: JSON.stringify(["b"]), label: "b" },
        { value: JSON.stringify(["c"]), label: "c" },
      ],
    };
  },
};
</script>

<style scoped>
.label {
  width: 100%;
}
</style>

1 Like