diff --git a/.playwright-mcp/both-actionbars-test.png b/.playwright-mcp/both-actionbars-test.png
new file mode 100644
index 0000000..bde2ca1
Binary files /dev/null and b/.playwright-mcp/both-actionbars-test.png differ
diff --git a/.playwright-mcp/editor-actionbar-test.png b/.playwright-mcp/editor-actionbar-test.png
new file mode 100644
index 0000000..9aa2337
Binary files /dev/null and b/.playwright-mcp/editor-actionbar-test.png differ
diff --git a/.playwright-mcp/editor-actionbar-visible.png b/.playwright-mcp/editor-actionbar-visible.png
new file mode 100644
index 0000000..2da40bf
Binary files /dev/null and b/.playwright-mcp/editor-actionbar-visible.png differ
diff --git a/.playwright-mcp/editor-actionbar-working.png b/.playwright-mcp/editor-actionbar-working.png
new file mode 100644
index 0000000..2da40bf
Binary files /dev/null and b/.playwright-mcp/editor-actionbar-working.png differ
diff --git a/.playwright-mcp/terminal-actionbar-resize-issue.png b/.playwright-mcp/terminal-actionbar-resize-issue.png
new file mode 100644
index 0000000..a8bf7b1
Binary files /dev/null and b/.playwright-mcp/terminal-actionbar-resize-issue.png differ
diff --git a/.playwright-mcp/terminal-resize-fix-verification.png b/.playwright-mcp/terminal-resize-fix-verification.png
new file mode 100644
index 0000000..d31f57c
Binary files /dev/null and b/.playwright-mcp/terminal-resize-fix-verification.png differ
diff --git a/.playwright-mcp/terminal-with-actionbar-fix.png b/.playwright-mcp/terminal-with-actionbar-fix.png
new file mode 100644
index 0000000..08632fc
Binary files /dev/null and b/.playwright-mcp/terminal-with-actionbar-fix.png differ
diff --git a/.playwright-mcp/workspace-actionbar-layout.png b/.playwright-mcp/workspace-actionbar-layout.png
new file mode 100644
index 0000000..ff5a5dd
Binary files /dev/null and b/.playwright-mcp/workspace-actionbar-layout.png differ
diff --git a/.playwright-mcp/workspace-file-open.png b/.playwright-mcp/workspace-file-open.png
new file mode 100644
index 0000000..2da40bf
Binary files /dev/null and b/.playwright-mcp/workspace-file-open.png differ
diff --git a/ts_web/elements/00group-workspace/dees-workspace-terminal/dees-workspace-terminal.ts b/ts_web/elements/00group-workspace/dees-workspace-terminal/dees-workspace-terminal.ts
index caf1d46..5637997 100644
--- a/ts_web/elements/00group-workspace/dees-workspace-terminal/dees-workspace-terminal.ts
+++ b/ts_web/elements/00group-workspace/dees-workspace-terminal/dees-workspace-terminal.ts
@@ -16,6 +16,8 @@ import { themeDefaultStyles } from '../../00theme.js';
import type { IExecutionEnvironment } from '../../00group-runtime/index.js';
import { WebContainerEnvironment } from '../../00group-runtime/index.js';
import '../../dees-icon/dees-icon.js';
+import '../../dees-actionbar/dees-actionbar.js';
+import type { DeesActionbar } from '../../dees-actionbar/dees-actionbar.js';
import { TerminalTabManager } from './terminal-tab-manager.js';
import type {
ITerminalTab,
@@ -79,6 +81,9 @@ export class DeesWorkspaceTerminal extends DeesElement {
private terminalThemeSubscription: any = null;
private isBright: boolean = false;
+ // Actionbar reference for terminal-context notifications
+ private terminalActionbar: DeesActionbar | null = null;
+
/**
* Promise that resolves when the environment is ready.
* @deprecated Use executionEnvironment directly
@@ -120,17 +125,21 @@ export class DeesWorkspaceTerminal extends DeesElement {
.terminal-content {
flex: 1;
- position: relative;
+ display: flex;
+ flex-direction: column;
overflow: hidden;
background: ${cssManager.bdTheme('#ffffff', '#000000')};
}
#active-terminal-container {
- position: absolute;
- top: 20px;
- left: 20px;
- right: 20px;
- bottom: 20px;
+ flex: 1;
+ position: relative;
+ min-height: 0;
+ margin: 20px;
+ }
+
+ .terminal-content dees-actionbar {
+ flex-shrink: 0;
}
/* Tab bar on the right side */
@@ -426,6 +435,7 @@ export class DeesWorkspaceTerminal extends DeesElement {
No terminal open
`}
+
@@ -491,11 +501,15 @@ export class DeesWorkspaceTerminal extends DeesElement {
async connectedCallback(): Promise {
await super.connectedCallback();
- this.resizeObserver.observe(this);
+ // ResizeObserver is set up in attachTerminalToContainer when the container exists
}
async disconnectedCallback(): Promise {
- this.resizeObserver.unobserve(this);
+ // Unobserve the terminal container
+ const container = this.shadowRoot?.getElementById('active-terminal-container');
+ if (container) {
+ this.resizeObserver.unobserve(container);
+ }
if (this.terminalThemeSubscription) {
this.terminalThemeSubscription.unsubscribe();
this.terminalThemeSubscription = null;
@@ -558,6 +572,10 @@ export class DeesWorkspaceTerminal extends DeesElement {
const container = this.shadowRoot?.getElementById('active-terminal-container');
if (!container) return;
+ // Observe container for resize (handles actionbar appearing/disappearing)
+ // ResizeObserver.observe() is idempotent - safe to call multiple times
+ this.resizeObserver.observe(container);
+
// Clear container
container.innerHTML = '';
@@ -656,6 +674,36 @@ export class DeesWorkspaceTerminal extends DeesElement {
detail: { tabId, exitCode },
})
);
+
+ // Show actionbar to offer closing the tab (only if tab is closeable)
+ if (tab.closeable) {
+ this.showExitedTabActionbar(tabId, tab.label, exitCode);
+ }
+ }
+
+ /**
+ * Show actionbar offering to close an exited tab
+ */
+ private async showExitedTabActionbar(tabId: string, tabLabel: string, exitCode: number): Promise {
+ const isSuccess = exitCode === 0;
+ const result = await this.showActionbar({
+ message: isSuccess
+ ? `"${tabLabel}" completed. Close tab?`
+ : `"${tabLabel}" exited (code ${exitCode}). Close tab?`,
+ type: isSuccess ? 'info' : 'warning',
+ icon: isSuccess ? 'lucide:checkCircle' : 'lucide:alertTriangle',
+ actions: [
+ { id: 'close', label: 'Close Tab', primary: true },
+ { id: 'keep', label: 'Keep Open' },
+ ],
+ timeout: { duration: 10000, defaultActionId: 'close' },
+ dismissible: true,
+ });
+
+ // Close tab if user clicked "Close Tab" or timeout triggered auto-close
+ if (result.actionId === 'close') {
+ this.closeTab(tabId);
+ }
}
// ========== Public API ==========
@@ -816,6 +864,19 @@ export class DeesWorkspaceTerminal extends DeesElement {
return true;
}
+ /**
+ * Show an actionbar notification in the terminal panel context.
+ * Use this for terminal-related decisions (e.g., retry failed process, kill process, etc.)
+ */
+ public async showActionbar(
+ options: Parameters[0]
+ ): Promise> {
+ if (!this.terminalActionbar) {
+ this.terminalActionbar = this.shadowRoot?.querySelector('dees-actionbar') as DeesActionbar;
+ }
+ return this.terminalActionbar?.show(options);
+ }
+
// ========== Utility Methods ==========
public async waitForPrompt(term: Terminal, prompt: string): Promise {
diff --git a/ts_web/elements/00group-workspace/dees-workspace/dees-workspace.ts b/ts_web/elements/00group-workspace/dees-workspace/dees-workspace.ts
index c6a255b..296d6ee 100644
--- a/ts_web/elements/00group-workspace/dees-workspace/dees-workspace.ts
+++ b/ts_web/elements/00group-workspace/dees-workspace/dees-workspace.ts
@@ -957,6 +957,7 @@ testSmartPromise();
>
`}
+
@@ -1021,9 +1022,6 @@ testSmartPromise();
.executionEnvironment=${this.executionEnvironment}
@run-process=${this.handleRunProcess}
>
-
-
-
`;
}
@@ -1056,9 +1054,6 @@ testSmartPromise();
this.currentFileTreeWidth = this.fileTreeWidth;
this.currentTerminalHeight = this.terminalHeight;
- // Get actionbar reference for file change notifications
- this.actionbarElement = this.shadowRoot?.querySelector('dees-actionbar') as DeesActionbar;
-
if (this.executionEnvironment) {
await this.initializeWorkspace();
}
@@ -1068,6 +1063,11 @@ testSmartPromise();
if (changedProperties.has('executionEnvironment') && this.executionEnvironment) {
await this.initializeWorkspace();
}
+
+ // Capture actionbar reference when it becomes available (after initialization completes)
+ if (!this.actionbarElement) {
+ this.actionbarElement = this.shadowRoot?.querySelector('.editor-panel dees-actionbar') as DeesActionbar;
+ }
}
private async initializeWorkspace() {
diff --git a/ts_web/elements/dees-actionbar/dees-actionbar.ts b/ts_web/elements/dees-actionbar/dees-actionbar.ts
index 29e29d3..fa55ccb 100644
--- a/ts_web/elements/dees-actionbar/dees-actionbar.ts
+++ b/ts_web/elements/dees-actionbar/dees-actionbar.ts
@@ -130,12 +130,12 @@ export class DeesActionbar extends DeesElement {
:host {
display: block;
overflow: hidden;
- height: 0;
- transition: height 0.2s ease-out;
+ max-height: 0;
+ transition: max-height 0.2s ease-out;
}
:host(.visible) {
- height: auto;
+ max-height: 100px; /* Enough for actionbar content */
}
.actionbar-item {