From 7246c0b935e2600a8dd7a83fb850bd1ec482f169 Mon Sep 17 00:00:00 2001 From: shuqi7 Date: Mon, 22 Apr 2019 18:02:20 -0700 Subject: [PATCH 01/12] Grouped actions in task/supervisor table to a dialog --- web-console/package.json | 2 + .../src/dialogs/table-action-dialog.scss | 84 +++++++ .../src/dialogs/table-action-dialog.tsx | 223 ++++++++++++++++++ web-console/src/views/tasks-view.scss | 5 + web-console/src/views/tasks-view.tsx | 72 ++++-- 5 files changed, 360 insertions(+), 26 deletions(-) create mode 100644 web-console/src/dialogs/table-action-dialog.scss create mode 100644 web-console/src/dialogs/table-action-dialog.tsx diff --git a/web-console/package.json b/web-console/package.json index ad9c0f82e302..9bc9b09f5ea0 100644 --- a/web-console/package.json +++ b/web-console/package.json @@ -42,11 +42,13 @@ "druid-console": "^0.0.2", "es6-shim": "^0.35.5", "es7-shim": "^6.0.0", + "file-saver": "^2.0.1", "hjson": "^3.1.2", "lodash.debounce": "^4.0.8", "numeral": "^2.0.6", "react": "^16.8.6", "react-ace": "^6.4.0", + "react-copy-to-clipboard": "^5.0.1", "react-dom": "^16.8.6", "react-router": "^5.0.0", "react-router-dom": "^5.0.0", diff --git a/web-console/src/dialogs/table-action-dialog.scss b/web-console/src/dialogs/table-action-dialog.scss new file mode 100644 index 000000000000..c4ef59f1c879 --- /dev/null +++ b/web-console/src/dialogs/table-action-dialog.scss @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +.table-action-dialog { + &.bp3-dialog { + width: 700px; + top: 5%; + height: 70vh; + display: flex; + flex-direction: row; + } + + .side-bar { + width: 20%; + + .info-button { + &.active { + background-color: #2C74A8; + } + + width: 100%; + height: 10vh; + cursor: pointer; + + .icon { + position: relative; + left: 45%; + top: 2vh; + } + + .text { + position: relative; + left: 28%; + top: 5vh; + } + } + } + + .main-section { + width: 76%; + height: 100%; + padding-left: 1vw; + + .top-actions { + + margin: 0.5vh 0; + + .right-buttons { + float: right; + } + } + + textarea { + width: 100%; + height: 85%; + } + + .bottom-buttons { + margin: 2vh 0; + + button { + width: 100px; + } + .button-done { + float: right; + } + } + } +} diff --git a/web-console/src/dialogs/table-action-dialog.tsx b/web-console/src/dialogs/table-action-dialog.tsx new file mode 100644 index 000000000000..b5a83dc10cd4 --- /dev/null +++ b/web-console/src/dialogs/table-action-dialog.tsx @@ -0,0 +1,223 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {Button, ButtonGroup, Dialog, Intent, TextArea} from '@blueprintjs/core'; +import axios from 'axios'; +import * as FileSaver from 'file-saver'; +import * as React from 'react'; +import * as CopyToClipboard from 'react-copy-to-clipboard'; + +import {AppToaster} from '../singletons/toaster'; +import { getDruidErrorMessage } from '../utils'; + +import './table-action-dialog.scss'; + +interface TableActionDialogProps extends React.Props { + onClose: () => void; + metaData: TableActionDialogMetaData; + terminateSupervisor: (id: string) => void; + resetSupervisor: (id: string) => void; + resumeSupervisor: (id: string) => void; + suspendSupervisor: (id: string) => void; + killTask: (id: string) => void; +} + +interface TableActionDialogState { + jsonValue: string; + activeEndpoint: '' | 'status' | 'stats' | 'history' | 'reports' | 'log?offset=-8192' | 'log'; +} + +export interface TableActionDialogMetaData { + id: string | null; + mode: 'supervisor' | 'task' | null; + status: 'RUNNING' | 'WAITING' | 'PENDING' | 'SUCCESS' | 'FAILED' | null; + supervisorSuspended: boolean | null; +} + +export class TableActionDialog extends React.Component { + constructor(props: TableActionDialogProps) { + super(props); + this.state = { + jsonValue: '', + activeEndpoint: '' + }; + } + + private getJsonInfo = async (endpoint: string) => { + const { mode, id } = this.props.metaData; + try { + const resp = await axios.get(`/druid/indexer/v1/${mode}/${id}/${endpoint}`); + const data = resp.data; + this.setState({ + jsonValue: JSON.stringify(data, undefined, 2) + }); + } catch (e) { + AppToaster.show({ + message: getDruidErrorMessage(e), + intent: Intent.WARNING + }); + } + } + + private downloadJson = () => { + const { id, mode } = this.props.metaData; + const { jsonValue, activeEndpoint } = this.state; + + const blob = new Blob([jsonValue], { + type: 'text/json' + }); + + FileSaver.saveAs(blob, `${mode}-${id}-${activeEndpoint === '' ? 'payload' : activeEndpoint}.json`); + } + + render() { + const { onClose, terminateSupervisor, resetSupervisor, resumeSupervisor, suspendSupervisor } = this.props; + const { jsonValue, activeEndpoint } = this.state; + const { id, mode, status, supervisorSuspended } = this.props.metaData; + + const supervisorTableInfoButtons = [ + {icon: 'align-left', text: 'Payload', endpoint: ``}, + {icon: 'dashboard', text: 'Status', endpoint: `status`}, + {icon: 'chart', text: 'Statistics', endpoint: `stats`}, + {icon: 'history', text: 'History', endpoint: `history`} + ]; + + const taskTableInfoButtons = [ + {icon: 'align-left', text: 'Payload', endpoint: ``}, + {icon: 'dashboard', text: 'Status', endpoint: `status`}, + {icon: 'comparison', text: 'Reports', endpoint: `reports`}, + {icon: 'align-justify', text: 'Logs', endpoint: `log?offset=-8192`} + ]; + + const tableInfoButtons = mode === 'supervisor' ? supervisorTableInfoButtons : taskTableInfoButtons; + + const tableActionButtions = mode === 'supervisor' + ? [ +