jerosoler / Drawflow

Simple flow library 🖥️🖱️
https://jerosoler.github.io/Drawflow/
MIT License
4.65k stars 722 forks source link

Can't use i18n inside Node Component #274

Closed SilasNiewierra closed 2 years ago

SilasNiewierra commented 2 years ago

Hi @jerosoler , I'm desperately trying to get vuei18n to work. I have a simple workflow:

Editor.vue

...
 // Register nodes
const nodeProps = (key) => ({
  step: stepTemplates[key],
  toggleDetails: this.toggleNodeDetails,
  editor: this.editor,
})

Object.keys(stepTemplates).forEach((key) => {
  this.editor.registerNode(key, Step, nodeProps(key))
})
...

Step.vue

<template>
  <div class="header d-flex align-center">
    <img :src="step.icon" height="32" />
    <div class="ml-2 title text-h5 font-weight-medium">
      {{ $t(step.title) }}
    </div>
  </div>
  <div class="mt-4">
    <trigger-step
      :toggleDetails="toggleDetails"
      :editor="editor"
    />
  </div>
</template>

TriggerStep.vue

<template>
  <div class="mt-4">
    <div class="d-flex">
      <p>{{ $t('steps.trigger.desc') }}</p>
      <div class="ml-1" @click="toggleDetails">
        <input
          class="dynamic-field"
          disabled
          :value="node.eventname"
          :placeholder="$t('steps.trigger.placeholderEventName')"
        />
      </div>
    </div>
  </div>
</template>

What I expected to happen: The Step is displayed in the editor correctly with the string in the .json file.

What happens: TypeError: _ctx.$t is not a function

jerosoler commented 2 years ago

Hi

The problem is https://github.com/jerosoler/Drawflow/issues/258

The instance is not injected in Node.

Have you tried to import the library in each node and put the translation?

I have to look to solve the issue of the instance.

jerosoler commented 2 years ago

Hi @SilasNiewierra

Good News!! 🎉

👀 I think I have found the solution. Also for the problem https://github.com/jerosoler/Drawflow/issues/258

Found in comment of @yyx990803 https://github.com/vuejs/vue-next/issues/2097#issuecomment-707975628

You can replicate it, to see if it is correct.

First step copy drawflow file: https://github.com/jerosoler/Drawflow/blob/master/src/drawflow.js

Add new file in your project: drawflow.js and edit function addNode and addNodeImport: Change this lines:

        //Vue 3
        /*let wrapper = this.render.createApp({
          parent: this.parent,
          render: h => this.render.h(this.noderegister[dataNode.html].html, this.noderegister[dataNode.html].props, this.noderegister[dataNode.html].options)
        }).mount(content)*/
        let wrapper = this.render.h(this.noderegister[html].html, this.noderegister[html].props, this.noderegister[html].options);
        wrapper.appContext = this.parent;
        this.render.render(wrapper,content);

In your component drawflow.vue

import Drawflow from '../drawflow'  // Import from you folder
import styleDrawflow from 'drawflow/dist/drawflow.min.css'
import { onMounted, shallowRef, h, getCurrentInstance, render } from 'vue'

// In Setup function
 setup() {
   const Vue = { version: 3, h, render };
   const internalInstance = getCurrentInstance()
}
// And onMounted() 
onMounted(() => {

       const id = document.getElementById("drawflow");
       editor.value = new Drawflow(id, Vue, internalInstance.appContext.app._context);

Can you prove it? I would appreciate your feedback!

jerosoler commented 2 years ago

It works well. We can even pass drawflow as a globalProperties

Parent Node "drawflow.vue"

 const internalInstance = getCurrentInstance()
   internalInstance.appContext.app._context.config.globalProperties.$df = editor;

Child component:

<template>
 <div ref="el">Hi!</div>
 <input df-namevalue>
 <el-button type="primary" @click="getdata()">Button</el-button>
</template>

<script>
import { onMounted, ref, getCurrentInstance } from 'vue'

export default {

  setup() {

   const el = ref(null);
    const app = getCurrentInstance()
    const df = app.appContext.config.globalProperties.$df

    function getdata() {
      console.log(df._value.getNodeFromId(el.value.parentElement.parentElement.id.slice(5)));
    }

    onMounted(() => {
      console.log(el.value.parentElement.parentElement.id);
    });

    return {
      el, getdata
    }
  }
}
</script>
SilasNiewierra commented 2 years ago

Hi @jerosoler ,

thanks that's amazing!! Unfortunately I'm not able to get it running? When I copy the drawflow.js file and point to it I get 146 errors and 168 warnings found. 🤔 All inside the drawflow.js file? Can you figure out why? Or make the installation possible with npm as before?

SilasNiewierra commented 2 years ago

I went inside the drawflow.js and fixed the errors manually, but am not sure if I broke something with it?

For now it seems to work, but instead of editor.value = new Drawflow(id, Vue, internalInstance.appContext.app._context); I had to do editor= new Drawflow(id, Vue, internalInstance.appContext.app._context); or else I would get errors like editor.on is not a function

jerosoler commented 2 years ago

Drawflow project not a eslint.

add in head of file: errors disable

/*eslint-disable */
export default class Drawflow {

If you check that it works I will upload the changes to npm

SilasNiewierra commented 2 years ago

Cool, I will try it again 👍 I'll give you an update in a second 😄

SilasNiewierra commented 2 years ago

Okay, with the following workflow everything worked fine

  1. Download drawflow.js
  2. Adjust addNode
    //Vue 3
    // let wrapper = this.render.createApp({
    //   parent: this.parent,
    //   render: h => this.render.h(this.noderegister[html].html, this.noderegister[html].props, this.noderegister[html].options)
    // }).mount(content)
    let wrapper = this.render.h(this.noderegister[html].html, this.noderegister[html].props, this.noderegister[html].options);
    wrapper.appContext = this.parent;
    this.render.render(wrapper,content);
  3. Adjust addNodeImport ( dataNode.html instead of html)
    //Vue 3
    // let wrapper = this.render.createApp({
    //   parent: this.parent,
    //   render: h => this.render.h(this.noderegister[dataNode.html].html, this.noderegister[dataNode.html].props, this.noderegister[dataNode.html].options)
    // }).mount(content)
    let wrapper = this.render.h(this.noderegister[dataNode.html].html, this.noderegister[dataNode.html].props, this.noderegister[dataNode.html].options);
    wrapper.appContext = this.parent;
    this.render.render(wrapper,content);
  4. Add /*eslint-disable */ to the top of drawflow.js
  5. Editor.vue, import new Drawflow file
    import { h, getCurrentInstance, render, defineComponent } from 'vue'
    import Drawflow from '@/lib/drawflow/drawflow'
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    import styleDrawflow from 'drawflow/dist/drawflow.min.css'
  6. Editor.vue, add setup function
    setup() {
    const Vue = { version: 3, h, render }
    const internalInstance = getCurrentInstance()
    return { Vue, internalInstance }
    },
  7. Editor.vue, assign editor instead of editor.value
    mounted(){
    const id = document.getElementById('drawflow')
    this.editor = new Drawflow(
    id,
    this.Vue,
    this.internalInstance.appContext.app._context,
    )
    }

Result: I am able to call $t('my.key) inside the Node components. 👍 So i18n works fine, which is amazing 🎉

However, when I try to do <v-btn>Click</v-btn> inside the Node component, I get the following Error: TypeError: Cannot read properties of undefined (reading 'global') Linking to this error: https://github.com/jerosoler/Drawflow/issues/258

jerosoler commented 2 years ago

In my test used library Element UI

In the main.js

import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import App from './App.vue'

const app = createApp(App)

app.use(ElementPlus)
app.mount('#app')

in the component vue usend "onMounted" with compositon API

<template>
    <el-button type="primary" @click="exportEditor">Okey</el-button>
    <div id="drawflow"></div> 
</template>
<script>
/*eslint-disable */

import Drawflow from '../drawflow'
import styleDrawflow from 'drawflow/dist/drawflow.min.css'
import { onMounted, shallowRef, h, getCurrentInstance, render, inject } from 'vue'
import NodeClick from './NodeClick.vue'

export default {
  name: 'drawflow',
  setup() {

   const editor = shallowRef({})
   const Vue = { version: 3, h, render };
   const internalInstance = getCurrentInstance()
   internalInstance.appContext.app._context.config.globalProperties.$df = editor;

      function exportEditor() {
      alert(JSON.stringify(editor.value.export()));
    }

   onMounted(() => {

       const id = document.getElementById("drawflow");

       editor.value = new Drawflow(id, Vue, internalInstance.appContext.app._context);
       editor.value.start();

       const props = { name: "hey"};
       const options = {};
       editor.value.registerNode('NodeClick', NodeClick, props, options);

       editor.value.addNode('Name', 0, 1, 0, 300, 'Class', { namevalue: "TEST!"}, 'NodeClick', 'vue');
       editor.value.addNode('Name', 1, 1, 250, 300, 'Class', {}, 'NodeClick', 'vue');

  })

  return {
    exportEditor
  }

  }

}
/*eslint-enable */
</script>
<style scoped>
#drawflow {
  width: 100%;
  height: 500px;
  min-height: 400px;
  border: 1px solid red;
  text-align: initial;
}
</style>

And the NodeClick.vue

<template>
 <div ref="el">Hi!</div>
 <input df-namevalue>
 <el-button type="primary" @click="getdata()">Button</el-button>
</template>

<script>
import { onMounted, ref, getCurrentInstance } from 'vue'

export default {

  setup() {

   const el = ref(null);
    const app = getCurrentInstance()
    const df = app.appContext.config.globalProperties.$df

    function getdata() {
      console.log(df._value.getNodeFromId(el.value.parentElement.parentElement.id.slice(5)));
    }

    onMounted(() => {
      console.log(el.value.parentElement.parentElement.id);
    });

    return {
      el, getdata
    }
  }
}
</script>

and the button show: image

SilasNiewierra commented 2 years ago

Okay I will try that as well. Maybe its a vuetify 3 alpha problem.

Thank you so much, this is amazing 😍 🎉 If you upload it to npm, please let me know, so I can just install it and remove my local drawflow.js file 😄

jerosoler commented 2 years ago

This afternoon I'll upload it if I can!

SilasNiewierra commented 2 years ago

Awesome 🙌 thank you so much 👍

SilasNiewierra commented 2 years ago

Hi @jerosoler , as I mentioned above, you need to change html to dataNode.html inside the addNodeImport adjustments. Right now the library does not work with 0.0.5 😁

jerosoler commented 2 years ago

Fix in new 0.0.51 ;) Thanks!!

SilasNiewierra commented 2 years ago

Awesome thank you so much 👍