-
-
没有 session。发送前必须显式新建或选择 session。
+
+
+
+
+ 没有 session。发送前必须显式新建或选择 session。
+
- {{ workbench.loading ? '加载中' : activeTab ? `当前 ${activeTab.sessionId || activeTab.conversationId}` : '等待 workspace' }}
- trace {{ activeTab.lastTraceId }}
+ {{ showSessionListLoading ? '加载中' : activeTab ? `当前 ${activeTab.sessionId || activeTab.conversationId}` : '等待 workspace' }}
+ trace {{ activeTab.lastTraceId }}
已复制
-
-
+
+
{
const gatewayShellTimeoutMs = ref(readNumber("hwlab.workbench.gatewayShellTimeoutMs.v1", DEFAULT_GATEWAY_TIMEOUT_MS));
const live = ref(null);
const loading = ref(false);
+ const conversationsReady = ref(false);
const switchingConversationId = ref(null);
const chatPending = ref(false);
const error = ref(null);
@@ -35,6 +36,7 @@ export const useWorkbenchStore = defineStore("workbench", () => {
const selectedThreadId = computed(() => firstNonEmptyString(workspace.value?.workspace?.threadId, activeConversation.value?.threadId));
const activeConversation = computed(() => visibleConversations.value.find((item) => item.conversationId === activeConversationId.value) ?? null);
const sessionTabs = computed(() => sortSessionTabs(visibleConversations.value, activeConversationId.value));
+ const sessionListLoading = computed(() => shouldShowSessionListLoading({ loading: loading.value, conversationsReady: conversationsReady.value }));
const activeProjectId = computed(() => workspaceProjectId(workspace.value, projectId.value));
const composer = computed(() => resolveComposerState({ workspace: workspace.value, messages: messages.value, conversations: visibleConversations.value, activeConversationId: activeConversationId.value, chatPending: chatPending.value, currentRequest: currentRequest.value }));
@@ -45,10 +47,12 @@ export const useWorkbenchStore = defineStore("workbench", () => {
async function hydrate(): Promise {
const requestEpoch = workspaceSelectionEpoch.value;
+ conversationsReady.value = conversations.value.length > 0;
loading.value = true;
error.value = null;
const [workspaceResult, conversationsResult] = await Promise.all([api.workbench.workspace(projectId.value), api.workbench.conversations(projectId.value)]);
loading.value = false;
+ conversationsReady.value = true;
if (!workspaceResult.ok) {
error.value = workspaceResult.error ?? "workspace unavailable";
return;
@@ -158,6 +162,7 @@ export const useWorkbenchStore = defineStore("workbench", () => {
async function refreshConversations(): Promise {
const response = await api.workbench.conversations(activeProjectId.value);
+ conversationsReady.value = true;
if (response.ok) conversations.value = response.data?.conversations ?? [];
}
@@ -468,7 +473,7 @@ export const useWorkbenchStore = defineStore("workbench", () => {
return true;
}
- return { projectId, workspace, conversations, messages, providerProfile, providerOptions, recentDrafts, codeAgentTimeoutMs, gatewayShellTimeoutMs, live, loading, chatPending, error, activeConversationId, selectedSessionId, selectedThreadId, sessionTabs, composer, hydrate, refreshLive, createSession, selectConversation, selectConversationById, deleteCurrentSession, refreshConversations, submitMessage, cancelAgentMessage, cancelRunningTrace, retryAgentMessage, replayAgentTrace, setProviderProfile, refreshProviderOptions, pickDraft, clearRecentDrafts, clearConversation, recordActivity };
+ return { projectId, workspace, conversations, messages, providerProfile, providerOptions, recentDrafts, codeAgentTimeoutMs, gatewayShellTimeoutMs, live, loading, sessionListLoading, chatPending, error, activeConversationId, selectedSessionId, selectedThreadId, sessionTabs, composer, hydrate, refreshLive, createSession, selectConversation, selectConversationById, deleteCurrentSession, refreshConversations, submitMessage, cancelAgentMessage, cancelRunningTrace, retryAgentMessage, replayAgentTrace, setProviderProfile, refreshProviderOptions, pickDraft, clearRecentDrafts, clearConversation, recordActivity };
});
function optimisticWorkspaceSelection(current: WorkspaceRecord, conversation: ConversationRecord, projectId: string): WorkspaceRecord {
diff --git a/web/hwlab-cloud-web/src/styles/workbench.css b/web/hwlab-cloud-web/src/styles/workbench.css
index b2184184..b308af13 100644
--- a/web/hwlab-cloud-web/src/styles/workbench.css
+++ b/web/hwlab-cloud-web/src/styles/workbench.css
@@ -594,6 +594,16 @@
overflow: auto;
}
+.session-list[data-loading="true"] {
+ align-content: center;
+ justify-items: center;
+ overflow: hidden;
+}
+
+.session-list-loading {
+ min-height: 120px;
+}
+
.conversation-panel {
display: flex;
min-height: 0;