build(dev-deps): upgrade Jest to major version v30 (#33979)

This commit is contained in:
Đỗ Trọng Hải
2025-07-03 11:01:40 +07:00
committed by GitHub
parent c008190a08
commit 42288c4784
46 changed files with 4535 additions and 1162 deletions

View File

@@ -12,6 +12,10 @@ updates:
# not until React >= 18.0.0
- dependency-name: "storybook"
- dependency-name: "@storybook*"
# JSDOM v30 doesn't play well with Jest v30
# Source: https://jestjs.io/blog#known-issues
# GH thread: https://github.com/jsdom/jsdom/issues/3492
- dependency-name: "jest-environment-jsdom"
directory: "/superset-frontend/"
schedule:
interval: "monthly"

View File

@@ -86,9 +86,7 @@ module.exports = {
],
parser: '@babel/eslint-parser',
parserOptions: {
ecmaFeatures: {
experimentalObjectRestSpread: true,
},
ecmaVersion: 2018,
},
env: {
browser: true,
@@ -127,6 +125,11 @@ module.exports = {
'react-prefer-function-component',
'prettier',
],
// Add this TS ESlint rule in separate `rules` section to avoid breakages with JS/TS files in /cypress-base.
// TODO(hainenber): merge it to below `rules` section.
rules: {
'@typescript-eslint/prefer-optional-chain': 'error',
},
overrides: [
{
files: ['*.ts', '*.tsx'],
@@ -160,7 +163,7 @@ module.exports = {
'@typescript-eslint/no-non-null-assertion': 0, // disabled temporarily
'@typescript-eslint/explicit-function-return-type': 0,
'@typescript-eslint/explicit-module-boundary-types': 0, // re-enable up for discussion
'@typescript-eslint/prefer-optional-chain': 2,
'@typescript-eslint/no-unused-vars': 'warn', // downgrade to Warning severity for Jest v30 upgrade
camelcase: 0,
'class-methods-use-this': 0,
'func-names': 0,
@@ -395,6 +398,7 @@ module.exports = {
},
},
],
// eslint-disable-next-line no-dupe-keys
rules: {
'theme-colors/no-literal-colors': 'error',
'icons/no-fa-icons-usage': 'error',

View File

@@ -21,30 +21,21 @@ import qs from 'querystring';
import {
dashboardView,
nativeFilters,
exploreView,
dataTestChartName,
} from 'cypress/support/directories';
import {
addCountryNameFilter,
addParentFilterWithValue,
applyAdvancedTimeRangeFilterOnDashboard,
applyNativeFilterValueWithIndex,
cancelNativeFilterSettings,
checkNativeFilterTooltip,
clickOnAddFilterInModal,
collapseFilterOnLeftPanel,
deleteNativeFilter,
enterNativeFilterEditModal,
expandFilterOnLeftPanel,
fillNativeFilterForm,
getNativeFilterPlaceholderWithIndex,
inputNativeFilterDefaultValue,
saveNativeFilterSettings,
nativeFilterTooltips,
undoDeleteNativeFilter,
validateFilterContentOnDashboard,
valueNativeFilterOptions,
validateFilterNameOnDashboard,
testItems,
WORLD_HEALTH_CHARTS,
@@ -55,19 +46,19 @@ import {
visitDashboard,
} from './shared_dashboard_functions';
function selectFilter(index: number) {
cy.get("[data-test='filter-title-container'] [draggable='true']")
.eq(index)
.click();
}
// function selectFilter(index: number) {
// cy.get("[data-test='filter-title-container'] [draggable='true']")
// .eq(index)
// .click();
// }
function closeFilterModal() {
cy.get('body').then($body => {
if ($body.find('[data-test="native-filter-modal-cancel-button"]').length) {
cy.getBySel('native-filter-modal-cancel-button').click();
}
});
}
// function closeFilterModal() {
// cy.get('body').then($body => {
// if ($body.find('[data-test="native-filter-modal-cancel-button"]').length) {
// cy.getBySel('native-filter-modal-cancel-button').click();
// }
// });
// }
describe('Native filters', () => {
describe('Nativefilters initial state not required', () => {

View File

@@ -16,37 +16,29 @@
* specific language governing permissions and limitations
* under the License.
*/
import qs from 'querystring';
import {
dashboardView,
nativeFilters,
exploreView,
dataTestChartName,
} from 'cypress/support/directories';
import {
addCountryNameFilter,
addParentFilterWithValue,
applyAdvancedTimeRangeFilterOnDashboard,
applyNativeFilterValueWithIndex,
cancelNativeFilterSettings,
checkNativeFilterTooltip,
clickOnAddFilterInModal,
collapseFilterOnLeftPanel,
deleteNativeFilter,
enterNativeFilterEditModal,
expandFilterOnLeftPanel,
fillNativeFilterForm,
getNativeFilterPlaceholderWithIndex,
inputNativeFilterDefaultValue,
saveNativeFilterSettings,
nativeFilterTooltips,
undoDeleteNativeFilter,
validateFilterContentOnDashboard,
valueNativeFilterOptions,
validateFilterNameOnDashboard,
testItems,
WORLD_HEALTH_CHARTS,
} from './utils';
import {
prepareDashboardFilters,

View File

@@ -18,7 +18,6 @@
*/
import '@cypress/code-coverage/support';
import '@applitools/eyes-cypress/commands';
import failOnConsoleError from 'cypress-fail-on-console-error';
import { expect } from 'chai';
import rison from 'rison';

View File

@@ -10,7 +10,7 @@
"allowJs": true,
"noEmit": true
},
"files": ["cypress/support/index.d.ts", "./node_modules/@applitools/eyes-cypress/eyes-index.d.ts"],
"files": ["cypress/support/index.d.ts", "./node_modules/@applitools/eyes-cypress/types/index.d.ts"],
"include": ["cypress/**/*.ts", "./cypress.config.ts"],
"exclude": ["node_modules"]
}

View File

@@ -37,6 +37,7 @@ module.exports = {
setupFilesAfterEnv: ['<rootDir>/spec/helpers/setup.ts'],
snapshotSerializers: ['@emotion/jest/serializer'],
testEnvironmentOptions: {
globalsCleanup: true,
url: 'http://localhost',
},
collectCoverageFrom: [

File diff suppressed because it is too large Load Diff

View File

@@ -164,7 +164,6 @@
"ol": "^7.5.2",
"polished": "^4.3.1",
"prop-types": "^15.8.1",
"rc-trigger": "^5.3.4",
"re-resizable": "^6.10.1",
"react": "^17.0.2",
"react-checkbox-tree": "^1.8.0",
@@ -258,7 +257,6 @@
"@types/node": "^22.12.0",
"@types/react": "^17.0.83",
"@types/react-dom": "^17.0.26",
"@types/react-gravatar": "^2.6.14",
"@types/react-json-tree": "^0.6.11",
"@types/react-loadable": "^5.5.11",
"@types/react-redux": "^7.1.10",
@@ -275,17 +273,16 @@
"@types/sinon": "^17.0.3",
"@types/testing-library__jest-dom": "^5.14.9",
"@types/tinycolor2": "^1.4.3",
"@types/yargs": "12 - 18",
"@typescript-eslint/eslint-plugin": "^5.62.0",
"@typescript-eslint/parser": "^5.62.0",
"babel-jest": "^29.7.0",
"@typescript-eslint/eslint-plugin": "^7.18.0",
"@typescript-eslint/parser": "^7.18.0",
"babel-jest": "^30.0.2",
"babel-loader": "^10.0.0",
"babel-plugin-dynamic-import-node": "^2.3.3",
"babel-plugin-jsx-remove-data-test-id": "^3.0.0",
"babel-plugin-lodash": "^3.3.4",
"babel-plugin-typescript-to-proptypes": "^2.0.0",
"cheerio": "1.0.0-rc.10",
"copy-webpack-plugin": "^12.0.2",
"copy-webpack-plugin": "^13.0.0",
"cross-env": "^7.0.3",
"css-loader": "^7.1.2",
"css-minimizer-webpack-plugin": "^7.0.2",
@@ -315,9 +312,9 @@
"history": "^5.3.0",
"html-webpack-plugin": "^5.6.3",
"imports-loader": "^5.0.0",
"jest": "^29.7.0",
"jest": "^30.0.2",
"jest-environment-jsdom": "^29.7.0",
"jest-html-reporter": "^3.10.2",
"jest-html-reporter": "^4.3.0",
"jest-websocket-mock": "^2.5.0",
"jsdom": "^26.0.0",
"lerna": "^8.2.1",
@@ -336,11 +333,11 @@
"storybook": "8.1.11",
"style-loader": "^4.0.0",
"thread-loader": "^4.0.4",
"ts-jest": "^29.2.5",
"ts-jest": "^29.4.0",
"ts-loader": "^9.5.1",
"tscw-config": "^1.1.2",
"tsx": "^4.19.2",
"typescript": "5.1.6",
"typescript": "5.4.5",
"vm-browserify": "^1.1.2",
"webpack": "^5.98.0",
"webpack-bundle-analyzer": "^4.10.1",

View File

@@ -36,7 +36,7 @@
"devDependencies": {
"cross-env": "^7.0.3",
"fs-extra": "^11.2.0",
"jest": "^29.7.0",
"jest": "^30.0.2",
"yeoman-test": "^8.3.0"
},
"engines": {

View File

@@ -27,10 +27,9 @@ import {
import { PostProcessingFactory } from './types';
import { extractExtraMetrics } from './utils';
export const sortOperator: PostProcessingFactory<PostProcessingSort> = (
formData,
queryObject,
) => {
export const sortOperator: PostProcessingFactory<
PostProcessingSort
> = formData => {
// the sortOperator only used in the barchart v2
const sortableLabels = [
getXAxisLabel(formData),

View File

@@ -1,31 +0,0 @@
/**
* 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.
*/
// /superset/sqllab_viz
interface SqlLabPostRequest {
data: {
schema: string;
sql: string;
dbId: number;
templateParams?: string | undefined;
datasourceName: string;
metrics?: string[];
columns?: string[];
};
}

View File

@@ -27,6 +27,8 @@ import getLabelsColorMap, {
import { getAnalogousColors } from './utils';
import { FeatureFlag, isFeatureEnabled } from '../utils';
/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */
// Use type augmentation to correct the fact that
// an instance of CategoricalScale is also a function
interface CategoricalColorScale {

View File

@@ -17,6 +17,7 @@
* under the License.
*/
import { StoryObj } from '@storybook/react';
import { noop } from 'lodash';
import { SelectOptionsType, SelectProps } from './types';
import { Select } from '.';
@@ -93,23 +94,26 @@ export const InteractiveSelect: StoryObj = {
options,
optionsCount,
...args
}: SelectProps & { header: string; optionsCount: number }) => (
<div
style={{
width: DEFAULT_WIDTH,
}}
>
<Select
{...args}
options={
Array.isArray(options)
? generateOptions(options, optionsCount)
: options
}
mode="multiple"
/>
</div>
),
}: SelectProps & { header: string; optionsCount: number }) => {
noop(header);
return (
<div
style={{
width: DEFAULT_WIDTH,
}}
>
<Select
{...args}
options={
Array.isArray(options)
? generateOptions(options, optionsCount)
: options
}
mode="multiple"
/>
</div>
);
},
args: {
autoFocus: true,
allowNewOptions: false,

View File

@@ -21,6 +21,8 @@ import { ExtensibleFunction } from '../models';
import { getNumberFormatter, NumberFormats } from '../number-format';
import { Currency } from '../query';
/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */
interface CurrencyFormatterConfig {
d3Format?: string;
currency: Currency;

View File

@@ -20,6 +20,8 @@ import { ExtensibleFunction } from '../models';
import { isRequired } from '../utils';
import { NumberFormatFunction } from './types';
/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */
export const PREVIEW_VALUE = 12345.432;
export interface NumberFormatterConfig {

View File

@@ -35,6 +35,7 @@ import {
CacheProvider as EmotionCacheProvider,
} from '@emotion/react';
import createCache from '@emotion/cache';
import { noop } from 'lodash';
import { GlobalStyles } from './GlobalStyles';
import {
@@ -285,6 +286,7 @@ export class Theme {
antdConfig: AntdThemeConfig,
emotionCache: any,
): void {
noop(theme, antdConfig, emotionCache);
// Overridden at runtime by SupersetThemeProvider using setThemeState
}

View File

@@ -21,6 +21,8 @@ import { isRequired } from '../utils';
import { TimeFormatFunction } from './types';
import stringifyTimeInput from './utils/stringifyTimeInput';
/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */
export const PREVIEW_TIME = new Date(Date.UTC(2017, 1, 14, 11, 22, 33));
// Use type augmentation to indicate that

View File

@@ -19,6 +19,8 @@
import { ExtensibleFunction } from '../models';
import { TimeRangeFormatFunction } from './types';
/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */
// Use type augmentation to indicate that
// an instance of TimeFormatter is also a function
interface TimeRangeFormatter {

View File

@@ -17,6 +17,8 @@
* under the License.
*/
/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */
import { ExtensibleFunction } from '@superset-ui/core';
describe('ExtensibleFunction', () => {

View File

@@ -28,9 +28,7 @@ const colorTypes = [
'grayscale',
];
const AntDFunctionalColors = ({ antdTheme }) => {
const { antd } = supersetTheme;
const AntDFunctionalColors = () => {
// Define color types and variants dynamically
const variants = [
'active',
@@ -44,7 +42,6 @@ const AntDFunctionalColors = ({ antdTheme }) => {
'bg',
];
const { colors } = supersetTheme;
return (
<table
style={{ borderCollapse: 'collapse', width: '100%', textAlign: 'left' }}
@@ -63,32 +60,29 @@ const AntDFunctionalColors = ({ antdTheme }) => {
</tr>
</thead>
<tbody>
{colorTypes.map(type => {
const typeKey = `color${type}`;
return (
<tr key={type}>
<td style={{ border: '1px solid #ddd', padding: '8px' }}>
<strong>{type}</strong>
</td>
{variants.map(variant => {
const color = themeObject.getColorVariants(type)[variant];
return (
<td
key={variant}
style={{
border: '1px solid #ddd',
padding: '8px',
backgroundColor: color || 'transparent',
color: [`color${type}${variant}`],
}}
>
{color ? <code>{color}</code> : '-'}
</td>
);
})}
</tr>
);
})}
{colorTypes.map(type => (
<tr key={type}>
<td style={{ border: '1px solid #ddd', padding: '8px' }}>
<strong>{type}</strong>
</td>
{variants.map(variant => {
const color = themeObject.getColorVariants(type)[variant];
return (
<td
key={variant}
style={{
border: '1px solid #ddd',
padding: '8px',
backgroundColor: color || 'transparent',
color: `color${type}${variant}`,
}}
>
{color ? <code>{color}</code> : '-'}
</td>
);
})}
</tr>
))}
</tbody>
</table>
);
@@ -159,7 +153,7 @@ export const ThemeColors = () => {
</table>
<h2>Ant Design Theme Colors</h2>
<h3>Functional Colors</h3>
<AntDFunctionalColors antdTheme={supersetTheme.antd} />
<AntDFunctionalColors />
<h2>The supersetTheme object</h2>
<pre>
<code>{JSON.stringify(supersetTheme, null, 2)}</code>

View File

@@ -23,6 +23,7 @@ import {
sharedControls,
sections,
} from '@superset-ui/chart-controls';
import { noop } from 'lodash';
import {
headerFontSize,
subheaderFontSize,
@@ -143,6 +144,7 @@ const config: ControlPanelConfig = {
return true;
},
mapStateToProps(explore, _, chart) {
noop(explore, _, chart);
return {
columnsPropsObject: {
colnames: ['Previous value', 'Delta', 'Percent change'],

View File

@@ -36,7 +36,10 @@ jest.mock('@superset-ui/core', () => ({
jest.mock('../utils', () => ({
getDateFormatter: jest.fn(() => (v: any) => `${v}pm`),
parseMetricValue: jest.fn(val => Number(val)),
getOriginalLabel: jest.fn((metric, metrics) => metric),
getOriginalLabel: jest.fn((metric, metrics) => {
console.log(metrics);
return metric;
}),
}));
describe('BigNumberTotal transformProps', () => {

View File

@@ -39,7 +39,10 @@ jest.mock('@superset-ui/core', () => ({
jest.mock('../utils', () => ({
getDateFormatter: jest.fn(() => (v: any) => `${v}pm`),
parseMetricValue: jest.fn(val => Number(val)),
getOriginalLabel: jest.fn((metric, metrics) => metric),
getOriginalLabel: jest.fn((metric, metrics) => {
console.log(metrics);
return metric;
}),
}));
jest.mock('../../utils/tooltip', () => ({

View File

@@ -44,6 +44,6 @@
"devDependencies": {
"@types/jest": "^29.5.14",
"@types/lodash": "^4.17.16",
"jest": "^29.7.0"
"jest": "^30.0.2"
}
}

View File

@@ -38,6 +38,6 @@
"devDependencies": {
"@babel/types": "^7.26.9",
"@types/jest": "^29.5.12",
"jest": "^29.7.0"
"jest": "^30.0.2"
}
}

View File

@@ -29,6 +29,7 @@ import {
} from 'spec/helpers/testing-library';
import ShareSqlLabQuery from 'src/SqlLab/components/ShareSqlLabQuery';
import { initialState } from 'src/SqlLab/fixtures';
import { omit } from 'lodash';
const mockStore = configureStore([thunk]);
const defaultProps = {
@@ -110,7 +111,7 @@ describe('ShareSqlLabQuery', () => {
});
});
const button = screen.getByRole('button');
const { id: _id, remoteId: _remoteId, ...expected } = mockQueryEditor;
const expected = omit(mockQueryEditor, ['id', 'remoteId']);
userEvent.click(button);
await waitFor(() =>
expect(fetchMock.calls(storeQueryUrl)).toHaveLength(1),
@@ -134,7 +135,7 @@ describe('ShareSqlLabQuery', () => {
});
});
const button = screen.getByRole('button');
const { id: _id, ...expected } = unsavedQueryEditor;
const expected = omit(unsavedQueryEditor, ['id']);
userEvent.click(button);
await waitFor(() =>
expect(fetchMock.calls(storeQueryUrl)).toHaveLength(1),

View File

@@ -42,6 +42,7 @@ import {
LocalStorageKeys,
setItem,
} from 'src/utils/localStorageHelpers';
import { noop } from 'lodash';
import TableElement from '../TableElement';
export interface SqlEditorLeftBarProps {
@@ -98,6 +99,8 @@ const SqlEditorLeftBar = ({
[allSelectedTables, dbId, schema],
);
noop(_emptyResultsWithSearch); // This is to avoid unused variable warning, can be removed if not needed
useEffect(() => {
const bool = new URLSearchParams(window.location.search).get('db');
const userSelected = getItem(

View File

@@ -35,7 +35,6 @@ interface DatabaseErrorExtra {
export function DatabaseErrorMessage({
error,
source,
subtitle,
}: ErrorMessageComponentProps<DatabaseErrorExtra | null>) {
const { extra, level, message } = error;

View File

@@ -33,7 +33,6 @@ interface SupersetParseErrorExtra {
*/
export function InvalidSQLErrorMessage({
error,
source,
subtitle,
}: ErrorMessageComponentProps<SupersetParseErrorExtra>) {
const { extra, level, message } = error;

View File

@@ -54,7 +54,6 @@ const findMatches = (undefinedParameters: string[], templateKeys: string[]) => {
export function ParameterErrorMessage({
error,
source = 'sqllab',
subtitle,
}: ErrorMessageComponentProps<ParameterErrorExtra>) {
const { extra = { issue_codes: [] }, level, message } = error;

View File

@@ -30,7 +30,7 @@ import {
export const useNativeFilters = () => {
const [isInitialized, setIsInitialized] = useState(false);
const showNativeFilters = useSelector<RootState, boolean>(
state => getUrlParam(URL_PARAMS.showFilters) ?? true,
() => getUrlParam(URL_PARAMS.showFilters) ?? true,
);
const canEdit = useSelector<RootState, boolean>(
({ dashboardInfo }) => dashboardInfo.dash_edit_perm,

View File

@@ -31,7 +31,7 @@ const mockAddDangerToast = jest.fn();
jest.mock('src/utils/downloadAsImage', () => ({
__esModule: true,
default: jest.fn(() => (_e: SyntheticEvent) => {}),
default: jest.fn(() => (_e: SyntheticEvent) => console.log(_e)),
}));
jest.mock('src/components/MessageToasts/withToasts', () => ({

View File

@@ -31,7 +31,7 @@ const mockAddDangerToast = jest.fn();
jest.mock('src/utils/downloadAsPdf', () => ({
__esModule: true,
default: jest.fn(() => (_e: SyntheticEvent) => {}),
default: jest.fn(() => (_e: SyntheticEvent) => console.log(_e)),
}));
jest.mock('src/components/MessageToasts/withToasts', () => ({

View File

@@ -181,7 +181,7 @@ const HorizontalFormItem = styled(StyledFormItem)<{
}
.select-container {
${({ inverseSelection, theme }) =>
${({ inverseSelection }) =>
inverseSelection &&
`
width: 164px;

View File

@@ -232,7 +232,7 @@ export const DashboardPage: FC<PageProps> = ({ idOrSlug }: PageProps) => {
const globalStyles = useMemo(
() => [
filterCardPopoverStyle(theme),
filterCardPopoverStyle(),
headerStyles(theme),
chartContextMenuStyles(theme),
focusStyle(theme),

View File

@@ -65,7 +65,7 @@ export const chartHeaderStyles = (theme: SupersetTheme) => css`
}
`;
export const filterCardPopoverStyle = (theme: SupersetTheme) => css`
export const filterCardPopoverStyle = () => css`
.filter-card-tooltip {
&.ant-tooltip-placement-bottom {
padding-top: 0;

View File

@@ -75,51 +75,50 @@ const expectedDisplayValues = {
test('useTableColumns with no options', () => {
const hook = renderHook(() => useTableColumns(colnames, coltypes, data));
expect(hook.result.current).toEqual([
{
Cell: expect.any(Function),
Header: 'col01',
accessor: expect.any(Function),
id: 'col01',
},
{
Cell: expect.any(Function),
Header: 'col02',
accessor: expect.any(Function),
id: 'col02',
},
{
Cell: expect.any(Function),
Header: ASCII_KEY,
accessor: expect.any(Function),
id: ASCII_KEY,
},
{
Cell: expect.any(Function),
Header: UNICODE_KEY,
accessor: expect.any(Function),
id: UNICODE_KEY,
},
{
Cell: expect.any(Function),
Header: expect.objectContaining({
type: expect.objectContaining({
name: 'DataTableTemporalHeaderCell',
}),
props: expect.objectContaining({
onTimeColumnChange: expect.any(Function),
}),
}),
accessor: expect.any(Function),
id: NUMTIME_KEY,
},
{
Cell: expect.any(Function),
Header: STRTIME_KEY,
accessor: expect.any(Function),
id: STRTIME_KEY,
},
]);
expect(hook.result.current).toMatchInlineSnapshot(`
[
{
"Cell": [Function],
"Header": "col01",
"accessor": [Function],
"id": "col01",
},
{
"Cell": [Function],
"Header": "col02",
"accessor": [Function],
"id": "col02",
},
{
"Cell": [Function],
"Header": " !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_\`abcdefghijklmnopqrstuvwxyz{|}~",
"accessor": [Function],
"id": " !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_\`abcdefghijklmnopqrstuvwxyz{|}~",
},
{
"Cell": [Function],
"Header": "你好. 吃了吗?",
"accessor": [Function],
"id": "你好. 吃了吗?",
},
{
"Cell": [Function],
"Header": <DataTableTemporalHeaderCell
columnName="numtime"
isOriginalTimeColumn={false}
onTimeColumnChange={[Function]}
/>,
"accessor": [Function],
"id": "numtime",
},
{
"Cell": [Function],
"Header": "strtime",
"accessor": [Function],
"id": "strtime",
},
]
`);
hook.result.current.forEach((col: JsonObject) => {
expect(col.accessor(data[0])).toBe(data[0][col.id]);
});
@@ -139,51 +138,50 @@ test('useTableColumns with options', () => {
col01: { Header: 'Header' },
}),
);
expect(hook.result.current).toEqual([
{
Cell: expect.any(Function),
Header: 'Header',
accessor: expect.any(Function),
id: 'col01',
},
{
Cell: expect.any(Function),
Header: 'col02',
accessor: expect.any(Function),
id: 'col02',
},
{
Cell: expect.any(Function),
Header: ASCII_KEY,
accessor: expect.any(Function),
id: ASCII_KEY,
},
{
Cell: expect.any(Function),
Header: UNICODE_KEY,
accessor: expect.any(Function),
id: UNICODE_KEY,
},
{
Cell: expect.any(Function),
Header: expect.objectContaining({
type: expect.objectContaining({
name: 'DataTableTemporalHeaderCell',
}),
props: expect.objectContaining({
onTimeColumnChange: expect.any(Function),
}),
}),
accessor: expect.any(Function),
id: NUMTIME_KEY,
},
{
Cell: expect.any(Function),
Header: STRTIME_KEY,
accessor: expect.any(Function),
id: STRTIME_KEY,
},
]);
expect(hook.result.current).toMatchInlineSnapshot(`
[
{
"Cell": [Function],
"Header": "Header",
"accessor": [Function],
"id": "col01",
},
{
"Cell": [Function],
"Header": "col02",
"accessor": [Function],
"id": "col02",
},
{
"Cell": [Function],
"Header": " !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_\`abcdefghijklmnopqrstuvwxyz{|}~",
"accessor": [Function],
"id": " !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_\`abcdefghijklmnopqrstuvwxyz{|}~",
},
{
"Cell": [Function],
"Header": "你好. 吃了吗?",
"accessor": [Function],
"id": "你好. 吃了吗?",
},
{
"Cell": [Function],
"Header": <DataTableTemporalHeaderCell
columnName="numtime"
isOriginalTimeColumn={false}
onTimeColumnChange={[Function]}
/>,
"accessor": [Function],
"id": "numtime",
},
{
"Cell": [Function],
"Header": "strtime",
"accessor": [Function],
"id": "strtime",
},
]
`);
hook.result.current.forEach((col: JsonObject) => {
expect(col.accessor(data[0])).toBe(data[0][col.id]);
});

View File

@@ -39,7 +39,7 @@ import {
import { DataTablesPaneProps, ResultTypes } from './types';
const StyledDiv = styled.div`
${({ theme }) => `
${() => `
display: flex;
height: 100%;
flex-direction: column;

View File

@@ -19,7 +19,7 @@
import { useEffect, useState } from 'react';
import { useSelector } from 'react-redux';
import { isEmpty, isEqual } from 'lodash';
import { isEmpty, isEqual, noop } from 'lodash';
import {
BinaryAdhocFilter,
css,
@@ -61,6 +61,8 @@ const oldChoices = {
export const ComparisonRangeLabel = ({
multi = true,
}: ComparisonRangeLabelProps) => {
noop(multi); // This is to avoid unused variable warning, can be removed if not needed
const [labels, setLabels] = useState<string[]>([]);
const currentTimeRangeFilters = useSelector<RootState, BinaryAdhocFilter[]>(
state =>

View File

@@ -38,7 +38,9 @@ const defaultProps = {
multi: true,
needAsyncVerification: true,
actions: { setControlValue: mockSetControlValue },
onChange: (p0: string[]) => {},
onChange: (p0: string[]) => {
console.log('onChange called with:', p0);
},
columns: [
{ type: 'VARCHAR(255)', column_name: 'source' },
{ type: 'VARCHAR(255)', column_name: 'target' },

View File

@@ -59,11 +59,7 @@ export interface EmptyStateProps {
otherTabTitle?: string;
}
export default function EmptyState({
tableName,
tab,
otherTabTitle,
}: EmptyStateProps) {
export default function EmptyState({ tableName, tab }: EmptyStateProps) {
const getActionButton = () => {
if (tableName === WelcomeTable.Recents) {
return null;

View File

@@ -47,10 +47,7 @@ interface TagCardProps {
function TagCard({
tag,
hasPerm,
bulkSelectEnabled,
tagFilter,
refreshData,
userId,
addDangerToast,
addSuccessToast,
showThumbnails,

View File

@@ -234,7 +234,7 @@ const TagModal: FC<TagModalProps> = ({
objects_to_tag: [...dashboards, ...charts, ...savedQueries],
},
})
.then(({ json = {} }) => {
.then(() => {
refreshData();
clearTagForm();
addSuccessToast(t('Tag updated'));
@@ -252,7 +252,7 @@ const TagModal: FC<TagModalProps> = ({
objects_to_tag: [...dashboards, ...charts, ...savedQueries],
},
})
.then(({ json = {} }) => {
.then(() => {
refreshData();
clearTagForm();
addSuccessToast(t('Tag created'));

View File

@@ -74,11 +74,10 @@ export function fetchTags(
{
objectType,
objectId,
includeTypes = false,
}: {
objectType: string;
objectId: number;
includeTypes: boolean;
includeTypes?: boolean;
},
callback: (json: JsonObject) => void,
error: (response: Response) => void,
@@ -151,11 +150,10 @@ export function addTag(
{
objectType,
objectId,
includeTypes = false,
}: {
objectType: string;
objectId: number;
includeTypes: boolean;
includeTypes?: boolean;
},
tag: string,
callback: (text: string) => void,

View File

@@ -109,7 +109,7 @@ function AllEntities() {
const editableTitleProps = {
title: tag?.name || '',
placeholder: 'testing',
onSave: (newDatasetName: string) => {},
onSave: () => {},
canEdit: false,
label: t('dataset name'),
};