mirror of
https://github.com/apache/superset.git
synced 2026-08-25 17:41:14 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
50f4802bbf | ||
|
|
fd07663dc1 |
@@ -29,22 +29,7 @@ import {
|
||||
} from 'src/utils/localStorageHelpers';
|
||||
import { SamplesPane, useResultsPane } from './components';
|
||||
import { DataTablesPaneProps, ResultTypes } from './types';
|
||||
|
||||
/**
|
||||
* A mixed chart can be reconfigured to return fewer result panes than before
|
||||
* (e.g. dropping a query), which removes the corresponding results tab. If the
|
||||
* selected tab was one of those, the active key goes stale and the data panel
|
||||
* renders blank until the user reselects a valid tab. Returns the first
|
||||
* results tab to fall back to in that case, otherwise undefined.
|
||||
*/
|
||||
export const getStaleResultsTabFallback = (
|
||||
activeTabKey: string,
|
||||
resultsTabKeys: string[],
|
||||
): string | undefined =>
|
||||
activeTabKey.startsWith(ResultTypes.Results) &&
|
||||
!resultsTabKeys.includes(activeTabKey)
|
||||
? ResultTypes.Results
|
||||
: undefined;
|
||||
import { getStaleResultsTabFallback } from './utils';
|
||||
|
||||
const StyledDiv = styled.div`
|
||||
${() => `
|
||||
|
||||
+19
-10
@@ -20,22 +20,15 @@ import { t } from '@apache-superset/core/translation';
|
||||
import { styled } from '@apache-superset/core/theme';
|
||||
import Tabs from '@superset-ui/core/components/Tabs';
|
||||
import { ResultTypes, ResultsPaneProps } from '../types';
|
||||
import { getStaleResultsTabFallback } from '../utils';
|
||||
import { useResultsPane } from './useResultsPane';
|
||||
import { useState } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
const Wrapper = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
|
||||
.ant-tabs {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.ant-tabs-body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.ant-tabs-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -86,9 +79,25 @@ export const ResultsPaneOnDashboard = ({
|
||||
};
|
||||
});
|
||||
|
||||
const resultsTabFallback = getStaleResultsTabFallback(
|
||||
activeTabKey,
|
||||
items.map(({ key }) => key),
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (resultsTabFallback) {
|
||||
setActiveTabKey(resultsTabFallback);
|
||||
}
|
||||
}, [resultsTabFallback]);
|
||||
|
||||
return (
|
||||
<Wrapper>
|
||||
<Tabs activeKey={activeTabKey} onChange={setActiveTabKey} items={items} />
|
||||
<Tabs
|
||||
fullHeight
|
||||
activeKey={activeTabKey}
|
||||
onChange={setActiveTabKey}
|
||||
items={items}
|
||||
/>
|
||||
</Wrapper>
|
||||
);
|
||||
};
|
||||
|
||||
+56
@@ -20,14 +20,34 @@ import fetchMock from 'fetch-mock';
|
||||
import {
|
||||
screen,
|
||||
render,
|
||||
act,
|
||||
waitForElementToBeRemoved,
|
||||
waitFor,
|
||||
} from 'spec/helpers/testing-library';
|
||||
import { ChartMetadata, ChartPlugin, VizType } from '@superset-ui/core';
|
||||
import { setupAGGridModules } from '@superset-ui/core/components/ThemedAgGridReact';
|
||||
import Tabs from '@superset-ui/core/components/Tabs';
|
||||
import { ResultsPaneOnDashboard } from '../components';
|
||||
import { useResultsPane } from '../components/useResultsPane';
|
||||
import { createResultsPaneOnDashboardProps } from './fixture';
|
||||
|
||||
// `fullHeight`'s CSS isn't testable under jsdom (no `importSource` for the
|
||||
// `css` prop in jest's babel config), so spy on call args instead.
|
||||
jest.mock('@superset-ui/core/components/Tabs', () => {
|
||||
const actual = jest.requireActual('@superset-ui/core/components/Tabs');
|
||||
return { __esModule: true, ...actual, default: jest.fn(actual.default) };
|
||||
});
|
||||
|
||||
// Wraps the real hook; only overridden below to avoid mounting a second
|
||||
// real AG Grid instance, which jsdom doesn't support.
|
||||
jest.mock('../components/useResultsPane', () => {
|
||||
const actual = jest.requireActual('../components/useResultsPane');
|
||||
return {
|
||||
__esModule: true,
|
||||
useResultsPane: jest.fn(actual.useResultsPane),
|
||||
};
|
||||
});
|
||||
|
||||
beforeAll(() => {
|
||||
setupAGGridModules();
|
||||
});
|
||||
@@ -106,6 +126,10 @@ describe('ResultsPaneOnDashboard', () => {
|
||||
expect(
|
||||
await findByText('No results were returned for this query'),
|
||||
).toBeVisible();
|
||||
expect(Tabs).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ fullHeight: true }),
|
||||
expect.anything(),
|
||||
);
|
||||
});
|
||||
|
||||
test('render errorMessage', async () => {
|
||||
@@ -219,4 +243,36 @@ describe('ResultsPaneOnDashboard', () => {
|
||||
expect(tab2).toBeVisible();
|
||||
expect(tab3).toBeNull();
|
||||
});
|
||||
|
||||
test('falls back to the first results tab when the active one disappears', async () => {
|
||||
const mockedUseResultsPane = useResultsPane as jest.Mock;
|
||||
mockedUseResultsPane.mockReturnValue([<div key="a" />, <div key="b" />]);
|
||||
|
||||
const props = createResultsPaneOnDashboardProps({ sliceId: 999 });
|
||||
const { rerender } = render(<ResultsPaneOnDashboard {...props} />, {
|
||||
useRedux: true,
|
||||
});
|
||||
|
||||
const latestTabsProps = () => {
|
||||
const { calls } = (Tabs as unknown as jest.Mock).mock;
|
||||
return calls[calls.length - 1][0];
|
||||
};
|
||||
expect(latestTabsProps().items.map((i: { key: string }) => i.key)).toEqual([
|
||||
'results',
|
||||
'results 2',
|
||||
]);
|
||||
|
||||
act(() => {
|
||||
latestTabsProps().onChange('results 2');
|
||||
});
|
||||
expect(latestTabsProps().activeKey).toBe('results 2');
|
||||
|
||||
// A mixed chart dropped from two query results to one, removing "results 2"
|
||||
mockedUseResultsPane.mockReturnValue([<div key="a" />]);
|
||||
rerender(<ResultsPaneOnDashboard {...props} />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(latestTabsProps().activeKey).toBe('results');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { getStaleResultsTabFallback } from '../DataTablesPane';
|
||||
import { getStaleResultsTabFallback } from '../utils';
|
||||
import { ResultTypes } from '../types';
|
||||
|
||||
test('keeps the active tab when it still exists', () => {
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* 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 { ResultTypes } from './types';
|
||||
|
||||
/**
|
||||
* A mixed chart can be reconfigured to return fewer result panes than before
|
||||
* (e.g. dropping a query), which removes the corresponding results tab. If the
|
||||
* selected tab was one of those, the active key goes stale and the data panel
|
||||
* renders blank until the user reselects a valid tab. Returns the first
|
||||
* results tab to fall back to in that case, otherwise undefined.
|
||||
*/
|
||||
export const getStaleResultsTabFallback = (
|
||||
activeTabKey: string,
|
||||
resultsTabKeys: string[],
|
||||
): string | undefined =>
|
||||
activeTabKey.startsWith(ResultTypes.Results) &&
|
||||
!resultsTabKeys.includes(activeTabKey)
|
||||
? ResultTypes.Results
|
||||
: undefined;
|
||||
Reference in New Issue
Block a user