Skip to content

Commit

Permalink
Merge pull request #310 from FlowFuse/309-placeholder-page
Browse files Browse the repository at this point in the history
Improve placeholder page with appropriate error reporting where required
  • Loading branch information
joepavitt committed Oct 27, 2023
2 parents 89fb064 + bb7eddb commit 11bf47d
Show file tree
Hide file tree
Showing 7 changed files with 174 additions and 21 deletions.
10 changes: 8 additions & 2 deletions nodes/config/ui_page.js
Expand Up @@ -21,12 +21,18 @@ module.exports = function (RED) {
node.register = function (group, widgetNode, widgetConfig, widgetEvents) {
const ui = RED.nodes.getNode(config.ui)
const page = config
ui.register(page, group, widgetNode, widgetConfig, widgetEvents)
if (ui) {
ui.register(page, group, widgetNode, widgetConfig, widgetEvents)
} else {
node.error(`Error registering Widget - ${widgetNode.name || widgetNode.id}. No parent ui-base node found for ui-page node: ${(page.name || page.id)}`)
}
}
node.deregister = function (group, widgetNode) {
const ui = RED.nodes.getNode(config.ui)
const page = config
ui.deregister(page, group, widgetNode)
if (ui) {
ui.deregister(page, group, widgetNode)
}
}
}
RED.nodes.registerType('ui-page', UIPageNode)
Expand Down
Binary file modified ui/public/favicon.ico
Binary file not shown.
124 changes: 106 additions & 18 deletions ui/src/App.vue
@@ -1,6 +1,14 @@
<template>
<v-app>
<router-view />
<router-view v-if="!status" />
<div v-else class="nrdb-placeholder-container">
<div class="nrdb-placeholder">
<img src="./assets/logo.png">
<h1>Node-RED Dashboard 2.0</h1>
<!-- eslint-disable-next-line vue/no-v-html -->
<p :class="'status-' + status.type" v-html="status.msg" />
</div>
</div>
</v-app>
</template>

Expand All @@ -17,31 +25,111 @@ export default {
name: 'App',
inject: ['$socket'],
computed: {
...mapState('ui', ['dashboards', 'pages', 'widgets'])
...mapState('ui', ['dashboards', 'pages', 'widgets']),
status: function () {
if (this.dashboards) {
const dashboards = Object.keys(this.dashboards)
if (!dashboards || dashboards.length === 0) {
return {
type: 'info',
msg: 'Please add some Dashboard 2.0 nodes to your flow and re-deploy.'
}
} else if (dashboards.length > 1) {
return {
type: 'warning',
msg: 'We currently do not support multiple <code>ui-base</code> nodes in a single flow. <p>Please remove all but one (in the "config" menu on the right-side of Node-RED) and re-deploy.</p>'
}
} else {
const pages = Object.values(this.pages)
console.log(dashboards)
console.log(pages)
let msg = null
for (let i = 0; i < pages.length; i++) {
const page = pages[i]
console.log(page)
if (!dashboards.includes(page.ui)) {
// Catch instances of multiple Dashboards, or pages not bound to a Dashboard we know about
msg = {
type: 'warning',
msg: 'You have at least one <code>ui-page</code> that is mapped to a <code>ui-base</code> that we can\'t find. We currently do not support multiple <code>ui-base</code> nodes in a single flow, so can only import one at a time.<p>Please remove all but one (in the "config" menu on the right-side of Node-RED) and re-deploy.</p>'
}
break
}
}
if (msg) {
return msg
}
}
// check pages overlapping with URL
if (this.pages) {
const endpoints = {}
const duplicates = {}
Object.values(this.pages).forEach(page => {
const route = this.dashboards[page.ui].path + page.path
if (endpoints[route]) {
if (!duplicates[route]) {
// our first instance of a duplicate
duplicates[route] = {
pages: [endpoints[route]],
route
}
}
duplicates[route].pages.push(page)
} else {
endpoints[route] = page
}
})
if (Object.keys(duplicates).length > 0) {
let msg = 'Warning: You have multiple pages configured with the same URL.'
let list = '<div class="status-duplicates">'
Object.values(duplicates).forEach((d) => {
d.pages.forEach((p) => {
list += `<div>${p.name} (path: ${p.path})</div>`
})
})
list += '</div>'
msg += list
return {
type: 'warning',
msg
}
}
}
return null
} else {
return {
type: 'info',
msg: 'Please add and configure your first Dashboard 2.0 node to get started.'
}
}
}
},
created () {
this.$socket.on('ui-config', (topic, payload) => {
console.log('ui-config received. topic:', topic, 'payload:', payload)
// loop over pages, add them to vue router
Object.values(payload.pages).forEach(page => {
const route = payload.dashboards[page.ui].path + page.path
const routeName = 'Page:' + page.name
console.log('adding route', route)
this.$router?.addRoute({
path: route,
name: routeName,
component: layouts[page.layout],
meta: {
title: page.name, // the page name
id: page.id, // the pages id
dashboard: page.ui // the dashboard id - to simplify determining which dashboard we're on
// check that the page's bound UI is also in our config
if (payload.dashboards[page.ui]) {
console.log('adding route for page', page)
const route = payload.dashboards[page.ui].path + page.path
const routeName = 'Page:' + page.name
this.$router?.addRoute({
path: route,
name: routeName,
component: layouts[page.layout],
meta: {
title: page.name, // the page name
id: page.id, // the pages id
dashboard: page.ui // the dashboard id - to simplify determining which dashboard we're on
}
})
// store data on the "page" object so it's easy for us to map in the navigation drawer
page.route = {
path: route,
name: routeName
}
})
// store data on the "page" object so it's easy for us to map in the navigation drawer
page.route = {
path: route,
name: routeName
}
})
Expand Down
Binary file modified ui/src/assets/logo.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion ui/src/main.js
Expand Up @@ -19,7 +19,7 @@ import * as directives from 'vuetify/directives'
const theme = {
dark: false,
colors: {
background: '#0000ff',
background: '#fff',
'group-background': '#ffffff',
primary: '#0000ff',
accent: '#ff6b99',
Expand Down
10 changes: 10 additions & 0 deletions ui/src/store/ui.js
Expand Up @@ -4,6 +4,7 @@

// initial state
const state = () => ({
dashboards: null,
pages: null,
groups: null,
themes: null,
Expand All @@ -12,6 +13,9 @@ const state = () => ({

// getters
const getters = {
dashboards (state) {
return state.dashboards
},
pages (state) {
return state.pages
},
Expand Down Expand Up @@ -74,6 +78,12 @@ const getters = {
}

const mutations = {
dashboards (state, dashboards) {
state.dashboards = {
...state.dashboards,
...dashboards
}
},
pages (state, pages) {
state.pages = pages
},
Expand Down
49 changes: 49 additions & 0 deletions ui/src/stylesheets/common.css
Expand Up @@ -29,6 +29,55 @@ main {
padding: var(--nrdb-main-padding);
}

/**
* Placeholder
*/

.nrdb-placeholder-container {
height: 100%;
display: flex;
align-items: center;
justify-content: center;
background-color: #eee;
}

.nrdb-placeholder {
max-width: 480px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
color: #222;
text-align: center;
padding: 1.5rem 2rem;
border-radius: 6px;
border: 1px solid #d1d1d1;
background-color: #fff;
}

.nrdb-placeholder img {
width: 150px;
}

.nrdb-placeholder p {
margin: 0.5rem 0 0;
}

.nrdb-placeholder .status-info {
font-weight: 600;
}

.nrdb-placeholder .status-warning {
color: #bb2020;
font-weight: 600;
}

.nrdb-placeholder .status-duplicates {
font-weight: 400;
color: #222;
margin-top: 0.5rem;
}

/**
* Common Widget Styling
*/
Expand Down

0 comments on commit 11bf47d

Please sign in to comment.