function buildEnvUIRow(row, tenv, node) {
        if(RED.subflow.debug) { console.log("buildEnvUIRow", tenv) }
        const ui = tenv.ui || {}
        ui.label = ui.label||{};
        if ((tenv.type === "cred" || (tenv.parent && tenv.parent.type === "cred")) && !ui.type) {
            ui.type = "cred";
            ui.opts = {};
        } else if (tenv.type === "conf-types") {
            ui.type = "conf-types"
            ui.opts = { types: ['conf-types'] }
        } else if (!ui.type) {
            ui.type = "input";
            ui.opts = { types: RED.editor.envVarList.DEFAULT_ENV_TYPE_LIST }
        } else {
            if (!ui.opts) {
                ui.opts = (ui.type === "select") ? {opts:[]} : {};
            }
        }

        var labels = ui.label || {};
        var locale = RED.i18n.lang();
        var labelText = RED.editor.envVarList.lookupLabel(labels, labels["en-US"]||tenv.name, locale);
        var label = $('<label>').appendTo(row);
        $('<span>&nbsp;</span>').appendTo(row);
        var labelContainer = $('<span></span>').appendTo(label);
        if (ui.icon) {
            var newPath = RED.utils.separateIconPath(ui.icon);
            if (newPath) {
                $("<i class='fa "+newPath.file +"'/>").appendTo(labelContainer);
            }
        }
        if (ui.type !== "checkbox") {
            var css = ui.icon ? {"padding-left":"5px"} : {};
            $('<span>').css(css).text(labelText).appendTo(label);
            if (ui.type === 'none') {
                label.width('100%');
            }
        }
        var input;
        var val = {
            value: "",
            type: "str"
        };
        if (tenv.parent) {
            val.value = tenv.parent.value;
            val.type = tenv.parent.type;
        }
        if (tenv.hasOwnProperty('value')) {
            val.value = tenv.value;
        }
        if (tenv.hasOwnProperty('type')) {
            val.type = tenv.type;
        }
        const elId = getSubflowEnvPropertyName(tenv.name)
        switch(ui.type) {
            case "input":
                input = $('<input type="text">').css('width','70%').attr('id', elId).appendTo(row);
                if (ui.opts.types && ui.opts.types.length > 0) {
                    var inputType = val.type;
                    if (ui.opts.types.indexOf(inputType) === -1) {
                        inputType = ui.opts.types[0]
                    }
                    input.typedInput({
                        types: ui.opts.types,
                        default: inputType
                    })
                    input.typedInput('value',val.value)
                    if (inputType === 'cred') {
                        if (node.credentials) {
                            if (node.credentials[tenv.name]) {
                                input.typedInput('value', node.credentials[tenv.name]);
                            } else if (node.credentials['has_'+tenv.name]) {
                                input.typedInput('value', "__PWRD__")
                            } else {
                                input.typedInput('value', "");
                            }
                        }
                    }
                } else {
                    input.val(val.value)
                }
                break;
            case "select":
                input = $('<select>').css('width','70%').attr('id', elId).appendTo(row);
                if (ui.opts.opts) {
                    ui.opts.opts.forEach(function(o) {
                        $('<option>').val(o.v).text(RED.editor.envVarList.lookupLabel(o.l, o.l['en-US']||o.v, locale)).appendTo(input);
                    })
                }
                input.val(val.value);
                break;
            case "checkbox":
                label.css("cursor","default");
                var cblabel = $('<label>').css('width','70%').appendTo(row);
                input = $('<input type="checkbox">').attr('id', elId).css({
                    marginTop: 0,
                    width: 'auto',
                    height: '34px'
                }).appendTo(cblabel);
                labelContainer.css({"padding-left":"5px"}).appendTo(cblabel);
                $('<span>').css({"padding-left":"5px"}).text(labelText).appendTo(cblabel);
                var boolVal = false;
                if (val.type === 'bool') {
                    boolVal = val.value === 'true'
                } else if (val.type === 'num') {
                    boolVal = val.value !== "0"
                } else {
                    boolVal = val.value !== ""
                }
                input.prop("checked",boolVal);
                break;
            case "spinner":
                input = $('<input>').css('width','70%').attr('id', elId).appendTo(row);
                var spinnerOpts = {};
                if (ui.opts.hasOwnProperty('min')) {
                    spinnerOpts.min = ui.opts.min;
                }
                if (ui.opts.hasOwnProperty('max')) {
                    spinnerOpts.max = ui.opts.max;
                }
                input.spinner(spinnerOpts).parent().width('70%');
                input.val(val.value);
                break;
            case "cred":
                input = $('<input type="password">').css('width','70%').attr('id', elId).appendTo(row);
                if (node.credentials) {
                    if (node.credentials[tenv.name]) {
                        input.val(node.credentials[tenv.name]);
                    } else if (node.credentials['has_'+tenv.name]) {
                        input.val("__PWRD__")
                    } else {
                        input.val("");
                    }
                } else {
                    input.val("");
                }
                input.typedInput({
                    types: ['cred'],
                    default: 'cred'
                })
                break;
            case "conf-types":
                // let clsId = 'config-node-input-' + val.type + '-' + val.value + '-' + Math.floor(Math.random() * 100000);
                // clsId = clsId.replace(/\W/g, '-');
                // input = $('<input>').css('width','70%').addClass(clsId).attr('id', elId).appendTo(row);
                input = $('<input>').css('width','70%').attr('id', elId).appendTo(row);
                const _type = tenv.parent?.type || tenv.type;
                RED.editor.prepareConfigNodeSelect(node, tenv.name, _type, 'node-input-subflow-env', null, tenv);
                break;
        }
    }
Build a UI row for a subflow instance environment variable
Also used to build the UI row for subflow template preview
@param {JQuery} row - A form row element
@param {Object} tenv - A template environment variable
@param {String} tenv.name - The name of the environment variable
@param {String} tenv.type - The type of the environment variable
@param {String} tenv.value - The value set for this environment variable
@param {Object} tenv.parent - The parent environment variable
@param {String} tenv.parent.value - The value set for the parent environment variable
@param {String} tenv.parent.type - The type of the parent environment variable
@param {Object} tenv.ui - The UI configuration for the environment variable
@param {String} tenv.ui.icon - The icon for the environment variable
@param {Object} tenv.ui.label - The label for the environment variable
@param {String} tenv.ui.type - The type of the UI control for the environment variable
@param {Object} node - The subflow instance node