mirror of https://github.com/apache/druid.git
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
This commit is contained in:
parent
e2aa6e47f8
commit
0fa122ecf2
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
window.consoleConfig = { /* future configs may go here */ };
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "web-console",
|
||||
"version": "0.14.0",
|
||||
"version": "0.15.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
/>;
|
||||
}
|
||||
|
|
|
@ -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>;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
</>;
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue