From 77eef1dc7dda775779b9b987087ae6ee5adfe544 Mon Sep 17 00:00:00 2001 From: Vadim Ogievetsky Date: Sat, 6 Jul 2024 11:06:11 -0700 Subject: [PATCH 01/12] better sql data loader reset --- .../assets/{azureStorage.png => azure-storage.png} | Bin web-console/src/console-application.tsx | 1 + .../druid-models/ingestion-spec/ingestion-spec.tsx | 6 ++++-- .../ingestion-progress-dialog.tsx | 7 ++++--- .../sql-data-loader-view/sql-data-loader-view.tsx | 9 +++++++-- 5 files changed, 16 insertions(+), 7 deletions(-) rename web-console/assets/{azureStorage.png => azure-storage.png} (100%) diff --git a/web-console/assets/azureStorage.png b/web-console/assets/azure-storage.png similarity index 100% rename from web-console/assets/azureStorage.png rename to web-console/assets/azure-storage.png diff --git a/web-console/src/console-application.tsx b/web-console/src/console-application.tsx index e500af23e5d2..4cb735fdc267 100644 --- a/web-console/src/console-application.tsx +++ b/web-console/src/console-application.tsx @@ -331,6 +331,7 @@ export class ConsoleApplication extends React.PureComponent< capabilities={capabilities} goToQuery={this.goToQuery} goToTask={this.goToTasksWithTaskId} + goToTaskGroup={this.goToTasksWithTaskGroupId} />, ); }; diff --git a/web-console/src/druid-models/ingestion-spec/ingestion-spec.tsx b/web-console/src/druid-models/ingestion-spec/ingestion-spec.tsx index 2705614571dc..b1eb447312f8 100644 --- a/web-console/src/druid-models/ingestion-spec/ingestion-spec.tsx +++ b/web-console/src/druid-models/ingestion-spec/ingestion-spec.tsx @@ -212,8 +212,10 @@ export function getIngestionTitle(ingestionType: IngestionComboTypeWithExtra): s export function getIngestionImage(ingestionType: IngestionComboTypeWithExtra): string { const parts = ingestionType.split(':'); - if (parts.length === 2) return parts[1]; - return ingestionType; + return parts[parts.length - 1] + .split(/(?=[A-Z])/) + .join('-') + .toLowerCase(); } export function getIngestionDocLink(spec: Partial): string { diff --git a/web-console/src/views/sql-data-loader-view/ingestion-progress-dialog/ingestion-progress-dialog.tsx b/web-console/src/views/sql-data-loader-view/ingestion-progress-dialog/ingestion-progress-dialog.tsx index 261fe929bfc5..ac6def8151c0 100644 --- a/web-console/src/views/sql-data-loader-view/ingestion-progress-dialog/ingestion-progress-dialog.tsx +++ b/web-console/src/views/sql-data-loader-view/ingestion-progress-dialog/ingestion-progress-dialog.tsx @@ -33,7 +33,8 @@ import './ingestion-progress-dialog.scss'; interface IngestionProgressDialogProps { taskId: string; goToQuery(queryWithContext: QueryWithContext): void; - goToTask(taskId: string): void; + goToTask(taskGroupId: string): void; + goToTaskGroup(taskGroupId: string): void; onReset(): void; onClose(): void; } @@ -41,7 +42,7 @@ interface IngestionProgressDialogProps { export const IngestionProgressDialog = React.memo(function IngestionProgressDialog( props: IngestionProgressDialogProps, ) { - const { taskId, goToQuery, goToTask, onReset, onClose } = props; + const { taskId, goToQuery, goToTask, goToTaskGroup, onReset, onClose } = props; const [showLiveReports, setShowLiveReports] = useState(false); const [insertResultState, ingestQueryManager] = useQueryManager({ @@ -104,7 +105,7 @@ export const IngestionProgressDialog = React.memo(function IngestionProgressDial rightIcon={IconNames.ARROW_TOP_RIGHT} onClick={() => { if (!insertResultState.intermediate) return; - goToTask(insertResultState.intermediate.id); + goToTaskGroup(insertResultState.intermediate.id); }} /> diff --git a/web-console/src/views/sql-data-loader-view/sql-data-loader-view.tsx b/web-console/src/views/sql-data-loader-view/sql-data-loader-view.tsx index c07bdd4380fe..686b5b4df717 100644 --- a/web-console/src/views/sql-data-loader-view/sql-data-loader-view.tsx +++ b/web-console/src/views/sql-data-loader-view/sql-data-loader-view.tsx @@ -58,12 +58,13 @@ export interface SqlDataLoaderViewProps { capabilities: Capabilities; goToQuery(queryWithContext: QueryWithContext): void; goToTask(taskId: string): void; + goToTaskGroup(taskGroupId: string): void; } export const SqlDataLoaderView = React.memo(function SqlDataLoaderView( props: SqlDataLoaderViewProps, ) { - const { capabilities, goToQuery, goToTask } = props; + const { capabilities, goToQuery, goToTask, goToTaskGroup } = props; const [alertElement, setAlertElement] = useState(); const [externalConfigStep, setExternalConfigStep] = useState>({}); const [content, setContent] = useLocalStorageState( @@ -239,7 +240,11 @@ export const SqlDataLoaderView = React.memo(function SqlDataLoaderView( taskId={content.id} goToQuery={goToQuery} goToTask={goToTask} - onReset={() => setContent(undefined)} + goToTaskGroup={goToTaskGroup} + onReset={() => { + setExternalConfigStep({}); + setContent(undefined); + }} onClose={() => setContent(deepDelete(content, 'id'))} /> )} From b963c658282f1236e88c667ec7195c95377b6230 Mon Sep 17 00:00:00 2001 From: Vadim Ogievetsky Date: Sat, 6 Jul 2024 11:10:29 -0700 Subject: [PATCH 02/12] snapshot --- .../load-data-view/__snapshots__/load-data-view.spec.tsx.snap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web-console/src/views/load-data-view/__snapshots__/load-data-view.spec.tsx.snap b/web-console/src/views/load-data-view/__snapshots__/load-data-view.spec.tsx.snap index 266bfc9c05cd..6bbafa818c0c 100644 --- a/web-console/src/views/load-data-view/__snapshots__/load-data-view.spec.tsx.snap +++ b/web-console/src/views/load-data-view/__snapshots__/load-data-view.spec.tsx.snap @@ -182,7 +182,7 @@ exports[`LoadDataView matches snapshot batch 1`] = ` > Ingestion tile for index_parallel:azureStorage

Azure Data Lake From cc71ce78d9f91500528c32f5dc69b9b324153a83 Mon Sep 17 00:00:00 2001 From: Vadim Ogievetsky Date: Tue, 9 Jul 2024 12:45:44 -0700 Subject: [PATCH 03/12] fix destination pane sizing --- .../src/druid-models/execution/execution.ts | 2 ++ .../src/helpers/execution/sql-task-execution.ts | 7 ++----- .../destination-pages-dialog.scss | 10 +++++++++- .../destination-pages-dialog.tsx | 7 ++++++- .../destination-pages-pane.scss | 7 +++++++ .../destination-pages-pane.tsx | 2 +- .../execution-details-pane.scss | 14 +++++++++++--- .../execution-details-pane.tsx | 2 +- 8 files changed, 39 insertions(+), 12 deletions(-) diff --git a/web-console/src/druid-models/execution/execution.ts b/web-console/src/druid-models/execution/execution.ts index 799de6f9c511..4ed90b9c3c20 100644 --- a/web-console/src/druid-models/execution/execution.ts +++ b/web-console/src/druid-models/execution/execution.ts @@ -192,6 +192,8 @@ export interface ExecutionValue { } export class Execution { + static USE_TASK_PAYLOAD = true; + static USE_TASK_REPORTS = true; static INLINE_DATASOURCE_MARKER = '__query_select'; static validAsyncState(status: string | undefined): status is AsyncState { diff --git a/web-console/src/helpers/execution/sql-task-execution.ts b/web-console/src/helpers/execution/sql-task-execution.ts index f0aa7dde54ce..7f4cf6f72280 100644 --- a/web-console/src/helpers/execution/sql-task-execution.ts +++ b/web-console/src/helpers/execution/sql-task-execution.ts @@ -25,9 +25,6 @@ import { Api } from '../../singletons'; import { deepGet, DruidError, IntermediateQueryState, QueryManager } from '../../utils'; import { maybeGetClusterCapacity } from '../capacity'; -const USE_TASK_PAYLOAD = true; -const USE_TASK_REPORTS = true; - // some executionMode has to be set on the /druid/v2/sql/statements API function ensureExecutionModeIsSet(context: QueryContext | undefined): QueryContext { if (typeof context?.executionMode === 'string') return context; @@ -161,7 +158,7 @@ export async function getTaskExecution( let execution: Execution | undefined; - if (USE_TASK_REPORTS) { + if (Execution.USE_TASK_REPORTS) { let taskReport: any; try { taskReport = ( @@ -198,7 +195,7 @@ export async function getTaskExecution( } let taskPayload = taskPayloadOverride; - if (USE_TASK_PAYLOAD && !taskPayload) { + if (Execution.USE_TASK_PAYLOAD && !taskPayload) { try { taskPayload = ( await Api.instance.get(`/druid/indexer/v1/task/${encodedId}`, { diff --git a/web-console/src/views/workbench-view/destination-pages-dialog/destination-pages-dialog.scss b/web-console/src/views/workbench-view/destination-pages-dialog/destination-pages-dialog.scss index 430cdc300d1a..bffc5f675f53 100644 --- a/web-console/src/views/workbench-view/destination-pages-dialog/destination-pages-dialog.scss +++ b/web-console/src/views/workbench-view/destination-pages-dialog/destination-pages-dialog.scss @@ -21,6 +21,14 @@ .destination-pages-dialog { &.#{$bp-ns}-dialog { min-width: 700px; - min-height: 480px; + height: 80vh; + } + + .destination-pages-pane { + height: 100%; + } + + .#{$bp-ns}-dialog-footer { + margin-top: 0; } } diff --git a/web-console/src/views/workbench-view/destination-pages-dialog/destination-pages-dialog.tsx b/web-console/src/views/workbench-view/destination-pages-dialog/destination-pages-dialog.tsx index 68c66487e3c4..7fed3ce83e1c 100644 --- a/web-console/src/views/workbench-view/destination-pages-dialog/destination-pages-dialog.tsx +++ b/web-console/src/views/workbench-view/destination-pages-dialog/destination-pages-dialog.tsx @@ -16,7 +16,7 @@ * limitations under the License. */ -import { Classes, Dialog } from '@blueprintjs/core'; +import { Button, Classes, Dialog } from '@blueprintjs/core'; import React from 'react'; import type { Execution } from '../../../druid-models'; @@ -39,6 +39,11 @@ export const DestinationPagesDialog = React.memo(function DestinationPagesDialog

+
+
+ +
+
); }); diff --git a/web-console/src/views/workbench-view/destination-pages-pane/destination-pages-pane.scss b/web-console/src/views/workbench-view/destination-pages-pane/destination-pages-pane.scss index 09b8609af4b7..86e9212c9839 100644 --- a/web-console/src/views/workbench-view/destination-pages-pane/destination-pages-pane.scss +++ b/web-console/src/views/workbench-view/destination-pages-pane/destination-pages-pane.scss @@ -17,8 +17,15 @@ */ .destination-pages-pane { + display: flex; + flex-direction: column; + .download-button { margin-top: 4px; margin-left: 2px; } + + & > .ReactTable { + flex: 1; + } } diff --git a/web-console/src/views/workbench-view/destination-pages-pane/destination-pages-pane.tsx b/web-console/src/views/workbench-view/destination-pages-pane/destination-pages-pane.tsx index b58a75aea4b6..0258233338cd 100644 --- a/web-console/src/views/workbench-view/destination-pages-pane/destination-pages-pane.tsx +++ b/web-console/src/views/workbench-view/destination-pages-pane/destination-pages-pane.tsx @@ -177,7 +177,7 @@ export const DestinationPagesPane = React.memo(function DestinationPagesPane( Header: '', id: 'download', accessor: 'id', - width: 300, + width: 130, Cell: ({ value }) => ( * { + height: 100%; + } } - .flexible-query-input, - .result-table-pane { - height: 100%; + .execution-details-pane-general { + display: flex; + flex-direction: column; + + .execution-stages-pane { + flex: 1; + } } } diff --git a/web-console/src/views/workbench-view/execution-details-pane/execution-details-pane.tsx b/web-console/src/views/workbench-view/execution-details-pane/execution-details-pane.tsx index 0f1200a8661f..617c832e55a5 100644 --- a/web-console/src/views/workbench-view/execution-details-pane/execution-details-pane.tsx +++ b/web-console/src/views/workbench-view/execution-details-pane/execution-details-pane.tsx @@ -61,7 +61,7 @@ export const ExecutionDetailsPane = React.memo(function ExecutionDetailsPane( case 'general': { const ingestDatasource = execution.getIngestDatasource(); return ( -
+

{`General info for ${execution.id}${ ingestDatasource ? ` ingesting into ${T(ingestDatasource)}` : '' }`}

From 168c2c6c305a3dde98d433583337e7eb24b9d751 Mon Sep 17 00:00:00 2001 From: Vadim Ogievetsky Date: Tue, 9 Jul 2024 16:41:40 -0700 Subject: [PATCH 04/12] clean doc links --- .../restricted-mode.spec.tsx.snap | 4 +-- .../restricted-mode/restricted-mode.tsx | 2 +- .../__snapshots__/about-dialog.spec.tsx.snap | 2 +- .../compaction-config-dialog.spec.tsx.snap | 8 ++--- .../compaction-config-dialog.tsx | 4 +-- .../compaction-dynamic-config-dialog.tsx | 4 +-- .../coordinator-dynamic-config-dialog.tsx | 4 +-- .../overlord-dynamic-config-dialog.tsx | 4 +-- .../retention-dialog.spec.tsx.snap | 2 +- .../retention-dialog/retention-dialog.tsx | 2 +- .../src/druid-models/filter/filter.tsx | 2 +- .../ingestion-spec/ingestion-spec.tsx | 33 +++++++++---------- .../input-format/input-format.tsx | 4 +-- .../input-source/input-source.tsx | 16 ++++----- .../druid-models/metric-spec/metric-spec.tsx | 6 ++-- .../timestamp-spec/timestamp-spec.tsx | 2 +- .../transform-spec/transform-spec.tsx | 6 ++-- web-console/src/hooks/use-query-manager.ts | 2 +- web-console/src/links.ts | 10 +++--- web-console/src/utils/joda-to-regexp.ts | 2 +- .../views/load-data-view/info-messages.tsx | 26 +++++++-------- .../views/load-data-view/load-data-view.tsx | 24 +++++++------- .../schema-step/column-list/column-list.tsx | 4 +-- .../schema-step/schema-step.tsx | 4 +-- .../execution-details-pane.spec.tsx.snap | 4 ++- .../execution-error-pane.spec.tsx.snap | 2 +- .../input-format-step/input-format-step.tsx | 2 +- 27 files changed, 87 insertions(+), 98 deletions(-) diff --git a/web-console/src/components/header-bar/restricted-mode/__snapshots__/restricted-mode.spec.tsx.snap b/web-console/src/components/header-bar/restricted-mode/__snapshots__/restricted-mode.spec.tsx.snap index ed352ecbf5fe..8a2e325815d8 100644 --- a/web-console/src/components/header-bar/restricted-mode/__snapshots__/restricted-mode.spec.tsx.snap +++ b/web-console/src/components/header-bar/restricted-mode/__snapshots__/restricted-mode.spec.tsx.snap @@ -17,7 +17,7 @@ exports[`RestrictedMode matches snapshot when in auto capability detection mode For more info refer to the web console documentation @@ -88,7 +88,7 @@ exports[`RestrictedMode matches snapshot when in manual capability detection mod For more info refer to the web console documentation diff --git a/web-console/src/components/header-bar/restricted-mode/restricted-mode.tsx b/web-console/src/components/header-bar/restricted-mode/restricted-mode.tsx index 072d5b10e587..d9b7e18a5ec0 100644 --- a/web-console/src/components/header-bar/restricted-mode/restricted-mode.tsx +++ b/web-console/src/components/header-bar/restricted-mode/restricted-mode.tsx @@ -128,7 +128,7 @@ export const RestrictedMode = React.memo(function RestrictedMode(props: Restrict {message}

For more info refer to the{' '} - + web console documentation . diff --git a/web-console/src/dialogs/about-dialog/__snapshots__/about-dialog.spec.tsx.snap b/web-console/src/dialogs/about-dialog/__snapshots__/about-dialog.spec.tsx.snap index 9509dd1ecf93..7ea843d01dfb 100644 --- a/web-console/src/dialogs/about-dialog/__snapshots__/about-dialog.spec.tsx.snap +++ b/web-console/src/dialogs/about-dialog/__snapshots__/about-dialog.spec.tsx.snap @@ -109,7 +109,7 @@ exports[`AboutDialog matches snapshot 1`] = ` Druid is made with ❤️ by a community of passionate developers. To contribute, join in the discussion on the diff --git a/web-console/src/dialogs/compaction-config-dialog/__snapshots__/compaction-config-dialog.spec.tsx.snap b/web-console/src/dialogs/compaction-config-dialog/__snapshots__/compaction-config-dialog.spec.tsx.snap index 6df207060fff..30df7eeca2ff 100644 --- a/web-console/src/dialogs/compaction-config-dialog/__snapshots__/compaction-config-dialog.spec.tsx.snap +++ b/web-console/src/dialogs/compaction-config-dialog/__snapshots__/compaction-config-dialog.spec.tsx.snap @@ -360,7 +360,7 @@ exports[`CompactionConfigDialog matches snapshot with compactionConfig (dynamic For more information refer to the documentation @@ -770,7 +770,7 @@ exports[`CompactionConfigDialog matches snapshot with compactionConfig (hashed p For more information refer to the documentation @@ -1180,7 +1180,7 @@ exports[`CompactionConfigDialog matches snapshot with compactionConfig (range pa For more information refer to the documentation @@ -1590,7 +1590,7 @@ exports[`CompactionConfigDialog matches snapshot without compactionConfig 1`] = For more information refer to the documentation diff --git a/web-console/src/dialogs/compaction-config-dialog/compaction-config-dialog.tsx b/web-console/src/dialogs/compaction-config-dialog/compaction-config-dialog.tsx index f07d0ce55ec2..985430755c74 100644 --- a/web-console/src/dialogs/compaction-config-dialog/compaction-config-dialog.tsx +++ b/web-console/src/dialogs/compaction-config-dialog/compaction-config-dialog.tsx @@ -122,9 +122,7 @@ export const CompactionConfigDialog = React.memo(function CompactionConfigDialog

For more information refer to the{' '} - + documentation . diff --git a/web-console/src/dialogs/compaction-dynamic-config-dialog/compaction-dynamic-config-dialog.tsx b/web-console/src/dialogs/compaction-dynamic-config-dialog/compaction-dynamic-config-dialog.tsx index 59f73c27a110..be5234b5bdb2 100644 --- a/web-console/src/dialogs/compaction-dynamic-config-dialog/compaction-dynamic-config-dialog.tsx +++ b/web-console/src/dialogs/compaction-dynamic-config-dialog/compaction-dynamic-config-dialog.tsx @@ -86,7 +86,7 @@ export const CompactionDynamicConfigDialog = React.memo(function CompactionDynam async function saveConfig() { if (!dynamicConfig) return; try { - // This API is terrible. https://druid.apache.org/docs/latest/operations/api-reference.html#automatic-compaction-configuration + // This API is terrible. https://druid.apache.org/docs/latest/operations/api-reference#automatic-compaction-configuration await Api.instance.post( `/druid/coordinator/v1/config/compaction/taskslots?ratio=${ dynamicConfig.compactionTaskSlotRatio ?? DEFAULT_RATIO @@ -124,7 +124,7 @@ export const CompactionDynamicConfigDialog = React.memo(function CompactionDynam documentation diff --git a/web-console/src/dialogs/coordinator-dynamic-config-dialog/coordinator-dynamic-config-dialog.tsx b/web-console/src/dialogs/coordinator-dynamic-config-dialog/coordinator-dynamic-config-dialog.tsx index b31f774d88be..3caa2c71b74f 100644 --- a/web-console/src/dialogs/coordinator-dynamic-config-dialog/coordinator-dynamic-config-dialog.tsx +++ b/web-console/src/dialogs/coordinator-dynamic-config-dialog/coordinator-dynamic-config-dialog.tsx @@ -107,9 +107,7 @@ export const CoordinatorDynamicConfigDialog = React.memo(function CoordinatorDyn

Edit the coordinator dynamic configuration on the fly. For more information please refer to the{' '} - + documentation . diff --git a/web-console/src/dialogs/overlord-dynamic-config-dialog/overlord-dynamic-config-dialog.tsx b/web-console/src/dialogs/overlord-dynamic-config-dialog/overlord-dynamic-config-dialog.tsx index 109901a71b25..64e5a6d168a9 100644 --- a/web-console/src/dialogs/overlord-dynamic-config-dialog/overlord-dynamic-config-dialog.tsx +++ b/web-console/src/dialogs/overlord-dynamic-config-dialog/overlord-dynamic-config-dialog.tsx @@ -107,9 +107,7 @@ export const OverlordDynamicConfigDialog = React.memo(function OverlordDynamicCo

Edit the overlord dynamic configuration at runtime. For more information please refer to the{' '} - + documentation . diff --git a/web-console/src/dialogs/retention-dialog/__snapshots__/retention-dialog.spec.tsx.snap b/web-console/src/dialogs/retention-dialog/__snapshots__/retention-dialog.spec.tsx.snap index 68fe45ae1b58..c22b15631553 100644 --- a/web-console/src/dialogs/retention-dialog/__snapshots__/retention-dialog.spec.tsx.snap +++ b/web-console/src/dialogs/retention-dialog/__snapshots__/retention-dialog.spec.tsx.snap @@ -64,7 +64,7 @@ exports[`RetentionDialog matches snapshot 1`] = ` Druid uses rules to determine what data should be retained in the cluster. The rules are evaluated in order from top to bottom. For more information please refer to the diff --git a/web-console/src/dialogs/retention-dialog/retention-dialog.tsx b/web-console/src/dialogs/retention-dialog/retention-dialog.tsx index 677173cc6d3f..cc9645bd79f2 100644 --- a/web-console/src/dialogs/retention-dialog/retention-dialog.tsx +++ b/web-console/src/dialogs/retention-dialog/retention-dialog.tsx @@ -129,7 +129,7 @@ ORDER BY 1`,

Druid uses rules to determine what data should be retained in the cluster. The rules are evaluated in order from top to bottom. For more information please refer to the{' '} - + documentation . diff --git a/web-console/src/druid-models/filter/filter.tsx b/web-console/src/druid-models/filter/filter.tsx index a7fd317197b3..41f0d09ca856 100644 --- a/web-console/src/druid-models/filter/filter.tsx +++ b/web-console/src/druid-models/filter/filter.tsx @@ -170,7 +170,7 @@ export const FILTERS_FIELDS: Field[] = [ <>

A Druid{' '} - + JSON filter expression {' '} to apply to the data. diff --git a/web-console/src/druid-models/ingestion-spec/ingestion-spec.tsx b/web-console/src/druid-models/ingestion-spec/ingestion-spec.tsx index b1eb447312f8..3bea288c8c6a 100644 --- a/web-console/src/druid-models/ingestion-spec/ingestion-spec.tsx +++ b/web-console/src/druid-models/ingestion-spec/ingestion-spec.tsx @@ -223,13 +223,13 @@ export function getIngestionDocLink(spec: Partial): string { switch (type) { case 'kafka': - return `${getLink('DOCS')}/development/extensions-core/kafka-ingestion.html`; + return `${getLink('DOCS')}/development/extensions-core/kafka-ingestion`; case 'kinesis': - return `${getLink('DOCS')}/development/extensions-core/kinesis-ingestion.html`; + return `${getLink('DOCS')}/development/extensions-core/kinesis-ingestion`; default: - return `${getLink('DOCS')}/ingestion/native-batch.html#input-sources`; + return `${getLink('DOCS')}/ingestion/native-batch#input-sources`; } } @@ -585,7 +585,7 @@ export function getIoConfigFormFields(ingestionComboType: IngestionComboType): F info: (

Druid connects to raw data through{' '} - + inputSources . You can change your selected inputSource here. @@ -610,7 +610,7 @@ export function getIoConfigFormFields(ingestionComboType: IngestionComboType): F

For more information, refer to the documentation for{' '} - + FileSystem#getPathMatcher . @@ -664,7 +664,7 @@ export function getIoConfigFormFields(ingestionComboType: IngestionComboType): F required: true, info: ( <> - + inputSource.baseDir

Specifies the directory to search recursively for files to be ingested.

@@ -679,14 +679,12 @@ export function getIoConfigFormFields(ingestionComboType: IngestionComboType): F suggestions: FILTER_SUGGESTIONS, info: ( <> - + inputSource.filter

A wildcard filter for files. See{' '} - + here {' '} for format information. Files matching the filter criteria are considered for @@ -728,8 +726,7 @@ export function getIoConfigFormFields(ingestionComboType: IngestionComboType): F hideInMore: true, info: (

- The{' '} - filter{' '} + The filter{' '} to apply to the data as part of querying.

), @@ -789,7 +786,7 @@ export function getIoConfigFormFields(ingestionComboType: IngestionComboType): F <>

JSON array of{' '} - + S3 Objects . @@ -952,7 +949,7 @@ export function getIoConfigFormFields(ingestionComboType: IngestionComboType): F <>

JSON array of{' '} - + S3 Objects . @@ -1026,7 +1023,7 @@ export function getIoConfigFormFields(ingestionComboType: IngestionComboType): F <>

JSON array of{' '} - + Google Cloud Storage Objects . @@ -1256,7 +1253,7 @@ export function getIoConfigFormFields(ingestionComboType: IngestionComboType): F info: ( <> The Amazon Kinesis stream endpoint for a region. You can find a list of endpoints{' '} - + here . @@ -1886,7 +1883,7 @@ export function getSecondaryPartitionRelatedFormFields(

This should be the first dimension in your schema which would make it first in the sort order. As{' '} - + Partitioning and sorting are best friends!

@@ -2513,7 +2510,7 @@ export function guessSimpleInputFormat( if (sampleDatum.startsWith('ORC')) { return inputFormatFromType({ type: 'orc' }); } - // Avro OCF 4 byte magic header: https://avro.apache.org/docs/current/spec.html#Object+Container+Files + // Avro OCF 4 byte magic header: https://avro.apache.org/docs/current/spec#Object+Container+Files if (sampleDatum.startsWith('Obj\x01')) { return inputFormatFromType({ type: 'avro_ocf' }); } diff --git a/web-console/src/druid-models/input-format/input-format.tsx b/web-console/src/druid-models/input-format/input-format.tsx index 7692a62a7a44..a5a1fbdfa073 100644 --- a/web-console/src/druid-models/input-format/input-format.tsx +++ b/web-console/src/druid-models/input-format/input-format.tsx @@ -76,7 +76,7 @@ function generateInputFormatFields(streaming: boolean) {

The parser used to parse the data.

For more information see{' '} - + the documentation . @@ -329,7 +329,7 @@ export const KAFKA_METADATA_INPUT_FORMAT_FIELDS: Field[] = [

The parser used to parse the key of the Kafka message.

For more information see{' '} - + the documentation . diff --git a/web-console/src/druid-models/input-source/input-source.tsx b/web-console/src/druid-models/input-source/input-source.tsx index 174f8aba516b..e20ce1b8ca90 100644 --- a/web-console/src/druid-models/input-source/input-source.tsx +++ b/web-console/src/druid-models/input-source/input-source.tsx @@ -97,7 +97,7 @@ export type InputSourceDesc = dataSource: string; interval: string; filter?: any; - dimensions?: string[]; // ToDo: these are not in the docs https://druid.apache.org/docs/latest/ingestion/input-sources.html + dimensions?: string[]; // ToDo: these are not in the docs https://druid.apache.org/docs/latest/ingestion/input-sources metrics?: string[]; maxInputSegmentBytesPerTask?: number; } @@ -264,7 +264,7 @@ export const INPUT_SOURCE_FIELDS: Field[] = [ required: true, info: ( <> - + baseDir

Specifies the directory to search recursively for files to be ingested.

@@ -280,12 +280,12 @@ export const INPUT_SOURCE_FIELDS: Field[] = [ suggestions: FILTER_SUGGESTIONS, info: ( <> - + filter

A wildcard filter for files. See{' '} - + here {' '} for format information. @@ -344,7 +344,7 @@ export const INPUT_SOURCE_FIELDS: Field[] = [ <>

JSON array of{' '} - + S3 Objects . @@ -406,7 +406,7 @@ export const INPUT_SOURCE_FIELDS: Field[] = [ <>

JSON array of{' '} - + S3 Objects . @@ -480,7 +480,7 @@ export const INPUT_SOURCE_FIELDS: Field[] = [ <>

JSON array of{' '} - + Google Cloud Storage Objects . @@ -508,7 +508,7 @@ export const INPUT_SOURCE_FIELDS: Field[] = [

For more information, refer to the documentation for{' '} - + FileSystem#getPathMatcher . diff --git a/web-console/src/druid-models/metric-spec/metric-spec.tsx b/web-console/src/druid-models/metric-spec/metric-spec.tsx index 367f922ca48b..f8dbfd964439 100644 --- a/web-console/src/druid-models/metric-spec/metric-spec.tsx +++ b/web-console/src/druid-models/metric-spec/metric-spec.tsx @@ -201,7 +201,7 @@ export const METRIC_SPEC_FIELDS: Field[] = [

See the{' '} - + DataSketches site {' '} for details. @@ -307,7 +307,7 @@ export const METRIC_SPEC_FIELDS: Field[] = [

Must be a power of 2 from 2 to 32768. See the{' '} - + Quantiles Accuracy {' '} for details. @@ -385,7 +385,7 @@ export const METRIC_SPEC_FIELDS: Field[] = [ outlier handling modes {' '} diff --git a/web-console/src/druid-models/timestamp-spec/timestamp-spec.tsx b/web-console/src/druid-models/timestamp-spec/timestamp-spec.tsx index a88ffc3d0ef8..07ef6ade3ff3 100644 --- a/web-console/src/druid-models/timestamp-spec/timestamp-spec.tsx +++ b/web-console/src/druid-models/timestamp-spec/timestamp-spec.tsx @@ -138,7 +138,7 @@ export const TIMESTAMP_SPEC_FIELDS: Field[] = [ info: (

Specify your timestamp format by using the suggestions menu or typing in a{' '} - + format string . diff --git a/web-console/src/druid-models/transform-spec/transform-spec.tsx b/web-console/src/druid-models/transform-spec/transform-spec.tsx index ffb90d2226ee..cf8224d90f1e 100644 --- a/web-console/src/druid-models/transform-spec/transform-spec.tsx +++ b/web-console/src/druid-models/transform-spec/transform-spec.tsx @@ -56,7 +56,7 @@ export const TRANSFORM_FIELDS: Field[] = [ info: ( <> A valid Druid{' '} - expression. + expression. ), }, @@ -83,8 +83,8 @@ export function getTimestampExpressionFields(transforms: Transform[]): Field A valid Druid{' '} - expression{' '} - that should output a millis timestamp. You most likely want to use the{' '} + expression that + should output a millis timestamp. You most likely want to use the{' '} timestamp_parse function at the outer level. ), diff --git a/web-console/src/hooks/use-query-manager.ts b/web-console/src/hooks/use-query-manager.ts index a21d7b64691a..384443745838 100644 --- a/web-console/src/hooks/use-query-manager.ts +++ b/web-console/src/hooks/use-query-manager.ts @@ -58,7 +58,7 @@ export function useQueryManager( // will be compatible with future React versions that may mount/unmount/remount // the same component multiple times while. // - // See https://reactjs.org/docs/strict-mode.html#ensuring-reusable-state + // See https://reactjs.org/docs/strict-mode#ensuring-reusable-state // and https://github.com/reactwg/react-18/discussions/18 let myQueryManager = queryManager; if (queryManager.isTerminated()) { diff --git a/web-console/src/links.ts b/web-console/src/links.ts index ccd26367969d..552ca5e81221 100644 --- a/web-console/src/links.ts +++ b/web-console/src/links.ts @@ -40,7 +40,7 @@ const DEFAULT_LINKS: Links = { communityHref: 'https://druid.apache.org/community/', slackHref: 'https://druid.apache.org/community/join-slack', userGroup: 'https://groups.google.com/forum/#!forum/druid-user', - developerGroup: 'https://lists.apache.org/list.html?dev@druid.apache.org', + developerGroup: 'https://lists.apache.org/list?dev@druid.apache.org', }; const links = DEFAULT_LINKS; @@ -76,13 +76,13 @@ export function getLink(linkName: LinkNames): string { case 'DOCS': return links.docsHref; case 'DOCS_SQL': - return `${links.docsHref}/querying/sql.html`; + return `${links.docsHref}/querying/sql`; case 'DOCS_RUNE': - return `${links.docsHref}/querying/querying.html`; + return `${links.docsHref}/querying/querying`; case 'DOCS_API': - return `${links.docsHref}/api-reference/api-reference.html`; + return `${links.docsHref}/api-reference/api-reference`; case 'DOCS_MSQ_ERROR': - return `${links.docsHref}/multi-stage-query/reference.html`; + return `${links.docsHref}/multi-stage-query/reference`; case 'COMMUNITY': return links.communityHref; case 'SLACK': diff --git a/web-console/src/utils/joda-to-regexp.ts b/web-console/src/utils/joda-to-regexp.ts index 10ca006986a3..8c412dd8911d 100644 --- a/web-console/src/utils/joda-to-regexp.ts +++ b/web-console/src/utils/joda-to-regexp.ts @@ -16,7 +16,7 @@ * limitations under the License. */ -// Refer to https://www.joda.org/joda-time/key_format.html +// Refer to https://www.joda.org/joda-time/key_format const TEXT = '\\w+'; const NUMBER_2_DIGIT = '[0-9]{2}'; const NUMBER_4_DIGIT = '[0-9]{4}'; diff --git a/web-console/src/views/load-data-view/info-messages.tsx b/web-console/src/views/load-data-view/info-messages.tsx index ad9e96667db5..8ec021c68ead 100644 --- a/web-console/src/views/load-data-view/info-messages.tsx +++ b/web-console/src/views/load-data-view/info-messages.tsx @@ -38,9 +38,7 @@ export const ConnectMessage = React.memo(function ConnectMessage(props: ConnectM

Druid ingests raw data and converts it into a custom,{' '} - - indexed format - {' '} + indexed format{' '} that is optimized for analytic queries.

{inlineMode ? ( @@ -67,10 +65,10 @@ export const ParserMessage = React.memo(function ParserMessage() {

If you have nested data, you can ingest it as{' '} - json{' '} + json{' '} dimensions.

- + ); @@ -91,7 +89,7 @@ export const TimestampMessage = React.memo(function TimestampMessage() { combine them into one by selecting Expression and defining a transform expression.

- + ); @@ -103,12 +101,12 @@ export const TransformMessage = React.memo(function TransformMessage() {

Druid can perform per-row{' '} - + transforms {' '} of column values allowing you to create new derived columns or alter existing column.

- +
); @@ -120,9 +118,9 @@ export const FilterMessage = React.memo(function FilterMessage() {

Druid can filter out unwanted data by applying per-row{' '} - filters. + filters.

- +
); @@ -148,7 +146,7 @@ export const SchemaMessage = React.memo(function SchemaMessage(props: SchemaMess change the type, click on the column header.

)} - + ); @@ -164,7 +162,7 @@ export const PartitionMessage = React.memo(function PartitionMessage() { Primary partitioning), and each time chunk contains one or more segments ( Secondary partitioning).

- + ); @@ -175,7 +173,7 @@ export const TuningMessage = React.memo(function TuningMessage() {

Fine tune how Druid will ingest data.

- +
); @@ -201,7 +199,7 @@ export const SpecMessage = React.memo(function SpecMessage() { you modify any values in previous sections, this spec will automatically update.

Submit the spec to begin loading data into Druid.

- + ); diff --git a/web-console/src/views/load-data-view/load-data-view.tsx b/web-console/src/views/load-data-view/load-data-view.tsx index 5e907a242674..9e87520a8eba 100644 --- a/web-console/src/views/load-data-view/load-data-view.tsx +++ b/web-console/src/views/load-data-view/load-data-view.tsx @@ -1006,7 +1006,7 @@ export class LoadDataView extends React.PureComponent If you do not see your source of raw data here, you can try to ingest it by submitting a{' '} - + JSON task or supervisor spec . @@ -1707,7 +1707,7 @@ export class LoadDataView extends React.PureComponent @@ -2377,12 +2377,12 @@ export class LoadDataView extends React.PureComponent Select whether or not you want to set an explicit list of{' '} dimensions {' '} and{' '} - + metrics . Explicitly setting dimensions and metrics can lead to better compression and @@ -2437,7 +2437,7 @@ export class LoadDataView extends React.PureComponent

If you enable{' '} - + roll-up , Druid will try to pre-aggregate data before indexing it to conserve storage. @@ -2446,12 +2446,12 @@ export class LoadDataView extends React.PureComponent

If you enable rollup, you must specify which columns are{' '} - + dimensions {' '} (fields you want to group and filter on), and which are{' '} - metrics (fields - you want to aggregate on). + metrics (fields you + want to aggregate on).

} @@ -2708,7 +2708,7 @@ export class LoadDataView extends React.PureComponent documentation @@ -3283,9 +3283,7 @@ export class LoadDataView extends React.PureComponent

For more information refer to the{' '} - + documentation . @@ -3465,7 +3463,7 @@ export class LoadDataView extends React.PureComponent documentation diff --git a/web-console/src/views/sql-data-loader-view/schema-step/column-list/column-list.tsx b/web-console/src/views/sql-data-loader-view/schema-step/column-list/column-list.tsx index e4c7a94c9e95..0b9da6651768 100644 --- a/web-console/src/views/sql-data-loader-view/schema-step/column-list/column-list.tsx +++ b/web-console/src/views/sql-data-loader-view/schema-step/column-list/column-list.tsx @@ -76,7 +76,7 @@ export const ColumnList = function ColumnList(props: ColumnListProps) { aggregated at query time. They are always single Strings, arrays of Strings, single Longs, single Doubles or single Floats.

- + } position="left-bottom" @@ -122,7 +122,7 @@ export const ColumnList = function ColumnList(props: ColumnListProps) { (integers or floats) but can also be stored as complex objects like HyperLogLog sketches or approximate quantile sketches.

- + } position="left-bottom" diff --git a/web-console/src/views/sql-data-loader-view/schema-step/schema-step.tsx b/web-console/src/views/sql-data-loader-view/schema-step/schema-step.tsx index 5f0d24f69b1d..d9a1fdba6acc 100644 --- a/web-console/src/views/sql-data-loader-view/schema-step/schema-step.tsx +++ b/web-console/src/views/sql-data-loader-view/schema-step/schema-step.tsx @@ -900,7 +900,7 @@ export const SchemaStep = function SchemaStep(props: SchemaStepProps) { of a column you can cast it to a specific type. You can do that by clicking on a column header.

- + )} @@ -961,7 +961,7 @@ export const SchemaStep = function SchemaStep(props: SchemaStepProps) { -
+

General info for query-26d490c6-c06d-4cd2-938f-bc5f7f982754 ingesting into "kttm-blank-lines"

diff --git a/web-console/src/views/workbench-view/execution-error-pane/__snapshots__/execution-error-pane.spec.tsx.snap b/web-console/src/views/workbench-view/execution-error-pane/__snapshots__/execution-error-pane.spec.tsx.snap index 9d133e240abf..7fff3b26a3d1 100644 --- a/web-console/src/views/workbench-view/execution-error-pane/__snapshots__/execution-error-pane.spec.tsx.snap +++ b/web-console/src/views/workbench-view/execution-error-pane/__snapshots__/execution-error-pane.spec.tsx.snap @@ -10,7 +10,7 @@ exports[`ExecutionErrorPane matches snapshot 1`] = ` > TooManyWarnings diff --git a/web-console/src/views/workbench-view/input-format-step/input-format-step.tsx b/web-console/src/views/workbench-view/input-format-step/input-format-step.tsx index cfe51d8fc3d9..3586170d63db 100644 --- a/web-console/src/views/workbench-view/input-format-step/input-format-step.tsx +++ b/web-console/src/views/workbench-view/input-format-step/input-format-step.tsx @@ -224,7 +224,7 @@ export const InputFormatStep = React.memo(function InputFormatStep(props: InputF

Ensure that your data appears correctly in a row/column orientation.

- +
Date: Tue, 9 Jul 2024 19:51:04 -0700 Subject: [PATCH 05/12] update doc links --- .../ingestion-spec/ingestion-spec.tsx | 38 +++++++++---------- .../input-source/input-source.tsx | 12 +++--- .../views/load-data-view/info-messages.tsx | 12 +++--- 3 files changed, 31 insertions(+), 31 deletions(-) diff --git a/web-console/src/druid-models/ingestion-spec/ingestion-spec.tsx b/web-console/src/druid-models/ingestion-spec/ingestion-spec.tsx index 3bea288c8c6a..afbdc3922758 100644 --- a/web-console/src/druid-models/ingestion-spec/ingestion-spec.tsx +++ b/web-console/src/druid-models/ingestion-spec/ingestion-spec.tsx @@ -223,13 +223,13 @@ export function getIngestionDocLink(spec: Partial): string { switch (type) { case 'kafka': - return `${getLink('DOCS')}/development/extensions-core/kafka-ingestion`; + return `${getLink('DOCS')}/ingestion/kafka-ingestion`; case 'kinesis': - return `${getLink('DOCS')}/development/extensions-core/kinesis-ingestion`; + return `${getLink('DOCS')}/ingestion/kinesis-ingestion`; default: - return `${getLink('DOCS')}/ingestion/native-batch#input-sources`; + return `${getLink('DOCS')}/ingestion/input-sources`; } } @@ -585,7 +585,7 @@ export function getIoConfigFormFields(ingestionComboType: IngestionComboType): F info: (

Druid connects to raw data through{' '} - + inputSources . You can change your selected inputSource here. @@ -664,7 +664,7 @@ export function getIoConfigFormFields(ingestionComboType: IngestionComboType): F required: true, info: ( <> - + inputSource.baseDir

Specifies the directory to search recursively for files to be ingested.

@@ -786,7 +786,7 @@ export function getIoConfigFormFields(ingestionComboType: IngestionComboType): F <>

JSON array of{' '} - + S3 Objects . @@ -949,7 +949,9 @@ export function getIoConfigFormFields(ingestionComboType: IngestionComboType): F <>

JSON array of{' '} - + S3 Objects . @@ -1023,7 +1025,11 @@ export function getIoConfigFormFields(ingestionComboType: IngestionComboType): F <>

JSON array of{' '} - + Google Cloud Storage Objects . @@ -1090,11 +1096,7 @@ export function getIoConfigFormFields(ingestionComboType: IngestionComboType): F placeholder: 'kafka_broker_host:9092', info: ( <> - + consumerProperties

@@ -1140,11 +1142,7 @@ export function getIoConfigFormFields(ingestionComboType: IngestionComboType): F defaultValue: {}, info: ( <> - + consumerProperties

A map of properties to be passed to the Kafka consumer.

@@ -1883,7 +1881,9 @@ export function getSecondaryPartitionRelatedFormFields(

This should be the first dimension in your schema which would make it first in the sort order. As{' '} - + Partitioning and sorting are best friends!

diff --git a/web-console/src/druid-models/input-source/input-source.tsx b/web-console/src/druid-models/input-source/input-source.tsx index e20ce1b8ca90..4479150227d3 100644 --- a/web-console/src/druid-models/input-source/input-source.tsx +++ b/web-console/src/druid-models/input-source/input-source.tsx @@ -264,9 +264,7 @@ export const INPUT_SOURCE_FIELDS: Field[] = [ required: true, info: ( <> - - baseDir - + baseDir

Specifies the directory to search recursively for files to be ingested.

), @@ -344,7 +342,7 @@ export const INPUT_SOURCE_FIELDS: Field[] = [ <>

JSON array of{' '} - + S3 Objects . @@ -406,7 +404,7 @@ export const INPUT_SOURCE_FIELDS: Field[] = [ <>

JSON array of{' '} - + S3 Objects . @@ -480,7 +478,9 @@ export const INPUT_SOURCE_FIELDS: Field[] = [ <>

JSON array of{' '} - + Google Cloud Storage Objects . diff --git a/web-console/src/views/load-data-view/info-messages.tsx b/web-console/src/views/load-data-view/info-messages.tsx index 8ec021c68ead..e3a5e7f3993b 100644 --- a/web-console/src/views/load-data-view/info-messages.tsx +++ b/web-console/src/views/load-data-view/info-messages.tsx @@ -89,7 +89,7 @@ export const TimestampMessage = React.memo(function TimestampMessage() { combine them into one by selecting Expression and defining a transform expression.

- + ); @@ -106,7 +106,7 @@ export const TransformMessage = React.memo(function TransformMessage() { {' '} of column values allowing you to create new derived columns or alter existing column.

- + ); @@ -120,7 +120,7 @@ export const FilterMessage = React.memo(function FilterMessage() { Druid can filter out unwanted data by applying per-row{' '} filters.

- + ); @@ -162,7 +162,7 @@ export const PartitionMessage = React.memo(function PartitionMessage() { Primary partitioning), and each time chunk contains one or more segments ( Secondary partitioning).

- + ); @@ -173,7 +173,7 @@ export const TuningMessage = React.memo(function TuningMessage() {

Fine tune how Druid will ingest data.

- +
); @@ -199,7 +199,7 @@ export const SpecMessage = React.memo(function SpecMessage() { you modify any values in previous sections, this spec will automatically update.

Submit the spec to begin loading data into Druid.

- + ); From 94655c29d35a1039595c211e8f09d47968b2f6b1 Mon Sep 17 00:00:00 2001 From: Vadim Ogievetsky Date: Tue, 9 Jul 2024 20:00:40 -0700 Subject: [PATCH 06/12] more doc links --- .../overlord-dynamic-config.tsx | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/web-console/src/druid-models/overlord-dynamic-config/overlord-dynamic-config.tsx b/web-console/src/druid-models/overlord-dynamic-config/overlord-dynamic-config.tsx index 63ebb9381915..3c4060e5621e 100644 --- a/web-console/src/druid-models/overlord-dynamic-config/overlord-dynamic-config.tsx +++ b/web-console/src/druid-models/overlord-dynamic-config/overlord-dynamic-config.tsx @@ -20,6 +20,8 @@ import { Callout } from '@blueprintjs/core'; import React from 'react'; import type { Field } from '../../components'; +import { ExternalLink } from '../../components'; +import { getLink } from '../../links'; import { deepGet, oneOf } from '../../utils'; export interface OverlordDynamicConfig { @@ -92,6 +94,11 @@ export const OVERLORD_DYNAMIC_CONFIG_FIELDS: Field[] = [ "datasource2": ["host3:port"] }`} +

+ + Learn more + +

), }, @@ -131,6 +138,11 @@ export const OVERLORD_DYNAMIC_CONFIG_FIELDS: Field[] = [ } }`} +

+ + Learn more + +

), }, From e0d694bde5c4277b9b7f2be201c0ccc4bf53416b Mon Sep 17 00:00:00 2001 From: Vadim Ogievetsky Date: Tue, 9 Jul 2024 21:06:00 -0700 Subject: [PATCH 07/12] extract getClusterCapacity --- web-console/src/console-application.tsx | 4 +++- .../src/druid-models/execution/execution.ts | 4 ++++ web-console/src/helpers/capabilities.ts | 14 ++++++------ .../helpers/execution/sql-task-execution.ts | 5 ++--- .../sql-data-loader-view.tsx | 18 ++++++++++----- .../workbench-view/query-tab/query-tab.tsx | 7 +++--- .../views/workbench-view/workbench-view.tsx | 22 +++++++++++++++---- 7 files changed, 50 insertions(+), 24 deletions(-) diff --git a/web-console/src/console-application.tsx b/web-console/src/console-application.tsx index 4cb735fdc267..6acefa40e7f0 100644 --- a/web-console/src/console-application.tsx +++ b/web-console/src/console-application.tsx @@ -29,7 +29,7 @@ import type { Filter } from 'react-table'; import type { HeaderActiveTab } from './components'; import { HeaderBar, Loader } from './components'; import type { DruidEngine, QueryWithContext } from './druid-models'; -import { Capabilities } from './helpers'; +import { Capabilities, maybeGetClusterCapacity } from './helpers'; import { stringToTableFilters, tableFiltersToString } from './react-table'; import { AppToaster } from './singletons'; import { compact, localStorageGetJson, LocalStorageKeys, QueryManager } from './utils'; @@ -318,6 +318,7 @@ export class ConsoleApplication extends React.PureComponent< queryEngines={queryEngines} allowExplain goToTask={this.goToTasksWithTaskId} + getClusterCapacity={maybeGetClusterCapacity} />, 'thin', ); @@ -332,6 +333,7 @@ export class ConsoleApplication extends React.PureComponent< goToQuery={this.goToQuery} goToTask={this.goToTasksWithTaskId} goToTaskGroup={this.goToTasksWithTaskGroupId} + getClusterCapacity={maybeGetClusterCapacity} />, ); }; diff --git a/web-console/src/druid-models/execution/execution.ts b/web-console/src/druid-models/execution/execution.ts index 4ed90b9c3c20..dcb5b2d1b939 100644 --- a/web-console/src/druid-models/execution/execution.ts +++ b/web-console/src/druid-models/execution/execution.ts @@ -18,6 +18,7 @@ import { Column, QueryResult, SqlExpression, SqlQuery, SqlWithQuery } from '@druid-toolkit/query'; +import { maybeGetClusterCapacity } from '../../helpers'; import { deepGet, deleteKeys, @@ -196,6 +197,9 @@ export class Execution { static USE_TASK_REPORTS = true; static INLINE_DATASOURCE_MARKER = '__query_select'; + static getClusterCapacity: (() => Promise) | undefined = + maybeGetClusterCapacity; + static validAsyncState(status: string | undefined): status is AsyncState { return oneOf(status, 'ACCEPTED', 'RUNNING', 'FINISHED', 'FAILED'); } diff --git a/web-console/src/helpers/capabilities.ts b/web-console/src/helpers/capabilities.ts index ce8509072f2a..4b10a49c9652 100644 --- a/web-console/src/helpers/capabilities.ts +++ b/web-console/src/helpers/capabilities.ts @@ -38,7 +38,7 @@ export interface CapabilitiesValue { multiStageQuery: boolean; coordinator: boolean; overlord: boolean; - clusterCapacity?: number; + maxTaskSlots?: number; } export class Capabilities { @@ -54,7 +54,7 @@ export class Capabilities { private readonly multiStageQuery: boolean; private readonly coordinator: boolean; private readonly overlord: boolean; - private readonly clusterCapacity?: number; + private readonly maxTaskSlots?: number; static async detectQueryType(): Promise { // Check SQL endpoint @@ -171,7 +171,7 @@ export class Capabilities { return new Capabilities({ ...capabilities.valueOf(), - clusterCapacity: capacity.totalTaskSlots, + maxTaskSlots: capacity.totalTaskSlots, }); } @@ -180,7 +180,7 @@ export class Capabilities { this.multiStageQuery = value.multiStageQuery; this.coordinator = value.coordinator; this.overlord = value.overlord; - this.clusterCapacity = value.clusterCapacity; + this.maxTaskSlots = value.maxTaskSlots; } public valueOf(): CapabilitiesValue { @@ -189,7 +189,7 @@ export class Capabilities { multiStageQuery: this.multiStageQuery, coordinator: this.coordinator, overlord: this.overlord, - clusterCapacity: this.clusterCapacity, + maxTaskSlots: this.maxTaskSlots, }; } @@ -263,8 +263,8 @@ export class Capabilities { return this.hasSql() || this.hasOverlordAccess(); } - public getClusterCapacity(): number | undefined { - return this.clusterCapacity; + public getMaxTaskSlots(): number | undefined { + return this.maxTaskSlots; } } Capabilities.FULL = new Capabilities({ diff --git a/web-console/src/helpers/execution/sql-task-execution.ts b/web-console/src/helpers/execution/sql-task-execution.ts index 7f4cf6f72280..ca7c0485bd4a 100644 --- a/web-console/src/helpers/execution/sql-task-execution.ts +++ b/web-console/src/helpers/execution/sql-task-execution.ts @@ -23,7 +23,6 @@ import type { AsyncStatusResponse, MsqTaskPayloadResponse, QueryContext } from ' import { Execution } from '../../druid-models'; import { Api } from '../../singletons'; import { deepGet, DruidError, IntermediateQueryState, QueryManager } from '../../utils'; -import { maybeGetClusterCapacity } from '../capacity'; // some executionMode has to be set on the /druid/v2/sql/statements API function ensureExecutionModeIsSet(context: QueryContext | undefined): QueryContext { @@ -226,8 +225,8 @@ export async function getTaskExecution( } } - if (execution.hasPotentiallyStuckStage()) { - const capacityInfo = await maybeGetClusterCapacity(); + if (Execution.getClusterCapacity && execution.hasPotentiallyStuckStage()) { + const capacityInfo = await Execution.getClusterCapacity(); if (capacityInfo) { execution = execution.changeCapacityInfo(capacityInfo); } diff --git a/web-console/src/views/sql-data-loader-view/sql-data-loader-view.tsx b/web-console/src/views/sql-data-loader-view/sql-data-loader-view.tsx index 686b5b4df717..6cc00957b8d4 100644 --- a/web-console/src/views/sql-data-loader-view/sql-data-loader-view.tsx +++ b/web-console/src/views/sql-data-loader-view/sql-data-loader-view.tsx @@ -23,14 +23,19 @@ import { SqlQuery, SqlTable } from '@druid-toolkit/query'; import type { JSX } from 'react'; import React, { useState } from 'react'; -import type { ExternalConfig, QueryContext, QueryWithContext } from '../../druid-models'; +import type { + CapacityInfo, + ExternalConfig, + QueryContext, + QueryWithContext, +} from '../../druid-models'; import { Execution, externalConfigToIngestQueryPattern, ingestQueryPatternToQuery, } from '../../druid-models'; import type { Capabilities } from '../../helpers'; -import { maybeGetClusterCapacity, submitTaskQuery } from '../../helpers'; +import { submitTaskQuery } from '../../helpers'; import { useLocalStorageState } from '../../hooks'; import { AppToaster } from '../../singletons'; import { deepDelete, LocalStorageKeys } from '../../utils'; @@ -59,12 +64,13 @@ export interface SqlDataLoaderViewProps { goToQuery(queryWithContext: QueryWithContext): void; goToTask(taskId: string): void; goToTaskGroup(taskGroupId: string): void; + getClusterCapacity: (() => Promise) | undefined; } export const SqlDataLoaderView = React.memo(function SqlDataLoaderView( props: SqlDataLoaderViewProps, ) { - const { capabilities, goToQuery, goToTask, goToTaskGroup } = props; + const { capabilities, goToQuery, goToTask, goToTaskGroup, getClusterCapacity } = props; const [alertElement, setAlertElement] = useState(); const [externalConfigStep, setExternalConfigStep] = useState>({}); const [content, setContent] = useLocalStorageState( @@ -146,7 +152,7 @@ export const SqlDataLoaderView = React.memo(function SqlDataLoaderView( return; } - const clusterCapacity = capabilities.getClusterCapacity(); + const clusterCapacity = capabilities.getMaxTaskSlots(); let effectiveContext = queryContext || {}; if ( typeof effectiveContext.maxNumTasks === 'undefined' && @@ -155,7 +161,7 @@ export const SqlDataLoaderView = React.memo(function SqlDataLoaderView( effectiveContext = { ...effectiveContext, maxNumTasks: clusterCapacity }; } - const capacityInfo = await maybeGetClusterCapacity(); + const capacityInfo = await getClusterCapacity?.(); const effectiveMaxNumTasks = effectiveContext.maxNumTasks ?? 2; @@ -178,7 +184,7 @@ export const SqlDataLoaderView = React.memo(function SqlDataLoaderView( }} extraCallout={ setContent({ ...content, queryContext })} minimal diff --git a/web-console/src/views/workbench-view/query-tab/query-tab.tsx b/web-console/src/views/workbench-view/query-tab/query-tab.tsx index 69234b584543..1c7aebdff690 100644 --- a/web-console/src/views/workbench-view/query-tab/query-tab.tsx +++ b/web-console/src/views/workbench-view/query-tab/query-tab.tsx @@ -27,11 +27,10 @@ import SplitterLayout from 'react-splitter-layout'; import { useStore } from 'zustand'; import { Loader, QueryErrorPane } from '../../../components'; -import type { DruidEngine, LastExecution, QueryContext } from '../../../druid-models'; +import type { CapacityInfo, DruidEngine, LastExecution, QueryContext } from '../../../druid-models'; import { Execution, WorkbenchQuery } from '../../../druid-models'; import { executionBackgroundStatusCheck, - maybeGetClusterCapacity, reattachTaskExecution, submitTaskQuery, } from '../../../helpers'; @@ -82,6 +81,7 @@ export interface QueryTabProps { runMoreMenu: JSX.Element; clusterCapacity: number | undefined; goToTask(taskId: string): void; + getClusterCapacity: (() => Promise) | undefined; } export const QueryTab = React.memo(function QueryTab(props: QueryTabProps) { @@ -97,6 +97,7 @@ export const QueryTab = React.memo(function QueryTab(props: QueryTabProps) { runMoreMenu, clusterCapacity, goToTask, + getClusterCapacity, } = props; const [alertElement, setAlertElement] = useState(); @@ -336,7 +337,7 @@ export const QueryTab = React.memo(function QueryTab(props: QueryTabProps) { ? effectiveQuery.makePreview() : effectiveQuery.setMaxNumTasksIfUnset(clusterCapacity); - const capacityInfo = await maybeGetClusterCapacity(); + const capacityInfo = await getClusterCapacity?.(); const effectiveMaxNumTasks = effectiveQuery.queryContext.maxNumTasks ?? 2; if (capacityInfo && capacityInfo.availableTaskSlots < effectiveMaxNumTasks) { diff --git a/web-console/src/views/workbench-view/workbench-view.tsx b/web-console/src/views/workbench-view/workbench-view.tsx index 625c6c514c6d..ca7e4f10fac1 100644 --- a/web-console/src/views/workbench-view/workbench-view.tsx +++ b/web-console/src/views/workbench-view/workbench-view.tsx @@ -26,7 +26,13 @@ import copy from 'copy-to-clipboard'; import React from 'react'; import { SpecDialog, StringInputDialog } from '../../dialogs'; -import type { DruidEngine, Execution, QueryWithContext, TabEntry } from '../../druid-models'; +import type { + CapacityInfo, + DruidEngine, + Execution, + QueryWithContext, + TabEntry, +} from '../../druid-models'; import { guessDataSourceNameFromInputSource, WorkbenchQuery } from '../../druid-models'; import type { Capabilities } from '../../helpers'; import { convertSpecToSql, getSpecDatasourceName, getTaskExecution } from '../../helpers'; @@ -87,6 +93,7 @@ export interface WorkbenchViewProps { queryEngines: DruidEngine[]; allowExplain: boolean; goToTask(taskId: string): void; + getClusterCapacity: (() => Promise) | undefined; } export interface WorkbenchViewState { @@ -628,8 +635,14 @@ export class WorkbenchView extends React.PureComponent {allowExplain && From c22248b016cf3ad5dd1a140ed2355f1069bbf13a Mon Sep 17 00:00:00 2001 From: Vadim Ogievetsky Date: Tue, 9 Jul 2024 22:52:51 -0700 Subject: [PATCH 08/12] update snapsohts --- .../__snapshots__/header-bar.spec.tsx.snap | 2 +- .../__snapshots__/home-view.spec.tsx.snap | 30 +++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/web-console/src/components/header-bar/__snapshots__/header-bar.spec.tsx.snap b/web-console/src/components/header-bar/__snapshots__/header-bar.spec.tsx.snap index 6c7cf34cb70f..a189bf5f9546 100644 --- a/web-console/src/components/header-bar/__snapshots__/header-bar.spec.tsx.snap +++ b/web-console/src/components/header-bar/__snapshots__/header-bar.spec.tsx.snap @@ -205,8 +205,8 @@ exports[`HeaderBar matches snapshot 1`] = ` Date: Wed, 10 Jul 2024 11:09:48 -0700 Subject: [PATCH 09/12] allow submit suspended --- docs/ingestion/supervisor.md | 1 + .../views/load-data-view/load-data-view.scss | 7 ++ .../views/load-data-view/load-data-view.tsx | 117 ++++++++++-------- 3 files changed, 76 insertions(+), 49 deletions(-) diff --git a/docs/ingestion/supervisor.md b/docs/ingestion/supervisor.md index 9320c39a02a8..70939adb633d 100644 --- a/docs/ingestion/supervisor.md +++ b/docs/ingestion/supervisor.md @@ -42,6 +42,7 @@ The following table outlines the high-level configuration options for a supervis |`spec.dataSchema`|Object|The schema for the indexing task to use during ingestion. See [`dataSchema`](../ingestion/ingestion-spec.md#dataschema) for more information.|Yes| |`spec.ioConfig`|Object|The I/O configuration object to define the connection and I/O-related settings for the supervisor and indexing tasks.|Yes| |`spec.tuningConfig`|Object|The tuning configuration object to define performance-related settings for the supervisor and indexing tasks.|No| +|`suspended`|Boolean|Puts the supervisor in a suspended state|No| ### I/O configuration diff --git a/web-console/src/views/load-data-view/load-data-view.scss b/web-console/src/views/load-data-view/load-data-view.scss index 8532313b10bd..d5248c5190db 100644 --- a/web-console/src/views/load-data-view/load-data-view.scss +++ b/web-console/src/views/load-data-view/load-data-view.scss @@ -273,6 +273,7 @@ $actual-icon-height: 400px; } .control { + position: relative; grid-area: ctrl; overflow: auto; padding: 0 5px; @@ -320,4 +321,10 @@ $actual-icon-height: 400px; .parse-metadata { border-top: 1px solid $gray1; } + + .suspended-switch { + position: absolute; + bottom: 0; + right: 5px; + } } diff --git a/web-console/src/views/load-data-view/load-data-view.tsx b/web-console/src/views/load-data-view/load-data-view.tsx index 9e87520a8eba..60a5901ecdce 100644 --- a/web-console/src/views/load-data-view/load-data-view.tsx +++ b/web-console/src/views/load-data-view/load-data-view.tsx @@ -3473,75 +3473,94 @@ export class LoadDataView extends React.PureComponent )} + {isStreamingSpec(spec) && ( + this.updateSpec({ ...spec, suspended: !spec.suspended })} + /> + )}
- {!isEmptyIngestionSpec(spec) && ( + {isStreamingSpec(spec) ? ( +
); } - private readonly handleSubmit = async () => { - const { goToSupervisor, goToTasks } = this.props; + private readonly handleSubmitSupervisor = async () => { + const { goToSupervisor } = this.props; const { spec, submitting } = this.state; if (submitting) return; this.setState({ submitting: true }); - if (isStreamingSpec(spec)) { - try { - await Api.instance.post('/druid/indexer/v1/supervisor', spec); - } catch (e) { - AppToaster.show({ - message: `Failed to submit supervisor: ${getDruidErrorMessage(e)}`, - intent: Intent.DANGER, - }); - this.setState({ submitting: false }); - return; - } - + try { + await Api.instance.post('/druid/indexer/v1/supervisor', spec); + } catch (e) { AppToaster.show({ - message: 'Supervisor submitted successfully. Going to task view...', - intent: Intent.SUCCESS, + message: `Failed to submit supervisor: ${getDruidErrorMessage(e)}`, + intent: Intent.DANGER, }); + this.setState({ submitting: false }); + return; + } - setTimeout(() => { - goToSupervisor(getSpecDatasourceName(spec)); - }, 1000); - } else { - let taskResp: any; - try { - taskResp = await Api.instance.post('/druid/indexer/v1/task', spec); - } catch (e) { - AppToaster.show({ - message: `Failed to submit task: ${getDruidErrorMessage(e)}`, - intent: Intent.DANGER, - }); - this.setState({ submitting: false }); - return; - } + AppToaster.show({ + message: 'Supervisor submitted successfully. Going to Supervisors view...', + intent: Intent.SUCCESS, + }); + + setTimeout(() => { + goToSupervisor(getSpecDatasourceName(spec)); + }, 1000); + }; + + private readonly handleSubmitTask = async () => { + const { goToTasks } = this.props; + const { spec, submitting } = this.state; + if (submitting) return; + this.setState({ submitting: true }); + let taskResp: any; + try { + taskResp = await Api.instance.post('/druid/indexer/v1/task', spec); + } catch (e) { AppToaster.show({ - message: 'Task submitted successfully. Going to task view...', - intent: Intent.SUCCESS, + message: `Failed to submit task: ${getDruidErrorMessage(e)}`, + intent: Intent.DANGER, }); - - setTimeout(() => { - goToTasks(taskResp.data.task); - }, 1000); + this.setState({ submitting: false }); + return; } + + AppToaster.show({ + message: 'Task submitted successfully. Going to Tasks view...', + intent: Intent.SUCCESS, + }); + + setTimeout(() => { + goToTasks(taskResp.data.task); + }, 1000); }; } From dd30f3c1fb9e398779ea56264f5bbb7cd41f12c4 Mon Sep 17 00:00:00 2001 From: Vadim Ogievetsky Date: Wed, 10 Jul 2024 11:27:48 -0700 Subject: [PATCH 10/12] some renaming --- .../supervisor-history-panel.tsx | 4 +- .../compaction-history-dialog.tsx | 4 +- .../src/dialogs/diff-dialog/diff-dialog.tsx | 54 ++++++++++--------- .../dialogs/history-dialog/history-dialog.tsx | 4 +- 4 files changed, 35 insertions(+), 31 deletions(-) diff --git a/web-console/src/components/supervisor-history-panel/supervisor-history-panel.tsx b/web-console/src/components/supervisor-history-panel/supervisor-history-panel.tsx index e3fd38b91612..89af2a0d5f10 100644 --- a/web-console/src/components/supervisor-history-panel/supervisor-history-panel.tsx +++ b/web-console/src/components/supervisor-history-panel/supervisor-history-panel.tsx @@ -87,8 +87,8 @@ export const SupervisorHistoryPanel = React.memo(function SupervisorHistoryPanel ({ label: s.version, value: s.spec }))} - initLeftIndex={diffIndex + 1} - initRightIndex={diffIndex} + initOldIndex={diffIndex + 1} + initNewIndex={diffIndex} onClose={() => setDiffIndex(-1)} /> )} diff --git a/web-console/src/dialogs/compaction-history-dialog/compaction-history-dialog.tsx b/web-console/src/dialogs/compaction-history-dialog/compaction-history-dialog.tsx index cb886d0483da..45234c68ad28 100644 --- a/web-console/src/dialogs/compaction-history-dialog/compaction-history-dialog.tsx +++ b/web-console/src/dialogs/compaction-history-dialog/compaction-history-dialog.tsx @@ -135,8 +135,8 @@ export const CompactionHistoryDialog = React.memo(function CompactionHistoryDial ({ label: s.auditTime, value: s.compactionConfig }))} - initLeftIndex={diffIndex + 1} - initRightIndex={diffIndex} + initOldIndex={diffIndex + 1} + initNewIndex={diffIndex} onClose={() => setDiffIndex(-1)} /> )} diff --git a/web-console/src/dialogs/diff-dialog/diff-dialog.tsx b/web-console/src/dialogs/diff-dialog/diff-dialog.tsx index bb42f1db8471..011bbfa5d380 100644 --- a/web-console/src/dialogs/diff-dialog/diff-dialog.tsx +++ b/web-console/src/dialogs/diff-dialog/diff-dialog.tsx @@ -44,43 +44,47 @@ export interface DiffVersion { export interface DiffDialogProps { title?: string; - left?: unknown; - right?: unknown; + onClose(): void; + + // Single value + oldValue?: unknown; + newValue?: unknown; + + // Versions versions?: DiffVersion[]; - initLeftIndex?: number; - initRightIndex?: number; - onClose: () => void; + initOldIndex?: number; + initNewIndex?: number; } export const DiffDialog = React.memo(function DiffDialog(props: DiffDialogProps) { - const { title, left, right, versions, initLeftIndex, initRightIndex, onClose } = props; + const { title, oldValue, newValue, versions, initOldIndex, initNewIndex, onClose } = props; - const [leftIndex, setLeftIndex] = useState(initLeftIndex || 0); - const [rightIndex, setRightIndex] = useState(initRightIndex || 0); + const [leftIndex, setLeftIndex] = useState(initOldIndex || 0); + const [rightIndex, setRightIndex] = useState(initNewIndex || 0); - let leftValue: string; - let rightValue: string; + let oldValueString: string; + let newValueString: string; if (Array.isArray(versions)) { if (versions.length) { - const leftVersion = versions[leftIndex].value; - const rightVersion = versions[rightIndex].value; - if (typeof leftVersion === 'string' && typeof rightVersion === 'string') { - leftValue = leftVersion; - rightValue = rightVersion; + const oldVersionValue = versions[leftIndex].value; + const newVersionValue = versions[rightIndex].value; + if (typeof oldVersionValue === 'string' && typeof newVersionValue === 'string') { + oldValueString = oldVersionValue; + newValueString = newVersionValue; } else { - leftValue = JSONBig.stringify(leftVersion, undefined, 2); - rightValue = JSONBig.stringify(rightVersion, undefined, 2); + oldValueString = JSONBig.stringify(oldVersionValue, undefined, 2); + newValueString = JSONBig.stringify(newVersionValue, undefined, 2); } } else { - leftValue = rightValue = 'Nothing to diff'; + oldValueString = newValueString = 'Nothing to diff'; } } else { - if (typeof left === 'string' && typeof right === 'string') { - leftValue = left; - rightValue = right; + if (typeof oldValue === 'string' && typeof newValue === 'string') { + oldValueString = oldValue; + newValueString = newValue; } else { - leftValue = JSONBig.stringify(left, undefined, 2); - rightValue = JSONBig.stringify(right, undefined, 2); + oldValueString = JSONBig.stringify(oldValue, undefined, 2); + newValueString = JSONBig.stringify(newValue, undefined, 2); } } @@ -121,8 +125,8 @@ export const DiffDialog = React.memo(function DiffDialog(props: DiffDialogProps) )}
setDiffIndex(-1)} /> ); From efe391033708948a2a426b294ded6ed27b4fb8f7 Mon Sep 17 00:00:00 2001 From: Vadim Ogievetsky Date: Wed, 10 Jul 2024 12:22:07 -0700 Subject: [PATCH 11/12] diff with current --- .../supervisor-history-panel.tsx | 4 +- .../supervisor-table-action-dialog.tsx | 2 +- .../ingestion-spec/ingestion-spec.tsx | 11 +-- .../views/load-data-view/load-data-view.tsx | 68 ++++++++++++++++++- 4 files changed, 69 insertions(+), 16 deletions(-) diff --git a/web-console/src/components/supervisor-history-panel/supervisor-history-panel.tsx b/web-console/src/components/supervisor-history-panel/supervisor-history-panel.tsx index 89af2a0d5f10..0e1043a56818 100644 --- a/web-console/src/components/supervisor-history-panel/supervisor-history-panel.tsx +++ b/web-console/src/components/supervisor-history-panel/supervisor-history-panel.tsx @@ -52,9 +52,7 @@ export const SupervisorHistoryPanel = React.memo(function SupervisorHistoryPanel const resp = await Api.instance.get( `/druid/indexer/v1/supervisor/${Api.encodePath(supervisorId)}/history`, ); - return resp.data.map((vs: SupervisorHistoryEntry) => - deepSet(vs, 'spec', cleanSpec(vs.spec, true)), - ); + return resp.data.map((vs: SupervisorHistoryEntry) => deepSet(vs, 'spec', cleanSpec(vs.spec))); }, }); diff --git a/web-console/src/dialogs/supervisor-table-action-dialog/supervisor-table-action-dialog.tsx b/web-console/src/dialogs/supervisor-table-action-dialog/supervisor-table-action-dialog.tsx index 5e3d9e500288..44ef05d5d59f 100644 --- a/web-console/src/dialogs/supervisor-table-action-dialog/supervisor-table-action-dialog.tsx +++ b/web-console/src/dialogs/supervisor-table-action-dialog/supervisor-table-action-dialog.tsx @@ -93,7 +93,7 @@ export const SupervisorTableActionDialog = React.memo(function SupervisorTableAc {activeTab === 'spec' && ( cleanSpec(x, true)} + transform={cleanSpec} downloadFilename={`supervisor-payload-${supervisorId}.json`} /> )} diff --git a/web-console/src/druid-models/ingestion-spec/ingestion-spec.tsx b/web-console/src/druid-models/ingestion-spec/ingestion-spec.tsx index afbdc3922758..d51fd34e901a 100644 --- a/web-console/src/druid-models/ingestion-spec/ingestion-spec.tsx +++ b/web-console/src/druid-models/ingestion-spec/ingestion-spec.tsx @@ -478,16 +478,9 @@ export function normalizeSpec(spec: Partial): IngestionSpec { /** * Make sure that any extra junk in the spec other than 'type', 'spec', and 'context' is removed * @param spec - the spec to clean - * @param allowSuspended - allow keeping 'suspended' also */ -export function cleanSpec( - spec: Partial, - allowSuspended?: boolean, -): Partial { - return allowKeys( - spec, - ['type', 'spec', 'context'].concat(allowSuspended ? ['suspended'] : []) as any, - ) as IngestionSpec; +export function cleanSpec(spec: Partial): Partial { + return allowKeys(spec, ['type', 'spec', 'context', 'suspended']) as IngestionSpec; } export function upgradeSpec(spec: any, yolo = false): Partial { diff --git a/web-console/src/views/load-data-view/load-data-view.tsx b/web-console/src/views/load-data-view/load-data-view.tsx index 60a5901ecdce..0dd8cde078f2 100644 --- a/web-console/src/views/load-data-view/load-data-view.tsx +++ b/web-console/src/views/load-data-view/load-data-view.tsx @@ -56,7 +56,7 @@ import { Loader, PopoverText, } from '../../components'; -import { AlertDialog, AsyncActionDialog } from '../../dialogs'; +import { AlertDialog, AsyncActionDialog, DiffDialog } from '../../dialogs'; import type { ArrayMode, DimensionSpec, @@ -146,6 +146,7 @@ import { deepMove, deepSet, deepSetMulti, + deleteKeys, EMPTY_ARRAY, EMPTY_OBJECT, filterMap, @@ -427,6 +428,8 @@ export interface LoadDataViewState { // for final step existingDatasources?: string[]; submitting: boolean; + currentSpecToDiff?: Partial; + currentSpecToDiffLoading: boolean; } export class LoadDataView extends React.PureComponent { @@ -478,6 +481,7 @@ export class LoadDataView extends React.PureComponent )} + {isStreamingSpec(spec) && initSupervisorId && ( +
@@ -3505,6 +3523,18 @@ export class LoadDataView extends React.PureComponent )}
+ {currentSpecToDiff && ( + { + this.setState({ + currentSpecToDiff: undefined, + }); + }} + /> + )} ); } @@ -3563,4 +3593,36 @@ export class LoadDataView extends React.PureComponent { + const { initSupervisorId } = this.props; + const { currentSpecToDiffLoading } = this.state; + if (!initSupervisorId || currentSpecToDiffLoading) return; + + this.setState({ + currentSpecToDiffLoading: true, + }); + + let spec: Partial; + try { + spec = cleanSpec( + (await Api.instance.get(`/druid/indexer/v1/supervisor/${Api.encodePath(initSupervisorId)}`)) + .data, + ); + } catch (e) { + this.setState({ + currentSpecToDiffLoading: false, + }); + AppToaster.show({ + message: `Could not load current spec: ${e.message}`, + intent: Intent.DANGER, + }); + return; + } + + this.setState({ + currentSpecToDiffLoading: false, + currentSpecToDiff: spec, + }); + }; } From 1c814b497eefc32b3178dfc16b72bfee5cafc8a7 Mon Sep 17 00:00:00 2001 From: Vadim Ogievetsky Date: Wed, 10 Jul 2024 15:27:01 -0700 Subject: [PATCH 12/12] Do delta --- web-console/src/helpers/spec-conversion.ts | 4 +- .../views/load-data-view/load-data-view.tsx | 81 ++++++++----------- .../views/workbench-view/workbench-view.tsx | 2 +- 3 files changed, 37 insertions(+), 50 deletions(-) diff --git a/web-console/src/helpers/spec-conversion.ts b/web-console/src/helpers/spec-conversion.ts index 7e7673c73842..2c621f2466c2 100644 --- a/web-console/src/helpers/spec-conversion.ts +++ b/web-console/src/helpers/spec-conversion.ts @@ -46,8 +46,8 @@ import { } from '../druid-models'; import { deepGet, filterMap, nonEmptyArray, oneOf } from '../utils'; -export function getSpecDatasourceName(spec: Partial): string { - return deepGet(spec, 'spec.dataSchema.dataSource') || 'unknown_datasource'; +export function getSpecDatasourceName(spec: Partial): string | undefined { + return deepGet(spec, 'spec.dataSchema.dataSource'); } function convertFilter(filter: any): SqlExpression { diff --git a/web-console/src/views/load-data-view/load-data-view.tsx b/web-console/src/views/load-data-view/load-data-view.tsx index 0dd8cde078f2..555ba6f4a09a 100644 --- a/web-console/src/views/load-data-view/load-data-view.tsx +++ b/web-console/src/views/load-data-view/load-data-view.tsx @@ -428,8 +428,8 @@ export interface LoadDataViewState { // for final step existingDatasources?: string[]; submitting: boolean; - currentSpecToDiff?: Partial; - currentSpecToDiffLoading: boolean; + currentSupervisorSpec?: Partial; + showDiffWithCurrent: boolean; } export class LoadDataView extends React.PureComponent { @@ -481,7 +481,7 @@ export class LoadDataView extends React.PureComponent('/druid/coordinator/v1/datasources')) @@ -3417,14 +3419,25 @@ export class LoadDataView extends React.PureComponent | undefined; + const supervisorId = getSpecDatasourceName(spec); + if (isStreamingSpec(spec) && supervisorId) { + try { + currentSupervisorSpec = cleanSpec( + (await Api.instance.get(`/druid/indexer/v1/supervisor/${Api.encodePath(supervisorId)}`)) + .data, + ); + } catch {} + } + this.setState({ existingDatasources, + currentSupervisorSpec, }); } renderSpecStep() { - const { initSupervisorId } = this.props; - const { spec, existingDatasources, submitting, currentSpecToDiffLoading, currentSpecToDiff } = + const { spec, existingDatasources, submitting, currentSupervisorSpec, showDiffWithCurrent } = this.state; const issueWithSpec = getIssueWithSpec(spec); const datasource = deepGet(spec, 'spec.dataSchema.dataSource'); @@ -3479,11 +3492,14 @@ export class LoadDataView extends React.PureComponent )} - {isStreamingSpec(spec) && initSupervisorId && ( + {isStreamingSpec(spec) && currentSupervisorSpec && (
- {currentSpecToDiff && ( + {showDiffWithCurrent && currentSupervisorSpec && ( { this.setState({ - currentSpecToDiff: undefined, + showDiffWithCurrent: false, }); }} /> @@ -3561,9 +3577,12 @@ export class LoadDataView extends React.PureComponent { - goToSupervisor(getSpecDatasourceName(spec)); - }, 1000); + const supervisorId = getSpecDatasourceName(spec); + if (supervisorId) { + setTimeout(() => { + goToSupervisor(supervisorId); + }, 1000); + } }; private readonly handleSubmitTask = async () => { @@ -3593,36 +3612,4 @@ export class LoadDataView extends React.PureComponent { - const { initSupervisorId } = this.props; - const { currentSpecToDiffLoading } = this.state; - if (!initSupervisorId || currentSpecToDiffLoading) return; - - this.setState({ - currentSpecToDiffLoading: true, - }); - - let spec: Partial; - try { - spec = cleanSpec( - (await Api.instance.get(`/druid/indexer/v1/supervisor/${Api.encodePath(initSupervisorId)}`)) - .data, - ); - } catch (e) { - this.setState({ - currentSpecToDiffLoading: false, - }); - AppToaster.show({ - message: `Could not load current spec: ${e.message}`, - intent: Intent.DANGER, - }); - return; - } - - this.setState({ - currentSpecToDiffLoading: false, - currentSpecToDiff: spec, - }); - }; } diff --git a/web-console/src/views/workbench-view/workbench-view.tsx b/web-console/src/views/workbench-view/workbench-view.tsx index ca7e4f10fac1..9fbba23ca1e1 100644 --- a/web-console/src/views/workbench-view/workbench-view.tsx +++ b/web-console/src/views/workbench-view/workbench-view.tsx @@ -395,7 +395,7 @@ export class WorkbenchView extends React.PureComponent this.setState({ specDialogOpen: false })}