mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-09-01 07:07:14 +00:00
fix(monitoring): hide disabled box status on cloud
This commit is contained in:
@@ -1,6 +1,9 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from langbot.pkg.utils import constants
|
||||||
|
|
||||||
from .. import group
|
from .. import group
|
||||||
|
from .box_visibility import should_hide_box_runtime_status
|
||||||
|
|
||||||
|
|
||||||
@group.group_class('box', '/api/v1/box')
|
@group.group_class('box', '/api/v1/box')
|
||||||
@@ -9,6 +12,7 @@ class BoxRouterGroup(group.RouterGroup):
|
|||||||
@self.route('/status', methods=['GET'], auth_type=group.AuthType.USER_TOKEN)
|
@self.route('/status', methods=['GET'], auth_type=group.AuthType.USER_TOKEN)
|
||||||
async def _() -> str:
|
async def _() -> str:
|
||||||
status = await self.ap.box_service.get_status()
|
status = await self.ap.box_service.get_status()
|
||||||
|
status['hidden'] = should_hide_box_runtime_status(constants.edition, status.get('enabled'))
|
||||||
return self.success(data=status)
|
return self.success(data=status)
|
||||||
|
|
||||||
@self.route('/sessions', methods=['GET'], auth_type=group.AuthType.USER_TOKEN)
|
@self.route('/sessions', methods=['GET'], auth_type=group.AuthType.USER_TOKEN)
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
|
||||||
|
def should_hide_box_runtime_status(edition: str, box_enabled: bool | None) -> bool:
|
||||||
|
return edition == 'cloud' and box_enabled is False
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from langbot.pkg.api.http.controller.groups.box_visibility import should_hide_box_runtime_status
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
('edition', 'box_enabled', 'expected'),
|
||||||
|
[
|
||||||
|
('cloud', False, True),
|
||||||
|
('cloud', True, False),
|
||||||
|
('cloud', None, False),
|
||||||
|
('community', False, False),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_should_hide_box_runtime_status(edition, box_enabled, expected):
|
||||||
|
assert should_hide_box_runtime_status(edition, box_enabled) is expected
|
||||||
@@ -65,11 +65,13 @@ export default function SystemStatusCard({
|
|||||||
|
|
||||||
const fetchStatus = useCallback(async () => {
|
const fetchStatus = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
const [plugin, box, sessions] = await Promise.all([
|
const [plugin, box] = await Promise.all([
|
||||||
httpClient.getPluginSystemStatus().catch(() => null),
|
httpClient.getPluginSystemStatus().catch(() => null),
|
||||||
httpClient.getBoxStatus().catch(() => null),
|
httpClient.getBoxStatus().catch(() => null),
|
||||||
httpClient.getBoxSessions().catch(() => [] as BoxSessionInfo[]),
|
|
||||||
]);
|
]);
|
||||||
|
const sessions = box?.hidden
|
||||||
|
? []
|
||||||
|
: await httpClient.getBoxSessions().catch(() => [] as BoxSessionInfo[]);
|
||||||
setPluginStatus(plugin);
|
setPluginStatus(plugin);
|
||||||
setBoxStatus(box);
|
setBoxStatus(box);
|
||||||
setBoxSessions(sessions);
|
setBoxSessions(sessions);
|
||||||
@@ -95,6 +97,7 @@ export default function SystemStatusCard({
|
|||||||
: 'failed'
|
: 'failed'
|
||||||
: null;
|
: null;
|
||||||
const boxOk = boxStatus ? boxStatus.available : null;
|
const boxOk = boxStatus ? boxStatus.available : null;
|
||||||
|
const hideBoxRuntime = boxStatus?.hidden === true;
|
||||||
// Box has three observable states: connected (ok), disabled by config
|
// Box has three observable states: connected (ok), disabled by config
|
||||||
// (enabled = false → distinct gray dot + "disabled" hint), and configured
|
// (enabled = false → distinct gray dot + "disabled" hint), and configured
|
||||||
// but failed (red dot + connector_error). The dashboard must distinguish
|
// but failed (red dot + connector_error). The dashboard must distinguish
|
||||||
@@ -152,11 +155,13 @@ export default function SystemStatusCard({
|
|||||||
<Plug className="w-3.5 h-3.5 text-muted-foreground" />
|
<Plug className="w-3.5 h-3.5 text-muted-foreground" />
|
||||||
<span className="text-sm">{t('monitoring.pluginRuntime')}</span>
|
<span className="text-sm">{t('monitoring.pluginRuntime')}</span>
|
||||||
</div>
|
</div>
|
||||||
|
{!hideBoxRuntime && (
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<StatusDot state={boxState} />
|
<StatusDot state={boxState} />
|
||||||
<Box className="w-3.5 h-3.5 text-muted-foreground" />
|
<Box className="w-3.5 h-3.5 text-muted-foreground" />
|
||||||
<span className="text-sm">{t('monitoring.boxRuntime')}</span>
|
<span className="text-sm">{t('monitoring.boxRuntime')}</span>
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
@@ -214,6 +219,8 @@ export default function SystemStatusCard({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{!hideBoxRuntime && (
|
||||||
|
<>
|
||||||
<div className="border-t" />
|
<div className="border-t" />
|
||||||
|
|
||||||
{/* Box Runtime */}
|
{/* Box Runtime */}
|
||||||
@@ -320,7 +327,9 @@ export default function SystemStatusCard({
|
|||||||
{session.image}
|
{session.image}
|
||||||
</span>
|
</span>
|
||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
<TooltipContent>{session.image}</TooltipContent>
|
<TooltipContent>
|
||||||
|
{session.image}
|
||||||
|
</TooltipContent>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-1.5 text-muted-foreground">
|
<div className="flex items-center gap-1.5 text-muted-foreground">
|
||||||
@@ -347,14 +356,16 @@ export default function SystemStatusCard({
|
|||||||
<Tooltip>
|
<Tooltip>
|
||||||
<TooltipTrigger asChild>
|
<TooltipTrigger asChild>
|
||||||
<span className="text-foreground font-mono truncate">
|
<span className="text-foreground font-mono truncate">
|
||||||
{session.host_path} : {session.mount_path}{' '}
|
{session.host_path} :{' '}
|
||||||
|
{session.mount_path}{' '}
|
||||||
<span className="text-muted-foreground">
|
<span className="text-muted-foreground">
|
||||||
({session.host_path_mode})
|
({session.host_path_mode})
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
<TooltipContent>
|
<TooltipContent>
|
||||||
{session.host_path} : {session.mount_path} (
|
{session.host_path} :{' '}
|
||||||
|
{session.mount_path} (
|
||||||
{session.host_path_mode})
|
{session.host_path_mode})
|
||||||
</TooltipContent>
|
</TooltipContent>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@@ -389,6 +400,8 @@ export default function SystemStatusCard({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</TooltipProvider>
|
</TooltipProvider>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
|
|||||||
@@ -373,6 +373,8 @@ export interface ApiRespPluginSystemStatus {
|
|||||||
|
|
||||||
export interface ApiRespBoxStatus {
|
export interface ApiRespBoxStatus {
|
||||||
available: boolean;
|
available: boolean;
|
||||||
|
/** UI hint: hide the Box runtime status surface for this deployment. */
|
||||||
|
hidden?: boolean;
|
||||||
/** Whether ``box.enabled`` is true in config. When false, the sandbox
|
/** Whether ``box.enabled`` is true in config. When false, the sandbox
|
||||||
* is deliberately disabled — distinct from "configured but failed". */
|
* is deliberately disabled — distinct from "configured but failed". */
|
||||||
enabled?: boolean;
|
enabled?: boolean;
|
||||||
|
|||||||
Reference in New Issue
Block a user