fix(settings): gate the AI settings page on AI_SETTINGS, not the chat flag (#21239)
## Summary Closes #21229. The two AI role permissions behaved **opposite to their labels**. The trap is that the flag's code name is the inverse of its UI label: | `PermissionFlagType` | UI label | Section | Means | |---|---|---|---| | `AI` | **"Ask AI"** | Actions | End-user: chat with AI | | `AI_SETTINGS` | **"AI"** | Member / settings | Admin: configure AI agents | Before this PR (on `main`): - `AI` ("Ask AI", chat) gated **both** the AI chat **and** the AI settings page. - `AI_SETTINGS` ("AI", configure agents) gated **nothing** the user could see. So a chat-only user could reach the whole AI **configuration** page, and toggling the "AI" settings permission did nothing — exactly the misalignment reported in #21229. ## Root cause `PermissionFlagType.AI` *reads* like "the AI permission", so it looks like the natural gate for the AI settings page — but it's actually the **chat** flag. The settings page (nav item + route) had been pointed at `AI` in #21072 to match the Overview stats query (`findWorkspaceAiStats`), which was itself mis-gated on `AI`. Both the stats query and the rest of the settings surface are admin/config features, so they belong on `AI_SETTINGS`. ## Changes All three move the **AI settings surface** from the chat flag (`AI`) to the settings flag (`AI_SETTINGS`); chat keeps following `AI`: - `useSettingsNavigationItems.tsx` — AI nav item → `AI_SETTINGS` - `SettingsRoutes.tsx` — AI settings route group → `AI_SETTINGS` - `ai-workspace-stats.resolver.ts` — `findWorkspaceAiStats` (settings-only, drives the Overview tab) → `AI_SETTINGS` After this: the "AI" permission controls the AI settings page + its Overview; the "Ask AI" permission controls the chat. Both toggles now match their labels. ## Test plan - [ ] Role with **only "Ask AI"** (`AI`): AI chat tabs/pane visible; **Settings → AI is hidden** and the route is not reachable. - [ ] Role with **only "AI"** (`AI_SETTINGS`): Settings → AI is visible, Overview stats load; chat nav is hidden. - [ ] Admin (both flags): everything works as before. ## Known follow-ups (out of scope — pre-existing, shared endpoints) These remain on `AI` because they're shared with non-settings surfaces and need either OR-gating or a resolver split, so a role with `AI_SETTINGS` but **not** `AI` still can't use them yet: - `getAiSystemPromptPreview` (Models/Prompts tabs) lives in the chat resolver, class-gated `AI`; NestJS guards are additive so it can't be cleanly method-overridden — it should be pulled into a settings resolver. - Agent reads `findManyAgents` / `findOneAgent` (agent create/edit forms) are class-gated `AI` and shared with the **Workflow** editor and **Roles** pages; these want a guard that accepts `AI ∨ AI_SETTINGS ∨ WORKFLOWS`.
This commit is contained in:
@@ -690,7 +690,7 @@ export const SettingsRoutes = ({ isAdminPageEnabled }: SettingsRoutesProps) => (
|
||||
<Route
|
||||
element={
|
||||
<SettingsProtectedRouteWrapper
|
||||
settingsPermission={PermissionFlagType.AI}
|
||||
settingsPermission={PermissionFlagType.AI_SETTINGS}
|
||||
/>
|
||||
}
|
||||
>
|
||||
|
||||
@@ -171,7 +171,7 @@ const useSettingsNavigationItems = (): SettingsNavigationSection[] => {
|
||||
label: t`AI`,
|
||||
path: SettingsPath.AI,
|
||||
Icon: IconSparkles,
|
||||
isHidden: !permissionMap[PermissionFlagType.AI],
|
||||
isHidden: !permissionMap[PermissionFlagType.AI_SETTINGS],
|
||||
},
|
||||
{
|
||||
label: t`Email`,
|
||||
|
||||
+4
-1
@@ -13,7 +13,10 @@ import { WorkspaceAiStatsDTO } from 'src/engine/metadata-modules/ai/ai-workspace
|
||||
import { AiWorkspaceStatsService } from 'src/engine/metadata-modules/ai/ai-workspace-stats/services/ai-workspace-stats.service';
|
||||
import { UserRoleService } from 'src/engine/metadata-modules/user-role/user-role.service';
|
||||
|
||||
@UseGuards(WorkspaceAuthGuard, SettingsPermissionGuard(PermissionFlagType.AI))
|
||||
@UseGuards(
|
||||
WorkspaceAuthGuard,
|
||||
SettingsPermissionGuard(PermissionFlagType.AI_SETTINGS),
|
||||
)
|
||||
@MetadataResolver()
|
||||
export class AiWorkspaceStatsResolver {
|
||||
constructor(
|
||||
|
||||
Reference in New Issue
Block a user