Task #609: Per-user app enable/disable in Settings
- New `user_hidden_apps` table (userId+appId composite PK, cascade) in
lib/db/src/schema/user-hidden-apps.ts; registered in schema index;
pushed to dev DB via drizzle-kit.
- Backend (artifacts/api-server/src/routes/apps.ts):
- GET /me/apps — returns every globally-active app visible to the
user with a `hidden` flag.
- PUT /me/apps/:appId/hidden — toggles a row in user_hidden_apps,
gated by getVisibleAppsForUser + isActive so a user can't toggle
apps they can't reach.
- GET /apps (Home/Dock) now uses getVisibleNonHiddenAppsForUser so
hidden apps disappear immediately.
- lib/appsVisibility.ts: added getHiddenAppIdsForUser and
getVisibleNonHiddenAppsForUser helpers.
- OpenAPI: added /me/apps + /me/apps/{appId}/hidden, MyApp and
UpdateMyAppHiddenBody schemas; regenerated api-zod + api-client-react.
- Frontend (settings-panel.tsx): added "My apps" accordion section as
first GroupItem with MyAppsBody — Switch per app, optimistic update,
invalidates getListMyAppsQueryKey + getListAppsQueryKey so Home/Dock
refresh without reload.
- Translations: added settingsPanel.section.myApps + settingsPanel.myApps
in ar.json + en.json.
- Code review fix: /me/apps and PUT gating filter isActive even for
admins, so inactive apps don't appear in the Settings list.
- Proposed follow-up #611 (Playwright test that hidden apps disappear
from Home and Dock).
This commit is contained in:
@@ -633,6 +633,64 @@ paths:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ErrorResponse"
|
||||
|
||||
/me/apps:
|
||||
get:
|
||||
operationId: listMyApps
|
||||
tags: [apps]
|
||||
summary: List apps for the current user with their per-user hidden state
|
||||
description: |
|
||||
Returns every globally active app (regardless of the per-user hidden
|
||||
flag), each with a `hidden` boolean indicating whether the current
|
||||
user has hidden it from their own Home/Dock via PUT /me/apps/{appId}/hidden.
|
||||
Used by the per-user Settings panel; the Home and Dock continue to use
|
||||
GET /apps which already filters out hidden apps server-side.
|
||||
responses:
|
||||
"200":
|
||||
description: Apps visible to the current user, with per-user hidden state
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/MyApp"
|
||||
|
||||
/me/apps/{appId}/hidden:
|
||||
put:
|
||||
operationId: updateMyAppHidden
|
||||
tags: [apps]
|
||||
summary: Hide or show an app for the current user
|
||||
parameters:
|
||||
- name: appId
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/UpdateMyAppHiddenBody"
|
||||
responses:
|
||||
"200":
|
||||
description: Updated per-user app state
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/MyApp"
|
||||
"400":
|
||||
description: Validation error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ErrorResponse"
|
||||
"404":
|
||||
description: App not found or not visible to the current user
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ErrorResponse"
|
||||
|
||||
# Settings
|
||||
/settings:
|
||||
get:
|
||||
@@ -4231,6 +4289,23 @@ components:
|
||||
type: string
|
||||
format: date-time
|
||||
|
||||
MyApp:
|
||||
allOf:
|
||||
- $ref: "#/components/schemas/App"
|
||||
- type: object
|
||||
required: [hidden]
|
||||
properties:
|
||||
hidden:
|
||||
type: boolean
|
||||
description: True when the current user has hidden this app from their Home/Dock.
|
||||
|
||||
UpdateMyAppHiddenBody:
|
||||
type: object
|
||||
required: [hidden]
|
||||
properties:
|
||||
hidden:
|
||||
type: boolean
|
||||
|
||||
UpdateMyAppOrderBody:
|
||||
type: object
|
||||
required: [order]
|
||||
|
||||
Reference in New Issue
Block a user