|
|
|
@ -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<PanelOptions> {} |
|
|
|
|
|
|
|
|
|
export function Panel({ width, height, timeRange, eventBus }: Props) { |
|
|
|
|
console.log('contextSrv', contextSrv, OrgRole.Admin); |
|
|
|
|
// TODO: Dashboard type
|
|
|
|
|
const [dashboard, setDashboard] = useState<any | null>(null); |
|
|
|
|
const [datasources, setDatasources] = useState<DataSourceSettings[] | null>(null); |
|
|
|
@ -56,6 +58,13 @@ export function Panel({ width, height, timeRange, eventBus }: Props) {
|
|
|
|
|
|
|
|
|
|
const [selectedTimeRange, setTimeRange] = useState<TimeRange>(timeRange); |
|
|
|
|
|
|
|
|
|
const [panelStatus, setPanelStatus] = useState<PanelStatus>(PanelStatus.LOADING); |
|
|
|
|
|
|
|
|
|
if (contextSrv.user.orgRole !== OrgRole.Admin) { |
|
|
|
|
// TODO: it shouldn't be overriten
|
|
|
|
|
setPanelStatus(PanelStatus.PERMISSION_ERROR); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
|
async function getCurrentDashboard(): Promise<any> { |
|
|
|
|
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 = <LoadingPlaceholder text="Loading..."></LoadingPlaceholder>; |
|
|
|
|
// TODO: add styles
|
|
|
|
|
const datasourceErrorDiv = ( |
|
|
|
|
<div> |
|
|
|
|
{tasksDataFrame === null ? ( |
|
|
|
|
// TODO: if datasource responds with error, display the error
|
|
|
|
|
<LoadingPlaceholder text="Loading..."></LoadingPlaceholder> |
|
|
|
|
) : ( |
|
|
|
|
<div> |
|
|
|
|
<Table width={width} height={height - 40} data={tasksDataFrame} /> |
|
|
|
|
<HorizontalGroup justify="flex-end"> |
|
|
|
|
<Button |
|
|
|
|
variant="primary" |
|
|
|
|
aria-label="Rich history button" |
|
|
|
|
icon="plus" |
|
|
|
|
style={{ marginTop: '8px' }} |
|
|
|
|
onClick={openDatasourceModal} |
|
|
|
|
> |
|
|
|
|
Add Task |
|
|
|
|
</Button> |
|
|
|
|
<Modal |
|
|
|
|
title="Select Queries" |
|
|
|
|
isOpen={isModalOpen} |
|
|
|
|
onDismiss={onCloseModal} |
|
|
|
|
className={styles.calendarModal} |
|
|
|
|
> |
|
|
|
|
{queriesDataFrame === null ? ( |
|
|
|
|
// TODO: if datasource responds with error, display the error
|
|
|
|
|
<LoadingPlaceholder text="Loading..."></LoadingPlaceholder> |
|
|
|
|
) : ( |
|
|
|
|
<div> |
|
|
|
|
<VerticalGroup spacing="xs"> |
|
|
|
|
<HorizontalGroup justify="flex-start" spacing="md"> |
|
|
|
|
<TimeRangeInput |
|
|
|
|
value={selectedTimeRange} |
|
|
|
|
onChange={(newTimeRange) => { |
|
|
|
|
setTimeRange(newTimeRange); |
|
|
|
|
}} |
|
|
|
|
/> |
|
|
|
|
</HorizontalGroup> |
|
|
|
|
<Table width={width / 2 - 20} height={height - 40} data={queriesDataFrame} /> |
|
|
|
|
<HorizontalGroup justify="flex-end" spacing="md"> |
|
|
|
|
<Button |
|
|
|
|
variant="primary" |
|
|
|
|
aria-label="Add task button" |
|
|
|
|
onClick={onAddTaskClick} |
|
|
|
|
// TODO: move to function
|
|
|
|
|
disabled={!queries?.filter((query: QueryTableRowConfig) => query.selected)?.length} |
|
|
|
|
> |
|
|
|
|
Add Task |
|
|
|
|
</Button> |
|
|
|
|
</HorizontalGroup> |
|
|
|
|
</VerticalGroup> |
|
|
|
|
</div> |
|
|
|
|
)} |
|
|
|
|
</Modal> |
|
|
|
|
</HorizontalGroup> |
|
|
|
|
</div> |
|
|
|
|
)} |
|
|
|
|
<p>Datasource is unavailable.</p> |
|
|
|
|
<div> |
|
|
|
|
Click <a href={`/plugins/${APP_ID}`}>here</a> to configure DataExporter. |
|
|
|
|
</div> |
|
|
|
|
{/* TODO: display error message? */} |
|
|
|
|
</div> |
|
|
|
|
); |
|
|
|
|
const permissionErrorDiv = ( |
|
|
|
|
<div> |
|
|
|
|
<p>Permission Error.</p> |
|
|
|
|
<div> DataExporter panel availabel only for Admins </div> |
|
|
|
|
</div> |
|
|
|
|
); |
|
|
|
|
const mainDiv = ( |
|
|
|
|
<div> |
|
|
|
|
<Table width={width} height={height - 40} data={tasksDataFrame as DataFrame} /> |
|
|
|
|
<HorizontalGroup justify="flex-end"> |
|
|
|
|
<Button |
|
|
|
|
variant="primary" |
|
|
|
|
aria-label="Rich history button" |
|
|
|
|
icon="plus" |
|
|
|
|
style={{ marginTop: '8px' }} |
|
|
|
|
onClick={openDatasourceModal} |
|
|
|
|
> |
|
|
|
|
Add Task |
|
|
|
|
</Button> |
|
|
|
|
<Modal title="Select Queries" isOpen={isModalOpen} onDismiss={onCloseModal} className={styles.calendarModal}> |
|
|
|
|
{queriesDataFrame === null ? ( |
|
|
|
|
<LoadingPlaceholder text="Loading..."></LoadingPlaceholder> |
|
|
|
|
) : ( |
|
|
|
|
<div> |
|
|
|
|
<VerticalGroup spacing="xs"> |
|
|
|
|
<HorizontalGroup justify="flex-start" spacing="md"> |
|
|
|
|
<TimeRangeInput |
|
|
|
|
value={selectedTimeRange} |
|
|
|
|
onChange={(newTimeRange) => { |
|
|
|
|
setTimeRange(newTimeRange); |
|
|
|
|
}} |
|
|
|
|
/> |
|
|
|
|
</HorizontalGroup> |
|
|
|
|
<Table width={width / 2 - 20} height={height - 40} data={queriesDataFrame} /> |
|
|
|
|
<HorizontalGroup justify="flex-end" spacing="md"> |
|
|
|
|
<Button |
|
|
|
|
variant="primary" |
|
|
|
|
aria-label="Add task button" |
|
|
|
|
onClick={onAddTaskClick} |
|
|
|
|
// TODO: move to function
|
|
|
|
|
disabled={!queries?.filter((query: QueryTableRowConfig) => query.selected)?.length} |
|
|
|
|
> |
|
|
|
|
Add Task |
|
|
|
|
</Button> |
|
|
|
|
</HorizontalGroup> |
|
|
|
|
</VerticalGroup> |
|
|
|
|
</div> |
|
|
|
|
)} |
|
|
|
|
</Modal> |
|
|
|
|
</HorizontalGroup> |
|
|
|
|
</div> |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
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 <div>{renderSwitch(panelStatus)}</div>; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const getStyles = () => ({ |
|
|
|
|