Skip to content

Commit 2458aef

Browse files
committed
OPG-501: Grafana 12 compatibility updates
1 parent 7198f57 commit 2458aef

File tree

6 files changed

+436
-362
lines changed

6 files changed

+436
-362
lines changed

.gitignore

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,10 @@
11
.DS_Store
22
node_modules
33
npm-debug.log
4-
yarn-error.log
54
coverage/
65
.aws-config.json
76
awsconfig
8-
/emails/dist
9-
/public_gen
107
/tmp
11-
vendor/phantomjs/phantomjs
12-
vendor/opennms*.js*
13-
vendor/parenthesis
14-
vendor/crypto-js
158

169
docs/AWS_S3_BUCKET
1710
docs/GIT_BRANCH
@@ -33,19 +26,13 @@ public/css/*.min.css
3326
/bin/*
3427

3528
conf/custom.ini
36-
fig.yml
37-
profile.cov
38-
/grafana
39-
.notouch
4029

4130
# Antora documentation
4231
public/
4332
build/
4433

4534
# Not ready yet
4635
/dist
47-
/SPECS
48-
/SOURCES
4936

5037
# Debian package droppings
5138
/dist/opennms-grafana-plugin

DEVELOPMENT.md

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,92 @@ Use the `npm overrides` mechanism in the `package.json`. Delete the `package-loc
9292
}
9393
```
9494

95+
## Issue with Grafana, json-source-map and our opennms-js OnmsEnum / toJSON representation
9596
## opennms-js and json-source-map isJSON issue
9697

9798
This is described more fully here: https://github.com/OpenNMS/opennms-js/pull/1118
9899

99100
Just note that if `opennms-js` has any model data classes which have a `toJSON` method (which returns a somewhat more human-readable version of the object), it will also have this fix, meaning the object will also have a fake `.replace()` method on it. Should not cause any issues, but just noting it here.
101+
102+
More details...
103+
104+
This is a bit long-winded, but it was tricky to debug.
105+
106+
There is an issue with how Grafana saves and serializes panel data and our `opennms-js` implementation of `OnmsEnum`
107+
and derived classes.
108+
109+
In cases where we are using the Grafana `SegmentAsync` dropdown, which has a `loadOptions` function to
110+
load nodes (ultimately via `opennms-js` and to our Rest API), we need to make sure that the `loadNodes` prop receives a
111+
`SelectableValue<T>[]`, e.g. `SelectableValue<PerformanceAttributeItemState>[]`, and
112+
*not* an `OnmsNode[]`.
113+
114+
While `OnmsNode` has an `id` and `label` which `SelectableValue<T>` might be expecting, there's another issue.
115+
116+
When you make a change in a query editor, Grafana saves off the panel state.
117+
Grafana does a `jsonDiff` by serializing the old and new state.
118+
They use the `json-source-map` npm library to stringify objects (recursively) before diffing.
119+
120+
`json-source-map` has a line where if an object has a `toJSON()` function, it uses
121+
it to stringify the object. It expects `toJSON()` to return a `String`.
122+
123+
Our `OnmsEnum`, and derived classes (for example `OnmsManagedType`, used in `OnmsIpInterface.isManaged`,
124+
used in `OnmsNode.ipInterfaces`), has a `toJSON()` function defined, but it returns
125+
an object `{ id: this.i, label: this.l }` instead of a `String`.
126+
127+
The Grafana code then calls `getDashboardChanges`, `getPanelChanges`:
128+
129+
```
130+
const diff = jsonDiff(originalSaveModel, saveModel);
131+
```
132+
133+
`jsonDiff` calls `jsonMap.stringify()` (`jsonMap` is from `json-source-map`) which calls `_stringify`.
134+
135+
`_stringify` does a check if the item is an object and has a `toJSON` function and calls it.
136+
137+
Then also inside json-source-map:
138+
139+
```
140+
function quoted(str) {
141+
str = str.replace(ESC_QUOTE, '\\$&')
142+
...
143+
```
144+
145+
This throws a `TypeError` since `str` is actually an `OnmsNode`, not a `String`, and does not have a
146+
`replace` function.
147+
148+
```
149+
case 'object':
150+
if (_data === null) {
151+
out('null');
152+
} else if (typeof _data.toJSON == 'function') {
153+
out(quoted(_data.toJSON()));
154+
}
155+
```
156+
157+
See: https://github.com/epoberezkin/json-source-map/blob/master/index.js, `_stringify`.
158+
159+
See: https://github.com/grafana/grafana/blob/main/public/app/features/dashboard-scene/panel-edit/PanelEditor.tsx where `getPanelChanges` is called.
160+
161+
See: https://github.com/grafana/grafana/blob/main/public/app/features/dashboard-scene/saving/getDashboardChanges.ts where the `jsonDiff` occurs.
162+
163+
If we do the conversion from `OnmsNode` to a `SelectableValue<T>`, `json-source-map` will call their `stringifyObject` since
164+
the object does not have a `toJSON`, and it should work correctly.
165+
166+
Example, in `PerformanceQueryEditor.tsx`:
167+
168+
```
169+
const nodes = await datasource.client.findNodes(filter, true)
170+
171+
const selectableValues: SelectableValue<PerformanceAttributeItemState>[] = nodes.map(n => {
172+
return {
173+
id: n.id,
174+
label: n.label,
175+
value: {
176+
id: n.id,
177+
label: n.label
178+
}
179+
}
180+
})
181+
182+
return selectableValues
183+
```

0 commit comments

Comments
 (0)