This commit is contained in:
2026-01-01 18:33:05 +00:00
parent a218b6a0a1
commit bbb57f1b9f
12 changed files with 78 additions and 17 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

View File

@@ -16,6 +16,8 @@ import { themeDefaultStyles } from '../../00theme.js';
import type { IExecutionEnvironment } from '../../00group-runtime/index.js'; import type { IExecutionEnvironment } from '../../00group-runtime/index.js';
import { WebContainerEnvironment } from '../../00group-runtime/index.js'; import { WebContainerEnvironment } from '../../00group-runtime/index.js';
import '../../dees-icon/dees-icon.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 { TerminalTabManager } from './terminal-tab-manager.js';
import type { import type {
ITerminalTab, ITerminalTab,
@@ -79,6 +81,9 @@ export class DeesWorkspaceTerminal extends DeesElement {
private terminalThemeSubscription: any = null; private terminalThemeSubscription: any = null;
private isBright: boolean = false; private isBright: boolean = false;
// Actionbar reference for terminal-context notifications
private terminalActionbar: DeesActionbar | null = null;
/** /**
* Promise that resolves when the environment is ready. * Promise that resolves when the environment is ready.
* @deprecated Use executionEnvironment directly * @deprecated Use executionEnvironment directly
@@ -120,17 +125,21 @@ export class DeesWorkspaceTerminal extends DeesElement {
.terminal-content { .terminal-content {
flex: 1; flex: 1;
position: relative; display: flex;
flex-direction: column;
overflow: hidden; overflow: hidden;
background: ${cssManager.bdTheme('#ffffff', '#000000')}; background: ${cssManager.bdTheme('#ffffff', '#000000')};
} }
#active-terminal-container { #active-terminal-container {
position: absolute; flex: 1;
top: 20px; position: relative;
left: 20px; min-height: 0;
right: 20px; margin: 20px;
bottom: 20px; }
.terminal-content dees-actionbar {
flex-shrink: 0;
} }
/* Tab bar on the right side */ /* Tab bar on the right side */
@@ -426,6 +435,7 @@ export class DeesWorkspaceTerminal extends DeesElement {
<span>No terminal open</span> <span>No terminal open</span>
</div> </div>
`} `}
<dees-actionbar></dees-actionbar>
</div> </div>
<!-- Vertical tab bar on the right --> <!-- Vertical tab bar on the right -->
@@ -491,11 +501,15 @@ export class DeesWorkspaceTerminal extends DeesElement {
async connectedCallback(): Promise<void> { async connectedCallback(): Promise<void> {
await super.connectedCallback(); await super.connectedCallback();
this.resizeObserver.observe(this); // ResizeObserver is set up in attachTerminalToContainer when the container exists
} }
async disconnectedCallback(): Promise<void> { async disconnectedCallback(): Promise<void> {
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) { if (this.terminalThemeSubscription) {
this.terminalThemeSubscription.unsubscribe(); this.terminalThemeSubscription.unsubscribe();
this.terminalThemeSubscription = null; this.terminalThemeSubscription = null;
@@ -558,6 +572,10 @@ export class DeesWorkspaceTerminal extends DeesElement {
const container = this.shadowRoot?.getElementById('active-terminal-container'); const container = this.shadowRoot?.getElementById('active-terminal-container');
if (!container) return; 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 // Clear container
container.innerHTML = ''; container.innerHTML = '';
@@ -656,6 +674,36 @@ export class DeesWorkspaceTerminal extends DeesElement {
detail: { tabId, exitCode }, 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<void> {
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 ========== // ========== Public API ==========
@@ -816,6 +864,19 @@ export class DeesWorkspaceTerminal extends DeesElement {
return true; 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<DeesActionbar['show']>[0]
): Promise<ReturnType<DeesActionbar['show']>> {
if (!this.terminalActionbar) {
this.terminalActionbar = this.shadowRoot?.querySelector('dees-actionbar') as DeesActionbar;
}
return this.terminalActionbar?.show(options);
}
// ========== Utility Methods ========== // ========== Utility Methods ==========
public async waitForPrompt(term: Terminal, prompt: string): Promise<void> { public async waitForPrompt(term: Terminal, prompt: string): Promise<void> {

View File

@@ -957,6 +957,7 @@ testSmartPromise();
></dees-workspace-monaco> ></dees-workspace-monaco>
`} `}
</div> </div>
<dees-actionbar></dees-actionbar>
</div> </div>
<!-- Horizontal resize handle for terminal --> <!-- Horizontal resize handle for terminal -->
@@ -1021,9 +1022,6 @@ testSmartPromise();
.executionEnvironment=${this.executionEnvironment} .executionEnvironment=${this.executionEnvironment}
@run-process=${this.handleRunProcess} @run-process=${this.handleRunProcess}
></dees-workspace-bottombar> ></dees-workspace-bottombar>
<!-- Action Bar for notifications -->
<dees-actionbar></dees-actionbar>
</div> </div>
`; `;
} }
@@ -1056,9 +1054,6 @@ testSmartPromise();
this.currentFileTreeWidth = this.fileTreeWidth; this.currentFileTreeWidth = this.fileTreeWidth;
this.currentTerminalHeight = this.terminalHeight; this.currentTerminalHeight = this.terminalHeight;
// Get actionbar reference for file change notifications
this.actionbarElement = this.shadowRoot?.querySelector('dees-actionbar') as DeesActionbar;
if (this.executionEnvironment) { if (this.executionEnvironment) {
await this.initializeWorkspace(); await this.initializeWorkspace();
} }
@@ -1068,6 +1063,11 @@ testSmartPromise();
if (changedProperties.has('executionEnvironment') && this.executionEnvironment) { if (changedProperties.has('executionEnvironment') && this.executionEnvironment) {
await this.initializeWorkspace(); 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() { private async initializeWorkspace() {

View File

@@ -130,12 +130,12 @@ export class DeesActionbar extends DeesElement {
:host { :host {
display: block; display: block;
overflow: hidden; overflow: hidden;
height: 0; max-height: 0;
transition: height 0.2s ease-out; transition: max-height 0.2s ease-out;
} }
:host(.visible) { :host(.visible) {
height: auto; max-height: 100px; /* Enough for actionbar content */
} }
.actionbar-item { .actionbar-item {