frontend_nyla/src/components/FlowEditor/editor/Automation2FlowEditor.module.css

1989 lines
40 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* Automation2 Flow Editor Styles
* Sidebar with node list + canvas area.
*/
.container {
display: flex;
flex: 1;
min-height: 0;
overflow: hidden;
}
/* =============================================================================
SIDEBAR - Node List
============================================================================= */
.resizeDivider {
flex-shrink: 0;
width: 5px;
cursor: col-resize;
background: var(--border-color, #e0e0e0);
transition: background 0.15s;
position: relative;
z-index: 5;
}
.resizeDivider:hover,
.resizeDivider:active {
background: var(--primary-color, #007bff);
}
.sidebar {
flex: 1;
min-height: 0;
width: 280px;
display: flex;
flex-direction: column;
background: var(--bg-secondary, #f8f9fa);
border-left: none;
overflow: hidden;
}
.sidebarHeader {
padding: 1rem;
border-bottom: 1px solid var(--border-color, #e0e0e0);
background: var(--bg-primary, #fff);
}
.sidebarTitle {
margin: 0;
font-size: 1rem;
font-weight: 600;
color: var(--text-primary, #1a1a1a);
}
.sidebarSearch {
margin-top: 0.75rem;
width: 100%;
padding: 0.5rem 0.75rem;
border: 1px solid var(--border-color, #e0e0e0);
border-radius: 6px;
font-size: 0.875rem;
background: var(--bg-primary, #fff);
color: var(--text-primary, #333);
}
.sidebarSearch::placeholder {
color: var(--text-tertiary, #999);
}
.sidebarSearch:focus {
outline: none;
border-color: var(--primary-color, #007bff);
box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.15);
}
.nodeList {
flex: 1;
overflow-y: auto;
padding: 0.5rem;
}
/* Category Groups */
.categoryGroup {
margin-bottom: 1rem;
}
.categoryHeader {
display: flex;
align-items: center;
padding: 0.5rem 0.75rem;
font-size: 0.75rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--text-secondary, #666);
}
.categoryIcon {
margin-right: 0.5rem;
font-size: 0.875rem;
}
.categoryLabel {
flex: 1;
}
.categoryCount {
background: var(--bg-tertiary, #e9ecef);
color: var(--text-secondary, #666);
padding: 0.125rem 0.5rem;
border-radius: 10px;
font-size: 0.7rem;
}
/* Node Items */
.nodeItem {
display: flex;
align-items: center;
padding: 0.5rem 0.75rem;
margin-bottom: 0.25rem;
border-radius: 6px;
cursor: grab;
transition: background 0.15s;
border: 1px solid transparent;
position: relative;
}
.nodeItem:hover {
background: var(--bg-hover, #e9ecef);
}
.nodeItem:active {
cursor: grabbing;
}
.nodeItemIcon {
flex-shrink: 0;
width: 28px;
height: 28px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 6px;
margin-right: 0.75rem;
font-size: 0.875rem;
}
.nodeItemInfo {
flex: 1;
min-width: 0;
}
.nodeItemLabelRow {
display: flex;
align-items: center;
justify-content: space-between;
gap: 0.35rem;
width: 100%;
}
.nodeItemLabel {
display: block;
flex: 1;
min-width: 0;
font-size: 0.875rem;
font-weight: 500;
color: var(--text-primary, #333);
}
.nodeItemDesc {
display: block;
font-size: 0.75rem;
color: var(--text-secondary, #666);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.nodeItem .nodeItemTooltip {
display: none;
position: absolute;
left: 0;
top: 100%;
z-index: 100;
background: var(--bg-primary, #fff);
border: 1px solid var(--border-color, #e0e0e0);
border-radius: 6px;
padding: 0.5rem 0.75rem;
font-size: 0.75rem;
color: var(--text-primary, #333);
white-space: normal;
word-break: break-word;
max-width: 280px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
pointer-events: none;
}
.nodeItem:hover .nodeItemTooltip {
display: block;
}
/* Loading / Error */
.loading,
.error {
padding: 2rem;
text-align: center;
color: var(--text-secondary, #666);
}
.error {
color: var(--danger-color, #dc3545);
}
.retryButton {
margin-top: 0.75rem;
padding: 0.5rem 1rem;
background: var(--primary-color, #007bff);
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 0.875rem;
}
.retryButton:hover {
background: var(--primary-hover, #0056b3);
}
.spinner {
animation: spin 1s linear infinite;
}
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
/* =============================================================================
CANVAS
============================================================================= */
.canvas {
flex: 1;
display: flex;
flex-direction: column;
min-width: 0;
background: var(--canvas-bg, #fafafa);
}
.canvasHeader {
flex-shrink: 0;
padding: 0.75rem 1rem;
border-bottom: 1px solid var(--border-color, #e0e0e0);
background: var(--bg-primary, #fff);
}
/* Toolbar: context (load + name) is fluid with ellipsis; actions stay right-aligned. */
.canvasHeaderRow {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
gap: 0.75rem;
align-items: center;
width: 100%;
}
@media (max-width: 900px) {
.canvasHeaderRow {
grid-template-columns: 1fr;
}
}
.canvasHeaderContext {
display: flex;
align-items: center;
gap: 0.5rem;
min-width: 0;
flex: 1;
}
/* Closed <select> width must not follow the longest option label. */
.canvasHeaderWorkflowSelect {
flex: 0 0 auto;
width: 12.5rem;
max-width: 100%;
padding: 0.4rem 0.5rem;
min-height: 2rem;
font-size: 0.85rem;
border: 1px solid var(--border-color, #ccc);
border-radius: 6px;
background: var(--bg-primary, #fff);
color: var(--text-primary, #333);
}
.canvasHeaderTitleBlock {
flex: 1 1 8rem;
min-width: 0;
display: flex;
align-items: center;
gap: 0.25rem;
}
.canvasHeaderTitle,
.canvasHeaderTitle input {
margin: 0;
min-width: 0;
font-size: 0.95rem;
font-weight: 600;
color: var(--text-primary, #1a1a1a);
}
.canvasHeaderTitle {
line-height: 1.2;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.canvasHeaderTitleMuted {
font-style: italic;
font-weight: 500;
opacity: 0.65;
color: var(--text-secondary, #666);
}
.canvasHeaderTitle input {
width: 100%;
max-width: 100%;
padding: 0.25rem 0.4rem;
border: 1px solid var(--primary-color, #007bff);
border-radius: 4px;
outline: none;
background: var(--bg-primary, #fff);
box-sizing: border-box;
}
.canvasHeaderActionPanel {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: flex-end;
gap: 0.4rem;
padding: 0.35rem 0.5rem;
border-radius: 8px;
border: 1px solid var(--border-color, #e0e0e0);
background: var(--bg-secondary, #f8f9fa);
flex: 0 1 auto;
max-width: 100%;
}
/* .retryButton sets margin-top for legacy error stacks — not wanted in the toolbar. */
.canvasHeaderActionPanel button {
margin-top: 0;
}
/* Run label switches between "Ausführen", "Ausführen…", "Pflicht-Felder fehlen" — reserve space. */
.canvasHeaderRunButton {
min-width: 12.5rem;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 0.25rem;
}
@media (max-width: 900px) {
.canvasHeaderActionPanel {
justify-content: flex-start;
}
}
.canvasHeaderVersionRow {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 0.5rem;
margin-top: 0.5rem;
padding-top: 0.5rem;
border-top: 1px solid var(--border-color, #e8e8e8);
width: 100%;
}
.canvasHeaderVersionRow button {
margin-top: 0;
}
.canvasHeaderVersionLabel {
font-size: 0.8rem;
font-weight: 600;
color: var(--text-secondary, #666);
flex: 0 0 auto;
}
.canvasHeaderVersionSelect {
width: 11rem;
max-width: 100%;
padding: 0.3rem 0.45rem;
font-size: 0.85rem;
min-height: 1.9rem;
border: 1px solid var(--border-color, #ccc);
border-radius: 4px;
background: var(--bg-primary, #fff);
color: var(--text-primary, #333);
}
.canvasHeaderSysadmin {
display: inline-flex;
align-items: center;
gap: 0.35rem;
font-size: 0.75rem;
color: var(--text-secondary, #666);
padding: 0.2rem 0.45rem;
border: 1px dashed var(--border-color, #ccc);
border-radius: 4px;
cursor: pointer;
user-select: none;
white-space: nowrap;
flex: 0 0 auto;
}
.canvasHeaderNewSplit {
position: relative;
display: inline-flex;
flex: 0 0 auto;
}
.canvasHeaderSplitPair {
display: flex;
flex: 0 0 auto;
}
.canvasHeaderNewSplitMain {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.canvasHeaderNewSplitMenu {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
padding-left: 0.25rem;
padding-right: 0.4rem;
border-left: 1px solid rgba(0, 0, 0, 0.12);
}
.canvasHeaderMenuDropdown {
position: absolute;
top: 100%;
left: 0;
z-index: 100;
background: var(--bg-primary, #fff);
border: 1px solid var(--border-color, #e0e0e0);
border-radius: 6px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
min-width: 11rem;
margin-top: 0.25rem;
}
.canvasHeaderMenuItem {
display: block;
width: 100%;
text-align: left;
padding: 0.5rem 0.75rem;
border: none;
background: transparent;
cursor: pointer;
font-size: 0.85rem;
color: var(--text-primary, #333);
}
.canvasHeaderMenuItem:hover {
background: var(--bg-hover, #e9ecef);
}
.canvasHeaderMenuItem + .canvasHeaderMenuItem {
border-top: 1px solid var(--border-color, #e0e0e0);
}
.canvasTitle {
margin: 0;
font-size: 0.875rem;
font-weight: 500;
color: var(--text-secondary, #666);
}
.canvasArea {
flex: 1;
padding: 2rem;
min-height: 400px;
overflow: hidden;
}
.canvasDropZone {
position: relative;
min-height: 100%;
height: 100%;
overflow: hidden;
border-radius: 8px;
/* Infinite grid: on viewport, moves with pan/zoom via inline style */
background-image: radial-gradient(circle, var(--canvas-grid, var(--border-color, #e0e0e0)) 1px, transparent 1px);
background-repeat: repeat;
}
.canvasContent {
position: absolute;
left: 0;
top: 0;
will-change: transform;
background: transparent;
}
.canvasGrab {
cursor: grab;
}
.canvasPanning {
cursor: grabbing;
user-select: none;
}
.canvasSelecting {
user-select: none;
}
.selectionBox {
position: absolute;
left: 0;
top: 0;
border: 2px dashed var(--primary-color, #007bff);
background: rgba(0, 123, 255, 0.08);
pointer-events: none;
z-index: 5;
}
.connectionHint {
position: absolute;
left: 50%;
top: 0.75rem;
transform: translateX(-50%);
padding: 0.4rem 0.75rem;
font-size: 0.8rem;
color: var(--primary-color, #007bff);
background: rgba(0, 123, 255, 0.1);
border: 1px solid rgba(0, 123, 255, 0.3);
border-radius: 6px;
z-index: 10;
pointer-events: none;
}
.connectionHint kbd {
padding: 0.15rem 0.35rem;
font-size: 0.75rem;
background: var(--bg-secondary, #f8f9fa);
border: 1px solid var(--border-color, #dee2e6);
border-radius: 4px;
}
.canvasPlaceholder {
position: absolute;
left: 2rem;
top: 2rem;
text-align: center;
color: var(--text-tertiary, #999);
border: 2px dashed var(--border-color, #dee2e6);
border-radius: 8px;
padding: 2rem 3rem;
}
.canvasPlaceholder p {
margin: 0.25rem 0;
font-size: 0.875rem;
}
/* Canvas Nodes */
.canvasNode {
position: absolute;
border-radius: 8px;
border: 2px solid;
cursor: grab;
overflow: visible;
}
.canvasNode:active {
cursor: grabbing;
}
.canvasNodeSelected {
box-shadow: 0 0 0 2px var(--primary-color, #007bff);
}
.canvasNodeHighlighted {
transition: border-color 0.3s ease, background-color 0.3s ease, box-shadow 0.3s ease;
}
@keyframes pulseGlow {
0%, 100% { opacity: 1; }
50% { opacity: 0.6; }
}
.canvasNodeHighlighted[style*="box-shadow"] {
animation: pulseGlow 1.5s ease-in-out infinite;
}
.canvasNodeContent {
display: flex;
align-items: flex-start;
gap: 0.5rem;
padding: 0.4rem 0.6rem;
height: 100%;
box-sizing: border-box;
}
.canvasNodeIcon {
flex-shrink: 0;
width: 32px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 6px;
font-size: 0.9rem;
}
.canvasNodeText {
flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
gap: 0.15rem;
}
.canvasNodeTitle {
font-size: 0.875rem;
font-weight: 500;
color: var(--text-primary, #333);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
cursor: text;
}
.canvasNodeTitle:hover {
text-decoration: underline;
}
.canvasNodeComment {
font-size: 0.7rem;
color: var(--text-tertiary, #999);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
line-height: 1.2;
}
.canvasNode .canvasNodeCommentTooltip {
display: none;
position: absolute;
left: 50%;
transform: translateX(-50%);
bottom: calc(100% + 6px);
z-index: 100;
background: var(--bg-primary, #fff);
border: 1px solid var(--border-color, #e0e0e0);
border-radius: 6px;
padding: 0.4rem 0.6rem;
font-size: 0.75rem;
color: var(--text-primary, #333);
white-space: normal;
word-break: break-word;
max-width: 260px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
pointer-events: none;
}
.canvasNode:hover .canvasNodeCommentTooltip {
display: block;
}
.canvasNodeInput {
width: 100%;
padding: 0.15rem 0.25rem;
font-size: 0.875rem;
border: 1px solid var(--primary-color, #007bff);
border-radius: 4px;
outline: none;
}
/* Connection Handles */
.handleWrapper {
position: absolute;
display: flex;
align-items: center;
gap: 4px;
z-index: 2;
}
.handleWrapper:has(.handleOutput) {
flex-direction: row;
}
.handleWrapper:has(.handleInput) {
flex-direction: row-reverse;
}
.handleLabel {
font-size: 0.65rem;
color: var(--text-secondary, #666);
white-space: nowrap;
pointer-events: none;
}
.handle {
flex-shrink: 0;
border-radius: 50%;
background: var(--bg-primary, #fff);
border: 2px solid var(--border-color, #666);
cursor: crosshair;
}
.handle:hover,
.handleConnectable {
border-color: var(--primary-color, #007bff);
background: var(--primary-color, #007bff);
}
.handleInput {
cursor: copy;
}
/* Node Config Panel
* Fixed-width side panel. The `box-sizing: border-box` + `overflow-x: hidden`
* pair acts as a safety net so long unbreakable strings (type names like
* `List[ActionDocument]`, hashed IDs, refs like `← node.path → field`) can
* never push content out of the panel frame. Children rely on this; e.g.
* `RequiredAttributePicker` lays out label/badge so the badge wraps below
* a long label rather than escaping to the right.
*/
.nodeConfigPanel {
padding: 1rem;
background: var(--bg-primary, #fff);
border-left: 1px solid var(--border-color, #e0e0e0);
width: 280px;
flex-shrink: 0;
box-sizing: border-box;
overflow-y: auto;
overflow-x: hidden;
min-width: 0;
overflow-wrap: anywhere;
word-break: break-word;
}
.nodeConfigPanel h4 {
margin: 0 0 0.75rem 0;
font-size: 0.9rem;
overflow-wrap: anywhere;
}
.nodeConfigNameRow {
margin-bottom: 1rem;
padding-bottom: 1rem;
border-bottom: 1px solid var(--border-color, #e8e8e8);
}
.nodeConfigNameRow label {
display: block;
font-size: 0.75rem;
color: var(--text-secondary, #666);
margin-bottom: 0.25rem;
}
.nodeConfigNameHint {
margin: 0.35rem 0 0;
font-size: 0.7rem;
color: var(--text-tertiary, #999);
}
.nodeConfigDescription {
margin: -0.5rem 0 0.75rem;
font-size: 0.75rem;
color: var(--text-secondary, #666);
line-height: 1.4;
overflow-wrap: anywhere;
word-break: break-word;
}
.nodeConfigPanel label {
display: block;
font-size: 0.75rem;
color: var(--text-secondary, #666);
margin-top: 0.5rem;
margin-bottom: 0.25rem;
}
.nodeConfigPanel input[type='text'],
.nodeConfigPanel input[type='number']:not(.scheduleNumberInput),
.nodeConfigPanel select:not(.scheduleSelect):not(.scheduleUnitSelect),
.nodeConfigPanel textarea {
width: 100%;
padding: 0.4rem;
font-size: 0.875rem;
border: 1px solid var(--border-color, #e0e0e0);
border-radius: 4px;
}
.nodeConfigPanel textarea {
min-height: 60px;
}
/* Kein Primär-Button-Stil für Zeitplan-Karten / Wochentage / Monat-Jahr-Chips
(DataPicker-Dialog wird per createPortal an document.body gehangen — nicht hier). */
.nodeConfigPanel
button:not(.scheduleModeCard):not(.scheduleDayOn):not(.scheduleDayOff):not(.scheduleSubModeBtn) {
margin-top: 0.5rem;
padding: 0.4rem 0.75rem;
font-size: 0.8rem;
background: var(--primary-color, #007bff);
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
/* Form fields editor (input.form) */
.formFieldsList {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.formFieldRow {
display: flex;
flex-direction: column;
gap: 0.35rem;
padding: 0.5rem;
background: var(--bg-secondary, #f8f9fa);
border-radius: 6px;
border: 1px solid var(--border-color, #e0e0e0);
}
.formFieldRowHeader {
display: flex;
align-items: flex-start;
gap: 0.35rem;
}
.formFieldDragHandle {
flex-shrink: 0;
padding: 0.25rem;
cursor: grab;
color: var(--text-tertiary, #999);
align-self: stretch;
display: flex;
align-items: center;
}
.formFieldDragHandle:active {
cursor: grabbing;
}
.formFieldDragHandle:hover {
color: var(--text-secondary, #666);
}
.formFieldInputs {
flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
gap: 0.35rem;
}
.formFieldRowFooter {
display: flex;
align-items: center;
gap: 0.5rem;
flex-wrap: wrap;
}
.formFieldRequiredLabel {
display: inline-flex;
align-items: center;
gap: 0.35rem;
font-size: 0.75rem;
color: var(--text-secondary, #666);
cursor: pointer;
}
.formFieldRemoveButton {
margin-left: auto;
padding: 0.25rem 0.4rem;
border: none;
background: transparent;
color: var(--text-tertiary, #999);
cursor: pointer;
border-radius: 4px;
display: flex;
align-items: center;
}
.formFieldRemoveButton:hover {
color: var(--danger-color, #dc3545);
background: rgba(220, 53, 69, 0.1);
}
/* Upload node config */
.uploadNodeConfig {
display: flex;
flex-direction: column;
gap: 1rem;
}
.uploadNodeConfig .configBlock {
display: flex;
flex-direction: column;
gap: 0.35rem;
}
.uploadNodeConfig .configBlock label {
font-size: 0.875rem;
font-weight: 500;
}
.uploadNodeConfig .configHint {
font-size: 0.8rem;
color: var(--text-secondary, #666);
margin: 0;
}
.uploadNodeConfig .fileTypeChips {
display: flex;
flex-wrap: wrap;
gap: 0.4rem;
}
.uploadNodeConfig .fileTypeChip {
display: inline-flex;
align-items: center;
gap: 0.35rem;
padding: 0.35rem 0.6rem;
background: var(--bg-secondary, #f8f9fa);
border: 1px solid var(--border-color, #e0e0e0);
border-radius: 6px;
font-size: 0.8rem;
cursor: pointer;
}
.uploadNodeConfig .fileTypeChip:hover {
border-color: var(--primary-color, #007bff);
background: rgba(0, 123, 255, 0.06);
}
.uploadNodeConfig .fileTypeChip input {
margin: 0;
}
.uploadNodeConfig .configBlock input[type='number'] {
max-width: 6rem;
}
/* Start node (trigger) — documentation panel */
.startNodeDoc {
font-size: 0.85rem;
line-height: 1.45;
color: var(--text-secondary, #555);
}
.startNodeDocIntro {
margin: 0 0 0.75rem;
}
.startNodeDocSub {
margin: 0 0 1rem;
font-size: 0.8rem;
}
.startNodeDoc code {
font-size: 0.8rem;
background: var(--bg-hover, #f0f0f0);
padding: 0.1rem 0.35rem;
border-radius: 4px;
}
.startNodeSchema {
border: 1px solid var(--border-color, #ddd);
border-radius: 8px;
overflow: hidden;
background: var(--bg-secondary, #fafafa);
}
.startNodeSchemaTitle {
padding: 0.4rem 0.65rem;
font-size: 0.75rem;
font-weight: 600;
color: var(--text-tertiary, #888);
border-bottom: 1px solid var(--border-color, #eee);
}
.startNodePre {
margin: 0;
padding: 0.65rem;
font-size: 0.72rem;
overflow-x: auto;
white-space: pre;
color: var(--text-primary, #333);
}
.formFieldsList {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
/* Schedule (Zeitplan) — Karten + Konfiguration unter Auswahl */
.schedulePanel {
display: flex;
flex-direction: column;
gap: 1rem;
font-size: 0.85rem;
line-height: 1.45;
color: var(--text-secondary, #555);
}
.scheduleModeStack {
display: flex;
flex-direction: column;
gap: 0.6rem;
position: relative;
}
/*
* Ohne gestaffeltes z-index können layout-Animationen / Exit-Layer Klicks „verschlucken“
* (Klick auf „Intervall“ trifft fälschlich die oberste Karte). Spätere Karten liegen oben.
*/
.scheduleModeStack .scheduleModeBlock:nth-child(1) {
z-index: 1;
}
.scheduleModeStack .scheduleModeBlock:nth-child(2) {
z-index: 2;
}
.scheduleModeStack .scheduleModeBlock:nth-child(3) {
z-index: 3;
}
.scheduleModeStack .scheduleModeBlock:nth-child(4) {
z-index: 4;
}
.scheduleModeStack .scheduleModeBlock:nth-child(5) {
z-index: 5;
}
/* Inaktiv: neutrale Flächen — NICHT --color-bg / --color-secondary (oft Brand-Orange im Theme) */
.scheduleModeBlock {
position: relative;
/* Ausgewählte Karte (orange) + Text auf „An“-Chips im erweiterten Bereich */
--schedule-active: var(--schedule-mode-active, var(--color-secondary));
--schedule-active-border: var(--schedule-mode-active-border, var(--color-text));
display: flex;
flex-direction: column;
gap: 0;
border-radius: 8px;
border: 1px solid var(--color-border, #E2E8F0);
background-color: var(--bg-primary, #fff);
color: var(--color-text, #222);
overflow: hidden;
transition:
border-color 0.38s cubic-bezier(0.33, 1, 0.68, 1),
background-color 0.38s cubic-bezier(0.33, 1, 0.68, 1),
color 0.32s ease;
}
.scheduleModeBlock:hover:not(.scheduleModeBlockActive) {
border-color: var(--color-text);
background-color: var(--color-bg, #f5f5f5);
}
.scheduleModeBlockActive {
z-index: 20;
border-color: var(--schedule-active-border);
background-color: var(--color-secondary);
color: #fff;
}
.scheduleModeConfigShell {
min-height: 0;
will-change: height, opacity;
/* Klicks gehen durch den Shell-Rand; Inhalt bleibt bedienbar */
pointer-events: none;
}
.scheduleModeConfigShell .scheduleModeConfig {
pointer-events: auto;
}
/* Kopfzeile: kein eigener Rahmen — Rahmen sitzt auf .scheduleModeBlock */
.scheduleModeCard {
display: flex;
flex-direction: column;
align-items: stretch;
text-align: left;
width: 100%;
padding: 0.65rem 0.85rem;
margin: 0;
background: transparent;
border: none;
border-radius: 0;
cursor: pointer;
color: inherit;
font: inherit;
transition: opacity 0.2s ease;
}
.scheduleModeBlock:not(.scheduleModeBlockActive) .scheduleModeCard:focus-visible {
outline: 2px solid var(--accent-color, #1a73e8);
outline-offset: 2px;
}
.scheduleModeBlockActive .scheduleModeCard:focus-visible {
outline: 2px solid rgba(255, 255, 255, 0.95);
outline-offset: 2px;
}
.scheduleModeCardTitle {
font-weight: 600;
font-size: 0.9rem;
color: var(--text-primary, #222);
transition: color 0.32s ease;
}
.scheduleModeCardSubtitle {
display: block;
margin-top: 0.2rem;
font-size: 0.78rem;
font-weight: 400;
color: var(--text-secondary, #666);
line-height: 1.35;
transition: color 0.32s ease;
}
.scheduleModeBlockActive .scheduleModeCardTitle,
.scheduleModeBlockActive .scheduleModeCardSubtitle {
color: #fff;
}
.scheduleModeConfig {
margin-top: 0;
padding: 0.75rem 0.85rem 0.85rem;
border: none;
border-radius: 0;
border-top: 1px solid rgba(0, 0, 0, 0.08);
background: transparent;
display: flex;
flex-direction: column;
gap: 0.75rem;
}
.scheduleModeBlockActive .scheduleModeConfig {
border-top-color: rgba(255, 255, 255, 0.35);
}
/* Erweiterte Fläche: Beschriftungen hell; Steuerelemente bleiben heller Hintergrund */
.scheduleModeBlockActive .scheduleFieldLabel {
color: rgba(255, 255, 255, 0.95);
}
.scheduleModeBlockActive .scheduleSubModeBtn {
border-color: rgba(255, 255, 255, 0.45);
background: rgba(255, 255, 255, 0.12);
color: #fff;
}
.scheduleModeBlockActive .scheduleSubModeBtnOn {
border-color: #fff;
background: #fff;
color: var(--schedule-active);
font-weight: 600;
}
.scheduleModeBlockActive .scheduleDayOff {
border-color: rgba(255, 255, 255, 0.45);
background: rgba(255, 255, 255, 0.1);
color: #fff;
}
.scheduleModeBlockActive .scheduleDayOff:hover {
background: rgba(255, 255, 255, 0.2);
}
.scheduleModeBlockActive .scheduleDayOn {
background: #fff;
border-color: #fff;
color: var(--schedule-active);
font-weight: 600;
}
.scheduleFieldRow {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 0.5rem 1rem;
}
.scheduleFieldCol {
display: flex;
flex-direction: column;
gap: 0.45rem;
}
.scheduleFieldLabel {
min-width: 6.5rem;
font-weight: 500;
font-size: 0.82rem;
color: var(--text-primary, #333);
margin-right: 0.5rem;
}
.scheduleFieldRowGrow {
display: flex;
flex-direction: column;
gap: 0.35rem;
flex: 1;
min-width: 0;
}
/*
* Zeitplan: Uhrzeit, Selects, Intervall-Zahl — .nodeConfigPanel select/number hatte
* höhere Spezifität; daher :not(...) bei der globalen Regel + hier .nodeConfigPanel …
*/
.nodeConfigPanel input[type='time'].scheduleTimeInput,
.nodeConfigPanel input[type='number'].scheduleNumberInput,
.nodeConfigPanel select.scheduleSelect,
.nodeConfigPanel select.scheduleUnitSelect {
box-sizing: border-box;
padding: 0.2rem 0.2rem;
width: auto;
max-width: 100%;
flex: 0 0 auto;
border: none;
border-radius: 15px;
font-size: 0.95rem;
font-variant-numeric: tabular-nums;
color: var(--color-text);
background: var(--bg-primary, #fff);
}
.nodeConfigPanel select.scheduleSelect,
.nodeConfigPanel select.scheduleUnitSelect {
cursor: pointer;
}
/* Monatstag / Monat / Tag — kompakt, nicht volle Breite */
.nodeConfigPanel select.scheduleSelect {
min-width: 4.5rem;
max-width: 10rem;
}
.nodeConfigPanel select.scheduleUnitSelect {
min-width: 2.75rem;
max-width: 4rem;
}
.nodeConfigPanel input[type='time'].scheduleTimeInput {
max-width: 7.5rem;
}
.nodeConfigPanel input[type='number'].scheduleNumberInput {
width: 3.75rem;
min-width: 3.75rem;
max-width: 5rem;
}
.nodeConfigPanel input[type='time'].scheduleTimeInput:focus,
.nodeConfigPanel input[type='number'].scheduleNumberInput:focus,
.nodeConfigPanel select.scheduleSelect:focus,
.nodeConfigPanel select.scheduleUnitSelect:focus {
outline: none;
box-shadow: 0 0 0 2px rgba(26, 115, 232, 0.2);
}
.scheduleLabel {
min-width: 7rem;
font-weight: 500;
color: var(--text-primary, #333);
}
.scheduleSubModes {
display: flex;
flex-wrap: wrap;
gap: 0.4rem;
}
.scheduleSubModeBtn {
padding: 0.35rem 0.75rem;
border-radius: 15px;
border: 1px solid var(--border-color, #ccc);
background: var(--bg-secondary, #f5f5f5);
font-size: 0.8rem;
cursor: pointer;
color: var(--text-secondary, #555);
}
.scheduleSubModeBtnOn {
border-color: var(--accent-color, #1a73e8);
background: var(--accent-bg, #e8f0fe);
color: var(--accent-color, #1a73e8);
font-weight: 600;
}
.scheduleYearlyRow {
display: flex;
flex-wrap: wrap;
gap: 0.75rem 1rem;
align-items: flex-end;
}
.scheduleIntervalRow {
display: flex;
flex-wrap: nowrap;
align-items: center;
gap: 0.5rem 0.65rem;
min-width: 0;
}
/* „Alle“ + Zahl + Einheit — eine Zeile; Label nicht 6.5rem breit wie bei anderen Feldern */
.scheduleIntervalRow .scheduleFieldLabel {
min-width: 0;
margin-right: 0;
flex-shrink: 0;
white-space: nowrap;
}
.scheduleWeekdayToggles {
display: flex;
flex-wrap: wrap;
gap: 0.35rem;
}
.scheduleDayOn,
.scheduleDayOff {
min-width: 2.35rem;
padding: 0.4rem 0.55rem;
border-radius: 8px;
border: 1px solid var(--schedule-wd-off-border);
font-size: 0.8rem;
font-weight: 500;
cursor: pointer;
background: var(--schedule-wd-off-bg);
color: var(--schedule-wd-off-text);
transition:
background 0.2s ease,
border-color 0.2s ease,
color 0.2s ease;
}
.scheduleDayOn {
background: var(--schedule-wd-on-bg);
border-color: var(--schedule-wd-on-border);
color: var(--schedule-wd-on-text);
font-weight: 600;
}
.scheduleDayOff:hover {
background: var(--hover-bg, rgba(0, 0, 0, 0.05));
border-color: var(--border-dark, #d0d0d0);
}
.scheduleDayOn:hover {
filter: brightness(0.96);
}
.scheduleCronPreview {
display: flex;
flex-direction: column;
gap: 0.35rem;
padding: 0.65rem 0.75rem;
border: 1px dashed var(--border-color, #ccc);
border-radius: 8px;
background: var(--bg-secondary, #fafafa);
}
.scheduleCronCode {
font-size: 0.78rem;
padding: 0.35rem 0.5rem;
background: var(--bg-hover, #f0f0f0);
border-radius: 4px;
word-break: break-all;
}
.scheduleCronNote {
font-size: 0.75rem;
color: var(--text-tertiary, #888);
}
/* Workflow configuration modal (gear) */
.workflowModalBackdrop {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.45);
z-index: 1000;
display: flex;
align-items: center;
justify-content: center;
padding: 1rem;
}
.workflowModal {
background: var(--bg-primary, #fff);
border-radius: 10px;
max-width: 420px;
width: 100%;
padding: 1.25rem;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15);
}
.workflowModalTitle {
margin: 0 0 0.5rem;
font-size: 1.1rem;
}
.workflowModalHint {
margin: 0 0 1rem;
font-size: 0.82rem;
color: var(--text-secondary, #666);
line-height: 1.45;
}
.workflowModalLabel {
display: block;
font-size: 0.8rem;
font-weight: 600;
margin-bottom: 0.35rem;
color: var(--text-primary, #333);
}
.workflowModalInput {
width: 100%;
padding: 0.45rem 0.55rem;
margin-bottom: 1rem;
border: 1px solid var(--border-color, #ccc);
border-radius: 6px;
font-size: 0.9rem;
box-sizing: border-box;
}
.workflowModalRadioGroup {
margin-bottom: 1rem;
}
.workflowModalSub {
font-size: 0.72rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.04em;
color: var(--text-tertiary, #888);
margin: 0.5rem 0 0.35rem;
}
.workflowModalRadio {
display: flex;
align-items: center;
gap: 0.45rem;
font-size: 0.85rem;
margin-bottom: 0.35rem;
cursor: pointer;
}
.workflowModalActions {
display: flex;
justify-content: flex-end;
gap: 0.5rem;
margin-top: 0.5rem;
}
.workflowModalBtnPrimary {
padding: 0.45rem 0.9rem;
border: none;
border-radius: 6px;
background: var(--primary-color, #007bff);
color: #fff;
font-size: 0.875rem;
cursor: pointer;
}
.workflowModalBtnSecondary {
padding: 0.45rem 0.9rem;
border: 1px solid var(--border-color, #ccc);
border-radius: 6px;
background: transparent;
font-size: 0.875rem;
cursor: pointer;
}
.canvasGearBtn {
display: inline-flex;
align-items: center;
justify-content: center;
width: 2rem;
height: 2rem;
padding: 0;
border: 1px solid var(--border-color, #ccc);
border-radius: 6px;
background: var(--bg-primary, #fff);
cursor: pointer;
font-size: 1rem;
}
.canvasGearBtn:hover {
background: var(--bg-hover, #f0f0f0);
}
.startsInput,
.startsSelect {
padding: 0.35rem 0.5rem;
font-size: 0.85rem;
border: 1px solid var(--border-color, #ccc);
border-radius: 4px;
min-width: 0;
}
/* Data Picker — rendered with createPortal(document.body) so it is not affected
by .nodeConfigPanels generic CTA `button` styles. */
.dataPickerOverlay {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.4);
display: flex;
align-items: center;
justify-content: center;
z-index: 11000;
padding: 1rem;
box-sizing: border-box;
}
.dataPickerModal {
background: var(--bg-primary, #fff);
color: var(--text-primary, #1a1a1a);
border-radius: 10px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12);
border: 1px solid var(--border-color, #e0e0e0);
max-width: min(420px, 100vw - 2rem);
width: 100%;
max-height: min(80vh, 640px);
display: flex;
flex-direction: column;
min-height: 0;
}
.dataPickerHeader {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 0.75rem;
padding: 1rem 1.15rem;
border-bottom: 1px solid var(--border-color, #e0e0e0);
flex-shrink: 0;
}
.dataPickerHeaderControls {
display: flex;
align-items: center;
gap: 0.5rem;
flex-wrap: wrap;
justify-content: flex-end;
}
.dataPickerTitle {
margin: 0;
font-size: 1rem;
font-weight: 600;
color: var(--text-primary, #1a1a1a);
line-height: 1.35;
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 0.5rem 0.4rem;
min-width: 0;
}
.dataPickerTypeBadge {
display: inline-block;
font-size: 0.7rem;
font-weight: 400;
font-family: ui-monospace, 'Cascadia Code', monospace;
color: var(--text-secondary, #666);
background: var(--bg-secondary, #f0f0f0);
border: 1px solid var(--border-color, #ddd);
border-radius: 4px;
padding: 0.1rem 0.45rem;
line-height: 1.2;
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.dataPickerStrictLabel {
display: inline-flex;
align-items: center;
gap: 0.3rem;
font-size: 0.7rem;
color: var(--text-secondary, #666);
user-select: none;
}
.dataPickerClose {
display: inline-flex;
align-items: center;
justify-content: center;
width: 2rem;
height: 2rem;
flex-shrink: 0;
background: var(--bg-secondary, #f5f5f5);
border: 1px solid var(--border-color, #d0d0d0);
border-radius: 6px;
font-size: 1.25rem;
line-height: 1;
cursor: pointer;
color: var(--text-primary, #333);
}
.dataPickerClose:hover {
background: var(--bg-hover, #e9ecef);
color: var(--text-primary, #1a1a1a);
border-color: var(--border-color, #b8b8b8);
}
.dataPickerBody {
padding: 1rem;
overflow-y: auto;
}
.dataPickerEmpty {
margin: 0;
color: var(--text-secondary, #666);
font-size: 0.875rem;
}
.dataPickerNodeSection {
margin-bottom: 0.5rem;
}
/* Expandable source row: neutral “list row”, not a primary CTA. */
.dataPickerNodeHeader {
display: flex;
align-items: center;
width: 100%;
box-sizing: border-box;
padding: 0.5rem 0.6rem;
background: var(--bg-secondary, #f4f5f7);
border: 1px solid var(--border-color, #dde1e5);
border-radius: 6px;
cursor: pointer;
font-size: 0.85rem;
text-align: left;
color: var(--text-primary, #1a1a1a);
margin: 0;
transition: background 0.12s, border-color 0.12s, box-shadow 0.12s;
}
.dataPickerNodeHeader:hover {
background: var(--bg-hover, #e9ebef);
border-color: var(--border-color, #c8cfd6);
}
.dataPickerNodeHeader:focus-visible {
outline: 2px solid var(--primary-color, #4a6fa5);
outline-offset: 1px;
}
.dataPickerExpandIcon {
margin-right: 0.5rem;
font-size: 0.7rem;
color: var(--text-secondary, #666);
}
.dataPickerNodeLabel {
font-weight: 500;
color: var(--text-primary, #333);
}
.dataPickerTree {
display: flex;
flex-direction: column;
gap: 0.25rem;
margin-left: 1.25rem;
margin-top: 0.35rem;
}
.dataPickerLeaf {
padding: 0.4rem 0.6rem;
background: none;
border: 1px solid transparent;
border-radius: 4px;
font-size: 0.8rem;
text-align: left;
cursor: pointer;
color: var(--text-primary, #333);
}
.dataPickerLeaf:hover {
background: var(--primary-color, #007bff);
color: #fff;
border-color: var(--primary-color, #007bff);
}
/* Hover safety net: every nested span in a leaf inherits the white text so
* type-hints and meta info stay readable on the blue hover background. */
.dataPickerLeaf:hover * {
color: inherit;
}
/* Inline type-hint after a leaf label, e.g. "documents (List[ActionDocument])". */
.dataPickerLeafType {
color: var(--text-secondary, #666);
font-size: 10px;
margin-left: 4px;
}
/* Schema-name hint on the node-section header row. */
.dataPickerNodeSchemaHint {
color: var(--text-secondary, #666);
font-size: 10px;
margin-left: 4px;
}
/* Type-mismatch warning badge (⚠) — shown instead of hiding incompatible fields. */
.dataPickerMismatchBadge {
font-size: 10px;
margin-left: 4px;
color: var(--color-warning, #f59e0b);
flex-shrink: 0;
}
/* Recommended pick: subtle highlight on the row */
.dataPickerLeafRecommended {
font-weight: 500;
}
/* "Empfohlen" pill shown on recommended entries */
.dataPickerRecommendedPill {
display: inline-block;
font-size: 9px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.03em;
padding: 1px 5px;
border-radius: 10px;
margin-left: 5px;
background: var(--color-primary-light, #dbeafe);
color: var(--color-primary, #2563eb);
flex-shrink: 0;
vertical-align: middle;
}
/* "iterieren" affordance — visually distinct (subtle accent), readable on
* the picker's white background and on the leaf's blue hover background. */
.dataPickerIterateBtn {
font-size: 10px;
padding: 2px 6px;
background: var(--bg-secondary, #f5f7fa);
color: var(--primary-color, #007bff);
border: 1px solid var(--border-color, #e0e0e0);
white-space: nowrap;
}
.dataPickerIterateBtn:hover {
background: var(--primary-color, #007bff);
color: #fff;
border-color: var(--primary-color, #007bff);
}
/* Curated picker: disclose technical / rare paths behind a single quiet control. */
.dataPickerCuratedToggle {
display: block;
width: 100%;
margin-top: 0.4rem;
padding: 0.38rem 0.55rem;
font-size: 0.72rem;
font-weight: 500;
color: var(--text-secondary, #5c6370);
background: var(--bg-primary, #fff);
border: 1px dashed var(--border-color, #cfd4dc);
border-radius: 5px;
cursor: pointer;
text-align: center;
transition: background 0.12s, color 0.12s, border-color 0.12s;
}
.dataPickerCuratedToggle:hover {
color: var(--text-primary, #333);
background: var(--bg-secondary, #f4f6f8);
border-color: var(--border-color, #b8c0cc);
}
.dataPickerCuratedDivider {
font-size: 0.65rem;
font-weight: 600;
letter-spacing: 0.04em;
text-transform: uppercase;
color: var(--text-secondary, #8a9199);
margin: 0.75rem 0 0.35rem 0;
padding-left: 0.15rem;
}
/* Dynamic Value Field */
.dynamicValueField {
display: flex;
flex-direction: column;
gap: 0.35rem;
}
.dynamicValueModeRow {
display: flex;
align-items: center;
gap: 0.5rem;
}
.dynamicValueModeBtn {
padding: 0.25rem 0.5rem;
font-size: 0.75rem;
border: 1px solid var(--border-color, #ccc);
border-radius: 4px;
background: var(--bg-primary, #fff);
cursor: pointer;
}
.dynamicValueModeBtnActive {
background: var(--primary-color, #007bff);
color: #fff;
border-color: var(--primary-color, #007bff);
}
.dynamicValueRefDisplay {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.5rem;
background: var(--bg-secondary, #f8f9fa);
border: 1px solid var(--border-color, #e0e0e0);
border-radius: 4px;
}
.dynamicValueRefLabel {
flex: 1;
font-size: 0.875rem;
color: var(--text-primary, #333);
}
.dynamicValuePickBtn {
padding: 0.35rem 0.6rem;
font-size: 0.75rem;
border: 1px solid var(--primary-color, #007bff);
border-radius: 4px;
background: transparent;
color: var(--primary-color, #007bff);
cursor: pointer;
}
.dynamicValuePickBtn:hover {
background: var(--primary-color, #007bff);
color: #fff;
}
.dynamicValueEmptyHint {
margin: 0;
font-size: 0.8rem;
color: var(--text-tertiary, #999);
}
/* If/Else Condition Editor - inline, no popup */
.ifElseConditionEditor {
display: flex;
flex-direction: column;
gap: 0.75rem;
}
.ifElseConditionRow {
display: flex;
flex-direction: column;
gap: 0.25rem;
}
.ifElseConditionRow label {
font-size: 0.75rem;
color: var(--text-secondary, #666);
}
.ifElseConditionRow select,
.ifElseConditionRow input {
width: 100%;
padding: 0.4rem;
font-size: 0.875rem;
border: 1px solid var(--border-color, #e0e0e0);
border-radius: 4px;
}
/* File Create - multiple content sources */
.fileCreateContentSources {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.fileCreateContentSources > label {
font-size: 0.75rem;
color: var(--text-secondary, #666);
}
.contentSourceRow {
display: flex;
gap: 0.25rem;
align-items: center;
}
.contentSourceRow select {
flex: 1;
min-width: 0;
padding: 0.4rem;
font-size: 0.875rem;
border: 1px solid var(--border-color, #e0e0e0);
border-radius: 4px;
}
.contentSourceRemoveBtn {
flex-shrink: 0;
width: 28px;
height: 28px;
padding: 0;
border: 1px solid var(--border-color, #e0e0e0);
border-radius: 4px;
background: var(--bg-primary, #fff);
color: var(--text-secondary, #666);
font-size: 1.2rem;
line-height: 1;
cursor: pointer;
}
.contentSourceRemoveBtn:hover {
background: var(--bg-secondary, #f8f9fa);
color: var(--danger-color, #dc3545);
}
.contentSourceAddBtn {
align-self: flex-start;
padding: 0.4rem 0.75rem;
font-size: 0.8rem;
border: 1px dashed var(--border-color, #e0e0e0);
border-radius: 4px;
background: var(--bg-primary, #fff);
color: var(--text-secondary, #666);
cursor: pointer;
}
.contentSourceAddBtn:hover {
border-color: var(--primary-color, #007bff);
color: var(--primary-color, #007bff);
}
/* Right panel tab bar (Nodes / Tracing) */
.rightTabBar {
display: flex;
border-bottom: 1px solid var(--border-color, #e0e0e0);
flex-shrink: 0;
background: var(--bg-primary, #fff);
}
.rightTab {
flex: 1;
padding: 8px;
border: none;
background: transparent;
cursor: pointer;
font-size: 12px;
font-weight: 600;
color: var(--text-secondary, #666);
transition: background 0.15s, color 0.15s;
}
.rightTab:hover {
background: var(--bg-hover, #f0f0f0);
}
.rightTabActive {
background: var(--bg-secondary, #f5f5f5);
color: var(--text-primary, #333);
box-shadow: inset 0 -2px 0 var(--primary-color, #007bff);
}