mirror of https://github.com/apache/druid.git
Web console: tidy up stage UI (#13615)
* show the right info * sort indicator * nicer marker * move error icon
This commit is contained in:
parent
78ae0b7533
commit
8773d619a2
|
@ -65,9 +65,11 @@ export class WorkbenchQueryPart {
|
|||
const matchInsertReplaceIndex = queryFragment.match(/(?:INSERT|REPLACE)\s+INTO/i)?.index;
|
||||
if (typeof matchInsertReplaceIndex !== 'number') return;
|
||||
|
||||
const matchEnd = queryFragment.match(/\b(?:SELECT|WITH)\b|$/i);
|
||||
const queryStartingWithInsertOrReplace = queryFragment.substring(matchInsertReplaceIndex);
|
||||
|
||||
const matchEnd = queryStartingWithInsertOrReplace.match(/\b(?:SELECT|WITH)\b|$/i);
|
||||
const fragmentQuery = SqlQuery.maybeParse(
|
||||
queryFragment.substring(matchInsertReplaceIndex, matchEnd?.index) + ' SELECT * FROM t',
|
||||
queryStartingWithInsertOrReplace.substring(0, matchEnd?.index) + ' SELECT * FROM t',
|
||||
);
|
||||
if (!fragmentQuery) return;
|
||||
|
||||
|
|
|
@ -507,6 +507,19 @@ describe('WorkbenchQuery', () => {
|
|||
expect(workbenchQuery.getIngestDatasource()).toEqual('trips2');
|
||||
expect(workbenchQuery.changeEngine('sql-native').getIngestDatasource()).toBeUndefined();
|
||||
});
|
||||
|
||||
it('works with REPLACE (unparsable with comment at start)', () => {
|
||||
const sql = sane`
|
||||
-- Hello world SELECT
|
||||
|
||||
REPLACE INTO trips2 OVERWRITE ALL
|
||||
WITH kttm_data AS (SELECT *
|
||||
`;
|
||||
|
||||
const workbenchQuery = WorkbenchQuery.blank().changeQueryString(sql);
|
||||
expect(workbenchQuery.getIngestDatasource()).toEqual('trips2');
|
||||
expect(workbenchQuery.changeEngine('sql-native').getIngestDatasource()).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('#extractCteHelpers', () => {
|
||||
|
|
|
@ -666,11 +666,9 @@ END AS "time_span"`,
|
|||
|
||||
switch (v?.type) {
|
||||
case 'range': {
|
||||
const dimensions = v.dimensions || [];
|
||||
const dimensions: string[] = v.dimensions || [];
|
||||
const formatEdge = (values: string[]) =>
|
||||
values
|
||||
.map((x, i) => formatRangeDimensionValue(dimensions[i] || `d${i}`, x))
|
||||
.join('; ');
|
||||
dimensions.map((d, i) => formatRangeDimensionValue(d, values[i])).join('; ');
|
||||
|
||||
return (
|
||||
<TableClickableCell
|
||||
|
|
|
@ -268,6 +268,22 @@ export class ColumnTree extends React.PureComponent<ColumnTreeProps, ColumnTreeS
|
|||
);
|
||||
}}
|
||||
/>
|
||||
<MenuItem
|
||||
icon={IconNames.FULLSCREEN}
|
||||
text={`SELECT MIN(__time), MAX(__time) FROM ${tableName}`}
|
||||
onClick={() => {
|
||||
onQueryChange(
|
||||
getQueryOnTable()
|
||||
.changeSelectExpressions([
|
||||
F.min(C('__time')).as('min_time'),
|
||||
F.max(C('__time')).as('max_time'),
|
||||
])
|
||||
.changeGroupByExpressions([])
|
||||
.changeWhereExpression(getWhere(true)),
|
||||
true,
|
||||
);
|
||||
}}
|
||||
/>
|
||||
{parsedQuery && parsedQuery.getFirstTableName() !== tableName && (
|
||||
<MenuItem
|
||||
icon={IconNames.EXCHANGE}
|
||||
|
|
|
@ -41,6 +41,17 @@
|
|||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.sort-marker {
|
||||
font-style: italic;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.error-warning {
|
||||
position: absolute;
|
||||
top: 7px;
|
||||
right: 3px;
|
||||
}
|
||||
|
||||
.counter-spacer {
|
||||
position: relative;
|
||||
height: 5px;
|
||||
|
|
|
@ -402,6 +402,7 @@ ${title} uncompressed size: ${formatBytesCompact(
|
|||
|
||||
const shuffleRows = stages.getTotalCounterForStage(stage, 'shuffle', 'rows');
|
||||
const sortProgress = stages.getSortProgressForStage(stage);
|
||||
const showSortedPercent = 0 < sortProgress && sortProgress < 1;
|
||||
const title = stages.getStageCounterTitle(stage, 'shuffle');
|
||||
return (
|
||||
<div
|
||||
|
@ -413,10 +414,9 @@ ${title} uncompressed size: ${formatBytesCompact(
|
|||
stages.getTotalCounterForStage(stage, 'shuffle', 'bytes'),
|
||||
)} ${NOT_SIZE_ON_DISK}`}
|
||||
>
|
||||
<BracedText text={shuffleRows ? formatRows(shuffleRows) : ''} braces={rowsValues} /> {' '}
|
||||
{0 < sortProgress && sortProgress < 1 && (
|
||||
<> {` ${formatPercent(sortProgress)} sorted`}</>
|
||||
)}
|
||||
{Boolean(shuffleRows) && <BracedText text={formatRows(shuffleRows)} braces={rowsValues} />}
|
||||
{Boolean(shuffleRows && showSortedPercent) && <> : </>}
|
||||
{showSortedPercent && `${formatPercent(sortProgress)} sorted`}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -449,28 +449,28 @@ ${title} uncompressed size: ${formatBytesCompact(
|
|||
<span className="stage">{`Stage${stage.stageNumber}`}</span>
|
||||
</div>
|
||||
<div>{stage.definition.processor.type}</div>
|
||||
{stage.sort && <div className="sort-marker">(with sort)</div>}
|
||||
{(myError || warnings > 0) && (
|
||||
<div>
|
||||
<div className="error-warning">
|
||||
{myError && (
|
||||
<>
|
||||
<Tooltip2
|
||||
content={
|
||||
<div>
|
||||
{(error.error.errorCode ? `${error.error.errorCode}: ` : '') +
|
||||
error.error.errorMessage}
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<Button
|
||||
minimal
|
||||
small
|
||||
icon={IconNames.ERROR}
|
||||
intent={Intent.DANGER}
|
||||
onClick={onErrorClick}
|
||||
/>
|
||||
</Tooltip2>{' '}
|
||||
</>
|
||||
<Tooltip2
|
||||
content={
|
||||
<div>
|
||||
{(error.error.errorCode ? `${error.error.errorCode}: ` : '') +
|
||||
error.error.errorMessage}
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<Button
|
||||
minimal
|
||||
small
|
||||
icon={IconNames.ERROR}
|
||||
intent={Intent.DANGER}
|
||||
onClick={onErrorClick}
|
||||
/>
|
||||
</Tooltip2>
|
||||
)}
|
||||
{myError && warnings > 0 && ' '}
|
||||
{warnings > 0 && (
|
||||
<Tooltip2
|
||||
content={
|
||||
|
|
Loading…
Reference in New Issue