-
Notifications
You must be signed in to change notification settings - Fork 14.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Flow for tables that already have a dataset #22136
Changes from 10 commits
f5b01d5
16f1f6e
d697bbf
73c5950
4281a00
b58e689
8f47e55
8654966
ad13ff4
955ffc0
01f4ffa
f4a42c1
d77263d
0bed85a
5a3f188
11e2409
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -17,12 +17,14 @@ | |||||||||||||||||||||||
* under the License. | ||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||
import React from 'react'; | ||||||||||||||||||||||||
import { supersetTheme, t, styled } from '@superset-ui/core'; | ||||||||||||||||||||||||
import { t, styled, useTheme } from '@superset-ui/core'; | ||||||||||||||||||||||||
import Icons from 'src/components/Icons'; | ||||||||||||||||||||||||
import Alert from 'src/components/Alert'; | ||||||||||||||||||||||||
import Table, { ColumnsType, TableSize } from 'src/components/Table'; | ||||||||||||||||||||||||
import { alphabeticalSort } from 'src/components/Table/sorters'; | ||||||||||||||||||||||||
// @ts-ignore | ||||||||||||||||||||||||
import LOADING_GIF from 'src/assets/images/loading.gif'; | ||||||||||||||||||||||||
import { DatasetObject } from 'src/views/CRUD/data/dataset/AddDataset/types'; | ||||||||||||||||||||||||
import { ITableColumn } from './types'; | ||||||||||||||||||||||||
import MessageContent from './MessageContent'; | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
|
@@ -53,43 +55,51 @@ const HALF = 0.5; | |||||||||||||||||||||||
const MARGIN_MULTIPLIER = 3; | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
const StyledHeader = styled.div<StyledHeaderProps>` | ||||||||||||||||||||||||
${({ theme }) => ` | ||||||||||||||||||||||||
position: ${(props: StyledHeaderProps) => props.position}; | ||||||||||||||||||||||||
margin: ${({ theme }) => theme.gridUnit * MARGIN_MULTIPLIER}px; | ||||||||||||||||||||||||
margin-top: ${({ theme }) => theme.gridUnit * (MARGIN_MULTIPLIER + 1)}px; | ||||||||||||||||||||||||
font-size: ${({ theme }) => theme.gridUnit * 6}px; | ||||||||||||||||||||||||
font-weight: ${({ theme }) => theme.typography.weights.medium}; | ||||||||||||||||||||||||
padding-bottom: ${({ theme }) => theme.gridUnit * MARGIN_MULTIPLIER}px; | ||||||||||||||||||||||||
margin: ${theme.gridUnit * (MARGIN_MULTIPLIER + 1)}px | ||||||||||||||||||||||||
${theme.gridUnit * MARGIN_MULTIPLIER}px | ||||||||||||||||||||||||
${theme.gridUnit * MARGIN_MULTIPLIER}px | ||||||||||||||||||||||||
${theme.gridUnit * (MARGIN_MULTIPLIER + 3)}px; | ||||||||||||||||||||||||
font-size: ${theme.gridUnit * 6}px; | ||||||||||||||||||||||||
font-weight: ${theme.typography.weights.medium}; | ||||||||||||||||||||||||
padding-bottom: ${theme.gridUnit * MARGIN_MULTIPLIER}px; | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
white-space: nowrap; | ||||||||||||||||||||||||
overflow: hidden; | ||||||||||||||||||||||||
text-overflow: ellipsis; | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
.anticon:first-of-type { | ||||||||||||||||||||||||
margin-right: ${({ theme }) => theme.gridUnit * (MARGIN_MULTIPLIER + 1)}px; | ||||||||||||||||||||||||
margin-right: ${theme.gridUnit * (MARGIN_MULTIPLIER + 1)}px; | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
.anticon:nth-of-type(2) { | ||||||||||||||||||||||||
margin-left: ${({ theme }) => theme.gridUnit * (MARGIN_MULTIPLIER + 1)}px; | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
margin-left: ${theme.gridUnit * (MARGIN_MULTIPLIER + 1)}px; | ||||||||||||||||||||||||
`} | ||||||||||||||||||||||||
`; | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
const StyledTitle = styled.div` | ||||||||||||||||||||||||
margin-left: ${({ theme }) => theme.gridUnit * MARGIN_MULTIPLIER}px; | ||||||||||||||||||||||||
margin-bottom: ${({ theme }) => theme.gridUnit * MARGIN_MULTIPLIER}px; | ||||||||||||||||||||||||
font-weight: ${({ theme }) => theme.typography.weights.bold}; | ||||||||||||||||||||||||
${({ theme }) => ` | ||||||||||||||||||||||||
margin-left: ${theme.gridUnit * (MARGIN_MULTIPLIER + 3)}px; | ||||||||||||||||||||||||
margin-bottom: ${theme.gridUnit * MARGIN_MULTIPLIER}px; | ||||||||||||||||||||||||
font-weight: ${theme.typography.weights.bold}; | ||||||||||||||||||||||||
`} | ||||||||||||||||||||||||
`; | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
const LoaderContainer = styled.div` | ||||||||||||||||||||||||
padding: ${({ theme }) => theme.gridUnit * 8}px | ||||||||||||||||||||||||
${({ theme }) => theme.gridUnit * 6}px; | ||||||||||||||||||||||||
${({ theme }) => ` | ||||||||||||||||||||||||
padding: ${theme.gridUnit * 8}px | ||||||||||||||||||||||||
${theme.gridUnit * 6}px; | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
display: flex; | ||||||||||||||||||||||||
align-items: center; | ||||||||||||||||||||||||
justify-content: center; | ||||||||||||||||||||||||
height: 100%; | ||||||||||||||||||||||||
`} | ||||||||||||||||||||||||
`; | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
const StyledLoader = styled.div` | ||||||||||||||||||||||||
${({ theme }) => ` | ||||||||||||||||||||||||
max-width: 50%; | ||||||||||||||||||||||||
width: ${LOADER_WIDTH}px; | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
|
@@ -100,19 +110,23 @@ const StyledLoader = styled.div` | |||||||||||||||||||||||
|
||||||||||||||||||||||||
div { | ||||||||||||||||||||||||
width: 100%; | ||||||||||||||||||||||||
margin-top: ${({ theme }) => theme.gridUnit * MARGIN_MULTIPLIER}px; | ||||||||||||||||||||||||
margin-top: ${theme.gridUnit * MARGIN_MULTIPLIER}px; | ||||||||||||||||||||||||
text-align: center; | ||||||||||||||||||||||||
font-weight: ${({ theme }) => theme.typography.weights.normal}; | ||||||||||||||||||||||||
font-size: ${({ theme }) => theme.typography.sizes.l}px; | ||||||||||||||||||||||||
color: ${({ theme }) => theme.colors.grayscale.light1}; | ||||||||||||||||||||||||
font-weight: ${theme.typography.weights.normal}; | ||||||||||||||||||||||||
font-size: ${theme.typography.sizes.l}px; | ||||||||||||||||||||||||
color: ${theme.colors.grayscale.light1}; | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
`} | ||||||||||||||||||||||||
`; | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
const TableContainer = styled.div` | ||||||||||||||||||||||||
${({ theme }) => ` | ||||||||||||||||||||||||
position: relative; | ||||||||||||||||||||||||
margin: ${({ theme }) => theme.gridUnit * MARGIN_MULTIPLIER}px; | ||||||||||||||||||||||||
margin: ${theme.gridUnit * MARGIN_MULTIPLIER}px; | ||||||||||||||||||||||||
margin-left: ${theme.gridUnit * (MARGIN_MULTIPLIER + 3)}px; | ||||||||||||||||||||||||
overflow: scroll; | ||||||||||||||||||||||||
height: calc(100% - ${({ theme }) => theme.gridUnit * 36}px); | ||||||||||||||||||||||||
height: calc(100% - ${theme.gridUnit * 36}px); | ||||||||||||||||||||||||
`} | ||||||||||||||||||||||||
`; | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
const StyledTable = styled(Table)` | ||||||||||||||||||||||||
|
@@ -123,6 +137,26 @@ const StyledTable = styled(Table)` | |||||||||||||||||||||||
right: 0; | ||||||||||||||||||||||||
`; | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
const StyledAlert = styled(Alert)` | ||||||||||||||||||||||||
${({ theme }) => ` | ||||||||||||||||||||||||
border: 1px solid ${theme.colors.info.base}; | ||||||||||||||||||||||||
padding: ${theme.gridUnit * 4}px; | ||||||||||||||||||||||||
margin: ${theme.gridUnit * 6}px ${theme.gridUnit * 6}px | ||||||||||||||||||||||||
${theme.gridUnit * 8}px; | ||||||||||||||||||||||||
.view-dataset-button { | ||||||||||||||||||||||||
position: absolute; | ||||||||||||||||||||||||
top: ${theme.gridUnit * 4}px; | ||||||||||||||||||||||||
right: ${theme.gridUnit * 4}px; | ||||||||||||||||||||||||
font-weight: ${theme.typography.weights.normal}; | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
&:hover { | ||||||||||||||||||||||||
color: ${theme.colors.secondary.dark3}; | ||||||||||||||||||||||||
text-decoration: underline; | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
`} | ||||||||||||||||||||||||
`; | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
export const REFRESHING = t('Refreshing columns'); | ||||||||||||||||||||||||
export const COLUMN_TITLE = t('Table columns'); | ||||||||||||||||||||||||
export const ALT_LOADING = t('Loading'); | ||||||||||||||||||||||||
|
@@ -168,15 +202,52 @@ export interface IDatasetPanelProps { | |||||||||||||||||||||||
* Boolean indicating if the component is in a loading state | ||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||
loading: boolean; | ||||||||||||||||||||||||
datasets?: DatasetObject[] | undefined; | ||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: I kind of want this to have a better name, maybe existingDatasets? or something along those lines. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was going off of what @eschutho suggested in this review comment. I'm not really settled on the best name here but I'd be fine changing it, would like to hear what Elizabeth thinks of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Makes sense! Does this need to be a list or can it be boolean? From my, limited, understanding of this feature you're seeing if there already is a dataset linked, so we don't need to be passing in a list of datasets, we could just check to see if there is an associated one. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We need the whole object so we can cross-reference the list of table names with the table names in the list of datasets here: superset/superset-frontend/src/views/CRUD/data/dataset/AddDataset/DatasetPanel/DatasetPanel.tsx Lines 292 to 295 in d77263d
And when it's passed into superset/superset-frontend/src/views/CRUD/data/dataset/AddDataset/DatasetPanel/DatasetPanel.tsx Lines 224 to 230 in 0bed85a
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. got it! Makes sense |
||||||||||||||||||||||||
} | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
const EXISTING_DATASET_DESCRIPTION = t( | ||||||||||||||||||||||||
'You can only associate one dataset with one table. This table already has a dataset associated with it in Preset.\n', | ||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, does this need to be preset specific language? If so, then I think we need to add that in on the Preset side and have a more generic description in superset. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That makes sense, but I'm not sure about Preset-specific language here. I think we'd need @yousoph 's input on this one. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated text: This table already has a dataset associated with it. You can only associate one dataset with a table. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I spoke with Sophie and Karan in Slack and we discussed changing the text to be more general and not include Superset or Preset. Changed in |
||||||||||||||||||||||||
); | ||||||||||||||||||||||||
const VIEW_DATASET = t('View Dataset'); | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
const renderExistingDatasetAlert = (dataset?: DatasetObject) => ( | ||||||||||||||||||||||||
<StyledAlert | ||||||||||||||||||||||||
closable={false} | ||||||||||||||||||||||||
type="info" | ||||||||||||||||||||||||
showIcon | ||||||||||||||||||||||||
message={t('This table already has a dataset')} | ||||||||||||||||||||||||
description={ | ||||||||||||||||||||||||
<> | ||||||||||||||||||||||||
{EXISTING_DATASET_DESCRIPTION} | ||||||||||||||||||||||||
<span | ||||||||||||||||||||||||
role="button" | ||||||||||||||||||||||||
onClick={() => { | ||||||||||||||||||||||||
window.open( | ||||||||||||||||||||||||
dataset?.explore_url, | ||||||||||||||||||||||||
'_blank', | ||||||||||||||||||||||||
'noreferer noopener popup=false', | ||||||||||||||||||||||||
); | ||||||||||||||||||||||||
}} | ||||||||||||||||||||||||
tabIndex={0} | ||||||||||||||||||||||||
className="view-dataset-button" | ||||||||||||||||||||||||
> | ||||||||||||||||||||||||
{VIEW_DATASET} | ||||||||||||||||||||||||
</span> | ||||||||||||||||||||||||
</> | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
/> | ||||||||||||||||||||||||
); | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
const DatasetPanel = ({ | ||||||||||||||||||||||||
tableName, | ||||||||||||||||||||||||
columnList, | ||||||||||||||||||||||||
loading, | ||||||||||||||||||||||||
hasError, | ||||||||||||||||||||||||
datasets, | ||||||||||||||||||||||||
}: IDatasetPanelProps) => { | ||||||||||||||||||||||||
const theme = useTheme(); | ||||||||||||||||||||||||
const hasColumns = columnList?.length > 0 ?? false; | ||||||||||||||||||||||||
const datasetNames = datasets?.map(dataset => dataset.table_name); | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
let component; | ||||||||||||||||||||||||
if (loading) { | ||||||||||||||||||||||||
|
@@ -217,17 +288,23 @@ const DatasetPanel = ({ | |||||||||||||||||||||||
return ( | ||||||||||||||||||||||||
<> | ||||||||||||||||||||||||
{tableName && ( | ||||||||||||||||||||||||
<StyledHeader | ||||||||||||||||||||||||
position={ | ||||||||||||||||||||||||
!loading && hasColumns ? EPosition.RELATIVE : EPosition.ABSOLUTE | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
title={tableName || ''} | ||||||||||||||||||||||||
> | ||||||||||||||||||||||||
{tableName && ( | ||||||||||||||||||||||||
<Icons.Table iconColor={supersetTheme.colors.grayscale.base} /> | ||||||||||||||||||||||||
)} | ||||||||||||||||||||||||
{tableName} | ||||||||||||||||||||||||
</StyledHeader> | ||||||||||||||||||||||||
<> | ||||||||||||||||||||||||
{datasetNames?.includes(tableName) && | ||||||||||||||||||||||||
renderExistingDatasetAlert( | ||||||||||||||||||||||||
datasets?.find(dataset => dataset.table_name === tableName), | ||||||||||||||||||||||||
)} | ||||||||||||||||||||||||
<StyledHeader | ||||||||||||||||||||||||
position={ | ||||||||||||||||||||||||
!loading && hasColumns ? EPosition.RELATIVE : EPosition.ABSOLUTE | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
title={tableName || ''} | ||||||||||||||||||||||||
> | ||||||||||||||||||||||||
{tableName && ( | ||||||||||||||||||||||||
<Icons.Table iconColor={theme.colors.grayscale.base} /> | ||||||||||||||||||||||||
)} | ||||||||||||||||||||||||
{tableName} | ||||||||||||||||||||||||
</StyledHeader> | ||||||||||||||||||||||||
</> | ||||||||||||||||||||||||
)} | ||||||||||||||||||||||||
{component} | ||||||||||||||||||||||||
</> | ||||||||||||||||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,6 +18,7 @@ | |
*/ | ||
import React, { useEffect, useState, useRef } from 'react'; | ||
import { SupersetClient } from '@superset-ui/core'; | ||
import { DatasetObject } from 'src/views/CRUD/data/dataset/AddDataset/types'; | ||
import DatasetPanel from './DatasetPanel'; | ||
import { ITableColumn, IDatabaseTable, isIDatabaseTable } from './types'; | ||
|
||
|
@@ -53,13 +54,15 @@ export interface IDatasetPanelWrapperProps { | |
*/ | ||
schema?: string | null; | ||
setHasColumns?: Function; | ||
datasets?: DatasetObject[] | undefined; | ||
} | ||
|
||
const DatasetPanelWrapper = ({ | ||
tableName, | ||
dbId, | ||
schema, | ||
setHasColumns, | ||
datasets, | ||
}: IDatasetPanelWrapperProps) => { | ||
const [columnList, setColumnList] = useState<ITableColumn[]>([]); | ||
const [loading, setLoading] = useState(false); | ||
|
@@ -110,7 +113,7 @@ const DatasetPanelWrapper = ({ | |
if (tableName && schema && dbId) { | ||
getTableMetadata({ tableName, dbId, schema }); | ||
} | ||
// getTableMetadata is a const and should not be independency array | ||
// getTableMetadata is a const and should not be in dependency array | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nice catch! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks! 😁 |
||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
}, [tableName, dbId, schema]); | ||
|
||
|
@@ -120,6 +123,7 @@ const DatasetPanelWrapper = ({ | |
hasError={hasError} | ||
loading={loading} | ||
tableName={tableName} | ||
datasets={datasets} | ||
/> | ||
); | ||
}; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Related to coment on line 20, we shuld repelase use of supertThem with:
const StyledAlert = styled(Alert)( ({ theme }) =>
and replace all the
supersetTheme
withtheme
for example:
`border: 1px solid ${theme.colors.info.base};
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FIxed in
this commit
.