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
-
0"
- buttonContent="Regenerate User Stories"
- theme="secondary"
- size="sm"
- (click)="addMoreContext(true)"
+ (click)="addMoreContext(userStories.length > 0)"
rounded="lg"
/>
{
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);
}