ronantakizawa/codereview-bench huggingface dataset:
Repository: All-Hands-AI/OpenHands
File: frontend/__tests__/routes/manage-org.test.tsx (TypeScript)

Code before:
      getConfigSpy.mockRestore();
    });

    it("should not show Add Credits modal when HIDE_BILLING is true even if state is set", async () => {
      // Arrange
      const getConfigSpy = vi.spyOn(OptionService, "getConfig");
      getConfigSpy.mockResolvedValue({
        APP_MODE: "saas",
        GITHUB_CLIENT_ID: "test",
        POSTHOG_CLIENT_KEY: "test",
        FEATURE_FLAGS: {
          ENABLE_BILLING: false,
          HIDE_LLM_SETTINGS: false,
          HIDE_BILLING: true,
          ENABLE_JIRA: false,
          ENABLE_JIRA_DC: false,
          ENABLE_LINEAR: false,
        },
      });

      // Act
      renderManageOrg();
      await screen.findByTestId("manage-org-screen");
      await selectOrganization({ orgIndex: 0 });

      // Assert - Modal should not be accessible even if somehow triggered
      await waitFor(() => {
        expect(
          screen.queryByTestId("add-credits-form"),
        ).not.toBeInTheDocument();
      });

      getConfigSpy.mockRestore();
    });

    it("should show all billing-related elements when HIDE_BILLING is false", async () => {
      // Arrange
      const getConfigSpy = vi.spyOn(OptionService, "getConfig");
      getConfigSpy.mockResolvedValue({
        APP_MODE: "saas",
        GITHUB_CLIENT_ID: "test",
        POSTHOG_CLIENT_KEY: "test",
        FEATURE_FLAGS: {
          ENABLE_BILLING: false,
          HIDE_LLM_SETTINGS: false,
          HIDE_BILLING: false,
          ENABLE_JIRA: false,
          ENABLE_JIRA_DC: false,
          ENABLE_LINEAR: false,
        },
      });

Review comment (suggestion):
The test never sets `addCreditsFormVisible` to true. Since the `”Add"` button is already hidden when `HIDE_BILLING` is `true`, this is redundant with the previous test (see `"should hide Add Credits button when HIDE_BILLING is true”`). I verified this by removing the `!isBillingHidden` guard — test still passes. Suggest deleting.

Code after:
      getConfigSpy.mockRestore();
    });

    it("should show all billing-related elements when HIDE_BILLING is false", async () => {
      // Arrange
      const getConfigSpy = vi.spyOn(OptionService, "getConfig");
      getConfigSpy.mockResolvedValue({
        APP_MODE: "saas",
        GITHUB_CLIENT_ID: "test",
        POSTHOG_CLIENT_KEY: "test",
        FEATURE_FLAGS: {
          ENABLE_BILLING: false,
          HIDE_LLM_SETTINGS: false,
          HIDE_BILLING: false,
          ENABLE_JIRA: false,
          ENABLE_JIRA_DC: false,
          ENABLE_LINEAR: false,
        },
      });

      // Act
      renderManageOrg();
      await screen.findByTestId("manage-org-screen");
      await selectOrganization({ orgIndex: 0 });

      // Assert
      await waitFor(() => {
        expect(screen.getByTestId("available-credits")).toBeInTheDocument();
        expect(screen.getByTestId("billing-info")).toBeInTheDocument();
        expect(screen.getByText(/add/i)).toBeInTheDocument();
      });

      getConfigSpy.mockRestore();
    });
  });
});
Repository: All-Hands-AI/OpenHands
File: frontend/src/hooks/mutation/use-accept-tos.ts (TypeScript)

Code before:
import { useTracking } from "#/hooks/use-tracking";

interface AcceptTosVariables {
  redirectUrl: string;
}

interface AcceptTosResponse {
  data: {
    redirect_url?: string;
  };
}

export const useAcceptTos = () => {
  const posthog = usePostHog();
  const navigate = useNavigate();
  const { trackUserSignupCompleted } = useTracking();

  return useMutation({
    mutationFn: async ({ redirectUrl }: AcceptTosVariables) => {
      // Set consent for analytics
      handleCaptureConsent(posthog, true);

      // Call the API to record TOS acceptance in the database
      return openHands.post("/api/accept_tos", {
        redirect_url: redirectUrl,
      }) as Promise<AcceptTosResponse>;
    },
    onSuccess: (response, { redirectUrl }) => {
      // Track user signup completion
      trackUserSignupCompleted();

      // Get the redirect URL from the response
      const finalRedirectUrl = response.data.redirect_url || redirectUrl;

      // Check if the redirect URL is an external URL (starts with http or https)
      if (
        finalRedirectUrl.startsWith("http://") ||
        finalRedirectUrl.startsWith("https://")
      ) {
        // For external URLs, redirect using window.location
        window.location.href = finalRedirectUrl;
      } else {
        // For internal routes, use navigate
        navigate(finalRedirectUrl);
      }
    },
    onError: () => {
      window.location.href = "/";
    },
  });
};

Review comment (suggestion):
```suggestion
      return openHands.post<AcceptTosResponse>("/api/accept_tos", {
        redirect_url: redirectUrl,
      });
```

Code after:
import { useTracking } from "#/hooks/use-tracking";

interface AcceptTosVariables {
  redirectUrl: string;
}

interface AcceptTosResponse {
  redirect_url?: string;
}

export const useAcceptTos = () => {
  const posthog = usePostHog();
  const navigate = useNavigate();
  const { trackUserSignupCompleted } = useTracking();

  return useMutation({
    mutationFn: async ({ redirectUrl }: AcceptTosVariables) => {
      // Set consent for analytics
      handleCaptureConsent(posthog, true);

      // Call the API to record TOS acceptance in the database
      return openHands.post<AcceptTosResponse>("/api/accept_tos", {
        redirect_url: redirectUrl,
      });
    },
    onSuccess: (response, { redirectUrl }) => {
      // Track user signup completion
      trackUserSignupCompleted();

      // Get the redirect URL from the response
      const finalRedirectUrl = response.data.redirect_url || redirectUrl;

      // Check if the redirect URL is an external URL (starts with http or https)
      if (
        finalRedirectUrl.startsWith("http://") ||
        finalRedirectUrl.startsWith("https://")
      ) {
        // For external URLs, redirect using window.location
        window.location.href = finalRedirectUrl;
      } else {
        // For internal routes, use navigate
        navigate(finalRedirectUrl);
      }
    },
    onError: () => {
      window.location.href = "/";
    },
  });
};
Repository: All-Hands-AI/OpenHands
File: frontend/src/hooks/mutation/use-accept-tos.ts (TypeScript)

Code before:
import { useMutation } from "@tanstack/react-query";
import { usePostHog } from "posthog-js/react";
import { useNavigate } from "react-router";
import { openHands } from "#/api/open-hands-axios";
import { handleCaptureConsent } from "#/utils/handle-capture-consent";
import { useTracking } from "#/hooks/use-tracking";

interface AcceptTosVariables {
  redirectUrl: string;
}

interface AcceptTosResponse {
  data: {
    redirect_url?: string;
  };
}

export const useAcceptTos = () => {
  const posthog = usePostHog();
  const navigate = useNavigate();
  const { trackUserSignupCompleted } = useTracking();

  return useMutation({
    mutationFn: async ({ redirectUrl }: AcceptTosVariables) => {
      // Set consent for analytics
      handleCaptureConsent(posthog, true);

      // Call the API to record TOS acceptance in the database
      return openHands.post("/api/accept_tos", {
        redirect_url: redirectUrl,
      }) as Promise<AcceptTosResponse>;
    },
    onSuccess: (response, { redirectUrl }) => {
      // Track user signup completion
      trackUserSignupCompleted();

      // Get the redirect URL from the response
      const finalRedirectUrl = response.data.redirect_url || redirectUrl;


Review comment (suggestion):
```suggestion
interface AcceptTosResponse {
  redirect_url?: string;
}
```

Code after:
import { useMutation } from "@tanstack/react-query";
import { usePostHog } from "posthog-js/react";
import { useNavigate } from "react-router";
import { openHands } from "#/api/open-hands-axios";
import { handleCaptureConsent } from "#/utils/handle-capture-consent";
import { useTracking } from "#/hooks/use-tracking";

interface AcceptTosVariables {
  redirectUrl: string;
}

interface AcceptTosResponse {
  redirect_url?: string;
}

export const useAcceptTos = () => {
  const posthog = usePostHog();
  const navigate = useNavigate();
  const { trackUserSignupCompleted } = useTracking();

  return useMutation({
    mutationFn: async ({ redirectUrl }: AcceptTosVariables) => {
      // Set consent for analytics
      handleCaptureConsent(posthog, true);

      // Call the API to record TOS acceptance in the database
      return openHands.post<AcceptTosResponse>("/api/accept_tos", {
        redirect_url: redirectUrl,
      });
    },
    onSuccess: (response, { redirectUrl }) => {
      // Track user signup completion
      trackUserSignupCompleted();

      // Get the redirect URL from the response
      const finalRedirectUrl = response.data.redirect_url || redirectUrl;

      // Check if the redirect URL is an external URL (starts with http or https)
      if (
Repository: All-Hands-AI/OpenHands
File: frontend/__tests__/routes/manage-org.test.tsx (TypeScript)

Code before:

const { navigateMock } = vi.hoisted(() => ({
  navigateMock: vi.fn(),
}));

vi.mock("react-router", async () => ({
  ...(await vi.importActual("react-router")),
  useNavigate: () => navigateMock,
}));

describe("Manage Org Route", () => {
  const getMeSpy = vi.spyOn(organizationService, "getMe");

  // Test data constants
  const TEST_USERS = {
    OWNER: {
      org_id: "1",
      user_id: "1",
      email: "test@example.com",
      role: "owner" as const,
      llm_api_key: "**********",
      max_iterations: 20,
      llm_model: "gpt-4",
      llm_api_key_for_byor: null,
      llm_base_url: "https://api.openai.com",
      status: "active" as const,
    },
    ADMIN: {
      org_id: "1",
      user_id: "1",
      email: "test@example.com",
      role: "admin" as const,
      llm_api_key: "**********",
      max_iterations: 20,
      llm_model: "gpt-4",
      llm_api_key_for_byor: null,
      llm_base_url: "https://api.openai.com",
      status: "active" as const,
    },
  };

  // Helper function to set up user mock
  const setupUserMock = (userData: {
    org_id: string;
    user_id: string;
    email: string;
    role: "owner" | "admin" | "user";
    llm_api_key: string;
    max_iterations: number;
    llm_model: string;
    llm_api_key_for_byor: string | null;

Review comment (suggestion):
We can add a `Record<"OWNER" | "ADMIN", OrganizationMember>` type annotation and remove the `as const` type annotation in the object properties like `”role"`

Code after:
  });

const { navigateMock } = vi.hoisted(() => ({
  navigateMock: vi.fn(),
}));

vi.mock("react-router", async () => ({
  ...(await vi.importActual("react-router")),
  useNavigate: () => navigateMock,
}));

describe("Manage Org Route", () => {
  const getMeSpy = vi.spyOn(organizationService, "getMe");

  // Test data constants
  const TEST_USERS: Record<"OWNER" | "ADMIN", OrganizationMember> = {
    OWNER: {
      org_id: "1",
      user_id: "1",
      email: "test@example.com",
      role: "owner",
      llm_api_key: "**********",
      max_iterations: 20,
      llm_model: "gpt-4",
      llm_api_key_for_byor: null,
      llm_base_url: "https://api.openai.com",
      status: "active",
    },
    ADMIN: {
      org_id: "1",
      user_id: "1",
      email: "test@example.com",
      role: "admin",
      llm_api_key: "**********",
      max_iterations: 20,
      llm_model: "gpt-4",
      llm_api_key_for_byor: null,
      llm_base_url: "https://api.openai.com",
      status: "active",
    },
  };

  // Helper function to set up user mock
  const setupUserMock = (userData: {
    org_id: string;
    user_id: string;
    email: string;
    role: "owner" | "admin" | "user";
    llm_api_key: string;
    max_iterations: number;
    llm_model: string;
Repository: All-Hands-AI/OpenHands
File: frontend/src/components/features/chat/chat-status-indicator.tsx (TypeScript)

Code before:
      (txt) => txt.charAt(0).toUpperCase() + txt.slice(1).toLowerCase(),
    );

  return (
    <div
      id="chat-status-indicator"
      className="
                h-[31px]
                w-fit
                rounded-[100px]
                pt-[20px]
                pr-[16px]
                pb-[20px]
                pl-[5px]
                bg-[#25272D]
                flex
                items-center
                mb-[8px]
                "
    >
      <span className="animate-[pulse_1.2s_ease-in-out_infinite]">
        <DebugStackframeDot className="w-6 h-6 shrink-0" color={statusColor} />
      </span>
      <div className="font-normal text-[11px] leading-[20px]">
        {formatString(status)}
      </div>
    </div>
  );
}

export default ChatStatusIndicator;


Review comment (refactor):
TailwindCSS has a `capitalize` utility that can be used instead of a function. See https://tailwindcss.com/docs/text-transform

Code after:
    <div
      data-testid="chat-status-indicator"
      className={cn(
        "h-[31px] w-fit rounded-[100px] pt-[20px] pr-[16px] pb-[20px] pl-[5px] bg-[#25272D] flex items-center gap-2",
      )}
    >
      <AnimatePresence mode="wait">
        {/* Dot */}
        <motion.span
          key={`dot-${status}`}
          className="animate-[pulse_1.2s_ease-in-out_infinite]"
          initial={{ opacity: 0 }}
          animate={{ opacity: 1 }}
          exit={{ opacity: 0 }}
          transition={{ duration: 0.3 }}
        >
          <DebugStackframeDot
            className="w-6 h-6 shrink-0"
            color={statusColor}
          />
        </motion.span>

        {/* Text */}
        <motion.span
          key={`text-${status}`}
          initial={{ opacity: 0, y: -2 }}
          animate={{ opacity: 1, y: 0 }}
          exit={{ opacity: 0, y: 2 }}
          transition={{ duration: 0.3 }}
          className="font-normal text-[11px] leading-[20px] normal-case"
        >
          {status}
        </motion.span>
      </AnimatePresence>
    </div>
  );
}

export default ChatStatusIndicator;
Repository: All-Hands-AI/OpenHands
File: frontend/src/components/features/chat/interactive-chat-box.tsx (TypeScript)

Code before:
      displayErrorToast("An unexpected error occurred while processing files");
    }
  };

  const handleSubmit = (message: string) => {
    onSubmit(message, images, files);
    clearAllFiles();
  };

  const handleSuggestionsClick = (suggestion: string) => {
    handleSubmit(suggestion);
  };

  const isDisabled =
    curAgentState === AgentState.LOADING ||
    curAgentState === AgentState.AWAITING_USER_CONFIRMATION ||
    isTaskPolling(subConversationTaskStatus);

  const statusColor = getStatusColor({
    isPausing: false,
    isTask: isDisabled,
    taskStatus: null,
    isStartingStatus: conversation?.status === "STARTING",
    isStopStatus: conversation?.status === "STOPPED",
    curAgentState,
  });

  return (
    <div data-testid="interactive-chat-box">
      {conversation?.status && isDisabled && (
        <ChatStatusIndicator
          statusColor={statusColor}
          status={conversation.status}
        />
      )}
      <CustomChatInput
        disabled={isDisabled}
        onSubmit={handleSubmit}
        onFilesPaste={handleUpload}
        conversationStatus={conversation?.status || null}
      />
      <div className="mt-4">
        <GitControlBar onSuggestionsClick={handleSuggestionsClick} />
      </div>
    </div>
  );
}


Review comment (suggestion):
Always setting `isPausing: false` and `taskStatus: null` feels off, maybe we can -ass in the same data (if possible) as we do in https://github.com/OpenHands/OpenHands/blob/d6fc553ad97b52677ee9b414a92db547e82dd918/frontend/src/components/features/controls/server-status.tsx#L32-L39

Code after:
    }
  };

  const handleSubmit = (message: string) => {
    onSubmit(message, images, files);
    clearAllFiles();
  };

  const handleSuggestionsClick = (suggestion: string) => {
    handleSubmit(suggestion);
  };

  const isDisabled =
    curAgentState === AgentState.LOADING ||
    curAgentState === AgentState.AWAITING_USER_CONFIRMATION ||
    isTaskPolling(subConversationTaskStatus);

  return (
    <div data-testid="interactive-chat-box">
      <CustomChatInput
        disabled={isDisabled}
        onSubmit={handleSubmit}
        onFilesPaste={handleUpload}
        conversationStatus={conversation?.status || null}
      />
      <div className="mt-4">
        <GitControlBar onSuggestionsClick={handleSuggestionsClick} />
      </div>
    </div>
  );
}
Repository: All-Hands-AI/OpenHands
File: frontend/__tests__/components/chat/chat-interface.test.tsx (TypeScript)

Code before:
      rerender(
        <MemoryRouter>
          <ChatInterface />
        </MemoryRouter>,
      );

      await waitFor(() =>
        expect(sendMock).toHaveBeenCalledWith(expect.any(String)),
      );
    },
  );
});

describe('ChatInterface - Status Indicator', () => {
  it("should render ChatStatusIndicator when agent is not awaiting user input / conversation is NOT ready", () => {
    (useAgentState as unknown as ReturnType<typeof vi.fn>).mockReturnValue({
      curAgentState: AgentState.LOADING,
    });

    renderChatInterfaceWithRouter();

    expect(screen.getByTestId("chat-status-indicator")).toBeInTheDocument();
  });

  it("should NOT render ChatStatusIndicator when agent is awaiting user input / conversation is ready", () => {
    (useAgentState as unknown as ReturnType<typeof vi.fn>).mockReturnValue({
      curAgentState: AgentState.AWAITING_USER_INPUT,
    });

    renderChatInterfaceWithRouter();

    expect(screen.queryByTestId("chat-status-indicator")).not.toBeInTheDocument();
  });
});

describe.skip("ChatInterface - General functionality", () => {
  beforeAll(() => {
    // mock useScrollToBottom hook
    vi.mock("#/hooks/useScrollToBottom", () => ({
      useScrollToBottom: vi.fn(() => ({
        scrollDomToBottom: vi.fn(),
        onChatBodyScroll: vi.fn(),
        hitBottom: vi.fn(),
      })),
    }));
  });

  afterEach(() => {
    vi.clearAllMocks();
  });


Review comment (suggestion):
```suggestion
    vi.mocked(useAgentState).mockReturnValue({
```

Code after:
      rerender(
        <MemoryRouter>
          <ChatInterface />
        </MemoryRouter>,
      );

      await waitFor(() =>
        expect(sendMock).toHaveBeenCalledWith(expect.any(String)),
      );
    },
  );
});

describe('ChatInterface - Status Indicator', () => {
  it("should render ChatStatusIndicator when agent is not awaiting user input / conversation is NOT ready", () => {
    vi.mocked(useAgentState).mockReturnValue({
      curAgentState: AgentState.LOADING,
    });

    renderChatInterfaceWithRouter();

    expect(screen.getByTestId("chat-status-indicator")).toBeInTheDocument();
  });

  it("should NOT render ChatStatusIndicator when agent is awaiting user input / conversation is ready", () => {
    vi.mocked(useAgentState).mockReturnValue({
      curAgentState: AgentState.AWAITING_USER_INPUT,
    });

    renderChatInterfaceWithRouter();

    expect(screen.queryByTestId("chat-status-indicator")).not.toBeInTheDocument();
  });
});

describe.skip("ChatInterface - General functionality", () => {
  beforeAll(() => {
    // mock useScrollToBottom hook
    vi.mock("#/hooks/useScrollToBottom", () => ({
      useScrollToBottom: vi.fn(() => ({
        scrollDomToBottom: vi.fn(),
        onChatBodyScroll: vi.fn(),
        hitBottom: vi.fn(),
      })),
    }));
  });

  afterEach(() => {
    vi.clearAllMocks();
  });
Repository: All-Hands-AI/OpenHands
File: frontend/__tests__/components/chat-status-indicator.test.tsx (TypeScript)

Code before:

  it("passes the statusColor to the DebugStackframeDot icon", () => {
    render(
      <ChatStatusIndicator
        status="Error"
        statusColor="#FF684E"
      />
    );

    const icon = screen.getByTestId("debug-stackframe-dot");
    expect(icon).toHaveAttribute("color", "#FF684E");
  });

  it("renders the animated status dot", () => {
    render(
      <ChatStatusIndicator
        status="Loading"
        statusColor="#FFD600"
      />
    );

    const animatedWrapper = screen
      .getByTestId("debug-stackframe-dot")
      .parentElement;

    expect(animatedWrapper?.className).toContain("animate");
  });
});


Review comment (suggestion):
```suggestion
```

Let’s avoid testing CSS, classNames, or visuals as they can change frequently with no negative effect to the underlying behavior

Code after:
import { render, screen } from "@testing-library/react";
import { describe, it, expect, vi } from "vitest";
import ChatStatusIndicator from "#/components/features/chat/chat-status-indicator";

vi.mock("#/icons/debug-stackframe-dot.svg?react", () => ({
  default: (props: any) => (
    <svg data-testid="debug-stackframe-dot" {...props} />
  ),
}));

describe("ChatStatusIndicator", () => {
  it("renders the status indicator with status text", () => {
    render(
      <ChatStatusIndicator
        status="Waiting for sandbox"
        statusColor="#FFD600"
      />
    );

    expect(
      screen.getByTestId("chat-status-indicator"),
    ).toBeInTheDocument();
    expect(screen.getByText("Waiting for sandbox")).toBeInTheDocument();
  });

  it("passes the statusColor to the DebugStackframeDot icon", () => {
    render(
      <ChatStatusIndicator
        status="Error"
        statusColor="#FF684E"
      />
    );

    const icon = screen.getByTestId("debug-stackframe-dot");
    expect(icon).toHaveAttribute("color", "#FF684E");
  });

  it("renders the DebugStackframeDot icon", () => {
    render(
      <ChatStatusIndicator
        status="Loading"
        statusColor="#FFD600"
      />
    );

    expect(screen.getByTestId("debug-stackframe-dot")).toBeInTheDocument();
  });
});
Repository: All-Hands-AI/OpenHands
File: frontend/src/components/features/chat/chat-status-indicator.tsx (TypeScript)

Code before:
  statusColor,
}: ChatStatusIndicatorProps) {
  const [displayStatus, setDisplayStatus] = useState(status);
  const [fadingOut, setFadingOut] = useState(false);

  useEffect(() => {
    setFadingOut(true);

    const timeout = setTimeout(() => {
      setDisplayStatus(status);
      setFadingOut(false);
    }, 300);

    return () => clearTimeout(timeout);
  }, [status, displayStatus]);

  return (
    <div
      data-testid="chat-status-indicator"
      className="h-[31px] w-fit rounded-[100px] pt-[20px] pr-[16px] pb-[20px] pl-[5px] bg-[#25272D] flex items-center mb-[8px]"
    >
      <span className="animate-[pulse_1.2s_ease-in-out_infinite]">
        <DebugStackframeDot className="w-6 h-6 shrink-0" color={statusColor} />
      </span>
      <span
        className={`font-normal text-[11px] leading-[20px] normal-case transition-opacity duration-900 ease-out ${fadingOut ? "opacity-0" : "opacity-100"}`}
      >
        {displayStatus}
      </span>
    </div>
  );
}

export default ChatStatusIndicator;


Review comment (suggestion):
```suggestion
        className={cn(
          "font-normal text-[11px] leading-[20px] normal-case transition-opacity duration-900 ease-out",
          fadingOut ? "opacity-0" : "opacity-100",
        )}
```

You’ll need to also

```ts
import { cn } from "#/utils/utils”;
```

Code after:
  status,
  statusColor,
}: ChatStatusIndicatorProps) {
  return (
    <div
      data-testid="chat-status-indicator"
      className={cn(
        "h-[31px] w-fit rounded-[100px] pt-[20px] pr-[16px] pb-[20px] pl-[5px] bg-[#25272D] flex items-center gap-2",
      )}
    >
      <AnimatePresence mode="wait">
        {/* Dot */}
        <motion.span
          key={`dot-${status}`}
          className="animate-[pulse_1.2s_ease-in-out_infinite]"
          initial={{ opacity: 0 }}
          animate={{ opacity: 1 }}
          exit={{ opacity: 0 }}
          transition={{ duration: 0.3 }}
        >
          <DebugStackframeDot
            className="w-6 h-6 shrink-0"
            color={statusColor}
          />
        </motion.span>

        {/* Text */}
        <motion.span
          key={`text-${status}`}
          initial={{ opacity: 0, y: -2 }}
          animate={{ opacity: 1, y: 0 }}
          exit={{ opacity: 0, y: 2 }}
          transition={{ duration: 0.3 }}
          className="font-normal text-[11px] leading-[20px] normal-case"
        >
          {status}
        </motion.span>
      </AnimatePresence>
    </div>
  );
}

export default ChatStatusIndicator;