mirror of https://github.com/apache/druid.git
Web-Console: Column tree button fixes (#8253)
* small fixes * run jest -u * add trim * remove trim, update package * fix package-lock
This commit is contained in:
parent
8fa114c349
commit
03a37936ec
|
@ -4395,9 +4395,9 @@
|
||||||
"integrity": "sha512-0sYnfUHHMoajaud/i5BHKA12bUxiWEHJ9rxGqVEppFxsEcxef0TZQ5J59lU+UniEBcz/sG5fTESRyS7cOm3tSQ=="
|
"integrity": "sha512-0sYnfUHHMoajaud/i5BHKA12bUxiWEHJ9rxGqVEppFxsEcxef0TZQ5J59lU+UniEBcz/sG5fTESRyS7cOm3tSQ=="
|
||||||
},
|
},
|
||||||
"druid-query-toolkit": {
|
"druid-query-toolkit": {
|
||||||
"version": "0.3.12",
|
"version": "0.3.13",
|
||||||
"resolved": "https://registry.npmjs.org/druid-query-toolkit/-/druid-query-toolkit-0.3.12.tgz",
|
"resolved": "https://registry.npmjs.org/druid-query-toolkit/-/druid-query-toolkit-0.3.13.tgz",
|
||||||
"integrity": "sha512-q2w6dDdZFYuLRTVyUvZwyXx/63ZQivjhll3Ppo3zpRcF4iWg+z+sXY9UI+sobl5q3/WojOkw/ZI0Kwzy9bWd2Q==",
|
"integrity": "sha512-yBPAJ0tjbV/2X1tgvByx53bnoOizMQet4mhUv43Zlx0ongS7Hj7na/6E1iISmPVKOPbJd38DfvIf7yr50BkYsw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"tslib": "^1.10.0"
|
"tslib": "^1.10.0"
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,7 +61,7 @@
|
||||||
"d3": "^5.9.7",
|
"d3": "^5.9.7",
|
||||||
"d3-array": "^2.2.0",
|
"d3-array": "^2.2.0",
|
||||||
"druid-console": "^0.0.2",
|
"druid-console": "^0.0.2",
|
||||||
"druid-query-toolkit": "^0.3.12",
|
"druid-query-toolkit": "^0.3.13",
|
||||||
"file-saver": "^2.0.2",
|
"file-saver": "^2.0.2",
|
||||||
"has-own-prop": "^2.0.0",
|
"has-own-prop": "^2.0.0",
|
||||||
"hjson": "^3.1.2",
|
"hjson": "^3.1.2",
|
||||||
|
|
|
@ -44,6 +44,7 @@ exports[`sql view matches snapshot 1`] = `
|
||||||
<QueryOutput
|
<QueryOutput
|
||||||
disabled={true}
|
disabled={true}
|
||||||
loading={false}
|
loading={false}
|
||||||
|
runeMode={false}
|
||||||
sqlExcludeColumn={[Function]}
|
sqlExcludeColumn={[Function]}
|
||||||
sqlFilterRow={[Function]}
|
sqlFilterRow={[Function]}
|
||||||
sqlOrderBy={[Function]}
|
sqlOrderBy={[Function]}
|
||||||
|
|
|
@ -48,23 +48,6 @@ FROM ${tableSchema}.${nodeData.label}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTableQuery(tableSchema: string, nodeData: ITreeNode): string {
|
|
||||||
let columns: string[];
|
|
||||||
if (nodeData.childNodes) {
|
|
||||||
columns = nodeData.childNodes.map(child => escapeSqlIdentifier(String(child.label)));
|
|
||||||
} else {
|
|
||||||
columns = ['*'];
|
|
||||||
}
|
|
||||||
if (tableSchema === 'druid') {
|
|
||||||
return `SELECT ${columns.join(', ')}
|
|
||||||
FROM ${escapeSqlIdentifier(String(nodeData.label))}
|
|
||||||
WHERE "__time" >= CURRENT_TIMESTAMP - INTERVAL '1' DAY`;
|
|
||||||
} else {
|
|
||||||
return `SELECT ${columns.join(', ')}
|
|
||||||
FROM ${tableSchema}.${nodeData.label}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleColumnClick(
|
function handleColumnClick(
|
||||||
columnSchema: string,
|
columnSchema: string,
|
||||||
columnTable: string,
|
columnTable: string,
|
||||||
|
@ -99,35 +82,6 @@ ORDER BY "Count" DESC`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getColumnQuery(columnSchema: string, columnTable: string, nodeData: ITreeNode): string {
|
|
||||||
if (columnSchema === 'druid') {
|
|
||||||
if (nodeData.icon === IconNames.TIME) {
|
|
||||||
return `SELECT
|
|
||||||
TIME_FLOOR(${escapeSqlIdentifier(String(nodeData.label))}, 'PT1H') AS "Time",
|
|
||||||
COUNT(*) AS "Count"
|
|
||||||
FROM ${escapeSqlIdentifier(columnTable)}
|
|
||||||
WHERE "__time" >= CURRENT_TIMESTAMP - INTERVAL '1' DAY
|
|
||||||
GROUP BY 1
|
|
||||||
ORDER BY "Time" ASC`;
|
|
||||||
} else {
|
|
||||||
return `SELECT
|
|
||||||
"${nodeData.label}",
|
|
||||||
COUNT(*) AS "Count"
|
|
||||||
FROM ${escapeSqlIdentifier(columnTable)}
|
|
||||||
WHERE "__time" >= CURRENT_TIMESTAMP - INTERVAL '1' DAY
|
|
||||||
GROUP BY 1
|
|
||||||
ORDER BY "Count" DESC`;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return `SELECT
|
|
||||||
${escapeSqlIdentifier(String(nodeData.label))},
|
|
||||||
COUNT(*) AS "Count"
|
|
||||||
FROM ${columnSchema}.${columnTable}
|
|
||||||
GROUP BY 1
|
|
||||||
ORDER BY "Count" DESC`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ColumnTreeProps {
|
export interface ColumnTreeProps {
|
||||||
columnMetadataLoading: boolean;
|
columnMetadataLoading: boolean;
|
||||||
columnMetadata?: ColumnMetadata[];
|
columnMetadata?: ColumnMetadata[];
|
||||||
|
@ -190,19 +144,7 @@ export class ColumnTree extends React.PureComponent<ColumnTreeProps, ColumnTreeS
|
||||||
icon={IconNames.CLIPBOARD}
|
icon={IconNames.CLIPBOARD}
|
||||||
text={`Copy: ${table}`}
|
text={`Copy: ${table}`}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
copyAndAlert(
|
copyAndAlert(table, `${table} query copied to clipboard`);
|
||||||
getTableQuery(schema, {
|
|
||||||
id: table,
|
|
||||||
icon: IconNames.TH,
|
|
||||||
label: table,
|
|
||||||
childNodes: metadata.map(columnData => ({
|
|
||||||
id: columnData.COLUMN_NAME,
|
|
||||||
icon: ColumnTree.dataTypeToIcon(columnData.DATA_TYPE),
|
|
||||||
label: columnData.COLUMN_NAME,
|
|
||||||
})),
|
|
||||||
}),
|
|
||||||
`${table} query copied to clipboard`,
|
|
||||||
);
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Menu>
|
</Menu>
|
||||||
|
@ -241,11 +183,7 @@ export class ColumnTree extends React.PureComponent<ColumnTreeProps, ColumnTreeS
|
||||||
text={`Copy: ${columnData.COLUMN_NAME}`}
|
text={`Copy: ${columnData.COLUMN_NAME}`}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
copyAndAlert(
|
copyAndAlert(
|
||||||
getColumnQuery(schema, table, {
|
columnData.COLUMN_NAME,
|
||||||
id: columnData.COLUMN_NAME,
|
|
||||||
icon: ColumnTree.dataTypeToIcon(columnData.DATA_TYPE),
|
|
||||||
label: columnData.COLUMN_NAME,
|
|
||||||
}),
|
|
||||||
`${columnData.COLUMN_NAME} query copied to clipboard`,
|
`${columnData.COLUMN_NAME} query copied to clipboard`,
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -25,6 +25,7 @@ describe('query output', () => {
|
||||||
it('matches snapshot', () => {
|
it('matches snapshot', () => {
|
||||||
const queryOutput = (
|
const queryOutput = (
|
||||||
<QueryOutput
|
<QueryOutput
|
||||||
|
runeMode={false}
|
||||||
sqlOrderBy={() => null}
|
sqlOrderBy={() => null}
|
||||||
sqlFilterRow={() => null}
|
sqlFilterRow={() => null}
|
||||||
sqlExcludeColumn={() => null}
|
sqlExcludeColumn={() => null}
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Popover } from '@blueprintjs/core';
|
import { Menu, MenuItem, Popover } from '@blueprintjs/core';
|
||||||
import { IconNames } from '@blueprintjs/icons';
|
import { IconNames } from '@blueprintjs/icons';
|
||||||
import { HeaderRows } from 'druid-query-toolkit';
|
import { HeaderRows } from 'druid-query-toolkit';
|
||||||
import {
|
import {
|
||||||
|
@ -41,6 +41,7 @@ export interface QueryOutputProps {
|
||||||
sorted?: { id: string; desc: boolean }[];
|
sorted?: { id: string; desc: boolean }[];
|
||||||
result?: HeaderRows;
|
result?: HeaderRows;
|
||||||
error?: string;
|
error?: string;
|
||||||
|
runeMode: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class QueryOutput extends React.PureComponent<QueryOutputProps> {
|
export class QueryOutput extends React.PureComponent<QueryOutputProps> {
|
||||||
|
@ -91,38 +92,44 @@ export class QueryOutput extends React.PureComponent<QueryOutputProps> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
getHeaderActions(h: string) {
|
getHeaderActions(h: string) {
|
||||||
const { disabled, sqlExcludeColumn, sqlOrderBy } = this.props;
|
const { disabled, sqlExcludeColumn, sqlOrderBy, runeMode } = this.props;
|
||||||
let actionsMenu;
|
let actionsMenu;
|
||||||
if (disabled) {
|
if (disabled) {
|
||||||
actionsMenu = basicActionsToMenu([
|
actionsMenu = (
|
||||||
{
|
<Menu>
|
||||||
icon: IconNames.CLIPBOARD,
|
<MenuItem
|
||||||
title: `Copy: ${h}`,
|
icon={IconNames.CLIPBOARD}
|
||||||
onAction: () => {
|
text={`Copy: ${h}`}
|
||||||
copyAndAlert(h, `${h}' copied to clipboard`);
|
onClick={() => {
|
||||||
},
|
copyAndAlert(h, `${h}' copied to clipboard`);
|
||||||
},
|
}}
|
||||||
{
|
/>
|
||||||
icon: IconNames.CLIPBOARD,
|
{runeMode && (
|
||||||
title: `Copy: ORDER BY ${basicIdentifierEscape(h)} ASC`,
|
<MenuItem
|
||||||
onAction: () => {
|
icon={IconNames.CLIPBOARD}
|
||||||
copyAndAlert(
|
text={`Copy: ORDER BY ${basicIdentifierEscape(h)} ASC`}
|
||||||
`ORDER BY ${basicIdentifierEscape(h)} ASC`,
|
onClick={() =>
|
||||||
`ORDER BY ${basicIdentifierEscape(h)} ASC' copied to clipboard`,
|
copyAndAlert(
|
||||||
);
|
`ORDER BY ${basicIdentifierEscape(h)} ASC`,
|
||||||
},
|
`ORDER BY ${basicIdentifierEscape(h)} ASC' copied to clipboard`,
|
||||||
},
|
)
|
||||||
{
|
}
|
||||||
icon: IconNames.CLIPBOARD,
|
/>
|
||||||
title: `Copy: 'ORDER BY ${basicIdentifierEscape(h)} DESC'`,
|
)}
|
||||||
onAction: () => {
|
{runeMode && (
|
||||||
copyAndAlert(
|
<MenuItem
|
||||||
`ORDER BY ${basicIdentifierEscape(h)} DESC`,
|
icon={IconNames.CLIPBOARD}
|
||||||
`ORDER BY ${basicIdentifierEscape(h)} DESC' copied to clipboard`,
|
text={`Copy: 'ORDER BY ${basicIdentifierEscape(h)} DESC'`}
|
||||||
);
|
onClick={() =>
|
||||||
},
|
copyAndAlert(
|
||||||
},
|
`ORDER BY ${basicIdentifierEscape(h)} DESC`,
|
||||||
]);
|
`ORDER BY ${basicIdentifierEscape(h)} DESC' copied to clipboard`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Menu>
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
const { sorted } = this.props;
|
const { sorted } = this.props;
|
||||||
const basicActions: BasicAction[] = [];
|
const basicActions: BasicAction[] = [];
|
||||||
|
@ -162,38 +169,46 @@ export class QueryOutput extends React.PureComponent<QueryOutputProps> {
|
||||||
}
|
}
|
||||||
|
|
||||||
getRowActions(row: string, header: string) {
|
getRowActions(row: string, header: string) {
|
||||||
const { disabled, sqlFilterRow } = this.props;
|
const { disabled, sqlFilterRow, runeMode } = this.props;
|
||||||
let actionsMenu;
|
let actionsMenu;
|
||||||
if (disabled) {
|
if (disabled) {
|
||||||
actionsMenu = basicActionsToMenu([
|
actionsMenu = (
|
||||||
{
|
<Menu>
|
||||||
icon: IconNames.CLIPBOARD,
|
<MenuItem
|
||||||
title: `Copy: '${row}'`,
|
icon={IconNames.CLIPBOARD}
|
||||||
onAction: () => {
|
text={`Copy: ${row}`}
|
||||||
copyAndAlert(row, `${row} copied to clipboard`);
|
onClick={() => copyAndAlert(row, `${row} copied to clipboard`)}
|
||||||
},
|
/>
|
||||||
},
|
{runeMode && (
|
||||||
{
|
<MenuItem
|
||||||
icon: IconNames.CLIPBOARD,
|
icon={IconNames.CLIPBOARD}
|
||||||
title: `Copy: ${basicIdentifierEscape(header)} = ${basicLiteralEscape(row)}`,
|
text={`Copy: ${basicIdentifierEscape(header)} = ${basicLiteralEscape(row)}`}
|
||||||
onAction: () => {
|
onClick={() =>
|
||||||
copyAndAlert(
|
copyAndAlert(
|
||||||
`${basicIdentifierEscape(header)} = ${basicLiteralEscape(row)}`,
|
`${basicIdentifierEscape(header)} = ${basicLiteralEscape(row)}`,
|
||||||
`${basicIdentifierEscape(header)} = ${basicLiteralEscape(row)} copied to clipboard`,
|
`${basicIdentifierEscape(header)} = ${basicLiteralEscape(
|
||||||
);
|
row,
|
||||||
},
|
)} copied to clipboard`,
|
||||||
},
|
)
|
||||||
{
|
}
|
||||||
icon: IconNames.CLIPBOARD,
|
/>
|
||||||
title: `Copy: ${basicIdentifierEscape(header)} != ${basicLiteralEscape(row)}`,
|
)}
|
||||||
onAction: () => {
|
{runeMode && (
|
||||||
copyAndAlert(
|
<MenuItem
|
||||||
`${basicIdentifierEscape(header)} != ${basicLiteralEscape(row)}`,
|
icon={IconNames.CLIPBOARD}
|
||||||
`${basicIdentifierEscape(header)} != ${basicLiteralEscape(row)} copied to clipboard`,
|
text={`Copy: ${basicIdentifierEscape(header)} != ${basicLiteralEscape(row)}`}
|
||||||
);
|
onClick={() =>
|
||||||
},
|
copyAndAlert(
|
||||||
},
|
`${basicIdentifierEscape(header)} != ${basicLiteralEscape(row)}`,
|
||||||
]);
|
`${basicIdentifierEscape(header)} != ${basicLiteralEscape(
|
||||||
|
row,
|
||||||
|
)} copied to clipboard`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Menu>
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
actionsMenu = basicActionsToMenu([
|
actionsMenu = basicActionsToMenu([
|
||||||
{
|
{
|
||||||
|
|
|
@ -418,6 +418,7 @@ export class QueryView extends React.PureComponent<QueryViewProps, QueryViewStat
|
||||||
sqlExcludeColumn={this.sqlExcludeColumn}
|
sqlExcludeColumn={this.sqlExcludeColumn}
|
||||||
sqlFilterRow={this.sqlFilterRow}
|
sqlFilterRow={this.sqlFilterRow}
|
||||||
sqlOrderBy={this.sqlOrderBy}
|
sqlOrderBy={this.sqlOrderBy}
|
||||||
|
runeMode={runeMode}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
result={result}
|
result={result}
|
||||||
error={error}
|
error={error}
|
||||||
|
|
Loading…
Reference in New Issue