Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
14 changes: 0 additions & 14 deletions flatpak/generated-sources.json
Original file line number Diff line number Diff line change
Expand Up @@ -19909,20 +19909,6 @@
"dest-filename": "react-refresh-0.18.0.tgz",
"dest": "flatpak-node/yarn-mirror"
},
{
"type": "file",
"url": "https://registry.yarnpkg.com/react-resize-detector/-/react-resize-detector-2.3.0.tgz#57bad1ae26a28a62a2ddb678ba6ffdf8fa2b599c",
"sha512": "a0201d7445967855981f914070774161c663030f5f3334542bdb164b1e96bd248e3d5471707779cd3206cbf98ebacf8084dfeee93e133225b1beaefd3f2c2725",
"dest-filename": "react-resize-detector-2.3.0.tgz",
"dest": "flatpak-node/yarn-mirror"
},
{
"type": "file",
"url": "https://registry.yarnpkg.com/react-resize-detector/-/react-resize-detector-4.2.3.tgz#7df258668a30bdfd88e655bbdb27db7fd7b23127",
"sha512": "e00792ea5c5dcf628e80365a395b7576ea031eb6d8c12ad45f7d8a78cf63eadf484b246986825b4d108c4b568f17164716a70218b4f580c977944712599356d0",
"dest-filename": "react-resize-detector-4.2.3.tgz",
"dest": "flatpak-node/yarn-mirror"
},
{
"type": "file",
"url": "https://registry.yarnpkg.com/react-select/-/react-select-1.3.0.tgz#1828ad5bf7f3e42a835c7e2d8cb13b5c20714876",
Expand Down
258 changes: 153 additions & 105 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

3 changes: 1 addition & 2 deletions pnpm-workspace.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -230,11 +230,10 @@ catalog:
react-markdown: ^6.0.2
react-overlays: ^1.2.0
react-redux: ^7.1.3
react-resize-detector: ^4.2.1
react-select: ^1.2.1
react-sortable-tree: ^2.6.2
react-sortable-tree-theme-file-explorer: ^2.0.0
recharts: ^1.8.5
recharts: ^2.15.4
redux: ^4.0.4
redux-act: ^1.8.0
redux-batched-actions: ^0.5.0
Expand Down
1 change: 0 additions & 1 deletion src/main/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,6 @@
"react-markdown": "catalog:",
"react-overlays": "catalog:",
"react-redux": "catalog:",
"react-resize-detector": "catalog:",
"react-select": "catalog:",
"react-sortable-tree": "catalog:",
"recharts": "catalog:",
Expand Down
1 change: 0 additions & 1 deletion src/renderer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,6 @@
"react-markdown": "catalog:",
"react-overlays": "catalog:",
"react-redux": "catalog:",
"react-resize-detector": "catalog:",
"react-select": "catalog:",
"react-sortable-tree": "catalog:",
"recharts": "catalog:",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import { render, screen, waitFor, cleanup } from "@testing-library/react";
import type { ReactNode } from "react";
import React from "react";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";

const resizeObserverInstances: MockResizeObserver[] = [];

class MockResizeObserver {
public callback: ResizeObserverCallback;
public observe = vi.fn();
public disconnect = vi.fn();

constructor(callback: ResizeObserverCallback) {
this.callback = callback;
resizeObserverInstances.push(this);
}
}

vi.mock("../../../controls/ErrorBoundary", () => ({
default: ({ children }: { children: ReactNode }) => <>{children}</>,
}));

vi.mock("react-redux", () => ({
connect: () => (component: React.ComponentType<Record<string, unknown>>) => component,
}));

vi.mock("react-i18next", () => ({
withTranslation: () => (component: unknown) => component,
translate: () => (component: unknown) => component,
useTranslation: () => ({ t: (key: string) => key }),
}));

vi.mock("recharts", () => ({
Area: () => null,
AreaChart: ({ children, height, width }: any) => (
<div data-testid="download-graph-chart" data-height={String(height)} data-width={String(width)}>
{children}
</div>
),
CartesianGrid: () => null,
Label: ({ value }: { value: string }) => <span>{value}</span>,
ReferenceLine: ({ children }: { children?: ReactNode }) => (
<div data-testid="download-graph-limit">{children}</div>
),
YAxis: () => null,
}));

import DownloadGraph from "./DownloadGraph";

const Graph = DownloadGraph as unknown as React.ComponentType<{
t: (key: string) => string;
maxBandwidth: number;
speeds: number[];
}>;

const t = (key: string) => key;

afterEach(() => {
cleanup();
resizeObserverInstances.length = 0;
delete (globalThis as any).ResizeObserver;
});

beforeEach(() => {
Object.defineProperty(HTMLElement.prototype, "clientWidth", {
configurable: true,
get: () => 320,
});
Object.defineProperty(HTMLElement.prototype, "clientHeight", {
configurable: true,
get: () => 120,
});
(globalThis as any).ResizeObserver = MockResizeObserver;
});

describe("DownloadGraph", () => {
it("updates the chart width when ResizeObserver reports a new size", async () => {
const { unmount } = render(<Graph t={t} maxBandwidth={0} speeds={[1, 2, 3]} />);

await waitFor(() => {
expect(screen.getByTestId("download-graph-chart")).toHaveAttribute("data-width", "320");
});

const observer = resizeObserverInstances[0];
expect(observer.observe).toHaveBeenCalledTimes(1);

observer.callback([{ contentRect: { width: 512, height: 120 } }] as any, observer as any);

await waitFor(() => {
expect(screen.getByTestId("download-graph-chart")).toHaveAttribute("data-width", "512");
});

unmount();
expect(observer.disconnect).toHaveBeenCalledTimes(1);
});

it("renders the bandwidth limit label when maxBandwidth constrains the graph", () => {
render(<Graph t={t} maxBandwidth={100} speeds={[120, 140]} />);

expect(screen.getByTestId("download-graph-limit")).toHaveTextContent(
"Bandwidth Limit (see Settings)",
);
});
});
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import type { TFunction } from "i18next";
import * as React from "react";
import ResizeDetector from "react-resize-detector";
import * as recharts from "recharts";

import { setSettingsPage } from "../../../actions/session";
import { ComponentEx, connect } from "../../../controls/ComponentEx";
import ErrorBoundary from "../../../controls/ErrorBoundary";
import type { IState } from "../../../types/IState";
import { bytesToString, truthy } from "../../../util/util";
import { bytesToString } from "../../../util/util";
import { NUM_SPEED_DATA_POINTS } from "../reducers/state";

interface IBaseProps {
Expand All @@ -29,13 +28,26 @@ interface IComponentState {
* download speed dashlet
*/
class DownloadGraph extends ComponentEx<IProps, IComponentState> {
private chartContainer?: HTMLDivElement;
private resizeObserver?: ResizeObserver;

constructor(props: IProps) {
super(props);
this.initState({ width: 800 });
}

public componentDidMount() {
this.forceUpdate();
if (this.chartContainer) {
this.resizeObserver = new ResizeObserver(([entry]) => {
this.onResize(entry.contentRect.width, entry.contentRect.height);
});
this.resizeObserver.observe(this.chartContainer);
}
}

public componentWillUnmount() {
this.resizeObserver?.disconnect();
}

public render(): JSX.Element {
Expand Down Expand Up @@ -80,7 +92,7 @@ class DownloadGraph extends ComponentEx<IProps, IComponentState> {
{showLimit ? (
<ReferenceLine y={maxBandwidth} strokeDasharray="6 2">
<Label
value={t("Bandwidth Limit (see Settings)")}
value={t("Bandwidth Limit (see Settings)") as string}
position="top"
onClick={this.openSettings}
/>
Expand All @@ -96,9 +108,6 @@ class DownloadGraph extends ComponentEx<IProps, IComponentState> {
}
</AreaChart>
</ErrorBoundary>
<ErrorBoundary>
<ResizeDetector handleWidth handleHeight onResize={this.onResize} />
</ErrorBoundary>
</div>
);
}
Expand All @@ -120,8 +129,9 @@ class DownloadGraph extends ComponentEx<IProps, IComponentState> {
return Math.ceil(input / roundVal) * roundVal;
}

private setRef = (ref: HTMLDivElement) => {
if (truthy(ref)) {
private setRef = (ref: HTMLDivElement | null) => {
this.chartContainer = ref ?? undefined;
if (ref) {
this.onResize(ref.clientWidth, ref.clientHeight);
}
};
Expand Down
7 changes: 2 additions & 5 deletions src/stylesheets/vortex/charts.scss
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,10 @@
}

.download-chart .recharts-area {
// unfortunately stroke and area are two separate groups that
// are indistinguishable by class/id so we have to rely on their order
// here (which is an implementation detail)
:first-child {
.recharts-area-area {
fill: url(#graph-gradient);
}
:last-child {
.recharts-area-curve {
stroke: $brand-clickable;
stroke-width: 1.2px;
}
Expand Down
1 change: 1 addition & 0 deletions vitest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export default defineConfig({
test: {
projects: [
"./src/**/vitest.config.ts",
"./src/**/vitest.config.mts",
"./src/main/vitest.downloader.config.ts",
"./packages/**/vitest.config.ts",
"./extensions/**/vitest.config.ts",
Expand Down
Loading