diff --git a/plugins/file-manager/src/frontend/FileManager.tsx b/plugins/file-manager/src/frontend/FileManager.tsx
index c234717ac..9d10f5ff9 100644
--- a/plugins/file-manager/src/frontend/FileManager.tsx
+++ b/plugins/file-manager/src/frontend/FileManager.tsx
@@ -1416,10 +1416,13 @@ function FileManagerContent({
const { downloadSSHFileStream } =
await import("./api/ssh-file-operations-api");
- toast.loading(, {
- id: toastId,
- duration: Infinity,
- });
+ toast.loading(
+ ,
+ {
+ id: toastId,
+ duration: Infinity,
+ },
+ );
await downloadSSHFileStream(
sshSessionId,
@@ -1438,6 +1441,7 @@ function FileManagerContent({
toast.loading(
{
const toastId = toast.loading(
- ,
+ ,
{ duration: Infinity },
);
try {
@@ -145,6 +145,7 @@ export function DiffViewer({
({ loaded, total }) => {
toast.loading(
0
? Math.min(100, Math.round((loaded / total) * 100))
diff --git a/plugins/file-manager/src/frontend/components/FileWindow.tsx b/plugins/file-manager/src/frontend/components/FileWindow.tsx
index 2db6bad3e..e727e6527 100644
--- a/plugins/file-manager/src/frontend/components/FileWindow.tsx
+++ b/plugins/file-manager/src/frontend/components/FileWindow.tsx
@@ -483,7 +483,7 @@ export function FileWindow({
const handleDownload = async () => {
const toastId = toast.loading(
- ,
+ ,
{ duration: Infinity },
);
try {
@@ -495,6 +495,7 @@ export function FileWindow({
({ loaded, total }) => {
toast.loading(
void;
}
export function LocalTransferProgressToast({
+ t,
status,
onCancel,
}: LocalTransferProgressToastProps) {
- const { t } = useTranslation();
const percent =
status.totalBytes > 0
? Math.min(100, Math.round((status.bytesDone / status.totalBytes) * 100))
diff --git a/plugins/file-manager/src/frontend/components/TransferProgressToast.tsx b/plugins/file-manager/src/frontend/components/TransferProgressToast.tsx
index 830b143f8..4a85f1b9e 100644
--- a/plugins/file-manager/src/frontend/components/TransferProgressToast.tsx
+++ b/plugins/file-manager/src/frontend/components/TransferProgressToast.tsx
@@ -4,7 +4,7 @@ import {
getTransferProgressPercent,
type TransferProgressResponse,
} from "../api/transfer-api";
-import { useTranslation } from "@termix/plugin-sdk/frontend";
+import type { TranslateFn } from "@termix/plugin-sdk/frontend";
import {
Archive,
ArchiveRestore,
@@ -16,6 +16,7 @@ import {
import { TransferProgressBar } from "./TransferProgressBar";
interface TransferProgressToastProps {
+ t: TranslateFn;
status: TransferProgressResponse;
liveMbPerSec?: number;
stalled?: boolean;
@@ -25,6 +26,7 @@ interface TransferProgressToastProps {
}
export function TransferProgressToast({
+ t,
status,
liveMbPerSec,
stalled = false,
@@ -32,7 +34,6 @@ export function TransferProgressToast({
onCancel,
cancelling = false,
}: TransferProgressToastProps) {
- const { t } = useTranslation();
const percent = getTransferProgressPercent(status);
let title = t("transfer.progressTransferring");
diff --git a/plugins/file-manager/src/frontend/hooks/useLocalTransfers.ts b/plugins/file-manager/src/frontend/hooks/useLocalTransfers.ts
index 3ea737781..1ac7541c5 100644
--- a/plugins/file-manager/src/frontend/hooks/useLocalTransfers.ts
+++ b/plugins/file-manager/src/frontend/hooks/useLocalTransfers.ts
@@ -193,6 +193,7 @@ export function useLocalTransfers({
const render = () => {
toast.loading(
createElement(LocalTransferProgressToast, {
+ t,
status: { ...status, cancelling },
onCancel: () => {
cancelled = true;
diff --git a/plugins/file-manager/src/frontend/transferProgressMonitor.tsx b/plugins/file-manager/src/frontend/transferProgressMonitor.tsx
index ae1b742bf..8c86f3e30 100644
--- a/plugins/file-manager/src/frontend/transferProgressMonitor.tsx
+++ b/plugins/file-manager/src/frontend/transferProgressMonitor.tsx
@@ -38,6 +38,7 @@ function formatFileSize(bytes?: number): string {
}
function renderTransferProgressToast(
+ t: TFunction,
toastId: string | number,
status: TransferProgressResponse,
liveMbPerSec?: number,
@@ -47,6 +48,7 @@ function renderTransferProgressToast(
): void {
toast.loading(
,
@@ -279,6 +282,7 @@ export function beginTransferProgressMonitoring(
if (cancelling) return;
cancelling = true;
renderTransferProgressToast(
+ t,
progressToast,
{ ...initialStatus, transferId },
undefined,
@@ -294,6 +298,7 @@ export function beginTransferProgressMonitoring(
options.onProgress?.(status);
const { rate, stalled } = progressTracker.update(status);
renderTransferProgressToast(
+ t,
progressToast,
status,
rate,
@@ -333,6 +338,7 @@ export function beginTransferProgressMonitoring(
});
renderTransferProgressToast(
+ t,
progressToast,
initialStatus,
undefined,
diff --git a/plugins/file-manager/tests/frontend/progress-toast-context.test.tsx b/plugins/file-manager/tests/frontend/progress-toast-context.test.tsx
new file mode 100644
index 000000000..4032b6644
--- /dev/null
+++ b/plugins/file-manager/tests/frontend/progress-toast-context.test.tsx
@@ -0,0 +1,54 @@
+import { cleanup, fireEvent, render, screen } from "@testing-library/react";
+import { afterEach, expect, it, vi } from "vitest";
+vi.mock("@termix/plugin-sdk/frontend", () => ({
+ useTranslation: () => {
+ throw Error("No plugin scope in the global toaster");
+ },
+}));
+import { DownloadProgressToast } from "../../src/frontend/components/DownloadProgressToast";
+import { TransferProgressToast } from "../../src/frontend/components/TransferProgressToast";
+import { LocalTransferProgressToast } from "../../src/frontend/components/LocalTransferProgressToast";
+afterEach(cleanup);
+const t = (key: string) => key;
+it("renders download progress outside plugin scope", () => {
+ render(
+ ,
+ );
+ expect(screen.getByRole("progressbar").getAttribute("aria-valuenow")).toBe(
+ "50",
+ );
+});
+it("renders host transfer progress outside plugin scope", () => {
+ render(
+ ,
+ );
+ expect(screen.getByRole("progressbar")).toBeTruthy();
+});
+it("preserves cancellation on local transfers outside plugin scope", () => {
+ const cancel = vi.fn();
+ render(
+ ,
+ );
+ fireEvent.click(screen.getByRole("button"));
+ expect(cancel).toHaveBeenCalledOnce();
+});