Compare commits

...

5 Commits

Author SHA1 Message Date
Evan Rusackas
366ab0f3fd fix(lint): fix incorrectly underscored variables and remove dead props
- Remove underscore from dbId (TreeNodeRenderer) - variable is used
- Remove underscore from columns/folders (DatasourcePanel) - variables are used
- Rename _colnames/_coltypes to queryColnames/queryColtypes (control panels)
- Remove dead datasource, onDatasourceChange, className props from ColumnCollectionTable

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-19 23:32:26 -08:00
Evan Rusackas
96b2cc9e56 fix(lint): remove dead props from GridTable, Modal, and AgGrid components
- Remove unused totals prop from useColDefs
- Remove unused striped prop from GridTable
- Remove unused validateStatus, hasFeedback from ModalFormField
- Remove unused defaultExpanded from CollapsibleModalSection
- Remove unused ariaLabel from RefreshFrequencySelect
- Clean up unused theme params from NumericCellRenderer

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-19 15:34:45 -08:00
Evan Rusackas
66eb994d76 refactor(lint): properly fix unused vars instead of underscore hacks
Instead of just prefixing unused variables with underscores, properly
fix the underlying issues:

- Label: pass `id` through via rest spread instead of ignoring it
- TimezoneSelector: remove unused `minWidth` prop (Select doesn't support style)
- MatrixifyGridCell: remove unused `rowHeight` and `datasource` from interface
- StandardModal: pass through `centered`, `destroyOnHidden`, `maskClosable`
  props to inner Modal; remove dead `cancelText` prop
- TabsRenderer: remove dead `onTabTitleEditingChange` prop from interface
- SaveModal: remove dead props (`addSuccessToast`, `colorNamespace`,
  `colorScheme`, `expandedSlices`)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-19 14:56:51 -08:00
Evan Rusackas
0ac2b42ba5 fix(lint): resolve no-unused-vars errors across frontend
Remove or prefix unused variables to comply with the upgraded
no-unused-vars rule (warn -> error).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-19 09:28:46 -08:00
Evan Rusackas
0206e7bcab chore(lint): upgrade no-unused-vars rule from warn to error
Change @typescript-eslint/no-unused-vars from 'warn' to 'error' in both
eslintrc.js and oxlint.json to enforce stricter code quality.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-19 09:28:45 -08:00
73 changed files with 147 additions and 211 deletions

View File

@@ -375,7 +375,7 @@ module.exports = {
'@typescript-eslint/no-non-null-assertion': 0,
'@typescript-eslint/explicit-function-return-type': 0,
'@typescript-eslint/explicit-module-boundary-types': 0,
'@typescript-eslint/no-unused-vars': 'warn',
'@typescript-eslint/no-unused-vars': 'error',
'@typescript-eslint/prefer-optional-chain': 'error',
// Disable base rules that conflict with TS versions

View File

@@ -23,7 +23,7 @@ import thunk from 'redux-thunk';
import { Provider } from 'react-redux';
import reducerIndex from 'spec/helpers/reducerIndex';
import { Global } from '@emotion/react';
import { App, Layout, Space, Content } from 'antd';
import { App, Layout } from 'antd';
import 'src/theme.ts';
import './storybook.css';

View File

@@ -238,7 +238,14 @@
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/explicit-module-boundary-types": "off",
"@typescript-eslint/no-unused-vars": "warn",
"@typescript-eslint/no-unused-vars": [
"error",
{
"argsIgnorePattern": "^_",
"varsIgnorePattern": "^_",
"caughtErrors": "none"
}
],
"@typescript-eslint/prefer-optional-chain": "error",
"@typescript-eslint/naming-convention": [
"error",

View File

@@ -187,7 +187,7 @@ test('should pass through additional formData properties', () => {
});
test('should handle small cell dimensions', () => {
renderWithTheme(<MatrixifyGridCell {...defaultProps} rowHeight={80} />);
renderWithTheme(<MatrixifyGridCell {...defaultProps} />);
const superChart = screen.getByText('SuperChart Mock');
const cellContainer = superChart.parentElement?.parentElement;

View File

@@ -76,8 +76,6 @@ const NoDataMessage = styled.div<{ theme: any }>`
interface MatrixifyGridCellProps {
cell: GridCellData;
rowHeight: number;
datasource?: any;
hooks?: any;
}
@@ -91,7 +89,7 @@ const MatrixNoDataComponent = () => {
* Individual grid cell component - memoized to prevent unnecessary re-renders
*/
const MatrixifyGridCell = memo(
({ cell, rowHeight, datasource, hooks }: MatrixifyGridCellProps) => {
({ cell, hooks }: MatrixifyGridCellProps) => {
// Use computed title from template (will be empty string if no template)
const cellLabel = cell.title || '';
@@ -173,11 +171,6 @@ const MatrixifyGridCell = memo(
return false;
}
// Re-render if rowHeight changes
if (prevProps.rowHeight !== nextProps.rowHeight) {
return false;
}
// Re-render if cell position changes (shouldn't happen, but just in case)
if (prevProps.cell.id !== nextProps.cell.id) {
return false;

View File

@@ -31,8 +31,8 @@ jest.mock('./MatrixifyGridGenerator', () => ({
// Mock MatrixifyGridCell component
jest.mock('./MatrixifyGridCell', () =>
// eslint-disable-next-line react/display-name, @typescript-eslint/no-unused-vars
({ cell, rowHeight, datasource, hooks }: any) => (
// eslint-disable-next-line react/display-name
({ cell }: any) => (
<div data-testid={`grid-cell-${cell.id}`}>Cell: {cell.id}</div>
),
);

View File

@@ -117,8 +117,8 @@ interface MatrixifyGridRendererProps {
function MatrixifyGridRenderer({
formData,
datasource,
width,
datasource: _datasource,
width: _width,
height,
hooks,
}: MatrixifyGridRendererProps) {
@@ -247,13 +247,11 @@ function MatrixifyGridRenderer({
{/* Row cells for this column group */}
{row
.slice(colGroup.startIdx, colGroup.endIdx)
.map((cell, colIdx) =>
.map(cell =>
cell ? (
<MatrixifyGridCell
key={cell.id}
cell={cell}
rowHeight={rowHeight}
datasource={datasource}
hooks={hooks}
/>
) : null,

View File

@@ -33,7 +33,6 @@ export function Label(props: LabelProps) {
onClick,
children,
icon,
id,
...rest
} = props;

View File

@@ -34,12 +34,9 @@ import 'dayjs/plugin/timezone';
export type TimezoneSelectorProps = {
onTimezoneChange: (value: string) => void;
timezone?: string | null;
minWidth?: string;
placeholder?: string;
};
const MIN_SELECT_WIDTH = '400px';
function findMatchingTimezone(
timezone: string | null | undefined,
options: TimezoneOption[],
@@ -66,7 +63,6 @@ function findMatchingTimezone(
export default function TimezoneSelector({
onTimezoneChange,
timezone,
minWidth = MIN_SELECT_WIDTH,
placeholder,
...rest
}: TimezoneSelectorProps) {

View File

@@ -40,7 +40,7 @@ export default function createD3NumberFormatter(config: {
try {
formatFunc = formatLocale(locale ?? DEFAULT_D3_FORMAT).format(formatString);
} catch (error) {
} catch {
formatFunc = value => `${value} (Invalid format: ${formatString})`;
isInvalid = true;
}

View File

@@ -117,7 +117,7 @@ export default function extractQueryFields(
if (typeof item === 'string') {
try {
return JSON.parse(item);
} catch (error) {
} catch {
throw new Error(t('Found invalid orderby options'));
}
}

View File

@@ -105,7 +105,7 @@ export function initFeatureFlags(featureFlags?: FeatureFlagMap) {
export function isFeatureEnabled(feature: FeatureFlag): boolean {
try {
return !!window.featureFlags[feature as keyof FeatureFlagMap];
} catch (error) {
} catch {
logger.error(`Failed to query feature flag ${feature}`);
}
return false;

View File

@@ -187,7 +187,7 @@ export function isJsonString(str: string): boolean {
try {
JSON.parse(str);
return true;
} catch (e) {
} catch {
return false;
}
}

View File

@@ -111,7 +111,7 @@ function Calendar(element: HTMLElement, props: CalendarProps) {
const colorScheme = getSequentialSchemeRegistry().get(linearColorScheme);
const colorScale = colorScheme
? colorScheme.createLinearScale(extents)
: (v: number) => '#ccc'; // fallback if scheme not found
: (_v: number) => '#ccc'; // fallback if scheme not found
const legend = d3Range(steps).map(i => extents[0] + step * i);
const legendColors = legend.map(x => colorScale(x));

View File

@@ -231,7 +231,6 @@ export default function TableChart<D extends DataRecord = DataRecord>(
defaultAlignPN: alignPositiveNegative,
showCellBars,
colorPositiveNegative,
totals,
columnColorFormatters,
allowRearrangeColumns,
basicColorFormatters,

View File

@@ -512,10 +512,10 @@ const config: ControlPanelConfig = {
mapStateToProps(explore, _, chart) {
const timeComparisonValue =
explore?.controls?.time_compare?.value;
const { colnames: _colnames, coltypes: _coltypes } =
const { colnames: queryColnames, coltypes: queryColtypes } =
chart?.queriesResponse?.[0] ?? {};
let colnames: string[] = _colnames || [];
let coltypes: GenericDataType[] = _coltypes || [];
let colnames: string[] = queryColnames || [];
let coltypes: GenericDataType[] = queryColtypes || [];
const childColumnMap: Record<string, boolean> = {};
const timeComparisonColumnMap: Record<string, boolean> = {};

View File

@@ -16,10 +16,9 @@
* specific language governing permissions and limitations
* under the License.
*/
import { styled, useTheme, type SupersetTheme } from '@apache-superset/core/ui';
import { styled } from '@apache-superset/core/ui';
import { CustomCellRendererProps } from '@superset-ui/core/components/ThemedAgGridReact';
import { BasicColorFormatterType, InputColumn, ValueRange } from '../types';
import { useIsDark } from '../utils/useTableTheme';
const StyledTotalCell = styled.div`
${() => `
@@ -106,13 +105,9 @@ function cellOffset({
function cellBackground({
value,
colorPositiveNegative = false,
isDarkTheme = false,
theme,
}: {
value: number;
colorPositiveNegative: boolean;
isDarkTheme: boolean;
theme: SupersetTheme | null;
}) {
if (!colorPositiveNegative) {
return 'transparent'; // Use transparent background when colorPositiveNegative is false
@@ -149,9 +144,6 @@ export const NumericCellRenderer = (
colorPositiveNegative,
} = params;
const isDarkTheme = useIsDark();
const theme = !colorPositiveNegative ? null : useTheme();
if (node?.rowPinned === 'bottom') {
return <StyledTotalCell>{valueFormatted ?? value}</StyledTotalCell>;
}
@@ -195,8 +187,6 @@ export const NumericCellRenderer = (
const background = cellBackground({
value: value as number,
colorPositiveNegative,
isDarkTheme,
theme,
});
return (

View File

@@ -19,7 +19,7 @@
*/
import { ColDef } from '@superset-ui/core/components/ThemedAgGridReact';
import { useCallback, useMemo } from 'react';
import { DataRecord, DataRecordValue } from '@superset-ui/core';
import { DataRecordValue } from '@superset-ui/core';
import { GenericDataType } from '@apache-superset/core/api/core';
import { ColorFormatters } from '@superset-ui/chart-controls';
import { extent as d3Extent, max as d3Max } from 'd3-array';
@@ -53,7 +53,6 @@ type UseColDefsProps = {
defaultAlignPN: boolean;
showCellBars: boolean;
colorPositiveNegative: boolean;
totals: DataRecord | undefined;
columnColorFormatters: ColorFormatters;
allowRearrangeColumns?: boolean;
basicColorFormatters?: { [Key: string]: BasicColorFormatterType }[];
@@ -216,7 +215,6 @@ export const useColDefs = ({
defaultAlignPN,
showCellBars,
colorPositiveNegative,
totals,
columnColorFormatters,
allowRearrangeColumns,
basicColorFormatters,

View File

@@ -52,14 +52,14 @@ function BigNumberVis({
kickerFontSize = PROPORTION.KICKER,
metricNameFontSize = PROPORTION.METRIC_NAME,
showMetricName = true,
mainColor = BRAND_COLOR,
mainColor: _mainColor = BRAND_COLOR,
showTimestamp = false,
showTrendLine = false,
startYAxisAtZero = true,
startYAxisAtZero: _startYAxisAtZero = true,
subheader = '',
subheaderFontSize = PROPORTION.SUBHEADER,
subtitleFontSize = PROPORTION.SUBHEADER,
timeRangeFixed = false,
timeRangeFixed: _timeRangeFixed = false,
...props
}: BigNumberVizProps) {
const theme = useTheme();

View File

@@ -213,10 +213,10 @@ const config: ControlPanelConfig = {
}
return value.label;
});
const { colnames: _colnames, coltypes: _coltypes } =
const { colnames: queryColnames, coltypes: queryColtypes } =
chart?.queriesResponse?.[0] ?? {};
const colnames: string[] = _colnames || [];
const coltypes: GenericDataType[] = _coltypes || [];
const colnames: string[] = queryColnames || [];
const coltypes: GenericDataType[] = queryColtypes || [];
return {
queryResponse: chart?.queriesResponse?.[0] as

View File

@@ -341,12 +341,12 @@ const config: ControlPanelConfig = {
'Stack in groups, where each group corresponds to a dimension',
),
shouldMapStateToProps: (
prevState,
state,
controlState,
chartState,
_prevState,
_state,
_controlState,
_chartState,
) => true,
mapStateToProps: (state, controlState, chartState) => {
mapStateToProps: (state, _controlState, _chartState) => {
const value: JsonArray = ensureIsArray(
state.controls.groupby?.value,
) as JsonArray;

View File

@@ -106,7 +106,7 @@ const mockGroups = {
const createMockPivotData = (rowData: Record<string, number>) =>
({
rowKeys: Object.keys(rowData).map(key => key.split('.')),
getAggregator: (rowKey: string[], colName: string) => ({
getAggregator: (rowKey: string[], _colName: string) => ({
value: () => rowData[rowKey.join('.')],
}),
}) as unknown as PivotData;

View File

@@ -570,10 +570,10 @@ const config: ControlPanelConfig = {
mapStateToProps(explore, _, chart) {
const timeComparisonValue =
explore?.controls?.time_compare?.value;
const { colnames: _colnames, coltypes: _coltypes } =
const { colnames: queryColnames, coltypes: queryColtypes } =
chart?.queriesResponse?.[0] ?? {};
let colnames: string[] = _colnames || [];
let coltypes: GenericDataType[] = _coltypes || [];
let colnames: string[] = queryColnames || [];
let coltypes: GenericDataType[] = queryColtypes || [];
const childColumnMap: Record<string, boolean> = {};
const timeComparisonColumnMap: Record<string, boolean> = {};

View File

@@ -86,7 +86,7 @@ const TreeNodeRenderer: React.FC<TreeNodeRendererProps> = ({
}) => {
const { data } = node;
const parts = data.id.split(':');
const [identifier, _dbId, schema, tableName] = parts;
const [identifier, dbId, schema, tableName] = parts;
// Use manually tracked open state for icon display
// This prevents search auto-expansion from affecting the icon
@@ -205,7 +205,7 @@ const TreeNodeRenderer: React.FC<TreeNodeRendererProps> = ({
onClick={e => {
e.stopPropagation();
fetchLazyTables({
dbId: _dbId,
dbId,
catalog,
schema,
forceRefresh: true,

View File

@@ -71,7 +71,7 @@ export const ItemSeparator = styled.div<{
export const TreeFolderContainer = styled(TreeItemContainer)<{
isForbiddenDropTarget?: boolean;
}>`
${({ theme, depth, isForbiddenDropTarget, isOverlay }) => `
${({ theme, depth, isForbiddenDropTarget, isOverlay: _isOverlay }) => `
margin-top: 0;
margin-bottom: 0;
padding-top: ${theme.paddingSM}px;

View File

@@ -288,14 +288,11 @@ interface CollectionTabTitleProps {
interface ColumnCollectionTableProps {
columns: Column[];
datasource: DatasourceObject;
onColumnsChange: (columns: Column[]) => void;
onDatasourceChange: (datasource: DatasourceObject) => void;
editableColumnName?: boolean;
showExpression?: boolean;
allowAddItem?: boolean;
allowEditDataType?: boolean;
className?: string;
itemGenerator?: () => Partial<Column>;
columnLabelTooltips?: Record<string, string>;
}
@@ -472,9 +469,7 @@ function CollectionTabTitle({
function ColumnCollectionTable({
columns,
datasource,
onColumnsChange,
onDatasourceChange,
editableColumnName = false,
showExpression = false,
allowAddItem = false,
@@ -2320,13 +2315,10 @@ class DatasourceEditor extends PureComponent<
</StyledButtonWrapper>
</ColumnButtonWrapper>
<ColumnCollectionTable
className="columns-table"
columns={this.state.databaseColumns}
datasource={datasource}
onColumnsChange={databaseColumns =>
this.setColumns({ databaseColumns })
}
onDatasourceChange={this.onDatasourceChange}
/>
{this.state.metadataLoading && <Loading />}
</StyledTableTabWrapper>
@@ -2358,8 +2350,6 @@ class DatasourceEditor extends PureComponent<
'as the alias in the SQL query.',
),
}}
onDatasourceChange={this.onDatasourceChange}
datasource={datasource}
editableColumnName
showExpression
allowAddItem

View File

@@ -23,7 +23,7 @@ import { ErrorAlert } from './ErrorAlert';
export function FrontendNetworkErrorMessage({
error,
subtitle,
subtitle: _subtitle,
compact,
}: ErrorMessageComponentProps) {
const { level, message } = error;

View File

@@ -64,7 +64,6 @@ export const FilterableTable = ({
filterText = '',
expandedColumns = [],
allowHTML = true,
striped,
}: FilterableTableProps) => {
const getCellContent = useCellContentParser({
columnKeys: orderedColumnKeys,
@@ -128,7 +127,6 @@ export const FilterableTable = ({
data={data}
externalFilter={keywordFilter}
showRowNumber
striped={striped}
enableActions
columnReorderable
/>

View File

@@ -28,7 +28,6 @@ export interface FilterableTableProps {
overscanColumnCount?: number;
overscanRowCount?: number;
rowHeight?: number;
striped?: boolean;
expandedColumns?: string[];
allowHTML?: boolean;
}

View File

@@ -45,7 +45,6 @@ export function GridTable<RecordType extends object>({
showRowNumber,
enableActions,
size = GridSize.Middle,
striped,
}: TableProps<RecordType>) {
const theme = useTheme();
const isExternalFilterPresent = useCallback(

View File

@@ -57,6 +57,4 @@ export interface TableProps<RecordType> {
showRowNumber?: boolean;
usePagination?: boolean;
striped?: boolean;
}

View File

@@ -24,7 +24,6 @@ interface CollapsibleModalSectionProps {
sectionKey: string;
title: string;
subtitle?: string;
defaultExpanded?: boolean;
hasErrors?: boolean;
testId?: string;
children: ReactNode;
@@ -41,7 +40,6 @@ export function CollapsibleModalSection({
sectionKey,
title,
subtitle,
defaultExpanded = false,
hasErrors = false,
testId,
children,

View File

@@ -29,8 +29,6 @@ interface ModalFormFieldProps {
bottomSpacing?: boolean;
children: ReactNode;
testId?: string;
validateStatus?: 'success' | 'warning' | 'error' | 'validating';
hasFeedback?: boolean;
}
const StyledFieldContainer = styled.div<{ bottomSpacing: boolean }>`
@@ -125,8 +123,6 @@ export function ModalFormField({
bottomSpacing = true,
children,
testId,
validateStatus,
hasFeedback = false,
}: ModalFormFieldProps) {
return (
<StyledFieldContainer bottomSpacing={bottomSpacing} data-test={testId}>

View File

@@ -32,12 +32,11 @@ interface StandardModalProps {
saveDisabled?: boolean;
saveLoading?: boolean;
saveText?: string;
cancelText?: string;
errorTooltip?: ReactNode;
children: ReactNode;
isEditMode?: boolean;
centered?: boolean;
destroyOnClose?: boolean;
destroyOnHidden?: boolean;
maskClosable?: boolean;
wrapProps?: object;
contentLoading?: boolean;
@@ -107,12 +106,11 @@ export function StandardModal({
saveDisabled = false,
saveLoading = false,
saveText,
cancelText,
errorTooltip,
children,
isEditMode = false,
centered = true,
destroyOnClose = true,
destroyOnHidden = true,
maskClosable = false,
wrapProps,
contentLoading = false,
@@ -129,6 +127,9 @@ export function StandardModal({
primaryButtonName={primaryButtonName}
show={show}
width={`${width}px`}
centered={centered}
destroyOnHidden={destroyOnHidden}
maskClosable={maskClosable}
wrapProps={wrapProps}
title={
icon ? (

View File

@@ -166,7 +166,7 @@ describe('loadTags', () => {
const calls = fetchMock.callHistory.calls();
// Verify all calls include the custom tag filter
calls.forEach(call => {
calls.forEach(() => {
const { url } = calls[0];
const urlObj = new URL(url);
const queryParam = urlObj.searchParams.get('q');

View File

@@ -173,7 +173,11 @@ export class QueryResultContext
requestedLimit?: number;
} = {},
) {
const { appliedLimit, appliedLimitingFactor, ...opt } = options;
const {
appliedLimit,
appliedLimitingFactor: _appliedLimitingFactor,
...opt
} = options;
super(clientId, tab, runAsync, startDttm, opt);
this.remoteId = remoteId;
this.executedSql = executedSql;
@@ -216,7 +220,7 @@ export class QueryErrorResultContext
queryId?: number;
} = {},
) {
const { queryId, executedSql, endDttm, ...opt } = options;
const { queryId: _queryId, executedSql, endDttm, ...opt } = options;
super(clientId, tab, runAsync, startDttm, opt);
this.executedSql = executedSql ?? null;
this.errorMessage = errorMessage;

View File

@@ -230,20 +230,16 @@ export const useHeaderActionsMenu = ({
createModalMenuItem(
MenuKeys.SaveModal,
<SaveModal
addSuccessToast={addSuccessToast}
addDangerToast={addDangerToast}
dashboardId={dashboardId}
dashboardTitle={dashboardTitle ?? ''}
dashboardInfo={dashboardInfo}
saveType={SAVE_TYPE_NEWDASHBOARD}
layout={layout}
expandedSlices={expandedSlices ?? {}}
refreshFrequency={refreshFrequency}
shouldPersistRefreshFrequency={shouldPersistRefreshFrequency}
lastModifiedTime={lastModifiedTime}
customCss={customCss ?? ''}
colorNamespace={colorNamespace}
colorScheme={colorScheme}
onSave={onSave}
triggerNode={
<div data-test="save-as-menu-item">{t('Save as')}</div>

View File

@@ -67,7 +67,6 @@ export const REFRESH_FREQUENCY_OPTIONS = [
interface RefreshFrequencySelectProps {
value: number;
onChange: (value: number) => void;
ariaLabel?: string;
}
/**
@@ -77,7 +76,6 @@ interface RefreshFrequencySelectProps {
export const RefreshFrequencySelect = ({
value,
onChange,
ariaLabel = t('Refresh frequency'),
}: RefreshFrequencySelectProps) => {
// Separate radio selection state from value state
const [radioSelection, setRadioSelection] = useState(() =>

View File

@@ -42,18 +42,14 @@ import {
type SaveType = typeof SAVE_TYPE_OVERWRITE | typeof SAVE_TYPE_NEWDASHBOARD;
type SaveModalProps = {
addSuccessToast: (arg: string) => void;
addDangerToast: (arg: string) => void;
dashboardId: number;
dashboardTitle: string;
dashboardInfo: Record<string, any>;
expandedSlices: Record<string, any>;
layout: Record<string, any>;
saveType: SaveType;
triggerNode: JSX.Element;
customCss: string;
colorNamespace?: string;
colorScheme?: string;
onSave: (data: any, id: number | string, saveType: SaveType) => void;
canOverwrite: boolean;
shouldPersistRefreshFrequency: boolean;
@@ -65,18 +61,14 @@ type SaveModalProps = {
function SaveModal({
saveType: initialSaveType = SAVE_TYPE_OVERWRITE,
colorNamespace,
colorScheme,
shouldPersistRefreshFrequency = false,
dashboardTitle,
onSave,
triggerNode,
canOverwrite,
addSuccessToast,
addDangerToast,
dashboardId,
dashboardInfo,
expandedSlices,
layout,
customCss,
refreshFrequency,

View File

@@ -35,7 +35,7 @@ describe('Divider', () => {
index: 0,
editMode: false,
handleComponentDrop: jest.fn(),
deleteComponent: (id: string, parentId: string) => {},
deleteComponent: () => {},
};
const setup = (overrideProps: Partial<DividerProps> = {}) =>

View File

@@ -543,7 +543,6 @@ const Tabs = (props: TabsProps): ReactElement => {
tabBarPaddingLeft={tabBarPaddingLeft}
onTabsReorder={handleTabsReorder}
isEditingTabTitle={isEditingTabTitle}
onTabTitleEditingChange={handleTabTitleEditingChange}
/>
),
[
@@ -559,7 +558,6 @@ const Tabs = (props: TabsProps): ReactElement => {
tabBarPaddingLeft,
handleTabsReorder,
isEditingTabTitle,
handleTabTitleEditingChange,
],
);

View File

@@ -108,7 +108,6 @@ export interface TabsRendererProps {
tabBarPaddingLeft?: number;
onTabsReorder?: (oldIndex: number, newIndex: number) => void;
isEditingTabTitle?: boolean;
onTabTitleEditingChange?: (isEditing: boolean) => void;
}
interface DraggableTabNodeProps extends React.HTMLAttributes<HTMLDivElement> {
@@ -117,7 +116,7 @@ interface DraggableTabNodeProps extends React.HTMLAttributes<HTMLDivElement> {
}
const DraggableTabNode: React.FC<Readonly<DraggableTabNodeProps>> = ({
className,
className: _className,
disabled = false,
...props
}) => {
@@ -170,7 +169,6 @@ const TabsRenderer = memo<TabsRendererProps>(
tabBarPaddingLeft = 0,
onTabsReorder,
isEditingTabTitle = false,
onTabTitleEditingChange,
}) => {
const [activeId, setActiveId] = useState<string | null>(null);

View File

@@ -141,7 +141,7 @@ export default class WithPopoverMenu extends PureComponent<
this.handleClick = this.handleClick.bind(this);
}
componentDidUpdate(prevProps: WithPopoverMenuProps) {
componentDidUpdate(_prevProps: WithPopoverMenuProps) {
if (this.props.editMode && this.props.isFocused && !this.state.isFocused) {
document.addEventListener('click', this.handleClick);
document.addEventListener('drag', this.handleClick);

View File

@@ -71,7 +71,7 @@ export const useFilterConfigModal = ({
);
}
closeFilterConfigModal();
} catch (error) {
} catch {
// Error toast already shown in action, prevent modal close
}
},

View File

@@ -268,7 +268,7 @@ const FilterControls: FC<FilterControlsProps> = ({
);
const customizationRenderer = useCallback(
(item: ChartCustomization | ChartCustomizationDivider, index: number) => {
(item: ChartCustomization | ChartCustomizationDivider, _index: number) => {
if (isChartCustomizationDivider(item)) {
return (
<FilterDivider

View File

@@ -139,8 +139,8 @@ const VerticalFilterBar: FC<VerticalBarProps> = ({
onPendingCustomizationDataMaskChange,
toggleFiltersBar,
width,
clearAllTriggers,
onClearAllComplete,
clearAllTriggers: _clearAllTriggers,
onClearAllComplete: _onClearAllComplete,
}) => {
const theme = useTheme();
const [isScrolling, setIsScrolling] = useState(false);

View File

@@ -321,12 +321,11 @@ function FiltersConfigModal({
(dragIndex: number, targetIndex: number, id: string) => {
const isFilter = isFilterId(id);
if (isFilter) {
filterOperations.handleRearrangeFilters(dragIndex, targetIndex, id);
filterOperations.handleRearrangeFilters(dragIndex, targetIndex);
} else {
customizationOperations.handleRearrangeCustomizations(
dragIndex,
targetIndex,
id,
);
}
},

View File

@@ -35,7 +35,6 @@ export interface CustomizationOperations {
handleRearrangeCustomizations: (
dragIndex: number,
targetIndex: number,
id: string,
) => void;
}
@@ -105,7 +104,7 @@ export function useCustomizationOperations({
);
const handleRearrangeCustomizations = useCallback(
(dragIndex: number, targetIndex: number, id: string) => {
(dragIndex: number, targetIndex: number) => {
const newOrderedIds = [...customizationState.orderedIds];
const [removed] = newOrderedIds.splice(dragIndex, 1);
newOrderedIds.splice(targetIndex, 0, removed);

View File

@@ -50,11 +50,7 @@ export interface FilterOperations {
addFilter: (type: NativeFilterType) => void;
handleRemoveFilter: (id: string) => void;
restoreFilter: (id: string) => void;
handleRearrangeFilters: (
dragIndex: number,
targetIndex: number,
id: string,
) => void;
handleRearrangeFilters: (dragIndex: number, targetIndex: number) => void;
canBeUsedAsDependency: (filterId: string) => boolean;
buildDependencyMap: () => Map<string, string[]>;
getAvailableFilters: (
@@ -125,7 +121,7 @@ export function useFilterOperations({
);
const handleRearrangeFilters = useCallback(
(dragIndex: number, targetIndex: number, id: string) => {
(dragIndex: number, targetIndex: number) => {
const newOrderedIds = [...filterState.orderedIds];
const [removed] = newOrderedIds.splice(dragIndex, 1);
newOrderedIds.splice(targetIndex, 0, removed);

View File

@@ -133,12 +133,12 @@ export default function DataSourcePanel({
width,
}: Props) {
const [dropzones] = useContext(DropzoneContext);
const { columns: _columns, metrics, folders: _folders } = datasource;
const { columns, metrics, folders: rawFolders } = datasource;
const allowedColumns = useMemo(() => {
const validators = Object.values(dropzones);
if (!Array.isArray(_columns)) return [];
return _columns.filter(column =>
if (!Array.isArray(columns)) return [];
return columns.filter(column =>
validators.some(validator =>
validator({
value: column as DndItemValue,
@@ -146,7 +146,7 @@ export default function DataSourcePanel({
}),
),
);
}, [dropzones, _columns]);
}, [dropzones, columns]);
const allowedMetrics = useMemo(() => {
const validators = Object.values(dropzones);
@@ -229,11 +229,11 @@ export default function DataSourcePanel({
transformDatasourceWithFolders(
filteredMetrics,
sortedColumns,
_folders,
rawFolders,
allowedMetrics,
allowedColumns,
),
[_folders, filteredMetrics, sortedColumns],
[rawFolders, filteredMetrics, sortedColumns],
);
const showInfoboxCheck = () => {

View File

@@ -17,7 +17,7 @@
* under the License.
*/
import { forwardRef, RefObject, MouseEvent } from 'react';
import { MouseEvent } from 'react';
import { Button } from '@superset-ui/core/components';
import { ErrorAlert } from 'src/components';
import { styled } from '@apache-superset/core/ui';
@@ -39,20 +39,17 @@ const ButtonContainer = styled.div`
margin-top: ${({ theme }) => theme.sizeUnit * 4}px;
`;
export const ExploreAlert = forwardRef(
(
{
title,
bodyText,
primaryButtonAction,
secondaryButtonAction,
primaryButtonText,
secondaryButtonText,
type = 'info',
className = '',
}: ControlPanelAlertProps,
ref: RefObject<HTMLDivElement>,
) => (
export function ExploreAlert({
title,
bodyText,
primaryButtonAction,
secondaryButtonAction,
primaryButtonText,
secondaryButtonText,
type = 'info',
className = '',
}: ControlPanelAlertProps) {
return (
<ErrorAlert
errorType={title}
message={bodyText}
@@ -74,5 +71,5 @@ export const ExploreAlert = forwardRef(
</ButtonContainer>
)}
</ErrorAlert>
),
);
);
}

View File

@@ -867,8 +867,11 @@ function ExploreViewContainer(props: ExploreViewContainerProps) {
setForceQuery: props.actions.setForceQuery,
postChartFormData: props.actions.postChartFormData,
updateQueryFormData: props.actions.updateQueryFormData,
setControlValue: (controlName: string, value: any, chartId: number) =>
props.actions.setControlValue(controlName, value),
setControlValue: (
controlName: string,
value: any,
_chartId: number,
) => props.actions.setControlValue(controlName, value),
}}
can_overwrite={props.can_overwrite}
can_download={props.can_download}

View File

@@ -134,7 +134,7 @@ class CollectionControl extends Component<CollectionControlProps> {
>
{currentValue.map((o: CollectionItem, i: number) => {
// label relevant only for header, not here
const { label, theme, ...commonProps } = this.props;
const { label: _label, theme: _theme, ...commonProps } = this.props;
return (
<SortableListItem
selectable={false}

View File

@@ -66,18 +66,19 @@ export default function ColumnConfigControl<T extends ColumnConfig>({
height,
...props
}: ColumnConfigControlProps<T>) {
const { colnames: _colnames, coltypes: _coltypes } = columnsPropsObject || {};
const { colnames: queryColnames, coltypes: queryColtypes } =
columnsPropsObject || {};
let colnames: string[] = [];
let coltypes: GenericDataType[] = [];
if (appliedColumnNames.length === 0) {
colnames = _colnames || [];
coltypes = _coltypes || [];
colnames = queryColnames || [];
coltypes = queryColtypes || [];
} else {
const appliedCol = new Set(appliedColumnNames);
_colnames?.forEach((col, idx) => {
queryColnames?.forEach((col, idx) => {
if (appliedCol.has(col)) {
colnames.push(col);
coltypes.push(_coltypes?.[idx] as GenericDataType);
coltypes.push(queryColtypes?.[idx] as GenericDataType);
}
});
}

View File

@@ -306,7 +306,7 @@ export default class AdhocFilterEditPopover extends Component<
.filter((item: { sliceIndex: number }) => item.sliceIndex !== -1)
.map(
({
sliceIndex,
sliceIndex: _sliceIndex,
...item
}: {
sliceIndex: number;
@@ -358,12 +358,12 @@ export default class AdhocFilterEditPopover extends Component<
const {
adhocFilter: propsAdhocFilter,
options,
onChange,
onClose,
onResize,
onChange: _onChange,
onClose: _onClose,
onResize: _onResize,
datasource,
partitionColumn,
theme,
theme: _theme,
operators,
requireSave,
...popoverProps

View File

@@ -353,9 +353,9 @@ export default class AdhocMetricEditPopover extends PureComponent<
savedMetric: propsSavedMetric,
columns,
savedMetricsOptions,
onChange,
onClose,
onResize,
onChange: _onChange,
onClose: _onClose,
onResize: _onResize,
datasource,
isNewMetric,
isLabelModified,

View File

@@ -1137,7 +1137,7 @@ const AlertReportModal: FunctionComponent<AlertReportModalProps> = ({
);
}
})
.catch(e => {
.catch(() => {
addDangerToast(t('There was an error retrieving dashboard tabs.'));
});
}
@@ -2596,7 +2596,6 @@ const AlertReportModal: FunctionComponent<AlertReportModalProps> = ({
<TimezoneSelector
onTimezoneChange={onTimezoneChange}
timezone={currentAlert?.timezone}
minWidth="100%"
/>
) : (
<Loading size="s" muted position="normal" />

View File

@@ -306,7 +306,7 @@ export const NotificationMethod: FunctionComponent<NotificationMethodProps> = ({
}
}
})
.catch(e => {
.catch(() => {
// Fallback to slack v1 if slack v2 is not compatible
setUseSlackV1(true);
})

View File

@@ -59,7 +59,7 @@ interface AllEntitiesTableProps {
}
export default function AllEntitiesTable({
search = '',
search: _search = '',
setShowTagModal,
objects,
canEditTag,

View File

@@ -208,7 +208,7 @@ const AnnotationModal: FunctionComponent<AnnotationModalProps> = ({
setCurrentAnnotation(data);
};
const onDateChange = (dates: any, dateString: Array<string>) => {
const onDateChange = (dates: any, _dateString: Array<string>) => {
if (!dates?.[0] || !dates?.[1]) {
const data = {
...currentAnnotation,

View File

@@ -1634,7 +1634,7 @@ test('validates fix by testing all form field types clear validation errors', ()
mockClearError();
};
const handleChangeWithValidation = (actionType: any, payload: any) => {
const handleChangeWithValidation = (_actionType: any, _payload: any) => {
handleClearValidationErrors();
};

View File

@@ -330,7 +330,7 @@ const UploadDataModal: FunctionComponent<UploadDataModalProps> = ({
const loadDatabaseOptions = useMemo(
() =>
(input = '', page: number, pageSize: number) => {
(_input = '', page: number, pageSize: number) => {
const query = rison.encode_uri({
filters: [
{
@@ -358,21 +358,20 @@ const UploadDataModal: FunctionComponent<UploadDataModalProps> = ({
);
const loadSchemaOptions = useMemo(
() =>
(input = '', page: number, pageSize: number) => {
if (!currentDatabaseId) {
return Promise.resolve({ data: [], totalCount: 0 });
}
return SupersetClient.get({
endpoint: `/api/v1/database/${currentDatabaseId}/schemas/?q=(upload_allowed:!t)`,
}).then(response => {
const list = response.json.result.map((item: string) => ({
value: item,
label: item,
}));
return { data: list, totalCount: response.json.count };
});
},
() => () => {
if (!currentDatabaseId) {
return Promise.resolve({ data: [], totalCount: 0 });
}
return SupersetClient.get({
endpoint: `/api/v1/database/${currentDatabaseId}/schemas/?q=(upload_allowed:!t)`,
}).then(response => {
const list = response.json.result.map((item: string) => ({
value: item,
label: item,
}));
return { data: list, totalCount: response.json.count };
});
},
[currentDatabaseId],
);
@@ -563,7 +562,7 @@ const UploadDataModal: FunctionComponent<UploadDataModalProps> = ({
}
}, [show]);
const validateUpload = (_: any, value: string) => {
const validateUpload = () => {
if (fileList.length === 0) {
return Promise.reject(t('Uploading a file is required'));
}
@@ -578,7 +577,7 @@ const UploadDataModal: FunctionComponent<UploadDataModalProps> = ({
return Promise.resolve();
};
const validateDatabase = (_: any, value: string) => {
const validateDatabase = () => {
if (!currentDatabaseId) {
return Promise.reject(t('Selecting a database is required'));
}

View File

@@ -85,7 +85,7 @@ const BulkTagModal: FC<BulkTagModalProps> = ({
}
addSuccessToast(t('Tagged %s %ss', tagged.length, resourceName));
})
.catch(err => {
.catch(() => {
addDangerToast(t('Failed to tag items'));
});

View File

@@ -130,7 +130,7 @@ const TagModal: FC<TagModalProps> = ({
setChartsToTag(resourceMap[TaggableResources.Chart]);
setSavedQueriesToTag(resourceMap[TaggableResources.SavedQuery]);
},
(error: Response) => {
() => {
addDangerToast('Error Fetching Tagged Objects');
},
);

View File

@@ -48,7 +48,7 @@ function UserInfoModal({
: {};
const handleFormSubmit = async (values: FormValues) => {
try {
const { confirm_password, ...payload } = values;
const { confirm_password: _confirm_password, ...payload } = values;
await SupersetClient.put({
endpoint: `/api/v1/me/`,
jsonPayload: { ...payload },

View File

@@ -22,7 +22,7 @@ import { SelectOption } from 'src/components/ListView';
import { FormValues } from './types';
export const createUser = async (values: FormValues) => {
const { confirmPassword, ...payload } = values;
const { confirmPassword: _confirmPassword, ...payload } = values;
if (payload.active == null) {
payload.active = false;
}

View File

@@ -155,7 +155,7 @@ function AllEntities() {
setObjects(objects);
setLoading(false);
},
(error: Response) => {
() => {
addDangerToast('Error Fetching Tagged Objects');
setLoading(false);
},
@@ -169,7 +169,7 @@ function AllEntities() {
setTag(tag);
setLoading(false);
},
(error: Response) => {
() => {
addDangerToast(t('Error Fetching Tagged Objects'));
setLoading(false);
},

View File

@@ -69,9 +69,9 @@ const createMockUser = (overrides = {}) => ({
const createMockStore = (initialState: any = {}) =>
configureStore({
reducer: {
user: (state = initialState.user || {}, action: any) => state,
common: (state = initialState.common || {}, action: any) => state,
charts: (state = initialState.charts || {}, action: any) => state,
user: (state = initialState.user || {}, _action: any) => state,
common: (state = initialState.common || {}, _action: any) => state,
charts: (state = initialState.charts || {}, _action: any) => state,
},
preloadedState: initialState,
middleware: getDefaultMiddleware =>

View File

@@ -291,11 +291,7 @@ const DatasetList: FunctionComponent<DatasetListProps> = ({
const columns = useMemo(
() => [
{
Cell: ({
row: {
original: { kind },
},
}: any) => null,
Cell: () => null,
accessor: 'kind_icon',
disableSortBy: true,
size: 'xs',

View File

@@ -146,7 +146,7 @@ function GroupsList({ user }: GroupsListProps) {
.then(() => {
deletedGroupsNames.push(group.name);
})
.catch(err => {
.catch(() => {
addDangerToast(t('Error deleting %s', group.name));
}),
),

View File

@@ -168,7 +168,7 @@ function UsersList({ user }: UsersListProps) {
.then(() => {
deletedUserNames.push(user.username);
})
.catch(err => {
.catch(() => {
addDangerToast(t('Error deleting %s', user.username));
}),
),

View File

@@ -31,4 +31,6 @@ interface CodeOverrideOptions {
* Hook for individual deployments to add custom overrides
* @param options - Configuration options for the setup process
*/
export default function setupCodeOverrides(options: CodeOverrideOptions = {}) {}
export default function setupCodeOverrides(
_options: CodeOverrideOptions = {},
) {}

View File

@@ -801,7 +801,7 @@ export class ThemeController {
* @param newMode - The new mode to validate
* @throws {Error} If the user does not have permission to update the theme mode
*/
private validateModeUpdatePermission(newMode: ThemeMode): void {
private validateModeUpdatePermission(_newMode: ThemeMode): void {
// Check if user can set a new theme mode (dark theme must exist)
if (!this.canSetMode())
throw new Error(