Encrypts the Grafana bearer token via Node-RED credentials block instead of plain config (F-11). Adds folderUid config field threaded through to the buildUpsertRequest payload (F-8, resolves PRD O-5). Migration path: legacy plain bearerToken still loads, with one-time warn() prompting user to re-save. Composition + URL + headers + per-instance UID were already in place; only the credentials + folderUid + tests are new. - dashboardAPI.html: bearerToken moved to credentials block; folderUid added. - dashboardAPI.js: registerType options pass credentials descriptor. - src/nodeClass.js: read token from node.credentials; legacy fallback warns. - src/specificClass.js: buildUpsertRequest emits folderUid when set. - src/commands/handlers.js: pass folderUid from config to buildUpsertRequest. - test/basic/slice34-credentials-and-folder.basic.test.js: 5 new tests. Diff-based regeneration (F-1) and the explicit flows:started lifecycle hook land in #36 once the S1 spike predicate is wired. Until then, the existing child.register message trigger continues to drive composition on every startup-time child registration. Closes #34
119 lines
4.1 KiB
HTML
119 lines
4.1 KiB
HTML
<script src="/dashboardapi/menu.js"></script>
|
|
<script src="/dashboardapi/configData.js"></script>
|
|
|
|
<script>
|
|
RED.nodes.registerType('dashboardapi', {
|
|
category: 'EVOLV',
|
|
color: '#7A8BA3',
|
|
defaults: {
|
|
name: { value: '' },
|
|
enableLog: { value: true },
|
|
logLevel: { value: 'info' },
|
|
|
|
protocol: { value: 'http' },
|
|
host: { value: 'localhost' },
|
|
port: { value: 3000 },
|
|
folderUid: { value: '' },
|
|
defaultBucket: { value: '' },
|
|
},
|
|
credentials: {
|
|
bearerToken: { type: 'password' },
|
|
},
|
|
inputs: 1,
|
|
outputs: 1,
|
|
inputLabels: ['Input'],
|
|
outputLabels: ['grafana'],
|
|
icon: 'font-awesome/fa-area-chart',
|
|
|
|
label: function () {
|
|
return this.name || 'dashboardapi';
|
|
},
|
|
|
|
oneditprepare: function () {
|
|
const waitForMenuData = () => {
|
|
if (window.EVOLV?.nodes?.dashboardapi?.loggerMenu?.initEditor) {
|
|
window.EVOLV.nodes.dashboardapi.loggerMenu.initEditor(this);
|
|
} else {
|
|
setTimeout(waitForMenuData, 50);
|
|
}
|
|
};
|
|
waitForMenuData();
|
|
},
|
|
|
|
oneditsave: function () {
|
|
const node = this;
|
|
|
|
if (window.EVOLV?.nodes?.dashboardapi?.loggerMenu?.saveEditor) {
|
|
window.EVOLV.nodes.dashboardapi.loggerMenu.saveEditor(node);
|
|
}
|
|
|
|
['name', 'protocol', 'host', 'port', 'folderUid', 'defaultBucket'].forEach((field) => {
|
|
const element = document.getElementById(`node-input-${field}`);
|
|
if (!element) return;
|
|
node[field] = field === 'port' ? parseInt(element.value, 10) || 3000 : element.value || '';
|
|
});
|
|
// bearerToken is handled by Node-RED's credentials system (encrypted at rest in flow_cred.json).
|
|
},
|
|
});
|
|
</script>
|
|
|
|
<!-- Main UI Template -->
|
|
<script type="text/html" data-template-name="dashboardapi">
|
|
<div class="form-row">
|
|
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
|
|
<input type="text" id="node-input-name" placeholder="name" style="width:70%;" />
|
|
</div>
|
|
|
|
<div class="form-row">
|
|
<label for="node-input-protocol"><i class="fa fa-exchange"></i> Protocol</label>
|
|
<select id="node-input-protocol" style="width:70%;">
|
|
<option value="http">http</option>
|
|
<option value="https">https</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="form-row">
|
|
<label for="node-input-host"><i class="fa fa-server"></i> Grafana Host</label>
|
|
<input type="text" id="node-input-host" placeholder="localhost" style="width:70%;" />
|
|
</div>
|
|
|
|
<div class="form-row">
|
|
<label for="node-input-port"><i class="fa fa-plug"></i> Grafana Port</label>
|
|
<input type="number" id="node-input-port" placeholder="3000" style="width:70%;" />
|
|
</div>
|
|
|
|
<div class="form-row">
|
|
<label for="node-input-bearerToken"><i class="fa fa-key"></i> Bearer Token</label>
|
|
<input type="password" id="node-input-bearerToken" placeholder="encrypted at rest" style="width:70%;" />
|
|
</div>
|
|
|
|
<div class="form-row">
|
|
<label for="node-input-folderUid"><i class="fa fa-folder-open"></i> Grafana Folder UID</label>
|
|
<input type="text" id="node-input-folderUid" placeholder="optional — empty = General folder" style="width:70%;" />
|
|
</div>
|
|
|
|
<div class="form-row">
|
|
<label for="node-input-defaultBucket"><i class="fa fa-database"></i> InfluxDB Bucket</label>
|
|
<input type="text" id="node-input-defaultBucket" placeholder="env INFLUXDB_BUCKET or lvl2" style="width:70%;" />
|
|
</div>
|
|
|
|
<div id="logger-fields-placeholder"></div>
|
|
</script>
|
|
|
|
<script type="text/html" data-help-name="dashboardapi">
|
|
<p>
|
|
This node interacts with the Grafana API with the following capabilities:
|
|
|
|
• Dashboard Management: Create, update, or delete dashboards.
|
|
• Metrics Querying: Retrieve performance and operational data.
|
|
• Alerts Management: Monitor and manage alerts.
|
|
|
|
It allows you to configure:
|
|
|
|
- Connection details (host, port, bearer token) for secure API access.
|
|
- Logging options, including the ability to enable logging and set the log level (info, debug, warn, error).
|
|
|
|
These features provide flexible and controlled interactions with the Grafana API.
|
|
</p>
|
|
</script>
|