Skip to content

Commit 001ca87

Browse files
author
Thomas Hardy
committed
cluster-ui: handle partial response errors on the database details page
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.
1 parent 0d073f4 commit 001ca87

File tree

9 files changed

+301
-242
lines changed

9 files changed

+301
-242
lines changed

pkg/ui/workspaces/cluster-ui/src/api/sqlApi.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ export function isUpgradeError(message: string): boolean {
147147
}
148148

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

pkg/ui/workspaces/cluster-ui/src/api/tableDetailsApi.ts

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
// licenses/APL.txt.
1010

1111
import {
12+
combineQueryErrors,
1213
executeInternalSql,
1314
formatApiResult,
1415
LARGE_RESULT_SIZE,
@@ -111,7 +112,7 @@ const getTableId: TableDetailsQuery<TableIdRow> = {
111112
};
112113

113114
// Table create statement.
114-
type TableCreateStatementRow = { create_statement: string };
115+
export type TableCreateStatementRow = { create_statement: string };
115116

116117
const getTableCreateStatement: TableDetailsQuery<TableCreateStatementRow> = {
117118
createStmt: (dbName, tableName) => {
@@ -129,22 +130,22 @@ const getTableCreateStatement: TableDetailsQuery<TableCreateStatementRow> = {
129130
txn_result: SqlTxnResult<TableCreateStatementRow>,
130131
resp: TableDetailsResponse,
131132
) => {
133+
if (txn_result.error) {
134+
resp.createStmtResp.error = txn_result.error;
135+
}
132136
if (!txnResultIsEmpty(txn_result)) {
133137
resp.createStmtResp.create_statement =
134138
txn_result.rows[0].create_statement;
135-
} else {
139+
} else if (!txn_result.error) {
136140
txn_result.error = new Error(
137141
"getTableCreateStatement: unexpected empty results",
138142
);
139143
}
140-
if (txn_result.error) {
141-
resp.createStmtResp.error = txn_result.error;
142-
}
143144
},
144145
};
145146

146147
// Table grants.
147-
type TableGrantsResponse = {
148+
export type TableGrantsResponse = {
148149
grants: TableGrantsRow[];
149150
};
150151

@@ -181,7 +182,7 @@ const getTableGrants: TableDetailsQuery<TableGrantsRow> = {
181182
};
182183

183184
// Table schema details.
184-
type TableSchemaDetailsRow = {
185+
export type TableSchemaDetailsRow = {
185186
columns: string[];
186187
indexes: string[];
187188
};
@@ -332,7 +333,7 @@ const getTableZoneConfig: TableDetailsQuery<TableZoneConfigRow> = {
332333
};
333334

334335
// Table heuristics details.
335-
type TableHeuristicDetailsRow = {
336+
export type TableHeuristicDetailsRow = {
336337
stats_last_created_at: moment.Moment;
337338
};
338339

@@ -371,7 +372,7 @@ type TableDetailsStats = {
371372
};
372373

373374
// Table span stats.
374-
type TableSpanStatsRow = {
375+
export type TableSpanStatsRow = {
375376
approximate_disk_bytes: number;
376377
live_bytes: number;
377378
total_bytes: number;
@@ -418,7 +419,7 @@ const getTableSpanStats: TableDetailsQuery<TableSpanStatsRow> = {
418419
},
419420
};
420421

421-
type TableReplicaData = SqlApiQueryResponse<{
422+
export type TableReplicaData = SqlApiQueryResponse<{
422423
nodeIDs: number[];
423424
nodeCount: number;
424425
replicaCount: number;
@@ -471,7 +472,7 @@ const getTableReplicas: TableDetailsQuery<TableReplicasRow> = {
471472
};
472473

473474
// Table index usage stats.
474-
type TableIndexUsageStats = {
475+
export type TableIndexUsageStats = {
475476
has_index_recommendations: boolean;
476477
};
477478

@@ -569,6 +570,7 @@ export function createTableDetailsReq(
569570
max_result_size: LARGE_RESULT_SIZE,
570571
timeout: LONG_TIMEOUT,
571572
database: dbName,
573+
separate_txns: true,
572574
};
573575
}
574576

@@ -605,19 +607,24 @@ async function fetchTableDetails(
605607
csIndexUnusedDuration,
606608
);
607609
const resp = await executeInternalSql<TableDetailsRow>(req);
610+
const errs: Error[] = [];
608611
resp.execution.txn_results.forEach(txn_result => {
609-
if (txn_result.rows) {
610-
const query: TableDetailsQuery<TableDetailsRow> =
611-
tableDetailQueries[txn_result.statement - 1];
612-
query.addToTableDetail(txn_result, detailsResponse);
612+
if (txn_result.error) {
613+
errs.push(txn_result.error);
613614
}
615+
const query: TableDetailsQuery<TableDetailsRow> =
616+
tableDetailQueries[txn_result.statement - 1];
617+
query.addToTableDetail(txn_result, detailsResponse);
614618
});
615619
if (resp.error) {
616620
detailsResponse.error = resp.error;
617621
}
622+
623+
detailsResponse.error = combineQueryErrors(errs, detailsResponse.error);
618624
return formatApiResult<TableDetailsResponse>(
619625
detailsResponse,
620626
detailsResponse.error,
621-
"retrieving table details information",
627+
`retrieving table details information for table '${tableName}'`,
628+
false,
622629
);
623630
}

pkg/ui/workspaces/cluster-ui/src/databaseDetailsPage/databaseDetailsConnected.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ import {
3737
selectDatabaseDetailsTablesSortSetting,
3838
selectDatabaseDetailsViewModeSetting,
3939
} from "../store/databaseDetails/databaseDetails.selectors";
40-
import { combineLoadingErrors, deriveTableDetailsMemoized } from "../databases";
40+
import { deriveTableDetailsMemoized } from "../databases";
4141
import {
4242
selectDropUnusedIndexDuration,
4343
selectIndexRecommendationsEnabled,
@@ -56,11 +56,8 @@ const mapStateToProps = (
5656
return {
5757
loading: !!databaseDetails[database]?.inFlight,
5858
loaded: !!databaseDetails[database]?.valid,
59-
lastError: combineLoadingErrors(
60-
databaseDetails[database]?.lastError,
61-
databaseDetails[database]?.data?.maxSizeReached,
62-
null,
63-
),
59+
requestError: databaseDetails[database]?.lastError,
60+
queryError: databaseDetails[database]?.data?.results?.error,
6461
name: database,
6562
showNodeRegionsColumn: Object.keys(nodeRegions).length > 1 && !isTenant,
6663
viewMode: selectDatabaseDetailsViewModeSetting(state),

pkg/ui/workspaces/cluster-ui/src/databaseDetailsPage/databaseDetailsPage.stories.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ const history = H.createHashHistory();
3434
const withLoadingIndicator: DatabaseDetailsPageProps = {
3535
loading: true,
3636
loaded: false,
37-
lastError: undefined,
37+
requestError: undefined,
38+
queryError: undefined,
3839
showIndexRecommendations: false,
3940
csIndexUnusedDuration: indexUnusedDuration,
4041
name: randomName(),
@@ -68,7 +69,8 @@ const withLoadingIndicator: DatabaseDetailsPageProps = {
6869
const withoutData: DatabaseDetailsPageProps = {
6970
loading: false,
7071
loaded: true,
71-
lastError: null,
72+
requestError: null,
73+
queryError: undefined,
7274
showIndexRecommendations: false,
7375
csIndexUnusedDuration: indexUnusedDuration,
7476
name: randomName(),
@@ -108,7 +110,8 @@ function createTable(): DatabaseDetailsPageDataTable {
108110
return {
109111
loading: false,
110112
loaded: true,
111-
lastError: null,
113+
requestError: null,
114+
queryError: undefined,
112115
name: randomName(),
113116
details: {
114117
columnCount: _.random(5, 42),

0 commit comments

Comments
 (0)