Files
fusion/packages/dashboard/app/components/SetupWarningBanner.tsx
gsxdsm 50786f29d4 FN-7475: delay GitHub setup warnings
Delay dashboard GitHub setup warnings until the project grace period expires while keeping AI setup warnings immediate.

- Add per-project GitHub warning delay state and persistence.
- Route dashboard GitHub warnings to Settings → Authentication with a Connect GitHub action.
- Hide non-actionable GitHub-only warnings in the New Task modal and update localized copy, docs, and tests.

Files changed:
 .changeset/fn-7475-github-setup-warning.md         |   7 ++
 docs/dashboard-guide.md                            |   6 +
 packages/dashboard/app/App.tsx                     |  11 +-
 packages/dashboard/app/components/NewTaskModal.tsx |   8 +-
 .../app/components/SetupWarningBanner.css          |  10 ++
 .../app/components/SetupWarningBanner.tsx          |  18 ++-
 .../app/components/__tests__/NewTaskModal.test.tsx |  46 ++++++-
 .../__tests__/SetupWarningBanner.test.tsx          |  40 ++++++
 .../app/components/dashboard/DashboardBanners.tsx  |   3 +
 .../dashboard/__tests__/DashboardBanners.test.tsx  | 125 ++++++++++++++++++-
 .../dashboard/app/components/dashboard/types.ts    |   1 +
 .../__tests__/useGithubSetupWarningDelay.test.ts   | 134 +++++++++++++++++++++
 .../app/hooks/useGithubSetupWarningDelay.ts        |  96 +++++++++++++++
 packages/dashboard/app/utils/projectStorage.ts     |   1 +
 packages/i18n/locales/en/app.json                  |   5 +-
 packages/i18n/locales/es/app.json                  |   5 +-
 packages/i18n/locales/fr/app.json                  |   5 +-
 packages/i18n/locales/ko/app.json                  |   5 +-
 packages/i18n/locales/zh-CN/app.json               |   5 +-
 packages/i18n/locales/zh-TW/app.json               |   5 +-
 packages/i18n/src/resources.d.ts                   | 127 +++++++++++++------
 21 files changed, 606 insertions(+), 57 deletions(-)

Fusion-Task-Id: FN-7475
Fusion-Task-Lineage: 5bf1fffa-b58c-42a1-b170-367a4c20eaaf
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-03 21:45:21 -07:00

107 lines
3.3 KiB
TypeScript

import "./SetupWarningBanner.css";
import { X } from "lucide-react";
import { useTranslation } from "react-i18next";
interface SetupWarningBannerProps {
/** Whether an AI provider is connected */
hasAiProvider: boolean;
/** Whether GitHub is connected */
hasGithub: boolean;
/** Whether the GitHub warning item is allowed to render after any grace period */
showGithubWarning?: boolean;
/** Optional: compact mode for inline use (QuickEntryBox) */
compact?: boolean;
/** Optional callback to open GitHub/authentication setup */
onConnectGithub?: () => void;
/** Optional callback to dismiss the banner */
onDismiss?: () => void;
}
interface WarningItem {
key: "ai" | "github";
title: string;
description: string;
}
export function SetupWarningBanner({
hasAiProvider,
hasGithub,
showGithubWarning = !hasGithub,
compact = false,
onDismiss,
onConnectGithub,
}: SetupWarningBannerProps) {
const { t } = useTranslation("app");
const shouldShowGithubWarning = !hasGithub && showGithubWarning;
if (hasAiProvider && !shouldShowGithubWarning) {
return null;
}
const dismissButton = onDismiss ? (
<button
type="button"
className="setup-warning-banner__dismiss touch-target"
aria-label={t("setup.dismissWarning", "Dismiss setup warning")}
onClick={onDismiss}
>
<X size={16} aria-hidden="true" />
</button>
) : null;
if (compact) {
return (
<div
className={`setup-warning-banner setup-warning-banner--compact${onDismiss ? " setup-warning-banner--dismissible" : ""}`}
role="status"
aria-live="polite"
>
<p className="setup-warning-banner__compact-text">
{t("setup.compactWarning", "⚠ Setup incomplete — AI and/or GitHub features will be limited.")}
</p>
{dismissButton}
</div>
);
}
const warningItems: WarningItem[] = [];
if (!hasAiProvider) {
warningItems.push({
key: "ai",
title: t("setup.noAiProvider", "No AI provider connected"),
description: t("setup.noAiProviderDesc", "AI agents won't be able to work on tasks until you connect a provider. Set one up in Settings → AI Setup."),
});
}
if (shouldShowGithubWarning) {
warningItems.push({
key: "github",
title: t("setup.noGithub", "GitHub not connected"),
description: t("setup.noGithubDesc", "You won't be able to import issues from GitHub, but you can still create tasks manually."),
});
}
return (
<div
className={`setup-warning-banner${onDismiss ? " setup-warning-banner--dismissible" : ""}`}
role="status"
aria-live="polite"
>
{dismissButton}
{warningItems.map((warning) => (
<div key={warning.key} className="setup-warning-banner__item">
<strong className="setup-warning-banner__title">{warning.title}</strong>
<p className="setup-warning-banner__description">{warning.description}</p>
{warning.key === "github" && onConnectGithub ? (
<div className="setup-warning-banner__actions">
<button type="button" className="btn btn-sm btn-primary" onClick={onConnectGithub}>
{t("setup.connectGithub", "Connect GitHub")}
</button>
</div>
) : null}
</div>
))}
</div>
);
}