feat(FN-4856): merge fusion/fn-4856
This commit is contained in:
5
.changeset/fn-4856-quick-entry-github-toggle.md
Normal file
5
.changeset/fn-4856-quick-entry-github-toggle.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"@runfusion/fusion": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Fix Quick Entry GitHub link button: correctly reflects enabled/disabled state from project settings, reliably toggles on click, and shows an unambiguous active visual state.
|
||||||
@@ -179,56 +179,65 @@ export function QuickEntryBox({ onCreate, addToast, tasks = [], availableModels,
|
|||||||
// If onCreate is not provided, the component is disabled
|
// If onCreate is not provided, the component is disabled
|
||||||
const isDisabled = !onCreate;
|
const isDisabled = !onCreate;
|
||||||
|
|
||||||
// Fetch models and settings if not provided by parent
|
// Fetch models if not provided by parent
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (availableModels) {
|
if (availableModels) {
|
||||||
setLoadedModels(availableModels);
|
setLoadedModels(availableModels);
|
||||||
setModelsLoading(false);
|
setModelsLoading(false);
|
||||||
setModelsError(null);
|
setModelsError(null);
|
||||||
} else {
|
return;
|
||||||
let cancelled = false;
|
|
||||||
setModelsLoading(true);
|
|
||||||
setModelsError(null);
|
|
||||||
fetchModels()
|
|
||||||
.then((response) => {
|
|
||||||
if (!cancelled) {
|
|
||||||
setLoadedModels(response.models);
|
|
||||||
// Only set internal favorites when parent doesn't manage them
|
|
||||||
if (!parentFavoriteProviders) {
|
|
||||||
setFavoriteProviders(response.favoriteProviders);
|
|
||||||
}
|
|
||||||
if (!parentFavoriteModels) {
|
|
||||||
setFavoriteModels(response.favoriteModels);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
if (!cancelled) {
|
|
||||||
setModelsError(getErrorMessage(err) || "Failed to load models");
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
if (!cancelled) {
|
|
||||||
setModelsLoading(false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Also fetch settings for presets
|
|
||||||
fetchSettings(projectId)
|
|
||||||
.then((nextSettings) => {
|
|
||||||
if (!cancelled) {
|
|
||||||
setSettings(nextSettings);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
// Silently ignore settings fetch failure
|
|
||||||
});
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
cancelled = true;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}, [availableModels, parentFavoriteProviders, parentFavoriteModels, projectId]);
|
|
||||||
|
let cancelled = false;
|
||||||
|
setModelsLoading(true);
|
||||||
|
setModelsError(null);
|
||||||
|
fetchModels()
|
||||||
|
.then((response) => {
|
||||||
|
if (!cancelled) {
|
||||||
|
setLoadedModels(response.models);
|
||||||
|
// Only set internal favorites when parent doesn't manage them
|
||||||
|
if (!parentFavoriteProviders) {
|
||||||
|
setFavoriteProviders(response.favoriteProviders);
|
||||||
|
}
|
||||||
|
if (!parentFavoriteModels) {
|
||||||
|
setFavoriteModels(response.favoriteModels);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
if (!cancelled) {
|
||||||
|
setModelsError(getErrorMessage(err) || "Failed to load models");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
if (!cancelled) {
|
||||||
|
setModelsLoading(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
cancelled = true;
|
||||||
|
};
|
||||||
|
}, [availableModels, parentFavoriteProviders, parentFavoriteModels]);
|
||||||
|
|
||||||
|
// Settings always drive toggle/preset behavior, regardless of model source.
|
||||||
|
useEffect(() => {
|
||||||
|
let cancelled = false;
|
||||||
|
|
||||||
|
fetchSettings(projectId)
|
||||||
|
.then((nextSettings) => {
|
||||||
|
if (!cancelled) {
|
||||||
|
setSettings(nextSettings);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
// Silently ignore settings fetch failure
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
cancelled = true;
|
||||||
|
};
|
||||||
|
}, [projectId]);
|
||||||
|
|
||||||
const executorSelectionValue = getModelSelectionValue(executorProvider, executorModelId);
|
const executorSelectionValue = getModelSelectionValue(executorProvider, executorModelId);
|
||||||
const validatorSelectionValue = getModelSelectionValue(validatorProvider, validatorModelId);
|
const validatorSelectionValue = getModelSelectionValue(validatorProvider, validatorModelId);
|
||||||
@@ -1898,8 +1907,13 @@ export function QuickEntryBox({ onCreate, addToast, tasks = [], availableModels,
|
|||||||
|
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className={`btn btn-sm ${effectiveGithubTracking ? "btn-primary" : ""}`}
|
className={`btn btn-sm ${githubTrackingProjectEnabled && effectiveGithubTracking ? "btn-primary" : ""}`}
|
||||||
onClick={() => setGithubTrackingOverride(!effectiveGithubTracking)}
|
onClick={() => {
|
||||||
|
if (!githubTrackingProjectEnabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setGithubTrackingOverride((prev) => (prev ?? true) ? false : true);
|
||||||
|
}}
|
||||||
onMouseDown={(e) => e.preventDefault()}
|
onMouseDown={(e) => e.preventDefault()}
|
||||||
disabled={!githubTrackingProjectEnabled}
|
disabled={!githubTrackingProjectEnabled}
|
||||||
aria-pressed={effectiveGithubTracking}
|
aria-pressed={effectiveGithubTracking}
|
||||||
|
|||||||
@@ -1659,7 +1659,7 @@ describe("App auto-open Settings on unauthenticated", () => {
|
|||||||
await waitFor(() => expect(fetchAuthStatus).toHaveBeenCalled());
|
await waitFor(() => expect(fetchAuthStatus).toHaveBeenCalled());
|
||||||
|
|
||||||
// Settings modal should NOT be open
|
// Settings modal should NOT be open
|
||||||
await waitFor(() => expect(fetchSettings).toHaveBeenCalledTimes(1));
|
await waitFor(() => expect(fetchSettings).toHaveBeenCalled());
|
||||||
expect(screen.queryByText("Settings")).toBeNull();
|
expect(screen.queryByText("Settings")).toBeNull();
|
||||||
|
|
||||||
// Onboarding modal should NOT be open
|
// Onboarding modal should NOT be open
|
||||||
@@ -1681,7 +1681,7 @@ describe("App auto-open Settings on unauthenticated", () => {
|
|||||||
render(<App />);
|
render(<App />);
|
||||||
|
|
||||||
await waitFor(() => expect(fetchAuthStatus).toHaveBeenCalled());
|
await waitFor(() => expect(fetchAuthStatus).toHaveBeenCalled());
|
||||||
await waitFor(() => expect(fetchSettings).toHaveBeenCalledTimes(1));
|
await waitFor(() => expect(fetchSettings).toHaveBeenCalled());
|
||||||
|
|
||||||
expect(screen.queryByText("Settings")).toBeNull();
|
expect(screen.queryByText("Settings")).toBeNull();
|
||||||
expect(screen.queryByText("Set Up AI")).toBeNull();
|
expect(screen.queryByText("Set Up AI")).toBeNull();
|
||||||
@@ -1715,7 +1715,7 @@ describe("App auto-open Settings on unauthenticated", () => {
|
|||||||
render(<App />);
|
render(<App />);
|
||||||
|
|
||||||
await waitFor(() => expect(fetchAuthStatus).toHaveBeenCalled());
|
await waitFor(() => expect(fetchAuthStatus).toHaveBeenCalled());
|
||||||
await waitFor(() => expect(fetchSettings).toHaveBeenCalledTimes(1));
|
await waitFor(() => expect(fetchSettings).toHaveBeenCalled());
|
||||||
|
|
||||||
// Settings modal should NOT be open
|
// Settings modal should NOT be open
|
||||||
expect(screen.queryByText("Settings")).toBeNull();
|
expect(screen.queryByText("Settings")).toBeNull();
|
||||||
@@ -1746,7 +1746,7 @@ describe("App auto-open Settings on unauthenticated", () => {
|
|||||||
fireEvent.click(settingsButton);
|
fireEvent.click(settingsButton);
|
||||||
|
|
||||||
// Settings should open with Authentication section (first/default)
|
// Settings should open with Authentication section (first/default)
|
||||||
await waitFor(() => expect(fetchSettings).toHaveBeenCalledTimes(2));
|
await waitFor(() => expect(fetchSettings.mock.calls.length).toBeGreaterThanOrEqual(2));
|
||||||
await waitFor(() => expect(fetchAuthStatus).toHaveBeenCalled());
|
await waitFor(() => expect(fetchAuthStatus).toHaveBeenCalled());
|
||||||
|
|
||||||
// Authentication section content should be visible (providers listed)
|
// Authentication section content should be visible (providers listed)
|
||||||
@@ -1955,7 +1955,7 @@ describe("App engine pause (soft pause)", () => {
|
|||||||
describe("App view switching", () => {
|
describe("App view switching", () => {
|
||||||
it("opens research view from overflow and persists view selection", async () => {
|
it("opens research view from overflow and persists view selection", async () => {
|
||||||
localStorage.setItem("kb-dashboard-view-mode", "project");
|
localStorage.setItem("kb-dashboard-view-mode", "project");
|
||||||
(fetchSettings as ReturnType<typeof vi.fn>).mockResolvedValueOnce({
|
(fetchSettings as ReturnType<typeof vi.fn>).mockResolvedValue({
|
||||||
...defaultSettings,
|
...defaultSettings,
|
||||||
experimentalFeatures: {
|
experimentalFeatures: {
|
||||||
...defaultSettings.experimentalFeatures,
|
...defaultSettings.experimentalFeatures,
|
||||||
@@ -2003,7 +2003,7 @@ describe("App view switching", () => {
|
|||||||
|
|
||||||
it("does not expose research navigation when research feature is disabled", async () => {
|
it("does not expose research navigation when research feature is disabled", async () => {
|
||||||
localStorage.setItem("kb-dashboard-view-mode", "project");
|
localStorage.setItem("kb-dashboard-view-mode", "project");
|
||||||
(fetchSettings as ReturnType<typeof vi.fn>).mockResolvedValueOnce({
|
(fetchSettings as ReturnType<typeof vi.fn>).mockResolvedValue({
|
||||||
...defaultSettings,
|
...defaultSettings,
|
||||||
experimentalFeatures: {
|
experimentalFeatures: {
|
||||||
...defaultSettings.experimentalFeatures,
|
...defaultSettings.experimentalFeatures,
|
||||||
@@ -2026,7 +2026,7 @@ describe("App view switching", () => {
|
|||||||
it("initializes research view from persisted task-view when feature-enabled", async () => {
|
it("initializes research view from persisted task-view when feature-enabled", async () => {
|
||||||
localStorage.setItem("kb-dashboard-view-mode", "project");
|
localStorage.setItem("kb-dashboard-view-mode", "project");
|
||||||
localStorage.setItem(taskViewStorageKey(), "research");
|
localStorage.setItem(taskViewStorageKey(), "research");
|
||||||
(fetchSettings as ReturnType<typeof vi.fn>).mockResolvedValueOnce({
|
(fetchSettings as ReturnType<typeof vi.fn>).mockResolvedValue({
|
||||||
...defaultSettings,
|
...defaultSettings,
|
||||||
experimentalFeatures: {
|
experimentalFeatures: {
|
||||||
...defaultSettings.experimentalFeatures,
|
...defaultSettings.experimentalFeatures,
|
||||||
@@ -2047,7 +2047,7 @@ describe("App view switching", () => {
|
|||||||
it("falls back to board when research view is feature-disabled", async () => {
|
it("falls back to board when research view is feature-disabled", async () => {
|
||||||
localStorage.setItem("kb-dashboard-view-mode", "project");
|
localStorage.setItem("kb-dashboard-view-mode", "project");
|
||||||
localStorage.setItem(taskViewStorageKey(), "research");
|
localStorage.setItem(taskViewStorageKey(), "research");
|
||||||
(fetchSettings as ReturnType<typeof vi.fn>).mockResolvedValueOnce({
|
(fetchSettings as ReturnType<typeof vi.fn>).mockResolvedValue({
|
||||||
...defaultSettings,
|
...defaultSettings,
|
||||||
experimentalFeatures: {
|
experimentalFeatures: {
|
||||||
...defaultSettings.experimentalFeatures,
|
...defaultSettings.experimentalFeatures,
|
||||||
@@ -2069,7 +2069,7 @@ describe("App view switching", () => {
|
|||||||
it("falls back to board when evals view is feature-disabled", async () => {
|
it("falls back to board when evals view is feature-disabled", async () => {
|
||||||
localStorage.setItem("kb-dashboard-view-mode", "project");
|
localStorage.setItem("kb-dashboard-view-mode", "project");
|
||||||
localStorage.setItem(taskViewStorageKey(), "evals");
|
localStorage.setItem(taskViewStorageKey(), "evals");
|
||||||
(fetchSettings as ReturnType<typeof vi.fn>).mockResolvedValueOnce({
|
(fetchSettings as ReturnType<typeof vi.fn>).mockResolvedValue({
|
||||||
...defaultSettings,
|
...defaultSettings,
|
||||||
experimentalFeatures: {
|
experimentalFeatures: {
|
||||||
...defaultSettings.experimentalFeatures,
|
...defaultSettings.experimentalFeatures,
|
||||||
@@ -2308,7 +2308,7 @@ describe("App view switching", () => {
|
|||||||
|
|
||||||
it("opens planning mode when TodoView triggers planning from todo item", async () => {
|
it("opens planning mode when TodoView triggers planning from todo item", async () => {
|
||||||
localStorage.setItem("kb-dashboard-view-mode", "project");
|
localStorage.setItem("kb-dashboard-view-mode", "project");
|
||||||
(fetchSettings as ReturnType<typeof vi.fn>).mockResolvedValueOnce({
|
(fetchSettings as ReturnType<typeof vi.fn>).mockResolvedValue({
|
||||||
...defaultSettings,
|
...defaultSettings,
|
||||||
experimentalFeatures: {
|
experimentalFeatures: {
|
||||||
...defaultSettings.experimentalFeatures,
|
...defaultSettings.experimentalFeatures,
|
||||||
|
|||||||
@@ -759,58 +759,69 @@ describe("QuickEntryBox", () => {
|
|||||||
expect(fastToggle.getAttribute("aria-pressed")).toBe("false");
|
expect(fastToggle.getAttribute("aria-pressed")).toBe("false");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("renders GitHub toggle off by default when project setting is disabled", async () => {
|
it("keeps GitHub toggle disabled while project settings are still loading", async () => {
|
||||||
vi.mocked(fetchSettings).mockResolvedValueOnce({
|
vi.mocked(fetchSettings).mockReturnValueOnce(new Promise(() => undefined));
|
||||||
githubTrackingEnabledByDefault: false,
|
renderQuickEntryBox({});
|
||||||
} as any);
|
|
||||||
renderQuickEntryBox({ availableModels: undefined });
|
|
||||||
expandQuickEntry();
|
expandQuickEntry();
|
||||||
|
|
||||||
const githubToggle = await screen.findByTestId("quick-entry-github-toggle");
|
const githubToggle = await screen.findByTestId("quick-entry-github-toggle");
|
||||||
expect(githubToggle.getAttribute("aria-pressed")).toBe("false");
|
|
||||||
expect(githubToggle).toBeDisabled();
|
expect(githubToggle).toBeDisabled();
|
||||||
expect(githubToggle.getAttribute("aria-disabled")).toBe("true");
|
expect(githubToggle).toHaveAttribute("aria-disabled", "true");
|
||||||
expect(githubToggle.className.includes("btn-primary")).toBe(false);
|
expect(githubToggle).toHaveAttribute("aria-pressed", "false");
|
||||||
|
expect(githubToggle.classList.contains("btn-primary")).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("renders GitHub toggle on by default when project setting is enabled", async () => {
|
it("renders GitHub toggle disabled when project setting is disabled", async () => {
|
||||||
|
vi.mocked(fetchSettings).mockResolvedValueOnce({
|
||||||
|
githubTrackingEnabledByDefault: false,
|
||||||
|
} as any);
|
||||||
|
renderQuickEntryBox({});
|
||||||
|
expandQuickEntry();
|
||||||
|
|
||||||
|
const githubToggle = await screen.findByTestId("quick-entry-github-toggle");
|
||||||
|
expect(githubToggle).toBeDisabled();
|
||||||
|
expect(githubToggle).toHaveAttribute("aria-disabled", "true");
|
||||||
|
expect(githubToggle).toHaveAttribute("aria-pressed", "false");
|
||||||
|
expect(githubToggle.classList.contains("btn-primary")).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders GitHub toggle enabled and active when project setting is enabled", async () => {
|
||||||
vi.mocked(fetchSettings).mockResolvedValueOnce({
|
vi.mocked(fetchSettings).mockResolvedValueOnce({
|
||||||
githubTrackingEnabledByDefault: true,
|
githubTrackingEnabledByDefault: true,
|
||||||
} as any);
|
} as any);
|
||||||
renderQuickEntryBox({ availableModels: undefined });
|
renderQuickEntryBox({});
|
||||||
expandQuickEntry();
|
|
||||||
|
|
||||||
await waitFor(() => {
|
|
||||||
expect(screen.getByTestId("quick-entry-github-toggle").getAttribute("aria-pressed")).toBe("true");
|
|
||||||
});
|
|
||||||
expect(screen.getByTestId("quick-entry-github-toggle").className.includes("btn-primary")).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("flips GitHub toggle from both project-default directions", async () => {
|
|
||||||
vi.mocked(fetchSettings).mockResolvedValueOnce({
|
|
||||||
githubTrackingEnabledByDefault: false,
|
|
||||||
} as any);
|
|
||||||
const { unmount } = renderQuickEntryBox({ availableModels: undefined });
|
|
||||||
expandQuickEntry();
|
expandQuickEntry();
|
||||||
|
|
||||||
const githubToggle = await screen.findByTestId("quick-entry-github-toggle");
|
const githubToggle = await screen.findByTestId("quick-entry-github-toggle");
|
||||||
expect(githubToggle.getAttribute("aria-pressed")).toBe("false");
|
await waitFor(() => {
|
||||||
expect(githubToggle).toBeDisabled();
|
expect(githubToggle).not.toBeDisabled();
|
||||||
|
});
|
||||||
|
expect(githubToggle).toHaveAttribute("aria-pressed", "true");
|
||||||
|
expect(githubToggle.classList.contains("btn-primary")).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("flips GitHub toggle pressed state deterministically when enabled", async () => {
|
||||||
|
vi.mocked(fetchSettings).mockResolvedValueOnce({
|
||||||
|
githubTrackingEnabledByDefault: true,
|
||||||
|
} as any);
|
||||||
|
renderQuickEntryBox({});
|
||||||
|
expandQuickEntry();
|
||||||
|
|
||||||
|
const githubToggle = await screen.findByTestId("quick-entry-github-toggle");
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(githubToggle).not.toBeDisabled();
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(githubToggle).toHaveAttribute("aria-pressed", "true");
|
||||||
|
expect(githubToggle.classList.contains("btn-primary")).toBe(true);
|
||||||
|
|
||||||
fireEvent.click(githubToggle);
|
fireEvent.click(githubToggle);
|
||||||
expect(githubToggle.getAttribute("aria-pressed")).toBe("false");
|
expect(githubToggle).toHaveAttribute("aria-pressed", "false");
|
||||||
unmount();
|
expect(githubToggle.classList.contains("btn-primary")).toBe(false);
|
||||||
|
|
||||||
vi.mocked(fetchSettings).mockResolvedValueOnce({
|
fireEvent.click(githubToggle);
|
||||||
githubTrackingEnabledByDefault: true,
|
expect(githubToggle).toHaveAttribute("aria-pressed", "true");
|
||||||
} as any);
|
expect(githubToggle.classList.contains("btn-primary")).toBe(true);
|
||||||
renderQuickEntryBox({ availableModels: undefined });
|
|
||||||
expandQuickEntry();
|
|
||||||
|
|
||||||
await waitFor(() => {
|
|
||||||
expect(screen.getByTestId("quick-entry-github-toggle").getAttribute("aria-pressed")).toBe("true");
|
|
||||||
});
|
|
||||||
fireEvent.click(screen.getByTestId("quick-entry-github-toggle"));
|
|
||||||
expect(screen.getByTestId("quick-entry-github-toggle").getAttribute("aria-pressed")).toBe("false");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it.each(["Enter", "Save"] as const)("submits executionMode=fast when Fast is active via %s", async (submitPath) => {
|
it.each(["Enter", "Save"] as const)("submits executionMode=fast when Fast is active via %s", async (submitPath) => {
|
||||||
@@ -854,10 +865,17 @@ describe("QuickEntryBox", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("omits githubTracking when toggle is untouched", async () => {
|
it("omits githubTracking when toggle is untouched", async () => {
|
||||||
|
vi.mocked(fetchSettings).mockResolvedValueOnce({
|
||||||
|
githubTrackingEnabledByDefault: true,
|
||||||
|
} as any);
|
||||||
const { props } = renderQuickEntryBox({});
|
const { props } = renderQuickEntryBox({});
|
||||||
expandQuickEntry();
|
expandQuickEntry();
|
||||||
const textarea = screen.getByTestId("quick-entry-input");
|
const textarea = screen.getByTestId("quick-entry-input");
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.getByTestId("quick-entry-github-toggle")).not.toBeDisabled();
|
||||||
|
});
|
||||||
|
|
||||||
fireEvent.change(textarea, { target: { value: "No github override" } });
|
fireEvent.change(textarea, { target: { value: "No github override" } });
|
||||||
fireEvent.keyDown(textarea, { key: "Enter" });
|
fireEvent.keyDown(textarea, { key: "Enter" });
|
||||||
|
|
||||||
@@ -895,15 +913,16 @@ describe("QuickEntryBox", () => {
|
|||||||
vi.mocked(fetchSettings).mockResolvedValueOnce({
|
vi.mocked(fetchSettings).mockResolvedValueOnce({
|
||||||
githubTrackingEnabledByDefault: true,
|
githubTrackingEnabledByDefault: true,
|
||||||
} as any);
|
} as any);
|
||||||
const { props } = renderQuickEntryBox({ availableModels: undefined });
|
const { props } = renderQuickEntryBox({});
|
||||||
expandQuickEntry();
|
expandQuickEntry();
|
||||||
const textarea = screen.getByTestId("quick-entry-input");
|
const textarea = screen.getByTestId("quick-entry-input");
|
||||||
|
|
||||||
|
const githubToggle = await screen.findByTestId("quick-entry-github-toggle");
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
expect(screen.getByTestId("quick-entry-github-toggle").getAttribute("aria-pressed")).toBe("true");
|
expect(githubToggle).not.toBeDisabled();
|
||||||
});
|
});
|
||||||
|
|
||||||
fireEvent.click(screen.getByTestId("quick-entry-github-toggle"));
|
fireEvent.click(githubToggle);
|
||||||
fireEvent.change(textarea, { target: { value: "Disable github tracking override" } });
|
fireEvent.change(textarea, { target: { value: "Disable github tracking override" } });
|
||||||
fireEvent.keyDown(textarea, { key: "Enter" });
|
fireEvent.keyDown(textarea, { key: "Enter" });
|
||||||
|
|
||||||
@@ -915,6 +934,32 @@ describe("QuickEntryBox", () => {
|
|||||||
expect(payload.githubTracking).toEqual({ enabled: false });
|
expect(payload.githubTracking).toEqual({ enabled: false });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("submits githubTracking enabled=true after opt-out then opt-in", async () => {
|
||||||
|
vi.mocked(fetchSettings).mockResolvedValueOnce({
|
||||||
|
githubTrackingEnabledByDefault: true,
|
||||||
|
} as any);
|
||||||
|
const { props } = renderQuickEntryBox({});
|
||||||
|
expandQuickEntry();
|
||||||
|
const textarea = screen.getByTestId("quick-entry-input");
|
||||||
|
|
||||||
|
const githubToggle = await screen.findByTestId("quick-entry-github-toggle");
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(githubToggle).not.toBeDisabled();
|
||||||
|
});
|
||||||
|
|
||||||
|
fireEvent.click(githubToggle);
|
||||||
|
fireEvent.click(githubToggle);
|
||||||
|
fireEvent.change(textarea, { target: { value: "Re-enable github tracking override" } });
|
||||||
|
fireEvent.keyDown(textarea, { key: "Enter" });
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(props.onCreate).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
const payload = props.onCreate.mock.calls[0]?.[0];
|
||||||
|
expect(payload.githubTracking).toEqual({ enabled: true });
|
||||||
|
});
|
||||||
|
|
||||||
it("shows disabled GitHub tracking guidance label when project setting is disabled", async () => {
|
it("shows disabled GitHub tracking guidance label when project setting is disabled", async () => {
|
||||||
vi.mocked(fetchSettings).mockResolvedValueOnce({
|
vi.mocked(fetchSettings).mockResolvedValueOnce({
|
||||||
githubTrackingEnabledByDefault: false,
|
githubTrackingEnabledByDefault: false,
|
||||||
|
|||||||
Reference in New Issue
Block a user