// SPDX-FileCopyrightText: 2025-2026 Lucio Lelii - ISTI-CNR // SPDX-License-Identifier: AGPL-3.0-or-later // Attribution term under AGPL-3.0 section 7(b): see LICENSE-ADDENDUM. import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnChanges, Output, SimpleChanges, signal } from '@angular/core'; export type NodeListFieldItem = { index: number; summary: string; /** Something the item can be opened to read in full, when it has one. */ definition?: unknown | null; }; /** * A node parameter that is a list: its name and how many items it has, the items themselves on * demand. Shared by every node that shows lists - blocks, the execution view, and containers once * one has a list parameter - so they all read and behave the same. * *

Starts closed. With no items there is nothing to open, and the add button is the way in; an * item added opens the list, so what was just added is there to see rather than only counted. */ @Component({ selector: 'app-node-list-field', standalone: true, templateUrl: './node-list-field.html', styleUrl: './node-list-field.css', changeDetection: ChangeDetectionStrategy.OnPush }) export class NodeListFieldComponent implements OnChanges { @Input({ required: true }) label = ''; @Input() items: NodeListFieldItem[] = []; /** Read-only views - an execution - show the items and offer nothing to change them. */ @Input() readonly = false; @Output() readonly add = new EventEmitter(); @Output() readonly edit = new EventEmitter(); @Output() readonly remove = new EventEmitter(); @Output() readonly view = new EventEmitter(); readonly expanded = signal(false); ngOnChanges(changes: SimpleChanges): void { const change = changes['items']; if (!change || change.firstChange) return; const before = Array.isArray(change.previousValue) ? change.previousValue.length : 0; const after = this.items?.length ?? 0; if (after > before) this.expanded.set(true); if (after === 0) this.expanded.set(false); } toggle(event: Event) { event.preventDefault(); event.stopPropagation(); if (!this.items.length) return; this.expanded.update((open) => !open); } emit(emitter: EventEmitter, value: T, event: Event) { event.preventDefault(); event.stopPropagation(); emitter.emit(value); } }