/**
* 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 rison from 'rison';
import React, { useCallback } from 'react';
import PropTypes from 'prop-types';
import { Radio } from 'src/components/Radio';
import Card from 'src/components/Card';
import Alert from 'src/components/Alert';
import Badge from 'src/components/Badge';
import shortid from 'shortid';
import { styled, SupersetClient, t, withTheme } from '@superset-ui/core';
import { Select, Row, Col } from 'src/components';
import { FormLabel } from 'src/components/Form';
import Button from 'src/components/Button';
import Tabs from 'src/components/Tabs';
import CertifiedBadge from 'src/components/CertifiedBadge';
import WarningIconWithTooltip from 'src/components/WarningIconWithTooltip';
import DatabaseSelector from 'src/components/DatabaseSelector';
import Label from 'src/components/Label';
import Loading from 'src/components/Loading';
import TableSelector from 'src/components/TableSelector';
import EditableTitle from 'src/components/EditableTitle';
import { getClientErrorObject } from 'src/utils/getClientErrorObject';
import CheckboxControl from 'src/explore/components/controls/CheckboxControl';
import TextControl from 'src/explore/components/controls/TextControl';
import TextAreaControl from 'src/explore/components/controls/TextAreaControl';
import SpatialControl from 'src/explore/components/controls/SpatialControl';
import withToasts from 'src/components/MessageToasts/withToasts';
import { FeatureFlag, isFeatureEnabled } from 'src/featureFlags';
import Icons from 'src/components/Icons';
import CollectionTable from './CollectionTable';
import Fieldset from './Fieldset';
import Field from './Field';
const DatasourceContainer = styled.div`
.change-warning {
margin: 16px 10px 0;
color: ${({ theme }) => theme.colors.warning.base};
}
.change-warning .bold {
font-weight: ${({ theme }) => theme.typography.weights.bold};
}
.form-group.has-feedback > .help-block {
margin-top: 8px;
}
.form-group.form-group-md {
margin-bottom: 8px;
}
`;
const FlexRowContainer = styled.div`
align-items: center;
display: flex;
svg {
margin-right: ${({ theme }) => theme.gridUnit}px;
}
`;
const StyledTableTabs = styled(Tabs)`
overflow: visible;
.ant-tabs-content-holder {
overflow: visible;
}
`;
const StyledBadge = styled(Badge)`
.ant-badge-count {
line-height: ${({ theme }) => theme.gridUnit * 4}px;
height: ${({ theme }) => theme.gridUnit * 4}px;
margin-left: ${({ theme }) => theme.gridUnit}px;
}
`;
const EditLockContainer = styled.div`
font-size: ${({ theme }) => theme.typography.sizes.s}px;
display: flex;
align-items: center;
a {
padding: 0 10px;
}
`;
const ColumnButtonWrapper = styled.div`
text-align: right;
${({ theme }) => `margin-bottom: ${theme.gridUnit * 2}px`}
`;
const StyledLabelWrapper = styled.div`
display: flex;
align-items: center;
span {
margin-right: ${({ theme }) => theme.gridUnit}px;
}
`;
const StyledColumnsTabWrapper = styled.div`
.table > tbody > tr > td {
vertical-align: middle;
}
.ant-tag {
margin-top: ${({ theme }) => theme.gridUnit}px;
}
`;
const StyledButtonWrapper = styled.span`
${({ theme }) => `
margin-top: ${theme.gridUnit * 3}px;
margin-left: ${theme.gridUnit * 3}px;
`}
`;
const checkboxGenerator = (d, onChange) => (
);
const DATA_TYPES = [
{ value: 'STRING', label: 'STRING' },
{ value: 'NUMERIC', label: 'NUMERIC' },
{ value: 'DATETIME', label: 'DATETIME' },
{ value: 'BOOLEAN', label: 'BOOLEAN' },
];
const DATASOURCE_TYPES_ARR = [
{ key: 'physical', label: t('Physical (table or view)') },
{ key: 'virtual', label: t('Virtual (SQL)') },
];
const DATASOURCE_TYPES = {};
DATASOURCE_TYPES_ARR.forEach(o => {
DATASOURCE_TYPES[o.key] = o;
});
function CollectionTabTitle({ title, collection }) {
return (
{title}{' '}
);
}
CollectionTabTitle.propTypes = {
title: PropTypes.string,
collection: PropTypes.array,
};
function ColumnCollectionTable({
columns,
datasource,
onColumnsChange,
onDatasourceChange,
editableColumnName,
showExpression,
allowAddItem,
allowEditDataType,
itemGenerator,
}) {
return (
}
columnLabels={
isFeatureEnabled(FeatureFlag.ENABLE_ADVANCED_DATA_TYPES)
? {
column_name: t('Column'),
advanced_data_type: t('Advanced data type'),
type: t('Data type'),
groupby: t('Is dimension'),
is_dttm: t('Is temporal'),
main_dttm_col: t('Default datetime'),
filterable: t('Is filterable'),
}
: {
column_name: t('Column'),
type: t('Data type'),
groupby: t('Is dimension'),
is_dttm: t('Is temporal'),
main_dttm_col: t('Default datetime'),
filterable: t('Is filterable'),
}
}
onChange={onColumnsChange}
itemRenderers={
isFeatureEnabled(FeatureFlag.ENABLE_ADVANCED_DATA_TYPES)
? {
column_name: (v, onItemChange, _, record) =>
editableColumnName ? (
{record.is_certified && (
)}
) : (
{record.is_certified && (
)}
{v}
),
main_dttm_col: (value, _onItemChange, _label, record) => {
const checked = datasource.main_dttm_col === record.column_name;
const disabled = !columns.find(
column => column.column_name === record.column_name,
).is_dttm;
return (
onDatasourceChange({
...datasource,
main_dttm_col: record.column_name,
})
}
/>
);
},
type: d => (d ? : null),
advanced_data_type: d => (
),
is_dttm: checkboxGenerator,
filterable: checkboxGenerator,
groupby: checkboxGenerator,
}
: {
column_name: (v, onItemChange, _, record) =>
editableColumnName ? (
{record.is_certified && (
)}
) : (
{record.is_certified && (
)}
{v}
),
main_dttm_col: (value, _onItemChange, _label, record) => {
const checked = datasource.main_dttm_col === record.column_name;
const disabled = !columns.find(
column => column.column_name === record.column_name,
).is_dttm;
return (
onDatasourceChange({
...datasource,
main_dttm_col: record.column_name,
})
}
/>
);
},
type: d => (d ? : null),
is_dttm: checkboxGenerator,
filterable: checkboxGenerator,
groupby: checkboxGenerator,
}
}
/>
);
}
ColumnCollectionTable.propTypes = {
columns: PropTypes.array.isRequired,
datasource: PropTypes.object.isRequired,
onColumnsChange: PropTypes.func.isRequired,
onDatasourceChange: PropTypes.func.isRequired,
editableColumnName: PropTypes.bool,
showExpression: PropTypes.bool,
allowAddItem: PropTypes.bool,
allowEditDataType: PropTypes.bool,
itemGenerator: PropTypes.func,
};
ColumnCollectionTable.defaultProps = {
editableColumnName: false,
showExpression: false,
allowAddItem: false,
allowEditDataType: false,
itemGenerator: () => ({
column_name: '',
filterable: true,
groupby: true,
}),
};
function StackedField({ label, formElement }) {
return (
);
}
StackedField.propTypes = {
label: PropTypes.string,
formElement: PropTypes.node,
};
function FormContainer({ children }) {
return {children};
}
FormContainer.propTypes = {
children: PropTypes.node,
};
const propTypes = {
datasource: PropTypes.object.isRequired,
onChange: PropTypes.func,
addSuccessToast: PropTypes.func.isRequired,
addDangerToast: PropTypes.func.isRequired,
setIsEditing: PropTypes.func,
};
const defaultProps = {
onChange: () => {},
setIsEditing: () => {},
};
function OwnersSelector({ datasource, onChange }) {
const loadOptions = useCallback((search = '', page, pageSize) => {
const query = rison.encode({ filter: search, page, page_size: pageSize });
return SupersetClient.get({
endpoint: `/api/v1/dataset/related/owners?q=${query}`,
}).then(response => ({
data: response.json.result.map(item => ({
value: item.value,
label: item.text,
})),
totalCount: response.json.count,
}));
}, []);
return (