This is an automated email from the ASF dual-hosted git repository. cwylie pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/incubator-druid.git
The following commit(s) were added to refs/heads/master by this push: new 0fa122e Adding ability to pass configs in and fixing misc bugs (#7414) 0fa122e is described below commit 0fa122ecf21211921162be0c0c3b67a210f6c0f2 Author: Vadim Ogievetsky <vadi...@gmail.com> AuthorDate: Fri Apr 5 12:40:43 2019 -0700 Adding ability to pass configs in and fixing misc bugs (#7414) * Adding ability to pass configs in and fixing misc bugs * update lock file * remove dead version param --- ...ble-column-selection.scss => console-config.js} | 17 +--- web-console/package-lock.json | 2 +- web-console/script/cp-to | 1 + web-console/src/components/auto-form.tsx | 1 + web-console/src/components/header-bar.tsx | 39 ++++++--- .../src/components/table-column-selection.scss | 6 +- web-console/src/console-application.tsx | 11 ++- web-console/src/entry.ts | 9 +- web-console/src/views/lookups-view.tsx | 96 ++++++++++++++-------- web-console/unified-console.html | 3 +- 10 files changed, 110 insertions(+), 75 deletions(-) diff --git a/web-console/src/components/table-column-selection.scss b/web-console/console-config.js similarity index 76% copy from web-console/src/components/table-column-selection.scss copy to web-console/console-config.js index b1cb80a..127d3a0 100644 --- a/web-console/src/components/table-column-selection.scss +++ b/web-console/console-config.js @@ -16,19 +16,4 @@ * limitations under the License. */ -.table-column-selection { - position: absolute; - right: 0; - margin: 0; -} - -// This will be mounted in a portal -.table-column-selection-menu { - .form-group { - margin-bottom: 0; - - .bp3-checkbox:last-child { - margin-bottom: 0; - } - } -} +window.consoleConfig = { /* future configs may go here */ }; diff --git a/web-console/package-lock.json b/web-console/package-lock.json index 61dba3c..22ea74e 100644 --- a/web-console/package-lock.json +++ b/web-console/package-lock.json @@ -1,6 +1,6 @@ { "name": "web-console", - "version": "0.14.0", + "version": "0.15.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/web-console/script/cp-to b/web-console/script/cp-to index 81240ff..b8ad2eb 100755 --- a/web-console/script/cp-to +++ b/web-console/script/cp-to @@ -20,6 +20,7 @@ echo "Copying web-console files to $1..." mkdir -p "$1" cp *.html "$1" cp *.png "$1" +cp console-config.js "$1" cp -r coordinator-console "$1" cp -r old-console "$1" cp -r pages "$1" diff --git a/web-console/src/components/auto-form.tsx b/web-console/src/components/auto-form.tsx index aad21e0..c1ade7a 100644 --- a/web-console/src/components/auto-form.tsx +++ b/web-console/src/components/auto-form.tsx @@ -134,6 +134,7 @@ export class AutoForm<T> extends React.Component<AutoFormProps<T>, AutoFormState onChange={(v: any) => { onChange(Object.assign({}, model, { [field.name]: v })); }} + addOnBlur fill />; } diff --git a/web-console/src/components/header-bar.tsx b/web-console/src/components/header-bar.tsx index f0f5853..ac1cd67 100644 --- a/web-console/src/components/header-bar.tsx +++ b/web-console/src/components/header-bar.tsx @@ -38,6 +38,7 @@ export type HeaderActiveTab = null | 'datasources' | 'segments' | 'tasks' | 'ser export interface HeaderBarProps extends React.Props<any> { active: HeaderActiveTab; + hideLegacy: boolean; } export interface HeaderBarState { @@ -106,7 +107,7 @@ export class HeaderBar extends React.Component<HeaderBarProps, HeaderBarState> { } render() { - const { active } = this.props; + const { active, hideLegacy } = this.props; const { aboutDialogOpen, coordinatorDynamicConfigDialogOpen, overlordDynamicConfigDialogOpen } = this.state; const legacyMenu = <Menu> @@ -144,22 +145,34 @@ export class HeaderBar extends React.Component<HeaderBarProps, HeaderBarState> { </Popover> </NavbarGroup> <NavbarGroup align={Alignment.RIGHT}> - <Popover className="legacy-popover" content={legacyMenu} position={Position.BOTTOM_RIGHT}> - <Button className={Classes.MINIMAL} icon={IconNames.SHARE} text="Legacy" /> - </Popover> + { + !hideLegacy && + <Popover className="legacy-popover" content={legacyMenu} position={Position.BOTTOM_RIGHT}> + <Button className={Classes.MINIMAL} icon={IconNames.SHARE} text="Legacy"/> + </Popover> + } <Popover className="help-popover" content={helpMenu} position={Position.BOTTOM_RIGHT}> <Button className={Classes.MINIMAL} icon={IconNames.HELP} text="Help" /> </Popover> </NavbarGroup> - { aboutDialogOpen ? <AboutDialog - onClose={() => this.setState({ aboutDialogOpen: false })} - /> : null } - { coordinatorDynamicConfigDialogOpen ? <CoordinatorDynamicConfigDialog - onClose={() => this.setState({ coordinatorDynamicConfigDialogOpen: false })} - /> : null } - { overlordDynamicConfigDialogOpen ? <OverlordDynamicConfigDialog - onClose={() => this.setState({ overlordDynamicConfigDialogOpen: false })} - /> : null } + { + aboutDialogOpen && + <AboutDialog + onClose={() => this.setState({ aboutDialogOpen: false })} + /> + } + { + coordinatorDynamicConfigDialogOpen && + <CoordinatorDynamicConfigDialog + onClose={() => this.setState({ coordinatorDynamicConfigDialogOpen: false })} + /> + } + { + overlordDynamicConfigDialogOpen && + <OverlordDynamicConfigDialog + onClose={() => this.setState({ overlordDynamicConfigDialogOpen: false })} + /> + } </Navbar>; } } diff --git a/web-console/src/components/table-column-selection.scss b/web-console/src/components/table-column-selection.scss index b1cb80a..9e52a5c 100644 --- a/web-console/src/components/table-column-selection.scss +++ b/web-console/src/components/table-column-selection.scss @@ -24,11 +24,7 @@ // This will be mounted in a portal .table-column-selection-menu { - .form-group { + .bp3-form-group { margin-bottom: 0; - - .bp3-checkbox:last-child { - margin-bottom: 0; - } } } diff --git a/web-console/src/console-application.tsx b/web-console/src/console-application.tsx index 4d921e0..e009fd2 100644 --- a/web-console/src/console-application.tsx +++ b/web-console/src/console-application.tsx @@ -37,7 +37,8 @@ import { TasksView } from './views/tasks-view'; import "./console-application.scss"; export interface ConsoleApplicationProps extends React.Props<any> { - version: string; + hideLegacy: boolean; + baseURL?: string; } export interface ConsoleApplicationState { @@ -94,6 +95,10 @@ export class ConsoleApplication extends React.Component<ConsoleApplicationProps, this.state = { aboutDialogOpen: false }; + + if (props.baseURL) { + axios.defaults.baseURL = props.baseURL; + } } componentDidMount(): void { @@ -136,9 +141,11 @@ export class ConsoleApplication extends React.Component<ConsoleApplicationProps, } render() { + const { hideLegacy } = this.props; + const wrapInViewContainer = (active: HeaderActiveTab, el: JSX.Element, scrollable = false) => { return <> - <HeaderBar active={active}/> + <HeaderBar active={active} hideLegacy={hideLegacy}/> <div className={classNames('view-container', { scrollable })}>{el}</div> </>; }; diff --git a/web-console/src/entry.ts b/web-console/src/entry.ts index 9597d70..985032b 100644 --- a/web-console/src/entry.ts +++ b/web-console/src/entry.ts @@ -30,11 +30,18 @@ import "./entry.scss"; const container = document.getElementsByClassName('app-container')[0]; if (!container) throw new Error('container not found'); +interface ConsoleConfig { + hideLegacy?: boolean; + baseURL?: string; +} + +const consoleConfig: ConsoleConfig = (window as any).consoleConfig; ReactDOM.render( React.createElement( ConsoleApplication, { - version: '0.0.1' + hideLegacy: Boolean(consoleConfig.hideLegacy), + baseURL: consoleConfig.baseURL } ) as any, container diff --git a/web-console/src/views/lookups-view.tsx b/web-console/src/views/lookups-view.tsx index fd31e72..397d631 100644 --- a/web-console/src/views/lookups-view.tsx +++ b/web-console/src/views/lookups-view.tsx @@ -22,9 +22,9 @@ import axios from 'axios'; import * as classNames from 'classnames'; import * as React from 'react'; import ReactTable from "react-table"; -import { Filter } from "react-table"; import { TableColumnSelection } from "../components/table-column-selection"; +import { AsyncActionDialog } from '../dialogs/async-action-dialog'; import { LookupEditDialog } from "../dialogs/lookup-edit-dialog"; import { AppToaster } from "../singletons/toaster"; import { @@ -35,16 +35,17 @@ import { import "./lookups-view.scss"; -const tableColumns: string[] = ["Lookup Name", "Tier", "Type", "Version", "Config"]; +const tableColumns: string[] = ["Lookup name", "Tier", "Type", "Version", "Actions"]; export interface LookupsViewProps extends React.Props<any> { } export interface LookupsViewState { - lookups: {}[]; + lookups: {}[] | null; loadingLookups: boolean; lookupsError: string | null; + lookupsUninitialized: boolean; lookupEditDialogOpen: boolean; lookupEditName: string; lookupEditTier: string; @@ -52,11 +53,13 @@ export interface LookupsViewState { lookupEditSpec: string; isEdit: boolean; allLookupTiers: string[]; + + deleteLookupTier: string | null; + deleteLookupName: string | null; } export class LookupsView extends React.Component<LookupsViewProps, LookupsViewState> { private lookupsGetQueryManager: QueryManager<string, {lookupEntries: any[], tiers: string[]}>; - private lookupDeleteQueryManager: QueryManager<string, any[]>; private tableColumnSelectionHandler: TableColumnSelectionHandler; constructor(props: LookupsViewProps, context: any) { @@ -65,13 +68,17 @@ export class LookupsView extends React.Component<LookupsViewProps, LookupsViewSt lookups: [], loadingLookups: true, lookupsError: null, + lookupsUninitialized: false, lookupEditDialogOpen: false, lookupEditTier: "", lookupEditName: "", lookupEditVersion: "", lookupEditSpec: "", isEdit: false, - allLookupTiers: [] + allLookupTiers: [], + + deleteLookupTier: null, + deleteLookupName: null }; this.tableColumnSelectionHandler = new TableColumnSelectionHandler( LocalStorageKeys.LOOKUP_TABLE_COLUMN_SELECTION, () => this.setState({}) @@ -90,9 +97,10 @@ export class LookupsView extends React.Component<LookupsViewProps, LookupsViewSt Object.keys(lookupData).map((tier: string) => { const lookupIds = lookupData[tier]; Object.keys(lookupIds).map((id: string) => { - lookupEntries.push({tier, id, version: lookupData[tier][id].version, spec: lookupData[tier][id].lookupExtractorFactory}); + lookupEntries.push({tier, id, version: lookupIds[id].version, spec: lookupIds[id].lookupExtractorFactory}); }); }); + return { lookupEntries, tiers @@ -100,30 +108,20 @@ export class LookupsView extends React.Component<LookupsViewProps, LookupsViewSt }, onStateChange: ({ result, loading, error }) => { this.setState({ - lookups: result === null ? [] : result.lookupEntries, + lookups: result ? result.lookupEntries : null, loadingLookups: loading, lookupsError: error, + lookupsUninitialized: error === 'Request failed with status code 404', allLookupTiers: result === null ? [] : result.tiers }); } }); this.lookupsGetQueryManager.runQuery("dummy"); - - this.lookupDeleteQueryManager = new QueryManager({ - processQuery: async (url: string) => { - const lookupDeleteResp = await axios.delete(url); - return lookupDeleteResp.data; - }, - onStateChange: ({}) => { - this.lookupsGetQueryManager.rerunLastQuery(); - } - }); } componentWillUnmount(): void { this.lookupsGetQueryManager.terminate(); - this.lookupDeleteQueryManager.terminate(); } private async initializeLookup() { @@ -143,6 +141,8 @@ export class LookupsView extends React.Component<LookupsViewProps, LookupsViewSt private async openLookupEditDialog(tier: string, id: string) { const { lookups, allLookupTiers } = this.state; + if (!lookups) return; + const target: any = lookups.find((lookupEntry: any) => { return lookupEntry.tier === tier && lookupEntry.id === id; }); @@ -211,16 +211,35 @@ export class LookupsView extends React.Component<LookupsViewProps, LookupsViewSt } } - private deleteLookup(tier: string, name: string): void { - const url = `/druid/coordinator/v1/lookups/config/${tier}/${name}`; - this.lookupDeleteQueryManager.runQuery(url); + renderDeleteLookupAction() { + const { deleteLookupTier, deleteLookupName } = this.state; + + return <AsyncActionDialog + action={ + deleteLookupTier ? async () => { + await axios.delete(`/druid/coordinator/v1/lookups/config/${deleteLookupTier}/${deleteLookupName}`); + } : null + } + confirmButtonText="Delete lookup" + successText="Lookup was deleted" + failText="Could not delete lookup" + intent={Intent.DANGER} + onClose={(success) => { + this.setState({ deleteLookupTier: null, deleteLookupName: null }); + if (success) this.lookupsGetQueryManager.rerunLastQuery(); + }} + > + <p> + {`Are you sure you want to delete the lookup '${deleteLookupName}'?`} + </p> + </AsyncActionDialog>; } renderLookupsTable() { - const { lookups, loadingLookups, lookupsError } = this.state; + const { lookups, loadingLookups, lookupsError, lookupsUninitialized } = this.state; const { tableColumnSelectionHandler } = this; - if (lookupsError) { + if (lookupsUninitialized) { return <div className={"init-div"}> <Button icon={IconNames.BUILD} @@ -229,19 +248,20 @@ export class LookupsView extends React.Component<LookupsViewProps, LookupsViewSt /> </div>; } + return <> <ReactTable - data={lookups} + data={lookups || []} loading={loadingLookups} noDataText={!loadingLookups && lookups && !lookups.length ? 'No lookups' : (lookupsError || '')} filterable columns={[ { - Header: "Lookup Name", + Header: "Lookup name", id: "lookup_name", accessor: (row: any) => row.id, filterable: true, - show: tableColumnSelectionHandler.showColumn("Lookup Name") + show: tableColumnSelectionHandler.showColumn("Lookup name") }, { Header: "Tier", @@ -265,8 +285,8 @@ export class LookupsView extends React.Component<LookupsViewProps, LookupsViewSt show: tableColumnSelectionHandler.showColumn("Version") }, { - Header: "Config", - id: "config", + Header: "Actions", + id: "actions", accessor: row => ({id: row.id, tier: row.tier}), filterable: false, Cell: (row: any) => { @@ -275,10 +295,10 @@ export class LookupsView extends React.Component<LookupsViewProps, LookupsViewSt return <div> <a onClick={() => this.openLookupEditDialog(lookupTier, lookupId)}>Edit</a> - <a onClick={() => this.deleteLookup(lookupTier, lookupId)}>Delete</a> + <a onClick={() => this.setState({ deleteLookupTier: lookupTier, deleteLookupName: lookupId })}>Delete</a> </div>; }, - show: tableColumnSelectionHandler.showColumn("Config") + show: tableColumnSelectionHandler.showColumn("Actions") } ]} defaultPageSize={50} @@ -305,7 +325,9 @@ export class LookupsView extends React.Component<LookupsViewProps, LookupsViewSt } render() { + const { lookupsError } = this.state; const { tableColumnSelectionHandler } = this; + return <div className="lookups-view app-view"> <div className="control-bar"> <div className="control-label">Lookups</div> @@ -314,12 +336,13 @@ export class LookupsView extends React.Component<LookupsViewProps, LookupsViewSt text="Refresh" onClick={() => this.lookupsGetQueryManager.rerunLastQuery()} /> - <Button - icon={IconNames.PLUS} - text="Add" - style={{display: this.state.lookupsError !== null ? 'none' : 'inline'}} - onClick={() => this.openLookupEditDialog("", "")} - /> + { !lookupsError && + <Button + icon={IconNames.PLUS} + text="Add" + onClick={() => this.openLookupEditDialog("", "")} + /> + } <TableColumnSelection columns={tableColumns} onChange={(column) => tableColumnSelectionHandler.changeTableColumnSelection(column)} @@ -328,6 +351,7 @@ export class LookupsView extends React.Component<LookupsViewProps, LookupsViewSt </div> {this.renderLookupsTable()} {this.renderLookupEditDialog()} + {this.renderDeleteLookupAction()} </div>; } } diff --git a/web-console/unified-console.html b/web-console/unified-console.html index cd721f9..2567875 100644 --- a/web-console/unified-console.html +++ b/web-console/unified-console.html @@ -22,10 +22,11 @@ <meta charset="utf-8"> <title>Apache Druid</title> <meta name="description" content="Apache Druid web console"> - <link rel="shortcut icon" href="/favicon.png"> + <link rel="shortcut icon" href="favicon.png"> </head> <body class="bp3-dark mouse-mode"> <div class="app-container"></div> + <script src="console-config.js"></script> <script src="public/web-console-0.15.0.js"></script> </body> </html> --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@druid.apache.org For additional commands, e-mail: commits-h...@druid.apache.org