humainflow-web/src/app/shared/nodes/container-node/container-node.html

156 lines
6.5 KiB
HTML

<div class="container-node" [class.container-node-assigning]="isAssigning" [class.container-node-delete-pending]="deleteConfirmOpen">
@if (deleteConfirmOpen) {
<div class="container-node__delete-overlay"></div>
}
<div class="container-node__header" [class.cursor-move]="!isReadonly">
<div class="container-node__icon">
<i class="bi bi-box-seam"></i>
</div>
<div class="container-node__titles">
<div class="container-node__eyebrow">Generic Container</div>
<div class="container-node__name">{{ name }}</div>
</div>
<div class="container-node__header-actions">
@if (missingRequiredParams.length) {
<div class="container-node__warning-wrap">
<div class="container-node__warning">
<i class="bi bi-exclamation-triangle-fill"></i>
</div>
<div class="container-node__warning-tooltip">
<div class="container-node__warning-title">Missing required fields</div>
@for (missing of missingRequiredParams; track missing) {
<div class="container-node__warning-item">{{ missing }}</div>
}
</div>
</div>
}
@if (!isReadonly && deleteConfirmOpen) {
<div class="container-node__delete-confirm" (pointerdown)="$event.stopPropagation()" (click)="$event.stopPropagation()">
<span class="container-node__delete-confirm-text">Delete container?</span>
<button type="button" class="container-node__delete-confirm-cancel" (click)="cancelDelete($event)">Cancel</button>
<button type="button" class="container-node__delete-confirm-action" (click)="deleteNode($event)">Delete</button>
</div>
}
@if (!isReadonly) {
<button type="button" class="container-node__delete" title="Delete node" (pointerdown)="$event.stopPropagation()" (click)="deleteNode($event)">
<i class="bi bi-trash"></i>
</button>
}
</div>
</div>
<div class="container-node__ports">
<div class="container-node__port-column">
<div class="container-node__port-title">Inputs</div>
@for (input of inputs; track input.key) {
<div class="container-node__port-row">
<div
refComponent
class="container-node__socket"
[data]="{
type: 'socket',
side: 'input',
key: input.key,
nodeId: data.id,
__readonly: isReadonly,
payload: input.socket
}"
[emit]="emit">
</div>
<span class="container-node__port-label container-node__port-label--input">
@if (inputDisplayLabelParts(input.key).context; as context) {
<span class="container-node__port-context">{{ context }}</span>
}
<span class="container-node__port-name">{{ inputDisplayLabelParts(input.key).name }}</span>
<span class="container-node__port-kind">{{ inputKindLabel(input.key) }}</span>
</span>
</div>
}
</div>
<div class="container-node__port-column container-node__port-column--right">
<div class="container-node__port-title">Outputs</div>
@for (output of outputs; track output.key) {
<div class="container-node__port-row container-node__port-row--right">
<span class="container-node__port-label container-node__port-label--output">
@if (outputDisplayLabelParts(output.key).context; as context) {
<span class="container-node__port-context">{{ context }}</span>
}
<span class="container-node__port-name">{{ outputDisplayLabelParts(output.key).name }}</span>
<span class="container-node__port-kind">{{ outputKindLabel(output.key) }}</span>
</span>
<div
refComponent
class="container-node__socket container-node__socket--right"
[data]="{
type: 'socket',
side: 'output',
key: output.key,
nodeId: data.id,
__readonly: isReadonly,
payload: output.socket
}"
[emit]="emit">
</div>
</div>
}
</div>
</div>
<div
class="container-node__dropzone"
[class.container-node__dropzone--active]="!isReadonly && selectedCount > 0"
[class.container-node__dropzone--filled]="subFlowBlockCount > 0"
(dragover)="onDropZoneDragOver($event)"
(dragleave)="onDropZoneDragLeave($event)"
(drop)="onDropZoneDrop($event)">
@if (replaceConfirmOpen) {
<div class="container-node__replace-confirm" (pointerdown)="$event.stopPropagation()" (click)="$event.stopPropagation()">
<div class="container-node__replace-confirm-text">Replace current subflow?</div>
<div class="container-node__replace-confirm-note">The existing embedded flow will be removed and replaced by the dropped selection.</div>
<div class="container-node__replace-confirm-actions">
<button type="button" class="container-node__replace-confirm-cancel" (click)="cancelReplaceSubflow($event)">Cancel</button>
<button type="button" class="container-node__replace-confirm-action" (click)="confirmReplaceSubflow($event)">Replace</button>
</div>
</div>
} @else if (isAssigning) {
<div class="container-node__dropzone-main">
<span class="container-node__spinner" aria-hidden="true"></span>
<span>Updating container...</span>
</div>
} @else {
<div class="container-node__dropzone-main">
<span class="container-node__dropzone-empty">Drag a flow here or import from flow</span>
</div>
<div class="container-node__dropzone-note">
Use the selection box in the editor, then drag the floating selection badge into this area.
</div>
}
@if (subFlowBlockCount > 0 && !replaceConfirmOpen && !isAssigning) {
<div class="container-node__dropzone-actions">
<button type="button" class="container-node__subflow-view" (pointerdown)="$event.stopPropagation()" (click)="openSubflowPreview($event)">
View Flow
</button>
</div>
}
@if (!isReadonly && !replaceConfirmOpen && !isAssigning) {
<div class="container-node__dropzone-actions">
<button type="button" class="container-node__import" (pointerdown)="$event.stopPropagation()" (click)="importSubflow($event)">
@if (importLoading) {
<span class="container-node__spinner" aria-hidden="true"></span>
<span>Loading flows...</span>
} @else {
<span>Import flow</span>
}
</button>
</div>
}
</div>
@if (assignmentErrorMessage) {
<div class="container-node__message container-node__message--error">
{{ assignmentErrorMessage }}
</div>
}
</div>