Skip to content

Commit

Permalink
add ability to delete cases from projects
Browse files Browse the repository at this point in the history
  • Loading branch information
itsmostafa committed Feb 17, 2025
1 parent 4250790 commit 399c5fc
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 72 deletions.
Original file line number Diff line number Diff line change
@@ -1,53 +1,57 @@
<div class="container">
<h1>{{ projectName }}</h1>
<ul class="nav nav-tabs">
<li class="nav-item" *ngFor="let tab of tabs; let i = index">
<a
class="nav-link"
[class.active]="i === activeTabIndex"
(click)="activateTab(i)"
style="cursor: pointer;"
>
{{ tab.title }}
</a>
</li>
<!-- Plus sign triggers modal -->
<li class="nav-item">
<a class="nav-link" (click)="openNewTabModal()" style="cursor: pointer;">+</a>
</li>
</ul>

<!-- Tab content: Display DiagramComponent in active tab -->
<div class="tab-content border border-top-0 p-3">
<div class="tab-pane fade show active">
<app-diagram></app-diagram>
</div>
</div>

<!-- Modal Dialog -->
<div class="modal-backdrop fade show" *ngIf="showModal"></div>
<div class="modal fade show d-block" tabindex="-1" *ngIf="showModal" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Add a New Case</h5>
<button type="button" class="btn-close" (click)="closeNewTabModal()" aria-label="Close"></button>
</div>
<div class="modal-body">
<label for="tabSelector" class="form-label">Select Hazard:</label>
<select id="tabSelector" class="form-select" [(ngModel)]="selectedTabName">
<option *ngFor="let name of availableTabs" [value]="name">{{ name }}</option>
</select>
<div *ngIf="selectedTabName === 'Custom'" class="mt-3">
<label for="customTabName" class="form-label">Custom Hazard:</label>
<input id="customTabName" type="text" class="form-control" [(ngModel)]="customTabName" placeholder="Enter custom tab name">
<ul class="nav nav-tabs">
<li class="nav-item" *ngFor="let tab of tabs; let i = index">
<a
class="nav-link"
[class.active]="i === activeTabIndex"
(click)="activateTab(i)"
style="cursor: pointer;"
>
{{ tab.title }}
</a>
</li>
<!-- Plus sign triggers modal -->
<li class="nav-item">
<a class="nav-link" (click)="openNewTabModal()" style="cursor: pointer;">+</a>
</li>
</ul>

<!-- Tab content: Display DiagramComponent in active tab -->
<div class="tab-content border border-top-0 p-3">
<div class="tab-pane fade show active">
<div class="d-flex justify-content-between mb-2">
<h4>{{ tabs[activeTabIndex].title }} Diagram</h4>
<button *ngIf="tabs[activeTabIndex].title !== 'Base Case'" class="btn btn-danger" (click)="deleteTab(activeTabIndex)">Delete</button>
</div>
<app-diagram></app-diagram>
</div>
</div>

<!-- Modal Dialog -->
<div class="modal-backdrop fade show" *ngIf="showModal"></div>
<div class="modal fade show d-block" tabindex="-1" *ngIf="showModal" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Add a New Case</h5>
<button type="button" class="btn-close" (click)="closeNewTabModal()" aria-label="Close"></button>
</div>
<div class="modal-body">
<label for="tabSelector" class="form-label">Select Hazard:</label>
<select id="tabSelector" class="form-select" [(ngModel)]="selectedTabName">
<option *ngFor="let name of availableTabs" [value]="name">{{ name }}</option>
</select>
<div *ngIf="selectedTabName === 'Custom'" class="mt-3">
<label for="customTabName" class="form-label">Custom Hazard:</label>
<input id="customTabName" type="text" class="form-control" [(ngModel)]="customTabName" placeholder="Enter custom tab name">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" (click)="closeNewTabModal()">Cancel</button>
<button type="button" class="btn btn-primary" (click)="addTabFromModal()">Add Hazard Case</button>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" (click)="closeNewTabModal()">Cancel</button>
<button type="button" class="btn btn-primary" (click)="addTabFromModal()">Add Hazard Case</button>
</div>
</div>
</div>
</div>
</div>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { ActivatedRoute } from '@angular/router';

interface Tab {
title: string;
_id?: string; // store the case id so we can delete it
}

@Component({
Expand All @@ -18,9 +19,7 @@ interface Tab {
})
export class ProjectDiagramComponent implements OnInit {
// Default tab list.
tabs: Tab[] = [
{ title: 'Base Case' }
];
tabs: Tab[] = [{ title: "Base Case", _id: "id" }];

// Active tab index.
activeTabIndex: number = 0;
Expand All @@ -42,22 +41,20 @@ export class ProjectDiagramComponent implements OnInit {
projectName: string = '';
cases: Case[] = [];


constructor(private _projectService: ProjectService, private _route: ActivatedRoute) { }

ngOnInit(): void {
this.projectId = this._route.snapshot.paramMap.get('id') || ''
this.loadProject()
this.loadCases()
this.projectId = this._route.snapshot.paramMap.get('id') || '';
this.loadProject();
this.loadCases();
}

private loadCases(): void {
this._projectService.getCases(this.projectId).subscribe({
next: (cases) => {
this.cases = cases;

if (this.cases.length > 0) {
this.tabs = this.cases.map(c => ({ title: c.name }));
this.tabs = this.cases.map(c => ({ title: c.name, _id: c._id }));
}
},
error: () => {
Expand Down Expand Up @@ -89,35 +86,68 @@ export class ProjectDiagramComponent implements OnInit {
this.showModal = false;
}

// Add a new tab from modal selection.
addTabFromModal(): void {
const tabTitle = this.selectedTabName === 'Custom'
? (this.customTabName.trim() ? this.customTabName : 'Custom Case')
: this.selectedTabName;

this.tabs.push({
title: tabTitle
});
// Activate new tab.
this.activeTabIndex = this.tabs.length - 1;

// Create new Case:
// TODO: Implement diagram data.
// Create new Case
this._projectService.createCase(this.projectId, { name: tabTitle, diagram_data: "{'test': 'test'}" }).subscribe({
next: (newCase) => {
console.log('Case created:', newCase);
next: (caseId: string) => {
// Append the new case to the cases array
this.cases = [...this.cases, { name: tabTitle, _id: caseId }];
// Regenerate the tabs array from the updated cases
this.tabs = this.cases.map(c => ({ title: c.name, _id: c._id }));

// Activate the new tab
this.activeTabIndex = this.tabs.length - 1;
},
error: () => {
console.log('Failed to load cases');
console.log('Failed to create case');
}
});

// Close the modal.
// Close the modal
this.closeNewTabModal();
}

// Activate a tab.
activateTab(index: number): void {
this.activeTabIndex = index;
}

// Delete the active tab and call deleteCase from ProjectService.
deleteTab(index: number): void {
const tabToDelete = this.tabs[index];
if (!tabToDelete._id) {
console.log('Cannot delete tab without a valid case id.');
return;
}

const confirmed = confirm(`Are you sure you want to delete ${tabToDelete.title}?`);
if (!confirmed) {
return;
}

this._projectService.deleteCase(this.projectId, tabToDelete._id).subscribe({
next: () => {
// Remove the case from the tabs array.
this.tabs.splice(index, 1);

// Find and remove the corresponding case from this.cases
const caseIndex = this.cases.findIndex(c => c._id === tabToDelete._id);
if (caseIndex !== -1) {
this.cases.splice(caseIndex, 1);
}

// Adjust active tab index if necessary.
if (this.activeTabIndex >= this.tabs.length) {
this.activeTabIndex = this.tabs.length - 1;
}
},
error: () => {
console.log('Failed to delete case');
}
});
}
}
11 changes: 9 additions & 2 deletions web/src/app/services/project.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,15 @@ export class ProjectService {
}

// Create a new case for a specific project
createCase(projectId: string, caseData: Case): Observable<Case> {
return this.http.post<Case>(`${this.apiUrl}/project/${projectId}/case/create/`, caseData, {
createCase(projectId: string, caseData: Case): Observable<string> {
return this.http.post<string>(`${this.apiUrl}/project/${projectId}/case/create/`, caseData, {
headers: this.getAuthHeaders()
});
}

// Delete a case by ID
deleteCase(projectId: string, caseId: string): Observable<void> {
return this.http.delete<void>(`${this.apiUrl}/project/${projectId}/case/${caseId}/delete/`, {
headers: this.getAuthHeaders()
});
}
Expand Down

0 comments on commit 399c5fc

Please sign in to comment.