CoolFace
Datasetpublic

GSaha567/seq_level_training_data

sourceHugging Faceupdated 8mo agoView on Hugging Face
0likes52downloads
shard_000035.csv99281 linesDownload Raw Back to root
1text,length,is_long_context,metric_val,label_metric2":toc: macro3toc::[]4:idprefix:5:idseparator: -6ifdef::env-github[]7:tip-caption: :bulb:8:note-caption: :information_source:9:important-caption: :heavy_exclamation_mark:10:caution-caption: :fire:11:warning-caption: :warning:12endif::[]13 14= devon4j adding Custom Functionality15 16Now we have a fully functional blank project. All we have to do now is to create the components and services which will compose our application.17 18First, we are going to develop the views of the app through its components, then we will create the services with the logic, security and back-end connection.19 20[NOTE]21====22This tutorial is only going to develop a mobile view. The app is not going to be responsive or well suited for desktop use. The new https://github.com/devonfw-forge/jump-the-queue-v2[JumpTheQueue V2] implements these features, but currently no tutorial walkthrough exists for it.23====24 25== Creating Components26 27[NOTE]28====29You have already learned about creating Components in devon4ng https://github.com/devonfw/jump-the-queue/wiki/devon4ng-components#create-a-new-component[here]. +30You can go back and read that section again to refresh your memory.31====32 33Our app is going to consist of 3 main views:34 35* Login36* Register37* ViewQueue38 39To navigate between these views/components, we are going to implement routes using the Angular Router.40 41To see our progress, move to the root folder of the `angular` project and run `ng serve -o` again. This will recompile and publish our client app to http://localhost:4200. Angular will keep watching for changes, so whenever we modify the code, the app will automatically reload.42 43=== Root Component44 45`app.component.ts` inside `angular/src/app` will be our root component, so we don't have to create a new file yet. We are going to add elements to the root component that will be common no matter what view will be displayed.46 47[NOTE]48====49You have already learned about the Root Component in devon4ng https://github.com/devonfw/jump-the-queue/wiki/devon4ng-components#root-component[here]. +50You can go back and read that section again to refresh your memory.51====52 53This applies to the header element which will be on top of the window and on top of all other components. If you want, you can read more about https://teradata.github.io/covalent/#/layouts[Covalent layouts], which we are going to use a lot from now on, for every view component.54 55[NOTE]56====57You have already learned about Covalent Layouts in devon4ng https://github.com/devonfw/jump-the-queue/wiki/devon4ng-components#teradata-covalent-layouts[here]. +58You can go back and read that section again to refresh your memory.59====60 61We don't really need anything more than a header, so we are going to use the simplest layout for this purpose; the *nav view*.62 63In order to be able to use Covalent and Angular Material we are going to create a core module, which we will import into every other module where we want to use Covalent and Angular Material. First, we create a folder called `shared` in the `angular/src/app` directory. Inside there we are going to create a file called `core.module.ts` and will fill it with the following content:64 65[source, typescript]66----67import { NgModule } from '@angular/core';68import { RouterModule } from '@angular/router';69import { CommonModule } from '@angular/common';70import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';71import { BrowserAnimationsModule } from '@angular/platform-browser/animations';72import {73  MatAutocompleteModule,74  MatButtonModule,75  MatButtonToggleModule,76  MatCardModule,77  MatCheckboxModule,78  MatChipsModule,79  MatDatepickerModule,80  MatDialogModule,81  MatExpansionModule,82  MatGridListModule,83  MatIconModule,84  MatInputModule,85  MatListModule,86  MatMenuModule,87  MatNativeDateModule,88  MatPaginatorModule,89  MatProgressBarModule,90  MatProgressSpinnerModule,91  MatRadioModule,92  MatRippleModule,93  MatSelectModule,94  MatSidenavModule,95  MatSliderModule,96  MatSlideToggleModule,97  MatSnackBarModule,98  MatSortModule,99  MatTableModule,100  MatTabsModule,101  MatToolbarModule,102  MatTooltipModule,103} from '@angular/material';104import { CdkTableModule } from '@angular/cdk/table';105import {106  CovalentChipsModule,107  CovalentLayoutModule,108  CovalentExpansionPanelModule,109  CovalentDataTableModule,110  CovalentPagingModule,111  CovalentDialogsModule,112  CovalentLoadingModule,113  CovalentMediaModule,114  CovalentNotificationsModule,115  CovalentCommonModule,116} from '@covalent/core';117 118@NgModule({119  imports: [120    RouterModule,121    BrowserAnimationsModule,122    MatCardModule,123    MatButtonModule,124    MatIconModule,125    CovalentMediaModule,126    CovalentLayoutModule,127    CdkTableModule,128  ],129  exports: [130    CommonModule,131    CovalentChipsModule,132    CovalentLayoutModule,133    CovalentExpansionPanelModule,134    CovalentDataTableModule,135    CovalentPagingModule,136    CovalentDialogsModule,137    CovalentLoadingModule,138    CovalentMediaModule,139    CovalentNotificationsModule,140    CovalentCommonModule,141    CdkTableModule,142    MatAutocompleteModule,143    MatButtonModule,144    MatButtonToggleModule,145    MatCardModule,146    MatCheckboxModule,147    MatChipsModule,148    MatDatepickerModule,149    MatDialogModule,150    MatExpansionModule,151    MatGridListModule,152    MatIconModule,153    MatInputModule,154    MatListModule,155    MatMenuModule,156    MatNativeDateModule,157    MatPaginatorModule,158    MatProgressBarModule,159    MatProgressSpinnerModule,160    MatRadioModule,161    MatRippleModule,162    MatSelectModule,163    MatSidenavModule,164    MatSliderModule,165    MatSlideToggleModule,166    MatSnackBarModule,167    MatSortModule,168    MatTableModule,169    MatTabsModule,170    MatToolbarModule,171    MatTooltipModule,172    HttpClientModule,173  ],174  declarations: [],175  providers: [176    HttpClientModule177  ],178})179export class CoreModule {}180----181 182[NOTE]183====184This `CoreModule` has almost every module of the different components for *Angular Material* and *Covalent Teradata*. If you decide to use a component that is not included yet, you need to add the corresponding module here.185====186 187Remember that we need to import this `CoreModule` module into the `AppModule` and inside every module of the different components that use *Angular Material* and *Covalent Teradata*. If a component does not have a module, it will be imported in the `AppModule` and hence automatically have the `CoreModule`. Our `app.module.ts` should have the following content:188 189[source, typescript]190----191import { BrowserModule } from '@angular/platform-browser';192import { NgModule } from '@angular/core';193 194// Application components and services195import { AppRoutingModule } from './app-routing.module';196import { AppComponent } from './app.component';197import { CoreModule } from './shared/core.module';198 199@NgModule({200  declarations: [201    AppComponent202  ],203  imports: [204    BrowserModule,205    AppRoutingModule,206    CoreModule,207  ],208  providers: [209  ],210  bootstrap: [AppComponent]211})212export class AppModule { }213----214 215[NOTE]216====217Remember this step because you will have to repeat it for every other component from Teradata you use in your app.218====219 220Now we can use this layout, so let's implement it in `app.component.html`. Use the following code:221 222[source, html]223----224<td-layout-nav>             <!-- Layout tag-->225  <div td-toolbar-content>226    Jump The Queue          <!-- Header container-->227  </div>228  <h1>229    app works!              <!-- Main content-->230  </h1>231</td-layout-nav>232----233 234[NOTE]235====236You have already learned about Toolbars in devon4ng https://github.com/devonfw/jump-the-queue/wiki/devon4ng-components#toolbars[here]. +237You can go back and read that section again to refresh your memory.238====239 240Once this is done, our app should have a header and ""app works!"" should appear in the body of the page:241 242image::images/devon4ng/3.BuildYourOwn/root_header.jpg[Root Header, 250]243 244To go a step further, we have to modify the body of the root component because it should be the *output of the router*. Now it's time to prepare the routing system.245 246First, we need to create a component to show as default which will be our access view. We will modify it later. Stop `ng serve` and run:247 248----249ng generate component form-login250----251 252It will add a folder to our project with all the files needed for a component. Now we can move on to the router task again. Run `ng serve` again to continue the development.253 254Let's create a module that navigates between components when the Router checks for routes. The file `app-routing.module.ts` was created automatically when we chose to include Angular Routing during project creation and we only need to modify it now:255 256[source, typescript]257----258import { NgModule } from '@angular/core';259import { RouterModule, Routes } from '@angular/router';260import { FormLoginComponent } from './form-login/form-login.component';261 262const appRoutes: Routes = [263  { path: 'FormLogin', component: FormLoginComponent},        // Redirect if url path is /FormLogin.264  { path: '**', redirectTo: '/FormLogin', pathMatch: 'full' } // Redirect if url path do not match any other route.265];266 267@NgModule({268  imports: [269    RouterModule.forRoot(270      appRoutes,271      { enableTracing: true }, // <-- debugging purposes only272    ),273  ],274  exports: [RouterModule],275})276export class AppRoutingModule {}277----278 279[NOTE]280====281You have already learned about Routing in devon4ng https://github.com/devonfw/jump-the-queue/wiki/devon4ng-components#routing[here]. +282You can go back and read that section again to refresh your memory.283====284 285Finally, we remove the `<h1>app works!</h1>` from `app.component.html` and replace it with a `<router-outlet></router-outlet>` tag. The final result of our root component will look like this:286 287image::images/devon4ng/3.BuildYourOwn/root_router.jpg[Root Router, 250]288 289As you can see, now the body content is the HTML of `FormLoginComponent`. This is because we told the Router to redirect to formlogin when the path is `/FormLogin`, but also, redirect to it by default if any of the other routes match the given path.290 291For now we are going to leave the header like this. In the future we will separate it into another component inside a layout folder.292 293=== LoginForm Component294 295As we have already created this component from the section before, let's move on to building the template of the login view.296 297First, we need to add the Covalent Layout and the card to the file `form-login.component.html`:298 299[source, html]300----301<td-layout>302  <mat-card>303    <mat-card-title>Login</mat-card-title>304  </mat-card>305</td-layout>306----307 308This will add a grey background to the view and a card on top of it with the title ""Login"" now that we have the basic structure of the view.309 310Now we are going to add this image:311 312image::images/devon4ng/3.BuildYourOwn/jumptheq.png[JumpTheQueue Logo Image, 250]313 314In order to have it available, save it in the following path of the project: `angular/src/assets/images/` and name it `jumptheq.png`.315 316The final code with the form added will look like this:317 318[source, html]319----320<td-layout>321  <mat-card>322    <img mat-card-image src=""assets/images/jumptheq.png"">323  </mat-card>324</td-layout>325----326 327This code will give us as a result similar to this:328 329image::images/devon4ng/3.BuildYourOwn/formlogin.png[Form Login, 250]330 331This is going to be the container for the login. +332Now we will continue with the second component: Login.333 334=== Login Component335 336Our first step will be to create the component in the exact same way we created the `FormLogin` component but this time we are going to generate it in a new folder called components inside formlogin. Putting every child component inside that folder will allow us to keep a good and clear structure. In order to do this, we use the command:337 338----339ng generate component form-login/components/login340----341 342After _Angular/CLI_ has finished generating the component, we have to create two modules, one for the form-login and one for the login:343 3441.- We create a new file called `login-module.ts` in the login root:345 346[source, typescript]347----348import { NgModule } from '@angular/core';349import { CommonModule } from '@angular/common';350import { CoreModule } from 'src/app/shared/core.module';351import { LoginComponent } from './login.component';352 353@NgModule({354  imports: [CommonModule, CoreModule],355  providers: [],356  declarations: [LoginComponent],357  exports: [LoginComponent],358})359export class LoginModule {}360----361 3622.- We create a new file called `form-login-module.ts` in the form-login root:363 364[source, typescript]365----366import { NgModule } from '@angular/core';367import { CommonModule } from '@angular/common';368import { FormLoginComponent } from './form-login.component';369import { CoreModule } from '../shared/core.module';370import { LoginModule } from './components/login/login-module';371 372@NgModule({373  imports: [CommonModule, CoreModule, LoginModule],374  providers: [],375  declarations: [FormLoginComponent],376  exports: [FormLoginComponent],377})378export class FormLoginModule {}379----380 381As you can see, the `LoginModule` is already added to the `FormLoginModule`. Once this is done, we need to remove the `FormLoginComponent` and the `LoginComponent` from the `declarations` since they are already declared in their own modules. Then add the `FormLoginModule`. This will be done inside `AppModule`:382 383[source, typescript]384----385...386import { FormLoginModule } from './form-login/form-login-module';387...388  declarations: [389    AppComponent,390  ]391 392  imports: [393    BrowserModule,394    FormLoginModule,395    CoreModule,396    AppRoutingModule397  ]398...399----400 401[NOTE]402====403This is done so the `form-login` (container/wrapper) and the `login` stay separated allowing us to reuse the login without having the card around in other views.404====405 406After this, we modify the `login.component.html` and add the form: 407 408[source, typescript]409----410<form #loginForm=""ngForm"" layout-padding>411    <div layout=""row"" flex>412        <mat-form-field flex>413                <input matInput placeholder=""Email"" ngModel email name=""username"" required>414        </mat-form-field>415    </div>416    <div layout=""row"" flex>417        <mat-form-field flex>418            <input matInput placeholder=""Password"" ngModel name=""password"" type=""password"" required>419        </mat-form-field>420    </div>421    <div layout=""row"" flex>422    </div>423    <div layout=""row"" flex layout-margin>424        <div layout=""column"" flex>425            <button mat-raised-button [disabled]=""!loginForm.form.valid"">Login</button>426        </div>427        <div layout=""column"" flex>428            <button mat-raised-button color=""primary"">Register</button>429        </div>430    </div>431</form>432----433 434[NOTE]435====436You have already learned about Forms in devon4ng https://github.com/devonfw/jump-the-queue/wiki/devon4ng-components#forms[here]. +437You can go back and read that section again to refresh your memory.438====439 440This form contains two input containers from Material. The containers enclose the input with the properties listed above.441 442We also need to add a button to send the information and redirect to the `QueueViewer` or show an error if something went wrong in the process. But for the moment, as we neither have another component nor the auth service yet, we will implement the button visually, as well as the validator to disable it if the form is not correct. We will tackle the on-click-event later.443 444As a last step we will add this component to the `form-login-component.html`:445 446[source, html]447----448<td-layout>449    <mat-card>450        <img mat-card-image src=""assets/images/jumptheq.png"">451        <app-login></app-login>452    </mat-card>453</td-layout>454----455 456Now you should see something like this:457 458image::images/devon4ng/3.BuildYourOwn/login.png[JumpTheQueue Login Screen, 250]459 460With two components already created, we need to use the router to navigate between them. Following the application flow of events, we are going to add a _navigate_ function to the register button. When we press it, we will be redirected to our future register component.461 462=== Register Component463 464First, we are going to generate the register component via:465 466----467ng generate component register`468----469 470This will create our component so we can start working on it. Turning back to `login.component.html` we have to modify these lines of code:471 472[source, html]473----474<form (ngSubmit)=""submitLogin()"" #loginForm=""ngForm"" layout-padding>475... 476<button mat-raised-button type=""submit"" [disabled]=""!loginForm.form.valid"">Login</button>477...       478<button mat-raised-button (click)=""onRegisterClick()"" color=""primary"">Register</button>479----480 481Two events were added. First, when we submit the form, the method `submitLogin()` is going to be called. Second, when the user clicks the button `(click)` will send an event to the function `onRegisterClick()`. This function should be inside `login.component.ts` which is going to be created now:482 483[source, typescript]484----485  ...486  import { Router } from '@angular/router';487  ...488  constructor(private router: Router) { }489  ...490  onRegisterClick(): void {491    this.router.navigate(['Register']);492  }493 494  submitLogin(): void {495  }496----497 498We need to inject an instance of the Router object and declare it with the name _router_ in order to use it in the code, as we did with `onRegisterClick()`. Doing this will use the navigate function and redirect to the next view. In our case, it will redirect using the route we are going to define in `app.routing.module.ts`:499 500[source, typescript]501----502...503import { RegisterComponent } from './register/register.component';504...505const appRoutes: Routes = [506  { path: 'FormLogin', component: FormLoginComponent},          // Redirect if url path is /FormLogin.507  { path: 'Register', component: RegisterComponent},            // Redirect if url path is /Register.508  { path: '**', redirectTo: '/FormLogin', pathMatch: 'full' }   // Redirect if url path do not match any other route.509];510...511----512 513[NOTE]514====515You have already learned about Dependency Injection in devon4ng https://github.com/devonfw/jump-the-queue/wiki/devon4ng-services#dependency-injection[here]. +516You can go back and read that section again to refresh your memory.517====518 519Now we are going to imitate the `login` to shape our `register.component.html`:520 521[source, html]522----523<form layout-padding (ngSubmit)=""submitRegister()"" #registerForm=""ngForm"">524  <div layout=""row"" flex>525      <mat-form-field flex>526        <input matInput placeholder=""Email"" ngModel email name=""username"" required>527      </mat-form-field>528  </div>529  <div layout=""row"" flex>530      <mat-form-field flex>531        <input matInput placeholder=""Password"" ngModel name=""password"" type=""password"" required>532      </mat-form-field>533  </div>534  <div layout=""row"" flex>535      <mat-form-field flex>536        <input matInput placeholder=""Name"" ngModel name=""name"" required>537      </mat-form-field>538  </div>539  <div layout=""row"" flex>540      <mat-form-field flex>541        <input matInput placeholder=""Phone Number"" ngModel name=""phoneNumber"" required>542      </mat-form-field>543  </div>544  <div layout-xs=""row"" flex>545      <div layout=""column"" flex>546        <mat-checkbox name=""acceptedTerms"" ngModel required>Accept Terms And conditions</mat-checkbox>547      </div>548  </div>549  <div layout-xs=""row"" flex>550      <div layout=""column"" flex>551        <mat-checkbox name=""acceptedCommercial"" ngModel required>I want to receive notifications</mat-checkbox>552      </div>553  </div>554  <div layout=""row"" flex>555  </div>556  <div layout=""row"" flex>557      <div layout=""column"" flex=""10"">558        </div>559      <div layout=""column"" flex>560          <button mat-raised-button type=""submit"" [disabled]=""!registerForm.form.valid"">Register</button>561      </div>562      <div layout=""column"" flex=""10"">563      </div>564  </div>565</form>566----567 568Now that we have a minimum of navigation flow inside our application, we are going to generate our first service using the command:569 570----571ng generate service register/services/register572----573 574This will create a folder ""services"" inside ""register"" and create the service itself. Services are where we keep the logic that connects to our database and fetches data which is going to be used by our `component.ts`.575 576In order to use the service, we are going to create some interface models. Let's create a folder called `backendModels` inside ""shared"" and inside this folder a file called `interfaces.ts` in which we are going to add the model interfaces that will match our backend:577 578[source, typescript]579----580export class Visitor {581    id?: number;582    username: string;583    name: string;584    password: string;585    phoneNumber: string;586    acceptedCommercial: boolean;587    acceptedTerms: boolean;588    userType: boolean;589}590----591 592[NOTE]593====594You have already learned about creating new services in devon4ng https://github.com/devonfw/jump-the-queue/wiki/devon4ng-services#create-a-new-service[here]. +595You can go back and read that section again to refresh your memory.596====597 598If we take a closer look, we can see that id has a `?` behind it. This indicates that the id is optional.599 600[NOTE]601====602At this point we are going to assume that you have finished the https://github.com/devonfw/jump-the-queue/wiki/build-devon4j-application[devon4j] part of this tutorial, or have at least downloaded the project and have the back end running locally on http://localhost:8081.603====604 605After doing this, we are going to add an environment variable with our base-URL for the REST services. This way we won't have to change every URL when we switch to production. Inside `environments/environment.ts` we add:606 607[source, typescript]608----609export const environment: {production: boolean, baseUrlRestServices: string} = {610  production: false,611  baseUrlRestServices: 'http://localhost:8081/jumpthequeue/services/rest'612};613----614 615Now in the service, we are going to add a `registerVisitor` method.616 617To call the server in this method we are going to inject the Angular `HttpClient` class from `@angular/common/http`. This class is the standard used by Angular to perform HTTP calls. The register call demands a `Visitor` model which we created in the `interfaces` file. We are going to build a POST call and send the information to the proper URL of the server service. The call will return an observable:618 619[source, typescript]620----621import { Injectable } from '@angular/core';622import { HttpClient } from '@angular/common/http';623import { Visitor} from 'src/app/shared/backendModels/interfaces';624import { Observable } from 'rxjs';625import { environment } from 'src/environments/environment';626 627@Injectable({628  providedIn: 'root'629})630export class RegisterService {631 632  private baseUrl = environment.baseUrlRestServices;633 634  constructor(private http: HttpClient) { }635 636  registerVisitor(visitor: Visitor): Observable<Visitor> {637    return this.http.post<Visitor>(`${this.baseUrl}` + '/visitormanagement/v1/visitor', visitor);638  }639}640----641 642This method will send our model to the backend and return an Observable that we will use on the `component.ts`.643 644[NOTE]645====646You have already learned about Observables and RxJs in devon4ng https://github.com/devonfw/jump-the-queue/wiki/devon4ng-services#server-communication[here]. +647You can go back and read that section again to refresh your memory.648====649 650Now we are going to modify `register.component.ts` to call this service:651 652[source, typescript]653----654import { Component, OnInit } from '@angular/core';655import { RegisterService } from './services/register.service';656import { Visitor } from '../shared/backendModels/interfaces';657import { Router } from '@angular/router';658import { MatSnackBar } from '@angular/material/snack-bar';659 660@Component({661  selector: 'app-register',662  templateUrl: './register.component.html',663  styleUrls: ['./register.component.scss']664})665export class RegisterComponent implements OnInit {666 667  constructor(private registerService: RegisterService, private router: Router, public snackBar: MatSnackBar) { }668 669  submitRegister(formValue): void {670    const visitor: Visitor = new Visitor();671    visitor.username = formValue.username;672    visitor.name = formValue.name;673    visitor.phoneNumber = formValue.phoneNumber;674    visitor.password = formValue.password;675    visitor.acceptedCommercial = formValue.acceptedCommercial;676    visitor.acceptedTerms = formValue.acceptedTerms;677    visitor.userType = false;678 679    this.registerService.registerVisitor(visitor).subscribe(680      (visitorResult: Visitor) => console.log(JSON.stringify(visitorResult)), // When call is received681      (err) =>  this.snackBar.open(err.error.message, 'OK', {682        duration: 5000,683      }), // When theres an error684    );685  }686 687  ngOnInit() {688  }689}690----691 692In this file we injected `RegisterService` and `Router` to use them. Then, inside the method `submitRegister`, we created a visitor that we are going to pass to the service. We called the service method `registerVisitor`, we passed the visitor and we subscribed to the `Observable<Visitor>`, which we returned from the service. This subscription allows us to control three things:693 694. What to do when the data is received.695 696. What to do when there's an error.697 698. What to do when the call is complete.699 700Finally, we modify the `register.component.html` to send the form values to the method:701 702[source, html]703----704...705<form layout-padding (ngSubmit)=""submitRegister(registerForm.form.value)"" #registerForm=""ngForm"">706...707----708 709image::images/devon4ng/3.BuildYourOwn/register.png[Register Page, 250]710 711Using the method and taking a look at the browser console, we should see the visitor model being returned.712 713== Creating Services714 715Now that we registered a `Visitor`, it's time to create 3 important services:716 717- AuthService718- AuthGuardService719- LoginService720 721The `AuthService` will be the one that contains the login info, the `AuthGuardService` will check if a user is authorized to use a component (via the `canActivate` method), and the `LoginService` will be used to fill the `AuthService`.722 723[NOTE]724====725To keep this tutorial simple, we are going to perform the password check client side. *THIS IS NOT CORRECT!* Usually, you would send the username and password to the backend, check that the values are correct, and create a corresponding token which you would pass in the header and use it inside the `AuthService` -- checking with some interceptors that the token is both in the `AuthService` and in the request.726====727 728=== Login, Auth and AuthGuard Services729 730We are going to create the 3 services via `ng generate service <path>`:731 732. `LoginService` via: +733`ng generate service form-login/components/login/services/login`734 735. `Auth` service via: +736`ng generate service core/authentication/auth`737 738. `AuthGuard` service via: +739`ng generate service core/authentication/auth-guard`740 741After generating the services, we are going to start modyfing the interfaces. Inside `angular/src/app/shared/backendModels/interfaces` we are going to add `Role`, `FilterVisitor`, `Pageable` and a `Sort` interface:742 743[source, typescript]744----745...746export class FilterVisitor {747    pageable: Pageable;748    username?: string;749    password?: string;750}751 752export class Pageable {753    pageSize: number;754    pageNumber: number;755    sort?: Sort[];756}757 758export class Sort {759    property: string;760    direction: string;761}762 763export class Role {764    name: string;765    permission: number;766}767----768 769[NOTE]770====771As you can see, we added a `Pageable`, since a lot of the search methods in the backend are using `SearchCriterias`. These need pageables which specify a `paseSize` and `pageNumber`. Also, we can see that in this case `FilterVisitor` uses a pageable and adds parameters as a filter (`username` and `password`), which are optional.772====773 774Then we are going to create a `config.ts` file inside the root (`angular/app`). We are going to use that file to set up default config variables, for example: role names with their permission number, default pagination settings etc. For now we are just adding the roles:775 776[source, typescript]777----778export const config: any = {779    roles: [780        { name: 'VISITOR', permission: 0 },781        { name: 'BOSS', permission: 1 },782    ],783};784----785 786After that, we are going to modify the `auth.service.ts`:787 788[source, typescript]789----790import { Injectable } from '@angular/core';791import { find } from 'lodash';792import { Role } from 'src/app/shared/backendModels/interfaces';793import { config } from 'src/app/config';794 795@Injectable({796  providedIn: 'root'797})798export class AuthService {799  private logged = false;800  private user = '';801  private userId = 0;802  private currentRole = 'NONE';803  private token: string;804 805  public isLogged(): boolean {806    return this.logged;807  }808 809  public setLogged(login: boolean): void {810    this.logged = login;811  }812 813  public getUser(): string {814    return this.user;815  }816 817  public setUser(username: string): void {818    this.user = username;819  }820 821  public getUserId(): number {822    return this.userId;823  }824 825  public setUserId(userId: number): void {826    this.userId = userId;827  }828 829  public getToken(): string {830    return this.token;831  }832 833  public setToken(token: string): void {834    this.token = token;835  }836 837  public setRole(role: string): void {838    this.currentRole = role;839  }840 841  public getPermission(roleName: string): number {842    const role: Role = <Role>find(config.roles, { name: roleName });843    return role.permission;844  }845 846  public isPermited(userRole: string): boolean {847    return (848      this.getPermission(this.currentRole) === this.getPermission(userRole)849    );850  }851}852----853 854We will use this service to fill it with information from the logged-in user once the user logs in. This will allow us to check the information of the logged-in user in any way necessary.855 856[NOTE]857====858You have already learned about Authentication in devon4ng https://github.com/devonfw/jump-the-queue/wiki/devon4ng-services#authentication[here]. +859You can go back and read that section again to refresh your memory.860====861 862Now we are going to use this class to fill the `auth-guard.service.ts`:863 864[source, typescript]865----866import { Injectable } from '@angular/core';867import {868  CanActivate,869  Router,870  ActivatedRouteSnapshot,871  RouterStateSnapshot,872} from '@angular/router';873import { AuthService } from './auth.service';874 875@Injectable({876  providedIn: 'root'877})878export class AuthGuardService implements CanActivate {879  constructor(880    private authService: AuthService,881    private router: Router,882  ) {}883 884  canActivate(885    route: ActivatedRouteSnapshot,886    state: RouterStateSnapshot,887  ): boolean {888    if (this.authService.isLogged() && this.authService.isPermited('VISITOR')) { // If its logged in and its role is visitor889      return true;890    }891 892    if (!this.authService.isLogged()) { // if its not logged in893      console.log('Error login');894    }895 896    if (this.router.url === '/') {  // if the router is the app route897      this.router.navigate(['/login']);898    }899    return false;900  }901}902----903 904This service will be slightly different because we have to implement an interface called `CanActivate`. It has a method called `canActivate()` returning a boolean. This method will be called when navigating to a specified route, and -- depending on the return value of this implemented method -- the navigation will proceed or be rejected.905 906[NOTE]907====908You have already learned about Guards in devon4ng https://github.com/devonfw/jump-the-queue/wiki/devon4ng-services#guards[here]. +909You can go back and read that section again to refresh your memory.910====911 912Once this is done, the last step is to fill the `login.service.ts`. In this case, there's going to be three methods:913 914. `getVisitorByUsername(username: string)`: +915A method that recovers a single user corresponding to the email.916 917. `login(username: string, password: string)`: +918A method, which is going to use the previous method, to check that the username and password match the form input and then fill the `AuthService`.919 920. `logout()`: +921This is going to be used to reset the `AuthService` and log out the user.922 923Also, we see the first use of `pipe` and `map`: +924`pipe` allows us to execute a chain of functions, then `map` allows us to return the single visitor instead of all the parameters that the server will send us.925 926[source, typescript]927----928import { map, tap } from 'rxjs/operators';929import { Injectable } from '@angular/core';930import { Observable } from 'rxjs';931import { Visitor, FilterVisitor, Pageable } from 'src/app/shared/backendModels/interfaces';932import { HttpClient } from '@angular/common/http';933import { environment } from 'src/environments/environment';934import { AuthService } from 'src/app/core/authentication/auth.service';935import { Router } from '@angular/router';936import { MatSnackBar } from '@angular/material/snack-bar';937 938@Injectable({939  providedIn: 'root'940})941export class LoginService {942 943    private baseUrl = environment.baseUrlRestServices;944    constructor(private router: Router, private http: HttpClient, private authService: AuthService, public snackBar: MatSnackBar) { }945 946    getVisitorByUsername(username: string): Observable<Visitor> {947        const filters: FilterVisitor = new FilterVisitor();948        const pageable: Pageable = new Pageable();949 950        pageable.pageNumber = 0;951        pageable.pageSize = 1;952        filters.username = username;953        filters.pageable = pageable;954        return this.http.post<Visitor>(`${this.baseUrl}` + '/visitormanagement/v1/visitor/search', filters)955       .pipe(956            map(visitors => visitors['content'][0]),957        );958    }959 960    login(username: string, password: string): void {961      // Checks if given username and password are the ones aved in the database962      this.getVisitorByUsername(username).subscribe(963          (visitorFound) => {964              if (visitorFound.username === username && visitorFound.password === password) {965                  this.authService.setUserId(visitorFound.id);966                  this.authService.setLogged(true);967                  this.authService.setUser(visitorFound.username);968                  if (visitorFound.userType === false) {969                      this.authService.setRole('VISITOR');970                      this.router.navigate(['ViewQueue']);971                  } else {972                      this.authService.setLogged(false);973                      this.snackBar.open('access error', 'OK', {974                          duration: 2000,975                        });976                  }977              } else {978                  this.snackBar.open('access error', 'OK', {979                      duration: 2000,980                    });981              }982          },983          (err: any) => {984            this.snackBar.open('access error', 'OK', {985              duration: 2000,986            });987          },988      );989    }990 991    logout(): void {992        this.authService.setLogged(false);993        this.authService.setUser('');994        this.authService.setUserId(0);995        this.router.navigate(['FormLogin']);996    }997}998----999 1000If you remember the devon4j tutorial, we used `Criteria` in order to filter and to search the DB. The `Criteria` require a pageable and you can add extra parameters to get specific results. In `getVisitorByUsername()` you can see the creation of a `FilterVisitor` corresponding to the `Criteria` in the backend. This `FilterVisitor` gets a `Pageable` and a `username` and will return a single result as soon as the POST call is performed. That's why we return the first page and only a single result.1001 1002[NOTE]1003====1004For the tutorial we are only considering the visitor side of the application. That's why we `setLogged(false)` if it's `userType === true` (BOSS side).1005====1006 1007Then we add to the `login-module.ts` and `LoginService`:1008 1009[source, typescript]1010----1011...1012import { LoginService } from './services/login.service';1013 1014@NgModule({1015  ...1016  providers: [LoginService],1017  ...1018})1019...1020----1021 1022After that, we are going to add the `AuthGuard` and the `Auth` into the `shared/core-module.ts`. This will allow us to employ these two services when importing the core module avoiding having to provide these services in every component:1023 1024[source, typescript]1025----1026...1027  providers: [1028    HttpClientModule,1029    AuthService,1030    AuthGuardService,1031  ],1032...1033----1034 1035You need to import these modules as well, as shown earlier.1036 1037Finally, we modify the `login.component.html` to send the form values to the `login.component.ts` like we did with the register form. Afterwards, we are going to modify the `register.components.ts`: When the visitor registers, we can log him in automatically to avoid any nuisances. Let's start with the `login.component.html`:1038 1039[source, html]1040----1041...1042<form (ngSubmit)=""submitLogin(loginForm.form.value)"" #loginForm=""ngForm"" layout-padding>1043...1044----1045 1046As you can see, in the form we just added, the values to the `ngSubmit` allow us to call the method `submitLogin()` within the logic, sending the `loginForm.form.values` which are the form's input values. In the next step we are going to modify the `login.components.ts`, adding the `submitLogin()` method. This method calls the `LoginService`, providing the service with the necessary values received from the form (i.e. the `loginFormValues`).1047 1048[source, typescript]1049----1050...1051import { LoginService } from './services/login.service';1052...1053export class LoginComponent implements OnInit {1054  ...1055  constructor(private router: Router, private loginService: LoginService) {1056  }1057  ...1058  submitLogin(loginFormValues): void {1059    this.loginService.login(loginFormValues.username, loginFormValues.password);1060  }1061}1062----1063 1064Finally, in the `register.components.ts` we are going to inject the `LoginService` and use it to login the visitor after registering him. This will also send the user to the `ViewQueue`, which we will create and secure later in the tutorial.1065 1066[source, typescript]1067----1068import { LoginService } from '../form-login/components/login/services/login.service';1069...1070constructor(private registerService: RegisterService, private router: Router, public snackBar: MatSnackBar,1071    private loginService: LoginService) { } 1072...1073  submitRegister(formValue): void {1074    ...1075    this.registerService.registerVisitor(visitor).subscribe(1076      (visitorResult: Visitor) => {1077        this.loginService.login(visitorResult.username, visitorResult.password);1078      },1079      ...1080    );1081  }1082...1083----1084 1085== Finishing Touches1086 1087Now we only need to generate two more components (`header` and `view-queue`) and services (`AccessCodeService` and `QueueService`) in order to finish the implementation of our _JumpTheQueue_ app.1088 1089=== Separating Header from Layout1090 1091By separating the header on top of the page from the layout, we enable the reuse of this component and reach a better separation of concerns across our application. To do this, we are going to generate a new component inside `angular/src/app/layout/header` via:1092 1093----1094ng generate component layout/header1095----1096 1097Now we are going to add it to the main view `app.component.html`:1098 1099[source, html]1100----1101...1102  <div td-toolbar-content flex>1103    <app-header layout-align=""center center"" layout=""row"" flex></app-header>1104  </div> <!-- Header container-->1105...1106----1107 1108After adding the component to the header view (`app-header`), we are going to modify the HTML of the component (`header.component.html`) and the logic of the component (`header.component.ts`). As a first step, we are going to modify the HTML, adding an icon as a button, which checks whether or not the user is logged in via `*ngIf` by calling the auth service's `isLogged()` method. This will make the icon appear only if the user is logged in:1109 1110[source, html]1111----1112Jump The Queue1113<span flex></span> 1114<button mat-icon-button mdTooltip=""Log out"" (click)=onClickLogout() *ngIf=""authService.isLogged()"">1115  <mat-icon>exit_to_app</mat-icon>1116</button>1117----1118 1119In the header logic (`header.component.ts`) we are simply going to inject the `AuthService` and `LoginService`, then we are going call `logout()` from `LoginService` in the `OnClickLogout()`. Finally, the `AuthService` is needed because it's being used by the HTML template to control if the user is logged in with `isLogged()`:1120 1121[source, typescript]1122----1123...1124  constructor(private authService: AuthService, private loginService: LoginService) { }1125...1126  onClickLogout(): void {1127    this.loginService.logout();1128  }1129...1130----1131 1132Separating components will allow us to keep the code clean and easy to work with.1133 1134=== ViewQueue Component1135 1136For the last view, we are going to learn how to use our Observables on the HTML template directly without having to `subscribe()` to them.1137 1138First, we are going to generate the component via:1139 1140----1141ng generate component view-queue1142----1143 1144After that, we are going to include the component in the `app-routing.module.ts`, also adding the guard, to only allow users that are `VISITOR` to see the component. It is important to insert the following code before `{ path: '**', redirectTo: '/FormLogin', pathMatch: 'full' }`:1145 1146[source, typescript]1147----1148...1149const appRoutes: Routes = [1150  ...1151  { path: 'ViewQueue',1152    component: ViewQueueComponent,1153    canActivate: [AuthGuardService]}, // Redirect if url path is /ViewQueue, check if canActivate() with the AuthGuardService.1154  ...1155];1156...1157----1158 1159Now in order to make this view work, we are going to do these things:1160  1161. Add the `Queue` and `AccessCode` interface in our `angular/src/app/shared/backendModels/interfaces` and their corresponding filters.1162 1163. Generate the `QueueService` and `AccessCodeService` and add the necessary methods.1164 1165. Modify the `view-queue.component.html`.1166 1167. Modify the logic of the component `view-queue.component.ts`.1168 1169First, we are going to add the necessary interfaces. We modify `angular/src/app/shared/backendModels/interfaces.ts` and add the `FilterQueue`, `Queue`, `FilterAccessCode` and `AccessCode`. These are going to be necessary in order to communicate with the backend.1170 1171[source, typescript]1172----1173...1174export class FilterAccessCode {1175    pageable: Pageable;1176    visitorId?: Number;1177    endTime?: string;1178}1179 1180export class FilterQueue {1181    pageable: Pageable;1182    active: boolean;1183}1184 1185export class AccessCode {1186    id?: number;1187    ticketNumber: string;1188    creationTime: string;1189    startTime?: string;1190    endTime?: string;1191    visitorId: number;1192    queueId: number;1193}1194 1195export class Queue {1196    id?: number;1197    name: string;1198    logo: string;1199    currentNumber: string;1200    attentionTime: string;

Showing the first 1,200 of 99281 lines. Download the file for the rest.