Commit c4678c4b authored by Ryan Diehl's avatar Ryan Diehl

Merge branch 'develop' into 'master'

Develop

See merge request !17
parents b4bcc0f1 ebf706af
Pipeline #90433 passed with stages
in 4 minutes and 30 seconds
......@@ -19,7 +19,6 @@
# IDE - VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
......
......@@ -280,6 +280,90 @@
}
}
}
},
"utils-properties": {
"projectType": "library",
"root": "libs/utils/properties",
"sourceRoot": "libs/utils/properties/src",
"prefix": "ut",
"architect": {
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": ["libs/utils/properties/tsconfig.lib.json", "libs/utils/properties/tsconfig.spec.json"],
"exclude": ["**/node_modules/**", "!libs/utils/properties/**"]
}
},
"test": {
"builder": "@nrwl/jest:jest",
"options": {
"jestConfig": "libs/utils/properties/jest.config.js",
"tsConfig": "libs/utils/properties/tsconfig.spec.json",
"setupFile": "libs/utils/properties/src/test-setup.ts"
}
}
},
"schematics": {
"@nrwl/angular:component": {
"styleext": "scss"
}
}
},
"utils-logger": {
"projectType": "library",
"root": "libs/utils/logger",
"sourceRoot": "libs/utils/logger/src",
"prefix": "ut",
"architect": {
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": ["libs/utils/logger/tsconfig.lib.json", "libs/utils/logger/tsconfig.spec.json"],
"exclude": ["**/node_modules/**", "!libs/utils/logger/**"]
}
},
"test": {
"builder": "@nrwl/jest:jest",
"options": {
"jestConfig": "libs/utils/logger/jest.config.js",
"tsConfig": "libs/utils/logger/tsconfig.spec.json",
"setupFile": "libs/utils/logger/src/test-setup.ts"
}
}
},
"schematics": {
"@nrwl/angular:component": {
"styleext": "scss"
}
}
},
"utils-loading-events": {
"projectType": "library",
"root": "libs/utils/loading-events",
"sourceRoot": "libs/utils/loading-events/src",
"prefix": "ut",
"architect": {
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": ["libs/utils/loading-events/tsconfig.lib.json", "libs/utils/loading-events/tsconfig.spec.json"],
"exclude": ["**/node_modules/**", "!libs/utils/loading-events/**"]
}
},
"test": {
"builder": "@nrwl/jest:jest",
"options": {
"jestConfig": "libs/utils/loading-events/jest.config.js",
"tsConfig": "libs/utils/loading-events/tsconfig.spec.json",
"setupFile": "libs/utils/loading-events/src/test-setup.ts"
}
}
},
"schematics": {
"@nrwl/angular:component": {
"styleext": "scss"
}
}
}
},
"cli": {
......
# @psu/utils/loading-events
This library is used to dispatch a `CustomEvent` to the DOM when the application
is done bootstrapping. Our index.html files show a loading banner outside of Angular.
This library is used to communicate that the app is ready to load, which fades out
the loading banner and fades in the application.
## Running unit tests
Run `nx test utils-loading-events` to execute the unit tests.
module.exports = {
name: 'utils-loading-events',
preset: '../../../jest.config.js',
coverageDirectory: '../../../coverage/libs/utils/loading-events',
snapshotSerializers: [
'jest-preset-angular/AngularSnapshotSerializer.js',
'jest-preset-angular/HTMLCommentSerializer.js'
]
};
{
"lib": {
"entryFile": "src/index.ts"
}
}
export { LoadingEvents } from './lib/loading-events';
export { LoadingEventsModule } from './lib/loading-events.module';
import { async, TestBed } from '@angular/core/testing';
import { LoadingEventsModule } from './loading-events.module';
describe('LoadingEventsModule', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [LoadingEventsModule]
}).compileComponents();
}));
it('should create', () => {
expect(LoadingEventsModule).toBeDefined();
});
});
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { LoggerModule } from '@psu/utils/logger';
import { LoadingEvents } from './loading-events';
@NgModule({
imports: [CommonModule, LoggerModule],
providers: [LoadingEvents]
})
export class LoadingEventsModule {}
import { DOCUMENT } from '@angular/common';
import { Inject, Injectable } from '@angular/core';
import { Logger } from '@psu/utils/logger';
@Injectable()
export class LoadingEvents {
private doc: Document;
private isAppReady: boolean;
constructor(@Inject(DOCUMENT) doc: any, private log: Logger) {
this.doc = doc;
this.isAppReady = false;
}
public triggerAppReady(): void {
if (this.isAppReady) {
return;
}
this.log.debug('appready event triggered');
this.doc.dispatchEvent(this.createEvent('appready', true, false));
this.isAppReady = true;
}
private createEvent(eventType: string, bubbles: boolean, cancelable: boolean): Event {
const customEvent: any = new CustomEvent(eventType, {
bubbles,
cancelable
});
return customEvent;
}
}
import 'jest-preset-angular';
import '../../../../jestGlobalMocks';
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
"types": ["node", "jest"]
},
"include": ["**/*.ts"]
}
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../../dist/out-tsc",
"target": "es2015",
"declaration": true,
"inlineSources": true,
"types": [],
"lib": ["dom", "es2018"]
},
"angularCompilerOptions": {
"annotateForClosureCompiler": true,
"skipTemplateCodegen": true,
"strictMetadataEmit": true,
"fullTemplateTypeCheck": true,
"strictInjectionParameters": true,
"enableResourceInlining": true
},
"exclude": ["src/test-setup.ts", "**/*.spec.ts"]
}
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../../dist/out-tsc",
"module": "commonjs",
"types": ["jest", "node"]
},
"files": ["src/test-setup.ts"],
"include": ["**/*.spec.ts", "**/*.d.ts"]
}
{
"extends": "../../../tslint.json",
"rules": {
"directive-selector": [true, "attribute", "ut", "camelCase"],
"component-selector": [true, "element", "ut", "kebab-case"]
}
}
# @psu/utils/logger
`Logger` is a simple facade around console logging. In the future, if we are
able to add some type of RESTful logging (Splunk for example), it would go here.
## Usage
1. Define logger options in your environment files
```typescript
// environment.ts
export function loggerOptions(): Options {
return { level: Level.LOG };
}
export const environment = {
production: false,
loggerOptions
};
```
2. Import LoggerModule into your AppModule
```typescript
imports: [LoggerModule.forRoot(environment.loggerOptions)];
```
3. Inject `Logger` and log stuff
## Running unit tests
Run `nx test utils-logger` to execute the unit tests.
module.exports = {
name: 'utils-logger',
preset: '../../../jest.config.js',
coverageDirectory: '../../../coverage/libs/utils/logger',
snapshotSerializers: [
'jest-preset-angular/AngularSnapshotSerializer.js',
'jest-preset-angular/HTMLCommentSerializer.js'
]
};
{
"lib": {
"entryFile": "src/index.ts"
}
}
export { Level } from './lib/log-level.model';
export { LoggerModule } from './lib/logger.module';
export { Logger } from './lib/logger.service';
/**
* The available options to set the Level of the Logger.
* See {@link Logger}.
*/
export enum Level {
OFF = 0,
ERROR = 1,
WARN = 2,
INFO = 3,
DEBUG = 4,
LOG = 5
}
import { async, TestBed } from '@angular/core/testing';
import { LoggerModule } from './logger.module';
describe('LoggerModule', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [LoggerModule]
}).compileComponents();
}));
it('should create', () => {
expect(LoggerModule).toBeDefined();
});
});
import { ModuleWithProviders, NgModule } from '@angular/core';
import { Logger, Options } from './logger.service';
@NgModule({})
export class LoggerModule {
public static forRoot(options: () => Options): ModuleWithProviders {
return {
ngModule: LoggerModule,
providers: [{ provide: Options, useFactory: options }, Logger]
};
}
}
import { Logger, Options } from './logger.service';
import { TestBed } from '@angular/core/testing';
describe('LoggerService', () => {
let service: Logger;
beforeEach(() => {
TestBed.configureTestingModule({
providers: [Logger, { provide: Options, useValue: {} }]
});
service = TestBed.get(Logger);
});
it('should create', () => {
expect(service).toBeDefined();
});
});
import { Injectable } from '@angular/core';
import { Level } from './log-level.model';
/**
* Logger options.
* See {@link Logger}.
*
* level - How much detail you want to see in the logs, 0 being off, 1 being the less detailed, 5 being the most. Defaults to LOG.
*/
export class Options {
level: Level;
}
// For browsers that don't implement the debug method, log will be used instead.
const CONSOLE_DEBUG_METHOD = console['debug'] ? 'debug' : 'log';
const DEFAULT_OPTIONS: Options = {
level: Level.LOG
};
@Injectable()
export class Logger {
private _level: Level;
public Level: any = Level;
constructor(options: Options) {
const { level } = Object.assign({}, DEFAULT_OPTIONS, options);
this._level = level;
}
public error(message?: any, ...optionalParams: any[]) {
if (this.isErrorEnabled()) {
console.error.apply(console, arguments);
}
}
public warn(message?: any, ...optionalParams: any[]) {
if (this.isWarnEnabled()) {
console.warn.apply(console, arguments);
}
}
public info(message?: any, ...optionalParams: any[]) {
if (this.isInfoEnabled()) {
// tslint:disable-next-line:no-console
console.info.apply(console, arguments);
}
}
public debug(message?: any, ...optionalParams: any[]) {
if (this.isDebugEnabled()) {
(<any>console)[CONSOLE_DEBUG_METHOD].apply(console, arguments);
}
}
public log(message?: any, ...optionalParams: any[]) {
if (this.isLogEnabled()) {
// tslint:disable-next-line: no-console
console.log.apply(console, arguments);
}
}
public isErrorEnabled = (): boolean => this.level >= Level.ERROR;
public isWarnEnabled = (): boolean => this.level >= Level.WARN;
public isInfoEnabled = (): boolean => this.level >= Level.INFO;
public isDebugEnabled = (): boolean => this.level >= Level.DEBUG;
public isLogEnabled = (): boolean => this.level >= Level.LOG;
public get level(): Level {
return this._level;
}
public set level(level: Level) {
this._level = level;
}
}
import 'jest-preset-angular';
import '../../../../jestGlobalMocks';
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
"types": ["node", "jest"]
},
"include": ["**/*.ts"]
}
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../../dist/out-tsc",
"target": "es2015",
"declaration": true,
"inlineSources": true,
"types": [],
"lib": ["dom", "es2018"]
},
"angularCompilerOptions": {
"annotateForClosureCompiler": true,
"skipTemplateCodegen": true,
"strictMetadataEmit": true,
"fullTemplateTypeCheck": true,
"strictInjectionParameters": true,
"enableResourceInlining": true
},
"exclude": ["src/test-setup.ts", "**/*.spec.ts"]
}
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../../dist/out-tsc",
"module": "commonjs",
"types": ["jest", "node"]
},
"files": ["src/test-setup.ts"],
"include": ["**/*.spec.ts", "**/*.d.ts"]
}
{
"extends": "../../../tslint.json",
"rules": {
"directive-selector": [true, "attribute", "ut", "camelCase"],
"component-selector": [true, "element", "ut", "kebab-case"]
}
}
......@@ -5,7 +5,9 @@
"@angular/common": "^8.0.0",
"@angular/core": "^8.0.0",
"@angular/cdk": "^8.2.3",
"ramda": "^0.27.0"
"ngx-cookie": "^4.1.2",
"ramda": "^0.27.0",
"short-uuid": "^3.1.1"
},
"private": false,
"repository": {
......
# @psu/utils/properties
This library handles loading application properties asyncronously.
Typical Angular documentation shows the use of `environment.ts` and `environment.prod.ts` to
store application properties. However, that strategy means that the properties are compile-time
dependencies - so in order to change a property at runtime, you need to re-compile the whole app.
This library is the first piece of supporting property changes at runtime. `PropetiesService` will
load the property file via HTTP, and exposes a `Promise<T>` to work with Angular's `APP_INITIALIZER`.
## Usage
1. Import PropertiesModule into your AppModule
2. Define an interface(s) that describes the shape of your application properties.
```typescript
import { SecurityConfig } from '@psu/security';
export interface MyAppProperties {
myAppConfig: MyAppConfig;
security: SecurityConfig;
}
export interface MyAppConfig {
someUrl: string;
doStuff: boolean;
}
```
3. Setup an [APP_INITIALIZER](https://angular.io/api/core/APP_INITIALIZER)
to load properties and delay loading of the application by returning a Promise
```typescript
// inside AppMdoule's providers array:
{
provide: MY_APP_CONFIG, // provide your app's token
useValue: {} // provide default values for the token
},
{ provide: SECURITY_CONFIG, useValue: {} },
{
provide: APP_INITIALIZER,
useFactory: initProperties,
multi: true,
deps: [
PropertiesService,
MY_APP_CONFIG, // your app config injection token
SECURITY_CONFIG
]
}
// Define the initProperties function
export function initProperties(
propertiesService: PropertiesService<MyAppProperties>,
myAppConfig: MyAppConfig,
securityConfig: SecurityConfig): () => Promise<MyAppProperties> {
return () => propertiesService.load('my-app').then(props => {
// populate injection tokens with values from property file
// "props" is of type MyAppProperties
Object.assign(myAppConfig, p.myAppConfig);
Object.assign(securityConfig, p.security);
});
}
```
## Running unit tests
Run `ng test utils-properties` to execute the unit tests.
module.exports = {
name: 'utils-properties',
preset: '../../../jest.config.js',
coverageDirectory: '../../../coverage/libs/utils/properties',
snapshotSerializers: [
'jest-preset-angular/AngularSnapshotSerializer.js',
'jest-preset-angular/HTMLCommentSerializer.js'
]
};
{
"lib": {
"entryFile": "src/index.ts"