Custom Plugin Settings UI using Vue

tiensng
tiensng Registered Posts: 7 ✭✭✭✭

Hi All,

I've read the DSS docs on creating a custom settings UI using an Angular-based UI https://doc.dataiku.com/dss/latest/plugins/reference/other.html#custom-settings-ui and was wondering if it's possible to use a different UI framework like Vue. I've read other posts on how to create Vue-based webapps in DSS but a key additional requirement for the plugin settings UI is accessing and modifying the config variable appropriately so user selections can be conveyed to the underlying plugin recipe's python runtime (i.e. in get_recipe_config()). The docs indicate how $scope.config is used to access this in Angular but I don't think this is possible using a different UI framework like Vue or React. If anyone has additional or different information on this topic, it would be greatly appreciated! Thanks in advance.

Best Answers

  • Andrey
    Andrey Dataiker Alumni Posts: 119 ✭✭✭✭✭✭✭
    edited July 17 Answer ✓

    Hi @tiensng

    DSS provides a native support of AngularJS custom UIs, that's why users have direct access to config object. Moreover, any change to this object is also detected by DSS and the save button activates.

    If needed, the custom UI could also be created using other frameworks, including Vue, however, you'd need to take care of synchronization between Vue's config object and DSS's one in AngularJS.

    Here's an example of a small custom UI in Vue:

    <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.js"></script>
    <script type="text/javascript">
        var mySimpleApp = new Vue({
            el: '#mainapp',
            data: { config: undefined },
            template: `
      <div id="app-wrapper">
            <h2 id="app-title">Tiny vue app</h2>
            Config: <code>{{config}}</code>
            <input v-model="config.parameter2" placeholder="parameter2 value">
      </div>
      `,
            mounted() {
                this.config = angular.element(this.$el).scope().config; // sync changes from DSS's AngularJS to Vue
            },
    
            watch: {
                config: {
                    handler: function (val, oldVal) {
                        angular.element(this.$el).scope().$apply() // sync changes from Vue to DSS's AngularJS
                    },
                    deep: true
                }
            }
        })
    </script>
    
    <section id="mainapp"></section>

    it's stored in resource/form.html

    the recipe.json should include this line:

    "paramsTemplate" : "form.html"

    the rest of json config is typical, in my example I used a parameter called "parameter2", which can be declared as:

    "params": [
            ...
            {
                "name": "parameter2",
                "type": "INT",
                "defaultValue": 42
            }
    ...
    }
    

    Hope this helps

    Best Regards,

    Andrey Avtomonov

    R&D Engineer

  • tiensng
    tiensng Registered Posts: 7 ✭✭✭✭
    Answer ✓

    Hi @Andrey
    ,

    That's very helpful to know that we could use a different framework for the custom settings UI if needed. That being said, it does sound like using Angular will provide a potentially easier and less error-prone integration so we'll probably try that first. Thank you very much for the guidance!

    - Tien

Answers

  • tiensng
    tiensng Registered Posts: 7 ✭✭✭✭
    edited July 17

    Hi Andrey,

    I've made some progress implementing a custom Recipe Plugin settings UI using a Vue 2.x web component initialized from a html page specified via the paramsTemplate attribute in recipe.json. I'm embedding the Vue web component JS code (compiled using vue-cli-service) inline in one of the <script> elements of the html fragment and then following your example, I'm initializing the Vue instance as follows:

    var mySimpleApp = new Vue({
            el: '#cctapp',
            data: { config: undefined },
            template: '<cct-vue v-on:config-set="updateConfig"></cct-vue>',
            mounted() {
                this.config = angular.element(this.$el).scope().config; // sync changes from DSS's AngularJS to Vue
                console.log("Set Angular config in Vue")
            },
            methods: {
              updateConfig: function(event) {
                console.log("Updating config from " + event);
                for (var attrname in event) { this.config[attrname] = event[attrname]; }
                angular.element(this.$el).scope().$apply();
                console.log(this.config);
              }
            }
    });
    </script>
    <section id="cctapp"></section>

    This seems to work and I can use the Vue UI to dynamically configure the recipe and see the expected console output as the angular scope is updated with each change made in the custom UI. However when I click Run on the recipe, I see an exception thrown in the console with a "cyclic object value" error. I've included a screenshot of the console output to give you an idea of the exception being thrown and what is in the config object (the only property I'm setting is "CCT_PROTOCOL_ID") just before clicking Run:

    RecipeUIError.png

    I also have another question on how to get the list of dataset columns selected as input by the user so I can display them in the custom UI but resolving this error is probably more critical at this stage. If you can offer any advice or suggestions on how to proceed further, I would be most appreciative. Thanks!

  • Andrey
    Andrey Dataiker Alumni Posts: 119 ✭✭✭✭✭✭✭
    edited July 17

    Hi @tiensng
    ,

    Regarding the dataset schema retrieval, you can use the "callPythonDo" functionality described here:

    https://doc.dataiku.com/dss/latest/plugins/reference/other.html

    So my previous example could become something like this:

    def do(payload, config, plugin_config, inputs):
        return {'example' : ["hello", "world"]}

    to implement the required function on python side you'd have to add a following key to your recipe.json:

    "paramsPythonSetup": "pythonsetup.py"

    pythonsetup.py (the name could be anything) should be created in the "resource" directory and should contain a python function called "do":

    console.log(JSON.stringify(this.config))

    you can do anything in this method, including importing dataiku module and retrieving the list of columns of a given dataset.

    As for the cyclic object error, It seems that your config object cannot be serialized before being sent to DSS. Try calling

    mounted() {
            this.scope = angular.element(this.$el).scope();
            this.config = this.scope.config;
            this.scope.callPythonDo({}).then(function(data) {
                // success
            }, function(data) {
                // failure
            });
        },

    as the last step of your updateConfig method, if it throws the same exception, you'd need to make sure that your config object is serializable.

    Regards

Setup Info
    Tags
      Help me…