Web console: misc bug fixes (#14216)

* fixing little things

* clear edit columns when switching to SQL tab

* updated snapshots
This commit is contained in:
Vadim Ogievetsky 2023-05-05 15:45:19 -07:00 committed by GitHub
parent 6ca3fb9b08
commit 4c15e978f1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 240 additions and 20 deletions

View File

@ -2154,9 +2154,9 @@ export function issueWithSampleData(
if (firstData === '{') {
return (
<>
This data looks like regular JSON object. For Druid to parse a text file it must have one
row per event. Maybe look at{' '}
<ExternalLink href="http://ndjson.org/">newline delimited JSON</ExternalLink> instead.
This data looks like multi-line formatted JSON object. For Druid to parse a text file it
must have one row per event. Consider reformatting your data as{' '}
<ExternalLink href="http://ndjson.org/">newline delimited JSON</ExternalLink>.
</>
);
}
@ -2165,8 +2165,8 @@ export function issueWithSampleData(
return (
<>
This data looks like a multi-line JSON array. For Druid to parse a text file it must have
one row per event. Maybe look at{' '}
<ExternalLink href="http://ndjson.org/">newline delimited JSON</ExternalLink> instead.
one row per event. Consider reformatting your data as{' '}
<ExternalLink href="http://ndjson.org/">newline delimited JSON</ExternalLink>.
</>
);
}

View File

@ -100,8 +100,8 @@ export const ReactTablePagination = React.memo(function ReactTablePagination(
const start = page * pageSize + 1;
let end = page * pageSize + pageSize;
if (nonEmptyArray(sortedData)) {
end = Math.min(end, page * pageSize + sortedData.length);
if (nonEmptyArray(sortedData) && (page === 0 || sortedData.length > pageSize)) {
end = Math.min(end, sortedData.length);
}
let pageInfo = 'Showing';
@ -110,7 +110,7 @@ export const ReactTablePagination = React.memo(function ReactTablePagination(
} else {
pageInfo += '...';
}
if (ofText && Array.isArray(sortedData)) {
if (ofText && nonEmptyArray(sortedData)) {
pageInfo += ` ${ofText} ${formatInteger(sortedData.length)}`;
}

View File

@ -171,7 +171,10 @@ export async function getProxyOverlordModules(): Promise<string[]> {
throw new Error(getDruidErrorMessage(e));
}
return statusResp.data.modules.map((m: any) => m.artifact);
const { modules } = statusResp.data;
if (!Array.isArray(modules)) throw new Error('unexpected result from overlord/status');
return modules.map((m: any) => m.artifact);
}
export async function postToSampler(

View File

@ -159,7 +159,148 @@ exports[`LoadDataView matches snapshot batch 1`] = `
<div
className="ingestion-cards"
>
<React.Fragment />
<React.Fragment>
<Blueprint4.Card
className="ingestion-card"
elevation={1}
interactive={true}
onClick={[Function]}
>
<img
alt="Ingestion tile for index_parallel:s3"
src="/some/base_url/assets/s3.png"
/>
<p>
Amazon S3
</p>
</Blueprint4.Card>
<Blueprint4.Card
className="ingestion-card"
elevation={1}
interactive={true}
onClick={[Function]}
>
<img
alt="Ingestion tile for index_parallel:azure"
src="/some/base_url/assets/azure.png"
/>
<p>
Azure Data Lake
</p>
</Blueprint4.Card>
<Blueprint4.Card
className="ingestion-card"
elevation={1}
interactive={true}
onClick={[Function]}
>
<img
alt="Ingestion tile for index_parallel:google"
src="/some/base_url/assets/google.png"
/>
<p>
Google Cloud Storage
</p>
</Blueprint4.Card>
<Blueprint4.Card
className="ingestion-card"
elevation={1}
interactive={true}
onClick={[Function]}
>
<img
alt="Ingestion tile for index_parallel:hdfs"
src="/some/base_url/assets/hdfs.png"
/>
<p>
HDFS
</p>
</Blueprint4.Card>
<Blueprint4.Card
className="ingestion-card"
elevation={1}
interactive={true}
onClick={[Function]}
>
<img
alt="Ingestion tile for index_parallel:druid"
src="/some/base_url/assets/druid.png"
/>
<p>
Reindex from Druid
</p>
</Blueprint4.Card>
<Blueprint4.Card
className="ingestion-card"
elevation={1}
interactive={true}
onClick={[Function]}
>
<img
alt="Ingestion tile for index_parallel:http"
src="/some/base_url/assets/http.png"
/>
<p>
HTTP(s)
</p>
</Blueprint4.Card>
<Blueprint4.Card
className="ingestion-card"
elevation={1}
interactive={true}
onClick={[Function]}
>
<img
alt="Ingestion tile for index_parallel:local"
src="/some/base_url/assets/local.png"
/>
<p>
Local disk
</p>
</Blueprint4.Card>
<Blueprint4.Card
className="ingestion-card"
elevation={1}
interactive={true}
onClick={[Function]}
>
<img
alt="Ingestion tile for index_parallel:inline"
src="/some/base_url/assets/inline.png"
/>
<p>
Paste data
</p>
</Blueprint4.Card>
<Blueprint4.Card
className="ingestion-card"
elevation={1}
interactive={true}
onClick={[Function]}
>
<img
alt="Ingestion tile for example"
src="/some/base_url/assets/example.png"
/>
<p>
Example data
</p>
</Blueprint4.Card>
</React.Fragment>
<Blueprint4.Card
className="ingestion-card"
elevation={1}
interactive={true}
onClick={[Function]}
>
<img
alt="Ingestion tile for other"
src="/some/base_url/assets/other.png"
/>
<p>
Other
</p>
</Blueprint4.Card>
</div>
</div>
<div
@ -336,7 +477,64 @@ exports[`LoadDataView matches snapshot streaming 1`] = `
<div
className="ingestion-cards"
>
<React.Fragment />
<React.Fragment>
<Blueprint4.Card
className="ingestion-card"
elevation={1}
interactive={true}
onClick={[Function]}
>
<img
alt="Ingestion tile for kafka"
src="/some/base_url/assets/kafka.png"
/>
<p>
Apache Kafka
</p>
</Blueprint4.Card>
<Blueprint4.Card
className="ingestion-card"
elevation={1}
interactive={true}
onClick={[Function]}
>
<img
alt="Ingestion tile for kinesis"
src="/some/base_url/assets/kinesis.png"
/>
<p>
Amazon Kinesis
</p>
</Blueprint4.Card>
<Blueprint4.Card
className="ingestion-card"
elevation={1}
interactive={true}
onClick={[Function]}
>
<img
alt="Ingestion tile for azure-event-hubs"
src="/some/base_url/assets/azure-event-hubs.png"
/>
<p>
Azure Event Hub
</p>
</Blueprint4.Card>
</React.Fragment>
<Blueprint4.Card
className="ingestion-card"
elevation={1}
interactive={true}
onClick={[Function]}
>
<img
alt="Ingestion tile for other"
src="/some/base_url/assets/other.png"
/>
<p>
Other
</p>
</Blueprint4.Card>
</div>
</div>
<div

View File

@ -498,10 +498,10 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
overlordModules = await getProxyOverlordModules();
} catch (e) {
AppToaster.show({
message: `Failed to get overlord modules: ${e.message}`,
message: `Failed to get the list of loaded modules from the overlord: ${e.message}`,
intent: Intent.DANGER,
});
this.setState({ overlordModules: [] });
this.setState({ overlordModules: undefined });
return;
}
@ -810,9 +810,10 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
disabled?: boolean,
): JSX.Element | undefined {
const { overlordModules, selectedComboType, spec } = this.state;
if (!overlordModules) return;
const requiredModule = getRequiredModule(comboType);
const goodToGo = !disabled && (!requiredModule || overlordModules.includes(requiredModule));
const goodToGo =
!disabled &&
(!requiredModule || !overlordModules || overlordModules.includes(requiredModule));
return (
<Card
@ -1124,7 +1125,7 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
<p>
Please make sure that the
<Code>&quot;{requiredModule}&quot;</Code> extension is included in the{' '}
<Code>loadList</Code>.
<Code>druid.extensions.loadList</Code>.
</p>
<p>
For more information please refer to the{' '}

View File

@ -299,12 +299,30 @@ export const SchemaStep = function SchemaStep(props: SchemaStepProps) {
onQueryStringChange(parsedQuery.apply(queryAction).toString());
});
const handleModeSelect = (newMode: Mode) => {
if (newMode === 'sql' && editorColumn) {
if (editorColumn.dirty) {
AppToaster.show({
message:
'Please save or discard the changes in the column editor before switching to the SQL tab.',
intent: Intent.WARNING,
});
return;
}
setEditorColumn(undefined);
}
setMode(newMode);
};
const handleColumnSelect = usePermanentCallback((index: number) => {
if (!ingestQueryPattern) return;
if (editorColumn?.dirty) {
AppToaster.show({
message: 'Please save or discard the changes in the column editor.',
message:
'Please save or discard the changes in the column editor before switching columns.',
intent: Intent.WARNING,
});
return;
@ -697,20 +715,20 @@ export const SchemaStep = function SchemaStep(props: SchemaStepProps) {
text="Table"
disabled={!ingestQueryPattern}
active={effectiveMode === 'table'}
onClick={() => setMode('table')}
onClick={() => handleModeSelect('table')}
/>
<Button
icon={IconNames.LIST_COLUMNS}
text="List"
disabled={!ingestQueryPattern}
active={effectiveMode === 'list'}
onClick={() => setMode('list')}
onClick={() => handleModeSelect('list')}
/>
<Button
icon={IconNames.APPLICATION}
text="SQL"
active={effectiveMode === 'sql'}
onClick={() => setMode('sql')}
onClick={() => handleModeSelect('sql')}
/>
</ButtonGroup>
{enableAnalyze && ingestQueryPattern?.metrics && (