diff --git a/cockpit/langgraph/client-tools/angular/src/app/confirm-booking.component.ts b/cockpit/langgraph/client-tools/angular/src/app/confirm-booking.component.ts index 40e0c3397..8067b3238 100644 --- a/cockpit/langgraph/client-tools/angular/src/app/confirm-booking.component.ts +++ b/cockpit/langgraph/client-tools/angular/src/app/confirm-booking.component.ts @@ -47,12 +47,12 @@ type ConfirmBookingProps = ViewProps; } `, styles: [` - .cb { border: 1px solid var(--tplane-chat-separator, #e5e7eb); border-radius: 12px; padding: 16px; max-width: 360px; } + .cb { border: 1px solid var(--ds-border, #e5e7eb); border-radius: 12px; padding: 16px; max-width: 360px; background: var(--ds-surface); color: var(--ds-text-primary); } .cb__summary { margin: 0 0 12px; } - .cb--resolved .cb__summary { margin: 0; opacity: 0.85; } + .cb--resolved .cb__summary { margin: 0; color: var(--ds-text-secondary); } .cb__actions { display: flex; gap: 8px; } - .cb__btn { padding: 6px 14px; border-radius: 8px; border: 1px solid var(--tplane-chat-separator, #e5e7eb); background: transparent; color: inherit; cursor: pointer; } - .cb__btn--primary { background: var(--tplane-chat-accent, #2563eb); color: #fff; border-color: transparent; } + .cb__btn { padding: 6px 14px; border-radius: 8px; border: 1px solid var(--ds-border, #e5e7eb); background: var(--ds-surface-dim); color: var(--ds-text-secondary); cursor: pointer; } + .cb__btn--primary { background: var(--ds-accent, #64C3FD); color: #08243a; border-color: transparent; font-weight: 600; } `], }) export class ConfirmBookingComponent { diff --git a/cockpit/langgraph/client-tools/angular/src/app/weather-card.component.ts b/cockpit/langgraph/client-tools/angular/src/app/weather-card.component.ts index f12ca7947..fee109be7 100644 --- a/cockpit/langgraph/client-tools/angular/src/app/weather-card.component.ts +++ b/cockpit/langgraph/client-tools/angular/src/app/weather-card.component.ts @@ -38,14 +38,14 @@ type WeatherCardProps = ViewProps; `, styles: [` - .wc { border: 1px solid var(--tplane-chat-separator, #e5e7eb); border-radius: 12px; padding: 16px; max-width: 320px; } + .wc { border: 1px solid var(--ds-border, #e5e7eb); border-radius: 12px; padding: 16px; max-width: 320px; background: var(--ds-surface); color: var(--ds-text-primary); } .wc__head { display: flex; align-items: center; justify-content: space-between; } .wc__loc { font-weight: 600; } - .wc__badge { font-size: 12px; opacity: 0.7; } + .wc__badge { font-size: 12px; color: var(--ds-text-muted); } .wc__temp { font-size: 32px; font-weight: 700; margin-top: 8px; } - .wc__cond { opacity: 0.8; } + .wc__cond { color: var(--ds-text-secondary); } .wc__meta { display: flex; gap: 24px; margin: 12px 0 0; } - .wc__meta dt { font-size: 11px; text-transform: uppercase; opacity: 0.6; } + .wc__meta dt { font-size: 11px; text-transform: uppercase; color: var(--ds-text-muted); } .wc__meta dd { margin: 0; font-weight: 600; } `], }) diff --git a/cockpit/langgraph/client-tools/angular/tsconfig.app.json b/cockpit/langgraph/client-tools/angular/tsconfig.app.json index 925942d5d..5039e9318 100644 --- a/cockpit/langgraph/client-tools/angular/tsconfig.app.json +++ b/cockpit/langgraph/client-tools/angular/tsconfig.app.json @@ -8,6 +8,7 @@ }, "files": ["src/main.ts"], "include": ["src/**/*.ts"], + "exclude": ["src/**/*.spec.ts", "src/**/*.test.ts"], "references": [ { "path": "../../../../libs/cockpit-telemetry" diff --git a/cockpit/langgraph/durable-execution/angular/src/app/durable-execution.component.ts b/cockpit/langgraph/durable-execution/angular/src/app/durable-execution.component.ts index 0d64b8667..c124e4bcb 100644 --- a/cockpit/langgraph/durable-execution/angular/src/app/durable-execution.component.ts +++ b/cockpit/langgraph/durable-execution/angular/src/app/durable-execution.component.ts @@ -37,53 +37,149 @@ const STEP_LABELS: Record = { selector: 'app-durable-execution', standalone: true, imports: [ChatComponent, ExampleChatLayoutComponent], + styles: ` + :host { + --st-done: #2ea567; + --st-active: #e0a850; + --st-error: #e0645a; + } + .panel { + padding: 1rem; + background: var(--ds-surface, #1c1c1c); + color: var(--ds-text-primary, #f5f5f5); + height: 100%; + } + .cap { + margin-bottom: 1.5rem; + font-size: 10px; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.12em; + color: var(--ds-text-muted, #a0a0a0); + } + .steps { + display: flex; + flex-direction: column; + } + .step { + display: flex; + align-items: flex-start; + gap: 0.75rem; + } + .step__col { + display: flex; + flex-direction: column; + align-items: center; + } + .circle { + width: 28px; + height: 28px; + border-radius: 999px; + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + } + .circle--complete { + background: var(--st-done); + } + .circle--complete svg { + width: 16px; + height: 16px; + color: #fff; + } + .circle--active { + border: 2px solid var(--st-active); + animation: dx-spin 1.2s linear infinite; + } + .circle--pending { + border: 2px solid var(--ds-border, #2d2d2d); + } + .dot { + width: 8px; + height: 8px; + border-radius: 999px; + } + .dot--active { + background: var(--st-active); + } + .dot--pending { + background: var(--ds-text-muted, #a0a0a0); + } + @keyframes dx-spin { + to { + transform: rotate(360deg); + } + } + .line { + width: 2px; + height: 2rem; + } + .line--done { + background: var(--st-done); + } + .line--pending { + background: var(--ds-border, #2d2d2d); + } + .label { + font-size: 13px; + padding-top: 4px; + } + .label--active { + font-weight: 600; + color: var(--st-active); + } + .label--complete { + color: var(--st-done); + } + .label--pending { + color: var(--ds-text-muted, #a0a0a0); + } + `, template: ` - + -
-

Pipeline

+
+

Pipeline

-
+
@for (step of steps(); track step.id; let last = $last) { -
+
-
+
@switch (step.status) { @case ('complete') { -
- +
+
} @case ('active') { -
-
+
+
} @default { -
-
+
+
} } @if (!last) { -
-
+
}
- + {{ step.label }}
diff --git a/cockpit/langgraph/durable-execution/angular/src/app/views/step-pipeline.component.ts b/cockpit/langgraph/durable-execution/angular/src/app/views/step-pipeline.component.ts index 235a1efbf..f97e1eef2 100644 --- a/cockpit/langgraph/durable-execution/angular/src/app/views/step-pipeline.component.ts +++ b/cockpit/langgraph/durable-execution/angular/src/app/views/step-pipeline.component.ts @@ -8,54 +8,139 @@ interface PipelineStep { @Component({ selector: 'step-pipeline', standalone: true, + styles: ` + :host { + --st-done: #2ea567; + --st-active: #e0a850; + --st-error: #e0645a; + } + .pipeline { + border: 1px solid var(--ds-border, #2d2d2d); + border-radius: var(--ds-radius-xl, 18px); + padding: 1rem; + margin: 0.5rem 0; + background: var(--ds-surface, #1c1c1c); + overflow-x: auto; + } + .row { + display: flex; + align-items: center; + gap: 0; + min-width: max-content; + } + .node { + display: flex; + flex-direction: column; + align-items: center; + gap: 6px; + } + .circle { + width: 32px; + height: 32px; + border-radius: 999px; + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + } + .circle--complete { + background: var(--st-done); + } + .circle--complete svg { + width: 16px; + height: 16px; + color: #fff; + } + .circle--active { + border: 2px solid var(--st-active); + animation: sp-spin 1.2s linear infinite; + } + .circle--pending { + border: 2px solid var(--ds-border, #2d2d2d); + } + .dot { + width: 8px; + height: 8px; + border-radius: 999px; + } + .dot--active { + background: var(--st-active); + } + .dot--pending { + background: var(--ds-text-muted, #a0a0a0); + } + @keyframes sp-spin { + to { + transform: rotate(360deg); + } + } + .label { + font-size: 12px; + white-space: nowrap; + } + .label--active { + font-weight: 600; + color: var(--st-active); + } + .label--complete { + color: var(--st-done); + } + .label--pending { + color: var(--ds-text-muted, #a0a0a0); + } + .line { + width: 2.5rem; + height: 2px; + margin: 0 4px; + margin-top: -20px; + } + .line--done { + background: var(--st-done); + } + .line--pending { + background: var(--ds-border, #2d2d2d); + } + `, template: ` -
-
+
+
@for (step of steps(); track step.label; let i = $index; let last = $last) { -
+
@switch (step.status) { @case ('complete') { -
- +
+
} @case ('active') { -
-
+
+
} @default { -
-
+
+
} } - + {{ step.label }}
@if (!last) { -
-
+
} }
diff --git a/cockpit/langgraph/durable-execution/angular/tsconfig.app.json b/cockpit/langgraph/durable-execution/angular/tsconfig.app.json index ef34262b1..785b27786 100644 --- a/cockpit/langgraph/durable-execution/angular/tsconfig.app.json +++ b/cockpit/langgraph/durable-execution/angular/tsconfig.app.json @@ -8,6 +8,7 @@ }, "files": ["src/main.ts"], "include": ["src/**/*.ts"], + "exclude": ["src/**/*.spec.ts", "src/**/*.test.ts"], "references": [ { "path": "../../../../libs/cockpit-telemetry" diff --git a/cockpit/langgraph/interrupts/angular/src/app/interrupts.component.ts b/cockpit/langgraph/interrupts/angular/src/app/interrupts.component.ts index cc432ee33..e5c02be7e 100644 --- a/cockpit/langgraph/interrupts/angular/src/app/interrupts.component.ts +++ b/cockpit/langgraph/interrupts/angular/src/app/interrupts.component.ts @@ -45,6 +45,39 @@ const WELCOME_SUGGESTIONS = [ CurrencyPipe, ], changeDetection: ChangeDetectionStrategy.OnPush, + styles: ` + .body { display: flex; flex-direction: column; gap: 6px; } + .field { font-size: 13px; } + .field__label { color: var(--ds-text-muted); margin-right: 6px; } + .field__value { color: var(--ds-text-primary); } + .reason { font-style: italic; color: var(--ds-text-muted); margin-top: 4px; font-size: 13px; } + .edit-form { margin-top: 10px; display: flex; gap: 6px; align-items: center; } + .edit-form__label { color: var(--ds-text-muted); font-size: 12px; } + .control-input { + background: var(--ds-surface-dim); + border: 1px solid var(--ds-border); + border-radius: var(--ds-radius-sm); + color: var(--ds-text-primary); + padding: 5px 8px; + width: 120px; + font-size: 13px; + } + .control-input:focus { + outline: none; + border-color: var(--ds-accent); + box-shadow: 0 0 0 3px var(--ds-accent-glow); + } + .btn--primary { + background: var(--ds-accent); + color: #08243a; + border: 0; + border-radius: var(--ds-radius-sm); + padding: 6px 12px; + font-size: 12px; + font-weight: 600; + cursor: pointer; + } + `, template: `
@@ -69,17 +102,17 @@ const WELCOME_SUGGESTIONS = [ (action)="onAction($event)" > -
-
Amount{{ payload.amount | currency }}
-
Customer{{ payload.customer_id }}
+
+
Amount{{ payload.amount | currency }}
+
Customer{{ payload.customer_id }}
@if (payload.reason) { -
{{ payload.reason }}
+
{{ payload.reason }}
} @if (editing()) { -
- - - +
+ + +
}
diff --git a/cockpit/langgraph/interrupts/angular/tsconfig.app.json b/cockpit/langgraph/interrupts/angular/tsconfig.app.json index 4d1fa84d2..30c38f15c 100644 --- a/cockpit/langgraph/interrupts/angular/tsconfig.app.json +++ b/cockpit/langgraph/interrupts/angular/tsconfig.app.json @@ -8,6 +8,7 @@ }, "files": ["src/main.ts"], "include": ["src/**/*.ts"], + "exclude": ["src/**/*.spec.ts", "src/**/*.test.ts"], "references": [ { "path": "../../../../libs/cockpit-telemetry" diff --git a/cockpit/langgraph/memory/angular/src/app/memory.component.ts b/cockpit/langgraph/memory/angular/src/app/memory.component.ts index 11d911b62..8bdf69032 100644 --- a/cockpit/langgraph/memory/angular/src/app/memory.component.ts +++ b/cockpit/langgraph/memory/angular/src/app/memory.component.ts @@ -20,20 +20,38 @@ import { ExampleChatLayoutComponent } from '@threadplane/example-layouts'; selector: 'app-memory', standalone: true, imports: [ChatComponent, ExampleChatLayoutComponent], + styles: ` + .panel { padding: 1rem; } + .cap { + margin-bottom: 1rem; + font-size: 10px; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.12em; + color: var(--ds-text-muted, #a0a0a0); + } + .empty { font-size: 13px; font-style: italic; color: var(--ds-text-muted, #a0a0a0); } + .fact { + padding: 6px 0; + font-size: 13px; + border-bottom: 1px solid var(--ds-border, #2d2d2d); + } + .fact:last-child { border-bottom: none; } + .fact__key { font-weight: 600; color: var(--ds-text-primary, #f5f5f5); } + .fact__value { color: var(--ds-text-secondary, #c8c8c8); } + `, template: ` -
-

Learned Facts

+
+

Learned Facts

@if (memoryEntries().length === 0) { -

No facts learned yet

+

No facts learned yet

} @for (entry of memoryEntries(); track entry[0]) { -
- {{ entry[0] }}: - {{ entry[1] }} +
+ {{ entry[0] }}: + {{ entry[1] }}
}
diff --git a/cockpit/langgraph/memory/angular/tsconfig.app.json b/cockpit/langgraph/memory/angular/tsconfig.app.json index 925942d5d..5039e9318 100644 --- a/cockpit/langgraph/memory/angular/tsconfig.app.json +++ b/cockpit/langgraph/memory/angular/tsconfig.app.json @@ -8,6 +8,7 @@ }, "files": ["src/main.ts"], "include": ["src/**/*.ts"], + "exclude": ["src/**/*.spec.ts", "src/**/*.test.ts"], "references": [ { "path": "../../../../libs/cockpit-telemetry" diff --git a/cockpit/langgraph/persistence/angular/src/app/persistence.component.ts b/cockpit/langgraph/persistence/angular/src/app/persistence.component.ts index 359adc3fc..4b4c8bcfd 100644 --- a/cockpit/langgraph/persistence/angular/src/app/persistence.component.ts +++ b/cockpit/langgraph/persistence/angular/src/app/persistence.component.ts @@ -63,8 +63,74 @@ let threadCounter = 0; }, }), ], + styles: ` + .sidebar { + display: flex; + flex-direction: column; + height: 100%; + background: var(--ds-surface, #1c1c1c); + color: var(--ds-text-primary, #f5f5f5); + } + .cap { + padding: 0.625rem 0.75rem; + font-size: 10px; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.12em; + color: var(--ds-text-muted, #a0a0a0); + border-bottom: 1px solid var(--ds-border, #2d2d2d); + } + .thread-list { + flex: 1; + overflow-y: auto; + } + .thread { + display: block; + width: 100%; + padding: 0.5rem 0.75rem; + font-size: 13px; + text-align: left; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + border: 0; + background: transparent; + color: var(--ds-text-primary, #f5f5f5); + cursor: pointer; + transition: background 0.15s ease; + } + .thread:hover { + background: var(--ds-surface-tinted, rgba(255, 255, 255, 0.04)); + } + .thread--active { + font-weight: 600; + background: var(--ds-accent-surface, rgba(100, 195, 253, 0.08)); + } + .thread--active:hover { + background: var(--ds-accent-surface, rgba(100, 195, 253, 0.08)); + } + .footer { + padding: 0.5rem; + border-top: 1px solid var(--ds-border, #2d2d2d); + } + .btn--primary { + width: 100%; + padding: 6px 12px; + font-size: 13px; + font-weight: 600; + border: 0; + border-radius: var(--ds-radius-sm, 6px); + background: var(--ds-accent, #64c3fd); + color: #08243a; + cursor: pointer; + transition: background 0.15s ease; + } + .btn--primary:hover { + background: var(--ds-accent-hover, #8dd4ff); + } + `, template: ` - +
@for (s of suggestions; track s.value) { @@ -78,25 +144,15 @@ let threadCounter = 0;
-
-
- Threads -
+