Skip to content

Commit

Permalink
Add Editable Table for Custom Scales (#11)
Browse files Browse the repository at this point in the history
* Add Editable Table for Custom Scales

* Add upsert timescales and group by well

* Add reset button and exclude current scale from Table

* Remove form from Custom Scales Editor

* Updates

---------

Co-authored-by: Mikhail Volkov <[email protected]>
  • Loading branch information
asimonok and mikhail-vl authored Jul 31, 2024
1 parent a166e9b commit 2f2e060
Show file tree
Hide file tree
Showing 15 changed files with 475 additions and 190 deletions.
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Change Log

## 1.1.0 (IN PROGRESS)
## 1.1.0 (2024-07-31)

### Features / Enhancements

Expand All @@ -13,4 +13,4 @@

- Based on the Abc Panel template 3.1.0
- Add Time Series panel from 10.0.3 (#1)
- Update README and Provisioning (#2)
- Update README and Provisioning (#2)
3 changes: 0 additions & 3 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ version: '3.4'

services:
grafana:
container_name: grafana
image: ghcr.io/volkovlabs/app:latest
ports:
- 3000:3000/tcp
Expand All @@ -15,7 +14,6 @@ services:
- ./provisioning:/etc/grafana/provisioning

timescale:
container_name: timescale
image: timescale/timescaledb:latest-pg12
restart: always
environment:
Expand All @@ -26,7 +24,6 @@ services:
- ./timescale:/docker-entrypoint-initdb.d

server:
container_name: server
build:
context: ./timescale
ports:
Expand Down
32 changes: 32 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"@grafana/runtime": "^10.0.2",
"@grafana/ui": "^10.0.0",
"@reduxjs/toolkit": "^1.9.5",
"@tanstack/react-table": "^8.10.7",
"logfmt": "^1.3.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
Expand Down Expand Up @@ -72,5 +73,5 @@
"test:ci": "jest --maxWorkers 4 --coverage",
"upgrade": "npm upgrade --save"
},
"version": "1.0.0"
"version": "1.1.0"
}
2 changes: 1 addition & 1 deletion provisioning/dashboards/panels.json
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@
"format": "table",
"hide": false,
"rawQuery": true,
"rawSql": "select min, max from scales where metric='Temperature' order by time desc limit 1;",
"rawSql": "select min, max from scales where metric='Temperature';",
"refId": "B",
"sql": {
"columns": [
Expand Down
35 changes: 27 additions & 8 deletions src/TimeSeriesPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ import { ExemplarsPlugin, getVisibleLabels } from './plugins/ExemplarsPlugin';
import { OutsideRangePlugin } from './plugins/OutsideRangePlugin';
import { ThresholdControlsPlugin } from './plugins/ThresholdControlsPlugin';
import { TimescaleEditor } from './plugins/timescales/TimescaleEditor';
import { TimescaleEditFormDTO } from './plugins/timescales/TimescaleEditorForm';
import { TimescaleItem } from './plugins/timescales/TimescaleEditorForm';
import { getPrepareTimeseriesSuggestion } from './suggestions';
import { useRuntimeVariables } from './hooks';
import { getTimezones, prepareGraphableFields, regenerateLinksSupplier } from './utils';

interface TimeSeriesPanelProps extends PanelProps<Options> {}
Expand All @@ -30,6 +31,7 @@ export const TimeSeriesPanel = ({
onChangeTimeRange,
replaceVariables,
id,
eventBus,
}: TimeSeriesPanelProps) => {
const { sync, canAddAnnotations, onThresholdsChange, canEditThresholds, showThresholds, onSplitOpen } =
usePanelContext();
Expand Down Expand Up @@ -64,10 +66,20 @@ export const TimeSeriesPanel = ({
});
}

const { variable: wellVariable } = useRuntimeVariables(eventBus, options.variable);

let well = '';
if (
wellVariable &&
(wellVariable.type === 'query' || wellVariable.type === 'custom' || wellVariable.type === 'constant')
) {
well = Array.isArray(wellVariable.current.value) ? wellVariable.current.value[0] : wellVariable.current.value;
}

const getTimescales = useCallback(async () => {
const user = config.bootData.user;
const userId = user?.id;
const rawSql = `select last(min, time) as min, last(max, time) as max, metric from scales where user_id='${userId}' group by metric;`;
const rawSql = `select min, max, metric from scales where user_id='${userId}' and well='${well}';`;
const target = data.request?.targets[0];
const datasourceId = target?.datasource?.uid;
const refId = target?.refId;
Expand Down Expand Up @@ -97,15 +109,15 @@ export const TimeSeriesPanel = ({
}

setTimescalesFrame(null);
}, [data.request?.targets]);
}, [data.request?.targets, well]);

const onAddTimescale = useCallback(
async (formData: TimescaleEditFormDTO) => {
const onUpsertTimescale = useCallback(
async (formData: TimescaleItem) => {
const { min, max, description, scale } = formData;
const user = config.bootData.user;
const userId = user?.id;
const sanitizedDescription = description.replace(/\"|\'/g, '');
const rawSql = `insert into scales values(now(), ${min}, ${max}, '${sanitizedDescription}', ${userId}, '${scale}')`;
const rawSql = `insert into scales values ('${well}', '${userId}', '${scale}', ${min}, ${max}, '${sanitizedDescription}') on conflict (well, user_id, metric) do update set min = excluded.min, max = excluded.max;`;
const target = data.request?.targets[0];
const datasourceId = target?.datasource?.uid;
const refId = target?.refId;
Expand All @@ -128,9 +140,16 @@ export const TimeSeriesPanel = ({
],
to: 'now',
});
},
[data.request?.targets, well]
);

const onUpsertTimescales = useCallback(
async (timescales: TimescaleItem[]) => {
await Promise.all(timescales.map((timescale) => onUpsertTimescale(timescale)));
setAddingTimescale(false);
},
[data]
[onUpsertTimescale]
);

const suggestions = useMemo(() => {
Expand Down Expand Up @@ -258,7 +277,7 @@ export const TimeSeriesPanel = ({
)}
{isAddingTimescale && (
<TimescaleEditor
onSave={onAddTimescale}
onSave={onUpsertTimescales}
onDismiss={() => setAddingTimescale(false)}
scales={scales}
style={{
Expand Down
1 change: 1 addition & 0 deletions src/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './useRuntimeVariables';
44 changes: 44 additions & 0 deletions src/hooks/useRuntimeVariables.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { useCallback, useEffect, useState } from 'react';
import { EventBus, TypedVariableModel } from '@grafana/data';
import { getTemplateSrv, RefreshEvent } from '@grafana/runtime';

/**
* Runtime Variables
* @param eventBus
* @param variableName
*/
export const useRuntimeVariables = (eventBus: EventBus, variableName: string) => {
const [variables, setVariables] = useState<TypedVariableModel[]>([]);
const [variable, setVariable] = useState<TypedVariableModel>();

useEffect(() => {
setVariables(getTemplateSrv().getVariables());

/**
* Update variable on Refresh
*/
const subscriber = eventBus.getStream(RefreshEvent).subscribe(() => {
setVariables(getTemplateSrv().getVariables());
});

return () => {
subscriber.unsubscribe();
};
}, [eventBus]);

const getVariable = useCallback(
(variableName: string) => {
return variables.find((variable) => variable.name === variableName);
},
[variables]
);

useEffect(() => {
setVariable(getVariable(variableName));
}, [getVariable, variableName]);

return {
variable,
getVariable,
};
};
4 changes: 2 additions & 2 deletions src/plugins/timescales/TimescaleEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import React, { HTMLAttributes, useState } from 'react';
import { usePopper } from 'react-popper';
import { Portal } from '@grafana/ui';
import { DataFrame } from '@grafana/data';
import { TimescaleEditFormDTO, TimescaleEditorForm } from './TimescaleEditorForm';
import { TimescaleEditorForm, TimescaleItem } from './TimescaleEditorForm';

interface TimescaleEditorProps extends HTMLAttributes<HTMLDivElement> {
onSave: (data: TimescaleEditFormDTO) => void;
onSave: (data: TimescaleItem[]) => void;
onDismiss: () => void;
scales: string[];
timescalesFrame: DataFrame | null;
Expand Down
Loading

0 comments on commit 2f2e060

Please sign in to comment.