FN-7202: add Quick Chat outside-click dismissal setting
Add a project setting that lets operators keep Quick Chat open until explicitly closed. - Add quickChatCloseOnOutsideClick to project settings defaults, schema, types, and app settings hook. - Wire the Quick Chat floating window to honor the setting while preserving default outside-click dismissal. - Add a Settings > General toggle, documentation, release changeset, and coverage for defaults, settings loading, modal form, and floating-window behavior. Files changed: .../fn-7202-quick-chat-outside-click-setting.md | 7 +++ docs/dashboard-guide.md | 2 +- docs/settings-reference.md | 1 + .../core/src/__tests__/settings-defaults.test.ts | 13 +++++ packages/core/src/settings-schema.ts | 5 ++ packages/core/src/types.ts | 6 +++ packages/dashboard/app/App.tsx | 6 ++- .../components/__tests__/FloatingWindow.test.tsx | 13 +++++ .../__tests__/SettingsModal.general.test.tsx | 8 +++ .../settings/sections/GeneralSection.tsx | 9 ++++ .../app/hooks/__tests__/useAppSettings.test.ts | 62 ++++++++++++++++++++++ packages/dashboard/app/hooks/useAppSettings.ts | 5 ++ 12 files changed, 135 insertions(+), 2 deletions(-) Fusion-Task-Id: FN-7202 Fusion-Task-Lineage: 4d52ea30-6475-404e-b1b9-28e8e581005c Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
This commit is contained in:
7
.changeset/fn-7202-quick-chat-outside-click-setting.md
Normal file
7
.changeset/fn-7202-quick-chat-outside-click-setting.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
"@runfusion/fusion": minor
|
||||||
|
---
|
||||||
|
|
||||||
|
summary: Add a setting to control whether clicking outside the Quick Chat window closes it.
|
||||||
|
category: feature
|
||||||
|
dev: New project setting `quickChatCloseOnOutsideClick` (default true, preserving FN-7152 behavior). Wired through ProjectSettings/DEFAULT_PROJECT_SETTINGS, useAppSettings, the Settings → General toggle, and the Quick Chat FloatingWindow `closeOnOutsidePointerDown` prop. Project-scoped only.
|
||||||
@@ -418,7 +418,7 @@ Quick Chat is an optional fast, project-scoped assistant surface for conversatio
|
|||||||
- Submitting the inline chooser uses explicit fresh-session creation and immediately persists/selects the new thread, then refreshes the session dropdown list
|
- Submitting the inline chooser uses explicit fresh-session creation and immediately persists/selects the new thread, then refreshes the session dropdown list
|
||||||
- On first open for a project, Quick Chat restores the last opened non-archived session from per-project local storage; if that saved session is missing, it falls back to the most recently touched non-archived session by latest activity (`max(lastMessageAt, updatedAt)`), and only falls back to the first agent / configured default model when no prior session exists.
|
- On first open for a project, Quick Chat restores the last opened non-archived session from per-project local storage; if that saved session is missing, it falls back to the most recently touched non-archived session by latest activity (`max(lastMessageAt, updatedAt)`), and only falls back to the first agent / configured default model when no prior session exists.
|
||||||
- Closing and reopening Quick Chat keeps the active conversation warm in memory, so messages stay visible without a conversation reload or "Loading conversation…" flash.
|
- Closing and reopening Quick Chat keeps the active conversation warm in memory, so messages stay visible without a conversation reload or "Loading conversation…" flash.
|
||||||
- Clicking outside the desktop Quick Chat floating window closes it; task pop-out floating windows remain persistent on page clicks.
|
- Clicking outside the desktop Quick Chat floating window closes it by default; disable **Settings → General → Close Quick Chat on outside click** to keep it open until you explicitly close/minimize/maximize it. Task pop-out floating windows remain persistent on page clicks.
|
||||||
- Queued follow-up messages entered while a Quick Chat response is still streaming now persist per session, so closing/reopening the panel restores the queued stack and flushes the messages one at a time in FIFO order as active responses complete.
|
- Queued follow-up messages entered while a Quick Chat response is still streaming now persist per session, so closing/reopening the panel restores the queued stack and flushes the messages one at a time in FIFO order as active responses complete.
|
||||||
- Resume lookups still use targeted session queries instead of loading the full active-session list first
|
- Resume lookups still use targeted session queries instead of loading the full active-session list first
|
||||||
- Tool-call summaries in the floating quick-chat panel are intentionally condensed into a single-line header row (especially on small screens) so tool name + status stay scannable without multi-line wrapping
|
- Tool-call summaries in the floating quick-chat panel are intentionally condensed into a single-line header row (especially on small screens) so tool name + status stay scannable without multi-line wrapping
|
||||||
|
|||||||
@@ -621,6 +621,7 @@ Default notes:
|
|||||||
| `reflectionAfterTask` | `boolean` | `true` | Trigger reflection after task completion. |
|
| `reflectionAfterTask` | `boolean` | `true` | Trigger reflection after task completion. |
|
||||||
| `reviewHandoffPolicy` | `"disabled" \| "comment-triggered" \| "always"` | `"disabled"` | Policy for agent-to-user review handoff detection. |
|
| `reviewHandoffPolicy` | `"disabled" \| "comment-triggered" \| "always"` | `"disabled"` | Policy for agent-to-user review handoff detection. |
|
||||||
| `showQuickChatFAB` | `boolean` | `false` | Show floating quick-chat button (chat remains available via More menu). |
|
| `showQuickChatFAB` | `boolean` | `false` | Show floating quick-chat button (chat remains available via More menu). |
|
||||||
|
| `quickChatCloseOnOutsideClick` | `boolean` | `true` | Close the desktop Quick Chat floating window when clicking outside it; disable to keep it open until explicitly closed. |
|
||||||
| `chatAutoCleanupDays` | `0 \| 7 \| 14 \| 30 \| 60 \| 90` | `0` | Auto-cleanup retention window for idle chat sessions and chat rooms. `0` is off (default). When enabled, periodic self-healing maintenance deletes rows with `updatedAt` older than the configured day window. |
|
| `chatAutoCleanupDays` | `0 \| 7 \| 14 \| 30 \| 60 \| 90` | `0` | Auto-cleanup retention window for idle chat sessions and chat rooms. `0` is off (default). When enabled, periodic self-healing maintenance deletes rows with `updatedAt` older than the configured day window. |
|
||||||
| `mailAutoCleanupDays` | `0 \| 7 \| 14 \| 30 \| 60 \| 90` | `0` | Auto-prune retention window for inbox/outbox mail messages. `0` is off (default). When enabled, periodic self-healing maintenance deletes `messages` rows where `updatedAt < cutoff` for the configured day window. Suggested setting: `7`. |
|
| `mailAutoCleanupDays` | `0 \| 7 \| 14 \| 30 \| 60 \| 90` | `0` | Auto-prune retention window for inbox/outbox mail messages. `0` is off (default). When enabled, periodic self-healing maintenance deletes `messages` rows where `updatedAt < cutoff` for the configured day window. Suggested setting: `7`. |
|
||||||
| `operationalLogRetentionDays` | `0 \| 7 \| 14 \| 30 \| 60 \| 90` | `30` | Retention window for SQLite operational-log tables (`activityLog`, `runAuditEvents`, `agentHeartbeats`), terminal `agentRuns` rows (by `endedAt`), and `agentConfigRevisions` (by `createdAt`). `0` is off. Lower values mean Reliability metrics/charts and the Activity feed will not show history older than the configured window; per-task task detail history is unaffected. Periodic maintenance prunes timestamped operational-log rows older than this many days while always preserving in-flight `agentRuns` (`endedAt IS NULL`) and the most-recent `agentConfigRevisions` row per agent. |
|
| `operationalLogRetentionDays` | `0 \| 7 \| 14 \| 30 \| 60 \| 90` | `30` | Retention window for SQLite operational-log tables (`activityLog`, `runAuditEvents`, `agentHeartbeats`), terminal `agentRuns` rows (by `endedAt`), and `agentConfigRevisions` (by `createdAt`). `0` is off. Lower values mean Reliability metrics/charts and the Activity feed will not show history older than the configured window; per-task task detail history is unaffected. Periodic maintenance prunes timestamped operational-log rows older than this many days while always preserving in-flight `agentRuns` (`endedAt IS NULL`) and the most-recent `agentConfigRevisions` row per agent. |
|
||||||
|
|||||||
@@ -150,6 +150,19 @@ describe("settings defaults invariants", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("quickChatCloseOnOutsideClick default", () => {
|
||||||
|
it("keeps Quick Chat outside-click dismissal explicitly true in project defaults", () => {
|
||||||
|
expect(DEFAULT_PROJECT_SETTINGS.quickChatCloseOnOutsideClick).toBe(true);
|
||||||
|
expect("quickChatCloseOnOutsideClick" in DEFAULT_PROJECT_SETTINGS).toBe(true);
|
||||||
|
expect(PROJECT_SETTINGS_KEYS).toContain("quickChatCloseOnOutsideClick");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("keeps quickChatCloseOnOutsideClick project-scoped only", () => {
|
||||||
|
expect("quickChatCloseOnOutsideClick" in DEFAULT_GLOBAL_SETTINGS).toBe(false);
|
||||||
|
expect(GLOBAL_SETTINGS_KEYS).not.toContain("quickChatCloseOnOutsideClick");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("mergeIntegrationWorktree default", () => {
|
describe("mergeIntegrationWorktree default", () => {
|
||||||
it("defaults project settings to reuse-task-worktree", () => {
|
it("defaults project settings to reuse-task-worktree", () => {
|
||||||
expect(DEFAULT_PROJECT_SETTINGS.mergeIntegrationWorktree).toBe("reuse-task-worktree");
|
expect(DEFAULT_PROJECT_SETTINGS.mergeIntegrationWorktree).toBe("reuse-task-worktree");
|
||||||
|
|||||||
@@ -520,6 +520,11 @@ export const DEFAULT_PROJECT_SETTINGS = {
|
|||||||
reflectionAfterTask: true,
|
reflectionAfterTask: true,
|
||||||
// reviewHandoffPolicy MOVED to workflow settings (U4) — see MOVED_SETTINGS_KEYS.
|
// reviewHandoffPolicy MOVED to workflow settings (U4) — see MOVED_SETTINGS_KEYS.
|
||||||
quickChatButtonMode: "off",
|
quickChatButtonMode: "off",
|
||||||
|
/*
|
||||||
|
FNXC:ChatModal 2026-06-28-00:00:
|
||||||
|
Quick Chat outside-click dismissal remains default-on for upgrades, but it is now a project setting so operators can disable accidental board-click closes.
|
||||||
|
*/
|
||||||
|
quickChatCloseOnOutsideClick: true,
|
||||||
showQuickChatFAB: false,
|
showQuickChatFAB: false,
|
||||||
chatAutoCleanupDays: 0,
|
chatAutoCleanupDays: 0,
|
||||||
mailAutoCleanupDays: 0,
|
mailAutoCleanupDays: 0,
|
||||||
|
|||||||
@@ -4368,6 +4368,12 @@ export interface ProjectSettings {
|
|||||||
reviewHandoffPolicy?: "disabled" | "comment-triggered" | "always";
|
reviewHandoffPolicy?: "disabled" | "comment-triggered" | "always";
|
||||||
/** Quick Chat launcher placement. "floating" shows the draggable FAB, "footer" shows a footer button, "off" hides both. */
|
/** Quick Chat launcher placement. "floating" shows the draggable FAB, "footer" shows a footer button, "off" hides both. */
|
||||||
quickChatButtonMode?: "floating" | "footer" | "off";
|
quickChatButtonMode?: "floating" | "footer" | "off";
|
||||||
|
/**
|
||||||
|
* FNXC:ChatModal 2026-06-28-00:00:
|
||||||
|
* Outside-click dismissal of Quick Chat is now user-configurable; default true preserves the prior always-on behavior from FN-7152.
|
||||||
|
* When true (default), the Quick Chat floating window closes when the user clicks outside it. Set false to keep it open until explicitly closed.
|
||||||
|
*/
|
||||||
|
quickChatCloseOnOutsideClick?: boolean;
|
||||||
/** Legacy Quick Chat FAB toggle. Prefer quickChatButtonMode for new callers. */
|
/** Legacy Quick Chat FAB toggle. Prefer quickChatButtonMode for new callers. */
|
||||||
showQuickChatFAB?: boolean;
|
showQuickChatFAB?: boolean;
|
||||||
/** Number of days of chat inactivity before old chat sessions/rooms are auto-cleaned.
|
/** Number of days of chat inactivity before old chat sessions/rooms are auto-cleaned.
|
||||||
|
|||||||
@@ -540,6 +540,7 @@ function AppInner() {
|
|||||||
capacityRiskTodoThreshold,
|
capacityRiskTodoThreshold,
|
||||||
openTasksInRightSidebar,
|
openTasksInRightSidebar,
|
||||||
quickChatButtonMode,
|
quickChatButtonMode,
|
||||||
|
quickChatCloseOnOutsideClick,
|
||||||
maxTotalRetriesBeforeFail,
|
maxTotalRetriesBeforeFail,
|
||||||
prAuthAvailable,
|
prAuthAvailable,
|
||||||
settingsLoaded,
|
settingsLoaded,
|
||||||
@@ -1531,6 +1532,9 @@ function AppInner() {
|
|||||||
|
|
||||||
FNXC:ChatModal 2026-06-27-00:00:
|
FNXC:ChatModal 2026-06-27-00:00:
|
||||||
Quick Chat is a transient utility window, so it opts into FloatingWindow's outside-click dismissal in addition to minimize, close, and maximize controls. Task pop-outs intentionally do not opt in because they are persistent workspace windows that should survive page clicks.
|
Quick Chat is a transient utility window, so it opts into FloatingWindow's outside-click dismissal in addition to minimize, close, and maximize controls. Task pop-outs intentionally do not opt in because they are persistent workspace windows that should survive page clicks.
|
||||||
|
|
||||||
|
FNXC:ChatModal 2026-06-28-00:00:
|
||||||
|
Outside-click dismissal is now governed by the project-scoped quickChatCloseOnOutsideClick setting, default-on to preserve FN-7152 behavior. Other FloatingWindow callers still do not pass closeOnOutsidePointerDown, so task pop-outs and utility windows remain persistent.
|
||||||
*/}
|
*/}
|
||||||
{viewMode === "project" && currentProject && (
|
{viewMode === "project" && currentProject && (
|
||||||
<QuickChatFAB
|
<QuickChatFAB
|
||||||
@@ -1544,7 +1548,7 @@ function AppInner() {
|
|||||||
windowKey="chat-modal"
|
windowKey="chat-modal"
|
||||||
title="Chat"
|
title="Chat"
|
||||||
onClose={() => setQuickChatOpen(false)}
|
onClose={() => setQuickChatOpen(false)}
|
||||||
closeOnOutsidePointerDown
|
closeOnOutsidePointerDown={quickChatCloseOnOutsideClick}
|
||||||
hideHeader
|
hideHeader
|
||||||
dragHandleSelector=".chat-view--floating .view-header"
|
dragHandleSelector=".chat-view--floating .view-header"
|
||||||
className="floating-window--chat"
|
className="floating-window--chat"
|
||||||
|
|||||||
@@ -149,6 +149,19 @@ describe("FloatingWindow", () => {
|
|||||||
expect(onClose).not.toHaveBeenCalled();
|
expect(onClose).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("does not close on outside pointerdown when the opt-in prop is explicitly false", () => {
|
||||||
|
const onClose = vi.fn();
|
||||||
|
render(
|
||||||
|
<FloatingWindow windowKey="outside-disabled" title="Outside disabled" onClose={onClose} closeOnOutsidePointerDown={false}>
|
||||||
|
<div>chat body</div>
|
||||||
|
</FloatingWindow>
|
||||||
|
);
|
||||||
|
|
||||||
|
fireEvent.pointerDown(document.body);
|
||||||
|
|
||||||
|
expect(onClose).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
it("does not close when the outside target is another floating or dialog surface", () => {
|
it("does not close when the outside target is another floating or dialog surface", () => {
|
||||||
for (const surfaceClassOrRole of ["modal-overlay", "floating-window", "dialog-role"] as const) {
|
for (const surfaceClassOrRole of ["modal-overlay", "floating-window", "dialog-role"] as const) {
|
||||||
const onClose = vi.fn();
|
const onClose = vi.fn();
|
||||||
|
|||||||
@@ -708,6 +708,14 @@ describe("SettingsModal", () => {
|
|||||||
scope: "project",
|
scope: "project",
|
||||||
expectedKey: "chatAutoCleanupDays",
|
expectedKey: "chatAutoCleanupDays",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
section: "Project General",
|
||||||
|
label: "Close Quick Chat on outside click",
|
||||||
|
kind: "checkbox",
|
||||||
|
value: false,
|
||||||
|
scope: "project",
|
||||||
|
expectedKey: "quickChatCloseOnOutsideClick",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
section: "Project General",
|
section: "Project General",
|
||||||
label: "Operational log retention",
|
label: "Operational log retention",
|
||||||
|
|||||||
@@ -131,6 +131,15 @@ export function GeneralSection({ scopeBanner, form, setForm, projectId, addToast
|
|||||||
</select>
|
</select>
|
||||||
<small>{t("settings.general.quickChatLauncherHint", "Choose whether Quick Chat opens from the draggable floating button, a footer button beside Terminal, or stays hidden.")}</small>
|
<small>{t("settings.general.quickChatLauncherHint", "Choose whether Quick Chat opens from the draggable floating button, a footer button beside Terminal, or stays hidden.")}</small>
|
||||||
</div>
|
</div>
|
||||||
|
{/*
|
||||||
|
FNXC:ChatModal 2026-06-28-00:00:
|
||||||
|
Operators need a Settings > General toggle for Quick Chat outside-click dismissal because accidental board clicks can otherwise close active chat context. Default checked preserves the shipped FN-7152 interaction.
|
||||||
|
*/}
|
||||||
|
<div className="form-group">
|
||||||
|
<label htmlFor="quickChatCloseOnOutsideClick" className="checkbox-label">
|
||||||
|
<input id="quickChatCloseOnOutsideClick" type="checkbox" checked={form.quickChatCloseOnOutsideClick !== false} onChange={(e) => setForm((f) => ({ ...f, quickChatCloseOnOutsideClick: e.target.checked }))}/>{t("settings.general.quickChatCloseOnOutsideClick", "Close Quick Chat on outside click")}</label>
|
||||||
|
<small>{t("settings.general.quickChatCloseOnOutsideClickHint", "When enabled, clicking outside the Quick Chat window closes it. Disable to keep it open until you close it explicitly.")}</small>
|
||||||
|
</div>
|
||||||
<h4 className="settings-section-heading settings-section-heading--spaced">{t("settings.general.chatHistory", "Chat history")}</h4>
|
<h4 className="settings-section-heading settings-section-heading--spaced">{t("settings.general.chatHistory", "Chat history")}</h4>
|
||||||
<div className="form-group">
|
<div className="form-group">
|
||||||
<label htmlFor="chatAutoCleanupDays">{t("settings.general.autoCleanupOldChats", "Auto-cleanup old chats")}</label>
|
<label htmlFor="chatAutoCleanupDays">{t("settings.general.autoCleanupOldChats", "Auto-cleanup old chats")}</label>
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ describe("useAppSettings", () => {
|
|||||||
expect(result.current.taskStuckTimeoutMs).toBe(600000);
|
expect(result.current.taskStuckTimeoutMs).toBe(600000);
|
||||||
expect(result.current.staleHighFanoutBlockerAgeThresholdMs).toBe(7200000);
|
expect(result.current.staleHighFanoutBlockerAgeThresholdMs).toBe(7200000);
|
||||||
expect(result.current.showQuickChatFAB).toBe(false);
|
expect(result.current.showQuickChatFAB).toBe(false);
|
||||||
|
expect(result.current.quickChatCloseOnOutsideClick).toBe(true);
|
||||||
expect(result.current.capacityRiskBannerEnabled).toBe(false);
|
expect(result.current.capacityRiskBannerEnabled).toBe(false);
|
||||||
expect(result.current.capacityRiskTodoThreshold).toBe(20);
|
expect(result.current.capacityRiskTodoThreshold).toBe(20);
|
||||||
});
|
});
|
||||||
@@ -219,6 +220,67 @@ describe("useAppSettings", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("loads Quick Chat outside-click dismissal as default-on unless explicitly disabled", async () => {
|
||||||
|
const { result, rerender } = renderHook(({ projectId }) => useAppSettings(projectId), {
|
||||||
|
initialProps: { projectId: "proj_123" },
|
||||||
|
});
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(result.current.quickChatCloseOnOutsideClick).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
mockFetchSettings.mockResolvedValueOnce({
|
||||||
|
autoMerge: false,
|
||||||
|
globalPause: false,
|
||||||
|
enginePaused: false,
|
||||||
|
prAuthAvailable: true,
|
||||||
|
taskStuckTimeoutMs: 600000,
|
||||||
|
showQuickChatFAB: false,
|
||||||
|
quickChatCloseOnOutsideClick: false,
|
||||||
|
} as never);
|
||||||
|
|
||||||
|
rerender({ projectId: "proj_456" });
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(result.current.quickChatCloseOnOutsideClick).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("refresh() live-applies saved Quick Chat outside-click setting changes", async () => {
|
||||||
|
mockFetchSettings.mockResolvedValueOnce({
|
||||||
|
autoMerge: false,
|
||||||
|
globalPause: false,
|
||||||
|
enginePaused: false,
|
||||||
|
prAuthAvailable: true,
|
||||||
|
taskStuckTimeoutMs: 600000,
|
||||||
|
showQuickChatFAB: false,
|
||||||
|
quickChatCloseOnOutsideClick: false,
|
||||||
|
} as never);
|
||||||
|
const { result } = renderHook(() => useAppSettings("proj_123"));
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(result.current.quickChatCloseOnOutsideClick).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
mockFetchSettings.mockResolvedValueOnce({
|
||||||
|
autoMerge: false,
|
||||||
|
globalPause: false,
|
||||||
|
enginePaused: false,
|
||||||
|
prAuthAvailable: true,
|
||||||
|
taskStuckTimeoutMs: 600000,
|
||||||
|
showQuickChatFAB: false,
|
||||||
|
quickChatCloseOnOutsideClick: true,
|
||||||
|
} as never);
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
await result.current.refresh();
|
||||||
|
});
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(result.current.quickChatCloseOnOutsideClick).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it("propagates capacity risk settings from fetchSettings", async () => {
|
it("propagates capacity risk settings from fetchSettings", async () => {
|
||||||
mockFetchSettings.mockResolvedValueOnce({
|
mockFetchSettings.mockResolvedValueOnce({
|
||||||
autoMerge: false,
|
autoMerge: false,
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ export interface UseAppSettingsResult {
|
|||||||
capacityRiskTodoThreshold: number;
|
capacityRiskTodoThreshold: number;
|
||||||
openTasksInRightSidebar: boolean;
|
openTasksInRightSidebar: boolean;
|
||||||
quickChatButtonMode: QuickChatButtonMode;
|
quickChatButtonMode: QuickChatButtonMode;
|
||||||
|
quickChatCloseOnOutsideClick: boolean;
|
||||||
showQuickChatFAB: boolean;
|
showQuickChatFAB: boolean;
|
||||||
maxTotalRetriesBeforeFail: number;
|
maxTotalRetriesBeforeFail: number;
|
||||||
prAuthAvailable: boolean;
|
prAuthAvailable: boolean;
|
||||||
@@ -61,6 +62,7 @@ export function useAppSettings(projectId?: string): UseAppSettingsResult {
|
|||||||
const [capacityRiskTodoThreshold, setCapacityRiskTodoThreshold] = useState(20);
|
const [capacityRiskTodoThreshold, setCapacityRiskTodoThreshold] = useState(20);
|
||||||
const [openTasksInRightSidebar, setOpenTasksInRightSidebar] = useState(false);
|
const [openTasksInRightSidebar, setOpenTasksInRightSidebar] = useState(false);
|
||||||
const [quickChatButtonMode, setQuickChatButtonMode] = useState<QuickChatButtonMode>("off");
|
const [quickChatButtonMode, setQuickChatButtonMode] = useState<QuickChatButtonMode>("off");
|
||||||
|
const [quickChatCloseOnOutsideClick, setQuickChatCloseOnOutsideClick] = useState(true);
|
||||||
const [showQuickChatFAB, setShowQuickChatFAB] = useState(false);
|
const [showQuickChatFAB, setShowQuickChatFAB] = useState(false);
|
||||||
const [maxTotalRetriesBeforeFail, setMaxTotalRetriesBeforeFail] = useState(25);
|
const [maxTotalRetriesBeforeFail, setMaxTotalRetriesBeforeFail] = useState(25);
|
||||||
const [prAuthAvailable, setPrAuthAvailable] = useState(false);
|
const [prAuthAvailable, setPrAuthAvailable] = useState(false);
|
||||||
@@ -111,6 +113,7 @@ export function useAppSettings(projectId?: string): UseAppSettingsResult {
|
|||||||
? "floating"
|
? "floating"
|
||||||
: "off";
|
: "off";
|
||||||
setQuickChatButtonMode(nextQuickChatButtonMode);
|
setQuickChatButtonMode(nextQuickChatButtonMode);
|
||||||
|
setQuickChatCloseOnOutsideClick(settings.quickChatCloseOnOutsideClick !== false);
|
||||||
setShowQuickChatFAB(nextQuickChatButtonMode === "floating");
|
setShowQuickChatFAB(nextQuickChatButtonMode === "floating");
|
||||||
setMaxTotalRetriesBeforeFail(settings.maxTotalRetriesBeforeFail ?? 25);
|
setMaxTotalRetriesBeforeFail(settings.maxTotalRetriesBeforeFail ?? 25);
|
||||||
setCapacityRiskBannerEnabled(settings.capacityRiskBannerEnabled === true);
|
setCapacityRiskBannerEnabled(settings.capacityRiskBannerEnabled === true);
|
||||||
@@ -143,6 +146,7 @@ export function useAppSettings(projectId?: string): UseAppSettingsResult {
|
|||||||
setMemoryEnabled(true);
|
setMemoryEnabled(true);
|
||||||
setDevServerEnabled(false);
|
setDevServerEnabled(false);
|
||||||
setOpenTasksInRightSidebar(false);
|
setOpenTasksInRightSidebar(false);
|
||||||
|
setQuickChatCloseOnOutsideClick(true);
|
||||||
setTodosEnabled(true);
|
setTodosEnabled(true);
|
||||||
setGoalsEnabled(true);
|
setGoalsEnabled(true);
|
||||||
void refresh();
|
void refresh();
|
||||||
@@ -244,6 +248,7 @@ export function useAppSettings(projectId?: string): UseAppSettingsResult {
|
|||||||
capacityRiskTodoThreshold,
|
capacityRiskTodoThreshold,
|
||||||
openTasksInRightSidebar,
|
openTasksInRightSidebar,
|
||||||
quickChatButtonMode,
|
quickChatButtonMode,
|
||||||
|
quickChatCloseOnOutsideClick,
|
||||||
showQuickChatFAB,
|
showQuickChatFAB,
|
||||||
maxTotalRetriesBeforeFail,
|
maxTotalRetriesBeforeFail,
|
||||||
prAuthAvailable,
|
prAuthAvailable,
|
||||||
|
|||||||
Reference in New Issue
Block a user