mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-28 22:42:11 +01:00
Compare commits
169 Commits
1.5.423
...
fix/3051-R
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a074b9605b | ||
|
|
1228698fcf | ||
|
|
d1eba5f1e2 | ||
|
|
08ac71dc1b | ||
|
|
da579ecc3a | ||
|
|
f286dd1e1b | ||
|
|
0c5aedfee8 | ||
|
|
b7d7c88fc6 | ||
|
|
8c2671e2fb | ||
|
|
b281f7c25b | ||
|
|
750caa522e | ||
|
|
62ed8affb1 | ||
|
|
92e0e90120 | ||
|
|
9b0dea213e | ||
|
|
a73acfa4e8 | ||
|
|
833542f303 | ||
|
|
b666e4b38c | ||
|
|
794daf3746 | ||
|
|
32f2fd0754 | ||
|
|
04cd5e9437 | ||
|
|
3785ad614f | ||
|
|
4e9b4064a6 | ||
|
|
319d8b96bb | ||
|
|
272824e236 | ||
|
|
4b3e80cadb | ||
|
|
f6675b67e8 | ||
|
|
6974324c9b | ||
|
|
c805106759 | ||
|
|
5448ac034b | ||
|
|
79667ae4b6 | ||
|
|
336a98e576 | ||
|
|
4e4dc47ad6 | ||
|
|
ee02e89fa7 | ||
|
|
7e6f5a7837 | ||
|
|
7b824bd13b | ||
|
|
146ad7b20a | ||
|
|
f657a088d4 | ||
|
|
c4ed8d0648 | ||
|
|
810a7d0a8f | ||
|
|
25d5f183c5 | ||
|
|
9052fe25db | ||
|
|
776115fbed | ||
|
|
962f0bc2c6 | ||
|
|
c184df717d | ||
|
|
26a7348d25 | ||
|
|
cf5052cbe5 | ||
|
|
be848123a1 | ||
|
|
04232b85a7 | ||
|
|
09bb84c34e | ||
|
|
4449992442 | ||
|
|
39c40f2e13 | ||
|
|
9813575584 | ||
|
|
b0af718cbc | ||
|
|
550544cbe4 | ||
|
|
3ec3cf0e5b | ||
|
|
0b79464e52 | ||
|
|
a1642c5749 | ||
|
|
148aab1495 | ||
|
|
2f78f2685f | ||
|
|
6dde5682a9 | ||
|
|
af8a3d89af | ||
|
|
ec97d1e84a | ||
|
|
eea412abd3 | ||
|
|
cf65ba3e6b | ||
|
|
3d4445bb46 | ||
|
|
94753ceac4 | ||
|
|
af16542ce5 | ||
|
|
e4c82441b8 | ||
|
|
8783802483 | ||
|
|
8ad28a16b0 | ||
|
|
f9403649e6 | ||
|
|
698af2ecc3 | ||
|
|
c92649a8d4 | ||
|
|
dfd1847a2d | ||
|
|
eeaafec80a | ||
|
|
896e91d4d9 | ||
|
|
d6507b428f | ||
|
|
6ff4d204c2 | ||
|
|
8145436d1d | ||
|
|
25f22b46c5 | ||
|
|
558d846812 | ||
|
|
05916031ad | ||
|
|
ffad6aa939 | ||
|
|
cb22a39ffc | ||
|
|
c6130dcffb | ||
|
|
c9f4143204 | ||
|
|
fa0e1d7d60 | ||
|
|
621b545e34 | ||
|
|
53e3d90064 | ||
|
|
c175826fd3 | ||
|
|
c6b584d637 | ||
|
|
d992ce87a9 | ||
|
|
a87072e542 | ||
|
|
eff0388b8f | ||
|
|
9c517810ba | ||
|
|
882cbddec0 | ||
|
|
d188272cbf | ||
|
|
72b3688365 | ||
|
|
0f81914875 | ||
|
|
e8e895d7b1 | ||
|
|
f0cc76f180 | ||
|
|
91b3f44c1e | ||
|
|
43859599f0 | ||
|
|
4dff0b1e6a | ||
|
|
f5fcee4e4a | ||
|
|
9ffb0b9a97 | ||
|
|
34698aca5e | ||
|
|
4fcf9fabbf | ||
|
|
fd907cf0cc | ||
|
|
cb543c7c98 | ||
|
|
02ee730080 | ||
|
|
5cccc5fedd | ||
|
|
9b6f4d1ecf | ||
|
|
022e8e9e73 | ||
|
|
a81581e67f | ||
|
|
5823f57e03 | ||
|
|
96f2233421 | ||
|
|
ac1a772b21 | ||
|
|
04851dbe39 | ||
|
|
29181469db | ||
|
|
cb447e13f9 | ||
|
|
04a3b1767a | ||
|
|
20f1a5c77e | ||
|
|
c979b48592 | ||
|
|
88ebc39d65 | ||
|
|
9aa3820e95 | ||
|
|
722ed6ade6 | ||
|
|
8f7448a095 | ||
|
|
5e9b3b56d4 | ||
|
|
95656b20d7 | ||
|
|
12fe8b46c3 | ||
|
|
92958f4b22 | ||
|
|
05a3bbef7a | ||
|
|
03467fcb83 | ||
|
|
e96c98e344 | ||
|
|
c660c5626d | ||
|
|
b443c7a5de | ||
|
|
578f3fee7a | ||
|
|
caddcd0e2b | ||
|
|
cce810d4e3 | ||
|
|
2f060e6209 | ||
|
|
df94c1ab59 | ||
|
|
9c2ed96331 | ||
|
|
b462e39a51 | ||
|
|
8340649292 | ||
|
|
1d2df695d3 | ||
|
|
f46ef394d9 | ||
|
|
fcf016ea85 | ||
|
|
e2ebba9f9f | ||
|
|
d9460df0ca | ||
|
|
9d988e18be | ||
|
|
949ee7da6e | ||
|
|
736f402179 | ||
|
|
e5c4eb6a8e | ||
|
|
c93233674b | ||
|
|
02abf0852e | ||
|
|
cf3e5ce9a3 | ||
|
|
da71454070 | ||
|
|
08a8575025 | ||
|
|
a99494b6ea | ||
|
|
52ab4fccbd | ||
|
|
2ab1599fa3 | ||
|
|
f220dde3b2 | ||
|
|
d027df8856 | ||
|
|
1dc979baaf | ||
|
|
19fe83ed25 | ||
|
|
3c033a1f0d | ||
|
|
be031fb702 | ||
|
|
6cfbce4f16 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -34,6 +34,7 @@ speed-measure-plugin.json
|
||||
/.sass-cache
|
||||
/connect.lock
|
||||
/coverage
|
||||
/testresults
|
||||
/libpeerconnection.log
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
|
||||
3
.vscode/extensions.json
vendored
3
.vscode/extensions.json
vendored
@@ -3,7 +3,6 @@
|
||||
"johnpapa.angular2",
|
||||
"esbenp.prettier-vscode",
|
||||
"angular.ng-template",
|
||||
"ms-vscode.vscode-typescript-tslint-plugin",
|
||||
"eg2.vscode-npm-script"
|
||||
]
|
||||
}
|
||||
}
|
||||
20
Dockerfile
20
Dockerfile
@@ -1,5 +1,5 @@
|
||||
#stage 1
|
||||
FROM node:14 as node
|
||||
FROM node:14 as base
|
||||
ARG IS_PRODUCTION=false
|
||||
ARG SEMVERSION=1.0.0
|
||||
ARG BuildUniqueID
|
||||
@@ -11,9 +11,19 @@ RUN npm version ${SEMVERSION}
|
||||
RUN npm install --always-auth=false
|
||||
RUN if [ "${IS_PRODUCTION}" = "true" ] ; then npm run-script build-prod ; else npm run-script build ; fi
|
||||
|
||||
# stage 2
|
||||
FROM nginx:alpine
|
||||
# stage final
|
||||
FROM nginx:alpine as publish
|
||||
ARG BuildUniqueID
|
||||
LABEL build.uniqueid="${BuildUniqueID:-1}"
|
||||
COPY --from=node /app/dist/sales /usr/share/nginx/html
|
||||
COPY --from=node /app/nginx.conf /etc/nginx/conf.d/default.conf
|
||||
COPY --from=base /app/dist/isa-app /usr/share/nginx/html
|
||||
COPY --from=base /app/nginx.conf /etc/nginx/conf.d/default.conf
|
||||
|
||||
# stage npm test
|
||||
FROM base as test
|
||||
ARG BuildUniqueID
|
||||
LABEL build.uniqueid="${BuildUniqueID:-1}"
|
||||
RUN wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb -q -O /tmp/chrome.deb && apt update && apt install -y /tmp/chrome.deb
|
||||
# ignore exitcode, sonst gibts keinen container
|
||||
RUN npm test || true
|
||||
ENTRYPOINT [ "/bin/sleep", "60000" ]
|
||||
|
||||
|
||||
590
angular.json
590
angular.json
@@ -10,7 +10,7 @@
|
||||
"prefix": "lib",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-ng-packagr:build",
|
||||
"builder": "@angular-devkit/build-angular:ng-packagr",
|
||||
"options": {
|
||||
"tsConfig": "libs/ui/tsconfig.lib.json",
|
||||
"project": "libs/ui/ng-package.json"
|
||||
@@ -55,7 +55,6 @@
|
||||
"options": {
|
||||
"aot": true,
|
||||
"outputPath": "dist/sales",
|
||||
"outputHashing": "all",
|
||||
"index": "apps/sales/src/index.html",
|
||||
"main": "apps/sales/src/main.ts",
|
||||
"polyfills": "apps/sales/src/polyfills.ts",
|
||||
@@ -123,10 +122,7 @@
|
||||
"serve": {
|
||||
"builder": "@angular-builders/custom-webpack:dev-server",
|
||||
"options": {
|
||||
"browserTarget": "sales:build",
|
||||
"customWebpackConfig": {
|
||||
"path": "apps/sales/webpack.config.js"
|
||||
}
|
||||
"browserTarget": "sales:build"
|
||||
},
|
||||
"configurations": {
|
||||
"test": {
|
||||
@@ -224,7 +220,7 @@
|
||||
"prefix": "lib",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-ng-packagr:build",
|
||||
"builder": "@angular-devkit/build-angular:ng-packagr",
|
||||
"options": {
|
||||
"tsConfig": "libs/sso/tsconfig.lib.json",
|
||||
"project": "libs/sso/ng-package.json"
|
||||
@@ -264,7 +260,7 @@
|
||||
"prefix": "lib",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-ng-packagr:build",
|
||||
"builder": "@angular-devkit/build-angular:ng-packagr",
|
||||
"options": {
|
||||
"tsConfig": "apps/swagger/availability/tsconfig.lib.json",
|
||||
"project": "apps/swagger/availability/ng-package.json"
|
||||
@@ -304,7 +300,7 @@
|
||||
"prefix": "lib",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-ng-packagr:build",
|
||||
"builder": "@angular-devkit/build-angular:ng-packagr",
|
||||
"options": {
|
||||
"tsConfig": "apps/swagger/checkout/tsconfig.lib.json",
|
||||
"project": "apps/swagger/checkout/ng-package.json"
|
||||
@@ -344,7 +340,7 @@
|
||||
"prefix": "lib",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-ng-packagr:build",
|
||||
"builder": "@angular-devkit/build-angular:ng-packagr",
|
||||
"options": {
|
||||
"tsConfig": "apps/swagger/crm/tsconfig.lib.json",
|
||||
"project": "apps/swagger/crm/ng-package.json"
|
||||
@@ -384,7 +380,7 @@
|
||||
"prefix": "lib",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-ng-packagr:build",
|
||||
"builder": "@angular-devkit/build-angular:ng-packagr",
|
||||
"options": {
|
||||
"tsConfig": "apps/swagger/isa/tsconfig.lib.json",
|
||||
"project": "apps/swagger/isa/ng-package.json"
|
||||
@@ -424,7 +420,7 @@
|
||||
"prefix": "lib",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-ng-packagr:build",
|
||||
"builder": "@angular-devkit/build-angular:ng-packagr",
|
||||
"options": {
|
||||
"tsConfig": "apps/swagger/oms/tsconfig.lib.json",
|
||||
"project": "apps/swagger/oms/ng-package.json"
|
||||
@@ -464,7 +460,7 @@
|
||||
"prefix": "lib",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-ng-packagr:build",
|
||||
"builder": "@angular-devkit/build-angular:ng-packagr",
|
||||
"options": {
|
||||
"tsConfig": "apps/swagger/print/tsconfig.lib.json",
|
||||
"project": "apps/swagger/print/ng-package.json"
|
||||
@@ -504,7 +500,7 @@
|
||||
"prefix": "lib",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-ng-packagr:build",
|
||||
"builder": "@angular-devkit/build-angular:ng-packagr",
|
||||
"options": {
|
||||
"tsConfig": "apps/swagger/cat/tsconfig.lib.json",
|
||||
"project": "apps/swagger/cat/ng-package.json"
|
||||
@@ -544,7 +540,7 @@
|
||||
"prefix": "lib",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-ng-packagr:build",
|
||||
"builder": "@angular-devkit/build-angular:ng-packagr",
|
||||
"options": {
|
||||
"tsConfig": "apps/swagger/eis/tsconfig.lib.json",
|
||||
"project": "apps/swagger/eis/ng-package.json"
|
||||
@@ -584,7 +580,7 @@
|
||||
"prefix": "lib",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-ng-packagr:build",
|
||||
"builder": "@angular-devkit/build-angular:ng-packagr",
|
||||
"options": {
|
||||
"tsConfig": "apps/native-container/tsconfig.lib.json",
|
||||
"project": "apps/native-container/ng-package.json"
|
||||
@@ -624,7 +620,7 @@
|
||||
"prefix": "lib",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-ng-packagr:build",
|
||||
"builder": "@angular-devkit/build-angular:ng-packagr",
|
||||
"options": {
|
||||
"tsConfig": "apps/isa/remission/tsconfig.lib.json",
|
||||
"project": "apps/isa/remission/ng-package.json"
|
||||
@@ -664,7 +660,7 @@
|
||||
"prefix": "crm",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-ng-packagr:build",
|
||||
"builder": "@angular-devkit/build-angular:ng-packagr",
|
||||
"options": {
|
||||
"tsConfig": "apps/domain/crm/tsconfig.lib.json",
|
||||
"project": "apps/domain/crm/ng-package.json"
|
||||
@@ -704,7 +700,7 @@
|
||||
"prefix": "checkout",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-ng-packagr:build",
|
||||
"builder": "@angular-devkit/build-angular:ng-packagr",
|
||||
"options": {
|
||||
"tsConfig": "apps/domain/checkout/tsconfig.lib.json",
|
||||
"project": "apps/domain/checkout/ng-package.json"
|
||||
@@ -3296,7 +3292,559 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"isa-app": {
|
||||
"projectType": "application",
|
||||
"schematics": {
|
||||
"@schematics/angular:component": {
|
||||
"style": "scss"
|
||||
},
|
||||
"@schematics/angular:application": {
|
||||
"strict": true
|
||||
}
|
||||
},
|
||||
"root": "apps/isa-app",
|
||||
"sourceRoot": "apps/isa-app/src",
|
||||
"prefix": "app",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:browser",
|
||||
"options": {
|
||||
"outputPath": "dist/isa-app",
|
||||
"index": "apps/isa-app/src/index.html",
|
||||
"main": "apps/isa-app/src/main.ts",
|
||||
"polyfills": "apps/isa-app/src/polyfills.ts",
|
||||
"tsConfig": "apps/isa-app/tsconfig.app.json",
|
||||
"inlineStyleLanguage": "scss",
|
||||
"assets": [
|
||||
"apps/isa-app/src/favicon.ico",
|
||||
"apps/isa-app/src/assets",
|
||||
"apps/isa-app/src/config",
|
||||
"apps/isa-app/src/silent-refresh.html",
|
||||
"apps/isa-app/src/manifest.webmanifest"
|
||||
],
|
||||
"styles": [
|
||||
"apps/isa-app/src/styles.scss"
|
||||
],
|
||||
"scripts": [],
|
||||
"serviceWorker": true,
|
||||
"ngswConfigPath": "apps/isa-app/ngsw-config.json"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"budgets": [
|
||||
{
|
||||
"type": "initial",
|
||||
"maximumWarning": "500kb",
|
||||
"maximumError": "1mb"
|
||||
},
|
||||
{
|
||||
"type": "anyComponentStyle",
|
||||
"maximumWarning": "2kb",
|
||||
"maximumError": "4kb"
|
||||
}
|
||||
],
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "apps/isa-app/src/environments/environment.ts",
|
||||
"with": "apps/isa-app/src/environments/environment.prod.ts"
|
||||
}
|
||||
],
|
||||
"outputHashing": "all"
|
||||
},
|
||||
"development": {
|
||||
"buildOptimizer": false,
|
||||
"optimization": false,
|
||||
"vendorChunk": true,
|
||||
"extractLicenses": false,
|
||||
"sourceMap": true,
|
||||
"namedChunks": true
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production"
|
||||
},
|
||||
"serve": {
|
||||
"builder": "@angular-devkit/build-angular:dev-server",
|
||||
"configurations": {
|
||||
"production": {
|
||||
"browserTarget": "isa-app:build:production"
|
||||
},
|
||||
"development": {
|
||||
"browserTarget": "isa-app:build:development"
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "development"
|
||||
},
|
||||
"extract-i18n": {
|
||||
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||
"options": {
|
||||
"browserTarget": "isa-app:build"
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"main": "apps/isa-app/src/test.ts",
|
||||
"polyfills": "apps/isa-app/src/polyfills.ts",
|
||||
"tsConfig": "apps/isa-app/tsconfig.spec.json",
|
||||
"karmaConfig": "apps/isa-app/karma.conf.js",
|
||||
"inlineStyleLanguage": "scss",
|
||||
"assets": [
|
||||
"apps/isa-app/src/favicon.ico",
|
||||
"apps/isa-app/src/assets",
|
||||
"apps/isa-app/src/manifest.webmanifest"
|
||||
],
|
||||
"styles": [
|
||||
"apps/isa-app/src/styles.scss"
|
||||
],
|
||||
"scripts": []
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@core/config": {
|
||||
"projectType": "library",
|
||||
"root": "apps/core/config",
|
||||
"sourceRoot": "apps/core/config/src",
|
||||
"prefix": "lib",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:ng-packagr",
|
||||
"options": {
|
||||
"project": "apps/core/config/ng-package.json"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"tsConfig": "apps/core/config/tsconfig.lib.prod.json"
|
||||
},
|
||||
"development": {
|
||||
"tsConfig": "apps/core/config/tsconfig.lib.json"
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production"
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"main": "apps/core/config/src/test.ts",
|
||||
"tsConfig": "apps/core/config/tsconfig.spec.json",
|
||||
"karmaConfig": "apps/core/config/karma.conf.js"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@core/auth": {
|
||||
"projectType": "library",
|
||||
"root": "apps/core/auth",
|
||||
"sourceRoot": "apps/core/auth/src",
|
||||
"prefix": "lib",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:ng-packagr",
|
||||
"options": {
|
||||
"project": "apps/core/auth/ng-package.json"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"tsConfig": "apps/core/auth/tsconfig.lib.prod.json"
|
||||
},
|
||||
"development": {
|
||||
"tsConfig": "apps/core/auth/tsconfig.lib.json"
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production"
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"main": "apps/core/auth/src/test.ts",
|
||||
"tsConfig": "apps/core/auth/tsconfig.spec.json",
|
||||
"karmaConfig": "apps/core/auth/karma.conf.js"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@shell/footer": {
|
||||
"projectType": "library",
|
||||
"root": "apps/shell/footer",
|
||||
"sourceRoot": "apps/shell/footer/src",
|
||||
"prefix": "lib",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:ng-packagr",
|
||||
"options": {
|
||||
"project": "apps/shell/footer/ng-package.json"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"tsConfig": "apps/shell/footer/tsconfig.lib.prod.json"
|
||||
},
|
||||
"development": {
|
||||
"tsConfig": "apps/shell/footer/tsconfig.lib.json"
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production"
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"main": "apps/shell/footer/src/test.ts",
|
||||
"tsConfig": "apps/shell/footer/tsconfig.spec.json",
|
||||
"karmaConfig": "apps/shell/footer/karma.conf.js"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@shell/process": {
|
||||
"projectType": "library",
|
||||
"root": "apps/shell/process",
|
||||
"sourceRoot": "apps/shell/process/src",
|
||||
"prefix": "lib",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:ng-packagr",
|
||||
"options": {
|
||||
"project": "apps/shell/process/ng-package.json"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"tsConfig": "apps/shell/process/tsconfig.lib.prod.json"
|
||||
},
|
||||
"development": {
|
||||
"tsConfig": "apps/shell/process/tsconfig.lib.json"
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production"
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"main": "apps/shell/process/src/test.ts",
|
||||
"tsConfig": "apps/shell/process/tsconfig.spec.json",
|
||||
"karmaConfig": "apps/shell/process/karma.conf.js"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@page/dashboard": {
|
||||
"projectType": "library",
|
||||
"root": "apps/page/dashboard",
|
||||
"sourceRoot": "apps/page/dashboard/src",
|
||||
"prefix": "page",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:ng-packagr",
|
||||
"options": {
|
||||
"project": "apps/page/dashboard/ng-package.json"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"tsConfig": "apps/page/dashboard/tsconfig.lib.prod.json"
|
||||
},
|
||||
"development": {
|
||||
"tsConfig": "apps/page/dashboard/tsconfig.lib.json"
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production"
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"main": "apps/page/dashboard/src/test.ts",
|
||||
"tsConfig": "apps/page/dashboard/tsconfig.spec.json",
|
||||
"karmaConfig": "apps/page/dashboard/karma.conf.js"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@domain/isa": {
|
||||
"projectType": "library",
|
||||
"root": "apps/domain/isa",
|
||||
"sourceRoot": "apps/domain/isa/src",
|
||||
"prefix": "lib",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:ng-packagr",
|
||||
"options": {
|
||||
"project": "apps/domain/isa/ng-package.json"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"tsConfig": "apps/domain/isa/tsconfig.lib.prod.json"
|
||||
},
|
||||
"development": {
|
||||
"tsConfig": "apps/domain/isa/tsconfig.lib.json"
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production"
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"main": "apps/domain/isa/src/test.ts",
|
||||
"tsConfig": "apps/domain/isa/tsconfig.spec.json",
|
||||
"karmaConfig": "apps/domain/isa/karma.conf.js"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@core/logger": {
|
||||
"projectType": "library",
|
||||
"root": "apps/core/logger",
|
||||
"sourceRoot": "apps/core/logger/src",
|
||||
"prefix": "lib",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:ng-packagr",
|
||||
"options": {
|
||||
"project": "apps/core/logger/ng-package.json"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"tsConfig": "apps/core/logger/tsconfig.lib.prod.json"
|
||||
},
|
||||
"development": {
|
||||
"tsConfig": "apps/core/logger/tsconfig.lib.json"
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production"
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"main": "apps/core/logger/src/test.ts",
|
||||
"tsConfig": "apps/core/logger/tsconfig.spec.json",
|
||||
"karmaConfig": "apps/core/logger/karma.conf.js"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@shell/filter-overlay": {
|
||||
"projectType": "library",
|
||||
"root": "apps/shell/filter-overlay",
|
||||
"sourceRoot": "apps/shell/filter-overlay/src",
|
||||
"prefix": "lib",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:ng-packagr",
|
||||
"options": {
|
||||
"project": "apps/shell/filter-overlay/ng-package.json"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"tsConfig": "apps/shell/filter-overlay/tsconfig.lib.prod.json"
|
||||
},
|
||||
"development": {
|
||||
"tsConfig": "apps/shell/filter-overlay/tsconfig.lib.json"
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production"
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"main": "apps/shell/filter-overlay/src/test.ts",
|
||||
"tsConfig": "apps/shell/filter-overlay/tsconfig.spec.json",
|
||||
"karmaConfig": "apps/shell/filter-overlay/karma.conf.js"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@store/search-component-store": {
|
||||
"projectType": "library",
|
||||
"root": "apps/store/search-component-store",
|
||||
"sourceRoot": "apps/store/search-component-store/src",
|
||||
"prefix": "lib",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:ng-packagr",
|
||||
"options": {
|
||||
"project": "apps/store/search-component-store/ng-package.json"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"tsConfig": "apps/store/search-component-store/tsconfig.lib.prod.json"
|
||||
},
|
||||
"development": {
|
||||
"tsConfig": "apps/store/search-component-store/tsconfig.lib.json"
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production"
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"main": "apps/store/search-component-store/src/test.ts",
|
||||
"tsConfig": "apps/store/search-component-store/tsconfig.spec.json",
|
||||
"karmaConfig": "apps/store/search-component-store/karma.conf.js"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@domain/remission": {
|
||||
"projectType": "library",
|
||||
"root": "apps/domain/remission",
|
||||
"sourceRoot": "apps/domain/remission/src",
|
||||
"prefix": "lib",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:ng-packagr",
|
||||
"options": {
|
||||
"project": "apps/domain/remission/ng-package.json"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"tsConfig": "apps/domain/remission/tsconfig.lib.prod.json"
|
||||
},
|
||||
"development": {
|
||||
"tsConfig": "apps/domain/remission/tsconfig.lib.json"
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production"
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"main": "apps/domain/remission/src/test.ts",
|
||||
"tsConfig": "apps/domain/remission/tsconfig.spec.json",
|
||||
"karmaConfig": "apps/domain/remission/karma.conf.js"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@page/remission": {
|
||||
"projectType": "library",
|
||||
"root": "apps/page/remission",
|
||||
"sourceRoot": "apps/page/remission/src",
|
||||
"prefix": "page",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:ng-packagr",
|
||||
"options": {
|
||||
"project": "apps/page/remission/ng-package.json"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"tsConfig": "apps/page/remission/tsconfig.lib.prod.json"
|
||||
},
|
||||
"development": {
|
||||
"tsConfig": "apps/page/remission/tsconfig.lib.json"
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production"
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"main": "apps/page/remission/src/test.ts",
|
||||
"tsConfig": "apps/page/remission/tsconfig.spec.json",
|
||||
"karmaConfig": "apps/page/remission/karma.conf.js"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@modal/notifications": {
|
||||
"projectType": "library",
|
||||
"root": "apps/modal/notifications",
|
||||
"sourceRoot": "apps/modal/notifications/src",
|
||||
"prefix": "lib",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:ng-packagr",
|
||||
"options": {
|
||||
"project": "apps/modal/notifications/ng-package.json"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"tsConfig": "apps/modal/notifications/tsconfig.lib.prod.json"
|
||||
},
|
||||
"development": {
|
||||
"tsConfig": "apps/modal/notifications/tsconfig.lib.json"
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production"
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"main": "apps/modal/notifications/src/test.ts",
|
||||
"tsConfig": "apps/modal/notifications/tsconfig.spec.json",
|
||||
"karmaConfig": "apps/modal/notifications/karma.conf.js"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@ui/branch-dropdown": {
|
||||
"projectType": "library",
|
||||
"root": "apps/ui/branch-dropdown",
|
||||
"sourceRoot": "apps/ui/branch-dropdown/src",
|
||||
"prefix": "lib",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:ng-packagr",
|
||||
"options": {
|
||||
"tsConfig": "apps/ui/branch-dropdown/tsconfig.lib.json",
|
||||
"project": "apps/ui/branch-dropdown/ng-package.json"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"tsConfig": "apps/ui/branch-dropdown/tsconfig.lib.prod.json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"main": "apps/ui/branch-dropdown/src/test.ts",
|
||||
"tsConfig": "apps/ui/branch-dropdown/tsconfig.spec.json",
|
||||
"karmaConfig": "apps/ui/branch-dropdown/karma.conf.js"
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-devkit/build-angular:tslint",
|
||||
"options": {
|
||||
"tsConfig": [
|
||||
"apps/ui/branch-dropdown/tsconfig.lib.json",
|
||||
"apps/ui/branch-dropdown/tsconfig.spec.json"
|
||||
],
|
||||
"exclude": [
|
||||
"**/node_modules/**"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@adapter/scan": {
|
||||
"projectType": "library",
|
||||
"root": "apps/adapter/scan",
|
||||
"sourceRoot": "apps/adapter/scan/src",
|
||||
"prefix": "lib",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:ng-packagr",
|
||||
"options": {
|
||||
"project": "apps/adapter/scan/ng-package.json"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"tsConfig": "apps/adapter/scan/tsconfig.lib.prod.json"
|
||||
},
|
||||
"development": {
|
||||
"tsConfig": "apps/adapter/scan/tsconfig.lib.json"
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production"
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"main": "apps/adapter/scan/src/test.ts",
|
||||
"tsConfig": "apps/adapter/scan/tsconfig.spec.json",
|
||||
"karmaConfig": "apps/adapter/scan/karma.conf.js"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"defaultProject": "sales"
|
||||
},
|
||||
"defaultProject": "isa-app"
|
||||
}
|
||||
25
apps/adapter/scan/README.md
Normal file
25
apps/adapter/scan/README.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# Scan
|
||||
|
||||
This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 12.2.0.
|
||||
|
||||
## Code scaffolding
|
||||
|
||||
Run `ng generate component component-name --project scan` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project scan`.
|
||||
|
||||
> Note: Don't forget to add `--project scan` or else it will be added to the default project in your `angular.json` file.
|
||||
|
||||
## Build
|
||||
|
||||
Run `ng build scan` to build the project. The build artifacts will be stored in the `dist/` directory.
|
||||
|
||||
## Publishing
|
||||
|
||||
After building your library with `ng build scan`, go to the dist folder `cd dist/scan` and run `npm publish`.
|
||||
|
||||
## Running unit tests
|
||||
|
||||
Run `ng test scan` to execute the unit tests via [Karma](https://karma-runner.github.io).
|
||||
|
||||
## Further help
|
||||
|
||||
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.
|
||||
41
apps/adapter/scan/karma.conf.js
Normal file
41
apps/adapter/scan/karma.conf.js
Normal file
@@ -0,0 +1,41 @@
|
||||
// Karma configuration file, see link for more information
|
||||
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||
|
||||
module.exports = function (config) {
|
||||
config.set({
|
||||
basePath: '',
|
||||
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
||||
plugins: [
|
||||
require('karma-jasmine'),
|
||||
require('karma-chrome-launcher'),
|
||||
require('karma-jasmine-html-reporter'),
|
||||
require('karma-coverage'),
|
||||
require('@angular-devkit/build-angular/plugins/karma'),
|
||||
],
|
||||
client: {
|
||||
jasmine: {
|
||||
// you can add configuration options for Jasmine here
|
||||
// the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
|
||||
// for example, you can disable the random execution with `random: false`
|
||||
// or set a specific seed with `seed: 4321`
|
||||
},
|
||||
clearContext: false, // leave Jasmine Spec Runner output visible in browser
|
||||
},
|
||||
jasmineHtmlReporter: {
|
||||
suppressAll: true, // removes the duplicated traces
|
||||
},
|
||||
coverageReporter: {
|
||||
dir: require('path').join(__dirname, '../../../coverage/adapter/scan'),
|
||||
subdir: '.',
|
||||
reporters: [{ type: 'html' }, { type: 'text-summary' }],
|
||||
},
|
||||
reporters: ['progress', 'kjhtml'],
|
||||
port: 9876,
|
||||
colors: true,
|
||||
logLevel: config.LOG_INFO,
|
||||
autoWatch: true,
|
||||
browsers: ['Chrome'],
|
||||
singleRun: false,
|
||||
restartOnFileChange: true,
|
||||
});
|
||||
};
|
||||
7
apps/adapter/scan/ng-package.json
Normal file
7
apps/adapter/scan/ng-package.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"$schema": "../../../node_modules/ng-packagr/ng-package.schema.json",
|
||||
"dest": "../../../dist/adapter/scan",
|
||||
"lib": {
|
||||
"entryFile": "src/public-api.ts"
|
||||
}
|
||||
}
|
||||
11
apps/adapter/scan/package.json
Normal file
11
apps/adapter/scan/package.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "@adapter/scan",
|
||||
"version": "0.0.1",
|
||||
"peerDependencies": {
|
||||
"@angular/common": "^12.2.0",
|
||||
"@angular/core": "^12.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": "^2.3.0"
|
||||
}
|
||||
}
|
||||
46
apps/adapter/scan/src/lib/dev.scan-adapter.ts
Normal file
46
apps/adapter/scan/src/lib/dev.scan-adapter.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { PromptModalData, UiModalService, UiPromptModalComponent } from '@ui/modal';
|
||||
import { Observable } from 'rxjs';
|
||||
import { ScanAdapter } from './scan-adapter';
|
||||
|
||||
@Injectable()
|
||||
export class DevScanAdapter implements ScanAdapter {
|
||||
constructor(private _modal: UiModalService) {}
|
||||
|
||||
getName(): string {
|
||||
return 'Dev Scanner';
|
||||
}
|
||||
|
||||
isPrimary(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
isReady(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
scan(): Observable<string> {
|
||||
return new Observable((observer) => {
|
||||
const modalRef = this._modal.open({
|
||||
content: UiPromptModalComponent,
|
||||
title: 'Scannen',
|
||||
data: {
|
||||
message: 'Diese Eingabemaske dient nur zu Entwicklungs und Testzwecken.',
|
||||
placeholder: 'Scan Code',
|
||||
confirmText: 'weiter',
|
||||
cancelText: 'abbrechen',
|
||||
} as PromptModalData,
|
||||
});
|
||||
|
||||
const sub = modalRef.afterClosed$.subscribe((result) => {
|
||||
observer.next(result.data);
|
||||
observer.complete();
|
||||
});
|
||||
|
||||
return () => {
|
||||
modalRef.close();
|
||||
sub.unsubscribe();
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
32
apps/adapter/scan/src/lib/native.scan-adapter.ts
Normal file
32
apps/adapter/scan/src/lib/native.scan-adapter.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { NativeContainerService } from 'native-container';
|
||||
import { Observable } from 'rxjs';
|
||||
import { filter, map, take } from 'rxjs/operators';
|
||||
import { ScanAdapter } from './scan-adapter';
|
||||
|
||||
@Injectable()
|
||||
export class NativeScanAdapter implements ScanAdapter {
|
||||
constructor(private readonly nativeContainerService: NativeContainerService) {}
|
||||
|
||||
getName(): string {
|
||||
return 'Native Scanner';
|
||||
}
|
||||
|
||||
isPrimary(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
isReady(): boolean {
|
||||
// TODO: Fix Login Keycard Dauerschleife
|
||||
return this.nativeContainerService.isUiWebview().isNative || this.nativeContainerService.isIpadMini6();
|
||||
// return false;
|
||||
}
|
||||
|
||||
scan(): Observable<string> {
|
||||
return this.nativeContainerService.openScanner('scanBook').pipe(
|
||||
filter((result) => result.status === 'SUCCESS'),
|
||||
map((result) => result.data),
|
||||
take(1)
|
||||
);
|
||||
}
|
||||
}
|
||||
11
apps/adapter/scan/src/lib/scan-adapter.ts
Normal file
11
apps/adapter/scan/src/lib/scan-adapter.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
export interface ScanAdapter {
|
||||
getName(): string;
|
||||
|
||||
isPrimary(): boolean;
|
||||
|
||||
isReady(): boolean;
|
||||
|
||||
scan(): Observable<string>;
|
||||
}
|
||||
16
apps/adapter/scan/src/lib/scan.module.ts
Normal file
16
apps/adapter/scan/src/lib/scan.module.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { DevScanAdapter } from './dev.scan-adapter';
|
||||
import { NativeScanAdapter } from './native.scan-adapter';
|
||||
import { SCAN_ADAPTER } from './tokens';
|
||||
|
||||
@NgModule({})
|
||||
export class ScanAdapterModule {
|
||||
static forRoot(dev?: boolean) {
|
||||
return {
|
||||
ngModule: ScanAdapterModule,
|
||||
providers: [{ provide: SCAN_ADAPTER, useClass: NativeScanAdapter, multi: true }],
|
||||
// Use for testing:
|
||||
// providers: [{ provide: SCAN_ADAPTER, useClass: dev ? DevScanAdapter : NativeScanAdapter, multi: true }],
|
||||
};
|
||||
}
|
||||
}
|
||||
30
apps/adapter/scan/src/lib/scan.service.ts
Normal file
30
apps/adapter/scan/src/lib/scan.service.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { Inject, Injectable } from '@angular/core';
|
||||
import { ScanAdapter } from './scan-adapter';
|
||||
import { SCAN_ADAPTER } from './tokens';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class ScanAdapterService {
|
||||
constructor(@Inject(SCAN_ADAPTER) private readonly scanAdapters: ScanAdapter[]) {}
|
||||
|
||||
scanners() {
|
||||
return this.scanAdapters.filter((adapter) => adapter.isReady());
|
||||
}
|
||||
|
||||
scanner() {
|
||||
return this.scanners().find((scanner) => scanner.isPrimary()) || this.scanners().find(() => true);
|
||||
}
|
||||
|
||||
isReady() {
|
||||
return this.scanAdapters.some((adapter) => adapter.isReady());
|
||||
}
|
||||
|
||||
scan() {
|
||||
const primaryScanner = this.scanner();
|
||||
if (primaryScanner) {
|
||||
return primaryScanner.scan();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
4
apps/adapter/scan/src/lib/tokens.ts
Normal file
4
apps/adapter/scan/src/lib/tokens.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
import { InjectionToken } from '@angular/core';
|
||||
import { ScanAdapter } from './scan-adapter';
|
||||
|
||||
export const SCAN_ADAPTER = new InjectionToken<ScanAdapter>('SCAN_ADAPTER');
|
||||
6
apps/adapter/scan/src/public-api.ts
Normal file
6
apps/adapter/scan/src/public-api.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
/*
|
||||
* Public API Surface of scan
|
||||
*/
|
||||
|
||||
export * from './lib/scan.service';
|
||||
export * from './lib/scan.module';
|
||||
25
apps/adapter/scan/src/test.ts
Normal file
25
apps/adapter/scan/src/test.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
||||
|
||||
import 'zone.js';
|
||||
import 'zone.js/testing';
|
||||
import { getTestBed } from '@angular/core/testing';
|
||||
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
declare const require: {
|
||||
context(
|
||||
path: string,
|
||||
deep?: boolean,
|
||||
filter?: RegExp
|
||||
): {
|
||||
keys(): string[];
|
||||
<T>(id: string): T;
|
||||
};
|
||||
};
|
||||
|
||||
// First, initialize the Angular testing environment.
|
||||
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting(), { teardown: { destroyAfterEach: true } });
|
||||
|
||||
// Then we find all the tests.
|
||||
const context = require.context('./', true, /\.spec\.ts$/);
|
||||
// And load the modules.
|
||||
context.keys().map(context);
|
||||
20
apps/adapter/scan/tsconfig.lib.json
Normal file
20
apps/adapter/scan/tsconfig.lib.json
Normal file
@@ -0,0 +1,20 @@
|
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../../out-tsc/lib",
|
||||
"target": "es2015",
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"inlineSources": true,
|
||||
"types": [],
|
||||
"lib": [
|
||||
"dom",
|
||||
"es2018"
|
||||
]
|
||||
},
|
||||
"exclude": [
|
||||
"src/test.ts",
|
||||
"**/*.spec.ts"
|
||||
]
|
||||
}
|
||||
10
apps/adapter/scan/tsconfig.lib.prod.json
Normal file
10
apps/adapter/scan/tsconfig.lib.prod.json
Normal file
@@ -0,0 +1,10 @@
|
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||
{
|
||||
"extends": "./tsconfig.lib.json",
|
||||
"compilerOptions": {
|
||||
"declarationMap": false
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"compilationMode": "partial"
|
||||
}
|
||||
}
|
||||
17
apps/adapter/scan/tsconfig.spec.json
Normal file
17
apps/adapter/scan/tsconfig.spec.json
Normal file
@@ -0,0 +1,17 @@
|
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../../out-tsc/spec",
|
||||
"types": [
|
||||
"jasmine"
|
||||
]
|
||||
},
|
||||
"files": [
|
||||
"src/test.ts"
|
||||
],
|
||||
"include": [
|
||||
"**/*.spec.ts",
|
||||
"**/*.d.ts"
|
||||
]
|
||||
}
|
||||
@@ -1,11 +1,12 @@
|
||||
import { Inject, Injectable } from '@angular/core';
|
||||
import { Config } from '@core/config';
|
||||
import { CDN_PRODUCT_IMAGE } from './tokens';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class ProductImageService {
|
||||
constructor(@Inject(CDN_PRODUCT_IMAGE) private imageUrl: string) {}
|
||||
constructor(private readonly _config: Config) {}
|
||||
|
||||
getImageUrl({
|
||||
imageId,
|
||||
@@ -18,6 +19,6 @@ export class ProductImageService {
|
||||
height?: number;
|
||||
showDummy?: boolean;
|
||||
}): string {
|
||||
return `${this.imageUrl}/${imageId}_${width}x${height}.jpg?showDummy=${showDummy}`;
|
||||
return `${this._config.get('@cdn/product-image.url')}/${imageId}_${width}x${height}.jpg?showDummy=${showDummy}`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
||||
|
||||
import 'zone.js/dist/zone';
|
||||
import 'zone.js/dist/zone-testing';
|
||||
import 'zone.js';
|
||||
import 'zone.js/testing';
|
||||
import { getTestBed } from '@angular/core/testing';
|
||||
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
// Karma configuration file, see link for more information
|
||||
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||
const customLaunchers = require('../../../karma/custom-launchers');
|
||||
const junitReporter = require('../../../karma/junit-reporter')('core-application');
|
||||
const coverageReporter = require('../../../karma/coverage-reporter')('core-application');
|
||||
|
||||
module.exports = function (config) {
|
||||
config.set({
|
||||
@@ -9,23 +12,31 @@ module.exports = function (config) {
|
||||
require('karma-jasmine'),
|
||||
require('karma-chrome-launcher'),
|
||||
require('karma-jasmine-html-reporter'),
|
||||
require('karma-coverage-istanbul-reporter'),
|
||||
require('karma-coverage'),
|
||||
require('karma-junit-reporter'),
|
||||
require('@angular-devkit/build-angular/plugins/karma'),
|
||||
],
|
||||
client: {
|
||||
jasmine: {
|
||||
// you can add configuration options for Jasmine here
|
||||
// the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
|
||||
// for example, you can disable the random execution with `random: false`
|
||||
// or set a specific seed with `seed: 4321`
|
||||
},
|
||||
clearContext: false, // leave Jasmine Spec Runner output visible in browser
|
||||
},
|
||||
coverageIstanbulReporter: {
|
||||
dir: require('path').join(__dirname, '../../../coverage/core/application'),
|
||||
reports: ['html', 'lcovonly', 'text-summary'],
|
||||
fixWebpackSourcePaths: true,
|
||||
jasmineHtmlReporter: {
|
||||
suppressAll: true, // removes the duplicated traces
|
||||
},
|
||||
coverageReporter,
|
||||
junitReporter,
|
||||
reporters: ['progress', 'kjhtml'],
|
||||
port: 9876,
|
||||
colors: true,
|
||||
logLevel: config.LOG_INFO,
|
||||
autoWatch: true,
|
||||
browsers: ['Chrome'],
|
||||
customLaunchers,
|
||||
singleRun: false,
|
||||
restartOnFileChange: true,
|
||||
});
|
||||
|
||||
@@ -11,8 +11,13 @@ import { ApplicationService } from './application.service';
|
||||
export class CoreApplicationModule {
|
||||
static forRoot(): ModuleWithProviders<CoreApplicationModule> {
|
||||
return {
|
||||
ngModule: CoreApplicationModule,
|
||||
providers: [ApplicationService, StoreModule.forFeature('core-application', applicationReducer).providers],
|
||||
ngModule: RootCoreApplicationModule,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
imports: [StoreModule.forFeature('core-application', applicationReducer)],
|
||||
providers: [ApplicationService],
|
||||
})
|
||||
export class RootCoreApplicationModule {}
|
||||
|
||||
@@ -1,32 +1,232 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { isObservable } from 'rxjs';
|
||||
import { createServiceFactory, SpectatorService, SpyObject } from '@ngneat/spectator';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { Observable, of } from 'rxjs';
|
||||
import { first } from 'rxjs/operators';
|
||||
import { ApplicationProcess } from './defs';
|
||||
|
||||
import { ApplicationService } from './application.service';
|
||||
import * as actions from './store/application.actions';
|
||||
|
||||
describe('ApplicationService', () => {
|
||||
let service: ApplicationService;
|
||||
let spectator: SpectatorService<ApplicationService>;
|
||||
let store: SpyObject<Store>;
|
||||
const createService = createServiceFactory({
|
||||
service: ApplicationService,
|
||||
mocks: [Store],
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [ApplicationService],
|
||||
});
|
||||
service = TestBed.inject(ApplicationService);
|
||||
spectator = createService({});
|
||||
store = spectator.inject(Store);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
|
||||
describe('activatedProcessId', () => {
|
||||
it('should return the processId', () => {
|
||||
service.setActivatedProcessId(100);
|
||||
expect(service.activatedProcessId).toEqual(100);
|
||||
});
|
||||
expect(spectator.service).toBeTruthy();
|
||||
});
|
||||
|
||||
describe('activatedProcessId$', () => {
|
||||
it('should return an observable', () => {
|
||||
expect(isObservable(service.activatedProcessId$)).toBeTruthy();
|
||||
expect(spectator.service.activatedProcessId$).toBeInstanceOf(Observable);
|
||||
});
|
||||
});
|
||||
|
||||
describe('activatedProcessId', () => {
|
||||
it('should return the process id as a number', () => {
|
||||
spyOnProperty(spectator.service['activatedProcessIdSubject'] as any, 'value').and.returnValue(2);
|
||||
expect(spectator.service.activatedProcessId).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getProcesses$()', () => {
|
||||
it('should call select on store and return all selected processes', async () => {
|
||||
const processes: ApplicationProcess[] = [
|
||||
{ id: 1, name: 'Vorgang', type: 'cart', section: 'customer', data: { count: 1 } },
|
||||
{ id: 2, name: 'Vorgang', type: 'task-calendar', section: 'branch' },
|
||||
];
|
||||
store.select.and.returnValue(of(processes));
|
||||
const result = await spectator.service.getProcesses$().pipe(first()).toPromise();
|
||||
expect(result).toEqual(processes);
|
||||
expect(store.select).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should call select on store and return all section customer processes', async () => {
|
||||
const processes: ApplicationProcess[] = [
|
||||
{ id: 1, name: 'Vorgang', type: 'cart', section: 'customer', data: { count: 1 } },
|
||||
{ id: 2, name: 'Vorgang', type: 'task-calendar', section: 'branch' },
|
||||
];
|
||||
store.select.and.returnValue(of(processes));
|
||||
const result = await spectator.service.getProcesses$('customer').pipe(first()).toPromise();
|
||||
expect(result).toEqual([processes[0]]);
|
||||
expect(store.select).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should call select on store and return all section branch processes', async () => {
|
||||
const processes: ApplicationProcess[] = [
|
||||
{ id: 1, name: 'Vorgang', type: 'cart', section: 'customer', data: { count: 1 } },
|
||||
{ id: 2, name: 'Vorgang', type: 'task-calendar', section: 'branch' },
|
||||
];
|
||||
store.select.and.returnValue(of(processes));
|
||||
const result = await spectator.service.getProcesses$('branch').pipe(first()).toPromise();
|
||||
expect(result).toEqual([processes[1]]);
|
||||
expect(store.select).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getProcessById$()', () => {
|
||||
it('should return the process by id', async () => {
|
||||
const processes: ApplicationProcess[] = [
|
||||
{ id: 1, name: 'Vorgang 1', section: 'customer' },
|
||||
{ id: 2, name: 'Vorgang 2', section: 'customer' },
|
||||
];
|
||||
spyOn(spectator.service, 'getProcesses$').and.returnValue(of(processes));
|
||||
|
||||
const process = await spectator.service.getProcessById$(1).toPromise();
|
||||
expect(process.id).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getSection$()', () => {
|
||||
it('should return the selected section branch', async () => {
|
||||
const section = 'branch';
|
||||
store.select.and.returnValue(of(section));
|
||||
const result = await spectator.service.getSection$().pipe(first()).toPromise();
|
||||
expect(result).toEqual(section);
|
||||
expect(store.select).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getActivatedProcessId$', () => {
|
||||
it('should return the current selected activated process id', async () => {
|
||||
const activatedProcessId = 2;
|
||||
store.select.and.returnValue(of({ id: activatedProcessId }));
|
||||
const result = await spectator.service.getActivatedProcessId$().pipe(first()).toPromise();
|
||||
expect(result).toEqual(activatedProcessId);
|
||||
expect(store.select).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('activateProcess()', () => {
|
||||
it('should dispatch action setActivatedProcess with argument activatedProcessId and action type', () => {
|
||||
const activatedProcessId = 2;
|
||||
spectator.service.activateProcess(activatedProcessId);
|
||||
expect(store.dispatch).toHaveBeenCalledWith({ activatedProcessId, type: actions.setActivatedProcess.type });
|
||||
});
|
||||
});
|
||||
|
||||
describe('removeProcess()', () => {
|
||||
it('should dispatch action removeProcess with argument processId and action type', () => {
|
||||
const processId = 2;
|
||||
spectator.service.removeProcess(processId);
|
||||
expect(store.dispatch).toHaveBeenCalledWith({ processId, type: actions.removeProcess.type });
|
||||
});
|
||||
});
|
||||
|
||||
describe('createProcess()', () => {
|
||||
it('should dispatch action addProcess with process', async () => {
|
||||
const process: ApplicationProcess = {
|
||||
id: 1,
|
||||
name: 'Vorgang 1',
|
||||
section: 'customer',
|
||||
type: 'cart',
|
||||
};
|
||||
|
||||
const timestamp = 100;
|
||||
spyOn(spectator.service as any, '_createTimestamp').and.returnValue(timestamp);
|
||||
spyOn(spectator.service, 'getProcessById$').and.returnValue(of(undefined));
|
||||
await spectator.service.createProcess(process);
|
||||
|
||||
expect(store.dispatch).toHaveBeenCalledWith({
|
||||
type: actions.addProcess.type,
|
||||
process: {
|
||||
...process,
|
||||
activated: 0,
|
||||
created: timestamp,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should throw an error if the process id is already existing', async () => {
|
||||
const process: ApplicationProcess = {
|
||||
id: 1,
|
||||
name: 'Vorgang 1',
|
||||
section: 'customer',
|
||||
type: 'cart',
|
||||
};
|
||||
spyOn(spectator.service, 'getProcessById$').and.returnValue(of(process));
|
||||
await expectAsync(spectator.service.createProcess(process)).toBeRejectedWithError('Process Id existiert bereits');
|
||||
});
|
||||
|
||||
it('should throw an error if the process id is not a number', async () => {
|
||||
const process: ApplicationProcess = {
|
||||
id: undefined,
|
||||
name: 'Vorgang 1',
|
||||
section: 'customer',
|
||||
type: 'cart',
|
||||
};
|
||||
spyOn(spectator.service, 'getProcessById$').and.returnValue(of({ id: 5, name: 'Vorgang 2', section: 'customer' }));
|
||||
await expectAsync(spectator.service.createProcess(process)).toBeRejectedWithError('Process Id nicht gesetzt');
|
||||
});
|
||||
});
|
||||
|
||||
describe('patchProcess', () => {
|
||||
it('should dispatch action patchProcess with changes', async () => {
|
||||
const process: ApplicationProcess = {
|
||||
id: 1,
|
||||
name: 'Vorgang 1',
|
||||
section: 'customer',
|
||||
type: 'cart',
|
||||
};
|
||||
|
||||
await spectator.service.patchProcess(process.id, process);
|
||||
|
||||
expect(store.dispatch).toHaveBeenCalledWith({
|
||||
type: actions.patchProcess.type,
|
||||
process: {
|
||||
...process,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('setSection()', () => {
|
||||
it('should dispatch action setSection with argument section and action type', () => {
|
||||
const section = 'customer';
|
||||
spectator.service.setSection(section);
|
||||
expect(store.dispatch).toHaveBeenCalledWith({ section, type: actions.setSection.type });
|
||||
});
|
||||
});
|
||||
|
||||
describe('getLastActivatedProcessWithSectionAndType()', () => {
|
||||
it('should return the last activated process by section and type', async () => {
|
||||
const processes: ApplicationProcess[] = [
|
||||
{ id: 1, name: 'Vorgang 1', section: 'customer', type: 'cart', activated: 100 },
|
||||
{ id: 2, name: 'Vorgang 2', section: 'customer', type: 'cart', activated: 200 },
|
||||
{ id: 3, name: 'Vorgang 3', section: 'customer', type: 'goodsOut', activated: 300 },
|
||||
];
|
||||
spyOn(spectator.service, 'getProcesses$').and.returnValue(of(processes));
|
||||
|
||||
expect(await spectator.service.getLastActivatedProcessWithSectionAndType$('customer', 'cart').pipe(first()).toPromise()).toBe(
|
||||
processes[1]
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getLastActivatedProcessWithSection()', () => {
|
||||
it('should return the last activated process by section', async () => {
|
||||
const processes: ApplicationProcess[] = [
|
||||
{ id: 1, name: 'Vorgang 1', section: 'customer', activated: 100 },
|
||||
{ id: 2, name: 'Vorgang 2', section: 'customer', activated: 200 },
|
||||
{ id: 3, name: 'Vorgang 3', section: 'customer', activated: 300 },
|
||||
];
|
||||
spyOn(spectator.service, 'getProcesses$').and.returnValue(of(processes));
|
||||
|
||||
expect(await spectator.service.getLastActivatedProcessWithSection$('customer').pipe(first()).toPromise()).toBe(processes[2]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('_createTimestamp', () => {
|
||||
it('should return the current timestamp in ms', () => {
|
||||
expect(spectator.service['_createTimestamp']()).toBeCloseTo(Date.now());
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,37 +1,129 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { processRemoved, selectSection, setSection } from './store';
|
||||
import { isBoolean, isNumber } from '@utils/common';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { first, map, switchMap } from 'rxjs/operators';
|
||||
import { ApplicationProcess } from './defs';
|
||||
import {
|
||||
removeProcess,
|
||||
selectSection,
|
||||
selectProcesses,
|
||||
setSection,
|
||||
addProcess,
|
||||
setActivatedProcess,
|
||||
selectActivatedProcess,
|
||||
patchProcess,
|
||||
patchProcessData,
|
||||
} from './store';
|
||||
|
||||
@Injectable()
|
||||
export class ApplicationService {
|
||||
/** @deprecated */
|
||||
private activatedProcessIdSubject = new BehaviorSubject<number>(undefined);
|
||||
|
||||
/** @deprecated */
|
||||
get activatedProcessId() {
|
||||
return this.activatedProcessIdSubject.value;
|
||||
}
|
||||
|
||||
/** @deprecated */
|
||||
get activatedProcessId$() {
|
||||
return this.activatedProcessIdSubject.asObservable();
|
||||
}
|
||||
|
||||
readonly section$ = this.store.select(selectSection);
|
||||
|
||||
constructor(private store: Store) {}
|
||||
|
||||
setActivatedProcessId(processId: number) {
|
||||
if (this.activatedProcessId !== processId) {
|
||||
this.activatedProcessIdSubject.next(processId);
|
||||
}
|
||||
getProcesses$(section?: 'customer' | 'branch') {
|
||||
const processes$ = this.store.select(selectProcesses);
|
||||
return processes$.pipe(map((processes) => processes.filter((process) => (section ? process.section === section : true))));
|
||||
}
|
||||
|
||||
getProcessById$(processId: number): Observable<ApplicationProcess> {
|
||||
return this.getProcesses$().pipe(map((processes) => processes.find((process) => process.id === processId)));
|
||||
}
|
||||
|
||||
getSection$() {
|
||||
return this.store.select(selectSection);
|
||||
}
|
||||
|
||||
/** @deprecated */
|
||||
getActivatedProcessId$() {
|
||||
return this.store.select(selectActivatedProcess).pipe(map((process) => process?.id));
|
||||
}
|
||||
|
||||
activateProcess(activatedProcessId: number) {
|
||||
this.store.dispatch(setActivatedProcess({ activatedProcessId }));
|
||||
this.activatedProcessIdSubject.next(activatedProcessId);
|
||||
}
|
||||
|
||||
removeProcess(processId: number) {
|
||||
this.store.dispatch(processRemoved({ processId }));
|
||||
this.store.dispatch(removeProcess({ processId }));
|
||||
}
|
||||
|
||||
createProcess() {}
|
||||
patchProcess(processId: number, changes: Partial<ApplicationProcess>) {
|
||||
this.store.dispatch(patchProcess({ processId, changes }));
|
||||
}
|
||||
|
||||
patchProcessData(processId: number, data: Record<string, any>) {
|
||||
this.store.dispatch(patchProcessData({ processId, data }));
|
||||
}
|
||||
|
||||
async createProcess(process: ApplicationProcess) {
|
||||
const existingProcess = await this.getProcessById$(process?.id).pipe(first()).toPromise();
|
||||
if (existingProcess?.id === process?.id) {
|
||||
throw new Error('Process Id existiert bereits');
|
||||
}
|
||||
|
||||
if (!isNumber(process.id)) {
|
||||
throw new Error('Process Id nicht gesetzt');
|
||||
}
|
||||
|
||||
if (!isBoolean(process.closeable)) {
|
||||
process.closeable = true;
|
||||
}
|
||||
|
||||
if (!isBoolean(process.confirmClosing)) {
|
||||
process.confirmClosing = true;
|
||||
}
|
||||
|
||||
process.created = this._createTimestamp();
|
||||
process.activated = 0;
|
||||
this.store.dispatch(addProcess({ process }));
|
||||
}
|
||||
|
||||
setSection(section: 'customer' | 'branch') {
|
||||
this.store.dispatch(setSection({ section }));
|
||||
}
|
||||
|
||||
getLastActivatedProcessWithSectionAndType$(section: 'customer' | 'branch', type: string): Observable<ApplicationProcess> {
|
||||
return this.getProcesses$(section).pipe(
|
||||
map((processes) =>
|
||||
processes
|
||||
?.filter((process) => process.type === type)
|
||||
?.reduce((latest, current) => {
|
||||
if (!latest) {
|
||||
return current;
|
||||
}
|
||||
return latest?.activated > current?.activated ? latest : current;
|
||||
}, undefined)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
getLastActivatedProcessWithSection$(section: 'customer' | 'branch'): Observable<ApplicationProcess> {
|
||||
return this.getProcesses$(section).pipe(
|
||||
map((processes) =>
|
||||
processes?.reduce((latest, current) => {
|
||||
if (!latest) {
|
||||
return current;
|
||||
}
|
||||
return latest?.activated > current?.activated ? latest : current;
|
||||
}, undefined)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private _createTimestamp() {
|
||||
return Date.now();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
export interface ApplicationProcess {
|
||||
id: number;
|
||||
created?: number;
|
||||
activated?: number;
|
||||
name: string;
|
||||
data: { [key: string]: any };
|
||||
section: 'customer' | 'branch';
|
||||
type?: string;
|
||||
data?: { [key: string]: any };
|
||||
closeable?: boolean;
|
||||
confirmClosing?: boolean;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// start:ng42.barrel
|
||||
export * from './application.module';
|
||||
export * from './application.service';
|
||||
export * from './process.service';
|
||||
export * from './defs';
|
||||
export * from './store';
|
||||
// end:ng42.barrel
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class ProcessService {
|
||||
constructor() {}
|
||||
|
||||
updateName(processId: number, name: string) {}
|
||||
}
|
||||
@@ -1,10 +1,16 @@
|
||||
import { createAction, props } from '@ngrx/store';
|
||||
import { ApplicationProcess } from '..';
|
||||
|
||||
const prefix = '[CORE-APPLICATION]';
|
||||
|
||||
/**
|
||||
* Action nach Entfernung eines Prozesses
|
||||
*/
|
||||
export const processRemoved = createAction(`${prefix} Process Removed`, props<{ processId: number }>());
|
||||
|
||||
export const setSection = createAction(`${prefix} Set Section`, props<{ section: 'customer' | 'branch' }>());
|
||||
|
||||
export const addProcess = createAction(`${prefix} Add Process`, props<{ process: ApplicationProcess }>());
|
||||
|
||||
export const removeProcess = createAction(`${prefix} Remove Process`, props<{ processId: number }>());
|
||||
|
||||
export const setActivatedProcess = createAction(`${prefix} Set Activated Process`, props<{ activatedProcessId: number }>());
|
||||
|
||||
export const patchProcess = createAction(`${prefix} Patch Process`, props<{ processId: number; changes: Partial<ApplicationProcess> }>());
|
||||
|
||||
export const patchProcessData = createAction(`${prefix} Patch Process Data`, props<{ processId: number; data: Record<string, any> }>());
|
||||
|
||||
200
apps/core/application/src/lib/store/application.reducer.spec.ts
Normal file
200
apps/core/application/src/lib/store/application.reducer.spec.ts
Normal file
@@ -0,0 +1,200 @@
|
||||
import { INITIAL_APPLICATION_STATE } from './application.state';
|
||||
import * as actions from './application.actions';
|
||||
import { applicationReducer } from './application.reducer';
|
||||
import { ApplicationProcess } from '../defs';
|
||||
import { ApplicationState } from './application.state';
|
||||
|
||||
describe('applicationReducer', () => {
|
||||
describe('setSection()', () => {
|
||||
it('should return modified state with section customer', () => {
|
||||
const initialState = INITIAL_APPLICATION_STATE;
|
||||
|
||||
const action = actions.setSection({ section: 'customer' });
|
||||
const state = applicationReducer(initialState, action);
|
||||
|
||||
expect(state).toEqual({
|
||||
...initialState,
|
||||
section: 'customer',
|
||||
});
|
||||
});
|
||||
|
||||
it('should return modified state with section branch', () => {
|
||||
const initialState = INITIAL_APPLICATION_STATE;
|
||||
|
||||
const action = actions.setSection({ section: 'branch' });
|
||||
const state = applicationReducer(initialState, action);
|
||||
|
||||
expect(state).toEqual({
|
||||
...initialState,
|
||||
section: 'branch',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('addProcess()', () => {
|
||||
it('should return modified state with new process if no processes are registered in the state', () => {
|
||||
const initialState = INITIAL_APPLICATION_STATE;
|
||||
|
||||
const process: ApplicationProcess = {
|
||||
id: 1,
|
||||
name: 'Vorgang',
|
||||
section: 'customer',
|
||||
type: 'cart',
|
||||
data: {},
|
||||
};
|
||||
|
||||
const action = actions.addProcess({ process });
|
||||
const state = applicationReducer(initialState, action);
|
||||
expect(state.processes[0]).toEqual(process);
|
||||
});
|
||||
});
|
||||
|
||||
describe('patchProcess()', () => {
|
||||
it('should return modified state with updated process when id is found', () => {
|
||||
const initialState = INITIAL_APPLICATION_STATE;
|
||||
|
||||
const process: ApplicationProcess = {
|
||||
id: 1,
|
||||
name: 'Vorgang',
|
||||
section: 'customer',
|
||||
type: 'cart',
|
||||
};
|
||||
|
||||
const action = actions.patchProcess({ process: { ...process, name: 'Test' } });
|
||||
const state = applicationReducer(
|
||||
{
|
||||
...initialState,
|
||||
processes: [process],
|
||||
},
|
||||
action
|
||||
);
|
||||
expect(state.processes[0].name).toEqual('Test');
|
||||
});
|
||||
|
||||
it('should return unmodified state when id is not existing', () => {
|
||||
const initialState = INITIAL_APPLICATION_STATE;
|
||||
|
||||
const process: ApplicationProcess = {
|
||||
id: 1,
|
||||
name: 'Vorgang',
|
||||
section: 'customer',
|
||||
type: 'cart',
|
||||
};
|
||||
|
||||
const action = actions.patchProcess({ process: { ...process, id: 2 } });
|
||||
const state = applicationReducer(
|
||||
{
|
||||
...initialState,
|
||||
processes: [process],
|
||||
},
|
||||
action
|
||||
);
|
||||
expect(state.processes).toEqual([process]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('removeProcess()', () => {
|
||||
it('should return initial state if no processes are registered in the state', () => {
|
||||
const initialState = INITIAL_APPLICATION_STATE;
|
||||
|
||||
const action = actions.removeProcess({ processId: 2 });
|
||||
const state = applicationReducer(initialState, action);
|
||||
expect(state).toEqual(initialState);
|
||||
});
|
||||
|
||||
it('should return the unmodified state if processId not found', () => {
|
||||
const initialState = INITIAL_APPLICATION_STATE;
|
||||
const modifiedState: ApplicationState = {
|
||||
...initialState,
|
||||
section: 'customer',
|
||||
processes: [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Vorgang',
|
||||
section: 'customer',
|
||||
type: 'cart',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: 'Vorgang',
|
||||
section: 'customer',
|
||||
type: 'goods-out',
|
||||
},
|
||||
] as ApplicationProcess[],
|
||||
};
|
||||
|
||||
const action = actions.removeProcess({ processId: 2 });
|
||||
const state = applicationReducer(modifiedState, action);
|
||||
expect(state).toEqual(modifiedState);
|
||||
});
|
||||
|
||||
it('should return modified state, after process gets removed', () => {
|
||||
const initialState = INITIAL_APPLICATION_STATE;
|
||||
const modifiedState: ApplicationState = {
|
||||
...initialState,
|
||||
section: 'customer',
|
||||
processes: [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Vorgang',
|
||||
section: 'customer',
|
||||
type: 'cart',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'Vorgang',
|
||||
section: 'customer',
|
||||
type: 'goods-out',
|
||||
},
|
||||
] as ApplicationProcess[],
|
||||
};
|
||||
|
||||
const action = actions.removeProcess({ processId: 2 });
|
||||
const state = applicationReducer(modifiedState, action);
|
||||
expect(state.processes).toEqual([
|
||||
{
|
||||
id: 1,
|
||||
name: 'Vorgang',
|
||||
section: 'customer',
|
||||
type: 'cart',
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('setActivatedProcess()', () => {
|
||||
it('should return modified state with process.activated value', () => {
|
||||
const process: ApplicationProcess = {
|
||||
id: 3,
|
||||
name: 'Vorgang 3',
|
||||
section: 'customer',
|
||||
};
|
||||
const initialState: ApplicationState = {
|
||||
...INITIAL_APPLICATION_STATE,
|
||||
processes: [process],
|
||||
};
|
||||
|
||||
const action = actions.setActivatedProcess({ activatedProcessId: 3 });
|
||||
const state = applicationReducer(initialState, action);
|
||||
|
||||
expect(state.processes[0].activated).toBeDefined();
|
||||
});
|
||||
|
||||
it('should return modified state without process.activated value when activatedProcessId doesnt exist', () => {
|
||||
const process: ApplicationProcess = {
|
||||
id: 1,
|
||||
name: 'Vorgang 3',
|
||||
section: 'customer',
|
||||
};
|
||||
const initialState: ApplicationState = {
|
||||
...INITIAL_APPLICATION_STATE,
|
||||
processes: [process],
|
||||
};
|
||||
|
||||
const action = actions.setActivatedProcess({ activatedProcessId: 3 });
|
||||
const state = applicationReducer(initialState, action);
|
||||
|
||||
expect(state.processes[0].activated).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,10 +1,45 @@
|
||||
import { Action, createReducer, on } from '@ngrx/store';
|
||||
import { setSection } from './application.actions';
|
||||
import { setSection, addProcess, removeProcess, setActivatedProcess, patchProcess, patchProcessData } from './application.actions';
|
||||
import { ApplicationState, INITIAL_APPLICATION_STATE } from './application.state';
|
||||
|
||||
const _applicationReducer = createReducer(
|
||||
INITIAL_APPLICATION_STATE,
|
||||
on(setSection, (state, { section }) => ({ ...state, section }))
|
||||
on(setSection, (state, { section }) => ({ ...state, section })),
|
||||
on(addProcess, (state, { process }) => ({ ...state, processes: [...state.processes, { data: {}, ...process }] })),
|
||||
on(removeProcess, (state, { processId }) => {
|
||||
const processes = state?.processes?.filter((process) => process.id !== processId) || [];
|
||||
return { ...state, processes };
|
||||
}),
|
||||
on(setActivatedProcess, (state, { activatedProcessId }) => {
|
||||
const processes = state.processes.map((process) => {
|
||||
if (process.id === activatedProcessId) {
|
||||
return { ...process, activated: Date.now() };
|
||||
}
|
||||
return process;
|
||||
});
|
||||
|
||||
return { ...state, processes };
|
||||
}),
|
||||
on(patchProcess, (state, { processId, changes }) => {
|
||||
const processes = state.processes.map((process) => {
|
||||
if (process.id === processId) {
|
||||
return { ...process, ...changes };
|
||||
}
|
||||
return process;
|
||||
});
|
||||
|
||||
return { ...state, processes };
|
||||
}),
|
||||
on(patchProcessData, (state, { processId, data }) => {
|
||||
const processes = state.processes.map((process) => {
|
||||
if (process.id === processId) {
|
||||
return { ...process, data: { ...(process.data || {}), ...data } };
|
||||
}
|
||||
return process;
|
||||
});
|
||||
|
||||
return { ...state, processes };
|
||||
})
|
||||
);
|
||||
|
||||
export function applicationReducer(state: ApplicationState, action: Action) {
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
import { ApplicationState } from './application.state';
|
||||
import { ApplicationProcess } from '../defs';
|
||||
import * as selectors from './application.selectors';
|
||||
|
||||
describe('applicationSelectors', () => {
|
||||
it('should select the processes', () => {
|
||||
const processes: ApplicationProcess[] = [{ id: 1, name: 'Vorgang 1', section: 'customer' }];
|
||||
const state: Partial<ApplicationState> = {
|
||||
processes,
|
||||
};
|
||||
expect(selectors.selectProcesses.projector(state)).toEqual(processes);
|
||||
});
|
||||
|
||||
it('should select the section', () => {
|
||||
const state: Partial<ApplicationState> = {
|
||||
section: 'customer',
|
||||
};
|
||||
expect(selectors.selectSection.projector(state)).toEqual('customer');
|
||||
});
|
||||
|
||||
it('should select the activatedProcess', () => {
|
||||
const processes: ApplicationProcess[] = [
|
||||
{ id: 1, name: 'Vorgang 1', section: 'customer', activated: 100 },
|
||||
{ id: 2, name: 'Vorgang 2', section: 'customer', activated: 300 },
|
||||
{ id: 3, name: 'Vorgang 3', section: 'customer', activated: 200 },
|
||||
];
|
||||
const state: Partial<ApplicationState> = {
|
||||
processes,
|
||||
};
|
||||
expect(selectors.selectActivatedProcess.projector(state)).toEqual(processes[1]);
|
||||
});
|
||||
});
|
||||
@@ -3,3 +3,14 @@ import { ApplicationState } from './application.state';
|
||||
export const selectApplicationState = createFeatureSelector<ApplicationState>('core-application');
|
||||
|
||||
export const selectSection = createSelector(selectApplicationState, (s) => s.section);
|
||||
|
||||
export const selectProcesses = createSelector(selectApplicationState, (s) => s.processes);
|
||||
|
||||
export const selectActivatedProcess = createSelector(selectApplicationState, (s) =>
|
||||
s?.processes?.reduce((process, current) => {
|
||||
if (!process) {
|
||||
return current;
|
||||
}
|
||||
return process.activated > current.activated ? process : current;
|
||||
}, undefined)
|
||||
);
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import { ApplicationProcess } from '../defs';
|
||||
|
||||
export interface ApplicationState {
|
||||
processes: ApplicationProcess[];
|
||||
section: 'customer' | 'branch';
|
||||
}
|
||||
|
||||
export const INITIAL_APPLICATION_STATE: ApplicationState = {
|
||||
processes: [],
|
||||
section: 'customer',
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
||||
|
||||
import 'zone.js/dist/zone';
|
||||
import 'zone.js/dist/zone-testing';
|
||||
import 'zone.js';
|
||||
import 'zone.js/testing';
|
||||
import { getTestBed } from '@angular/core/testing';
|
||||
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
|
||||
25
apps/core/auth/README.md
Normal file
25
apps/core/auth/README.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# Auth
|
||||
|
||||
This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 12.2.0.
|
||||
|
||||
## Code scaffolding
|
||||
|
||||
Run `ng generate component component-name --project auth` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project auth`.
|
||||
|
||||
> Note: Don't forget to add `--project auth` or else it will be added to the default project in your `angular.json` file.
|
||||
|
||||
## Build
|
||||
|
||||
Run `ng build auth` to build the project. The build artifacts will be stored in the `dist/` directory.
|
||||
|
||||
## Publishing
|
||||
|
||||
After building your library with `ng build auth`, go to the dist folder `cd dist/auth` and run `npm publish`.
|
||||
|
||||
## Running unit tests
|
||||
|
||||
Run `ng test auth` to execute the unit tests via [Karma](https://karma-runner.github.io).
|
||||
|
||||
## Further help
|
||||
|
||||
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.
|
||||
43
apps/core/auth/karma.conf.js
Normal file
43
apps/core/auth/karma.conf.js
Normal file
@@ -0,0 +1,43 @@
|
||||
// Karma configuration file, see link for more information
|
||||
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||
const customLaunchers = require('../../../karma/custom-launchers');
|
||||
const junitReporter = require('../../../karma/junit-reporter')('core-auth');
|
||||
const coverageReporter = require('../../../karma/coverage-reporter')('core-auth');
|
||||
|
||||
module.exports = function (config) {
|
||||
config.set({
|
||||
basePath: '',
|
||||
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
||||
plugins: [
|
||||
require('karma-jasmine'),
|
||||
require('karma-chrome-launcher'),
|
||||
require('karma-jasmine-html-reporter'),
|
||||
require('karma-coverage'),
|
||||
require('karma-junit-reporter'),
|
||||
require('@angular-devkit/build-angular/plugins/karma'),
|
||||
],
|
||||
client: {
|
||||
jasmine: {
|
||||
// you can add configuration options for Jasmine here
|
||||
// the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
|
||||
// for example, you can disable the random execution with `random: false`
|
||||
// or set a specific seed with `seed: 4321`
|
||||
},
|
||||
clearContext: false, // leave Jasmine Spec Runner output visible in browser
|
||||
},
|
||||
jasmineHtmlReporter: {
|
||||
suppressAll: true, // removes the duplicated traces
|
||||
},
|
||||
coverageReporter,
|
||||
junitReporter,
|
||||
reporters: ['progress', 'kjhtml'],
|
||||
port: 9876,
|
||||
colors: true,
|
||||
logLevel: config.LOG_INFO,
|
||||
autoWatch: true,
|
||||
browsers: ['Chrome'],
|
||||
customLaunchers,
|
||||
singleRun: false,
|
||||
restartOnFileChange: true,
|
||||
});
|
||||
};
|
||||
7
apps/core/auth/ng-package.json
Normal file
7
apps/core/auth/ng-package.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"$schema": "../../../node_modules/ng-packagr/ng-package.schema.json",
|
||||
"dest": "../../../dist/core/auth",
|
||||
"lib": {
|
||||
"entryFile": "src/public-api.ts"
|
||||
}
|
||||
}
|
||||
11
apps/core/auth/package.json
Normal file
11
apps/core/auth/package.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "@core/auth",
|
||||
"version": "0.0.1",
|
||||
"peerDependencies": {
|
||||
"@angular/common": "^12.2.0",
|
||||
"@angular/core": "^12.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": "^2.3.0"
|
||||
}
|
||||
}
|
||||
17
apps/core/auth/src/lib/auth.module.ts
Normal file
17
apps/core/auth/src/lib/auth.module.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { ModuleWithProviders, NgModule } from '@angular/core';
|
||||
import { AuthService } from './auth.service';
|
||||
import { OAuthModule } from 'angular-oauth2-oidc';
|
||||
@NgModule({})
|
||||
export class AuthModule {
|
||||
static forRoot(): ModuleWithProviders<AuthModule> {
|
||||
return {
|
||||
ngModule: AuthModule,
|
||||
providers: [
|
||||
AuthService,
|
||||
OAuthModule.forRoot({
|
||||
resourceServer: { sendAccessToken: true },
|
||||
}).providers,
|
||||
],
|
||||
};
|
||||
}
|
||||
}
|
||||
151
apps/core/auth/src/lib/auth.service.spec.ts
Normal file
151
apps/core/auth/src/lib/auth.service.spec.ts
Normal file
@@ -0,0 +1,151 @@
|
||||
import { Config } from '@core/config';
|
||||
import { SpectatorService, createServiceFactory, SpyObject } from '@ngneat/spectator';
|
||||
import { OAuthService } from 'angular-oauth2-oidc';
|
||||
import { JwksValidationHandler } from 'angular-oauth2-oidc-jwks';
|
||||
import { Observable } from 'rxjs';
|
||||
import { AuthService } from './auth.service';
|
||||
|
||||
describe('AuthService', () => {
|
||||
let spectator: SpectatorService<AuthService>;
|
||||
const createService = createServiceFactory({
|
||||
service: AuthService,
|
||||
mocks: [Config, OAuthService],
|
||||
});
|
||||
let config: SpyObject<Config>;
|
||||
let oAuthService: SpyObject<OAuthService>;
|
||||
|
||||
beforeEach(() => {
|
||||
spectator = createService();
|
||||
config = spectator.inject(Config);
|
||||
oAuthService = spectator.inject(OAuthService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(spectator.service).toBeTruthy();
|
||||
});
|
||||
|
||||
describe('init()', () => {
|
||||
it('should configure the oAuthService', () => {
|
||||
config.get.and.returnValue({});
|
||||
spectator.service.init();
|
||||
expect(oAuthService.configure).toHaveBeenCalledWith({
|
||||
redirectUri: window.location.origin,
|
||||
silentRefreshRedirectUri: window.location.origin + '/silent-refresh.html',
|
||||
useSilentRefresh: true,
|
||||
});
|
||||
expect(oAuthService.tokenValidationHandler).toBeInstanceOf(JwksValidationHandler);
|
||||
expect(oAuthService.setupAutomaticSilentRefresh).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should load the discovery document', async () => {
|
||||
config.get.and.returnValue({});
|
||||
oAuthService.loadDiscoveryDocumentAndTryLogin.and.returnValue(Promise.resolve(true));
|
||||
|
||||
spyOn(spectator.service['_initialized'], 'next');
|
||||
await spectator.service.init();
|
||||
|
||||
expect(oAuthService.loadDiscoveryDocumentAndTryLogin).toHaveBeenCalled();
|
||||
expect(spectator.service['_initialized'].next).toHaveBeenCalledWith(true);
|
||||
});
|
||||
|
||||
it('should throw an error if its already initialized', async () => {
|
||||
spyOn(spectator.service['_initialized'], 'getValue').and.returnValue(true);
|
||||
await expectAsync(spectator.service.init()).toBeRejectedWithError('AuthService is already initialized');
|
||||
});
|
||||
});
|
||||
|
||||
describe('isAuthenticated()', () => {
|
||||
it('should call hasValidIdToken() and return its value', () => {
|
||||
oAuthService.hasValidIdToken.and.returnValue(true);
|
||||
expect(spectator.service.isAuthenticated()).toBeTrue();
|
||||
expect(oAuthService.hasValidIdToken).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getToken()', () => {
|
||||
it('should call getAccessToken() and return its value', () => {
|
||||
oAuthService.getAccessToken.and.returnValue('token');
|
||||
expect(spectator.service.getToken()).toEqual('token');
|
||||
expect(oAuthService.getAccessToken).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getClaims()', () => {
|
||||
it('should call getAccessToken() and return its value', () => {
|
||||
oAuthService.getAccessToken.and.returnValue('token');
|
||||
const claims = {
|
||||
claim1: 'value',
|
||||
claim2: 'value2',
|
||||
};
|
||||
spyOn(spectator.service, 'parseJwt').and.returnValue(claims);
|
||||
expect(spectator.service.getClaims()).toEqual(claims);
|
||||
expect(spectator.service.parseJwt).toHaveBeenCalledWith('token');
|
||||
expect(oAuthService.getAccessToken).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getClaimByKey()', () => {
|
||||
it('should call getClaims() and return its key value', () => {
|
||||
spyOn(spectator.service, 'getClaims').and.returnValue({
|
||||
claim1: 'value',
|
||||
claim2: 'value2',
|
||||
});
|
||||
|
||||
expect(spectator.service.getClaimByKey('claim1')).toEqual('value');
|
||||
expect(spectator.service.getClaims).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should return null if getClaims() returns null or undefined', () => {
|
||||
spyOn(spectator.service, 'getClaims').and.returnValue(null);
|
||||
|
||||
expect(spectator.service.getClaimByKey('claim1')).toBeNull();
|
||||
expect(spectator.service.getClaims).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('parseJwt()', () => {
|
||||
it('should return null if the token is null or undefined', () => {
|
||||
expect(spectator.service.parseJwt(null)).toBeNull();
|
||||
expect(spectator.service.parseJwt(undefined)).toBeNull();
|
||||
});
|
||||
|
||||
it('should return the value of the key', () => {
|
||||
const token =
|
||||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ';
|
||||
expect(spectator.service.parseJwt(token)).toEqual({
|
||||
sub: '1234567890',
|
||||
name: 'John Doe',
|
||||
admin: true,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('login()', () => {
|
||||
it('should call initLoginFlow()', () => {
|
||||
spectator.service.login();
|
||||
expect(oAuthService.initLoginFlow).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('logout()', () => {
|
||||
it('should call revokeTokenAndLogout()', async () => {
|
||||
await spectator.service.logout();
|
||||
expect(oAuthService.revokeTokenAndLogout).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getToken()', () => {
|
||||
it('should return getAccessToken()', () => {
|
||||
spectator.service.getToken();
|
||||
expect(oAuthService.getAccessToken).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('initialized', () => {
|
||||
it('should return _initialized as Observable', () => {
|
||||
spyOn(spectator.service['_initialized'], 'asObservable').and.callThrough();
|
||||
expect(spectator.service.initialized$).toBeInstanceOf(Observable);
|
||||
expect(spectator.service['_initialized'].asObservable).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
84
apps/core/auth/src/lib/auth.service.ts
Normal file
84
apps/core/auth/src/lib/auth.service.ts
Normal file
@@ -0,0 +1,84 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Config } from '@core/config';
|
||||
import { isNullOrUndefined } from '@utils/common';
|
||||
import { AuthConfig, OAuthService } from 'angular-oauth2-oidc';
|
||||
import { JwksValidationHandler } from 'angular-oauth2-oidc-jwks';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class AuthService {
|
||||
private readonly _initialized = new BehaviorSubject<boolean>(false);
|
||||
get initialized$() {
|
||||
return this._initialized.asObservable();
|
||||
}
|
||||
|
||||
constructor(private _config: Config, private readonly _oAuthService: OAuthService) {}
|
||||
|
||||
async init() {
|
||||
if (this._initialized.getValue()) {
|
||||
throw new Error('AuthService is already initialized');
|
||||
}
|
||||
|
||||
const authConfig: AuthConfig = this._config.get('@core/auth');
|
||||
|
||||
authConfig.redirectUri = window.location.origin;
|
||||
authConfig.silentRefreshRedirectUri = window.location.origin + '/silent-refresh.html';
|
||||
authConfig.useSilentRefresh = true;
|
||||
|
||||
this._oAuthService.configure(authConfig);
|
||||
this._oAuthService.tokenValidationHandler = new JwksValidationHandler();
|
||||
|
||||
this._oAuthService.setupAutomaticSilentRefresh();
|
||||
await this._oAuthService.loadDiscoveryDocumentAndTryLogin();
|
||||
|
||||
this._initialized.next(true);
|
||||
}
|
||||
|
||||
isAuthenticated() {
|
||||
return this._oAuthService.hasValidIdToken();
|
||||
}
|
||||
|
||||
getToken() {
|
||||
return this._oAuthService.getAccessToken();
|
||||
}
|
||||
|
||||
getClaims() {
|
||||
const token = this._oAuthService.getAccessToken();
|
||||
return this.parseJwt(token);
|
||||
}
|
||||
|
||||
getClaimByKey(key: string) {
|
||||
const claims = this.getClaims();
|
||||
if (isNullOrUndefined(claims)) {
|
||||
return null;
|
||||
}
|
||||
return claims[key];
|
||||
}
|
||||
|
||||
parseJwt(token: string) {
|
||||
if (isNullOrUndefined(token)) {
|
||||
return null;
|
||||
}
|
||||
const base64Url = token.split('.')[1];
|
||||
const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
|
||||
|
||||
const encoded = window.atob(base64);
|
||||
return JSON.parse(encoded);
|
||||
}
|
||||
|
||||
login() {
|
||||
this._oAuthService.initLoginFlow();
|
||||
}
|
||||
|
||||
setKeyCardToken(token: string) {
|
||||
this._oAuthService.customQueryParams = {
|
||||
temp_token: token,
|
||||
};
|
||||
}
|
||||
|
||||
async logout() {
|
||||
await this._oAuthService.revokeTokenAndLogout();
|
||||
}
|
||||
}
|
||||
4
apps/core/auth/src/lib/index.ts
Normal file
4
apps/core/auth/src/lib/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
// start:ng42.barrel
|
||||
export * from './auth.module';
|
||||
export * from './auth.service';
|
||||
// end:ng42.barrel
|
||||
5
apps/core/auth/src/public-api.ts
Normal file
5
apps/core/auth/src/public-api.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
/*
|
||||
* Public API Surface of auth
|
||||
*/
|
||||
|
||||
export * from './lib';
|
||||
25
apps/core/auth/src/test.ts
Normal file
25
apps/core/auth/src/test.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
||||
|
||||
import 'zone.js';
|
||||
import 'zone.js/testing';
|
||||
import { getTestBed } from '@angular/core/testing';
|
||||
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
declare const require: {
|
||||
context(
|
||||
path: string,
|
||||
deep?: boolean,
|
||||
filter?: RegExp
|
||||
): {
|
||||
keys(): string[];
|
||||
<T>(id: string): T;
|
||||
};
|
||||
};
|
||||
|
||||
// First, initialize the Angular testing environment.
|
||||
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting(), { teardown: { destroyAfterEach: true } });
|
||||
|
||||
// Then we find all the tests.
|
||||
const context = require.context('./', true, /\.spec\.ts$/);
|
||||
// And load the modules.
|
||||
context.keys().map(context);
|
||||
20
apps/core/auth/tsconfig.lib.json
Normal file
20
apps/core/auth/tsconfig.lib.json
Normal file
@@ -0,0 +1,20 @@
|
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../../out-tsc/lib",
|
||||
"target": "es2015",
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"inlineSources": true,
|
||||
"types": [],
|
||||
"lib": [
|
||||
"dom",
|
||||
"es2018"
|
||||
]
|
||||
},
|
||||
"exclude": [
|
||||
"src/test.ts",
|
||||
"**/*.spec.ts"
|
||||
]
|
||||
}
|
||||
10
apps/core/auth/tsconfig.lib.prod.json
Normal file
10
apps/core/auth/tsconfig.lib.prod.json
Normal file
@@ -0,0 +1,10 @@
|
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||
{
|
||||
"extends": "./tsconfig.lib.json",
|
||||
"compilerOptions": {
|
||||
"declarationMap": false
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"compilationMode": "partial"
|
||||
}
|
||||
}
|
||||
17
apps/core/auth/tsconfig.spec.json
Normal file
17
apps/core/auth/tsconfig.spec.json
Normal file
@@ -0,0 +1,17 @@
|
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../../out-tsc/spec",
|
||||
"types": [
|
||||
"jasmine"
|
||||
]
|
||||
},
|
||||
"files": [
|
||||
"src/test.ts"
|
||||
],
|
||||
"include": [
|
||||
"**/*.spec.ts",
|
||||
"**/*.d.ts"
|
||||
]
|
||||
}
|
||||
@@ -3,7 +3,7 @@ import { Store } from '@ngrx/store';
|
||||
import { getNumberId } from '@utils/id';
|
||||
|
||||
import { Observable } from 'rxjs';
|
||||
import { map, take } from 'rxjs/operators';
|
||||
import { first, map, take } from 'rxjs/operators';
|
||||
import { Breadcrumb } from './defs';
|
||||
|
||||
import * as actions from './store/breadcrumb.actions';
|
||||
@@ -29,6 +29,19 @@ export class BreadcrumbService {
|
||||
return this.store.select(selectors.selectBreadcrumbsByKey, key);
|
||||
}
|
||||
|
||||
getLastActivatedBreadcrumbByKey$(key: string | number): Observable<Breadcrumb> {
|
||||
return this.getBreadcrumbByKey$(key).pipe(
|
||||
map((crumbs) =>
|
||||
crumbs.reduce((latest, current) => {
|
||||
if (!latest) {
|
||||
return current;
|
||||
}
|
||||
return latest.timestamp > current.timestamp ? latest : current;
|
||||
}, undefined)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
addBreadcrumb(breadcrumb: Breadcrumb): Breadcrumb {
|
||||
const newBreadcrumb: Breadcrumb = { ...breadcrumb, id: getNumberId(), timestamp: Date.now(), changed: Date.now() };
|
||||
this.store.dispatch(actions.addBreadcrumb({ breadcrumb: newBreadcrumb }));
|
||||
@@ -39,6 +52,11 @@ export class BreadcrumbService {
|
||||
this.store.dispatch(actions.updateBreadcrumb({ id: breadcrumbId, changes: { ...changes, changed: Date.now() } }));
|
||||
}
|
||||
|
||||
async patchBreadcrumbByKeyAndTags(key: string | number, tags: string[], changes: Partial<Breadcrumb>) {
|
||||
const crumbs = await this.getBreadcrumbsByKeyAndTags$(key, tags).pipe(first()).toPromise();
|
||||
crumbs.forEach((crumb) => this.patchBreadcrumb(crumb.id, changes));
|
||||
}
|
||||
|
||||
async addBreadcrumbIfNotExists(breadcrumb: Breadcrumb) {
|
||||
const crumbs = await this.getBreadcrumbsByKeyAndTags$(breadcrumb.key, breadcrumb.tags).pipe(take(1)).toPromise();
|
||||
if (crumbs.length === 0) {
|
||||
@@ -112,6 +130,11 @@ export class BreadcrumbService {
|
||||
this.store.dispatch(actions.removeManyBreadcrumb({ ids: breadcrumbsToRemove.map((crumb) => crumb.id) }));
|
||||
}
|
||||
|
||||
async removeBreadcrumbsByKeyAndTags(key: number | string, tags: string[]) {
|
||||
const crumbs = await this.getBreadcrumbsByKeyAndTags$(key, tags).pipe(first()).toPromise();
|
||||
crumbs.forEach((crumb) => this.removeBreadcrumb(crumb.id));
|
||||
}
|
||||
|
||||
getLatestBreadcrumbForSection(section: 'customer' | 'branch') {
|
||||
return this.store
|
||||
.select(selectors.selectBreadcrumbsBySection, { section })
|
||||
|
||||
@@ -42,5 +42,5 @@ export interface Breadcrumb {
|
||||
/**
|
||||
* Applicatiuon Section
|
||||
*/
|
||||
section: 'branch' | 'customer';
|
||||
section: string;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { processRemoved } from '@core/application';
|
||||
import { removeProcess } from '@core/application';
|
||||
import { Actions, createEffect, ofType } from '@ngrx/effects';
|
||||
import { NEVER } from 'rxjs';
|
||||
import { mergeMap, tap, first, map } from 'rxjs/operators';
|
||||
@@ -10,7 +10,7 @@ export class BreadcrumbEffects {
|
||||
removeProcess$ = createEffect(
|
||||
() =>
|
||||
this.actions$.pipe(
|
||||
ofType(processRemoved),
|
||||
ofType(removeProcess),
|
||||
mergeMap((action) =>
|
||||
this.breadcrumb.getBreadcrumbByKey$(action.processId).pipe(
|
||||
first(),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
||||
|
||||
import 'zone.js/dist/zone';
|
||||
import 'zone.js/dist/zone-testing';
|
||||
import 'zone.js';
|
||||
import 'zone.js/testing';
|
||||
import { getTestBed } from '@angular/core/testing';
|
||||
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
|
||||
2
apps/core/cache/src/lib/cache.service.ts
vendored
2
apps/core/cache/src/lib/cache.service.ts
vendored
@@ -51,7 +51,7 @@ export class CacheService {
|
||||
return cached.data;
|
||||
}
|
||||
|
||||
private delete(token: Object, from: 'session' | 'persist' = 'session') {
|
||||
delete(token: Object, from: 'session' | 'persist' = 'session') {
|
||||
if (from === 'session') {
|
||||
sessionStorage.removeItem(this.getKey(token));
|
||||
} else if (from === 'persist') {
|
||||
|
||||
4
apps/core/cache/src/test.ts
vendored
4
apps/core/cache/src/test.ts
vendored
@@ -1,7 +1,7 @@
|
||||
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
||||
|
||||
import 'zone.js/dist/zone';
|
||||
import 'zone.js/dist/zone-testing';
|
||||
import 'zone.js';
|
||||
import 'zone.js/testing';
|
||||
import { getTestBed } from '@angular/core/testing';
|
||||
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
||||
|
||||
import 'zone.js/dist/zone';
|
||||
import 'zone.js/dist/zone-testing';
|
||||
import 'zone.js';
|
||||
import 'zone.js/testing';
|
||||
import { getTestBed } from '@angular/core/testing';
|
||||
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
|
||||
25
apps/core/config/README.md
Normal file
25
apps/core/config/README.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# Config
|
||||
|
||||
This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 12.2.0.
|
||||
|
||||
## Code scaffolding
|
||||
|
||||
Run `ng generate component component-name --project config` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project config`.
|
||||
|
||||
> Note: Don't forget to add `--project config` or else it will be added to the default project in your `angular.json` file.
|
||||
|
||||
## Build
|
||||
|
||||
Run `ng build config` to build the project. The build artifacts will be stored in the `dist/` directory.
|
||||
|
||||
## Publishing
|
||||
|
||||
After building your library with `ng build config`, go to the dist folder `cd dist/config` and run `npm publish`.
|
||||
|
||||
## Running unit tests
|
||||
|
||||
Run `ng test config` to execute the unit tests via [Karma](https://karma-runner.github.io).
|
||||
|
||||
## Further help
|
||||
|
||||
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.
|
||||
43
apps/core/config/karma.conf.js
Normal file
43
apps/core/config/karma.conf.js
Normal file
@@ -0,0 +1,43 @@
|
||||
// Karma configuration file, see link for more information
|
||||
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||
const customLaunchers = require('../../../karma/custom-launchers');
|
||||
const junitReporter = require('../../../karma/junit-reporter')('core-config');
|
||||
const coverageReporter = require('../../../karma/coverage-reporter')('core-config');
|
||||
|
||||
module.exports = function (config) {
|
||||
config.set({
|
||||
basePath: '',
|
||||
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
||||
plugins: [
|
||||
require('karma-jasmine'),
|
||||
require('karma-chrome-launcher'),
|
||||
require('karma-jasmine-html-reporter'),
|
||||
require('karma-coverage'),
|
||||
require('karma-junit-reporter'),
|
||||
require('@angular-devkit/build-angular/plugins/karma'),
|
||||
],
|
||||
client: {
|
||||
jasmine: {
|
||||
// you can add configuration options for Jasmine here
|
||||
// the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
|
||||
// for example, you can disable the random execution with `random: false`
|
||||
// or set a specific seed with `seed: 4321`
|
||||
},
|
||||
clearContext: false, // leave Jasmine Spec Runner output visible in browser
|
||||
},
|
||||
jasmineHtmlReporter: {
|
||||
suppressAll: true, // removes the duplicated traces
|
||||
},
|
||||
coverageReporter,
|
||||
junitReporter,
|
||||
reporters: ['progress', 'kjhtml'],
|
||||
port: 9876,
|
||||
colors: true,
|
||||
logLevel: config.LOG_INFO,
|
||||
autoWatch: true,
|
||||
browsers: ['Chrome'],
|
||||
customLaunchers,
|
||||
singleRun: false,
|
||||
restartOnFileChange: true,
|
||||
});
|
||||
};
|
||||
7
apps/core/config/ng-package.json
Normal file
7
apps/core/config/ng-package.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"$schema": "../../../node_modules/ng-packagr/ng-package.schema.json",
|
||||
"dest": "../../../dist/core/config",
|
||||
"lib": {
|
||||
"entryFile": "src/public-api.ts"
|
||||
}
|
||||
}
|
||||
11
apps/core/config/package.json
Normal file
11
apps/core/config/package.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "@core/config",
|
||||
"version": "0.0.1",
|
||||
"peerDependencies": {
|
||||
"@angular/common": "^12.2.0",
|
||||
"@angular/core": "^12.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": "^2.3.0"
|
||||
}
|
||||
}
|
||||
8
apps/core/config/src/lib/config-loaders/config-loader.ts
Normal file
8
apps/core/config/src/lib/config-loaders/config-loader.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
/**
|
||||
* Config loader interface for loading configurations
|
||||
*/
|
||||
export interface ConfigLoader {
|
||||
load(): Promise<any>;
|
||||
}
|
||||
4
apps/core/config/src/lib/config-loaders/index.ts
Normal file
4
apps/core/config/src/lib/config-loaders/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
// start:ng42.barrel
|
||||
export * from './config-loader';
|
||||
export * from './json.config-loader';
|
||||
// end:ng42.barrel
|
||||
@@ -0,0 +1,36 @@
|
||||
// unit test JsonConfigLoader
|
||||
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
|
||||
import { createServiceFactory, SpectatorService } from '@ngneat/spectator';
|
||||
import { CORE_JSON_CONFIG_LOADER_URL } from '../tokens';
|
||||
import { JsonConfigLoader } from './json.config-loader';
|
||||
|
||||
describe('JsonConfigLoader', () => {
|
||||
let spectator: SpectatorService<JsonConfigLoader>;
|
||||
const createService = createServiceFactory({
|
||||
imports: [HttpClientTestingModule],
|
||||
service: JsonConfigLoader,
|
||||
mocks: [],
|
||||
providers: [{ provide: CORE_JSON_CONFIG_LOADER_URL, useValue: '/assets/config.json' }],
|
||||
});
|
||||
let httpTestingController: HttpTestingController;
|
||||
|
||||
beforeEach(() => {
|
||||
spectator = createService();
|
||||
httpTestingController = spectator.inject(HttpTestingController);
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(spectator.service).toBeTruthy();
|
||||
});
|
||||
|
||||
describe('load', () => {
|
||||
it('should call the provided url', async () => {
|
||||
const reqPromise = spectator.service.load();
|
||||
const req = httpTestingController.expectOne('/assets/config.json');
|
||||
req.flush({ unit: 'test' });
|
||||
const result = await reqPromise;
|
||||
httpTestingController.verify();
|
||||
expect(result).toEqual({ unit: 'test' });
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,13 @@
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Inject, Injectable } from '@angular/core';
|
||||
import { ConfigLoader } from './config-loader';
|
||||
import { CORE_JSON_CONFIG_LOADER_URL } from '../tokens';
|
||||
|
||||
@Injectable()
|
||||
export class JsonConfigLoader implements ConfigLoader {
|
||||
constructor(@Inject(CORE_JSON_CONFIG_LOADER_URL) private url: string, private http: HttpClient) {}
|
||||
|
||||
load(): Promise<any> {
|
||||
return this.http.get(this.url).toPromise();
|
||||
}
|
||||
}
|
||||
7
apps/core/config/src/lib/config-module-options.ts
Normal file
7
apps/core/config/src/lib/config-module-options.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { Type } from '@angular/core';
|
||||
import { ConfigLoader } from './config-loaders';
|
||||
|
||||
export interface ConfigModuleOptions {
|
||||
useConfigLoader: Type<ConfigLoader>;
|
||||
jsonConfigLoaderUrl?: string;
|
||||
}
|
||||
28
apps/core/config/src/lib/config.module.ts
Normal file
28
apps/core/config/src/lib/config.module.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { APP_INITIALIZER, ModuleWithProviders, NgModule } from '@angular/core';
|
||||
import { CORE_CONFIG_LOADER } from '@core/config';
|
||||
import { Config } from './config';
|
||||
import { ConfigModuleOptions } from './config-module-options';
|
||||
import { CORE_JSON_CONFIG_LOADER_URL } from './tokens';
|
||||
|
||||
export function _initializeConfigFactory(config: Config) {
|
||||
return () => config.init();
|
||||
}
|
||||
|
||||
@NgModule({})
|
||||
export class ConfigModule {
|
||||
static forRoot(options: ConfigModuleOptions): ModuleWithProviders<ConfigModule> {
|
||||
const configLoaderProvider = {
|
||||
provide: CORE_CONFIG_LOADER,
|
||||
useClass: options.useConfigLoader,
|
||||
};
|
||||
|
||||
return {
|
||||
ngModule: ConfigModule,
|
||||
providers: [
|
||||
Config,
|
||||
configLoaderProvider,
|
||||
options.jsonConfigLoaderUrl ? { provide: CORE_JSON_CONFIG_LOADER_URL, useValue: options.jsonConfigLoaderUrl } : null,
|
||||
],
|
||||
};
|
||||
}
|
||||
}
|
||||
45
apps/core/config/src/lib/config.spec.ts
Normal file
45
apps/core/config/src/lib/config.spec.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { createServiceFactory, SpectatorService } from '@ngneat/spectator';
|
||||
import { Config } from './config';
|
||||
import { ConfigLoader } from './config-loaders';
|
||||
import { CORE_CONFIG_LOADER } from './tokens';
|
||||
|
||||
class TestConfigLoader implements ConfigLoader {
|
||||
load() {
|
||||
return Promise.resolve({});
|
||||
}
|
||||
}
|
||||
|
||||
// Unit test Config
|
||||
describe('Config', () => {
|
||||
let spectator: SpectatorService<Config>;
|
||||
const createService = createServiceFactory({
|
||||
service: Config,
|
||||
providers: [{ provide: CORE_CONFIG_LOADER, useClass: TestConfigLoader }],
|
||||
});
|
||||
let configLoader: ConfigLoader;
|
||||
|
||||
beforeEach(() => {
|
||||
spectator = createService();
|
||||
configLoader = spectator.inject(CORE_CONFIG_LOADER);
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(spectator.service).toBeTruthy();
|
||||
});
|
||||
|
||||
describe('init()', () => {
|
||||
it('should load config and assigns it to _config', async () => {
|
||||
const config = { unit: 'test' };
|
||||
spyOn(configLoader, 'load').and.returnValue(Promise.resolve(config));
|
||||
await spectator.service.init();
|
||||
expect(spectator.service['_config']).toEqual(config);
|
||||
});
|
||||
});
|
||||
|
||||
describe('get()', () => {
|
||||
it('should return config value', () => {
|
||||
spectator.service['_config'] = { test: 'test' };
|
||||
expect(spectator.service.get('test')).toEqual('test');
|
||||
});
|
||||
});
|
||||
});
|
||||
27
apps/core/config/src/lib/config.ts
Normal file
27
apps/core/config/src/lib/config.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { Inject, Injectable } from '@angular/core';
|
||||
import { ReplaySubject } from 'rxjs';
|
||||
import { ConfigLoader } from './config-loaders';
|
||||
import { CORE_CONFIG_LOADER } from './tokens';
|
||||
import { pick } from './utils';
|
||||
|
||||
@Injectable()
|
||||
export class Config {
|
||||
private _config: any;
|
||||
|
||||
private readonly _initilized = new ReplaySubject<void>(1);
|
||||
get initialized() {
|
||||
return this._initilized.asObservable();
|
||||
}
|
||||
|
||||
constructor(@Inject(CORE_CONFIG_LOADER) private readonly _configLoader: ConfigLoader) {}
|
||||
|
||||
// load config and assign it to this._config
|
||||
async init() {
|
||||
this._config = await this._configLoader.load();
|
||||
this._initilized.next();
|
||||
}
|
||||
|
||||
get(path: string) {
|
||||
return pick(path, this._config);
|
||||
}
|
||||
}
|
||||
8
apps/core/config/src/lib/index.ts
Normal file
8
apps/core/config/src/lib/index.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
// start:ng42.barrel
|
||||
export * from './config-module-options';
|
||||
export * from './config.module';
|
||||
export * from './config';
|
||||
export * from './tokens';
|
||||
export * from './config-loaders';
|
||||
export * from './utils';
|
||||
// end:ng42.barrel
|
||||
6
apps/core/config/src/lib/tokens.ts
Normal file
6
apps/core/config/src/lib/tokens.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { InjectionToken } from '@angular/core';
|
||||
import { ConfigLoader } from './config-loaders';
|
||||
|
||||
export const CORE_CONFIG_LOADER = new InjectionToken<ConfigLoader>('core.config.loader');
|
||||
|
||||
export const CORE_JSON_CONFIG_LOADER_URL = new InjectionToken<ConfigLoader>('core.json.config.loader.url');
|
||||
3
apps/core/config/src/lib/utils/index.ts
Normal file
3
apps/core/config/src/lib/utils/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
// start:ng42.barrel
|
||||
export * from './pick';
|
||||
// end:ng42.barrel
|
||||
41
apps/core/config/src/lib/utils/pick.spec.ts
Normal file
41
apps/core/config/src/lib/utils/pick.spec.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import { pick } from './pick';
|
||||
|
||||
describe('pick', () => {
|
||||
it('should pick properties from the 1st level from the object', () => {
|
||||
const obj = {
|
||||
foo: 'bar',
|
||||
};
|
||||
expect(pick('foo', obj)).toEqual('bar');
|
||||
});
|
||||
|
||||
it('should pick properties from the 2nd level from the object', () => {
|
||||
const obj = {
|
||||
foo: {
|
||||
bar: 'baz',
|
||||
},
|
||||
};
|
||||
expect(pick('foo.bar', obj)).toEqual('baz');
|
||||
});
|
||||
|
||||
it('should pick properties from the 3rd level from the object', () => {
|
||||
const obj = {
|
||||
foo: {
|
||||
bar: {
|
||||
baz: 'qux',
|
||||
},
|
||||
},
|
||||
};
|
||||
expect(pick('foo.bar.baz', obj)).toEqual('qux');
|
||||
});
|
||||
|
||||
it('should throw an error of obj is not an object', () => {
|
||||
expect(() => pick('foo', 'bar')).toThrowError(`bar is not an object`);
|
||||
});
|
||||
|
||||
it('should return undefined if the property is not found', () => {
|
||||
const obj = {
|
||||
foo: 'bar',
|
||||
};
|
||||
expect(pick('bar', obj)).toEqual(undefined);
|
||||
});
|
||||
});
|
||||
33
apps/core/config/src/lib/utils/pick.ts
Normal file
33
apps/core/config/src/lib/utils/pick.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Pick a value from an object at a given path.
|
||||
* @param path path of the value to pick
|
||||
* @param obj object to pick from
|
||||
* @returns the value at the path or undefined
|
||||
* @throws if obj is not an object
|
||||
*/
|
||||
export function pick<T = any>(path: string, obj: Object): T {
|
||||
const paths = path.split('.');
|
||||
|
||||
// check if obj is null or undefined
|
||||
if (obj == null) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// check if obj is of type object and not an array
|
||||
// and throw an error if not
|
||||
if (typeof obj !== 'object' || Array.isArray(obj)) {
|
||||
throw new Error(`${obj} is not an object`);
|
||||
}
|
||||
|
||||
let result = obj;
|
||||
|
||||
// loop through the path and pick the value
|
||||
// early exit if the path is empty
|
||||
for (const path of paths) {
|
||||
result = result[path];
|
||||
if (result == null) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
return result as T;
|
||||
}
|
||||
5
apps/core/config/src/public-api.ts
Normal file
5
apps/core/config/src/public-api.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
/*
|
||||
* Public API Surface of config
|
||||
*/
|
||||
|
||||
export * from './lib';
|
||||
25
apps/core/config/src/test.ts
Normal file
25
apps/core/config/src/test.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
||||
|
||||
import 'zone.js';
|
||||
import 'zone.js/testing';
|
||||
import { getTestBed } from '@angular/core/testing';
|
||||
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
declare const require: {
|
||||
context(
|
||||
path: string,
|
||||
deep?: boolean,
|
||||
filter?: RegExp
|
||||
): {
|
||||
keys(): string[];
|
||||
<T>(id: string): T;
|
||||
};
|
||||
};
|
||||
|
||||
// First, initialize the Angular testing environment.
|
||||
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting(), { teardown: { destroyAfterEach: true } });
|
||||
|
||||
// Then we find all the tests.
|
||||
const context = require.context('./', true, /\.spec\.ts$/);
|
||||
// And load the modules.
|
||||
context.keys().map(context);
|
||||
20
apps/core/config/tsconfig.lib.json
Normal file
20
apps/core/config/tsconfig.lib.json
Normal file
@@ -0,0 +1,20 @@
|
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../../out-tsc/lib",
|
||||
"target": "es2015",
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"inlineSources": true,
|
||||
"types": [],
|
||||
"lib": [
|
||||
"dom",
|
||||
"es2018"
|
||||
]
|
||||
},
|
||||
"exclude": [
|
||||
"src/test.ts",
|
||||
"**/*.spec.ts"
|
||||
]
|
||||
}
|
||||
10
apps/core/config/tsconfig.lib.prod.json
Normal file
10
apps/core/config/tsconfig.lib.prod.json
Normal file
@@ -0,0 +1,10 @@
|
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||
{
|
||||
"extends": "./tsconfig.lib.json",
|
||||
"compilerOptions": {
|
||||
"declarationMap": false
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"compilationMode": "partial"
|
||||
}
|
||||
}
|
||||
17
apps/core/config/tsconfig.spec.json
Normal file
17
apps/core/config/tsconfig.spec.json
Normal file
@@ -0,0 +1,17 @@
|
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../../out-tsc/spec",
|
||||
"types": [
|
||||
"jasmine"
|
||||
]
|
||||
},
|
||||
"files": [
|
||||
"src/test.ts"
|
||||
],
|
||||
"include": [
|
||||
"**/*.spec.ts",
|
||||
"**/*.d.ts"
|
||||
]
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
||||
|
||||
import 'zone.js/dist/zone';
|
||||
import 'zone.js/dist/zone-testing';
|
||||
import 'zone.js';
|
||||
import 'zone.js/testing';
|
||||
import { getTestBed } from '@angular/core/testing';
|
||||
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
|
||||
25
apps/core/logger/README.md
Normal file
25
apps/core/logger/README.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# Logger
|
||||
|
||||
This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 12.2.0.
|
||||
|
||||
## Code scaffolding
|
||||
|
||||
Run `ng generate component component-name --project logger` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project logger`.
|
||||
|
||||
> Note: Don't forget to add `--project logger` or else it will be added to the default project in your `angular.json` file.
|
||||
|
||||
## Build
|
||||
|
||||
Run `ng build logger` to build the project. The build artifacts will be stored in the `dist/` directory.
|
||||
|
||||
## Publishing
|
||||
|
||||
After building your library with `ng build logger`, go to the dist folder `cd dist/logger` and run `npm publish`.
|
||||
|
||||
## Running unit tests
|
||||
|
||||
Run `ng test logger` to execute the unit tests via [Karma](https://karma-runner.github.io).
|
||||
|
||||
## Further help
|
||||
|
||||
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.
|
||||
43
apps/core/logger/karma.conf.js
Normal file
43
apps/core/logger/karma.conf.js
Normal file
@@ -0,0 +1,43 @@
|
||||
// Karma configuration file, see link for more information
|
||||
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||
const customLaunchers = require('../../../karma/custom-launchers');
|
||||
const junitReporter = require('../../../karma/junit-reporter')('core-logger');
|
||||
const coverageReporter = require('../../../karma/coverage-reporter')('core-logger');
|
||||
|
||||
module.exports = function (config) {
|
||||
config.set({
|
||||
basePath: '',
|
||||
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
||||
plugins: [
|
||||
require('karma-jasmine'),
|
||||
require('karma-chrome-launcher'),
|
||||
require('karma-jasmine-html-reporter'),
|
||||
require('karma-coverage'),
|
||||
require('karma-junit-reporter'),
|
||||
require('@angular-devkit/build-angular/plugins/karma'),
|
||||
],
|
||||
client: {
|
||||
jasmine: {
|
||||
// you can add configuration options for Jasmine here
|
||||
// the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
|
||||
// for example, you can disable the random execution with `random: false`
|
||||
// or set a specific seed with `seed: 4321`
|
||||
},
|
||||
clearContext: false, // leave Jasmine Spec Runner output visible in browser
|
||||
},
|
||||
jasmineHtmlReporter: {
|
||||
suppressAll: true, // removes the duplicated traces
|
||||
},
|
||||
junitReporter,
|
||||
coverageReporter,
|
||||
reporters: ['progress', 'kjhtml'],
|
||||
port: 9876,
|
||||
colors: true,
|
||||
logLevel: config.LOG_INFO,
|
||||
autoWatch: true,
|
||||
browsers: ['Chrome'],
|
||||
customLaunchers,
|
||||
singleRun: false,
|
||||
restartOnFileChange: true,
|
||||
});
|
||||
};
|
||||
7
apps/core/logger/ng-package.json
Normal file
7
apps/core/logger/ng-package.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"$schema": "../../../node_modules/ng-packagr/ng-package.schema.json",
|
||||
"dest": "../../../dist/core/logger",
|
||||
"lib": {
|
||||
"entryFile": "src/public-api.ts"
|
||||
}
|
||||
}
|
||||
11
apps/core/logger/package.json
Normal file
11
apps/core/logger/package.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "@core/logger",
|
||||
"version": "0.0.1",
|
||||
"peerDependencies": {
|
||||
"@angular/common": "^12.2.0",
|
||||
"@angular/core": "^12.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": "^2.3.0"
|
||||
}
|
||||
}
|
||||
51
apps/core/logger/src/lib/console-log.provider.spec.ts
Normal file
51
apps/core/logger/src/lib/console-log.provider.spec.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import { createServiceFactory, SpectatorService } from '@ngneat/spectator';
|
||||
import { ConsoleLogProvider } from './console-log.provider';
|
||||
import { LogLevel } from './log-level';
|
||||
|
||||
describe('ConsoleLogProvider', () => {
|
||||
let spectator: SpectatorService<ConsoleLogProvider>;
|
||||
|
||||
const createService = createServiceFactory({
|
||||
service: ConsoleLogProvider,
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
spectator = createService();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(spectator.service).toBeTruthy();
|
||||
});
|
||||
|
||||
describe('log', () => {
|
||||
it('should call console.debug', () => {
|
||||
spyOn(console, 'debug');
|
||||
spectator.service.log(LogLevel.DEBUG, 'test');
|
||||
expect(console.debug).toHaveBeenCalledWith('test');
|
||||
});
|
||||
|
||||
it('should call console.info', () => {
|
||||
spyOn(console, 'info');
|
||||
spectator.service.log(LogLevel.INFO, 'test');
|
||||
expect(console.info).toHaveBeenCalledWith('test');
|
||||
});
|
||||
|
||||
it('should call console.warn', () => {
|
||||
spyOn(console, 'warn');
|
||||
spectator.service.log(LogLevel.WARN, 'test');
|
||||
expect(console.warn).toHaveBeenCalledWith('test');
|
||||
});
|
||||
|
||||
it('should call console.error', () => {
|
||||
spyOn(console, 'error');
|
||||
spectator.service.log(LogLevel.ERROR, 'test');
|
||||
expect(console.error).toHaveBeenCalledWith('test');
|
||||
});
|
||||
|
||||
it('should not call console.log', () => {
|
||||
spyOn(console, 'log');
|
||||
spectator.service.log(LogLevel.OFF, 'test');
|
||||
expect(console.log).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
25
apps/core/logger/src/lib/console-log.provider.ts
Normal file
25
apps/core/logger/src/lib/console-log.provider.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { LogLevel } from './log-level';
|
||||
import { LogProvider } from './log.provider';
|
||||
|
||||
@Injectable()
|
||||
export class ConsoleLogProvider implements LogProvider {
|
||||
log(logLevel: LogLevel, message: string, ...optionalParams: any[]): void {
|
||||
switch (logLevel) {
|
||||
case LogLevel.DEBUG:
|
||||
console.debug(message, ...optionalParams);
|
||||
break;
|
||||
case LogLevel.INFO:
|
||||
console.info(message, ...optionalParams);
|
||||
break;
|
||||
case LogLevel.WARN:
|
||||
console.warn(message, ...optionalParams);
|
||||
break;
|
||||
case LogLevel.ERROR:
|
||||
console.error(message, ...optionalParams);
|
||||
break;
|
||||
case LogLevel.OFF:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
8
apps/core/logger/src/lib/index.ts
Normal file
8
apps/core/logger/src/lib/index.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
// start:ng42.barrel
|
||||
export * from './console-log.provider';
|
||||
export * from './log-level';
|
||||
export * from './log.provider';
|
||||
export * from './logger.module';
|
||||
export * from './logger.service';
|
||||
export * from './tokens';
|
||||
// end:ng42.barrel
|
||||
14
apps/core/logger/src/lib/log-level.ts
Normal file
14
apps/core/logger/src/lib/log-level.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
export enum LogLevel {
|
||||
DEBUG = 0,
|
||||
INFO = 1,
|
||||
WARN = 2,
|
||||
ERROR = 3,
|
||||
OFF = 4,
|
||||
|
||||
// aliases
|
||||
debug = 0,
|
||||
info = 1,
|
||||
warn = 2,
|
||||
error = 3,
|
||||
off = 4,
|
||||
}
|
||||
6
apps/core/logger/src/lib/log.provider.ts
Normal file
6
apps/core/logger/src/lib/log.provider.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { LogLevel } from './log-level';
|
||||
|
||||
export interface LogProvider {
|
||||
log(logLevel: LogLevel, message: string, ...optionalParams: any[]): void;
|
||||
}
|
||||
31
apps/core/logger/src/lib/logger.module.ts
Normal file
31
apps/core/logger/src/lib/logger.module.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { ModuleWithProviders, NgModule } from '@angular/core';
|
||||
import { Config } from '@core/config';
|
||||
import { ConsoleLogProvider } from './console-log.provider';
|
||||
import { Logger } from './logger.service';
|
||||
import { LOG_PROVIDER, LOG_LEVEL } from './tokens';
|
||||
|
||||
export function _logLevelProviderFactory(config: Config) {
|
||||
return config.get('@core/logger.logLevel');
|
||||
}
|
||||
|
||||
@NgModule({})
|
||||
export class CoreLoggerModule {
|
||||
static forRoot(): ModuleWithProviders<CoreLoggerModule> {
|
||||
return {
|
||||
ngModule: CoreLoggerModule,
|
||||
providers: [
|
||||
Logger,
|
||||
{
|
||||
provide: LOG_PROVIDER,
|
||||
useClass: ConsoleLogProvider,
|
||||
multi: true,
|
||||
},
|
||||
{
|
||||
provide: LOG_LEVEL,
|
||||
useFactory: _logLevelProviderFactory,
|
||||
deps: [Config],
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
}
|
||||
140
apps/core/logger/src/lib/logger.service.spec.ts
Normal file
140
apps/core/logger/src/lib/logger.service.spec.ts
Normal file
@@ -0,0 +1,140 @@
|
||||
import { SpectatorService, createServiceFactory } from '@ngneat/spectator';
|
||||
import { LogLevel } from './log-level';
|
||||
import { Logger } from './logger.service';
|
||||
import { LOG_PROVIDER } from './tokens';
|
||||
import { LOG_LEVEL } from '.';
|
||||
|
||||
describe('LoggerService', () => {
|
||||
let spectator: SpectatorService<Logger>;
|
||||
let logProviderMock1 = jasmine.createSpyObj('LogProvider', ['log']);
|
||||
let logProviderMock2 = jasmine.createSpyObj('LogProvider', ['log']);
|
||||
|
||||
const createService = createServiceFactory({
|
||||
service: Logger,
|
||||
mocks: [Logger],
|
||||
providers: [
|
||||
{
|
||||
provide: LOG_PROVIDER,
|
||||
useValue: logProviderMock1,
|
||||
multi: true,
|
||||
},
|
||||
{
|
||||
provide: LOG_PROVIDER,
|
||||
useValue: logProviderMock2,
|
||||
multi: true,
|
||||
},
|
||||
{
|
||||
provide: LOG_LEVEL,
|
||||
useValue: LogLevel.DEBUG,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
spectator = createService();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(spectator.service).toBeTruthy();
|
||||
});
|
||||
|
||||
const testData: {
|
||||
serviceLogLevel: LogLevel;
|
||||
callLogLevel: LogLevel;
|
||||
shoudCall: boolean;
|
||||
}[] = [
|
||||
{ serviceLogLevel: LogLevel.DEBUG, callLogLevel: LogLevel.DEBUG, shoudCall: true },
|
||||
{ serviceLogLevel: LogLevel.DEBUG, callLogLevel: LogLevel.INFO, shoudCall: true },
|
||||
{ serviceLogLevel: LogLevel.DEBUG, callLogLevel: LogLevel.WARN, shoudCall: true },
|
||||
{ serviceLogLevel: LogLevel.DEBUG, callLogLevel: LogLevel.ERROR, shoudCall: true },
|
||||
|
||||
{ serviceLogLevel: LogLevel.INFO, callLogLevel: LogLevel.DEBUG, shoudCall: false },
|
||||
{ serviceLogLevel: LogLevel.INFO, callLogLevel: LogLevel.INFO, shoudCall: true },
|
||||
{ serviceLogLevel: LogLevel.INFO, callLogLevel: LogLevel.WARN, shoudCall: true },
|
||||
{ serviceLogLevel: LogLevel.INFO, callLogLevel: LogLevel.ERROR, shoudCall: true },
|
||||
|
||||
{ serviceLogLevel: LogLevel.WARN, callLogLevel: LogLevel.DEBUG, shoudCall: false },
|
||||
{ serviceLogLevel: LogLevel.WARN, callLogLevel: LogLevel.INFO, shoudCall: false },
|
||||
{ serviceLogLevel: LogLevel.WARN, callLogLevel: LogLevel.WARN, shoudCall: true },
|
||||
{ serviceLogLevel: LogLevel.WARN, callLogLevel: LogLevel.ERROR, shoudCall: true },
|
||||
|
||||
{ serviceLogLevel: LogLevel.ERROR, callLogLevel: LogLevel.DEBUG, shoudCall: false },
|
||||
{ serviceLogLevel: LogLevel.ERROR, callLogLevel: LogLevel.INFO, shoudCall: false },
|
||||
{ serviceLogLevel: LogLevel.ERROR, callLogLevel: LogLevel.WARN, shoudCall: false },
|
||||
{ serviceLogLevel: LogLevel.ERROR, callLogLevel: LogLevel.ERROR, shoudCall: true },
|
||||
|
||||
{ serviceLogLevel: LogLevel.OFF, callLogLevel: LogLevel.DEBUG, shoudCall: false },
|
||||
{ serviceLogLevel: LogLevel.OFF, callLogLevel: LogLevel.INFO, shoudCall: false },
|
||||
{ serviceLogLevel: LogLevel.OFF, callLogLevel: LogLevel.WARN, shoudCall: false },
|
||||
{ serviceLogLevel: LogLevel.OFF, callLogLevel: LogLevel.ERROR, shoudCall: false },
|
||||
];
|
||||
|
||||
describe('log()', () => {
|
||||
beforeEach(() => {
|
||||
logProviderMock1.log.calls.reset();
|
||||
logProviderMock2.log.calls.reset();
|
||||
});
|
||||
|
||||
for (const test of testData) {
|
||||
if (test.shoudCall) {
|
||||
it(`should call logProvider if logLevel is ${LogLevel[test.callLogLevel]} and serviceLogLevel is ${
|
||||
LogLevel[test.serviceLogLevel]
|
||||
}`, () => {
|
||||
spectator.service['_logLevel'] = test.serviceLogLevel;
|
||||
spectator.service.log(test.callLogLevel, 'test');
|
||||
expect(logProviderMock1.log).toHaveBeenCalledTimes(1);
|
||||
expect(logProviderMock2.log).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
} else {
|
||||
it(`should not call logProvider if logLevel is ${LogLevel[test.callLogLevel]} and serviceLogLevel is ${
|
||||
LogLevel[test.serviceLogLevel]
|
||||
}`, () => {
|
||||
spectator.service['_logLevel'] = test.serviceLogLevel;
|
||||
spectator.service.log(test.callLogLevel, 'test');
|
||||
expect(logProviderMock1.log).not.toHaveBeenCalled();
|
||||
expect(logProviderMock2.log).not.toHaveBeenCalled();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
describe('warn()', () => {
|
||||
it('should call log and logLevel should be WARN', () => {
|
||||
spyOn(spectator.service, 'log');
|
||||
|
||||
spectator.service.warn('test', 'data');
|
||||
|
||||
expect(spectator.service.log).toHaveBeenCalledWith(LogLevel.WARN, 'test', 'data');
|
||||
});
|
||||
});
|
||||
|
||||
describe('info()', () => {
|
||||
it('should call log and logLevel should be INFO', () => {
|
||||
spyOn(spectator.service, 'log');
|
||||
|
||||
spectator.service.info('test', 'data');
|
||||
|
||||
expect(spectator.service.log).toHaveBeenCalledWith(LogLevel.INFO, 'test', 'data');
|
||||
});
|
||||
});
|
||||
|
||||
describe('debug()', () => {
|
||||
it('should call log and logLevel should be DEBUG', () => {
|
||||
spyOn(spectator.service, 'log');
|
||||
|
||||
spectator.service.debug('test', 'data');
|
||||
|
||||
expect(spectator.service.log).toHaveBeenCalledWith(LogLevel.DEBUG, 'test', 'data');
|
||||
});
|
||||
});
|
||||
|
||||
describe('error()', () => {
|
||||
it('should call log and logLevel should be ERROR', () => {
|
||||
spyOn(spectator.service, 'log');
|
||||
|
||||
spectator.service.error('test', 'data');
|
||||
|
||||
expect(spectator.service.log).toHaveBeenCalledWith(LogLevel.ERROR, 'test', 'data');
|
||||
});
|
||||
});
|
||||
});
|
||||
39
apps/core/logger/src/lib/logger.service.ts
Normal file
39
apps/core/logger/src/lib/logger.service.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import { Inject, Injectable } from '@angular/core';
|
||||
|
||||
import { LogLevel } from './log-level';
|
||||
import { LogProvider } from './log.provider';
|
||||
import { LOG_LEVEL, LOG_PROVIDER } from './tokens';
|
||||
|
||||
@Injectable()
|
||||
export class Logger {
|
||||
constructor(@Inject(LOG_PROVIDER) private readonly _loggerProviders: LogProvider[], @Inject(LOG_LEVEL) private _logLevel: LogLevel) {}
|
||||
|
||||
log(logLevel: LogLevel, message: string, ...optionalParams: any[]): void {
|
||||
if (this._logLevel === LogLevel.OFF) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._logLevel <= logLevel) {
|
||||
console.log(this._logLevel, logLevel, this._logLevel <= logLevel);
|
||||
this._loggerProviders.forEach((provider) => {
|
||||
provider.log(logLevel, message, ...optionalParams);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
warn(message: string, ...optionalParams: any[]): void {
|
||||
this.log(LogLevel.WARN, message, ...optionalParams);
|
||||
}
|
||||
|
||||
info(message: string, ...optionalParams: any[]): void {
|
||||
this.log(LogLevel.INFO, message, ...optionalParams);
|
||||
}
|
||||
|
||||
debug(message: string, ...optionalParams: any[]): void {
|
||||
this.log(LogLevel.DEBUG, message, ...optionalParams);
|
||||
}
|
||||
|
||||
error(message: string, ...optionalParams: any[]): void {
|
||||
this.log(LogLevel.ERROR, message, ...optionalParams);
|
||||
}
|
||||
}
|
||||
6
apps/core/logger/src/lib/tokens.ts
Normal file
6
apps/core/logger/src/lib/tokens.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { LogProvider } from './log.provider';
|
||||
import { InjectionToken } from '@angular/core';
|
||||
import { LogLevel } from './log-level';
|
||||
|
||||
export const LOG_PROVIDER = new InjectionToken<LogProvider[]>('LOG_PROVIDER');
|
||||
export const LOG_LEVEL = new InjectionToken<LogLevel>('LOG_LEVEL');
|
||||
5
apps/core/logger/src/public-api.ts
Normal file
5
apps/core/logger/src/public-api.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
/*
|
||||
* Public API Surface of logger
|
||||
*/
|
||||
|
||||
export * from './lib';
|
||||
25
apps/core/logger/src/test.ts
Normal file
25
apps/core/logger/src/test.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
||||
|
||||
import 'zone.js';
|
||||
import 'zone.js/testing';
|
||||
import { getTestBed } from '@angular/core/testing';
|
||||
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
declare const require: {
|
||||
context(
|
||||
path: string,
|
||||
deep?: boolean,
|
||||
filter?: RegExp
|
||||
): {
|
||||
keys(): string[];
|
||||
<T>(id: string): T;
|
||||
};
|
||||
};
|
||||
|
||||
// First, initialize the Angular testing environment.
|
||||
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting(), { teardown: { destroyAfterEach: true } });
|
||||
|
||||
// Then we find all the tests.
|
||||
const context = require.context('./', true, /\.spec\.ts$/);
|
||||
// And load the modules.
|
||||
context.keys().map(context);
|
||||
20
apps/core/logger/tsconfig.lib.json
Normal file
20
apps/core/logger/tsconfig.lib.json
Normal file
@@ -0,0 +1,20 @@
|
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../../out-tsc/lib",
|
||||
"target": "es2015",
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"inlineSources": true,
|
||||
"types": [],
|
||||
"lib": [
|
||||
"dom",
|
||||
"es2018"
|
||||
]
|
||||
},
|
||||
"exclude": [
|
||||
"src/test.ts",
|
||||
"**/*.spec.ts"
|
||||
]
|
||||
}
|
||||
10
apps/core/logger/tsconfig.lib.prod.json
Normal file
10
apps/core/logger/tsconfig.lib.prod.json
Normal file
@@ -0,0 +1,10 @@
|
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||
{
|
||||
"extends": "./tsconfig.lib.json",
|
||||
"compilerOptions": {
|
||||
"declarationMap": false
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"compilationMode": "partial"
|
||||
}
|
||||
}
|
||||
17
apps/core/logger/tsconfig.spec.json
Normal file
17
apps/core/logger/tsconfig.spec.json
Normal file
@@ -0,0 +1,17 @@
|
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../../out-tsc/spec",
|
||||
"types": [
|
||||
"jasmine"
|
||||
]
|
||||
},
|
||||
"files": [
|
||||
"src/test.ts"
|
||||
],
|
||||
"include": [
|
||||
"**/*.spec.ts",
|
||||
"**/*.d.ts"
|
||||
]
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
||||
|
||||
import 'zone.js/dist/zone';
|
||||
import 'zone.js/dist/zone-testing';
|
||||
import 'zone.js';
|
||||
import 'zone.js/testing';
|
||||
import { getTestBed } from '@angular/core/testing';
|
||||
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ItemDTO } from '@swagger/cat';
|
||||
import { ItemDTO, SearchService } from '@swagger/cat';
|
||||
import { AvailabilityDTO, BranchDTO, OLAAvailabilityDTO, StoreCheckoutService, SupplierDTO } from '@swagger/checkout';
|
||||
import { Observable } from 'rxjs';
|
||||
import { AvailabilityService as SwaggerAvailabilityService } from '@swagger/availability';
|
||||
import { combineLatest, Observable, of } from 'rxjs';
|
||||
import {
|
||||
AvailabilityRequestDTO,
|
||||
AvailabilityService as SwaggerAvailabilityService,
|
||||
AvailabilityDTO as SwaggerAvailabilityDTO,
|
||||
AvailabilityType,
|
||||
} from '@swagger/availability';
|
||||
import { AvailabilityDTO as CatAvailabilityDTO } from '@swagger/cat';
|
||||
import { map, shareReplay, switchMap, withLatestFrom, mergeMap, timeout } from 'rxjs/operators';
|
||||
import { isArray, memorize } from '@utils/common';
|
||||
import { OrderService } from '@swagger/oms';
|
||||
@@ -55,7 +61,31 @@ export class DomainAvailabilityService {
|
||||
@memorize()
|
||||
getCurrentBranch(): Observable<BranchDTO> {
|
||||
return this._stock.StockCurrentBranch().pipe(
|
||||
map((response) => response.result),
|
||||
map((response) => ({
|
||||
id: response.result.id,
|
||||
name: response.result.name,
|
||||
address: response.result.address,
|
||||
branchType: response.result.branchType,
|
||||
branchNumber: response.result.branchNumber,
|
||||
changed: response.result.changed,
|
||||
created: response.result.created,
|
||||
isDefault: response.result.isDefault,
|
||||
isOnline: response.result.isOnline,
|
||||
key: response.result.key,
|
||||
label: response.result.label,
|
||||
pId: response.result.pId,
|
||||
shortName: response.result.shortName,
|
||||
status: response.result.status,
|
||||
version: response.result.version,
|
||||
})),
|
||||
shareReplay()
|
||||
);
|
||||
}
|
||||
|
||||
@memorize({})
|
||||
getLogisticians() {
|
||||
return this.orderService.OrderGetLogisticians({}).pipe(
|
||||
map((response) => response.result?.find((l) => l.logisticianNumber === '2470')),
|
||||
shareReplay()
|
||||
);
|
||||
}
|
||||
@@ -117,8 +147,10 @@ export class DomainAvailabilityService {
|
||||
price: PriceDTO;
|
||||
quantity: number;
|
||||
}): Observable<AvailabilityDTO> {
|
||||
return this._stock.StockStockRequest({ stockRequest: { branchIds: [branch.id], itemId } }).pipe(
|
||||
withLatestFrom(this.getTakeAwaySupplier()),
|
||||
return combineLatest([
|
||||
this._stock.StockStockRequest({ stockRequest: { branchIds: [branch.id], itemId } }),
|
||||
this.getTakeAwaySupplier(),
|
||||
]).pipe(
|
||||
map(([response, supplier]) => {
|
||||
return this._mapToTakeAwayAvailability({ response, supplier, branch, quantity, price });
|
||||
}),
|
||||
@@ -168,29 +200,7 @@ export class DomainAvailabilityService {
|
||||
},
|
||||
])
|
||||
.pipe(
|
||||
map((r) => {
|
||||
const availabilities = r.result;
|
||||
|
||||
if (isArray(availabilities)) {
|
||||
const preferred = availabilities.find((f) => f.preferred === 1);
|
||||
const totalAvailable = availabilities.reduce((sum, av) => sum + (av?.qty || 0), 0);
|
||||
|
||||
const availability: AvailabilityDTO = {
|
||||
availabilityType: preferred?.status,
|
||||
ssc: preferred?.ssc,
|
||||
sscText: preferred?.sscText,
|
||||
supplier: { id: preferred?.supplierId },
|
||||
isPrebooked: preferred?.isPrebooked,
|
||||
estimatedShippingDate: preferred?.at,
|
||||
price: preferred?.price,
|
||||
inStock: totalAvailable,
|
||||
supplierProductNumber: preferred?.supplierProductNumber,
|
||||
supplierInfo: preferred?.requestStatusCode,
|
||||
lastRequest: preferred?.requested,
|
||||
};
|
||||
return availability;
|
||||
}
|
||||
}),
|
||||
map((r) => this._mapToPickUpAvailability(r.result)?.find((_) => true)),
|
||||
shareReplay()
|
||||
);
|
||||
}
|
||||
@@ -208,23 +218,7 @@ export class DomainAvailabilityService {
|
||||
])
|
||||
.pipe(
|
||||
timeout(5000),
|
||||
map((r) => {
|
||||
const availabilities = r.result;
|
||||
const preferred = availabilities.find((f) => f.preferred === 1);
|
||||
|
||||
const availability: AvailabilityDTO = {
|
||||
availabilityType: preferred?.status,
|
||||
ssc: preferred?.ssc,
|
||||
sscText: preferred?.sscText,
|
||||
isPrebooked: preferred?.isPrebooked,
|
||||
estimatedShippingDate: preferred?.at,
|
||||
price: preferred?.price,
|
||||
supplierProductNumber: preferred?.supplierProductNumber,
|
||||
supplierInfo: preferred?.requestStatusCode,
|
||||
lastRequest: preferred?.requested,
|
||||
};
|
||||
return availability;
|
||||
}),
|
||||
map((r) => this._mapToShippingAvailability(r.result)?.find((_) => true)),
|
||||
shareReplay()
|
||||
);
|
||||
}
|
||||
@@ -244,7 +238,7 @@ export class DomainAvailabilityService {
|
||||
timeout(5000),
|
||||
map((r) => {
|
||||
const availabilities = r.result;
|
||||
const preferred = availabilities.find((f) => f.preferred === 1);
|
||||
const preferred = availabilities?.find((f) => f.preferred === 1);
|
||||
|
||||
const availability: AvailabilityDTO = {
|
||||
availabilityType: preferred?.status,
|
||||
@@ -252,7 +246,8 @@ export class DomainAvailabilityService {
|
||||
sscText: preferred?.sscText,
|
||||
supplier: { id: preferred?.supplierId },
|
||||
isPrebooked: preferred?.isPrebooked,
|
||||
estimatedShippingDate: preferred?.at,
|
||||
estimatedShippingDate: preferred?.requestStatusCode === '32' ? preferred?.altAt : preferred?.at,
|
||||
estimatedDelivery: preferred?.estimatedDelivery,
|
||||
price: preferred?.price,
|
||||
logistician: { id: preferred?.logisticianId },
|
||||
supplierProductNumber: preferred?.supplierProductNumber,
|
||||
@@ -267,9 +262,7 @@ export class DomainAvailabilityService {
|
||||
|
||||
@memorize({ ttl: 10000 })
|
||||
getB2bDeliveryAvailability({ item, quantity }: { item: ItemData; quantity: number }): Observable<AvailabilityDTO> {
|
||||
const logistician$ = this.orderService
|
||||
.OrderGetLogisticians({})
|
||||
.pipe(map((response) => response.result.find((l) => l.logisticianNumber === '2470')));
|
||||
const logistician$ = this.getLogisticians();
|
||||
|
||||
const currentBranch$ = this.getCurrentBranch();
|
||||
|
||||
@@ -298,7 +291,7 @@ export class DomainAvailabilityService {
|
||||
.pipe(
|
||||
map((r) => {
|
||||
const availabilities = r.result;
|
||||
const preferred = availabilities.find((f) => f.preferred === 1);
|
||||
const preferred = availabilities?.find((f) => f.preferred === 1);
|
||||
|
||||
const availability: AvailabilityDTO = {
|
||||
availabilityType: preferred?.status,
|
||||
@@ -306,7 +299,7 @@ export class DomainAvailabilityService {
|
||||
sscText: preferred?.sscText,
|
||||
supplier: { id: preferred?.supplierId },
|
||||
isPrebooked: preferred?.isPrebooked,
|
||||
estimatedShippingDate: preferred?.at,
|
||||
estimatedShippingDate: preferred?.requestStatusCode === '32' ? preferred?.altAt : preferred?.at,
|
||||
price: preferred?.price,
|
||||
supplierProductNumber: preferred?.supplierProductNumber,
|
||||
logistician: { id: preferred?.logisticianId },
|
||||
@@ -320,18 +313,83 @@ export class DomainAvailabilityService {
|
||||
}
|
||||
|
||||
@memorize({ ttl: 10000 })
|
||||
getStoreAvailabilities({ item, branch, quantity }: { item: ItemData; quantity: number; branch: BranchDTO }) {
|
||||
return this.swaggerAvailabilityService
|
||||
.AvailabilityStoreAvailability([
|
||||
{
|
||||
qty: quantity,
|
||||
ean: item?.ean,
|
||||
itemId: item?.itemId ? String(item?.itemId) : null,
|
||||
shopId: branch?.id,
|
||||
price: item?.price,
|
||||
},
|
||||
])
|
||||
.pipe(map((response) => response.result));
|
||||
getTakeAwayAvailabilities(items: { id: number; price: PriceDTO }[], branchId: number) {
|
||||
return this._stock.StockGetStocksByBranch({ branchId }).pipe(
|
||||
map((req) => req.result?.find((_) => true)?.id),
|
||||
switchMap((stockId) =>
|
||||
stockId
|
||||
? this._stock.StockInStock({ articleIds: items.map((i) => i.id), stockId })
|
||||
: of({ result: [] } as ResponseArgsOfIEnumerableOfStockInfoDTO)
|
||||
),
|
||||
timeout(20000),
|
||||
withLatestFrom(this.getTakeAwaySupplier()),
|
||||
map(([response, supplier]) => {
|
||||
return response.result?.map((stockInfo) =>
|
||||
this._mapToTakeAwayAvailabilities({
|
||||
stockInfo,
|
||||
supplier,
|
||||
quantity: 1,
|
||||
price: items?.find((i) => i.id === stockInfo.itemId)?.price,
|
||||
})
|
||||
);
|
||||
}),
|
||||
shareReplay()
|
||||
);
|
||||
}
|
||||
|
||||
@memorize({ ttl: 10000 })
|
||||
getPickUpAvailabilities(payload: AvailabilityRequestDTO[], preferred?: boolean) {
|
||||
return this.swaggerAvailabilityService.AvailabilityStoreAvailability(payload).pipe(
|
||||
timeout(20000),
|
||||
map((response) => (preferred ? this._mapToPickUpAvailability(response.result) : response.result))
|
||||
);
|
||||
}
|
||||
|
||||
@memorize({ ttl: 10000 })
|
||||
getDeliveryAvailabilities(payload: AvailabilityRequestDTO[]) {
|
||||
return this.swaggerAvailabilityService.AvailabilityShippingAvailability(payload).pipe(
|
||||
timeout(20000),
|
||||
map((response) => this._mapToShippingAvailability(response.result))
|
||||
);
|
||||
}
|
||||
|
||||
@memorize({ ttl: 10000 })
|
||||
getDigDeliveryAvailabilities(payload: AvailabilityRequestDTO[]) {
|
||||
return this.swaggerAvailabilityService.AvailabilityShippingAvailability(payload).pipe(
|
||||
timeout(20000),
|
||||
map((response) => this._mapToShippingAvailability(response.result))
|
||||
);
|
||||
}
|
||||
|
||||
@memorize({ ttl: 10000 })
|
||||
getB2bDeliveryAvailabilities(payload: AvailabilityRequestDTO[]) {
|
||||
const logistician$ = this.getLogisticians();
|
||||
|
||||
return this.getPickUpAvailabilities(payload, true).pipe(
|
||||
timeout(20000),
|
||||
switchMap((availability) =>
|
||||
logistician$.pipe(map((logistician) => ({ availability: [...availability], logistician: { id: logistician.id } })))
|
||||
),
|
||||
shareReplay()
|
||||
);
|
||||
}
|
||||
|
||||
getPriceForAvailability(
|
||||
purchasingOption: string,
|
||||
catalogAvailability: CatAvailabilityDTO | AvailabilityDTO,
|
||||
availability: AvailabilityDTO
|
||||
): PriceDTO {
|
||||
switch (purchasingOption) {
|
||||
case 'take-away':
|
||||
return availability?.price || availability?.retailPrice;
|
||||
case 'delivery':
|
||||
case 'dig-delivery':
|
||||
if (catalogAvailability?.price?.value?.value < availability?.price?.value?.value) {
|
||||
return catalogAvailability?.price;
|
||||
}
|
||||
return availability?.price || catalogAvailability?.price;
|
||||
}
|
||||
return availability?.price;
|
||||
}
|
||||
|
||||
isAvailable({ availability }: { availability: AvailabilityDTO }) {
|
||||
@@ -377,7 +435,7 @@ export class DomainAvailabilityService {
|
||||
quantity: number;
|
||||
price: PriceDTO;
|
||||
}): AvailabilityDTO {
|
||||
const stockInfo = response.result.find((si) => si.branchId === branch.id);
|
||||
const stockInfo = response.result?.find((si) => si.branchId === branch.id);
|
||||
const inStock = stockInfo?.inStock ?? 0;
|
||||
const availability: AvailabilityDTO = {
|
||||
availabilityType: quantity <= inStock ? 1024 : 1, // 1024 (=Available)
|
||||
@@ -386,7 +444,77 @@ export class DomainAvailabilityService {
|
||||
supplierSSCText: quantity <= inStock ? 'Filialentnahme' : '',
|
||||
price,
|
||||
supplier: { id: supplier?.id },
|
||||
retailPrice: (stockInfo as any)?.retailPrice, // TODO: Change after API Update
|
||||
};
|
||||
return availability;
|
||||
}
|
||||
|
||||
private _mapToTakeAwayAvailabilities({
|
||||
stockInfo,
|
||||
quantity,
|
||||
price,
|
||||
supplier,
|
||||
}: {
|
||||
stockInfo: StockInfoDTO;
|
||||
quantity: number;
|
||||
price: PriceDTO;
|
||||
supplier: SupplierDTO;
|
||||
}) {
|
||||
const inStock = stockInfo?.inStock ?? 0;
|
||||
|
||||
const availability = {
|
||||
itemId: stockInfo.itemId,
|
||||
availabilityType: quantity <= inStock ? (1024 as AvailabilityType) : (1 as AvailabilityType), // 1024 (=Available)
|
||||
inStock: inStock,
|
||||
supplierSSC: quantity <= inStock ? '999' : '',
|
||||
supplierSSCText: quantity <= inStock ? 'Filialentnahme' : '',
|
||||
price,
|
||||
supplier: { id: supplier?.id },
|
||||
};
|
||||
return availability;
|
||||
}
|
||||
|
||||
private _mapToPickUpAvailability(availabilities: SwaggerAvailabilityDTO[]) {
|
||||
if (isArray(availabilities)) {
|
||||
const preferred = availabilities.filter((f) => f.preferred === 1);
|
||||
const totalAvailable = availabilities.reduce((sum, av) => sum + (av?.qty || 0), 0);
|
||||
|
||||
return preferred.map((p) => {
|
||||
return {
|
||||
availabilityType: p?.status,
|
||||
ssc: p?.ssc,
|
||||
sscText: p?.sscText,
|
||||
supplier: { id: p?.supplierId },
|
||||
isPrebooked: p?.isPrebooked,
|
||||
estimatedShippingDate: p?.requestStatusCode === '32' ? p?.altAt : p?.at,
|
||||
price: p?.price,
|
||||
inStock: totalAvailable,
|
||||
supplierProductNumber: p?.supplierProductNumber,
|
||||
supplierInfo: p?.requestStatusCode,
|
||||
lastRequest: p?.requested,
|
||||
itemId: p.itemId,
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private _mapToShippingAvailability(availabilities: SwaggerAvailabilityDTO[]) {
|
||||
const preferred = availabilities.filter((f) => f.preferred === 1);
|
||||
|
||||
return preferred.map((p) => {
|
||||
return {
|
||||
availabilityType: p?.status,
|
||||
ssc: p?.ssc,
|
||||
sscText: p?.sscText,
|
||||
isPrebooked: p?.isPrebooked,
|
||||
estimatedShippingDate: p?.requestStatusCode === '32' ? p?.altAt : p?.at,
|
||||
estimatedDelivery: p?.estimatedDelivery,
|
||||
price: p?.price,
|
||||
supplierProductNumber: p?.supplierProductNumber,
|
||||
supplierInfo: p?.requestStatusCode,
|
||||
lastRequest: p?.requested,
|
||||
itemId: p.itemId,
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
||||
|
||||
import 'zone.js/dist/zone';
|
||||
import 'zone.js/dist/zone-testing';
|
||||
import 'zone.js';
|
||||
import 'zone.js/testing';
|
||||
import { getTestBed } from '@angular/core/testing';
|
||||
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
||||
|
||||
import 'zone.js/dist/zone';
|
||||
import 'zone.js/dist/zone-testing';
|
||||
import 'zone.js';
|
||||
import 'zone.js/testing';
|
||||
import { getTestBed } from '@angular/core/testing';
|
||||
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user