Skip to content

Commit

Permalink
cluster-ui: handle partial response errors on the database details page
Browse files Browse the repository at this point in the history
Part of: #102386

This change applies the same error handling ideas from #109245 to the
database details page, enabling non-admin users to use the database
details page and providing better transparency to data fetching issues.

Errors encountered while fetching table details can be viewed via the
tooltip provided by the `Caution` icon at the table's name.
`unavailable` cells also provide a tooltip that displays the error
impacting that exact cell.

Release note (ui change): Non-admin users are able to use the database
details page.
  • Loading branch information
Thomas Hardy committed Sep 11, 2023
1 parent 0d073f4 commit 001ca87
Show file tree
Hide file tree
Showing 9 changed files with 301 additions and 242 deletions.
3 changes: 1 addition & 2 deletions pkg/ui/workspaces/cluster-ui/src/api/sqlApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ export function isUpgradeError(message: string): boolean {
}

/**
* errorMessage cleans the error message returned by the sqlApi,
* sqlApiErrorMessage cleans the error message returned by the sqlApi,
* removing information not useful for the user.
* e.g. the error message
* "$executing stmt 1: run-query-via-api: only users with either MODIFYCLUSTERSETTING
Expand All @@ -170,7 +170,6 @@ export function sqlApiErrorMessage(message: string): string {
const idx = message.indexOf(":") + 1;
return idx < message.length ? message.substring(idx) : message;
}

return message;
}

Expand Down
39 changes: 23 additions & 16 deletions pkg/ui/workspaces/cluster-ui/src/api/tableDetailsApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
// licenses/APL.txt.

import {
combineQueryErrors,
executeInternalSql,
formatApiResult,
LARGE_RESULT_SIZE,
Expand Down Expand Up @@ -111,7 +112,7 @@ const getTableId: TableDetailsQuery<TableIdRow> = {
};

// Table create statement.
type TableCreateStatementRow = { create_statement: string };
export type TableCreateStatementRow = { create_statement: string };

const getTableCreateStatement: TableDetailsQuery<TableCreateStatementRow> = {
createStmt: (dbName, tableName) => {
Expand All @@ -129,22 +130,22 @@ const getTableCreateStatement: TableDetailsQuery<TableCreateStatementRow> = {
txn_result: SqlTxnResult<TableCreateStatementRow>,
resp: TableDetailsResponse,
) => {
if (txn_result.error) {
resp.createStmtResp.error = txn_result.error;
}
if (!txnResultIsEmpty(txn_result)) {
resp.createStmtResp.create_statement =
txn_result.rows[0].create_statement;
} else {
} else if (!txn_result.error) {
txn_result.error = new Error(
"getTableCreateStatement: unexpected empty results",
);
}
if (txn_result.error) {
resp.createStmtResp.error = txn_result.error;
}
},
};

// Table grants.
type TableGrantsResponse = {
export type TableGrantsResponse = {
grants: TableGrantsRow[];
};

Expand Down Expand Up @@ -181,7 +182,7 @@ const getTableGrants: TableDetailsQuery<TableGrantsRow> = {
};

// Table schema details.
type TableSchemaDetailsRow = {
export type TableSchemaDetailsRow = {
columns: string[];
indexes: string[];
};
Expand Down Expand Up @@ -332,7 +333,7 @@ const getTableZoneConfig: TableDetailsQuery<TableZoneConfigRow> = {
};

// Table heuristics details.
type TableHeuristicDetailsRow = {
export type TableHeuristicDetailsRow = {
stats_last_created_at: moment.Moment;
};

Expand Down Expand Up @@ -371,7 +372,7 @@ type TableDetailsStats = {
};

// Table span stats.
type TableSpanStatsRow = {
export type TableSpanStatsRow = {
approximate_disk_bytes: number;
live_bytes: number;
total_bytes: number;
Expand Down Expand Up @@ -418,7 +419,7 @@ const getTableSpanStats: TableDetailsQuery<TableSpanStatsRow> = {
},
};

type TableReplicaData = SqlApiQueryResponse<{
export type TableReplicaData = SqlApiQueryResponse<{
nodeIDs: number[];
nodeCount: number;
replicaCount: number;
Expand Down Expand Up @@ -471,7 +472,7 @@ const getTableReplicas: TableDetailsQuery<TableReplicasRow> = {
};

// Table index usage stats.
type TableIndexUsageStats = {
export type TableIndexUsageStats = {
has_index_recommendations: boolean;
};

Expand Down Expand Up @@ -569,6 +570,7 @@ export function createTableDetailsReq(
max_result_size: LARGE_RESULT_SIZE,
timeout: LONG_TIMEOUT,
database: dbName,
separate_txns: true,
};
}

Expand Down Expand Up @@ -605,19 +607,24 @@ async function fetchTableDetails(
csIndexUnusedDuration,
);
const resp = await executeInternalSql<TableDetailsRow>(req);
const errs: Error[] = [];
resp.execution.txn_results.forEach(txn_result => {
if (txn_result.rows) {
const query: TableDetailsQuery<TableDetailsRow> =
tableDetailQueries[txn_result.statement - 1];
query.addToTableDetail(txn_result, detailsResponse);
if (txn_result.error) {
errs.push(txn_result.error);
}
const query: TableDetailsQuery<TableDetailsRow> =
tableDetailQueries[txn_result.statement - 1];
query.addToTableDetail(txn_result, detailsResponse);
});
if (resp.error) {
detailsResponse.error = resp.error;
}

detailsResponse.error = combineQueryErrors(errs, detailsResponse.error);
return formatApiResult<TableDetailsResponse>(
detailsResponse,
detailsResponse.error,
"retrieving table details information",
`retrieving table details information for table '${tableName}'`,
false,
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import {
selectDatabaseDetailsTablesSortSetting,
selectDatabaseDetailsViewModeSetting,
} from "../store/databaseDetails/databaseDetails.selectors";
import { combineLoadingErrors, deriveTableDetailsMemoized } from "../databases";
import { deriveTableDetailsMemoized } from "../databases";
import {
selectDropUnusedIndexDuration,
selectIndexRecommendationsEnabled,
Expand All @@ -56,11 +56,8 @@ const mapStateToProps = (
return {
loading: !!databaseDetails[database]?.inFlight,
loaded: !!databaseDetails[database]?.valid,
lastError: combineLoadingErrors(
databaseDetails[database]?.lastError,
databaseDetails[database]?.data?.maxSizeReached,
null,
),
requestError: databaseDetails[database]?.lastError,
queryError: databaseDetails[database]?.data?.results?.error,
name: database,
showNodeRegionsColumn: Object.keys(nodeRegions).length > 1 && !isTenant,
viewMode: selectDatabaseDetailsViewModeSetting(state),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ const history = H.createHashHistory();
const withLoadingIndicator: DatabaseDetailsPageProps = {
loading: true,
loaded: false,
lastError: undefined,
requestError: undefined,
queryError: undefined,
showIndexRecommendations: false,
csIndexUnusedDuration: indexUnusedDuration,
name: randomName(),
Expand Down Expand Up @@ -68,7 +69,8 @@ const withLoadingIndicator: DatabaseDetailsPageProps = {
const withoutData: DatabaseDetailsPageProps = {
loading: false,
loaded: true,
lastError: null,
requestError: null,
queryError: undefined,
showIndexRecommendations: false,
csIndexUnusedDuration: indexUnusedDuration,
name: randomName(),
Expand Down Expand Up @@ -108,7 +110,8 @@ function createTable(): DatabaseDetailsPageDataTable {
return {
loading: false,
loaded: true,
lastError: null,
requestError: null,
queryError: undefined,
name: randomName(),
details: {
columnCount: _.random(5, 42),
Expand Down
Loading

0 comments on commit 001ca87

Please sign in to comment.