From c36115c861c023f4dcb6cd5460f33e4c44b66984 Mon Sep 17 00:00:00 2001 From: vargburz Date: Fri, 13 Jan 2023 16:51:21 +0300 Subject: [PATCH 1/6] set dashboard timerange in date picker --- .../corpglory-dataexporter-panel/components/Panel.tsx | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/panels/corpglory-dataexporter-panel/components/Panel.tsx b/src/panels/corpglory-dataexporter-panel/components/Panel.tsx index 1af10d9..73527be 100644 --- a/src/panels/corpglory-dataexporter-panel/components/Panel.tsx +++ b/src/panels/corpglory-dataexporter-panel/components/Panel.tsx @@ -31,6 +31,7 @@ import { DataQuery, DataSourceSettings, TimeRange, + OrgRole, } from '@grafana/data'; import { RefreshEvent } from '@grafana/runtime'; @@ -40,6 +41,7 @@ import * as _ from 'lodash'; interface Props extends PanelProps {} export function Panel({ width, height, timeRange, eventBus }: Props) { + console.log('contextSrv', contextSrv, OrgRole.Admin); // TODO: Dashboard type const [dashboard, setDashboard] = useState(null); const [datasources, setDatasources] = useState(null); @@ -103,10 +105,10 @@ export function Panel({ width, height, timeRange, eventBus }: Props) { }, [dashboard, datasources]); // eslint-disable-line react-hooks/exhaustive-deps useEffect(() => { - if (tasks === null) { - return; - } - const dataFrame = getDataFrameForTaskTable(tasks); + // if (tasks === null) { + // return; + // } + const dataFrame = getDataFrameForTaskTable([]); setTasksDataFrame(dataFrame); }, [tasks]); // eslint-disable-line react-hooks/exhaustive-deps @@ -185,6 +187,7 @@ export function Panel({ width, height, timeRange, eventBus }: Props) { } function openDatasourceModal(): void { + setTimeRange(timeRange); setModalVisibility(true); } From 1deeb6e6260c55ba3c17b0fdd4389b2094b1969b Mon Sep 17 00:00:00 2001 From: rozetko Date: Fri, 13 Jan 2023 19:25:10 +0300 Subject: [PATCH 2/6] it works --- .../components/Panel.tsx | 73 +++++++++++-------- .../corpglory-dataexporter-panel/types.ts | 49 ++++++++----- src/services/api_service.ts | 24 +++--- src/utils/index.ts | 6 +- 4 files changed, 89 insertions(+), 63 deletions(-) diff --git a/src/panels/corpglory-dataexporter-panel/components/Panel.tsx b/src/panels/corpglory-dataexporter-panel/components/Panel.tsx index 1af10d9..fe6fc83 100644 --- a/src/panels/corpglory-dataexporter-panel/components/Panel.tsx +++ b/src/panels/corpglory-dataexporter-panel/components/Panel.tsx @@ -1,4 +1,4 @@ -import { PanelOptions, TaskTableRowConfig, QueryTableRowConfig, DatasourceType } from '../types'; +import { PanelOptions, ExportTask, DashboardQuery, DatasourceType, ExportStatus } from '../types'; import { convertTimestampToDate, getDashboardUid } from '../../../utils'; import { CLOSE_ICON_BASE_64, DOWNLOAD_ICON_BASE_64, SELECT_ICON_BASE_64, UNSELECT_ICON_BASE_64 } from '../../../icons'; @@ -44,8 +44,8 @@ export function Panel({ width, height, timeRange, eventBus }: Props) { const [dashboard, setDashboard] = useState(null); const [datasources, setDatasources] = useState(null); - const [tasks, setTasks] = useState(null); - const [queries, setQueries] = useState(null); + const [tasks, setTasks] = useState(null); + const [queries, setQueries] = useState(null); const [tasksDataFrame, setTasksDataFrame] = useState(null); const [queriesDataFrame, setQueriesDataFrame] = useState(null); @@ -77,7 +77,7 @@ export function Panel({ width, height, timeRange, eventBus }: Props) { return; } dashboard.panels.forEach((panel: PanelModel) => { - const queries: QueryTableRowConfig[] = []; + const queries: DashboardQuery[] = []; // @ts-ignore // TODO: move plugin id to const @@ -124,8 +124,7 @@ export function Panel({ width, height, timeRange, eventBus }: Props) { .then((tasks) => { setTasks(tasks); for (let task of tasks) { - // TODO: ExportStatus enum - if (task.status === 'exporting') { + if (task.progress?.status === ExportStatus.EXPORTING) { setTimeout(refresh, 1000); return; } @@ -155,18 +154,23 @@ export function Panel({ width, height, timeRange, eventBus }: Props) { } async function onAddTaskClick(): Promise { - const selectedQueries = _.filter(queries, (query: QueryTableRowConfig) => query.selected); - // TODO: timerange picker + const selectedQueries = _.filter(queries, (query: DashboardQuery) => query.selected); const timerange: [number, number] = [selectedTimeRange.from.unix(), selectedTimeRange.to.unix()]; + + const task: ExportTask = { + // @ts-ignore + username: contextSrv.user.name, + timeRange: { + from: timerange[0] * 1000, + to: timerange[1] * 1000, + }, + queries: selectedQueries + } // TODO: move this function to API Service await queryApi('/task', { method: 'POST', data: { - from: timerange[0] * 1000, - to: timerange[1] * 1000, - // @ts-ignore - username: contextSrv.user.name, - tasks: selectedQueries, + task, url: window.location.toString(), }, }); @@ -181,7 +185,7 @@ export function Panel({ width, height, timeRange, eventBus }: Props) { if (queries === null) { return; } - setQueries(queries.map((query: QueryTableRowConfig) => ({ ...query, selected: false }))); + setQueries(queries.map((query: DashboardQuery) => ({ ...query, selected: false }))); } function openDatasourceModal(): void { @@ -193,7 +197,7 @@ export function Panel({ width, height, timeRange, eventBus }: Props) { unselectAllQueries(); } - function getDataFrameForQueriesTable(configs: QueryTableRowConfig[]): DataFrame { + function getDataFrameForQueriesTable(queries: DashboardQuery[]): DataFrame { const dataFrame = toDataFrame({ name: 'A', fields: [ @@ -201,8 +205,8 @@ export function Panel({ width, height, timeRange, eventBus }: Props) { name: 'Select', type: FieldType.string, values: _.map( - configs, - (config) => `data:image/svg+xml;base64,${config.selected ? SELECT_ICON_BASE_64 : UNSELECT_ICON_BASE_64}` + queries, + (query) => `data:image/svg+xml;base64,${query.selected ? SELECT_ICON_BASE_64 : UNSELECT_ICON_BASE_64}` ), config: { custom: { @@ -222,17 +226,17 @@ export function Panel({ width, height, timeRange, eventBus }: Props) { { name: 'Panel', type: FieldType.string, - values: _.map(configs, (config) => config.panel.title), + values: _.map(queries, (query) => query.panel.title), }, { name: 'RefId', type: FieldType.string, - values: _.map(configs, (config) => config.refId), + values: _.map(queries, (query) => query.refId), }, { name: 'Datasource', type: FieldType.string, - values: _.map(configs, (config) => config.datasource.name), + values: _.map(queries, (query) => query.datasource.name), }, ], }); @@ -249,44 +253,49 @@ export function Panel({ width, height, timeRange, eventBus }: Props) { return dataFrames[0]; } - function getDataFrameForTaskTable(configs: TaskTableRowConfig[]): DataFrame { + function getDataFrameForTaskTable(tasks: ExportTask[]): DataFrame { const dataFrame = toDataFrame({ name: 'A', fields: [ { name: 'Time', type: FieldType.number, - values: _.map(configs, (config) => convertTimestampToDate(config.timestamp)), + values: _.map(tasks, (task) => convertTimestampToDate(task.progress?.time)), }, { name: 'User', type: FieldType.string, - values: _.map(configs, (config) => config.username), + values: _.map(tasks, (task) => task.username), }, { name: 'Datasource', type: FieldType.string, - values: _.map(configs, (config) => getDatasourceByUid(config.datasourceRef?.uid)?.name), + values: _.map(tasks, (task) => task.queries.map(query => query.datasource?.name).join(',')), }, { name: 'Exported Rows', type: FieldType.number, - values: _.map(configs, (config) => config.rowsCount), + values: _.map(tasks, (task) => task.progress?.exportedRowsCount), }, { name: 'Progress', type: FieldType.string, - values: _.map(configs, (config) => `${(config.progress * 100).toFixed(0)}%`), + values: _.map(tasks, (task) => `${((task.progress?.progress || 0) * 100).toFixed(0)}%`), }, { name: 'Status', type: FieldType.string, - values: _.map(configs, (config) => config.status), + values: _.map(tasks, (task) => task.progress?.status), + }, + { + name: 'Error', + type: FieldType.string, + values: _.map(tasks, (task) => task.progress?.errorMessage || '-'), }, { name: 'Download CSV', type: FieldType.string, - values: _.map(configs, () => `data:image/png;base64,${DOWNLOAD_ICON_BASE_64}`), + values: _.map(tasks, () => `data:image/png;base64,${DOWNLOAD_ICON_BASE_64}`), config: { custom: { filterable: false, @@ -305,7 +314,7 @@ export function Panel({ width, height, timeRange, eventBus }: Props) { { name: 'Delete task', type: FieldType.string, - values: _.map(configs, () => `data:image/png;base64,${CLOSE_ICON_BASE_64}`), + values: _.map(tasks, () => `data:image/png;base64,${CLOSE_ICON_BASE_64}`), config: { custom: { filterable: false, @@ -340,7 +349,7 @@ export function Panel({ width, height, timeRange, eventBus }: Props) { const rowIndex = e.origin.rowIndex; const task = _.find(tasks, (task, idx) => idx === rowIndex); - await deleteTask(task?.filename); + await deleteTask(task?.id); const filteredTasks = _.filter(tasks, (task, idx) => idx !== rowIndex); setTasks(filteredTasks); @@ -349,7 +358,7 @@ export function Panel({ width, height, timeRange, eventBus }: Props) { function onDownloadClick(e: DataLinkClickEvent): void { const rowIndex = e.origin.rowIndex; const task = _.find(tasks, (task, idx) => idx === rowIndex); - getStaticFile(task?.filename); + getStaticFile(task?.id); } function onDatasourceSelectClick(e: DataLinkClickEvent): void { @@ -409,7 +418,7 @@ export function Panel({ width, height, timeRange, eventBus }: Props) { aria-label="Add task button" onClick={onAddTaskClick} // TODO: move to function - disabled={!queries?.filter((query: QueryTableRowConfig) => query.selected)?.length} + disabled={!queries?.filter((query: DashboardQuery) => query.selected)?.length} > Add Task diff --git a/src/panels/corpglory-dataexporter-panel/types.ts b/src/panels/corpglory-dataexporter-panel/types.ts index c83ef92..915a58d 100644 --- a/src/panels/corpglory-dataexporter-panel/types.ts +++ b/src/panels/corpglory-dataexporter-panel/types.ts @@ -1,23 +1,7 @@ -import { DataQuery, DataSourceRef, DataSourceSettings, PanelModel } from '@grafana/data'; +import { DataQuery, DataSourceSettings, PanelModel } from '@grafana/data'; export interface PanelOptions {} -export type TaskTableRowConfig = { - timestamp: number; - username: string; - datasourceRef: DataSourceRef; - rowsCount: number; - progress: number; - status: string; - filename?: string; -}; - -export type QueryTableRowConfig = Omit & { - selected: boolean; - panel: PanelModel; - datasource: DataSourceSettings; -}; - export enum DatasourceType { INFLUXDB = 'influxdb', GRAPHITE = 'graphite', @@ -26,3 +10,34 @@ export enum DatasourceType { ELASTICSEARCH = 'elasticsearch', MYSQL = 'mysql', } + +export enum ExportStatus { + EXPORTING = 'exporting', + FINISHED = 'finished', + ERROR = 'error', +} + +export type ExportProgress = { + time: number; + exportedRowsCount: number; + progress: number; + status: ExportStatus; + errorMessage?: string; +}; + +export type ExportTask = { + username: string; + queries: DashboardQuery[]; + timeRange: { + from: number; + to: number; + }; + progress?: ExportProgress; + id?: string; +}; + +export type DashboardQuery = DataQuery & { + selected: boolean; + panel: PanelModel; + datasource: DataSourceSettings; +}; diff --git a/src/services/api_service.ts b/src/services/api_service.ts index a803327..d12acd0 100644 --- a/src/services/api_service.ts +++ b/src/services/api_service.ts @@ -1,4 +1,4 @@ -import { TaskTableRowConfig } from '../panels/corpglory-dataexporter-panel/types'; +import { ExportTask } from '../panels/corpglory-dataexporter-panel/types'; import axios from 'axios'; import * as _ from 'lodash'; @@ -43,24 +43,24 @@ export const queryApi = async (path: string, config: RequestConfig) => return response.data as RT; }; -export async function getTasks(): Promise { - return queryApi('/task', {}); +export async function getTasks(): Promise { + return queryApi('/task', {}); } -export async function deleteTask(filename?: string): Promise { - if (_.isEmpty(filename)) { - console.warn(`can't delete task without filename`); +export async function deleteTask(taskId?: string): Promise { + if (_.isEmpty(taskId)) { + console.warn(`can't delete task without taskId`); return; } - await queryApi('/task', { method: 'DELETE', data: { filename } }); + await queryApi('/task', { method: 'DELETE', data: { taskId } }); } -export async function getStaticFile(filename?: string): Promise { - if (_.isEmpty(filename)) { - console.warn(`can't download file without name`); +export async function getStaticFile(taskId?: string): Promise { + if (_.isEmpty(taskId)) { + console.warn(`can't download file without taskId`); return; } - const respData = await queryApi(`/static/${filename}.csv`, {}); + const respData = await queryApi(`/static/${taskId}.csv`, {}); // TODO: check if resp exists // create file link in browser's memory const href = URL.createObjectURL(new Blob([respData], { type: 'text/csv' })); @@ -68,7 +68,7 @@ export async function getStaticFile(filename?: string): Promise { // create "a" HTML element with href to file & click const link = document.createElement('a'); link.href = href; - link.setAttribute('download', `${filename}.csv`); + link.setAttribute('download', `${taskId}.csv`); document.body.appendChild(link); link.click(); diff --git a/src/utils/index.ts b/src/utils/index.ts index 43ac013..83e9eac 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -15,7 +15,7 @@ export function getDashboardUid(url: string): string { } } -export function convertTimestampToDate(timestamp: number): string { +export function convertTimestampToDate(timestamp?: number): string { const options: Intl.DateTimeFormatOptions = { year: 'numeric', month: 'short', @@ -24,5 +24,7 @@ export function convertTimestampToDate(timestamp: number): string { minute: 'numeric', second: 'numeric', }; - return new Date(timestamp).toLocaleString('en-GB', options); + return timestamp ? + new Date(timestamp).toLocaleString('en-GB', options): + '-'; } From ff567a6148efefda0d529e0df0b34d9a72a77753 Mon Sep 17 00:00:00 2001 From: vargburz Date: Fri, 13 Jan 2023 19:56:10 +0300 Subject: [PATCH 3/6] UX improve for bad cases --- .../components/Panel.tsx | 154 +++++++++++------- .../corpglory-dataexporter-panel/types.ts | 7 + 2 files changed, 100 insertions(+), 61 deletions(-) diff --git a/src/panels/corpglory-dataexporter-panel/components/Panel.tsx b/src/panels/corpglory-dataexporter-panel/components/Panel.tsx index 73527be..66a44f1 100644 --- a/src/panels/corpglory-dataexporter-panel/components/Panel.tsx +++ b/src/panels/corpglory-dataexporter-panel/components/Panel.tsx @@ -1,4 +1,4 @@ -import { PanelOptions, TaskTableRowConfig, QueryTableRowConfig, DatasourceType } from '../types'; +import { PanelOptions, TaskTableRowConfig, QueryTableRowConfig, DatasourceType, PanelStatus } from '../types'; import { convertTimestampToDate, getDashboardUid } from '../../../utils'; import { CLOSE_ICON_BASE_64, DOWNLOAD_ICON_BASE_64, SELECT_ICON_BASE_64, UNSELECT_ICON_BASE_64 } from '../../../icons'; @@ -38,10 +38,12 @@ import { RefreshEvent } from '@grafana/runtime'; import React, { useState, useEffect } from 'react'; import * as _ from 'lodash'; +const PANEL_ID = 'corpglory-dataexporter-panel'; +const APP_ID = 'corpglory-dataexporter-app'; + interface Props extends PanelProps {} export function Panel({ width, height, timeRange, eventBus }: Props) { - console.log('contextSrv', contextSrv, OrgRole.Admin); // TODO: Dashboard type const [dashboard, setDashboard] = useState(null); const [datasources, setDatasources] = useState(null); @@ -56,6 +58,13 @@ export function Panel({ width, height, timeRange, eventBus }: Props) { const [selectedTimeRange, setTimeRange] = useState(timeRange); + const [panelStatus, setPanelStatus] = useState(PanelStatus.LOADING); + + if (contextSrv.user.orgRole !== OrgRole.Admin) { + // TODO: it shouldn't be overriten + setPanelStatus(PanelStatus.PERMISSION_ERROR); + } + useEffect(() => { async function getCurrentDashboard(): Promise { const currentDashboardUid = getDashboardUid(window.location.toString()); @@ -82,8 +91,7 @@ export function Panel({ width, height, timeRange, eventBus }: Props) { const queries: QueryTableRowConfig[] = []; // @ts-ignore - // TODO: move plugin id to const - if (panel.type === 'corpglory-dataexporter-panel') { + if (panel.type === PANEL_ID) { return; } @@ -125,6 +133,7 @@ export function Panel({ width, height, timeRange, eventBus }: Props) { getTasks() .then((tasks) => { setTasks(tasks); + setPanelStatus(PanelStatus.OK); for (let task of tasks) { // TODO: ExportStatus enum if (task.status === 'exporting') { @@ -133,7 +142,10 @@ export function Panel({ width, height, timeRange, eventBus }: Props) { } } }) - .catch((err) => console.error(err)); + .catch((err) => { + setPanelStatus(PanelStatus.DATASOURCE_ERROR); + console.error('some error', err); + }); } eventBus.subscribe(RefreshEvent, refresh); @@ -367,65 +379,85 @@ export function Panel({ width, height, timeRange, eventBus }: Props) { const styles = useStyles2(getStyles); - return ( + const loadingDiv = ; + // TODO: add styles + const datasourceErrorDiv = (
- {tasksDataFrame === null ? ( - // TODO: if datasource responds with error, display the error - - ) : ( -
- - - - - {queriesDataFrame === null ? ( - // TODO: if datasource responds with error, display the error - - ) : ( -
- - - { - setTimeRange(newTimeRange); - }} - /> - -
- - - - - - )} - - - - )} +

Datasource is unavailable.

+
+ Click here to configure DataExporter. +
+ {/* TODO: display error message? */} ); + const permissionErrorDiv = ( +
+

Permission Error.

+
DataExporter panel availabel only for Admins
+
+ ); + const mainDiv = ( +
+
+ + + + {queriesDataFrame === null ? ( + + ) : ( +
+ + + { + setTimeRange(newTimeRange); + }} + /> + +
+ + + + + + )} + + + + ); + + function renderSwitch(panelStatus: PanelStatus): JSX.Element { + switch (panelStatus) { + case PanelStatus.LOADING: + return loadingDiv; + case PanelStatus.DATASOURCE_ERROR: + return datasourceErrorDiv; + case PanelStatus.PERMISSION_ERROR: + return permissionErrorDiv; + case PanelStatus.OK: + return mainDiv; + default: + return datasourceErrorDiv; + } + } + return
{renderSwitch(panelStatus)}
; } const getStyles = () => ({ diff --git a/src/panels/corpglory-dataexporter-panel/types.ts b/src/panels/corpglory-dataexporter-panel/types.ts index c83ef92..421660e 100644 --- a/src/panels/corpglory-dataexporter-panel/types.ts +++ b/src/panels/corpglory-dataexporter-panel/types.ts @@ -26,3 +26,10 @@ export enum DatasourceType { ELASTICSEARCH = 'elasticsearch', MYSQL = 'mysql', } + +export enum PanelStatus { + LOADING = 'Loading', + DATASOURCE_ERROR = 'Datasource Error', + PERMISSION_ERROR = 'Permission Error', + OK = 'Ok', +} From 29d7c5393c885f4270dfc2dcae507464b3e2018f Mon Sep 17 00:00:00 2001 From: vargburz Date: Fri, 13 Jan 2023 20:07:57 +0300 Subject: [PATCH 4/6] return tassks --- .../corpglory-dataexporter-panel/components/Panel.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/panels/corpglory-dataexporter-panel/components/Panel.tsx b/src/panels/corpglory-dataexporter-panel/components/Panel.tsx index ce92b46..e2b1b17 100644 --- a/src/panels/corpglory-dataexporter-panel/components/Panel.tsx +++ b/src/panels/corpglory-dataexporter-panel/components/Panel.tsx @@ -113,10 +113,10 @@ export function Panel({ width, height, timeRange, eventBus }: Props) { }, [dashboard, datasources]); // eslint-disable-line react-hooks/exhaustive-deps useEffect(() => { - // if (tasks === null) { - // return; - // } - const dataFrame = getDataFrameForTaskTable([]); + if (tasks === null) { + return; + } + const dataFrame = getDataFrameForTaskTable(tasks); setTasksDataFrame(dataFrame); }, [tasks]); // eslint-disable-line react-hooks/exhaustive-deps From 05a643436ae4bafc1e4f31cf0bf1a5cbc9fb71d1 Mon Sep 17 00:00:00 2001 From: rozetko Date: Wed, 18 Jan 2023 19:45:21 +0300 Subject: [PATCH 5/6] upd DashboardQuery type --- src/panels/corpglory-dataexporter-panel/components/Panel.tsx | 5 ++--- src/panels/corpglory-dataexporter-panel/types.ts | 3 ++- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/panels/corpglory-dataexporter-panel/components/Panel.tsx b/src/panels/corpglory-dataexporter-panel/components/Panel.tsx index e2b1b17..e537936 100644 --- a/src/panels/corpglory-dataexporter-panel/components/Panel.tsx +++ b/src/panels/corpglory-dataexporter-panel/components/Panel.tsx @@ -100,12 +100,11 @@ export function Panel({ width, height, timeRange, eventBus }: Props) { } panel.targets?.forEach((target: DataQuery) => { - console.log('uid', target.datasource?.uid); const datasource = getDatasourceByUid(target.datasource?.uid); if (!datasource) { return; } - queries.push({ ...target, selected: false, panel, datasource }); + queries.push({ selected: false, target, panel, datasource }); }); setQueries(queries); @@ -246,7 +245,7 @@ export function Panel({ width, height, timeRange, eventBus }: Props) { { name: 'RefId', type: FieldType.string, - values: _.map(queries, (query) => query.refId), + values: _.map(queries, (query) => query.target.refId), }, { name: 'Datasource', diff --git a/src/panels/corpglory-dataexporter-panel/types.ts b/src/panels/corpglory-dataexporter-panel/types.ts index edacd6f..1af9a8d 100644 --- a/src/panels/corpglory-dataexporter-panel/types.ts +++ b/src/panels/corpglory-dataexporter-panel/types.ts @@ -43,8 +43,9 @@ export type ExportTask = { id?: string; }; -export type DashboardQuery = DataQuery & { +export type DashboardQuery = { selected: boolean; + target: DataQuery; panel: PanelModel; datasource: DataSourceSettings; }; From a9184050f42e98bb2730922426be119b84ef63d7 Mon Sep 17 00:00:00 2001 From: rozetko Date: Thu, 19 Jan 2023 14:40:36 +0300 Subject: [PATCH 6/6] pass timezone to the api --- .../components/Panel.tsx | 11 +++++++---- src/utils/index.ts | 13 ++++++++++++- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/panels/corpglory-dataexporter-panel/components/Panel.tsx b/src/panels/corpglory-dataexporter-panel/components/Panel.tsx index e537936..cb45844 100644 --- a/src/panels/corpglory-dataexporter-panel/components/Panel.tsx +++ b/src/panels/corpglory-dataexporter-panel/components/Panel.tsx @@ -1,6 +1,6 @@ import { PanelOptions, ExportTask, DashboardQuery, DatasourceType, ExportStatus, PanelStatus } from '../types'; -import { convertTimestampToDate, getDashboardUid } from '../../../utils'; +import { convertTimestampToDate, convertTimeZoneTypeToName, getDashboardUid } from '../../../utils'; import { CLOSE_ICON_BASE_64, DOWNLOAD_ICON_BASE_64, SELECT_ICON_BASE_64, UNSELECT_ICON_BASE_64 } from '../../../icons'; import { deleteTask, getStaticFile, getTasks, queryApi } from '../../../services/api_service'; @@ -43,7 +43,7 @@ const APP_ID = 'corpglory-dataexporter-app'; interface Props extends PanelProps {} -export function Panel({ width, height, timeRange, eventBus }: Props) { +export function Panel({ width, height, timeRange, eventBus, timeZone }: Props) { // TODO: Dashboard type const [dashboard, setDashboard] = useState(null); const [datasources, setDatasources] = useState(null); @@ -60,6 +60,8 @@ export function Panel({ width, height, timeRange, eventBus }: Props) { const [panelStatus, setPanelStatus] = useState(PanelStatus.LOADING); + const timeZoneName = convertTimeZoneTypeToName(timeZone); + if (contextSrv.user.orgRole !== OrgRole.Admin) { // TODO: it shouldn't be overriten setPanelStatus(PanelStatus.PERMISSION_ERROR); @@ -166,7 +168,7 @@ export function Panel({ width, height, timeRange, eventBus }: Props) { return datasource; } - async function onAddTaskClick(): Promise { + async function onAddTaskClick(timeZoneName: string): Promise { const selectedQueries = _.filter(queries, (query: DashboardQuery) => query.selected); const timerange: [number, number] = [selectedTimeRange.from.unix(), selectedTimeRange.to.unix()]; @@ -185,6 +187,7 @@ export function Panel({ width, height, timeRange, eventBus }: Props) { data: { task, url: window.location.toString(), + timeZoneName, }, }); @@ -437,7 +440,7 @@ export function Panel({ width, height, timeRange, eventBus }: Props) {