Skip to content

fix: OPTIC-1794: Improve handling of missing tasks and projects when fetching data within DataManager #7210

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 29 commits into from
Mar 13, 2025
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
b915440
feat: OPTIC-1746: Improve global error message handling by showing to…
bmartel Mar 4, 2025
7793c42
linting
bmartel Mar 4, 2025
5e274b5
Capture error boundary in sentry, remove stacktrace from Modal
bmartel Mar 5, 2025
d11fef6
linting
bmartel Mar 5, 2025
1d7b327
don't throw an error in test from useToast as it forces every consume…
bmartel Mar 5, 2025
7360e53
Update web/apps/labelstudio/src/components/Modal/Modal.jsx
bmartel Mar 5, 2025
2d3f2b4
Merge branch 'develop' into 'fb-optic-1746'
robot-ci-heartex Mar 6, 2025
e4907ce
Sync Follow Merge dependencies
robot-ci-heartex Mar 6, 2025
119d070
Merge remote-tracking branch 'origin/develop' into fb-optic-1746
bmartel Mar 6, 2025
959b1c3
adding better 404 handling
bmartel Mar 6, 2025
94e8efd
Sync Follow Merge dependencies
robot-ci-heartex Mar 7, 2025
332bf86
only automatically handle 404 errors if not inline
bmartel Mar 10, 2025
20cae3b
linting
bmartel Mar 10, 2025
2a22930
fix errorFilter checking resulting in implementation breakages with e…
bmartel Mar 10, 2025
9097d2e
fix: OPTIC-1794: Improve handling of missing tasks and projects when …
bmartel Mar 11, 2025
dac5c31
Merge branch 'develop' into 'fb-optic-1746'
robot-ci-heartex Mar 11, 2025
0b21bd4
Sync Follow Merge dependencies
robot-ci-heartex Mar 11, 2025
1efa47b
Merge remote-tracking branch 'origin/develop' into fb-optic-1794
bmartel Mar 11, 2025
2159a46
Merge remote-tracking branch 'origin/fb-optic-1746' into fb-optic-1794
bmartel Mar 11, 2025
acee621
Merge remote-tracking branch 'origin/develop' into fb-optic-1794
bmartel Mar 11, 2025
4abedb3
Make the messaging more streamlined
bmartel Mar 12, 2025
ebd650f
linting
bmartel Mar 12, 2025
42d703f
Update web/apps/labelstudio/src/pages/DataManager/DataManager.jsx
bmartel Mar 12, 2025
1a5cc30
Apply suggestions from code review
bmartel Mar 12, 2025
623ed3a
applying feedback from CR
bmartel Mar 12, 2025
d3188e2
Merge branch 'develop' into 'fb-optic-1794'
robot-ci-heartex Mar 13, 2025
e0b505f
Sync Follow Merge dependencies
robot-ci-heartex Mar 13, 2025
f753694
don't cancel, this apparently causes a regression with regards to pre…
bmartel Mar 13, 2025
0153425
Sync Follow Merge dependencies
robot-ci-heartex Mar 13, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 23 additions & 3 deletions web/apps/labelstudio/src/pages/DataManager/DataManager.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { isDefined } from "../../utils/helpers";
import { ImportModal } from "../CreateProject/Import/ImportModal";
import { ExportPage } from "../ExportPage/ExportPage";
import { APIConfig } from "./api-config";
import { ToastContext } from "@humansignal/ui";
import { ToastContext, ToastType } from "@humansignal/ui";
import { FF_OPTIC_2, isFF } from "../../utils/feature-flags";

import "./DataManager.scss";
Expand Down Expand Up @@ -96,7 +96,27 @@ export const DataManagerPage = ({ ...props }) => {

Object.assign(window, { dataManager });

dataManager.on("crash", () => setCrashed());
dataManager.on("crash", (details) => {
const error = details?.error;
const isMissingTaskError = error?.startsWith("Task ID:");
const isMissingProjectError = error?.startsWith("Project ID:");

if (isMissingTaskError || isMissingProjectError) {
toast.show({
message: `The ${
isMissingTaskError ? "task" : "project"
} you are trying to access does not exist or is no longer available.`,
type: ToastType.error,
duration: 10000,
});
}

if (isMissingTaskError) {
history.push(buildLink("", { id: params.id }));
} else if (isMissingProjectError) {
history.push("/projects");
}
});

dataManager.on("settingsClicked", () => {
history.push(buildLink("/settings/labeling", { id: params.id }));
Expand All @@ -122,7 +142,7 @@ export const DataManagerPage = ({ ...props }) => {
const target = route.replace(/^projects/, "");

if (target) history.push(buildLink(target, { id: params.id }));
else history.push("/projects/");
else history.push("/projects");
});

if (interactiveBacked) {
Expand Down
29 changes: 21 additions & 8 deletions web/libs/datamanager/src/stores/AppStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -484,17 +484,18 @@ export const AppStore = types
try {
const newProject = yield self.apiCall("project", params);
const projectLength = Object.entries(self.project ?? {}).length;
const newProjectLength = Object.entries(newProject ?? {}).length;

self.needsDataFetch =
options.force !== true && projectLength > 0
options.force !== true && projectLength > 0 && newProjectLength > 0
? self.project.task_count !== newProject.task_count ||
self.project.task_number !== newProject.task_number ||
self.project.annotation_count !== newProject.annotation_count ||
self.project.num_tasks_with_annotations !== newProject.num_tasks_with_annotations
: false;

if (options.interaction === "timer") {
self.project = Object.assign(self.project ?? {}, newProject);
self.project = Object.assign(self.project ?? {}, newProject ?? {});
} else if (JSON.stringify(newProject ?? {}) !== JSON.stringify(self.project ?? {})) {
self.project = newProject;
}
Expand All @@ -504,7 +505,15 @@ export const AppStore = types
self.SDK.invoke(`${itemType}Updated`, self.project);
}
} catch {
self.crash();
// When in timer (polling project counts) mode, we can still continue
// but we need to crash for non-polling interactions
// because we can't display the app without the project itself and will need to redirect
if (options.interaction !== "timer") {
self.crash({
error: `Project ID: ${self.SDK.projectId} does not exist or is no longer available`,
redirect: true,
});
}
return false;
}
self.projectFetch = false;
Expand Down Expand Up @@ -622,7 +631,9 @@ export const AppStore = types
result.isCanceled = signal.aborted;
self.requestsInFlight.delete(requestKey);
}
if (result.error && result.status !== 404 && !signal.aborted) {
// We don't want to show errors when loading data in polling mode
// we will just allow it to try again later
if (result.error && result.status !== 404 && !signal.aborted && params.interaction !== "timer") {
if (options?.errorHandler?.(result)) {
return result;
}
Expand Down Expand Up @@ -739,10 +750,12 @@ export const AppStore = types
return result;
}),

crash() {
self.destroy();
self.crashed = true;
self.SDK.invoke("crash");
crash(options = {}) {
if (options.redirect !== true) {
self.destroy();
self.crashed = true;
}
self.SDK.invoke("crash", options);
},

destroy() {
Expand Down
13 changes: 12 additions & 1 deletion web/libs/datamanager/src/stores/DataStores/tasks.js
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,19 @@ export const create = (columns) => {

self.setLoading(taskID);

const taskData = yield self.root.apiCall("task", { taskID });
const taskData = yield self.root.apiCall("task", { taskID }, undefined, { allowToCancel: true });

if (taskData.isCanceled) {
return null;
}
if (taskData.status === 404) {
self.finishLoading(taskID);
getRoot(self).SDK.invoke("crash", {
error: `Task ID: ${taskID} does not exist or is no longer available`,
redirect: true,
});
return null;
}
const task = self.applyTaskSnapshot(taskData, taskID);

if (select !== false) self.setSelected(task);
Expand Down
Loading