-
Notifications
You must be signed in to change notification settings - Fork 502
feat(viewer): add advanced dashboard view with widget configuration #1987
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: prepare/1.13.0
Are you sure you want to change the base?
Conversation
hu: 'Irányítópultok elrejtése', | ||
}, | ||
noWidgetsTitle: { | ||
zh: '开始你的新仪表盘,添加一个可视化', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
zh: '开始你的新仪表盘,添加一个可视化', | |
zh: '添加可视化组件,开始使用仪表盘', |
hu: 'Válasszon ki egy adatforrást, majd lekérdezze és vizualizálja adatait diagramokkal, statisztikákkal és egyéb widgetekkel', | ||
}, | ||
addVisualization: { | ||
zh: '添加可视化', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
zh: '添加可视化', | |
zh: '添加可视化组件', |
connection: { | ||
zh: '连接', | ||
en: 'Connection', | ||
tr: 'Bağlantı', | ||
ja: '接続', | ||
hu: 'Kapcsolat', | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is a duplicate
hu: 'Téma minta', | ||
}, | ||
valueField: { | ||
zh: '值字段', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
zh: '值字段', | |
zh: '字段', |
name: 'Viewer', | ||
component: () => import('@/views/viewer/index.vue'), | ||
redirect: '/viewer/topic_tree', | ||
redirect: '/viewer/dashboard', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer the dashboard to the second tab, and the topic tree is the first default.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll move it to the second tab, thank you.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a huge file and a lot of code; I recommend splitting it into components.
</div> | ||
<div class="viewer-view-tabs"> | ||
<el-tabs v-model="activeTab" @tab-click="handleTabClick"> | ||
<el-tab-pane :label="$t('viewer.dashboard')" name="Dashboard"></el-tab-pane> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move under the topic tree.
let STORE_PATH: string | ||
try { | ||
STORE_PATH = getUnifiedAppDataPath('MQTTX') | ||
} catch (e) { | ||
const home = process.env.HOME || require('os').homedir() | ||
STORE_PATH = process.env.MQTTX_DATA_PATH || join(home, '.mqttx') | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What issue was fixed here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TypeORM CLI commands such as yarn db:migration:show
and the rest fail with:
TypeError: Cannot read properties of undefined (reading 'getPath'), because there's no electron instance while running TypeORM CLI commands, while I now think it might be better to add error handling here in appDataPath.ts
export const getUnifiedAppDataPath = (subDir?: string): string => {
// Handle both main and renderer process
const isRenderer = process.type === 'renderer'
const electronApp = isRenderer ? require('@electron/remote').app : app
// Use Electron's native API which handles Windows %APPDATA% redirection correctly
const userDataPath = electronApp.getPath('userData')
if (subDir) {
// For backward compatibility, if subDir is 'MQTTX' and it's already in the path, don't duplicate it
if (subDir === 'MQTTX' && userDataPath.includes('MQTTX')) {
return userDataPath
}
return path.join(userDataPath, subDir)
}
return userDataPath
}
Perhaps we could use the getLegacyDataPath
function as a fallback instead of using the home directory which i used for development purposes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So this change is mainly to ensure we can operate the database even when the Electron app isn’t running, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes
<template> | ||
<div class="gauge-container"> | ||
<div v-if="hasData" :id="id" style="width: 100%; height: 100%"></div> | ||
<div v-else class="no-data">No Data</div> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i18n
<!-- @ts-ignore --> | ||
<component :is="widgetComponent" v-bind="widgetProps" @error="onError" /> | ||
<div v-if="!widgetComponent" class="widget-error"> | ||
<div class="error-message">Unknown widget type: {{ widget.type }}</div> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i18n
class="big-stat-panel" | ||
> | ||
<div v-if="hasData" :id="id" class="chart-container"></div> | ||
<div v-else class="no-data-background">No Data</div> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i18n
<template> | ||
<div class="line-chart-container"> | ||
<div :id="id" class="chart-container"></div> | ||
<div v-if="!hasData" class="no-data-overlay">No Data</div> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i18n
.color-picker-item { | ||
.el-form-item__content { | ||
display: flex !important; | ||
align-items: center !important; | ||
line-height: normal !important; | ||
height: 43px !important; | ||
justify-content: flex-start !important; | ||
} | ||
.el-color-picker { | ||
vertical-align: middle !important; | ||
margin: 0 !important; | ||
align-self: center !important; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like there's a lot of duplication here, and all of them have strict import
keywords.
@@ -0,0 +1,133 @@ | |||
<template> | |||
<div class="key-value-editor"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this new component created because the built-in key value editor couldn't satisfy the needs?
PR Checklist
If you have any questions, you can refer to the Contributing Guide
What is the current behavior?
Currently, MQTTX does not provide a dashboard feature for visualizing MQTT message data in real time or historically. Users cannot create, configure, or manage dashboards and widgets for monitoring numeric or structured payloads. There is no support for widget-based visualization (Big Number, Gauge, Line), time range selection, or schema-aware extraction from Protobuf/Avro.
Issue Number
None
What is the new behavior?
This PR introduces a comprehensive dashboard feature, including:
DashboardsList.vue
,index.vue
).WidgetConfig.vue
,WidgetRenderer.vue
,widgetRegistry.ts
).DashboardView.vue
).BigNumber.vue
): Displays latest value, supports thresholds, units, and field names.Gauge.vue
): Visualizes value with thresholds and dynamic coloring.LineChart.vue
): Plots historical or live data with area/smooth options.TimeRangeSelect.vue
).BigNumberConfig.vue
,GaugeConfig.vue
,LineConfig.vue
).Screenshots:



Does this PR introduce a breaking change?
Specific Instructions
Testing on the following lines:
DashboardView.vue
: Here most of the message processing takes placeWidgetRenderer.vue
BigNumber.vue
,Gauge.vue
,LineChart.vue
WidgetConfig.vue
widgetRegistry.ts
Other information