Compare commits

...

31 Commits

Author SHA1 Message Date
Developer 02
27954cc0c4 chore(client): Client-App aktualisieren 2024-09-02 10:12:20 +02:00
Developer 02
3e0aeced71 Reapply "refactor(middleware): Entferne WebApiMiddleware"
This reverts commit 381f428f77.
2024-09-02 09:42:47 +02:00
Developer 02
43d0d86c79 Reapply "chore(config): NLog-Konfiguration aus WebApiConfig entfernt"
This reverts commit dddc01d24c.
2024-09-02 09:42:39 +02:00
Developer 02
dddc01d24c Revert "chore(config): NLog-Konfiguration aus WebApiConfig entfernt"
This reverts commit a55b4c5f63.
2024-09-02 09:36:59 +02:00
Developer 02
381f428f77 Revert "refactor(middleware): Entferne WebApiMiddleware"
This reverts commit bb61c6dca0.
2024-09-02 09:36:51 +02:00
Developer 02
bb61c6dca0 refactor(middleware): Entferne WebApiMiddleware 2024-09-02 09:15:58 +02:00
Developer 02
a55b4c5f63 chore(config): NLog-Konfiguration aus WebApiConfig entfernt 2024-09-02 09:12:32 +02:00
Developer 02
197db1e08b refactor: Entfernen des App Loggers und Implementierung des ILogger-Interfaces; Konfiguration der API für NLog
- App Logger entfernt und durch die Implementierung des `ILogger`-Interfaces ersetzt, um eine konsistente Logging-Architektur zu gewährleisten.
- API für die Nutzung von NLog konfiguriert, um eine leistungsstarke und flexible Logging-Lösung bereitzustellen.
- Konfigurationsdateien und Setup-Anpassungen für die Integration von NLog in die API vorgenommen.
2024-08-27 19:41:12 +02:00
Developer 02
cfd163a7a7 refactor: LdapTest von HRD.LdapService.Text nach XUnitWebApi.Test verschoben und Abhängigkeiten refaktoriert
- `LdapTest`-Klasse vom Namespace `HRD.LdapService.Text` in den Namespace `XUnitWebApi.Test` verschoben.
- `LdapTest`-Klasse aktualisiert, um von `TestBuilder` zu erben, um die erforderlichen Abhängigkeiten per Dependency Injection (DI) bereitzustellen.
- Direkte Instanziierung von Diensten (`JwtManager`, `LdapAuthenticationService`, `LdapManager`) entfernt und durch DI-basierte Abrufmethoden (`Provider.GetRequiredService`) ersetzt.
- Das veraltete Projekt `HRD.LdapService` gelöscht, da dessen Code nun in `XUnitWebApi.Test` integriert ist.
2024-08-27 15:47:47 +02:00
Developer 02
41900e8e06 test: TestBuilder für einfache DI-Konfiguration in xUnit-Tests hinzufügen
- `TestBuilder`-Klasse erstellt, um die Einrichtung der Abhängigkeitsinjektion für Unit-Tests zu vereinfachen.
- `TestBuilder` so konfiguriert, dass Dienstregistrierungen und Datenbankkontext enthalten sind.
- `TestBuilder` in das Test-Framework integriert, um eine einfache Bereitstellung von Diensten und Controllern zu ermöglichen.
2024-08-27 14:41:39 +02:00
Developer 02
c362cb30e1 feat: Benutzerrollen und JWT-Konfiguration aktualisieren
- Benutzerrollen-Enums im Frontend aktualisiert, um die neuen Namenskonventionen für 'sDigital Data'-Rollen zu reflektieren.
- Neue Rollen in `JwtGlobals` für Digital Data-Administratoren und Benutzer hinzugefügt.
- Die Rolleneinstellungen in `LdapUser` erweitert, um neue Digital Data-Rollen einzubeziehen.
- `JwtMiddlewareOptionsHelper` modifiziert, um zusätzliche Rollen zu unterstützen und die JWT-Rollenliste entsprechend strukturiert.
2024-08-27 11:58:50 +02:00
Developer 02
1d8ae2c371 feat: Konfigurierbare Tabellennamenregel in WebApiContextOptions hinzugefügt
- Einführung der WebApiContextOptions-Klasse mit einer Nullable-String-Eigenschaft `TableNamingRule`.
- Ermöglicht die Konfiguration von `TableNamingRule` über Anwendungseinstellungen (z.B. 'DIGITAL_DATA', 'PREPARED-SQL').
- Aktualisierte Dependency Injection-Einrichtung, um WebApiContextOptions aus der Konfiguration zu konfigurieren.
2024-08-26 11:35:22 +02:00
Developer 02
4387d62865 chore: Verbindungszeichenfolge angepasst, um die neue Datenbankkonfiguration widerzuspiegeln. 2024-08-06 09:34:12 +02:00
Developer 02
8038b1fd11 chore: Methode zur Aktualisierung von Spaltennamen gemäß Digital Data GmbH-Konventionen entwickeln
- Methode erstellt, um Spaltennamen in Entity Framework an die Benennungsstandards der Digital Data GmbH anzupassen.
- Entity Framework-Migrationen aktualisiert, um diese Änderungen widerzuspiegeln.
2024-08-06 09:20:18 +02:00
Developer 02
895d252c34 chore: Tabellennamen in Entity Framework aktualisiert, um den Benennungsstandards der Digital Data GmbH zu entsprechen. 2024-08-06 08:50:23 +02:00
Developer 02
70c5c1bf4e chore: environment.apiUrl-Konfiguration auf /api geändert 2024-08-05 17:22:46 +02:00
Developer 02
b43a769216 Proxy-Konfiguration hinzugefügt, um API-Anfragen während der Entwicklung zu erleichtern. 2024-08-05 17:09:24 +02:00
Developer 02
d6a2153530 chore: Startkonfiguration für bessere Entwicklungsoptionen angepasst. 2024-08-05 17:00:43 +02:00
Developer 02
bef026b9da chore: .vscode-Verzeichnis gelöscht, um das Projekt aufzuräumen. 2024-08-05 16:44:07 +02:00
Developer 02
772a6af503 chore: Quellcode der bestehenden Angular-Anwendung für die Entwicklung hinzugefügt. 2024-08-05 16:41:22 +02:00
Developer 02
bb9f524648 todo: TODO für Web API-Konfiguration hinzufügen 2024-08-05 15:42:57 +02:00
Developer 02
236e40857f refactor: ConfigureWebApiExtensionsEnd entfernen und direkt in Program.cs konfigurieren 2024-08-05 15:39:04 +02:00
Developer 02
1ecf5e48f8 refactor: Service Swagger-Erweiterungen entfernen und direkt in Program.cs hinzufügen 2024-08-05 15:37:27 +02:00
Developer 02
8190e0005a refactor: remove ConfigureWebApiExtensionsAtFirst extension 2024-08-05 15:21:42 +02:00
Developer 02
1f9fb4163b chore: LDAP_DOMAIN auf DD-VMP01-DC01 aktualisieren 2024-08-05 15:17:53 +02:00
Developer 02
cd456015c2 feat: LDAP-Optionen im JSON aktualisieren 2024-08-05 14:46:52 +02:00
Developer 02
8958ca2243 refaktor: Unnötige Startup.cs und local.db entfernen 2024-08-05 14:41:51 +02:00
Developer 02
e202dc54a5 feat: Konfiguration zum Builder verschoben, Dependency Injection optimiert und Fehlerbehandlungs- sowie Logging-Setup in Program.cs zentralisiert. 2024-08-05 14:36:59 +02:00
Developer 02
eedc726440 feat: LdapOptions erstellt anstelle statischer (fest codierter) Konfigurationswerte, LdapOptions und Abhängigkeitsinjektionen dafür hinzugefügt 2024-08-05 14:31:59 +02:00
Developer 02
d434a5964b feat: LdapOptions erstellt anstelle statischer (fest codierter) Konfigurationswerte, LdapOptions und Abhängigkeitsinjektionen dafür hinzugefügt 2024-08-05 14:18:20 +02:00
Developer 02
bc04c2d36d feat: WebAppUserRepository und WebAppUserHelper als Scoped-Dienste zur Service-Collection hinzugefügt 2024-08-05 13:10:07 +02:00
516 changed files with 46885 additions and 3468 deletions

View File

@@ -0,0 +1,303 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"staffdb": {
"root": "",
"sourceRoot": "src",
"projectType": "application",
"prefix": "app",
"schematics": {
"@schematics/angular:component": {
"style": "scss"
}
},
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"aot": true,
"outputPath": "dist",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "src/tsconfig.app.json",
"assets": [
"src/assets",
{
"glob": "**/*",
"ignore": [
"styles/*"
],
"input": "src/app/shared/core/assets/",
"output": "/assets/"
},
{
"glob": "dhr-icon-152x152i.png",
"input": "src/assets/icons/develop/",
"output": "/assets/icons/"
},
"src/webmanifest.json",
{
"glob": "environment.js",
"input": "src/environments/",
"output": "/assets/js/"
},
{
"glob": "package.json",
"input": "./",
"output": "./assets/json"
}
],
"styles": [
"src/styles.scss",
"node_modules/ngx-spinner/animations/ball-clip-rotate.css"
],
"stylePreprocessorOptions": {
"includePaths": [
"src/app/shared/core/css/0-base/",
"src/app/shared/core/components/popup-base"
]
},
"scripts": [],
"serviceWorker": true,
"ngswConfigPath": "ngsw-config.json"
},
"configurations": {
"default": {
"progress": true,
"optimization": false,
"outputHashing": "all",
"sourceMap": true,
"namedChunks": true,
"aot": true,
"extractLicenses": false,
"vendorChunk": true,
"buildOptimizer": false,
"budgets": [
{
"type": "initial",
"maximumWarning": "30mb",
"maximumError": "70mb"
}
]
},
"develop": {
"assets": [
"src/assets",
{
"glob": "**/*",
"ignore": [
"styles/*"
],
"input": "src/app/shared/core/assets/",
"output": "/assets/"
},
{
"glob": "dhr-icon-152x152i.png",
"input": "src/assets/icons/develop/",
"output": "/assets/icons/"
},
{
"glob": "webmanifest.json",
"input": "src/manifest/develop/",
"output": "/"
},
{
"glob": "environment.js",
"input": "src/environments/develop/",
"output": "/assets/js/"
},
{
"glob": "package.json",
"input": "./",
"output": "./assets/json"
}
],
"progress": true,
"optimization": false,
"outputHashing": "all",
"sourceMap": true,
"namedChunks": true,
"aot": true,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": false,
"budgets": [
{
"type": "initial",
"maximumWarning": "30mb",
"maximumError": "70mb"
}
]
},
"production": {
"assets": [
"src/assets",
{
"glob": "**/*",
"ignore": [
"styles/*"
],
"input": "src/app/shared/core/assets/",
"output": "/assets/"
},
{
"glob": "dhr-icon-152x152i.png",
"input": "src/assets/icons/production/",
"output": "/assets/icons/"
},
{
"glob": "webmanifest.json",
"input": "src/manifest/production/",
"output": "/"
},
{
"glob": "environment.js",
"input": "src/environments/production/",
"output": "/assets/js/"
},
{
"glob": "package.json",
"input": "./",
"output": "./assets/json"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"namedChunks": false,
"aot": true,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"budgets": [
{
"type": "initial",
"maximumWarning": "30mb",
"maximumError": "50mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "10kb"
}
]
}
}
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"liveReload": false,
"port": 4204,
"buildTarget": "staffdb:build",
"proxyConfig": "proxy.conf.json"
},
"configurations": {
"production": {
"buildTarget": "staffdb:build:production"
},
"develop": {
"buildTarget": "staffdb:build:develop"
},
"default": {
"buildTarget": "staffdb:build:default"
}
},
"defaultConfiguration": "default"
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"buildTarget": "staffdb:build"
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "src/test.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "src/tsconfig.spec.json",
"karmaConfig": "src/karma.conf.js",
"styles": [
"src/styles.scss",
"node_modules/ngx-spinner/animations/ball-clip-rotate.css"
],
"scripts": [],
"assets": [
"src/assets",
{
"glob": "translate-core/*",
"input": "src/app/shared/core/assets/",
"output": "/assets/"
},
{
"glob": "dhr-icon-152x152i.png",
"input": "src/assets/icons/develop/",
"output": "/assets/icons/"
},
"src/webmanifest.json",
{
"glob": "environment.js",
"input": "src/environments/",
"output": "/assets/js/"
},
{
"glob": "package.json",
"input": "./",
"output": "./assets/json"
}
]
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"src/tsconfig.app.json",
"src/tsconfig.spec.json"
],
"exclude": [
"**/node_modules/**"
]
}
}
}
},
"staffdb-e2e": {
"root": "e2e/",
"projectType": "application",
"prefix": "",
"architect": {
"e2e": {
"builder": "@angular-devkit/build-angular:protractor",
"options": {
"protractorConfig": "e2e/protractor.conf.js",
"devServerTarget": "staffdb:serve"
},
"configurations": {
"production": {
"devServerTarget": "staffdb:serve:production"
}
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": "e2e/tsconfig.e2e.json",
"exclude": [
"**/node_modules/**"
]
}
}
}
}
},
"cli": {
"analytics": false,
"cache": {
"enabled": false
}
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
"use strict";(self.webpackChunkstaffdb=self.webpackChunkstaffdb||[]).push([[732],{69732:(D,c,n)=>{n.r(c),n.d(c,{AppAccountModule:()=>M});var u=n(60177),i=n(89417),m=n(19664),d=n(94753),h=n(31837),l=n(18498),t=n(54438),p=n(49619),v=n(96995),f=n(85956),A=n(99213),r=n(21009);const y=[{path:"",component:(()=>{class e extends p.l{constructor(){super(...arguments),this.appDataService=(0,t.WQX)(v.D)}onClick(){}static#t=this.\u0275fac=(()=>{let a;return function(s){return(a||(a=t.xGo(e)))(s||e)}})();static#n=this.\u0275cmp=t.VBU({type:e,selectors:[["app-account-ext"]],features:[t.Vt3],decls:9,vars:2,consts:[["profile-settings",""],["admin-settings",""],["id","input-WebApp","placeholder","Webapp","keyExpr","entityId","displayExpr","webAppName","sortField","*","separator",",",1,"input-webapp",3,"selectedItemsChange","dataSource","multiSelect"],["mat-button","",1,"btn",3,"click"],["other-settings",""]],template:function(o,s){1&o&&(t.j41(0,"app-account"),t.nrm(1,"div",0),t.j41(2,"div",1)(3,"hensel-selection",2),t.bIt("selectedItemsChange",function(j){return s.webAppIdList=j}),t.k0s(),t.j41(4,"button",3),t.bIt("click",function(){return s.onClick()}),t.j41(5,"mat-icon"),t.EFF(6,"autorenew"),t.k0s(),t.EFF(7," Synchronize WebAppRole mit ADGroupen "),t.k0s()(),t.nrm(8,"div",4),t.k0s()),2&o&&(t.R7$(3),t.Y8G("dataSource",s.appDataService.webAppList.items)("multiSelect",!0))},dependencies:[p.l,f.iV,A.An,r.n],styles:[".input-webapp[_ngcontent-%COMP%]{float:left}.btn[_ngcontent-%COMP%]{margin-left:10px;margin-top:8px}"]})}return e})(),canActivate:[n(27938).q]}];let F=(()=>{class e{static#t=this.\u0275fac=function(o){return new(o||e)};static#n=this.\u0275mod=t.$C({type:e});static#e=this.\u0275inj=t.G2t({imports:[l.iI.forChild(y),l.iI]})}return e})();var I=n(39655),x=n(18406);let M=(()=>{class e{static#t=this.\u0275fac=function(o){return new(o||e)};static#n=this.\u0275mod=t.$C({type:e});static#e=this.\u0275inj=t.G2t({imports:[u.MD,F,I.AccountModule,x.e,i.X1,i.YN,d.N,h.WC8,r.n,m.h]})}return e})()}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="900" height="600">
<rect fill="#c8102e" width="900" height="600"/>
<rect fill="#fff" y="200" width="900" height="200"/>
</svg>

After

Width:  |  Height:  |  Size: 213 B

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1280" height="640" viewBox="0 0 10080 5040">
<defs>
<clipPath id="c1"><path d="M0,0H6V3H0z"/></clipPath>
<clipPath id="c2"><path d="M0,0V1.5H6V3H6zM6,0H3V3H0V3z"/></clipPath>
<path id="Star7" d="M0,-360 69.421398,-144.155019 281.459334,-224.456329 155.988466,-35.603349 350.974048,80.107536 125.093037,99.758368 156.198146,324.348792 0,160 -156.198146,324.348792 -125.093037,99.758368 -350.974048,80.107536 -155.988466,-35.603349 -281.459334,-224.456329 -69.421398,-144.155019z"/>
<path id="Star5" d="M0,-210 54.859957,-75.508253 199.721868,-64.893569 88.765275,28.841586 123.434903,169.893569 0,93.333333 -123.434903,169.893569 -88.765275,28.841586 -199.721868,-64.893569 -54.859957,-75.508253z"/>
</defs>
<g transform="scale(840)">
<rect width="12" height="6" fill="#00008b"/>
<path d="M0,0 6,3M6,0 0,3" stroke="#fff" stroke-width="0.6" clip-path="url(#c1)"/>
<path d="M0,0 6,3M6,0 0,3" stroke="#f00" stroke-width="0.4" clip-path="url(#c2)"/>
<path d="M3,0V3M0,1.5H6" stroke="#fff"/>
<path d="M3,0V3M0,1.5H6" stroke="#f00" stroke-width="0.6"/>
</g>
<g fill="#fff">
<use id="Comwlth" xlink:href="#Star7" transform="translate(2520, 3780) scale(2.1)"/>
<use id="αCrucis" xlink:href="#Star7" x="7560" y="4200"/>
<use id="βCrucis" xlink:href="#Star7" x="6300" y="2205"/>
<use id="γCrucis" xlink:href="#Star7" x="7560" y="840"/>
<use id="δCrucis" xlink:href="#Star7" x="8680" y="1869"/>
<use id="εCrucis" xlink:href="#Star5" x="8064" y="2730"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="900" height="600" viewBox="0 0 9 6">
<rect fill="#FFCE00" width="9" height="6"/>
<rect fill="#DD0000" width="9" height="4"/>
<rect fill="#000000" width="9" height="2"/>
</svg>

After

Width:  |  Height:  |  Size: 222 B

View File

@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="900" height="600"><rect width="900" height="600" fill="#ED2939"/><rect width="600" height="600" fill="#fff"/><rect width="300" height="600" fill="#002395"/></svg>

After

Width:  |  Height:  |  Size: 249 B

View File

@@ -0,0 +1,16 @@
<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 60 30" width="1200" height="600">
<clipPath id="s">
<path d="M0,0 v30 h60 v-30 z"/>
</clipPath>
<clipPath id="t">
<path d="M30,15 h30 v15 z v15 h-30 z h-30 v-15 z v-15 h30 z"/>
</clipPath>
<g clip-path="url(#s)">
<path d="M0,0 v30 h60 v-30 z" fill="#012169"/>
<path d="M0,0 L60,30 M60,0 L0,30" stroke="#fff" stroke-width="6"/>
<path d="M0,0 L60,30 M60,0 L0,30" clip-path="url(#t)" stroke="#C8102E" stroke-width="4"/>
<path d="M30,0 v30 M0,15 h60" stroke="#fff" stroke-width="10"/>
<path d="M30,0 v30 M0,15 h60" stroke="#C8102E" stroke-width="6"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 641 B

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="900" height="600" viewBox="-36 -24 72 48">
<title>Flag of South Korea</title>
<path d="M-36-24h72v48h-72z" fill="#fff"/>
<g transform="rotate(-56.3099325)"><!--arctan(-3/2)-->
<g id="b2"><path id="b" d="M-6-26H6v2H-6zm0 3H6v2H-6zm0 3H6v2H-6z"/>
<use xlink:href="#b" y="44"/></g>
<path stroke="#fff" d="M0,17v10"/>
<path fill="#cd2e3a" d="M0-12A12 12 0 0 1 0 12z"/>
<path fill="#0047a0" d="M0-12A12 12 0 0 0 0 12 6 6 0 0 0 0 0z"/>
<circle cy="-6" fill="#cd2e3a" r="6"/></g>
<g transform="rotate(-123.6900675)"><use xlink:href="#b2"/>
<path stroke="#fff" d="M0-23.5v3M0,17v3.5M0,23.5v3"/></g></svg>

After

Width:  |  Height:  |  Size: 726 B

View File

@@ -0,0 +1,11 @@
<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="600" viewBox="0 0 13440 6720" fill="none">
<title>Flag of Malaysia</title>
<g transform="scale(480)">
<path fill="#fff" d="m0 0h28v14H0z"/>
<path stroke="#c00" d="m1 .5h27m0 2H1m0 2h27m0 2H1"/>
<path fill="#006" d="m0 0h14v8.5H0z"/>
<path stroke="#c00" d="m0 8.5h28m0 2H0m0 2h28"/>
</g>
<path fill="#fc0" d="m4200 720 107 732 414-613-222 706 639-373-506 540 738-59-690 267 690 267-738-59 506 540-639-373 222 706-414-613-107 732-107-732-414 613 222-706-639 373 506-540-738 59 690-267-690-267 738 59-506-540 639 373-222-706 414 613zm-600 30a1280 1280 0 1 0 0 2340 1440 1440 0 1 1 0-2340z"/>
</svg>

After

Width:  |  Height:  |  Size: 683 B

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1235" height="650" viewBox="0 0 7410 3900">
<rect width="7410" height="3900" fill="#b22234"/>
<path d="M0,450H7410m0,600H0m0,600H7410m0,600H0m0,600H7410m0,600H0" stroke="#fff" stroke-width="300"/>
<rect width="2964" height="2100" fill="#3c3b6e"/>
<g fill="#fff">
<g id="s18">
<g id="s9">
<g id="s5">
<g id="s4">
<path id="s" d="M247,90 317.534230,307.082039 132.873218,172.917961H361.126782L176.465770,307.082039z"/>
<use xlink:href="#s" y="420"/>
<use xlink:href="#s" y="840"/>
<use xlink:href="#s" y="1260"/>
</g>
<use xlink:href="#s" y="1680"/>
</g>
<use xlink:href="#s4" x="247" y="210"/>
</g>
<use xlink:href="#s9" x="494"/>
</g>
<use xlink:href="#s18" x="988"/>
<use xlink:href="#s9" x="1976"/>
<use xlink:href="#s5" x="2470"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 874 B

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

View File

@@ -0,0 +1,7 @@
const environment = {
production: true,
useLoginWithJWT: true,
apiUrl: '/api',
sentry_dsn: '',
translationFolder: './assets/translate/',
};

View File

@@ -0,0 +1,70 @@
{
"name": "staffdb",
"version": "14.23.33",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"watch": "ng build --watch --configuration development",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e",
"reinstall:packages": "rm -rf node_modules dist && npm cache clean --force && rm package-lock.json && npm install",
"win_reinstall:packages": "rd /s /q node_modules && npm cache clean --force && del package-lock.json && npm install",
"add_pwa": "ng add @angular/pwa@latest"
},
"private": true,
"dependencies": {
"@angular/animations": "^17.3.10",
"@angular/cdk": "^16.2.14",
"@angular/common": "^17.3.10",
"@angular/compiler": "^17.3.10",
"@angular/core": "^17.3.10",
"@angular/forms": "^17.3.10",
"@angular/localize": "^17.3.10",
"@angular/material": "^16.2.14",
"@angular/material-moment-adapter": "^16.2.14",
"@angular/platform-browser": "^17.3.10",
"@angular/platform-browser-dynamic": "^17.3.10",
"@angular/pwa": "^17.3.8",
"@angular/router": "^17.3.10",
"@angular/service-worker": "^17.3.10",
"@ngx-translate/core": "^15.0.0",
"@ngx-translate/http-loader": "^8.0.0",
"@sentry/angular": "^8.4.0",
"angular-in-memory-web-api": "^0.17.0",
"devextreme-angular": "~23.2.6",
"exceljs": "^4.4.0",
"file-saver": "^2.0.5",
"jspdf": "^2.5.1",
"moment": "^2.30.1",
"ngx-clipboard": "^16.0.0",
"ngx-device-detector": "^7.0.0",
"ngx-mask": "^17.0.8",
"ngx-spinner": "^17.0.0",
"ngx-translate-multi-http-loader": "^17.0.0",
"ngx-webcam": "^0.4.1",
"rxjs": "^7.8.1",
"zone.js": "^0.14.6"
},
"devDependencies": {
"@angular-devkit/build-angular": "^17.3.8",
"@angular/cli": "^17.3.8",
"@angular/compiler-cli": "^17.3.10",
"@angular/language-service": "^17.3.10",
"@types/jasmine": "latest",
"@types/node": "latest",
"codelyzer": "latest",
"jasmine-core": "latest",
"jasmine-spec-reporter": "latest",
"karma": "latest",
"karma-chrome-launcher": "latest",
"karma-coverage": "latest",
"karma-jasmine": "latest",
"karma-jasmine-html-reporter": "latest",
"protractor": "latest",
"ts-node": "latest",
"tslint": "latest",
"typescript": "~5.4.5"
}
}

View File

@@ -0,0 +1,110 @@
{
"core.btn.ok": "Ok",
"core.btn.yes": "Ja",
"core.btn.no": "Nein",
"core.btn.cancel": "Abbrechen",
"core.btn.apply": "Übernehmen",
"core.btn.reset": "Reset",
"core.hint.reset": "Zurücksetzen",
"core.hint.undo": "Änderungen verwerfen",
"core.btn.undo": "Verwerfen",
"core.btn.search": "Suchen",
"core.dropdown-option.all": "< Alle >",
"core.dropdown-option.none": "< Keine >",
"core.caption.login": "Login",
"core.caption.hidepassword": "Hide password",
"core.caption.registration": "Anmeldung",
"core.caption.logout": "Logout",
"core.caption.config": "Einstellungen",
"core.caption.version": "Version",
"core.caption.username": "Benutzername",
"core.caption.password": "Passwort",
"core.caption.account": "Konto",
"core.caption.all": "Alle",
"core.caption.none": "Keine",
"core.caption.serverinfo-pollinginterval": "Abstang für Erneuerung von Serverver Info (Sek., 0-nie)",
"core.msg.saving": "Speichern {{value}}...",
"core.msg.saved": "Gespeichert {{value}}",
"core.msg.loading": "Laden {{value}}...",
"core.msg.loaded": "Geladen {{value}}: {{count}}",
"core.msg.loggedon": "Benutzeranmeldung für {{value}} war erfolgreich",
"core.msg.renewJWT": "Versuche zu verlängern von JWT",
"core.msg.waitingconnecton": "Warte auf Verbindung...",
"core.msg.checkuser": "Benutzer wird überprüft...",
"core.msg.greeting": "Hallo",
"core.msg.update": "Bitte aktualisieren!",
"core.hint.update": "Klicke um die Version zu aktualisieren",
"core.error.loading": "Fehler beim Laden von {{value}}",
"core.error.saving": "Fehler beim Speichern von {{value}}",
"core.error.deleting": "Fehler beim Löschen von {{value}}",
"core.error.nouserrole": "Keine Benutzerrole ist zugewiesen!",
"core.error.logon": "Anmeldung ist fehlgeschlagen!",
"core.error.logonnotpossible": "{{value}}Anmeldung ist nicht möglich!",
"core.error.disclaimernotconfirmed": "Haftungsausschluss muss bestätigt werden!",
"core.msgbox.header.cancel": "{{value}}",
"core.msgbox.body.cancel": "Sollen Änderungen gespeichert werden?",
"core.msgbox.header.delete": "{{value}}",
"core.msgbox.body.delete": "Soll {{value}} gelöscht werden?",
"core.msgbox.header.connect": "Verbindungsaufbau",
"core.msgbox.body.connect": "Keine Verbindung zum Server kann aufgebaut werden. Bitte wenden sie sich an IT-Entwicklung",
"core.grid.nodata": "Keine Daten vorhanden",
"core.hdatepicker.dateoutofrange": "Das Datum ist ausser zulässigem Bereich",
"core.hensel-selection.nohits": "Keine Treffer gefunden",
"core.hensel-selection.selectedfirst": "Selektierte zuerst",
"core.hensel-selection.processlist": "Liste bearbeiten",
"core.hensel-selection.inputminsybols": "Für Auswahl mind. {{value}} Zeichen eingeben",
"core.hwebcam.delete": "Foto löschen",
"core.hwebcam.takepicture": "Foto aufnehmen",
"core.footer.status": "Status",
"core.footer.noconnection": "Keine Verbindung ist vorhanden !!!",
"core.footer.lastloading": "Letzte Datenabruf",
"core.footer.loginexpires": "Anmeldung läuft ab in",
"core.footer.days": "Tag(e)",
"core.footer.hours": "Std.",
"core.footer.mins": "Min.",
"core.footer.secs": "Sek.",
"core.account.caption.price": "Preis",
"core.account.caption.weight" : "Gewicht",
"core.caption.date": "Datum",
"core.caption.user": "Benutzer",
"core.caption.role": "Rolle",
"core.caption.myaccount": "Mein Konto",
"core.caption.disclaimer": "Haftungsausschluss",
"core.caption.addsettings" : "Admineinstellungen",
"core.caption.showstatusbar" : "Statuszeile anzeigen",
"core.caption.showids" : "Ids anzeigen",
"core.caption.language" : "Sprache",
"core.caption.regionformat" : "Regionales Format",
"core.caption.name": "Name",
"core.caption.userloginname": "Benutzername",
"core.caption.country-ge": "Deutschland",
"core.caption.country-at": "Österrecih",
"core.caption.country-gb": "Grossbritanien",
"core.caption.country-us": "United States",
"core.caption.country-au": "Australien",
"core.caption.country-fr": "Frankreich",
"core.caption.country-kr": "Korea",
"core.caption.country-my": "Malaysia",
"core.caption.lang-ge": "Deutsch",
"core.caption.lang-at": "Deutsch",
"core.caption.lang-gb": "Englisch",
"core.caption.lang-us": "Englisch",
"core.caption.lang-au": "Englisch",
"core.caption.lang-fr": "Französisch",
"core.caption.lang-kr": "Koreanisch",
"core.caption.lang-my": "Malaiisch"
}

View File

@@ -0,0 +1,110 @@
{
"core.btn.ok": "Ok",
"core.btn.yes": "Yes",
"core.btn.no": "No",
"core.btn.cancel": "Cancel",
"core.btn.apply": "Apply",
"core.btn.reset": "Reset",
"core.hint.reset": "Reset",
"core.hint.undo": "Discard changes",
"core.btn.undo": "Discard",
"core.btn.search": "Search",
"core.dropdown-option.all": "< All >",
"core.dropdown-option.none": "< None >",
"core.caption.login": "Login",
"core.caption.hidepassword": "Hide password",
"core.caption.registration": "Log in",
"core.caption.logout": "Logout",
"core.caption.config": "Configuration",
"core.caption.version": "Version",
"core.caption.username": "Username",
"core.caption.password": "Password",
"core.caption.account": "Account",
"core.caption.all": "All",
"core.caption.none": "None",
"core.caption.serverinfo-pollinginterval": "Interval to refresh of Serverver Info (sec., 0-never)",
"core.msg.saving": "Saving {{value}}...",
"core.msg.saved": "Saved {{value}}",
"core.msg.loading": "Loading {{value}}...",
"core.msg.loaded": "Loaded {{value}}: {{count}}",
"core.msg.loggedon": "Logon for {{value}} succeeded",
"core.msg.renewJWT": "Try to renew JWT",
"core.msg.waitingconnecton": "Waiting connection...",
"core.msg.checkuser": "Check user...",
"core.msg.greeting": "Hello",
"core.msg.update": "Please update!",
"core.hint.update": "Click to update the version",
"core.error.loading": "Error during loading of {{value}}",
"core.error.saving": "Error during saving of {{value}}",
"core.error.deleting": "Error during deleting of {{value}}",
"core.error.nouserrole": "User is assigned no role!",
"core.error.logon": "Logon failed!",
"core.error.logonnotpossible": "{{value}}Logon is not possible!",
"core.error.disclaimernotconfirmed": "Disclaimer must be confirmed!",
"core.msgbox.header.cancel": "{{value}}",
"core.msgbox.body.cancel": "Save changes?",
"core.msgbox.header.delete": "{{value}}",
"core.msgbox.body.delete": "Delete {{value}}?",
"core.msgbox.header.connect": "Establish connection",
"core.msgbox.body.connect": "The server connot be connected. Please contact IT-Development",
"core.grid.nodata": "No data",
"core.hdatepicker.dateoutofrange": "The date is out of range",
"core.hensel-selection.nohits": "No hits",
"core.hensel-selection.selectedfirst": "Selected first",
"core.hensel-selection.processlist": "Edit list",
"core.hensel-selection.inputminsybols": "For selection input at least {{value}} symbols",
"core.hwebcam.delete": "Delete picture",
"core.hwebcam.takepicture": "Take picture",
"core.footer.status": "Status",
"core.footer.noconnection": "No connectoin to the server !!!",
"core.footer.lastloading": "Last Dataloading",
"core.footer.loginexpires": "Login expires in",
"core.footer.days": "Day(s)",
"core.footer.hours": "Hr(s)",
"core.footer.mins": "Min(s)",
"core.footer.secs": "Sec(s)",
"core.account.caption.price": "Price",
"core.account.caption.weight" : "Weight",
"core.caption.date": "Date",
"core.caption.user": "User",
"core.caption.role": "Role",
"core.caption.myaccount": "My Account",
"core.caption.disclaimer": "Disclaimer",
"core.caption.addsettings" : "Admin Settings",
"core.caption.showstatusbar" : "Show Statusbar",
"core.caption.showids" : "Show Ids",
"core.caption.language" : "Language",
"core.caption.regionformat" : "Regional Format",
"core.caption.name": "Name",
"core.caption.userloginname": "Loginname",
"core.caption.country-ge": "Germany",
"core.caption.country-at": "Austria",
"core.caption.country-gb": "United Kingdom",
"core.caption.country-us": "United States",
"core.caption.country-au": "Australia",
"core.caption.country-fr": "France",
"core.caption.country-kr": "Korea",
"core.caption.country-my": "Malaysia",
"core.caption.lang-ge": "German",
"core.caption.lang-at": "German",
"core.caption.lang-gb": "English",
"core.caption.lang-us": "English",
"core.caption.lang-au": "English",
"core.caption.lang-fr": "French",
"core.caption.lang-kr": "Korean",
"core.caption.lang-my": "Malay"
}

View File

@@ -0,0 +1,107 @@
{
"core.btn.ok": "Ok",
"core.btn.yes": "Yes",
"core.btn.no": "No",
"core.btn.cancel": "Cancel",
"core.btn.apply": "Accept",
"core.btn.reset": "Reset",
"core.hint.reset": "Reset",
"core.btn.search": "Search",
"core.dropdown-option.all": "< All >",
"core.dropdown-option.none": "< None >",
"core.caption.login": "Login",
"core.caption.registration": "Log in",
"core.caption.logout": "Logout",
"core.caption.config": "Configuration",
"core.caption.version": "Version",
"core.caption.username": "Username",
"core.caption.password": "Password",
"core.caption.account": "Account",
"core.caption.all": "All",
"core.caption.none": "None",
"core.caption.serverinfo-pollinginterval": "Interval to refresh of Serverver Info (sec., 0-never)",
"core.msg.saving": "Saving {{value}}...",
"core.msg.saved": "Saved {{value}}",
"core.msg.loading": "Loading {{value}}...",
"core.msg.loaded": "Loaded {{value}}: {{count}}",
"core.msg.loggedon": "Logon for {{value}} succeeded",
"core.msg.renewJWT": "Try to renew JWT",
"core.msg.waitingconnecton": "Waiting connection...",
"core.msg.checkuser": "Check user...",
"core.msg.greeting": "Hello",
"core.msg.update": "Please update!",
"core.hint.update": "Click to update the version",
"core.error.loading": "Error during loading of {{value}}",
"core.error.saving": "Error during saving of {{value}}",
"core.error.deleting": "Error during deleting of {{value}}",
"core.error.nouserrole": "User is assigned no role!",
"core.error.logon": "Logon failed!",
"core.error.logonnotpossible": "{{value}}Logon is not possible!",
"core.error.disclaimernotconfirmed": "Disclaimer must be confirmed!",
"core.msgbox.header.cancel": "Cancelling of processing of {{value}}",
"core.msgbox.body.cancel": "{{value}} was changed. Should changes be saved?",
"core-confirmmsgheader_delete": "Deleting of {{value}}",
"core.msgbox.body.delete": "Should {{value}} be deleted?",
"core-confirmmsgheader_connect": "Establish connection",
"core.msgbox.body.connect": "The server connot be connected. Please contact IT-Development",
"core.grid.nodata": "No data",
"core.hdatepicker.dateoutofrange": "The date is out of range",
"core.hensel-selection.nohits": "No hits",
"core.hensel-selection.selectedfirst": "Selected first",
"core.hensel-selection.processlist": "Edit list",
"core.hensel-selection.inputminsybols": "For selection input at least {{value}} symbols",
"core.hwebcam.takepicture": "Take picture",
"core.hwebcam.delete": "Delete picture",
"core.footer.status": "Status",
"core.footer.noconnection": "No connectoin to the server !!!",
"core.footer.lastloading": "Last Dataloading",
"core.footer.loginexpires": "Login expires in",
"core.footer.days": "Day(s)",
"core.footer.hours": "Hr(s)",
"core.footer.mins": "Min(s)",
"core.footer.secs": "Sec(s)",
"core.account.caption.price": "Price",
"core.account.caption.weight" : "Weight",
"core.caption.date": "Date",
"core.caption.user": "User",
"core.caption.role": "Role",
"core.caption.myaccount": "My Account",
"core.caption.disclaimer": "Disclaimer",
"core.caption.addsettings" : "Admin Settings",
"core.caption.showstatusbar" : "Show Statusbar",
"core.caption.showids" : "Show Ids",
"core.caption.language" : "Language",
"core.caption.regionformat" : "Regional Format",
"core.caption.name": "Name",
"core.caption.userloginname": "Loginname",
"core.caption.country-ge": "Germany",
"core.caption.country-at": "Austria",
"core.caption.country-gb": "United Kingdom",
"core.caption.country-us": "United States",
"core.caption.country-au": "Australia",
"core.caption.country-fr": "France",
"core.caption.country-kr": "Korea",
"core.caption.country-my": "Malaysia",
"core.caption.lang-ge": "German",
"core.caption.lang-at": "German",
"core.caption.lang-gb": "English",
"core.caption.lang-us": "English",
"core.caption.lang-au": "English",
"core.caption.lang-fr": "French",
"core.caption.lang-kr": "Korean",
"core.caption.lang-my": "Malay"
}

View File

@@ -0,0 +1,2 @@
{
}

View File

@@ -0,0 +1,2 @@
{
}

View File

@@ -0,0 +1,2 @@
{
}

File diff suppressed because one or more lines are too long

39
ClientApp/staff-db-ui/dist/index.html vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

1863
ClientApp/staff-db-ui/dist/ngsw-worker.js vendored Normal file

File diff suppressed because it is too large Load Diff

181
ClientApp/staff-db-ui/dist/ngsw.json vendored Normal file
View File

@@ -0,0 +1,181 @@
{
"configVersion": 1,
"timestamp": 1725263531505,
"index": "/index.html",
"assetGroups": [
{
"name": "app",
"installMode": "prefetch",
"updateMode": "prefetch",
"cacheQueryOptions": {
"ignoreVary": true
},
"urls": [
"/102.a1cebbe1b2264d1a.js",
"/140.c3d21c5ed0a40561.js",
"/147.b04a1078d98ad77b.js",
"/233.c22447bd85c8ff2d.js",
"/239.8ff4ba6fe30b27c5.js",
"/426.76e714807174469a.js",
"/732.7127fbc84084fa8d.js",
"/826.a9ef1bb06db1b9fc.js",
"/973.d62bccb3860d3e9d.js",
"/995.4c2113718131dc04.js",
"/assets/icons/hr-logo_color.ico",
"/common.20ad2b8268292298.js",
"/index.html",
"/main.79a551caa62eec25.js",
"/polyfills.f3a85f3df42fd3cb.js",
"/runtime.3357f0de0086757c.js",
"/styles.3c191a76efd858de.css",
"/webmanifest.json"
],
"patterns": []
},
{
"name": "assets",
"installMode": "lazy",
"updateMode": "prefetch",
"cacheQueryOptions": {
"ignoreVary": true
},
"urls": [
"/assets/flags/at.svg",
"/assets/flags/au.svg",
"/assets/flags/de.svg",
"/assets/flags/fr.svg",
"/assets/flags/gb.svg",
"/assets/flags/ko.svg",
"/assets/flags/my.svg",
"/assets/flags/us.svg",
"/assets/icons/Master_Icon.xcf",
"/assets/icons/develop/dhr-icon-128x128.png",
"/assets/icons/develop/dhr-icon-144x144.png",
"/assets/icons/develop/dhr-icon-152x152.png",
"/assets/icons/develop/dhr-icon-152x152i.png",
"/assets/icons/develop/dhr-icon-16x16.png",
"/assets/icons/develop/dhr-icon-192x192.png",
"/assets/icons/develop/dhr-icon-24x24.png",
"/assets/icons/develop/dhr-icon-384x384.png",
"/assets/icons/develop/dhr-icon-48x48.png",
"/assets/icons/develop/dhr-icon-512x512.png",
"/assets/icons/develop/dhr-icon-72x72.png",
"/assets/icons/develop/dhr-icon-96x96.png",
"/assets/icons/dhr-icon-152x152i.png",
"/assets/icons/hr-logo_bright.ico",
"/assets/icons/hr-logo_color3d.ico",
"/assets/icons/hr-logo_red.ico",
"/assets/icons/hr-logo_white.ico",
"/assets/icons/main_48x48.png",
"/assets/icons/production/dhr-icon-128x128.png",
"/assets/icons/production/dhr-icon-144x144.png",
"/assets/icons/production/dhr-icon-152x152.png",
"/assets/icons/production/dhr-icon-152x152i.png",
"/assets/icons/production/dhr-icon-16x16.png",
"/assets/icons/production/dhr-icon-192x192.png",
"/assets/icons/production/dhr-icon-24x24.png",
"/assets/icons/production/dhr-icon-384x384.png",
"/assets/icons/production/dhr-icon-48x48.png",
"/assets/icons/production/dhr-icon-512x512.png",
"/assets/icons/production/dhr-icon-72x72.png",
"/assets/icons/production/dhr-icon-96x96.png",
"/assets/js/environment.js",
"/assets/json/package.json",
"/assets/translate-core/de.json",
"/assets/translate-core/en.json",
"/assets/translate-core/fr.json",
"/assets/translate/de.json",
"/assets/translate/en.json",
"/assets/translate/fr.json"
],
"patterns": []
}
],
"dataGroups": [],
"hashTable": {
"/102.a1cebbe1b2264d1a.js": "0411f02cdf9e10ba2176ca9f3de78b063ed09480",
"/140.c3d21c5ed0a40561.js": "97be34cbab80027e774995fb9062a4ec315cc028",
"/147.b04a1078d98ad77b.js": "51eec921d96189c155b4506fc603cdd277d01428",
"/233.c22447bd85c8ff2d.js": "39dc0fc05a5dd6a3d34c02f7ee90a11fe8cd7822",
"/239.8ff4ba6fe30b27c5.js": "8b91ad0d0a691a29020ea0b28ea0788554978cb7",
"/426.76e714807174469a.js": "2f7bf9c6708a630c8730cb2d55f0c763519796e4",
"/732.7127fbc84084fa8d.js": "f04be01aabf928a5889103a1a6a15a4fa9249c7e",
"/826.a9ef1bb06db1b9fc.js": "c3e899cc6916fdcb5e9d9d9ba1474892d97bde33",
"/973.d62bccb3860d3e9d.js": "05b58887b6e89767b641b28263e02a4f6ae64cff",
"/995.4c2113718131dc04.js": "64db02f4d432f60f2f8508e21fe04b00c1dc622c",
"/assets/flags/at.svg": "6183e2da9a0264dc227387294332895f1da4b9bf",
"/assets/flags/au.svg": "7993ca14904b1e1bd3af97aece612e77fec9c2f3",
"/assets/flags/de.svg": "4cb4d111b606807483240a8a1d8028e688c0a13e",
"/assets/flags/fr.svg": "9e00364488485559dcc5644f67c969f27be2526a",
"/assets/flags/gb.svg": "4fa0230bc933fb751866617eb102b1266a1738d3",
"/assets/flags/ko.svg": "54117c35dc98c6002ccdc13f9a8ff9abe48fbda1",
"/assets/flags/my.svg": "fb63e9d2a56dc3dcafcf1d51f8909623dc56fd40",
"/assets/flags/us.svg": "b3054f4dbd6e5353901537c770ff24360656a8b5",
"/assets/icons/Master_Icon.xcf": "a60ae86bcb50c97bd20e56b605ea62389cd211de",
"/assets/icons/develop/dhr-icon-128x128.png": "069d2f6bc03e5c6b35a6660d487a36bfd16f9ab5",
"/assets/icons/develop/dhr-icon-144x144.png": "22314bd2f99c99ac504253aac166f889856c4581",
"/assets/icons/develop/dhr-icon-152x152.png": "8fa84de00c3764dc6d5d779dee4728a038f8a773",
"/assets/icons/develop/dhr-icon-152x152i.png": "0650a9829e14413b064c6b1276fd30dca68598cf",
"/assets/icons/develop/dhr-icon-16x16.png": "e4a7e28c987b1d8b17bc90d93d651c5945f074d6",
"/assets/icons/develop/dhr-icon-192x192.png": "ad4584822c8a3ab1ae9020c243b652b1e3d58f2c",
"/assets/icons/develop/dhr-icon-24x24.png": "45b4f3fcc3845f53a45c2802539b1cbc03c881f3",
"/assets/icons/develop/dhr-icon-384x384.png": "533171e1c9ddb3580facc2a46ef2131d435d3cb3",
"/assets/icons/develop/dhr-icon-48x48.png": "5c9b8b185c9e7fa6046441dc45356d0558d2420a",
"/assets/icons/develop/dhr-icon-512x512.png": "fa36a5e3f96dad351c2c604a90a56050f1d10daf",
"/assets/icons/develop/dhr-icon-72x72.png": "ebf56206dd26bdf21b49e78b8aa3477ded3562aa",
"/assets/icons/develop/dhr-icon-96x96.png": "1893cc6ad131b50874ae12e70ac31418f96378f6",
"/assets/icons/dhr-icon-152x152i.png": "6ac691564d70831a487da0590a1675932e478e87",
"/assets/icons/hr-logo_bright.ico": "9c0f87a2b74e6841ccca8879a0ede0ec0ffbc0fa",
"/assets/icons/hr-logo_color.ico": "b5ad8eb4d1a526655a0b8639ede858876a9fd143",
"/assets/icons/hr-logo_color3d.ico": "16bb2f75d0d8a436a9d1c49e5f1a036e6d41b137",
"/assets/icons/hr-logo_red.ico": "66eb4a94f6c72dc540fe29884ad8ca8e52a06637",
"/assets/icons/hr-logo_white.ico": "34cb8164e6996c80372cbfc4032236776133df0f",
"/assets/icons/main_48x48.png": "e6d9580c6d1b910da8e0add9c41d051b9b119d46",
"/assets/icons/production/dhr-icon-128x128.png": "820470f0aa9639f86a639d341100b9b345c9a8b9",
"/assets/icons/production/dhr-icon-144x144.png": "17ede46b4568521a0c9ffa13c2a683e71cc16f72",
"/assets/icons/production/dhr-icon-152x152.png": "753ff9abf2451c3e1955ca20bd04830ce3a1fde0",
"/assets/icons/production/dhr-icon-152x152i.png": "6ac691564d70831a487da0590a1675932e478e87",
"/assets/icons/production/dhr-icon-16x16.png": "d5b8172ded82934ee4e92fe01e6fb6f11914204f",
"/assets/icons/production/dhr-icon-192x192.png": "c7f6481307fa369814f75ecf6fda308bf19a37a1",
"/assets/icons/production/dhr-icon-24x24.png": "8d7866fed1a63e4bbdace1e2dc8aa45f3dfd9a34",
"/assets/icons/production/dhr-icon-384x384.png": "837e17ec77159f7aff7a9aada79cb9026cc291f0",
"/assets/icons/production/dhr-icon-48x48.png": "2f54d152260d7e12d73bc23aaf0a62b500693b92",
"/assets/icons/production/dhr-icon-512x512.png": "69f1f4f514f0c10aaac151e951d4ae52c270283e",
"/assets/icons/production/dhr-icon-72x72.png": "ff384e38bd212d36da44b83d85730f5caf4b4e01",
"/assets/icons/production/dhr-icon-96x96.png": "0860e68d02018ce7dd9081720d88dd89ce998b73",
"/assets/js/environment.js": "f228e51d32b9b1e07b55b0e1c62108877e163e06",
"/assets/json/package.json": "2b4dcfe09606bf67d08364ae60eaec9d2a3ffd87",
"/assets/translate-core/de.json": "f50b0f2b2d49d7df89fec02a438daee23c3d73e8",
"/assets/translate-core/en.json": "c0226be00bbda803dc8e1cddf8b24d6f338ce5d7",
"/assets/translate-core/fr.json": "bf907a896e676f1e86e7475ff53eafaf38df6b3f",
"/assets/translate/de.json": "534e5f914ae99bf0a342a2f7a7e0724bd0d11ef7",
"/assets/translate/en.json": "534e5f914ae99bf0a342a2f7a7e0724bd0d11ef7",
"/assets/translate/fr.json": "534e5f914ae99bf0a342a2f7a7e0724bd0d11ef7",
"/common.20ad2b8268292298.js": "e3c2837ab8689c41ca2b3260e460a9f450bcf0c8",
"/index.html": "6cdb2574e917f149f8b9ac4717fca9fbe354275c",
"/main.79a551caa62eec25.js": "1ca119164988cba206064ec40243c23574c5baf7",
"/polyfills.f3a85f3df42fd3cb.js": "e7154fa31ed5feb8023c3aa2ac33a150776bb404",
"/runtime.3357f0de0086757c.js": "6a3751bd58616232d783a9c9b544abd4cb7ea927",
"/styles.3c191a76efd858de.css": "44d803a2ede68a3d431a99dfafb606057ff98fc0",
"/webmanifest.json": "5866f6cd8c30c59be09d37e12e294b432450cd0f"
},
"navigationUrls": [
{
"positive": true,
"regex": "^\\/.*$"
},
{
"positive": false,
"regex": "^\\/(?:.+\\/)?[^/]*\\.[^/]*$"
},
{
"positive": false,
"regex": "^\\/(?:.+\\/)?[^/]*__[^/]*$"
},
{
"positive": false,
"regex": "^\\/(?:.+\\/)?[^/]*__[^/]*\\/.*$"
}
],
"navigationRequestStrategy": "performance"
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
(()=>{"use strict";var e,v={},g={};function r(e){var f=g[e];if(void 0!==f)return f.exports;var t=g[e]={id:e,loaded:!1,exports:{}};return v[e].call(t.exports,t,t.exports,r),t.loaded=!0,t.exports}r.m=v,e=[],r.O=(f,t,n,i)=>{if(!t){var a=1/0;for(o=0;o<e.length;o++){for(var[t,n,i]=e[o],l=!0,d=0;d<t.length;d++)(!1&i||a>=i)&&Object.keys(r.O).every(p=>r.O[p](t[d]))?t.splice(d--,1):(l=!1,i<a&&(a=i));if(l){e.splice(o--,1);var s=n();void 0!==s&&(f=s)}}return f}i=i||0;for(var o=e.length;o>0&&e[o-1][2]>i;o--)e[o]=e[o-1];e[o]=[t,n,i]},r.n=e=>{var f=e&&e.__esModule?()=>e.default:()=>e;return r.d(f,{a:f}),f},(()=>{var f,e=Object.getPrototypeOf?t=>Object.getPrototypeOf(t):t=>t.__proto__;r.t=function(t,n){if(1&n&&(t=this(t)),8&n||"object"==typeof t&&t&&(4&n&&t.__esModule||16&n&&"function"==typeof t.then))return t;var i=Object.create(null);r.r(i);var o={};f=f||[null,e({}),e([]),e(e)];for(var a=2&n&&t;"object"==typeof a&&!~f.indexOf(a);a=e(a))Object.getOwnPropertyNames(a).forEach(l=>o[l]=()=>t[l]);return o.default=()=>t,r.d(i,o),i}})(),r.d=(e,f)=>{for(var t in f)r.o(f,t)&&!r.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:f[t]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce((f,t)=>(r.f[t](e,f),f),[])),r.u=e=>(76===e?"common":e)+"."+{76:"20ad2b8268292298",102:"a1cebbe1b2264d1a",140:"c3d21c5ed0a40561",147:"b04a1078d98ad77b",233:"c22447bd85c8ff2d",239:"8ff4ba6fe30b27c5",426:"76e714807174469a",732:"7127fbc84084fa8d",826:"a9ef1bb06db1b9fc",973:"d62bccb3860d3e9d",995:"4c2113718131dc04"}[e]+".js",r.miniCssF=e=>{},r.o=(e,f)=>Object.prototype.hasOwnProperty.call(e,f),(()=>{var e={},f="staffdb:";r.l=(t,n,i,o)=>{if(e[t])e[t].push(n);else{var a,l;if(void 0!==i)for(var d=document.getElementsByTagName("script"),s=0;s<d.length;s++){var c=d[s];if(c.getAttribute("src")==t||c.getAttribute("data-webpack")==f+i){a=c;break}}a||(l=!0,(a=document.createElement("script")).type="module",a.charset="utf-8",a.timeout=120,r.nc&&a.setAttribute("nonce",r.nc),a.setAttribute("data-webpack",f+i),a.src=r.tu(t)),e[t]=[n];var u=(_,p)=>{a.onerror=a.onload=null,clearTimeout(b);var h=e[t];if(delete e[t],a.parentNode&&a.parentNode.removeChild(a),h&&h.forEach(y=>y(p)),_)return _(p)},b=setTimeout(u.bind(null,void 0,{type:"timeout",target:a}),12e4);a.onerror=u.bind(null,a.onerror),a.onload=u.bind(null,a.onload),l&&document.head.appendChild(a)}}})(),r.r=e=>{typeof Symbol<"u"&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),(()=>{var e;r.tt=()=>(void 0===e&&(e={createScriptURL:f=>f},typeof trustedTypes<"u"&&trustedTypes.createPolicy&&(e=trustedTypes.createPolicy("angular#bundler",e))),e)})(),r.tu=e=>r.tt().createScriptURL(e),r.p="",(()=>{var e={121:0};r.f.j=(n,i)=>{var o=r.o(e,n)?e[n]:void 0;if(0!==o)if(o)i.push(o[2]);else if(121!=n){var a=new Promise((c,u)=>o=e[n]=[c,u]);i.push(o[2]=a);var l=r.p+r.u(n),d=new Error;r.l(l,c=>{if(r.o(e,n)&&(0!==(o=e[n])&&(e[n]=void 0),o)){var u=c&&("load"===c.type?"missing":c.type),b=c&&c.target&&c.target.src;d.message="Loading chunk "+n+" failed.\n("+u+": "+b+")",d.name="ChunkLoadError",d.type=u,d.request=b,o[1](d)}},"chunk-"+n,n)}else e[n]=0},r.O.j=n=>0===e[n];var f=(n,i)=>{var d,s,[o,a,l]=i,c=0;if(o.some(b=>0!==e[b])){for(d in a)r.o(a,d)&&(r.m[d]=a[d]);if(l)var u=l(r)}for(n&&n(i);c<o.length;c++)r.o(e,s=o[c])&&e[s]&&e[s][0](),e[s]=0;return r.O(u)},t=self.webpackChunkstaffdb=self.webpackChunkstaffdb||[];t.forEach(f.bind(null,0)),t.push=f.bind(null,t.push.bind(t))})()})();

View File

@@ -0,0 +1,30 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
// tslint:disable:no-console
self.addEventListener('install', (event) => {
self.skipWaiting();
});
self.addEventListener('activate', (event) => {
event.waitUntil(self.clients.claim());
event.waitUntil(
self.registration.unregister().then(() => {
console.log('NGSW Safety Worker - unregistered old service worker');
}),
);
event.waitUntil(
caches.keys().then((cacheNames) => {
const ngswCacheNames = cacheNames.filter((name) => /^ngsw:/.test(name));
return Promise.all(ngswCacheNames.map((name) => caches.delete(name)));
}),
);
});

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,77 @@
{
"name": "StaffDB",
"short_name": "StaffDB",
"theme_color": "#1976d2",
"background_color": "#fafafa",
"display": "standalone",
"scope": "./",
"start_url": "./",
"icons": [
{
"src": "assets/icons/production/dhr-icon-16x16.png",
"sizes": "16x16",
"type": "image/png",
"purpose": "maskable any"
},
{
"src": "assets/icons/production/dhr-icon-24x24.png",
"sizes": "24x24",
"type": "image/png",
"purpose": "maskable any"
},
{
"src": "assets/icons/production/dhr-icon-48x48.png",
"sizes": "48x48",
"type": "image/png",
"purpose": "maskable any"
},
{
"src": "assets/icons/production/dhr-icon-72x72.png",
"sizes": "72x72",
"type": "image/png",
"purpose": "maskable any"
},
{
"src": "assets/icons/production/dhr-icon-96x96.png",
"sizes": "96x96",
"type": "image/png",
"purpose": "maskable any"
},
{
"src": "assets/icons/production/dhr-icon-128x128.png",
"sizes": "128x128",
"type": "image/png",
"purpose": "maskable any"
},
{
"src": "assets/icons/production/dhr-icon-144x144.png",
"sizes": "144x144",
"type": "image/png",
"purpose": "maskable any"
},
{
"src": "assets/icons/production/dhr-icon-152x152.png",
"sizes": "152x152",
"type": "image/png",
"purpose": "maskable any"
},
{
"src": "assets/icons/production/dhr-icon-192x192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "maskable any"
},
{
"src": "assets/icons/production/dhr-icon-384x384.png",
"sizes": "384x384",
"type": "image/png",
"purpose": "maskable any"
},
{
"src": "assets/icons/production/dhr-icon-512x512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable any"
}
]
}

View File

@@ -0,0 +1,30 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
// tslint:disable:no-console
self.addEventListener('install', (event) => {
self.skipWaiting();
});
self.addEventListener('activate', (event) => {
event.waitUntil(self.clients.claim());
event.waitUntil(
self.registration.unregister().then(() => {
console.log('NGSW Safety Worker - unregistered old service worker');
}),
);
event.waitUntil(
caches.keys().then((cacheNames) => {
const ngswCacheNames = cacheNames.filter((name) => /^ngsw:/.test(name));
return Promise.all(ngswCacheNames.map((name) => caches.delete(name)));
}),
);
});

View File

@@ -0,0 +1,9 @@
module.exports = {
packages: {
'devextreme-angular': {
ignorableDeepImportMatchers: [
/devextreme\//
]
},
}
};

View File

@@ -0,0 +1,30 @@
{
"$schema": "./node_modules/@angular/service-worker/config/schema.json",
"index": "/index.html",
"assetGroups": [
{
"name": "app",
"installMode": "prefetch",
"resources": {
"files": [
"/assets/icons/hr-logo_color.ico",
"/index.html",
"/webmanifest.json",
"/*.css",
"/*.js"
]
}
},
{
"name": "assets",
"installMode": "lazy",
"updateMode": "prefetch",
"resources": {
"files": [
"/assets/**",
"/*.(svg|cur|jpg|jpeg|png|apng|webp|avif|gif|otf|ttf|woff|woff2)"
]
}
}
]
}

16517
ClientApp/staff-db-ui/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,70 @@
{
"name": "staffdb",
"version": "14.23.33",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"watch": "ng build --watch --configuration development",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e",
"reinstall:packages": "rm -rf node_modules dist && npm cache clean --force && rm package-lock.json && npm install",
"win_reinstall:packages": "rd /s /q node_modules && npm cache clean --force && del package-lock.json && npm install",
"add_pwa": "ng add @angular/pwa@latest"
},
"private": true,
"dependencies": {
"@angular/animations": "^17.3.10",
"@angular/cdk": "^16.2.14",
"@angular/common": "^17.3.10",
"@angular/compiler": "^17.3.10",
"@angular/core": "^17.3.10",
"@angular/forms": "^17.3.10",
"@angular/localize": "^17.3.10",
"@angular/material": "^16.2.14",
"@angular/material-moment-adapter": "^16.2.14",
"@angular/platform-browser": "^17.3.10",
"@angular/platform-browser-dynamic": "^17.3.10",
"@angular/pwa": "^17.3.8",
"@angular/router": "^17.3.10",
"@angular/service-worker": "^17.3.10",
"@ngx-translate/core": "^15.0.0",
"@ngx-translate/http-loader": "^8.0.0",
"@sentry/angular": "^8.4.0",
"angular-in-memory-web-api": "^0.17.0",
"devextreme-angular": "~23.2.6",
"exceljs": "^4.4.0",
"file-saver": "^2.0.5",
"jspdf": "^2.5.1",
"moment": "^2.30.1",
"ngx-clipboard": "^16.0.0",
"ngx-device-detector": "^7.0.0",
"ngx-mask": "^17.0.8",
"ngx-spinner": "^17.0.0",
"ngx-translate-multi-http-loader": "^17.0.0",
"ngx-webcam": "^0.4.1",
"rxjs": "^7.8.1",
"zone.js": "^0.14.6"
},
"devDependencies": {
"@angular-devkit/build-angular": "^17.3.8",
"@angular/cli": "^17.3.8",
"@angular/compiler-cli": "^17.3.10",
"@angular/language-service": "^17.3.10",
"@types/jasmine": "latest",
"@types/node": "latest",
"codelyzer": "latest",
"jasmine-core": "latest",
"jasmine-spec-reporter": "latest",
"karma": "latest",
"karma-chrome-launcher": "latest",
"karma-coverage": "latest",
"karma-jasmine": "latest",
"karma-jasmine-html-reporter": "latest",
"protractor": "latest",
"ts-node": "latest",
"tslint": "latest",
"typescript": "~5.4.5"
}
}

View File

@@ -0,0 +1,7 @@
{
"/api": {
"target": "https://localhost:7202",
"secure": false,
"changeOrigin": true
}
}

View File

@@ -0,0 +1,21 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule, PreloadAllModules } from '@angular/router';
import { APP_PAGES } from '@app_consts';
import { ACCOUNT_PAGE, Globals, LOGIN_PAGE } from '@app_core/services/globals';
ACCOUNT_PAGE.loadChildren = () => import('@app_modules/app-account/app-account.module').then(m => m.AppAccountModule);
const routes: Routes = [
...APP_PAGES,
{
path: '',
redirectTo: '/' + LOGIN_PAGE.path,
pathMatch: 'full'
}
];
@NgModule({
imports: [RouterModule.forRoot(routes, { useHash: true, preloadingStrategy: PreloadAllModules })],
exports: [RouterModule]
})
export class AppRoutingModule { public globals: Globals; }

View File

@@ -0,0 +1,2 @@
<app-layout [title]=globals.appTitleWithVersion></app-layout>
<ngx-spinner type="ball-clip-rotate"> </ngx-spinner>

View File

@@ -0,0 +1,27 @@
import { TestBed, async } from '@angular/core/testing';
import { AppComponent } from './app.component';
describe('AppComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
AppComponent
],
}).compileComponents();
}));
it('should create the app', async(() => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance;
expect(app).toBeTruthy();
}));
it(`should have as title 'staffdb'`, async(() => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance;
expect(app.title).toEqual('ang-material');
}));
it('should render title in a h1 tag', async(() => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
const compiled = fixture.debugElement.nativeElement;
expect(compiled.querySelector('h1').textContent).toContain('Welcome to Angular!');
}));
});

View File

@@ -0,0 +1,58 @@
import { Component, inject, OnInit } from '@angular/core';
import { SwUpdate } from '@angular/service-worker';
import * as AppCnst from '@app_consts';
import * as Cnst from '@app_core/consts';
import * as Utils from '@app_core/utils';
import { TranslateService } from '@ngx-translate/core';
import * as AppModule from './app.module';
import { ENVIRONMENT_TOKEN } from '@app_core/injection-tokens';
import { Globals } from '@app_core/services/globals';
import { RepositoryService } from '@app_core/services/http/repository.service';
import { ServerInfoService } from '@app_core/services/serverinfo.service';
import { LocaleService } from '@app_core/services/localization/locale.service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
private environment = inject(ENVIRONMENT_TOKEN);
constructor(
public globals: Globals,
public repository: RepositoryService,
public translate: TranslateService,
private serverInfoService: ServerInfoService,
private localeService: LocaleService,
private updateService: SwUpdate
) {
this.initLangCulture();
globals.appTitle = AppCnst.APP_TITLE;
Utils.setIndexTitle(globals.appTitle);
globals.appTitleWithVersion = `${AppCnst.APP_TITLE} V.${this.environment.appVersion} (${this.environment.appBuild})`;
globals.appPages = AppCnst.APP_PAGES;
globals.mainPage = AppCnst.APP_PAGES[0];
this.serverInfoService.defaultServerInfoVisible = false;
}
private initLangCulture() {
this.translate.addLangs(AppCnst.SUPPORTED_LANGUAGES);
const languageFromBrowser: string = navigator.language.split('-')[0];
const startLanguage: string = Utils.isLanguageSupported(languageFromBrowser, AppCnst.SUPPORTED_LANGUAGES, Cnst.SUPPORTED_LANGUAGES) ? languageFromBrowser : AppCnst.cnst_DefaultLanguage;
const startCulture: string = Utils.isCultureSupported(navigator.language, AppModule.SUPPORTED_CULTURES, Cnst.SUPPORTED_CULTURES) ? navigator.language : AppCnst.cnst_DefaultCulture;
this.localeService.initLocaleLanguage(startCulture, startLanguage);
}
ngOnInit(): void {
this.updateService.checkForUpdate().then((res) => { if (res) { this.updateService.activateUpdate(); window.location.reload(); } });
}
}

View File

@@ -0,0 +1,144 @@
import { AppComponent } from './app.component';
import { BrowserModule } from '@angular/platform-browser';
/* Routing */
import { AppRoutingModule } from './app-routing.module';
/* Angular Material */
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { AngularMaterialModule } from '@app_core/components/angular-material.module';
import { APPICON4LIVE_TOKEN, APPICON4NAVBAR_TOKEN, APPICON4TEST_TOKEN, ENVIRONMENT_TOKEN, IENVIRONMENT, SUPPORTED_CULTURES_TOKEN, SUPPORTED_LANGUAGES_TOKEN } from '@app_core/injection-tokens';
import { NgModule, CUSTOM_ELEMENTS_SCHEMA, Injectable } from '@angular/core';
/* FormsModule */
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
/* Components */
import { LayoutModule } from '@app_core/components/layout/layout.module';
import { NgxSpinnerModule } from 'ngx-spinner';
/* data acess */
import { HttpInterceptorService } from '@app_core/services/http/http-interceptor.service';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
/* Globals */
import { ErrorStateMatcher, ShowOnDirtyErrorStateMatcher } from '@angular/material/core';
import { DxFormModule, DxButtonModule, DxTemplateHost, DxTemplateModule, DxChartModule, DxDataGridModule } from 'devextreme-angular';
import { NgxMaskDirective, NgxMaskPipe, optionsConfig, provideNgxMask } from 'ngx-mask';
import { Router } from '@angular/router';
import { ServiceWorkerModule } from '@angular/service-worker';
import { MessageBoxModule } from '@app_core/components/message-box/message-box.module';
import { ClipboardModule } from 'ngx-clipboard';
/* Localisaton */
import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { LocaleProvider } from '@app_core/services/localization/locale.provider';
import { HenselTranslateService } from '@app_core/services/localization/hensel-translate.service';
import { registerLocaleData } from '@angular/common';
import { loadMessages } from 'devextreme/localization';
import localeDe from '@angular/common/locales/de';
import localeUs from '@angular/common/locales/en';
import localeFr from '@angular/common/locales/fr';
import localeGb from '@angular/common/locales/en-GB';
export const SUPPORTED_CULTURES = ['de-DE', 'en-GB', 'en-US', 'fr-FR'];
registerLocaleData(localeDe, 'de-DE');
registerLocaleData(localeUs, 'en-US');
registerLocaleData(localeFr, 'fr-FR');
registerLocaleData(localeGb, 'en-GB');
import * as deMessages from 'devextreme/localization/messages/de.json';
loadMessages(deMessages);
// import { HammerGestureConfig, HAMMER_GESTURE_CONFIG, HammerModule } from '@angular/platform-browser';
// AoT requires an exported function for factories
// export class MyHammerConfig extends HammerGestureConfig {
// // tslint:disable-next-line:no-angle-bracket-type-assertion
// overrides = <any>{
// swipe: { direction: Hammer.DIRECTION_ALL },
// };
// }
/* Sentry */
import { APP_INITIALIZER, ErrorHandler } from '@angular/core';
import * as Sentry from '@sentry/angular';
import { SUPPORTED_LANGUAGES } from '@app_consts';
import { TranslateLoaderProvider } from '@app_core/services/localization/translation-loader.provider';
import { MAT_FORM_FIELD_DEFAULT_OPTIONS } from '@app_core/components/angular-material-index';
/* important to use mask functionality */
const maskConfig: optionsConfig = {
validation: false,
};
declare const environment: IENVIRONMENT;
declare const appVersion: string;
declare const appBuild: string;
environment['appVersion'] = appVersion;
environment['appBuild'] = appBuild;
@Injectable()
export class SentryErrorHandler implements ErrorHandler {
handleError(error) {
Sentry.captureException(error.originalError || error);
}
}
@NgModule({
declarations: [
AppComponent,
],
imports: [
HttpClientModule,
BrowserModule,
BrowserAnimationsModule,
AngularMaterialModule,
ReactiveFormsModule,
FormsModule,
DxFormModule,
DxTemplateModule,
DxDataGridModule,
DxChartModule,
DxButtonModule,
MessageBoxModule,
ClipboardModule,
NgxSpinnerModule,
NgxMaskDirective,
NgxMaskPipe,
TranslateModule.forRoot({loader: TranslateLoaderProvider}),
ServiceWorkerModule.register('ngsw-worker.js', {
enabled: true, //environment.production,
// Register the ServiceWorker as soon as the application is stable
// or after 30 seconds (whichever comes first).
registrationStrategy: 'registerWhenStable:30000'
}),
LayoutModule,
AppRoutingModule, // must be the last!!!
],
providers: [
DxTemplateHost,
LocaleProvider,
{ provide: ENVIRONMENT_TOKEN, useValue: environment },
{ provide: SUPPORTED_LANGUAGES_TOKEN, useValue: SUPPORTED_LANGUAGES},
{ provide: SUPPORTED_CULTURES_TOKEN, useValue: SUPPORTED_CULTURES},
{ provide: APPICON4TEST_TOKEN, useValue: 'assets/icons/develop/dhr-icon-48x48.png'},
{ provide: APPICON4LIVE_TOKEN, useValue: 'assets/icons/production/dhr-icon-48x48.png'},
{ provide: APPICON4NAVBAR_TOKEN, useValue: 'assets/icons/main_48x48.png'},
{ provide: TranslateService, useClass: HenselTranslateService },
{ provide: HTTP_INTERCEPTORS, useClass: HttpInterceptorService, multi: true },
{ provide: MAT_FORM_FIELD_DEFAULT_OPTIONS, useValue: { floatLabel: 'auto' } },
{ provide: ErrorStateMatcher, useClass: ShowOnDirtyErrorStateMatcher },
/* Sentry */
{ provide: ErrorHandler, useClass: SentryErrorHandler/*, useValue: Sentry.createErrorHandler({showDialog: false, })*/ },
{ provide: Sentry.TraceService, deps: [Router] },
{ provide: APP_INITIALIZER, useFactory: () => () => {}, deps: [Sentry.TraceService], multi: true },
provideNgxMask(maskConfig)
],
bootstrap: [AppComponent],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule { }

View File

@@ -0,0 +1,19 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { AppAccountComponent } from './app-account.component';
import { AuthGuard } from '@app_core/services/authguard';
const routes: Routes = [
{
path: '',
component: AppAccountComponent,
canActivate: [AuthGuard]
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class AppAccountRoutingModule { }

View File

@@ -0,0 +1,22 @@
<app-account>
<div profile-settings></div>
<div admin-settings>
<hensel-selection
id="input-WebApp"
class="input-webapp"
[dataSource]=appDataService.webAppList.items
placeholder="Webapp"
keyExpr="entityId"
displayExpr="webAppName"
sortField="*"
[multiSelect]=true
separator=","
(selectedItemsChange)="webAppIdList=$event">
</hensel-selection>
<button mat-button (click)="onClick()" class="btn">
<mat-icon>autorenew</mat-icon>
Synchronize WebAppRole mit ADGroupen
</button>
</div>
<div other-settings></div>
</app-account>

View File

@@ -0,0 +1,9 @@
.input-webapp{
float: left;
}
.btn{
margin-left: 10px;
margin-top: 8px;
}

View File

@@ -0,0 +1,16 @@
import { Component, inject } from '@angular/core';
import { AccountComponent } from '@app_core/components/account/account.component';
import { AppDataService } from '@app_services/app.data.service';
@Component({
selector: 'app-account-ext',
templateUrl: 'app-account.component.html',
styleUrls: ['app-account.component.scss']
})
export class AppAccountComponent extends AccountComponent {
public appDataService = inject(AppDataService);
onClick() {
}
}

View File

@@ -0,0 +1,29 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { TranslateModule } from '@ngx-translate/core';
import { DxDataGridModule } from 'devextreme-angular';
import { DxoSearchPanelModule } from 'devextreme-angular/ui/nested';
import { AppAccountRoutingModule } from './app-account-routing.module';
import { AppAccountComponent } from './app-account.component';
import { AccountModule } from '@app_core/components/account/account.module';
import { AngularMaterialModule } from '@app_core/components/angular-material.module';
import { HenselSelectionComponent } from '@app_core/components/hensel-selection/hensel-selection.component';
@NgModule({
declarations: [AppAccountComponent],
imports: [
CommonModule,
AppAccountRoutingModule, //must be earlier AccountModule
AccountModule,
AngularMaterialModule,
ReactiveFormsModule,
FormsModule,
DxDataGridModule,
DxoSearchPanelModule,
HenselSelectionComponent,
TranslateModule
]
})
export class AppAccountModule { }

View File

@@ -0,0 +1,181 @@
import { Injectable } from '@angular/core';
import { cnst_LoadedEntitiesExpiresInMs, EN_AppEntities, EN_AppPages, EN_HttpQueriesCount4Page } from '@app_consts';
import { CoreUser } from '@app_core/models/coreuser';
import { RepositoryService } from '@app_core/services/http/repository.service';
import { CorePageService } from '@app_core/services/page.service';
import { Department, DepartmentFilter } from '@app_models/basedata/department';
import { DocumentArtToDepartment } from '@app_models/documentart-to-department';
import { Employee } from '@app_models/employee';
import { User } from '@app_models/user';
import { WindreamIndex } from '@app_models/windream-index';
import { WindreamIndexToWindreamSearchToDepartment } from '@app_models/windream-index-to-windream-search-to-department';
import { ClientIdFilter, WindreamSearch } from '@app_models/windream-search';
import { WindreamSearchItem } from '@app_models/windream-search-item';
import { WindreamSearchItemToWindreamSearchToDepartment } from '@app_models/windream-search-item-to-windream-search-to-department';
import { WindreamSearchToDepartment, WindreamSearchToDepartmentFilter } from '@app_models/windream-search-to-department';
import { AppBaseEntityWrapper } from '@app_services/app.baseentity.wrapper';
import { AppBaseEntityListWrapper } from '@app_services/app.baseentitylist.wrapper';
@Injectable({ providedIn: 'root' })
export class DepartmentDataService extends CorePageService {
protected appPage: EN_AppPages = EN_AppPages.Department;
protected loadImedeately: boolean = true; //load on pening the page
protected get appPageNoQueries() { return EN_HttpQueriesCount4Page.Department; }
// --- running data
departmentFilter: DepartmentFilter = new DepartmentFilter('DepartmentFullFilter');
departmentList: AppBaseEntityListWrapper<Department> = new AppBaseEntityListWrapper<Department>(Department, 'Abteilungsliste', EN_AppEntities.Department);
departmentDetails: AppBaseEntityWrapper<Department>;
windreamSearchToDepartmentDetails: AppBaseEntityWrapper<WindreamSearchToDepartment>;
// tslint:disable-next-line: max-line-length
windreamSearchToDepartmentList: AppBaseEntityListWrapper<WindreamSearchToDepartment> = new AppBaseEntityListWrapper<WindreamSearchToDepartment>(WindreamSearchToDepartment, 'Windream Suche Kacheln', EN_AppEntities.WindreamSearchToDepartment);
windreamSearchToDepartmentFilter: WindreamSearchToDepartmentFilter = new WindreamSearchToDepartmentFilter('DepartmentFilter');
// tslint:disable-next-line: max-line-length
windreamSearchItemToWindreamSearchToDepartmentList: AppBaseEntityListWrapper<WindreamSearchItemToWindreamSearchToDepartment> = new AppBaseEntityListWrapper<WindreamSearchItemToWindreamSearchToDepartment>(WindreamSearchItemToWindreamSearchToDepartment, 'Windream Suchbausteine', EN_AppEntities.WindreamSearchItemToWindreamSearchToDepartment);
windreamSearchItemToWindreamSearchToDepartmentFilter: WindreamSearchToDepartmentFilter = new WindreamSearchToDepartmentFilter('WindreamSearchToDepartmentFilter');
windreamSearchItemToWindreamSearchToDepartmentDetails: AppBaseEntityWrapper<WindreamSearchItemToWindreamSearchToDepartment>;
windreamSearchItemList: AppBaseEntityListWrapper<WindreamSearchItem> = new AppBaseEntityListWrapper<WindreamSearchItem>(WindreamSearchItem, 'windream suche kacheln attribute', EN_AppEntities.WindreamSearchItem);
windreamIndexToWindreamSearchToDepartmentDetails: AppBaseEntityWrapper<WindreamIndexToWindreamSearchToDepartment>;
// tslint:disable-next-line: max-line-length
windreamIndexToWindreamSearchToDepartmentList: AppBaseEntityListWrapper<WindreamIndexToWindreamSearchToDepartment> = new AppBaseEntityListWrapper<WindreamIndexToWindreamSearchToDepartment>(WindreamIndexToWindreamSearchToDepartment, 'Ausgabespalten für Windream Suche', EN_AppEntities.WindreamIndexToWindreamSearchToDepartment);
windreamIndexToWindreamSearchToDepartmentFilter: WindreamSearchToDepartmentFilter = new WindreamSearchToDepartmentFilter('WindreamSearchToDepartmentFilter');
windreamSearchList: AppBaseEntityListWrapper<WindreamSearch> =
new AppBaseEntityListWrapper<WindreamSearch>(WindreamSearch, 'Windream Suche Kacheln', EN_AppEntities.WindreamSearch);
clientIdFilter: ClientIdFilter = new ClientIdFilter('ClientIdFilter');
windreamIndexList: AppBaseEntityListWrapper<WindreamIndex> =
new AppBaseEntityListWrapper<WindreamIndex>(WindreamIndex, 'Windream Index', EN_AppEntities.WindreamIndex);
documentArtToDepartmentListFilter: DepartmentFilter = new DepartmentFilter('DepartmentFilter');
documentArtToDepartmentList: AppBaseEntityListWrapper<DocumentArtToDepartment> =
new AppBaseEntityListWrapper<DocumentArtToDepartment>(DocumentArtToDepartment, 'Dokumentartenliste für Department', EN_AppEntities.DocumentArtToDepartment);
employeeList: AppBaseEntityListWrapper<Employee> = new AppBaseEntityListWrapper<Employee>(Employee, 'mitarbeiter', EN_AppEntities.Employee + '/all');
selectedDocumentarts: number[] = [];
clpbrdWindreamOutColHint1: string;
clpbrdWindreamOutColHints: string;
clpbrdWindreamOutColList: WindreamIndexToWindreamSearchToDepartment[] = [];
clpbrdWindreamSearchItemHint1: string;
clpbrdWindreamSearchItemHints: string;
clpbrdWindreamSearchItemList: WindreamSearchItemToWindreamSearchToDepartment[] = [];
constructor(
private repositoryService: RepositoryService,
) {
super();
this.departmentList.focusedCallBack = this.focusCallBack.bind(this);
this.departmentList.filter = this.departmentFilter;
this.departmentDetails = this.departmentList.createFocusedShadowEntity(AppBaseEntityWrapper.EN_ViewMode);
this.departmentDetails.loadedDataExpiresInMs = cnst_LoadedEntitiesExpiresInMs;
this.baseEntityWrapperWaitLoading = this.departmentDetails;
this.activateRouting4EntityList(this.departmentList); //we are using routing
this.windreamSearchToDepartmentList.filter = this.windreamSearchToDepartmentFilter;
this.windreamSearchToDepartmentDetails = this.windreamSearchToDepartmentList.createFocusedShadowEntity();
this.windreamSearchToDepartmentDetails.dontLoadEntity = true;
this.windreamSearchToDepartmentDetails.beforeNewCallBack = this.prepareSearchToDepartment.bind(this);
this.windreamIndexToWindreamSearchToDepartmentList.filter = this.windreamIndexToWindreamSearchToDepartmentFilter;
this.windreamIndexToWindreamSearchToDepartmentDetails = this.windreamIndexToWindreamSearchToDepartmentList.createFocusedShadowEntity();
this.windreamIndexToWindreamSearchToDepartmentDetails.dontLoadEntity = true;
this.windreamSearchItemToWindreamSearchToDepartmentList.filter = this.windreamSearchItemToWindreamSearchToDepartmentFilter;
this.windreamSearchItemToWindreamSearchToDepartmentDetails = this.windreamSearchItemToWindreamSearchToDepartmentList.createFocusedShadowEntity();
this.windreamSearchItemToWindreamSearchToDepartmentDetails.dontLoadEntity = true;
this.windreamSearchList.filter = this.clientIdFilter;
this.windreamIndexList.filter = this.clientIdFilter;
this.windreamSearchItemList.filter = this.clientIdFilter;
this.documentArtToDepartmentList.filter = this.documentArtToDepartmentListFilter;
this.departmentDetails.detailItems.register(this.windreamSearchToDepartmentList, null, 'departmentId');
this.departmentDetails.detailItems.register(this.documentArtToDepartmentList, null, 'departmentId', (docarts: DocumentArtToDepartment[]) => {
this.selectedDocumentarts = docarts.map(docart => docart.documentArtId);
});
this.windreamSearchToDepartmentDetails.detailItems.register(this.windreamIndexToWindreamSearchToDepartmentList, null, 'windreamSearchToDepartmentId');
this.windreamSearchToDepartmentDetails.detailItems.register(this.windreamSearchItemToWindreamSearchToDepartmentList, null, 'windreamSearchToDepartmentId');
this.loadBaseData();
this.init();
}
loadData() {
super.loadData();
this.departmentList.load(null, null, () => this.pageLoadingService.updatePageLoadedCounters(this.appPage));
}
public loadBaseData() {
super.loadBaseData(this.appPage, 1);
this.employeeList.load(null, null, () => this.pageLoadingService.updatePageLoadedCounters(this.appPage));
}
public focusCallBack(focusedItem: Department) {
this.clientIdFilter.clientId = focusedItem?.clientId;
}
public clearData() {
super.clearData();
this.departmentFilter.filterReset();
this.departmentList.clear();
}
protected onLoggedInOut(user: CoreUser) {
this.userChanged(new User(user));
super.onLoggedInOut(user);
}
private userChanged(user: User) {
if (this.authService.isLoggedIn()) {
this.departmentDetails.canNew = user.isMaster;
this.departmentDetails.canEdit = this.departmentDetails.canNew;
this.departmentDetails.canDelete = this.departmentDetails.canNew;
}
}
moveUpDown(direction: number,
list:
AppBaseEntityListWrapper<WindreamSearchToDepartment>
| AppBaseEntityListWrapper<WindreamSearchItemToWindreamSearchToDepartment>
| AppBaseEntityListWrapper<WindreamIndexToWindreamSearchToDepartment>
) {
const curItemIndex: number = list.focusedItemIndex;
if (!(direction < 0 && curItemIndex === 0 || direction > 0 && curItemIndex === list.items.length)) {
const targetItem = list.items[curItemIndex + direction];
const targetSeq: number = targetItem.seq;
const currentItem = list.focusedItem;
targetItem.seq = currentItem.seq;
currentItem.seq = targetSeq;
targetItem.entityChanged = true;
currentItem.entityChanged = true;
targetItem.save(this.repositoryService, null, null, null);
currentItem.save(this.repositoryService, null, null, null);
this.sortBySeq(list.items);
}
}
public sortBySeq(list: WindreamSearchToDepartment[] | WindreamSearchItemToWindreamSearchToDepartment[] | WindreamIndexToWindreamSearchToDepartment[]) {
list.sort((fp1, fp2) => (fp1.seq - fp2.seq));
}
prepareSearchToDepartment(item: WindreamSearchToDepartment) {
const maxSeq = this.windreamSearchToDepartmentList.items.reduce<number>((max: number, _index: WindreamSearchToDepartment) => max > _index.seq ? max : _index.seq, 0);
item.seq = maxSeq + 1;
item.isActive = true;
}
}

View File

@@ -0,0 +1,100 @@
<form class="departmentDetailsContent" #detailForm="ngForm">
<hensel-input
class="input-departmentName"
name="departmentName"
placeholder="Abteilungsname"
maxlength="50"
required
[(ngModel)]=department.departmentName
[disabled]="!departmentDetails.inNewEditMode"
(blur)=depNameWasChanged()>
</hensel-input>
<hensel-selection
name="costcentre"
class="input-cost-centre"
[dataSource]=costCentreList
placeholder="CostCentre"
keyExpr="entityId"
displayExpr="costCentreName"
sortField="*" required
[multiSelect]=false
[(selectedItems)]="department.costCentreId"
[disabled]="!departmentDetails.inNewEditMode">
</hensel-selection>
<hensel-input
class="input-departmentType"
name="Type Id"
placeholder="Abteilungstyp"
maxlength="50"
department
[(ngModel)]=department.departmentTypeId
[disabled]="!departmentDetails.inNewEditMode">
</hensel-input>
<hensel-selection
name="headofDepartmentId"
class="input-headofDepartmentId"
[dataSource]=employeeList
placeholder="Abteilungsleiter"
keyExpr="entityId"
displayExpr="fullname"
sortField="*"
[multiSelect]=false
[(selectedItems)]="department.headofDepartmentId"
[disabled]="!departmentDetails.inNewEditMode">
</hensel-selection>
<hensel-selection
name="executiveDirectorId"
class="input-executiveDirectorId"
[dataSource]=employeeList
placeholder="CEO"
keyExpr="entityId"
displayExpr="fullname"
sortField="*"
[multiSelect]=false
[(selectedItems)]="department.executiveDirectorId"
[disabled]="!departmentDetails.inNewEditMode">
</hensel-selection>
<hensel-selection
name="managingDirectorId"
class="input-managingDirectorId"
[dataSource]=employeeList
placeholder="COO"
keyExpr="entityId"
displayExpr="fullname"
sortField="*"
[multiSelect]=false
[(selectedItems)]="department.managingDirectorId"
[disabled]="!departmentDetails.inNewEditMode">
</hensel-selection>
<hensel-input
class="input-departmentNameFolder"
name="departmentNameFolder"
placeholder="Folder"
maxlength="50"
required
[(ngModel)]=department.departmentNameFolder
[disabled]="!departmentDetails.inNewEditMode">
</hensel-input>
<hensel-input
class="input-adGroupDepartmentName"
name="adGroupDepartmentName"
placeholder="AD-Group Name"
maxlength="50"
required
[(ngModel)]=department.adGroupDepartmentName
[disabled]="!departmentDetails.inNewEditMode">
</hensel-input>
<hensel-input
class="input-clientId"
name="clientId"
placeholder="Client Id"
maxlength="50"
required
[(ngModel)]=department.clientId
[disabled]="!departmentDetails.inNewEditMode">
</hensel-input>
<mat-checkbox class="input-isVirtual check-box" name="Enabled" style="float: left; margin-top: auto; margin-bottom: 12px;" labelPosition="before"
[(ngModel)]=department.isVirtual inactive [disabled]="!departmentDetails.inNewEditMode">
Virtual
</mat-checkbox>
</form>

View File

@@ -0,0 +1,52 @@
.departmentDetailsContent{
// z-index: 10;
// position: relative; //otherwise z-index is not working
padding: 0 0 0 0; // no extra padding -> padding is calculated in the child comp
margin: 0; // see above
overflow: hidden; // overflow hidden => all "to big" child components are hidden
display: grid; // we define a grid
width: 100%; // 100 % view width (hardware screen)
height: 100%; // 100% view height
grid-column-gap: 8px;
grid-template-columns: repeat(2, minmax(1px, 1fr)); // column relationship
grid-template-rows: repeat(5, 1fr); // auto auto auto auto auto auto auto auto auto; // row relationships
grid-template-areas:
"input-departmentName input-cost-centre"
"input-departmentType input-headofDepartmentId"
"input-executiveDirectorId input-managingDirectorId"
"input-departmentNameFolder input-adGroupDepartmentName"
"input-clientId input-isVirtual"
;
}
.input-departmentName{
grid-area: input-departmentName;
}
.input-cost-centre{
grid-area: input-cost-centre;
}
.input-departmentType{
grid-area: input-departmentType;
}
.input-headofDepartmentId{
grid-area: input-headofDepartmentId;
}
.input-executiveDirectorId{
grid-area: input-executiveDirectorId;
}
.input-managingDirectorId{
grid-area: input-managingDirectorId;
}
.input-departmentNameFolder{
grid-area: input-departmentNameFolder;
}
.input-adGroupDepartmentName{
grid-area: input-adGroupDepartmentName;
}
.input-clientId{
grid-area: input-clientId;
}
.input-isVirtual{
grid-area: input-isVirtual;
}

View File

@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { DepartmentContentComponent } from './department-content.component';
describe('DepartmentContentComponent', () => {
let component: DepartmentContentComponent;
let fixture: ComponentFixture<DepartmentContentComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ DepartmentContentComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(DepartmentContentComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,53 @@
import { Component, Input, OnInit, ViewChild, AfterViewInit } from '@angular/core';
import { Department } from '@app_models/basedata/department';
import { AppBaseEntityWrapper } from '@app_services/app.baseentity.wrapper';
import { AppDataService } from '@app_services/app.data.service';
import { CostCentre } from '@app_models/basedata/cost-centre';
import { Employee } from '@app_models/employee';
import { EmployeeDataService } from '@app_modules/employee/employee-data.service';
import { DepartmentDataService } from '@app_modules/department/department-data.service';
import { NgForm } from '@angular/forms';
@Component({
selector: 'app-department-content',
templateUrl: './department-content.component.html',
styleUrls: ['./department-content.component.scss']
})
export class DepartmentContentComponent implements OnInit, AfterViewInit {
@ViewChild('detailForm') detailForm: NgForm;
@Input() departmentDetails: AppBaseEntityWrapper<Department>;
public get department(): Department {
return this.departmentDetails.entity;
}
public get employeeList(): Employee[] {
return this.departmentService.employeeList.items;
}
public get costCentreList(): CostCentre[] {
return this.appDataService.costCentreList.items;
}
constructor(
private appDataService: AppDataService,
private departmentService: DepartmentDataService) { }
ngOnInit() {
}
ngAfterViewInit(): void {
this.departmentDetails.detailForm = this.detailForm;
}
depNameWasChanged() {
if (!this.department.departmentName) return;
if (!this.department.departmentNameFolder) this.department.departmentNameFolder = this.department.departmentName;
if (!this.department.adGroupDepartmentName) this.department.adGroupDepartmentName = this.department.departmentName;
}
}

View File

@@ -0,0 +1,59 @@
<form class="DepartmentDetailsForm" #detailForm="ngForm" id="form_department">
<mat-card class="card">
<mat-card-header>
</mat-card-header>
<mat-card-content class="DepartmentDetails">
<section class="toolbar">
<div class="toolbar-button-row">
<button *ngIf="departmentDetails.canNew" #btnNew id="btnNew" name="btnNew" class="abstand" mat-stroked-button
title="Neue Abteilung" (click)="departmentDetails.new()"
[disabled]="!departmentDetails.enabledNewButton()">
<mat-icon>add</mat-icon> Hinzufügen
</button>
<button *ngIf="departmentDetails.canEdit" #btnEdit id="btnEdit" name="btnEdit" class="abstand" mat-stroked-button
title="Bearbeiten" (click)="departmentDetails.edit()"
[disabled]="!departmentDetails.enabledEditButton()">
<mat-icon>edit</mat-icon> Bearbeiten
</button>
<button *ngIf="departmentDetails.canEdit||departmentDetails.canNew" id="btnSave" name="btnSave" class="abstand"
mat-stroked-button disabled title="Speichern" (click)="save()"
[disabled]="!departmentDetails.enabledSaveButton()">
<mat-icon>save</mat-icon> Speichern
</button>
<button *ngIf="departmentDetails.canEdit||departmentDetails.canNew" id="btnUndo" name="btnUndo" class="abstand"
mat-stroked-button disabled title="Änderungen verwerfen" (click)="cancel()" [autofocus]=true
[disabled]="!departmentDetails.enabledCancelButton()">
<mat-icon>undo</mat-icon> Verwerfen
</button>
<button *ngIf="departmentDetails.canDelete" id="btnDelete" name="btnDelete" mat-stroked-button class="abstand"
title="Benutzer löschen" class="last" (click)="departmentDetails.delete()"
[disabled]="!departmentDetails.enabledDeleteButton()">
<mat-icon>delete</mat-icon> Löschen
</button>
</div>
</section>
<app-department-content class="DetailsContent"
[departmentDetails]="departmentDetails">
</app-department-content>
<app-department-documentart class="DocumentArtList" [departmentDetails]=departmentDetails></app-department-documentart>
<app-department-windream-search class="WindreamSearchList"
[windreamSearchList]="windreamSearchList"
[departmentDetails]="departmentDetails">
</app-department-windream-search>
<app-department-windream-search-item class="WindreamSearchItemList"
[windreamSearchItemList]="windreamSearchItemToWindreamSearchToDepartmentList"
[windreamSearchItemDetails]="windreamSearchItemToWindreamSearchToDepartmentDetails"
[windreamSearchToDepartmentDetails]="windreamSearchToDepartmentDetails"
[departmentDetails]="departmentDetails">
</app-department-windream-search-item>
<app-department-windream-index class="WindreamIndexList"
[windreamIndexList]="windreamIndexList"
[windreamIndexDetails]="windreamIndexDetails"
[windreamSearchToDepartmentDetails]="windreamSearchToDepartmentDetails"
[departmentDetails]="departmentDetails">
</app-department-windream-index>
</mat-card-content>
</mat-card>
</form>

View File

@@ -0,0 +1,46 @@
.DepartmentDetails {
padding: 0 0 0; // no extra padding -> padding is calculated in the child comp
margin: 0; // see above
overflow: hidden; // overflow hidden => all "to big" child components are hidden
display: grid; // we define a grid
width: 100%; // 100 % view width (hardware screen)
height: 100%; // 100% view height
grid-template-rows: auto repeat(1, minmax(1px, 250px)); // row relationships
grid-template-columns: minmax(1px, 0.7fr) minmax(1px, 0.7fr) minmax(1px, 0.5fr) minmax(1px, 0.5fr) minmax(1px, 1fr); // column relationship
grid-row-gap: 6px;
grid-column-gap: 10px;
grid-template-areas:
'toolbar toolbar toolbar toolbar toolbar'
'detail documentArtList windreamSearchList windreamSearchItemList windreamIndexList';
z-index: 10;
position: relative; //otherwise z-index is not working
}
.WindreamSearchItemList{
grid-area: windreamSearchItemList;
}
.WindreamIndexList{
grid-area: windreamIndexList;
}
.WindreamSearchList{
grid-area: windreamSearchList;
}
.DetailsContent {
grid-area: detail;
}
.DocumentArtList {
grid-area: documentArtList;
}
.abstand {
margin-right: 1px !important;
}
.toolbar {
grid-area: toolbar;
}
.card {
padding: 12px;
margin: 2px 2px 2px 2px;
}

View File

@@ -0,0 +1,109 @@
import { Component, OnInit, Input, ChangeDetectorRef, DoCheck, ChangeDetectionStrategy, Output, EventEmitter, ViewChild, ElementRef, AfterViewInit, HostListener } from '@angular/core';
import { AppBaseEntityWrapper } from '@app_services/app.baseentity.wrapper';
import { DepartmentDataService } from '../department-data.service';
import { WindreamSearchToDepartment } from '@app_models/windream-search-to-department';
import { AppBaseEntityListWrapper } from '@app_services/app.baseentitylist.wrapper';
import { WindreamIndexToWindreamSearchToDepartment } from '@app_models/windream-index-to-windream-search-to-department';
import { Department } from '@app_models/basedata/department';
import { WindreamSearchItemToWindreamSearchToDepartment } from '@app_models/windream-search-item-to-windream-search-to-department';
import { WindreamSearchItem } from '@app_models/windream-search-item';
import { NgForm } from '@angular/forms';
import { reduce } from 'rxjs/operators';
import { AuthorizeService } from '@app_core/services/authorize.service';
import { PageLoadingService } from '@app_core/services/pageloading.service';
import { EN_EntityBeforeSaveCallBackResults } from '@app_core/consts';
import { LoginPopupComponent } from '@app_core/components/login/login-popup/login-popup.component';
@Component({
selector: 'app-department-detail',
templateUrl: './department-detail.component.html',
styleUrls: ['./department-detail.component.scss'],
})
export class DepartmentDetailComponent implements AfterViewInit {
@ViewChild('detailForm') detailForm: NgForm;
@Input() public departmentDetails: AppBaseEntityWrapper<Department>;
public get windreamSearchToDepartmentDetails(): AppBaseEntityWrapper<WindreamSearchToDepartment> {
return this.departmentDataService.windreamSearchToDepartmentDetails;
}
constructor(
public departmentDataService: DepartmentDataService,
public authorizeService: AuthorizeService,
private pageLoadingService: PageLoadingService,
) {
}
public get windreamSearchList(): AppBaseEntityListWrapper<WindreamSearchToDepartment> {
return this.departmentDataService.windreamSearchToDepartmentList;
}
public get windreamSearchDetails(): AppBaseEntityWrapper<WindreamSearchToDepartment> {
return this.departmentDataService.windreamSearchToDepartmentDetails;
}
public get windreamSearchItemToWindreamSearchToDepartmentList(): AppBaseEntityListWrapper<WindreamSearchItemToWindreamSearchToDepartment> {
return this.departmentDataService.windreamSearchItemToWindreamSearchToDepartmentList;
}
public get windreamSearchItemToWindreamSearchToDepartmentDetails(): AppBaseEntityWrapper<WindreamSearchItemToWindreamSearchToDepartment> {
return this.departmentDataService.windreamSearchItemToWindreamSearchToDepartmentDetails;
}
public get windreamSearchItemList(): AppBaseEntityListWrapper<WindreamSearchItem> {
return this.departmentDataService.windreamSearchItemList;
}
public get windreamIndexList(): AppBaseEntityListWrapper<WindreamIndexToWindreamSearchToDepartment> {
return this.departmentDataService.windreamIndexToWindreamSearchToDepartmentList;
}
public get windreamIndexDetails(): AppBaseEntityWrapper<WindreamIndexToWindreamSearchToDepartment> {
return this.departmentDataService.windreamIndexToWindreamSearchToDepartmentDetails;
}
public get focusedItem(): Department {
return this.departmentDetails.entity;
}
ngAfterViewInit(): void {
this.departmentDetails.beforeNewCallBack = this.newDepartmentInit.bind(this);
this.departmentDetails.beforeSaveCallBack = this.beforeSaveDepartment.bind(this);
}
newDepartmentInit(department: Department) {
this.departmentDataService.selectedDocumentarts = [];
department.departmentTypeId = 1;
department.clientId = 24110;
}
async beforeSaveDepartment(department: Department): Promise<EN_EntityBeforeSaveCallBackResults> {
const maxId: number = this.departmentDataService.departmentList.items.reduce((max, currentItem) => (currentItem.entityId > max ? currentItem.entityId : max), 0);
if (department.isNew()) department.departmentId = -(maxId + 1);
this.departmentDataService.documentArtToDepartmentList.match2KeysArray(department, 'departmentId', this.departmentDataService.selectedDocumentarts, 'documentArtId');
return EN_EntityBeforeSaveCallBackResults.Ok_Continue;
}
public save = () => { //because of calling as callback of cancel
this.pageLoadingService.startSpinner();
this.departmentDetails.save((department: Department) => this.afterSave(department), null, () => this.pageLoadingService.hideSpinner());
}
afterSave(department: Department) {
// this.departmentDetails.loadDetails(this.catalogDataService.departmentCategoryList);
}
public cancel = () => {
// this.setCurrentMaster4Subdepartment = null;
this.departmentDetails.cancelWithSave(this.save);
}
@HostListener('window:keydown', ['$event'])
keyboardInput(event: any) {
return LoginPopupComponent.LOGIN_IS_SHOWN || this.departmentDetails.shortcutsHandler(event, this.save, this.cancel);
}
}

View File

@@ -0,0 +1,21 @@
<div class="department-documentart">
<label class="label"></label>
<hensel-selection
id="documentarts"
class="documentart"
name="documentarts"
[dataSource]=appDataService.documentArtList.items
placeholder="Dokumentenart"
keyExpr="documentArtId"
displayTemplate="${name} (${shortname})"
sortField="*"
[multiSelect]=true
[customFilter]="'clientId='+departmentDetails.entity.clientId"
separator=","
[(selectedItems)]="departmentDataService.selectedDocumentarts"
(selectedItemsChange)="departmentDetails.entityWasChanged = true"
[disabled]=!departmentDetails.inNewEditMode
[height]="'100%'"
[useResultGrid]=true>
</hensel-selection>
</div>

View File

@@ -0,0 +1,19 @@
.department-documentart {
width: 100%;
height: 100%;
display: grid;
grid-template-columns: minmax(0, 1fr); // column relationship
grid-template-rows: 0 minmax(1px, 1fr); // auto auto auto auto auto auto auto auto auto; // row relationships
grid-template-areas: "label" "attributes";
}
.documentart {
grid-area: attributes;
height: 100%;
width: 100%;
}
.label {
grid-area: label;
}

View File

@@ -0,0 +1,28 @@
import { Component, OnInit, Input } from '@angular/core';
import { AppBaseEntityWrapper } from '@app_services/app.baseentity.wrapper';
import { AppDataService } from '@app_services/app.data.service';
import { Department } from '@app_models/basedata/department';
import { DepartmentDataService } from '@app_modules/department/department-data.service';
@Component({
selector: 'app-department-documentart',
templateUrl: './department-documentart.component.html',
styleUrls: ['./department-documentart.component.scss']
})
export class DepartmentDocumentartsComponent implements OnInit {
@Input() public departmentDetails: AppBaseEntityWrapper<Department>;
constructor(
public appDataService: AppDataService,
public departmentDataService: DepartmentDataService,
) {
}
ngOnInit() {
}
}

View File

@@ -0,0 +1,35 @@
<form class="PopupContainer" #popupForm="ngForm">
<!-- <dx-button class="buttonLayoutCancel" icon="close" (click)="close()"></dx-button> -->
<h2 mat-dialog-title class="messageBoxHeader">{{description}} - {{keyItemName}} </h2>
<mat-dialog-content class="PopupContent">
<div class="buttons">
<button id="btnSave" name="btnSave" class="btnSave" mat-stroked-button
[disabled]="!baseEntityWrapper.enabledSaveButton() || readOnly" (click)="save() ">
<mat-icon>save</mat-icon> Übernehmen
</button>
<button #btnCancel id="btnCancel" name="btnCancel" class="btnCancel" mat-stroked-button (click)="cancel()">
<mat-icon>cancel</mat-icon> Abbrechen
</button>
</div>
<hensel-selection
#input_windreamIndex
id="input-windreamIndex"
class="input-windreamIndex"
[dataSource]=windreamIndexList
placeholder="Ausgabespalte"
keyExpr="entityId"
displayExpr="selectionName"
sortField="*"
[multiSelect]=true
separator=","
[(selectedItems)]="windreamIndexIds"
[disabled]="readOnly || focusedItem.entityId !== 0"
[customFilterFn]="focusedItem.entityId === 0? getNotUsedwindreamIndexes: ''"
[showSpinner]=this.departmentDataService.windreamIndexList.isLoading
required>
</hensel-selection>
</mat-dialog-content>
</form>

View File

@@ -0,0 +1,24 @@
@import 'popup-base.component';
.PopupContent {
padding: 0 0 0; // no extra padding -> padding is calculated in the child comp
margin: 0; // see above
overflow: hidden; // overflow hidden => all "to big" child components are hidden
display: grid; // we define a grid: ;
height: 100%; // 100% view height
grid-template-rows: auto auto; // row relationships
grid-template-columns: repeat(2, minmax(0, 1fr)); // column relationship
grid-column-gap: 15px;
grid-row-gap: 15px;
grid-template-areas:
'input-windreamSearch .'
'buttons buttons'
}
.input-windreamSearch {
grid-area: input-windreamSearch;
}
.input-seq {
grid-area: input-seq;
}

Some files were not shown because too many files have changed in this diff Show More