v0.1.4-p4
parent
d196e57804
commit
ad59bc3794
|
|
@ -1,22 +0,0 @@
|
|||
import os
|
||||
|
||||
def fix_sf(path):
|
||||
with open(path, 'r') as f:
|
||||
lines = f.readlines()
|
||||
new_lines = []
|
||||
for line in lines:
|
||||
if "from services.bot_service import _skills_root" in line: continue
|
||||
if "from services.bot_service import _workspace_root" in line: continue
|
||||
new_lines.append(line)
|
||||
|
||||
# Add corrected imports at the top
|
||||
if path.endswith("skill_service.py"):
|
||||
new_lines.insert(20, "from services.bot_service import _skills_root, _workspace_root\n")
|
||||
elif path.endswith("workspace_service.py"):
|
||||
new_lines.insert(20, "from services.bot_service import _workspace_root\n")
|
||||
|
||||
with open(path, 'w') as f:
|
||||
f.writelines(new_lines)
|
||||
|
||||
# Wait, if _skills_root is defined in skill_service.py, it shouldn't be imported from bot_service.
|
||||
# Let's check where it IS defined.
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -23,7 +23,6 @@ import { getAppRouteMeta, navigateToRoute, readCompactModeFromUrl, useAppRoute,
|
|||
import './components/ui/SharedUi.css';
|
||||
import './App.css';
|
||||
import './App.h5.css';
|
||||
import './modules/platform/PlatformDashboardPage.css';
|
||||
|
||||
const defaultLoadingTitle = 'Dashboard Nanobot';
|
||||
|
||||
|
|
|
|||
|
|
@ -127,21 +127,22 @@
|
|||
padding: 10px 10px 10px 14px;
|
||||
margin-bottom: 10px;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.2s ease, transform 0.2s ease, box-shadow 0.2s ease, background 0.2s ease;
|
||||
transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.ops-bot-card:hover {
|
||||
border-color: color-mix(in oklab, var(--brand) 58%, var(--line) 42%);
|
||||
box-shadow: 0 8px 18px color-mix(in oklab, var(--brand) 14%, transparent);
|
||||
box-shadow: 0 8px 24px color-mix(in oklab, var(--brand) 12%, transparent);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.ops-bot-card.is-active {
|
||||
border-color: color-mix(in oklab, var(--brand) 80%, var(--line) 20%);
|
||||
border-color: var(--brand);
|
||||
background: color-mix(in oklab, var(--brand) 4%, var(--panel-soft));
|
||||
box-shadow:
|
||||
0 0 0 2px color-mix(in oklab, var(--brand) 70%, transparent),
|
||||
0 16px 30px color-mix(in oklab, var(--brand) 28%, transparent),
|
||||
inset 0 0 0 1px color-mix(in oklab, var(--brand) 84%, transparent);
|
||||
transform: translateY(0);
|
||||
0 0 0 2px color-mix(in oklab, var(--brand) 30%, transparent),
|
||||
0 12px 28px color-mix(in oklab, var(--brand) 18%, transparent);
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
|
|
@ -150,20 +151,27 @@
|
|||
position: absolute;
|
||||
inset: 0;
|
||||
border-radius: 12px;
|
||||
border: 2px solid color-mix(in oklab, var(--brand) 78%, transparent);
|
||||
border: 2px solid var(--brand);
|
||||
pointer-events: none;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.ops-bot-card.state-running {
|
||||
background: linear-gradient(145deg, color-mix(in oklab, var(--ok) 14%, var(--panel-soft) 86%), color-mix(in oklab, var(--ok) 8%, var(--panel) 92%));
|
||||
background: linear-gradient(145deg, color-mix(in oklab, var(--ok) 8%, var(--panel-soft) 92%), color-mix(in oklab, var(--ok) 4%, var(--panel) 96%));
|
||||
}
|
||||
|
||||
.ops-bot-card.state-running.is-active {
|
||||
background: linear-gradient(145deg, color-mix(in oklab, var(--ok) 12%, var(--brand) 4%), color-mix(in oklab, var(--ok) 6%, var(--panel) 94%));
|
||||
}
|
||||
|
||||
.ops-bot-card.state-stopped {
|
||||
background: linear-gradient(145deg, color-mix(in oklab, #b79aa2 14%, var(--panel-soft) 86%), color-mix(in oklab, #b79aa2 7%, var(--panel) 93%));
|
||||
background: linear-gradient(145deg, color-mix(in oklab, var(--err) 8%, var(--panel-soft) 92%), color-mix(in oklab, var(--err) 4%, var(--panel) 96%));
|
||||
}
|
||||
|
||||
.ops-bot-card.state-disabled {
|
||||
background: linear-gradient(145deg, color-mix(in oklab, #9ca3b5 14%, var(--panel-soft) 86%), color-mix(in oklab, #9ca3b5 7%, var(--panel) 93%));
|
||||
opacity: 0.72;
|
||||
filter: grayscale(0.2);
|
||||
background: var(--panel-soft);
|
||||
}
|
||||
|
||||
.ops-bot-top {
|
||||
|
|
@ -220,7 +228,7 @@
|
|||
border-radius: 999px;
|
||||
border: 1px solid color-mix(in oklab, var(--line) 82%, transparent);
|
||||
background: color-mix(in oklab, #9ca3b5 42%, var(--panel-soft) 58%);
|
||||
transition: background 0.2s ease, border-color 0.2s ease;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.ops-bot-enable-switch-track::after {
|
||||
|
|
@ -232,7 +240,7 @@
|
|||
height: 14px;
|
||||
border-radius: 999px;
|
||||
background: color-mix(in oklab, var(--text) 75%, #fff 25%);
|
||||
transition: transform 0.2s ease, background 0.2s ease;
|
||||
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.ops-bot-enable-switch input:checked + .ops-bot-enable-switch-track {
|
||||
|
|
@ -253,24 +261,27 @@
|
|||
.ops-bot-strip {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 8px;
|
||||
bottom: 8px;
|
||||
width: 3px;
|
||||
border-radius: 999px;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 4px;
|
||||
background: color-mix(in oklab, var(--line) 80%, transparent);
|
||||
opacity: 0.7;
|
||||
opacity: 0.8;
|
||||
transition: all 0.25s ease;
|
||||
}
|
||||
|
||||
.ops-bot-strip.is-running {
|
||||
background: linear-gradient(180deg, color-mix(in oklab, var(--ok) 80%, #9be8c6 20%), color-mix(in oklab, var(--ok) 54%, transparent));
|
||||
background: var(--ok);
|
||||
box-shadow: 2px 0 8px color-mix(in oklab, var(--ok) 40%, transparent);
|
||||
}
|
||||
|
||||
.ops-bot-strip.is-stopped {
|
||||
background: linear-gradient(180deg, color-mix(in oklab, var(--err) 74%, #e7b1ba 26%), color-mix(in oklab, var(--err) 54%, transparent));
|
||||
background: var(--err);
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.ops-bot-strip.is-disabled {
|
||||
background: linear-gradient(180deg, color-mix(in oklab, #9ca3b5 82%, #d4d9e2 18%), color-mix(in oklab, #9ca3b5 52%, transparent));
|
||||
background: #9ca3b5;
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
.ops-bot-icon-btn {
|
||||
|
|
@ -281,6 +292,7 @@
|
|||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.ops-bot-icon-btn svg {
|
||||
|
|
@ -377,42 +389,45 @@
|
|||
}
|
||||
|
||||
.ops-control-pending {
|
||||
display: inline-flex;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.ops-control-dots {
|
||||
display: inline-flex;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 3px;
|
||||
}
|
||||
|
||||
.ops-control-dots i {
|
||||
width: 4px;
|
||||
height: 4px;
|
||||
border-radius: 999px;
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
border-radius: 50%;
|
||||
display: block;
|
||||
background: currentColor;
|
||||
opacity: 0.35;
|
||||
animation: ops-control-dot 1.2s infinite ease-in-out;
|
||||
background: white;
|
||||
opacity: 1;
|
||||
animation: ops-control-dot 1s infinite ease-in-out;
|
||||
}
|
||||
|
||||
.ops-control-dots i:nth-child(2) {
|
||||
animation-delay: 0.2s;
|
||||
animation-delay: 0.15s;
|
||||
}
|
||||
|
||||
.ops-control-dots i:nth-child(3) {
|
||||
animation-delay: 0.4s;
|
||||
animation-delay: 0.3s;
|
||||
}
|
||||
|
||||
@keyframes ops-control-dot {
|
||||
0%, 80%, 100% {
|
||||
transform: translateY(0);
|
||||
opacity: 0.35;
|
||||
0%, 100% {
|
||||
transform: scale(0.8);
|
||||
opacity: 0.4;
|
||||
}
|
||||
40% {
|
||||
transform: translateY(-2px);
|
||||
50% {
|
||||
transform: scale(1.2);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -220,7 +220,7 @@ export function BotListPanel({
|
|||
const isEnabling = controlState === 'enabling';
|
||||
const isDisabling = controlState === 'disabling';
|
||||
const isRunning = String(bot.docker_status || '').toUpperCase() === 'RUNNING';
|
||||
const showActionPending = isStarting || isStopping;
|
||||
const showActionPending = isStarting || isStopping || isEnabling || isDisabling;
|
||||
return (
|
||||
<div
|
||||
key={bot.id}
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ export function useDashboardRuntimeControl({
|
|||
notify,
|
||||
confirm,
|
||||
}: UseDashboardRuntimeControlOptions) {
|
||||
const CONTROL_MIN_VISIBLE_MS = 450;
|
||||
const CONTROL_MIN_VISIBLE_MS = 1200;
|
||||
const [showResourceModal, setShowResourceModal] = useState(false);
|
||||
const [resourceBotId, setResourceBotId] = useState('');
|
||||
const [resourceSnapshot, setResourceSnapshot] = useState<BotResourceSnapshot | null>(null);
|
||||
|
|
@ -248,11 +248,23 @@ export function useDashboardRuntimeControl({
|
|||
}
|
||||
}, []);
|
||||
|
||||
const setControlState = useCallback((id: string, state: BotControlState) => {
|
||||
setControlStateByBot((prev) => ({ ...prev, [id]: state }));
|
||||
}, []);
|
||||
|
||||
const clearControlState = useCallback((id: string) => {
|
||||
setControlStateByBot((prev) => {
|
||||
const next = { ...prev };
|
||||
delete next[id];
|
||||
return next;
|
||||
});
|
||||
}, []);
|
||||
|
||||
const stopBot = useCallback(async (id: string, status: string) => {
|
||||
if (status !== 'RUNNING') return;
|
||||
const startedAt = Date.now();
|
||||
setOperatingBotId(id);
|
||||
setControlStateByBot((prev) => ({ ...prev, [id]: 'stopping' }));
|
||||
setControlState(id, 'stopping');
|
||||
try {
|
||||
await axios.post(`${APP_ENDPOINTS.apiBase}/bots/${id}/stop`);
|
||||
updateBotStatus(id, 'STOPPED');
|
||||
|
|
@ -263,19 +275,15 @@ export function useDashboardRuntimeControl({
|
|||
await ensureControlVisible(startedAt);
|
||||
} finally {
|
||||
setOperatingBotId(null);
|
||||
setControlStateByBot((prev) => {
|
||||
const next = { ...prev };
|
||||
delete next[id];
|
||||
return next;
|
||||
});
|
||||
clearControlState(id);
|
||||
}
|
||||
}, [ensureControlVisible, notify, refresh, t.stopFail, updateBotStatus]);
|
||||
}, [clearControlState, ensureControlVisible, notify, refresh, setControlState, t.stopFail, updateBotStatus]);
|
||||
|
||||
const startBot = useCallback(async (id: string, status: string) => {
|
||||
if (status === 'RUNNING') return;
|
||||
const startedAt = Date.now();
|
||||
setOperatingBotId(id);
|
||||
setControlStateByBot((prev) => ({ ...prev, [id]: 'starting' }));
|
||||
setControlState(id, 'starting');
|
||||
try {
|
||||
await axios.post(`${APP_ENDPOINTS.apiBase}/bots/${id}/start`);
|
||||
updateBotStatus(id, 'RUNNING');
|
||||
|
|
@ -287,13 +295,9 @@ export function useDashboardRuntimeControl({
|
|||
await ensureControlVisible(startedAt);
|
||||
} finally {
|
||||
setOperatingBotId(null);
|
||||
setControlStateByBot((prev) => {
|
||||
const next = { ...prev };
|
||||
delete next[id];
|
||||
return next;
|
||||
});
|
||||
clearControlState(id);
|
||||
}
|
||||
}, [ensureControlVisible, notify, refresh, t.startFail, updateBotStatus]);
|
||||
}, [clearControlState, ensureControlVisible, notify, refresh, setControlState, t.startFail, updateBotStatus]);
|
||||
|
||||
const restartBot = useCallback(async (id: string, status: string) => {
|
||||
const normalized = String(status || '').toUpperCase();
|
||||
|
|
@ -307,11 +311,11 @@ export function useDashboardRuntimeControl({
|
|||
setOperatingBotId(id);
|
||||
try {
|
||||
if (normalized === 'RUNNING') {
|
||||
setControlStateByBot((prev) => ({ ...prev, [id]: 'stopping' }));
|
||||
setControlState(id, 'stopping');
|
||||
await axios.post(`${APP_ENDPOINTS.apiBase}/bots/${id}/stop`);
|
||||
updateBotStatus(id, 'STOPPED');
|
||||
}
|
||||
setControlStateByBot((prev) => ({ ...prev, [id]: 'starting' }));
|
||||
setControlState(id, 'starting');
|
||||
await axios.post(`${APP_ENDPOINTS.apiBase}/bots/${id}/start`);
|
||||
updateBotStatus(id, 'RUNNING');
|
||||
await refresh();
|
||||
|
|
@ -322,17 +326,13 @@ export function useDashboardRuntimeControl({
|
|||
await ensureControlVisible(startedAt);
|
||||
} finally {
|
||||
setOperatingBotId(null);
|
||||
setControlStateByBot((prev) => {
|
||||
const next = { ...prev };
|
||||
delete next[id];
|
||||
return next;
|
||||
});
|
||||
clearControlState(id);
|
||||
}
|
||||
}, [confirm, ensureControlVisible, notify, refresh, t, updateBotStatus]);
|
||||
}, [clearControlState, confirm, ensureControlVisible, notify, refresh, setControlState, t, updateBotStatus]);
|
||||
|
||||
const setBotEnabled = useCallback(async (id: string, enabled: boolean) => {
|
||||
setOperatingBotId(id);
|
||||
setControlStateByBot((prev) => ({ ...prev, [id]: enabled ? 'enabling' : 'disabling' }));
|
||||
setControlState(id, enabled ? 'enabling' : 'disabling');
|
||||
try {
|
||||
if (enabled) {
|
||||
await axios.post(`${APP_ENDPOINTS.apiBase}/bots/${id}/enable`);
|
||||
|
|
@ -351,13 +351,9 @@ export function useDashboardRuntimeControl({
|
|||
notify(error?.response?.data?.detail || (enabled ? t.enableFail : t.disableFail), { tone: 'error' });
|
||||
} finally {
|
||||
setOperatingBotId(null);
|
||||
setControlStateByBot((prev) => {
|
||||
const next = { ...prev };
|
||||
delete next[id];
|
||||
return next;
|
||||
});
|
||||
clearControlState(id);
|
||||
}
|
||||
}, [confirm, notify, refresh, t]);
|
||||
}, [clearControlState, confirm, notify, refresh, setControlState, t]);
|
||||
|
||||
useEffect(() => {
|
||||
void loadImageOptions();
|
||||
|
|
|
|||
|
|
@ -60,59 +60,80 @@
|
|||
gap: 10px;
|
||||
padding: 14px 14px 14px 18px;
|
||||
border-radius: 16px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
background: rgba(8, 13, 22, 0.72);
|
||||
border: 1px solid var(--line);
|
||||
background: linear-gradient(145deg, color-mix(in oklab, var(--panel-soft) 86%, var(--panel) 14%), color-mix(in oklab, var(--panel-soft) 94%, transparent 6%));
|
||||
cursor: pointer;
|
||||
transition: transform 0.18s ease, border-color 0.18s ease, box-shadow 0.18s ease, background 0.18s ease;
|
||||
transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.platform-bot-card:hover,
|
||||
.platform-bot-card.is-selected {
|
||||
.platform-bot-card:hover {
|
||||
border-color: color-mix(in oklab, var(--brand) 58%, var(--line) 42%);
|
||||
box-shadow: 0 8px 24px color-mix(in oklab, var(--brand) 12%, transparent);
|
||||
transform: translateY(-1px);
|
||||
border-color: rgba(97, 174, 255, 0.45);
|
||||
box-shadow: 0 16px 40px rgba(8, 25, 60, 0.18);
|
||||
}
|
||||
|
||||
.platform-bot-card.is-selected {
|
||||
border-color: var(--brand);
|
||||
background: color-mix(in oklab, var(--brand) 4%, var(--panel-soft));
|
||||
box-shadow:
|
||||
0 0 0 2px color-mix(in oklab, var(--brand) 70%, transparent),
|
||||
0 16px 30px color-mix(in oklab, var(--brand) 28%, transparent),
|
||||
inset 0 0 0 1px color-mix(in oklab, var(--brand) 84%, transparent);
|
||||
0 0 0 2px color-mix(in oklab, var(--brand) 30%, transparent),
|
||||
0 12px 28px color-mix(in oklab, var(--brand) 18%, transparent);
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.platform-bot-card.is-selected::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
border-radius: 16px;
|
||||
border: 2px solid var(--brand);
|
||||
pointer-events: none;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.platform-bot-card.state-running {
|
||||
background: linear-gradient(145deg, color-mix(in oklab, var(--ok) 14%, var(--panel-soft) 86%), color-mix(in oklab, var(--ok) 8%, var(--panel) 92%));
|
||||
background: linear-gradient(145deg, color-mix(in oklab, var(--ok) 8%, var(--panel-soft) 92%), color-mix(in oklab, var(--ok) 4%, var(--panel) 96%));
|
||||
}
|
||||
|
||||
.platform-bot-card.state-running.is-selected {
|
||||
background: linear-gradient(145deg, color-mix(in oklab, var(--ok) 12%, var(--brand) 4%), color-mix(in oklab, var(--ok) 6%, var(--panel) 94%));
|
||||
}
|
||||
|
||||
.platform-bot-card.state-stopped {
|
||||
background: linear-gradient(145deg, color-mix(in oklab, #b79aa2 14%, var(--panel-soft) 86%), color-mix(in oklab, #b79aa2 7%, var(--panel) 93%));
|
||||
background: linear-gradient(145deg, color-mix(in oklab, var(--err) 8%, var(--panel-soft) 92%), color-mix(in oklab, var(--err) 4%, var(--panel) 96%));
|
||||
}
|
||||
|
||||
.platform-bot-card.state-disabled {
|
||||
background: linear-gradient(145deg, color-mix(in oklab, #9ca3b5 14%, var(--panel-soft) 86%), color-mix(in oklab, #9ca3b5 7%, var(--panel) 93%));
|
||||
opacity: 0.72;
|
||||
filter: grayscale(0.2);
|
||||
background: var(--panel-soft);
|
||||
}
|
||||
|
||||
.platform-bot-strip {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 8px;
|
||||
bottom: 8px;
|
||||
width: 3px;
|
||||
border-radius: 999px;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 4px;
|
||||
background: color-mix(in oklab, var(--line) 80%, transparent);
|
||||
opacity: 0.7;
|
||||
opacity: 0.8;
|
||||
transition: all 0.25s ease;
|
||||
}
|
||||
|
||||
.platform-bot-strip.is-running {
|
||||
background: linear-gradient(180deg, color-mix(in oklab, var(--ok) 80%, #9be8c6 20%), color-mix(in oklab, var(--ok) 54%, transparent));
|
||||
background: var(--ok);
|
||||
box-shadow: 2px 0 8px color-mix(in oklab, var(--ok) 40%, transparent);
|
||||
}
|
||||
|
||||
.platform-bot-strip.is-stopped {
|
||||
background: linear-gradient(180deg, color-mix(in oklab, var(--err) 74%, #e7b1ba 26%), color-mix(in oklab, var(--err) 54%, transparent));
|
||||
background: var(--err);
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.platform-bot-strip.is-disabled {
|
||||
background: linear-gradient(180deg, color-mix(in oklab, #9ca3b5 82%, #d4d9e2 18%), color-mix(in oklab, #9ca3b5 52%, transparent));
|
||||
background: #9ca3b5;
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
.platform-bot-top {
|
||||
|
|
@ -245,15 +266,66 @@
|
|||
}
|
||||
|
||||
.platform-bot-action-start {
|
||||
background: color-mix(in oklab, var(--ok) 24%, var(--panel-soft) 76%);
|
||||
border-color: color-mix(in oklab, var(--ok) 52%, var(--line) 48%);
|
||||
color: color-mix(in oklab, var(--text) 76%, white 24%);
|
||||
background: color-mix(in oklab, var(--ok) 38%, var(--panel-soft) 62%);
|
||||
border-color: color-mix(in oklab, var(--ok) 60%, var(--line) 40%);
|
||||
color: color-mix(in oklab, var(--text) 82%, white 18%);
|
||||
}
|
||||
|
||||
.platform-bot-action-stop {
|
||||
background: color-mix(in oklab, #f5af48 30%, var(--panel-soft) 70%);
|
||||
border-color: color-mix(in oklab, #f5af48 58%, var(--line) 42%);
|
||||
color: #5e3b00;
|
||||
background: color-mix(in oklab, #f5af48 45%, var(--panel-soft) 55%);
|
||||
border-color: color-mix(in oklab, #f5af48 68%, var(--line) 32%);
|
||||
color: #4a2d00;
|
||||
}
|
||||
|
||||
.platform-bot-icon-btn:disabled {
|
||||
opacity: 1;
|
||||
cursor: not-allowed;
|
||||
filter: saturate(1.1);
|
||||
}
|
||||
|
||||
.ops-control-pending {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.ops-control-dots {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 3px;
|
||||
}
|
||||
|
||||
.ops-control-dots i {
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
border-radius: 50%;
|
||||
display: block;
|
||||
background: #ffffff;
|
||||
box-shadow: 0 0 2px rgba(0, 0, 0, 0.3);
|
||||
opacity: 1;
|
||||
animation: ops-control-dot 1s infinite ease-in-out;
|
||||
}
|
||||
|
||||
.ops-control-dots i:nth-child(2) {
|
||||
animation-delay: 0.15s;
|
||||
}
|
||||
|
||||
.ops-control-dots i:nth-child(3) {
|
||||
animation-delay: 0.3s;
|
||||
}
|
||||
|
||||
@keyframes ops-control-dot {
|
||||
0%, 100% {
|
||||
transform: scale(0.8);
|
||||
opacity: 0.4;
|
||||
}
|
||||
50% {
|
||||
transform: scale(1.2);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.platform-bot-lock {
|
||||
|
|
|
|||
|
|
@ -1,166 +0,0 @@
|
|||
import { useState } from 'react';
|
||||
import { PlatformSettingsModal } from './components/PlatformSettingsModal';
|
||||
import { TemplateManagerModal } from './components/TemplateManagerModal';
|
||||
import { PlatformBotListSection } from './components/PlatformBotListSection';
|
||||
import { PlatformBotOverviewSection } from './components/PlatformBotOverviewSection';
|
||||
import {
|
||||
PlatformCompactBotSheet,
|
||||
PlatformImageFactoryModal,
|
||||
PlatformLastActionModal,
|
||||
PlatformResourceMonitorModal,
|
||||
} from './components/PlatformDashboardModals';
|
||||
import { PlatformManagementSection } from './components/PlatformManagementSection';
|
||||
import { PlatformSummaryCards } from './components/PlatformSummaryCards';
|
||||
import { PlatformUsageAnalyticsSection } from './components/PlatformUsageAnalyticsSection';
|
||||
import { usePlatformDashboard } from './hooks/usePlatformDashboard';
|
||||
import { CreateBotWizardModal } from '../onboarding/CreateBotWizardModal';
|
||||
import { navigateToDashboardSkills } from '../../utils/appRoute';
|
||||
import './PlatformDashboardPage.css';
|
||||
|
||||
interface PlatformDashboardPageProps {
|
||||
compactMode: boolean;
|
||||
}
|
||||
|
||||
export function PlatformDashboardPage({ compactMode }: PlatformDashboardPageProps) {
|
||||
const dashboard = usePlatformDashboard({ compactMode });
|
||||
const [showCreateBotModal, setShowCreateBotModal] = useState(false);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={`platform-grid ${compactMode ? 'is-compact' : ''}`}>
|
||||
<PlatformBotListSection
|
||||
botListPage={dashboard.botListPage}
|
||||
botListPageCount={dashboard.botListPageCount}
|
||||
filteredBots={dashboard.filteredBots}
|
||||
isZh={dashboard.isZh}
|
||||
loading={dashboard.loading}
|
||||
operatingBotId={dashboard.operatingBotId}
|
||||
pagedBots={dashboard.pagedBots}
|
||||
pageSizeReady={dashboard.pageSizeReady}
|
||||
search={dashboard.search}
|
||||
selectedBotId={dashboard.selectedBotId}
|
||||
onBotListPageChange={dashboard.setBotListPage}
|
||||
onOpenCreateBot={() => setShowCreateBotModal(true)}
|
||||
onRefresh={dashboard.refreshAll}
|
||||
onSearchChange={dashboard.setSearch}
|
||||
onSelectBot={dashboard.handleSelectBot}
|
||||
onSetBotEnabled={dashboard.setBotEnabled}
|
||||
onToggleBot={dashboard.toggleBot}
|
||||
/>
|
||||
|
||||
{!compactMode ? (
|
||||
<section className="platform-main">
|
||||
<PlatformSummaryCards
|
||||
isZh={dashboard.isZh}
|
||||
overview={dashboard.overview}
|
||||
overviewBots={dashboard.overviewBots}
|
||||
overviewImages={dashboard.overviewImages}
|
||||
overviewResources={dashboard.overviewResources}
|
||||
/>
|
||||
|
||||
<div className="platform-main-grid">
|
||||
<PlatformBotOverviewSection
|
||||
isZh={dashboard.isZh}
|
||||
lastActionPreview={dashboard.lastActionPreview}
|
||||
operatingBotId={dashboard.operatingBotId}
|
||||
selectedBotInfo={dashboard.selectedBotInfo}
|
||||
selectedBotUsageSummary={dashboard.selectedBotUsageSummary}
|
||||
onClearDashboardDirectSession={dashboard.clearDashboardDirectSession}
|
||||
onOpenBotPanel={dashboard.openBotPanel}
|
||||
onOpenLastAction={() => dashboard.setShowBotLastActionModal(true)}
|
||||
onOpenResourceMonitor={dashboard.openResourceMonitor}
|
||||
onRemoveBot={dashboard.removeBot}
|
||||
/>
|
||||
|
||||
<PlatformManagementSection
|
||||
isZh={dashboard.isZh}
|
||||
onOpenImageFactory={() => dashboard.setShowImageFactory(true)}
|
||||
onOpenPlatformSettings={() => dashboard.setShowPlatformSettings(true)}
|
||||
onOpenSkillMarketplace={navigateToDashboardSkills}
|
||||
onOpenTemplateManager={() => dashboard.setShowTemplateManager(true)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<PlatformUsageAnalyticsSection
|
||||
isZh={dashboard.isZh}
|
||||
usageAnalytics={dashboard.usageAnalytics}
|
||||
usageAnalyticsMax={dashboard.usageAnalyticsMax}
|
||||
usageAnalyticsSeries={dashboard.usageAnalyticsSeries}
|
||||
usageAnalyticsTicks={dashboard.usageAnalyticsTicks}
|
||||
usageLoading={dashboard.usageLoading}
|
||||
usageSummary={dashboard.usageSummary}
|
||||
/>
|
||||
</section>
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
<PlatformCompactBotSheet
|
||||
open={compactMode && dashboard.compactSheetMounted && Boolean(dashboard.selectedBotInfo)}
|
||||
closing={dashboard.compactSheetClosing}
|
||||
isZh={dashboard.isZh}
|
||||
onClose={dashboard.closeCompactBotSheet}
|
||||
>
|
||||
<PlatformBotOverviewSection
|
||||
compactSheet
|
||||
isZh={dashboard.isZh}
|
||||
lastActionPreview={dashboard.lastActionPreview}
|
||||
operatingBotId={dashboard.operatingBotId}
|
||||
selectedBotInfo={dashboard.selectedBotInfo}
|
||||
selectedBotUsageSummary={dashboard.selectedBotUsageSummary}
|
||||
onClearDashboardDirectSession={dashboard.clearDashboardDirectSession}
|
||||
onOpenBotPanel={dashboard.openBotPanel}
|
||||
onOpenLastAction={() => dashboard.setShowBotLastActionModal(true)}
|
||||
onOpenResourceMonitor={dashboard.openResourceMonitor}
|
||||
onRemoveBot={dashboard.removeBot}
|
||||
/>
|
||||
</PlatformCompactBotSheet>
|
||||
|
||||
<PlatformImageFactoryModal
|
||||
isZh={dashboard.isZh}
|
||||
open={dashboard.showImageFactory}
|
||||
onClose={() => dashboard.setShowImageFactory(false)}
|
||||
/>
|
||||
|
||||
<CreateBotWizardModal
|
||||
open={showCreateBotModal}
|
||||
onClose={() => setShowCreateBotModal(false)}
|
||||
onCreated={() => {
|
||||
void dashboard.refreshAll();
|
||||
}}
|
||||
/>
|
||||
|
||||
<TemplateManagerModal
|
||||
isZh={dashboard.isZh}
|
||||
open={dashboard.showTemplateManager}
|
||||
onClose={() => dashboard.setShowTemplateManager(false)}
|
||||
/>
|
||||
|
||||
<PlatformSettingsModal
|
||||
isZh={dashboard.isZh}
|
||||
open={dashboard.showPlatformSettings}
|
||||
onClose={() => dashboard.setShowPlatformSettings(false)}
|
||||
onSaved={dashboard.handlePlatformSettingsSaved}
|
||||
/>
|
||||
|
||||
<PlatformLastActionModal
|
||||
botName={dashboard.selectedBotInfo?.name}
|
||||
isZh={dashboard.isZh}
|
||||
lastAction={dashboard.selectedBotInfo?.last_action}
|
||||
open={dashboard.showBotLastActionModal && Boolean(dashboard.selectedBotInfo)}
|
||||
onClose={() => dashboard.setShowBotLastActionModal(false)}
|
||||
/>
|
||||
|
||||
<PlatformResourceMonitorModal
|
||||
isZh={dashboard.isZh}
|
||||
open={dashboard.showResourceModal}
|
||||
resourceBot={dashboard.resourceBot}
|
||||
resourceBotId={dashboard.resourceBotId}
|
||||
resourceError={dashboard.resourceError}
|
||||
resourceLoading={dashboard.resourceLoading}
|
||||
resourceSnapshot={dashboard.resourceSnapshot}
|
||||
onClose={dashboard.closeResourceModal}
|
||||
onRefresh={dashboard.loadResourceSnapshot}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
@ -117,7 +117,15 @@ export function PlatformBotListSection({
|
|||
tooltip={running ? (isZh ? '停止' : 'Stop') : (isZh ? '启动' : 'Start')}
|
||||
aria-label={running ? (isZh ? '停止' : 'Stop') : (isZh ? '启动' : 'Start')}
|
||||
>
|
||||
{running ? <Square size={14} /> : <Power size={14} />}
|
||||
{operatingBotId === bot.id ? (
|
||||
<span className="ops-control-pending">
|
||||
<span className="ops-control-dots" aria-hidden="true">
|
||||
<i />
|
||||
<i />
|
||||
<i />
|
||||
</span>
|
||||
</span>
|
||||
) : running ? <Square size={14} /> : <Power size={14} />}
|
||||
</LucentIconButton>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
1147
frontend/yarn.lock
1147
frontend/yarn.lock
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue