Skip to content

Commit

Permalink
Don't let toast elapse in background in some browsers (#7741)
Browse files Browse the repository at this point in the history
* WIP: try to not let toast elapse in background

* add console print of error and warning messages

* roughly check Toast.error occurrences for duplications

* roughly check Toast.warning occurrences for console print duplications

* only print toast content to console if its a string

* add changelog

* address review
  • Loading branch information
dieknolle3333 committed Apr 15, 2024
1 parent d7da22e commit ca2b052
Show file tree
Hide file tree
Showing 14 changed files with 35 additions and 22 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ For upgrade instructions, please check the [migration guide](MIGRATIONS.released
- Duplicated annotations are opened in a new browser tab. [#7724](https://github.com/scalableminds/webknossos/pull/7724)
- When proofreading segments and merging two segments, the segment item that doesn't exist anymore after the merge is automatically removed. [#7729](https://github.com/scalableminds/webknossos/pull/7729)
- Changed some internal APIs to use spelling dataset instead of dataSet. This requires all connected datastores to be the latest version. [#7690](https://github.com/scalableminds/webknossos/pull/7690)
- Toasts are shown until WEBKNOSSOS is running in the active browser tab again. Also, the content of most toasts that show errors or warnings is printed to the browser's console. [#7741](https://github.com/scalableminds/webknossos/pull/7741)

### Fixed
- Fixed that the Command modifier on MacOS wasn't treated correctly for some shortcuts. Also, instead of the Alt key, the ⌥ key is shown as a hint in the status bar on MacOS. [#7659](https://github.com/scalableminds/webknossos/pull/7659)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ export async function tryToFetchDatasetsByName(
);
return datasets;
} catch (exception) {
console.warn(exception);
Toast.warning(userErrorMessage);
console.warn(exception);
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ export default function WorkflowListView() {
const _workflows = (await getVoxelyticsWorkflows()).map(parseWorkflowInfo);
setWorkflows(_workflows);
} catch (err) {
console.error(err);
Toast.error("Could not load workflow list.");
console.error(err);
} finally {
setIsLoading(false);
}
Expand Down
2 changes: 1 addition & 1 deletion frontend/javascripts/admin/voxelytics/workflow_view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -372,8 +372,8 @@ export default function WorkflowView() {
error: err as Error,
});
} catch (accessibleBySwitchingError) {
console.log(accessibleBySwitchingError);
Toast.error("Could not load workflow report.");
console.error(accessibleBySwitchingError);
setLoadingState({ status: "FAILED", error: accessibleBySwitchingError as Error });
}
}
Expand Down
8 changes: 4 additions & 4 deletions frontend/javascripts/libs/browser_feature_check.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,6 @@ export default function checkBrowserFeatures() {
new BigUint64Array(1);
"hello".replaceAll("l", "k");
} catch (exception) {
console.error(
"This browser lacks support for some modern features. Exception caught during test of features:",
exception,
);
Toast.warning(
<div>
Your browser seems to be outdated.{" "}
Expand All @@ -23,5 +19,9 @@ export default function checkBrowserFeatures() {
to avoid errors. See console for details.
</div>,
);
console.error(
"This browser lacks support for some modern features. Exception caught during test of features:",
exception,
);
}
}
1 change: 0 additions & 1 deletion frontend/javascripts/libs/error_handling.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,6 @@ class ErrorHandling {
error = new Error(message);
}

console.error(error);
this.notify(error);

if (error.toString() === "Error: Script error.") {
Expand Down
22 changes: 18 additions & 4 deletions frontend/javascripts/libs/toast.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { notification, Collapse } from "antd";
import { CloseCircleOutlined } from "@ant-design/icons";
import React from "react";
import { animationFrame, sleep } from "./utils";

export type ToastStyle = "info" | "warning" | "success" | "error";
export type Message = {
Expand Down Expand Up @@ -75,12 +76,12 @@ const Toast = {
);
},

message(
async message(
type: ToastStyle,
rawMessage: string | React.ReactNode,
config: ToastConfig,
details?: string,
): void {
): Promise<void> {
const message = this.buildContentWithDetails(rawMessage, details);
const timeout = config.timeout != null ? config.timeout : 6000;
const key = config.key || (typeof message === "string" ? message : undefined);
Expand All @@ -94,11 +95,10 @@ const Toast = {
toastMessage = message;
}

const timeOutInSeconds = timeout / 1000;
let toastConfig = {
icon: undefined,
key,
duration: sticky ? 0 : timeOutInSeconds,
duration: 0,
message: toastMessage,
style: {},
className: "",
Expand All @@ -112,13 +112,26 @@ const Toast = {
}

notification[type](toastConfig);

// Make sure that toasts don't just disappear while the user has WK in a background tab (e.g. while uploading large dataset).
// Most browsers pause requestAnimationFrame() if the current tab is not active, but Firefox does not seem to do that.
if (!sticky && key != null) {
const splitTimeout = timeout / 2;
await animationFrame(); // ensure tab is active
await sleep(splitTimeout);
await animationFrame();
// If the user has switched the tab, show the toast again so that the user doesn't just see the toast dissapear.
await sleep(splitTimeout);
this.close(key);
}
},

info(message: React.ReactNode, config: ToastConfig = {}, details?: string | undefined): void {
this.message("info", message, config, details);
},

warning(message: React.ReactNode, config: ToastConfig = {}, details?: string | undefined): void {
if (typeof message === "string") console.warn(message);
this.message("warning", message, config, details);
},

Expand All @@ -135,6 +148,7 @@ const Toast = {
config: ToastConfig = {},
details?: string | undefined,
): void {
if (typeof message === "string") console.error(message);
this.message("error", message, config, details);
},

Expand Down
2 changes: 1 addition & 1 deletion frontend/javascripts/oxalis/controller.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -194,10 +194,10 @@ class Controller extends React.PureComponent<PropsWithRouter, State> {
try {
eval(content);
} catch (error) {
console.error(error);
Toast.error(
`Error executing the task script "${script.name}". See console for more information.`,
);
console.error(error);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ export function* pushAnnotationUpdateAsync(action: Action) {
// we will only notify the user if the name, visibility or description could not be changed.
// Otherwise, we won't notify the user and won't let the sagas crash as the actual skeleton/volume
// tracings are handled separately.
console.error(error);
ErrorHandling.notify(error as Error);
if (
["SET_ANNOTATION_NAME", "SET_ANNOTATION_VISIBILITY", "SET_ANNOTATION_DESCRIPTION"].includes(
Expand All @@ -92,6 +91,7 @@ export function* pushAnnotationUpdateAsync(action: Action) {
) {
Toast.error("Could not update annotation property. Please try again.");
}
console.error(error);
}
}

Expand Down
8 changes: 4 additions & 4 deletions frontend/javascripts/oxalis/model/sagas/mesh_saga.ts
Original file line number Diff line number Diff line change
Expand Up @@ -785,8 +785,8 @@ function* loadPrecomputedMeshForSegmentId(
scale = chunkDescriptors.scale;
loadingOrder = chunkDescriptors.loadingOrder;
} catch (exception) {
console.warn("Mesh chunk couldn't be loaded due to", exception);
Toast.warning(messages["tracing.mesh_listing_failed"]);
console.warn("Mesh chunk couldn't be loaded due to", exception);
yield* put(finishedLoadingMeshAction(layerName, id));
yield* put(removeMeshAction(layerName, id));
return;
Expand All @@ -808,8 +808,8 @@ function* loadPrecomputedMeshForSegmentId(
try {
yield* call(processTaskWithPool, loadChunksTasks, PARALLEL_PRECOMPUTED_MESH_LOADING_COUNT);
} catch (exception) {
console.error(exception);
Toast.warning(`Some mesh chunks could not be loaded for segment ${id}.`);
console.error(exception);
}

yield* put(finishedLoadingMeshAction(layerName, id));
Expand Down Expand Up @@ -1089,8 +1089,8 @@ function* downloadMeshCellById(cellName: string, segmentId: number, layerName: s
yield* call(saveAs, blob, `${cellName}-${segmentId}.stl`);
} catch (exception) {
ErrorHandling.notify(exception as Error);
console.error(exception);
Toast.error("Could not export to STL. See console for details");
console.error(exception);
}
}

Expand Down Expand Up @@ -1123,8 +1123,8 @@ function* downloadMeshCellsAsZIP(
yield* call(saveAs, result as Blob, "mesh-export.zip");
} catch (exception) {
ErrorHandling.notify(exception as Error);
console.error(exception);
Toast.error("Could not export meshes as STL files. See console for details");
console.error(exception);
}
}

Expand Down
2 changes: 1 addition & 1 deletion frontend/javascripts/oxalis/model/sagas/proofread_saga.ts
Original file line number Diff line number Diff line change
Expand Up @@ -826,10 +826,10 @@ function* getAgglomerateInfos(
}> | null> {
const idInfos = yield* all(positions.map((pos) => call(getMappedAndUnmapped, pos)));
if (idInfos.find((idInfo) => idInfo.agglomerateId === 0 || idInfo.unmappedId === 0) != null) {
console.warn("At least one id was zero:", idInfos);
Toast.warning(
"One of the selected segments has the id 0 which is the background. Cannot merge/split.",
);
console.warn("At least one id was zero:", idInfos);
return null;
}
return idInfos;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ export default function* listenToQuickSelect(): Saga<void> {
} catch (ex) {
Toast.error((ex as Error).toString());
ErrorHandling.notify(ex as Error);
console.error(ex);
} finally {
yield* put(setBusyBlockingInfoAction(false));
action.quickSelectGeometry.setCoordinates([0, 0, 0], [0, 0, 0]);
Expand Down
2 changes: 1 addition & 1 deletion frontend/javascripts/oxalis/model_initialization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -700,11 +700,11 @@ async function applyLayerState(stateByLayer: UrlStateByLayer) {
// The name of the layer could have changed if a volume tracing was created from a viewed annotation
effectiveLayerName = getLayerByName(dataset, layerName, true).name;
} catch (e) {
console.error(e);
Toast.error(
// @ts-ignore
`URL configuration values for the layer "${layerName}" are ignored, because: ${e.message}`,
);
console.error(e);
// @ts-ignore
ErrorHandling.notify(e, {
urlLayerState: stateByLayer,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -553,10 +553,10 @@ function StartJobForm(props: StartJobFormProps) {
);
handleClose();
} catch (error) {
console.error(error);
Toast.error(
`The ${jobName} job could not be started. Please contact an administrator or look in the console for more details.`,
);
console.error(error);
handleClose();
}
};
Expand Down

0 comments on commit ca2b052

Please sign in to comment.