diff --git a/web-console/src/components/auto-form/__snapshots__/auto-form.spec.tsx.snap b/web-console/src/components/auto-form/__snapshots__/auto-form.spec.tsx.snap index 99c41445d10..c9714345d11 100644 --- a/web-console/src/components/auto-form/__snapshots__/auto-form.spec.tsx.snap +++ b/web-console/src/components/auto-form/__snapshots__/auto-form.spec.tsx.snap @@ -5,7 +5,7 @@ exports[`auto-form snapshot matches snapshot 1`] = ` class="auto-form" >
} - position="left-bottom" - > - - - ) - } + info={field.info ?
{field.info}
: undefined} > {this.renderFieldInput(field)} - + ); }; diff --git a/web-console/src/components/form-group-with-info/__snapshots__/form-group-with-info.spec.tsx.snap b/web-console/src/components/form-group-with-info/__snapshots__/form-group-with-info.spec.tsx.snap new file mode 100644 index 00000000000..e73b8fb1fbd --- /dev/null +++ b/web-console/src/components/form-group-with-info/__snapshots__/form-group-with-info.spec.tsx.snap @@ -0,0 +1,50 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`form group with info matches snapshot 1`] = ` +
+ +
+ Some buttons and stuff +
+
+`; diff --git a/web-console/src/components/form-group-with-info/form-group-with-info.scss b/web-console/src/components/form-group-with-info/form-group-with-info.scss new file mode 100644 index 00000000000..ddde9ec3dd7 --- /dev/null +++ b/web-console/src/components/form-group-with-info/form-group-with-info.scss @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +.form-group-with-info { + .bp3-form-content { + position: relative; + + & > .bp3-popover-wrapper { + position: absolute; + right: 0; + top: 7px; + } + } +} diff --git a/web-console/src/components/form-group-with-info/form-group-with-info.spec.tsx b/web-console/src/components/form-group-with-info/form-group-with-info.spec.tsx new file mode 100644 index 00000000000..6d354241798 --- /dev/null +++ b/web-console/src/components/form-group-with-info/form-group-with-info.spec.tsx @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { render } from '@testing-library/react'; +import React from 'react'; + +import { FormGroupWithInfo } from './form-group-with-info'; + +describe('form group with info', () => { + it('matches snapshot', () => { + const formGroupWithInfo = ( + Information is gold}> + Some buttons and stuff + + ); + + const { container } = render(formGroupWithInfo); + expect(container.firstChild).toMatchSnapshot(); + }); +}); diff --git a/web-console/src/components/form-group-with-info/form-group-with-info.tsx b/web-console/src/components/form-group-with-info/form-group-with-info.tsx new file mode 100644 index 00000000000..791a02a17ff --- /dev/null +++ b/web-console/src/components/form-group-with-info/form-group-with-info.tsx @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { FormGroup, Icon, Popover } from '@blueprintjs/core'; +import { IconNames } from '@blueprintjs/icons'; +import React from 'react'; + +import './form-group-with-info.scss'; + +export interface FormGroupWithInfoProps { + label?: React.ReactNode; + info?: JSX.Element | string; + inlineInfo?: boolean; + children?: React.ReactNode; +} + +export const FormGroupWithInfo = React.memo(function FormGroupWithInfo( + props: FormGroupWithInfoProps, +) { + const { label, info, inlineInfo, children } = props; + + const popover = ( + + + + ); + + return ( + + {children} + {info && inlineInfo && popover} + + ); +}); 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 f055cc5a2d1..6b899838449 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 @@ -171,7 +171,7 @@ exports[`header bar matches snapshot 1`] = ` />
+ diff --git a/web-console/src/dialogs/history-dialog/history-dialog.tsx b/web-console/src/dialogs/history-dialog/history-dialog.tsx index 017a55fb9a1..9c82a894e8e 100644 --- a/web-console/src/dialogs/history-dialog/history-dialog.tsx +++ b/web-console/src/dialogs/history-dialog/history-dialog.tsx @@ -16,7 +16,8 @@ * limitations under the License. */ -import { Card, Dialog, Divider } from '@blueprintjs/core'; +import { Card, Classes, Dialog, Divider } from '@blueprintjs/core'; +import classNames from 'classnames'; import React, { ReactNode } from 'react'; import { JsonCollapse } from '../../components'; @@ -25,54 +26,50 @@ import './history-dialog.scss'; interface HistoryDialogProps { historyRecords: any[]; - children?: ReactNode; + buttons?: ReactNode; } export const HistoryDialog = React.memo(function HistoryDialog(props: HistoryDialogProps) { - function renderRecords() { - const { children, historyRecords } = props; - let content; - if (historyRecords.length === 0) { - content =
No history records available
; - } else { - content = ( - <> - History -
- {historyRecords.map((record, i) => { - const auditInfo = record.auditInfo; - const auditTime = record.auditTime; - const formattedTime = auditTime.replace('T', ' ').substring(0, auditTime.length - 5); + const { buttons, historyRecords } = props; - return ( -
- -
- Change - {formattedTime} -
- -

{auditInfo.comment === '' ? '(No comment)' : auditInfo.comment}

- -
-
- ); - })} -
- - ); - } - return ( -
- {content} - {children} -
+ let content; + if (historyRecords.length === 0) { + content =
No history records available
; + } else { + content = ( + <> + History +
+ {historyRecords.map((record, i) => { + const auditInfo = record.auditInfo; + const auditTime = record.auditTime; + const formattedTime = auditTime.replace('T', ' ').substring(0, auditTime.length - 5); + + return ( +
+ +
+ Change + {formattedTime} +
+ +

{auditInfo.comment === '' ? '(No comment)' : auditInfo.comment}

+ +
+
+ ); + })} +
+ ); } return ( - {renderRecords()} +
{content}
+
+
{buttons}
+
); }); diff --git a/web-console/src/dialogs/overlord-dynamic-config-dialog/__snapshots__/overload-dynamic-config-dialog.spec.tsx.snap b/web-console/src/dialogs/overlord-dynamic-config-dialog/__snapshots__/overload-dynamic-config-dialog.spec.tsx.snap index c5b2326cb34..ad3005a2a3c 100644 --- a/web-console/src/dialogs/overlord-dynamic-config-dialog/__snapshots__/overload-dynamic-config-dialog.spec.tsx.snap +++ b/web-console/src/dialogs/overlord-dynamic-config-dialog/__snapshots__/overload-dynamic-config-dialog.spec.tsx.snap @@ -58,7 +58,7 @@ exports[`overload dynamic config matches snapshot 1`] = ` Edit the overlord dynamic configuration on the fly. For more information please refer to the
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 b46e8637130..d3192398acc 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 @@ -24,6 +24,7 @@ import React from 'react'; import { AutoForm, ExternalLink } from '../../components'; import { AppToaster } from '../../singletons/toaster'; import { getDruidErrorMessage, QueryManager } from '../../utils'; +import { DRUID_DOCS_VERSION } from '../../variables'; import { SnitchDialog } from '../snitch-dialog/snitch-dialog'; import './overlord-dynamic-config-dialog.scss'; @@ -129,7 +130,9 @@ export class OverlordDynamicConfigDialog extends React.PureComponent<

Edit the overlord dynamic configuration on the fly. 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 1aaf1ca9dec..42920ceffe9 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 @@ -58,7 +58,7 @@ exports[`retention dialog 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 documentation diff --git a/web-console/src/dialogs/retention-dialog/retention-dialog.tsx b/web-console/src/dialogs/retention-dialog/retention-dialog.tsx index 478375771b3..80a0ec84dde 100644 --- a/web-console/src/dialogs/retention-dialog/retention-dialog.tsx +++ b/web-console/src/dialogs/retention-dialog/retention-dialog.tsx @@ -23,6 +23,7 @@ import React from 'react'; import { RuleEditor } from '../../components'; import { QueryManager } from '../../utils'; +import { DRUID_DOCS_VERSION } from '../../variables'; import { SnitchDialog } from '../snitch-dialog/snitch-dialog'; import './retention-dialog.scss'; @@ -183,7 +184,7 @@ export class RetentionDialog extends React.PureComponent< 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/dialogs/snitch-dialog/snitch-dialog.tsx b/web-console/src/dialogs/snitch-dialog/snitch-dialog.tsx index a28ce0f60b0..fd41b12c6d0 100644 --- a/web-console/src/dialogs/snitch-dialog/snitch-dialog.tsx +++ b/web-console/src/dialogs/snitch-dialog/snitch-dialog.tsx @@ -116,13 +116,15 @@ export class SnitchDialog extends React.PureComponent -

+ Back -
- + } + /> ); } diff --git a/web-console/src/entry.scss b/web-console/src/entry.scss index 8e36392ac5a..2f2709cf23d 100644 --- a/web-console/src/entry.scss +++ b/web-console/src/entry.scss @@ -62,17 +62,3 @@ svg { margin-bottom: 0; } } - -.bp3-form-group { - .bp3-form-content { - position: relative; - - & > .bp3-popover-wrapper { - position: absolute; - right: 0; - top: 7px; - } - } -} - -// Some SplitterLayout globals diff --git a/web-console/src/utils/ingestion-spec.tsx b/web-console/src/utils/ingestion-spec.tsx index af9d30ab2fa..8550c88abdc 100644 --- a/web-console/src/utils/ingestion-spec.tsx +++ b/web-console/src/utils/ingestion-spec.tsx @@ -21,6 +21,7 @@ import React from 'react'; import { Field } from '../components/auto-form/auto-form'; import { ExternalLink } from '../components/external-link/external-link'; +import { DRUID_DOCS_VERSION } from '../variables'; import { BASIC_TIME_FORMATS, @@ -162,13 +163,13 @@ export function getIngestionDocLink(spec: IngestionSpec): string { switch (type) { case 'kafka': - return 'https://druid.apache.org/docs/latest/development/extensions-core/kafka-ingestion.html'; + return `https://druid.apache.org/docs/${DRUID_DOCS_VERSION}/development/extensions-core/kafka-ingestion.html`; case 'kinesis': - return 'https://druid.apache.org/docs/latest/development/extensions-core/kinesis-ingestion.html'; + return `https://druid.apache.org/docs/${DRUID_DOCS_VERSION}/development/extensions-core/kinesis-ingestion.html`; default: - return 'https://druid.apache.org/docs/latest/ingestion/native-batch.html#firehoses'; + return `https://druid.apache.org/docs/${DRUID_DOCS_VERSION}/ingestion/native-batch.html#firehoses`; } } @@ -306,7 +307,9 @@ const PARSE_SPEC_FORM_FIELDS: Field[] = [

The parser used to parse the data.

For more information see{' '} - + the documentation . @@ -573,7 +576,9 @@ const FLATTEN_FIELD_FORM_FIELDS: Field[] = [ info: ( <> Specify a flatten{' '} - + expression . @@ -618,7 +623,9 @@ const TRANSFORM_FORM_FIELDS: Field[] = [ info: ( <> A valid Druid{' '} - + expression . @@ -820,7 +827,9 @@ export function getIoConfigFormFields(ingestionComboType: IngestionComboType): F info: (

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

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

@@ -888,7 +899,9 @@ export function getIoConfigFormFields(ingestionComboType: IngestionComboType): F suggestions: ['*', '*.json', '*.json.gz', '*.csv', '*.tsv'], info: ( <> - + firehose.filter

@@ -963,7 +976,9 @@ export function getIoConfigFormFields(ingestionComboType: IngestionComboType): F info: (

The{' '} - + filter {' '} to apply to the data as part of querying. @@ -1026,7 +1041,9 @@ export function getIoConfigFormFields(ingestionComboType: IngestionComboType): F <>

JSON array of{' '} - + Google Blobs . @@ -1057,7 +1074,9 @@ export function getIoConfigFormFields(ingestionComboType: IngestionComboType): F required: true, info: ( <> - + consumerProperties

@@ -1079,7 +1098,9 @@ export function getIoConfigFormFields(ingestionComboType: IngestionComboType): F defaultValue: {}, info: ( <> - + consumerProperties

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

@@ -1129,7 +1150,9 @@ export function getIoConfigFormFields(ingestionComboType: IngestionComboType): F info: ( <> The Amazon Kinesis stream endpoint for a region. You can find a list of endpoints{' '} - + here . diff --git a/web-console/src/variables.ts b/web-console/src/variables.ts index 2fa5894aae8..7af017578cb 100644 --- a/web-console/src/variables.ts +++ b/web-console/src/variables.ts @@ -19,13 +19,16 @@ export const LEGACY_COORDINATOR_CONSOLE = '/index.html'; export const LEGACY_OVERLORD_CONSOLE = '/console.html'; +// This is set to the latest available version and should be updated to the next version before release +export const DRUID_DOCS_VERSION = '0.16.0-incubating'; + export const DRUID_WEBSITE = 'https://druid.apache.org'; export const DRUID_GITHUB = 'https://github.com/apache/druid'; -export const DRUID_DOCS = 'https://druid.apache.org/docs/latest'; -export const DRUID_DOCS_SQL = 'https://druid.apache.org/docs/latest/querying/sql.html'; -export const DRUID_DOCS_RUNE = 'https://druid.apache.org/docs/latest/querying/querying.html'; +export const DRUID_DOCS = `https://druid.apache.org/docs/${DRUID_DOCS_VERSION}`; +export const DRUID_DOCS_SQL = `https://druid.apache.org/docs/${DRUID_DOCS_VERSION}/querying/sql.html`; +export const DRUID_DOCS_RUNE = `https://druid.apache.org/docs/${DRUID_DOCS_VERSION}/querying/querying.html`; export const DRUID_COMMUNITY = 'https://druid.apache.org/community/'; export const DRUID_USER_GROUP = 'https://groups.google.com/forum/#!forum/druid-user'; export const DRUID_ASF_SLACK = 'https://druid.apache.org/community/join-slack'; export const DRUID_DEVELOPER_GROUP = 'https://lists.apache.org/list.html?dev@druid.apache.org'; -export const DRUID_DOCS_API = 'https://druid.apache.org/docs/latest/operations/api-reference.html'; +export const DRUID_DOCS_API = `https://druid.apache.org/docs/${DRUID_DOCS_VERSION}/operations/api-reference.html`; diff --git a/web-console/src/views/load-data-view/learn-more/__snapshots__/learn-more.spec.tsx.snap b/web-console/src/views/load-data-view/learn-more/__snapshots__/learn-more.spec.tsx.snap index ab8a6d68087..635af92498e 100644 --- a/web-console/src/views/load-data-view/learn-more/__snapshots__/learn-more.spec.tsx.snap +++ b/web-console/src/views/load-data-view/learn-more/__snapshots__/learn-more.spec.tsx.snap @@ -5,7 +5,7 @@ exports[`learn more matches snapshot 1`] = ` class="learn-more" >
diff --git a/web-console/src/views/load-data-view/learn-more/learn-more.spec.tsx b/web-console/src/views/load-data-view/learn-more/learn-more.spec.tsx index 67d45836fdf..3c013ff5a24 100644 --- a/web-console/src/views/load-data-view/learn-more/learn-more.spec.tsx +++ b/web-console/src/views/load-data-view/learn-more/learn-more.spec.tsx @@ -23,9 +23,7 @@ import { LearnMore } from './learn-more'; describe('learn more', () => { it('matches snapshot', () => { - const learnMore = ( - - ); + const learnMore = ; const { container } = render(learnMore); expect(container.firstChild).toMatchSnapshot(); 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 21b57b9a789..6244034c96a 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 @@ -88,7 +88,7 @@ bottom: 0; left: 0; content: ''; - border: 2px solid #48aff0; + border: 2px solid #008adc; border-radius: 2px; } @@ -195,7 +195,7 @@ left: 0; right: 0; content: ''; - border: 2px solid #ff5d10; + border: 2px solid #008adc; border-radius: 2px; } @@ -208,7 +208,7 @@ } &.used { - background: rgba(24, 201, 201, 0.5); + background: rgba(99, 129, 137, 0.5); } } @@ -218,7 +218,7 @@ } &.used { - background: rgba(24, 201, 201, 0.15); + background: rgba(99, 129, 137, 0.15); } } } @@ -243,12 +243,6 @@ } } - .apply-button-bar { - .revert { - margin-left: 15px; - } - } - .next-bar { grid-area: next; text-align: right; @@ -268,19 +262,19 @@ padding: 10px; border-radius: 2px; margin-bottom: 15px; + } - .control-buttons { - position: relative; + .control-buttons { + position: relative; - .bp3-button { - margin-right: 15px; - } + .bp3-button { + margin-right: 15px; + } - .cancel { - position: absolute; - right: 0; - margin-right: 0; - } + .right { + position: absolute; + right: 0; + margin-right: 0; } } 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 5156ec3abbe..c7a16ee5506 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 @@ -31,6 +31,8 @@ import { Icon, IconName, Intent, + Menu, + MenuItem, Popover, Switch, TextArea, @@ -49,6 +51,7 @@ import { JsonInput, Loader, } from '../../components'; +import { FormGroupWithInfo } from '../../components/form-group-with-info/form-group-with-info'; import { AsyncActionDialog } from '../../dialogs'; import { AppToaster } from '../../singletons/toaster'; import { UrlBaser } from '../../singletons/url-baser'; @@ -140,6 +143,7 @@ import { SampleStrategy, } from '../../utils/sampler'; import { computeFlattenPathsForData } from '../../utils/spec-utils'; +import { DRUID_DOCS_VERSION } from '../../variables'; import { ExamplePicker } from './example-picker/example-picker'; import { FilterTable, filterTableSelectedColumnName } from './filter-table/filter-table'; @@ -555,7 +559,7 @@ export class LoadDataView extends React.PureComponent +