diff --git a/.changeset/whole-dancers-cry.md b/.changeset/whole-dancers-cry.md new file mode 100644 index 0000000..6d9bf78 --- /dev/null +++ b/.changeset/whole-dancers-cry.md @@ -0,0 +1,5 @@ +--- +"specif-ai": patch +--- + +Introduce success & failure toast messages for Task/User Story generation/regeneration diff --git a/ui/src/app/constants/app.constants.ts b/ui/src/app/constants/app.constants.ts index f170724..0148efb 100644 --- a/ui/src/app/constants/app.constants.ts +++ b/ui/src/app/constants/app.constants.ts @@ -156,6 +156,18 @@ export const TOASTER_MESSAGES = { FAILURE: (entityType: string, entityId: string) => TOASTER_MESSAGES_DEFAULT_TEMPLATE.FAILURE(entityType, 'copy', entityId), }, + GENERATE: { + SUCCESS: (entityType: string, isRegenerate = false) => + TOASTER_MESSAGES_DEFAULT_TEMPLATE.SUCCESS( + entityType, + isRegenerate ? 'regenerated' : 'generated', + ), + FAILURE: (entityType: string, isRegenerate = false) => + TOASTER_MESSAGES_DEFAULT_TEMPLATE.FAILURE( + entityType, + isRegenerate ? 'regenerate' : 'generate', + ), + }, }, }; diff --git a/ui/src/app/pages/tasks/task-list/task-list.component.html b/ui/src/app/pages/tasks/task-list/task-list.component.html index 3f5e4c1..d998c78 100644 --- a/ui/src/app/pages/tasks/task-list/task-list.component.html +++ b/ui/src/app/pages/tasks/task-list/task-list.component.html @@ -43,7 +43,7 @@

Tasks

theme="secondary" size="sm" rounded="lg" - (click)="addExtraContext()" + (click)="addExtraContext(taskList.length > 0)" /> @@ -87,6 +87,7 @@

Tasks

[isIconButton]="true" icon="heroDocumentDuplicate" (click)="copyTaskContent($event, task)" + matTooltip="Copy" /> diff --git a/ui/src/app/pages/tasks/task-list/task-list.component.ts b/ui/src/app/pages/tasks/task-list/task-list.component.ts index d8f9e96..da1d6cf 100644 --- a/ui/src/app/pages/tasks/task-list/task-list.component.ts +++ b/ui/src/app/pages/tasks/task-list/task-list.component.ts @@ -22,6 +22,7 @@ import { MatDialog } from '@angular/material/dialog'; import { ProjectsState } from '../../../store/projects/projects.state'; import { AsyncPipe, NgForOf, NgIf } from '@angular/common'; import { ButtonComponent } from '../../../components/core/button/button.component'; +import { MatTooltipModule } from '@angular/material/tooltip'; import { NgIconComponent } from '@ng-icons/core'; import { ListItemComponent } from '../../../components/core/list-item/list-item.component'; import { BadgeComponent } from '../../../components/core/badge/badge.component'; @@ -46,6 +47,7 @@ import { BehaviorSubject } from 'rxjs'; ListItemComponent, BadgeComponent, SearchInputComponent, + MatTooltipModule, ], }) export class TaskListComponent implements OnInit, OnDestroy { @@ -145,7 +147,7 @@ export class TaskListComponent implements OnInit, OnDestroy { }); } - addExtraContext() { + addExtraContext(regenerate: boolean = false) { const dialogText = { title: 'Generate User Story Tasks', description: @@ -159,18 +161,18 @@ export class TaskListComponent implements OnInit, OnDestroy { }); dialogRef.componentInstance.generate.subscribe((emittedValue) => { - this.refineUserStoryIntoTasks(emittedValue); + this.refineUserStoryIntoTasks(regenerate, emittedValue); }); } - refineUserStoryIntoTasks(extraContext: string) { + refineUserStoryIntoTasks(regenerate: boolean = false, extraContext: string) { let request: ITaskRequest = { appId: this.config.projectId, reqId: this.config.newFileName.split('-')[0], featureId: this.selectedUserStory.id, name: this.selectedUserStory.name, description: this.selectedUserStory.description, - regenerate: true, + regenerate: regenerate, technicalDetails: this.metadata.technicalDetails || '', extraContext: extraContext, }; @@ -184,17 +186,23 @@ export class TaskListComponent implements OnInit, OnDestroy { tasks: tasksResponse, }; this.userStories = updatedUserStories; - this.updateWithUserStories(updatedUserStories[this.config.i]); + this.updateWithUserStories( + updatedUserStories[this.config.i], + regenerate, + ); }, error: (error) => { console.error('There was an error!', error); this.loadingService.setLoading(false); + this.toastService.showError( + TOASTER_MESSAGES.ENTITY.GENERATE.FAILURE(this.entityType, regenerate), + ); }, }); this.dialog.closeAll(); } - updateWithUserStories(userStories: IUserStory) { + updateWithUserStories(userStories: IUserStory, regenerate: boolean = false) { this.store.dispatch( new EditUserStory( `${this.config.folderName}/${this.config.newFileName}`, @@ -204,6 +212,9 @@ export class TaskListComponent implements OnInit, OnDestroy { setTimeout(() => { this.getLatestUserStories(); this.loadingService.setLoading(false); + this.toastService.showSuccess( + TOASTER_MESSAGES.ENTITY.GENERATE.SUCCESS(this.entityType, regenerate), + ); }, 2000); } diff --git a/ui/src/app/pages/user-stories/user-stories.component.html b/ui/src/app/pages/user-stories/user-stories.component.html index 08731c0..be69ab6 100644 --- a/ui/src/app/pages/user-stories/user-stories.component.html +++ b/ui/src/app/pages/user-stories/user-stories.component.html @@ -19,19 +19,14 @@

User Stories

- { this.userStories = response; this.generateTasks(regenerate).then(() => { - this.updateWithUserStories(this.userStories); + this.updateWithUserStories(this.userStories, regenerate); }); }, error: (error) => { this.loadingService.setLoading(false); - console.error('Error fetching user stories:', error); + this.toast.showError( + TOASTER_MESSAGES.ENTITY.GENERATE.FAILURE(this.entityType, regenerate), + ); }, }); this.dialog.closeAll(); @@ -308,7 +313,10 @@ export class UserStoriesComponent implements OnInit { return Promise.all(requests); } - updateWithUserStories(userStories: IUserStory[]) { + updateWithUserStories( + userStories: IUserStory[], + regenerate: boolean = false, + ) { this.store.dispatch( new CreateFile( `${this.navigation.folderName}`, @@ -320,6 +328,9 @@ export class UserStoriesComponent implements OnInit { setTimeout(() => { this.getLatestUserStories(); this.loadingService.setLoading(false); + this.toast.showSuccess( + TOASTER_MESSAGES.ENTITY.GENERATE.SUCCESS(this.entityType, regenerate), + ); }, 2000); }