mirror of
https://github.com/OpenHands/OpenHands.git
synced 2026-03-22 05:37:20 +08:00
Fix: OSS suggested tasks empty state (#12563)
Co-authored-by: Mohammed Abdulai <nurud43@gmail.com> Co-authored-by: hieptl <hieptl.developer@gmail.com>
This commit is contained in:
76
frontend/__tests__/task-suggestions.test.tsx
Normal file
76
frontend/__tests__/task-suggestions.test.tsx
Normal file
@@ -0,0 +1,76 @@
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import { describe, it, expect, beforeEach, vi } from "vitest";
|
||||
import { MemoryRouter } from "react-router";
|
||||
import { TaskSuggestions } from "#/components/features/home/tasks/task-suggestions";
|
||||
|
||||
// Mock translation
|
||||
vi.mock("react-i18next", () => ({
|
||||
useTranslation: () => ({
|
||||
t: (key: string) => key,
|
||||
}),
|
||||
}));
|
||||
|
||||
// Mock suggested tasks hook
|
||||
vi.mock("#/hooks/query/use-suggested-tasks", () => ({
|
||||
useSuggestedTasks: () => ({
|
||||
data: [],
|
||||
isLoading: false,
|
||||
}),
|
||||
}));
|
||||
|
||||
// Mock config hook
|
||||
vi.mock("#/hooks/query/use-config", () => ({
|
||||
useConfig: vi.fn(),
|
||||
}));
|
||||
|
||||
// Mock user providers hook
|
||||
vi.mock("#/hooks/use-user-providers", () => ({
|
||||
useUserProviders: vi.fn(),
|
||||
}));
|
||||
|
||||
import { useConfig } from "#/hooks/query/use-config";
|
||||
import { useUserProviders } from "#/hooks/use-user-providers";
|
||||
|
||||
describe("TaskSuggestions empty states", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("OSS mode + no providers → shows Git provider empty state", () => {
|
||||
(useConfig as any).mockReturnValue({
|
||||
data: { app_mode: "oss" },
|
||||
});
|
||||
|
||||
(useUserProviders as any).mockReturnValue({
|
||||
providers: [],
|
||||
});
|
||||
|
||||
render(
|
||||
<MemoryRouter>
|
||||
<TaskSuggestions />
|
||||
</MemoryRouter>
|
||||
);
|
||||
|
||||
expect(screen.getByText("TASKS$NO_GIT_PROVIDERS_TITLE")).toBeInTheDocument();
|
||||
expect(screen.getByText("TASKS$NO_GIT_PROVIDERS_DESCRIPTION")).toBeInTheDocument();
|
||||
expect(screen.getByText("TASKS$NO_GIT_PROVIDERS_CTA")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("OSS mode + providers exist but no tasks → shows no tasks message", () => {
|
||||
(useConfig as any).mockReturnValue({
|
||||
data: { app_mode: "oss" },
|
||||
});
|
||||
|
||||
(useUserProviders as any).mockReturnValue({
|
||||
providers: [{ id: "github" }],
|
||||
});
|
||||
|
||||
render(
|
||||
<MemoryRouter>
|
||||
<TaskSuggestions />
|
||||
</MemoryRouter>
|
||||
);
|
||||
|
||||
expect(screen.getByText("TASKS$NO_TASKS_AVAILABLE")).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -1,11 +1,15 @@
|
||||
import { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Link } from "react-router";
|
||||
import { TaskGroup } from "./task-group";
|
||||
import { useSuggestedTasks } from "#/hooks/query/use-suggested-tasks";
|
||||
import { TaskSuggestionsSkeleton } from "./task-suggestions-skeleton";
|
||||
import { cn, getDisplayedTaskGroups, getTotalTaskCount } from "#/utils/utils";
|
||||
import { I18nKey } from "#/i18n/declaration";
|
||||
import { GitRepository } from "#/types/git";
|
||||
import { useConfig } from "#/hooks/query/use-config";
|
||||
import { useUserProviders } from "#/hooks/use-user-providers";
|
||||
import { Typography } from "#/ui/typography";
|
||||
|
||||
interface TaskSuggestionsProps {
|
||||
filterFor?: GitRepository | null;
|
||||
@@ -14,7 +18,13 @@ interface TaskSuggestionsProps {
|
||||
export function TaskSuggestions({ filterFor }: TaskSuggestionsProps) {
|
||||
const { t } = useTranslation();
|
||||
const [isExpanded, setIsExpanded] = useState(false);
|
||||
|
||||
const { data: config } = useConfig();
|
||||
const { data: tasks, isLoading } = useSuggestedTasks();
|
||||
const { providers } = useUserProviders();
|
||||
|
||||
const isOSS = config?.app_mode === "oss";
|
||||
const hasNoProviders = isOSS && providers.length === 0;
|
||||
|
||||
const suggestedTasks = filterFor
|
||||
? tasks?.filter(
|
||||
@@ -63,11 +73,32 @@ export function TaskSuggestions({ filterFor }: TaskSuggestionsProps) {
|
||||
<TaskSuggestionsSkeleton />
|
||||
</div>
|
||||
)}
|
||||
{!hasSuggestedTasks && !isLoading && (
|
||||
<span className="text-xs leading-4 text-white font-medium px-[14px]">
|
||||
{t(I18nKey.TASKS$NO_TASKS_AVAILABLE)}
|
||||
</span>
|
||||
)}
|
||||
{!hasSuggestedTasks &&
|
||||
!isLoading &&
|
||||
(hasNoProviders ? (
|
||||
<div className="px-[14px] flex flex-col gap-3 pb-6 sm:pb-8">
|
||||
<Typography.Text className="text-xs leading-4 text-white font-medium">
|
||||
{t(I18nKey.TASKS$NO_GIT_PROVIDERS_TITLE)}
|
||||
</Typography.Text>
|
||||
|
||||
<Typography.Text className="text-xs leading-4 text-[#C9C9C9] font-normal">
|
||||
{t(I18nKey.TASKS$NO_GIT_PROVIDERS_DESCRIPTION)}
|
||||
</Typography.Text>
|
||||
|
||||
<Link
|
||||
to="/settings/integrations"
|
||||
className="w-fit hover:underline"
|
||||
>
|
||||
<Typography.Text className="text-xs leading-4 text-[#FAFAFA] font-normal">
|
||||
{t(I18nKey.TASKS$NO_GIT_PROVIDERS_CTA)}
|
||||
</Typography.Text>
|
||||
</Link>
|
||||
</div>
|
||||
) : (
|
||||
<Typography.Text className="text-xs leading-4 text-white font-medium px-[14px]">
|
||||
{t(I18nKey.TASKS$NO_TASKS_AVAILABLE)}
|
||||
</Typography.Text>
|
||||
))}
|
||||
|
||||
{!isLoading &&
|
||||
displayedTaskGroups &&
|
||||
|
||||
@@ -722,6 +722,9 @@ export enum I18nKey {
|
||||
HOME$ADD_GITHUB_REPOS = "HOME$ADD_GITHUB_REPOS",
|
||||
REPOSITORY$SELECT_BRANCH = "REPOSITORY$SELECT_BRANCH",
|
||||
REPOSITORY$SELECT_REPO = "REPOSITORY$SELECT_REPO",
|
||||
TASKS$NO_GIT_PROVIDERS_TITLE = "TASKS$NO_GIT_PROVIDERS_TITLE",
|
||||
TASKS$NO_GIT_PROVIDERS_DESCRIPTION = "TASKS$NO_GIT_PROVIDERS_DESCRIPTION",
|
||||
TASKS$NO_GIT_PROVIDERS_CTA = "TASKS$NO_GIT_PROVIDERS_CTA",
|
||||
TASKS$SUGGESTED_TASKS = "TASKS$SUGGESTED_TASKS",
|
||||
TASKS$NO_TASKS_AVAILABLE = "TASKS$NO_TASKS_AVAILABLE",
|
||||
TASKS$TASK_SUGGESTIONS_INFO = "TASKS$TASK_SUGGESTIONS_INFO",
|
||||
|
||||
@@ -11553,6 +11553,56 @@
|
||||
"de": "Ein Repository auswählen",
|
||||
"uk": "Вибрати репозиторій"
|
||||
},
|
||||
"TASKS$NO_GIT_PROVIDERS_TITLE": {
|
||||
"en": "Connect a Git provider",
|
||||
"ja": "Gitプロバイダーを接続",
|
||||
"zh-CN": "连接 Git 提供商",
|
||||
"zh-TW": "連接 Git 提供商",
|
||||
"ko-KR": "Git 제공자 연결",
|
||||
"no": "Koble til en Git-leverandør",
|
||||
"ar": "قم بتوصيل موفر Git",
|
||||
"de": "Git-Anbieter verbinden",
|
||||
"fr": "Connecter un fournisseur Git",
|
||||
"it": "Collega un provider Git",
|
||||
"pt": "Conectar um provedor Git",
|
||||
"es": "Conectar un proveedor Git",
|
||||
"tr": "Git sağlayıcısını bağla",
|
||||
"uk": "Підключити постачальник Git"
|
||||
},
|
||||
|
||||
"TASKS$NO_GIT_PROVIDERS_DESCRIPTION": {
|
||||
"en": "Connect a Git provider to see suggested tasks from your repositories.",
|
||||
"ja": "Gitプロバイダーを接続して、リポジトリからの提案タスクを表示します。",
|
||||
"zh-CN": "连接 Git 提供商以查看来自存储库的建议任务。",
|
||||
"zh-TW": "連接 Git 提供商以查看來自存儲庫的建議任務。",
|
||||
"ko-KR": "Git 제공자를 연결하여 저장소의 추천 작업을 확인하세요.",
|
||||
"no": "Koble til en Git-leverandør for å se foreslåtte oppgaver fra dine repositorier.",
|
||||
"ar": "قم بتوصيل موفر Git لرؤية المهام المقترحة من مستودعاتك.",
|
||||
"de": "Verbinde einen Git-Anbieter, um vorgeschlagene Aufgaben aus deinen Repositories zu sehen.",
|
||||
"fr": "Connectez un fournisseur Git pour voir les tâches suggérées depuis vos dépôts.",
|
||||
"it": "Collega un provider Git per vedere le attività suggerite dai tuoi repository.",
|
||||
"pt": "Conecte um provedor Git para ver tarefas sugeridas dos seus repositórios.",
|
||||
"es": "Conecta un proveedor Git para ver tareas sugeridas de tus repositorios.",
|
||||
"tr": "Depolarınızdan önerilen görevleri görmek için bir Git sağlayıcısı bağlayın.",
|
||||
"uk": "Підключіть постачальник Git, щоб бачити запропоновані завдання з ваших репозиторіїв."
|
||||
},
|
||||
|
||||
"TASKS$NO_GIT_PROVIDERS_CTA": {
|
||||
"en": "Go to Integrations",
|
||||
"ja": "統合へ移動",
|
||||
"zh-CN": "前往集成",
|
||||
"zh-TW": "前往整合",
|
||||
"ko-KR": "통합으로 이동",
|
||||
"no": "Gå til integrasjoner",
|
||||
"ar": "الانتقال إلى التكاملات",
|
||||
"de": "Zu Integrationen",
|
||||
"fr": "Aller aux intégrations",
|
||||
"it": "Vai alle integrazioni",
|
||||
"pt": "Ir para integrações",
|
||||
"es": "Ir a integraciones",
|
||||
"tr": "Entegrasyonlara git",
|
||||
"uk": "Перейти до інтеграцій"
|
||||
},
|
||||
"TASKS$SUGGESTED_TASKS": {
|
||||
"en": "Suggested Tasks",
|
||||
"ja": "推奨タスク",
|
||||
|
||||
Reference in New Issue
Block a user