Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master' into feat/fileter_set
Browse files Browse the repository at this point in the history
* upstream/master:
  fix(explore): Datepicker glitch on hover outside the modal (apache#15033)
  Add ming-height to empty tab (apache#14878)
  Remove nowrap (apache#14954)
  display all metric results in editor (apache#15031)
  feat: Add "is_select_query" method to base engine spec to make it possible to override it (apache#15013)
  fix(dashboard): custom css should be removed on unmount (apache#15025)
  feat(filter-box): hide druid options if druid not enabled (apache#14921)
  fix: adding additional configs and colors for queryHistory (apache#14995)
  chore: rename 'Source' to 'Database' for consistency (apache#15021)
  chore(ci): fix ci conflict (apache#15016)
  fix(native-filters): avoid double load on initialization (apache#15012)
  feat(native-filters): Support default to first value in select filter (apache#14869)
  docs: required information for OAuth2 configuration (apache#15010)
  Update index.mdx (apache#14990)
  • Loading branch information
amitmiran137 committed Jun 8, 2021
2 parents 16c8a18 + 0e07a5c commit a87172a
Show file tree
Hide file tree
Showing 32 changed files with 497 additions and 246 deletions.
6 changes: 6 additions & 0 deletions docs/src/pages/docs/installation/configuring.mdx
Expand Up @@ -113,6 +113,8 @@ RequestHeader set X-Forwarded-Proto "https"
Beyond FAB supported providers (Github, Twitter, LinkedIn, Google, Azure, etc), its easy to connect
Superset with other OAuth2 Authorization Server implementations that support “code” authorization.

Make sure the pip package [`Authlib`](https://authlib.org/) is installed on the webserver.

First, configure authorization in Superset `superset_config.py`.

```python
Expand Down Expand Up @@ -175,6 +177,10 @@ from custom_sso_security_manager import CustomSsoSecurityManager
CUSTOM_SECURITY_MANAGER = CustomSsoSecurityManager
```

Notice that the redirect URL will be `https://<superset-webserver>/oauth-authorized/<provider-name>`
When configuring an OAuth2 authorization provider if needed. For instance, the redirect URL will
be `https://<superset-webserver>/oauth-authorized/egaSSO` for the above configuration.

### Feature Flags

To support a diverse set of users, Superset has some features that are not enabled by default. For
Expand Down
2 changes: 1 addition & 1 deletion docs/src/pages/docs/installation/index.mdx
Expand Up @@ -79,7 +79,7 @@ The following is for users who want to configure how Superset starts up in Docke

You can configure the Docker Compose settings for dev and non-dev mode with `docker/.env` and `docker/.env-non-dev` respectively. These environment files set the environment for most containers in the Docker Compose setup, and some variables affect multiple containers and others only single ones.

One important variable is `SUPERSET_LOAD_EXAMPLES` which determines whether the `superset_init` container will load example data and visualizations into the database and Superset. Thiese examples are quite helpful for most people, but probably unnecessary for experienced users. The loading process can sometimes take a few minutes and a good amount of CPU, so you may want to disable it on a resource-constrained device.
One important variable is `SUPERSET_LOAD_EXAMPLES` which determines whether the `superset_init` container will load example data and visualizations into the database and Superset. These examples are quite helpful for most people, but probably unnecessary for experienced users. The loading process can sometimes take a few minutes and a good amount of CPU, so you may want to disable it on a resource-constrained device.

**Note:** Users often want to connect to other databases from Superset. Currently, the easiest way to do this is to modify the `docker-compose-non-dev.yml` file and add your database as a service that the other services depend on (via `x-superset-depends-on`). Others have attempted to set `network_mode: host` on the Superset services, but these generally break the installation, because the configuration requires use of the Docker Compose DNS resolver for the service names. If you have a good solution for this, let us know!

Expand Down
2 changes: 2 additions & 0 deletions superset-frontend/spec/fixtures/mockDatasource.js
Expand Up @@ -45,6 +45,8 @@ export default {
verbose_name: 'sum__num',
metric_name: 'sum__num',
description: null,
extra:
'{"certification":{"details":"foo", "certified_by":"someone"},"warning_markdown":"bar"}',
},
{
expression: 'AVG(birth_names.num)',
Expand Down
Expand Up @@ -21,6 +21,9 @@ import { shallow } from 'enzyme';
import configureStore from 'redux-mock-store';
import fetchMock from 'fetch-mock';
import thunk from 'redux-thunk';
import userEvent from '@testing-library/user-event';
import { render, screen } from 'spec/helpers/testing-library';

import { Radio } from 'src/components/Radio';

import Icon from 'src/components/Icon';
Expand Down Expand Up @@ -56,6 +59,10 @@ describe('DatasourceEditor', () => {
inst = wrapper.instance();
});

afterEach(() => {
wrapper.unmount();
});

it('is valid', () => {
expect(React.isValidElement(el)).toBe(true);
});
Expand Down Expand Up @@ -209,3 +216,21 @@ describe('DatasourceEditor', () => {
isFeatureEnabledMock.mockRestore();
});
});

describe('DatasourceEditor RTL', () => {
it('properly renders the metric information', async () => {
render(<DatasourceEditor {...props} />, { useRedux: true });
const metricButton = screen.getByTestId('collection-tab-Metrics');
userEvent.click(metricButton);
const expandToggle = await screen.findAllByLabelText(/toggle expand/i);
userEvent.click(expandToggle[0]);
const certificationDetails = await screen.findByPlaceholderText(
/certification details/i,
);
expect(certificationDetails.value).toEqual('foo');
const warningMarkdown = await await screen.findByPlaceholderText(
/certified by/i,
);
expect(warningMarkdown.value).toEqual('someone');
});
});
26 changes: 20 additions & 6 deletions superset-frontend/src/SqlLab/components/QueryTable/index.jsx
Expand Up @@ -88,6 +88,14 @@ const statusAttributes = {
status: 'running',
},
},
fetching: {
color: ({ theme }) => theme.colors.primary.base,
config: {
name: 'queued',
label: t('fetching'),
status: 'fetching',
},
},
timed_out: {
color: ({ theme }) => theme.colors.grayscale.light1,
config: {
Expand All @@ -97,14 +105,20 @@ const statusAttributes = {
},
},
scheduled: {
name: 'queued',
label: t('Scheduled'),
status: 'queued',
color: ({ theme }) => theme.colors.greyscale.base,
config: {
name: 'queued',
label: t('Scheduled'),
status: 'queued',
},
},
pending: {
name: 'queued',
label: t('Scheduled'),
status: 'queued',
color: ({ theme }) => theme.colors.greyscale.base,
config: {
name: 'queued',
label: t('Scheduled'),
status: 'queued',
},
},
};

Expand Down
Expand Up @@ -18,7 +18,7 @@
*/
/* eslint-env browser */
import cx from 'classnames';
import React, { FC, useEffect, useState } from 'react';
import React, { FC } from 'react';
import { Sticky, StickyContainer } from 'react-sticky';
import { JsonObject, styled } from '@superset-ui/core';
import ErrorBoundary from 'src/components/ErrorBoundary';
Expand All @@ -30,7 +30,6 @@ import DashboardComponent from 'src/dashboard/containers/DashboardComponent';
import ToastPresenter from 'src/messageToasts/containers/ToastPresenter';
import WithPopoverMenu from 'src/dashboard/components/menu/WithPopoverMenu';
import getDirectPathToTabIndex from 'src/dashboard/util/getDirectPathToTabIndex';
import { FeatureFlag, isFeatureEnabled } from 'src/featureFlags';
import { URL_PARAMS } from 'src/constants';
import { useDispatch, useSelector } from 'react-redux';
import { getUrlParam } from 'src/utils/urlUtils';
Expand All @@ -47,11 +46,11 @@ import {
DashboardStandaloneMode,
} from 'src/dashboard/util/constants';
import FilterBar from 'src/dashboard/components/nativeFilters/FilterBar';
import Loading from 'src/components/Loading';
import { StickyVerticalBar } from '../StickyVerticalBar';
import { shouldFocusTabs, getRootLevelTabsComponent } from './utils';
import { useFilters } from '../nativeFilters/FilterBar/state';
import { Filter } from '../nativeFilters/types';
import DashboardContainer from './DashboardContainer';
import { useNativeFilters } from './state';

const TABS_HEIGHT = 47;
const HEADER_HEIGHT = 67;
Expand Down Expand Up @@ -99,35 +98,13 @@ const DashboardBuilder: FC<DashboardBuilderProps> = () => {
const dashboardLayout = useSelector<RootState, DashboardLayout>(
state => state.dashboardLayout.present,
);
const showNativeFilters = useSelector<RootState, boolean>(
state => state.dashboardInfo.metadata?.show_native_filters,
);
const canEdit = useSelector<RootState, boolean>(
({ dashboardInfo }) => dashboardInfo.dash_edit_perm,
);
const editMode = useSelector<RootState, boolean>(
state => state.dashboardState.editMode,
);
const directPathToChild = useSelector<RootState, string[]>(
state => state.dashboardState.directPathToChild,
);

const filters = useFilters();
const filterValues = Object.values<Filter>(filters);

const nativeFiltersEnabled =
showNativeFilters &&
isFeatureEnabled(FeatureFlag.DASHBOARD_NATIVE_FILTERS) &&
(canEdit || (!canEdit && filterValues.length !== 0));

const [dashboardFiltersOpen, setDashboardFiltersOpen] = useState(
getUrlParam(URL_PARAMS.showFilters) ?? true,
);

const toggleDashboardFiltersOpen = (visible?: boolean) => {
setDashboardFiltersOpen(visible ?? !dashboardFiltersOpen);
};

const handleChangeTab = ({
pathToTabIndex,
}: {
Expand Down Expand Up @@ -161,15 +138,12 @@ const DashboardBuilder: FC<DashboardBuilderProps> = () => {
(hideDashboardHeader ? 0 : HEADER_HEIGHT) +
(topLevelTabs ? TABS_HEIGHT : 0);

useEffect(() => {
if (
filterValues.length === 0 &&
dashboardFiltersOpen &&
nativeFiltersEnabled
) {
toggleDashboardFiltersOpen(false);
}
}, [filterValues.length]);
const {
showDashboard,
dashboardFiltersOpen,
toggleDashboardFiltersOpen,
nativeFiltersEnabled,
} = useNativeFilters();

return (
<StickyContainer
Expand Down Expand Up @@ -245,7 +219,11 @@ const DashboardBuilder: FC<DashboardBuilderProps> = () => {
</ErrorBoundary>
</StickyVerticalBar>
)}
<DashboardContainer topLevelTabs={topLevelTabs} />
{showDashboard ? (
<DashboardContainer topLevelTabs={topLevelTabs} />
) : (
<Loading />
)}
{editMode && <BuilderComponentPane topOffset={barTopOffset} />}
</StyledDashboardContent>
<ToastPresenter />
Expand Down
@@ -0,0 +1,93 @@
/**
* 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 { useSelector } from 'react-redux';
import { FeatureFlag, isFeatureEnabled } from 'src/featureFlags';
import { useEffect, useState } from 'react';
import { URL_PARAMS } from 'src/constants';
import { getUrlParam } from 'src/utils/urlUtils';
import { RootState } from 'src/dashboard/types';
import {
useFilters,
useNativeFiltersDataMask,
} from '../nativeFilters/FilterBar/state';
import { Filter } from '../nativeFilters/types';

// eslint-disable-next-line import/prefer-default-export
export const useNativeFilters = () => {
const [isInitialized, setIsInitialized] = useState(false);
const [dashboardFiltersOpen, setDashboardFiltersOpen] = useState(
getUrlParam(URL_PARAMS.showFilters) ?? true,
);
const showNativeFilters = useSelector<RootState, boolean>(
state => state.dashboardInfo.metadata?.show_native_filters,
);
const canEdit = useSelector<RootState, boolean>(
({ dashboardInfo }) => dashboardInfo.dash_edit_perm,
);

const filters = useFilters();
const filterValues = Object.values<Filter>(filters);

const nativeFiltersEnabled =
showNativeFilters &&
isFeatureEnabled(FeatureFlag.DASHBOARD_NATIVE_FILTERS) &&
(canEdit || (!canEdit && filterValues.length !== 0));

const requiredFirstFilter = filterValues.filter(
({ requiredFirst }) => requiredFirst,
);
const dataMask = useNativeFiltersDataMask();
const showDashboard =
isInitialized ||
!nativeFiltersEnabled ||
!(
nativeFiltersEnabled &&
requiredFirstFilter.length &&
requiredFirstFilter.find(
({ id }) => dataMask[id]?.filterState?.value === undefined,
)
);

const toggleDashboardFiltersOpen = (visible?: boolean) => {
setDashboardFiltersOpen(visible ?? !dashboardFiltersOpen);
};

useEffect(() => {
if (
filterValues.length === 0 &&
dashboardFiltersOpen &&
nativeFiltersEnabled
) {
toggleDashboardFiltersOpen(false);
}
}, [filterValues.length]);

useEffect(() => {
if (showDashboard) {
setIsInitialized(true);
}
}, [showDashboard]);

return {
showDashboard,
dashboardFiltersOpen,
toggleDashboardFiltersOpen,
nativeFiltersEnabled,
};
};
Expand Up @@ -93,6 +93,10 @@ const StyledTabsContainer = styled.div`
.ant-tabs {
overflow: visible;
.ant-tabs-nav-wrap {
min-height: ${({ theme }) => theme.gridUnit * 12.5}px;
}
.ant-tabs-content-holder {
overflow: visible;
}
Expand Down
Expand Up @@ -74,7 +74,7 @@ const FilterValue: React.FC<FilterProps> = ({
const { name: groupby } = column;
const hasDataSource = !!datasetId;
const [isLoading, setIsLoading] = useState<boolean>(hasDataSource);
const [isRefreshing, setIsRefreshing] = useState<boolean>(false);
const [isRefreshing, setIsRefreshing] = useState<boolean>(true);
const dispatch = useDispatch();
useEffect(() => {
const newFormData = getFormData({
Expand Down
Expand Up @@ -18,19 +18,15 @@
*/

/* eslint-disable no-param-reassign */
import { HandlerFunction, styled, t } from '@superset-ui/core';
import { DataMask, HandlerFunction, styled, t } from '@superset-ui/core';
import React, { useEffect, useState } from 'react';
import { useDispatch } from 'react-redux';
import cx from 'classnames';
import Icon from 'src/components/Icon';
import { Tabs } from 'src/common/components';
import { FeatureFlag, isFeatureEnabled } from 'src/featureFlags';
import { updateDataMask } from 'src/dataMask/actions';
import {
DataMaskState,
DataMaskStateWithId,
DataMaskWithId,
} from 'src/dataMask/types';
import { DataMaskStateWithId, DataMaskWithId } from 'src/dataMask/types';
import { useImmer } from 'use-immer';
import { areObjectsEqual } from 'src/reduxUtils';
import { testWithId } from 'src/utils/testUtils';
Expand Down Expand Up @@ -178,10 +174,21 @@ const FilterBar: React.FC<FiltersBarProps> = ({

const handleFilterSelectionChange = (
filter: Pick<Filter, 'id'> & Partial<Filter>,
dataMask: Partial<DataMaskState>,
dataMask: Partial<DataMask>,
) => {
setIsFilterSetChanged(tab !== TabIds.AllFilters);
setDataMaskSelected(draft => {
// force instant updating on initialization for filters with `requiredFirst` is true or instant filters
if (
(dataMaskSelected[filter.id] && filter.isInstant) ||
// filterState.value === undefined - means that value not initialized
(dataMask.filterState?.value !== undefined &&
dataMaskSelected[filter.id]?.filterState?.value === undefined &&
filter.requiredFirst)
) {
dispatch(updateDataMask(filter.id, dataMask));
}

draft[filter.id] = {
...(getInitialDataMask(filter.id) as DataMaskWithId),
...dataMask,
Expand Down

0 comments on commit a87172a

Please sign in to comment.