From 748fb375118981f19220f4cf0810196412ec0466 Mon Sep 17 00:00:00 2001 From: tanshu Date: Mon, 11 Jan 2021 10:34:47 +0530 Subject: [PATCH] Case Sources added primarily to filter the kind of cases in case list. --- .../versions/87a06eaadd34_finish_import.py | 5 + luthor/luthor/models/case.py | 4 +- luthor/luthor/routers/case.py | 5 + luthor/luthor/routers/case_source.py | 10 +- otis/src/app/app-routing.module.ts | 4 + .../case-source-detail.component.css | 3 + .../case-source-detail.component.html | 50 +++++++++ .../case-source-detail.component.spec.ts | 26 +++++ .../case-source-detail.component.ts | 102 ++++++++++++++++++ .../case-source-list-resolver.service.spec.ts | 15 +++ .../case-source-list-resolver.service.ts | 18 ++++ .../case-source-list-datasource.ts | 16 +++ .../case-source-list.component.css | 0 .../case-source-list.component.html | 29 +++++ .../case-source-list.component.spec.ts | 22 ++++ .../case-source-list.component.ts | 28 +++++ .../case-source-resolver.service.spec.ts | 15 +++ .../case-source-resolver.service.ts | 19 ++++ .../case-sources/case-source.service.spec.ts | 15 +++ .../app/case-sources/case-source.service.ts | 58 ++++++++++ .../case-sources-routing.module.spec.ts | 13 +++ .../case-sources-routing.module.ts | 53 +++++++++ .../case-sources/case-sources.module.spec.ts | 13 +++ .../app/case-sources/case-sources.module.ts | 33 ++++++ .../app/cases/case-list-resolver.service.ts | 2 +- .../cases/case-list/case-list-datasource.ts | 37 ++++++- .../cases/case-list/case-list.component.html | 26 +++++ .../cases/case-list/case-list.component.ts | 35 ++++-- otis/src/app/cases/case.service.ts | 5 +- otis/src/app/cases/cases-routing.module.ts | 2 + otis/src/app/cases/cases.module.ts | 30 +++--- otis/src/app/core/case-source.ts | 12 +++ otis/src/app/nav-bar/nav-bar.component.html | 1 + 33 files changed, 673 insertions(+), 33 deletions(-) create mode 100644 otis/src/app/case-sources/case-source-detail/case-source-detail.component.css create mode 100644 otis/src/app/case-sources/case-source-detail/case-source-detail.component.html create mode 100644 otis/src/app/case-sources/case-source-detail/case-source-detail.component.spec.ts create mode 100644 otis/src/app/case-sources/case-source-detail/case-source-detail.component.ts create mode 100644 otis/src/app/case-sources/case-source-list-resolver.service.spec.ts create mode 100644 otis/src/app/case-sources/case-source-list-resolver.service.ts create mode 100644 otis/src/app/case-sources/case-source-list/case-source-list-datasource.ts create mode 100644 otis/src/app/case-sources/case-source-list/case-source-list.component.css create mode 100644 otis/src/app/case-sources/case-source-list/case-source-list.component.html create mode 100644 otis/src/app/case-sources/case-source-list/case-source-list.component.spec.ts create mode 100644 otis/src/app/case-sources/case-source-list/case-source-list.component.ts create mode 100644 otis/src/app/case-sources/case-source-resolver.service.spec.ts create mode 100644 otis/src/app/case-sources/case-source-resolver.service.ts create mode 100644 otis/src/app/case-sources/case-source.service.spec.ts create mode 100644 otis/src/app/case-sources/case-source.service.ts create mode 100644 otis/src/app/case-sources/case-sources-routing.module.spec.ts create mode 100644 otis/src/app/case-sources/case-sources-routing.module.ts create mode 100644 otis/src/app/case-sources/case-sources.module.spec.ts create mode 100644 otis/src/app/case-sources/case-sources.module.ts create mode 100644 otis/src/app/core/case-source.ts diff --git a/luthor/alembic/versions/87a06eaadd34_finish_import.py b/luthor/alembic/versions/87a06eaadd34_finish_import.py index 805fb17..07a0a9b 100644 --- a/luthor/alembic/versions/87a06eaadd34_finish_import.py +++ b/luthor/alembic/versions/87a06eaadd34_finish_import.py @@ -300,6 +300,11 @@ def update_auth(): .where(permissions.c.name == op.inline_literal("ContactPersons")) .values({"name": op.inline_literal("Contacts")}) ) + op.execute( + permissions.update() + .where(permissions.c.name == op.inline_literal("AllowFeeMenu")) + .values({"name": op.inline_literal("Case Sources")}) + ) def update_hearings(): diff --git a/luthor/luthor/models/case.py b/luthor/luthor/models/case.py index b6be282..c347f05 100644 --- a/luthor/luthor/models/case.py +++ b/luthor/luthor/models/case.py @@ -94,7 +94,7 @@ class Case(Base): court_status_id=None, case_source_id=None, is_deleted=None, - id=None, + id_=None, ): self.office_file_number = office_file_number self.court_case_number = court_case_number @@ -127,4 +127,4 @@ class Case(Base): self.court_status_id = court_status_id self.is_deleted = False if is_deleted is None else is_deleted self.case_source_id = case_source_id - self.id = id + self.id = id_ diff --git a/luthor/luthor/routers/case.py b/luthor/luthor/routers/case.py index 5e82c27..2d7eb93 100644 --- a/luthor/luthor/routers/case.py +++ b/luthor/luthor/routers/case.py @@ -164,6 +164,11 @@ def show_list(db: Session = Depends(get_db), user: UserToken = Depends(get_user) return [case_info(item) for item in db.query(Case).order_by(desc(Case.receipt_date)).all()] +@router.get("/list/{source_id}", response_model=List[schemas.Case]) +def show_list_of_source(source_id: uuid.UUID, db: Session = Depends(get_db), user: UserToken = Depends(get_user)) -> List[schemas.Case]: + return [case_info(item) for item in db.query(Case).filter(Case.case_source_id == source_id).order_by(desc(Case.receipt_date)).all()] + + @router.get("/{id_}", response_model=schemas.Case) def show_id( id_: uuid.UUID, diff --git a/luthor/luthor/routers/case_source.py b/luthor/luthor/routers/case_source.py index cfd661b..94d4c15 100644 --- a/luthor/luthor/routers/case_source.py +++ b/luthor/luthor/routers/case_source.py @@ -30,7 +30,7 @@ def get_db(): def save( data: schemas.CaseSourceIn, db: Session = Depends(get_db), - user: UserToken = Security(get_user, scopes=["case_sources"]), + user: UserToken = Security(get_user, scopes=["case-sources"]), ) -> schemas.CaseSource: try: item = CaseSource(name=data.name, prefix=data.prefix) @@ -53,7 +53,7 @@ def update( id_: uuid.UUID, data: schemas.CaseSourceIn, db: Session = Depends(get_db), - user: UserToken = Security(get_user, scopes=["case_sources"]), + user: UserToken = Security(get_user, scopes=["case-sources"]), ) -> schemas.CaseSource: try: item: CaseSource = db.query(CaseSource).filter(CaseSource.id == id_).first() @@ -76,7 +76,7 @@ def update( def delete( id_: uuid.UUID, db: Session = Depends(get_db), - user: UserToken = Security(get_user, scopes=["case_sources"]), + user: UserToken = Security(get_user, scopes=["case-sources"]), ) -> schemas.CaseSourceBlank: try: item: CaseSource = db.query(CaseSource).filter(CaseSource.id == id_).first() @@ -97,7 +97,7 @@ def delete( @router.get("", response_model=schemas.CaseSourceBlank) def show_blank( db: Session = Depends(get_db), - user: UserToken = Security(get_user, scopes=["case_sources"]), + user: UserToken = Security(get_user, scopes=["case-sources"]), ) -> schemas.CaseSourceBlank: return case_source_blank() @@ -111,7 +111,7 @@ def show_list(db: Session = Depends(get_db), user: UserToken = Depends(get_user) def show_id( id_: uuid.UUID, db: Session = Depends(get_db), - user: UserToken = Security(get_user, scopes=["case_sources"]), + user: UserToken = Security(get_user, scopes=["case-sources"]), ) -> schemas.CaseSource: item: CaseSource = db.query(CaseSource).filter(CaseSource.id == id_).first() return case_source_info(item) diff --git a/otis/src/app/app-routing.module.ts b/otis/src/app/app-routing.module.ts index ce5236d..b43ad47 100644 --- a/otis/src/app/app-routing.module.ts +++ b/otis/src/app/app-routing.module.ts @@ -14,6 +14,10 @@ const routes: Routes = [ path: 'advocates', loadChildren: () => import('./advocates/advocates.module').then((mod) => mod.AdvocatesModule), }, + { + path: 'case-sources', + loadChildren: () => import('./case-sources/case-sources.module').then((mod) => mod.CaseSourcesModule), + }, { path: 'case-types', loadChildren: () => import('./case-types/case-types.module').then((mod) => mod.CaseTypesModule), diff --git a/otis/src/app/case-sources/case-source-detail/case-source-detail.component.css b/otis/src/app/case-sources/case-source-detail/case-source-detail.component.css new file mode 100644 index 0000000..12052db --- /dev/null +++ b/otis/src/app/case-sources/case-source-detail/case-source-detail.component.css @@ -0,0 +1,3 @@ +.right-align { + text-align: right; +} diff --git a/otis/src/app/case-sources/case-source-detail/case-source-detail.component.html b/otis/src/app/case-sources/case-source-detail/case-source-detail.component.html new file mode 100644 index 0000000..af7aad7 --- /dev/null +++ b/otis/src/app/case-sources/case-source-detail/case-source-detail.component.html @@ -0,0 +1,50 @@ +
+ + + Case Source + + +
+
+ + Name + + +
+
+ + Prefix + + +
+
+
+ + + + +
+
diff --git a/otis/src/app/case-sources/case-source-detail/case-source-detail.component.spec.ts b/otis/src/app/case-sources/case-source-detail/case-source-detail.component.spec.ts new file mode 100644 index 0000000..bd4a2f5 --- /dev/null +++ b/otis/src/app/case-sources/case-source-detail/case-source-detail.component.spec.ts @@ -0,0 +1,26 @@ +import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; + +import { CaseSourceDetailComponent } from './case-source-detail.component'; + +describe('CaseSourceDetailComponent', () => { + let component: CaseSourceDetailComponent; + let fixture: ComponentFixture; + + beforeEach( + waitForAsync(() => { + TestBed.configureTestingModule({ + declarations: [CaseSourceDetailComponent], + }).compileComponents(); + }), + ); + + beforeEach(() => { + fixture = TestBed.createComponent(CaseSourceDetailComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/otis/src/app/case-sources/case-source-detail/case-source-detail.component.ts b/otis/src/app/case-sources/case-source-detail/case-source-detail.component.ts new file mode 100644 index 0000000..1ed192c --- /dev/null +++ b/otis/src/app/case-sources/case-source-detail/case-source-detail.component.ts @@ -0,0 +1,102 @@ +import { AfterViewInit, Component, ElementRef, OnInit, ViewChild } from '@angular/core'; +import { FormBuilder, FormGroup } from '@angular/forms'; +import { MatDialog } from '@angular/material/dialog'; +import { ActivatedRoute, Router } from '@angular/router'; + +import { CaseSource } from '../../core/case-source'; +import { ToasterService } from '../../core/toaster.service'; +import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component'; +import { CaseSourceService } from '../case-source.service'; + +@Component({ + selector: 'app-case-source-detail', + templateUrl: './case-source-detail.component.html', + styleUrls: ['./case-source-detail.component.css'], +}) +export class CaseSourceDetailComponent implements OnInit, AfterViewInit { + @ViewChild('nameElement', { static: true }) nameElement?: ElementRef; + form: FormGroup; + item: CaseSource = new CaseSource(); + + constructor( + private route: ActivatedRoute, + private router: Router, + private dialog: MatDialog, + private fb: FormBuilder, + private toaster: ToasterService, + private ser: CaseSourceService, + ) { + // Create form + this.form = this.fb.group({ + name: '', + prefix: '', + }); + } + + ngOnInit() { + this.route.data.subscribe((value) => { + const data = value as { item: CaseSource }; + this.showItem(data.item); + }); + } + + showItem(item: CaseSource) { + this.item = item; + this.form.setValue({ + name: this.item.name || '', + prefix: this.item.prefix, + }); + } + + ngAfterViewInit() { + setTimeout(() => { + if (this.nameElement !== undefined) { + this.nameElement.nativeElement.focus(); + } + }, 0); + } + + save() { + this.ser.saveOrUpdate(this.getItem()).subscribe( + () => { + this.toaster.show('Success', ''); + this.router.navigateByUrl('/case-sources'); + }, + (error) => { + this.toaster.show('Error', error); + }, + ); + } + + delete() { + this.ser.delete(this.item.id as string).subscribe( + () => { + this.toaster.show('Success', ''); + this.router.navigateByUrl('/case-sources'); + }, + (error) => { + this.toaster.show('Error', error); + }, + ); + } + + confirmDelete(): void { + const dialogRef = this.dialog.open(ConfirmDialogComponent, { + width: '250px', + data: { title: 'Delete Case Source?', content: 'Are you sure? This cannot be undone.' }, + }); + + dialogRef.afterClosed().subscribe((result: boolean) => { + if (result) { + this.delete(); + } + }); + } + + getItem(): CaseSource { + const formModel = this.form.value; + this.item.name = formModel.name; + this.item.prefix = formModel.prefix; + return this.item; + } +} diff --git a/otis/src/app/case-sources/case-source-list-resolver.service.spec.ts b/otis/src/app/case-sources/case-source-list-resolver.service.spec.ts new file mode 100644 index 0000000..2631f0c --- /dev/null +++ b/otis/src/app/case-sources/case-source-list-resolver.service.spec.ts @@ -0,0 +1,15 @@ +import { inject, TestBed } from '@angular/core/testing'; + +import { CaseSourceListResolver } from './case-source-list-resolver.service'; + +describe('CaseSourceListResolverService', () => { + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [CaseSourceListResolver], + }); + }); + + it('should be created', inject([CaseSourceListResolver], (service: CaseSourceListResolver) => { + expect(service).toBeTruthy(); + })); +}); diff --git a/otis/src/app/case-sources/case-source-list-resolver.service.ts b/otis/src/app/case-sources/case-source-list-resolver.service.ts new file mode 100644 index 0000000..24547cd --- /dev/null +++ b/otis/src/app/case-sources/case-source-list-resolver.service.ts @@ -0,0 +1,18 @@ +import { Injectable } from '@angular/core'; +import { Resolve } from '@angular/router'; +import { Observable } from 'rxjs/internal/Observable'; + +import { CaseSource } from '../core/case-source'; + +import { CaseSourceService } from './case-source.service'; + +@Injectable({ + providedIn: 'root', +}) +export class CaseSourceListResolver implements Resolve { + constructor(private ser: CaseSourceService) {} + + resolve(): Observable { + return this.ser.list(); + } +} diff --git a/otis/src/app/case-sources/case-source-list/case-source-list-datasource.ts b/otis/src/app/case-sources/case-source-list/case-source-list-datasource.ts new file mode 100644 index 0000000..a5bdfe3 --- /dev/null +++ b/otis/src/app/case-sources/case-source-list/case-source-list-datasource.ts @@ -0,0 +1,16 @@ +import { DataSource } from '@angular/cdk/collections'; +import { Observable, of as observableOf } from 'rxjs'; + +import { CaseSource } from '../../core/case-source'; + +export class CaseSourceListDataSource extends DataSource { + constructor(public data: CaseSource[]) { + super(); + } + + connect(): Observable { + return observableOf(this.data); + } + + disconnect() {} +} diff --git a/otis/src/app/case-sources/case-source-list/case-source-list.component.css b/otis/src/app/case-sources/case-source-list/case-source-list.component.css new file mode 100644 index 0000000..e69de29 diff --git a/otis/src/app/case-sources/case-source-list/case-source-list.component.html b/otis/src/app/case-sources/case-source-list/case-source-list.component.html new file mode 100644 index 0000000..b1abe0b --- /dev/null +++ b/otis/src/app/case-sources/case-source-list/case-source-list.component.html @@ -0,0 +1,29 @@ + + + Case Sources + + add_box + Add + + + + + + + Name + {{ row.name }} + + + + + Prefix + {{ row.prefix }} + + + + + + + diff --git a/otis/src/app/case-sources/case-source-list/case-source-list.component.spec.ts b/otis/src/app/case-sources/case-source-list/case-source-list.component.spec.ts new file mode 100644 index 0000000..bff9084 --- /dev/null +++ b/otis/src/app/case-sources/case-source-list/case-source-list.component.spec.ts @@ -0,0 +1,22 @@ +import { ComponentFixture, fakeAsync, TestBed } from '@angular/core/testing'; + +import { CaseSourceListComponent } from './case-source-list.component'; + +describe('CaseSourceListComponent', () => { + let component: CaseSourceListComponent; + let fixture: ComponentFixture; + + beforeEach(fakeAsync(() => { + TestBed.configureTestingModule({ + declarations: [CaseSourceListComponent], + }).compileComponents(); + + fixture = TestBed.createComponent(CaseSourceListComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + })); + + it('should compile', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/otis/src/app/case-sources/case-source-list/case-source-list.component.ts b/otis/src/app/case-sources/case-source-list/case-source-list.component.ts new file mode 100644 index 0000000..b262892 --- /dev/null +++ b/otis/src/app/case-sources/case-source-list/case-source-list.component.ts @@ -0,0 +1,28 @@ +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; + +import { CaseSource } from '../../core/case-source'; + +import { CaseSourceListDataSource } from './case-source-list-datasource'; + +@Component({ + selector: 'app-case-source-list', + templateUrl: './case-source-list.component.html', + styleUrls: ['./case-source-list.component.css'], +}) +export class CaseSourceListComponent implements OnInit { + list: CaseSource[] = []; + dataSource: CaseSourceListDataSource = new CaseSourceListDataSource(this.list); + /** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */ + displayedColumns = ['name', 'prefix']; + + constructor(private route: ActivatedRoute) {} + + ngOnInit() { + this.route.data.subscribe((value) => { + const data = value as { list: CaseSource[] }; + this.list = data.list; + }); + this.dataSource = new CaseSourceListDataSource(this.list); + } +} diff --git a/otis/src/app/case-sources/case-source-resolver.service.spec.ts b/otis/src/app/case-sources/case-source-resolver.service.spec.ts new file mode 100644 index 0000000..c8b2266 --- /dev/null +++ b/otis/src/app/case-sources/case-source-resolver.service.spec.ts @@ -0,0 +1,15 @@ +import { inject, TestBed } from '@angular/core/testing'; + +import { CaseSourceResolver } from './case-source-resolver.service'; + +describe('CaseSourceResolver', () => { + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [CaseSourceResolver], + }); + }); + + it('should be created', inject([CaseSourceResolver], (service: CaseSourceResolver) => { + expect(service).toBeTruthy(); + })); +}); diff --git a/otis/src/app/case-sources/case-source-resolver.service.ts b/otis/src/app/case-sources/case-source-resolver.service.ts new file mode 100644 index 0000000..9a4dd54 --- /dev/null +++ b/otis/src/app/case-sources/case-source-resolver.service.ts @@ -0,0 +1,19 @@ +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, Resolve } from '@angular/router'; +import { Observable } from 'rxjs/internal/Observable'; + +import { CaseSource } from '../core/case-source'; + +import { CaseSourceService } from './case-source.service'; + +@Injectable({ + providedIn: 'root', +}) +export class CaseSourceResolver implements Resolve { + constructor(private ser: CaseSourceService) {} + + resolve(route: ActivatedRouteSnapshot): Observable { + const id = route.paramMap.get('id'); + return this.ser.get(id); + } +} diff --git a/otis/src/app/case-sources/case-source.service.spec.ts b/otis/src/app/case-sources/case-source.service.spec.ts new file mode 100644 index 0000000..d0178d8 --- /dev/null +++ b/otis/src/app/case-sources/case-source.service.spec.ts @@ -0,0 +1,15 @@ +import { inject, TestBed } from '@angular/core/testing'; + +import { CaseSourceService } from './case-source.service'; + +describe('CaseSourceService', () => { + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [CaseSourceService], + }); + }); + + it('should be created', inject([CaseSourceService], (service: CaseSourceService) => { + expect(service).toBeTruthy(); + })); +}); diff --git a/otis/src/app/case-sources/case-source.service.ts b/otis/src/app/case-sources/case-source.service.ts new file mode 100644 index 0000000..c4f946d --- /dev/null +++ b/otis/src/app/case-sources/case-source.service.ts @@ -0,0 +1,58 @@ +import { HttpClient, HttpHeaders } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs/internal/Observable'; +import { catchError } from 'rxjs/operators'; + +import { CaseSource } from '../core/case-source'; +import { ErrorLoggerService } from '../core/error-logger.service'; + +const httpOptions = { + headers: new HttpHeaders({ 'Content-Type': 'application/json' }), +}; +const url = '/api/case-sources'; +const serviceName = 'CaseSourceService'; + +@Injectable({ + providedIn: 'root', +}) +export class CaseSourceService { + constructor(private http: HttpClient, private log: ErrorLoggerService) {} + + get(id: string | null): Observable { + const getUrl: string = id === null ? url : `${url}/${id}`; + return this.http + .get(getUrl) + .pipe(catchError(this.log.handleError(serviceName, `get id=${id}`))) as Observable; + } + + list(): Observable { + return this.http + .get(`${url}/list`) + .pipe(catchError(this.log.handleError(serviceName, 'list'))) as Observable; + } + + save(caseSource: CaseSource): Observable { + return this.http + .post(url, caseSource, httpOptions) + .pipe(catchError(this.log.handleError(serviceName, 'save'))) as Observable; + } + + update(caseSource: CaseSource): Observable { + return this.http + .put(`${url}/${caseSource.id}`, caseSource, httpOptions) + .pipe(catchError(this.log.handleError(serviceName, 'update'))) as Observable; + } + + saveOrUpdate(caseSource: CaseSource): Observable { + if (!caseSource.id) { + return this.save(caseSource); + } + return this.update(caseSource); + } + + delete(id: string): Observable { + return this.http + .delete(`${url}/${id}`, httpOptions) + .pipe(catchError(this.log.handleError(serviceName, 'delete'))) as Observable; + } +} diff --git a/otis/src/app/case-sources/case-sources-routing.module.spec.ts b/otis/src/app/case-sources/case-sources-routing.module.spec.ts new file mode 100644 index 0000000..3569587 --- /dev/null +++ b/otis/src/app/case-sources/case-sources-routing.module.spec.ts @@ -0,0 +1,13 @@ +import { CaseSourcesRoutingModule } from './case-sources-routing.module'; + +describe('CasesRoutingModule', () => { + let caseSourcesRoutingModule: CaseSourcesRoutingModule; + + beforeEach(() => { + caseSourcesRoutingModule = new CaseSourcesRoutingModule(); + }); + + it('should create an instance', () => { + expect(caseSourcesRoutingModule).toBeTruthy(); + }); +}); diff --git a/otis/src/app/case-sources/case-sources-routing.module.ts b/otis/src/app/case-sources/case-sources-routing.module.ts new file mode 100644 index 0000000..e9615b7 --- /dev/null +++ b/otis/src/app/case-sources/case-sources-routing.module.ts @@ -0,0 +1,53 @@ +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { AuthGuard } from '../auth/auth-guard.service'; + +import { CaseSourceDetailComponent } from './case-source-detail/case-source-detail.component'; +import { CaseSourceListResolver } from './case-source-list-resolver.service'; +import { CaseSourceListComponent } from './case-source-list/case-source-list.component'; +import { CaseSourceResolver } from './case-source-resolver.service'; + +const caseSourcesRoutes: Routes = [ + { + path: '', + component: CaseSourceListComponent, + canActivate: [AuthGuard], + data: { + permission: 'Case Sources', + }, + resolve: { + list: CaseSourceListResolver, + }, + }, + { + path: 'new', + component: CaseSourceDetailComponent, + canActivate: [AuthGuard], + data: { + permission: 'Case Sources', + }, + resolve: { + item: CaseSourceResolver, + }, + }, + { + path: ':id', + component: CaseSourceDetailComponent, + canActivate: [AuthGuard], + data: { + permission: 'Case Sources', + }, + resolve: { + item: CaseSourceResolver, + }, + }, +]; + +@NgModule({ + imports: [CommonModule, RouterModule.forChild(caseSourcesRoutes)], + exports: [RouterModule], + providers: [CaseSourceListResolver, CaseSourceResolver], +}) +export class CaseSourcesRoutingModule {} diff --git a/otis/src/app/case-sources/case-sources.module.spec.ts b/otis/src/app/case-sources/case-sources.module.spec.ts new file mode 100644 index 0000000..2fe98a5 --- /dev/null +++ b/otis/src/app/case-sources/case-sources.module.spec.ts @@ -0,0 +1,13 @@ +import { CaseSourcesModule } from './case-sources.module'; + +describe('CaseSourcesModule', () => { + let caseSourcesModule: CaseSourcesModule; + + beforeEach(() => { + caseSourcesModule = new CaseSourcesModule(); + }); + + it('should create an instance', () => { + expect(caseSourcesModule).toBeTruthy(); + }); +}); diff --git a/otis/src/app/case-sources/case-sources.module.ts b/otis/src/app/case-sources/case-sources.module.ts new file mode 100644 index 0000000..3f872c4 --- /dev/null +++ b/otis/src/app/case-sources/case-sources.module.ts @@ -0,0 +1,33 @@ +import { CdkTableModule } from '@angular/cdk/table'; +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { FlexLayoutModule } from '@angular/flex-layout'; +import { ReactiveFormsModule } from '@angular/forms'; +import { MatButtonModule } from '@angular/material/button'; +import { MatCardModule } from '@angular/material/card'; +import { MatIconModule } from '@angular/material/icon'; +import { MatInputModule } from '@angular/material/input'; +import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; +import { MatTableModule } from '@angular/material/table'; + +import { CaseSourceDetailComponent } from './case-source-detail/case-source-detail.component'; +import { CaseSourceListComponent } from './case-source-list/case-source-list.component'; +import { CaseSourcesRoutingModule } from './case-sources-routing.module'; + +@NgModule({ + imports: [ + CommonModule, + CdkTableModule, + FlexLayoutModule, + MatButtonModule, + MatCardModule, + MatIconModule, + MatInputModule, + MatProgressSpinnerModule, + MatTableModule, + ReactiveFormsModule, + CaseSourcesRoutingModule, + ], + declarations: [CaseSourceListComponent, CaseSourceDetailComponent], +}) +export class CaseSourcesModule {} diff --git a/otis/src/app/cases/case-list-resolver.service.ts b/otis/src/app/cases/case-list-resolver.service.ts index 3fcef70..5367f06 100644 --- a/otis/src/app/cases/case-list-resolver.service.ts +++ b/otis/src/app/cases/case-list-resolver.service.ts @@ -13,6 +13,6 @@ export class CaseListResolver implements Resolve { constructor(private ser: CaseService) {} resolve(): Observable { - return this.ser.list(); + return this.ser.list(null); } } diff --git a/otis/src/app/cases/case-list/case-list-datasource.ts b/otis/src/app/cases/case-list/case-list-datasource.ts index 9a69e46..77aa725 100644 --- a/otis/src/app/cases/case-list/case-list-datasource.ts +++ b/otis/src/app/cases/case-list/case-list-datasource.ts @@ -1,16 +1,47 @@ import { DataSource } from '@angular/cdk/collections'; -import { Observable, of as observableOf } from 'rxjs'; +import {merge, Observable, of as observableOf} from 'rxjs'; import { Case } from '../../core/case'; +import {MatPaginator, PageEvent} from "@angular/material/paginator"; +import {EventEmitter} from "@angular/core"; +import {map, tap} from "rxjs/operators"; export class CaseListDataSource extends DataSource { - constructor(public data: Case[]) { + private dataValues: Case[] = []; + private data: Observable = new Observable(); + constructor(public d: Observable, private paginator?: MatPaginator) { super(); + this.data = d.pipe(tap(x=> this.dataValues = x)); } connect(): Observable { - return observableOf(this.data); + const dataMutations: ( + | Observable + | EventEmitter + )[] = [this.data]; + if (this.paginator) { + dataMutations.push((this.paginator as MatPaginator).page); + } + + return merge(...dataMutations) + .pipe( + tap((x: Case[]) => { + if (this.paginator) { + this.paginator.length = x.length; + } + }), + ) + .pipe(map((x: Case[]) => this.getPagedData(this.dataValues))); } disconnect() {} + + private getPagedData(data: Case[]) { + if (this.paginator === undefined) { + return data; + } + const startIndex = this.paginator.pageIndex * this.paginator.pageSize; + return data.slice(startIndex, startIndex + this.paginator.pageSize); + } + } diff --git a/otis/src/app/cases/case-list/case-list.component.html b/otis/src/app/cases/case-list/case-list.component.html index 58f2eb0..a7ce67a 100644 --- a/otis/src/app/cases/case-list/case-list.component.html +++ b/otis/src/app/cases/case-list/case-list.component.html @@ -7,6 +7,24 @@ +
+
+ + Case Source + + + {{ cs.name }} + + + +
+
@@ -93,5 +111,13 @@ + +
diff --git a/otis/src/app/cases/case-list/case-list.component.ts b/otis/src/app/cases/case-list/case-list.component.ts index e527f7c..5ad1872 100644 --- a/otis/src/app/cases/case-list/case-list.component.ts +++ b/otis/src/app/cases/case-list/case-list.component.ts @@ -1,9 +1,15 @@ -import { Component, OnInit } from '@angular/core'; +import {Component, OnInit, ViewChild} from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { Case } from '../../core/case'; import { CaseListDataSource } from './case-list-datasource'; +import {CaseSource} from "../../core/case-source"; +import {FormBuilder, FormControl, FormGroup} from "@angular/forms"; +import {distinctUntilChanged, startWith, switchMap, tap} from "rxjs/operators"; +import {CaseService} from "../case.service"; +import { Observable, of as observableOf } from 'rxjs'; +import {MatPaginator} from "@angular/material/paginator"; @Component({ selector: 'app-case-list', @@ -11,7 +17,10 @@ import { CaseListDataSource } from './case-list-datasource'; styleUrls: ['./case-list.component.css'], }) export class CaseListComponent implements OnInit { - list: Case[] = []; + @ViewChild(MatPaginator, { static: true }) paginator?: MatPaginator; + form: FormGroup; + caseSources: CaseSource[] = []; + list: Observable = new Observable(); dataSource: CaseListDataSource = new CaseListDataSource(this.list); /** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */ displayedColumns = [ @@ -30,13 +39,27 @@ export class CaseListComponent implements OnInit { 'lowerCourtCaseNumber', ]; - constructor(private route: ActivatedRoute) {} + constructor(private route: ActivatedRoute, private fb: FormBuilder, private ser: CaseService) { + // Create form + this.form = this.fb.group({ + caseSource: '', + }); + } ngOnInit() { this.route.data.subscribe((value) => { - const data = value as { list: Case[] }; - this.list = data.list; + const data = value as { list: Case[]; caseSources: CaseSource[] }; + this.caseSources = data.caseSources; + this.list = observableOf(data.list); + + this.list = (this.form.get('caseSource') as FormControl).valueChanges.pipe( + startWith(''), + distinctUntilChanged(), + switchMap((x) => this.ser.list(x)), + tap(x=>console.log(x)) + ); + }); - this.dataSource = new CaseListDataSource(this.list); + this.dataSource = new CaseListDataSource(this.list, this.paginator); } } diff --git a/otis/src/app/cases/case.service.ts b/otis/src/app/cases/case.service.ts index 1e9f893..6121283 100644 --- a/otis/src/app/cases/case.service.ts +++ b/otis/src/app/cases/case.service.ts @@ -25,9 +25,10 @@ export class CaseService { .pipe(catchError(this.log.handleError(serviceName, `get id=${id}`))) as Observable; } - list(): Observable { + list(caseSource: string | null): Observable { + const listUrl: string = caseSource === null ? `${url}/list` : `${url}/list/${caseSource}`; return this.http - .get(`${url}/list`) + .get(listUrl) .pipe(catchError(this.log.handleError(serviceName, 'list'))) as Observable; } diff --git a/otis/src/app/cases/cases-routing.module.ts b/otis/src/app/cases/cases-routing.module.ts index e1aaaaa..476b437 100644 --- a/otis/src/app/cases/cases-routing.module.ts +++ b/otis/src/app/cases/cases-routing.module.ts @@ -9,6 +9,7 @@ import { CaseDetailComponent } from './case-detail/case-detail.component'; import { CaseListResolver } from './case-list-resolver.service'; import { CaseListComponent } from './case-list/case-list.component'; import { CaseResolver } from './case-resolver.service'; +import {CaseSourceListResolver} from "../case-sources/case-source-list-resolver.service"; const advocatesRoutes: Routes = [ { @@ -19,6 +20,7 @@ const advocatesRoutes: Routes = [ permission: 'Cases', }, resolve: { + caseSources: CaseSourceListResolver, list: CaseListResolver, }, }, diff --git a/otis/src/app/cases/cases.module.ts b/otis/src/app/cases/cases.module.ts index 7ecf47d..0e98b09 100644 --- a/otis/src/app/cases/cases.module.ts +++ b/otis/src/app/cases/cases.module.ts @@ -14,22 +14,24 @@ import { MatTableModule } from '@angular/material/table'; import { CaseDetailComponent } from './case-detail/case-detail.component'; import { CaseListComponent } from './case-list/case-list.component'; import { CasesRoutingModule } from './cases-routing.module'; +import {MatPaginatorModule} from "@angular/material/paginator"; @NgModule({ - imports: [ - CommonModule, - CdkTableModule, - FlexLayoutModule, - MatButtonModule, - MatCardModule, - MatIconModule, - MatInputModule, - MatProgressSpinnerModule, - MatTableModule, - ReactiveFormsModule, - CasesRoutingModule, - MatSelectModule, - ], + imports: [ + CommonModule, + CdkTableModule, + FlexLayoutModule, + MatButtonModule, + MatCardModule, + MatIconModule, + MatInputModule, + MatProgressSpinnerModule, + MatTableModule, + ReactiveFormsModule, + CasesRoutingModule, + MatSelectModule, + MatPaginatorModule, + ], declarations: [CaseListComponent, CaseDetailComponent], }) export class CasesModule {} diff --git a/otis/src/app/core/case-source.ts b/otis/src/app/core/case-source.ts new file mode 100644 index 0000000..f903834 --- /dev/null +++ b/otis/src/app/core/case-source.ts @@ -0,0 +1,12 @@ +export class CaseSource { + id: string | undefined; + name: string; + prefix: string; + + public constructor(init?: Partial) { + this.id = undefined; + this.name = ''; + this.prefix = ''; + Object.assign(this, init); + } +} diff --git a/otis/src/app/nav-bar/nav-bar.component.html b/otis/src/app/nav-bar/nav-bar.component.html index a7ddec8..abba0f9 100644 --- a/otis/src/app/nav-bar/nav-bar.component.html +++ b/otis/src/app/nav-bar/nav-bar.component.html @@ -7,6 +7,7 @@ Acts Advocates + Case Sources Case Types Contacts Courts