Convert template for Dashboard 1 to template for dashboard 2

Hello dear forum.
I am in the process of moving from Dashboard 1 to Dashboard 2. Most of it works.
Unfortunately, I'm having a hard time getting my created templates to work on the new dashboard.
Unfortunately I am not an expert in this area. I was happy that it ran under Dashboard 1.

Here is my template for the old dashboard.

[
    {
        "id": "5d2538ef5c48634d",
        "type": "ui_template",
        "z": "233f2e33b7762cdf",
        "g": "9adba24cdf37a851",
        "group": "3867402a42b1cb87",
        "name": "Pin_Unlock",
        "order": 1,
        "width": 0,
        "height": 0,
        "format": "<div ng-init=\"init()\" id=\"pin_insert\" class=\"dialog\">\n    \n    <div class=\"dialog_content\">\n        \n        <div class=\"dialog_header\">\n            <span ng-click=\"closeDialog()\" class=\"close\">&times;</span>\n            <h2 style=\"margin:10px\">Insert PIN</h2>\n        </div>\n        \n        <div class=\"dialog_body\">\n\n           <div layout=\"row\" layout-align=\"center\">\n                <div class=\"number_placeholder\">\n                    {{passcode.substring(0, 1)}}\n                </div>\n                <div class=\"number_placeholder\">\n                    {{passcode.substring(1, 2)}}\n                </div>\n                <div class=\"number_placeholder\">\n                    {{passcode.substring(2, 3)}}\n                </div>\n                <div class=\"number_placeholder\">\n                    {{passcode.substring(3, 4)}}\n                </div>\n            </div>\n            \n            <div layout=\"column\" layout-align=\"center\" style=\"margin-top: 10px\">\n                <div layout=\"row\" layout-align=\"center\">\n                    <div class=\"number_box\">\n                        <md-button class=\"pin\" ng-click=\"add(1)\">1</md-button>\n                    </div>\n                    <div class=\"number_box\">\n                        <md-button class=\"pin\" ng-click=\"add(2)\">2</md-button>\n                    </div>\n                    <div class=\"number_box\">\n                        <md-button class=\"pin\" ng-click=\"add(3)\">3</md-button>\n                    </div>\n                </div>\n                 <div layout=\"row\" layout-align=\"center\">\n                    <div class=\"number_box\">\n                        <md-button class=\"pin\" ng-click=\"add(4)\">4</md-button>\n                    </div>\n                    <div class=\"number_box\">\n                        <md-button class=\"pin\" ng-click=\"add(5)\">5</md-button>\n                    </div>\n                    <div class=\"number_box\">\n                        <md-button class=\"pin\" ng-click=\"add(6)\">6</md-button>\n                    </div>\n                </div>\n                 <div layout=\"row\" layout-align=\"center\">\n                    <div class=\"number_box\">\n                        <md-button class=\"pin\" ng-click=\"add(7)\">7</md-button>\n                    </div>\n                    <div class=\"number_box\">\n                        <md-button class=\"pin\" ng-click=\"add(8)\">8</md-button>\n                    </div>\n                    <div class=\"number_box\">\n                        <md-button class=\"pin\" ng-click=\"add(9)\">9</md-button>\n                    </div>\n                </div>\n                 <div layout=\"row\" layout-align=\"center\">\n                    <div class=\"number_box\">\n                        <md-button class=\"pin\" ng-click=\"confirm()\">\n                            <ng-md-icon icon=\"done\" style=\"color:#fff;\"></ng-md-icon>\n                        </md-button>\n                    </div>\n                    <div class=\"number_box\">\n                        <md-button class=\"pin\" ng-click=\"add(0)\">0</md-button>\n                    </div>\n                    <div class=\"number_box\">\n                        <md-button class=\"pin\" ng-click=\"delete()\">\n                            <ng-md-icon icon=\"arrow_back\" style=\"color:#fff;\"></ng-md-icon>\n                        </md-button>\n                    </div>\n                </div>\n            </div> \n          \n        </div> <!--dialog_body-->\n    </div> <!--dialog_content-->\n</div>  <!--dialog-->\n\n\n<style>\n\n/* The Dialog (background) */\n.dialog {\n    display: none; /* Hidden by default */\n    position: fixed; /* Stay in place */\n    z-index: 100; /* Sit on top */\n    left: 0;\n    top: 0;\n    width: 100%; /* Full width */\n    height: 100%; /* Full height */\n    overflow: auto; /* Enable scroll if needed */\n    background-color: rgb(0,0,0); /* Fallback color */\n    background-color: rgba(0,0,0,0.4); /* Black w/ opacity */\n    -webkit-transform: translateZ(0px);\n    -webkit-transform: translate3d(0,0,0);\n    -webkit-perspective: 1000;\n}\n\n.dialog_content {\n    position: absolute;\n    background-color: #E3E3E3;\n    left: calc(50% - 200px);\n    top: 90px;\n    border-radius: 10px;\n    padding: 0;\n    width: 400px;\n    box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2),0 6px 20px 0 rgba(0,0,0,0.19);\n    -webkit-animation-name: animatetop;\n    animation-name: animatetop;\n    animation-duration: 0.4s;\n}\n\n/* Media query for smartphones (to Fix?) */\n@media only screen and (min-device-width : 375px) and (max-device-width : 667px) { \n    .dialog_content {\n    margin-top: 5%;\n    margin-left: 5%;\n}\n}\n\n/* Add Animation */\n@-webkit-keyframes animatetop {\n    from {top: -300px; opacity: 0} \n    to {top: 90; opacity: 1}\n}\n\n@keyframes animatetop {\n    from {top: -300px; opacity: 0}\n    to {top: 90; opacity: 1}\n}\n\n/* Dialog Header */\n.dialog_header {\n    padding: 2px 16px;\n    background-color: #2E2E2E;\n    border-radius: 10px 10px 0 0;\n    color: white;\n}\n\n/* Dialog Body */\n.dialog_body {\n    padding: 5px;\n    background-color: #000F1E;\n}\n\n/* The Close Button */\n.close {\n    color: #E3E3E3;\n    float: right;\n    font-size: 42px;\n    font-weight: bold;\n    cursor: pointer;\n}\n\n.close:hover,\n.close:focus {\n    color: #FF0000;\n    text-decoration: none;\n    cursor: pointer;\n}\n\n/* __ */\n.number_placeholder{\n    width: 75px;\n    height: 51px;\n    margin: 20px;\n    font-size: 30pt;\n    text-align: center;\n    border-bottom: 1px solid #00F243;\n    color: #00F243;\n}\n\n/* Number container */\n.number_box{\n    margin: 5px;\n}\n\n/* Buttons style */\n.pin {\n    min-height: 75px;\n    min-width: 75px;\n    font-weight: bold;\n    margin: 0px 10px 10px 0px;\n    box-shadow: 4px 4px 6px 0 #1A1A1A;\n    background-color: #2E2E2E;\n    color: #fff;\n    font-size: 15pt;\n}\n\n.pin:not([disabled]):hover {\n    background-color:#00F243;\n}\n\n.btn1 {\n  color : rgb(49, 46, 46);\n  background-color: rgba(255, 222, 121, 0.96);\n  border-radius: 10px 0 0 10px;\n  font-size: 24px;\n}\n\n.btn1:not([disabled]):hover {\n  background-color: rgba(107, 103, 91, 0.96);\n  color: white;\n}\n\n.btn1[disabled] {\n  color : rgb(187, 187, 187);\n  background-color: rgba(230, 230, 229, 0.96);\n}\n\n</style>\n\n<script>\n\n/**\n * pin_dialog.js\n * Node-Red UI template for Node-Red Dashboard. \n * Custom dialog that asks for a PIN to allow actions\n * Enjoy it :). \n * -- Daniel\n *\n *\n * @license The Unlicense, http://unlicense.org/\n * @version 0.2\n * @author  Daniel Lando, https://github.com/robertsLando\n * @updated 2019-03-18\n * @link    ----\n *\n *\n */\n\nvar dialog;\n\n/* ==== */\n(function(scope) {\n    \n    scope.passcode = \"\";\n    scope.payload = \"\";\n    scope.inited = false;\n    \n    scope.init = function() {\n        scope.passcode = \"\";\n        //Hide the md-panel\n        $('#pin_insert').parent().parent().css(\"display\", \"none\");\n        //This trick make it works on smartphones too :)\n        dialog = $('#pin_insert').detach();\n        //remove any previously added pin dialog\n        $('.dialog').remove();\n    }\n    \n    scope.showDialog = function() {\n        dialog.appendTo(document.body);\n        dialog.css(\"display\", \"block\");\n    }\n    \n    scope.closeDialog = function(){\n        dialog.css(\"display\", \"none\");\n    }\n    \n    scope.add = function(value) {\n        if(scope.passcode.length < 4) {\n            scope.passcode = scope.passcode + value;\n            if(scope.passcode.length == 4) {\n                console.log(\"The four digit code was entered\");\n                   \n            }\n        }\n    }\n \n    scope.delete = function() {\n        if(scope.passcode.length > 0) {\n            scope.passcode = scope.passcode.substring(0, scope.passcode.length - 1);\n        }\n    }\n    \n    scope.confirm = function() {\n        if(scope.passcode.length == 4) {\n            scope.send({passcode: scope.passcode, payload : scope.payload});\n            scope.closeDialog();\n            scope.passcode = \"\";\n            scope.payload = \"\";\n        }\n    }\n\n    scope.$watch('msg', function(data) {\n        if(data && data.topic){\n            switch(data.topic){\n               case \"show\":\n                   if(scope.inited){\n                        scope.payload = data.payload;\n                        scope.showDialog();\n                   }\n                   else\n                        scope.inited = true;\n                break;\n                case \"close\": \n                    scope.closeDialog(); \n                break;\n            }\n        }\n    });\n})(scope);\n\n</script>\n",
        "storeOutMessages": false,
        "fwdInMessages": false,
        "resendOnRefresh": false,
        "templateScope": "local",
        "className": "",
        "x": 250,
        "y": 320,
        "wires": [
            [
                "1472f0d237a8a975",
                "629cda73f88188e3"
            ]
        ]
    },
    {
        "id": "3867402a42b1cb87",
        "type": "ui_group",
        "name": "pin",
        "tab": "d34b32fd3e0c8e11",
        "order": 6,
        "disp": false,
        "width": "1",
        "collapse": false,
        "className": "balken"
    },
    {
        "id": "d34b32fd3e0c8e11",
        "type": "ui_tab",
        "name": "Auswahl",
        "icon": "dashboard",
        "order": 2,
        "disabled": false,
        "hidden": true
    }
]

and here only the content of the template:

<div ng-init="init()" id="pin_insert" class="dialog">
    
    <div class="dialog_content">
        
        <div class="dialog_header">
            <span ng-click="closeDialog()" class="close">&times;</span>
            <h2 style="margin:10px">Insert PIN</h2>
        </div>
        
        <div class="dialog_body">

           <div layout="row" layout-align="center">
                <div class="number_placeholder">
                    {{passcode.substring(0, 1)}}
                </div>
                <div class="number_placeholder">
                    {{passcode.substring(1, 2)}}
                </div>
                <div class="number_placeholder">
                    {{passcode.substring(2, 3)}}
                </div>
                <div class="number_placeholder">
                    {{passcode.substring(3, 4)}}
                </div>
            </div>
            
            <div layout="column" layout-align="center" style="margin-top: 10px">
                <div layout="row" layout-align="center">
                    <div class="number_box">
                        <md-button class="pin" ng-click="add(1)">1</md-button>
                    </div>
                    <div class="number_box">
                        <md-button class="pin" ng-click="add(2)">2</md-button>
                    </div>
                    <div class="number_box">
                        <md-button class="pin" ng-click="add(3)">3</md-button>
                    </div>
                </div>
                 <div layout="row" layout-align="center">
                    <div class="number_box">
                        <md-button class="pin" ng-click="add(4)">4</md-button>
                    </div>
                    <div class="number_box">
                        <md-button class="pin" ng-click="add(5)">5</md-button>
                    </div>
                    <div class="number_box">
                        <md-button class="pin" ng-click="add(6)">6</md-button>
                    </div>
                </div>
                 <div layout="row" layout-align="center">
                    <div class="number_box">
                        <md-button class="pin" ng-click="add(7)">7</md-button>
                    </div>
                    <div class="number_box">
                        <md-button class="pin" ng-click="add(8)">8</md-button>
                    </div>
                    <div class="number_box">
                        <md-button class="pin" ng-click="add(9)">9</md-button>
                    </div>
                </div>
                 <div layout="row" layout-align="center">
                    <div class="number_box">
                        <md-button class="pin" ng-click="confirm()">
                            <ng-md-icon icon="done" style="color:#fff;"></ng-md-icon>
                        </md-button>
                    </div>
                    <div class="number_box">
                        <md-button class="pin" ng-click="add(0)">0</md-button>
                    </div>
                    <div class="number_box">
                        <md-button class="pin" ng-click="delete()">
                            <ng-md-icon icon="arrow_back" style="color:#fff;"></ng-md-icon>
                        </md-button>
                    </div>
                </div>
            </div> 
          
        </div> <!--dialog_body-->
    </div> <!--dialog_content-->
</div>  <!--dialog-->


<style>

/* The Dialog (background) */
.dialog {
    display: none; /* Hidden by default */
    position: fixed; /* Stay in place */
    z-index: 100; /* Sit on top */
    left: 0;
    top: 0;
    width: 100%; /* Full width */
    height: 100%; /* Full height */
    overflow: auto; /* Enable scroll if needed */
    background-color: rgb(0,0,0); /* Fallback color */
    background-color: rgba(0,0,0,0.4); /* Black w/ opacity */
    -webkit-transform: translateZ(0px);
    -webkit-transform: translate3d(0,0,0);
    -webkit-perspective: 1000;
}

.dialog_content {
    position: absolute;
    background-color: #E3E3E3;
    left: calc(50% - 200px);
    top: 90px;
    border-radius: 10px;
    padding: 0;
    width: 400px;
    box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2),0 6px 20px 0 rgba(0,0,0,0.19);
    -webkit-animation-name: animatetop;
    animation-name: animatetop;
    animation-duration: 0.4s;
}

/* Media query for smartphones (to Fix?) */
@media only screen and (min-device-width : 375px) and (max-device-width : 667px) { 
    .dialog_content {
    margin-top: 5%;
    margin-left: 5%;
}
}

/* Add Animation */
@-webkit-keyframes animatetop {
    from {top: -300px; opacity: 0} 
    to {top: 90; opacity: 1}
}

@keyframes animatetop {
    from {top: -300px; opacity: 0}
    to {top: 90; opacity: 1}
}

/* Dialog Header */
.dialog_header {
    padding: 2px 16px;
    background-color: #2E2E2E;
    border-radius: 10px 10px 0 0;
    color: white;
}

/* Dialog Body */
.dialog_body {
    padding: 5px;
    background-color: #000F1E;
}

/* The Close Button */
.close {
    color: #E3E3E3;
    float: right;
    font-size: 42px;
    font-weight: bold;
    cursor: pointer;
}

.close:hover,
.close:focus {
    color: #FF0000;
    text-decoration: none;
    cursor: pointer;
}

/* __ */
.number_placeholder{
    width: 75px;
    height: 51px;
    margin: 20px;
    font-size: 30pt;
    text-align: center;
    border-bottom: 1px solid #00F243;
    color: #00F243;
}

/* Number container */
.number_box{
    margin: 5px;
}

/* Buttons style */
.pin {
    min-height: 75px;
    min-width: 75px;
    font-weight: bold;
    margin: 0px 10px 10px 0px;
    box-shadow: 4px 4px 6px 0 #1A1A1A;
    background-color: #2E2E2E;
    color: #fff;
    font-size: 15pt;
}

.pin:not([disabled]):hover {
    background-color:#00F243;
}

.btn1 {
  color : rgb(49, 46, 46);
  background-color: rgba(255, 222, 121, 0.96);
  border-radius: 10px 0 0 10px;
  font-size: 24px;
}

.btn1:not([disabled]):hover {
  background-color: rgba(107, 103, 91, 0.96);
  color: white;
}

.btn1[disabled] {
  color : rgb(187, 187, 187);
  background-color: rgba(230, 230, 229, 0.96);
}

</style>

<script>

/**
 * pin_dialog.js
 * Node-Red UI template for Node-Red Dashboard. 
 * Custom dialog that asks for a PIN to allow actions
 * Enjoy it :). 
 * -- Daniel
 *
 *
 * @license The Unlicense, http://unlicense.org/
 * @version 0.2
 * @author  Daniel Lando, https://github.com/robertsLando
 * @updated 2019-03-18
 * @link    ----
 *
 *
 */

var dialog;

/* ==== */
(function(scope) {
    
    scope.passcode = "";
    scope.payload = "";
    scope.inited = false;
    
    scope.init = function() {
        scope.passcode = "";
        //Hide the md-panel
        $('#pin_insert').parent().parent().css("display", "none");
        //This trick make it works on smartphones too :)
        dialog = $('#pin_insert').detach();
        //remove any previously added pin dialog
        $('.dialog').remove();
    }
    
    scope.showDialog = function() {
        dialog.appendTo(document.body);
        dialog.css("display", "block");
    }
    
    scope.closeDialog = function(){
        dialog.css("display", "none");
    }
    
    scope.add = function(value) {
        if(scope.passcode.length < 4) {
            scope.passcode = scope.passcode + value;
            if(scope.passcode.length == 4) {
                console.log("The four digit code was entered");
                   
            }
        }
    }
 
    scope.delete = function() {
        if(scope.passcode.length > 0) {
            scope.passcode = scope.passcode.substring(0, scope.passcode.length - 1);
        }
    }
    
    scope.confirm = function() {
        if(scope.passcode.length == 4) {
            scope.send({passcode: scope.passcode, payload : scope.payload});
            scope.closeDialog();
            scope.passcode = "";
            scope.payload = "";
        }
    }

    scope.$watch('msg', function(data) {
        if(data && data.topic){
            switch(data.topic){
               case "show":
                   if(scope.inited){
                        scope.payload = data.payload;
                        scope.showDialog();
                   }
                   else
                        scope.inited = true;
                break;
                case "close": 
                    scope.closeDialog(); 
                break;
            }
        }
    });
})(scope);

</script>

Can someone perhaps give me some food for thought, or assess whether it works at all with the new dashboard. Or whether there are simpler methods.

The template opens a dialog in which you have to enter a pin and then confirm it.

Many thanks for any help
Manuel

Old dashboard uses the long depreciated angular v1

New dashboard uses vue + vuetify

The new dashboard has extensive docs including a migration guide: Dashboard 1.0 Migration Guide | Node-RED Dashboard 2.0

On top of what I wrote here: Subflow - UI Group - #11 by Steve-Mcl , most things have an immediate alternative. e.g. md-button becomes v-btn and the docs for v-btn are here: Button component — Vuetify

Thank you very much,

will have a look there

Search from web pin pad Vue vuetify. Some examples you can find. Sure they are not source for copy-paste-happy route but many things are usable for sure.

Worth noting, that with new Dashboard, you have Dialog's built in too, so your template would just need to have the PIN logic inside, then that could live in a "Dialog"-typed group

We also support all Vuetify components by default inside the template node, and they do have a OTP component which may be useful for you.

You can read more about our Template node here.

I will also be recording a tutorial about the template node this week, targeted at new users, so might be worth waiting for that too. I will publish it to the FlowFuse YouTube Channel

Many thanks for the tip. I'll see how far I can get.

Many thanks to you too. Then I will wait. That will certainly help me.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.