Skip to content
Merged
Show file tree
Hide file tree
Changes from 36 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
d9e8363
Update contexts request
kapantzak Jul 30, 2024
a8a73e2
Uopdate nodes request
kapantzak Jul 30, 2024
aa0cfb4
wip
kapantzak Jul 30, 2024
352e04e
Format files
kapantzak Jul 30, 2024
68f24d4
Fix response
kapantzak Jul 30, 2024
f5b5f2f
Fix contexts request
kapantzak Jul 30, 2024
30a327f
Add missing useEffect dependencies
kapantzak Jul 30, 2024
dfcb379
Fix failing test
kapantzak Jul 30, 2024
a317804
Transform nodes response
kapantzak Jul 30, 2024
320d436
[DEBUG]
kapantzak Jul 30, 2024
0846677
Revert "[DEBUG]"
kapantzak Jul 31, 2024
6054b0c
Fix node tranformation
kapantzak Jul 31, 2024
dfd7603
[DEBUG]
kapantzak Sep 9, 2024
ee23cf3
Revert "[DEBUG]"
kapantzak Sep 9, 2024
fa3df38
[wip] Refactor data payload
kapantzak Sep 9, 2024
ad7856b
Remove debuging code and add dimensions to scope
kapantzak Sep 10, 2024
054d25d
Adjust to v3 data response
kapantzak Sep 10, 2024
ef16f7a
Fix type
kapantzak Sep 10, 2024
8a32ce1
Get value index form point
kapantzak Sep 10, 2024
87a267d
wip
kapantzak Sep 10, 2024
159cfa6
Update deprecated actions/upload-artifact version
kapantzak Sep 12, 2024
55f9ac4
Remove charts/<context> request
kapantzak Sep 12, 2024
fb07644
Fix linting error
kapantzak Sep 12, 2024
3f62e66
Remove unused import
kapantzak Sep 12, 2024
9741528
[DEBUG]
kapantzak Sep 12, 2024
ec41559
Revert "[DEBUG]"
kapantzak Sep 12, 2024
be84d41
Fix groupingByList options type
kapantzak Sep 12, 2024
ee7b523
Remove comments
kapantzak Sep 12, 2024
9e17a58
Handle empty labels array
kapantzak Sep 12, 2024
413cc31
Fix filters
kapantzak Sep 12, 2024
1895452
Delete unused useFetchDimensions
kapantzak Sep 12, 2024
ab368c8
Reset filter value on each filter change
kapantzak Sep 13, 2024
491c3cf
Change node name accessor prop
kapantzak Mar 24, 2025
8b555cf
fixup! Change node name accessor prop
kapantzak Mar 24, 2025
4c7111b
Update major version
kapantzak Mar 24, 2025
45031cc
Fix licence text
kapantzak Mar 24, 2025
5e5fdc1
Minor change
kapantzak Apr 22, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,16 @@ on:
default: 'false'
type: choice
options:
- 'true'
- 'false'
- 'true'
- 'false'
ENV:
required: true
default: 'testing'
type: choice
options:
- testing
- staging
- production
- testing
- staging
- production

env:
BRANCH: ${{ github.event.inputs.BRANCH || github.ref }}
Expand All @@ -44,7 +44,7 @@ jobs:
- name: Setup Node.js environment
uses: actions/[email protected]
with:
node-version: "14.x"
node-version: '14.x'

- name: Get yarn cache directory path
id: yarn-cache-dir-path
Expand Down Expand Up @@ -84,7 +84,7 @@ jobs:
zip "netdata-datasource-${{ steps.build_environment.outputs.BUILD_VERSION }}.zip" netdata-datasource -r

- name: Upload artifacts
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v4
with:
name: netdata-datasource-${{ steps.build_environment.outputs.BUILD_VERSION }}.zip
path: ./netdata-datasource-${{ steps.build_environment.outputs.BUILD_VERSION }}.zip
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: Release
on:
push:
tags:
- "v*.*.*"
- 'v*.*.*'

jobs:
release:
Expand All @@ -17,7 +17,7 @@ jobs:
- name: Setup Node.js environment
uses: actions/[email protected]
with:
node-version: "14.x"
node-version: '14.x'

- name: Get yarn cache directory path
id: yarn-cache-dir-path
Expand Down Expand Up @@ -64,7 +64,7 @@ jobs:
export GRAFANA_PLUGIN_TYPE=$(cat dist/plugin.json | jq -r .type)
export GRAFANA_PLUGIN_ARTIFACT=${GRAFANA_PLUGIN_ID}-${GRAFANA_PLUGIN_VERSION}.zip
export GRAFANA_PLUGIN_ARTIFACT_CHECKSUM=${GRAFANA_PLUGIN_ARTIFACT}.md5

echo "plugin-id=${GRAFANA_PLUGIN_ID}" >> $GITHUB_OUTPUT
echo "plugin-version=${GRAFANA_PLUGIN_VERSION}" >> $GITHUB_OUTPUT
echo "plugin-type=${GRAFANA_PLUGIN_TYPE}" >> $GITHUB_OUTPUT
Expand All @@ -91,7 +91,7 @@ jobs:
echo "checksum=$(cat './${{ steps.metadata.outputs.archive-checksum }}' | cut -d' ' -f1)" >> $GITHUB_OUTPUT

- name: Upload artifacts
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v4
with:
name: ${{ steps.metadata.outputs.archive }}
path: ./${{ steps.metadata.outputs.archive }}
Expand Down
2 changes: 1 addition & 1 deletion .prettierrc.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module.exports = {
...require("./node_modules/@grafana/toolkit/src/config/prettier.plugin.config.json"),
...require('./node_modules/@grafana/toolkit/src/config/prettier.plugin.config.json'),
};
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.

Copyright {yyyy} {name of copyright owner}
Copyright 2025 Netdata

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "netdatacloud-netdata-datasource",
"version": "2.0.0",
"version": "3.0.0",
"description": "netdata datasource plugin",
"scripts": {
"build": "grafana-toolkit plugin:build",
Expand Down
41 changes: 26 additions & 15 deletions src/QueryEditor.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react';
import React, { useState } from 'react';
import { Input, LegacyForms, Select } from '@grafana/ui';
import { QueryEditorProps, SelectableValue } from '@grafana/data';
import { DataSource } from './datasource';
Expand All @@ -9,16 +9,21 @@ import { useFetchRooms } from 'shared/hooks/useFetchRooms';
import { useFetchContexts } from 'shared/hooks/useFetchContexts';
import { useFetchNodes } from 'shared/hooks/useFetchNodes';
import { Aggreagations, GroupByList, Methods } from 'shared/constants';
import { useFetchDimensions } from 'shared/hooks/useFetchDimensions';
import { Dropdown } from 'shared/types/dropdown.interface';
import { getDimensions, getFilters, getGroupingByList, defaultFilter } from 'shared/utils/transformations';
import PubSub from 'pubsub-js';

type Props = QueryEditorProps<DataSource, MyQuery, MyDataSourceOptions>;

const { FormField } = LegacyForms;

const QueryEditor: React.FC<Props> = ({ datasource, query, onChange, onRunQuery }) => {
const QueryEditor: React.FC<Props> = ({ datasource, query, range, onChange, onRunQuery }) => {
const { baseUrl } = datasource;
const from = range!.from.valueOf();
const to = range!.to.valueOf();
const after = Math.floor(from / 1000);
const before = Math.floor(to / 1000);

const [selectedSpace, setSelectedSpace] = React.useState<Dropdown>();
const [selectedRoom, setSelectedRoom] = React.useState<Dropdown>();
const [selectedFilter, setSelectedFilter] = React.useState<Dropdown>();
Expand All @@ -42,16 +47,26 @@ const QueryEditor: React.FC<Props> = ({ datasource, query, onChange, onRunQuery
const { rooms, fetchRooms } = useFetchRooms(baseUrl);
const { nodes, fetchNodes } = useFetchNodes(baseUrl);
const { contexts, fetchContexts } = useFetchContexts(baseUrl);
const { allDimensions, groupingByList, filters, units, fetchDimensions } = useFetchDimensions(baseUrl);
const [allDimensions, setAllDimension] = useState([]);
const [units, setUnits] = useState('');
const [filters, setFilters] = useState<any>(defaultFilter);
const [groupingByList, setGroupingByList] = useState<Dropdown[]>(GroupByList);

const filterList = React.useMemo(() => Object.keys(filters).map((s) => ({ label: s, value: s })), [filters]);
const nodeList = React.useMemo(() => nodes?.map((c: any) => ({ label: c.name, value: c.id })), [nodes]);

const { spaceId, roomId, nodes: allNodes, dimensions, groupBy, contextId, filterBy, filterValue } = query;

const mySubscriber = (msg: any, data: any) => {
setTotalNodes(data.data.nodes.length);
setTotalInstances(data.data.nodes.reduce((acc: number, node: any) => acc + node.chartIDs.length, 0));
const { summary, view } = data?.data || {};
const { nodes = [], instances = [], labels = [] } = summary || {};
const { dimensions, units } = view || {};
setFilters(getFilters(labels));
setGroupingByList(getGroupingByList(labels));
setAllDimension(getDimensions(dimensions));
setUnits(units);
setTotalNodes(nodes.length);
setTotalInstances(instances.length);
};

const isGroupFunctionAvailable = React.useCallback(() => {
Expand Down Expand Up @@ -88,9 +103,9 @@ const QueryEditor: React.FC<Props> = ({ datasource, query, onChange, onRunQuery
const room = rooms.find((r) => r.value === roomId);
setSelectedRoom({ label: room?.label, value: room?.value });
fetchNodes(spaceId || '', roomId);
fetchContexts(spaceId || '', roomId);
fetchContexts(spaceId || '', roomId, after, before);
}
}, [roomId, rooms, fetchContexts, fetchNodes, spaceId]);
}, [roomId, rooms, fetchContexts, fetchNodes, spaceId, after, before]);

React.useEffect(() => {
// eslint-disable-line
Expand All @@ -115,8 +130,6 @@ const QueryEditor: React.FC<Props> = ({ datasource, query, onChange, onRunQuery
filteredNodes.push({ label: currentNode?.name, value: currentNode?.id });
});
}

fetchDimensions({ spaceId, roomId, contextId, nodeIDs: filteredNodes.map((n: any) => n.value) });
}
}, [contextId]); // eslint-disable-line

Expand Down Expand Up @@ -171,7 +184,7 @@ const QueryEditor: React.FC<Props> = ({ datasource, query, onChange, onRunQuery
setSelectedMethod(Methods[0]);
setSelectedAggregations(Aggreagations[0]);

fetchContexts(selectedSpace?.value || '', v.value || '');
fetchContexts(selectedSpace?.value || '', v.value || '', after, before);
fetchNodes(selectedSpace?.value || '', v.value || '');
onChange({ ...query, spaceId: spaceId, roomId: v.value });
onRunQuery();
Expand All @@ -188,7 +201,6 @@ const QueryEditor: React.FC<Props> = ({ datasource, query, onChange, onRunQuery
setSelectedMethod(Methods[0]);
setSelectedAggregations(Aggreagations[0]);

fetchDimensions({ spaceId, roomId, contextId: v.value, nodeIDs: selectedNodes?.map((n: any) => n.value) || [] });
onChange({ ...query, contextId: v.value });
onRunQuery();
};
Expand All @@ -204,7 +216,6 @@ const QueryEditor: React.FC<Props> = ({ datasource, query, onChange, onRunQuery
setSelectedMethod(Methods[0]);
setSelectedAggregations(Aggreagations[0]);

fetchDimensions({ spaceId, roomId, contextId, nodeIDs: data });
setSelectedNodes(data);
onChange({ ...query, spaceId, roomId, contextId, nodes: data } as MyQuery);
onRunQuery();
Expand All @@ -225,13 +236,13 @@ const QueryEditor: React.FC<Props> = ({ datasource, query, onChange, onRunQuery

const onFilterByChange = (v: SelectableValue<string>) => {
setSelectedFilter(v);
setSelectedFilterValue({});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this correct?


if (v.value === 'No filter') {
setSelectedFilterValue({});
onChange({ ...query, filterBy: undefined, filterValue: undefined });
onRunQuery();
} else {
setFilterByValues(filters[v?.value || ''].map((v) => ({ label: v, value: v })));
setFilterByValues(filters[v?.value || ''].map((v: string) => ({ label: v, value: v })));
}
};

Expand Down
9 changes: 6 additions & 3 deletions src/datasource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,16 +61,19 @@ export class DataSource extends DataSourceApi<MyQuery, MyDataSourceOptions> {
const frame = new MutableDataFrame({
refId,
fields: response.data.result.labels.map((id: string, i: number) => {
const node = response.data.nodes.find((n: any) => n.id === id);
const node = response.data.summary.nodes.find((n: any) => n.mg === id);
return {
name: node?.name || id,
name: node?.nm || id,
type: i === 0 ? FieldType.time : FieldType.number,
};
}),
});

const valueIndex = response.data.result.point.value;

response.data.result.data.forEach((point: any) => {
frame.appendRow([...point]);
const [timestamp, ...rest] = point;
frame.appendRow([timestamp, ...rest.map((r: any[]) => r[valueIndex])]);
});

return frame;
Expand Down
2 changes: 1 addition & 1 deletion src/shared/hooks/useFetchContexts.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ describe('useFetchContexts', () => {

const { result, waitFor } = renderHook(() => hooks.useFetchContexts(baseUrl));

await result.current.fetchContexts('spaceId', 'roomId');
await result.current.fetchContexts('spaceId', 'roomId', -900, 0);

await waitFor(() => result.current.contexts.length > 0);

Expand Down
30 changes: 24 additions & 6 deletions src/shared/hooks/useFetchContexts.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,40 @@
import { Dropdown } from './../types/dropdown.interface';
import React from 'react';
import { Get } from 'shared/utils/request';
import { Post } from 'shared/utils/request';

export const getContexts = async (spaceId: string, roomId: string, baseUrl: string) => {
const response = await Get({ path: `/v2/spaces/${spaceId}/rooms/${roomId}/contexts`, baseUrl });
return response?.data?.results as string[];
export const getContexts = async (spaceId: string, roomId: string, after: number, before: number, baseUrl: string) => {
const response = await Post({
path: `/v3/spaces/${spaceId}/rooms/${roomId}/contexts`,
baseUrl,
data: {
scope: {
contexts: ['*'],
nodes: [],
},
selectors: {
contexts: [],
nodes: [],
},
window: {
after,
before,
},
},
});
const { contexts = {} } = response?.data || {};
return Object.keys(contexts) as string[];
};

export const useFetchContexts = (baseUrl: string) => {
const [isError, setIsError] = React.useState(false);
const [contexts, setContexts] = React.useState<Dropdown[]>([]);

const fetchContexts = React.useCallback(
async (spaceId: string, roomId: string) => {
async (spaceId: string, roomId: string, after: number, before: number) => {
setIsError(false);

try {
const result = await getContexts(spaceId, roomId, baseUrl);
const result = await getContexts(spaceId, roomId, after, before, baseUrl);
setContexts(result.map((c) => ({ label: c, value: c })));
} catch (error) {
setIsError(true);
Expand Down
Loading
Loading