* feat: Add read-only access support for Models
- Backend: Add write_access field to ModelAccessResponse
- Backend: Update /models/list to return ModelAccessListResponse
- Frontend: Display Read Only badge in Models list
- Frontend: Disable inputs and save button when no write access
- Frontend: Hide action buttons for read-only models
* fix: Handle ModelAccessListResponse format in getModels API
- Backend returns {items, total} instead of {data}
- Update getModels API to handle both formats for backward compatibility
* fix: Show read-only shared models in workspace list
- Backend: Change search_models permission from 'write' to 'read' to include shared models
- Backend: Keep user_id filter to only show owned/shared models (not all public)
- Frontend: Handle ModelAccessListResponse format in getModels API
* fix: Align Read Only badge inline with model name
* fix: Correct badge placement and fix syntax error
* fix: Resolve badge truncation in Models list
- Add w-full to flex container for proper spacing
- Wrap Badge in div to prevent truncation
- Match Knowledge.svelte badge pattern
* fix: Align Read Only badge with Knowledge.svelte pattern
- Match Knowledge.svelte structure for badge placement
- Actions only show when write_access or admin
- Remove w-full from container to prevent right-overflow
* fix: Return write_access from getModelById endpoint
fix: Return write_access from getModelById endpoint
- Use ModelAccessResponse instead of raw dict
- Remove inefficient getModels call in edit page
* revert
* fix
* fix
* fix
This commit is contained in:
@@ -130,6 +130,10 @@ class ModelUserResponse(ModelModel):
|
||||
user: Optional[UserResponse] = None
|
||||
|
||||
|
||||
class ModelAccessResponse(ModelUserResponse):
|
||||
write_access: Optional[bool] = False
|
||||
|
||||
|
||||
class ModelResponse(ModelModel):
|
||||
pass
|
||||
|
||||
@@ -139,6 +143,11 @@ class ModelListResponse(BaseModel):
|
||||
total: int
|
||||
|
||||
|
||||
class ModelAccessListResponse(BaseModel):
|
||||
items: list[ModelAccessResponse]
|
||||
total: int
|
||||
|
||||
|
||||
class ModelForm(BaseModel):
|
||||
id: str
|
||||
base_model_id: Optional[str] = None
|
||||
@@ -292,7 +301,7 @@ class ModelsTable:
|
||||
db,
|
||||
query,
|
||||
filter,
|
||||
permission="write",
|
||||
permission="read",
|
||||
)
|
||||
|
||||
tag = filter.get("tag")
|
||||
|
||||
@@ -11,6 +11,8 @@ from open_webui.models.models import (
|
||||
ModelModel,
|
||||
ModelResponse,
|
||||
ModelListResponse,
|
||||
ModelAccessListResponse,
|
||||
ModelAccessResponse,
|
||||
Models,
|
||||
)
|
||||
|
||||
@@ -51,7 +53,7 @@ PAGE_ITEM_COUNT = 30
|
||||
|
||||
|
||||
@router.get(
|
||||
"/list", response_model=ModelListResponse
|
||||
"/list", response_model=ModelAccessListResponse
|
||||
) # do NOT use "/" as path, conflicts with main.py
|
||||
async def get_models(
|
||||
query: Optional[str] = None,
|
||||
@@ -88,7 +90,21 @@ async def get_models(
|
||||
|
||||
filter["user_id"] = user.id
|
||||
|
||||
return Models.search_models(user.id, filter=filter, skip=skip, limit=limit, db=db)
|
||||
result = Models.search_models(user.id, filter=filter, skip=skip, limit=limit, db=db)
|
||||
return ModelAccessListResponse(
|
||||
items=[
|
||||
ModelAccessResponse(
|
||||
**model.model_dump(),
|
||||
write_access=(
|
||||
(user.role == "admin" and BYPASS_ADMIN_ACCESS_CONTROL)
|
||||
or user.id == model.user_id
|
||||
or has_access(user.id, "write", model.access_control, db=db)
|
||||
),
|
||||
)
|
||||
for model in result.items
|
||||
],
|
||||
total=result.total,
|
||||
)
|
||||
|
||||
|
||||
###########################
|
||||
@@ -290,7 +306,7 @@ class ModelIdForm(BaseModel):
|
||||
|
||||
|
||||
# Note: We're not using the typical url path param here, but instead using a query parameter to allow '/' in the id
|
||||
@router.get("/model", response_model=Optional[ModelResponse])
|
||||
@router.get("/model", response_model=Optional[ModelAccessResponse])
|
||||
async def get_model_by_id(
|
||||
id: str, user=Depends(get_verified_user), db: Session = Depends(get_session)
|
||||
):
|
||||
@@ -301,7 +317,14 @@ async def get_model_by_id(
|
||||
or model.user_id == user.id
|
||||
or has_access(user.id, "read", model.access_control, db=db)
|
||||
):
|
||||
return model
|
||||
return ModelAccessResponse(
|
||||
**model.model_dump(),
|
||||
write_access=(
|
||||
(user.role == "admin" and BYPASS_ADMIN_ACCESS_CONTROL)
|
||||
or user.id == model.user_id
|
||||
or has_access(user.id, "write", model.access_control, db=db)
|
||||
),
|
||||
)
|
||||
else:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
|
||||
Reference in New Issue
Block a user