From 120abcaf1d144f5f95f056243ecc999440d4ac09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Zieli=C5=84ski?= Date: Sun, 11 Dec 2022 23:40:16 +0100 Subject: [PATCH] WIP: DataSets Module --- Frontend/package-lock.json | 71 ++++++- Frontend/package.json | 5 +- Frontend/src/app/app-routing.module.ts | 4 + Frontend/src/app/app.module.ts | 11 +- Frontend/src/app/auth/auth.guard.ts | 6 +- Frontend/src/app/auth/auth.service.ts | 8 +- .../login-page/login-page.component.ts | 4 +- .../app/main-view/main-view.component.html | 16 +- .../src/app/main-view/main-view.component.ts | 9 +- Frontend/src/app/models/base.model.ts | 33 +++ Frontend/src/app/models/dataRow.model copy.ts | 26 +++ Frontend/src/app/models/dataSet.model.ts | 97 +++++++++ .../src/app/models/deserializable.model.ts | 3 + Frontend/src/app/models/serializable.model.ts | 3 + .../src/app/models/{user.ts => user.model.ts} | 0 .../data-set-detail.component.html | 1 + .../data-set-detail.component.scss | 0 .../data-set-detail.component.spec.ts | 23 +++ .../data-set-detail.component.ts | 10 + .../data-set-edit.component.html | 40 ++++ .../data-set-edit.component.scss | 1 + .../data-set-edit.component.spec.ts | 23 +++ .../data-set-edit/data-set-edit.component.ts | 68 +++++++ .../data-sets-list.component.html | 38 ++++ .../data-sets-list.component.scss | 1 + .../data-sets-list.component.spec.ts | 23 +++ .../data-sets-list.component.ts | 37 ++++ .../data-sets/data-sets-routing.module.ts | 17 ++ .../app/modules/data-sets/data-sets.module.ts | 24 +++ Frontend/src/app/services/data.service.ts | 3 +- Frontend/src/environments/environment.ts | 4 +- WebAPI/AppDbContext.cs | 2 + WebAPI/Controllers/DataSetsController.cs | 37 ++++ ...1211210507_DataSetsAndDataRows.Designer.cs | 192 ++++++++++++++++++ .../20221211210507_DataSetsAndDataRows.cs | 121 +++++++++++ .../Migrations/AppDbContextModelSnapshot.cs | 141 +++++++++++++ WebAPI/Models/DataRow.cs | 31 +++ WebAPI/Models/DataSet.cs | 25 +++ 38 files changed, 1123 insertions(+), 35 deletions(-) create mode 100644 Frontend/src/app/models/base.model.ts create mode 100644 Frontend/src/app/models/dataRow.model copy.ts create mode 100644 Frontend/src/app/models/dataSet.model.ts create mode 100644 Frontend/src/app/models/deserializable.model.ts create mode 100644 Frontend/src/app/models/serializable.model.ts rename Frontend/src/app/models/{user.ts => user.model.ts} (100%) create mode 100644 Frontend/src/app/modules/data-sets/data-set-detail/data-set-detail.component.html create mode 100644 Frontend/src/app/modules/data-sets/data-set-detail/data-set-detail.component.scss create mode 100644 Frontend/src/app/modules/data-sets/data-set-detail/data-set-detail.component.spec.ts create mode 100644 Frontend/src/app/modules/data-sets/data-set-detail/data-set-detail.component.ts create mode 100644 Frontend/src/app/modules/data-sets/data-set-edit/data-set-edit.component.html create mode 100644 Frontend/src/app/modules/data-sets/data-set-edit/data-set-edit.component.scss create mode 100644 Frontend/src/app/modules/data-sets/data-set-edit/data-set-edit.component.spec.ts create mode 100644 Frontend/src/app/modules/data-sets/data-set-edit/data-set-edit.component.ts create mode 100644 Frontend/src/app/modules/data-sets/data-sets-list/data-sets-list.component.html create mode 100644 Frontend/src/app/modules/data-sets/data-sets-list/data-sets-list.component.scss create mode 100644 Frontend/src/app/modules/data-sets/data-sets-list/data-sets-list.component.spec.ts create mode 100644 Frontend/src/app/modules/data-sets/data-sets-list/data-sets-list.component.ts create mode 100644 Frontend/src/app/modules/data-sets/data-sets-routing.module.ts create mode 100644 Frontend/src/app/modules/data-sets/data-sets.module.ts create mode 100644 WebAPI/Controllers/DataSetsController.cs create mode 100644 WebAPI/Migrations/20221211210507_DataSetsAndDataRows.Designer.cs create mode 100644 WebAPI/Migrations/20221211210507_DataSetsAndDataRows.cs create mode 100644 WebAPI/Models/DataRow.cs create mode 100644 WebAPI/Models/DataSet.cs diff --git a/Frontend/package-lock.json b/Frontend/package-lock.json index 627fd1a..e5a0998 100644 --- a/Frontend/package-lock.json +++ b/Frontend/package-lock.json @@ -1,12 +1,12 @@ { "name": "diuna", - "version": "0.0.2", + "version": "0.0.5", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "diuna", - "version": "0.0.2", + "version": "0.0.5", "dependencies": { "@abacritt/angularx-social-login": "^1.2.5", "@angular/animations": "^15.0.3", @@ -16,6 +16,7 @@ "@angular/core": "^15.0.3", "@angular/forms": "^15.0.3", "@angular/material": "^15.0.2", + "@angular/material-moment-adapter": "^15.0.2", "@angular/platform-browser": "^15.0.3", "@angular/platform-browser-dynamic": "^15.0.3", "@angular/pwa": "^15.0.3", @@ -24,6 +25,7 @@ "jwt-decode": "^3.1.2", "moment": "^2.29.4", "rxjs": "^7.6.0", + "uuid": "^9.0.0", "zone.js": "^0.12.0" }, "devDependencies": { @@ -31,6 +33,7 @@ "@angular/cli": "~15.0.3", "@angular/compiler-cli": "^15.0.3", "@types/jasmine": "^4.3.1", + "@types/uuid": "^9.0.0", "jasmine-core": "^4.5.0", "karma": "~6.4.0", "karma-chrome-launcher": "~3.1.0", @@ -651,6 +654,19 @@ "rxjs": "^6.5.3 || ^7.4.0" } }, + "node_modules/@angular/material-moment-adapter": { + "version": "15.0.2", + "resolved": "https://registry.npmjs.org/@angular/material-moment-adapter/-/material-moment-adapter-15.0.2.tgz", + "integrity": "sha512-d74B4DpZrT89F2EMYcaXcvjp+SJ3gNdI8dVY9iCLHuK3Zy1RN1q1DIlg4qMaZYA+fjmRSu0fh+elRRw6wTVPOQ==", + "dependencies": { + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/core": "^15.0.0 || ^16.0.0", + "@angular/material": "15.0.2", + "moment": "^2.18.1" + } + }, "node_modules/@angular/platform-browser": { "version": "15.0.3", "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-15.0.3.tgz", @@ -3753,6 +3769,12 @@ "@types/node": "*" } }, + "node_modules/@types/uuid": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-kr90f+ERiQtKWMz5rP32ltJ/BtULDI5RVO0uavn1HQUOwjx0R1h0rnDYNL0CepF1zL5bSY6FISAfd9tOdDhU5Q==", + "dev": true + }, "node_modules/@types/ws": { "version": "8.5.3", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", @@ -10663,6 +10685,15 @@ "websocket-driver": "^0.7.4" } }, + "node_modules/sockjs/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/socks": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", @@ -11394,10 +11425,9 @@ } }, "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true, + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", "bin": { "uuid": "dist/bin/uuid" } @@ -12339,6 +12369,14 @@ "tslib": "^2.3.0" } }, + "@angular/material-moment-adapter": { + "version": "15.0.2", + "resolved": "https://registry.npmjs.org/@angular/material-moment-adapter/-/material-moment-adapter-15.0.2.tgz", + "integrity": "sha512-d74B4DpZrT89F2EMYcaXcvjp+SJ3gNdI8dVY9iCLHuK3Zy1RN1q1DIlg4qMaZYA+fjmRSu0fh+elRRw6wTVPOQ==", + "requires": { + "tslib": "^2.3.0" + } + }, "@angular/platform-browser": { "version": "15.0.3", "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-15.0.3.tgz", @@ -14781,6 +14819,12 @@ "@types/node": "*" } }, + "@types/uuid": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-kr90f+ERiQtKWMz5rP32ltJ/BtULDI5RVO0uavn1HQUOwjx0R1h0rnDYNL0CepF1zL5bSY6FISAfd9tOdDhU5Q==", + "dev": true + }, "@types/ws": { "version": "8.5.3", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", @@ -19922,6 +19966,14 @@ "faye-websocket": "^0.11.3", "uuid": "^8.3.2", "websocket-driver": "^0.7.4" + }, + "dependencies": { + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true + } } }, "socks": { @@ -20456,10 +20508,9 @@ "dev": true }, "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==" }, "validate-npm-package-license": { "version": "3.0.4", diff --git a/Frontend/package.json b/Frontend/package.json index cbd8109..8efb561 100644 --- a/Frontend/package.json +++ b/Frontend/package.json @@ -18,6 +18,7 @@ "@angular/core": "^15.0.3", "@angular/forms": "^15.0.3", "@angular/material": "^15.0.2", + "@angular/material-moment-adapter": "^15.0.2", "@angular/platform-browser": "^15.0.3", "@angular/platform-browser-dynamic": "^15.0.3", "@angular/pwa": "^15.0.3", @@ -26,6 +27,7 @@ "jwt-decode": "^3.1.2", "moment": "^2.29.4", "rxjs": "^7.6.0", + "uuid": "^9.0.0", "zone.js": "^0.12.0" }, "devDependencies": { @@ -33,6 +35,7 @@ "@angular/cli": "~15.0.3", "@angular/compiler-cli": "^15.0.3", "@types/jasmine": "^4.3.1", + "@types/uuid": "^9.0.0", "jasmine-core": "^4.5.0", "karma": "~6.4.0", "karma-chrome-launcher": "~3.1.0", @@ -42,4 +45,4 @@ "tslib": "^2.4.1", "typescript": "^4.8.4" } -} \ No newline at end of file +} diff --git a/Frontend/src/app/app-routing.module.ts b/Frontend/src/app/app-routing.module.ts index b85b504..90530f7 100644 --- a/Frontend/src/app/app-routing.module.ts +++ b/Frontend/src/app/app-routing.module.ts @@ -18,6 +18,10 @@ const routes: Routes = [ path: '', loadChildren: () => import('./modules/dashboard/dashboard.module').then(m => m.DashboardModule) }, + { + path: 'datasets', + loadChildren: () => import('./modules/data-sets/data-sets.module').then(m => m.DataSetsModule) + }, ] } ]; diff --git a/Frontend/src/app/app.module.ts b/Frontend/src/app/app.module.ts index 26511ec..397f87e 100644 --- a/Frontend/src/app/app.module.ts +++ b/Frontend/src/app/app.module.ts @@ -1,6 +1,5 @@ -import { NgModule, isDevMode } from '@angular/core'; +import { NgModule, isDevMode, LOCALE_ID } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; - import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; @@ -11,7 +10,12 @@ import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; import { ServiceWorkerModule } from '@angular/service-worker'; import { LoaderInterceptor } from './interceptors/loader.interceptor'; import { AuthInterceptor } from './interceptors/auth.interceptor'; +import { DateAdapter, MAT_DATE_LOCALE } from '@angular/material/core'; +import { MAT_MOMENT_DATE_ADAPTER_OPTIONS, MomentDateAdapter } from '@angular/material-moment-adapter'; +import { registerLocaleData } from '@angular/common'; +import localePl from '@angular/common/locales/pl'; +registerLocaleData(localePl, 'pl-PL'); @NgModule({ declarations: [ @@ -33,6 +37,9 @@ import { AuthInterceptor } from './interceptors/auth.interceptor'; }) ], providers: [ + { provide: DateAdapter, useClass: MomentDateAdapter, deps: [MAT_DATE_LOCALE, MAT_MOMENT_DATE_ADAPTER_OPTIONS] }, + { provide: MAT_MOMENT_DATE_ADAPTER_OPTIONS, useValue: { useUtc: true } }, + { provide: LOCALE_ID, useValue: 'pl-PL' }, { provide: HTTP_INTERCEPTORS, useClass: LoaderInterceptor, diff --git a/Frontend/src/app/auth/auth.guard.ts b/Frontend/src/app/auth/auth.guard.ts index 460e2f1..5e2f7b1 100644 --- a/Frontend/src/app/auth/auth.guard.ts +++ b/Frontend/src/app/auth/auth.guard.ts @@ -1,21 +1,21 @@ import { Injectable } from '@angular/core'; import { ActivatedRouteSnapshot, CanActivate, CanActivateChild, Router, RouterStateSnapshot, UrlTree } from '@angular/router'; import { Observable } from 'rxjs'; -import { DataService } from '../services/data.service'; +import { AuthService } from './auth.service'; @Injectable({ providedIn: 'root' }) export class AuthGuard implements CanActivate { constructor( - private data$: DataService, + private auth$: AuthService, private router$: Router ) {} canActivate( route: ActivatedRouteSnapshot, state: RouterStateSnapshot, ): Observable | Promise | boolean | UrlTree { - if (this.data$.currentUser) { + if (this.auth$.user && this.auth$.user.googleCredentials) { return true; } else { this.router$.navigate(['']); diff --git a/Frontend/src/app/auth/auth.service.ts b/Frontend/src/app/auth/auth.service.ts index f712342..660b6e5 100644 --- a/Frontend/src/app/auth/auth.service.ts +++ b/Frontend/src/app/auth/auth.service.ts @@ -1,15 +1,15 @@ import { HttpClient, HttpHeaders } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { environment } from 'src/environments/environment'; -import { User } from '../models/user'; +import { User } from '../models/user.model'; @Injectable({ providedIn: 'root' }) export class AuthService { - apiToken: string | null = null; - user: User | null = null; + apiToken!: string; + user!: User; constructor( private http$: HttpClient @@ -35,7 +35,7 @@ export class AuthService { const header = new HttpHeaders().set('Content-type', 'application/json'); this.http$.post(`${environment.api.url}/auth/apiToken`, JSON.stringify(credentials), { headers: header }).subscribe({ next: (data) => { - if (this.user) { this.user.id = data.id } + this.user.id = data.id; this.apiToken = data.token; resolve(data); }, diff --git a/Frontend/src/app/components/login-page/login-page.component.ts b/Frontend/src/app/components/login-page/login-page.component.ts index 3b04550..1beebc8 100644 --- a/Frontend/src/app/components/login-page/login-page.component.ts +++ b/Frontend/src/app/components/login-page/login-page.component.ts @@ -2,7 +2,7 @@ import { Component, NgZone, OnInit } from '@angular/core'; import { Router } from '@angular/router'; import jwt_decode from "jwt-decode"; import { AuthService } from 'src/app/auth/auth.service'; -import { User } from 'src/app/models/user'; +import { User } from 'src/app/models/user.model'; import { DataService } from 'src/app/services/data.service'; import { environment } from 'src/environments/environment'; @@ -44,7 +44,7 @@ export class LoginPageComponent implements OnInit { async handleCredentialResponse(response: any) { try { const responsePayload: any = jwt_decode(response.credential); - this.data$.currentUser = new User({ + this.auth$.user = new User({ googleCredentials: response.credential, userName: `${responsePayload.given_name} ${responsePayload.family_name}`, email: responsePayload.email, diff --git a/Frontend/src/app/main-view/main-view.component.html b/Frontend/src/app/main-view/main-view.component.html index 1ce0473..d748fb1 100644 --- a/Frontend/src/app/main-view/main-view.component.html +++ b/Frontend/src/app/main-view/main-view.component.html @@ -14,9 +14,9 @@

Diuna

- - - {{data$.currentUser.userName}} + + + {{auth$.user.userName}} + + + + + + + Numer + + + Pole obowiązkowe + + + + + + + + Import ręczny + Arkusz Google + SAP + Symfonia + + + Pole obowiązkowe + + + + + + + + + \ No newline at end of file diff --git a/Frontend/src/app/modules/data-sets/data-set-edit/data-set-edit.component.scss b/Frontend/src/app/modules/data-sets/data-set-edit/data-set-edit.component.scss new file mode 100644 index 0000000..b199958 --- /dev/null +++ b/Frontend/src/app/modules/data-sets/data-set-edit/data-set-edit.component.scss @@ -0,0 +1 @@ +@import "../../../main-view/main-view.component.scss"; \ No newline at end of file diff --git a/Frontend/src/app/modules/data-sets/data-set-edit/data-set-edit.component.spec.ts b/Frontend/src/app/modules/data-sets/data-set-edit/data-set-edit.component.spec.ts new file mode 100644 index 0000000..7aac256 --- /dev/null +++ b/Frontend/src/app/modules/data-sets/data-set-edit/data-set-edit.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { DataSetEditComponent } from './data-set-edit.component'; + +describe('DataSetEditComponent', () => { + let component: DataSetEditComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ DataSetEditComponent ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(DataSetEditComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/Frontend/src/app/modules/data-sets/data-set-edit/data-set-edit.component.ts b/Frontend/src/app/modules/data-sets/data-set-edit/data-set-edit.component.ts new file mode 100644 index 0000000..8d7e4a6 --- /dev/null +++ b/Frontend/src/app/modules/data-sets/data-set-edit/data-set-edit.component.ts @@ -0,0 +1,68 @@ +import { HttpClient } from '@angular/common/http'; +import { Component, OnInit } from '@angular/core'; +import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; +import { MatDialog } from '@angular/material/dialog'; +import { Router, ActivatedRoute } from '@angular/router'; +import moment from 'moment'; +import { AuthService } from 'src/app/auth/auth.service'; +import { DataSet } from 'src/app/models/dataSet.model'; +import { DataService } from 'src/app/services/data.service'; +import { v4 as uuidv4 } from 'uuid'; + +@Component({ + selector: 'app-data-set-edit', + templateUrl: './data-set-edit.component.html', + styleUrls: ['./data-set-edit.component.scss'] +}) +export class DataSetEditComponent implements OnInit { + + public form!: UntypedFormGroup; + private document!: DataSet; + + constructor( + private fb$: UntypedFormBuilder, + private router$: Router, + private http$: HttpClient, + private data$: DataService, + private route$: ActivatedRoute, + private dialog$: MatDialog, + private auth$: AuthService + ) { } + + async ngOnInit() { + this.form = DataSet.getForm(this.fb$); + this.document = await this.load(); + this.document.fillForm(this.form); + } + private load(): Promise { + return new Promise((resolve) => { + const id = this.route$.snapshot.paramMap.get('id') || ""; + if (this.route$.snapshot.paramMap.get('id') === 'new') { + resolve(new DataSet({ id: uuidv4(), createdById: this.auth$.user.id, createdAt: moment(), + modifiedAt: moment() })) // new element + return; + } + resolve(DataSet.getById(id, this.http$)) + }); + } + async save() { + if (this.form.invalid) { + return; + } + /* + this.document.loadForm(this.form); + let id; + if (this.route$.snapshot.paramMap.get('id') === 'new') { + id = await DataSet.add(this.document, this.http$, this._data); + } else { + id = await DataSet.update(this.document, this._http, this._data); + } + this._router.navigate(['../../Detail', id], { relativeTo: this._route}); + */ + } + generateNumber() { + this.form.patchValue({ + number: `${this.form.controls['name'].value}-${moment().format("YYYY")}-${moment().format("MM")}` + }) + } +} diff --git a/Frontend/src/app/modules/data-sets/data-sets-list/data-sets-list.component.html b/Frontend/src/app/modules/data-sets/data-sets-list/data-sets-list.component.html new file mode 100644 index 0000000..329b54a --- /dev/null +++ b/Frontend/src/app/modules/data-sets/data-sets-list/data-sets-list.component.html @@ -0,0 +1,38 @@ +
+
+ + + + + + + Filtruj + + + + +
+ + + + + Numer + {{item.number}} + + + + Źródło + {{item.name}} + + + + + + + +
+ \ No newline at end of file diff --git a/Frontend/src/app/modules/data-sets/data-sets-list/data-sets-list.component.scss b/Frontend/src/app/modules/data-sets/data-sets-list/data-sets-list.component.scss new file mode 100644 index 0000000..b199958 --- /dev/null +++ b/Frontend/src/app/modules/data-sets/data-sets-list/data-sets-list.component.scss @@ -0,0 +1 @@ +@import "../../../main-view/main-view.component.scss"; \ No newline at end of file diff --git a/Frontend/src/app/modules/data-sets/data-sets-list/data-sets-list.component.spec.ts b/Frontend/src/app/modules/data-sets/data-sets-list/data-sets-list.component.spec.ts new file mode 100644 index 0000000..b2e4456 --- /dev/null +++ b/Frontend/src/app/modules/data-sets/data-sets-list/data-sets-list.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { DataSetsListComponent } from './data-sets-list.component'; + +describe('DataSetsListComponent', () => { + let component: DataSetsListComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ DataSetsListComponent ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(DataSetsListComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/Frontend/src/app/modules/data-sets/data-sets-list/data-sets-list.component.ts b/Frontend/src/app/modules/data-sets/data-sets-list/data-sets-list.component.ts new file mode 100644 index 0000000..a58b40c --- /dev/null +++ b/Frontend/src/app/modules/data-sets/data-sets-list/data-sets-list.component.ts @@ -0,0 +1,37 @@ +import { HttpClient } from '@angular/common/http'; +import { Component, OnInit, ViewChild } from '@angular/core'; +import { MatPaginator } from '@angular/material/paginator'; +import { MatSort } from '@angular/material/sort'; +import { MatTableDataSource } from '@angular/material/table'; +import { DataSet } from 'src/app/models/dataSet.model'; + +@Component({ + selector: 'app-data-sets-list', + templateUrl: './data-sets-list.component.html', + styleUrls: ['./data-sets-list.component.scss'] +}) +export class DataSetsListComponent implements OnInit { + displayedColumns = ['number', 'name']; + dataSource!: MatTableDataSource; + + @ViewChild(MatPaginator) paginator!: MatPaginator; + @ViewChild(MatSort) sort!: MatSort; + + constructor( + private _http: HttpClient + ) { } + + async ngOnInit() { + this.dataSource = new MatTableDataSource(await DataSet.getList(this._http)); + this.dataSource.paginator = this.paginator; + this.dataSource.sort = this.sort; + } + + applyFilter(event: Event) { + const filterValue = (event.target as HTMLInputElement).value; + this.dataSource.filter = filterValue.trim().toLowerCase(); + } + trackByUid(index : number, item : DataSet) { + return item.id; + } +} diff --git a/Frontend/src/app/modules/data-sets/data-sets-routing.module.ts b/Frontend/src/app/modules/data-sets/data-sets-routing.module.ts new file mode 100644 index 0000000..39e471a --- /dev/null +++ b/Frontend/src/app/modules/data-sets/data-sets-routing.module.ts @@ -0,0 +1,17 @@ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { DataSetDetailComponent } from './data-set-detail/data-set-detail.component'; +import { DataSetEditComponent } from './data-set-edit/data-set-edit.component'; +import { DataSetsListComponent } from './data-sets-list/data-sets-list.component'; + +const routes: Routes = [ + { path: '', component: DataSetsListComponent }, + { path: 'Edit/:id', component: DataSetEditComponent }, + { path: 'Detail/:id', component: DataSetDetailComponent } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class DataSetsRoutingModule { } diff --git a/Frontend/src/app/modules/data-sets/data-sets.module.ts b/Frontend/src/app/modules/data-sets/data-sets.module.ts new file mode 100644 index 0000000..6b13112 --- /dev/null +++ b/Frontend/src/app/modules/data-sets/data-sets.module.ts @@ -0,0 +1,24 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { DataSetsRoutingModule } from './data-sets-routing.module'; +import { DataSetsListComponent } from './data-sets-list/data-sets-list.component'; +import { MaterialModule } from 'src/app/material.module'; +import { DataSetDetailComponent } from './data-set-detail/data-set-detail.component'; +import { DataSetEditComponent } from './data-set-edit/data-set-edit.component'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; + +@NgModule({ + declarations: [ + DataSetsListComponent, + DataSetDetailComponent, + DataSetEditComponent + ], + imports: [ + CommonModule, + DataSetsRoutingModule, + MaterialModule, + FormsModule, + ReactiveFormsModule + ] +}) +export class DataSetsModule { } diff --git a/Frontend/src/app/services/data.service.ts b/Frontend/src/app/services/data.service.ts index abb9464..e8dc3fb 100644 --- a/Frontend/src/app/services/data.service.ts +++ b/Frontend/src/app/services/data.service.ts @@ -1,12 +1,11 @@ import { Injectable } from '@angular/core'; import { BehaviorSubject } from 'rxjs'; -import { User } from '../models/user'; +import { User } from '../models/user.model'; @Injectable({ providedIn: 'root' }) export class DataService { - currentUser?: User | null; public showLoader: BehaviorSubject = new BehaviorSubject(false); constructor() { } diff --git a/Frontend/src/environments/environment.ts b/Frontend/src/environments/environment.ts index 0b30576..06438ce 100644 --- a/Frontend/src/environments/environment.ts +++ b/Frontend/src/environments/environment.ts @@ -5,8 +5,8 @@ export const environment = { production: false, api: { - //url: "http://localhost:5400/api" - url: "https://diuna.bim-it.pl/api" + url: "http://localhost:5400/api" + //url: "https://diuna.bim-it.pl/api" }, google: { clientId: "107631825312-bkfe438ehr9k9ecb2h76g802tj6advma.apps.googleusercontent.com" diff --git a/WebAPI/AppDbContext.cs b/WebAPI/AppDbContext.cs index 3c297c6..b58aa28 100644 --- a/WebAPI/AppDbContext.cs +++ b/WebAPI/AppDbContext.cs @@ -7,6 +7,8 @@ namespace WebAPI public class AppDbContext : DbContext { public DbSet Users { get; set; } + public DbSet DataSets { get; set; } + public DbSet DataRows { get; set; } public AppDbContext(DbContextOptions options) : base(options) { diff --git a/WebAPI/Controllers/DataSetsController.cs b/WebAPI/Controllers/DataSetsController.cs new file mode 100644 index 0000000..0c8eda7 --- /dev/null +++ b/WebAPI/Controllers/DataSetsController.cs @@ -0,0 +1,37 @@ +using Google.Apis.Auth; +using Google.Apis.Http; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Configuration; +using Microsoft.Identity.Client.Platforms.Features.DesktopOs.Kerberos; +using Microsoft.IdentityModel.Tokens; +using System.Configuration; +using System.IdentityModel.Tokens.Jwt; +using System.Security.Claims; +using System.Text; +using WebAPI.Models; + +namespace WebAPI.Controllers +{ + [ApiController] + [Route("api/[controller]")] + [Authorize] + public class DataSetsController : Controller + { + private readonly AppDbContext db; + public DataSetsController(AppDbContext _db) { db = _db; } + + [HttpGet] + public IActionResult GetAll() + { + try + { + return Ok(db.DataSets.Where(x => !x.IsDeleted).ToList()); + } + catch (Exception e) + { + return BadRequest(e.ToString()); + } + } + } +} \ No newline at end of file diff --git a/WebAPI/Migrations/20221211210507_DataSetsAndDataRows.Designer.cs b/WebAPI/Migrations/20221211210507_DataSetsAndDataRows.Designer.cs new file mode 100644 index 0000000..533dbf0 --- /dev/null +++ b/WebAPI/Migrations/20221211210507_DataSetsAndDataRows.Designer.cs @@ -0,0 +1,192 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using WebAPI; + +#nullable disable + +namespace WebAPI.Migrations +{ + [DbContext(typeof(AppDbContext))] + [Migration("20221211210507_DataSetsAndDataRows")] + partial class DataSetsAndDataRows + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("WebAPI.Models.DataRow", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedById") + .HasColumnType("uniqueidentifier"); + + b.Property("DataSetId") + .HasColumnType("uniqueidentifier"); + + b.Property("Desc1") + .HasColumnType("nvarchar(max)"); + + b.Property("Desc2") + .HasColumnType("nvarchar(max)"); + + b.Property("Desc3") + .HasColumnType("nvarchar(max)"); + + b.Property("Desc4") + .HasColumnType("nvarchar(max)"); + + b.Property("Desc5") + .HasColumnType("nvarchar(max)"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("MPK") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ModifiedAt") + .HasColumnType("datetime2"); + + b.Property("ModifiedById") + .HasColumnType("uniqueidentifier"); + + b.Property("Value") + .HasColumnType("real"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("DataSetId"); + + b.HasIndex("ModifiedById"); + + b.ToTable("DataRows"); + }); + + modelBuilder.Entity("WebAPI.Models.DataSet", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedById") + .HasColumnType("uniqueidentifier"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("ModifiedAt") + .HasColumnType("datetime2"); + + b.Property("ModifiedById") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .HasColumnType("nvarchar(max)"); + + b.Property("Number") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("ModifiedById"); + + b.ToTable("DataSets"); + }); + + modelBuilder.Entity("WebAPI.Models.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("Email") + .HasColumnType("nvarchar(max)"); + + b.Property("UserName") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("WebAPI.Models.DataRow", b => + { + b.HasOne("WebAPI.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WebAPI.Models.DataSet", null) + .WithMany("DataRows") + .HasForeignKey("DataSetId"); + + b.HasOne("WebAPI.Models.User", "ModifiedBy") + .WithMany() + .HasForeignKey("ModifiedById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CreatedBy"); + + b.Navigation("ModifiedBy"); + }); + + modelBuilder.Entity("WebAPI.Models.DataSet", b => + { + b.HasOne("WebAPI.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WebAPI.Models.User", "ModifiedBy") + .WithMany() + .HasForeignKey("ModifiedById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CreatedBy"); + + b.Navigation("ModifiedBy"); + }); + + modelBuilder.Entity("WebAPI.Models.DataSet", b => + { + b.Navigation("DataRows"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/WebAPI/Migrations/20221211210507_DataSetsAndDataRows.cs b/WebAPI/Migrations/20221211210507_DataSetsAndDataRows.cs new file mode 100644 index 0000000..9c86424 --- /dev/null +++ b/WebAPI/Migrations/20221211210507_DataSetsAndDataRows.cs @@ -0,0 +1,121 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace WebAPI.Migrations +{ + /// + public partial class DataSetsAndDataRows : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "DataSets", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + Number = table.Column(type: "nvarchar(max)", nullable: false), + Name = table.Column(type: "nvarchar(max)", nullable: true), + CreatedAt = table.Column(type: "datetime2", nullable: false), + ModifiedAt = table.Column(type: "datetime2", nullable: false), + IsDeleted = table.Column(type: "bit", nullable: false), + CreatedById = table.Column(type: "uniqueidentifier", nullable: false), + ModifiedById = table.Column(type: "uniqueidentifier", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_DataSets", x => x.Id); + table.ForeignKey( + name: "FK_DataSets_Users_CreatedById", + column: x => x.CreatedById, + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.NoAction); + table.ForeignKey( + name: "FK_DataSets_Users_ModifiedById", + column: x => x.ModifiedById, + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.NoAction); + }); + + migrationBuilder.CreateTable( + name: "DataRows", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + MPK = table.Column(type: "nvarchar(max)", nullable: false), + Value = table.Column(type: "real", nullable: false), + Desc1 = table.Column(type: "nvarchar(max)", nullable: true), + Desc2 = table.Column(type: "nvarchar(max)", nullable: true), + Desc3 = table.Column(type: "nvarchar(max)", nullable: true), + Desc4 = table.Column(type: "nvarchar(max)", nullable: true), + Desc5 = table.Column(type: "nvarchar(max)", nullable: true), + CreatedAt = table.Column(type: "datetime2", nullable: false), + ModifiedAt = table.Column(type: "datetime2", nullable: false), + IsDeleted = table.Column(type: "bit", nullable: false), + CreatedById = table.Column(type: "uniqueidentifier", nullable: false), + ModifiedById = table.Column(type: "uniqueidentifier", nullable: false), + DataSetId = table.Column(type: "uniqueidentifier", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_DataRows", x => x.Id); + table.ForeignKey( + name: "FK_DataRows_DataSets_DataSetId", + column: x => x.DataSetId, + principalTable: "DataSets", + principalColumn: "Id"); + table.ForeignKey( + name: "FK_DataRows_Users_CreatedById", + column: x => x.CreatedById, + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.NoAction); + table.ForeignKey( + name: "FK_DataRows_Users_ModifiedById", + column: x => x.ModifiedById, + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.NoAction); + }); + + migrationBuilder.CreateIndex( + name: "IX_DataRows_CreatedById", + table: "DataRows", + column: "CreatedById"); + + migrationBuilder.CreateIndex( + name: "IX_DataRows_DataSetId", + table: "DataRows", + column: "DataSetId"); + + migrationBuilder.CreateIndex( + name: "IX_DataRows_ModifiedById", + table: "DataRows", + column: "ModifiedById"); + + migrationBuilder.CreateIndex( + name: "IX_DataSets_CreatedById", + table: "DataSets", + column: "CreatedById"); + + migrationBuilder.CreateIndex( + name: "IX_DataSets_ModifiedById", + table: "DataSets", + column: "ModifiedById"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "DataRows"); + + migrationBuilder.DropTable( + name: "DataSets"); + } + } +} diff --git a/WebAPI/Migrations/AppDbContextModelSnapshot.cs b/WebAPI/Migrations/AppDbContextModelSnapshot.cs index c06ff91..92ff024 100644 --- a/WebAPI/Migrations/AppDbContextModelSnapshot.cs +++ b/WebAPI/Migrations/AppDbContextModelSnapshot.cs @@ -22,6 +22,100 @@ namespace WebAPI.Migrations SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + modelBuilder.Entity("WebAPI.Models.DataRow", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedById") + .HasColumnType("uniqueidentifier"); + + b.Property("DataSetId") + .HasColumnType("uniqueidentifier"); + + b.Property("Desc1") + .HasColumnType("nvarchar(max)"); + + b.Property("Desc2") + .HasColumnType("nvarchar(max)"); + + b.Property("Desc3") + .HasColumnType("nvarchar(max)"); + + b.Property("Desc4") + .HasColumnType("nvarchar(max)"); + + b.Property("Desc5") + .HasColumnType("nvarchar(max)"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("MPK") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ModifiedAt") + .HasColumnType("datetime2"); + + b.Property("ModifiedById") + .HasColumnType("uniqueidentifier"); + + b.Property("Value") + .HasColumnType("real"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("DataSetId"); + + b.HasIndex("ModifiedById"); + + b.ToTable("DataRows"); + }); + + modelBuilder.Entity("WebAPI.Models.DataSet", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedById") + .HasColumnType("uniqueidentifier"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("ModifiedAt") + .HasColumnType("datetime2"); + + b.Property("ModifiedById") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .HasColumnType("nvarchar(max)"); + + b.Property("Number") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("ModifiedById"); + + b.ToTable("DataSets"); + }); + modelBuilder.Entity("WebAPI.Models.User", b => { b.Property("Id") @@ -42,6 +136,53 @@ namespace WebAPI.Migrations b.ToTable("Users"); }); + + modelBuilder.Entity("WebAPI.Models.DataRow", b => + { + b.HasOne("WebAPI.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WebAPI.Models.DataSet", null) + .WithMany("DataRows") + .HasForeignKey("DataSetId"); + + b.HasOne("WebAPI.Models.User", "ModifiedBy") + .WithMany() + .HasForeignKey("ModifiedById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CreatedBy"); + + b.Navigation("ModifiedBy"); + }); + + modelBuilder.Entity("WebAPI.Models.DataSet", b => + { + b.HasOne("WebAPI.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WebAPI.Models.User", "ModifiedBy") + .WithMany() + .HasForeignKey("ModifiedById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CreatedBy"); + + b.Navigation("ModifiedBy"); + }); + + modelBuilder.Entity("WebAPI.Models.DataSet", b => + { + b.Navigation("DataRows"); + }); #pragma warning restore 612, 618 } } diff --git a/WebAPI/Models/DataRow.cs b/WebAPI/Models/DataRow.cs new file mode 100644 index 0000000..511d084 --- /dev/null +++ b/WebAPI/Models/DataRow.cs @@ -0,0 +1,31 @@ +using System.ComponentModel.DataAnnotations; + +namespace WebAPI.Models +{ + public class DataRow + { + #region Properties + [Key] + public Guid Id { get; set; } + [Required] + public string? MPK { get; set; } + [Required] + public float Value { get; set; } + //Description fields + public string? Desc1 { get; set; } + public string? Desc2 { get; set; } + public string? Desc3 { get; set; } + public string? Desc4 { get; set; } + public string? Desc5 { get; set; } + public DateTime CreatedAt { get; set; } + public DateTime ModifiedAt { get; set; } + public bool IsDeleted { get; set; } + #endregion + #region Relations + public Guid CreatedById { get; set; } + public User? CreatedBy { get; set; } + public Guid ModifiedById { get; set; } + public User? ModifiedBy { get; set; } + #endregion + } +} diff --git a/WebAPI/Models/DataSet.cs b/WebAPI/Models/DataSet.cs new file mode 100644 index 0000000..9e0a0fc --- /dev/null +++ b/WebAPI/Models/DataSet.cs @@ -0,0 +1,25 @@ +using System.ComponentModel.DataAnnotations; + +namespace WebAPI.Models +{ + public class DataSet + { + #region Properties + [Key] + public Guid Id { get; set; } + [Required] + public string? Number { get; set; } + public string? Name { get; set; } + public DateTime CreatedAt { get; set; } + public DateTime ModifiedAt { get; set; } + public bool IsDeleted { get; set; } + #endregion + #region Relations + public ICollection? DataRows { get; set; } + public Guid CreatedById { get; set; } + public User? CreatedBy { get; set; } + public Guid ModifiedById { get; set; } + public User? ModifiedBy { get; set; } + #endregion + } +}