├── libs ├── .gitkeep ├── fruit-basket │ ├── index.ts │ └── src │ │ ├── counter-display │ │ ├── counter-display.component.ts │ │ └── counter-display.component.html │ │ ├── basket-ui │ │ ├── basket-ui.component.html │ │ └── basket-ui.component.ts │ │ ├── fruit-basket.module.ts │ │ └── state │ │ └── state.ts ├── employee-list │ ├── index.ts │ └── src │ │ ├── employee-list.module.ts │ │ └── employee-list │ │ ├── employee-list.component.html │ │ └── employee-list.component.ts ├── employee-search │ ├── index.ts │ └── src │ │ ├── employee-search.module.ts │ │ └── employee-list │ │ ├── employee-list.component.html │ │ └── employee-list.component.ts ├── retry-loader │ ├── index.ts │ └── src │ │ ├── retry-loader.module.ts │ │ ├── retry-loader.module.spec.ts │ │ ├── faulty.ts │ │ └── load-with-retry.ts ├── employee-display │ ├── index.ts │ └── src │ │ ├── employee-display.module.spec.ts │ │ ├── employee-detail-view │ │ ├── employee-detail-view.component.html │ │ └── employee-detail-view.component.ts │ │ ├── employee-list-table-view │ │ ├── employee-list-table-view.component.ts │ │ └── employee-list-table-view.component.html │ │ └── employee-display.module.ts ├── employee-management │ ├── index.ts │ └── src │ │ ├── employee-management.module.spec.ts │ │ ├── add-employee │ │ ├── add-employee.component.html │ │ └── add-employee.component.ts │ │ ├── edit-employee │ │ ├── edit-employee.component.html │ │ └── edit-employee.component.ts │ │ ├── employee-management.module.ts │ │ ├── employee-management.routes.ts │ │ ├── employee-fields │ │ ├── employee-fields.component.ts │ │ └── employee-fields.component.html │ │ ├── employee-navigation.service.ts │ │ └── management-screen │ │ ├── management-screen.component.html │ │ └── management-screen.component.ts ├── video-stat-dashboard │ ├── index.ts │ └── src │ │ ├── top-list │ │ ├── top-list-display.component.css │ │ ├── top-list.component.html │ │ ├── top-list-display.component.ts │ │ ├── top-list-display.component.html │ │ └── top-list.component.ts │ │ ├── video-container │ │ ├── video-container.component.html │ │ ├── video-container-display.component.html │ │ ├── video-container.component.ts │ │ └── video-container-display.component.ts │ │ ├── dashboard.component.css │ │ ├── views-filter │ │ ├── views-filter.component.ts │ │ ├── views-filter.component.html │ │ ├── views-filter-display.component.html │ │ └── views-filter-display.component.ts │ │ ├── services │ │ ├── top-list.service.ts │ │ ├── app.service.ts │ │ ├── dashboard.service.ts │ │ ├── views-filter.service.ts │ │ ├── mock-video-list.ts │ │ └── views-breakdown.service.ts │ │ ├── +state │ │ ├── video-stats.init.ts │ │ ├── video-stats.effects.ts │ │ ├── video-stats.interfaces.ts │ │ ├── video-stats.actions.ts │ │ └── video-stats.reducer.ts │ │ ├── dashboard.component.ts │ │ ├── dashboard.component.html │ │ ├── views-breakdown │ │ ├── views-breakdown-display.component.ts │ │ ├── filter-state-display.component.ts │ │ ├── filter-state-display.component.html │ │ ├── views-breakdown.component.html │ │ ├── views-breakdown.component.ts │ │ └── views-breakdown-display.component.html │ │ └── video-stat-dashboard.module.ts ├── age-range │ ├── index.ts │ └── src │ │ ├── age-range.module.spec.ts │ │ ├── age-range.module.ts │ │ ├── age-ranges.ts │ │ └── enum-to-range.pipe.ts ├── app-schema │ ├── index.ts │ ├── src │ │ ├── employee-listing.ts │ │ └── employee.ts │ └── README.md └── employee-api │ ├── index.ts │ └── src │ ├── employee-api.module.spec.ts │ ├── employee-api.module.ts │ └── employee-api.service.ts ├── apps ├── .gitkeep ├── admin │ ├── src │ │ ├── assets │ │ │ ├── .gitkeep │ │ │ └── nx-logo.png │ │ ├── app │ │ │ ├── app.component.css │ │ │ ├── app.component.ts │ │ │ ├── app.component.html │ │ │ ├── app.component.spec.ts │ │ │ └── app.module.ts │ │ ├── environments │ │ │ ├── environment.prod.ts │ │ │ └── environment.ts │ │ ├── favicon.ico │ │ ├── styles.css │ │ ├── index.html │ │ ├── main.ts │ │ ├── tsconfig.app.json │ │ └── polyfills.ts │ ├── e2e │ │ ├── app.po.ts │ │ ├── app.e2e-spec.ts │ │ └── tsconfig.e2e.json │ └── README.md ├── agent │ ├── src │ │ ├── assets │ │ │ ├── .gitkeep │ │ │ └── nx-logo.png │ │ ├── app │ │ │ ├── app.component.css │ │ │ ├── app.component.ts │ │ │ ├── app.component.html │ │ │ ├── app.component.spec.ts │ │ │ └── app.module.ts │ │ ├── environments │ │ │ ├── environment.prod.ts │ │ │ └── environment.ts │ │ ├── styles.css │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── main.ts │ │ ├── tsconfig.app.json │ │ └── polyfills.ts │ ├── e2e │ │ ├── app.po.ts │ │ ├── app.e2e-spec.ts │ │ └── tsconfig.e2e.json │ └── README.md └── portal │ ├── src │ ├── assets │ │ ├── .gitkeep │ │ └── nx-logo.png │ ├── app │ │ ├── app.component.css │ │ ├── app.component.ts │ │ ├── app.component.html │ │ ├── app.component.spec.ts │ │ └── app.module.ts │ ├── environments │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── styles.css │ ├── favicon.ico │ ├── index.html │ ├── tsconfig.app.json │ ├── main.ts │ └── polyfills.ts │ ├── e2e │ ├── app.po.ts │ ├── app.e2e-spec.ts │ └── tsconfig.e2e.json │ └── README.md ├── servers ├── node │ ├── .gitignore │ ├── src │ │ ├── rest │ │ │ └── rest.ts │ │ ├── sse │ │ │ ├── sse.ts │ │ │ ├── channels.ts │ │ │ └── fx.ts │ │ ├── main.ts │ │ └── graphql │ │ │ └── graphql.ts │ ├── tsconfig.json │ ├── package.json │ ├── tslint.json │ ├── README.md │ └── db.json └── README.md ├── .travis.yml ├── proxy.conf.json ├── .vscode ├── settings.json └── tasks.json ├── .editorconfig ├── tsconfig.spec.json ├── tsconfig.compodoc.json ├── tsconfig.json ├── .gitignore ├── protractor.conf.js ├── test.js ├── LICENSE ├── karma.conf.js ├── package.json ├── tslint.json ├── README.md └── .angular-cli.json /libs/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/.gitkeep: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /apps/admin/src/assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/agent/src/assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/portal/src/assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/admin/src/app/app.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/agent/src/app/app.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/portal/src/app/app.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /libs/fruit-basket/index.ts: -------------------------------------------------------------------------------- 1 | export { FruitBasketModule } from './src/fruit-basket.module'; 2 | -------------------------------------------------------------------------------- /servers/node/.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | node_modules 3 | *.log 4 | typings 5 | *.zip 6 | *.log 7 | -------------------------------------------------------------------------------- /libs/employee-list/index.ts: -------------------------------------------------------------------------------- 1 | export { EmployeeListModule } from './src/employee-list.module'; 2 | -------------------------------------------------------------------------------- /libs/employee-search/index.ts: -------------------------------------------------------------------------------- 1 | export { EmployeeSearchModule } from './src/employee-search.module'; 2 | -------------------------------------------------------------------------------- /libs/retry-loader/index.ts: -------------------------------------------------------------------------------- 1 | export * from './src/load-with-retry'; 2 | export * from './src/faulty'; 3 | -------------------------------------------------------------------------------- /libs/employee-display/index.ts: -------------------------------------------------------------------------------- 1 | export { EmployeeDisplayModule } from './src/employee-display.module'; 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "8" 4 | cache: 5 | yarn: true 6 | script: ./build.sh 7 | -------------------------------------------------------------------------------- /apps/admin/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /apps/agent/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /apps/agent/src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | -------------------------------------------------------------------------------- /apps/portal/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /apps/portal/src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | -------------------------------------------------------------------------------- /libs/employee-management/index.ts: -------------------------------------------------------------------------------- 1 | export { EmployeeManagementModule } from './src/employee-management.module'; 2 | -------------------------------------------------------------------------------- /libs/video-stat-dashboard/index.ts: -------------------------------------------------------------------------------- 1 | export { VideoStatDashboardModule } from './src/video-stat-dashboard.module'; 2 | 3 | -------------------------------------------------------------------------------- /libs/video-stat-dashboard/src/top-list/top-list-display.component.css: -------------------------------------------------------------------------------- 1 | .active { 2 | color: #26a69a !important; 3 | } 4 | -------------------------------------------------------------------------------- /apps/admin/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OasisDigital/angular-enterprise-example/HEAD/apps/admin/src/favicon.ico -------------------------------------------------------------------------------- /apps/agent/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OasisDigital/angular-enterprise-example/HEAD/apps/agent/src/favicon.ico -------------------------------------------------------------------------------- /apps/portal/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OasisDigital/angular-enterprise-example/HEAD/apps/portal/src/favicon.ico -------------------------------------------------------------------------------- /libs/age-range/index.ts: -------------------------------------------------------------------------------- 1 | export { AgeRangeModule } from './src/age-range.module'; 2 | export { ageRanges } from './src/age-ranges'; 3 | -------------------------------------------------------------------------------- /libs/app-schema/index.ts: -------------------------------------------------------------------------------- 1 | export { IEmployeeListing } from './src/employee-listing'; 2 | export { IEmployee } from './src/employee'; 3 | -------------------------------------------------------------------------------- /apps/admin/src/assets/nx-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OasisDigital/angular-enterprise-example/HEAD/apps/admin/src/assets/nx-logo.png -------------------------------------------------------------------------------- /apps/agent/src/assets/nx-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OasisDigital/angular-enterprise-example/HEAD/apps/agent/src/assets/nx-logo.png -------------------------------------------------------------------------------- /apps/portal/src/assets/nx-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OasisDigital/angular-enterprise-example/HEAD/apps/portal/src/assets/nx-logo.png -------------------------------------------------------------------------------- /apps/admin/src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | 3 | select { 4 | display: inherit; 5 | } 6 | -------------------------------------------------------------------------------- /libs/app-schema/src/employee-listing.ts: -------------------------------------------------------------------------------- 1 | export interface IEmployeeListing { 2 | id: number; 3 | first_name: string; 4 | last_name: string; 5 | } 6 | -------------------------------------------------------------------------------- /libs/employee-api/index.ts: -------------------------------------------------------------------------------- 1 | export { EmployeeApiModule } from './src/employee-api.module'; 2 | export { EmployeeApi } from './src/employee-api.service'; 3 | -------------------------------------------------------------------------------- /proxy.conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "/api/*": { 3 | "target": "http://localhost:8005", 4 | "pathRewrite": {"^/api": ""}, 5 | "logLevel": "debug" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /libs/video-stat-dashboard/src/video-container/video-container.component.html: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /libs/app-schema/src/employee.ts: -------------------------------------------------------------------------------- 1 | import { IEmployeeListing } from './employee-listing'; 2 | 3 | export interface IEmployee extends IEmployeeListing { 4 | email: string; 5 | hours_worked: number; 6 | hourly_wage: number; 7 | } 8 | -------------------------------------------------------------------------------- /libs/retry-loader/src/retry-loader.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | 4 | @NgModule({ 5 | imports: [CommonModule] 6 | }) 7 | export class RetryLoaderModule {} 8 | -------------------------------------------------------------------------------- /servers/README.md: -------------------------------------------------------------------------------- 1 | # Server(s) 2 | 3 | Server applications go here. 4 | 5 | The ideal vision is to have ~3 servers in ~3 different languages/platforms. This 6 | would be a good microcosm of the complexity of many enterprise systems. 7 | -------------------------------------------------------------------------------- /libs/video-stat-dashboard/src/top-list/top-list.component.html: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /libs/age-range/src/age-range.module.spec.ts: -------------------------------------------------------------------------------- 1 | import { AgeRangeModule } from './age-range.module'; 2 | 3 | describe('AgeRangeModule', () => { 4 | it('should work', () => { 5 | expect(new AgeRangeModule()).toBeDefined(); 6 | }); 7 | }); 8 | -------------------------------------------------------------------------------- /libs/video-stat-dashboard/src/dashboard.component.css: -------------------------------------------------------------------------------- 1 | img { 2 | max-height: 106px; 3 | } 4 | 5 | /* Override Materialize */ 6 | label { 7 | padding-left: 25px !important; 8 | } 9 | 10 | svg { 11 | display: block; 12 | margin: auto; 13 | } 14 | -------------------------------------------------------------------------------- /libs/employee-api/src/employee-api.module.spec.ts: -------------------------------------------------------------------------------- 1 | import { EmployeeApiModule } from './employee-api.module'; 2 | 3 | describe('EmployeeApiModule', () => { 4 | it('should work', () => { 5 | expect(new EmployeeApiModule()).toBeDefined(); 6 | }); 7 | }); 8 | -------------------------------------------------------------------------------- /libs/retry-loader/src/retry-loader.module.spec.ts: -------------------------------------------------------------------------------- 1 | import { RetryLoaderModule } from './retry-loader.module'; 2 | 3 | describe('RetryLoaderModule', () => { 4 | it('should work', () => { 5 | expect(new RetryLoaderModule()).toBeDefined(); 6 | }); 7 | }); 8 | -------------------------------------------------------------------------------- /apps/admin/e2e/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by } from 'protractor'; 2 | 3 | export class AppPage { 4 | navigateTo() { 5 | return browser.get('/'); 6 | } 7 | 8 | text() { 9 | return browser.findElement(by.css('body')).getText(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /apps/agent/e2e/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by } from 'protractor'; 2 | 3 | export class AppPage { 4 | navigateTo() { 5 | return browser.get('/'); 6 | } 7 | 8 | text() { 9 | return browser.findElement(by.css('body')).getText(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /apps/portal/e2e/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by } from 'protractor'; 2 | 3 | export class AppPage { 4 | navigateTo() { 5 | return browser.get('/'); 6 | } 7 | 8 | text() { 9 | return browser.findElement(by.css('body')).getText(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | "typescript.tsdk": "./node_modules/typescript/lib", 4 | "editor.detectIndentation": false, 5 | "editor.tabSize": 2, 6 | "vsicons.presets.angular": true 7 | } 8 | -------------------------------------------------------------------------------- /libs/employee-display/src/employee-display.module.spec.ts: -------------------------------------------------------------------------------- 1 | import { EmployeeDisplayModule } from './employee-display.module'; 2 | 3 | describe('EmployeeDisplayModule', () => { 4 | it('should work', () => { 5 | expect(new EmployeeDisplayModule()).toBeDefined(); 6 | }); 7 | }); 8 | -------------------------------------------------------------------------------- /libs/employee-display/src/employee-detail-view/employee-detail-view.component.html: -------------------------------------------------------------------------------- 1 | {{employee?.first_name}} {{employee?.last_name}} 2 |

Email: {{employee?.email}}

3 |

Hours Worked: {{employee?.hours_worked}}

4 |

Hourly Wage: {{employee?.hourly_wage}}

5 | -------------------------------------------------------------------------------- /libs/employee-management/src/employee-management.module.spec.ts: -------------------------------------------------------------------------------- 1 | import { EmployeeManagementModule } from './employee-management.module'; 2 | 3 | describe('EmployeeManagementModule', () => { 4 | it('should work', () => { 5 | expect(new EmployeeManagementModule()).toBeDefined(); 6 | }); 7 | }); 8 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /libs/age-range/src/age-range.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | 3 | import { EnumToRangePipe } from './enum-to-range.pipe'; 4 | 5 | @NgModule({ 6 | declarations: [ 7 | EnumToRangePipe 8 | ], 9 | exports: [ 10 | EnumToRangePipe 11 | ] 12 | }) 13 | export class AgeRangeModule { } 14 | -------------------------------------------------------------------------------- /servers/node/src/rest/rest.ts: -------------------------------------------------------------------------------- 1 | const jsonServer = require('json-server'); 2 | const router = jsonServer.router('db.json'); 3 | const middlewares = jsonServer.defaults(); 4 | 5 | export function addREST(server) { 6 | server.use(middlewares); 7 | server.use(jsonServer.bodyParser); 8 | server.use(router); 9 | } 10 | -------------------------------------------------------------------------------- /apps/admin/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-root', 5 | templateUrl: './app.component.html', 6 | styleUrls: ['./app.component.css'] 7 | }) 8 | export class AppComponent implements OnInit { 9 | constructor() {} 10 | 11 | ngOnInit() {} 12 | } 13 | -------------------------------------------------------------------------------- /apps/agent/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-root', 5 | templateUrl: './app.component.html', 6 | styleUrls: ['./app.component.css'] 7 | }) 8 | export class AppComponent implements OnInit { 9 | constructor() {} 10 | 11 | ngOnInit() {} 12 | } 13 | -------------------------------------------------------------------------------- /apps/portal/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-root', 5 | templateUrl: './app.component.html', 6 | styleUrls: ['./app.component.css'] 7 | }) 8 | export class AppComponent implements OnInit { 9 | constructor() {} 10 | 11 | ngOnInit() {} 12 | } 13 | -------------------------------------------------------------------------------- /apps/admin/e2e/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { AppPage } from './app.po'; 2 | 3 | describe('admin App', () => { 4 | let page: AppPage; 5 | 6 | beforeEach(() => { 7 | page = new AppPage(); 8 | }); 9 | 10 | it('should display welcome message', () => { 11 | page.navigateTo(); 12 | expect(page.text()).toContain('Welcome'); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /apps/agent/e2e/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { AppPage } from './app.po'; 2 | 3 | describe('agent App', () => { 4 | let page: AppPage; 5 | 6 | beforeEach(() => { 7 | page = new AppPage(); 8 | }); 9 | 10 | it('should display welcome message', () => { 11 | page.navigateTo(); 12 | expect(page.text()).toContain('Welcome'); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /apps/portal/e2e/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { AppPage } from './app.po'; 2 | 3 | describe('portal App', () => { 4 | let page: AppPage; 5 | 6 | beforeEach(() => { 7 | page = new AppPage(); 8 | }); 9 | 10 | it('should display welcome message', () => { 11 | page.navigateTo(); 12 | expect(page.text()).toContain('Welcome'); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /servers/node/src/sse/sse.ts: -------------------------------------------------------------------------------- 1 | import { lowfreqChannel, highfreqChannel } from './channels'; 2 | 3 | export function addSSE(server) { 4 | 5 | server.get('/lowfreq', function (req, res) { 6 | lowfreqChannel.addClient(req, res); 7 | }); 8 | 9 | server.get('/highfreq', function (req, res) { 10 | highfreqChannel.addClient(req, res); 11 | }); 12 | } 13 | -------------------------------------------------------------------------------- /apps/agent/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Agent 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /apps/admin/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Admin Application 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /apps/portal/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Employee Portal 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /libs/age-range/src/age-ranges.ts: -------------------------------------------------------------------------------- 1 | // Named like a variable because it might become configurable in the future. 2 | // Data is better than code. 3 | 4 | export const ageRanges = [ 5 | { label: 'Under 18', lower: 0, upper: 18 }, 6 | { label: '18 - 39', lower: 18, upper: 40 }, 7 | { label: '40 - 59', lower: 40, upper: 60 }, 8 | { label: '60 and up', lower: 60, upper: 999 } 9 | ]; 10 | -------------------------------------------------------------------------------- /apps/portal/src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 9 | 10 |
11 | 12 |
13 | -------------------------------------------------------------------------------- /apps/agent/README.md: -------------------------------------------------------------------------------- 1 | # Agent application 2 | 3 | This is the Agent application. It is intended to be used by a medium size number 4 | of people, for example all "agents" at a company. It has access to a partial 5 | subset of all the features of the system. 6 | 7 | Because essentially all of the features are delegated to libraries that are reused across this family related applications, there is very little code here. 8 | -------------------------------------------------------------------------------- /libs/video-stat-dashboard/src/views-filter/views-filter.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | import { ViewsFilterService } from '../services/views-filter.service'; 4 | 5 | @Component({ 6 | selector: 'views-filter', 7 | templateUrl: './views-filter.component.html' 8 | }) 9 | export class ViewsFilterComponent { 10 | 11 | constructor(public vfs: ViewsFilterService) { } 12 | } 13 | -------------------------------------------------------------------------------- /libs/employee-display/src/employee-detail-view/employee-detail-view.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input } from '@angular/core'; 2 | 3 | import { IEmployee } from '@enterprise-example/app-schema'; 4 | 5 | @Component({ 6 | selector: 'employee-detail-view', 7 | templateUrl: './employee-detail-view.component.html' 8 | }) 9 | export class EmployeeDetailViewComponent { 10 | @Input() employee: IEmployee; 11 | } 12 | -------------------------------------------------------------------------------- /libs/fruit-basket/src/counter-display/counter-display.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, Output, EventEmitter } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'counter-display', 5 | templateUrl: './counter-display.component.html' 6 | }) 7 | export class CounterDisplayComponent { 8 | @Input() label: string; 9 | @Input() counter: number; 10 | @Output() pick = new EventEmitter(); 11 | } 12 | -------------------------------------------------------------------------------- /libs/video-stat-dashboard/src/views-filter/views-filter.component.html: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /libs/fruit-basket/src/counter-display/counter-display.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
{{label}}
4 | Current total: {{ counter }} 5 |
6 |
7 | 8 | 9 |
10 |
11 | -------------------------------------------------------------------------------- /libs/employee-api/src/employee-api.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { HttpClientModule } from '@angular/common/http'; 4 | 5 | import { EmployeeApi } from './employee-api.service'; 6 | 7 | @NgModule({ 8 | imports: [ 9 | CommonModule, 10 | HttpClientModule 11 | ], 12 | providers: [EmployeeApi] 13 | }) 14 | export class EmployeeApiModule { } 15 | -------------------------------------------------------------------------------- /libs/video-stat-dashboard/src/video-container/video-container-display.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
{{currentVideo.title}} - {{currentVideo.author}}
5 |
6 | 7 |
8 |
9 |
10 | -------------------------------------------------------------------------------- /servers/node/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "lib": [ 5 | "es6" 6 | ], 7 | "module": "commonjs", 8 | "moduleResolution": "node", 9 | "skipLibCheck": true, 10 | "sourceMap": true, 11 | "outDir": "build", 12 | "noImplicitAny": false 13 | }, 14 | "files": [ 15 | "src/main.ts" 16 | ], 17 | "typeRoots": [ 18 | "node_modules/@types" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /apps/portal/src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../dist/out-tsc/apps/portal", 5 | "module": "es2015" 6 | }, 7 | "include": [ 8 | "**/*.ts" 9 | /* add all lazy-loaded libraries here: "../../../libs/my-lib/index.ts" */ 10 | 11 | , "../../../libs/employee-search/index.ts" 12 | ], 13 | "exclude": [ 14 | "**/*.spec.ts" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /apps/admin/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // The file contents for the current environment will overwrite these during build. 2 | // The build system defaults to the dev environment which uses `environment.ts`, but if you do 3 | // `ng build --env=prod` then `environment.prod.ts` will be used instead. 4 | // The list of which env maps to which file can be found in `.angular-cli.json`. 5 | 6 | export const environment = { 7 | production: false 8 | }; 9 | -------------------------------------------------------------------------------- /apps/admin/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic() 12 | .bootstrapModule(AppModule) 13 | .catch(err => console.log(err)); 14 | -------------------------------------------------------------------------------- /apps/agent/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // The file contents for the current environment will overwrite these during build. 2 | // The build system defaults to the dev environment which uses `environment.ts`, but if you do 3 | // `ng build --env=prod` then `environment.prod.ts` will be used instead. 4 | // The list of which env maps to which file can be found in `.angular-cli.json`. 5 | 6 | export const environment = { 7 | production: false 8 | }; 9 | -------------------------------------------------------------------------------- /apps/agent/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic() 12 | .bootstrapModule(AppModule) 13 | .catch(err => console.log(err)); 14 | -------------------------------------------------------------------------------- /apps/portal/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // The file contents for the current environment will overwrite these during build. 2 | // The build system defaults to the dev environment which uses `environment.ts`, but if you do 3 | // `ng build --env=prod` then `environment.prod.ts` will be used instead. 4 | // The list of which env maps to which file can be found in `.angular-cli.json`. 5 | 6 | export const environment = { 7 | production: false 8 | }; 9 | -------------------------------------------------------------------------------- /apps/portal/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic() 12 | .bootstrapModule(AppModule) 13 | .catch(err => console.log(err)); 14 | -------------------------------------------------------------------------------- /libs/video-stat-dashboard/src/services/top-list.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Store } from '@ngrx/store'; 3 | 4 | import { VideoStatsState } from '../+state/video-stats.interfaces'; 5 | 6 | @Injectable() 7 | export class TopListService { 8 | 9 | constructor(private store: Store) { } 10 | 11 | getTopList() { 12 | return this.store.select(state => state.videoStats.videoList); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./dist/out-tsc/spec", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "types": [ 8 | "jasmine", 9 | "node" 10 | ] 11 | }, 12 | "include": [ 13 | "**/*.ts" 14 | ], 15 | "exclude": [ 16 | "**/e2e/*.ts", 17 | "**/*.e2e-spec.ts", 18 | "**/*.po.ts", 19 | "node_modules", 20 | "tmp" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /apps/agent/src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 10 | 11 |
12 | 13 |
14 | -------------------------------------------------------------------------------- /libs/age-range/src/enum-to-range.pipe.ts: -------------------------------------------------------------------------------- 1 | import { Pipe, PipeTransform } from '@angular/core'; 2 | 3 | import { ageRanges } from './age-ranges'; 4 | 5 | @Pipe({ 6 | name: 'enumToRange' 7 | }) 8 | export class EnumToRangePipe implements PipeTransform { 9 | 10 | transform(value: any, _args?: any): any { 11 | try { 12 | const index = parseInt(value, 10); 13 | return ageRanges[index].label; 14 | } catch (error) { 15 | return null; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /servers/node/src/main.ts: -------------------------------------------------------------------------------- 1 | import { addSSE } from './sse/sse'; 2 | import { addGraphQL } from './graphql/graphql'; 3 | import { addREST } from './rest/rest'; 4 | import * as express from 'express'; 5 | 6 | const server = express().set('json spaces', 2); 7 | 8 | addSSE(server); 9 | addGraphQL(server); 10 | addREST(server); 11 | 12 | const port = process.env.PORT || 8005; 13 | server.listen(port, () => { 14 | console.log('JSON Server listening on http://localhost:%s/', port); 15 | }); 16 | -------------------------------------------------------------------------------- /apps/agent/src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../dist/out-tsc/apps/agent", 5 | "module": "es2015" 6 | }, 7 | "include": [ 8 | "**/*.ts" 9 | /* add all lazy-loaded libraries here: "../../../libs/my-lib/index.ts" */ 10 | 11 | , "../../../libs/employee-list/index.ts" 12 | 13 | , "../../../libs/employee-search/index.ts" 14 | ], 15 | "exclude": [ 16 | "**/*.spec.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /apps/agent/e2e/tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../dist/out-tsc/e2e/agent", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "types": [ 8 | "jasmine", 9 | "jasminewd2", 10 | "node" 11 | ] 12 | }, 13 | "include": [ 14 | "../**/*.ts" 15 | /* add all lazy-loaded libraries here: "../../../libs/my-lib/index.ts" */ 16 | ], 17 | "exclude": [ 18 | "**/*.spec.ts" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /apps/portal/e2e/tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../dist/out-tsc/e2e/portal", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "types": [ 8 | "jasmine", 9 | "jasminewd2", 10 | "node" 11 | ] 12 | }, 13 | "include": [ 14 | "../**/*.ts" 15 | /* add all lazy-loaded libraries here: "../../../libs/my-lib/index.ts" */ 16 | ], 17 | "exclude": [ 18 | "**/*.spec.ts" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /libs/video-stat-dashboard/src/+state/video-stats.init.ts: -------------------------------------------------------------------------------- 1 | import { ViewsFilterState, ViewsBreakdownState } from './video-stats.interfaces'; 2 | import * as moment from 'moment'; 3 | 4 | export const viewsBreakdownStateInitial: ViewsBreakdownState = { 5 | selectedAxis: ['age'] 6 | }; 7 | 8 | export const viewsFilterInitialState: ViewsFilterState = { 9 | region: 'All', 10 | dateTo: moment().startOf('day').valueOf(), 11 | dateFrom: moment('1995-01-01').valueOf(), 12 | ageRanges: [true, true, true, true] 13 | }; 14 | -------------------------------------------------------------------------------- /tsconfig.compodoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "moduleResolution": "node", 4 | "emitDecoratorMetadata": true, 5 | "experimentalDecorators": true, 6 | "target": "es5", 7 | "typeRoots": [ 8 | "node_modules/@types" 9 | ], 10 | "lib": [ 11 | "es2017", 12 | "dom" 13 | ], 14 | "paths": { 15 | "@enterprise-example/*": [ 16 | "libs/*" 17 | ] 18 | } 19 | }, 20 | "include": [ 21 | "apps/**/*.ts", 22 | "libs/**/*.ts" 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /libs/video-stat-dashboard/src/dashboard.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | import { AppService } from './services/app.service'; 4 | 5 | @Component({ 6 | selector: 'app-dashboard', 7 | templateUrl: './dashboard.component.html', 8 | styleUrls: ['./dashboard.component.css'] 9 | }) 10 | export class DashboardComponent { 11 | 12 | constructor(_appService: AppService) { 13 | // Have it injected for the side effect of triggering the data population. 14 | // This is an anti-pattern, right? 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /libs/video-stat-dashboard/src/dashboard.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 |
6 |
7 |
8 | 9 |
10 |
11 |
12 |
13 | 14 |
15 |
16 |
17 |
18 | 19 |
20 |
21 | -------------------------------------------------------------------------------- /libs/app-schema/README.md: -------------------------------------------------------------------------------- 1 | # The schema of the application (example) 2 | 3 | This reusable library is intended to express the idea that a family of related 4 | applications typically shares a certain amount of "schema". Within Angular at 5 | least, this usually takes the form of a set of typescript types, although it may 6 | also take the form of something like a GraphQL schema. 7 | 8 | This is the smallest of the example libraries, and has the greatest number of 9 | other libraries that depend on it; that is typical of a somewhat reasonable 10 | dependency graph. 11 | -------------------------------------------------------------------------------- /libs/fruit-basket/src/basket-ui/basket-ui.component.html: -------------------------------------------------------------------------------- 1 |

Fruit Basket

2 | 3 | 4 |

Total Fruit: {{ total | async }}

5 | 6 |
7 | 12 | 13 | 14 | 19 | 20 |
21 | -------------------------------------------------------------------------------- /libs/video-stat-dashboard/src/+state/video-stats.effects.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | // import { Actions } from '@ngrx/effects'; 3 | 4 | @Injectable() 5 | export class VideoStatsEffects { 6 | // I would prefer to do something roughly like this, but there is not yet an 7 | // automatic feature level initialization action provided by NgRx. 8 | // @Effect() startup = this.actions.ofType('@ngrx/store/init') 9 | // .pipe(map(_ => ({ type: 'VIDEOS_ARRIVED', payload: VIDEO_LIST }))) 10 | 11 | // constructor(private actions: Actions) { } 12 | } 13 | -------------------------------------------------------------------------------- /libs/video-stat-dashboard/src/views-breakdown/views-breakdown-display.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input } from '@angular/core'; 2 | 3 | import { Video } from '../+state/video-stats.interfaces'; 4 | import { GraphData } from '../services/views-breakdown.service'; 5 | 6 | @Component({ 7 | selector: 'views-breakdown-display', 8 | templateUrl: './views-breakdown-display.component.html' 9 | }) 10 | export class ViewsBreakdownDisplayComponent { 11 | @Input() currentVideo: Video; 12 | @Input() viewsBreakdown: string[]; 13 | @Input() graphData: GraphData[]; 14 | } 15 | -------------------------------------------------------------------------------- /libs/employee-management/src/add-employee/add-employee.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
Add employee
4 | 5 |
6 | 7 | 8 | 10 | 12 |
13 | 14 |
15 |
16 | -------------------------------------------------------------------------------- /libs/employee-display/src/employee-list-table-view/employee-list-table-view.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, Output, EventEmitter } from '@angular/core'; 2 | 3 | import { IEmployeeListing } from '@enterprise-example/app-schema'; 4 | 5 | @Component({ 6 | selector: 'employee-list-table-view', 7 | templateUrl: './employee-list-table-view.component.html' 8 | }) 9 | export class EmployeeListTableViewComponent { 10 | @Input() list: IEmployeeListing[]; 11 | @Input() selectedId: number; 12 | @Output() selectId = new EventEmitter(); 13 | 14 | noop(e: MouseEvent) { 15 | e.preventDefault(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /apps/portal/README.md: -------------------------------------------------------------------------------- 1 | # Portal application 2 | 3 | This is the portal application. It is intended to be an example of the smallest 4 | subset of functionality, likely to be used by the largest number of people, 5 | among the family of related applications. 6 | 7 | Because essentially all of the features are delegated to libraries that are reused across this family related applications, there is very little code here. 8 | 9 | Although this small example is very similar to the agent and admin applications, 10 | it would be more realistic if this were offered with extensive mobile support, 11 | additional attention to load time and size, etc. 12 | -------------------------------------------------------------------------------- /libs/video-stat-dashboard/src/video-container/video-container.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { Observable } from 'rxjs/Observable'; 3 | 4 | import { DashboardService } from '../services/dashboard.service'; 5 | import { Video } from '../+state/video-stats.interfaces'; 6 | 7 | @Component({ 8 | selector: 'video-container', 9 | templateUrl: './video-container.component.html' 10 | }) 11 | export class VideoContainerComponent { 12 | 13 | currentVideo: Observable