Add Angular client

This commit is contained in:
Christopher J. Walker 2024-02-22 17:12:04 -05:00
parent fd266e598d
commit 7be749bea2
30 changed files with 18060 additions and 0 deletions

1
web-app/.eslintignore Normal file
View File

@ -0,0 +1 @@
node_modules

47
web-app/.eslintrc.json Normal file
View File

@ -0,0 +1,47 @@
{
"root": true,
"ignorePatterns": ["!**/*"],
"plugins": ["@nx"],
"overrides": [
{
"files": ["*.ts", "*.tsx"],
"extends": ["plugin:@nx/typescript"],
"rules": {}
},
{
"files": ["*.js", "*.jsx"],
"extends": ["plugin:@nx/javascript"],
"rules": {}
},
{
"files": ["*.ts"],
"extends": [
"plugin:@nx/angular",
"plugin:@angular-eslint/template/process-inline-templates"
],
"rules": {
"@angular-eslint/directive-selector": [
"error",
{
"type": "attribute",
"prefix": "webClient",
"style": "camelCase"
}
],
"@angular-eslint/component-selector": [
"error",
{
"type": "element",
"prefix": "web-app",
"style": "kebab-case"
}
]
}
},
{
"files": ["*.html"],
"extends": ["plugin:@nx/angular-template"],
"rules": {}
}
]
}

42
web-app/.gitignore vendored Normal file
View File

@ -0,0 +1,42 @@
# See http://help.github.com/ignore-files/ for more about ignoring files.
# compiled output
dist
tmp
/out-tsc
# dependencies
node_modules
# IDEs and editors
/.idea
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# IDE - VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
# misc
/.sass-cache
/connect.lock
/coverage
/libpeerconnection.log
npm-debug.log
yarn-error.log
testem.log
/typings
# System Files
.DS_Store
Thumbs.db
.nx/cache
.angular

5
web-app/.prettierignore Normal file
View File

@ -0,0 +1,5 @@
# Add files here to ignore them from prettier formatting
/dist
/coverage
/.nx/cache
.angular

3
web-app/.prettierrc Normal file
View File

@ -0,0 +1,3 @@
{
"singleQuote": true
}

7
web-app/.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,7 @@
{
"recommendations": [
"nrwl.angular-console",
"esbenp.prettier-vscode",
"firsttris.vscode-jest-runner"
]
}

69
web-app/README.md Normal file
View File

@ -0,0 +1,69 @@
# WebClient
<a alt="Nx logo" href="https://nx.dev" target="_blank" rel="noreferrer"><img src="https://raw.githubusercontent.com/nrwl/nx/master/images/nx-logo.png" width="45"></a>
**This workspace has been generated by [Nx, Smart Monorepos · Fast CI.](https://nx.dev)**
## Start the app
To start the development server run `nx serve WebClient`. Open your browser and navigate to http://localhost:4200/. Happy coding!
## Generate code
If you happen to use Nx plugins, you can leverage code generators that might come with it.
Run `nx list` to get a list of available plugins and whether they have generators. Then run `nx list <plugin-name>` to see what generators are available.
Learn more about [Nx generators on the docs](https://nx.dev/features/generate-code).
## Running tasks
To execute tasks with Nx use the following syntax:
```
nx <target> <project> <...options>
```
You can also run multiple targets:
```
nx run-many -t <target1> <target2>
```
..or add `-p` to filter specific projects
```
nx run-many -t <target1> <target2> -p <proj1> <proj2>
```
Targets can be defined in the `package.json` or `projects.json`. Learn more [in the docs](https://nx.dev/features/run-tasks).
## Want better Editor Integration?
Have a look at the [Nx Console extensions](https://nx.dev/nx-console). It provides autocomplete support, a UI for exploring and running tasks & generators, and more! Available for VSCode, IntelliJ and comes with a LSP for Vim users.
## Ready to deploy?
Just run `nx build demoapp` to build the application. The build artifacts will be stored in the `dist/` directory, ready to be deployed.
## Set up CI!
Nx comes with local caching already built-in (check your `nx.json`). On CI you might want to go a step further.
- [Set up remote caching](https://nx.dev/features/share-your-cache)
- [Set up task distribution across multiple machines](https://nx.dev/nx-cloud/features/distribute-task-execution)
- [Learn more how to setup CI](https://nx.dev/recipes/ci)
## Explore the Project Graph
Run `nx graph` to show the graph of the workspace.
It will show tasks that you can run with Nx.
- [Learn more about Exploring the Project Graph](https://nx.dev/core-features/explore-graph)
## Connect with us!
- [Join the community](https://nx.dev/community)
- [Subscribe to the Nx Youtube Channel](https://www.youtube.com/@nxdevtools)
- [Follow us on Twitter](https://twitter.com/nxdevtools)

26
web-app/jest.config.ts Normal file
View File

@ -0,0 +1,26 @@
/* eslint-disable */
export default {
displayName: 'web-app',
preset: './jest.preset.js',
setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],
coverageDirectory: './coverage/web-app',
transform: {
'^.+\\.(ts|mjs|js|html)$': [
'jest-preset-angular',
{
tsconfig: '<rootDir>/tsconfig.spec.json',
stringifyContentPathRegex: '\\.(html|svg)$',
},
],
},
transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],
snapshotSerializers: [
'jest-preset-angular/build/serializers/no-ng-attributes',
'jest-preset-angular/build/serializers/ng-snapshot',
'jest-preset-angular/build/serializers/html-comment',
],
testMatch: [
'<rootDir>/src/**/__tests__/**/*.[jt]s?(x)',
'<rootDir>/src/**/*(*.)@(spec|test).[jt]s?(x)',
],
};

3
web-app/jest.preset.js Normal file
View File

@ -0,0 +1,3 @@
const nxPreset = require('@nx/jest/preset').default;
module.exports = { ...nxPreset };

50
web-app/nx.json Normal file
View File

@ -0,0 +1,50 @@
{
"$schema": "./node_modules/nx/schemas/nx-schema.json",
"affected": {
"defaultBase": "master"
},
"namedInputs": {
"default": ["{projectRoot}/**/*", "sharedGlobals"],
"production": [
"default",
"!{projectRoot}/.eslintrc.json",
"!{projectRoot}/eslint.config.js",
"!{projectRoot}/**/?(*.)+(spec|test).[jt]s?(x)?(.snap)",
"!{projectRoot}/tsconfig.spec.json",
"!{projectRoot}/jest.config.[jt]s",
"!{projectRoot}/src/test-setup.[jt]s",
"!{projectRoot}/test-setup.[jt]s"
],
"sharedGlobals": []
},
"targetDefaults": {
"@angular-devkit/build-angular:application": {
"cache": true,
"dependsOn": ["^build"],
"inputs": ["production", "^production"]
}
},
"plugins": [
{
"plugin": "@nx/eslint/plugin",
"options": {
"targetName": "lint"
}
},
{
"plugin": "@nx/jest/plugin",
"options": {
"targetName": "test"
}
}
],
"generators": {
"@nx/angular:application": {
"e2eTestRunner": "none",
"linter": "eslint",
"style": "scss",
"unitTestRunner": "jest"
}
},
"defaultProject": "web-app"
}

17474
web-app/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

63
web-app/package.json Normal file
View File

@ -0,0 +1,63 @@
{
"name": "@web-app/source",
"version": "0.0.0",
"license": "MIT",
"scripts": {
"start": "nx serve",
"build": "nx build",
"test": "nx test"
},
"private": true,
"dependencies": {
"@angular/animations": "~17.1.0",
"@angular/common": "~17.1.0",
"@angular/compiler": "~17.1.0",
"@angular/core": "~17.1.0",
"@angular/forms": "~17.1.0",
"@angular/platform-browser": "~17.1.0",
"@angular/platform-browser-dynamic": "~17.1.0",
"@angular/router": "~17.1.0",
"@nx/angular": "18.0.4",
"rxjs": "~7.8.0",
"tslib": "^2.3.0",
"zone.js": "~0.14.3"
},
"devDependencies": {
"@angular-devkit/build-angular": "~17.1.0",
"@angular-devkit/core": "~17.1.0",
"@angular-devkit/schematics": "~17.1.0",
"@angular-eslint/eslint-plugin": "~17.0.0",
"@angular-eslint/eslint-plugin-template": "~17.0.0",
"@angular-eslint/template-parser": "~17.0.0",
"@angular/cli": "~17.1.0",
"@angular/compiler-cli": "~17.1.0",
"@angular/language-service": "~17.1.0",
"@nx/eslint": "18.0.4",
"@nx/eslint-plugin": "18.0.4",
"@nx/jest": "18.0.4",
"@nx/js": "18.0.4",
"@nx/workspace": "18.0.4",
"@schematics/angular": "~17.1.0",
"@swc-node/register": "~1.8.0",
"@swc/core": "~1.3.85",
"@swc/helpers": "~0.5.2",
"@types/jest": "^29.4.0",
"@types/node": "18.16.9",
"@typescript-eslint/eslint-plugin": "^6.13.2",
"@typescript-eslint/parser": "^6.13.2",
"eslint": "~8.48.0",
"eslint-config-prettier": "^9.0.0",
"jest": "^29.4.1",
"jest-environment-jsdom": "^29.4.1",
"jest-preset-angular": "~13.1.4",
"jsonc-eslint-parser": "^2.1.0",
"nx": "18.0.4",
"prettier": "^2.6.2",
"ts-jest": "^29.1.0",
"ts-node": "10.9.1",
"typescript": "~5.3.2"
},
"nx": {
"includedScripts": []
}
}

69
web-app/project.json Normal file
View File

@ -0,0 +1,69 @@
{
"name": "web-app",
"$schema": "node_modules/nx/schemas/project-schema.json",
"projectType": "application",
"prefix": "web-app",
"sourceRoot": "./src",
"tags": [],
"targets": {
"build": {
"executor": "@angular-devkit/build-angular:application",
"outputs": ["{options.outputPath}"],
"options": {
"outputPath": "dist/web-app",
"index": "./src/index.html",
"browser": "./src/main.ts",
"polyfills": ["zone.js"],
"tsConfig": "./tsconfig.app.json",
"inlineStyleLanguage": "scss",
"assets": ["./src/favicon.ico", "./src/assets"],
"styles": ["./src/styles.scss"],
"scripts": []
},
"configurations": {
"production": {
"budgets": [
{
"type": "initial",
"maximumWarning": "500kb",
"maximumError": "1mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "2kb",
"maximumError": "4kb"
}
],
"outputHashing": "all"
},
"development": {
"optimization": false,
"extractLicenses": false,
"sourceMap": true
}
},
"defaultConfiguration": "production"
},
"serve": {
"executor": "@angular-devkit/build-angular:dev-server",
"options": {
"proxyConfig": "./proxy.conf.json"
},
"configurations": {
"production": {
"buildTarget": "web-app:build:production"
},
"development": {
"buildTarget": "web-app:build:development"
}
},
"defaultConfiguration": "development"
},
"extract-i18n": {
"executor": "@angular-devkit/build-angular:extract-i18n",
"options": {
"buildTarget": "web-app:build"
}
}
}
}

10
web-app/proxy.conf.json Normal file
View File

@ -0,0 +1,10 @@
{
"/api": {
"target": "http://localhost:5242",
"secure": false
},
"/swagger": {
"target": "http://localhost:5242",
"secure": false
}
}

View File

@ -0,0 +1,20 @@
<div class="jumbotron">
<h1>BrainWare Orders</h1>
<p class="lead">This is the BrainWare orders page! Welcome</p>
</div>
<div class="row">
<div class="col-md-12">
<h2>Your Orders</h2>
<div id="orders"></div>
</div>
</div>
<ul>
<li *ngFor="let order of orders">
{{order.description}} (Total: ${{order.orderTotal}})
<ul>
<li *ngFor="let orderProduct of order.orderProducts">
{{orderProduct.product.name}} ({{orderProduct.quantity}} &#64;&#64; ${{orderProduct.price}}/ea)
</li>
</ul>
</li>
</ul>

View File

View File

@ -0,0 +1,26 @@
import { TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { AppComponent } from './app.component';
describe('AppComponent', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [AppComponent, RouterTestingModule],
}).compileComponents();
});
it('should render title', () => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
const compiled = fixture.nativeElement as HTMLElement;
expect(compiled.querySelector('h1')?.textContent).toContain(
'Welcome web-app'
);
});
it(`should have as title 'web-app'`, () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app.title).toEqual('web-app');
});
});

View File

@ -0,0 +1,25 @@
import { CommonModule } from '@angular/common';
import { HttpClient } from '@angular/common/http';
import { ChangeDetectorRef, Component, inject } from '@angular/core';
import { RouterModule } from '@angular/router';
@Component({
standalone: true,
imports: [CommonModule, RouterModule],
selector: 'web-app-root',
templateUrl: './app.component.html',
styleUrl: './app.component.scss',
})
export class AppComponent {
private http = inject(HttpClient);
private cd = inject(ChangeDetectorRef);
orders: any[] = [];
constructor() {
this.http.get<any>('/api/order/1').subscribe((orders) => {
this.orders = orders;
this.cd.detectChanges();
});
}
}

View File

@ -0,0 +1,8 @@
import { provideHttpClient } from '@angular/common/http';
import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';
import { appRoutes } from './app.routes';
export const appConfig: ApplicationConfig = {
providers: [provideRouter(appRoutes), provideHttpClient()],
};

View File

@ -0,0 +1,3 @@
import { Route } from '@angular/router';
export const appRoutes: Route[] = [];

View File

BIN
web-app/src/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

13
web-app/src/index.html Normal file
View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>web-app</title>
<base href="/" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" type="image/x-icon" href="favicon.ico" />
</head>
<body>
<web-app-root></web-app-root>
</body>
</html>

7
web-app/src/main.ts Normal file
View File

@ -0,0 +1,7 @@
import { bootstrapApplication } from '@angular/platform-browser';
import { appConfig } from './app/app.config';
import { AppComponent } from './app/app.component';
bootstrapApplication(AppComponent, appConfig).catch((err) =>
console.error(err)
);

1
web-app/src/styles.scss Normal file
View File

@ -0,0 +1 @@
/* You can add global styles to this file, and also import other style files */

View File

@ -0,0 +1,8 @@
// @ts-expect-error https://thymikee.github.io/jest-preset-angular/docs/getting-started/test-environment
globalThis.ngJest = {
testEnvironmentOptions: {
errorOnUnknownElements: true,
errorOnUnknownProperties: true,
},
};
import 'jest-preset-angular/setup-jest';

10
web-app/tsconfig.app.json Normal file
View File

@ -0,0 +1,10 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./dist/out-tsc",
"types": []
},
"files": ["src/main.ts"],
"include": ["src/**/*.d.ts"],
"exclude": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts"]
}

View File

@ -0,0 +1,7 @@
{
"extends": "./tsconfig.json",
"include": ["src/**/*.ts"],
"compilerOptions": {
"types": ["jest", "node"]
}
}

47
web-app/tsconfig.json Normal file
View File

@ -0,0 +1,47 @@
{
"compilerOptions": {
"rootDir": ".",
"sourceMap": true,
"declaration": false,
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"importHelpers": true,
"target": "es2022",
"module": "esnext",
"lib": ["es2020", "dom"],
"skipLibCheck": true,
"skipDefaultLibCheck": true,
"baseUrl": ".",
"paths": {},
"useDefineForClassFields": false,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true
},
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.app.json"
},
{
"path": "./tsconfig.spec.json"
},
{
"path": "./tsconfig.editor.json"
}
],
"compileOnSave": false,
"exclude": ["node_modules", "tmp"],
"angularCompilerOptions": {
"enableI18nLegacyMessageIdFormat": false,
"strictInjectionParameters": true,
"strictInputAccessModifiers": true,
"strictTemplates": true
}
}

View File

@ -0,0 +1,16 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./dist/out-tsc",
"module": "commonjs",
"target": "es2016",
"types": ["jest", "node"]
},
"files": ["src/test-setup.ts"],
"include": [
"jest.config.ts",
"src/**/*.test.ts",
"src/**/*.spec.ts",
"src/**/*.d.ts"
]
}