humainflow-web/src/app/shared/task-execution-viewer/task-execution-viewer.css

1008 lines
19 KiB
CSS

/*
* SPDX-FileCopyrightText: 2025-2026 Lucio Lelii <lucio.lelii@isti.cnr.it> - ISTI-CNR
* SPDX-License-Identifier: AGPL-3.0-or-later
* Attribution term under AGPL-3.0 section 7(b): see LICENSE-ADDENDUM.
*/
:host {
display: block;
height: 100%;
}
.execution-viewer-fullscreen {
position: fixed;
inset: 0;
z-index: var(--z-modal);
background: #ffffff;
padding: 0.25rem;
}
.execution-header-main {
display: block;
}
.execution-header-details {
min-width: 0;
}
.execution-header-details h2 {
display: inline-flex;
align-items: center;
gap: 8px;
}
.execution-header-fullscreen-toggle {
display: inline-flex;
align-items: center;
justify-content: center;
width: 28px;
height: 28px;
border-radius: 8px;
border: 1px solid transparent;
background: #e2e8f0;
color: #334155;
padding: 0;
transition: filter 120ms ease;
}
.execution-header-fullscreen-toggle:hover {
filter: brightness(1.05);
}
.execution-header-fullscreen-toggle mat-icon {
font-size: 18px;
width: 18px;
height: 18px;
}
.execution-graph-body {
position: relative;
}
.execution-graph-actions {
position: absolute;
top: 12px;
left: 12px;
z-index: 4;
display: inline-flex;
flex-direction: row;
gap: 8px;
}
.execution-graph-actions-right {
left: auto;
right: 12px;
}
.execution-action-button {
display: inline-flex;
align-items: center;
justify-content: center;
width: 42px;
height: 42px;
border-radius: 12px;
border: 1px solid transparent;
font-size: 12px;
font-weight: 700;
line-height: 1;
padding: 0;
transition: filter 120ms ease, opacity 120ms ease, transform 120ms ease;
box-shadow: 0 10px 18px rgba(15, 23, 42, 0.16);
}
.execution-graph-action-button:hover:not(:disabled) {
transform: translateY(-1px);
}
.execution-action-button mat-icon {
font-size: 20px;
width: 20px;
height: 20px;
line-height: 20px;
}
/* The button has to be a positioning context for the badge, and must not clip it. */
.execution-action-button {
position: relative;
overflow: visible;
}
/*
* Who answers the flow's human steps - you, or an LLM - is the only difference between the two run
* buttons, so both keep the play and the badge carries that difference. It is small on purpose: it
* qualifies the play rather than competing with it, and the two sit side by side, which is what
* makes either one legible.
*/
.execution-action-badge {
position: absolute;
right: -3px;
bottom: -3px;
display: inline-flex;
align-items: center;
justify-content: center;
width: 17px;
height: 17px;
border-radius: 999px;
border: 1px solid currentColor;
background: #ffffff;
color: inherit;
}
.execution-action-badge mat-icon {
font-size: 11px;
width: 11px;
height: 11px;
line-height: 11px;
color: #0f172a;
}
.execution-action-button:disabled {
opacity: 0.4;
cursor: not-allowed;
}
.execution-action-button-play {
background: #15803d;
border-color: #166534;
color: #ffffff;
}
.execution-action-button-play:hover:not(:disabled) {
filter: brightness(1.1);
}
.execution-action-button-stop {
background: #dc2626;
border-color: #b91c1c;
color: #ffffff;
}
.execution-action-button-stop:hover:not(:disabled) {
filter: brightness(1.08);
}
.execution-action-button-resume {
background: #4f46e5;
border-color: #4338ca;
color: #ffffff;
}
.execution-action-button-resume:hover:not(:disabled) {
filter: brightness(1.1);
}
.execution-action-button-simulate {
background: #0c4a6e;
border-color: #075985;
color: #e0f2fe;
}
.execution-action-button-simulate:hover:not(:disabled) {
filter: brightness(1.1);
}
.execution-rete-readonly {
pointer-events: auto;
}
:host ::ng-deep .execution-rete-readonly :is(
.llm-socket,
.hi-socket,
.input-socket,
.output-socket
) {
pointer-events: none;
}
:host ::ng-deep .execution-rete-readonly .llm-input-info,
:host ::ng-deep .execution-rete-readonly .hi-input-info,
:host ::ng-deep .execution-rete-readonly .llm-input-info-wrap,
:host ::ng-deep .execution-rete-readonly .hi-input-info-wrap {
pointer-events: auto;
}
:host ::ng-deep .execution-rete-readonly :is(
.node-delete-btn,
.llm-delete-btn,
.hi-delete-btn,
.llm-edit-btn,
.hi-edit-btn,
.llm-name-edit-btn,
.hi-name-edit-btn
) {
display: none !important;
}
.context-title {
font-size: 11px;
color: #64748b;
font-weight: 600;
margin-bottom: 4px;
}
.context-json {
margin: 0;
border: 1px solid #e2e8f0;
border-radius: 8px;
background: #f8fafc;
color: #0f172a;
font-size: 11px;
line-height: 1.35;
padding: 8px;
white-space: pre-wrap;
word-break: break-word;
}
.execution-aside-tab {
flex: 0 0 auto;
border: 0;
border-bottom: 2px solid transparent;
background: transparent;
color: #64748b;
font-size: 11px;
font-weight: 700;
padding: 9px 6px;
cursor: pointer;
white-space: nowrap;
}
.execution-aside-tabs {
flex-wrap: nowrap;
}
.execution-aside-tab-active {
border-bottom-color: #2563eb;
color: #1d4ed8;
}
.execution-aside-tab:disabled {
cursor: not-allowed;
opacity: 0.45;
}
.execution-output-modal {
margin: 0;
border: 1px solid #e2e8f0;
border-radius: 10px;
background: #f8fafc;
color: #0f172a;
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
font-size: 12px;
line-height: 1.45;
padding: 14px;
white-space: pre-wrap;
word-break: break-word;
}
.execution-intermediate-group {
border: 1px solid #d9eadf;
border-radius: 8px;
background: #f7fbf8;
padding: 12px;
}
.execution-intermediate-group-title {
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 14px;
font-weight: 800;
color: #0f172a;
}
.execution-intermediate-group-list {
margin-top: 10px;
display: flex;
flex-direction: column;
gap: 10px;
}
.execution-intermediate-item {
border: 1px solid #cfe6d5;
border-radius: 8px;
background: #ffffff;
padding: 10px 12px;
}
.execution-intermediate-item-head {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 12px;
}
.execution-intermediate-item-name {
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 11px;
font-weight: 800;
text-transform: uppercase;
color: #15803d;
}
.execution-intermediate-item-meta {
display: flex;
flex-wrap: wrap;
gap: 4px 8px;
margin-top: 3px;
color: #64748b;
font-size: 10px;
font-weight: 700;
}
.execution-intermediate-preview {
margin-top: 8px;
white-space: pre-wrap;
word-break: break-word;
user-select: text;
color: #0f172a;
font-size: 12px;
line-height: 1.45;
}
.execution-output-group {
border: 1px solid #e2e8f0;
border-radius: 8px;
background: #f8fafc;
padding: 12px;
}
.execution-output-group-title {
font-size: 14px;
font-weight: 800;
color: #0f172a;
}
.execution-output-group-list {
margin-top: 10px;
display: flex;
flex-direction: column;
gap: 10px;
}
.execution-output-item {
border: 1px solid #dbe7f5;
border-radius: 8px;
background: #ffffff;
padding: 10px 12px;
}
.execution-output-item-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
}
.execution-output-item-name {
min-width: 0;
font-size: 11px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.04em;
color: #2563eb;
}
.execution-output-preview {
margin-top: 8px;
white-space: pre-wrap;
word-break: break-word;
color: #0f172a;
font-size: 12px;
line-height: 1.45;
}
.execution-output-view-btn {
flex: 0 0 auto;
width: 22px;
height: 22px;
border: 1px solid #bfdbfe;
border-radius: 999px;
background: #eff6ff;
color: #1d4ed8;
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0;
}
.execution-output-view-btn:hover {
background: #dbeafe;
}
.execution-output-view-btn i {
font-size: 11px;
}
.execution-log-card {
border: 1px solid #e2e8f0;
border-radius: 12px;
background: #f8fafc;
padding: 12px;
}
.execution-log-header {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 12px;
}
.execution-log-title-wrap {
display: flex;
align-items: flex-start;
gap: 10px;
min-width: 0;
}
.execution-log-icon {
flex: 0 0 auto;
width: 20px;
height: 20px;
font-size: 18px;
color: #475569;
line-height: 20px;
overflow: visible;
margin-top: 1px;
}
.execution-log-title {
color: #0f172a;
font-size: 13px;
font-weight: 700;
line-height: 1.35;
}
.execution-log-meta {
display: flex;
flex-wrap: wrap;
gap: 6px 10px;
margin-top: 4px;
color: #64748b;
font-size: 11px;
}
.execution-log-actions {
display: flex;
align-items: center;
gap: 6px;
flex: 0 0 auto;
}
/* Quiet until hovered: one of these sits on every row that carries details. */
.execution-log-details-btn {
display: inline-flex;
align-items: center;
justify-content: center;
width: 24px;
height: 24px;
padding: 0;
border: none;
border-radius: 6px;
background: transparent;
color: #64748b;
cursor: pointer;
}
.execution-log-details-btn:hover {
background: #e2e8f0;
color: #0f172a;
}
.execution-log-details-btn mat-icon {
font-size: 16px;
width: 16px;
height: 16px;
line-height: 16px;
}
.execution-log-level {
display: inline-flex;
align-items: center;
border-radius: 999px;
border: 1px solid transparent;
font-size: 10px;
font-weight: 700;
letter-spacing: 0.03em;
padding: 3px 8px;
text-transform: uppercase;
}
.execution-log-level-info {
background: #e0f2fe;
border-color: #bae6fd;
color: #0c4a6e;
}
.execution-log-level-warn {
background: #fef3c7;
border-color: #fde68a;
color: #92400e;
}
.execution-log-level-error {
background: #fee2e2;
border-color: #fecaca;
color: #991b1b;
}
.execution-logs-panel {
display: flex;
flex-direction: column;
height: 100%;
min-height: 0;
}
.execution-logs-toolbar {
display: flex;
justify-content: flex-end;
padding: 6px 12px 0;
flex: 0 0 auto;
}
.execution-logs-follow {
display: inline-flex;
align-items: center;
gap: 4px;
padding: 3px 9px;
border: 1px solid #cbd5e1;
border-radius: 999px;
background: #fff;
color: #475569;
font-size: 11px;
font-weight: 600;
cursor: pointer;
}
.execution-logs-follow:hover {
border-color: #94a3b8;
background: #f8fafc;
}
/* Held position: stated plainly, since a log that stopped moving on its own looks like a log that stopped. */
.execution-logs-follow-paused {
border-color: #fcd34d;
background: #fffbeb;
color: #92400e;
}
.execution-logs-follow mat-icon {
font-size: 14px;
width: 14px;
height: 14px;
line-height: 14px;
}
.execution-logs-scroll {
flex: 1 1 auto;
min-height: 0;
overflow-y: auto;
overscroll-behavior: contain;
}
.execution-bias-variant-context {
align-items: center;
color: #5b21b6;
display: flex;
flex-wrap: wrap;
font-size: .78rem;
gap: .35rem .75rem;
margin-top: .45rem;
}
/* Says what the other run used, while there is still a choice to make about this one. */
.execution-inherited-simulator-notice {
background: #f0f9ff;
border-left: 3px solid #0284c7;
border-radius: .25rem;
color: #075985;
font-size: .78rem;
line-height: 1.45;
margin-top: .45rem;
padding: .35rem .5rem;
}
.execution-subflow-context {
align-items: center;
color: #075985;
display: flex;
flex-wrap: wrap;
font-size: .78rem;
gap: .35rem .75rem;
margin-top: .45rem;
}
.execution-graph-action-button-bias { background: #f3e8ff; color: #7e22ce; }
.execution-graph-action-button-compare { background: #ccfbf1; color: #0f766e; }
.execution-graph-action-button-compare:hover:not(:disabled) { filter: brightness(1.05); }
.execution-bias-legend {
position: absolute;
top: 62px;
left: 12px;
z-index: 4;
display: flex;
align-items: center;
flex-wrap: wrap;
gap: .5rem .75rem;
background: #ffffff;
border: 1px solid #e2e8f0;
border-radius: .5rem;
box-shadow: 0 8px 18px rgba(15, 23, 42, 0.12);
padding: .4rem .65rem;
font-size: .76rem;
color: #334155;
}
.execution-bias-legend-title { font-weight: 700; }
.execution-bias-legend-item { display: inline-flex; align-items: center; gap: .3rem; }
.execution-bias-legend-dot { display: inline-block; width: 10px; height: 10px; border-radius: 999px; }
.execution-bias-legend-dot-active { background: #7c3aed; }
.execution-bias-legend-dot-changed { background: #b45309; }
.execution-bias-legend-reset { background: #f1f5f9; border: 1px solid #cbd5e1; border-radius: .4rem; color: #0f172a; cursor: pointer; font-size: .76rem; font-weight: 600; padding: .25rem .55rem; }
.execution-bias-legend-reset:hover { background: #e2e8f0; }
/*
* A flow whose last block is wired into an End node puts its answer here rather than in the flow
* result, so this reads as the run's conclusion, not as a footnote.
*/
.execution-outcomes {
margin: 0.25rem 0.25rem 0;
padding: 0.5rem 0.75rem 0.625rem;
border: 1px solid #bbf7d0;
border-radius: 6px;
background: #f0fdf4;
}
.execution-outcomes-title {
display: flex;
align-items: center;
gap: 0.375rem;
width: 100%;
padding: 0;
border: none;
background: transparent;
color: #166534;
font-size: 0.75rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.02em;
cursor: pointer;
text-align: left;
}
/* Collapsed, the codes stand in for the payload so the conclusion is never hidden entirely. */
.execution-outcomes-summary {
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: #15803d;
font-weight: 700;
text-transform: none;
}
.execution-outcomes-title .mat-icon {
font-size: 16px;
width: 16px;
height: 16px;
line-height: 16px;
}
.execution-outcome:first-of-type {
margin-top: 0.375rem;
}
.execution-outcome + .execution-outcome {
margin-top: 0.5rem;
padding-top: 0.5rem;
border-top: 1px dashed #bbf7d0;
}
.execution-outcome-head {
display: flex;
align-items: baseline;
flex-wrap: wrap;
gap: 0.375rem;
}
.execution-outcome-code {
padding: 0 0.375rem;
border-radius: 999px;
background: #16a34a;
color: #ffffff;
font-size: 0.6875rem;
font-weight: 700;
letter-spacing: 0.02em;
}
.execution-outcome-label {
color: #14532d;
font-size: 0.875rem;
font-weight: 600;
}
.execution-outcome-step {
color: #4d7c5f;
font-size: 0.75rem;
}
.execution-outcome-payload {
margin-top: 0.375rem;
padding: 0.375rem 0.5rem;
border: 1px solid #dcfce7;
border-radius: 4px;
background: #ffffff;
max-height: 220px;
overflow: auto;
}
.execution-outcome-empty {
margin-top: 0.25rem;
color: #4d7c5f;
font-size: 0.75rem;
font-style: italic;
}
/* Generated documents keep their line breaks; the JSON tree would quote and flatten them. */
.execution-outcome-text {
white-space: pre-wrap;
overflow-wrap: anywhere;
font-size: 0.8125rem;
line-height: 1.45;
color: #1f2937;
}
/*
* Only what changes how a result should be read stays in the header; ids, simulator descriptors
* and probe internals are diagnostics and live behind Details.
*/
.execution-header-badges {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 0.375rem;
margin-top: 0.125rem;
}
.execution-badge {
padding: 0 0.375rem;
border-radius: 999px;
font-size: 0.6875rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.03em;
cursor: help;
}
.execution-badge-simulated {
background: #e0f2fe;
color: #075985;
}
.execution-badge-bias {
background: #fee2e2;
color: #b91c1c;
}
.execution-badge-subflow {
background: #ede9fe;
color: #6d28d9;
}
.execution-header-details-toggle {
display: flex;
align-items: center;
gap: 0.125rem;
margin-left: auto;
padding: 0;
border: none;
background: transparent;
color: #64748b;
font-size: 0.6875rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.03em;
cursor: pointer;
}
.execution-header-details-toggle:hover {
color: #334155;
}
.execution-header-details-toggle .mat-icon {
font-size: 16px;
width: 16px;
height: 16px;
line-height: 16px;
}
.execution-header-detail-list {
margin-top: 0.25rem;
padding-top: 0.25rem;
border-top: 1px dashed #e2e8f0;
}
.execution-loop {
border: 1px solid #ddd6fe;
border-radius: 10px;
background: #faf5ff;
padding: 10px;
}
.execution-loop-head {
display: flex;
align-items: flex-start;
gap: 8px;
margin-bottom: 8px;
color: #5b21b6;
}
.execution-loop-head .bi {
font-size: 16px;
line-height: 1.2;
}
.execution-loop-title {
font-size: 13px;
font-weight: 700;
color: #3b0764;
}
.execution-loop-meta {
font-size: 11px;
color: #6d28d9;
}
.execution-round {
border: 1px solid #e9d5ff;
border-radius: 8px;
background: #fff;
margin-top: 6px;
}
.execution-round-summary {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
padding: 7px 10px;
cursor: pointer;
font-size: 12px;
}
.execution-round-number {
font-weight: 700;
color: #334155;
}
.execution-round-outcome {
font-size: 11px;
color: #64748b;
text-align: right;
}
.execution-round-outcome[data-outcome='left'] {
color: #047857;
}
.execution-round-outcome[data-outcome='limit-reached'],
.execution-round-outcome[data-outcome='failed'] {
color: #b91c1c;
}
.execution-round-outcome[data-outcome='in-progress'] {
color: #6d28d9;
}
.execution-round-steps {
display: flex;
flex-direction: column;
gap: 8px;
padding: 0 10px 10px;
}
.execution-round-step {
border-top: 1px solid #f1f5f9;
padding-top: 8px;
}
.execution-round-step-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
margin-bottom: 4px;
}
.execution-round-step-title {
font-size: 12px;
font-weight: 600;
color: #1e293b;
}
.execution-round-status {
font-size: 10px;
font-weight: 700;
letter-spacing: 0.02em;
border-radius: 999px;
padding: 1px 7px;
}
.execution-round-status-done {
background: #ecfdf5;
color: #047857;
}
.execution-round-status-failed {
background: #fef2f2;
color: #b91c1c;
}
.execution-round-status-idle {
background: #f1f5f9;
color: #64748b;
}
.execution-round-status-active {
background: #f5f3ff;
color: #6d28d9;
}
.execution-round-input {
margin-top: 4px;
}
.execution-round-input-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 6px;
}
/* A JSON value in a preview: the first level, a few entries - the whole tree opens with the eye. */
.execution-json-preview {
display: block;
margin-top: 4px;
max-height: 14rem;
overflow: auto;
border-radius: 6px;
background: #f8fafc;
padding: 6px 8px;
}
/*
* A tree grows and shrinks as its nodes are opened and closed. Sized to its content, the modal -
* centred on the page - would jump with every click; at a fixed height only its content scrolls.
*/
.execution-json-modal {
height: 90vh;
}
/* Stays in the corner while a long payload scrolls under it. */
.execution-outcome-copy {
position: sticky;
top: 0;
float: right;
z-index: 1;
display: inline-flex;
align-items: center;
justify-content: center;
width: 28px;
height: 28px;
margin-left: 6px;
border: 1px solid #d1fae5;
border-radius: 6px;
background: #fff;
color: #475569;
cursor: pointer;
}
.execution-outcome-copy:hover {
background: #f0fdf4;
}
.execution-outcome-copy .mat-icon {
width: 16px;
height: 16px;
font-size: 16px;
}