mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-07-26 22:36:11 +00:00
feat(cloud): complete Workspace settings navigation
This commit is contained in:
@@ -106,12 +106,21 @@ class WorkspacesRouterGroup(group.RouterGroup):
|
||||
if account is None:
|
||||
return self.http_status(401, 'invalid_authentication', 'Account not found')
|
||||
workspace = await self.ap.workspace_service.get_workspace(request_context.workspace_uuid)
|
||||
plan_name: str | None = None
|
||||
resolver = getattr(self.ap, 'entitlement_resolver', None)
|
||||
if workspace.source == WorkspaceSource.CLOUD_PROJECTION.value and resolver is not None:
|
||||
entitlement = await resolver.resolve(
|
||||
workspace.uuid,
|
||||
minimum_revision=request_context.entitlement_revision,
|
||||
)
|
||||
plan_name = entitlement.plan_name
|
||||
return self.success(
|
||||
data={
|
||||
'workspace': _workspace_payload(workspace),
|
||||
'membership': _membership_payload(membership, email=account.user),
|
||||
'permissions': sorted(request_context.workspace.permissions),
|
||||
'placement_generation': request_context.placement_generation,
|
||||
'plan_name': plan_name,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -18,10 +18,11 @@ class EntitlementUnavailableError(RuntimeError):
|
||||
|
||||
|
||||
class EntitlementSnapshot(pydantic.BaseModel):
|
||||
"""Plan-agnostic capability projection consumed by open-source Core.
|
||||
"""Capability projection consumed by open-source Core.
|
||||
|
||||
Product and billing names deliberately do not appear here. The closed
|
||||
Control Plane maps subscriptions to these generic features and limits.
|
||||
Admission and quota decisions use normalized features/limits rather than
|
||||
product plan names. ``plan_name`` is signed display metadata for Cloud UI
|
||||
only and must never drive authorization or quota enforcement.
|
||||
"""
|
||||
|
||||
model_config = pydantic.ConfigDict(frozen=True, extra='forbid')
|
||||
@@ -34,6 +35,9 @@ class EntitlementSnapshot(pydantic.BaseModel):
|
||||
expires_at: int = pydantic.Field(gt=0)
|
||||
features: dict[str, bool] = pydantic.Field(default_factory=dict)
|
||||
limits: dict[str, int] = pydantic.Field(default_factory=dict)
|
||||
# Signed display metadata for Cloud UI only. Admission and quota decisions
|
||||
# must continue to use generic ``features`` and ``limits`` exclusively.
|
||||
plan_name: str | None = pydantic.Field(default=None, min_length=1, max_length=128)
|
||||
|
||||
@pydantic.field_validator('features')
|
||||
@classmethod
|
||||
|
||||
@@ -281,6 +281,17 @@ class WorkspaceCollaborationService:
|
||||
*,
|
||||
session: AsyncSession | None = None,
|
||||
) -> list[WorkspaceMemberView]:
|
||||
if session is None:
|
||||
current_session = getattr(self.ap.persistence_mgr, 'current_session', lambda: None)()
|
||||
tenant_uow: typing.Any = getattr(self.ap.persistence_mgr, 'tenant_uow', None)
|
||||
if current_session is None and callable(tenant_uow):
|
||||
async with tenant_uow(workspace_uuid) as workspace_uow:
|
||||
return await self.list_members(
|
||||
workspace_uuid,
|
||||
actor,
|
||||
session=workspace_uow.session,
|
||||
)
|
||||
|
||||
async def operation(active_session: AsyncSession) -> list[WorkspaceMemberView]:
|
||||
await self._load_actor(active_session, workspace_uuid, actor)
|
||||
statement = (
|
||||
|
||||
Reference in New Issue
Block a user