-
docker login ${this.registryUrl.split('/')[0]} -u onebox -p YOUR_TOKEN
+
docker login ${this.registryUrl.split('/')[0]} -u registry -p YOUR_TOKEN
docker tag myapp ${this.registryUrl.split('/')[0]}/myservice:latest
docker push ${this.registryUrl.split('/')[0]}/myservice:latest
diff --git a/ts_web/elements/sz-service-detail-view.ts b/ts_web/elements/sz-service-detail-view.ts
index dc4bb79..a26d4d5 100644
--- a/ts_web/elements/sz-service-detail-view.ts
+++ b/ts_web/elements/sz-service-detail-view.ts
@@ -5,9 +5,12 @@ import {
css,
cssManager,
property,
+ state,
type TemplateResult,
} from '@design.estate/dees-element';
+import type { IExecutionEnvironment } from '@design.estate/dees-catalog';
+
import './sz-stat-card.js';
declare global {
@@ -123,6 +126,15 @@ export class SzServiceDetailView extends DeesElement {
@property({ type: Boolean })
public accessor streaming: boolean = false;
+ @property({ type: Object })
+ public accessor workspaceEnvironment: IExecutionEnvironment | null = null;
+
+ @property({ type: String })
+ public accessor workspacePath: string = '/';
+
+ @state()
+ private accessor currentView: 'details' | 'workspace' = 'details';
+
public static styles = [
cssManager.defaultStyles,
css`
@@ -455,10 +467,102 @@ export class SzServiceDetailView extends DeesElement {
font-size: 12px;
font-weight: 500;
}
+
+ :host(.workspace-mode) {
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+ }
+
+ .workspace-wrapper {
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+ }
+
+ .workspace-header {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ padding: 12px 16px;
+ border-bottom: 1px solid ${cssManager.bdTheme('#e4e4e7', '#27272a')};
+ background: ${cssManager.bdTheme('#ffffff', '#09090b')};
+ flex-shrink: 0;
+ }
+
+ .workspace-back-link {
+ display: inline-flex;
+ align-items: center;
+ gap: 6px;
+ font-size: 14px;
+ font-weight: 500;
+ color: ${cssManager.bdTheme('#2563eb', '#60a5fa')};
+ cursor: pointer;
+ transition: color 200ms ease;
+ }
+
+ .workspace-back-link:hover {
+ color: ${cssManager.bdTheme('#1d4ed8', '#93c5fd')};
+ }
+
+ .workspace-service-name {
+ font-size: 14px;
+ font-weight: 600;
+ color: ${cssManager.bdTheme('#18181b', '#fafafa')};
+ }
+
+ .workspace-status-badge {
+ display: inline-flex;
+ align-items: center;
+ width: 8px;
+ height: 8px;
+ border-radius: 50%;
+ }
+
+ .workspace-status-badge.running {
+ background: ${cssManager.bdTheme('#22c55e', '#22c55e')};
+ }
+
+ .workspace-status-badge.stopped {
+ background: ${cssManager.bdTheme('#ef4444', '#ef4444')};
+ }
+
+ .workspace-container {
+ position: relative;
+ flex: 1;
+ min-height: 0;
+ }
`,
];
public render(): TemplateResult {
+ if (this.currentView === 'workspace') {
+ return this.renderWorkspaceView();
+ }
+ return this.renderDetailsView();
+ }
+
+ private renderWorkspaceView(): TemplateResult {
+ return html`
+
+ `;
+ }
+
+ private renderDetailsView(): TemplateResult {
return html`
@@ -709,4 +820,30 @@ export class SzServiceDetailView extends DeesElement {
private handleDeleteBackup(backup: IServiceBackup) {
this.dispatchEvent(new CustomEvent('delete-backup', { detail: backup, bubbles: true, composed: true }));
}
+
+ private handleOpenWorkspace() {
+ if (this.workspaceEnvironment) {
+ this.currentView = 'workspace';
+ this.classList.add('workspace-mode');
+ } else {
+ this.dispatchEvent(new CustomEvent('request-workspace', {
+ detail: { service: this.service },
+ bubbles: true,
+ composed: true,
+ }));
+ }
+ }
+
+ private handleCloseWorkspace() {
+ this.currentView = 'details';
+ this.classList.remove('workspace-mode');
+ }
+
+ updated(changedProperties: Map
) {
+ super.updated(changedProperties);
+ if (changedProperties.has('workspaceEnvironment') && this.workspaceEnvironment && this.currentView === 'details') {
+ this.currentView = 'workspace';
+ this.classList.add('workspace-mode');
+ }
+ }
}