612 lines
24 KiB
HTML
612 lines
24 KiB
HTML
@if (focusOpen) {
|
|
<div class="llm-node__focus-backdrop" (pointerdown)="$event.stopPropagation()" (click)="closeFocus($event)"></div>
|
|
}
|
|
<div class="llm-node"
|
|
[class.llm-node-error]="hasUpdateBlockError()"
|
|
[class.llm-node-delete-pending]="deleteConfirmOpen"
|
|
[class.llm-node--human]="isHumanNode()"
|
|
[class.llm-node--focus]="focusOpen"
|
|
(pointerdown)="focusOpen && $event.stopPropagation()"
|
|
(click)="focusOpen && $event.stopPropagation()">
|
|
@if (isCreatingOnServer()) {
|
|
<div class="llm-loading-overlay">
|
|
<div class="llm-loading-chip">
|
|
<span class="llm-spinner" aria-hidden="true"></span>
|
|
<span>Updating block...</span>
|
|
</div>
|
|
</div>
|
|
}
|
|
@if (isSchemaLoading && !isCreatingOnServer()) {
|
|
<div class="llm-loading-overlay">
|
|
<div class="llm-loading-chip">
|
|
<span class="llm-spinner" aria-hidden="true"></span>
|
|
<span>Loading block...</span>
|
|
</div>
|
|
</div>
|
|
}
|
|
@if (deleteConfirmOpen) {
|
|
<div class="llm-delete-overlay"></div>
|
|
}
|
|
<div class="llm-header" [class.cursor-move]="!isReadonly">
|
|
<div class="llm-icon">
|
|
@if (nodeIcon().type === 'class') {
|
|
<i [class]="nodeIcon().value"></i>
|
|
} @else {
|
|
<img [src]="nodeIcon().value" alt="Node" class="llm-icon-image" />
|
|
}
|
|
</div>
|
|
<div class="llm-header-content">
|
|
<span class="llm-title">{{ nodeTitle() }}</span>
|
|
<div class="llm-subtitle-row">
|
|
<span class="llm-subtitle">{{ name }}</span>
|
|
@if (!isReadonly) {
|
|
<button type="button" class="llm-name-edit-btn" title="Edit name" (pointerdown)="$event.stopPropagation()" (click)="openNameEditor($event)">
|
|
<i class="bi bi-pencil-square"></i>
|
|
</button>
|
|
}
|
|
</div>
|
|
<div class="llm-node-id">{{ nodeIdLabel }}</div>
|
|
</div>
|
|
<div class="llm-header-actions">
|
|
@if (hasUpdateBlockError()) {
|
|
<div class="llm-error-alert-wrap">
|
|
<div class="llm-error-alert">
|
|
<i class="bi bi-exclamation-circle-fill"></i>
|
|
</div>
|
|
<div class="llm-error-tooltip">
|
|
<div class="llm-error-title">Block update failed</div>
|
|
<div class="llm-error-item">{{ updateBlockErrorMessage() }}</div>
|
|
</div>
|
|
</div>
|
|
}
|
|
@if (missingRequiredParams.length) {
|
|
<div class="llm-warning-wrap">
|
|
<div class="llm-warning">
|
|
<i class="bi bi-exclamation-triangle-fill"></i>
|
|
</div>
|
|
<div class="llm-warning-tooltip">
|
|
<div class="llm-warning-title">Missing required fields</div>
|
|
@for (missing of missingRequiredParams; track missing) {
|
|
<div class="llm-warning-item">{{ missing }}</div>
|
|
}
|
|
</div>
|
|
</div>
|
|
}
|
|
@if (biasAnnotationBadge; as biasBadge) {
|
|
<div class="llm-bias-badge-wrap" [class.llm-bias-badge-wrap-probe]="biasBadge.hasExecutableProbe">
|
|
<div class="llm-bias-badge">
|
|
<i class="bi bi-clipboard2-pulse-fill"></i>
|
|
<span>{{ biasBadge.count }}</span>
|
|
</div>
|
|
<div class="llm-bias-badge-tooltip">
|
|
<div class="llm-bias-badge-title">
|
|
{{ biasBadge.count }} bias annotation{{ biasBadge.count === 1 ? '' : 's' }}@if (biasBadge.maxSeverityLabel) {, max severity: {{ biasBadge.maxSeverityLabel }}}
|
|
</div>
|
|
@if (biasBadge.hasExecutableProbe) {
|
|
<div class="llm-bias-badge-item">Includes an executable behavioral probe</div>
|
|
}
|
|
</div>
|
|
</div>
|
|
}
|
|
@if (!isReadonly && deleteConfirmOpen) {
|
|
<div class="llm-delete-confirm" (pointerdown)="$event.stopPropagation()" (click)="$event.stopPropagation()">
|
|
<span class="llm-delete-confirm-text">Delete node?</span>
|
|
<button type="button" class="llm-delete-confirm-cancel" (click)="cancelDelete($event)">Cancel</button>
|
|
<button type="button" class="llm-delete-confirm-action" (click)="confirmDelete($event)">Delete</button>
|
|
</div>
|
|
}
|
|
@if (!isReadonly) {
|
|
<button
|
|
type="button"
|
|
class="llm-clone-btn"
|
|
[matTooltip]="focusOpen ? 'Close expanded node' : 'Expand node'"
|
|
(pointerdown)="$event.stopPropagation()"
|
|
(click)="toggleFocus($event)">
|
|
<i class="bi" [class.bi-fullscreen]="!focusOpen" [class.bi-fullscreen-exit]="focusOpen"></i>
|
|
</button>
|
|
@if (!focusOpen) {
|
|
<button type="button" class="llm-clone-btn" matTooltip="Clone node" (pointerdown)="$event.stopPropagation()" (click)="cloneCurrentNode($event)">
|
|
<i class="bi bi-copy"></i>
|
|
</button>
|
|
<button type="button" class="llm-delete-btn" matTooltip="Delete node" (pointerdown)="$event.stopPropagation()" (click)="confirmDelete($event)">
|
|
<i class="bi bi-trash"></i>
|
|
</button>
|
|
}
|
|
}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="llm-body">
|
|
<div class="llm-column">
|
|
<div class="llm-column-title">Inputs</div>
|
|
@for (input of inputs; track input.key) {
|
|
<div class="llm-row llm-row-input">
|
|
<div
|
|
refComponent
|
|
class="llm-socket"
|
|
[data]="{
|
|
type: 'socket',
|
|
side: 'input',
|
|
key: input.key,
|
|
nodeId: data.id,
|
|
__readonly: isReadonly,
|
|
payload: input.socket
|
|
}"
|
|
[emit]="emit">
|
|
</div>
|
|
<span class="llm-pill llm-pill-input">
|
|
<span class="llm-pill-meta">
|
|
<span class="llm-pill-name">{{ inputDisplayLabel(input.key) }}</span>
|
|
@if (!isReadonly && canTogglePortMultiplicity('input', input.key)) {
|
|
<select
|
|
class="llm-pill-kind-select"
|
|
[ngModel]="portCurrentKindValue('input', input.key)"
|
|
(pointerdown)="$event.stopPropagation()"
|
|
(click)="$event.stopPropagation()"
|
|
(ngModelChange)="onPortKindChange('input', input.key, $event)">
|
|
@for (option of portSelectableKindOptions('input', input.key); track option.value) {
|
|
<option [value]="option.value">{{ option.label }}</option>
|
|
}
|
|
</select>
|
|
} @else {
|
|
<span class="llm-pill-kind">{{ portCurrentKindLabel('input', input.key) }}</span>
|
|
}
|
|
</span>
|
|
</span>
|
|
</div>
|
|
}
|
|
</div>
|
|
|
|
<div class="llm-column">
|
|
<div class="llm-column-title llm-column-title-right">{{ outputsTitle() }}</div>
|
|
@for (output of outputs; track output.key) {
|
|
<div class="llm-row llm-row-output">
|
|
<span class="llm-pill llm-pill-output" [ngClass]="outputPillClass(output.key)">
|
|
<span class="llm-pill-meta llm-pill-meta-output">
|
|
<span class="llm-pill-name">{{ outputDisplayLabel(output.key) }}</span>
|
|
@if (!isReadonly && canTogglePortMultiplicity('output', output.key)) {
|
|
<select
|
|
class="llm-pill-kind-select"
|
|
[ngModel]="portCurrentKindValue('output', output.key)"
|
|
(pointerdown)="$event.stopPropagation()"
|
|
(click)="$event.stopPropagation()"
|
|
(ngModelChange)="onPortKindChange('output', output.key, $event)">
|
|
@for (option of portSelectableKindOptions('output', output.key); track option.value) {
|
|
<option [value]="option.value">{{ option.label }}</option>
|
|
}
|
|
</select>
|
|
} @else {
|
|
<span class="llm-pill-kind">{{ portCurrentKindLabel('output', output.key) }}</span>
|
|
}
|
|
</span>
|
|
</span>
|
|
<div
|
|
refComponent
|
|
class="llm-socket llm-socket-right"
|
|
[data]="{
|
|
type: 'socket',
|
|
side: 'output',
|
|
key: output.key,
|
|
nodeId: data.id,
|
|
__readonly: isReadonly,
|
|
payload: output.socket
|
|
}"
|
|
[emit]="emit">
|
|
</div>
|
|
</div>
|
|
}
|
|
</div>
|
|
</div>
|
|
|
|
@if (hasExecutionDependencyPorts()) {
|
|
<div class="llm-body llm-body-dependency">
|
|
<div class="llm-column">
|
|
<div class="llm-column-title">Dependency</div>
|
|
@if (dependencyInput; as dependencyInput) {
|
|
<div class="llm-row llm-row-input">
|
|
<div
|
|
refComponent
|
|
class="llm-socket"
|
|
[data]="{
|
|
type: 'socket',
|
|
side: 'input',
|
|
key: dependencyInput.key,
|
|
nodeId: data.id,
|
|
__readonly: isReadonly,
|
|
payload: dependencyInput.socket
|
|
}"
|
|
[emit]="emit">
|
|
</div>
|
|
<span class="llm-pill llm-pill-input llm-pill-dependency-input">Depends on</span>
|
|
</div>
|
|
}
|
|
</div>
|
|
|
|
<div class="llm-column">
|
|
<div class="llm-column-title llm-column-title-right">Dependant</div>
|
|
@if (dependantOutput; as dependantOutput) {
|
|
<div class="llm-row llm-row-output">
|
|
<span class="llm-pill llm-pill-output llm-pill-dependency-output">Prerequisite of</span>
|
|
<div
|
|
refComponent
|
|
class="llm-socket llm-socket-right"
|
|
[data]="{
|
|
type: 'socket',
|
|
side: 'output',
|
|
key: dependantOutput.key,
|
|
nodeId: data.id,
|
|
__readonly: isReadonly,
|
|
payload: dependantOutput.socket
|
|
}"
|
|
[emit]="emit">
|
|
</div>
|
|
</div>
|
|
}
|
|
</div>
|
|
</div>
|
|
}
|
|
|
|
<div class="llm-params llm-params-shell">
|
|
@if (!schemaReady) {
|
|
<div class="llm-skeleton-overlay" aria-hidden="true">
|
|
<div class="llm-skeleton-stack">
|
|
<div class="llm-skeleton-line llm-skeleton-line-title"></div>
|
|
<div class="llm-skeleton-line llm-skeleton-line-short"></div>
|
|
<div class="llm-skeleton-grid">
|
|
<div class="llm-skeleton-pill"></div>
|
|
<div class="llm-skeleton-pill"></div>
|
|
<div class="llm-skeleton-pill llm-skeleton-pill-wide"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
}
|
|
@for (section of parameterDisplaySections; track section.key) {
|
|
@if (section.group; as group) {
|
|
<fieldset class="llm-param-fieldset">
|
|
<legend class="llm-param-legend">{{ group.legend }}</legend>
|
|
<div class="llm-param-grid">
|
|
@for (item of group.items; track item.path) {
|
|
@if (item.field; as field) {
|
|
<div class="llm-param-chip" [class.llm-param-chip-wide]="field.wide" [class.llm-param-chip-boolean]="field.type === 'boolean'" [class.llm-param-chip-disabled]="!field.enabled">
|
|
<div class="llm-param-row-head">
|
|
<span class="llm-param-key">{{ field.label }}</span>
|
|
@if (field.type === 'boolean') {
|
|
<button
|
|
type="button"
|
|
class="llm-bool-toggle"
|
|
[class.llm-bool-toggle-on]="field.booleanValue"
|
|
[disabled]="isReadonly || !field.enabled"
|
|
[attr.aria-pressed]="field.booleanValue"
|
|
[attr.title]="'Toggle ' + field.label.toLowerCase()"
|
|
(pointerdown)="$event.stopPropagation()"
|
|
(click)="toggleBooleanParameter(field.path, $event)">
|
|
<span class="llm-bool-toggle-thumb"></span>
|
|
</button>
|
|
} @else if (!isReadonly) {
|
|
<button
|
|
type="button"
|
|
class="llm-edit-btn"
|
|
[disabled]="!field.enabled"
|
|
[attr.title]="'Edit ' + field.label.toLowerCase()"
|
|
(pointerdown)="$event.stopPropagation()"
|
|
(click)="openParameterEditor(field.path, $event)">
|
|
<i class="bi bi-pen"></i>
|
|
</button>
|
|
} @else if (field.expandable) {
|
|
<button
|
|
type="button"
|
|
class="llm-param-view-btn"
|
|
aria-label="View full value"
|
|
(pointerdown)="$event.stopPropagation()"
|
|
(click)="openFieldPreview(field, $event)">
|
|
<i class="bi bi-eye"></i>
|
|
</button>
|
|
}
|
|
</div>
|
|
@if (field.type !== 'boolean') {
|
|
<span class="llm-param-value" [class.llm-param-value-clamped]="field.expandable">{{ field.value }}</span>
|
|
}
|
|
</div>
|
|
} @else {
|
|
@if (item.richContentField; as contentField) {
|
|
<div class="llm-param-block llm-param-chip llm-param-chip-wide">
|
|
<div class="llm-param-row-head">
|
|
<div class="llm-param-key">{{ contentField.label }}</div>
|
|
@if (!isReadonly) {
|
|
<button type="button" class="llm-edit-btn" [attr.title]="'Edit ' + contentField.label.toLowerCase()" (pointerdown)="$event.stopPropagation()" (click)="openMainContentEditor(contentField.path, $event)">
|
|
<i class="bi bi-pen"></i>
|
|
</button>
|
|
} @else if (contentField.expandable) {
|
|
<button
|
|
type="button"
|
|
class="llm-param-view-btn"
|
|
aria-label="View full value"
|
|
(pointerdown)="$event.stopPropagation()"
|
|
(click)="openMainContentPreview(contentField, $event)">
|
|
<i class="bi bi-eye"></i>
|
|
</button>
|
|
}
|
|
</div>
|
|
<div class="llm-param-text" [class.llm-param-text-clamped]="contentField.expandable">
|
|
@if (!contentField.parts.length) {
|
|
-
|
|
} @else {
|
|
@for (part of contentField.parts; track $index) {
|
|
@if (part.isDynamicInput) {
|
|
<span class="llm-inline-token">{{ formatDynamicInputToken(part.text) }}</span>
|
|
} @else {
|
|
<span>{{ part.text }}</span>
|
|
}
|
|
}
|
|
}
|
|
</div>
|
|
</div>
|
|
}
|
|
@if (item.arrayField; as arrayField) {
|
|
<div class="llm-array-block llm-param-chip llm-param-chip-wide">
|
|
<div class="llm-param-row-head">
|
|
<div class="llm-param-key">{{ arrayField.label }}</div>
|
|
@if (!isReadonly) {
|
|
<button
|
|
type="button"
|
|
class="llm-edit-btn"
|
|
[attr.title]="'Add ' + arrayField.label.toLowerCase()"
|
|
(pointerdown)="$event.stopPropagation()"
|
|
(click)="addArrayItem(arrayField.path, $event)">
|
|
<i class="bi bi-plus-lg"></i>
|
|
</button>
|
|
}
|
|
</div>
|
|
@if (!arrayField.items.length) {
|
|
<div class="llm-array-empty">No items</div>
|
|
} @else {
|
|
@for (entry of arrayField.items; track entry.index) {
|
|
<div class="llm-array-item">
|
|
<span class="llm-array-item-summary">{{ entry.summary }}</span>
|
|
<div class="llm-array-item-actions">
|
|
@if (!isReadonly) {
|
|
<button
|
|
type="button"
|
|
class="llm-edit-btn"
|
|
title="Edit item"
|
|
(pointerdown)="$event.stopPropagation()"
|
|
(click)="editArrayItem(arrayField.path, entry.index, $event)">
|
|
<i class="bi bi-pen"></i>
|
|
</button>
|
|
}
|
|
@if (!isReadonly) {
|
|
<button
|
|
type="button"
|
|
class="llm-edit-btn llm-array-remove-btn"
|
|
title="Remove item"
|
|
(pointerdown)="$event.stopPropagation()"
|
|
(click)="removeArrayItem(arrayField.path, entry.index, $event)">
|
|
<i class="bi bi-trash"></i>
|
|
</button>
|
|
}
|
|
</div>
|
|
</div>
|
|
}
|
|
}
|
|
</div>
|
|
}
|
|
}
|
|
}
|
|
</div>
|
|
</fieldset>
|
|
} @else if (section.item; as item) {
|
|
<div class="llm-param-grid">
|
|
@if (item.field; as field) {
|
|
<div class="llm-param-chip llm-param-chip-root" [class.llm-param-chip-wide]="field.wide" [class.llm-param-chip-boolean]="field.type === 'boolean'" [class.llm-param-chip-disabled]="!field.enabled">
|
|
<div class="llm-param-row-head">
|
|
<span class="llm-param-key">{{ field.label }}</span>
|
|
@if (field.type === 'boolean') {
|
|
<button
|
|
type="button"
|
|
class="llm-bool-toggle"
|
|
[class.llm-bool-toggle-on]="field.booleanValue"
|
|
[disabled]="isReadonly || !field.enabled"
|
|
[attr.aria-pressed]="field.booleanValue"
|
|
[attr.title]="'Toggle ' + field.label.toLowerCase()"
|
|
(pointerdown)="$event.stopPropagation()"
|
|
(click)="toggleBooleanParameter(field.path, $event)">
|
|
<span class="llm-bool-toggle-thumb"></span>
|
|
</button>
|
|
} @else if (!isReadonly) {
|
|
<button
|
|
type="button"
|
|
class="llm-edit-btn"
|
|
[disabled]="!field.enabled"
|
|
[attr.title]="'Edit ' + field.label.toLowerCase()"
|
|
(pointerdown)="$event.stopPropagation()"
|
|
(click)="openParameterEditor(field.path, $event)">
|
|
<i class="bi bi-pen"></i>
|
|
</button>
|
|
} @else if (field.expandable) {
|
|
<button
|
|
type="button"
|
|
class="llm-param-view-btn"
|
|
aria-label="View full value"
|
|
(pointerdown)="$event.stopPropagation()"
|
|
(click)="openFieldPreview(field, $event)">
|
|
<i class="bi bi-eye"></i>
|
|
</button>
|
|
}
|
|
</div>
|
|
@if (field.type !== 'boolean') {
|
|
<span class="llm-param-value" [class.llm-param-value-clamped]="field.expandable">{{ field.value }}</span>
|
|
}
|
|
</div>
|
|
} @else {
|
|
@if (item.richContentField; as contentField) {
|
|
<div class="llm-param-block llm-param-chip llm-param-chip-wide">
|
|
<div class="llm-param-row-head">
|
|
<div class="llm-param-key">{{ contentField.label }}</div>
|
|
@if (!isReadonly) {
|
|
<button type="button" class="llm-edit-btn" [attr.title]="'Edit ' + contentField.label.toLowerCase()" (pointerdown)="$event.stopPropagation()" (click)="openMainContentEditor(contentField.path, $event)">
|
|
<i class="bi bi-pen"></i>
|
|
</button>
|
|
} @else if (contentField.expandable) {
|
|
<button
|
|
type="button"
|
|
class="llm-param-view-btn"
|
|
aria-label="View full value"
|
|
(pointerdown)="$event.stopPropagation()"
|
|
(click)="openMainContentPreview(contentField, $event)">
|
|
<i class="bi bi-eye"></i>
|
|
</button>
|
|
}
|
|
</div>
|
|
<div class="llm-param-text" [class.llm-param-text-clamped]="contentField.expandable">
|
|
@if (!contentField.parts.length) {
|
|
-
|
|
} @else {
|
|
@for (part of contentField.parts; track $index) {
|
|
@if (part.isDynamicInput) {
|
|
<span class="llm-inline-token">{{ formatDynamicInputToken(part.text) }}</span>
|
|
} @else {
|
|
<span>{{ part.text }}</span>
|
|
}
|
|
}
|
|
}
|
|
</div>
|
|
</div>
|
|
}
|
|
@if (item.arrayField; as arrayField) {
|
|
<div class="llm-array-block llm-param-chip llm-param-chip-wide">
|
|
<div class="llm-param-row-head">
|
|
<div class="llm-param-key">{{ arrayField.label }}</div>
|
|
@if (!isReadonly) {
|
|
<button
|
|
type="button"
|
|
class="llm-edit-btn"
|
|
[attr.title]="'Add ' + arrayField.label.toLowerCase()"
|
|
(pointerdown)="$event.stopPropagation()"
|
|
(click)="addArrayItem(arrayField.path, $event)">
|
|
<i class="bi bi-plus-lg"></i>
|
|
</button>
|
|
}
|
|
</div>
|
|
@if (!arrayField.items.length) {
|
|
<div class="llm-array-empty">No items</div>
|
|
} @else {
|
|
@for (entry of arrayField.items; track entry.index) {
|
|
<div class="llm-array-item">
|
|
<span class="llm-array-item-summary">{{ entry.summary }}</span>
|
|
<div class="llm-array-item-actions">
|
|
@if (!isReadonly) {
|
|
<button
|
|
type="button"
|
|
class="llm-edit-btn"
|
|
title="Edit item"
|
|
(pointerdown)="$event.stopPropagation()"
|
|
(click)="editArrayItem(arrayField.path, entry.index, $event)">
|
|
<i class="bi bi-pen"></i>
|
|
</button>
|
|
}
|
|
@if (!isReadonly) {
|
|
<button
|
|
type="button"
|
|
class="llm-edit-btn llm-array-remove-btn"
|
|
title="Remove item"
|
|
(pointerdown)="$event.stopPropagation()"
|
|
(click)="removeArrayItem(arrayField.path, entry.index, $event)">
|
|
<i class="bi bi-trash"></i>
|
|
</button>
|
|
}
|
|
</div>
|
|
</div>
|
|
}
|
|
}
|
|
</div>
|
|
}
|
|
}
|
|
</div>
|
|
}
|
|
}
|
|
</div>
|
|
|
|
<app-bias-annotations
|
|
[blockId]="blockId ?? ''"
|
|
[block]="biasBlock"
|
|
[annotations]="biasAnnotations"
|
|
[readonly]="isReadonly"
|
|
(annotationsChange)="updateBiasAnnotations($event)" />
|
|
|
|
@if (localEditorOpen) {
|
|
<dialog #simpleEditorDialog class="llm-modal-backdrop" (pointerdown)="$event.stopPropagation()" (click)="onSimpleEditorDialogClick($event)" (cancel)="closeSimpleParamEditor($event)">
|
|
<div class="llm-modal" (pointerdown)="$event.stopPropagation()" (click)="$event.stopPropagation()">
|
|
<div class="llm-modal-title">Edit {{ localEditorLabel }}</div>
|
|
@if (localEditorBindableAsInput && localEditorPath !== 'name') {
|
|
<div class="llm-modal-field">
|
|
<label>Source</label>
|
|
<select
|
|
[ngModel]="localEditorUseInput ? 'input' : 'static'"
|
|
(pointerdown)="$event.stopPropagation()"
|
|
(ngModelChange)="onLocalEditorSourceModeChange($event)">
|
|
<option value="static">Static value</option>
|
|
<option value="input">Workflow input</option>
|
|
</select>
|
|
@if (localEditorUseInput) {
|
|
<div class="llm-modal-tip">
|
|
This field will be provided by node input{{ localEditorBindableInputName ? (' "' + localEditorBindableInputName + '"') : '' }}.
|
|
</div>
|
|
}
|
|
</div>
|
|
}
|
|
<div class="llm-modal-field">
|
|
<label>{{ localEditorLabel }}</label>
|
|
@if (localEditorUseInput && localEditorPath !== 'name') {
|
|
<input
|
|
type="text"
|
|
[ngModel]="localEditorBindableInputName ? ('Provided by input ' + localEditorBindableInputName) : 'Provided by workflow input'"
|
|
readonly
|
|
(pointerdown)="$event.stopPropagation()" />
|
|
} @else if (localEditorLoading) {
|
|
<input type="text" [ngModel]="localEditorValue" placeholder="Loading..." disabled (pointerdown)="$event.stopPropagation()" />
|
|
} @else if (localEditorType === 'boolean') {
|
|
<button
|
|
type="button"
|
|
class="node-toggle"
|
|
[class.node-toggle-on]="localEditorValue === 'true'"
|
|
[attr.aria-pressed]="localEditorValue === 'true'"
|
|
(pointerdown)="$event.stopPropagation()"
|
|
(click)="localEditorValue = localEditorValue === 'true' ? 'false' : 'true'">
|
|
<span class="node-toggle-track">
|
|
<span class="node-toggle-thumb"></span>
|
|
</span>
|
|
<span class="node-toggle-label">{{ localEditorValue === 'true' ? 'true' : 'false' }}</span>
|
|
</button>
|
|
} @else if (localEditorWidget === 'textarea') {
|
|
<textarea
|
|
[rows]="localEditorRows ?? 6"
|
|
[(ngModel)]="localEditorValue"
|
|
[attr.maxlength]="localEditorMaxLength"
|
|
[placeholder]="localEditorMaxLength ? 'Max ' + localEditorMaxLength + ' characters' : 'Value...'"
|
|
(pointerdown)="$event.stopPropagation()"></textarea>
|
|
} @else if (localEditorHasRetriever) {
|
|
<select [(ngModel)]="localEditorValue" (pointerdown)="$event.stopPropagation()">
|
|
<option value="">{{ localEditorOptions.length ? ('Select ' + (localEditorLabel | lowercase) + '...') : 'No options available' }}</option>
|
|
@for (option of localEditorOptions; track option.value) {
|
|
<option [value]="option.value">{{ option.label }}</option>
|
|
}
|
|
</select>
|
|
} @else {
|
|
<input
|
|
[type]="localEditorType === 'number' || localEditorType === 'integer' ? 'number' : 'text'"
|
|
[(ngModel)]="localEditorValue"
|
|
[attr.maxlength]="localEditorMaxLength"
|
|
[placeholder]="localEditorMaxLength ? 'Max ' + localEditorMaxLength + ' characters' : 'Value...'"
|
|
(pointerdown)="$event.stopPropagation()" />
|
|
}
|
|
</div>
|
|
<div class="llm-modal-actions">
|
|
<button type="button" class="llm-btn llm-btn-ghost" (pointerdown)="$event.stopPropagation()" (click)="closeSimpleParamEditor($event)">Cancel</button>
|
|
<button type="button" class="llm-btn llm-btn-primary" [disabled]="!canSaveLocalEditor()" (pointerdown)="$event.stopPropagation()" (click)="saveSimpleParamEditor($event)">Save</button>
|
|
</div>
|
|
</div>
|
|
</dialog>
|
|
}
|
|
|
|
</div>
|