<script type="text/javascript"> RED.nodes.registerType('ui-page', { category: 'config', defaults: { name: { value: RED._('@flowfuse/node-red-dashboard/ui-page:ui-page.label.pageName'), required: true }, ui: { type: 'ui-base', value: '', required: true }, path: { value: -1, required: false }, icon: { value: 'home', required: false }, layout: { value: '', required: true }, theme: { type: 'ui-theme', value: 'default', required: true }, order: { value: -1 }, className: { value: '' }, visible: { value: 'true' }, disabled: { value: 'false' } }, oneditprepare: function () { if (this.path === -1) { // we have no path set yet let pageCount = 0 RED.nodes.eachConfig((cNode) => { pageCount += cNode.type === 'ui-page' ? 1 : 0 }) this.path = '/page' + (pageCount + 1) $('#node-config-input-path').val(this.path) } $('#node-config-input-layout').typedInput({ type: 'layout', types: [{ value: 'layout', options: [ { value: 'grid', label: RED._('@flowfuse/node-red-dashboard/ui-page:ui-page.label.grid') }, { value: 'flex', label: RED._('@flowfuse/node-red-dashboard/ui-page:ui-page.label.fixed') }, { value: 'tabs', label: RED._('@flowfuse/node-red-dashboard/ui-page:ui-page.label.tabs') }, { value: 'notebook', label: RED._('@flowfuse/node-red-dashboard/ui-page:ui-page.label.notebook') } ] }], typeField: '#node-input-layoutType' }) // backwards compatibility - because NR can't do boolean values on dropdowns if (this.visible === false || this.visible === 'false') { this.visible = false $('#node-config-input-visible').val('false') } else { this.visible = true $('#node-config-input-visible').val('true') } // backwards compatibility if (this.disabled === 'true' || this.disabled === true) { this.disabled = true $('#node-config-input-disabled').val('true') } else { this.disabled = false $('#node-config-input-disabled').val('false') } }, oneditsave: function () { // convert string to boolean const visible = $('#node-config-input-visible').val() if (visible === 'true') { this.visible = true } else { this.visible = false } // convert string to boolean const disabled = $('#node-config-input-disabled').val() if (disabled === 'true') { this.disabled = true } else { this.disabled = false } }, label: function () { const baseNode = RED.nodes.node(this.ui) const base = baseNode ? baseNode.path : '/' const path = this.path || '' return `${this.name} [${base}${path}]` || 'UI Page' } }) </script> <script type="text/html" data-template-name="ui-page"> <div class="form-row"> <label for="node-config-input-name"><i class="w-16 fa fa-tag"></i> <span data-i18n="node-red:common.label.name"></label> <input type="text" id="node-config-input-name" data-i18n="[placeholder]node-red:common.label.name"> </div> <div class="form-row"> <label for="node-config-input-ui"><i class="w-16 fa fa-sitemap"></i> <span data-i18n="ui-page.label.ui"></label> <input type="text" id="node-config-input-ui"> </div> <div class="form-row"> <label for="node-config-input-path"><i class="w-16 fa fa-link"></i> <span data-i18n="ui-page.label.path"></label> <input type="text" id="node-config-input-path"> </div> <div class="form-row"> <label for="node-config-input-icon"><i class="w-16 fa fa-home"></i> <span data-i18n="ui-page.label.icon"></label> <input type="text" id="node-config-input-icon"> </div> <div class="form-row"> <label for="node-config-input-theme"><i class="w-16 fa fa-paint-brush"></i> <span data-i18n="ui-page.label.theme"></label> <input type="text" id="node-config-input-theme"> </div> <div class="form-row"> <label for="node-config-input-layout"><i class="w-16 fa fa-th"></i> <span data-i18n="ui-page.label.layout"></label> <input type="text" id="node-config-input-layout"> <input type="hidden" id="node-config-input-layoutType"> </div> <div class="form-row" id="text-row-class"> <label for="node-config-input-className"><i class="w-16 fa fa-code"></i> <span data-i18n="ui-page.label.class"></label> <input type="text" id="node-config-input-className" data-i18n="[placeholder]ui-page.label.classNamePlaceholder"/> </div> <div class="form-row" style="font-weight: 600;"> <i class="w-16 fa fa-eye"></i> <span data-i18n="ui-page.label.defaultState"> </div> <div class="form-row"> <div style="display: flex; align-items: center; gap: 2px;"> <label for="node-config-input-visible" style="margin-bottom: 0" data-i18n="ui-page.label.visibility"></label> <select id="node-config-input-visible" style="width: 150px;"> <option value="true" data-i18n="ui-page.label.visible"></option> <option value="false" data-i18n="ui-page.label.hidden"></option> </select> </div> </div> <div class="form-row"> <div style="display: flex; align-items: center; gap: 2px;"> <label for="node-config-input-disabled" style="margin-bottom: 0" data-i18n="ui-page.label.interactivity"></label> <select id="node-config-input-disabled" style="width: 150px;"> <option value="false" data-i18n="ui-page.label.active"></option> <option value="true" data-i18n="ui-page.label.disabled"></option> </select> </div> </div> <div class="form-row"> <button onclick="RED.sidebar.show('dashboard-2.0')" class="editor-button editor-button-small" data-i18n="ui-page.label.openDashboardSidebar"></button> </div> </script>