Skip to content

Commit b60bbe7

Browse files
Rui Gaoclaude
andcommitted
fix job-detail page error handling for permission denied errors
When a user without permission opens another user's job page, fetchJobInfo returns 403 but the error was silently ignored, causing the page to show "Loading..." forever with a vague empty alert. Now fetchJobInfo checks HTTP status, shows a clear permission error, and skips subsequent requests. Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
1 parent 9867258 commit b60bbe7

4 files changed

Lines changed: 35 additions & 18 deletions

File tree

src/cluster-local-storage/src/kusto-sdk/.gitignore

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,4 @@ dist/
1414
downloads/
1515
eggs/
1616
.eggs/
17-
lib/
18-
19-
**/ltp-storage-common/
20-
**/ltp-kusto-sdk/
21-
**/postgresql-sdk/
17+
lib/

src/dev-box/build/build-pre.sh

100644100755
File mode changed.

src/webportal/src/app/job/job-view/fabric/job-detail.jsx

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -91,13 +91,19 @@ class JobDetail extends React.Component {
9191
reloading: false,
9292
error: null,
9393
};
94-
const loadJobInfo = async () => {
95-
try {
96-
nextState.jobInfo = await fetchJobInfo(this.state.selectedAttemptIndex);
97-
} catch (err) {
98-
nextState.error = `fetch job status failed: ${err.message}`;
94+
// Fetch job info first; if it fails (e.g. permission denied),
95+
// show the error and skip the remaining requests.
96+
try {
97+
nextState.jobInfo = await fetchJobInfo(this.state.selectedAttemptIndex);
98+
} catch (err) {
99+
nextState.error = `fetch job status failed: ${err.message}`;
100+
if (alertFlag === true) {
101+
alert(nextState.error);
99102
}
100-
};
103+
this.setState(nextState);
104+
return;
105+
}
106+
101107
const loadJobConfig = async () => {
102108
if (!isNil(jobConfig)) {
103109
return;
@@ -148,14 +154,10 @@ class JobDetail extends React.Component {
148154
}
149155
};
150156
await Promise.all([
151-
loadJobInfo(),
152157
loadJobConfig(),
153158
loadRawJobConfig(),
154159
loadSshInfo(),
155160
]);
156-
if (alertFlag === true && !isNil(nextState.error)) {
157-
alert(nextState.error);
158-
}
159161
if (isNil(this.state.selectedAttemptIndex)) {
160162
nextState.selectedAttemptIndex = nextState.jobInfo.jobStatus.retries;
161163
}
@@ -362,6 +364,19 @@ class JobDetail extends React.Component {
362364
}
363365
if (loading) {
364366
return <SpinnerLoading />;
367+
} else if (isNil(jobInfo)) {
368+
return (
369+
<Stack styles={{ root: { margin: '30px' } }} gap='l1'>
370+
<Top />
371+
{!isEmpty(error) && (
372+
<div className={t.bgWhite}>
373+
<MessageBar messageBarType={MessageBarType.error}>
374+
{error}
375+
</MessageBar>
376+
</div>
377+
)}
378+
</Stack>
379+
);
365380
} else {
366381
return (
367382
<Context.Provider

src/webportal/src/app/job/job-view/fabric/job-detail/conn.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,16 @@ const wrapper = async func => {
3131
try {
3232
return await func();
3333
} catch (err) {
34-
if (err.data && err.data.code === 'UnauthorizedUserError') {
34+
if (!err.data) {
35+
throw err;
36+
}
37+
if (err.data.code === 'UnauthorizedUserError') {
3538
alert(err.data.message);
3639
clearToken();
37-
} else if (err.data && err.data.code === 'NoJobConfigError') {
40+
} else if (err.data.code === 'NoJobConfigError') {
3841
throw new NotFoundError(err.data.message);
3942
} else {
40-
throw new Error((err.data && err.data.message) || err.message || 'Unknown error');
43+
throw new Error(err.data.message || err.message || 'Unknown error');
4144
}
4245
}
4346
};
@@ -58,6 +61,9 @@ export async function fetchJobInfo(attemptIndex) {
5861
},
5962
});
6063
const result = await res.json();
64+
if (!res.ok) {
65+
throw new Error(result.message || `HTTP ${res.status}`);
66+
}
6167
return result;
6268
});
6369
}

0 commit comments

Comments
 (0)