дзеркало
https://github.com/l0ng-ai/openidea.git
синхронізовано 2026-11-08 19:02:17 +02:00
fix: resolve frontend and cross-platform CI failures
Цей коміт міститься в:
1 джерело
4d503ef976
коміт
364bb5ef50
6 files changed
+54
-27
No files matched your search
@@ -158,6 +158,7 @@ pub fn path_with_shims(managers: &[Manager], path: &OsStr) -> OsString {
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[cfg(unix)]
|
||||
fn mkdir(p: &Path) {
|
||||
std::fs::create_dir_all(p).unwrap();
|
||||
}
|
||||
|
||||
@@ -109,7 +109,13 @@ fn server_environment_from_login_shell_and_devcontainer() {
|
||||
let started = project.join("started.txt");
|
||||
wait_for("postStartCommand", || std::fs::read_to_string(&started).is_ok_and(|s| s.ends_with('\n')));
|
||||
assert_eq!(std::fs::read_to_string(&started).unwrap(), "two-demo\n");
|
||||
wait_for("the task to end", || events.0.lock().iter().any(|e| matches!(e, IdeEvent::Task { done: true, .. })));
|
||||
wait_for("postStartCommand to end", || {
|
||||
events
|
||||
.0
|
||||
.lock()
|
||||
.iter()
|
||||
.any(|e| matches!(e, IdeEvent::Task { title, done: true, .. } if title == "postStartCommand"))
|
||||
});
|
||||
assert!(events.0.lock().iter().any(
|
||||
|e| matches!(e, IdeEvent::Task { message: Some(m), title, .. } if m == "post-start-output" && title == "postStartCommand")
|
||||
));
|
||||
|
||||
@@ -86,7 +86,6 @@ export function useStashTabCounts(available: boolean) {
|
||||
void Promise.all(roots.map((r) => call(commands.vcsStashes(r))))
|
||||
.then((lists) => live && setStashCount(lists.reduce((n, list) => n + list.length, 0)))
|
||||
.catch(() => undefined);
|
||||
else setStashCount(0);
|
||||
return () => {
|
||||
live = false;
|
||||
};
|
||||
@@ -95,7 +94,7 @@ export function useStashTabCounts(available: boolean) {
|
||||
useEffect(() => {
|
||||
if (available) void loadShelves().catch(() => undefined);
|
||||
}, [available]);
|
||||
return { stashCount, shelfCount };
|
||||
return { stashCount: available ? stashCount : 0, shelfCount };
|
||||
}
|
||||
|
||||
/** "Commit" / "Shelf" / "Stash" content tabs; they stand in for the tool window title. */
|
||||
@@ -842,36 +841,34 @@ export function StashesPanel() {
|
||||
const repo = useVcs((s) => s.repo);
|
||||
const repos = useVcs((s) => s.roots);
|
||||
const version = useVcs((s) => s.version);
|
||||
const [stashes, setStashes] = useState<(import("@/bindings").Stash & { repo: string | null })[]>([]);
|
||||
const [loaded, setLoaded] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [tick, setTick] = useState(0);
|
||||
const [active, setActive] = useState(0);
|
||||
const request = useMemo(() => ({ repos, repo, version, tick }), [repos, repo, version, tick]);
|
||||
const [result, setResult] = useState<{
|
||||
request: typeof request;
|
||||
stashes: (import("@/bindings").Stash & { repo: string | null })[];
|
||||
error: string | null;
|
||||
} | null>(null);
|
||||
const loaded = result?.request === request;
|
||||
const stashes = loaded ? result.stashes : [];
|
||||
const error = loaded ? result.error : null;
|
||||
useEffect(() => {
|
||||
let live = true;
|
||||
setLoaded(false);
|
||||
void Promise.all(
|
||||
(repos.length ? repos : [repo]).map(async (root) =>
|
||||
(request.repos.length ? request.repos : [request.repo]).map(async (root) =>
|
||||
(await call(commands.vcsStashes(root))).map((s) => ({ ...s, repo: root })),
|
||||
),
|
||||
)
|
||||
.then((lists) => {
|
||||
if (live) {
|
||||
setStashes(lists.flat());
|
||||
setError(null);
|
||||
setLoaded(true);
|
||||
}
|
||||
if (live) setResult({ request, stashes: lists.flat(), error: null });
|
||||
})
|
||||
.catch((e) => {
|
||||
if (live) {
|
||||
setError(String(e));
|
||||
setLoaded(true);
|
||||
}
|
||||
if (live) setResult({ request, stashes: [], error: String(e) });
|
||||
});
|
||||
return () => {
|
||||
live = false;
|
||||
};
|
||||
}, [repos, repo, version, tick]);
|
||||
}, [request]);
|
||||
const current = stashes[active];
|
||||
return (
|
||||
<div className={styles.changes}>
|
||||
|
||||
@@ -1,17 +1,13 @@
|
||||
import { beforeEach, expect, it, vi } from "vitest";
|
||||
import { act, fireEvent, render, screen } from "@testing-library/react";
|
||||
const apply = vi.hoisted(() => vi.fn());
|
||||
const { apply, list } = vi.hoisted(() => ({ apply: vi.fn(), list: vi.fn() }));
|
||||
vi.mock("@/platform/ipc", async (original) => {
|
||||
const real = await original<typeof import("@/platform/ipc")>();
|
||||
return {
|
||||
...real,
|
||||
commands: {
|
||||
...real.commands,
|
||||
vcsStashes: (repo: string) =>
|
||||
Promise.resolve({
|
||||
status: "ok",
|
||||
data: [{ index: 0, message: `On main: ${repo.endsWith("front") ? "First" : "Second"}`, timeMs: 0 }],
|
||||
}),
|
||||
vcsStashes: list,
|
||||
},
|
||||
};
|
||||
});
|
||||
@@ -24,6 +20,12 @@ import { useVcs } from "../store";
|
||||
|
||||
beforeEach(() => {
|
||||
apply.mockReset();
|
||||
list.mockReset().mockImplementation((repo: string) =>
|
||||
Promise.resolve({
|
||||
status: "ok",
|
||||
data: [{ index: 0, message: `On main: ${repo.endsWith("front") ? "First" : "Second"}`, timeMs: 0 }],
|
||||
}),
|
||||
);
|
||||
useVcs.setState({ root: "/p", roots: ["/p/front", "/p/back"], repo: "/p/front" });
|
||||
});
|
||||
|
||||
@@ -36,3 +38,24 @@ it("lists stashes from every root and applies the selected row in its own reposi
|
||||
fireEvent.click(screen.getByRole("button", { name: "Apply Stash" }));
|
||||
expect(apply).toHaveBeenCalledWith(0, false, "/p/front");
|
||||
});
|
||||
|
||||
it("disables stale stash actions while another repository is loading", async () => {
|
||||
render(<StashesPanel />);
|
||||
await screen.findByText("front · First");
|
||||
let resolve!: (value: unknown) => void;
|
||||
list.mockImplementation(
|
||||
() =>
|
||||
new Promise((done) => {
|
||||
resolve = done;
|
||||
}),
|
||||
);
|
||||
act(() => useVcs.setState({ root: "/other", roots: ["/other"], repo: "/other" }));
|
||||
expect(screen.queryByText("front · First")).not.toBeInTheDocument();
|
||||
expect(screen.getByRole("button", { name: "Apply Stash" })).toBeDisabled();
|
||||
await act(async () => {
|
||||
resolve({ status: "ok", data: [{ index: 0, message: "On main: New project", timeMs: 0 }] });
|
||||
});
|
||||
await screen.findByText("New project");
|
||||
fireEvent.click(screen.getByRole("button", { name: "Apply Stash" }));
|
||||
expect(apply).toHaveBeenCalledWith(0, false, "/other");
|
||||
});
|
||||
@@ -585,8 +585,6 @@
|
||||
"Duplicate groups": "重复组",
|
||||
"Duplicates": "重复项",
|
||||
"Duplicate…": "复制…",
|
||||
"Eclipse": "Eclipse",
|
||||
"Eclipse (macOS)": "Eclipse (macOS)",
|
||||
"Edit": "编辑",
|
||||
"Edit Cell": "编辑单元格",
|
||||
"Edit Changelist": "编辑更改列表",
|
||||
@@ -2849,7 +2847,6 @@
|
||||
"Test classpath of the module": "模块的测试类路径",
|
||||
"Run a Java main class": "运行 Java 主类",
|
||||
"Run a Spring Boot application": "运行 Spring Boot 应用程序",
|
||||
"Spring Boot": "Spring Boot",
|
||||
"Passed to the JVM that spring-boot:run or the tests start, not to Maven": "传给 spring-boot:run 或测试启动的 JVM,而不是 Maven 本身",
|
||||
"Passed to the JVMs the tasks start (bootRun, run, test), not to Gradle": "传给任务启动的 JVM(bootRun、run、test),而不是 Gradle 本身",
|
||||
"Run a package.json script": "运行 package.json 脚本",
|
||||
|
||||
@@ -102,6 +102,8 @@ const UNTRANSLATED = new Set<string>([
|
||||
"Docker",
|
||||
"Docker Compose",
|
||||
"Dockerfile",
|
||||
"Eclipse",
|
||||
"Eclipse (macOS)",
|
||||
"Eclipse Temurin",
|
||||
"EditorConfig",
|
||||
"Git",
|
||||
@@ -123,6 +125,7 @@ const UNTRANSLATED = new Set<string>([
|
||||
"Node.js",
|
||||
"npm",
|
||||
"OpenIDEA",
|
||||
"Spring Boot",
|
||||
"PostgreSQL",
|
||||
"Pyright",
|
||||
"Rust",
|
||||
|
||||
Reference in new issue
Заблокувати користувача