Quellcode durchsuchen

code base copy

master
Daniel vor 2 Jahren
Ursprung
Commit
be8c722eb7
100 geänderte Dateien mit 15444 neuen und 0 gelöschten Zeilen
  1. +1
    -0
      .gitignore
  2. +12
    -0
      plp-angular/.browserslistrc
  3. +13
    -0
      plp-angular/.editorconfig
  4. +49
    -0
      plp-angular/.gitignore
  5. +84
    -0
      plp-angular/.htaccess
  6. +1
    -0
      plp-angular/.htpasswd
  7. +27
    -0
      plp-angular/README.md
  8. +149
    -0
      plp-angular/angular.json
  9. +32
    -0
      plp-angular/e2e/protractor.conf.js
  10. +23
    -0
      plp-angular/e2e/src/app.e2e-spec.ts
  11. +11
    -0
      plp-angular/e2e/src/app.po.ts
  12. +13
    -0
      plp-angular/e2e/tsconfig.json
  13. +32
    -0
      plp-angular/karma.conf.js
  14. +12215
    -0
      plp-angular/package-lock.json
  15. +58
    -0
      plp-angular/package.json
  16. +39
    -0
      plp-angular/src/app/app-routing.module.ts
  17. +16
    -0
      plp-angular/src/app/app.component.html
  18. +0
    -0
      plp-angular/src/app/app.component.scss
  19. +53
    -0
      plp-angular/src/app/app.component.ts
  20. +151
    -0
      plp-angular/src/app/app.module.ts
  21. +158
    -0
      plp-angular/src/app/components/ag-grid-component-const.ts
  22. +466
    -0
      plp-angular/src/app/components/ag-grid-component.ts
  23. +9
    -0
      plp-angular/src/app/components/aside/aside.component.html
  24. +0
    -0
      plp-angular/src/app/components/aside/aside.component.scss
  25. +37
    -0
      plp-angular/src/app/components/aside/aside.component.ts
  26. +3
    -0
      plp-angular/src/app/components/calendar-legend/calendar-legend.component.html
  27. +0
    -0
      plp-angular/src/app/components/calendar-legend/calendar-legend.component.scss
  28. +34
    -0
      plp-angular/src/app/components/calendar-legend/calendar-legend.component.ts
  29. +37
    -0
      plp-angular/src/app/components/form-component.ts
  30. +18
    -0
      plp-angular/src/app/components/message/message.component.html
  31. +0
    -0
      plp-angular/src/app/components/message/message.component.scss
  32. +141
    -0
      plp-angular/src/app/components/message/message.component.ts
  33. +8
    -0
      plp-angular/src/app/components/modal/modal.component.html
  34. +0
    -0
      plp-angular/src/app/components/modal/modal.component.scss
  35. +79
    -0
      plp-angular/src/app/components/modal/modal.component.ts
  36. +3
    -0
      plp-angular/src/app/components/tab/tab.component.html
  37. +0
    -0
      plp-angular/src/app/components/tab/tab.component.scss
  38. +21
    -0
      plp-angular/src/app/components/tab/tab.component.ts
  39. +10
    -0
      plp-angular/src/app/components/tabs/tabs.component.html
  40. +0
    -0
      plp-angular/src/app/components/tabs/tabs.component.scss
  41. +99
    -0
      plp-angular/src/app/components/tabs/tabs.component.ts
  42. +186
    -0
      plp-angular/src/app/factory/factory.ts
  43. +1
    -0
      plp-angular/src/app/grid-cellrenderer/grid-blocked/grid-blocked-editor/grid-blocked-editor.component.html
  44. +1
    -0
      plp-angular/src/app/grid-cellrenderer/grid-blocked/grid-blocked-editor/grid-blocked-editor.component.scss
  45. +19
    -0
      plp-angular/src/app/grid-cellrenderer/grid-blocked/grid-blocked-editor/grid-blocked-editor.component.ts
  46. +1
    -0
      plp-angular/src/app/grid-cellrenderer/grid-blocked/grid-blocked-renderer/grid-blocked-renderer.component.html
  47. +0
    -0
      plp-angular/src/app/grid-cellrenderer/grid-blocked/grid-blocked-renderer/grid-blocked-renderer.component.scss
  48. +21
    -0
      plp-angular/src/app/grid-cellrenderer/grid-blocked/grid-blocked-renderer/grid-blocked-renderer.component.ts
  49. +9
    -0
      plp-angular/src/app/grid-cellrenderer/grid-cell-editor-params.ts
  50. +8
    -0
      plp-angular/src/app/grid-cellrenderer/grid-cell-params.ts
  51. +3
    -0
      plp-angular/src/app/grid-cellrenderer/grid-checkbox/grid-checkbox-editor/grid-checkbox-editor.component.html
  52. +0
    -0
      plp-angular/src/app/grid-cellrenderer/grid-checkbox/grid-checkbox-editor/grid-checkbox-editor.component.scss
  53. +41
    -0
      plp-angular/src/app/grid-cellrenderer/grid-checkbox/grid-checkbox-editor/grid-checkbox-editor.component.ts
  54. +8
    -0
      plp-angular/src/app/grid-cellrenderer/grid-checkbox/grid-checkbox-renderer/grid-checkbox-renderer.component.html
  55. +0
    -0
      plp-angular/src/app/grid-cellrenderer/grid-checkbox/grid-checkbox-renderer/grid-checkbox-renderer.component.scss
  56. +34
    -0
      plp-angular/src/app/grid-cellrenderer/grid-checkbox/grid-checkbox-renderer/grid-checkbox-renderer.component.ts
  57. +1
    -0
      plp-angular/src/app/grid-cellrenderer/grid-date/grid-date-editor/grid-date-editor.component.html
  58. +0
    -0
      plp-angular/src/app/grid-cellrenderer/grid-date/grid-date-editor/grid-date-editor.component.scss
  59. +12
    -0
      plp-angular/src/app/grid-cellrenderer/grid-date/grid-date-editor/grid-date-editor.component.ts
  60. +1
    -0
      plp-angular/src/app/grid-cellrenderer/grid-date/grid-date-renderer/grid-date-renderer.component.html
  61. +0
    -0
      plp-angular/src/app/grid-cellrenderer/grid-date/grid-date-renderer/grid-date-renderer.component.scss
  62. +27
    -0
      plp-angular/src/app/grid-cellrenderer/grid-date/grid-date-renderer/grid-date-renderer.component.ts
  63. +82
    -0
      plp-angular/src/app/grid-cellrenderer/grid-editor-component.ts
  64. +20
    -0
      plp-angular/src/app/grid-cellrenderer/grid-factory.ts
  65. +1
    -0
      plp-angular/src/app/grid-cellrenderer/grid-input/grid-input-editor/grid-input-editor.component.html
  66. +0
    -0
      plp-angular/src/app/grid-cellrenderer/grid-input/grid-input-editor/grid-input-editor.component.scss
  67. +107
    -0
      plp-angular/src/app/grid-cellrenderer/grid-input/grid-input-editor/grid-input-editor.component.ts
  68. +1
    -0
      plp-angular/src/app/grid-cellrenderer/grid-input/grid-input-renderer/grid-input-renderer.component.html
  69. +0
    -0
      plp-angular/src/app/grid-cellrenderer/grid-input/grid-input-renderer/grid-input-renderer.component.scss
  70. +27
    -0
      plp-angular/src/app/grid-cellrenderer/grid-input/grid-input-renderer/grid-input-renderer.component.ts
  71. +49
    -0
      plp-angular/src/app/grid-cellrenderer/grid-renderer-component.ts
  72. +4
    -0
      plp-angular/src/app/grid-cellrenderer/grid-select/grid-select-editor/grid-select-editor.component.html
  73. +8
    -0
      plp-angular/src/app/grid-cellrenderer/grid-select/grid-select-editor/grid-select-editor.component.scss
  74. +104
    -0
      plp-angular/src/app/grid-cellrenderer/grid-select/grid-select-editor/grid-select-editor.component.ts
  75. +123
    -0
      plp-angular/src/app/grid-cellrenderer/grid-select/grid-select-factory.ts
  76. +4
    -0
      plp-angular/src/app/grid-cellrenderer/grid-select/grid-select-item.ts
  77. +1
    -0
      plp-angular/src/app/grid-cellrenderer/grid-select/grid-select-renderer/grid-select-renderer.component.html
  78. +0
    -0
      plp-angular/src/app/grid-cellrenderer/grid-select/grid-select-renderer/grid-select-renderer.component.scss
  79. +83
    -0
      plp-angular/src/app/grid-cellrenderer/grid-select/grid-select-renderer/grid-select-renderer.component.ts
  80. +0
    -0
      plp-angular/src/app/grid-cellrenderer/grid-text/grid-text-editor/grid-text-editor.component.html
  81. +0
    -0
      plp-angular/src/app/grid-cellrenderer/grid-text/grid-text-editor/grid-text-editor.component.scss
  82. +24
    -0
      plp-angular/src/app/grid-cellrenderer/grid-text/grid-text-editor/grid-text-editor.component.ts
  83. +1
    -0
      plp-angular/src/app/grid-cellrenderer/grid-text/grid-text-renderer/grid-text-renderer.component.html
  84. +0
    -0
      plp-angular/src/app/grid-cellrenderer/grid-text/grid-text-renderer/grid-text-renderer.component.scss
  85. +27
    -0
      plp-angular/src/app/grid-cellrenderer/grid-text/grid-text-renderer/grid-text-renderer.component.ts
  86. +34
    -0
      plp-angular/src/app/interceptor/route-interceptor.ts
  87. +96
    -0
      plp-angular/src/app/lang/ag-gridlocale.ts
  88. +24
    -0
      plp-angular/src/app/model/constants/tools.ts
  89. +5
    -0
      plp-angular/src/app/model/entities/calendar-legend.ts
  90. +5
    -0
      plp-angular/src/app/model/entities/country.ts
  91. +21
    -0
      plp-angular/src/app/model/entities/customer-contact.ts
  92. +6
    -0
      plp-angular/src/app/model/entities/customer-meeting-participant.ts
  93. +24
    -0
      plp-angular/src/app/model/entities/customer-meeting.ts
  94. +22
    -0
      plp-angular/src/app/model/entities/customer-note.ts
  95. +26
    -0
      plp-angular/src/app/model/entities/customer.ts
  96. +6
    -0
      plp-angular/src/app/model/entities/internal-meeting-participant.ts
  97. +9
    -0
      plp-angular/src/app/model/entities/internal-meeting.ts
  98. +6
    -0
      plp-angular/src/app/model/entities/meeting-type.ts
  99. +7
    -0
      plp-angular/src/app/model/entities/user-type.ts
  100. +12
    -0
      plp-angular/src/app/model/entities/user.ts

+ 1
- 0
.gitignore Datei anzeigen

@@ -0,0 +1 @@
/.idea

+ 12
- 0
plp-angular/.browserslistrc Datei anzeigen

@@ -0,0 +1,12 @@
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
# For additional information regarding the format and rule options, please see:
# https://github.com/browserslist/browserslist#queries

# You can see what browsers were selected by your queries by running:
# npx browserslist

> 0.5%
last 2 versions
Firefox ESR
not dead
not IE 9-11 # For IE 9-11 support, remove 'not'.

+ 13
- 0
plp-angular/.editorconfig Datei anzeigen

@@ -0,0 +1,13 @@
# Editor configuration, see https://editorconfig.org
root = true

[*]
charset = utf-8
indent_style = space
indent_size = 4
insert_final_newline = true
trim_trailing_whitespace = true

[*.md]
max_line_length = off
trim_trailing_whitespace = false

+ 49
- 0
plp-angular/.gitignore Datei anzeigen

@@ -0,0 +1,49 @@
# See http://help.github.com/ignore-files/ for more about ignoring files.

# compiled output
/dist
/tmp
/out-tsc
# Only exists if Bazel was run
/bazel-out

# dependencies
/node_modules

# profiling files
chrome-profiler-events*.json
speed-measure-plugin*.json

# IDEs and editors
/.idea
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace

# IDE - VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.history/*

# misc
/.sass-cache
/connect.lock
/coverage
/libpeerconnection.log
npm-debug.log
yarn-error.log
testem.log
/typings

# System Files
.DS_Store
Thumbs.db

# cache etc
/.angular

+ 84
- 0
plp-angular/.htaccess Datei anzeigen

@@ -0,0 +1,84 @@
RewriteEngine on

# Don't rewrite files or directories
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]

# Rewrite everything else to index.html to allow html5 state links
RewriteRule ^ index.html [L]


# Enable Compression
<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE application/javascript
AddOutputFilterByType DEFLATE application/rss+xml
AddOutputFilterByType DEFLATE application/vnd.ms-fontobject
AddOutputFilterByType DEFLATE application/x-font
AddOutputFilterByType DEFLATE application/x-font-opentype
AddOutputFilterByType DEFLATE application/x-font-otf
AddOutputFilterByType DEFLATE application/x-font-truetype
AddOutputFilterByType DEFLATE application/x-font-ttf
AddOutputFilterByType DEFLATE application/x-javascript
AddOutputFilterByType DEFLATE application/xhtml+xml
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE application/atom_xml
AddOutputFilterByType DEFLATE application/x-shockwave-flash
AddOutputFilterByType DEFLATE font/opentype
AddOutputFilterByType DEFLATE font/otf
AddOutputFilterByType DEFLATE font/ttf
AddOutputFilterByType DEFLATE image/svg+xml
AddOutputFilterByType DEFLATE image/x-icon
AddOutputFilterByType DEFLATE image/jpeg
AddOutputFilterByType DEFLATE image/png
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/javascript
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/xml
</IfModule>
<IfModule mod_gzip.c>
mod_gzip_on Yes
mod_gzip_dechunk Yes
mod_gzip_item_include file .(html?|txt|css|js|php|pl)$
mod_gzip_item_include handler ^cgi-script$
mod_gzip_item_include mime ^text/.*
mod_gzip_item_include mime ^application/x-javascript.*
mod_gzip_item_exclude mime ^image/.*
mod_gzip_item_exclude rspheader ^Content-Encoding:.*gzip.*
</IfModule>

# Leverage Browser Caching
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType image/jpg "access 1 year"
ExpiresByType image/jpeg "access 1 year"
ExpiresByType image/gif "access 1 year"
ExpiresByType image/png "access 1 year"
ExpiresByType text/css "access 1 month"
ExpiresByType text/html "access 1 month"
ExpiresByType application/pdf "access 1 month"
ExpiresByType text/x-javascript "access 1 month"
ExpiresByType application/x-shockwave-flash "access 1 month"
ExpiresByType image/x-icon "access 1 year"
ExpiresDefault "access 1 month"
</IfModule>
<IfModule mod_headers.c>
<filesmatch "\.(ico|flv|jpg|jpeg|png|gif|css|swf)$">
Header set Cache-Control "max-age=2678400, public"
</filesmatch>
<filesmatch "\.(html|htm)$">
Header set Cache-Control "max-age=7200, private, must-revalidate"
</filesmatch>
<filesmatch "\.(pdf)$">
Header set Cache-Control "max-age=86400, public"
</filesmatch>
<filesmatch "\.(js)$">
Header set Cache-Control "max-age=2678400, private"
</filesmatch>
</IfModule>

AuthType Basic
AuthName "Password Protected Area"
AuthUserFile /var/www/vhosts/plp-tool.de/httpdocs/plp-tool-live/plp-angular/dist/plp-angular/.htpasswd
Require valid-user

+ 1
- 0
plp-angular/.htpasswd Datei anzeigen

@@ -0,0 +1 @@
plp:$2y$10$FvzeO0lzdARUTVPMithMoO9lYM7tTCniHb2DiHjKt.YGAdtuVpodG

+ 27
- 0
plp-angular/README.md Datei anzeigen

@@ -0,0 +1,27 @@
# PlpAngular

This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 8.3.5.

## Development server

Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.

## Code scaffolding

Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.

## Build

Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build.

## Running unit tests

Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).

## Running end-to-end tests

Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).

## Further help

To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).

+ 149
- 0
plp-angular/angular.json Datei anzeigen

@@ -0,0 +1,149 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"plp-angular": {
"projectType": "application",
"schematics": {
"@schematics/angular:component": {
"style": "scss"
}
},
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"crossOrigin": "anonymous",
"outputPath": "dist/plp-angular",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.app.json",
"aot": true,
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"src/scss/styles.scss",
"./node_modules/angular-calendar/css/angular-calendar.css",
"./node_modules/ag-grid-community/styles/ag-grid.css",
"./node_modules/ag-grid-community/styles/ag-theme-balham.css"
],
"scripts": []
},
"configurations": {
"gamma": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.gamma.ts"
}
]
},
"beta": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.beta.ts"
}
]
},
"production": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"extractCss": true,
"namedChunks": false,
"aot": true,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"budgets": [
{
"type": "initial",
"maximumWarning": "2mb",
"maximumError": "5mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "6kb",
"maximumError": "10kb"
}
]
}
}
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "plp-angular:build"
},
"configurations": {
"production": {
"browserTarget": "plp-angular:build:production"
}
}
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "plp-angular:build"
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "src/test.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.spec.json",
"karmaConfig": "karma.conf.js",
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"src/scss/styles.scss"
],
"scripts": []
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"tsconfig.app.json",
"tsconfig.spec.json",
"e2e/tsconfig.json"
],
"exclude": [
"**/node_modules/**"
]
}
},
"e2e": {
"builder": "@angular-devkit/build-angular:protractor",
"options": {
"protractorConfig": "e2e/protractor.conf.js",
"devServerTarget": "plp-angular:serve"
},
"configurations": {
"production": {
"devServerTarget": "plp-angular:serve:production"
}
}
}
}
}},
"defaultProject": "plp-angular"
}

+ 32
- 0
plp-angular/e2e/protractor.conf.js Datei anzeigen

@@ -0,0 +1,32 @@
// @ts-check
// Protractor configuration file, see link for more information
// https://github.com/angular/protractor/blob/master/lib/config.ts

const { SpecReporter } = require('jasmine-spec-reporter');

/**
* @type { import("protractor").Config }
*/
exports.config = {
allScriptsTimeout: 11000,
specs: [
'./src/**/*.e2e-spec.ts'
],
capabilities: {
'browserName': 'chrome'
},
directConnect: true,
baseUrl: 'http://localhost:4200/',
framework: 'jasmine',
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 30000,
print: function() {}
},
onPrepare() {
require('ts-node').register({
project: require('path').join(__dirname, './tsconfig.json')
});
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
}
};

+ 23
- 0
plp-angular/e2e/src/app.e2e-spec.ts Datei anzeigen

@@ -0,0 +1,23 @@
import { AppPage } from './app.po';
import { browser, logging } from 'protractor';

describe('workspace-project App', () => {
let page: AppPage;

beforeEach(() => {
page = new AppPage();
});

it('should display welcome message', () => {
page.navigateTo();
expect(page.getTitleText()).toEqual('plp-angular app is running!');
});

afterEach(async () => {
// Assert that there are no errors emitted from the browser
const logs = await browser.manage().logs().get(logging.Type.BROWSER);
expect(logs).not.toContain(jasmine.objectContaining({
level: logging.Level.SEVERE,
} as logging.Entry));
});
});

+ 11
- 0
plp-angular/e2e/src/app.po.ts Datei anzeigen

@@ -0,0 +1,11 @@
import { browser, by, element } from 'protractor';

export class AppPage {
navigateTo() {
return browser.get(browser.baseUrl) as Promise<any>;
}

getTitleText() {
return element(by.css('app-root .content span')).getText() as Promise<string>;
}
}

+ 13
- 0
plp-angular/e2e/tsconfig.json Datei anzeigen

@@ -0,0 +1,13 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/e2e",
"module": "commonjs",
"target": "es2018",
"types": [
"jasmine",
"jasminewd2",
"node"
]
}
}

+ 32
- 0
plp-angular/karma.conf.js Datei anzeigen

@@ -0,0 +1,32 @@
// Karma configuration file, see link for more information
// https://karma-runner.github.io/1.0/config/configuration-file.html

module.exports = function (config) {
config.set({
basePath: '',
frameworks: ['jasmine', '@angular-devkit/build-angular'],
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage-istanbul-reporter'),
require('@angular-devkit/build-angular/plugins/karma')
],
client: {
clearContext: false // leave Jasmine Spec Runner output visible in browser
},
coverageIstanbulReporter: {
dir: require('path').join(__dirname, './coverage/plp-angular'),
reports: ['html', 'lcovonly', 'text-summary'],
fixWebpackSourcePaths: true
},
reporters: ['progress', 'kjhtml'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
singleRun: false,
restartOnFileChange: true
});
};

+ 12215
- 0
plp-angular/package-lock.json
Datei-Diff unterdrückt, da er zu groß ist
Datei anzeigen


+ 58
- 0
plp-angular/package.json Datei anzeigen

@@ -0,0 +1,58 @@
{
"name": "plp-angular",
"version": "0.0.0",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
},
"private": true,
"dependencies": {
"@angular-devkit/build-angular": "^15.2.8",
"@angular-devkit/schematics": "^15.2.8",
"@angular/animations": "^15.2.8",
"@angular/common": "^15.2.8",
"@angular/compiler": "^15.2.8",
"@angular/core": "^15.2.8",
"@angular/forms": "^15.2.8",
"@angular/platform-browser": "^15.2.8",
"@angular/platform-browser-dynamic": "^15.2.8",
"@angular/router": "^15.2.8",
"@ng-bootstrap/ng-bootstrap": "^14.1.1",
"@npmcli/fs": "^3.1.0",
"ag-grid-angular": "^29.3.5",
"ag-grid-community": "^29.3.5",
"angular-calendar": "^0.31.0",
"angularx-flatpickr": "^6.2.0",
"codelyzer": "^6.0.2",
"date-fns": "^1.30.1",
"eslint": "^8.40.0",
"file-saver": "^2.0.2",
"flatpickr": "^4.6.13",
"ng6-breadcrumbs": "^1.0.7",
"rxjs": "~6.6.7",
"tslib": "^2.0.0",
"zone.js": "~0.13.0"
},
"devDependencies": {
"@angular/cli": "^15.2.8",
"@angular/compiler-cli": "^15.2.8",
"@angular/language-service": "^15.2.8",
"@types/file-saver": "^2.0.1",
"@types/jasmine": "~3.3.8",
"@types/jasminewd2": "^2.0.8",
"@types/node": "^20.1.5",
"jasmine-core": "~3.8.0",
"jasmine-spec-reporter": "~5.0.0",
"karma": "^6.4.2",
"karma-chrome-launcher": "~3.1.0",
"karma-coverage-istanbul-reporter": "~3.0.2",
"karma-jasmine": "~4.0.0",
"karma-jasmine-html-reporter": "^1.5.0",
"ts-node": "~7.0.0",
"typescript": "~4.9.5"
}
}

+ 39
- 0
plp-angular/src/app/app-routing.module.ts Datei anzeigen

@@ -0,0 +1,39 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { StartComponent } from './views/start/start.component';
import {CustomerManagementComponent} from './views/customer-management/customer-management.component';
import {LoginComponent} from './views/login/login.component';
import {RouteInterceptor} from './interceptor/route-interceptor';
import {AccountingComponent} from './views/accounting/accounting.component';
import {TechniqueComponent} from './views/technique/technique.component';
import {SalesComponent} from './views/sales/sales.component';


const routes: Routes = [
{path: '', redirectTo: '/start', pathMatch: 'full'},
{path: 'login', component: LoginComponent, data: {breadcrumb: 'Login'}},
{path: 'start', component: StartComponent, data: {breadcrumb: 'Home'}, canActivate: [RouteInterceptor]},
{path: 'customer-management', component: CustomerManagementComponent, data: {breadcrumb: 'Kunden'}, canActivate: [RouteInterceptor]},
// {path: 'accounting', component: AccountingComponent, data: {breadcrumb: 'Buchhaltung'}, canActivate: [RouteInterceptor]},
// {path: 'technique', component: TechniqueComponent, data: {breadcrumb: 'Technik'}, canActivate: [RouteInterceptor]},
// {path: 'sales', component: SalesComponent, data: {breadcrumb: 'Vertrieb'}, canActivate: [RouteInterceptor]},
{path: '**', redirectTo: '/start', pathMatch: 'full'},
];

@NgModule({
imports: [RouterModule.forRoot(routes, {useHash: true})],
exports: [RouterModule]
})

export class AppRoutingModule {

}

export const routingComponents = [
LoginComponent,
StartComponent,
CustomerManagementComponent,
AccountingComponent,
TechniqueComponent,
SalesComponent,
];

+ 16
- 0
plp-angular/src/app/app.component.html Datei anzeigen

@@ -0,0 +1,16 @@
<div id="wrapper">
<header id="header">
<div class="user" *ngIf="activeUser != null">{{activeUser.firstname}} {{activeUser.lastname}} ({{activeUser.v_translated_role}})</div>
</header>
<div id="content">
<aside *ngIf="isLoggedIn">
<div class="aside-inner">
<app-aside></app-aside>
</div>
</aside>
<div id="main" [class.not-logged-in]="!isLoggedIn">
<router-outlet></router-outlet>
</div>
</div>
</div>
<app-message></app-message>

+ 0
- 0
plp-angular/src/app/app.component.scss Datei anzeigen


+ 53
- 0
plp-angular/src/app/app.component.ts Datei anzeigen

@@ -0,0 +1,53 @@
import {Component, OnDestroy, OnInit} from '@angular/core';
import {AppService} from './services/app.service';
import {Subscription} from 'rxjs';
import {IUser} from './model/entities/user';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})

export class AppComponent implements OnInit, OnDestroy {

private loginSub: Subscription;
private userSub: Subscription;
public isLoggedIn: boolean;
public activeUser: IUser;

constructor(public appService: AppService) {

}

ngOnInit() {
this.isLoggedIn = false;
// Observe login state
this.loginSub = this.appService.getLoginState$().subscribe(
data => {
if (data !== null) {
this.isLoggedIn = true;
} else {
this.isLoggedIn = false;
}
}
);

this.userSub = this.appService.getUser$().subscribe(
data => {
this.activeUser = data as IUser;
}
);

}

/**
* Destroy
*/
ngOnDestroy(): void {
if (this.loginSub !== null && this.loginSub !== undefined) {
this.loginSub.unsubscribe();
}
}

}

+ 151
- 0
plp-angular/src/app/app.module.ts Datei anzeigen

@@ -0,0 +1,151 @@
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FlatpickrModule } from 'angularx-flatpickr';
import { NgbModalModule } from '@ng-bootstrap/ng-bootstrap';
import {AppRoutingModule, routingComponents} from './app-routing.module';
import { AppComponent } from './app.component';
import { StartComponent } from './views/start/start.component';
import { BrowserAnimationsModule} from '@angular/platform-browser/animations';
import {CalendarModule, DateAdapter} from 'angular-calendar';
import { adapterFactory} from 'angular-calendar/date-adapters/date-fns';
import {registerLocaleData} from '@angular/common';
import localeDe from '@angular/common/locales/de';
import { CustomerManagementComponent } from './views/customer-management/customer-management.component';
import { AgGridModule } from 'ag-grid-angular';
import { LoginComponent } from './views/login/login.component';
import {FormsModule, ReactiveFormsModule} from '@angular/forms';
import { AsideComponent } from './components/aside/aside.component';
import {AppService} from './services/app.service';
import {CacheService} from './services/cache.service';
import {MessageService} from './services/message.service';
import {HttpService} from './services/http.service';
import {HTTP_INTERCEPTORS, HttpClientModule} from '@angular/common/http';
import {HttpClientInterceptor} from './services/http.interceptor';
import {RouteInterceptor} from './interceptor/route-interceptor';
import { TechniqueComponent } from './views/technique/technique.component';
import { SalesComponent } from './views/sales/sales.component';
import { AccountingComponent } from './views/accounting/accounting.component';
import { ModalComponent } from './components/modal/modal.component';
import { CustomerViewComponent } from './views/customer-management/customer-view/customer-view.component';
import { TabsComponent } from './components/tabs/tabs.component';
import { TabComponent } from './components/tab/tab.component';
import { CustomerDataViewComponent } from './views/customer-management/customer-view/customer-data-view/customer-data-view.component';
import { CustomerDataEditComponent } from './views/customer-management/customer-view/customer-data-edit/customer-data-edit.component';
import { CustomerContactPersonViewComponent } from './views/customer-management/customer-view/customer-contact-person-view/customer-contact-person-view.component';
import { CustomerContactPersonEditComponent } from './views/customer-management/customer-view/customer-contact-person-edit/customer-contact-person-edit.component';
import { CustomerNoteViewComponent } from './views/customer-management/customer-view/customer-note-view/customer-note-view.component';
import { CustomerNoteEditComponent } from './views/customer-management/customer-view/customer-note-edit/customer-note-edit.component';
import {CustomerService} from './services/customer.service';
import { CustomerNoteDetailComponent } from './views/customer-management/customer-view/customer-note-detail/customer-note-detail.component';
import {GridCheckboxRendererComponent} from './grid-cellrenderer/grid-checkbox/grid-checkbox-renderer/grid-checkbox-renderer.component';
import {GridCheckboxEditorComponent} from './grid-cellrenderer/grid-checkbox/grid-checkbox-editor/grid-checkbox-editor.component';
import {GridSelectEditorComponent} from './grid-cellrenderer/grid-select/grid-select-editor/grid-select-editor.component';
import {GridSelectRendererComponent} from './grid-cellrenderer/grid-select/grid-select-renderer/grid-select-renderer.component';
import {GridDateEditorComponent} from './grid-cellrenderer/grid-date/grid-date-editor/grid-date-editor.component';
import {GridDateRendererComponent} from './grid-cellrenderer/grid-date/grid-date-renderer/grid-date-renderer.component';
import {GridTextRendererComponent} from './grid-cellrenderer/grid-text/grid-text-renderer/grid-text-renderer.component';
import {GridTextEditorComponent} from './grid-cellrenderer/grid-text/grid-text-editor/grid-text-editor.component';
import {GridInputRendererComponent} from './grid-cellrenderer/grid-input/grid-input-renderer/grid-input-renderer.component';
import {GridInputEditorComponent} from './grid-cellrenderer/grid-input/grid-input-editor/grid-input-editor.component';
import {GridBlockedRendererComponent} from './grid-cellrenderer/grid-blocked/grid-blocked-renderer/grid-blocked-renderer.component';
import {GridBlockedEditorComponent} from './grid-cellrenderer/grid-blocked/grid-blocked-editor/grid-blocked-editor.component';
import { CustomerMeetingViewComponent } from './views/customer-management/customer-view/customer-meeting-view/customer-meeting-view.component';
import { CustomerMeetingEditComponent } from './views/customer-management/customer-view/customer-meeting-edit/customer-meeting-edit.component';
import { CustomerMeetingDetailComponent } from './views/customer-management/customer-view/customer-meeting-detail/customer-meeting-detail.component';
import { MessageComponent } from './components/message/message.component';
import { CustomerListComponent } from './views/customer-management/customer-list/customer-list.component';
import { CustomerContactListComponent } from './views/customer-management/customer-contact-list/customer-contact-list.component';
import { MeetingListComponent } from './views/start/meeting-list/meeting-list.component';
import { MeetingCalendarComponent } from './views/start/meeting-calendar/meeting-calendar.component';
import { CustomerContactPersonDetailComponent } from './views/customer-management/customer-view/customer-contact-person-detail/customer-contact-person-detail.component';
import { InternalMeetingEditComponent } from './views/start/internal-meeting-edit/internal-meeting-edit.component';
import { InternalMeetingDetailComponent } from './views/start/internal-meeting-detail/internal-meeting-detail.component';
import { CalendarLegendComponent } from './components/calendar-legend/calendar-legend.component';
import { CommonService } from './services/common.service';
import {GridRendererComponent} from './grid-cellrenderer/grid-renderer-component';
import {GridEditorComponent} from './grid-cellrenderer/grid-editor-component';


registerLocaleData(localeDe);

@NgModule({
declarations: [
AppComponent,
routingComponents,
StartComponent,
CustomerManagementComponent,
LoginComponent,
AsideComponent,
TechniqueComponent,
SalesComponent,
AccountingComponent,
ModalComponent,
CustomerViewComponent,
TabsComponent,
TabComponent,
CustomerDataViewComponent,
CustomerDataEditComponent,
CustomerContactPersonViewComponent,
CustomerContactPersonEditComponent,
CustomerNoteViewComponent,
CustomerNoteEditComponent,
CustomerNoteDetailComponent,
GridRendererComponent,
GridEditorComponent,
GridCheckboxRendererComponent,
GridCheckboxEditorComponent,
GridSelectEditorComponent,
GridSelectRendererComponent,
GridDateEditorComponent,
GridDateRendererComponent,
GridBlockedRendererComponent,
GridTextRendererComponent,
GridTextEditorComponent,
GridInputRendererComponent,
GridInputEditorComponent,
GridBlockedEditorComponent,
CustomerMeetingViewComponent,
CustomerMeetingEditComponent,
CustomerMeetingDetailComponent,
MessageComponent,
CustomerListComponent,
CustomerContactListComponent,
MeetingListComponent,
MeetingCalendarComponent,
CustomerContactPersonDetailComponent,
InternalMeetingEditComponent,
InternalMeetingDetailComponent,
CalendarLegendComponent,
],
imports: [
BrowserModule,
CommonModule,
NgbModalModule,
FlatpickrModule.forRoot(),
AppRoutingModule,
HttpClientModule,
ReactiveFormsModule,
FormsModule,
BrowserAnimationsModule,
// ScrollToModule.forRoot(),
CalendarModule.forRoot({
provide: DateAdapter,
useFactory: adapterFactory
}),
AgGridModule,
],
providers: [
AppService,
RouteInterceptor,
CacheService,
MessageService,
HttpService,
CustomerService,
CommonService,
{provide: HTTP_INTERCEPTORS, useClass: HttpClientInterceptor, multi: true},
],
bootstrap: [AppComponent]
})

export class AppModule { }

+ 158
- 0
plp-angular/src/app/components/ag-grid-component-const.ts Datei anzeigen

@@ -0,0 +1,158 @@
import {GridFactory} from '../grid-cellrenderer/grid-factory';
import {IGridCellParams} from '../grid-cellrenderer/grid-cell-params';
import {Const} from '../utils/const';

export class AgGridComponentConst {

// Key for cell type (must be used in data of grid item)
public static CELL_KEY_TYPE = 'cellKeyType';
// Cell renderers
public static CELL_RENDERER_CHECKBOX = 'gridCheckboxRenderer';
public static CELL_RENDERER_TEXT = 'gridTextRenderer';
public static CELL_RENDERER_DATE = 'gridDateRenderer';
public static CELL_RENDERER_INPUT = 'gridInputRenderer';
public static CELL_RENDERER_SELECT = 'gridSelectRenderer';
public static CELL_RENDERER_BLOCKED = 'gridBlockedRenderer';
public static CELL_RENDERER_DEFAULT = '';
// Cell editors
public static CELL_EDITOR_CHECKBOX = 'gridCheckboxEditor';
public static CELL_EDITOR_TEXT = 'gridTextEditor';
public static CELL_EDITOR_DATE = 'gridDateEditor';
public static CELL_EDITOR_INPUT = 'gridInputEditor';
public static CELL_EDITOR_SELECT = 'gridSelectEditor';
public static CELL_EDITOR_BLOCKED = 'gridBlockedEditor';
public static CELL_EDITOR_DEFAULT = '';
// Cell types
public static CELL_TYPE_DEFAULT = 'default';
public static CELL_TYPE_CHECKBOX = 'checkbox';
public static CELL_TYPE_TEXT = 'text';
public static CELL_TYPE_DATE = 'date';
public static CELL_TYPE_INPUT = 'input';
public static CELL_TYPE_SELECT = 'select';
public static CELL_TYPE_BLOCKED = 'blocked';

// Cell units
public static CELL_UNIT_PERCENT = '%';
public static CELL_UNIT_EURO = '€';
public static CELL_UNIT_DAYS = ' Tage';
public static CELL_UNIT_SQUARE_METER: string = ' ' + Const.UNIT_SQUARE_METER;

// Cell value types
public static CELL_VALUE_TYPE_BOOL = 'bool';
public static CELL_VALUE_TYPE_INT = 'int';
public static CELL_VALUE_TYPE_FLOAT = 'float';
public static CELL_VALUE_TYPE_STRING = 'string';

public static validCellUnits: string[] = [
AgGridComponentConst.CELL_UNIT_PERCENT,
AgGridComponentConst.CELL_UNIT_EURO,
AgGridComponentConst.CELL_UNIT_DAYS,
AgGridComponentConst.CELL_UNIT_SQUARE_METER,
];

public static validCellValueTypes: string[] = [
AgGridComponentConst.CELL_VALUE_TYPE_BOOL,
AgGridComponentConst.CELL_VALUE_TYPE_INT,
AgGridComponentConst.CELL_VALUE_TYPE_FLOAT,
AgGridComponentConst.CELL_VALUE_TYPE_STRING,
];

public static gridInputError: string;

/**
* Sets input error
*/
public static setGridInputError(errorMessage: string = null): void {
AgGridComponentConst.gridInputError = errorMessage;
if (null !== errorMessage) {
setTimeout(() => {
AgGridComponentConst.setGridInputError();
}, 10);
}
}

/**
* Returns a cell renderer for given type with given parameters
*/
public static cellRendererSelector(params: any, gridCellParams: IGridCellParams = null): {} {
if (null === gridCellParams) {
gridCellParams = GridFactory.getGridCellParams();
}

AgGridComponentConst.checkCellValueType(gridCellParams.type);
AgGridComponentConst.checkCellUnit(gridCellParams.unit);
switch (params.data[AgGridComponentConst.CELL_KEY_TYPE]) {
case AgGridComponentConst.CELL_TYPE_CHECKBOX:
return {component: AgGridComponentConst.CELL_RENDERER_CHECKBOX, params: gridCellParams};
case AgGridComponentConst.CELL_TYPE_TEXT:
return {component: AgGridComponentConst.CELL_RENDERER_TEXT, params: gridCellParams};
case AgGridComponentConst.CELL_TYPE_INPUT:
return {component: AgGridComponentConst.CELL_RENDERER_INPUT, params: gridCellParams};
case AgGridComponentConst.CELL_TYPE_DATE:
return {component: AgGridComponentConst.CELL_RENDERER_DATE, params: gridCellParams};
case AgGridComponentConst.CELL_TYPE_SELECT:
return {component: AgGridComponentConst.CELL_RENDERER_SELECT, params: gridCellParams};
case AgGridComponentConst.CELL_TYPE_BLOCKED:
return {component: AgGridComponentConst.CELL_RENDERER_BLOCKED, params: gridCellParams};
case AgGridComponentConst.CELL_TYPE_DEFAULT:
// Nothing specific, so ag grid will take it's own default cell renderer
return;
default:
throw new Error('Unknown cell type');
}
}

/**
* Returns a cell editor for given type with given parameters
*/
public static cellEditorSelector(params: any, gridCellParams: IGridCellParams = null) {
if (null === gridCellParams) {
gridCellParams = GridFactory.getGridCellParams();
}

AgGridComponentConst.checkCellValueType(gridCellParams.type);
AgGridComponentConst.checkCellUnit(gridCellParams.unit);
switch (params.data[AgGridComponentConst.CELL_KEY_TYPE]) {
case AgGridComponentConst.CELL_TYPE_CHECKBOX:
// NOTE: Overwrite any given type for checkbox with boolean, since checkbox can only hold boolean values
gridCellParams.type = AgGridComponentConst.CELL_VALUE_TYPE_BOOL;
return {component: AgGridComponentConst.CELL_EDITOR_CHECKBOX, params: gridCellParams};
case AgGridComponentConst.CELL_TYPE_TEXT:
return {component: AgGridComponentConst.CELL_EDITOR_TEXT, params: gridCellParams};
case AgGridComponentConst.CELL_TYPE_INPUT:
return {component: AgGridComponentConst.CELL_EDITOR_INPUT, params: gridCellParams};
case AgGridComponentConst.CELL_TYPE_DATE:
return {component: AgGridComponentConst.CELL_EDITOR_DATE, params: gridCellParams};
case AgGridComponentConst.CELL_TYPE_SELECT:
return {component: AgGridComponentConst.CELL_EDITOR_SELECT, params: gridCellParams};
case AgGridComponentConst.CELL_TYPE_BLOCKED:
return {component: AgGridComponentConst.CELL_EDITOR_BLOCKED, params: gridCellParams};
case AgGridComponentConst.CELL_TYPE_DEFAULT:
// Nothing specific, so ag grid will take it's own default cell editor
return;
default:
throw new Error('Unknown cell type');
}
}

/**
* Checks if cell value type is valid
* @param {string} type
*/
private static checkCellValueType(type: string = null): void {
if (null !== type && AgGridComponentConst.validCellValueTypes.indexOf(type) < 0) {
throw new Error('Unknown cell value type');
}
}

/**
* Checks if cell unit is valid
* @param {string} type
*/
private static checkCellUnit(type: string = null): void {
if (null !== type && AgGridComponentConst.validCellUnits.indexOf(type) < 0) {
throw new Error('Unknown cell value type');
}
}

}

+ 466
- 0
plp-angular/src/app/components/ag-grid-component.ts Datei anzeigen

@@ -0,0 +1,466 @@
import {path} from '../../environments/path';
import {AgGridLocale} from '../lang/ag-gridlocale';
import {IGridValidationErrors} from '../model/virtual/grid-validation-errors';
import {GridSelectEditorComponent} from '../grid-cellrenderer/grid-select/grid-select-editor/grid-select-editor.component';
import {GridSelectRendererComponent} from '../grid-cellrenderer/grid-select/grid-select-renderer/grid-select-renderer.component';
import {GridCheckboxRendererComponent} from '../grid-cellrenderer/grid-checkbox/grid-checkbox-renderer/grid-checkbox-renderer.component';
import {GridCheckboxEditorComponent} from '../grid-cellrenderer/grid-checkbox/grid-checkbox-editor/grid-checkbox-editor.component';
import {GridDateRendererComponent} from '../grid-cellrenderer/grid-date/grid-date-renderer/grid-date-renderer.component';
import {GridDateEditorComponent} from '../grid-cellrenderer/grid-date/grid-date-editor/grid-date-editor.component';
import {GridTextRendererComponent} from '../grid-cellrenderer/grid-text/grid-text-renderer/grid-text-renderer.component';
import {GridTextEditorComponent} from '../grid-cellrenderer/grid-text/grid-text-editor/grid-text-editor.component';
import {AgGridComponentConst} from './ag-grid-component-const';
import {GridInputRendererComponent} from '../grid-cellrenderer/grid-input/grid-input-renderer/grid-input-renderer.component';
import {GridInputEditorComponent} from '../grid-cellrenderer/grid-input/grid-input-editor/grid-input-editor.component';
import {GridBlockedRendererComponent} from '../grid-cellrenderer/grid-blocked/grid-blocked-renderer/grid-blocked-renderer.component';
import {GridBlockedEditorComponent} from '../grid-cellrenderer/grid-blocked/grid-blocked-editor/grid-blocked-editor.component';
import {Utils} from '../utils/utils';

export class AgGridComponent {
static readonly MIN_HEIGHT: number = 16;
public params: any;
public columnDefs: any[] = [];
public defaultColDef: {} = {};
public rowData: any[] = [];
public rowSelection: string;
public gridParamsColumnApi;
public gridParamsApi;
public apiAssetsPath: string;
public resetSearchBtn: boolean;
public localeText: {};
public frameworkComponents: {};
public bSizeColumnsToFit: boolean;
public gridErrors: IGridValidationErrors[];
public errorIndex: number;
public resetValueByError: boolean;
public errorMessage: string;
public nextAddedItemId: number;

/**
* Constructor
*/
constructor(bSizeColumnsToFit: boolean = true) {
AgGridComponentConst.setGridInputError();
this.rowData = [];
this.columnDefs = [];
this.rowSelection = 'multiple';
this.defaultColDef = {
editable: true
};
this.apiAssetsPath = path.path_assets;
this.frameworkComponents = {};
this.localeText = AgGridLocale.getLocale();
this.bSizeColumnsToFit = bSizeColumnsToFit;
this.gridErrors = [];
this.errorIndex = -1;
this.resetValueByError = false;
this.errorMessage = null;
this.nextAddedItemId = null;

this.frameworkComponents = {
gridSelectEditor: GridSelectEditorComponent,
gridSelectRenderer: GridSelectRendererComponent,
gridCheckboxRenderer: GridCheckboxRendererComponent,
gridCheckboxEditor: GridCheckboxEditorComponent,
gridDateRenderer: GridDateRendererComponent,
gridDateEditor: GridDateEditorComponent,
gridInputRenderer: GridInputRendererComponent,
gridInputEditor: GridInputEditorComponent,
gridTextRenderer: GridTextRendererComponent,
gridTextEditor: GridTextEditorComponent,
gridBlockedRenderer: GridBlockedRendererComponent,
gridBlockedEditor: GridBlockedEditorComponent
};
}

/**
* Callback on grid ready
*/
public onGridReady(params): void {
this.params = params;
this.gridParamsColumnApi = params.columnApi;
this.gridParamsApi = params.api;

// Set for cadasters
if (!this.bSizeColumnsToFit) {
const allColumnIds = [];
this.gridParamsColumnApi.getAllColumns().forEach((column) => {
allColumnIds.push(column.colId);
});
this.gridParamsColumnApi.autoSizeColumns(allColumnIds);
}
}

/**
* On row clicked
*/
public onRowClicked(e): void {
// Reset error message
AgGridComponentConst.setGridInputError();
this.errorMessage = null;
}

/**
* On cell editing stopped
*/
public onCellEditingStopped(e): void {
if (null !== AgGridComponentConst.gridInputError) {
this.errorMessage = AgGridComponentConst.gridInputError;
e.api.ensureIndexVisible(e.rowIndex, 'middle');
e.api.ensureColumnVisible(e.colDef.field.toString());
} else {
this.errorMessage = null;
}
}

/**
* Sizes columns to fit
*/
public onFirstDataRendered(params: any): void {
// Set for info components
if (this.bSizeColumnsToFit) {
params.api.sizeColumnsToFit();
}
}

/**
* Resizes grid
*/
public gridSizeChanged(params: any): void {
if (undefined !== this.gridParamsApi) {
this.gridParamsApi.sizeColumnsToFit();
}
}

/**
* Search Form
*/
public searchFormSubmit(params: any): void {
if (params.target.value !== '') {
this.resetSearchBtn = true;
this.gridParamsApi.setQuickFilter(params.target.value);
} else {
this.resetSearchBtn = false;
this.gridParamsApi.setQuickFilter(null);
}
}

/**
* Reset search input
*/
public resetSearch(e: any): void {
e.originalTarget[0].value = '';
this.resetSearchBtn = false;
this.gridParamsApi.setQuickFilter(null);
}

/**
* Stop editing state
*/
public stopEditing(): void {
this.params.api.stopEditing();
}

/**
* Configures scrollToService - https://www.npmjs.com/package/@nicky-lenaers/ngx-scroll-to
*/
public scrollTo(targetFieldName: string = null, lastFieldName: string = null): void {
if (null !== targetFieldName) {
if (null !== lastFieldName) {
// Scroll to last field first to ensure our target field name is on left-hand side
this.params.api.ensureColumnVisible(lastFieldName);
}
this.params.api.ensureColumnVisible(targetFieldName);
}
}

/**
* Cell renderer selector for individual cells with optional default parameters
*/
public cellRendererSelector(params: any): {} {
return AgGridComponentConst.cellRendererSelector(params);
}

/**
* Cell editor selector for individual cells
*/
public cellEditorSelector(params: any): {} {
return AgGridComponentConst.cellEditorSelector(params);
}

/**
* Validates grid
*/
public validateGrid(): boolean {
const oldErrors: IGridValidationErrors[] = this.gridErrors;
this.gridErrors = [];
this.errorIndex = -1;

const primaryColumns = this.params.api.columnController.primaryColumns;
const errorColumn: any[] = [];
const errors: IGridValidationErrors[] = [];

primaryColumns.forEach((value) => {
if (undefined !== value.colDef.cellEditorParams) {
if (undefined !== value.colDef.cellEditorParams.mandatory && true === value.colDef.cellEditorParams.mandatory) {
errorColumn.push(value.colDef.field);
}
}
});

errorColumn.forEach((value, i) => {
this.params.api.forEachNode((rowNode, index) => {
if (null === rowNode.data[value] || undefined === rowNode.data[value]) {
errors.push({
column: value,
row: index
});
}
});
});
this.gridErrors = errors;

if (this.gridErrors.length !== 0) {
if (oldErrors.length !== this.gridErrors.length) {
this.params.api.ensureIndexVisible(this.gridErrors[0].row, 'middle');
this.params.api.ensureColumnVisible(this.gridErrors[0].column);
}
}

return this.gridErrors.length === 0;
}

/**
* Jumps to error
*/
public jumpToError(direction: string): void {
const errorLength: number = this.gridErrors.length - 1;
// If any errors
if (errorLength >= 0) {
// if errorIndex is smaller or same as list of all errors
if (errorLength === 0) {
this.errorIndex = 0;
} else {
if (direction === 'next') {
this.errorIndex = this.errorIndex < errorLength ? this.errorIndex + 1 : 0;
} else {
this.errorIndex = this.errorIndex <= 0 ? errorLength : this.errorIndex - 1;
}
}
this.params.api.ensureIndexVisible(this.gridErrors[this.errorIndex].row, 'middle');
this.params.api.ensureColumnVisible(this.gridErrors[this.errorIndex].column);
} else {
// reset errorIndex if no errors
this.errorIndex = -1;
}
}

/**
* Shows input error
*/
public showInputError(positionIndex: number, field: string, oldValue: string, type: string): void {
this.resetValueByError = true;
this.params.api.clearFocusedCell();
this.params.api.ensureIndexVisible(positionIndex, 'middle');
this.params.api.ensureColumnVisible(field);
// Lifecycle hack
setTimeout(() => {
// Reset to old value
this.params.api.getRowNode(positionIndex).setDataValue(field, oldValue);
this.params.api.startEditingCell({
rowIndex: positionIndex,
colKey: field,
});
switch (type) {
case 'int':
this.errorMessage = 'Bitte geben Sie einen ganzzahligen Wert ein.';
break;
case 'float':
this.errorMessage = 'Bitte geben Sie einen dezimalen oder ganzzahligen Wert ein.';
break;
}
}, 10);
}

/**
* Add row to grid and returns position index
*/
public addRow(item: {}): number {
this.initNextAddedItemId();
const rowModel = this.gridParamsApi.rowModel;
// Note: default is last row
let addIndex: number = rowModel.rowsToDisplay.length + 1;
rowModel.rowsToDisplay.forEach((row, i) => {
if (row.selected === true) {
// Note: Add index is the row after selected row
addIndex = i + 1;
return;
}
});
this.gridParamsApi.updateRowData({
add: [item],
addIndex
});
return addIndex;
}

/**
* Removes selected rows
*/
public removeRows(): void {
this.initNextAddedItemId();
const selectedRows: {}[] = this.gridParamsApi.getSelectedRows();
this.gridParamsApi.updateRowData({remove: selectedRows});
}

/**
* Gets next row position
*/
public getNextRowPosition(): number {
return this.gridParamsApi.rowModel.length + 1;
}

/**
* inits next dummy id for next added entry, if necessary
*/
private initNextAddedItemId(): void {
if (this.nextAddedItemId === null) {
this.nextAddedItemId = (this.rowData.length + 1) * -1;
}
}

/**
* Returns dummy id for added entry
*/
public getNextAddedItemId(): number {
this.initNextAddedItemId();
const res: number = this.nextAddedItemId;
this.nextAddedItemId--;
return res;
}

/**
* column resize event
*/
public onColumnResized(event): void {
if (event.finished !== false) {
event.api.setHeaderHeight(AgGridComponent.MIN_HEIGHT);
const headerCells = Array.from(document.querySelectorAll('.content .ag-header-cell-label'));
let minHeight: number = AgGridComponent.MIN_HEIGHT;
headerCells.forEach(cell => {
minHeight = Math.max(minHeight, cell.scrollHeight);
});

// set header height to calculated height + padding (top: 8px, bottom: 8px)
event.api.setHeaderHeight(minHeight + 16);
}
if (event.finished) {
this.gridParamsApi.resetRowHeights();
}
}

/**
* Renders colored dot
*/
public dotRenderer(params): string {
return '<span class=\'dot dot--' + params.value + '\'></span>';
}

/**
* Renders email address
*/
public emailRenderer(params): string {
return null !== params.value ? '<a href=\'mailto:' + params.value + '\'>' + params.value + '</a>' : '';
}

/**
* Renders phone number
*/
public phoneRenderer(params): string {
return null !== params.value ? '<a href=\'tel:' + params.value + '\'>' + params.value + '</a>' : '';
}

/**
* Renders phone number
*/
public urlRenderer(params): string {
return null !== params.value ? '<a href=\'' + Utils.checkUrl(params.value) + '\' target=\'_blank\'>' + params.value + '</a>' : '';
}

/**
* option renderer
*/
public optionRenderer(params): string {
return params.data.is_option_meeting ? 'Ja' : '';
}

/**
* address renderer
*/
public addressRenderer(params): string {
let address = '';
if (params.data.typeType === 'visit') {
const street = params.data.street !== null ? params.data.street : '';
const streetNo = params.data.street_no !== null ? params.data.street_no : '';
const zip = params.data.zip !== null ? params.data.zip : '';
const city = params.data.city !== null ? params.data.city : '';
let br = '';
if (zip !== null || city !== null) {
br = '<br />';
}
address = street + ' ' + streetNo + ' ' + br + zip + ' ' + city;
}
return address;
}

/**
* participants renderer
*/
public participantsRenderer(params): string {
let participantNames = '';
params.data.participants.forEach((value) => {
participantNames += params.data.that.appService.getConfig().vc_user_by_id[value.participant_user_id].firstname +
' ' + params.data.that.appService.getConfig().vc_user_by_id[value.participant_user_id].lastname + '<br />';
});
return participantNames;
}

/**
* Time renderer
*/
public timeRenderer(params): string {
return Utils.getDateTimeToDisplay(params.value, false, true);
}

/**
* Date renderer
*/
public dateRenderer(params): string {
return Utils.getDateTimeToDisplay(params.value);
}

/**
* Datetime renderer
*/
public dateTimeRenderer(params): string {
return Utils.getDateTimeToDisplay(params.value, true, true);
}

/**
* Date comparator
*/
public dateComparator(date1, date2, callbackCheck: boolean = true) {
if (date1 === null && date2 === null) {
return 0;
}
if (date1 === null) {
return -1;
}
if (date2 === null) {
return 1;
}
const stamp1: number = Utils.getParsedDate(date1);
const stamp2: number = Utils.getParsedDate(date2);
return stamp1 < stamp2 ? 1 : stamp1 === stamp2 ? 0 : -1;
}
}

+ 9
- 0
plp-angular/src/app/components/aside/aside.component.html Datei anzeigen

@@ -0,0 +1,9 @@
<div class="home-btn" routerLink="/start">
Startseite
</div>
<ul id="navigation">
<li *ngFor="let navItem of navItems" routerLink="{{navItem.route}}">
<p>{{navItem.name}}</p>
</li>
</ul>
<div id="logout" (click)="logout()">Logout</div>

+ 0
- 0
plp-angular/src/app/components/aside/aside.component.scss Datei anzeigen


+ 37
- 0
plp-angular/src/app/components/aside/aside.component.ts Datei anzeigen

@@ -0,0 +1,37 @@
import { Component, OnInit } from '@angular/core';
import {AppService} from '../../services/app.service';

@Component({
selector: 'app-aside',
templateUrl: './aside.component.html',
styleUrls: ['./aside.component.scss']
})

export class AsideComponent implements OnInit {

/* Navigation items */
public navItems: Array<object>;

constructor(public appService: AppService) { }

ngOnInit() {
this.navItems = [];
this.navItems.push({name: 'Kunden', route: '/customer-management', className: 'customer-management'});
this.navItems.push({name: 'Betreiber', route: '/operators', className: 'operators'});
this.navItems.push({name: 'Produzenten', route: '/productions', className: 'productions'});
this.navItems.push({name: 'Service', route: '/service', className: 'service'});
// this.navItems.push({name: 'Buchhaltung', route: '/accounting', className: 'accounting'});
// this.navItems.push({name: 'Produktion', route: '/production', className: 'production'});
// this.navItems.push({name: 'Service', route: '/service', className: 'service'});
// this.navItems.push({name: 'Technik', route: '/technique', className: 'technique'});
// this.navItems.push({name: 'Vertrieb', route: '/sales', className: 'sales'});
}

/**
* Logout
*/
public logout(): void {
this.appService.logout();
}

}

+ 3
- 0
plp-angular/src/app/components/calendar-legend/calendar-legend.component.html Datei anzeigen

@@ -0,0 +1,3 @@
<ul class="calendar-legend">
<li *ngFor="let l of legendEntries" class="legend-color--{{l.type}}">{{l.name}}</li>
</ul>

+ 0
- 0
plp-angular/src/app/components/calendar-legend/calendar-legend.component.scss Datei anzeigen


+ 34
- 0
plp-angular/src/app/components/calendar-legend/calendar-legend.component.ts Datei anzeigen

@@ -0,0 +1,34 @@
import { Component, OnInit } from '@angular/core';
import {ICalendarLegend} from '../../model/entities/calendar-legend';

@Component({
selector: 'app-calendar-legend',
templateUrl: './calendar-legend.component.html',
styleUrls: ['./calendar-legend.component.scss']
})
export class CalendarLegendComponent implements OnInit {

public legendEntries: ICalendarLegend[];

constructor() { }

ngOnInit() {
// this.legendEntries = [];
this.legendEntries = [
{id: 1, type: 'customer', name: 'Kunden'},
{id: 2, type: 'operator', name: 'Betreiber'},
{id: 3, type: 'internal', name: 'Intern'},
{id: 4, type: 'production', name: 'Produzenten'},
{id: 5, type: 'service', name: 'Service'},
];
}

/**
*
* @param legendEntries
*/
public setData(legendEntries: []): void {
// this.legendEntries = legendEntries;
}

}

+ 37
- 0
plp-angular/src/app/components/form-component.ts Datei anzeigen

@@ -0,0 +1,37 @@
// import {ScrollToService} from '@nicky-lenaers/ngx-scroll-to';

export class FormComponent {
public errorMsg: string;
public isCreationMode: boolean;
// protected scrollToService: ScrollToService;


// constructor(scrollToService: ScrollToService) {
// this.scrollToService = scrollToService;
// this.errorMsg = '';
// this.isCreationMode = false;
// }

constructor() {
this.errorMsg = '';
this.isCreationMode = false;
}

public checkDate(e: any): void {
const checkedDate: Date = new Date(e.target.value.replace(/\s/, 'T'));
const today: Date = new Date();
today.setHours(0);
today.setMinutes(0);
today.setSeconds(1);
if (checkedDate < today) {
alert('Hinweis: Das Datum liegt in der Vergangenheit.\nVergangene Termine können nicht bearbeitet oder gelöscht werden.');
}
}

/**
* Configures scrollToService - https://www.npmjs.com/package/@nicky-lenaers/ngx-scroll-to
*/
// public scrollUp(identifier: string): void {
// this.scrollToService.scrollTo({target: identifier});
// }
}

+ 18
- 0
plp-angular/src/app/components/message/message.component.html Datei anzeigen

@@ -0,0 +1,18 @@
<div class="message-modal" [class.active]="showError == true || showClientError == true">
<div class="message message--error" [class.active]="showError == true || showClientError == true">
<p>{{message}}</p>
<p *ngIf="optionalInfo != null" [innerHTML]="optionalInfo"></p>
<button class="button" (click)="closeComponent()" title="Fenster schließen">schließen</button>
</div>
</div>
<div class="message-modal" [class.active]="showSuccess == true">
<div class="message message--success" [class.active]="showSuccess == true">
<p>{{message}}</p>
</div>
</div>
<div class="message-modal" [class.active]="showInfo == true">
<div class="message message--info" [class.active]="showInfo == true">
<p>{{message}}</p>
<button class="button" (click)="closeComponent()" title="Fenster schließen">schließen</button>
</div>
</div>

+ 0
- 0
plp-angular/src/app/components/message/message.component.scss Datei anzeigen


+ 141
- 0
plp-angular/src/app/components/message/message.component.ts Datei anzeigen

@@ -0,0 +1,141 @@
import {Component, OnDestroy, OnInit} from '@angular/core';
import {MessageService} from '../../services/message.service';
import {Subscription} from 'rxjs';

@Component({
selector: 'app-message',
templateUrl: './message.component.html',
styleUrls: ['./message.component.scss']
})

export class MessageComponent implements OnInit, OnDestroy {

// Message display time in milliseconds
static MESSAGE_DISPLAY_TIME = 2000;

// Client Error codes
static CLIENT_ERROR_DATA = 1;
static CLIENT_ERROR_VALIDATION_FAILED = 2;


private messageSub: Subscription;
public showError: boolean;
public showSuccess: boolean;
public showInfo: boolean;
public showClientError: boolean;
public message: string;
public optionalInfo: string;

public errorMessages: string[];
public successMessages: string[];
public infoMessages: string[];
public clientErrorMessages: string[];

constructor(private messageService: MessageService) {
// Init client error messages
this.clientErrorMessages = [];
this.clientErrorMessages[MessageComponent.CLIENT_ERROR_DATA] = 'Die Daten sind unvollständig oder fehlerhaft.';
this.clientErrorMessages[MessageComponent.CLIENT_ERROR_VALIDATION_FAILED] = 'Die Daten sind nicht valide, kein Speichern möglich. Bitte überprüfen Sie Ihre Eingaben.';
}

ngOnInit() {
this.messageSub = this.messageService.getMessage$().subscribe(
data => {
if (data !== null) {
if (data.error_code != 0) {
this.showErrorMessage(data.error_code, data.error_msg, data.optional_info);
} else if (data.success_code != 0) {
this.showSuccessMessage(data.success_code, data.success_msg);
} else if (data.info_code != 0) {
this.showInfoMessage(data.info_code, data.info_msg);
} else if (data.client_error_code != 0) {
this.showClientErrorMessage(data.client_error_code);
}
}
});

this.showError = false;
this.showSuccess = false;
this.showInfo = false;
this.showClientError = false;
this.message = '';
this.optionalInfo = null;
}

/**
* Shows error message
* @param {number} errorCode
* @param {string} errorMsg
* @param {string} optionalInfo
*/
public showErrorMessage(errorCode: number, errorMsg: string, optionalInfo: string = null): void {
this.showError = true;
this.showSuccess = false;
this.showInfo = false;
this.showClientError = false;
this.message = errorMsg;
// Set optional info (if exists)
this.optionalInfo = null !== optionalInfo ? optionalInfo : null;
}

/**
* Shows success message
* @param {number} successCode
* @param {string} successMsg
*/
public showSuccessMessage(successCode: number, successMsg: string): void {
this.showSuccess = true;
this.showError = false;
this.showInfo = false;
this.showClientError = false;
const me: MessageComponent = this;
this.message = successMsg;
setTimeout(function() {
me.closeComponent();
}, MessageComponent.MESSAGE_DISPLAY_TIME);
}

/**
* Shows info message
* @param {number} infoCode
* @param {string} infoMsg
*/
public showInfoMessage(infoCode: number, infoMsg: string): void {
this.showInfo = true;
this.showSuccess = false;
this.showError = false;
this.showClientError = false;
this.message = infoMsg;
}

/**
* Shows client error message
* @param {number} clientErrorCode
*/
public showClientErrorMessage(clientErrorCode: number): void {
this.showInfo = false;
this.showSuccess = false;
this.showError = false;
this.showClientError = true;
if (this.clientErrorMessages[clientErrorCode]) {
this.message = this.clientErrorMessages[clientErrorCode];
}
}

/**
* Hides error- / success-message
*/
public closeComponent(): void {
this.showError = false;
this.showSuccess = false;
this.showInfo = false;
this.showClientError = false;
this.message = '';
}

ngOnDestroy(): void {
if (this.messageSub !== null) {
this.messageSub.unsubscribe();
}
}
}

+ 8
- 0
plp-angular/src/app/components/modal/modal.component.html Datei anzeigen

@@ -0,0 +1,8 @@
<div class="modal" (click)="closeModal()" [class.overlay]="overlay" [class.modal-open]="showModal" *ngIf="isVisible"></div>
<div class="modal-content" [class.overlay]="overlay" [class.modal-open]="showModal" *ngIf="isVisible">
<div class="modal-content-inner">
<ng-content></ng-content>
</div>
<span class="close" (click)="closeModal()">X</span>
</div>


+ 0
- 0
plp-angular/src/app/components/modal/modal.component.scss Datei anzeigen


+ 79
- 0
plp-angular/src/app/components/modal/modal.component.ts Datei anzeigen

@@ -0,0 +1,79 @@
import {AfterContentInit, Component, EventEmitter, OnInit, Input, Output, Renderer2} from '@angular/core';

@Component({
selector: 'app-spt-modal',
templateUrl: './modal.component.html',
styleUrls: ['./modal.component.scss']
})

export class ModalComponent implements OnInit, AfterContentInit {

@Input() autoclose = true;
@Input() overlay = false;
@Output() state: EventEmitter<boolean> = new EventEmitter<boolean>();
@Output() onClose: EventEmitter<boolean> = new EventEmitter<boolean>();

public showModal: boolean;
public isVisible: boolean;

constructor(private renderer: Renderer2) { }

ngOnInit() {
this.showModal = false;
this.isVisible = false;
}

/**
* After content children are set
*/
ngAfterContentInit() {
this.isVisible = true;
}

/**
* Opens modal dialog
*/
public openModal(): void {
this.showModal = true;
this.renderer.addClass(document.body, 'body--modal-open');
this.state.emit(this.showModal);
}

/**
* Closes modal dialog if no parameter showDialog == false
*/
public closeModal(): void {
if (!this.autoclose) {
this.onClose.emit(true);
} else {
this.exitModal();
}
}

/**
* Closes modal dialog with confirm message
*/
public closeWithConfirm(message: string): boolean {
if (confirm(message)) {
this.exitModal();
return true;
}
return false;
}

/**
* Closes modal dialog
*/
public exitModal(): void {
this.showModal = false;
this.renderer.removeClass(document.body, 'body--modal-open');
this.state.emit(this.showModal);
}

/**
* Returns if modal is open
*/
public isOpen(): boolean {
return this.showModal;
}
}

+ 3
- 0
plp-angular/src/app/components/tab/tab.component.html Datei anzeigen

@@ -0,0 +1,3 @@
<div class="tab-entry" [class.active]="active">
<ng-content></ng-content>
</div>

+ 0
- 0
plp-angular/src/app/components/tab/tab.component.scss Datei anzeigen


+ 21
- 0
plp-angular/src/app/components/tab/tab.component.ts Datei anzeigen

@@ -0,0 +1,21 @@
import {Component, Input, OnInit} from '@angular/core';

@Component({
selector: 'app-tab',
templateUrl: './tab.component.html',
styleUrls: ['./tab.component.scss']
})

export class TabComponent implements OnInit {

@Input('tabTitle') title: string;
@Input('tabIndex') index: number;
@Input() active = false;
@Input() disabled = false;

constructor() { }

ngOnInit() {
}

}

+ 10
- 0
plp-angular/src/app/components/tabs/tabs.component.html Datei anzeigen

@@ -0,0 +1,10 @@
<div class="tabs">
<ul class="tabs-nav">
<li *ngFor="let tab of tabs" (click)="selectTab(tab)" [class.active]="tab.active" [class.disabled]="tab.disabled">
{{tab.title}}
</li>
</ul>
<div class="tab-entries">
<ng-content></ng-content>
</div>
</div>

+ 0
- 0
plp-angular/src/app/components/tabs/tabs.component.scss Datei anzeigen


+ 99
- 0
plp-angular/src/app/components/tabs/tabs.component.ts Datei anzeigen

@@ -0,0 +1,99 @@
import {
AfterContentInit,
Component,
ContentChildren,
EventEmitter,
Input,
Output,
QueryList
} from '@angular/core';
import {TabComponent} from '../tab/tab.component';

@Component({
selector: 'app-tabs',
templateUrl: './tabs.component.html',
styleUrls: ['./tabs.component.scss']
})

export class TabsComponent implements AfterContentInit {

@ContentChildren(TabComponent) tabs: QueryList<TabComponent>;
@Input() notifyOnChange = false;
@Output() onChange: EventEmitter<number> = new EventEmitter<number>();

constructor() { }

/**
* After content children are set
*/
public ngAfterContentInit(): void {
// get all active tabs
const activeTabs = this.tabs.filter((tab) => tab.active);

// if there is no active tab set, activate the first
if (activeTabs.length === 0) {
this.setSelectedTabIndex(0);
}
}

/**
* Eventlistener for tab change
* @param {TabComponent} tab
*/
public selectTab(tab: TabComponent): void {
if (!tab.disabled) {
if (this.notifyOnChange) {
this.onChange.emit(tab.index);
} else {
this.setSelectedTabIndex(tab.index);
}
}
}

/**
* Sets selected tab by given
* @param {number} i
*/
public setSelectedTabIndex(i: number): void {
if (this.tabs != null) {
const tabsArray: TabComponent[] = this.tabs.toArray();
if (i < tabsArray.length) {
// Deactivate all tabs
tabsArray.forEach(tab => tab.active = false);
// Activate the tab the user has clicked on.
tabsArray[i].active = true;
}
}
}

/**
* Disable tab at given index
* @param {number} i
*/
public disableTabIndex(i: number): void {
this.toggleTabIndex(i, false);
}

/**
* Enable tab at given index
* @param {number} i
*/
public enableTabIndex(i: number): void {
this.toggleTabIndex(i, true);
}

/**
* Sets selected tab disabled/enabled
* @param {number} i
* @param {boolean} enable
*/
private toggleTabIndex(i: number, enable: boolean): void {
if (this.tabs != null) {
const tabsArray: TabComponent[] = this.tabs.toArray();
if (i < tabsArray.length) {
tabsArray[i].disabled = !enable;
}
}
}

}

+ 186
- 0
plp-angular/src/app/factory/factory.ts Datei anzeigen

@@ -0,0 +1,186 @@
import {IMessage} from '../model/virtual/message';
import {ICustomer} from '../model/entities/customer';
import {ICustomerContact} from '../model/entities/customer-contact';
import {ICustomerNote} from '../model/entities/customer-note';
import {ICustomerMeeting} from '../model/entities/customer-meeting';
import {IUser} from '../model/entities/user';
import {IMeetingType} from '../model/entities/meeting-type';
import {IInternalMeeting} from '../model/entities/internal-meeting';
import {Utils} from '../utils/utils';
export class Factory {

static getEmptyUser(): IUser {
const emptyUser: {} = {
id: null,
email: null,
firstname: null,
lastname: null,
active: false
};
return emptyUser as IUser;
}

/**
* Returns empty message
*/
static getEmptyMessage(errorCode: number, errorMsg: string, successCode: number, successMsg: string,
infoCode: number, infoMsg: string, clientErrorCode: number, optionalInfo: string = null): IMessage {
const emptyMessage: {} = {
error_code: errorCode,
error_msg: errorMsg,
success_code: successCode,
success_msg: successMsg,
info_code: infoCode,
info_msg: infoMsg,
client_error_code: clientErrorCode,
optional_info: optionalInfo
};
return emptyMessage as IMessage;
}

/**
* Returns empty customer
*/
static getEmptyCustomer(): ICustomer {
const emptyCustomer: {} = {
id: null,
old_plp_id: null,
name: null,
name_additional: null,
consultant_user_id: null,
street: null,
street_no: null,
zip: null,
city: null,
country_id: null,
url: null,
email: null,
phone_no: null,
mobile_no: null,
fax_no: null,
comment: null,
active: true,
};
return emptyCustomer as ICustomer;
}

/**
* Returns empty customer contact person
*/
static getEmptyCustomerContact(customerId: number = null): ICustomerContact {
const emptyCustomerContact: {} = {
id: null,
customer_id: customerId,
gender: null,
firstname: null,
lastname: null,
email: null,
phone_no: null,
mobile_no: null,
fax_no: null,
department: null,
date_of_birth: null,
comment: null,
street: null,
street_no: null,
zip: null,
city: null,
country_id: null,
is_xmas_mail_recipient: false,
};
return emptyCustomerContact as ICustomerContact;
}

static getEmptyCustomerNote(customerId: number = null, noteDate: string = null): ICustomerNote {
const emptyCustomerNote: {} = {
id: customerId,
customer_id: null,
customer_contact_id: null,
user_id: null,
gender: null,
firstname: null,
lastname: null,
email: null,
phone_no: null,
mobile_no: null,
fax_no: null,
department: null,
title: null,
comment: null,
note_date: noteDate,
creation_date: null,
creation_user_id: null,
creation_user_firstname: null,
creation_user_lastname: null
};
return emptyCustomerNote as ICustomerNote;
}

static getEmptyCustomerMeeting(customerId: number = null): ICustomerMeeting {
const emptyCustomerMeeting: {} = {
id: null,
customer_id: customerId,
creation_user_id: null,
owner_user_id: null,
meeting_type_id: null,
is_option_meeting: false,
title: null,
description: null,
start_date: Utils.getCurrentDate() + ' 09:00:00',
end_date: Utils.getCurrentDate() + ' 18:00:00',
customer_contact_id: null,
gender: null,
firstname: null,
lastname: null,
email: null,
phone_no: null,
mobile_no: null,
department: null,
street: null,
street_no: null,
zip: null,
city: null,
country_id: null,
report: null,
first_reminder_sent: false,
second_reminder_sent: false,
report_done: false,
report_reminder_sent: false,
creation_date: null,
v_participants: [],
v_is_editable: true
};
return emptyCustomerMeeting as ICustomerMeeting;
}

static getEmptyInternalMeeting(): IInternalMeeting {
const emptyInternalMeeting: {} = {
id: null,
creation_user_id: null,
owner_user_id: null,
title: null,
description: null,
start_date: Utils.getCurrentDate() + ' 09:00:00',
end_date: Utils.getCurrentDate() + ' 18:00:00',
report: null,
first_reminder_sent: false,
second_reminder_sent: false,
report_done: false,
report_reminder_sent: false,
creation_date: null,
v_participants: [],
v_is_editable: true
};
return emptyInternalMeeting as IInternalMeeting;
}

static getEmptyMeetingType(): IMeetingType {
const emptyMeetingType: {} = {
id: null,
type: null,
name: null,
};
return emptyMeetingType as IMeetingType;
}

}

+ 1
- 0
plp-angular/src/app/grid-cellrenderer/grid-blocked/grid-blocked-editor/grid-blocked-editor.component.html Datei anzeigen

@@ -0,0 +1 @@
<div class="block-renderer"></div>

+ 1
- 0
plp-angular/src/app/grid-cellrenderer/grid-blocked/grid-blocked-editor/grid-blocked-editor.component.scss Datei anzeigen

@@ -0,0 +1 @@


+ 19
- 0
plp-angular/src/app/grid-cellrenderer/grid-blocked/grid-blocked-editor/grid-blocked-editor.component.ts Datei anzeigen

@@ -0,0 +1,19 @@
import {Component} from '@angular/core';
import {GridEditorComponent} from '../../grid-editor-component';

@Component({
selector: 'app-grid-blocked-editor',
templateUrl: './grid-blocked-editor.component.html',
styleUrls: ['./grid-blocked-editor.component.scss']
})

export class GridBlockedEditorComponent extends GridEditorComponent {

/**
* Sets focus
*/
public afterGuiAttached(): void {

}

}

+ 1
- 0
plp-angular/src/app/grid-cellrenderer/grid-blocked/grid-blocked-renderer/grid-blocked-renderer.component.html Datei anzeigen

@@ -0,0 +1 @@
<div class="block-renderer"></div>

+ 0
- 0
plp-angular/src/app/grid-cellrenderer/grid-blocked/grid-blocked-renderer/grid-blocked-renderer.component.scss Datei anzeigen


+ 21
- 0
plp-angular/src/app/grid-cellrenderer/grid-blocked/grid-blocked-renderer/grid-blocked-renderer.component.ts Datei anzeigen

@@ -0,0 +1,21 @@
import {Component} from '@angular/core';
import {GridRendererComponent} from '../../grid-renderer-component';

@Component({
selector: 'app-grid-blocked-renderer',
templateUrl: './grid-blocked-renderer.component.html',
styleUrls: ['./grid-blocked-renderer.component.scss']
})

export class GridBlockedRendererComponent extends GridRendererComponent {

/**
* Initialize cell renderer (gets called on cell rendering and after editing / refresh)
* @param params
*/
agInit(params: any): void {
params.eGridCell.classList.remove('error');

}

}

+ 9
- 0
plp-angular/src/app/grid-cellrenderer/grid-cell-editor-params.ts Datei anzeigen

@@ -0,0 +1,9 @@
export interface IGridCellEditorParams {
itemKey: string;
itemValueKeys: string[];
relatesOnDgField: string;
values: any[];
exclusive: boolean;
exclusiveCompareDataKey: string;
exclusiveCompareData: any[];
}

+ 8
- 0
plp-angular/src/app/grid-cellrenderer/grid-cell-params.ts Datei anzeigen

@@ -0,0 +1,8 @@
export interface IGridCellParams {
type: string;
min: number;
max: number;
unit: string;
mandatory: boolean;
altVal: number;
}

+ 3
- 0
plp-angular/src/app/grid-cellrenderer/grid-checkbox/grid-checkbox-editor/grid-checkbox-editor.component.html Datei anzeigen

@@ -0,0 +1,3 @@
<input id="checkbox-editor-{{params.rowIndex}}-{{params.column.colId}}" type="checkbox" #editorInput [checked]="value"
(change)="valueIsChanged($event)"/>
<label for="checkbox-editor-{{params.rowIndex}}-{{params.column.colId}}"></label>

+ 0
- 0
plp-angular/src/app/grid-cellrenderer/grid-checkbox/grid-checkbox-editor/grid-checkbox-editor.component.scss Datei anzeigen


+ 41
- 0
plp-angular/src/app/grid-cellrenderer/grid-checkbox/grid-checkbox-editor/grid-checkbox-editor.component.ts Datei anzeigen

@@ -0,0 +1,41 @@
import {Component} from '@angular/core';
import {GridEditorComponent} from '../../grid-editor-component';
import {Utils} from '../../../utils/utils';

@Component({
selector: 'app-grid-checkbox-editor',
templateUrl: './grid-checkbox-editor.component.html',
styleUrls: ['./grid-checkbox-editor.component.scss']
})

export class GridCheckboxEditorComponent extends GridEditorComponent {

/**
* Initialize checkbox editor (called after double-click)
* @param params
*/
agInit(params: any): void {
super.agInit(params);

// Set true to false, because of single click
this.value = null === this.value ? true : !this.value;
if (!Utils.isBoolean(this.value)) {
throw new Error('checkbox requires boolean value');
}
}

/**
* Changes value on checkbox click
* @param e
*/
public valueIsChanged = (e) => {
this.value = !this.value;
}

/**
* Overwrite
*/
public afterGuiAttached(): void {
// do nothing
}
}

+ 8
- 0
plp-angular/src/app/grid-cellrenderer/grid-checkbox/grid-checkbox-renderer/grid-checkbox-renderer.component.html Datei anzeigen

@@ -0,0 +1,8 @@
<input id="checkbox-renderer-{{params.rowIndex}}-{{params.colDef.field}}" *ngIf="params.colDef.editable" type="checkbox"
[checked]="value" (click)="startEditing()"/>
<label for="checkbox-renderer-{{params.rowIndex}}-{{params.colDef.field}}"></label>
<ng-container *ngIf="!params.colDef.editable">
<input id="checkbox-renderer-{{params.rowIndex}}-{{params.colDef.field}}" disabled type="checkbox"
[checked]="value"/>
<label for="checkbox-renderer-{{params.rowIndex}}-{{params.colDef.field}}"></label>
</ng-container>

+ 0
- 0
plp-angular/src/app/grid-cellrenderer/grid-checkbox/grid-checkbox-renderer/grid-checkbox-renderer.component.scss Datei anzeigen


+ 34
- 0
plp-angular/src/app/grid-cellrenderer/grid-checkbox/grid-checkbox-renderer/grid-checkbox-renderer.component.ts Datei anzeigen

@@ -0,0 +1,34 @@
import {Component} from '@angular/core';
import {GridRendererComponent} from '../../grid-renderer-component';
import {Utils} from '../../../utils/utils';

@Component({
selector: 'app-grid-checkbox-renderer',
templateUrl: './grid-checkbox-renderer.component.html',
styleUrls: ['./grid-checkbox-renderer.component.scss']
})

export class GridCheckboxRendererComponent extends GridRendererComponent {
/**
* Initialize cell renderer (gets called on cell rendering and after editing / refresh)
* @param params
*/
agInit(params: any): void {
super.agInit(params);
this.value = null === this.value ? false : this.value;
if (!Utils.isBoolean(this.value)) {
throw new Error('checkbox requires boolean value');
}
}

/**
* Triggers cell editing start without using "singleClickEdit"
*/
public startEditing(): void {
const startEditingParams: {} = {
rowIndex: this.params.rowIndex,
colKey: this.params.column.getId()
};
this.params.api.startEditingCell(startEditingParams);
}
}

+ 1
- 0
plp-angular/src/app/grid-cellrenderer/grid-date/grid-date-editor/grid-date-editor.component.html Datei anzeigen

@@ -0,0 +1 @@
<input type="date" #editorInput (change)="valueIsChanged($event)" value="{{value}}" />

+ 0
- 0
plp-angular/src/app/grid-cellrenderer/grid-date/grid-date-editor/grid-date-editor.component.scss Datei anzeigen


+ 12
- 0
plp-angular/src/app/grid-cellrenderer/grid-date/grid-date-editor/grid-date-editor.component.ts Datei anzeigen

@@ -0,0 +1,12 @@
import {Component} from '@angular/core';
import {GridEditorComponent} from '../../grid-editor-component';

@Component({
selector: 'app-grid-checkbox-editor',
templateUrl: './grid-date-editor.component.html',
styleUrls: ['./grid-date-editor.component.scss']
})

export class GridDateEditorComponent extends GridEditorComponent {

}

+ 1
- 0
plp-angular/src/app/grid-cellrenderer/grid-date/grid-date-renderer/grid-date-renderer.component.html Datei anzeigen

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

+ 0
- 0
plp-angular/src/app/grid-cellrenderer/grid-date/grid-date-renderer/grid-date-renderer.component.scss Datei anzeigen


+ 27
- 0
plp-angular/src/app/grid-cellrenderer/grid-date/grid-date-renderer/grid-date-renderer.component.ts Datei anzeigen

@@ -0,0 +1,27 @@
import {Component} from '@angular/core';
import {GridRendererComponent} from '../../grid-renderer-component';

@Component({
selector: 'app-grid-date-renderer',
templateUrl: './grid-date-renderer.component.html',
styleUrls: ['./grid-date-renderer.component.scss']
})

export class GridDateRendererComponent extends GridRendererComponent {

public displayedValue: string;

/**
* Initialize cell renderer (gets called on cell rendering and after editing / refresh)
*/
agInit(params: any): void {
super.agInit(params);
let tempValue: string[] = [];
if (null === this.value || undefined === this.value) {
this.displayedValue = '';
} else {
tempValue = this.value.split('-');
this.displayedValue = tempValue[2] + '.' + tempValue[1] + '.' + tempValue[0];
}
}
}

+ 82
- 0
plp-angular/src/app/grid-cellrenderer/grid-editor-component.ts Datei anzeigen

@@ -0,0 +1,82 @@
import {Component, ElementRef, OnInit, ViewChild} from '@angular/core';
import {ICellEditorAngularComp} from 'ag-grid-angular';
import {IGridCellParams} from './grid-cell-params';

@Component({
template: '',
})

export class GridEditorComponent implements OnInit, ICellEditorAngularComp {

@ViewChild('editorInput', { static: true }) inputField: ElementRef;

readonly GRID_ERROR_EMPTY: string = 'Bitte geben Sie einen Wert ein.';
readonly GRID_ERROR_INT: string = 'Bitte geben Sie einen ganzahligen Wert ein.';
readonly GRID_ERROR_FLOAT: string = 'Bitte geben Sie einen dezimalen oder ganzzahligen Wert ein.';
readonly GRID_ERROR_RANGE_MIN: string = 'Minimaler Wert: ';
readonly GRID_ERROR_RANGE_MAX: string = 'Maximaler Wert: ';
readonly GRID_ERROR_RANGE_ALTERNATIVE: string = 'Alternativer Wert: ';

public value: any;
public params: any;
public cellParams: IGridCellParams;

constructor() {
this.cellParams = {} as IGridCellParams;
}

ngOnInit() {
}

/**
* Initialize cell renderer (gets called on cell rendering and after editing / refresh)
*/
agInit(params: any): void {
this.params = params;
this.cellParams.type = params.type;
this.cellParams.min = params.min;
this.cellParams.max = params.max;
this.cellParams.unit = params.unit;
this.cellParams.mandatory = params.mandatory;
this.cellParams.altVal = params.altVal;
this.value = params.value;
}

/**
* Returns value to cell renderer
*/
getValue(): any {
return this.value;
}

/**
* Cancels before value input (this editor is never editable)
*/
public isCancelBeforeStart(): boolean {
return false;
}

/**
* Cancels input of inserted value under certain conditions
*/
isCancelAfterEnd(): boolean {
return false;
}

/**
* Changes value on click
*/
public valueIsChanged = (e) => {
this.value = e.srcElement.value;
}


/**
* Sets focus
*/
public afterGuiAttached(): void {
this.inputField.nativeElement.focus();
this.inputField.nativeElement.select();
}

}

+ 20
- 0
plp-angular/src/app/grid-cellrenderer/grid-factory.ts Datei anzeigen

@@ -0,0 +1,20 @@
import {IGridCellParams} from './grid-cell-params';

export class GridFactory {
/**
* Returns param object for cell renderer and -editors
*/
static getGridCellParams(type: string = null, min: number = null,
max: number = null, unit: string = null,
mandatory: boolean = false, altValue: number = null): IGridCellParams {
const gridCellParams: IGridCellParams = {} as IGridCellParams;
gridCellParams.type = type;
gridCellParams.min = min;
gridCellParams.max = max;
gridCellParams.unit = unit;
gridCellParams.mandatory = mandatory;
gridCellParams.altVal = altValue;

return gridCellParams;
}
}

+ 1
- 0
plp-angular/src/app/grid-cellrenderer/grid-input/grid-input-editor/grid-input-editor.component.html Datei anzeigen

@@ -0,0 +1 @@
<input type="text" [required]="cellParams.mandatory" #editorInput (change)="valueIsChanged($event)" [(ngModel)]="value" value="{{value}}" />

+ 0
- 0
plp-angular/src/app/grid-cellrenderer/grid-input/grid-input-editor/grid-input-editor.component.scss Datei anzeigen


+ 107
- 0
plp-angular/src/app/grid-cellrenderer/grid-input/grid-input-editor/grid-input-editor.component.ts Datei anzeigen

@@ -0,0 +1,107 @@
import {Component} from '@angular/core';
import {GridEditorComponent} from '../../grid-editor-component';
import {AgGridComponentConst} from '../../../components/ag-grid-component-const';
import {Utils} from '../../../utils/utils';

@Component({
selector: 'app-grid-input-editor',
templateUrl: './grid-input-editor.component.html',
styleUrls: ['./grid-input-editor.component.scss']
})

export class GridInputEditorComponent extends GridEditorComponent {
/**
* Initialize cell renderer (gets called on cell rendering and after editing / refresh)
*/
agInit(params: any): void {
super.agInit(params);

if (this.cellParams !== undefined && this.cellParams.type === AgGridComponentConst.CELL_VALUE_TYPE_FLOAT) {
// Replace "." with "," for display purpose
this.value = isNaN(this.value) || null === this.value ? '' : parseFloat(this.value).toFixed(2).replace('.', ',');
}
}

/**
* Returns value to cell renderer
*/
getValue(): any {
if (this.cellParams !== undefined && this.cellParams.type === AgGridComponentConst.CELL_VALUE_TYPE_FLOAT) {
// Replace "." with "," for display purpose and cast back to number
this.value = this.value.replace(',', '.');
this.value = isNaN(this.value) || null === this.value ? '' : Number(parseFloat(this.value).toFixed(2));
}
return this.value;
}

/**
* Cancels input of inserted value under certain conditions
*/
isCancelAfterEnd(): boolean {
if (this.cellParams.mandatory && (null === this.value || this.value.toString().trim() === '')) {
// Null value or empty string
AgGridComponentConst.setGridInputError(this.GRID_ERROR_EMPTY);
return true;
}

if (this.cellParams.type === AgGridComponentConst.CELL_VALUE_TYPE_INT && !Utils.isInteger(this.value)) {
// No int value given
AgGridComponentConst.setGridInputError(this.GRID_ERROR_INT);
return true;
}

if (this.cellParams.type === AgGridComponentConst.CELL_VALUE_TYPE_FLOAT && !Utils.isFloat(this.value)) {
// No float value given
AgGridComponentConst.setGridInputError(this.GRID_ERROR_FLOAT);
return true;
}

if (this.cellParams.type === AgGridComponentConst.CELL_VALUE_TYPE_INT ||
this.cellParams.type === AgGridComponentConst.CELL_VALUE_TYPE_FLOAT) {
const numericVal: number = Number(String(this.value).replace(',', '.'));
if (null !== this.cellParams.min && numericVal < Number(this.cellParams.min)) {
// Check on alternative value
if (null !== this.cellParams.altVal) {
if (numericVal === this.cellParams.altVal) {
// Alternative value (to min and max) -> no error
return false;
} else {
// Value is not in range and not alternative value - cancel value input
AgGridComponentConst.setGridInputError(this.GRID_ERROR_RANGE_MIN + this.cellParams.min + ' (' + this.GRID_ERROR_RANGE_ALTERNATIVE + this.cellParams.altVal + ')');
return true;
}
} else {
// Value is not in range - cancel value input
AgGridComponentConst.setGridInputError(this.GRID_ERROR_RANGE_MIN + this.cellParams.min);
return true;
}
}
if (null !== this.cellParams.max && numericVal > Number(this.cellParams.max)) {
// Check on alternative value
if (null !== this.cellParams.altVal) {
if (numericVal === this.cellParams.altVal) {
// Alternative value (to min and max) -> no error
return false;
} else {
// Value is not in range and not alternative value - cancel value input
AgGridComponentConst.setGridInputError(this.GRID_ERROR_RANGE_MAX + this.cellParams.max + ' (' + this.GRID_ERROR_RANGE_ALTERNATIVE + this.cellParams.altVal + ')');
return true;
}
} else {
// Value is not in range - cancel value input
AgGridComponentConst.setGridInputError(this.GRID_ERROR_RANGE_MAX + this.cellParams.max);
return true;
}
}
}
return false;
}

/**
* Changes value on click
* todo maybe this should get refacotred properly?
*/
public valueIsChanged = (e) => {
this.value = e.srcElement.value;
}
}

+ 1
- 0
plp-angular/src/app/grid-cellrenderer/grid-input/grid-input-renderer/grid-input-renderer.component.html Datei anzeigen

@@ -0,0 +1 @@
{{value}}<span *ngIf="cellParams.unit != null">{{cellParams.unit}}</span>

+ 0
- 0
plp-angular/src/app/grid-cellrenderer/grid-input/grid-input-renderer/grid-input-renderer.component.scss Datei anzeigen


+ 27
- 0
plp-angular/src/app/grid-cellrenderer/grid-input/grid-input-renderer/grid-input-renderer.component.ts Datei anzeigen

@@ -0,0 +1,27 @@
import {Component} from '@angular/core';
import {GridRendererComponent} from '../../grid-renderer-component';
import {AgGridComponentConst} from '../../../components/ag-grid-component-const';

@Component({
selector: 'app-grid-input-renderer',
templateUrl: './grid-input-renderer.component.html',
styleUrls: ['./grid-input-renderer.component.scss']
})

export class GridInputRendererComponent extends GridRendererComponent {
/**
* Initialize cell renderer (gets called on cell rendering and after editing / refresh)
*/
agInit(params: any): void {
super.agInit(params);
if (this.cellParams !== undefined) {
// Replace "." with "," for display purpose
if (this.cellParams.type === AgGridComponentConst.CELL_VALUE_TYPE_FLOAT) {
this.value = isNaN(this.value) || null === this.value ? '' : parseFloat(parseFloat(this.value).toFixed(2)).toLocaleString('de-DE');
}
if (this.cellParams.type === AgGridComponentConst.CELL_VALUE_TYPE_INT) {
this.value = isNaN(this.value) || null === this.value ? '' : parseInt(parseInt(this.value).toFixed(2)).toLocaleString('de-DE');
}
}
}
}

+ 49
- 0
plp-angular/src/app/grid-cellrenderer/grid-renderer-component.ts Datei anzeigen

@@ -0,0 +1,49 @@
import {Component, OnInit} from '@angular/core';
import {ICellRendererAngularComp} from 'ag-grid-angular';
import {IGridCellParams} from './grid-cell-params';

@Component({
template: '',
})

export class GridRendererComponent implements OnInit, ICellRendererAngularComp {

public value: any;
public params: any;
public cellParams: IGridCellParams;

constructor() {
this.cellParams = {} as IGridCellParams;
}

ngOnInit() {
}

/**
* Initialize cell renderer (gets called on cell rendering and after editing / refresh)
*/
agInit(params: any): void {
this.params = params;
this.cellParams.type = params.type;
this.cellParams.min = params.min;
this.cellParams.max = params.max;
this.cellParams.unit = params.unit;
this.cellParams.mandatory = params.mandatory;
this.value = params.value;
}

/**
* Sets value
*/
setValue(value: any): void {
this.value = value;
}

/**
* Refreshes cell - Gets called after editing
*/
refresh(params: any): boolean {
return false;
}

}

+ 4
- 0
plp-angular/src/app/grid-cellrenderer/grid-select/grid-select-editor/grid-select-editor.component.html Datei anzeigen

@@ -0,0 +1,4 @@
<select *ngIf="!noValueAvailable" (change)="getSelectedItem($event.target.value)">
<option *ngFor="let v of values" value="{{v.key}}" [selected]="v.key == selectedItem.key">{{v.value}}</option>
</select>
<ng-container *ngIf="noValueAvailable">Keine Werte vorhanden</ng-container>

+ 8
- 0
plp-angular/src/app/grid-cellrenderer/grid-select/grid-select-editor/grid-select-editor.component.scss Datei anzeigen

@@ -0,0 +1,8 @@


/* NOTE: column width 100% (app-grid-select-editor) in basic.scss */

select {
width: 100%;
max-width: 250px;
}

+ 104
- 0
plp-angular/src/app/grid-cellrenderer/grid-select/grid-select-editor/grid-select-editor.component.ts Datei anzeigen

@@ -0,0 +1,104 @@
import {Component} from '@angular/core';
import {IGridSelectItem} from '../grid-select-item';
import {GridEditorComponent} from '../../grid-editor-component';
import {GridSelectFactory} from '../grid-select-factory';
import {IGridCellEditorParams} from '../../grid-cell-editor-params';

@Component({
selector: 'app-grid-select-editor',
templateUrl: './grid-select-editor.component.html',
styleUrls: ['./grid-select-editor.component.scss']
})

export class GridSelectEditorComponent extends GridEditorComponent {

public values: IGridSelectItem[];
public selectedItem: IGridSelectItem;
public newValue: IGridSelectItem;
public itemKey: string;
public itemValueKeys: string[];
public noValueAvailable: boolean;

/**
* Initialize select editor (called after double-click)
*/
agInit(params: any): void {
super.agInit(params);
this.noValueAvailable = false;
const cellEditorParams: IGridCellEditorParams = params.column.colDef.cellEditorParams as IGridCellEditorParams;
this.values = [];

this.itemKey = cellEditorParams.itemKey;
this.itemValueKeys = cellEditorParams.itemValueKeys;
const relatedValue: string | null = cellEditorParams.relatesOnDgField;

if (null !== relatedValue) {
const itemRange: any[] = (params.node.data.hasOwnProperty(relatedValue) && null !== params.node.data[relatedValue]) ?
cellEditorParams.values[params.node.data[relatedValue]] : null;

if (null !== itemRange && undefined !== itemRange) {
itemRange.forEach(item => {
this.values.push(GridSelectFactory.getGridSelectItem(item, this.itemKey, this.itemValueKeys));
});
}

} else if (cellEditorParams.exclusive === true) {
// Filter all items used by other selects (compareData)
const compareExcludeKey: string = cellEditorParams.exclusiveCompareDataKey;
const excludedItemKeys: {} = {};
cellEditorParams.exclusiveCompareData.forEach(item => {
if (item[compareExcludeKey] !== this.value) {
excludedItemKeys[item[compareExcludeKey]] = 1;
}
});
// This select contains only values that are not selected by other selects and it's own current item
cellEditorParams.values.forEach(item => {
if (!excludedItemKeys.hasOwnProperty(item[this.itemKey])) {
this.values.push(GridSelectFactory.getGridSelectItem(item, this.itemKey, this.itemValueKeys));
}
});
} else {
// Static values (default behaviour)
this.values = params.values;
}
this.selectedItem = this.getSelectedItem(params.value);
}

/**
* Returns value to cell renderer
*/
getValue(): any {
return null === this.newValue ?? this.newValue.key;
}

/**
* Makes selectItem out of ID
*/
public getSelectedItem(e: any): IGridSelectItem {
if (null !== e && e !== '') {
for (const item of this.values) {
if (item.key === e) {
this.newValue = item;
break;
}
}
} else {
if (this.values.length > 0) {
this.newValue = this.values[0];
} else {
// No value in select available
this.noValueAvailable = true;
this.newValue = null;
return;
}
}
return this.newValue;
}

/**
* Overwrite
*/
public afterGuiAttached(): void {
// do nothing
}
}

+ 123
- 0
plp-angular/src/app/grid-cellrenderer/grid-select/grid-select-factory.ts Datei anzeigen

@@ -0,0 +1,123 @@
import {Const} from '../../utils/const';
import {IGridSelectItem} from './grid-select-item';


export class GridSelectFactory {
/**
* Returns select item for grid
*/
static getGridSelect(headerName: string, field: string, editable: boolean, values: any[], itemKey: string,
itemValueKeys: string[], mandatory: boolean = true, relatesOnDgField: string = null,
headerClass: string = null, pinned: boolean = false, cellClass: any = null,
exclusive: boolean = false, exclusiveCompareData: any = null, exclusiveCompareDataKey: string = null): {} {

if (null !== relatesOnDgField && exclusive) {
// NOTE: This is not allowed for now, maybe needed in future
throw new Error('Select can be either relative or exclusive');
}

const res = {
headerName,
field,
headerClass,
pinned,
editable,
cellClass: null === cellClass ?? (editable ? '' : Const.CSS_NO_EDIT),
cellRenderer: 'gridSelectRenderer',
cellEditor: 'gridSelectEditor',
cellEditorParams: {
values: null === relatesOnDgField && !exclusive ? GridSelectFactory.getGridSelectItems(values, itemKey, itemValueKeys, mandatory) : values,
itemKey,
itemValueKeys,
mandatory,
relatesOnDgField,
exclusive,
exclusiveCompareData,
exclusiveCompareDataKey
}
};
if (mandatory) {
res['cellClassRules'] = {
error(params) {
return params.value == null;
}
};
}
return res;
}

/**
* Returns select item for grid without renderer and editor
*/
static getGridSelectForSelectors(headerName: string, field: string, editable: boolean, values: any[], itemKey: string,
itemValueKeys: string[], mandatory: boolean = true, relatesOnDgField: string = null,
headerClass: string = null, pinned: boolean = false, cellClass: any = null,
exclusive: boolean = false, exclusiveCompareData: any = null, exclusiveCompareDataKey: string = null): {} {

const res: {} = GridSelectFactory.getGridSelect(
headerName, field, editable, values, itemKey, itemValueKeys, mandatory, relatesOnDgField,
headerClass, pinned, cellClass, exclusive, exclusiveCompareData, exclusiveCompareDataKey
);
delete res['cellRenderer'];
delete res['cellEditor'];
return res;
}

/**
* Returns array of grid select items
*/
static getGridSelectItems(objArray: any[], key: string, valueKeys: string[], mandatory: boolean = true): IGridSelectItem[] {
const res: IGridSelectItem[] = [];

if (!mandatory) {
// Add empty item (null value)
res.push(GridSelectFactory.getGridSelectItem({key: null, value: '-'}, 'key', valueKeys, true));
}

objArray.forEach(item => {
res.push(GridSelectFactory.getGridSelectItem(item, key, valueKeys));
});
return res;
}

/**
* Returns single grid select item
*/
static getGridSelectItem(obj: any, key: string, valueKeys: string[], isNullItem: boolean = false): IGridSelectItem {
if (!obj.hasOwnProperty(key)) {
throw new Error('GridFactory: Key not found: ' + key);
}

let gridItem: {} = {};
if (!isNullItem) {
for (const item of valueKeys) {
if (!obj.hasOwnProperty(key) || !obj.hasOwnProperty(item)) {
throw new Error('GridFactory: Value not found: ' + item);
}
}
gridItem = {
key: obj[key],
value: GridSelectFactory.getGridSelectItemValue(obj, valueKeys)
};
} else {
// Empty placeholder item
gridItem = {
key: obj.key,
value: obj.value
};
}
return gridItem as IGridSelectItem;
}

/**
* Returns displayed value of grid item
*/
static getGridSelectItemValue(obj: any, valueKeys: string[]): string {
let value = '';
for (let i = 0; i < valueKeys.length; i++) {
value += obj[valueKeys[i]];
value += i < (valueKeys.length - 1) ? ' - ' : '';
}
return value;
}
}

+ 4
- 0
plp-angular/src/app/grid-cellrenderer/grid-select/grid-select-item.ts Datei anzeigen

@@ -0,0 +1,4 @@
export interface IGridSelectItem {
key: string;
value: string;
}

+ 1
- 0
plp-angular/src/app/grid-cellrenderer/grid-select/grid-select-renderer/grid-select-renderer.component.html Datei anzeigen

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

+ 0
- 0
plp-angular/src/app/grid-cellrenderer/grid-select/grid-select-renderer/grid-select-renderer.component.scss Datei anzeigen


+ 83
- 0
plp-angular/src/app/grid-cellrenderer/grid-select/grid-select-renderer/grid-select-renderer.component.ts Datei anzeigen

@@ -0,0 +1,83 @@
import {Component} from '@angular/core';
import {IGridSelectItem} from '../grid-select-item';
import {GridRendererComponent} from '../../grid-renderer-component';
import {GridSelectFactory} from '../grid-select-factory';

@Component({
selector: 'app-grid-select-renderer',
templateUrl: './grid-select-renderer.component.html',
styleUrls: ['./grid-select-renderer.component.scss']
})

export class GridSelectRendererComponent extends GridRendererComponent {

public itemRange: IGridSelectItem[];
public currentIndex: number;

constructor() {
super();
this.itemRange = null;
this.currentIndex = null;
}

/**
* Initialize cell renderer (gets called on cell rendering and after editing / refresh)
*/
agInit(params: any): void {
super.agInit(params);
if (null === params.colDef.cellEditorParams.relatesOnDgField) {
// Static item range (default behaviour)
this.setStaticValue(params);
} else {
// Item range relates on other dg field
this.setRelatedValue(params);
}
}

/**
* Case for static item range (all items in column have the same select items - default)
*/
private setStaticValue(params: any): void {
if (this.itemRange === null || undefined === this.itemRange) {
// Item range is the same for all rows
this.itemRange = params.colDef.cellEditorParams.values as IGridSelectItem[];
if (null !== params.value) {
for (const item of this.itemRange) {
if (item.key === params.value) {
this.value = item.value;
break;
}
}
} else {
this.value = params.colDef.cellEditorParams.mandatory ? 'Bitte wählen' : '';
}
}
}

/**
* Case for item range related on other dg grid field (Select has always to be updated within init)
*/
private setRelatedValue(params: any): void {
// @TODO: Might be checked
const relatedValue: any = params.colDef.cellEditorParams.relatesOnDgField;
const itemKey: any = params.colDef.cellEditorParams.itemKey;
const itemValueKeys: string[] = params.colDef.cellEditorParams.itemValueKeys;

// Get item range by related value
this.itemRange = params.data.hasOwnProperty(relatedValue) && null !== params.data[relatedValue] ?
params.colDef.cellEditorParams.values[params.data[relatedValue]] : null;

if (null !== params.value && null !== this.itemRange) {
// let value: string = GridFactory.getGridSelectItemValue()
for (const item of this.itemRange) {
if (item[itemKey] === params.value) {
this.value = GridSelectFactory.getGridSelectItemValue(item, itemValueKeys);
break;
}
}
} else {
this.value = 'Bitte wählen';
}
}

}

+ 0
- 0
plp-angular/src/app/grid-cellrenderer/grid-text/grid-text-editor/grid-text-editor.component.html Datei anzeigen


+ 0
- 0
plp-angular/src/app/grid-cellrenderer/grid-text/grid-text-editor/grid-text-editor.component.scss Datei anzeigen


+ 24
- 0
plp-angular/src/app/grid-cellrenderer/grid-text/grid-text-editor/grid-text-editor.component.ts Datei anzeigen

@@ -0,0 +1,24 @@
import {Component} from '@angular/core';
import {GridEditorComponent} from '../../grid-editor-component';

@Component({
selector: 'app-grid-text-editor',
templateUrl: './grid-text-editor.component.html',
styleUrls: ['./grid-text-editor.component.scss']
})

export class GridTextEditorComponent extends GridEditorComponent {
/**
* Cancels before value input (this editor is never editable)
*/
public isCancelBeforeStart(): boolean {
return true;
}

/**
* Overwrite
*/
public afterGuiAttached(): void {
// do nothing
}
}

+ 1
- 0
plp-angular/src/app/grid-cellrenderer/grid-text/grid-text-renderer/grid-text-renderer.component.html Datei anzeigen

@@ -0,0 +1 @@
<div class="text-renderer">{{value}}</div>

+ 0
- 0
plp-angular/src/app/grid-cellrenderer/grid-text/grid-text-renderer/grid-text-renderer.component.scss Datei anzeigen


+ 27
- 0
plp-angular/src/app/grid-cellrenderer/grid-text/grid-text-renderer/grid-text-renderer.component.ts Datei anzeigen

@@ -0,0 +1,27 @@
import {Component} from '@angular/core';
import {GridRendererComponent} from '../../grid-renderer-component';
import {AgGridComponentConst} from '../../../components/ag-grid-component-const';

@Component({
selector: 'app-grid-text-renderer',
templateUrl: './grid-text-renderer.component.html',
styleUrls: ['./grid-text-renderer.component.scss']
})

export class GridTextRendererComponent extends GridRendererComponent {
/**
* Initialize cell renderer (gets called on cell rendering and after editing / refresh)
*/
agInit(params: any): void {
super.agInit(params);
if (undefined !== this.cellParams) {
// Replace "." with "," for display purpose
if (this.cellParams.type === AgGridComponentConst.CELL_VALUE_TYPE_FLOAT) {
this.value = isNaN(this.value) || null === this.value ? '' : parseFloat(parseFloat(this.value).toFixed(2)).toLocaleString('de-DE');
}
if (this.cellParams.type === AgGridComponentConst.CELL_VALUE_TYPE_INT) {
this.value = isNaN(this.value) || null === this.value? '' : this.value = parseInt(parseInt(this.value).toFixed(2)).toLocaleString('de-DE');
}
}
}
}

+ 34
- 0
plp-angular/src/app/interceptor/route-interceptor.ts Datei anzeigen

@@ -0,0 +1,34 @@
import {Injectable} from '@angular/core';
import { Router } from '@angular/router';
import {AppService} from '../services/app.service';
import {Subscription} from 'rxjs/index';
import {ILoginState} from '../model/virtual/login-state';

@Injectable({
providedIn: 'root'
})
export class RouteInterceptor {
private loginSub: Subscription;
private loginState: ILoginState;

/**
* Constructor of router service
*/
constructor(private router: Router, private appService: AppService) {
// Observe login state
this.loginSub = this.appService.getLoginState$().subscribe(
data => this.loginState = data);
}

/**
* Checks if user is logged in and redirects to login page if not
* @returns {boolean}
*/
canActivate(): boolean {
if (this.loginState == null || !this.loginState.isLoggedIn) {
this.router.navigate(['./login']);
return false;
}
return true;
}
}

+ 96
- 0
plp-angular/src/app/lang/ag-gridlocale.ts Datei anzeigen

@@ -0,0 +1,96 @@
export class AgGridLocale {
static getLocale(): {} {
return {
// for filter panel
page: 'Seite',
more: 'mehr',
to: 'bis',
of: 'von',
next: 'nächstes',
last: 'letztes',
first: 'erstes',
previous: 'vorheriges',
loadingOoo: 'lade...',

// for set filter
selectAll: 'Alle auswählen',
searchOoo: 'Suche...',
blanks: 'leer',

// for number filter and text filter
filterOoo: 'Filter...',
applyFilter: 'Filter anwenden...',
equals: 'gleich',
notEquals: 'nicht gleich',
notEqual: 'nicht gleich',

// for number filter
lessThan: 'weniger als',
greaterThan: 'größer als',
lessThanOrEqual: 'weniger oder gleich',
greaterThanOrEqual: 'größer oder gleich',
inRange: 'in Spanne',

// for text filter
contains: 'beinhaltet',
notContains: 'beinhaltet nicht',
startsWith: 'beginnt mit',
endsWith: 'endet mit',

// the header of the default group column
group: 'Gruppe',

// tool panel
columns: 'Spalten',
filters: 'Filter',
rowGroupColumns: 'Pivot Spalten',
rowGroupColumnsEmptyMessage: 'Ziehe Spalten in Gruppe',
valueColumns: 'Spalten Werte',
pivotMode: 'Pivot-Mode',
groups: 'Gruppen',
values: 'Werte',
pivots: 'Pivots',
valueColumnsEmptyMessage: 'Ziehe Spalten zum zusammen',
pivotColumnsEmptyMessage: 'Für Pivot hierher ziehen',
toolPanelButton: 'Tool Feld',

// other
noRowsToShow: 'Keine Zeilen',

// enterprise menu
pinColumn: 'Spalte anpinnen',
valueAggregation: 'Agg Wert',
autosizeThiscolumn: 'Auto-Breite für diese Spalte',
autosizeAllColumns: 'Auto-Breite für alle Spalte',
groupBy: 'Gruppieren nach',
ungroupBy: 'Gruppierung aufheben nach',
resetColumns: 'Spalten zurücksetzen',
expandAll: 'Alle öffnen',
collapseAll: 'Alle schließen',
toolPanel: 'Tool Feld',
export: 'Export',
csvExport: 'CSV Export',
excelExport: 'Excel Export',

// enterprise menu pinning
pinLeft: 'Anpinnen <<',
pinRight: 'Anpinnen >>',
noPin: 'Nicht anpinnen <>',

// enterprise menu aggregation and status bar
sum: 'Summe',
min: 'Min',
max: 'Max',
none: 'Nichts',
count: 'Anzahl',
average: 'Durchschnitt',

// standard menu
copy: 'Kopieren',
copyWithHeaders: 'Mit Köpfen kopieren',
ctrlC: 'strg und C',
paste: 'Einfügen',
ctrlV: 'strg und V'
};
}
}

+ 24
- 0
plp-angular/src/app/model/constants/tools.ts Datei anzeigen

@@ -0,0 +1,24 @@
// The file contents for the current environment will overwrite these during build.
// The build system defaults to the dev environment which uses `environment.ts`, but if you do
// `ng build --env=prod` then `environment.prod.ts` will be used instead.
// The list of which env maps to which file can be found in `.angular-cli.json`.

export const tools = {
ROLE_ADMIN: 'ROLE_ADMIN',
ROLE_SALES: 'ROLE_SALES',
ROLE_TECHNIQUE: 'ROLE_TECHNIQUE',
ROLE_PRODUCTION: 'ROLE_PRODUCTION',
ROLE_ACCOUNTING: 'ROLE_ACCOUNTING',
ROLE_SERVICE: 'ROLE_SERVICE',

COLORS: [
'#4397d4', // blue
'#b56cdc', // purple
'#dd6bbe', // pink
'#45d4a7', // green
'#fede62', // yellow
'#fdb753', // orange
'#808080', // grey
'#363636' // black
],
};

+ 5
- 0
plp-angular/src/app/model/entities/calendar-legend.ts Datei anzeigen

@@ -0,0 +1,5 @@
export interface ICalendarLegend {
id: number;
type: string;
name: string;
}

+ 5
- 0
plp-angular/src/app/model/entities/country.ts Datei anzeigen

@@ -0,0 +1,5 @@
export interface ICountry {
id: number;
name: string;
iso_code: string;
}

+ 21
- 0
plp-angular/src/app/model/entities/customer-contact.ts Datei anzeigen

@@ -0,0 +1,21 @@
import {EntityInterface} from '../interface/entity-interface';

export interface ICustomerContact extends EntityInterface {
customer_id: string;
gender: string;
firstname: string;
lastname: string;
email: string;
phone_no: string;
mobile_no: string;
fax_no: string;
department: string;
date_of_birth: string;
comment: string;
street: string;
street_no: string;
zip: string;
city: string;
country_id: number;
is_xmas_mail_recipient: boolean;
}

+ 6
- 0
plp-angular/src/app/model/entities/customer-meeting-participant.ts Datei anzeigen

@@ -0,0 +1,6 @@
import {EntityInterface} from '../interface/entity-interface';

export interface ICustomerMeetingParticipant extends EntityInterface {
customer_meeting_id: number;
participant_user_id: number;
}

+ 24
- 0
plp-angular/src/app/model/entities/customer-meeting.ts Datei anzeigen

@@ -0,0 +1,24 @@
import {EntityInterface} from '../interface/entity-interface';
import {ICustomerMeetingParticipant} from './customer-meeting-participant';
import {MeetingInterface} from '../interface/meeting-interface';

export interface ICustomerMeeting extends EntityInterface, MeetingInterface {
customer_id: number;
meeting_type_id: number;
is_option_meeting: boolean;
customer_contact_id: number;
gender: string;
firstname: string;
lastname: string;
email: string;
phone_no: string;
mobile_no: string;
department: string;
street: string;
street_no: string;
zip: string;
city: string;
country_id: number;
v_participants: ICustomerMeetingParticipant[];
v_is_editable: boolean;
}

+ 22
- 0
plp-angular/src/app/model/entities/customer-note.ts Datei anzeigen

@@ -0,0 +1,22 @@
import {EntityInterface} from '../interface/entity-interface';

export interface ICustomerNote extends EntityInterface {
customer_id: number;
customer_contact_id: number;
user_id: number;
gender: string;
firstname: string;
lastname: string;
email: string;
phone_no: string;
mobile_no: string;
fax_no: string;
department: string;
title: string;
comment: string;
note_date: string;
creation_date: string;
creation_user_id: number;
creation_user_firstname: string;
creation_user_lastname: string;
}

+ 26
- 0
plp-angular/src/app/model/entities/customer.ts Datei anzeigen

@@ -0,0 +1,26 @@
import {ICustomerContact} from './customer-contact';
import {EntityInterface} from '../interface/entity-interface';
import {ICustomerMeeting} from './customer-meeting';
import {ICustomerNote} from './customer-note';

export interface ICustomer extends EntityInterface {
old_plp_id: string;
name: string;
name_additional: string;
consultant_user_id: number;
street: string;
street_no: string;
zip: string;
city: string;
country_id: number;
url: string;
email: string;
phone_no: string;
mobile_no: string;
fax_no: string;
comment: string;
active: boolean;
v_customer_contacts: ICustomerContact[];
v_customer_notes: ICustomerNote[];
v_customer_meetings: ICustomerMeeting[];
}

+ 6
- 0
plp-angular/src/app/model/entities/internal-meeting-participant.ts Datei anzeigen

@@ -0,0 +1,6 @@
import {EntityInterface} from '../interface/entity-interface';

export interface IInternalMeetingParticipant extends EntityInterface {
internal_meeting_id: number;
participant_user_id: number;
}

+ 9
- 0
plp-angular/src/app/model/entities/internal-meeting.ts Datei anzeigen

@@ -0,0 +1,9 @@
import {EntityInterface} from '../interface/entity-interface';
import {IInternalMeetingParticipant} from './internal-meeting-participant';
import {MeetingInterface} from '../interface/meeting-interface';

export interface IInternalMeeting extends EntityInterface, MeetingInterface {
creation_user_id: number;
v_participants: IInternalMeetingParticipant[];
v_is_editable: boolean;
}

+ 6
- 0
plp-angular/src/app/model/entities/meeting-type.ts Datei anzeigen

@@ -0,0 +1,6 @@
import {EntityInterface} from '../interface/entity-interface';

export interface IMeetingType extends EntityInterface {
type: string;
name: string;
}

+ 7
- 0
plp-angular/src/app/model/entities/user-type.ts Datei anzeigen

@@ -0,0 +1,7 @@
import {EntityInterface} from '../interface/entity-interface';

export interface IUserType extends EntityInterface {
user_type_id: number;
type: string;
v_roles: string[];
}

+ 12
- 0
plp-angular/src/app/model/entities/user.ts Datei anzeigen

@@ -0,0 +1,12 @@
import {IUserType} from './user-type';
import {EntityInterface} from '../interface/entity-interface';

export interface IUser extends EntityInterface {
email: string;
firstname: string;
lastname: string;
active: boolean;
visible: boolean;
v_translated_role: string;
v_user_type: IUserType;
}

Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden.

Laden…
Abbrechen
Speichern