This is an automated email from the ASF dual-hosted git repository.
vogievetsky pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/druid.git
The following commit(s) were added to refs/heads/master by this push:
new 5b769a7d326 Update load query detail archive dialog for file input
support (#15632)
5b769a7d326 is described below
commit 5b769a7d3260aa34f01240be0b44a009b376034a
Author: Vadim Ogievetsky <[email protected]>
AuthorDate: Wed Jan 10 20:48:46 2024 -0800
Update load query detail archive dialog for file input support (#15632)
* Update execution-submit-dialog for file input support
Modified the execution-submit-dialog to support file inputs instead of text
inputs for better usability. Users can now submit their queries by selecting a
JSON file directly or dragging the file into the dialog. Made appropriate UI
adjustments to accommodate this change in execution-submit-dialog styles file.
* Update
web-console/src/views/workbench-view/execution-submit-dialog/execution-submit-dialog.tsx
Co-authored-by: Charles Smith <[email protected]>
* Update
web-console/src/views/workbench-view/execution-submit-dialog/execution-submit-dialog.tsx
Co-authored-by: Charles Smith <[email protected]>
* Update
web-console/src/views/workbench-view/execution-submit-dialog/execution-submit-dialog.tsx
Co-authored-by: Charles Smith <[email protected]>
* Update drag-and-drop instructions in execution-submit-dialog
* Add snapshot tests for ExecutionSubmitDialog
* prettify
---------
Co-authored-by: Charles Smith <[email protected]>
---
.../execution-submit-dialog.spec.tsx.snap | 70 +++++++++++++
.../execution-submit-dialog.scss | 18 +++-
...ialog.scss => execution-submit-dialog.spec.tsx} | 22 ++--
.../execution-submit-dialog.tsx | 115 +++++++++++++++------
4 files changed, 178 insertions(+), 47 deletions(-)
diff --git
a/web-console/src/views/workbench-view/execution-submit-dialog/__snapshots__/execution-submit-dialog.spec.tsx.snap
b/web-console/src/views/workbench-view/execution-submit-dialog/__snapshots__/execution-submit-dialog.spec.tsx.snap
new file mode 100644
index 00000000000..6719e1b7ba4
--- /dev/null
+++
b/web-console/src/views/workbench-view/execution-submit-dialog/__snapshots__/execution-submit-dialog.spec.tsx.snap
@@ -0,0 +1,70 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`ExecutionSubmitDialog matches snapshot 1`] = `
+<Blueprint4.Dialog
+ backdropProps={
+ Object {
+ "onDragLeave": [Function],
+ "onDragOver": [Function],
+ "onDrop": [Function],
+ }
+ }
+ canOutsideClickClose={false}
+ className="execution-submit-dialog"
+ isOpen={true}
+ onClose={[Function]}
+ title="Load query detail archive"
+>
+ <div
+ className="bp4-dialog-body"
+ >
+ <p>
+ You can load query detail archive files from other Druid clusters to
render the query detail here.
+ </p>
+ <p>
+ To download the query detail archive for a query, click on the query in
the
+
+ <Unknown>
+ Recent query tasks
+ </Unknown>
+ panel in the query view.
+ </p>
+ <Blueprint4.FormGroup
+ label="Select query detail archive file"
+ >
+ <Blueprint4.FileInput
+ fill={true}
+ hasSelection={false}
+ inputProps={
+ Object {
+ "accept": ".json",
+ }
+ }
+ onInputChange={[Function]}
+ text="Choose file..."
+ />
+ </Blueprint4.FormGroup>
+ <p>
+ Alternatively, drag a file directly onto this dialog.
+ </p>
+ </div>
+ <div
+ className="bp4-dialog-footer"
+ >
+ <div
+ className="bp4-dialog-footer-actions"
+ >
+ <Blueprint4.Button
+ onClick={[Function]}
+ text="Close"
+ />
+ <Blueprint4.Button
+ disabled={true}
+ intent="primary"
+ onClick={[Function]}
+ text="Submit"
+ />
+ </div>
+ </div>
+</Blueprint4.Dialog>
+`;
diff --git
a/web-console/src/views/workbench-view/execution-submit-dialog/execution-submit-dialog.scss
b/web-console/src/views/workbench-view/execution-submit-dialog/execution-submit-dialog.scss
index 77d355bd841..8370c3503f0 100644
---
a/web-console/src/views/workbench-view/execution-submit-dialog/execution-submit-dialog.scss
+++
b/web-console/src/views/workbench-view/execution-submit-dialog/execution-submit-dialog.scss
@@ -21,11 +21,21 @@
.execution-submit-dialog {
&.#{$bp-ns}-dialog {
top: 5%;
- width: 90%;
+ width: 500px;
}
+}
+
+.#{$bp-ns}-overlay-backdrop.dragging-file {
+ &::after {
+ position: absolute;
+ top: 20px;
+ left: 20px;
+ right: 20px;
+ bottom: 20px;
+ border: 3px dashed cyan;
+ border-radius: 20px;
- .execution-submit-dialog-textarea {
- margin-bottom: 10px;
- border-bottom: 1px solid rgba(0, 0, 0, 0.25);
+ pointer-events: none;
+ content: '';
}
}
diff --git
a/web-console/src/views/workbench-view/execution-submit-dialog/execution-submit-dialog.scss
b/web-console/src/views/workbench-view/execution-submit-dialog/execution-submit-dialog.spec.tsx
similarity index 68%
copy from
web-console/src/views/workbench-view/execution-submit-dialog/execution-submit-dialog.scss
copy to
web-console/src/views/workbench-view/execution-submit-dialog/execution-submit-dialog.spec.tsx
index 77d355bd841..12379306e0f 100644
---
a/web-console/src/views/workbench-view/execution-submit-dialog/execution-submit-dialog.scss
+++
b/web-console/src/views/workbench-view/execution-submit-dialog/execution-submit-dialog.spec.tsx
@@ -16,16 +16,16 @@
* limitations under the License.
*/
-@import '../../../variables';
+import React from 'react';
-.execution-submit-dialog {
- &.#{$bp-ns}-dialog {
- top: 5%;
- width: 90%;
- }
+import { shallow } from '../../../utils/shallow-renderer';
- .execution-submit-dialog-textarea {
- margin-bottom: 10px;
- border-bottom: 1px solid rgba(0, 0, 0, 0.25);
- }
-}
+import { ExecutionSubmitDialog } from './execution-submit-dialog';
+
+describe('ExecutionSubmitDialog', () => {
+ it('matches snapshot', () => {
+ const comp = shallow(<ExecutionSubmitDialog onSubmit={() => {}}
onClose={() => {}} />);
+
+ expect(comp).toMatchSnapshot();
+ });
+});
diff --git
a/web-console/src/views/workbench-view/execution-submit-dialog/execution-submit-dialog.tsx
b/web-console/src/views/workbench-view/execution-submit-dialog/execution-submit-dialog.tsx
index 046de0ffb5f..3a563df1c94 100644
---
a/web-console/src/views/workbench-view/execution-submit-dialog/execution-submit-dialog.tsx
+++
b/web-console/src/views/workbench-view/execution-submit-dialog/execution-submit-dialog.tsx
@@ -16,10 +16,10 @@
* limitations under the License.
*/
-import { Button, Classes, Dialog, Intent } from '@blueprintjs/core';
+import { Button, Classes, Code, Dialog, FileInput, FormGroup, Intent } from
'@blueprintjs/core';
import * as JSONBig from 'json-bigint-native';
+import type { DragEvent } from 'react';
import React, { useState } from 'react';
-import AceEditor from 'react-ace';
import { Execution } from '../../../druid-models';
import { AppToaster } from '../../../singletons';
@@ -28,6 +28,22 @@ import { offsetToRowColumn } from '../../../utils';
import './execution-submit-dialog.scss';
+function getDraggedFile(ev: DragEvent<HTMLDivElement>): File | undefined {
+ if (!ev.dataTransfer) return;
+
+ if (ev.dataTransfer.items) {
+ // Use DataTransferItemList interface to access the file(s)
+ const item = ev.dataTransfer.items[0];
+ if (item.kind === 'file') {
+ return item.getAsFile() || undefined;
+ }
+ } else {
+ return ev.dataTransfer.files[0];
+ }
+
+ return;
+}
+
export interface ExecutionSubmitDialogProps {
onSubmit(execution: Execution): void;
onClose(): void;
@@ -37,14 +53,19 @@ export const ExecutionSubmitDialog = React.memo(function
ExecutionSubmitDialog(
props: ExecutionSubmitDialogProps,
) {
const { onClose, onSubmit } = props;
- const [archive, setArchive] = useState('');
+ const [selectedFile, setSelectedFile] = useState<File | undefined>();
+ const [dragging, setDragging] = useState(false);
+
+ async function handleSubmit(): Promise<void> {
+ if (!selectedFile) return;
+
+ const text = await selectedFile.text();
- function handleSubmit(): void {
let parsed: QueryDetailArchive;
try {
- parsed = JSONBig.parse(archive);
+ parsed = JSONBig.parse(text);
} catch (e) {
- const rowColumn = typeof e.at === 'number' ? offsetToRowColumn(archive,
e.at) : undefined;
+ const rowColumn = typeof e.at === 'number' ? offsetToRowColumn(text,
e.at) : undefined;
AppToaster.show({
intent: Intent.DANGER,
message: `Could not parse JSON: ${e.message}${
@@ -56,7 +77,8 @@ export const ExecutionSubmitDialog = React.memo(function
ExecutionSubmitDialog(
}
let execution: Execution | undefined;
- const detailArchiveVersion = parsed.detailArchiveVersion ?? (parsed as
any).profileVersion;
+ const detailArchiveVersion: unknown =
+ parsed.detailArchiveVersion ?? (parsed as any).profileVersion;
if (typeof detailArchiveVersion === 'number') {
try {
if (detailArchiveVersion === 2) {
@@ -102,42 +124,71 @@ export const ExecutionSubmitDialog = React.memo(function
ExecutionSubmitDialog(
return (
<Dialog
className="execution-submit-dialog"
+ backdropClassName={dragging ? `dragging-file` : undefined}
+ style={dragging ? { pointerEvents: 'none' } : undefined}
isOpen
onClose={onClose}
title="Load query detail archive"
+ backdropProps={{
+ onDrop(ev: DragEvent<HTMLDivElement>) {
+ // Prevent default behavior (Prevent file from being opened)
+ ev.preventDefault();
+ if (dragging) setDragging(false);
+
+ const droppedFile = getDraggedFile(ev);
+
+ if (droppedFile) {
+ if (!droppedFile.name.endsWith('.json')) {
+ AppToaster.show({
+ intent: Intent.DANGER,
+ message: `The Query Detail Archive must be a .json file`,
+ timeout: 5000,
+ });
+ return;
+ }
+
+ setSelectedFile(droppedFile);
+ }
+ },
+ onDragOver(ev: DragEvent<HTMLDivElement>) {
+ ev.preventDefault(); // Prevent default behavior (Prevent file from
being opened)
+ if (!dragging) setDragging(true);
+ },
+ onDragLeave(ev: DragEvent<HTMLDivElement>) {
+ ev.preventDefault(); // Prevent default behavior (Prevent file from
being opened)
+ if (dragging) setDragging(false);
+ },
+ }}
canOutsideClickClose={false}
>
- <AceEditor
- mode="hjson"
- theme="solarized_dark"
- className="execution-submit-dialog-textarea placeholder-padding"
- onChange={setArchive}
- fontSize={12}
- showPrintMargin={false}
- showGutter
- highlightActiveLine
- value={archive}
- width="100%"
- setOptions={{
- showLineNumbers: true,
- tabSize: 2,
- newLineMode: 'unix' as any, // newLineMode is incorrectly assumed to
be boolean in the typings
- }}
- style={{}}
- placeholder="{ Query detail archive or query report... }"
- onLoad={editor => {
- editor.renderer.setPadding(10);
- editor.renderer.setScrollMargin(10, 10, 0, 0);
- }}
- />
+ <div className={Classes.DIALOG_BODY}>
+ <p>
+ You can load query detail archive files from other Druid clusters to
render the query
+ detail here.
+ </p>
+ <p>
+ To download the query detail archive for a query, click on the query
in the{' '}
+ <Code>Recent query tasks</Code> panel in the query view.
+ </p>
+ <FormGroup label="Select query detail archive file">
+ <FileInput
+ hasSelection={Boolean(selectedFile)}
+ text={selectedFile?.name ?? 'Choose file...'}
+ onInputChange={e => setSelectedFile((e.target as any).files[0])}
+ inputProps={{ accept: '.json' }}
+ fill
+ />
+ </FormGroup>
+ <p>Alternatively, drag a file directly onto this dialog.</p>
+ </div>
<div className={Classes.DIALOG_FOOTER}>
<div className={Classes.DIALOG_FOOTER_ACTIONS}>
<Button text="Close" onClick={onClose} />
<Button
text="Submit"
intent={Intent.PRIMARY}
- onClick={handleSubmit}
- disabled={!archive}
+ onClick={() => void handleSubmit()}
+ disabled={!selectedFile}
/>
</div>
</div>
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]