Add option for authentication for public AI Hub

This commit is contained in:
yuneng-jiang 2026-02-04 15:49:05 -08:00
parent d2e113111f
commit ec4f7a38ff
3 changed files with 112 additions and 0 deletions

View File

@ -83,6 +83,11 @@ class UISettings(BaseModel):
description="List of page keys that internal users (non-admins) can see in the UI sidebar. If not set, all pages are visible based on role permissions.",
)
require_auth_for_public_ai_hub: bool = Field(
default=False,
description="If true, requires authentication for accessing the public AI Hub."
)
class UISettingsResponse(SettingsResponse):
"""Response model for UI settings"""
@ -95,6 +100,7 @@ ALLOWED_UI_SETTINGS_FIELDS = {
"disable_model_add_for_internal_users",
"disable_team_admin_delete_team_user",
"enabled_ui_pages_internal_users",
"require_auth_for_public_ai_hub",
}

View File

@ -20,6 +20,13 @@ vi.mock("@/app/(dashboard)/hooks/uiSettings/useUpdateUISettings", () => ({
useUpdateUISettings: mockUseUpdateUISettings,
}));
vi.mock("@/components/molecules/notifications_manager", () => ({
default: {
success: vi.fn(),
fromBackend: vi.fn(),
},
}));
const buildSettingsResponse = (overrides?: Partial<Record<string, unknown>>) => ({
data: {
field_schema: {
@ -28,10 +35,18 @@ const buildSettingsResponse = (overrides?: Partial<Record<string, unknown>>) =>
disable_model_add_for_internal_users: {
description: "Disable model add for internal users",
},
disable_team_admin_delete_team_user: {
description: "Disable team admin delete team user",
},
require_auth_for_public_ai_hub: {
description: "Require authentication for public AI Hub",
},
},
},
values: {
disable_model_add_for_internal_users: false,
disable_team_admin_delete_team_user: false,
require_auth_for_public_ai_hub: false,
},
},
isLoading: false,
@ -57,6 +72,8 @@ describe("UISettings", () => {
expect(screen.getByText("UI Settings")).toBeInTheDocument();
expect(screen.getByRole("switch", { name: "Disable model add for internal users" })).toBeInTheDocument();
expect(screen.getByRole("switch", { name: "Disable team admin delete team user" })).toBeInTheDocument();
expect(screen.getByRole("switch", { name: "Require authentication for public AI Hub" })).toBeInTheDocument();
});
it("should toggle setting and call update", () => {
@ -87,4 +104,62 @@ describe("UISettings", () => {
);
expect(NotificationManager.success).toHaveBeenCalledWith("UI settings updated successfully");
});
it("should toggle disable team admin delete team user setting and call update", () => {
const mutateMock = vi.fn((_settings, options) => {
options?.onSuccess?.();
});
mockUseUpdateUISettings.mockReturnValue({
mutate: mutateMock,
isPending: false,
error: null,
});
render(<UISettings />);
const toggle = screen.getByRole("switch", { name: "Disable team admin delete team user" });
act(() => {
fireEvent.click(toggle);
});
expect(mutateMock).toHaveBeenCalledWith(
{ disable_team_admin_delete_team_user: true },
expect.objectContaining({
onSuccess: expect.any(Function),
onError: expect.any(Function),
}),
);
expect(NotificationManager.success).toHaveBeenCalledWith("UI settings updated successfully");
});
it("should toggle require auth for public AI Hub setting and call update", () => {
const mutateMock = vi.fn((_settings, options) => {
options?.onSuccess?.();
});
mockUseUpdateUISettings.mockReturnValue({
mutate: mutateMock,
isPending: false,
error: null,
});
render(<UISettings />);
const toggle = screen.getByRole("switch", { name: "Require authentication for public AI Hub" });
act(() => {
fireEvent.click(toggle);
});
expect(mutateMock).toHaveBeenCalledWith(
{ require_auth_for_public_ai_hub: true },
expect.objectContaining({
onSuccess: expect.any(Function),
onError: expect.any(Function),
}),
);
expect(NotificationManager.success).toHaveBeenCalledWith("UI settings updated successfully");
});
});

View File

@ -15,6 +15,7 @@ export default function UISettings() {
const schema = data?.field_schema;
const property = schema?.properties?.disable_model_add_for_internal_users;
const disableTeamAdminDeleteProperty = schema?.properties?.disable_team_admin_delete_team_user;
const requireAuthForPublicAIHubProperty = schema?.properties?.require_auth_for_public_ai_hub;
const enabledPagesProperty = schema?.properties?.enabled_ui_pages_internal_users;
const values = data?.values ?? {};
const isDisabledForInternalUsers = Boolean(values.disable_model_add_for_internal_users);
@ -59,6 +60,20 @@ export default function UISettings() {
});
};
const handleToggleRequireAuthForPublicAIHub = (checked: boolean) => {
updateSettings(
{ require_auth_for_public_ai_hub: checked },
{
onSuccess: () => {
NotificationManager.success("UI settings updated successfully");
},
onError: (error) => {
NotificationManager.fromBackend(error);
},
},
);
};
return (
<Card title="UI Settings">
{isLoading ? (
@ -113,6 +128,22 @@ export default function UISettings() {
</Space>
</Space>
<Space align="start" size="middle">
<Switch
checked={values.require_auth_for_public_ai_hub}
disabled={isUpdating}
loading={isUpdating}
onChange={handleToggleRequireAuthForPublicAIHub}
aria-label={requireAuthForPublicAIHubProperty?.description ?? "Require authentication for public AI Hub"}
/>
<Space direction="vertical" size={4}>
<Typography.Text strong>Require authentication for public AI Hub</Typography.Text>
{requireAuthForPublicAIHubProperty?.description && (
<Typography.Text type="secondary">{requireAuthForPublicAIHubProperty.description}</Typography.Text>
)}
</Space>
</Space>
<Divider />
{/* Page Visibility for Internal Users */}