WTI UI Project Implementation Details - pc2ccs/pc2v9 GitHub Wiki

Overview

WTI-UI is an Eclipse Java project which provides the "front-end" code for the PC2v9 Web Team Interface (WTI). The WTI-UI project utilizes services provided by the WTI-API project, which implements the "back-end" (server-side) portion of the overall WTI web team interface. Like the WTI-API project, the WTI-UI Java Project is housed in the projects folder of the pc2v9 project.

WTI-UI is implemented using Angular and comprises the browser-side code which displays the PC² web-based team interface in the form of a single-page application (SPA). This wiki page gives some details on the implementation of the WTI-UI project. Familiarity with the basics of building single-page applications using Angular is necessary in order to understand many of the details of the WTI-UI implementation.

The WTI project (both the front-end -UI component and the back-end -API component) was developed by a team of students from Eastern Washington University (EWU) consisting of Josie Isaacson, Andrew Combs, Ethan Holman, and Danielle Frodge, under the direction of EWU Professor Tom Capaul. The project was ported into the Eclipse and pc2v9 GitHub environments by John Clevenger.

Many of the details presented in this wiki page were taken from Ethan Holman's videos "WTI_UI_Overview.mov" and "WTI_UI_Services.mov", which can be found in the _original _WebTeamClient repository in the /pc2v9/projects/EWWebTeam/FINAL DOCUMENTATION/Documentation/Tech Docs folder. (Note that this refers to the original EWWebTeam project repository, not the current WTI GitHub repository; these .mov files were removed from the GitHub repo due to their very large size.)

Top-level Project Organization

WTI-UI is an "Angular application"; most of the code for WTI-UI is written in TypeScript and contained under a top-level project folder named src (see below). The WTI-UI project also contains the following additional top-level folders:

  • Web App Libraries, a link to a library of .jar files in the separate WTI-API project.
  • .vscode, a holdover from the original VSCode implementation of the EWU WebTeamClient project (from which the WTI project was extracted).
  • e2e, a folder containing an end-to-end unit test of the WTI-UI project based on Protractor, an end-to-end unit test scripting framework for Angular applications. Note that in order to run the e2e test it is necessary to install Protractor (see the above link for further information).
  • Final EWU Student Documentation, the complete set of documentation delivered at the end of their project by the EWU students who implemented the initial version of the Web Team Interface.

The WTI-UI project may also contain the following folders:

  • dist, containing the "distribution" form of the project.
  • node_modules, a collection of node.js modules used by the Angular code.

These last two folders will only be present if the WTI-UI project has been built. node_modules will be present after the first time the project is built. The dist folder will be present after the first time the project is built, but depending on how the project was built it may be empty (specifically, a build initiated by the packageWTI.xml Ant file will cause the contents of dist to be moved; see WTI Build Package Details for further information about building the WTI-UI project).

The top-level WTI-UI project also contains, in addition to the standard Eclipse project configuration files (.classpath, .project, .gitignore, etc.), a set of configuration files for the Angular application. These include:

  • angular.json, which describes the top-level organization of the Angular application (the settings and build architecture).
  • package.json and package-lock.json, which define the dependencies for the WTI-UI project
  • tslint.json, a set of tslint rules for applying linting to the TypeScript code.

Finally, the top-level WTI-UI project contains README.md, a general discussion of the WTI-UI project. In particular this file contains information of interest to developers regarding running individual component tests for the Angular application.

src Folder Organization

The src folder contains the following:

  • app, a folder holding the main code of the Angular application.
  • assets, a folder holding assets used by the application, such as image files and font files.
  • environments, a folder holding TypeScript files defining both development and production environments. See the section below on Environments for details.
  • styles, a folder holding a collection of .css and .sccs (Sass-CSS) style sheets used by the project.
  • index.html, the main HTML into which the Angular application inserts application code.
  • various additional TypeScript, JavaScript, and JSON files used for configuration and testing.

src/app Organization

The src/app folder contains the main body of the WTI-UI application. This includes:

  • app.module.ts, which is the traditional "main" for an Angular TypeScript app. This file defines an Angular module (@NgModule) named AppModule which it exports as class AppModule. This is the main WTI-UI application module.

  • app-routing.module.ts, which defines an Angular module class AppRoutingModule. This class uses the Angular Routing Module to specify Routes which map URL elements (such as /login, /runs, /clarifications, etc.) to corresponding components, which are the Angular elements which manage views of a section of screen space. app-routing.module.ts also sets the authentication requirements for accessing these Routes (see below).

  • a modules folder containing "application features" in separate subfolders:

    • clarifications
    • login
    • options
    • runs
    • scoreboard

    Each of these defines an Angular module implementing a specific feature of the WTI-UI single-page application. Each of these Angular modules defines a corresponding component which is mapped (by the routing module, see above) from a URL element. clarifications, login, options, runs, and scoreboard are the only routed modules in WTI-UI. Each of these modules defines a .html template for the corresponding application page (for example, clarifications-page.component.html), together with a TypeScript file (for example, clarifications-page.component.ts) which defines the Angular component for the page along with a class (for example, class ClarificationsPageComponent) which defines the Angular methods which operate on the corresponding page.

  • Also under src/app/modules are core and shared, which contain application-wide modules.

    • core is where all the services and models which are used to communicate with the WTI-API back-end are stored (see below).
    • shared contains components which are shared between multiple application pages. File shared.module.ts defines an Angular module class SharedModule which contains components (defined in app.modules.shared.components) which represent components shared in common between all the SPA application pages. Examples include:
      • The "About WTI" information dialog visible via a link on every WTI page
      • The application page header containing banners/logos and links to other pages
      • The application page footer containing the copyright notice and link to the "About" dialog
      • Selectors ("drop-down lists") for displaying/choosing things like language or problem

See WTI UI Angular Project Structure for details on the structure of the Angular application which comprises the WTI-UI runtime user interface.

Services Overview

The core/services folder contains TypeScript files defining services which send requests to the back-end API to get things like lists of clarifications or to submit a new run. The service files include:

  • contest.service.ts, which defines class ContestService extends IContestService that provides service methods such as
    • getLanguages()
    • getProblems()
    • getJudgements()
    • getClarifications()
    • getIsContestRunning()
  • team.service.ts, which defines class TeamsService extends ITeamsService that provides service methods such as
    • login(LoginCredentials)
    • logout()
    • submitRun(Submission)
    • getRuns()
    • postClarification(NewClarification)_
  • websocket.service.ts, which defines class WebsocketService extends IWebsocketService that provides service methods such as
    • startWebsocket()
    • stopWebsocket()

All the above services are coded as implementations of abstractions. Specifically, folder app/modules/core/abstract-services contains definitions of abstract classes (e.g. abstract class IContestService) defining the interface required by implementations of the corresponding service.

(Note the mixing of the Java notions of "Interface" and "Abstract Class" in the WTI-UI TypeScript code: where IContestService in Java would normally represent an interface type, in the WTI-UI TypeScript code the file i-contest.service.ts for example exports abstract class IContestService, an abstract class that contains both abstract method definitions as well as concrete code. In conventional Java code this would be called abstract class AbstractContestService.)

The core services all have two implementations: the actual service (which communicates with the WTI-API back-end) and a mock implementation. The mock implementations are stored in the core/services directory alongside their actual-service counterparts. Using a mock service eliminates the need to have a back-end connected to a PC2 server, which is very useful when doing UI development work.

"Mock mode" is controlled by an entry useMock: in the current environment; setting this entry true causes all services to use their "mock counterparts". See the section below on Environments for further details.

Additional Core Components

The app/modules/core folder contains two additional subfolders:

  • models, which contains TypeScript class definitions for the basic types used in common between the front-end and backend: Clarification, ContestLanguage, ContestProblem, Submission, etc.
  • auth, which contains TypeScript classes supporting application authentication services:
    • auth.service.ts supports logging in through the ITeamsService and saving the login token returned from the WTI-API back-end.
    • auth.interceptor.ts intercepts all HTTP requests being sent to the back-end interface and adds the current team token as a "header" in the HTTP request. This allows other services to make HTTP requests without having to worry about passing authentication header information in the request. The interceptor only adds header tokens if the client is currently logged in.
    • auth.guard.ts defines a class AuthGuard which prevents accessing certain "routes" if the client is not currently logged in (see app-routing.module.ts, the main routing module, for examples of path routes which use AuthGuard to control whether the client can currently access the given path).

Environments

The files under src/environments define different environments (that is, sets of environment variable values) for the Angular build process. The environment variables defined by the environment files include:

  • production, whose value (true or false) indicates whether an Angular build is a production build or a development build (see below).
  • baseUrl, the URL at which the WTI-UI Angular front-end application expects to access the Web Team Server (WTI-API back-end) using HTTP requests.
  • websocketUrl, the URL at which the WTI-UI Angular front-end application expects to access the Web Team Server (WTI-API back-end) websockets (see below for more on the use and implementation of websockets in the project).
  • useMock, whose boolean value determines whether services make calls to the WTI-API back-end or instead rely on their mock counterparts (see above).

Two Angular environment files exist in the WTI-UI project: environment.ts and environment.prod.ts. The primary difference is that the former sets production=false while the latter sets production=true. The value of production is checked by the main startup file src/main.ts prior to bootstrapping app/app.module.ts as described above. Production builds use Angular's enableProdMode, which disables assertions and other development-mode runtime checks).

TODO: document the use of ng build --prod. (See srv/environments/environment.ts). Need to update buildWTI.xml ?

One problem with specifying environment values such as baseUrl in an Angular environment file is that the baseUrl becomes "hard-coded" in the Angular application. This works fine during development when the application is running on a known computer. However, it means that the application won't work properly when run on a different computer.

The solution to this problem in the WTI project is to determine the URL, and then to embed that URL into the Angular application, at runtime. "Runtime" for the WTI project is when the WTI-API web team server is started (see Web Access and WTI-API Project Implementation Details). To implement this, when the web team server (the WTI-API project) is started it determines the IP and port on which it is running and then saves that information in a file named appconfig.json in the WTI-UI assets folder. When the WTI-UI Angular application starts, it reads values for baseUrl and websocketUrl from this file and uses those as the actual URLs for communicating with the WTI-API back-end.

More on Services

Websockets

The WTI project uses websockets to pass messages back and forth between the WTI-UI front-end and the WTI-API back-end. Websockets are created/started on the WTI-UI side, during the login phase in the onSubmit() method in the login-page.component.ts file, which is invoked when the user clicks the Login button. Upon successful validation of user login credentials, onSubmit() invokes the startWebsocket() method in the websocket.service.ts implementation module, creating a websocket connection between the WTI-UI front-end and the WTI-API web team server back-end.

startWebsocket() constructs each new Websocket by passing to the constructor a string which is a concatenation of the websocketUrl (taken from the environment, as described above) and the auth service token associated with the current login. Since every user (login) has its own unique token, each websocket connection to the WTI-API back-end has a unique name which is associated with the team login. startWebsocket() then uses method addEventListener() on the websocket to add a listener for events of type message coming from the websocket.

Websocket Messages

Websocket messages are (always) JSON strings. When a message event is received from the websocket, the websocket.service.ts handleIncomingMessage() method is invoked. This method parses the incoming (JSON) message, extracting the message data and forwarding it to method incomingMessage(), which is defined in the WebsocketService class's IWebsocketService parent class. (The reason for putting the actual message handling in the parent class is so that the same code can be used to process messages whether the current service implementation is an actual service or a Mock service as described above.)

Method incomingMessage() uses a switch statement based on the message type to process different types of messages: runs (test and judged), clarification, or contest_clock. The handling of each message type is defined in the corresponding service module method invoked by incomingMessage().

For example, a judged message results in a call to the runsUpdated.next() method in the ITeamsService class. runsUpdated is an RxJS Subject -- which is just a special type of Observable (in the Observer design pattern sense). Objects such as the Angular RunsPageComponent class (defined in runs-page-component.ts) register (or subscribe) to listen for (or observe) updates to the runsUpdated Subject. Invoking next() in the runsUpdated Subject makes a callback to method loadRuns() in the RunsPageComponent class (because RunsPageComponent registered loadRuns() as a callback method when it subscribes to the runsUpdated Subject in method ngOnInit() in runs-page.component.ts). The effect is that an incoming judged message updates the stored list of runs for the team.

clarification messages work analogously to judged messages: an incoming clarification message triggers an update to a clarificationsUpdated Subject which in turn makes a callback to a method to update the clarifications list. (The method, in clarifications-page.component.ts, is incorrectly named loadRuns(); copy/paste strikes again. However, it properly updates the clarifications list, not the runs list.)

contest_clock messages indicate a change in the state of the contest clock. However, they do not contain information giving the actual current state. To handle this, incomingMessage() makes a WTI-API call (via ContestService.getIsContestRunning()) to determine the current contest clock state. It then makes a callback to a contestClock Subject updating the contest clock state. This state is monitored by certain objects such as the ProblemSelectorComponent (the "problems drop-down list" defined in shared/components/problem-selector/problem-selector.component.ts), which listens for ("subscribes to") changes in the contestClock Subject to determine whether the list of contest problems is allowed to be displayed or not.

Some types of messages (e.g. judged and clarification) are indications of things which a team might want to be immediately notified about -- a judgement has been received or a clarification request has been answered, for example. In these cases incomingMessage() also invokes a corresponding method in the UiHelperService class. These methods check to see whether the corresponding pop-up notification type is currently enabled, and if so they invoke an appropriate pop-up dialog using the Angular MatDialog library.

Adding New Services

TODO add a general description of how to add, say, a scoreboard service. (This should probably be done as a separate wiki page...)

Development and Testing

The WTI-UI project was developed using the Angular CLI tools. These tools provide a command line interface to Angular services including:

  • ng new, which initializes a new Angular project.
  • ng generate, which generates components, routes, and services for the new project.
  • ng serve, which runs a server to serve the application to web browsers.

These tools can be a handy light-weight alternative to building and running the WTI-API project every time it is desired to test changes in the WTI-UI application during development. The Angular CLI tools can be installed in Eclipse from the Eclipse MarketPlace.

See Also