Browse Source

Merge pull request 'UX improvements for bad cases' (#9) from ui-ux-improvements into master

Reviewed-on: #9
pull/10/head
rozetko 1 year ago
parent
commit
21578aa6b5
  1. 162
      src/panels/corpglory-dataexporter-panel/components/Panel.tsx
  2. 7
      src/panels/corpglory-dataexporter-panel/types.ts

162
src/panels/corpglory-dataexporter-panel/components/Panel.tsx

@ -1,4 +1,4 @@
import { PanelOptions, ExportTask, DashboardQuery, DatasourceType, ExportStatus } from '../types';
import { PanelOptions, ExportTask, DashboardQuery, DatasourceType, ExportStatus, 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';
@ -31,12 +31,16 @@ import {
DataQuery,
DataSourceSettings,
TimeRange,
OrgRole,
} from '@grafana/data';
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) {
@ -54,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());
@ -80,8 +91,7 @@ export function Panel({ width, height, timeRange, eventBus }: Props) {
const queries: DashboardQuery[] = [];
// @ts-ignore
// TODO: move plugin id to const
if (panel.type === 'corpglory-dataexporter-panel') {
if (panel.type === PANEL_ID) {
return;
}
@ -123,6 +133,7 @@ export function Panel({ width, height, timeRange, eventBus }: Props) {
getTasks()
.then((tasks) => {
setTasks(tasks);
setPanelStatus(PanelStatus.OK);
for (let task of tasks) {
if (task.progress?.status === ExportStatus.EXPORTING) {
setTimeout(refresh, 1000);
@ -130,7 +141,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);
@ -164,8 +178,8 @@ export function Panel({ width, height, timeRange, eventBus }: Props) {
from: timerange[0] * 1000,
to: timerange[1] * 1000,
},
queries: selectedQueries
}
queries: selectedQueries,
};
// TODO: move this function to API Service
await queryApi('/task', {
method: 'POST',
@ -189,6 +203,7 @@ export function Panel({ width, height, timeRange, eventBus }: Props) {
}
function openDatasourceModal(): void {
setTimeRange(timeRange);
setModalVisibility(true);
}
@ -270,7 +285,7 @@ export function Panel({ width, height, timeRange, eventBus }: Props) {
{
name: 'Datasource',
type: FieldType.string,
values: _.map(tasks, (task) => task.queries.map(query => query.datasource?.name).join(',')),
values: _.map(tasks, (task) => task.queries.map((query) => query.datasource?.name).join(',')),
},
{
name: 'Exported Rows',
@ -373,65 +388,86 @@ 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>
<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>
{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: DashboardQuery) => query.selected)?.length}
>
Add Task
</Button>
</HorizontalGroup>
</VerticalGroup>
</div>
)}
</Modal>
</HorizontalGroup>
</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 ? (
// 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: DashboardQuery) => 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 = () => ({

7
src/panels/corpglory-dataexporter-panel/types.ts

@ -11,6 +11,13 @@ export enum DatasourceType {
MYSQL = 'mysql',
}
export enum PanelStatus {
LOADING = 'Loading',
DATASOURCE_ERROR = 'Datasource Error',
PERMISSION_ERROR = 'Permission Error',
OK = 'Ok',
}
export enum ExportStatus {
EXPORTING = 'exporting',
FINISHED = 'finished',

Loading…
Cancel
Save