feat: busy container overlays for lifecycle actions
Add a reusable LoadingOverlay component that dims and disables the container owning an in-flight action, with a spinning indicator and label. Apply it to: - SessionCard (when actionBusyId matches) - InstanceList cards (per busyInstanceId with action-specific labels) - CreateSessionForm (while submitting) - ToolStarter (while starting) Also add .icon-spin animation and position:relative to the relevant containers. Quality gates: npm run typecheck, npm run lint, npm test -- --run (87 passed).
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { Icon } from "../../icon";
|
||||
import { LoadingOverlay } from "../../loading-overlay";
|
||||
import type { ToolInstance } from "../../../api/sessions";
|
||||
import {
|
||||
deleteInstance,
|
||||
@@ -60,6 +61,7 @@ export const InstanceList = ({
|
||||
|
||||
// Per-instance busy state for actions
|
||||
const [busyInstanceId, setBusyInstanceId] = useState<string | null>(null);
|
||||
const [busyLabel, setBusyLabel] = useState("Working...");
|
||||
|
||||
const loadInstances = useCallback(async () => {
|
||||
setLoading(true);
|
||||
@@ -135,6 +137,7 @@ export const InstanceList = ({
|
||||
sshKeyIds?: string[],
|
||||
) => {
|
||||
setBusyInstanceId(instanceId);
|
||||
setBusyLabel("Starting...");
|
||||
try {
|
||||
await startInstance(
|
||||
projectId,
|
||||
@@ -156,6 +159,7 @@ export const InstanceList = ({
|
||||
|
||||
const handleStop = async (instanceId: string) => {
|
||||
setBusyInstanceId(instanceId);
|
||||
setBusyLabel("Stopping...");
|
||||
try {
|
||||
await stopInstance(projectId, repoId, instanceId);
|
||||
setStopConfirmId(null);
|
||||
@@ -173,6 +177,7 @@ export const InstanceList = ({
|
||||
sshKeyIds?: string[],
|
||||
) => {
|
||||
setBusyInstanceId(instanceId);
|
||||
setBusyLabel("Restarting...");
|
||||
try {
|
||||
await restartInstance(
|
||||
projectId,
|
||||
@@ -195,6 +200,7 @@ export const InstanceList = ({
|
||||
const handleDelete = async (instanceId: string) => {
|
||||
if (!confirm("Are you sure you want to delete this instance?")) return;
|
||||
setBusyInstanceId(instanceId);
|
||||
setBusyLabel("Deleting...");
|
||||
try {
|
||||
await deleteInstance(projectId, repoId, instanceId);
|
||||
// Update state immediately instead of reloading
|
||||
@@ -250,6 +256,10 @@ export const InstanceList = ({
|
||||
<div className="instance-grid">
|
||||
{instances.map((instance) => (
|
||||
<div key={instance.id} className="instance-card">
|
||||
<LoadingOverlay
|
||||
visible={busyInstanceId === instance.id}
|
||||
label={busyLabel}
|
||||
/>
|
||||
<div className="instance-info">
|
||||
<div className="instance-name">{instance.display_name}</div>
|
||||
<div className="instance-meta">
|
||||
|
||||
Reference in New Issue
Block a user