feat: add database and schema names to dataset option (#25569)
Co-authored-by: Sonia <sonia.gautam@agoda.com>
This commit is contained in:
parent
dfff3c1cba
commit
39ad3226c7
|
|
@ -16,16 +16,19 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import React, { useCallback, useMemo, ReactNode } from 'react';
|
||||
import rison from 'rison';
|
||||
import { t } from '@superset-ui/core';
|
||||
import { t, JsonResponse } from '@superset-ui/core';
|
||||
import { AsyncSelect } from 'src/components';
|
||||
import {
|
||||
ClientErrorObject,
|
||||
getClientErrorObject,
|
||||
} from 'src/utils/getClientErrorObject';
|
||||
import { cachedSupersetGet } from 'src/utils/cachedSupersetGet';
|
||||
import { datasetToSelectOption } from './utils';
|
||||
import {
|
||||
Dataset,
|
||||
DatasetSelectLabel,
|
||||
} from 'src/features/datasets/DatasetSelectLabel';
|
||||
|
||||
interface DatasetSelectProps {
|
||||
onChange: (value: { label: string; value: number }) => void;
|
||||
|
|
@ -49,24 +52,29 @@ const DatasetSelect = ({ onChange, value }: DatasetSelectProps) => {
|
|||
page: number,
|
||||
pageSize: number,
|
||||
) => {
|
||||
const searchColumn = 'table_name';
|
||||
const query = rison.encode({
|
||||
filters: [{ col: searchColumn, opr: 'ct', value: search }],
|
||||
columns: ['id', 'table_name', 'database.database_name', 'schema'],
|
||||
filters: [{ col: 'table_name', opr: 'ct', value: search }],
|
||||
page,
|
||||
page_size: pageSize,
|
||||
order_column: searchColumn,
|
||||
order_column: 'table_name',
|
||||
order_direction: 'asc',
|
||||
});
|
||||
return cachedSupersetGet({
|
||||
endpoint: `/api/v1/dataset/?q=${query}`,
|
||||
})
|
||||
.then(response => {
|
||||
const data: {
|
||||
.then((response: JsonResponse) => {
|
||||
const list: {
|
||||
customLabel: ReactNode;
|
||||
label: string;
|
||||
value: string | number;
|
||||
}[] = response.json.result.map(datasetToSelectOption);
|
||||
}[] = response.json.result.map((item: Dataset) => ({
|
||||
customLabel: DatasetSelectLabel(item),
|
||||
label: item.table_name,
|
||||
value: item.id,
|
||||
}));
|
||||
return {
|
||||
data,
|
||||
data: list,
|
||||
totalCount: response.json.count,
|
||||
};
|
||||
})
|
||||
|
|
@ -83,6 +91,7 @@ const DatasetSelect = ({ onChange, value }: DatasetSelectProps) => {
|
|||
options={loadDatasetOptions}
|
||||
onChange={onChange}
|
||||
notFoundContent={t('No compatible datasets found')}
|
||||
placeholder={t('Select a dataset')}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -82,6 +82,7 @@ import {
|
|||
getFormData,
|
||||
mergeExtraFormData,
|
||||
} from 'src/dashboard/components/nativeFilters/utils';
|
||||
import { DatasetSelectLabel } from 'src/features/datasets/DatasetSelectLabel';
|
||||
import {
|
||||
ALLOW_DEPENDENCIES as TYPES_SUPPORT_DEPENDENCIES,
|
||||
getFiltersConfigModalTestId,
|
||||
|
|
@ -883,7 +884,15 @@ const FiltersConfigForm = (
|
|||
initialValue={
|
||||
datasetDetails
|
||||
? {
|
||||
label: datasetDetails.table_name,
|
||||
label: DatasetSelectLabel({
|
||||
id: datasetDetails.id,
|
||||
table_name: datasetDetails.table_name,
|
||||
schema: datasetDetails.schema,
|
||||
database: {
|
||||
database_name:
|
||||
datasetDetails.database.database_name,
|
||||
},
|
||||
}),
|
||||
value: datasetDetails.id,
|
||||
}
|
||||
: undefined
|
||||
|
|
|
|||
|
|
@ -66,18 +66,6 @@ export const getControlItems = (
|
|||
[],
|
||||
) as CustomControlItem[]) ?? [];
|
||||
|
||||
type DatasetSelectValue = {
|
||||
value: number;
|
||||
label: string;
|
||||
};
|
||||
|
||||
export const datasetToSelectOption = (
|
||||
item: Dataset & { table_name: string },
|
||||
): DatasetSelectValue => ({
|
||||
value: item.id,
|
||||
label: item.table_name,
|
||||
});
|
||||
|
||||
// TODO: add column_types field to Dataset
|
||||
// We return true if column_types is undefined or empty as a precaution against backend failing to return column_types
|
||||
export const hasTemporalColumns = (
|
||||
|
|
|
|||
|
|
@ -0,0 +1,136 @@
|
|||
/**
|
||||
* 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 React from 'react';
|
||||
import { Tooltip } from 'src/components/Tooltip';
|
||||
import { styled, t } from '@superset-ui/core';
|
||||
|
||||
type Database = {
|
||||
database_name: string;
|
||||
};
|
||||
|
||||
export type Dataset = {
|
||||
id: number;
|
||||
table_name: string;
|
||||
datasource_type?: string;
|
||||
schema: string;
|
||||
database: Database;
|
||||
};
|
||||
|
||||
const TooltipContent = styled.div`
|
||||
${({ theme }) => `
|
||||
.tooltip-header {
|
||||
font-size: ${theme.typography.sizes.m}px;
|
||||
font-weight: ${theme.typography.weights.bold};
|
||||
}
|
||||
|
||||
.tooltip-description {
|
||||
margin-top: ${theme.gridUnit * 2}px;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 20;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
`}
|
||||
`;
|
||||
|
||||
const StyledLabelContainer = styled.div`
|
||||
${({ theme }) => `
|
||||
left: ${theme.gridUnit * 3}px;
|
||||
right: ${theme.gridUnit * 3}px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: block;
|
||||
`}
|
||||
`;
|
||||
|
||||
const StyledLabel = styled.span`
|
||||
${({ theme }) => `
|
||||
left: ${theme.gridUnit * 3}px;
|
||||
right: ${theme.gridUnit * 3}px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: block;
|
||||
`}
|
||||
`;
|
||||
|
||||
const StyledDetailWrapper = styled.div`
|
||||
display: grid;
|
||||
grid-template-columns: auto auto;
|
||||
justify-content: start;
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
const StyledLabelDetail = styled.span`
|
||||
${({
|
||||
theme: {
|
||||
typography: { sizes, weights },
|
||||
},
|
||||
}) => `
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
font-size: ${sizes.s}px;
|
||||
font-weight: ${weights.light};
|
||||
line-height: 1.6;
|
||||
`}
|
||||
`;
|
||||
|
||||
const isValidValue = (value: string): boolean =>
|
||||
!['null', 'none'].includes(value.toLowerCase()) && value.trim() !== '';
|
||||
|
||||
export const DatasetSelectLabel = (item: Dataset) => (
|
||||
<Tooltip
|
||||
mouseEnterDelay={0.2}
|
||||
placement="right"
|
||||
title={
|
||||
<TooltipContent>
|
||||
<div className="tooltip-header">
|
||||
{item.table_name && isValidValue(item.table_name)
|
||||
? item.table_name
|
||||
: t('Not defined')}
|
||||
</div>
|
||||
<div className="tooltip-description">
|
||||
<div>
|
||||
{t('Database')}: {item.database.database_name}
|
||||
</div>
|
||||
<div>
|
||||
{t('Schema')}:{' '}
|
||||
{item.schema && isValidValue(item.schema)
|
||||
? item.schema
|
||||
: t('Not defined')}
|
||||
</div>
|
||||
</div>
|
||||
</TooltipContent>
|
||||
}
|
||||
>
|
||||
<StyledLabelContainer>
|
||||
<StyledLabel>
|
||||
{item.table_name && isValidValue(item.table_name)
|
||||
? item.table_name
|
||||
: item.database.database_name}
|
||||
</StyledLabel>
|
||||
<StyledDetailWrapper>
|
||||
<StyledLabelDetail>{item.database.database_name}</StyledLabelDetail>
|
||||
{item.schema && isValidValue(item.schema) && (
|
||||
<StyledLabelDetail> - {item.schema}</StyledLabelDetail>
|
||||
)}
|
||||
</StyledDetailWrapper>
|
||||
</StyledLabelContainer>
|
||||
</Tooltip>
|
||||
);
|
||||
|
|
@ -33,7 +33,6 @@ import { URL_PARAMS } from 'src/constants';
|
|||
import { Link, withRouter, RouteComponentProps } from 'react-router-dom';
|
||||
import Button from 'src/components/Button';
|
||||
import { AsyncSelect, Steps } from 'src/components';
|
||||
import { Tooltip } from 'src/components/Tooltip';
|
||||
import withToasts from 'src/components/MessageToasts/withToasts';
|
||||
|
||||
import VizTypeGallery, {
|
||||
|
|
@ -42,13 +41,10 @@ import VizTypeGallery, {
|
|||
import { findPermission } from 'src/utils/findPermission';
|
||||
import { UserWithPermissionsAndRoles } from 'src/types/bootstrapTypes';
|
||||
import getBootstrapData from 'src/utils/getBootstrapData';
|
||||
|
||||
type Dataset = {
|
||||
id: number;
|
||||
table_name: string;
|
||||
description: string;
|
||||
datasource_type: string;
|
||||
};
|
||||
import {
|
||||
Dataset,
|
||||
DatasetSelectLabel,
|
||||
} from 'src/features/datasets/DatasetSelectLabel';
|
||||
|
||||
export interface ChartCreationProps extends RouteComponentProps {
|
||||
user: UserWithPermissionsAndRoles;
|
||||
|
|
@ -169,40 +165,10 @@ const StyledContainer = styled.div`
|
|||
&&&& .ant-select-selection-placeholder {
|
||||
padding-left: ${theme.gridUnit * 3}px;
|
||||
}
|
||||
`}
|
||||
`;
|
||||
|
||||
const TooltipContent = styled.div<{ hasDescription: boolean }>`
|
||||
${({ theme, hasDescription }) => `
|
||||
.tooltip-header {
|
||||
font-size: ${
|
||||
hasDescription ? theme.typography.sizes.l : theme.typography.sizes.s
|
||||
}px;
|
||||
font-weight: ${
|
||||
hasDescription
|
||||
? theme.typography.weights.bold
|
||||
: theme.typography.weights.normal
|
||||
};
|
||||
&&&& .ant-select-selection-item {
|
||||
padding-left: ${theme.gridUnit * 3}px;
|
||||
}
|
||||
|
||||
.tooltip-description {
|
||||
margin-top: ${theme.gridUnit * 2}px;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 20;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
`}
|
||||
`;
|
||||
|
||||
const StyledLabel = styled.span`
|
||||
${({ theme }) => `
|
||||
position: absolute;
|
||||
left: ${theme.gridUnit * 3}px;
|
||||
right: ${theme.gridUnit * 3}px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
`}
|
||||
`;
|
||||
|
||||
|
|
@ -242,7 +208,6 @@ export class ChartCreation extends React.PureComponent<
|
|||
this.changeDatasource = this.changeDatasource.bind(this);
|
||||
this.changeVizType = this.changeVizType.bind(this);
|
||||
this.gotoSlice = this.gotoSlice.bind(this);
|
||||
this.newLabel = this.newLabel.bind(this);
|
||||
this.loadDatasources = this.loadDatasources.bind(this);
|
||||
this.onVizTypeDoubleClick = this.onVizTypeDoubleClick.bind(this);
|
||||
}
|
||||
|
|
@ -293,28 +258,15 @@ export class ChartCreation extends React.PureComponent<
|
|||
}
|
||||
}
|
||||
|
||||
newLabel(item: Dataset) {
|
||||
return (
|
||||
<Tooltip
|
||||
mouseEnterDelay={1}
|
||||
placement="right"
|
||||
title={
|
||||
<TooltipContent hasDescription={!!item.description}>
|
||||
<div className="tooltip-header">{item.table_name}</div>
|
||||
{item.description && (
|
||||
<div className="tooltip-description">{item.description}</div>
|
||||
)}
|
||||
</TooltipContent>
|
||||
}
|
||||
>
|
||||
<StyledLabel>{item.table_name}</StyledLabel>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
||||
loadDatasources(search: string, page: number, pageSize: number) {
|
||||
const query = rison.encode({
|
||||
columns: ['id', 'table_name', 'description', 'datasource_type'],
|
||||
columns: [
|
||||
'id',
|
||||
'table_name',
|
||||
'datasource_type',
|
||||
'database.database_name',
|
||||
'schema',
|
||||
],
|
||||
filters: [{ col: 'table_name', opr: 'ct', value: search }],
|
||||
page,
|
||||
page_size: pageSize,
|
||||
|
|
@ -332,7 +284,7 @@ export class ChartCreation extends React.PureComponent<
|
|||
}[] = response.json.result.map((item: Dataset) => ({
|
||||
id: item.id,
|
||||
value: `${item.id}__${item.datasource_type}`,
|
||||
customLabel: this.newLabel(item),
|
||||
customLabel: DatasetSelectLabel(item),
|
||||
label: item.table_name,
|
||||
}));
|
||||
return {
|
||||
|
|
|
|||
Loading…
Reference in New Issue