From a4a19401c65571ccd88b530fb7defdeea8c374c5 Mon Sep 17 00:00:00 2001 From: Xin Hao Zhang Date: Thu, 28 Sep 2023 16:44:07 -0400 Subject: [PATCH 1/4] cluster-ui: eslint should error on eqeqeq violation Add eqeqeq eslint rule for cluster-ui. This rule is on 'smart' mode, meaning we must use triple equals unless: - comparing two literal values - evaluating the value of typeof - comparing against null Epic: none Release note: None --- pkg/ui/workspaces/cluster-ui/.eslintrc.json | 3 +- .../cluster-ui/src/api/contentionApi.ts | 6 +-- .../cluster-ui/src/api/indexActionsApi.ts | 2 +- .../workspaces/cluster-ui/src/api/safesql.ts | 2 +- .../databaseDetailsPage.tsx | 38 +++++++++---------- .../src/databasesPage/databasesPage.tsx | 22 +++++------ .../src/insights/indexActionBtn.tsx | 8 ++-- .../transactionInsightDetailsOverviewTab.tsx | 2 +- .../workloadInsights/util/insightsColumns.tsx | 2 +- .../workloadInsights/util/queriesCell.tsx | 4 +- .../workloadInsightRootControl.tsx | 2 +- .../cluster-ui/src/jobs/util/duration.tsx | 2 +- .../cluster-ui/src/jobs/util/jobOptions.tsx | 4 +- .../cluster-ui/src/queryFilter/filter.tsx | 2 +- .../cluster-ui/src/sessions/sessionsPage.tsx | 10 ++--- .../cluster-ui/src/sessions/sessionsTable.tsx | 4 +- .../src/sortedtable/sortedtable.tsx | 8 ++-- .../src/sqlActivity/errorComponent.tsx | 2 +- .../planDetails/planDetails.tsx | 3 +- .../planDetails/plansTable.tsx | 6 +-- .../src/statementDetails/statementDetails.tsx | 4 +- .../activateStatementDiagnosticsModal.tsx | 6 +-- .../statementsPage/activeStatementsView.tsx | 2 +- .../src/statementsPage/statementsPage.tsx | 12 +++--- .../src/statementsTable/statementsTable.tsx | 2 +- .../src/tracez/snapshot/spanComponent.tsx | 2 +- .../src/tracez/snapshot/spanTable.tsx | 2 +- .../src/transactionsPage/transactionsPage.tsx | 10 ++--- .../cluster-ui/src/transactionsPage/utils.ts | 6 +-- .../transactionsTable/transactionsTable.tsx | 2 +- .../cluster-ui/src/util/appStats/appStats.ts | 4 +- .../workspaces/cluster-ui/src/util/format.ts | 20 +++++----- 32 files changed, 104 insertions(+), 100 deletions(-) diff --git a/pkg/ui/workspaces/cluster-ui/.eslintrc.json b/pkg/ui/workspaces/cluster-ui/.eslintrc.json index 931bfb8cc259..a043a55148ea 100644 --- a/pkg/ui/workspaces/cluster-ui/.eslintrc.json +++ b/pkg/ui/workspaces/cluster-ui/.eslintrc.json @@ -14,6 +14,7 @@ "@cockroachlabs/crdb/require-antd-style-import": "error", // Instead of using console log methods directly, cluster-ui code should // call the getLogger() method to provide the appropriate logger. - "no-console": "error" + "no-console": "error", + "eqeqeq": ["error", "smart"] } } diff --git a/pkg/ui/workspaces/cluster-ui/src/api/contentionApi.ts b/pkg/ui/workspaces/cluster-ui/src/api/contentionApi.ts index 47b27125185e..dcded3486946 100644 --- a/pkg/ui/workspaces/cluster-ui/src/api/contentionApi.ts +++ b/pkg/ui/workspaces/cluster-ui/src/api/contentionApi.ts @@ -134,21 +134,21 @@ function getContentionWhereClause(filters?: ContentionFilters): string { } if (filters?.waitingTxnID) { - if (whereClause != defaultWhereClause) { + if (whereClause !== defaultWhereClause) { whereClause += " and "; } whereClause = whereClause + ` waiting_txn_id >= '${filters.waitingTxnID}' `; } if (filters?.start) { - if (whereClause != defaultWhereClause) { + if (whereClause !== defaultWhereClause) { whereClause += " and "; } whereClause = whereClause + ` collection_ts >= '${filters.start.toISOString()}' `; } if (filters?.end) { - if (whereClause != defaultWhereClause) { + if (whereClause !== defaultWhereClause) { whereClause += " and "; } diff --git a/pkg/ui/workspaces/cluster-ui/src/api/indexActionsApi.ts b/pkg/ui/workspaces/cluster-ui/src/api/indexActionsApi.ts index 39e09bb1d776..6a5fa4b865d8 100644 --- a/pkg/ui/workspaces/cluster-ui/src/api/indexActionsApi.ts +++ b/pkg/ui/workspaces/cluster-ui/src/api/indexActionsApi.ts @@ -27,7 +27,7 @@ export function executeIndexRecAction( ): Promise { const statements = stmts .split(";") - .filter(stmt => stmt.trim().length != 0) + .filter(stmt => stmt.trim().length !== 0) .map(stmt => { return { sql: stmt.trim() }; }); diff --git a/pkg/ui/workspaces/cluster-ui/src/api/safesql.ts b/pkg/ui/workspaces/cluster-ui/src/api/safesql.ts index 6166c91786d7..7a863a4e53d2 100644 --- a/pkg/ui/workspaces/cluster-ui/src/api/safesql.ts +++ b/pkg/ui/workspaces/cluster-ui/src/api/safesql.ts @@ -178,7 +178,7 @@ export function Format(format: string, args?: any[]): string { if (i > 0) { const lastChar = format.substring(0, i).slice(-1); - if (!(lastChar == "=" || isPunct(lastChar) || isSpace(lastChar))) { + if (!(lastChar === "=" || isPunct(lastChar) || isSpace(lastChar))) { throw new Error( `invalid separator: '${lastChar}' is not punctuation or whitespace`, ); diff --git a/pkg/ui/workspaces/cluster-ui/src/databaseDetailsPage/databaseDetailsPage.tsx b/pkg/ui/workspaces/cluster-ui/src/databaseDetailsPage/databaseDetailsPage.tsx index 021bb23cbc30..30ee09759ec7 100644 --- a/pkg/ui/workspaces/cluster-ui/src/databaseDetailsPage/databaseDetailsPage.tsx +++ b/pkg/ui/workspaces/cluster-ui/src/databaseDetailsPage/databaseDetailsPage.tsx @@ -230,13 +230,13 @@ export class DatabaseDetailsPage extends React.Component< // View Mode. const view = searchParams.get("viewMode") || undefined; let viewMode = ViewMode.Tables; - if (view == ViewMode.Grants.toString()) { + if (view === ViewMode.Grants.toString()) { viewMode = ViewMode.Grants; } if ( this.props.onViewModeChange && view && - viewMode != this.props.viewMode + viewMode !== this.props.viewMode ) { this.props.onViewModeChange(viewMode); } @@ -245,19 +245,19 @@ export class DatabaseDetailsPage extends React.Component< const ascending = (searchParams.get("ascending") || undefined) === "true"; const columnTitle = searchParams.get("columnTitle") || undefined; const sortSetting = - viewMode == ViewMode.Tables + viewMode === ViewMode.Tables ? this.props.sortSettingTables : this.props.sortSettingGrants; const onSortingChange = - viewMode == ViewMode.Tables + viewMode === ViewMode.Tables ? this.props.onSortingTablesChange : this.props.onSortingGrantsChange; if ( onSortingChange && columnTitle && - (sortSetting.columnTitle != columnTitle || - sortSetting.ascending != ascending) + (sortSetting.columnTitle !== columnTitle || + sortSetting.ascending !== ascending) ) { onSortingChange(columnTitle, ascending); } @@ -293,17 +293,17 @@ export class DatabaseDetailsPage extends React.Component< // No new tables to update if ( !this.props.tables || - this.props.tables.length == 0 || + this.props.tables.length === 0 || this.props.tables.every(x => x.loaded || x.loading) ) { return false; } - if (this.state.pagination.current != prevState.pagination.current) { + if (this.state.pagination.current !== prevState.pagination.current) { return true; } - if (prevProps && this.props.search != prevProps.search) { + if (prevProps && this.props.search !== prevProps.search) { return true; } @@ -314,7 +314,7 @@ export class DatabaseDetailsPage extends React.Component< i++ ) { const table = filteredTables[i]; - if (!table.loaded && !table.loading && table.requestError == undefined) { + if (!table.loaded && !table.loading && table.requestError == null) { return true; } } @@ -371,7 +371,7 @@ export class DatabaseDetailsPage extends React.Component< this.props.history, ); const onSortingChange = - this.props.viewMode == ViewMode.Tables + this.props.viewMode === ViewMode.Tables ? this.props.onSortingTablesChange : this.props.onSortingGrantsChange; @@ -470,9 +470,9 @@ export class DatabaseDetailsPage extends React.Component< // Avoid the loop if no filters/search are applied if ( - (!search || search.length == 0) && - regionsSelected.length == 0 && - nodesSelected.length == 0 + (!search || search.length === 0) && + regionsSelected.length === 0 && + nodesSelected.length === 0 ) { return tables; } @@ -480,11 +480,11 @@ export class DatabaseDetailsPage extends React.Component< return tables .filter(table => (search ? filterBySearchQuery(table, search) : true)) .filter(table => { - if (regionsSelected.length == 0 && nodesSelected.length == 0) + if (regionsSelected.length === 0 && nodesSelected.length === 0) return true; - let foundRegion = regionsSelected.length == 0; - let foundNode = nodesSelected.length == 0; + let foundRegion = regionsSelected.length === 0; + let foundNode = nodesSelected.length === 0; table.details.nodes?.forEach(node => { const n = node?.toString() || ""; @@ -791,7 +791,7 @@ export class DatabaseDetailsPage extends React.Component< const regions = unique(Object.values(nodeRegions)); const sortSetting = - this.props.viewMode == ViewMode.Tables + this.props.viewMode === ViewMode.Tables ? this.props.sortSettingTables : this.props.sortSettingGrants; @@ -801,7 +801,7 @@ export class DatabaseDetailsPage extends React.Component< // Only show the filter component when the viewMode is Tables and if at // least one of drop-down is shown. const filterComponent = - this.props.viewMode == ViewMode.Tables && (showNodes || showRegions) ? ( + this.props.viewMode === ViewMode.Tables && (showNodes || showRegions) ? ( (search ? filterBySearchQuery(db, search) : true)) .filter(db => { - if (regionsSelected.length == 0 && nodesSelected.length == 0) + if (regionsSelected.length === 0 && nodesSelected.length === 0) return true; - let foundRegion = regionsSelected.length == 0; - let foundNode = nodesSelected.length == 0; + let foundRegion = regionsSelected.length === 0; + let foundNode = nodesSelected.length === 0; db.nodes?.forEach(node => { const n = node?.toString() || ""; @@ -487,17 +487,17 @@ export class DatabasesPage extends React.Component< // No new dbs to update if ( !this.props.databases || - this.props.databases.length == 0 || + this.props.databases.length === 0 || this.props.databases.every(x => x.loaded || x.loading) ) { return false; } - if (this.state.pagination.current != prevState.pagination.current) { + if (this.state.pagination.current !== prevState.pagination.current) { return true; } - if (prevProps && this.props.search != prevProps.search) { + if (prevProps && this.props.search !== prevProps.search) { return true; } @@ -508,7 +508,7 @@ export class DatabasesPage extends React.Component< i++ ) { const db = filteredDatabases[i]; - if (db.loaded || db.loading || db.requestError != undefined) { + if (db.loaded || db.loading || db.requestError != null) { continue; } // Info is not loaded for a visible database. diff --git a/pkg/ui/workspaces/cluster-ui/src/insights/indexActionBtn.tsx b/pkg/ui/workspaces/cluster-ui/src/insights/indexActionBtn.tsx index b5a816f0a6da..1788ffcbc097 100644 --- a/pkg/ui/workspaces/cluster-ui/src/insights/indexActionBtn.tsx +++ b/pkg/ui/workspaces/cluster-ui/src/insights/indexActionBtn.tsx @@ -53,7 +53,7 @@ const IdxRecAction = (props: idxRecProps): React.ReactElement => { setApplying(false); let foundError = false; for (let i = 0; i < r.length; i++) { - if (r[i].status == "FAILED") { + if (r[i].status === "FAILED") { foundError = true; setError(r[i].error); break; @@ -202,7 +202,7 @@ function addIdxName(statement: string): string { for (let i = 0; i < statements.length; i++) { if (statements[i].trim().toUpperCase().startsWith("CREATE INDEX ON ")) { result = `${result}${createIdxName(statements[i])}; `; - } else if (statements[i].length != 0) { + } else if (statements[i].length !== 0) { result = `${result}${statements[i]};`; } } @@ -231,10 +231,10 @@ export function createIdxName(statement: string): string { let parenthesis = 1; let i = 0; while (parenthesis > 0 && i < info.length) { - if (info[i] == "(") { + if (info[i] === "(") { parenthesis++; } - if (info[i] == ")") { + if (info[i] === ")") { parenthesis--; } i++; diff --git a/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsightDetails/transactionInsightDetailsOverviewTab.tsx b/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsightDetails/transactionInsightDetailsOverviewTab.tsx index 0a1062b843df..c0a3b9f25386 100644 --- a/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsightDetails/transactionInsightDetailsOverviewTab.tsx +++ b/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsightDetails/transactionInsightDetailsOverviewTab.tsx @@ -96,7 +96,7 @@ the maximum number of statements was reached in the console.`; const blockingExecutions: ContentionEvent[] = contentionDetails?.map( event => { const stmtInsight = statements.find( - stmt => stmt.statementExecutionID == event.waitingStmtID, + stmt => stmt.statementExecutionID === event.waitingStmtID, ); return { executionID: event.blockingExecutionID, diff --git a/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsights/util/insightsColumns.tsx b/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsights/util/insightsColumns.tsx index 46f949043c34..79acc7397b67 100644 --- a/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsights/util/insightsColumns.tsx +++ b/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsights/util/insightsColumns.tsx @@ -123,7 +123,7 @@ export const insightsTableTitles: InsightsTableTitleType = { }, query: (execType: InsightExecEnum) => { let tooltipText = `The ${execType} query.`; - if (execType == InsightExecEnum.TRANSACTION) { + if (execType === InsightExecEnum.TRANSACTION) { tooltipText = "The queries attempted in the transaction."; } return makeToolTip(

{tooltipText}

, "query", execType); diff --git a/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsights/util/queriesCell.tsx b/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsights/util/queriesCell.tsx index 45aa26e668d0..ce669cd14a0f 100644 --- a/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsights/util/queriesCell.tsx +++ b/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsights/util/queriesCell.tsx @@ -37,9 +37,9 @@ export function QueriesCell( const combinedQuery = transactionQueries?.map((query, idx, arr) => (
- {idx != 0 &&
} + {idx !== 0 &&
} {query} - {idx != arr.length - 1 &&
} + {idx !== arr.length - 1 &&
}
)); diff --git a/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsights/workloadInsightRootControl.tsx b/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsights/workloadInsightRootControl.tsx index 42073eed571b..0a065158052c 100644 --- a/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsights/workloadInsightRootControl.tsx +++ b/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsights/workloadInsightRootControl.tsx @@ -65,7 +65,7 @@ export const WorkloadInsightsRootControl = ({ /> ); - if (selectedInsightView == InsightExecEnum.TRANSACTION) { + if (selectedInsightView === InsightExecEnum.TRANSACTION) { return (
{"Duration: " + diff --git a/pkg/ui/workspaces/cluster-ui/src/jobs/util/jobOptions.tsx b/pkg/ui/workspaces/cluster-ui/src/jobs/util/jobOptions.tsx index 400c62b6ec9a..29c5ac159ed3 100644 --- a/pkg/ui/workspaces/cluster-ui/src/jobs/util/jobOptions.tsx +++ b/pkg/ui/workspaces/cluster-ui/src/jobs/util/jobOptions.tsx @@ -44,7 +44,7 @@ export function jobToVisual(job: Job): JobStatusVisual { case JOB_STATUS_CANCELED: case JOB_STATUS_CANCEL_REQUESTED: case JOB_STATUS_PAUSED: - return job.error == "" + return job.error === "" ? JobStatusVisual.BadgeOnly : JobStatusVisual.BadgeWithErrorMessage; case JOB_STATUS_PAUSE_REQUESTED: @@ -55,7 +55,7 @@ export function jobToVisual(job: Job): JobStatusVisual { } function jobToVisualForReplicationIngestion(job: Job): JobStatusVisual { - if (job.fraction_completed > 0 && job.status == JOB_STATUS_RUNNING) { + if (job.fraction_completed > 0 && job.status === JOB_STATUS_RUNNING) { return JobStatusVisual.ProgressBarWithDuration; } return JobStatusVisual.BadgeOnly; diff --git a/pkg/ui/workspaces/cluster-ui/src/queryFilter/filter.tsx b/pkg/ui/workspaces/cluster-ui/src/queryFilter/filter.tsx index 4f7ee2c6b9a6..eed0ca7fd748 100644 --- a/pkg/ui/workspaces/cluster-ui/src/queryFilter/filter.tsx +++ b/pkg/ui/workspaces/cluster-ui/src/queryFilter/filter.tsx @@ -751,7 +751,7 @@ export class Filter extends React.Component {