-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Update Decision # Generation to include NOIs and PRs
- Loading branch information
Daniel Haselhan
committed
Mar 14, 2024
1 parent
45fdf41
commit 099d2b9
Showing
53 changed files
with
3,893 additions
and
39 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
71 changes: 71 additions & 0 deletions
71
...pp/features/planning-review/decision/decision-documents/decision-documents.component.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
<div *ngIf="editable"> | ||
<div class="split"> | ||
<h3>Documents</h3> | ||
<div> | ||
<button | ||
type="button" | ||
[ngClass]="{ 'upload-button': true, 'error-field-outlined ng-invalid': showError }" | ||
(click)="onUploadFile()" | ||
mat-flat-button | ||
color="primary" | ||
> | ||
Add Document | ||
</button> | ||
<app-error-message *ngIf="showError"></app-error-message> | ||
</div> | ||
</div> | ||
</div> | ||
<table mat-table [dataSource]="dataSource" matSort class="documents"> | ||
<ng-container matColumnDef="type"> | ||
<th mat-header-cell *matHeaderCellDef mat-sort-header sortActionDescription="Sort by type">Type</th> | ||
<td mat-cell *matCellDef="let element" matTooltip="Decision Package">DECPACK</td> | ||
</ng-container> | ||
|
||
<ng-container matColumnDef="fileName"> | ||
<th mat-header-cell *matHeaderCellDef mat-sort-header sortActionDescription="Sort by name">Document Name</th> | ||
<td mat-cell *matCellDef="let element"> | ||
<a (click)="openFile(element.uuid, element.fileName)">{{ element.fileName }}</a> | ||
</td> | ||
</ng-container> | ||
|
||
<ng-container matColumnDef="source"> | ||
<th mat-header-cell *matHeaderCellDef mat-sort-header sortActionDescription="Sort by source">Source</th> | ||
<td mat-cell *matCellDef="let element">ALC</td> | ||
</ng-container> | ||
|
||
<ng-container matColumnDef="visibilityFlags"> | ||
<th mat-header-cell *matHeaderCellDef> | ||
Visibility | ||
<div class="subheading">* = Pending</div> | ||
</th> | ||
<td mat-cell *matCellDef="let element"> | ||
<span matTooltip="Commissioner">C<span *ngIf="!areDocumentsReleased">*</span></span> | ||
</td> | ||
</ng-container> | ||
|
||
<ng-container matColumnDef="uploadedAt"> | ||
<th mat-header-cell *matHeaderCellDef mat-sort-header sortActionDescription="Sort by date">Upload Date</th> | ||
<td mat-cell *matCellDef="let element">{{ element.uploadedAt | momentFormat }}</td> | ||
</ng-container> | ||
|
||
<ng-container matColumnDef="actions"> | ||
<th mat-header-cell *matHeaderCellDef>File Actions</th> | ||
<td mat-cell *matCellDef="let element"> | ||
<button type="button" mat-icon-button (click)="downloadFile(element.uuid, element.fileName)"> | ||
<mat-icon>file_download</mat-icon> | ||
</button> | ||
<button type="button" *ngIf="editable" mat-icon-button (click)="onEditFile(element)"> | ||
<mat-icon>edit</mat-icon> | ||
</button> | ||
<button type="button" *ngIf="editable" mat-icon-button (click)="onDeleteFile(element)"> | ||
<mat-icon color="warn">delete</mat-icon> | ||
</button> | ||
</td> | ||
</ng-container> | ||
|
||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> | ||
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr> | ||
<tr class="mat-row" *matNoDataRow> | ||
<td class="text-center" colspan="6">No Documents</td> | ||
</tr> | ||
</table> |
37 changes: 37 additions & 0 deletions
37
...pp/features/planning-review/decision/decision-documents/decision-documents.component.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
@use '../../../../../styles/colors'; | ||
|
||
.documents { | ||
margin-top: 12px; | ||
border-collapse: collapse; | ||
} | ||
|
||
.upload-button { | ||
width: 100%; | ||
margin: 4px 0 12px !important; | ||
} | ||
|
||
.mat-mdc-no-data-row { | ||
height: 56px; | ||
color: colors.$grey-dark; | ||
} | ||
|
||
a { | ||
word-break: break-all; | ||
} | ||
|
||
table { | ||
box-shadow: none; | ||
|
||
th { | ||
font-weight: 700; | ||
padding-bottom: 16px; | ||
position: relative; | ||
|
||
.subheading { | ||
font-size: 11px; | ||
line-height: 16px; | ||
font-weight: 400; | ||
position: absolute; | ||
} | ||
} | ||
} |
52 changes: 52 additions & 0 deletions
52
...features/planning-review/decision/decision-documents/decision-documents.component.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import { NO_ERRORS_SCHEMA } from '@angular/core'; | ||
import { ComponentFixture, TestBed } from '@angular/core/testing'; | ||
import { MatDialog } from '@angular/material/dialog'; | ||
import { createMock, DeepMocked } from '@golevelup/ts-jest'; | ||
import { BehaviorSubject } from 'rxjs'; | ||
import { PlanningReviewDecisionDto } from '../../../../services/planning-review/planning-review-decision/planning-review-decision.dto'; | ||
import { PlanningReviewDecisionService } from '../../../../services/planning-review/planning-review-decision/planning-review-decision.service'; | ||
import { ToastService } from '../../../../services/toast/toast.service'; | ||
|
||
import { DecisionDocumentsComponent } from './decision-documents.component'; | ||
|
||
describe('DecisionDocumentsComponent', () => { | ||
let component: DecisionDocumentsComponent; | ||
let fixture: ComponentFixture<DecisionDocumentsComponent>; | ||
let mockPRDecService: DeepMocked<PlanningReviewDecisionService>; | ||
let mockDialog: DeepMocked<MatDialog>; | ||
let mockToastService: DeepMocked<ToastService>; | ||
|
||
beforeEach(async () => { | ||
mockPRDecService = createMock(); | ||
mockDialog = createMock(); | ||
mockToastService = createMock(); | ||
mockPRDecService.$decision = new BehaviorSubject<PlanningReviewDecisionDto | undefined>(undefined); | ||
|
||
await TestBed.configureTestingModule({ | ||
declarations: [DecisionDocumentsComponent], | ||
providers: [ | ||
{ | ||
provide: PlanningReviewDecisionService, | ||
useValue: mockPRDecService, | ||
}, | ||
{ | ||
provide: MatDialog, | ||
useValue: mockDialog, | ||
}, | ||
{ | ||
provide: ToastService, | ||
useValue: mockToastService, | ||
}, | ||
], | ||
schemas: [NO_ERRORS_SCHEMA], | ||
}).compileComponents(); | ||
|
||
fixture = TestBed.createComponent(DecisionDocumentsComponent); | ||
component = fixture.componentInstance; | ||
fixture.detectChanges(); | ||
}); | ||
|
||
it('should create', () => { | ||
expect(component).toBeTruthy(); | ||
}); | ||
}); |
112 changes: 112 additions & 0 deletions
112
.../app/features/planning-review/decision/decision-documents/decision-documents.component.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
import { Component, EventEmitter, Input, OnChanges, OnDestroy, Output, SimpleChanges, ViewChild } from '@angular/core'; | ||
import { MatDialog } from '@angular/material/dialog'; | ||
import { MatSort } from '@angular/material/sort'; | ||
import { MatTableDataSource } from '@angular/material/table'; | ||
import { Subject } from 'rxjs'; | ||
import { | ||
PlanningReviewDecisionDocumentDto, | ||
PlanningReviewDecisionDto, | ||
} from '../../../../services/planning-review/planning-review-decision/planning-review-decision.dto'; | ||
import { PlanningReviewDecisionService } from '../../../../services/planning-review/planning-review-decision/planning-review-decision.service'; | ||
import { ToastService } from '../../../../services/toast/toast.service'; | ||
import { ConfirmationDialogService } from '../../../../shared/confirmation-dialog/confirmation-dialog.service'; | ||
import { DecisionDocumentUploadDialogComponent } from '../decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component'; | ||
|
||
@Component({ | ||
selector: 'app-decision-documents', | ||
templateUrl: './decision-documents.component.html', | ||
styleUrls: ['./decision-documents.component.scss'], | ||
}) | ||
export class DecisionDocumentsComponent implements OnDestroy, OnChanges { | ||
$destroy = new Subject<void>(); | ||
|
||
@Input() editable = true; | ||
@Input() loadData = true; | ||
@Input() decision: PlanningReviewDecisionDto | undefined; | ||
@Input() showError = false; | ||
@Output() beforeDocumentUpload = new EventEmitter<boolean>(); | ||
|
||
displayedColumns: string[] = ['type', 'fileName', 'source', 'visibilityFlags', 'uploadedAt', 'actions']; | ||
private fileId = ''; | ||
areDocumentsReleased = false; | ||
|
||
@ViewChild(MatSort) sort!: MatSort; | ||
dataSource: MatTableDataSource<PlanningReviewDecisionDocumentDto> = | ||
new MatTableDataSource<PlanningReviewDecisionDocumentDto>(); | ||
|
||
constructor( | ||
private decisionService: PlanningReviewDecisionService, | ||
private dialog: MatDialog, | ||
private toastService: ToastService, | ||
private confirmationDialogService: ConfirmationDialogService, | ||
) {} | ||
|
||
async openFile(fileUuid: string, fileName: string) { | ||
if (this.decision) { | ||
await this.decisionService.downloadFile(this.decision.uuid, fileUuid, fileName); | ||
} | ||
} | ||
|
||
async downloadFile(fileUuid: string, fileName: string) { | ||
if (this.decision) { | ||
await this.decisionService.downloadFile(this.decision.uuid, fileUuid, fileName, false); | ||
} | ||
} | ||
|
||
async onUploadFile() { | ||
this.beforeDocumentUpload.emit(); | ||
this.openFileDialog(); | ||
} | ||
|
||
onEditFile(element: PlanningReviewDecisionDocumentDto) { | ||
this.openFileDialog(element); | ||
} | ||
|
||
private openFileDialog(existingDocument?: PlanningReviewDecisionDocumentDto) { | ||
if (this.decision) { | ||
this.dialog | ||
.open(DecisionDocumentUploadDialogComponent, { | ||
minWidth: '600px', | ||
maxWidth: '800px', | ||
width: '70%', | ||
data: { | ||
fileId: this.fileId, | ||
decisionUuid: this.decision?.uuid, | ||
existingDocument: existingDocument, | ||
}, | ||
}) | ||
.beforeClosed() | ||
.subscribe((isDirty: boolean) => { | ||
if (isDirty && this.decision) { | ||
this.decisionService.loadDecision(this.decision.uuid); | ||
} | ||
}); | ||
} | ||
} | ||
|
||
onDeleteFile(element: PlanningReviewDecisionDocumentDto) { | ||
this.confirmationDialogService | ||
.openDialog({ | ||
body: 'Are you sure you want to delete the selected file?', | ||
}) | ||
.subscribe(async (accepted) => { | ||
if (accepted && this.decision) { | ||
await this.decisionService.deleteFile(this.decision.uuid, element.uuid); | ||
await this.decisionService.loadDecision(this.decision.uuid); | ||
this.toastService.showSuccessToast('Document deleted'); | ||
} | ||
}); | ||
} | ||
|
||
ngOnDestroy(): void { | ||
this.$destroy.next(); | ||
this.$destroy.complete(); | ||
} | ||
|
||
ngOnChanges(changes: SimpleChanges): void { | ||
this.areDocumentsReleased = true; | ||
if (this.decision) { | ||
this.dataSource = new MatTableDataSource(this.decision.documents); | ||
} | ||
} | ||
} |
98 changes: 98 additions & 0 deletions
98
...decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
<div mat-dialog-title> | ||
<h4>{{ title }} Document</h4> | ||
</div> | ||
<div mat-dialog-content> | ||
<form class="form" [formGroup]="form"> | ||
<div class="double"> | ||
<div> | ||
<mat-label>Document Upload*</mat-label> | ||
</div> | ||
<input hidden type="file" #fileInput (change)="uploadFile($event)" placeholder="Upload file" /> | ||
<button | ||
*ngIf="!pendingFile && !existingFile" | ||
class="full-width upload-button" | ||
mat-flat-button | ||
color="accent" | ||
[ngClass]="{ | ||
error: showVirusError | ||
}" | ||
(click)="fileInput.click()" | ||
> | ||
Upload | ||
</button> | ||
<div class="file" *ngIf="pendingFile"> | ||
<div> | ||
<a (click)="openFile()">{{ pendingFile.name }}</a> | ||
({{ pendingFile.size | filesize }}) | ||
</div> | ||
<button [disabled]="!allowsFileEdit" (click)="onRemoveFile()" mat-button> | ||
<mat-icon>close</mat-icon>Remove | ||
</button> | ||
</div> | ||
<div class="file" *ngIf="existingFile"> | ||
<div> | ||
<a (click)="openExistingFile()">{{ existingFile }}</a> | ||
</div> | ||
<button [disabled]="!allowsFileEdit" (click)="onRemoveFile()" mat-button> | ||
<mat-icon>close</mat-icon>Remove | ||
</button> | ||
</div> | ||
<mat-error class="left" style="display: flex" *ngIf="showVirusError"> | ||
<mat-icon>warning</mat-icon> A virus was detected in the file. Choose another file and try again. | ||
</mat-error> | ||
</div> | ||
|
||
<div class="double"> | ||
<mat-form-field class="full-width" appearance="outline"> | ||
<mat-label>Document Name</mat-label> | ||
<input required matInput id="name" [formControl]="name" name="name" /> | ||
</mat-form-field> | ||
</div> | ||
|
||
<div> | ||
<ng-select | ||
appearance="outline" | ||
required | ||
placeholder="Document Type*" | ||
[ngModelOptions]="{ standalone: true }" | ||
[(ngModel)]="documentType" | ||
disabled="true" | ||
> | ||
</ng-select> | ||
</div> | ||
<div> | ||
<mat-form-field class="full-width" appearance="outline"> | ||
<mat-label>Source</mat-label> | ||
<mat-select [formControl]="source"> | ||
<mat-option *ngFor="let source of documentSources" [value]="source">{{ source }}</mat-option> | ||
</mat-select> | ||
</mat-form-field> | ||
</div> | ||
<div class="double"> | ||
<mat-label>Visible To:</mat-label> | ||
<div> | ||
<mat-checkbox [formControl]="visibleToComissioner">Commissioner</mat-checkbox> | ||
</div> | ||
</div> | ||
</form> | ||
|
||
<mat-dialog-actions align="end"> | ||
<div class="button-container"> | ||
<button type="button" mat-stroked-button color="primary" [mat-dialog-close]="false">Close</button> | ||
<button | ||
*ngIf="!isSaving" | ||
type="button" | ||
mat-flat-button | ||
color="primary" | ||
[disabled]="!form.valid || (!pendingFile && !existingFile)" | ||
(click)="onSubmit()" | ||
> | ||
Save | ||
</button> | ||
<button *ngIf="isSaving" type="button" mat-flat-button color="primary" [disabled]="true"> | ||
<mat-spinner class="spinner" diameter="20"></mat-spinner> | ||
Uploading | ||
</button> | ||
</div> | ||
</mat-dialog-actions> | ||
</div> |
Oops, something went wrong.