Skip to content

Commit

Permalink
feat: add database and schema names to dataset option (apache#25569)
Browse files Browse the repository at this point in the history
Co-authored-by: Sonia <[email protected]>
  • Loading branch information
soniagtm and Sonia authored Oct 19, 2023
1 parent dfff3c1 commit 39ad322
Show file tree
Hide file tree
Showing 5 changed files with 179 additions and 85 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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,
};
})
Expand All @@ -83,6 +91,7 @@ const DatasetSelect = ({ onChange, value }: DatasetSelectProps) => {
options={loadDatasetOptions}
onChange={onChange}
notFoundContent={t('No compatible datasets found')}
placeholder={t('Select a dataset')}
/>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 = (
Expand Down
136 changes: 136 additions & 0 deletions superset-frontend/src/features/datasets/DatasetSelectLabel/index.tsx
Original file line number Diff line number Diff line change
@@ -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>&nbsp;- {item.schema}</StyledLabelDetail>
)}
</StyledDetailWrapper>
</StyledLabelContainer>
</Tooltip>
);
76 changes: 14 additions & 62 deletions superset-frontend/src/pages/ChartCreation/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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, {
Expand All @@ -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;
Expand Down Expand Up @@ -169,43 +165,13 @@ 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
};
}
.tooltip-description {
margin-top: ${theme.gridUnit * 2}px;
display: -webkit-box;
-webkit-line-clamp: 20;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
&&&& .ant-select-selection-item {
padding-left: ${theme.gridUnit * 3}px;
}
`}
`;

const StyledLabel = styled.span`
${({ theme }) => `
position: absolute;
left: ${theme.gridUnit * 3}px;
right: ${theme.gridUnit * 3}px;
overflow: hidden;
text-overflow: ellipsis;
`}
`;

const StyledStepTitle = styled.span`
${({
theme: {
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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,
Expand All @@ -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 {
Expand Down

0 comments on commit 39ad322

Please sign in to comment.