@seniorsistemas/components-ai 2.2.0 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { NgModule, Injectable, Optional, Inject, Pipe, EventEmitter, Component, Input, Output, ChangeDetectionStrategy, Directive, HostListener, ViewChild, ViewEncapsulation, APP_INITIALIZER, Injector, makeEnvironmentProviders, inject } from '@angular/core';
2
+ import { NgModule, Injectable, Optional, Inject, Pipe, EventEmitter, Component, Input, Output, ChangeDetectionStrategy, Directive, ContentChild, ViewChild, HostListener, ViewEncapsulation, APP_INITIALIZER, Injector, makeEnvironmentProviders, inject } from '@angular/core';
3
3
  import * as i2 from '@angular/common';
4
4
  import { CommonModule, DOCUMENT } from '@angular/common';
5
5
  import * as i1 from '@angular/common/http';
@@ -31,6 +31,11 @@ import * as i6$1 from 'primeng/tag';
31
31
  import { TagModule } from 'primeng/tag';
32
32
  import * as i1$2 from '@angular/router';
33
33
  import { NavigationEnd, Router } from '@angular/router';
34
+ import * as i2$3 from '@angular/cdk/drag-drop';
35
+ import { moveItemInArray, transferArrayItem, DragDropModule } from '@angular/cdk/drag-drop';
36
+ import { CardModule } from 'primeng/card';
37
+ import * as i7$1 from 'primeng/tooltip';
38
+ import { TooltipModule } from 'primeng/tooltip';
34
39
  import * as i6$2 from 'primeng/panel';
35
40
  import { PanelModule } from 'primeng/panel';
36
41
  import * as i9 from 'primeng/drawer';
@@ -43,8 +48,6 @@ import * as i4$2 from 'primeng/inputmask';
43
48
  import { InputMaskModule } from 'primeng/inputmask';
44
49
  import * as i5$1 from 'primeng/calendar';
45
50
  import { CalendarModule } from 'primeng/calendar';
46
- import * as i7$1 from 'primeng/tooltip';
47
- import { TooltipModule } from 'primeng/tooltip';
48
51
  import * as i3$1 from 'primeng/dropdown';
49
52
  import { DropdownModule } from 'primeng/dropdown';
50
53
  import * as i8$1 from 'primeng/table';
@@ -3186,6 +3189,312 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
3186
3189
  type: Directive
3187
3190
  }], ctorParameters: () => [{ type: EntityService }, { type: i2$2.MessageService }, { type: i2$2.ConfirmationService }, { type: TranslationService }, { type: i0.ChangeDetectorRef }] });
3188
3191
 
3192
+ class KanbanBoardComponent {
3193
+ ngZone;
3194
+ columns = [];
3195
+ allowReorder = true;
3196
+ allowDrag = true;
3197
+ showAddButton = false;
3198
+ showEditButton = false;
3199
+ showDeleteButton = false;
3200
+ canDeleteColumn;
3201
+ emptyMessage = 'No items';
3202
+ minColumnWidth = '280px';
3203
+ maxColumnWidth = '350px';
3204
+ /** Show scroll hint arrows when columns overflow horizontally. */
3205
+ showScrollHints = true;
3206
+ /** Enable item selection mode. Adds selected state management and CSS class on cards. */
3207
+ selectable = false;
3208
+ itemMoved = new EventEmitter();
3209
+ itemClicked = new EventEmitter();
3210
+ addItem = new EventEmitter();
3211
+ editColumn = new EventEmitter();
3212
+ deleteColumn = new EventEmitter();
3213
+ /** Emitted when selection changes. Payload is the full array of selected KanbanItems. */
3214
+ selectionChange = new EventEmitter();
3215
+ /** Custom template for the column header. Context: { $implicit: KanbanColumn } */
3216
+ columnHeaderTemplate;
3217
+ /**
3218
+ * Custom template for each item card.
3219
+ * Context: { $implicit: KanbanItem, column: KanbanColumn, selected: boolean, toggle: () => void }
3220
+ */
3221
+ itemTemplate;
3222
+ scrollContainer;
3223
+ columnIds = [];
3224
+ // Scroll state
3225
+ hasHorizontalScroll = false;
3226
+ scrollPosition = 'start';
3227
+ // Selection state
3228
+ selectedIds = new Set();
3229
+ // Auto-scroll during drag
3230
+ autoScrollActive = false;
3231
+ autoScrollSpeed = 0;
3232
+ autoScrollRaf = null;
3233
+ resizeObserver;
3234
+ constructor(ngZone) {
3235
+ this.ngZone = ngZone;
3236
+ }
3237
+ ngOnInit() {
3238
+ this.updateColumnIds();
3239
+ }
3240
+ ngAfterViewInit() {
3241
+ if (this.showScrollHints) {
3242
+ this.checkScroll();
3243
+ this.ngZone.runOutsideAngular(() => {
3244
+ this.resizeObserver = new ResizeObserver(() => {
3245
+ this.ngZone.run(() => this.checkScroll());
3246
+ });
3247
+ if (this.scrollContainer?.nativeElement) {
3248
+ this.resizeObserver.observe(this.scrollContainer.nativeElement);
3249
+ }
3250
+ });
3251
+ }
3252
+ }
3253
+ ngOnDestroy() {
3254
+ this.resizeObserver?.disconnect();
3255
+ this.stopAutoScroll();
3256
+ }
3257
+ ngOnChanges() {
3258
+ this.updateColumnIds();
3259
+ setTimeout(() => this.checkScroll(), 50);
3260
+ }
3261
+ updateColumnIds() {
3262
+ this.columnIds = this.columns.map(col => col.id);
3263
+ }
3264
+ // ==================== SELECTION ====================
3265
+ isSelected(item) {
3266
+ return this.selectedIds.has(item.id);
3267
+ }
3268
+ toggleSelection(item) {
3269
+ if (this.selectedIds.has(item.id)) {
3270
+ this.selectedIds.delete(item.id);
3271
+ }
3272
+ else {
3273
+ this.selectedIds.add(item.id);
3274
+ }
3275
+ this.emitSelectionChange();
3276
+ }
3277
+ /** Clear all selections. Can be called externally via ViewChild. */
3278
+ clearSelection() {
3279
+ this.selectedIds.clear();
3280
+ this.emitSelectionChange();
3281
+ }
3282
+ /** Get current selected items. */
3283
+ getSelectedItems() {
3284
+ const allItems = this.columns.flatMap(col => col.items);
3285
+ return allItems.filter(item => this.selectedIds.has(item.id));
3286
+ }
3287
+ emitSelectionChange() {
3288
+ this.selectionChange.emit(this.getSelectedItems());
3289
+ }
3290
+ /** Returns the template context for an item (used in the template). */
3291
+ getItemContext(item, column) {
3292
+ return {
3293
+ $implicit: item,
3294
+ column,
3295
+ selected: this.isSelected(item),
3296
+ toggle: () => this.toggleSelection(item)
3297
+ };
3298
+ }
3299
+ // ==================== SCROLL ====================
3300
+ onScroll() {
3301
+ this.checkScroll();
3302
+ }
3303
+ checkScroll() {
3304
+ const el = this.scrollContainer?.nativeElement;
3305
+ if (!el)
3306
+ return;
3307
+ const { scrollLeft, scrollWidth, clientWidth } = el;
3308
+ this.hasHorizontalScroll = scrollWidth > clientWidth + 2;
3309
+ if (scrollLeft <= 2) {
3310
+ this.scrollPosition = 'start';
3311
+ }
3312
+ else if (scrollLeft + clientWidth >= scrollWidth - 2) {
3313
+ this.scrollPosition = 'end';
3314
+ }
3315
+ else {
3316
+ this.scrollPosition = 'middle';
3317
+ }
3318
+ }
3319
+ scrollLeft() {
3320
+ const el = this.scrollContainer?.nativeElement;
3321
+ if (!el)
3322
+ return;
3323
+ const column = el.querySelector('.kanban-column');
3324
+ const scrollAmount = column ? column.offsetWidth + 16 : 300;
3325
+ el.scrollBy({ left: -scrollAmount, behavior: 'smooth' });
3326
+ }
3327
+ scrollRight() {
3328
+ const el = this.scrollContainer?.nativeElement;
3329
+ if (!el)
3330
+ return;
3331
+ const column = el.querySelector('.kanban-column');
3332
+ const scrollAmount = column ? column.offsetWidth + 16 : 300;
3333
+ el.scrollBy({ left: scrollAmount, behavior: 'smooth' });
3334
+ }
3335
+ // ==================== AUTO-SCROLL DURING DRAG ====================
3336
+ onDragMoved(event) {
3337
+ const el = this.scrollContainer?.nativeElement;
3338
+ if (!el)
3339
+ return;
3340
+ const rect = el.getBoundingClientRect();
3341
+ const pointerX = event.pointerPosition.x;
3342
+ const edgeZone = 80; // pixels from edge to trigger scroll
3343
+ if (pointerX < rect.left + edgeZone) {
3344
+ // Near left edge
3345
+ const proximity = 1 - (pointerX - rect.left) / edgeZone;
3346
+ this.autoScrollSpeed = -Math.max(3, proximity * 15);
3347
+ this.startAutoScroll();
3348
+ }
3349
+ else if (pointerX > rect.right - edgeZone) {
3350
+ // Near right edge
3351
+ const proximity = 1 - (rect.right - pointerX) / edgeZone;
3352
+ this.autoScrollSpeed = Math.max(3, proximity * 15);
3353
+ this.startAutoScroll();
3354
+ }
3355
+ else {
3356
+ this.stopAutoScroll();
3357
+ }
3358
+ }
3359
+ onDragEnded() {
3360
+ this.stopAutoScroll();
3361
+ }
3362
+ startAutoScroll() {
3363
+ if (this.autoScrollActive)
3364
+ return;
3365
+ this.autoScrollActive = true;
3366
+ this.runAutoScroll();
3367
+ }
3368
+ stopAutoScroll() {
3369
+ this.autoScrollActive = false;
3370
+ this.autoScrollSpeed = 0;
3371
+ if (this.autoScrollRaf) {
3372
+ cancelAnimationFrame(this.autoScrollRaf);
3373
+ this.autoScrollRaf = null;
3374
+ }
3375
+ }
3376
+ runAutoScroll() {
3377
+ if (!this.autoScrollActive)
3378
+ return;
3379
+ const el = this.scrollContainer?.nativeElement;
3380
+ if (el) {
3381
+ el.scrollLeft += this.autoScrollSpeed;
3382
+ }
3383
+ this.autoScrollRaf = requestAnimationFrame(() => this.runAutoScroll());
3384
+ }
3385
+ // ==================== DRAG & DROP ====================
3386
+ onDrop(event, column) {
3387
+ if (!this.allowDrag)
3388
+ return;
3389
+ const previousColumn = this.columns.find(col => col.id === event.previousContainer.id);
3390
+ if (event.previousContainer === event.container) {
3391
+ moveItemInArray(event.container.data, event.previousIndex, event.currentIndex);
3392
+ }
3393
+ else {
3394
+ if (column.allowDrop === false)
3395
+ return;
3396
+ if (column.maxItems && event.container.data.length >= column.maxItems)
3397
+ return;
3398
+ const item = event.previousContainer.data[event.previousIndex];
3399
+ transferArrayItem(event.previousContainer.data, event.container.data, event.previousIndex, event.currentIndex);
3400
+ if (previousColumn) {
3401
+ this.itemMoved.emit({
3402
+ item,
3403
+ previousColumn,
3404
+ currentColumn: column,
3405
+ previousIndex: event.previousIndex,
3406
+ currentIndex: event.currentIndex
3407
+ });
3408
+ }
3409
+ }
3410
+ }
3411
+ onItemClick(item) {
3412
+ this.itemClicked.emit(item);
3413
+ }
3414
+ onAddItem(column) {
3415
+ this.addItem.emit(column);
3416
+ }
3417
+ onEditColumn(column) {
3418
+ this.editColumn.emit(column);
3419
+ }
3420
+ onDeleteColumn(column) {
3421
+ this.deleteColumn.emit(column);
3422
+ }
3423
+ canShowDeleteButton(column) {
3424
+ if (!this.showDeleteButton)
3425
+ return false;
3426
+ if (this.canDeleteColumn) {
3427
+ return this.canDeleteColumn(column);
3428
+ }
3429
+ return true;
3430
+ }
3431
+ getColumnStyle(column) {
3432
+ return {
3433
+ 'min-width': this.minColumnWidth,
3434
+ 'max-width': this.maxColumnWidth,
3435
+ 'border-top': column.color ? `3px solid ${column.color}` : '3px solid #dee2e6'
3436
+ };
3437
+ }
3438
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: KanbanBoardComponent, deps: [{ token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component });
3439
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: KanbanBoardComponent, isStandalone: true, selector: "sia-kanban-board", inputs: { columns: "columns", allowReorder: "allowReorder", allowDrag: "allowDrag", showAddButton: "showAddButton", showEditButton: "showEditButton", showDeleteButton: "showDeleteButton", canDeleteColumn: "canDeleteColumn", emptyMessage: "emptyMessage", minColumnWidth: "minColumnWidth", maxColumnWidth: "maxColumnWidth", showScrollHints: "showScrollHints", selectable: "selectable" }, outputs: { itemMoved: "itemMoved", itemClicked: "itemClicked", addItem: "addItem", editColumn: "editColumn", deleteColumn: "deleteColumn", selectionChange: "selectionChange" }, queries: [{ propertyName: "columnHeaderTemplate", first: true, predicate: ["columnHeaderTemplate"], descendants: true }, { propertyName: "itemTemplate", first: true, predicate: ["itemTemplate"], descendants: true }], viewQueries: [{ propertyName: "scrollContainer", first: true, predicate: ["scrollContainer"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"kanban-board\">\n <!-- Scroll hint arrows -->\n <div class=\"kanban-scroll-controls\" *ngIf=\"showScrollHints && hasHorizontalScroll\">\n <button\n *ngIf=\"scrollPosition !== 'start'\"\n pButton\n type=\"button\"\n icon=\"pi pi-chevron-left\"\n [rounded]=\"true\"\n class=\"scroll-hint scroll-hint-left\"\n (click)=\"scrollLeft()\">\n </button>\n <button\n *ngIf=\"scrollPosition !== 'end'\"\n pButton\n type=\"button\"\n icon=\"pi pi-chevron-right\"\n [rounded]=\"true\"\n class=\"scroll-hint scroll-hint-right\"\n (click)=\"scrollRight()\">\n </button>\n </div>\n\n <!-- Scrollable columns container -->\n <div class=\"kanban-columns\" #scrollContainer (scroll)=\"onScroll()\">\n <div \n *ngFor=\"let column of columns\" \n class=\"kanban-column\"\n [style]=\"getColumnStyle(column)\">\n \n <!-- Column Header -->\n <div class=\"column-header\">\n <!-- Custom header template -->\n <ng-container *ngIf=\"columnHeaderTemplate; else defaultColumnHeader\"\n [ngTemplateOutlet]=\"columnHeaderTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: column }\">\n </ng-container>\n\n <ng-template #defaultColumnHeader>\n <div class=\"column-title\">\n <i *ngIf=\"column.icon\" [class]=\"'pi ' + column.icon\"></i>\n <span>{{ column.title }}</span>\n <span class=\"item-count\">{{ column.items.length }}</span>\n </div>\n <div class=\"column-actions\">\n <button \n *ngIf=\"showAddButton\"\n pButton \n type=\"button\" \n icon=\"pi pi-plus\" \n class=\"p-button-text p-button-sm p-button-rounded\"\n (click)=\"onAddItem(column)\"\n [pTooltip]=\"'Add item'\"\n tooltipPosition=\"top\">\n </button>\n <button \n *ngIf=\"showEditButton\"\n pButton \n type=\"button\" \n icon=\"pi pi-pencil\" \n class=\"p-button-text p-button-sm p-button-rounded\"\n (click)=\"onEditColumn(column)\"\n [pTooltip]=\"'Edit column'\"\n tooltipPosition=\"top\">\n </button>\n <button \n *ngIf=\"canShowDeleteButton(column)\"\n pButton \n type=\"button\" \n icon=\"pi pi-trash\" \n class=\"p-button-text p-button-sm p-button-rounded p-button-danger\"\n (click)=\"onDeleteColumn(column)\"\n [pTooltip]=\"'Delete column'\"\n tooltipPosition=\"top\">\n </button>\n </div>\n </ng-template>\n </div>\n\n <!-- Column Content -->\n <div \n class=\"column-content\"\n cdkDropList\n [id]=\"column.id\"\n [cdkDropListData]=\"column.items\"\n [cdkDropListConnectedTo]=\"columnIds\"\n (cdkDropListDropped)=\"onDrop($event, column)\">\n \n <!-- Items -->\n <div \n *ngFor=\"let item of column.items\"\n class=\"kanban-item\"\n [class.kanban-item--selected]=\"selectable && isSelected(item)\"\n cdkDrag\n [cdkDragDisabled]=\"!allowDrag\"\n (cdkDragMoved)=\"onDragMoved($event)\"\n (cdkDragEnded)=\"onDragEnded()\"\n (click)=\"onItemClick(item)\">\n \n <!-- Custom item template with selection context -->\n <ng-container *ngIf=\"itemTemplate; else defaultItem\"\n [ngTemplateOutlet]=\"itemTemplate\"\n [ngTemplateOutletContext]=\"getItemContext(item, column)\">\n </ng-container>\n\n <ng-template #defaultItem>\n <div class=\"item-content\">\n <div class=\"item-title\">{{ item.title }}</div>\n <div *ngIf=\"item.description\" class=\"item-description\">\n {{ item.description }}\n </div>\n <div *ngIf=\"item.tags && item.tags.length > 0\" class=\"item-tags\">\n <p-tag \n *ngFor=\"let tag of item.tags\"\n [value]=\"tag.label\"\n [severity]=\"tag.severity || 'secondary'\"\n styleClass=\"item-tag\">\n </p-tag>\n </div>\n </div>\n </ng-template>\n\n <!-- Drag Placeholder -->\n <div class=\"item-placeholder\" *cdkDragPlaceholder></div>\n </div>\n\n <!-- Empty State -->\n <div *ngIf=\"column.items.length === 0\" class=\"empty-column\">\n <i class=\"pi pi-inbox\"></i>\n <p>{{ emptyMessage }}</p>\n </div>\n </div>\n </div>\n </div>\n</div>\n", styles: [".kanban-board{position:relative;width:100%;height:100%;padding:1rem}.kanban-board .kanban-scroll-controls{position:absolute;inset:0;pointer-events:none;z-index:10}.kanban-board .kanban-scroll-controls .scroll-hint{position:absolute;top:50%;transform:translateY(-50%);pointer-events:auto;box-shadow:0 4px 12px #00000026;transition:all .3s ease}.kanban-board .kanban-scroll-controls .scroll-hint:hover{transform:translateY(-50%) scale(1.1);box-shadow:0 6px 16px #0003}.kanban-board .kanban-scroll-controls .scroll-hint.scroll-hint-left{left:.5rem}.kanban-board .kanban-scroll-controls .scroll-hint.scroll-hint-right{right:.5rem}.kanban-board .kanban-columns{display:flex;gap:1rem;min-height:500px;padding-bottom:1rem;overflow-x:auto;overflow-y:hidden;scrollbar-width:thin}.kanban-board .kanban-columns::-webkit-scrollbar{height:6px}.kanban-board .kanban-columns::-webkit-scrollbar-track{background:transparent}.kanban-board .kanban-columns::-webkit-scrollbar-thumb{background:#94a3b84d;border-radius:3px}.kanban-board .kanban-columns::-webkit-scrollbar-thumb:hover{background:#94a3b880}.kanban-board .kanban-column{flex-shrink:0;display:flex;flex-direction:column;background:#fff;border-radius:8px;box-shadow:0 1px 3px #0000001a}.kanban-board .kanban-column .column-header{display:flex;justify-content:space-between;align-items:center;padding:1rem;border-bottom:1px solid #e9ecef;background:#fafbfc;border-radius:8px 8px 0 0}.kanban-board .kanban-column .column-header .column-title{display:flex;align-items:center;gap:.5rem;font-weight:600;color:#2c3e50;font-size:.95rem}.kanban-board .kanban-column .column-header .column-title .pi{font-size:.875rem;color:#6c757d}.kanban-board .kanban-column .column-header .column-title .item-count{display:inline-flex;align-items:center;justify-content:center;min-width:24px;height:24px;padding:0 .5rem;background:#e9ecef;border-radius:12px;font-size:.75rem;font-weight:600;color:#495057}.kanban-board .kanban-column .column-header .column-actions{display:flex;gap:.25rem}.kanban-board .kanban-column .column-content{flex:1;padding:.75rem;overflow-y:auto;min-height:200px}.kanban-board .kanban-column .column-content .kanban-item{background:#fff;border:1px solid #e9ecef;border-radius:6px;padding:.875rem;margin-bottom:.75rem;cursor:pointer;transition:all .2s ease;box-shadow:0 1px 2px #0000000d}.kanban-board .kanban-column .column-content .kanban-item:hover{border-color:#007bff;box-shadow:0 2px 8px #007bff26;transform:translateY(-1px)}.kanban-board .kanban-column .column-content .kanban-item:last-child{margin-bottom:0}.kanban-board .kanban-column .column-content .kanban-item.kanban-item--selected{border-left:3px solid #007bff;background:#f0f7ff}.kanban-board .kanban-column .column-content .kanban-item .item-content .item-title{font-weight:500;color:#2c3e50;font-size:.875rem;margin-bottom:.5rem;line-height:1.4}.kanban-board .kanban-column .column-content .kanban-item .item-content .item-description{font-size:.8rem;color:#6c757d;margin-bottom:.5rem;line-height:1.4;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.kanban-board .kanban-column .column-content .kanban-item .item-content .item-tags{display:flex;flex-wrap:wrap;gap:.375rem;margin-top:.5rem}.kanban-board .kanban-column .column-content .kanban-item .item-content .item-tags ::ng-deep .item-tag{font-size:.7rem;padding:.25rem .5rem}.kanban-board .kanban-column .column-content .kanban-item .item-placeholder{background:#e9ecef;border:2px dashed #adb5bd;border-radius:6px;min-height:80px}.kanban-board .kanban-column .column-content .empty-column{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:2rem 1rem;color:#adb5bd;text-align:center}.kanban-board .kanban-column .column-content .empty-column .pi{font-size:2.5rem;margin-bottom:.5rem;opacity:.5}.kanban-board .kanban-column .column-content .empty-column p{font-size:.875rem;margin:0}::ng-deep .cdk-drag-preview{background:#fff;border:1px solid #007bff;border-radius:6px;padding:.875rem;box-shadow:0 4px 12px #007bff4d;opacity:.9;cursor:grabbing}::ng-deep .cdk-drag-animating{transition:transform .25s cubic-bezier(0,0,.2,1)}::ng-deep .cdk-drop-list-dragging .kanban-item:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}@media (max-width: 768px){.kanban-board .kanban-columns{flex-direction:column}.kanban-board .kanban-column{min-width:100%!important;max-width:100%!important}.kanban-board .kanban-scroll-controls{display:none}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i2$3.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i2$3.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: i2$3.CdkDragPlaceholder, selector: "ng-template[cdkDragPlaceholder]", inputs: ["data"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i6.ButtonDirective, selector: "[pButton]", inputs: ["iconPos", "loadingIcon", "loading", "severity", "raised", "rounded", "text", "outlined", "size", "plain", "fluid", "label", "icon", "buttonProps"] }, { kind: "ngmodule", type: CardModule }, { kind: "ngmodule", type: TagModule }, { kind: "component", type: i6$1.Tag, selector: "p-tag", inputs: ["style", "styleClass", "severity", "value", "icon", "rounded"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i7$1.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions"] }] });
3440
+ }
3441
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: KanbanBoardComponent, decorators: [{
3442
+ type: Component,
3443
+ args: [{ selector: 'sia-kanban-board', standalone: true, imports: [
3444
+ CommonModule,
3445
+ DragDropModule,
3446
+ ButtonModule,
3447
+ CardModule,
3448
+ TagModule,
3449
+ TooltipModule
3450
+ ], template: "<div class=\"kanban-board\">\n <!-- Scroll hint arrows -->\n <div class=\"kanban-scroll-controls\" *ngIf=\"showScrollHints && hasHorizontalScroll\">\n <button\n *ngIf=\"scrollPosition !== 'start'\"\n pButton\n type=\"button\"\n icon=\"pi pi-chevron-left\"\n [rounded]=\"true\"\n class=\"scroll-hint scroll-hint-left\"\n (click)=\"scrollLeft()\">\n </button>\n <button\n *ngIf=\"scrollPosition !== 'end'\"\n pButton\n type=\"button\"\n icon=\"pi pi-chevron-right\"\n [rounded]=\"true\"\n class=\"scroll-hint scroll-hint-right\"\n (click)=\"scrollRight()\">\n </button>\n </div>\n\n <!-- Scrollable columns container -->\n <div class=\"kanban-columns\" #scrollContainer (scroll)=\"onScroll()\">\n <div \n *ngFor=\"let column of columns\" \n class=\"kanban-column\"\n [style]=\"getColumnStyle(column)\">\n \n <!-- Column Header -->\n <div class=\"column-header\">\n <!-- Custom header template -->\n <ng-container *ngIf=\"columnHeaderTemplate; else defaultColumnHeader\"\n [ngTemplateOutlet]=\"columnHeaderTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: column }\">\n </ng-container>\n\n <ng-template #defaultColumnHeader>\n <div class=\"column-title\">\n <i *ngIf=\"column.icon\" [class]=\"'pi ' + column.icon\"></i>\n <span>{{ column.title }}</span>\n <span class=\"item-count\">{{ column.items.length }}</span>\n </div>\n <div class=\"column-actions\">\n <button \n *ngIf=\"showAddButton\"\n pButton \n type=\"button\" \n icon=\"pi pi-plus\" \n class=\"p-button-text p-button-sm p-button-rounded\"\n (click)=\"onAddItem(column)\"\n [pTooltip]=\"'Add item'\"\n tooltipPosition=\"top\">\n </button>\n <button \n *ngIf=\"showEditButton\"\n pButton \n type=\"button\" \n icon=\"pi pi-pencil\" \n class=\"p-button-text p-button-sm p-button-rounded\"\n (click)=\"onEditColumn(column)\"\n [pTooltip]=\"'Edit column'\"\n tooltipPosition=\"top\">\n </button>\n <button \n *ngIf=\"canShowDeleteButton(column)\"\n pButton \n type=\"button\" \n icon=\"pi pi-trash\" \n class=\"p-button-text p-button-sm p-button-rounded p-button-danger\"\n (click)=\"onDeleteColumn(column)\"\n [pTooltip]=\"'Delete column'\"\n tooltipPosition=\"top\">\n </button>\n </div>\n </ng-template>\n </div>\n\n <!-- Column Content -->\n <div \n class=\"column-content\"\n cdkDropList\n [id]=\"column.id\"\n [cdkDropListData]=\"column.items\"\n [cdkDropListConnectedTo]=\"columnIds\"\n (cdkDropListDropped)=\"onDrop($event, column)\">\n \n <!-- Items -->\n <div \n *ngFor=\"let item of column.items\"\n class=\"kanban-item\"\n [class.kanban-item--selected]=\"selectable && isSelected(item)\"\n cdkDrag\n [cdkDragDisabled]=\"!allowDrag\"\n (cdkDragMoved)=\"onDragMoved($event)\"\n (cdkDragEnded)=\"onDragEnded()\"\n (click)=\"onItemClick(item)\">\n \n <!-- Custom item template with selection context -->\n <ng-container *ngIf=\"itemTemplate; else defaultItem\"\n [ngTemplateOutlet]=\"itemTemplate\"\n [ngTemplateOutletContext]=\"getItemContext(item, column)\">\n </ng-container>\n\n <ng-template #defaultItem>\n <div class=\"item-content\">\n <div class=\"item-title\">{{ item.title }}</div>\n <div *ngIf=\"item.description\" class=\"item-description\">\n {{ item.description }}\n </div>\n <div *ngIf=\"item.tags && item.tags.length > 0\" class=\"item-tags\">\n <p-tag \n *ngFor=\"let tag of item.tags\"\n [value]=\"tag.label\"\n [severity]=\"tag.severity || 'secondary'\"\n styleClass=\"item-tag\">\n </p-tag>\n </div>\n </div>\n </ng-template>\n\n <!-- Drag Placeholder -->\n <div class=\"item-placeholder\" *cdkDragPlaceholder></div>\n </div>\n\n <!-- Empty State -->\n <div *ngIf=\"column.items.length === 0\" class=\"empty-column\">\n <i class=\"pi pi-inbox\"></i>\n <p>{{ emptyMessage }}</p>\n </div>\n </div>\n </div>\n </div>\n</div>\n", styles: [".kanban-board{position:relative;width:100%;height:100%;padding:1rem}.kanban-board .kanban-scroll-controls{position:absolute;inset:0;pointer-events:none;z-index:10}.kanban-board .kanban-scroll-controls .scroll-hint{position:absolute;top:50%;transform:translateY(-50%);pointer-events:auto;box-shadow:0 4px 12px #00000026;transition:all .3s ease}.kanban-board .kanban-scroll-controls .scroll-hint:hover{transform:translateY(-50%) scale(1.1);box-shadow:0 6px 16px #0003}.kanban-board .kanban-scroll-controls .scroll-hint.scroll-hint-left{left:.5rem}.kanban-board .kanban-scroll-controls .scroll-hint.scroll-hint-right{right:.5rem}.kanban-board .kanban-columns{display:flex;gap:1rem;min-height:500px;padding-bottom:1rem;overflow-x:auto;overflow-y:hidden;scrollbar-width:thin}.kanban-board .kanban-columns::-webkit-scrollbar{height:6px}.kanban-board .kanban-columns::-webkit-scrollbar-track{background:transparent}.kanban-board .kanban-columns::-webkit-scrollbar-thumb{background:#94a3b84d;border-radius:3px}.kanban-board .kanban-columns::-webkit-scrollbar-thumb:hover{background:#94a3b880}.kanban-board .kanban-column{flex-shrink:0;display:flex;flex-direction:column;background:#fff;border-radius:8px;box-shadow:0 1px 3px #0000001a}.kanban-board .kanban-column .column-header{display:flex;justify-content:space-between;align-items:center;padding:1rem;border-bottom:1px solid #e9ecef;background:#fafbfc;border-radius:8px 8px 0 0}.kanban-board .kanban-column .column-header .column-title{display:flex;align-items:center;gap:.5rem;font-weight:600;color:#2c3e50;font-size:.95rem}.kanban-board .kanban-column .column-header .column-title .pi{font-size:.875rem;color:#6c757d}.kanban-board .kanban-column .column-header .column-title .item-count{display:inline-flex;align-items:center;justify-content:center;min-width:24px;height:24px;padding:0 .5rem;background:#e9ecef;border-radius:12px;font-size:.75rem;font-weight:600;color:#495057}.kanban-board .kanban-column .column-header .column-actions{display:flex;gap:.25rem}.kanban-board .kanban-column .column-content{flex:1;padding:.75rem;overflow-y:auto;min-height:200px}.kanban-board .kanban-column .column-content .kanban-item{background:#fff;border:1px solid #e9ecef;border-radius:6px;padding:.875rem;margin-bottom:.75rem;cursor:pointer;transition:all .2s ease;box-shadow:0 1px 2px #0000000d}.kanban-board .kanban-column .column-content .kanban-item:hover{border-color:#007bff;box-shadow:0 2px 8px #007bff26;transform:translateY(-1px)}.kanban-board .kanban-column .column-content .kanban-item:last-child{margin-bottom:0}.kanban-board .kanban-column .column-content .kanban-item.kanban-item--selected{border-left:3px solid #007bff;background:#f0f7ff}.kanban-board .kanban-column .column-content .kanban-item .item-content .item-title{font-weight:500;color:#2c3e50;font-size:.875rem;margin-bottom:.5rem;line-height:1.4}.kanban-board .kanban-column .column-content .kanban-item .item-content .item-description{font-size:.8rem;color:#6c757d;margin-bottom:.5rem;line-height:1.4;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.kanban-board .kanban-column .column-content .kanban-item .item-content .item-tags{display:flex;flex-wrap:wrap;gap:.375rem;margin-top:.5rem}.kanban-board .kanban-column .column-content .kanban-item .item-content .item-tags ::ng-deep .item-tag{font-size:.7rem;padding:.25rem .5rem}.kanban-board .kanban-column .column-content .kanban-item .item-placeholder{background:#e9ecef;border:2px dashed #adb5bd;border-radius:6px;min-height:80px}.kanban-board .kanban-column .column-content .empty-column{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:2rem 1rem;color:#adb5bd;text-align:center}.kanban-board .kanban-column .column-content .empty-column .pi{font-size:2.5rem;margin-bottom:.5rem;opacity:.5}.kanban-board .kanban-column .column-content .empty-column p{font-size:.875rem;margin:0}::ng-deep .cdk-drag-preview{background:#fff;border:1px solid #007bff;border-radius:6px;padding:.875rem;box-shadow:0 4px 12px #007bff4d;opacity:.9;cursor:grabbing}::ng-deep .cdk-drag-animating{transition:transform .25s cubic-bezier(0,0,.2,1)}::ng-deep .cdk-drop-list-dragging .kanban-item:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}@media (max-width: 768px){.kanban-board .kanban-columns{flex-direction:column}.kanban-board .kanban-column{min-width:100%!important;max-width:100%!important}.kanban-board .kanban-scroll-controls{display:none}}\n"] }]
3451
+ }], ctorParameters: () => [{ type: i0.NgZone }], propDecorators: { columns: [{
3452
+ type: Input
3453
+ }], allowReorder: [{
3454
+ type: Input
3455
+ }], allowDrag: [{
3456
+ type: Input
3457
+ }], showAddButton: [{
3458
+ type: Input
3459
+ }], showEditButton: [{
3460
+ type: Input
3461
+ }], showDeleteButton: [{
3462
+ type: Input
3463
+ }], canDeleteColumn: [{
3464
+ type: Input
3465
+ }], emptyMessage: [{
3466
+ type: Input
3467
+ }], minColumnWidth: [{
3468
+ type: Input
3469
+ }], maxColumnWidth: [{
3470
+ type: Input
3471
+ }], showScrollHints: [{
3472
+ type: Input
3473
+ }], selectable: [{
3474
+ type: Input
3475
+ }], itemMoved: [{
3476
+ type: Output
3477
+ }], itemClicked: [{
3478
+ type: Output
3479
+ }], addItem: [{
3480
+ type: Output
3481
+ }], editColumn: [{
3482
+ type: Output
3483
+ }], deleteColumn: [{
3484
+ type: Output
3485
+ }], selectionChange: [{
3486
+ type: Output
3487
+ }], columnHeaderTemplate: [{
3488
+ type: ContentChild,
3489
+ args: ['columnHeaderTemplate']
3490
+ }], itemTemplate: [{
3491
+ type: ContentChild,
3492
+ args: ['itemTemplate']
3493
+ }], scrollContainer: [{
3494
+ type: ViewChild,
3495
+ args: ['scrollContainer', { static: false }]
3496
+ }] } });
3497
+
3189
3498
  /**
3190
3499
  * Directive para máscara de código postal
3191
3500
  * Usa o locale do cookie por padrão, ou aceita locale por parâmetro
@@ -5883,6 +6192,7 @@ class DynamicFormComponent {
5883
6192
  loadEntityData() {
5884
6193
  if (this.entityData && this.form) {
5885
6194
  this.form.patchValue(this.processEntityData(this.entityData));
6195
+ this.updateDisabledFields();
5886
6196
  }
5887
6197
  }
5888
6198
  processEntityData(entity) {
@@ -6022,10 +6332,10 @@ class DynamicFormComponent {
6022
6332
  ? [parseInt(dateParts[1], 10), parseInt(dateParts[0], 10), parseInt(dateParts[2], 10)]
6023
6333
  : [parseInt(dateParts[0], 10), parseInt(dateParts[1], 10), parseInt(dateParts[2], 10)];
6024
6334
  const [hours, minutes] = timePart.split(':').map(p => parseInt(p, 10));
6025
- out[field.field] = new Date(year, month - 1, day, hours, minutes);
6335
+ out[field.field] = new Date(year, month - 1, day, hours, minutes).toISOString();
6026
6336
  }
6027
6337
  else if (v instanceof Date) {
6028
- // Keep as Date
6338
+ out[field.field] = v.toISOString();
6029
6339
  }
6030
6340
  else if (!v || (typeof v === 'string' && v.includes('_'))) {
6031
6341
  out[field.field] = null;
@@ -6114,6 +6424,14 @@ class DynamicFormComponent {
6114
6424
  }
6115
6425
  // --- Public methods ---
6116
6426
  getForm() { return this.form; }
6427
+ /**
6428
+ * Returns the form values with date/time/lookup fields already converted
6429
+ * to the backend-expected format (date → yyyy-MM-dd, time → HH:mm:ss, lookup → object with id).
6430
+ * Use this instead of getForm().value when you need processed values without triggering formSubmit.
6431
+ */
6432
+ getProcessedValue() {
6433
+ return this.processFormValue(this.form.getRawValue());
6434
+ }
6117
6435
  open(entity) {
6118
6436
  if (entity) {
6119
6437
  this.entityData = entity;
@@ -7235,5 +7553,5 @@ const throttle = (func, limit) => {
7235
7553
  * Generated bundle index. Do not edit.
7236
7554
  */
7237
7555
 
7238
- export { AngularComponentsModule, AuthService, BreadcrumbComponent, BulkDeleteDialogComponent, CnpjPipe, CookieService, CpfPipe, DEFAULT_LANGUAGE, DateFormatPipe, DocumentMaskDirective, DocumentPipe, DynamicFieldCheckboxComponent, DynamicFieldDateComponent, DynamicFieldDropdownComponent, DynamicFieldImageComponent, DynamicFieldLookupComponent, DynamicFieldMultiselectComponent, DynamicFieldNumberComponent, DynamicFieldTextComponent, DynamicFieldTextareaComponent, DynamicFieldTimeComponent, DynamicFieldWrapperComponent, DynamicFormComponent, EntityListBaseComponent, EntityService, ExportDialogComponent, FieldType, IassistIconComponent, LoadingComponent, LocaleService, MaskService, MoneyMaskDirective, MoneyPipe, PermissionService, PhoneMaskDirective, PhonePipe, PostalCodeMaskDirective, PostalCodePipe, SUPPORTED_LANGUAGES, SeniorPreset, SeniorTokenService, TRANSLATION_CONFIG, TableLoadingDirective, ThemeService, TranslatePipe, TranslationHelper, TranslationService, WebSocketService, apiInterceptor, createFilterString, createFilterTokens, debounce, deepClone, deepEqual, escapeFilterValue, getEnumQuery, getLabelValueRequest, getLanguageInfo, getProp, getSuggestionValue, getTypeInformation, isValidFilter, mapTokenLocaleToLanguage, mergeUnique, provideSeniorPrimeNG, resolveRefs, setProp, throttle };
7556
+ export { AngularComponentsModule, AuthService, BreadcrumbComponent, BulkDeleteDialogComponent, CnpjPipe, CookieService, CpfPipe, DEFAULT_LANGUAGE, DateFormatPipe, DocumentMaskDirective, DocumentPipe, DynamicFieldCheckboxComponent, DynamicFieldDateComponent, DynamicFieldDropdownComponent, DynamicFieldImageComponent, DynamicFieldLookupComponent, DynamicFieldMultiselectComponent, DynamicFieldNumberComponent, DynamicFieldTextComponent, DynamicFieldTextareaComponent, DynamicFieldTimeComponent, DynamicFieldWrapperComponent, DynamicFormComponent, EntityListBaseComponent, EntityService, ExportDialogComponent, FieldType, IassistIconComponent, KanbanBoardComponent, LoadingComponent, LocaleService, MaskService, MoneyMaskDirective, MoneyPipe, PermissionService, PhoneMaskDirective, PhonePipe, PostalCodeMaskDirective, PostalCodePipe, SUPPORTED_LANGUAGES, SeniorPreset, SeniorTokenService, TRANSLATION_CONFIG, TableLoadingDirective, ThemeService, TranslatePipe, TranslationHelper, TranslationService, WebSocketService, apiInterceptor, createFilterString, createFilterTokens, debounce, deepClone, deepEqual, escapeFilterValue, getEnumQuery, getLabelValueRequest, getLanguageInfo, getProp, getSuggestionValue, getTypeInformation, isValidFilter, mapTokenLocaleToLanguage, mergeUnique, provideSeniorPrimeNG, resolveRefs, setProp, throttle };
7239
7557
  //# sourceMappingURL=seniorsistemas-components-ai.mjs.map