@flusys/ng-task-manager 9.2.1 → 9.2.2
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.
- package/fesm2022/{flusys-ng-task-manager-board-list-page.component-BAkiTEpy.mjs → flusys-ng-task-manager-board-list-page.component-S-H_VPtf.mjs} +4 -4
- package/fesm2022/{flusys-ng-task-manager-board-list-page.component-BAkiTEpy.mjs.map → flusys-ng-task-manager-board-list-page.component-S-H_VPtf.mjs.map} +1 -1
- package/fesm2022/{flusys-ng-task-manager-board-view-page.component-9ZrU7hON.mjs → flusys-ng-task-manager-board-view-page.component-CR5kmFau.mjs} +4 -4
- package/fesm2022/{flusys-ng-task-manager-board-view-page.component-9ZrU7hON.mjs.map → flusys-ng-task-manager-board-view-page.component-CR5kmFau.mjs.map} +1 -1
- package/fesm2022/flusys-ng-task-manager.mjs +32 -32
- package/package.json +4 -4
|
@@ -57,7 +57,7 @@ var BoardListPageComponent = class BoardListPageComponent {
|
|
|
57
57
|
}
|
|
58
58
|
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
59
59
|
minVersion: "12.0.0",
|
|
60
|
-
version: "22.2.
|
|
60
|
+
version: "22.2.2",
|
|
61
61
|
ngImport: i0,
|
|
62
62
|
type: BoardListPageComponent,
|
|
63
63
|
deps: [],
|
|
@@ -65,7 +65,7 @@ var BoardListPageComponent = class BoardListPageComponent {
|
|
|
65
65
|
});
|
|
66
66
|
static ɵcmp = i0.ɵɵngDeclareComponent({
|
|
67
67
|
minVersion: "17.0.0",
|
|
68
|
-
version: "22.2.
|
|
68
|
+
version: "22.2.2",
|
|
69
69
|
type: BoardListPageComponent,
|
|
70
70
|
isStandalone: true,
|
|
71
71
|
selector: "tm-board-list-page",
|
|
@@ -504,7 +504,7 @@ var BoardListPageComponent = class BoardListPageComponent {
|
|
|
504
504
|
};
|
|
505
505
|
i0.ɵɵngDeclareClassMetadata({
|
|
506
506
|
minVersion: "12.0.0",
|
|
507
|
-
version: "22.2.
|
|
507
|
+
version: "22.2.2",
|
|
508
508
|
ngImport: i0,
|
|
509
509
|
type: BoardListPageComponent,
|
|
510
510
|
decorators: [{
|
|
@@ -781,4 +781,4 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
781
781
|
});
|
|
782
782
|
export { BoardListPageComponent };
|
|
783
783
|
|
|
784
|
-
//# sourceMappingURL=flusys-ng-task-manager-board-list-page.component-
|
|
784
|
+
//# sourceMappingURL=flusys-ng-task-manager-board-list-page.component-S-H_VPtf.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flusys-ng-task-manager-board-list-page.component-BAkiTEpy.mjs","names":[],"sources":["../../../projects/ng-task-manager/pages/board-list-page/board-list-page.component.ts"],"sourcesContent":["import { Component, computed, inject, signal } from '@angular/core';\nimport { DatePipe } from '@angular/common';\nimport { FormsModule } from '@angular/forms';\nimport { Router } from '@angular/router';\nimport { TranslatePipe } from '@flusys/ng-shared';\nimport { TaskBoardApiService } from '../../services/task-board-api.service';\nimport { TaskBoardStateService } from '../../services/task-board-state.service';\nimport { BOARD_COLOR_PALETTE } from '../../utils/task-utils';\nimport {\n DialogComponent,\n FButtonDirective,\n IconFieldComponent,\n InputIconComponent,\n InputTextDirective,\n SkeletonComponent,\n TextareaDirective,\n TooltipDirective,\n UiIconComponent,\n} from '@flusys/ng-ui';\n\n@Component({\n selector: 'tm-board-list-page',\n imports: [\n DatePipe,\n FormsModule,\n DialogComponent,\n FButtonDirective,\n IconFieldComponent,\n InputIconComponent,\n InputTextDirective,\n SkeletonComponent,\n TextareaDirective,\n TooltipDirective,\n UiIconComponent,\n TranslatePipe,\n ],\n template: `\n <div class=\"p-2 sm:p-4\">\n <div\n class=\"flex flex-col sm:flex-row justify-between items-start sm:items-center gap-3 mb-4\"\n >\n <div>\n <h1 class=\"text-xl sm:text-2xl font-bold m-0\">\n {{ 'task.manager.boards.title' | translate }}\n </h1>\n <p class=\"text-muted-color mt-1 text-sm sm:text-base\">\n {{ 'task.manager.boards.subtitle' | translate }}\n </p>\n </div>\n <div\n class=\"flex flex-col sm:flex-row items-stretch sm:items-center gap-2 w-full sm:w-auto\"\n >\n <f-iconfield class=\"w-full sm:w-64\">\n <f-inputicon icon=\"search\" />\n <input\n fInputText\n type=\"text\"\n [ngModel]=\"searchTerm()\"\n (ngModelChange)=\"onSearchChange($event)\"\n [ngModelOptions]=\"{ standalone: true }\"\n [placeholder]=\"'shared.search' | translate\"\n class=\"w-full\"\n />\n </f-iconfield>\n <button\n fButton\n class=\"w-full sm:w-auto\"\n (click)=\"showCreateDialog.set(true)\"\n >\n <ui-icon pButtonIcon name=\"plus\"></ui-icon>\n <span pButtonLabel>{{ 'task.manager.board.new' | translate }}</span>\n </button>\n </div>\n </div>\n\n @if (state.isLoading()) {\n <div class=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4\">\n @for (i of [1, 2, 3, 4, 5, 6]; track i) {\n <div class=\"card !p-0 overflow-hidden\">\n <f-skeleton height=\"4px\" borderRadius=\"0\" />\n <div class=\"p-5\">\n <f-skeleton height=\"18px\" width=\"60%\" class=\"mb-3\" />\n <f-skeleton height=\"13px\" class=\"mb-1\" />\n <f-skeleton height=\"13px\" width=\"70%\" class=\"mb-5\" />\n <div class=\"flex gap-5 pt-4 border-t border-surface\">\n <f-skeleton height=\"14px\" width=\"55px\" />\n <f-skeleton height=\"14px\" width=\"45px\" />\n <f-skeleton height=\"14px\" width=\"50px\" />\n </div>\n <f-skeleton height=\"11px\" width=\"100px\" class=\"mt-2\" />\n </div>\n </div>\n }\n </div>\n } @else if (filteredBoards().length === 0) {\n <div\n class=\"flex flex-col items-center justify-center py-20 text-muted-color\"\n >\n <span\n class=\"w-16 h-16 rounded-2xl border-2 border-dashed border-surface flex items-center justify-center mb-4\"\n >\n <ui-icon name=\"th-large\" class=\"text-2xl text-muted-color\"></ui-icon>\n </span>\n <p class=\"text-base font-semibold mb-1\">\n {{ 'task.manager.board.empty' | translate }}\n </p>\n <p class=\"text-sm text-muted-color mb-5\">\n {{ 'task.manager.board.empty.hint' | translate }}\n </p>\n <button\n fButton\n size=\"small\"\n (click)=\"showCreateDialog.set(true)\"\n >\n <ui-icon pButtonIcon name=\"plus\"></ui-icon>\n <span pButtonLabel>{{ 'task.manager.board.new' | translate }}</span>\n </button>\n </div>\n } @else {\n <div class=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4\">\n @for (board of filteredBoards(); track board.id) {\n <div\n class=\"card !p-0 cursor-pointer overflow-hidden group hover:shadow-lg transition-all duration-200\"\n (click)=\"openBoard(board.id)\"\n >\n <div class=\"h-1\" [style.background-color]=\"board.color\"></div>\n\n <div class=\"p-5\">\n <div class=\"flex items-start justify-between gap-3 mb-2\">\n <div class=\"flex items-center gap-2 min-w-0\">\n <h3\n class=\"font-semibold text-base m-0 truncate group-hover:text-primary-500 transition-colors duration-150\"\n >\n {{ board.name }}\n </h3>\n </div>\n <ui-icon name=\"arrow-right\" class=\"text-xs text-muted-color group-hover:text-primary-500 group-hover:translate-x-0.5 transition-all duration-150 flex-shrink-0 mt-1\"></ui-icon>\n </div>\n\n <p\n class=\"text-sm text-muted-color line-clamp-2 pl-[18px] mb-0 min-h-[40px]\"\n >\n {{ board.description || '' }}\n </p>\n\n <div\n class=\"border-t border-surface mt-4 pt-4 space-y-2.5\"\n >\n <div class=\"flex items-center gap-4\">\n <span class=\"flex items-center gap-1.5\">\n <ui-icon name=\"users\" class=\"text-[11px] text-muted-color\"></ui-icon>\n <span class=\"text-sm font-semibold\">{{\n board.totalMembers ?? 0\n }}</span>\n <span class=\"text-xs text-muted-color\">{{\n 'task.manager.board.members' | translate\n }}</span>\n </span>\n <span\n class=\"w-px h-3 bg-surface-200 dark:bg-surface-600\"\n ></span>\n <span class=\"flex items-center gap-1.5\">\n <ui-icon name=\"list\" class=\"text-[11px] text-muted-color\"></ui-icon>\n <span class=\"text-sm font-semibold\">{{\n board.totalLists ?? 0\n }}</span>\n <span class=\"text-xs text-muted-color\">{{\n 'task.manager.board.lists' | translate\n }}</span>\n </span>\n <span\n class=\"w-px h-3 bg-surface-200 dark:bg-surface-600\"\n ></span>\n <span class=\"flex items-center gap-1.5\">\n <ui-icon name=\"check-square\" class=\"text-[11px] text-muted-color\"></ui-icon>\n <span class=\"text-sm font-semibold\">{{\n board.totalTasks ?? 0\n }}</span>\n <span class=\"text-xs text-muted-color\">{{\n 'task.manager.board.tasks' | translate\n }}</span>\n </span>\n </div>\n <div\n class=\"flex items-center gap-1.5 text-xs text-muted-color\"\n >\n <ui-icon name=\"clock\" class=\"text-[10px]\"></ui-icon>\n <span>{{ board.createdAt | date: 'MMM d, yyyy' }}</span>\n </div>\n </div>\n </div>\n </div>\n }\n </div>\n }\n </div>\n\n <f-dialog\n [header]=\"'task.manager.board.new' | translate\"\n [(visible)]=\"showCreateDialog\"\n [modal]=\"true\"\n [style]=\"{ width: '440px' }\"\n >\n <div class=\"flex flex-col gap-4 py-2\">\n <div class=\"flex flex-col gap-1\">\n <label class=\"text-sm font-medium\"\n >{{ 'shared.name' | translate }}\n <span class=\"text-red-500\">*</span></label\n >\n <input\n fInputText\n [(ngModel)]=\"newBoardName\"\n [placeholder]=\"'task.manager.board.name.placeholder' | translate\"\n />\n </div>\n <div class=\"flex flex-col gap-1\">\n <label class=\"text-sm font-medium\">{{\n 'shared.description' | translate\n }}</label>\n <textarea\n fTextarea\n [(ngModel)]=\"newBoardDescription\"\n rows=\"2\"\n [placeholder]=\"\n 'task.manager.board.description.placeholder' | translate\n \"\n ></textarea>\n </div>\n <div class=\"flex flex-col gap-2\">\n <label class=\"text-sm font-medium\">{{\n 'task.manager.board.color.label' | translate\n }}</label>\n <div class=\"flex flex-wrap gap-2\">\n @for (c of boardColors; track c) {\n <button\n type=\"button\"\n class=\"w-8 h-8 rounded-full border-2 transition-all hover:scale-110 focus:outline-none flex items-center justify-center\"\n [style.background-color]=\"c\"\n [class.ring-2]=\"newBoardColor === c\"\n [class.ring-offset-2]=\"newBoardColor === c\"\n [class.ring-surface-900]=\"newBoardColor === c\"\n [class.dark:ring-surface-0]=\"newBoardColor === c\"\n [fTooltip]=\"c\"\n (click)=\"newBoardColor = c\"\n >\n @if (newBoardColor === c) {\n <ui-icon name=\"check\" class=\"text-white text-xs\"></ui-icon>\n }\n </button>\n }\n </div>\n <div class=\"flex items-center gap-2 mt-1\">\n <span\n class=\"w-8 h-8 rounded-full border border-surface flex-shrink-0\"\n [style.background-color]=\"newBoardColor\"\n ></span>\n <span class=\"text-sm text-muted-color font-mono\">{{\n newBoardColor\n }}</span>\n </div>\n </div>\n </div>\n\n <ng-template #footer>\n <div class=\"flex justify-end gap-2\">\n <button\n fButton\n severity=\"secondary\"\n (click)=\"closeCreateDialog()\"\n >\n <span pButtonLabel>{{ 'shared.cancel' | translate }}</span>\n </button>\n <button\n fButton\n (click)=\"createBoard()\"\n [disabled]=\"isCreating()\"\n >\n @if (isCreating()) {\n <ui-icon pButtonIcon name=\"spinner\" [spin]=\"true\"></ui-icon>\n }\n <span pButtonLabel>{{ 'shared.create' | translate }}</span>\n </button>\n </div>\n </ng-template>\n </f-dialog>\n `,\n})\nexport class BoardListPageComponent {\n protected readonly state = inject(TaskBoardStateService);\n private readonly boardApi = inject(TaskBoardApiService);\n private readonly router = inject(Router);\n\n readonly showCreateDialog = signal(false);\n readonly isCreating = signal(false);\n newBoardName = '';\n newBoardDescription = '';\n newBoardColor = BOARD_COLOR_PALETTE[0];\n readonly boardColors = BOARD_COLOR_PALETTE;\n\n private readonly _searchTerm = signal('');\n readonly searchTerm = this._searchTerm.asReadonly();\n\n readonly filteredBoards = computed(() => {\n const term = this.searchTerm().toLowerCase().trim();\n const boards = this.state.boards();\n if (!term) return boards;\n return boards.filter(\n (board) =>\n board.name.toLowerCase().includes(term) ||\n (board.description ?? '').toLowerCase().includes(term),\n );\n });\n\n constructor() {\n void this.state.loadBoards().catch(() => undefined);\n }\n\n onSearchChange(term: string): void {\n this._searchTerm.set(term);\n }\n\n openBoard(boardId: string): void {\n this.router.navigate(['/task-manager/board', boardId]);\n }\n\n closeCreateDialog(): void {\n this.showCreateDialog.set(false);\n this.newBoardName = '';\n this.newBoardDescription = '';\n this.newBoardColor = BOARD_COLOR_PALETTE[0];\n }\n\n async createBoard(): Promise<void> {\n if (!this.newBoardName.trim()) return;\n this.isCreating.set(true);\n try {\n await this.boardApi.insert({\n name: this.newBoardName,\n description: this.newBoardDescription || undefined,\n color: this.newBoardColor,\n });\n await this.state.loadBoards();\n this.closeCreateDialog();\n } finally {\n this.isCreating.set(false);\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"flusys-ng-task-manager-board-list-page.component-S-H_VPtf.mjs","names":[],"sources":["../../../projects/ng-task-manager/pages/board-list-page/board-list-page.component.ts"],"sourcesContent":["import { Component, computed, inject, signal } from '@angular/core';\nimport { DatePipe } from '@angular/common';\nimport { FormsModule } from '@angular/forms';\nimport { Router } from '@angular/router';\nimport { TranslatePipe } from '@flusys/ng-shared';\nimport { TaskBoardApiService } from '../../services/task-board-api.service';\nimport { TaskBoardStateService } from '../../services/task-board-state.service';\nimport { BOARD_COLOR_PALETTE } from '../../utils/task-utils';\nimport {\n DialogComponent,\n FButtonDirective,\n IconFieldComponent,\n InputIconComponent,\n InputTextDirective,\n SkeletonComponent,\n TextareaDirective,\n TooltipDirective,\n UiIconComponent,\n} from '@flusys/ng-ui';\n\n@Component({\n selector: 'tm-board-list-page',\n imports: [\n DatePipe,\n FormsModule,\n DialogComponent,\n FButtonDirective,\n IconFieldComponent,\n InputIconComponent,\n InputTextDirective,\n SkeletonComponent,\n TextareaDirective,\n TooltipDirective,\n UiIconComponent,\n TranslatePipe,\n ],\n template: `\n <div class=\"p-2 sm:p-4\">\n <div\n class=\"flex flex-col sm:flex-row justify-between items-start sm:items-center gap-3 mb-4\"\n >\n <div>\n <h1 class=\"text-xl sm:text-2xl font-bold m-0\">\n {{ 'task.manager.boards.title' | translate }}\n </h1>\n <p class=\"text-muted-color mt-1 text-sm sm:text-base\">\n {{ 'task.manager.boards.subtitle' | translate }}\n </p>\n </div>\n <div\n class=\"flex flex-col sm:flex-row items-stretch sm:items-center gap-2 w-full sm:w-auto\"\n >\n <f-iconfield class=\"w-full sm:w-64\">\n <f-inputicon icon=\"search\" />\n <input\n fInputText\n type=\"text\"\n [ngModel]=\"searchTerm()\"\n (ngModelChange)=\"onSearchChange($event)\"\n [ngModelOptions]=\"{ standalone: true }\"\n [placeholder]=\"'shared.search' | translate\"\n class=\"w-full\"\n />\n </f-iconfield>\n <button\n fButton\n class=\"w-full sm:w-auto\"\n (click)=\"showCreateDialog.set(true)\"\n >\n <ui-icon pButtonIcon name=\"plus\"></ui-icon>\n <span pButtonLabel>{{ 'task.manager.board.new' | translate }}</span>\n </button>\n </div>\n </div>\n\n @if (state.isLoading()) {\n <div class=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4\">\n @for (i of [1, 2, 3, 4, 5, 6]; track i) {\n <div class=\"card !p-0 overflow-hidden\">\n <f-skeleton height=\"4px\" borderRadius=\"0\" />\n <div class=\"p-5\">\n <f-skeleton height=\"18px\" width=\"60%\" class=\"mb-3\" />\n <f-skeleton height=\"13px\" class=\"mb-1\" />\n <f-skeleton height=\"13px\" width=\"70%\" class=\"mb-5\" />\n <div class=\"flex gap-5 pt-4 border-t border-surface\">\n <f-skeleton height=\"14px\" width=\"55px\" />\n <f-skeleton height=\"14px\" width=\"45px\" />\n <f-skeleton height=\"14px\" width=\"50px\" />\n </div>\n <f-skeleton height=\"11px\" width=\"100px\" class=\"mt-2\" />\n </div>\n </div>\n }\n </div>\n } @else if (filteredBoards().length === 0) {\n <div\n class=\"flex flex-col items-center justify-center py-20 text-muted-color\"\n >\n <span\n class=\"w-16 h-16 rounded-2xl border-2 border-dashed border-surface flex items-center justify-center mb-4\"\n >\n <ui-icon name=\"th-large\" class=\"text-2xl text-muted-color\"></ui-icon>\n </span>\n <p class=\"text-base font-semibold mb-1\">\n {{ 'task.manager.board.empty' | translate }}\n </p>\n <p class=\"text-sm text-muted-color mb-5\">\n {{ 'task.manager.board.empty.hint' | translate }}\n </p>\n <button\n fButton\n size=\"small\"\n (click)=\"showCreateDialog.set(true)\"\n >\n <ui-icon pButtonIcon name=\"plus\"></ui-icon>\n <span pButtonLabel>{{ 'task.manager.board.new' | translate }}</span>\n </button>\n </div>\n } @else {\n <div class=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4\">\n @for (board of filteredBoards(); track board.id) {\n <div\n class=\"card !p-0 cursor-pointer overflow-hidden group hover:shadow-lg transition-all duration-200\"\n (click)=\"openBoard(board.id)\"\n >\n <div class=\"h-1\" [style.background-color]=\"board.color\"></div>\n\n <div class=\"p-5\">\n <div class=\"flex items-start justify-between gap-3 mb-2\">\n <div class=\"flex items-center gap-2 min-w-0\">\n <h3\n class=\"font-semibold text-base m-0 truncate group-hover:text-primary-500 transition-colors duration-150\"\n >\n {{ board.name }}\n </h3>\n </div>\n <ui-icon name=\"arrow-right\" class=\"text-xs text-muted-color group-hover:text-primary-500 group-hover:translate-x-0.5 transition-all duration-150 flex-shrink-0 mt-1\"></ui-icon>\n </div>\n\n <p\n class=\"text-sm text-muted-color line-clamp-2 pl-[18px] mb-0 min-h-[40px]\"\n >\n {{ board.description || '' }}\n </p>\n\n <div\n class=\"border-t border-surface mt-4 pt-4 space-y-2.5\"\n >\n <div class=\"flex items-center gap-4\">\n <span class=\"flex items-center gap-1.5\">\n <ui-icon name=\"users\" class=\"text-[11px] text-muted-color\"></ui-icon>\n <span class=\"text-sm font-semibold\">{{\n board.totalMembers ?? 0\n }}</span>\n <span class=\"text-xs text-muted-color\">{{\n 'task.manager.board.members' | translate\n }}</span>\n </span>\n <span\n class=\"w-px h-3 bg-surface-200 dark:bg-surface-600\"\n ></span>\n <span class=\"flex items-center gap-1.5\">\n <ui-icon name=\"list\" class=\"text-[11px] text-muted-color\"></ui-icon>\n <span class=\"text-sm font-semibold\">{{\n board.totalLists ?? 0\n }}</span>\n <span class=\"text-xs text-muted-color\">{{\n 'task.manager.board.lists' | translate\n }}</span>\n </span>\n <span\n class=\"w-px h-3 bg-surface-200 dark:bg-surface-600\"\n ></span>\n <span class=\"flex items-center gap-1.5\">\n <ui-icon name=\"check-square\" class=\"text-[11px] text-muted-color\"></ui-icon>\n <span class=\"text-sm font-semibold\">{{\n board.totalTasks ?? 0\n }}</span>\n <span class=\"text-xs text-muted-color\">{{\n 'task.manager.board.tasks' | translate\n }}</span>\n </span>\n </div>\n <div\n class=\"flex items-center gap-1.5 text-xs text-muted-color\"\n >\n <ui-icon name=\"clock\" class=\"text-[10px]\"></ui-icon>\n <span>{{ board.createdAt | date: 'MMM d, yyyy' }}</span>\n </div>\n </div>\n </div>\n </div>\n }\n </div>\n }\n </div>\n\n <f-dialog\n [header]=\"'task.manager.board.new' | translate\"\n [(visible)]=\"showCreateDialog\"\n [modal]=\"true\"\n [style]=\"{ width: '440px' }\"\n >\n <div class=\"flex flex-col gap-4 py-2\">\n <div class=\"flex flex-col gap-1\">\n <label class=\"text-sm font-medium\"\n >{{ 'shared.name' | translate }}\n <span class=\"text-red-500\">*</span></label\n >\n <input\n fInputText\n [(ngModel)]=\"newBoardName\"\n [placeholder]=\"'task.manager.board.name.placeholder' | translate\"\n />\n </div>\n <div class=\"flex flex-col gap-1\">\n <label class=\"text-sm font-medium\">{{\n 'shared.description' | translate\n }}</label>\n <textarea\n fTextarea\n [(ngModel)]=\"newBoardDescription\"\n rows=\"2\"\n [placeholder]=\"\n 'task.manager.board.description.placeholder' | translate\n \"\n ></textarea>\n </div>\n <div class=\"flex flex-col gap-2\">\n <label class=\"text-sm font-medium\">{{\n 'task.manager.board.color.label' | translate\n }}</label>\n <div class=\"flex flex-wrap gap-2\">\n @for (c of boardColors; track c) {\n <button\n type=\"button\"\n class=\"w-8 h-8 rounded-full border-2 transition-all hover:scale-110 focus:outline-none flex items-center justify-center\"\n [style.background-color]=\"c\"\n [class.ring-2]=\"newBoardColor === c\"\n [class.ring-offset-2]=\"newBoardColor === c\"\n [class.ring-surface-900]=\"newBoardColor === c\"\n [class.dark:ring-surface-0]=\"newBoardColor === c\"\n [fTooltip]=\"c\"\n (click)=\"newBoardColor = c\"\n >\n @if (newBoardColor === c) {\n <ui-icon name=\"check\" class=\"text-white text-xs\"></ui-icon>\n }\n </button>\n }\n </div>\n <div class=\"flex items-center gap-2 mt-1\">\n <span\n class=\"w-8 h-8 rounded-full border border-surface flex-shrink-0\"\n [style.background-color]=\"newBoardColor\"\n ></span>\n <span class=\"text-sm text-muted-color font-mono\">{{\n newBoardColor\n }}</span>\n </div>\n </div>\n </div>\n\n <ng-template #footer>\n <div class=\"flex justify-end gap-2\">\n <button\n fButton\n severity=\"secondary\"\n (click)=\"closeCreateDialog()\"\n >\n <span pButtonLabel>{{ 'shared.cancel' | translate }}</span>\n </button>\n <button\n fButton\n (click)=\"createBoard()\"\n [disabled]=\"isCreating()\"\n >\n @if (isCreating()) {\n <ui-icon pButtonIcon name=\"spinner\" [spin]=\"true\"></ui-icon>\n }\n <span pButtonLabel>{{ 'shared.create' | translate }}</span>\n </button>\n </div>\n </ng-template>\n </f-dialog>\n `,\n})\nexport class BoardListPageComponent {\n protected readonly state = inject(TaskBoardStateService);\n private readonly boardApi = inject(TaskBoardApiService);\n private readonly router = inject(Router);\n\n readonly showCreateDialog = signal(false);\n readonly isCreating = signal(false);\n newBoardName = '';\n newBoardDescription = '';\n newBoardColor = BOARD_COLOR_PALETTE[0];\n readonly boardColors = BOARD_COLOR_PALETTE;\n\n private readonly _searchTerm = signal('');\n readonly searchTerm = this._searchTerm.asReadonly();\n\n readonly filteredBoards = computed(() => {\n const term = this.searchTerm().toLowerCase().trim();\n const boards = this.state.boards();\n if (!term) return boards;\n return boards.filter(\n (board) =>\n board.name.toLowerCase().includes(term) ||\n (board.description ?? '').toLowerCase().includes(term),\n );\n });\n\n constructor() {\n void this.state.loadBoards().catch(() => undefined);\n }\n\n onSearchChange(term: string): void {\n this._searchTerm.set(term);\n }\n\n openBoard(boardId: string): void {\n this.router.navigate(['/task-manager/board', boardId]);\n }\n\n closeCreateDialog(): void {\n this.showCreateDialog.set(false);\n this.newBoardName = '';\n this.newBoardDescription = '';\n this.newBoardColor = BOARD_COLOR_PALETTE[0];\n }\n\n async createBoard(): Promise<void> {\n if (!this.newBoardName.trim()) return;\n this.isCreating.set(true);\n try {\n await this.boardApi.insert({\n name: this.newBoardName,\n description: this.newBoardDescription || undefined,\n color: this.newBoardColor,\n });\n await this.state.loadBoards();\n this.closeCreateDialog();\n } finally {\n this.isCreating.set(false);\n }\n }\n}\n"],"mappings":"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"}
|
|
@@ -241,7 +241,7 @@ var BoardViewPageComponent = class BoardViewPageComponent {
|
|
|
241
241
|
}
|
|
242
242
|
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
243
243
|
minVersion: "12.0.0",
|
|
244
|
-
version: "22.2.
|
|
244
|
+
version: "22.2.2",
|
|
245
245
|
ngImport: i0,
|
|
246
246
|
type: BoardViewPageComponent,
|
|
247
247
|
deps: [],
|
|
@@ -249,7 +249,7 @@ var BoardViewPageComponent = class BoardViewPageComponent {
|
|
|
249
249
|
});
|
|
250
250
|
static ɵcmp = i0.ɵɵngDeclareComponent({
|
|
251
251
|
minVersion: "17.0.0",
|
|
252
|
-
version: "22.2.
|
|
252
|
+
version: "22.2.2",
|
|
253
253
|
type: BoardViewPageComponent,
|
|
254
254
|
isStandalone: true,
|
|
255
255
|
selector: "tm-board-view-page",
|
|
@@ -1491,7 +1491,7 @@ var BoardViewPageComponent = class BoardViewPageComponent {
|
|
|
1491
1491
|
};
|
|
1492
1492
|
i0.ɵɵngDeclareClassMetadata({
|
|
1493
1493
|
minVersion: "12.0.0",
|
|
1494
|
-
version: "22.2.
|
|
1494
|
+
version: "22.2.2",
|
|
1495
1495
|
ngImport: i0,
|
|
1496
1496
|
type: BoardViewPageComponent,
|
|
1497
1497
|
decorators: [{
|
|
@@ -2339,4 +2339,4 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
2339
2339
|
});
|
|
2340
2340
|
export { BoardViewPageComponent };
|
|
2341
2341
|
|
|
2342
|
-
//# sourceMappingURL=flusys-ng-task-manager-board-view-page.component-
|
|
2342
|
+
//# sourceMappingURL=flusys-ng-task-manager-board-view-page.component-CR5kmFau.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flusys-ng-task-manager-board-view-page.component-9ZrU7hON.mjs","names":[],"sources":["../../../projects/ng-task-manager/pages/board-view-page/board-view-page.component.ts"],"sourcesContent":["import {\n CdkDragDrop,\n DragDropModule,\n moveItemInArray,\n} from '@angular/cdk/drag-drop';\nimport {\n Component,\n computed,\n DestroyRef,\n effect,\n inject,\n input,\n signal,\n untracked,\n} from '@angular/core';\nimport { DatePipe } from '@angular/common';\nimport { FormsModule } from '@angular/forms';\nimport {\n TranslatePipe,\n TranslateService,\n UserSelectComponent,\n} from '@flusys/ng-shared';\nimport {\n AvatarComponent,\n ConfirmationService,\n DialogComponent,\n FButtonDirective,\n InputTextDirective,\n MessageService,\n SelectComponent,\n SkeletonComponent,\n SortableColumnDirective,\n SortIconComponent,\n TableComponent,\n TagComponent,\n TextareaDirective,\n TooltipDirective,\n UiIconComponent,\n} from '@flusys/ng-ui';\nimport { TaskCardComponent } from '../../components/task-card/task-card.component';\nimport { TaskDetailPanelComponent } from '../../components/task-detail-panel/task-detail-panel.component';\nimport { TaskFormDialogComponent } from '../../components/task-form-dialog/task-form-dialog.component';\nimport {\n ITask,\n ITaskBoard,\n ITaskBoardMember,\n ITaskList,\n} from '../../interfaces/task.interface';\nimport { TaskListApiService } from '../../services/task-api.service';\nimport { TaskBoardStateService } from '../../services/task-board-state.service';\nimport {\n BOARD_COLOR_PALETTE,\n isTaskOverdue,\n memberColorFromId,\n memberInitials,\n taskPrioritySeverity,\n} from '../../utils/task-utils';\n\ntype ViewMode = 'board' | 'list';\ntype ITaskListWithTasks = ITaskList & { tasks: ITask[] };\n\ninterface ITaskRow extends ITask {\n listName: string;\n listColor: string;\n}\n\n@Component({\n selector: 'tm-board-view-page',\n imports: [\n AvatarComponent,\n DialogComponent,\n FButtonDirective,\n InputTextDirective,\n SelectComponent,\n SkeletonComponent,\n SortableColumnDirective,\n SortIconComponent,\n TableComponent,\n TagComponent,\n TextareaDirective,\n TooltipDirective,\n UiIconComponent,\n DragDropModule,\n DatePipe,\n FormsModule,\n TaskCardComponent,\n TaskFormDialogComponent,\n TaskDetailPanelComponent,\n TranslatePipe,\n UserSelectComponent,\n ],\n template: `\n <div class=\"flex flex-col h-full\">\n <div class=\"flex flex-col\">\n <div class=\"flex items-center justify-between px-5 py-2.5 gap-4\">\n @if (state.activeBoard(); as board) {\n <div class=\"flex items-center gap-2.5 min-w-0 flex-1 group\">\n <div class=\"flex flex-col min-w-0\">\n <div class=\"flex items-center gap-1.5 min-w-0\">\n <h1\n class=\"text-base font-bold text-surface-900 dark:text-surface-0 truncate leading-snug\"\n >\n {{ board.name }}\n </h1>\n <button\n fButton\n [text]=\"true\"\n size=\"small\"\n severity=\"secondary\"\n class=\"!w-6 !h-6 flex-shrink-0 opacity-0 group-hover:opacity-100 transition-opacity\"\n [fTooltip]=\"'task.manager.board.edit' | translate\"\n tooltipPosition=\"bottom\"\n (click)=\"openEditBoardDialog(board)\"\n >\n <ui-icon pButtonIcon name=\"pencil\"></ui-icon>\n </button>\n </div>\n @if (board.description) {\n <span\n class=\"text-xs text-muted-color truncate max-w-sm hidden md:block leading-snug\"\n >\n {{ board.description }}\n </span>\n }\n </div>\n </div>\n }\n\n <div class=\"flex items-center gap-1.5 flex-shrink-0\">\n @if (state.members().length > 0) {\n <div\n class=\"flex items-center -space-x-2 cursor-pointer mr-1\"\n (click)=\"showMembersDialog.set(true)\"\n [fTooltip]=\"'task.manager.board.manage.members' | translate\"\n tooltipPosition=\"bottom\"\n >\n @for (member of state.members().slice(0, 4); track member.id) {\n <f-avatar\n shape=\"circle\"\n size=\"small\"\n [label]=\"memberInitials(member)\"\n [color]=\"memberColor(member)\"\n styleClass=\"!border-2 !border-surface-card ring-1 ring-surface flex-shrink-0\"\n />\n }\n @if (state.members().length > 4) {\n <f-avatar\n shape=\"circle\"\n size=\"small\"\n [label]=\"'+' + (state.members().length - 4)\"\n styleClass=\"!border-2 !border-surface-card !bg-surface-200 dark:!bg-surface-700 !text-surface-600 dark:!text-surface-300 flex-shrink-0\"\n />\n }\n </div>\n }\n\n <div\n class=\"h-5 w-px bg-surface-300 dark:bg-surface-600 mx-0.5\"\n ></div>\n\n <div\n class=\"flex rounded-border overflow-hidden border border-surface\"\n >\n <button\n fButton\n [fTooltip]=\"'task.manager.view.board' | translate\"\n tooltipPosition=\"bottom\"\n size=\"small\"\n [severity]=\"viewMode() === 'board' ? 'primary' : 'secondary'\"\n [outlined]=\"viewMode() !== 'board'\"\n class=\"!rounded-none !border-0\"\n (click)=\"viewMode.set('board')\"\n >\n <ui-icon pButtonIcon name=\"th-large\"></ui-icon>\n </button>\n <button\n fButton\n [fTooltip]=\"'task.manager.view.list' | translate\"\n tooltipPosition=\"bottom\"\n size=\"small\"\n [severity]=\"viewMode() === 'list' ? 'primary' : 'secondary'\"\n [outlined]=\"viewMode() !== 'list'\"\n class=\"!rounded-none !border-0\"\n (click)=\"viewMode.set('list')\"\n >\n <ui-icon pButtonIcon name=\"list\"></ui-icon>\n </button>\n </div>\n\n <div\n class=\"h-5 w-px bg-surface-300 dark:bg-surface-600 mx-0.5\"\n ></div>\n\n <button\n fButton\n [text]=\"true\"\n severity=\"secondary\"\n size=\"small\"\n class=\"!w-8 !h-8\"\n [fTooltip]=\"'task.manager.board.manage.members' | translate\"\n tooltipPosition=\"bottom\"\n (click)=\"showMembersDialog.set(true)\"\n >\n <ui-icon pButtonIcon name=\"users\"></ui-icon>\n </button>\n <button\n fButton\n [text]=\"true\"\n severity=\"secondary\"\n size=\"small\"\n class=\"!w-8 !h-8\"\n [fTooltip]=\"'task.manager.board.manage.labels' | translate\"\n tooltipPosition=\"bottom\"\n (click)=\"showLabelsDialog.set(true)\"\n >\n <ui-icon pButtonIcon name=\"tag\"></ui-icon>\n </button>\n\n @if (viewMode() === 'board') {\n <div\n class=\"h-5 w-px bg-surface-300 dark:bg-surface-600 mx-0.5\"\n ></div>\n <button\n fButton\n size=\"small\"\n (click)=\"showAddListDialog.set(true)\"\n >\n <ui-icon pButtonIcon name=\"plus\"></ui-icon>\n <span pButtonLabel>{{\n 'task.manager.board.add.list' | translate\n }}</span>\n </button>\n }\n </div>\n </div>\n\n @if (state.activeBoard(); as board) {\n <div\n class=\"h-0.5 w-full flex-shrink-0\"\n [style.background-color]=\"board.color\"\n ></div>\n }\n </div>\n\n @if (state.isBoardLoading()) {\n @if (viewMode() === 'board') {\n <div class=\"flex gap-4 p-6 overflow-x-auto\">\n @for (i of [1, 2, 3]; track i) {\n <div class=\"flex-shrink-0 w-72\">\n <f-skeleton height=\"36px\" class=\"mb-3\" />\n @for (j of [1, 2, 3]; track j) {\n <f-skeleton height=\"90px\" class=\"mb-2\" />\n }\n </div>\n }\n </div>\n } @else {\n <div class=\"p-6\">\n @for (i of [1, 2, 3, 4, 5]; track i) {\n <f-skeleton height=\"48px\" class=\"mb-2\" />\n }\n </div>\n }\n } @else if (viewMode() === 'board') {\n <div\n class=\"flex gap-4 p-5 overflow-x-auto flex-1\"\n cdkDropList\n cdkDropListOrientation=\"horizontal\"\n [cdkDropListData]=\"state.listsWithTasks()\"\n (cdkDropListDropped)=\"onListDrop($event)\"\n >\n @for (list of state.listsWithTasks(); track list.id) {\n <div\n cdkDrag\n class=\"flex-shrink-0 w-72 flex flex-col max-h-[calc(100vh-140px)] self-start rounded-border border border-surface shadow-sm overflow-hidden\"\n >\n <div\n class=\"flex items-center gap-1 px-2.5 py-2.5 border-b border-surface\"\n >\n <ui-icon\n cdkDragHandle\n name=\"bars\"\n class=\"text-muted-color text-xs cursor-grab flex-shrink-0 px-1\"\n ></ui-icon>\n\n <div class=\"flex items-center gap-2 min-w-0 flex-1\">\n @if (editingListId() === list.id) {\n <input\n fInputText\n class=\"text-sm font-semibold !h-6 !py-0 !px-1 w-full\"\n [ngModel]=\"editingListNameValue()\"\n (ngModelChange)=\"editingListNameValue.set($event)\"\n (keydown.enter)=\"saveRenameList()\"\n (keydown.escape)=\"cancelRenameList()\"\n (blur)=\"cancelRenameList()\"\n (click)=\"$event.stopPropagation()\"\n autofocus\n />\n } @else {\n <span class=\"font-semibold text-sm truncate\">{{\n list.name\n }}</span>\n <span\n class=\"text-[11px] font-semibold px-1.5 py-0.5 rounded-full text-white flex-shrink-0\"\n [style.background-color]=\"list.color\"\n >\n {{ list.tasks.length }}\n </span>\n }\n </div>\n\n @if (editingListId() === list.id) {\n <button\n fButton\n [text]=\"true\"\n size=\"small\"\n severity=\"success\"\n class=\"!w-6 !h-6 flex-shrink-0\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"saveRenameList(); $event.stopPropagation()\"\n >\n <ui-icon pButtonIcon name=\"check\"></ui-icon>\n </button>\n <button\n fButton\n [text]=\"true\"\n size=\"small\"\n severity=\"secondary\"\n class=\"!w-6 !h-6 flex-shrink-0\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"cancelRenameList(); $event.stopPropagation()\"\n >\n <ui-icon pButtonIcon name=\"times\"></ui-icon>\n </button>\n } @else {\n <button\n fButton\n [text]=\"true\"\n size=\"small\"\n severity=\"secondary\"\n class=\"!w-6 !h-6 flex-shrink-0\"\n [fTooltip]=\"'task.manager.list.rename' | translate\"\n tooltipPosition=\"bottom\"\n (click)=\"startRenameList(list); $event.stopPropagation()\"\n >\n <ui-icon pButtonIcon name=\"pencil\"></ui-icon>\n </button>\n }\n </div>\n\n <div\n cdkDropList\n [id]=\"list.id\"\n [cdkDropListData]=\"list.tasks\"\n [cdkDropListConnectedTo]=\"listDropIds()\"\n (cdkDropListDropped)=\"onTaskDrop($event)\"\n class=\"flex flex-col gap-2 p-2 overflow-y-auto flex-1 min-h-[60px]\"\n >\n @for (task of list.tasks; track task.id) {\n <div cdkDrag [cdkDragData]=\"task\">\n <tm-task-card\n [task]=\"task\"\n (cardClick)=\"state.selectTask($event)\"\n (editClick)=\"onEditTask($event)\"\n (deleteClick)=\"onDeleteTask($event)\"\n />\n </div>\n }\n @if (list.tasks.length === 0) {\n <div\n class=\"flex items-center justify-center h-14 border-2 border-dashed border-surface rounded-border\"\n >\n <span class=\"text-xs text-muted-color\">{{\n 'task.manager.board.drop.tasks.here' | translate\n }}</span>\n </div>\n }\n </div>\n\n <div class=\"border-t border-surface p-1.5\">\n <button\n fButton\n severity=\"secondary\"\n [text]=\"true\"\n size=\"small\"\n class=\"w-full !justify-start\"\n (click)=\"openAddTask(list)\"\n >\n <ui-icon pButtonIcon name=\"plus\"></ui-icon>\n <span pButtonLabel>{{\n 'task.manager.board.add.task' | translate\n }}</span>\n </button>\n </div>\n </div>\n }\n\n @if (state.listsWithTasks().length === 0) {\n <div class=\"flex-1 flex items-center justify-center\">\n <div class=\"text-center text-muted-color\">\n <div\n class=\"w-16 h-16 rounded-2xl border-2 border-dashed border-surface flex items-center justify-center mx-auto mb-4\"\n >\n <ui-icon\n name=\"list\"\n class=\"text-3xl text-muted-color\"\n ></ui-icon>\n </div>\n <p class=\"font-medium text-muted-color\">\n {{ 'task.manager.board.list.empty' | translate }}\n </p>\n <button\n fButton\n severity=\"secondary\"\n size=\"small\"\n class=\"mt-3\"\n (click)=\"showAddListDialog.set(true)\"\n >\n <ui-icon pButtonIcon name=\"plus\"></ui-icon>\n <span pButtonLabel>{{\n 'task.manager.board.add.list' | translate\n }}</span>\n </button>\n </div>\n </div>\n }\n </div>\n } @else {\n <div class=\"p-4 sm:p-6 flex-1 overflow-auto\">\n <div class=\"card\">\n <div class=\"overflow-x-auto -mx-4 sm:mx-0\">\n <f-table\n [value]=\"allTasksFlat()\"\n [paginator]=\"allTasksFlat().length > 20\"\n [rows]=\"20\"\n [rowsPerPageOptions]=\"[10, 20, 50]\"\n [scrollable]=\"true\"\n [tableStyle]=\"{ 'min-width': '700px' }\"\n >\n <ng-template #header>\n <tr>\n <th fSortableColumn=\"title\" class=\"min-w-[240px]\">\n {{ 'task.manager.table.title' | translate }}\n <f-sorticon field=\"title\" />\n </th>\n <th fSortableColumn=\"listName\" class=\"w-40\">\n {{ 'task.manager.table.list' | translate }}\n <f-sorticon field=\"listName\" />\n </th>\n <th fSortableColumn=\"priority\" class=\"w-32\">\n {{ 'task.manager.table.priority' | translate }}\n <f-sorticon field=\"priority\" />\n </th>\n <th class=\"w-36\">\n {{ 'task.manager.table.assignee' | translate }}\n </th>\n <th fSortableColumn=\"dueDate\" class=\"w-32\">\n {{ 'task.manager.table.due.date' | translate }}\n <f-sorticon field=\"dueDate\" />\n </th>\n <th class=\"w-[100px]\">\n {{ 'shared.actions' | translate }}\n </th>\n </tr>\n </ng-template>\n <ng-template #body let-task>\n <tr>\n <td>\n <span\n class=\"font-medium text-sm cursor-pointer hover:text-primary-500 transition-colors\"\n (click)=\"state.selectTask(task)\"\n >{{ task.title }}</span\n >\n </td>\n <td>\n <span class=\"inline-flex items-center gap-1.5 text-sm\">\n <span\n class=\"w-2 h-2 rounded-full flex-shrink-0\"\n [style.background-color]=\"task.listColor\"\n ></span>\n {{ task.listName }}\n </span>\n </td>\n <td>\n <f-tag\n [value]=\"('task.priority.' + task.priority) | translate\"\n [severity]=\"prioritySeverity(task.priority)\"\n />\n </td>\n <td>\n @if (task.assignees?.length) {\n <div class=\"flex items-center -space-x-1.5\">\n @for (\n a of task.assignees!.slice(0, 3);\n track a.userId\n ) {\n <f-avatar\n shape=\"circle\"\n size=\"small\"\n [label]=\"getMemberInitials(a.userId)\"\n [color]=\"memberColorById(a.userId)\"\n styleClass=\"!ring-surface-card flex-shrink-0\"\n [fTooltip]=\"a.userName ?? ''\"\n />\n }\n @if (task.assignees!.length > 3) {\n <f-avatar\n shape=\"circle\"\n size=\"small\"\n [label]=\"'+' + (task.assignees!.length - 3)\"\n styleClass=\"!bg-surface-200 dark:!bg-surface-700 !text-surface-600 !ring-surface-card flex-shrink-0\"\n />\n }\n </div>\n } @else {\n <span class=\"text-muted-color text-sm\">—</span>\n }\n </td>\n <td>\n @if (task.dueDate) {\n <span\n class=\"text-sm\"\n [class.text-red-500]=\"isOverdue(task.dueDate)\"\n >\n {{ task.dueDate | date: 'MMM d, y' }}\n </span>\n } @else {\n <span class=\"text-muted-color text-sm\">—</span>\n }\n </td>\n <td>\n <div class=\"flex gap-1\">\n <button\n fButton\n [text]=\"true\"\n severity=\"secondary\"\n size=\"small\"\n [fTooltip]=\"'shared.edit' | translate\"\n (click)=\"onEditTask(task)\"\n >\n <ui-icon pButtonIcon name=\"pencil\"></ui-icon>\n </button>\n <button\n fButton\n [text]=\"true\"\n severity=\"danger\"\n size=\"small\"\n [fTooltip]=\"'shared.delete' | translate\"\n (click)=\"onDeleteTask(task)\"\n >\n <ui-icon pButtonIcon name=\"trash\"></ui-icon>\n </button>\n </div>\n </td>\n </tr>\n </ng-template>\n <ng-template #emptymessage>\n <tr>\n <td colspan=\"6\" class=\"text-center text-muted-color py-8\">\n <ui-icon\n name=\"inbox\"\n class=\"text-4xl block mb-3\"\n ></ui-icon>\n {{ 'task.manager.table.empty' | translate }}\n </td>\n </tr>\n </ng-template>\n </f-table>\n </div>\n </div>\n </div>\n }\n </div>\n\n <tm-task-form-dialog\n [(visible)]=\"showTaskForm\"\n [task]=\"editingTask()\"\n [boardId]=\"boardId()\"\n [listId]=\"activeListId()\"\n [members]=\"state.members()\"\n [labels]=\"state.labels()\"\n (saved)=\"onTaskSaved($event)\"\n />\n\n <tm-task-detail-panel\n [task]=\"state.selectedTask()\"\n (closePanel)=\"state.selectTask(null)\"\n (editTask)=\"onEditTask($event)\"\n />\n\n <f-dialog\n [header]=\"'task.manager.label.manage.title' | translate\"\n [(visible)]=\"showLabelsDialog\"\n [modal]=\"true\"\n [style]=\"{ width: '420px' }\"\n (onHide)=\"newLabelName = ''; newLabelColor = boardColorPalette[0]\"\n >\n <div class=\"flex flex-col gap-4 py-2\">\n <div class=\"flex gap-2 items-end\">\n <div class=\"flex flex-col gap-1 flex-1\">\n <label class=\"text-sm font-medium\">{{\n 'task.manager.label.name.label' | translate\n }}</label>\n <input\n fInputText\n [(ngModel)]=\"newLabelName\"\n [placeholder]=\"'task.manager.label.name.placeholder' | translate\"\n />\n </div>\n <div class=\"flex flex-col gap-1\">\n <label class=\"text-sm font-medium\">{{\n 'task.manager.label.color.label' | translate\n }}</label>\n <input\n type=\"color\"\n [(ngModel)]=\"newLabelColor\"\n class=\"w-10 h-10 rounded cursor-pointer border border-surface\"\n />\n </div>\n <button\n fButton\n size=\"small\"\n (click)=\"addLabel()\"\n [disabled]=\"isAddingLabel()\"\n >\n @if (isAddingLabel()) {\n <ui-icon pButtonIcon name=\"spinner\" [spin]=\"true\"></ui-icon>\n } @else {\n <ui-icon pButtonIcon name=\"plus\"></ui-icon>\n }\n <span pButtonLabel>{{ 'task.manager.label.add' | translate }}</span>\n </button>\n </div>\n\n <div class=\"flex flex-col gap-2 max-h-64 overflow-y-auto\">\n @if (state.labels().length === 0) {\n <p class=\"text-sm text-muted-color text-center py-4\">\n {{ 'task.manager.label.no.labels' | translate }}\n </p>\n }\n @for (label of state.labels(); track label.id) {\n <div\n class=\"flex items-center justify-between px-3 py-2 rounded-border border border-surface\"\n >\n <div class=\"flex items-center gap-2\">\n <span\n class=\"w-4 h-4 rounded-full flex-shrink-0\"\n [style.background-color]=\"label.color\"\n ></span>\n <span class=\"text-sm font-medium\">{{ label.name }}</span>\n </div>\n <button\n fButton\n severity=\"danger\"\n size=\"small\"\n [text]=\"true\"\n (click)=\"removeLabel(label.id)\"\n >\n <ui-icon pButtonIcon name=\"trash\"></ui-icon>\n </button>\n </div>\n }\n </div>\n </div>\n </f-dialog>\n\n <f-dialog\n [header]=\"'task.manager.member.manage.title' | translate\"\n [(visible)]=\"showMembersDialog\"\n [modal]=\"true\"\n [style]=\"{ width: '480px' }\"\n (onHide)=\"resetMemberForm()\"\n >\n <div class=\"flex flex-col gap-4 py-2\">\n <div class=\"flex flex-col gap-3\">\n <div class=\"flex flex-col gap-1\">\n <label class=\"text-sm font-medium\">{{\n 'task.manager.member.user.label' | translate\n }}</label>\n <lib-user-select\n [(value)]=\"selectedMemberUser\"\n [isEditMode]=\"true\"\n [placeHolder]=\"'task.manager.member.user.placeholder' | translate\"\n />\n </div>\n\n <div class=\"flex gap-2 items-end\">\n <div class=\"flex flex-col gap-1 flex-1\">\n <label class=\"text-sm font-medium\">{{\n 'task.manager.member.role.label' | translate\n }}</label>\n <f-select\n [(ngModel)]=\"newMemberRole\"\n [options]=\"memberRoleOptions\"\n optionValue=\"value\"\n [placeholder]=\"\n 'task.manager.member.role.placeholder' | translate\n \"\n class=\"w-full\"\n >\n <ng-template #selectedItem let-opt>\n {{ opt.labelKey | translate }}\n </ng-template>\n <ng-template #item let-opt>\n {{ opt.labelKey | translate }}\n </ng-template>\n </f-select>\n </div>\n <button\n fButton\n size=\"small\"\n [disabled]=\"!selectedMemberUser || isAddingMember()\"\n (click)=\"addMember()\"\n >\n @if (isAddingMember()) {\n <ui-icon pButtonIcon name=\"spinner\" [spin]=\"true\"></ui-icon>\n } @else {\n <ui-icon pButtonIcon name=\"plus\"></ui-icon>\n }\n <span pButtonLabel>{{\n 'task.manager.member.add' | translate\n }}</span>\n </button>\n </div>\n </div>\n\n <div class=\"flex flex-col gap-2 max-h-72 overflow-y-auto\">\n @if (state.members().length === 0) {\n <p class=\"text-sm text-muted-color text-center py-4\">\n {{ 'task.manager.member.no.members' | translate }}\n </p>\n }\n @for (member of state.members(); track member.id) {\n <div\n class=\"flex items-center justify-between px-3 py-2.5 rounded-border border border-surface\"\n >\n <div class=\"flex items-center gap-3\">\n <f-avatar\n shape=\"circle\"\n [label]=\"memberInitials(member)\"\n [color]=\"memberColor(member)\"\n styleClass=\"!text-[11px] flex-shrink-0\"\n />\n <div>\n <div class=\"text-sm font-medium \">\n {{ member.userName ?? member.userId }}\n </div>\n @if (member.userEmail) {\n <div class=\"text-xs text-muted-color\">\n {{ member.userEmail }}\n </div>\n }\n </div>\n </div>\n <div class=\"flex items-center gap-2\">\n <span\n class=\"text-[10px] font-semibold px-2 py-0.5 rounded-full\"\n [class]=\"roleBadgeClass(member.role)\"\n >\n {{\n 'task.manager.member.role.' + member.role.toLowerCase()\n | translate\n }}\n </span>\n @if (member.role !== 'OWNER') {\n <button\n fButton\n severity=\"danger\"\n size=\"small\"\n [text]=\"true\"\n (click)=\"removeMember(member.userId)\"\n >\n <ui-icon pButtonIcon name=\"trash\"></ui-icon>\n </button>\n }\n </div>\n </div>\n }\n </div>\n </div>\n </f-dialog>\n\n <f-dialog\n [header]=\"'task.manager.list.new' | translate\"\n [(visible)]=\"showAddListDialog\"\n [modal]=\"true\"\n [style]=\"{ width: '360px' }\"\n (onHide)=\"newListName = ''\"\n >\n <div class=\"flex flex-col gap-2 py-2\">\n <label class=\"text-sm font-medium\">\n {{ 'task.manager.list.name.label' | translate }}\n <span class=\"text-red-500\">*</span>\n </label>\n <input\n fInputText\n [(ngModel)]=\"newListName\"\n [placeholder]=\"'task.manager.list.name.placeholder' | translate\"\n />\n </div>\n <ng-template #footer>\n <div class=\"flex justify-end gap-2\">\n <button\n fButton\n severity=\"secondary\"\n (click)=\"showAddListDialog.set(false)\"\n >\n <span pButtonLabel>{{ 'shared.cancel' | translate }}</span>\n </button>\n <button fButton (click)=\"addList()\" [disabled]=\"isAddingList()\">\n @if (isAddingList()) {\n <ui-icon pButtonIcon name=\"spinner\" [spin]=\"true\"></ui-icon>\n }\n <span pButtonLabel>{{ 'shared.create' | translate }}</span>\n </button>\n </div>\n </ng-template>\n </f-dialog>\n\n <f-dialog\n [header]=\"'task.manager.board.edit' | translate\"\n [(visible)]=\"showEditBoardDialog\"\n [modal]=\"true\"\n [style]=\"{ width: '420px' }\"\n >\n <div class=\"flex flex-col gap-4 py-2\">\n <div class=\"flex flex-col gap-1\">\n <label class=\"text-sm font-medium\">\n {{ 'task.manager.board.name.label' | translate }}\n <span class=\"text-red-500\">*</span>\n </label>\n <input fInputText [(ngModel)]=\"editBoardName\" />\n </div>\n <div class=\"flex flex-col gap-1\">\n <label class=\"text-sm font-medium\">{{\n 'task.manager.board.description.label' | translate\n }}</label>\n <textarea\n fTextarea\n [(ngModel)]=\"editBoardDescription\"\n [rows]=\"3\"\n [placeholder]=\"\n 'task.manager.board.description.placeholder' | translate\n \"\n ></textarea>\n </div>\n <div class=\"flex flex-col gap-1\">\n <label class=\"text-sm font-medium\">{{\n 'task.manager.board.color.label' | translate\n }}</label>\n <div class=\"flex items-center gap-3\">\n <input\n type=\"color\"\n [(ngModel)]=\"editBoardColor\"\n class=\"w-10 h-10 rounded cursor-pointer border border-surface\"\n />\n <div class=\"flex gap-2 flex-wrap\">\n @for (color of boardColorPalette; track color) {\n <button\n type=\"button\"\n class=\"w-6 h-6 rounded-full border-2 transition-transform hover:scale-110\"\n [style.background-color]=\"color\"\n [class.border-surface-900]=\"editBoardColor === color\"\n [class.dark:border-surface-0]=\"editBoardColor === color\"\n [class.border-transparent]=\"editBoardColor !== color\"\n (click)=\"editBoardColor = color\"\n ></button>\n }\n </div>\n </div>\n </div>\n </div>\n <ng-template #footer>\n <div class=\"flex justify-end gap-2\">\n <button\n fButton\n severity=\"secondary\"\n (click)=\"showEditBoardDialog.set(false)\"\n >\n <span pButtonLabel>{{ 'shared.cancel' | translate }}</span>\n </button>\n <button\n fButton\n [disabled]=\"!editBoardName.trim() || isSavingBoard()\"\n (click)=\"saveBoard()\"\n >\n @if (isSavingBoard()) {\n <ui-icon pButtonIcon name=\"spinner\" [spin]=\"true\"></ui-icon>\n }\n <span pButtonLabel>{{ 'shared.save' | translate }}</span>\n </button>\n </div>\n </ng-template>\n </f-dialog>\n `,\n})\nexport class BoardViewPageComponent {\n protected readonly state = inject(TaskBoardStateService);\n private readonly listApi = inject(TaskListApiService);\n private readonly confirmationService = inject(ConfirmationService);\n private readonly messageService = inject(MessageService);\n private readonly translateAdapter = inject(TranslateService, {\n optional: true,\n });\n private readonly destroyRef = inject(DestroyRef);\n\n private translate(\n key: string,\n vars?: Record<string, string | number>,\n ): string {\n return this.translateAdapter?.translate(key, vars) ?? key;\n }\n\n readonly boardId = input.required<string>();\n\n readonly viewMode = signal<ViewMode>('board');\n readonly showTaskForm = signal(false);\n readonly editingTask = signal<ITask | null>(null);\n readonly activeListId = signal('');\n readonly showAddListDialog = signal(false);\n readonly isAddingList = signal(false);\n readonly showLabelsDialog = signal(false);\n readonly isAddingLabel = signal(false);\n readonly showMembersDialog = signal(false);\n readonly isAddingMember = signal(false);\n\n readonly editingListId = signal<string | null>(null);\n readonly editingListNameValue = signal('');\n readonly showEditBoardDialog = signal(false);\n readonly isSavingBoard = signal(false);\n\n newListName = '';\n newLabelName = '';\n newLabelColor = BOARD_COLOR_PALETTE[0];\n selectedMemberUser: string | null = null;\n newMemberRole = 'MEMBER';\n editBoardName = '';\n editBoardDescription = '';\n editBoardColor = BOARD_COLOR_PALETTE[0];\n\n readonly boardColorPalette = BOARD_COLOR_PALETTE;\n\n readonly memberRoleOptions = [\n { labelKey: 'task.manager.member.role.admin', value: 'ADMIN' },\n { labelKey: 'task.manager.member.role.member', value: 'MEMBER' },\n { labelKey: 'task.manager.member.role.viewer', value: 'VIEWER' },\n ];\n\n readonly allTasksFlat = computed<ITaskRow[]>(() =>\n this.state.listsWithTasks().flatMap((list) =>\n list.tasks.map((task) => ({\n ...task,\n listName: list.name,\n listColor: list.color,\n })),\n ),\n );\n\n readonly listDropIds = computed(() =>\n this.state.listsWithTasks().map((l) => l.id),\n );\n\n constructor() {\n effect(() => {\n const id = this.boardId();\n untracked(() => void this.state.openBoard(id).catch(() => undefined));\n });\n this.destroyRef.onDestroy(() => this.state.closeBoard());\n }\n\n openAddTask(list: ITaskList): void {\n this.editingTask.set(null);\n this.activeListId.set(list.id);\n this.showTaskForm.set(true);\n }\n\n onTaskSaved(task: ITask): void {\n this.state.addTaskOptimistic(task);\n }\n\n onDeleteTask(task: ITask): void {\n this.confirmationService.confirm({\n message: this.translate('shared.confirm.delete.item', {\n name: task.title,\n }),\n header: this.translate('task.detail.delete'),\n icon: 'exclamation-triangle',\n acceptButtonStyleClass: 'p-button-danger',\n accept: async () => {\n try {\n await this.state.deleteTask(task.id);\n this.messageService.add({\n severity: 'success',\n summary: this.translate('shared.success'),\n detail: this.translate('task.delete.success'),\n });\n } catch {}\n },\n });\n }\n\n onEditTask(task: ITask): void {\n this.editingTask.set(task);\n this.activeListId.set(task.listId);\n this.showTaskForm.set(true);\n this.state.selectTask(null);\n }\n\n getMemberName(assigneeId: string): string | null {\n return (\n this.state.members().find((m) => m.userId === assigneeId)?.userName ??\n null\n );\n }\n\n getMemberInitials(assigneeId: string): string {\n return memberInitials(this.getMemberName(assigneeId));\n }\n\n memberInitials(member: ITaskBoardMember): string {\n return memberInitials(member.userName);\n }\n\n memberColor(member: ITaskBoardMember): string {\n return memberColorFromId(member.userId);\n }\n\n memberColorById(userId: string): string {\n return memberColorFromId(userId);\n }\n\n roleBadgeClass(role: string): string {\n const map: Record<string, string> = {\n OWNER: 'text-primary-600 dark:text-primary-400 font-semibold',\n ADMIN: 'text-orange-600 dark:text-orange-400 font-semibold',\n MEMBER: 'text-surface-500 dark:text-surface-400',\n VIEWER: 'text-surface-400 dark:text-surface-500',\n };\n return map[role] ?? map['MEMBER'];\n }\n\n protected readonly prioritySeverity = taskPrioritySeverity;\n protected readonly isOverdue = isTaskOverdue;\n\n async onTaskDrop(event: CdkDragDrop<ITask[]>): Promise<void> {\n const sameList = event.previousContainer === event.container;\n if (sameList && event.previousIndex === event.currentIndex) return;\n const task = event.item?.data ?? event.previousContainer.data[event.previousIndex];\n if (!task) return;\n try {\n await this.state.moveTask(task.id, event.container.id, event.currentIndex);\n } catch {}\n }\n\n async onListDrop(event: CdkDragDrop<ITaskListWithTasks[]>): Promise<void> {\n if (event.previousIndex === event.currentIndex) return;\n const lists = this.state.listsWithTasks().slice();\n moveItemInArray(lists, event.previousIndex, event.currentIndex);\n const orderedIds = lists.map((l) => l.id);\n try {\n await this.state.reorderLists(this.boardId(), orderedIds);\n } catch {}\n }\n\n startRenameList(list: ITaskList): void {\n this.editingListId.set(list.id);\n this.editingListNameValue.set(list.name);\n }\n\n cancelRenameList(): void {\n this.editingListId.set(null);\n this.editingListNameValue.set('');\n }\n\n async saveRenameList(): Promise<void> {\n const id = this.editingListId();\n const name = this.editingListNameValue().trim();\n this.cancelRenameList();\n if (!id || !name) return;\n await this.state.renameList(id, name);\n this.messageService.add({\n severity: 'success',\n summary: this.translate('shared.success'),\n detail: this.translate('task.list.update.success'),\n });\n }\n\n openEditBoardDialog(board: ITaskBoard): void {\n this.editBoardName = board.name;\n this.editBoardDescription = board.description ?? '';\n this.editBoardColor = board.color;\n this.showEditBoardDialog.set(true);\n }\n\n async saveBoard(): Promise<void> {\n const board = this.state.activeBoard();\n if (!board || !this.editBoardName.trim()) return;\n this.isSavingBoard.set(true);\n try {\n await this.state.updateBoard({\n id: board.id,\n name: this.editBoardName.trim(),\n description: this.editBoardDescription.trim() || undefined,\n color: this.editBoardColor,\n });\n this.showEditBoardDialog.set(false);\n this.messageService.add({\n severity: 'success',\n summary: this.translate('shared.success'),\n detail: this.translate('task.board.update.success'),\n });\n } finally {\n this.isSavingBoard.set(false);\n }\n }\n\n async addLabel(): Promise<void> {\n if (!this.newLabelName.trim()) return;\n this.isAddingLabel.set(true);\n try {\n await this.state.addLabel(\n this.boardId(),\n this.newLabelName.trim(),\n this.newLabelColor,\n );\n this.newLabelName = '';\n this.newLabelColor = BOARD_COLOR_PALETTE[0];\n } finally {\n this.isAddingLabel.set(false);\n }\n }\n\n async removeLabel(labelId: string): Promise<void> {\n await this.state.deleteLabel(labelId);\n }\n\n async addMember(): Promise<void> {\n if (!this.selectedMemberUser) return;\n this.isAddingMember.set(true);\n try {\n await this.state.addMember(this.selectedMemberUser, this.newMemberRole);\n this.resetMemberForm();\n } finally {\n this.isAddingMember.set(false);\n }\n }\n\n resetMemberForm(): void {\n this.selectedMemberUser = null;\n this.newMemberRole = 'MEMBER';\n }\n\n async removeMember(userId: string): Promise<void> {\n await this.state.removeMember(userId);\n }\n\n async addList(): Promise<void> {\n if (!this.newListName.trim()) return;\n this.isAddingList.set(true);\n try {\n const position = this.state.lists().length * 100;\n await this.listApi.insert({\n boardId: this.boardId(),\n name: this.newListName.trim(),\n position,\n });\n await this.state.openBoard(this.boardId());\n this.showAddListDialog.set(false);\n this.newListName = '';\n } finally {\n this.isAddingList.set(false);\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"flusys-ng-task-manager-board-view-page.component-CR5kmFau.mjs","names":[],"sources":["../../../projects/ng-task-manager/pages/board-view-page/board-view-page.component.ts"],"sourcesContent":["import {\n CdkDragDrop,\n DragDropModule,\n moveItemInArray,\n} from '@angular/cdk/drag-drop';\nimport {\n Component,\n computed,\n DestroyRef,\n effect,\n inject,\n input,\n signal,\n untracked,\n} from '@angular/core';\nimport { DatePipe } from '@angular/common';\nimport { FormsModule } from '@angular/forms';\nimport {\n TranslatePipe,\n TranslateService,\n UserSelectComponent,\n} from '@flusys/ng-shared';\nimport {\n AvatarComponent,\n ConfirmationService,\n DialogComponent,\n FButtonDirective,\n InputTextDirective,\n MessageService,\n SelectComponent,\n SkeletonComponent,\n SortableColumnDirective,\n SortIconComponent,\n TableComponent,\n TagComponent,\n TextareaDirective,\n TooltipDirective,\n UiIconComponent,\n} from '@flusys/ng-ui';\nimport { TaskCardComponent } from '../../components/task-card/task-card.component';\nimport { TaskDetailPanelComponent } from '../../components/task-detail-panel/task-detail-panel.component';\nimport { TaskFormDialogComponent } from '../../components/task-form-dialog/task-form-dialog.component';\nimport {\n ITask,\n ITaskBoard,\n ITaskBoardMember,\n ITaskList,\n} from '../../interfaces/task.interface';\nimport { TaskListApiService } from '../../services/task-api.service';\nimport { TaskBoardStateService } from '../../services/task-board-state.service';\nimport {\n BOARD_COLOR_PALETTE,\n isTaskOverdue,\n memberColorFromId,\n memberInitials,\n taskPrioritySeverity,\n} from '../../utils/task-utils';\n\ntype ViewMode = 'board' | 'list';\ntype ITaskListWithTasks = ITaskList & { tasks: ITask[] };\n\ninterface ITaskRow extends ITask {\n listName: string;\n listColor: string;\n}\n\n@Component({\n selector: 'tm-board-view-page',\n imports: [\n AvatarComponent,\n DialogComponent,\n FButtonDirective,\n InputTextDirective,\n SelectComponent,\n SkeletonComponent,\n SortableColumnDirective,\n SortIconComponent,\n TableComponent,\n TagComponent,\n TextareaDirective,\n TooltipDirective,\n UiIconComponent,\n DragDropModule,\n DatePipe,\n FormsModule,\n TaskCardComponent,\n TaskFormDialogComponent,\n TaskDetailPanelComponent,\n TranslatePipe,\n UserSelectComponent,\n ],\n template: `\n <div class=\"flex flex-col h-full\">\n <div class=\"flex flex-col\">\n <div class=\"flex items-center justify-between px-5 py-2.5 gap-4\">\n @if (state.activeBoard(); as board) {\n <div class=\"flex items-center gap-2.5 min-w-0 flex-1 group\">\n <div class=\"flex flex-col min-w-0\">\n <div class=\"flex items-center gap-1.5 min-w-0\">\n <h1\n class=\"text-base font-bold text-surface-900 dark:text-surface-0 truncate leading-snug\"\n >\n {{ board.name }}\n </h1>\n <button\n fButton\n [text]=\"true\"\n size=\"small\"\n severity=\"secondary\"\n class=\"!w-6 !h-6 flex-shrink-0 opacity-0 group-hover:opacity-100 transition-opacity\"\n [fTooltip]=\"'task.manager.board.edit' | translate\"\n tooltipPosition=\"bottom\"\n (click)=\"openEditBoardDialog(board)\"\n >\n <ui-icon pButtonIcon name=\"pencil\"></ui-icon>\n </button>\n </div>\n @if (board.description) {\n <span\n class=\"text-xs text-muted-color truncate max-w-sm hidden md:block leading-snug\"\n >\n {{ board.description }}\n </span>\n }\n </div>\n </div>\n }\n\n <div class=\"flex items-center gap-1.5 flex-shrink-0\">\n @if (state.members().length > 0) {\n <div\n class=\"flex items-center -space-x-2 cursor-pointer mr-1\"\n (click)=\"showMembersDialog.set(true)\"\n [fTooltip]=\"'task.manager.board.manage.members' | translate\"\n tooltipPosition=\"bottom\"\n >\n @for (member of state.members().slice(0, 4); track member.id) {\n <f-avatar\n shape=\"circle\"\n size=\"small\"\n [label]=\"memberInitials(member)\"\n [color]=\"memberColor(member)\"\n styleClass=\"!border-2 !border-surface-card ring-1 ring-surface flex-shrink-0\"\n />\n }\n @if (state.members().length > 4) {\n <f-avatar\n shape=\"circle\"\n size=\"small\"\n [label]=\"'+' + (state.members().length - 4)\"\n styleClass=\"!border-2 !border-surface-card !bg-surface-200 dark:!bg-surface-700 !text-surface-600 dark:!text-surface-300 flex-shrink-0\"\n />\n }\n </div>\n }\n\n <div\n class=\"h-5 w-px bg-surface-300 dark:bg-surface-600 mx-0.5\"\n ></div>\n\n <div\n class=\"flex rounded-border overflow-hidden border border-surface\"\n >\n <button\n fButton\n [fTooltip]=\"'task.manager.view.board' | translate\"\n tooltipPosition=\"bottom\"\n size=\"small\"\n [severity]=\"viewMode() === 'board' ? 'primary' : 'secondary'\"\n [outlined]=\"viewMode() !== 'board'\"\n class=\"!rounded-none !border-0\"\n (click)=\"viewMode.set('board')\"\n >\n <ui-icon pButtonIcon name=\"th-large\"></ui-icon>\n </button>\n <button\n fButton\n [fTooltip]=\"'task.manager.view.list' | translate\"\n tooltipPosition=\"bottom\"\n size=\"small\"\n [severity]=\"viewMode() === 'list' ? 'primary' : 'secondary'\"\n [outlined]=\"viewMode() !== 'list'\"\n class=\"!rounded-none !border-0\"\n (click)=\"viewMode.set('list')\"\n >\n <ui-icon pButtonIcon name=\"list\"></ui-icon>\n </button>\n </div>\n\n <div\n class=\"h-5 w-px bg-surface-300 dark:bg-surface-600 mx-0.5\"\n ></div>\n\n <button\n fButton\n [text]=\"true\"\n severity=\"secondary\"\n size=\"small\"\n class=\"!w-8 !h-8\"\n [fTooltip]=\"'task.manager.board.manage.members' | translate\"\n tooltipPosition=\"bottom\"\n (click)=\"showMembersDialog.set(true)\"\n >\n <ui-icon pButtonIcon name=\"users\"></ui-icon>\n </button>\n <button\n fButton\n [text]=\"true\"\n severity=\"secondary\"\n size=\"small\"\n class=\"!w-8 !h-8\"\n [fTooltip]=\"'task.manager.board.manage.labels' | translate\"\n tooltipPosition=\"bottom\"\n (click)=\"showLabelsDialog.set(true)\"\n >\n <ui-icon pButtonIcon name=\"tag\"></ui-icon>\n </button>\n\n @if (viewMode() === 'board') {\n <div\n class=\"h-5 w-px bg-surface-300 dark:bg-surface-600 mx-0.5\"\n ></div>\n <button\n fButton\n size=\"small\"\n (click)=\"showAddListDialog.set(true)\"\n >\n <ui-icon pButtonIcon name=\"plus\"></ui-icon>\n <span pButtonLabel>{{\n 'task.manager.board.add.list' | translate\n }}</span>\n </button>\n }\n </div>\n </div>\n\n @if (state.activeBoard(); as board) {\n <div\n class=\"h-0.5 w-full flex-shrink-0\"\n [style.background-color]=\"board.color\"\n ></div>\n }\n </div>\n\n @if (state.isBoardLoading()) {\n @if (viewMode() === 'board') {\n <div class=\"flex gap-4 p-6 overflow-x-auto\">\n @for (i of [1, 2, 3]; track i) {\n <div class=\"flex-shrink-0 w-72\">\n <f-skeleton height=\"36px\" class=\"mb-3\" />\n @for (j of [1, 2, 3]; track j) {\n <f-skeleton height=\"90px\" class=\"mb-2\" />\n }\n </div>\n }\n </div>\n } @else {\n <div class=\"p-6\">\n @for (i of [1, 2, 3, 4, 5]; track i) {\n <f-skeleton height=\"48px\" class=\"mb-2\" />\n }\n </div>\n }\n } @else if (viewMode() === 'board') {\n <div\n class=\"flex gap-4 p-5 overflow-x-auto flex-1\"\n cdkDropList\n cdkDropListOrientation=\"horizontal\"\n [cdkDropListData]=\"state.listsWithTasks()\"\n (cdkDropListDropped)=\"onListDrop($event)\"\n >\n @for (list of state.listsWithTasks(); track list.id) {\n <div\n cdkDrag\n class=\"flex-shrink-0 w-72 flex flex-col max-h-[calc(100vh-140px)] self-start rounded-border border border-surface shadow-sm overflow-hidden\"\n >\n <div\n class=\"flex items-center gap-1 px-2.5 py-2.5 border-b border-surface\"\n >\n <ui-icon\n cdkDragHandle\n name=\"bars\"\n class=\"text-muted-color text-xs cursor-grab flex-shrink-0 px-1\"\n ></ui-icon>\n\n <div class=\"flex items-center gap-2 min-w-0 flex-1\">\n @if (editingListId() === list.id) {\n <input\n fInputText\n class=\"text-sm font-semibold !h-6 !py-0 !px-1 w-full\"\n [ngModel]=\"editingListNameValue()\"\n (ngModelChange)=\"editingListNameValue.set($event)\"\n (keydown.enter)=\"saveRenameList()\"\n (keydown.escape)=\"cancelRenameList()\"\n (blur)=\"cancelRenameList()\"\n (click)=\"$event.stopPropagation()\"\n autofocus\n />\n } @else {\n <span class=\"font-semibold text-sm truncate\">{{\n list.name\n }}</span>\n <span\n class=\"text-[11px] font-semibold px-1.5 py-0.5 rounded-full text-white flex-shrink-0\"\n [style.background-color]=\"list.color\"\n >\n {{ list.tasks.length }}\n </span>\n }\n </div>\n\n @if (editingListId() === list.id) {\n <button\n fButton\n [text]=\"true\"\n size=\"small\"\n severity=\"success\"\n class=\"!w-6 !h-6 flex-shrink-0\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"saveRenameList(); $event.stopPropagation()\"\n >\n <ui-icon pButtonIcon name=\"check\"></ui-icon>\n </button>\n <button\n fButton\n [text]=\"true\"\n size=\"small\"\n severity=\"secondary\"\n class=\"!w-6 !h-6 flex-shrink-0\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"cancelRenameList(); $event.stopPropagation()\"\n >\n <ui-icon pButtonIcon name=\"times\"></ui-icon>\n </button>\n } @else {\n <button\n fButton\n [text]=\"true\"\n size=\"small\"\n severity=\"secondary\"\n class=\"!w-6 !h-6 flex-shrink-0\"\n [fTooltip]=\"'task.manager.list.rename' | translate\"\n tooltipPosition=\"bottom\"\n (click)=\"startRenameList(list); $event.stopPropagation()\"\n >\n <ui-icon pButtonIcon name=\"pencil\"></ui-icon>\n </button>\n }\n </div>\n\n <div\n cdkDropList\n [id]=\"list.id\"\n [cdkDropListData]=\"list.tasks\"\n [cdkDropListConnectedTo]=\"listDropIds()\"\n (cdkDropListDropped)=\"onTaskDrop($event)\"\n class=\"flex flex-col gap-2 p-2 overflow-y-auto flex-1 min-h-[60px]\"\n >\n @for (task of list.tasks; track task.id) {\n <div cdkDrag [cdkDragData]=\"task\">\n <tm-task-card\n [task]=\"task\"\n (cardClick)=\"state.selectTask($event)\"\n (editClick)=\"onEditTask($event)\"\n (deleteClick)=\"onDeleteTask($event)\"\n />\n </div>\n }\n @if (list.tasks.length === 0) {\n <div\n class=\"flex items-center justify-center h-14 border-2 border-dashed border-surface rounded-border\"\n >\n <span class=\"text-xs text-muted-color\">{{\n 'task.manager.board.drop.tasks.here' | translate\n }}</span>\n </div>\n }\n </div>\n\n <div class=\"border-t border-surface p-1.5\">\n <button\n fButton\n severity=\"secondary\"\n [text]=\"true\"\n size=\"small\"\n class=\"w-full !justify-start\"\n (click)=\"openAddTask(list)\"\n >\n <ui-icon pButtonIcon name=\"plus\"></ui-icon>\n <span pButtonLabel>{{\n 'task.manager.board.add.task' | translate\n }}</span>\n </button>\n </div>\n </div>\n }\n\n @if (state.listsWithTasks().length === 0) {\n <div class=\"flex-1 flex items-center justify-center\">\n <div class=\"text-center text-muted-color\">\n <div\n class=\"w-16 h-16 rounded-2xl border-2 border-dashed border-surface flex items-center justify-center mx-auto mb-4\"\n >\n <ui-icon\n name=\"list\"\n class=\"text-3xl text-muted-color\"\n ></ui-icon>\n </div>\n <p class=\"font-medium text-muted-color\">\n {{ 'task.manager.board.list.empty' | translate }}\n </p>\n <button\n fButton\n severity=\"secondary\"\n size=\"small\"\n class=\"mt-3\"\n (click)=\"showAddListDialog.set(true)\"\n >\n <ui-icon pButtonIcon name=\"plus\"></ui-icon>\n <span pButtonLabel>{{\n 'task.manager.board.add.list' | translate\n }}</span>\n </button>\n </div>\n </div>\n }\n </div>\n } @else {\n <div class=\"p-4 sm:p-6 flex-1 overflow-auto\">\n <div class=\"card\">\n <div class=\"overflow-x-auto -mx-4 sm:mx-0\">\n <f-table\n [value]=\"allTasksFlat()\"\n [paginator]=\"allTasksFlat().length > 20\"\n [rows]=\"20\"\n [rowsPerPageOptions]=\"[10, 20, 50]\"\n [scrollable]=\"true\"\n [tableStyle]=\"{ 'min-width': '700px' }\"\n >\n <ng-template #header>\n <tr>\n <th fSortableColumn=\"title\" class=\"min-w-[240px]\">\n {{ 'task.manager.table.title' | translate }}\n <f-sorticon field=\"title\" />\n </th>\n <th fSortableColumn=\"listName\" class=\"w-40\">\n {{ 'task.manager.table.list' | translate }}\n <f-sorticon field=\"listName\" />\n </th>\n <th fSortableColumn=\"priority\" class=\"w-32\">\n {{ 'task.manager.table.priority' | translate }}\n <f-sorticon field=\"priority\" />\n </th>\n <th class=\"w-36\">\n {{ 'task.manager.table.assignee' | translate }}\n </th>\n <th fSortableColumn=\"dueDate\" class=\"w-32\">\n {{ 'task.manager.table.due.date' | translate }}\n <f-sorticon field=\"dueDate\" />\n </th>\n <th class=\"w-[100px]\">\n {{ 'shared.actions' | translate }}\n </th>\n </tr>\n </ng-template>\n <ng-template #body let-task>\n <tr>\n <td>\n <span\n class=\"font-medium text-sm cursor-pointer hover:text-primary-500 transition-colors\"\n (click)=\"state.selectTask(task)\"\n >{{ task.title }}</span\n >\n </td>\n <td>\n <span class=\"inline-flex items-center gap-1.5 text-sm\">\n <span\n class=\"w-2 h-2 rounded-full flex-shrink-0\"\n [style.background-color]=\"task.listColor\"\n ></span>\n {{ task.listName }}\n </span>\n </td>\n <td>\n <f-tag\n [value]=\"('task.priority.' + task.priority) | translate\"\n [severity]=\"prioritySeverity(task.priority)\"\n />\n </td>\n <td>\n @if (task.assignees?.length) {\n <div class=\"flex items-center -space-x-1.5\">\n @for (\n a of task.assignees!.slice(0, 3);\n track a.userId\n ) {\n <f-avatar\n shape=\"circle\"\n size=\"small\"\n [label]=\"getMemberInitials(a.userId)\"\n [color]=\"memberColorById(a.userId)\"\n styleClass=\"!ring-surface-card flex-shrink-0\"\n [fTooltip]=\"a.userName ?? ''\"\n />\n }\n @if (task.assignees!.length > 3) {\n <f-avatar\n shape=\"circle\"\n size=\"small\"\n [label]=\"'+' + (task.assignees!.length - 3)\"\n styleClass=\"!bg-surface-200 dark:!bg-surface-700 !text-surface-600 !ring-surface-card flex-shrink-0\"\n />\n }\n </div>\n } @else {\n <span class=\"text-muted-color text-sm\">—</span>\n }\n </td>\n <td>\n @if (task.dueDate) {\n <span\n class=\"text-sm\"\n [class.text-red-500]=\"isOverdue(task.dueDate)\"\n >\n {{ task.dueDate | date: 'MMM d, y' }}\n </span>\n } @else {\n <span class=\"text-muted-color text-sm\">—</span>\n }\n </td>\n <td>\n <div class=\"flex gap-1\">\n <button\n fButton\n [text]=\"true\"\n severity=\"secondary\"\n size=\"small\"\n [fTooltip]=\"'shared.edit' | translate\"\n (click)=\"onEditTask(task)\"\n >\n <ui-icon pButtonIcon name=\"pencil\"></ui-icon>\n </button>\n <button\n fButton\n [text]=\"true\"\n severity=\"danger\"\n size=\"small\"\n [fTooltip]=\"'shared.delete' | translate\"\n (click)=\"onDeleteTask(task)\"\n >\n <ui-icon pButtonIcon name=\"trash\"></ui-icon>\n </button>\n </div>\n </td>\n </tr>\n </ng-template>\n <ng-template #emptymessage>\n <tr>\n <td colspan=\"6\" class=\"text-center text-muted-color py-8\">\n <ui-icon\n name=\"inbox\"\n class=\"text-4xl block mb-3\"\n ></ui-icon>\n {{ 'task.manager.table.empty' | translate }}\n </td>\n </tr>\n </ng-template>\n </f-table>\n </div>\n </div>\n </div>\n }\n </div>\n\n <tm-task-form-dialog\n [(visible)]=\"showTaskForm\"\n [task]=\"editingTask()\"\n [boardId]=\"boardId()\"\n [listId]=\"activeListId()\"\n [members]=\"state.members()\"\n [labels]=\"state.labels()\"\n (saved)=\"onTaskSaved($event)\"\n />\n\n <tm-task-detail-panel\n [task]=\"state.selectedTask()\"\n (closePanel)=\"state.selectTask(null)\"\n (editTask)=\"onEditTask($event)\"\n />\n\n <f-dialog\n [header]=\"'task.manager.label.manage.title' | translate\"\n [(visible)]=\"showLabelsDialog\"\n [modal]=\"true\"\n [style]=\"{ width: '420px' }\"\n (onHide)=\"newLabelName = ''; newLabelColor = boardColorPalette[0]\"\n >\n <div class=\"flex flex-col gap-4 py-2\">\n <div class=\"flex gap-2 items-end\">\n <div class=\"flex flex-col gap-1 flex-1\">\n <label class=\"text-sm font-medium\">{{\n 'task.manager.label.name.label' | translate\n }}</label>\n <input\n fInputText\n [(ngModel)]=\"newLabelName\"\n [placeholder]=\"'task.manager.label.name.placeholder' | translate\"\n />\n </div>\n <div class=\"flex flex-col gap-1\">\n <label class=\"text-sm font-medium\">{{\n 'task.manager.label.color.label' | translate\n }}</label>\n <input\n type=\"color\"\n [(ngModel)]=\"newLabelColor\"\n class=\"w-10 h-10 rounded cursor-pointer border border-surface\"\n />\n </div>\n <button\n fButton\n size=\"small\"\n (click)=\"addLabel()\"\n [disabled]=\"isAddingLabel()\"\n >\n @if (isAddingLabel()) {\n <ui-icon pButtonIcon name=\"spinner\" [spin]=\"true\"></ui-icon>\n } @else {\n <ui-icon pButtonIcon name=\"plus\"></ui-icon>\n }\n <span pButtonLabel>{{ 'task.manager.label.add' | translate }}</span>\n </button>\n </div>\n\n <div class=\"flex flex-col gap-2 max-h-64 overflow-y-auto\">\n @if (state.labels().length === 0) {\n <p class=\"text-sm text-muted-color text-center py-4\">\n {{ 'task.manager.label.no.labels' | translate }}\n </p>\n }\n @for (label of state.labels(); track label.id) {\n <div\n class=\"flex items-center justify-between px-3 py-2 rounded-border border border-surface\"\n >\n <div class=\"flex items-center gap-2\">\n <span\n class=\"w-4 h-4 rounded-full flex-shrink-0\"\n [style.background-color]=\"label.color\"\n ></span>\n <span class=\"text-sm font-medium\">{{ label.name }}</span>\n </div>\n <button\n fButton\n severity=\"danger\"\n size=\"small\"\n [text]=\"true\"\n (click)=\"removeLabel(label.id)\"\n >\n <ui-icon pButtonIcon name=\"trash\"></ui-icon>\n </button>\n </div>\n }\n </div>\n </div>\n </f-dialog>\n\n <f-dialog\n [header]=\"'task.manager.member.manage.title' | translate\"\n [(visible)]=\"showMembersDialog\"\n [modal]=\"true\"\n [style]=\"{ width: '480px' }\"\n (onHide)=\"resetMemberForm()\"\n >\n <div class=\"flex flex-col gap-4 py-2\">\n <div class=\"flex flex-col gap-3\">\n <div class=\"flex flex-col gap-1\">\n <label class=\"text-sm font-medium\">{{\n 'task.manager.member.user.label' | translate\n }}</label>\n <lib-user-select\n [(value)]=\"selectedMemberUser\"\n [isEditMode]=\"true\"\n [placeHolder]=\"'task.manager.member.user.placeholder' | translate\"\n />\n </div>\n\n <div class=\"flex gap-2 items-end\">\n <div class=\"flex flex-col gap-1 flex-1\">\n <label class=\"text-sm font-medium\">{{\n 'task.manager.member.role.label' | translate\n }}</label>\n <f-select\n [(ngModel)]=\"newMemberRole\"\n [options]=\"memberRoleOptions\"\n optionValue=\"value\"\n [placeholder]=\"\n 'task.manager.member.role.placeholder' | translate\n \"\n class=\"w-full\"\n >\n <ng-template #selectedItem let-opt>\n {{ opt.labelKey | translate }}\n </ng-template>\n <ng-template #item let-opt>\n {{ opt.labelKey | translate }}\n </ng-template>\n </f-select>\n </div>\n <button\n fButton\n size=\"small\"\n [disabled]=\"!selectedMemberUser || isAddingMember()\"\n (click)=\"addMember()\"\n >\n @if (isAddingMember()) {\n <ui-icon pButtonIcon name=\"spinner\" [spin]=\"true\"></ui-icon>\n } @else {\n <ui-icon pButtonIcon name=\"plus\"></ui-icon>\n }\n <span pButtonLabel>{{\n 'task.manager.member.add' | translate\n }}</span>\n </button>\n </div>\n </div>\n\n <div class=\"flex flex-col gap-2 max-h-72 overflow-y-auto\">\n @if (state.members().length === 0) {\n <p class=\"text-sm text-muted-color text-center py-4\">\n {{ 'task.manager.member.no.members' | translate }}\n </p>\n }\n @for (member of state.members(); track member.id) {\n <div\n class=\"flex items-center justify-between px-3 py-2.5 rounded-border border border-surface\"\n >\n <div class=\"flex items-center gap-3\">\n <f-avatar\n shape=\"circle\"\n [label]=\"memberInitials(member)\"\n [color]=\"memberColor(member)\"\n styleClass=\"!text-[11px] flex-shrink-0\"\n />\n <div>\n <div class=\"text-sm font-medium \">\n {{ member.userName ?? member.userId }}\n </div>\n @if (member.userEmail) {\n <div class=\"text-xs text-muted-color\">\n {{ member.userEmail }}\n </div>\n }\n </div>\n </div>\n <div class=\"flex items-center gap-2\">\n <span\n class=\"text-[10px] font-semibold px-2 py-0.5 rounded-full\"\n [class]=\"roleBadgeClass(member.role)\"\n >\n {{\n 'task.manager.member.role.' + member.role.toLowerCase()\n | translate\n }}\n </span>\n @if (member.role !== 'OWNER') {\n <button\n fButton\n severity=\"danger\"\n size=\"small\"\n [text]=\"true\"\n (click)=\"removeMember(member.userId)\"\n >\n <ui-icon pButtonIcon name=\"trash\"></ui-icon>\n </button>\n }\n </div>\n </div>\n }\n </div>\n </div>\n </f-dialog>\n\n <f-dialog\n [header]=\"'task.manager.list.new' | translate\"\n [(visible)]=\"showAddListDialog\"\n [modal]=\"true\"\n [style]=\"{ width: '360px' }\"\n (onHide)=\"newListName = ''\"\n >\n <div class=\"flex flex-col gap-2 py-2\">\n <label class=\"text-sm font-medium\">\n {{ 'task.manager.list.name.label' | translate }}\n <span class=\"text-red-500\">*</span>\n </label>\n <input\n fInputText\n [(ngModel)]=\"newListName\"\n [placeholder]=\"'task.manager.list.name.placeholder' | translate\"\n />\n </div>\n <ng-template #footer>\n <div class=\"flex justify-end gap-2\">\n <button\n fButton\n severity=\"secondary\"\n (click)=\"showAddListDialog.set(false)\"\n >\n <span pButtonLabel>{{ 'shared.cancel' | translate }}</span>\n </button>\n <button fButton (click)=\"addList()\" [disabled]=\"isAddingList()\">\n @if (isAddingList()) {\n <ui-icon pButtonIcon name=\"spinner\" [spin]=\"true\"></ui-icon>\n }\n <span pButtonLabel>{{ 'shared.create' | translate }}</span>\n </button>\n </div>\n </ng-template>\n </f-dialog>\n\n <f-dialog\n [header]=\"'task.manager.board.edit' | translate\"\n [(visible)]=\"showEditBoardDialog\"\n [modal]=\"true\"\n [style]=\"{ width: '420px' }\"\n >\n <div class=\"flex flex-col gap-4 py-2\">\n <div class=\"flex flex-col gap-1\">\n <label class=\"text-sm font-medium\">\n {{ 'task.manager.board.name.label' | translate }}\n <span class=\"text-red-500\">*</span>\n </label>\n <input fInputText [(ngModel)]=\"editBoardName\" />\n </div>\n <div class=\"flex flex-col gap-1\">\n <label class=\"text-sm font-medium\">{{\n 'task.manager.board.description.label' | translate\n }}</label>\n <textarea\n fTextarea\n [(ngModel)]=\"editBoardDescription\"\n [rows]=\"3\"\n [placeholder]=\"\n 'task.manager.board.description.placeholder' | translate\n \"\n ></textarea>\n </div>\n <div class=\"flex flex-col gap-1\">\n <label class=\"text-sm font-medium\">{{\n 'task.manager.board.color.label' | translate\n }}</label>\n <div class=\"flex items-center gap-3\">\n <input\n type=\"color\"\n [(ngModel)]=\"editBoardColor\"\n class=\"w-10 h-10 rounded cursor-pointer border border-surface\"\n />\n <div class=\"flex gap-2 flex-wrap\">\n @for (color of boardColorPalette; track color) {\n <button\n type=\"button\"\n class=\"w-6 h-6 rounded-full border-2 transition-transform hover:scale-110\"\n [style.background-color]=\"color\"\n [class.border-surface-900]=\"editBoardColor === color\"\n [class.dark:border-surface-0]=\"editBoardColor === color\"\n [class.border-transparent]=\"editBoardColor !== color\"\n (click)=\"editBoardColor = color\"\n ></button>\n }\n </div>\n </div>\n </div>\n </div>\n <ng-template #footer>\n <div class=\"flex justify-end gap-2\">\n <button\n fButton\n severity=\"secondary\"\n (click)=\"showEditBoardDialog.set(false)\"\n >\n <span pButtonLabel>{{ 'shared.cancel' | translate }}</span>\n </button>\n <button\n fButton\n [disabled]=\"!editBoardName.trim() || isSavingBoard()\"\n (click)=\"saveBoard()\"\n >\n @if (isSavingBoard()) {\n <ui-icon pButtonIcon name=\"spinner\" [spin]=\"true\"></ui-icon>\n }\n <span pButtonLabel>{{ 'shared.save' | translate }}</span>\n </button>\n </div>\n </ng-template>\n </f-dialog>\n `,\n})\nexport class BoardViewPageComponent {\n protected readonly state = inject(TaskBoardStateService);\n private readonly listApi = inject(TaskListApiService);\n private readonly confirmationService = inject(ConfirmationService);\n private readonly messageService = inject(MessageService);\n private readonly translateAdapter = inject(TranslateService, {\n optional: true,\n });\n private readonly destroyRef = inject(DestroyRef);\n\n private translate(\n key: string,\n vars?: Record<string, string | number>,\n ): string {\n return this.translateAdapter?.translate(key, vars) ?? key;\n }\n\n readonly boardId = input.required<string>();\n\n readonly viewMode = signal<ViewMode>('board');\n readonly showTaskForm = signal(false);\n readonly editingTask = signal<ITask | null>(null);\n readonly activeListId = signal('');\n readonly showAddListDialog = signal(false);\n readonly isAddingList = signal(false);\n readonly showLabelsDialog = signal(false);\n readonly isAddingLabel = signal(false);\n readonly showMembersDialog = signal(false);\n readonly isAddingMember = signal(false);\n\n readonly editingListId = signal<string | null>(null);\n readonly editingListNameValue = signal('');\n readonly showEditBoardDialog = signal(false);\n readonly isSavingBoard = signal(false);\n\n newListName = '';\n newLabelName = '';\n newLabelColor = BOARD_COLOR_PALETTE[0];\n selectedMemberUser: string | null = null;\n newMemberRole = 'MEMBER';\n editBoardName = '';\n editBoardDescription = '';\n editBoardColor = BOARD_COLOR_PALETTE[0];\n\n readonly boardColorPalette = BOARD_COLOR_PALETTE;\n\n readonly memberRoleOptions = [\n { labelKey: 'task.manager.member.role.admin', value: 'ADMIN' },\n { labelKey: 'task.manager.member.role.member', value: 'MEMBER' },\n { labelKey: 'task.manager.member.role.viewer', value: 'VIEWER' },\n ];\n\n readonly allTasksFlat = computed<ITaskRow[]>(() =>\n this.state.listsWithTasks().flatMap((list) =>\n list.tasks.map((task) => ({\n ...task,\n listName: list.name,\n listColor: list.color,\n })),\n ),\n );\n\n readonly listDropIds = computed(() =>\n this.state.listsWithTasks().map((l) => l.id),\n );\n\n constructor() {\n effect(() => {\n const id = this.boardId();\n untracked(() => void this.state.openBoard(id).catch(() => undefined));\n });\n this.destroyRef.onDestroy(() => this.state.closeBoard());\n }\n\n openAddTask(list: ITaskList): void {\n this.editingTask.set(null);\n this.activeListId.set(list.id);\n this.showTaskForm.set(true);\n }\n\n onTaskSaved(task: ITask): void {\n this.state.addTaskOptimistic(task);\n }\n\n onDeleteTask(task: ITask): void {\n this.confirmationService.confirm({\n message: this.translate('shared.confirm.delete.item', {\n name: task.title,\n }),\n header: this.translate('task.detail.delete'),\n icon: 'exclamation-triangle',\n acceptButtonStyleClass: 'p-button-danger',\n accept: async () => {\n try {\n await this.state.deleteTask(task.id);\n this.messageService.add({\n severity: 'success',\n summary: this.translate('shared.success'),\n detail: this.translate('task.delete.success'),\n });\n } catch {}\n },\n });\n }\n\n onEditTask(task: ITask): void {\n this.editingTask.set(task);\n this.activeListId.set(task.listId);\n this.showTaskForm.set(true);\n this.state.selectTask(null);\n }\n\n getMemberName(assigneeId: string): string | null {\n return (\n this.state.members().find((m) => m.userId === assigneeId)?.userName ??\n null\n );\n }\n\n getMemberInitials(assigneeId: string): string {\n return memberInitials(this.getMemberName(assigneeId));\n }\n\n memberInitials(member: ITaskBoardMember): string {\n return memberInitials(member.userName);\n }\n\n memberColor(member: ITaskBoardMember): string {\n return memberColorFromId(member.userId);\n }\n\n memberColorById(userId: string): string {\n return memberColorFromId(userId);\n }\n\n roleBadgeClass(role: string): string {\n const map: Record<string, string> = {\n OWNER: 'text-primary-600 dark:text-primary-400 font-semibold',\n ADMIN: 'text-orange-600 dark:text-orange-400 font-semibold',\n MEMBER: 'text-surface-500 dark:text-surface-400',\n VIEWER: 'text-surface-400 dark:text-surface-500',\n };\n return map[role] ?? map['MEMBER'];\n }\n\n protected readonly prioritySeverity = taskPrioritySeverity;\n protected readonly isOverdue = isTaskOverdue;\n\n async onTaskDrop(event: CdkDragDrop<ITask[]>): Promise<void> {\n const sameList = event.previousContainer === event.container;\n if (sameList && event.previousIndex === event.currentIndex) return;\n const task = event.item?.data ?? event.previousContainer.data[event.previousIndex];\n if (!task) return;\n try {\n await this.state.moveTask(task.id, event.container.id, event.currentIndex);\n } catch {}\n }\n\n async onListDrop(event: CdkDragDrop<ITaskListWithTasks[]>): Promise<void> {\n if (event.previousIndex === event.currentIndex) return;\n const lists = this.state.listsWithTasks().slice();\n moveItemInArray(lists, event.previousIndex, event.currentIndex);\n const orderedIds = lists.map((l) => l.id);\n try {\n await this.state.reorderLists(this.boardId(), orderedIds);\n } catch {}\n }\n\n startRenameList(list: ITaskList): void {\n this.editingListId.set(list.id);\n this.editingListNameValue.set(list.name);\n }\n\n cancelRenameList(): void {\n this.editingListId.set(null);\n this.editingListNameValue.set('');\n }\n\n async saveRenameList(): Promise<void> {\n const id = this.editingListId();\n const name = this.editingListNameValue().trim();\n this.cancelRenameList();\n if (!id || !name) return;\n await this.state.renameList(id, name);\n this.messageService.add({\n severity: 'success',\n summary: this.translate('shared.success'),\n detail: this.translate('task.list.update.success'),\n });\n }\n\n openEditBoardDialog(board: ITaskBoard): void {\n this.editBoardName = board.name;\n this.editBoardDescription = board.description ?? '';\n this.editBoardColor = board.color;\n this.showEditBoardDialog.set(true);\n }\n\n async saveBoard(): Promise<void> {\n const board = this.state.activeBoard();\n if (!board || !this.editBoardName.trim()) return;\n this.isSavingBoard.set(true);\n try {\n await this.state.updateBoard({\n id: board.id,\n name: this.editBoardName.trim(),\n description: this.editBoardDescription.trim() || undefined,\n color: this.editBoardColor,\n });\n this.showEditBoardDialog.set(false);\n this.messageService.add({\n severity: 'success',\n summary: this.translate('shared.success'),\n detail: this.translate('task.board.update.success'),\n });\n } finally {\n this.isSavingBoard.set(false);\n }\n }\n\n async addLabel(): Promise<void> {\n if (!this.newLabelName.trim()) return;\n this.isAddingLabel.set(true);\n try {\n await this.state.addLabel(\n this.boardId(),\n this.newLabelName.trim(),\n this.newLabelColor,\n );\n this.newLabelName = '';\n this.newLabelColor = BOARD_COLOR_PALETTE[0];\n } finally {\n this.isAddingLabel.set(false);\n }\n }\n\n async removeLabel(labelId: string): Promise<void> {\n await this.state.deleteLabel(labelId);\n }\n\n async addMember(): Promise<void> {\n if (!this.selectedMemberUser) return;\n this.isAddingMember.set(true);\n try {\n await this.state.addMember(this.selectedMemberUser, this.newMemberRole);\n this.resetMemberForm();\n } finally {\n this.isAddingMember.set(false);\n }\n }\n\n resetMemberForm(): void {\n this.selectedMemberUser = null;\n this.newMemberRole = 'MEMBER';\n }\n\n async removeMember(userId: string): Promise<void> {\n await this.state.removeMember(userId);\n }\n\n async addList(): Promise<void> {\n if (!this.newListName.trim()) return;\n this.isAddingList.set(true);\n try {\n const position = this.state.lists().length * 100;\n await this.listApi.insert({\n boardId: this.boardId(),\n name: this.newListName.trim(),\n position,\n });\n await this.state.openBoard(this.boardId());\n this.showAddListDialog.set(false);\n this.newListName = '';\n } finally {\n this.isAddingList.set(false);\n }\n }\n}\n"],"mappings":"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"}
|
|
@@ -32,7 +32,7 @@ var TaskBoardApiService = class TaskBoardApiService extends ApiResourceService {
|
|
|
32
32
|
}
|
|
33
33
|
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
34
34
|
minVersion: "12.0.0",
|
|
35
|
-
version: "22.2.
|
|
35
|
+
version: "22.2.2",
|
|
36
36
|
ngImport: i0,
|
|
37
37
|
type: TaskBoardApiService,
|
|
38
38
|
deps: [],
|
|
@@ -40,14 +40,14 @@ var TaskBoardApiService = class TaskBoardApiService extends ApiResourceService {
|
|
|
40
40
|
});
|
|
41
41
|
static ɵprov = i0.ɵɵngDeclareService({
|
|
42
42
|
minVersion: "22.0.0",
|
|
43
|
-
version: "22.2.
|
|
43
|
+
version: "22.2.2",
|
|
44
44
|
ngImport: i0,
|
|
45
45
|
type: TaskBoardApiService
|
|
46
46
|
});
|
|
47
47
|
};
|
|
48
48
|
i0.ɵɵngDeclareClassMetadata({
|
|
49
49
|
minVersion: "12.0.0",
|
|
50
|
-
version: "22.2.
|
|
50
|
+
version: "22.2.2",
|
|
51
51
|
ngImport: i0,
|
|
52
52
|
type: TaskBoardApiService,
|
|
53
53
|
decorators: [{ type: Service }],
|
|
@@ -62,7 +62,7 @@ var TaskApiService = class TaskApiService extends ApiResourceService {
|
|
|
62
62
|
}
|
|
63
63
|
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
64
64
|
minVersion: "12.0.0",
|
|
65
|
-
version: "22.2.
|
|
65
|
+
version: "22.2.2",
|
|
66
66
|
ngImport: i0,
|
|
67
67
|
type: TaskApiService,
|
|
68
68
|
deps: [],
|
|
@@ -70,14 +70,14 @@ var TaskApiService = class TaskApiService extends ApiResourceService {
|
|
|
70
70
|
});
|
|
71
71
|
static ɵprov = i0.ɵɵngDeclareService({
|
|
72
72
|
minVersion: "22.0.0",
|
|
73
|
-
version: "22.2.
|
|
73
|
+
version: "22.2.2",
|
|
74
74
|
ngImport: i0,
|
|
75
75
|
type: TaskApiService
|
|
76
76
|
});
|
|
77
77
|
};
|
|
78
78
|
i0.ɵɵngDeclareClassMetadata({
|
|
79
79
|
minVersion: "12.0.0",
|
|
80
|
-
version: "22.2.
|
|
80
|
+
version: "22.2.2",
|
|
81
81
|
ngImport: i0,
|
|
82
82
|
type: TaskApiService,
|
|
83
83
|
decorators: [{ type: Service }],
|
|
@@ -95,7 +95,7 @@ var TaskListApiService = class TaskListApiService extends ApiResourceService {
|
|
|
95
95
|
}
|
|
96
96
|
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
97
97
|
minVersion: "12.0.0",
|
|
98
|
-
version: "22.2.
|
|
98
|
+
version: "22.2.2",
|
|
99
99
|
ngImport: i0,
|
|
100
100
|
type: TaskListApiService,
|
|
101
101
|
deps: [],
|
|
@@ -103,14 +103,14 @@ var TaskListApiService = class TaskListApiService extends ApiResourceService {
|
|
|
103
103
|
});
|
|
104
104
|
static ɵprov = i0.ɵɵngDeclareService({
|
|
105
105
|
minVersion: "22.0.0",
|
|
106
|
-
version: "22.2.
|
|
106
|
+
version: "22.2.2",
|
|
107
107
|
ngImport: i0,
|
|
108
108
|
type: TaskListApiService
|
|
109
109
|
});
|
|
110
110
|
};
|
|
111
111
|
i0.ɵɵngDeclareClassMetadata({
|
|
112
112
|
minVersion: "12.0.0",
|
|
113
|
-
version: "22.2.
|
|
113
|
+
version: "22.2.2",
|
|
114
114
|
ngImport: i0,
|
|
115
115
|
type: TaskListApiService,
|
|
116
116
|
decorators: [{ type: Service }],
|
|
@@ -122,7 +122,7 @@ var TaskLabelApiService = class TaskLabelApiService extends ApiResourceService {
|
|
|
122
122
|
}
|
|
123
123
|
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
124
124
|
minVersion: "12.0.0",
|
|
125
|
-
version: "22.2.
|
|
125
|
+
version: "22.2.2",
|
|
126
126
|
ngImport: i0,
|
|
127
127
|
type: TaskLabelApiService,
|
|
128
128
|
deps: [],
|
|
@@ -130,14 +130,14 @@ var TaskLabelApiService = class TaskLabelApiService extends ApiResourceService {
|
|
|
130
130
|
});
|
|
131
131
|
static ɵprov = i0.ɵɵngDeclareService({
|
|
132
132
|
minVersion: "22.0.0",
|
|
133
|
-
version: "22.2.
|
|
133
|
+
version: "22.2.2",
|
|
134
134
|
ngImport: i0,
|
|
135
135
|
type: TaskLabelApiService
|
|
136
136
|
});
|
|
137
137
|
};
|
|
138
138
|
i0.ɵɵngDeclareClassMetadata({
|
|
139
139
|
minVersion: "12.0.0",
|
|
140
|
-
version: "22.2.
|
|
140
|
+
version: "22.2.2",
|
|
141
141
|
ngImport: i0,
|
|
142
142
|
type: TaskLabelApiService,
|
|
143
143
|
decorators: [{ type: Service }],
|
|
@@ -149,7 +149,7 @@ var TaskCommentApiService = class TaskCommentApiService extends ApiResourceServi
|
|
|
149
149
|
}
|
|
150
150
|
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
151
151
|
minVersion: "12.0.0",
|
|
152
|
-
version: "22.2.
|
|
152
|
+
version: "22.2.2",
|
|
153
153
|
ngImport: i0,
|
|
154
154
|
type: TaskCommentApiService,
|
|
155
155
|
deps: [],
|
|
@@ -157,14 +157,14 @@ var TaskCommentApiService = class TaskCommentApiService extends ApiResourceServi
|
|
|
157
157
|
});
|
|
158
158
|
static ɵprov = i0.ɵɵngDeclareService({
|
|
159
159
|
minVersion: "22.0.0",
|
|
160
|
-
version: "22.2.
|
|
160
|
+
version: "22.2.2",
|
|
161
161
|
ngImport: i0,
|
|
162
162
|
type: TaskCommentApiService
|
|
163
163
|
});
|
|
164
164
|
};
|
|
165
165
|
i0.ɵɵngDeclareClassMetadata({
|
|
166
166
|
minVersion: "12.0.0",
|
|
167
|
-
version: "22.2.
|
|
167
|
+
version: "22.2.2",
|
|
168
168
|
ngImport: i0,
|
|
169
169
|
type: TaskCommentApiService,
|
|
170
170
|
decorators: [{ type: Service }],
|
|
@@ -227,7 +227,7 @@ var TaskBoardSocketService = class TaskBoardSocketService {
|
|
|
227
227
|
}
|
|
228
228
|
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
229
229
|
minVersion: "12.0.0",
|
|
230
|
-
version: "22.2.
|
|
230
|
+
version: "22.2.2",
|
|
231
231
|
ngImport: i0,
|
|
232
232
|
type: TaskBoardSocketService,
|
|
233
233
|
deps: [],
|
|
@@ -235,14 +235,14 @@ var TaskBoardSocketService = class TaskBoardSocketService {
|
|
|
235
235
|
});
|
|
236
236
|
static ɵprov = i0.ɵɵngDeclareService({
|
|
237
237
|
minVersion: "22.0.0",
|
|
238
|
-
version: "22.2.
|
|
238
|
+
version: "22.2.2",
|
|
239
239
|
ngImport: i0,
|
|
240
240
|
type: TaskBoardSocketService
|
|
241
241
|
});
|
|
242
242
|
};
|
|
243
243
|
i0.ɵɵngDeclareClassMetadata({
|
|
244
244
|
minVersion: "12.0.0",
|
|
245
|
-
version: "22.2.
|
|
245
|
+
version: "22.2.2",
|
|
246
246
|
ngImport: i0,
|
|
247
247
|
type: TaskBoardSocketService,
|
|
248
248
|
decorators: [{ type: Service }]
|
|
@@ -533,7 +533,7 @@ var TaskBoardStateService = class TaskBoardStateService {
|
|
|
533
533
|
}
|
|
534
534
|
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
535
535
|
minVersion: "12.0.0",
|
|
536
|
-
version: "22.2.
|
|
536
|
+
version: "22.2.2",
|
|
537
537
|
ngImport: i0,
|
|
538
538
|
type: TaskBoardStateService,
|
|
539
539
|
deps: [],
|
|
@@ -541,14 +541,14 @@ var TaskBoardStateService = class TaskBoardStateService {
|
|
|
541
541
|
});
|
|
542
542
|
static ɵprov = i0.ɵɵngDeclareService({
|
|
543
543
|
minVersion: "22.0.0",
|
|
544
|
-
version: "22.2.
|
|
544
|
+
version: "22.2.2",
|
|
545
545
|
ngImport: i0,
|
|
546
546
|
type: TaskBoardStateService
|
|
547
547
|
});
|
|
548
548
|
};
|
|
549
549
|
i0.ɵɵngDeclareClassMetadata({
|
|
550
550
|
minVersion: "12.0.0",
|
|
551
|
-
version: "22.2.
|
|
551
|
+
version: "22.2.2",
|
|
552
552
|
ngImport: i0,
|
|
553
553
|
type: TaskBoardStateService,
|
|
554
554
|
decorators: [{ type: Service }],
|
|
@@ -623,7 +623,7 @@ var TaskCardComponent = class TaskCardComponent {
|
|
|
623
623
|
memberColor = memberColorFromId;
|
|
624
624
|
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
625
625
|
minVersion: "12.0.0",
|
|
626
|
-
version: "22.2.
|
|
626
|
+
version: "22.2.2",
|
|
627
627
|
ngImport: i0,
|
|
628
628
|
type: TaskCardComponent,
|
|
629
629
|
deps: [],
|
|
@@ -631,7 +631,7 @@ var TaskCardComponent = class TaskCardComponent {
|
|
|
631
631
|
});
|
|
632
632
|
static ɵcmp = i0.ɵɵngDeclareComponent({
|
|
633
633
|
minVersion: "17.0.0",
|
|
634
|
-
version: "22.2.
|
|
634
|
+
version: "22.2.2",
|
|
635
635
|
type: TaskCardComponent,
|
|
636
636
|
isStandalone: true,
|
|
637
637
|
selector: "tm-task-card",
|
|
@@ -809,7 +809,7 @@ var TaskCardComponent = class TaskCardComponent {
|
|
|
809
809
|
};
|
|
810
810
|
i0.ɵɵngDeclareClassMetadata({
|
|
811
811
|
minVersion: "12.0.0",
|
|
812
|
-
version: "22.2.
|
|
812
|
+
version: "22.2.2",
|
|
813
813
|
ngImport: i0,
|
|
814
814
|
type: TaskCardComponent,
|
|
815
815
|
decorators: [{
|
|
@@ -1042,7 +1042,7 @@ var TaskFormDialogComponent = class TaskFormDialogComponent {
|
|
|
1042
1042
|
}
|
|
1043
1043
|
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
1044
1044
|
minVersion: "12.0.0",
|
|
1045
|
-
version: "22.2.
|
|
1045
|
+
version: "22.2.2",
|
|
1046
1046
|
ngImport: i0,
|
|
1047
1047
|
type: TaskFormDialogComponent,
|
|
1048
1048
|
deps: [],
|
|
@@ -1050,7 +1050,7 @@ var TaskFormDialogComponent = class TaskFormDialogComponent {
|
|
|
1050
1050
|
});
|
|
1051
1051
|
static ɵcmp = i0.ɵɵngDeclareComponent({
|
|
1052
1052
|
minVersion: "17.0.0",
|
|
1053
|
-
version: "22.2.
|
|
1053
|
+
version: "22.2.2",
|
|
1054
1054
|
type: TaskFormDialogComponent,
|
|
1055
1055
|
isStandalone: true,
|
|
1056
1056
|
selector: "tm-task-form-dialog",
|
|
@@ -1506,7 +1506,7 @@ var TaskFormDialogComponent = class TaskFormDialogComponent {
|
|
|
1506
1506
|
};
|
|
1507
1507
|
i0.ɵɵngDeclareClassMetadata({
|
|
1508
1508
|
minVersion: "12.0.0",
|
|
1509
|
-
version: "22.2.
|
|
1509
|
+
version: "22.2.2",
|
|
1510
1510
|
ngImport: i0,
|
|
1511
1511
|
type: TaskFormDialogComponent,
|
|
1512
1512
|
decorators: [{
|
|
@@ -1793,7 +1793,7 @@ var TaskDetailPanelComponent = class TaskDetailPanelComponent {
|
|
|
1793
1793
|
}
|
|
1794
1794
|
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
1795
1795
|
minVersion: "12.0.0",
|
|
1796
|
-
version: "22.2.
|
|
1796
|
+
version: "22.2.2",
|
|
1797
1797
|
ngImport: i0,
|
|
1798
1798
|
type: TaskDetailPanelComponent,
|
|
1799
1799
|
deps: [],
|
|
@@ -1801,7 +1801,7 @@ var TaskDetailPanelComponent = class TaskDetailPanelComponent {
|
|
|
1801
1801
|
});
|
|
1802
1802
|
static ɵcmp = i0.ɵɵngDeclareComponent({
|
|
1803
1803
|
minVersion: "17.0.0",
|
|
1804
|
-
version: "22.2.
|
|
1804
|
+
version: "22.2.2",
|
|
1805
1805
|
type: TaskDetailPanelComponent,
|
|
1806
1806
|
isStandalone: true,
|
|
1807
1807
|
selector: "tm-task-detail-panel",
|
|
@@ -2189,7 +2189,7 @@ var TaskDetailPanelComponent = class TaskDetailPanelComponent {
|
|
|
2189
2189
|
};
|
|
2190
2190
|
i0.ɵɵngDeclareClassMetadata({
|
|
2191
2191
|
minVersion: "12.0.0",
|
|
2192
|
-
version: "22.2.
|
|
2192
|
+
version: "22.2.2",
|
|
2193
2193
|
ngImport: i0,
|
|
2194
2194
|
type: TaskDetailPanelComponent,
|
|
2195
2195
|
decorators: [{
|
|
@@ -2576,7 +2576,7 @@ const TASK_MANAGER_ROUTES = [{
|
|
|
2576
2576
|
...SHARED_MESSAGES
|
|
2577
2577
|
}
|
|
2578
2578
|
}) },
|
|
2579
|
-
loadComponent: () => import("./flusys-ng-task-manager-board-list-page.component-
|
|
2579
|
+
loadComponent: () => import("./flusys-ng-task-manager-board-list-page.component-S-H_VPtf.mjs").then((m) => m.BoardListPageComponent)
|
|
2580
2580
|
}, {
|
|
2581
2581
|
path: "board/:boardId",
|
|
2582
2582
|
resolve: { translations: resolveTranslationModule({
|
|
@@ -2586,7 +2586,7 @@ const TASK_MANAGER_ROUTES = [{
|
|
|
2586
2586
|
...SHARED_MESSAGES
|
|
2587
2587
|
}
|
|
2588
2588
|
}) },
|
|
2589
|
-
loadComponent: () => import("./flusys-ng-task-manager-board-view-page.component-
|
|
2589
|
+
loadComponent: () => import("./flusys-ng-task-manager-board-view-page.component-CR5kmFau.mjs").then((m) => m.BoardViewPageComponent)
|
|
2590
2590
|
}];
|
|
2591
2591
|
export { BOARD_COLOR_PALETTE, MEMBER_COLOR_PALETTE, TASK_MANAGER_MESSAGES, TASK_MANAGER_ROUTES, TaskApiService, TaskBoardApiService, TaskBoardSocketService, TaskBoardStateService, TaskCardComponent, TaskCommentApiService, TaskDetailPanelComponent, TaskFormDialogComponent, TaskLabelApiService, TaskListApiService, isTaskOverdue, memberColorFromId, memberInitials, parseDateOnly, taskPrioritySeverity, toDateOnlyString };
|
|
2592
2592
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flusys/ng-task-manager",
|
|
3
|
-
"version": "9.2.
|
|
3
|
+
"version": "9.2.2",
|
|
4
4
|
"description": "Task management module with dynamic boards, lists, and real-time collaboration",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"peerDependencies": {
|
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
"@angular/core": ">=22.0.0",
|
|
10
10
|
"@angular/forms": ">=22.0.0",
|
|
11
11
|
"@angular/router": ">=22.0.0",
|
|
12
|
-
"@flusys/ng-core": ">=9.2.
|
|
13
|
-
"@flusys/ng-shared": ">=9.2.
|
|
14
|
-
"@flusys/ng-ui": ">=9.2.
|
|
12
|
+
"@flusys/ng-core": ">=9.2.2",
|
|
13
|
+
"@flusys/ng-shared": ">=9.2.2",
|
|
14
|
+
"@flusys/ng-ui": ">=9.2.2",
|
|
15
15
|
"socket.io-client": ">=4.0.0",
|
|
16
16
|
"rxjs": "^7.8.0"
|
|
17
17
|
},
|