TSK-981: Provide frontend formatter for common IDEs (#1187)

* TSK-981: tested adding prettier

* TSK-981: Refined prettier and eslint configs

* TSK-981: Update eslint rules

* TSK-981: Updated VS Code settings and ignore folders

* TSK-981: Added editor config

* TSK-981: added html to prettierignore

* TSK-981: tested adding prettier

* TSK-981: Refined prettier and eslint configs

* TSK-981: Update eslint rules

* TSK-981: Updated VS Code settings and ignore folders

* TSK-981: Added editor config

* TSK-981: added html to prettierignore

* TSK-981: reformatted code using prettier/new eslint configs
This commit is contained in:
Chi Nguyen 2020-07-22 10:44:33 +02:00 committed by GitHub
parent 59b45f626a
commit 29e468e6aa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
230 changed files with 3479 additions and 2983 deletions

14
web/.editorconfig Normal file
View File

@ -0,0 +1,14 @@
# Editor configuration, see http://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
max_line_length = off
trim_trailing_whitespace = false

View File

@ -1,42 +1,17 @@
module.exports = { module.exports = {
"extends": [ extends: ['prettier/@typescript-eslint', 'plugin:prettier/recommended'],
"airbnb-typescript/base" env: {
], browser: true,
"env": { node: true
"browser": true,
"node": true
}, },
"parser": "@typescript-eslint/parser", parser: '@typescript-eslint/parser',
"parserOptions": { parserOptions: {
"project": "tsconfig.json", ecmaVersion: 2018,
sourceType: 'module',
project: './tsconfig.json',
errorOnUnknownASTType: true,
errorOnTypeScriptSyntacticAndSemanticIssues: true
}, },
"plugins": [ plugins: ['@typescript-eslint', '@typescript-eslint/tslint'],
"@typescript-eslint", rules: {}
"@typescript-eslint/tslint"
],
"rules": {
"arrow-parens": ["error", "as-needed"],
"@typescript-eslint/indent": ['error', 2],
"max-len": ["error", { "code": 140, "ignorePattern": "import *" }], // smaller than 140?
"object-curly-newline": ["error", { "ImportDeclaration": "never" }],
"quote-props": ["error", "as-needed"],
"lines-between-class-members": ["error", "always", { "exceptAfterSingleLine": true }],
"comma-dangle": ["error", "only-multiline"],
"no-underscore-dangle": ["error", { "allow": ["_links", "__karma__"] }],
"no-param-reassign": ["error", { "props": false }],
"no-plusplus" : ["error", { "allowForLoopAfterthoughts": true }],
"@typescript-eslint/no-use-before-define": ["error", { "functions": false, "classes": false }],
"@typescript-eslint/no-unused-expressions": ["error", { "allowTernary": true }],
// all following rules SHOULD be removed
"class-methods-use-this": "off",
"import/extensions": "off",
"import/no-unresolved": "off",
"import/prefer-default-export": "off",
"max-classes-per-file": "off",
"@typescript-eslint/no-unused-vars": "off",
// all following rules MUST be removed (mostly autofix)
"linebreak-style": ["off", "unix"], // own PR
}
}; };

12
web/.prettierignore Normal file
View File

@ -0,0 +1,12 @@
*.lint.ts
**/node_modules/**
.github/**
.idea/**
.cache/**
.vscode/**
dist*/**
build/**
coverage/**
**/dist/**
out-tsc/**
**/*.html

8
web/.prettierrc.js Normal file
View File

@ -0,0 +1,8 @@
module.exports = {
tabWidth: 2,
semi: true,
singleQuote: true,
bracketSpacing: true,
printWidth: 120,
trailingComma: 'none'
};

15
web/.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,15 @@
{
"eslint.validate": [ "javascript", "typescript", "html"],
"eslint.options": {
"extensions": [".js", ".ts", "html"]
},
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true,
},
"[html]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "vscode.html-language-features"
}
}

View File

@ -16,14 +16,8 @@
"main": "src/main.ts", "main": "src/main.ts",
"tsConfig": "src/tsconfig.app.json", "tsConfig": "src/tsconfig.app.json",
"polyfills": "src/polyfills.ts", "polyfills": "src/polyfills.ts",
"assets": [ "assets": ["src/assets", "src/environments/data-sources"],
"src/assets", "styles": ["./node_modules/@angular/material/prebuilt-themes/indigo-pink.css", "src/theme/_main.scss"],
"src/environments/data-sources"
],
"styles": [
"./node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
"src/theme/_main.scss"
],
"scripts": [ "scripts": [
"node_modules/jquery/dist/jquery.min.js", "node_modules/jquery/dist/jquery.min.js",
"node_modules/popper.js/dist/umd/popper.min.js", "node_modules/popper.js/dist/umd/popper.min.js",
@ -80,23 +74,14 @@
"node_modules/popper.js/dist/umd/popper.min.js", "node_modules/popper.js/dist/umd/popper.min.js",
"node_modules/bootstrap/dist/js/bootstrap.min.js" "node_modules/bootstrap/dist/js/bootstrap.min.js"
], ],
"styles": [ "styles": ["./node_modules/@angular/material/prebuilt-themes/indigo-pink.css", "src/theme/_main.scss"],
"./node_modules/@angular/material/prebuilt-themes/indigo-pink.css", "assets": ["src/assets", "src/environments/data-sources"]
"src/theme/_main.scss"
],
"assets": [
"src/assets",
"src/environments/data-sources"
]
} }
}, },
"lint": { "lint": {
"builder": "@angular-devkit/build-angular:tslint", "builder": "@angular-devkit/build-angular:tslint",
"options": { "options": {
"tsConfig": [ "tsConfig": ["src/tsconfig.app.json", "src/tsconfig.spec.json"],
"src/tsconfig.app.json",
"src/tsconfig.spec.json"
],
"exclude": [] "exclude": []
} }
} }

View File

@ -1,13 +1,13 @@
var SeedReporter = function(baseReporterDecorator) { var SeedReporter = function (baseReporterDecorator) {
baseReporterDecorator(this); baseReporterDecorator(this);
this.onBrowserComplete = function(browser, result) { this.onBrowserComplete = function (browser, result) {
if (result.order && result.order.random && result.order.seed) { if (result.order && result.order.random && result.order.seed) {
this.write("%s: Randomized with seed %s\n", browser, result.order.seed); this.write('%s: Randomized with seed %s\n', browser, result.order.seed);
} }
}; };
}; };
module.exports = { module.exports = {
"reporter:jasmine-seed": ["type", SeedReporter] 'reporter:jasmine-seed': ['type', SeedReporter]
}; };

View File

@ -21,23 +21,21 @@ module.exports = function (config) {
}, },
clearContext: false // leave Jasmine Spec Runner output visible in browser clearContext: false // leave Jasmine Spec Runner output visible in browser
}, },
files: [ files: [],
preprocessors: {},
],
preprocessors: {
},
mime: { mime: {
'text/x-typescript': ['ts', 'tsx'] 'text/x-typescript': ['ts', 'tsx']
}, },
coverageIstanbulReporter: { coverageIstanbulReporter: {
dir: require('path').join(__dirname, 'coverage'), reports: ['html', 'lcovonly'], dir: require('path').join(__dirname, 'coverage'),
reports: ['html', 'lcovonly'],
fixWebpackSourcePaths: true fixWebpackSourcePaths: true
}, },
reporters: config.angularCli && config.angularCli.codeCoverage reporters:
? ['progress', 'coverage-istanbul', 'jasmine-seed'] config.angularCli && config.angularCli.codeCoverage
: ['progress', 'kjhtml', 'jasmine-seed'], ? ['progress', 'coverage-istanbul', 'jasmine-seed']
: ['progress', 'kjhtml', 'jasmine-seed'],
port: 9876, port: 9876,
colors: true, colors: true,
logLevel: config.LOG_INFO, logLevel: config.LOG_INFO,

67
web/package-lock.json generated
View File

@ -665,6 +665,7 @@
"dev": true, "dev": true,
"optional": true, "optional": true,
"requires": { "requires": {
"bindings": "^1.5.0",
"nan": "^2.12.1" "nan": "^2.12.1"
} }
}, },
@ -3166,6 +3167,16 @@
"integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==", "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==",
"dev": true "dev": true
}, },
"bindings": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
"integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
"dev": true,
"optional": true,
"requires": {
"file-uri-to-path": "1.0.0"
}
},
"blob": { "blob": {
"version": "0.0.5", "version": "0.0.5",
"resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz", "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz",
@ -5397,6 +5408,23 @@
"eslint-config-airbnb-base": "^14.0.0" "eslint-config-airbnb-base": "^14.0.0"
} }
}, },
"eslint-config-prettier": {
"version": "6.11.0",
"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.11.0.tgz",
"integrity": "sha512-oB8cpLWSAjOVFEJhhyMZh6NOEOtBVziaqdDQ86+qhDHFbZXoRTM7pNSvFRfW/W/L/LrQ38C99J5CGuRBBzBsdA==",
"dev": true,
"requires": {
"get-stdin": "^6.0.0"
},
"dependencies": {
"get-stdin": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz",
"integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==",
"dev": true
}
}
},
"eslint-import-resolver-node": { "eslint-import-resolver-node": {
"version": "0.3.4", "version": "0.3.4",
"resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz", "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz",
@ -5654,6 +5682,15 @@
} }
} }
}, },
"eslint-plugin-prettier": {
"version": "3.1.4",
"resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.4.tgz",
"integrity": "sha512-jZDa8z76klRqo+TdGDTFJSavwbnWK2ZpqGKNZ+VvweMW516pDUMmQ2koXvxEE4JhzNvTv+radye/bWGBmA6jmg==",
"dev": true,
"requires": {
"prettier-linter-helpers": "^1.0.0"
}
},
"eslint-scope": { "eslint-scope": {
"version": "4.0.3", "version": "4.0.3",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz",
@ -6044,6 +6081,12 @@
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
}, },
"fast-diff": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz",
"integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==",
"dev": true
},
"fast-glob": { "fast-glob": {
"version": "3.2.4", "version": "3.2.4",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.4.tgz", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.4.tgz",
@ -6132,6 +6175,13 @@
"resolved": "https://registry.npmjs.org/file-saver/-/file-saver-1.3.3.tgz", "resolved": "https://registry.npmjs.org/file-saver/-/file-saver-1.3.3.tgz",
"integrity": "sha1-zdTETTqiZOrC9o7BZbx5HDSvEjI=" "integrity": "sha1-zdTETTqiZOrC9o7BZbx5HDSvEjI="
}, },
"file-uri-to-path": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
"dev": true,
"optional": true
},
"fileset": { "fileset": {
"version": "2.0.3", "version": "2.0.3",
"resolved": "https://registry.npmjs.org/fileset/-/fileset-2.0.3.tgz", "resolved": "https://registry.npmjs.org/fileset/-/fileset-2.0.3.tgz",
@ -10116,6 +10166,21 @@
"integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=",
"dev": true "dev": true
}, },
"prettier": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.0.5.tgz",
"integrity": "sha512-7PtVymN48hGcO4fGjybyBSIWDsLU4H4XlvOHfq91pz9kkGlonzwTfYkaIEwiRg/dAJF9YlbsduBAgtYLi+8cFg==",
"dev": true
},
"prettier-linter-helpers": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz",
"integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==",
"dev": true,
"requires": {
"fast-diff": "^1.1.2"
}
},
"process": { "process": {
"version": "0.11.10", "version": "0.11.10",
"resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
@ -13278,6 +13343,7 @@
"dev": true, "dev": true,
"optional": true, "optional": true,
"requires": { "requires": {
"bindings": "^1.5.0",
"nan": "^2.12.1" "nan": "^2.12.1"
} }
}, },
@ -13855,6 +13921,7 @@
"dev": true, "dev": true,
"optional": true, "optional": true,
"requires": { "requires": {
"bindings": "^1.5.0",
"nan": "^2.12.1" "nan": "^2.12.1"
} }
}, },

View File

@ -11,7 +11,9 @@
"test": "ng test --karma-config karma.conf.js --watch=false --browsers Firefox", "test": "ng test --karma-config karma.conf.js --watch=false --browsers Firefox",
"test:watch": "ng test --karma-config karma.conf.js --browsers Chrome", "test:watch": "ng test --karma-config karma.conf.js --browsers Chrome",
"lint": "eslint --ext .ts src", "lint": "eslint --ext .ts src",
"lint:fix": "eslint --ext .ts src --fix" "lint:fix": "eslint --ext .ts src --fix",
"format": "prettier --write \"**/*.{js,ts,css,scss,md,json,yml}\"",
"format:html": "prettier --write \"**/*.{html,}\""
}, },
"private": true, "private": true,
"dependencies": { "dependencies": {
@ -62,6 +64,8 @@
"eslint-config-airbnb-typescript": "6.3.1", "eslint-config-airbnb-typescript": "6.3.1",
"eslint-plugin-import": "2.22.0", "eslint-plugin-import": "2.22.0",
"@hapi/hoek": "9.0.4", "@hapi/hoek": "9.0.4",
"eslint-config-prettier": "^6.11.0",
"eslint-plugin-prettier": "^3.1.4",
"jasmine-core": "3.5.0", "jasmine-core": "3.5.0",
"jasmine-spec-reporter": "4.2.1", "jasmine-spec-reporter": "4.2.1",
"karma": "5.1.0", "karma": "5.1.0",
@ -73,6 +77,7 @@
"karma-jasmine-html-reporter": "1.4.0", "karma-jasmine-html-reporter": "1.4.0",
"moment": "2.22.1", "moment": "2.22.1",
"ng2-mock-component": "0.1.1", "ng2-mock-component": "0.1.1",
"prettier": "^2.0.5",
"protractor": "7.0.0", "protractor": "7.0.0",
"ts-mockito": "2.3.0", "ts-mockito": "2.3.0",
"ts-node": "4.1.0", "ts-node": "4.1.0",

View File

@ -75,5 +75,4 @@ const routes: Routes = [
imports: [RouterModule.forChild(routes)], imports: [RouterModule.forChild(routes)],
exports: [RouterModule] exports: [RouterModule]
}) })
export class AdministrationRoutingModule { export class AdministrationRoutingModule {}
}

View File

@ -44,7 +44,7 @@ const MODULES = [
SharedModule, SharedModule,
AdministrationRoutingModule, AdministrationRoutingModule,
TypeaheadModule, TypeaheadModule,
InfiniteScrollModule, InfiniteScrollModule
]; ];
const DECLARATIONS = [ const DECLARATIONS = [
@ -66,17 +66,13 @@ const DECLARATIONS = [
@NgModule({ @NgModule({
declarations: DECLARATIONS, declarations: DECLARATIONS,
imports: [ imports: [MODULES, MatRadioModule],
MODULES,
MatRadioModule
],
providers: [ providers: [
ClassificationDefinitionService, ClassificationDefinitionService,
WorkbasketDefinitionService, WorkbasketDefinitionService,
SavingWorkbasketService, SavingWorkbasketService,
ClassificationCategoriesService, ClassificationCategoriesService,
ImportExportService, ImportExportService
] ]
}) })
export class AdministrationModule { export class AdministrationModule {}
}

View File

@ -1,36 +1,37 @@
@import '../../../../theme/colors'; @import '../../../../theme/colors';
.margin { .margin {
margin-top: 10px; margin-top: 10px;
margin-bottom: 20px; margin-bottom: 20px;
} }
.required-header:after { .required-header:after {
content: ' *';
content:" *"; color: $invalid;
color: $invalid;
} }
td { td {
&.has-changes { &.has-changes {
border-bottom: 1px solid $brown; border-bottom: 1px solid $brown;
} }
} }
.table > thead > tr > th { .table > thead > tr > th {
max-width: 150px; max-width: 150px;
border-bottom: none; border-bottom: none;
} }
.table > thead > tr:last-child > th { .table > thead > tr:last-child > th {
max-width: 150px; max-width: 150px;
border-bottom: 2px solid $grey; border-bottom: 2px solid $grey;
} }
.wrap{ .wrap {
max-width: 150px; max-width: 150px;
word-wrap:break-word; word-wrap: break-word;
}
.min-width {
min-width: 135px;
} }
.min-width{ min-width: 135px;}
.modal-title { .modal-title {
font-weight: bold; font-weight: bold;

View File

@ -22,8 +22,8 @@ describe('AccessItemsManagementComponent', () => {
}); });
}; };
beforeEach(done => { beforeEach((done) => {
configureTests(configure).then(testBed => { configureTests(configure).then((testBed) => {
fixture = testBed.createComponent(AccessItemsManagementComponent); fixture = testBed.createComponent(AccessItemsManagementComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
accessIdsService = testBed.get(AccessIdsService); accessIdsService = testBed.get(AccessIdsService);

View File

@ -16,9 +16,7 @@ import { AccessIdsService } from '../../../shared/services/access-ids/access-ids
import { AccessIdDefinition } from '../../../shared/models/access-id'; import { AccessIdDefinition } from '../../../shared/models/access-id';
import { NotificationService } from '../../../shared/services/notifications/notification.service'; import { NotificationService } from '../../../shared/services/notifications/notification.service';
import { NOTIFICATION_TYPES } from '../../../shared/models/notifications'; import { NOTIFICATION_TYPES } from '../../../shared/models/notifications';
import { AccessItemsCustomisation, import { AccessItemsCustomisation, CustomField, getCustomFields } from '../../../shared/models/customisation';
CustomField,
getCustomFields } from '../../../shared/models/customisation';
import { customFieldCount } from '../../../shared/models/workbasket-access-items'; import { customFieldCount } from '../../../shared/models/workbasket-access-items';
@Component({ @Component({
@ -34,22 +32,28 @@ export class AccessItemsManagementComponent implements OnInit {
toggleValidationAccessIdMap = new Map<number, boolean>(); toggleValidationAccessIdMap = new Map<number, boolean>();
accessId: AccessIdDefinition; accessId: AccessIdDefinition;
groups: AccessIdDefinition[]; groups: AccessIdDefinition[];
sortingFields = new Map([['access-id', 'Access id'], ['workbasket-key', 'Workbasket Key']]); sortingFields = new Map([
['access-id', 'Access id'],
['workbasket-key', 'Workbasket Key']
]);
sortModel: Sorting = new Sorting('access-id', Direction.DESC); sortModel: Sorting = new Sorting('access-id', Direction.DESC);
isGroup: boolean = false; isGroup: boolean = false;
@Select(EngineConfigurationSelectors.accessItemsCustomisation) accessItemsCustomization$: Observable<AccessItemsCustomisation>; @Select(EngineConfigurationSelectors.accessItemsCustomisation) accessItemsCustomization$: Observable<
AccessItemsCustomisation
>;
customFields$: Observable<CustomField[]>; customFields$: Observable<CustomField[]>;
constructor(private formBuilder: FormBuilder, constructor(
private formBuilder: FormBuilder,
private accessIdsService: AccessIdsService, private accessIdsService: AccessIdsService,
private formsValidatorService: FormsValidatorService, private formsValidatorService: FormsValidatorService,
private requestInProgressService: RequestInProgressService, private requestInProgressService: RequestInProgressService,
private notificationService: NotificationService) { private notificationService: NotificationService
} ) {}
get accessItemsGroups(): FormArray { get accessItemsGroups(): FormArray {
return this.accessItemsForm ? this.accessItemsForm.get('accessItemsGroups') as FormArray : null; return this.accessItemsForm ? (this.accessItemsForm.get('accessItemsGroups') as FormArray) : null;
} }
ngOnInit() { ngOnInit() {
@ -57,10 +61,10 @@ export class AccessItemsManagementComponent implements OnInit {
} }
setAccessItemsGroups(accessItems: Array<AccessItemWorkbasket>) { setAccessItemsGroups(accessItems: Array<AccessItemWorkbasket>) {
const AccessItemsFormGroups = accessItems.map(accessItem => this.formBuilder.group(accessItem)); const AccessItemsFormGroups = accessItems.map((accessItem) => this.formBuilder.group(accessItem));
AccessItemsFormGroups.forEach(accessItemGroup => { AccessItemsFormGroups.forEach((accessItemGroup) => {
accessItemGroup.controls.accessId.setValidators(Validators.required); accessItemGroup.controls.accessId.setValidators(Validators.required);
Object.keys(accessItemGroup.controls).forEach(key => { Object.keys(accessItemGroup.controls).forEach((key) => {
accessItemGroup.controls[key].disable(); accessItemGroup.controls[key].disable();
}); });
}); });
@ -86,16 +90,20 @@ export class AccessItemsManagementComponent implements OnInit {
if (this.accessIdPrevious !== selected.accessId) { if (this.accessIdPrevious !== selected.accessId) {
this.accessIdPrevious = selected.accessId; this.accessIdPrevious = selected.accessId;
this.accessIdsService.getGroupsByAccessId(selected.accessId) this.accessIdsService
.pipe(take(1)).subscribe((groups: AccessIdDefinition[]) => { .getGroupsByAccessId(selected.accessId)
this.accessId = selected; .pipe(take(1))
this.groups = groups; .subscribe(
this.searchForAccessItemsWorkbaskets(); (groups: AccessIdDefinition[]) => {
}, this.accessId = selected;
error => { this.groups = groups;
this.requestInProgressService.setRequestInProgress(false); this.searchForAccessItemsWorkbaskets();
this.notificationService.triggerError(NOTIFICATION_TYPES.FETCH_ERR, error); },
}); (error) => {
this.requestInProgressService.setRequestInProgress(false);
this.notificationService.triggerError(NOTIFICATION_TYPES.FETCH_ERR, error);
}
);
} }
} }
@ -110,41 +118,48 @@ export class AccessItemsManagementComponent implements OnInit {
searchForAccessItemsWorkbaskets() { searchForAccessItemsWorkbaskets() {
this.requestInProgressService.setRequestInProgress(true); this.requestInProgressService.setRequestInProgress(true);
this.accessIdsService.getAccessItems( this.accessIdsService
[this.accessId, ...this.groups], .getAccessItems(
this.accessItemsForm ? this.accessItemsForm.value.accessIdFilter : undefined, [this.accessId, ...this.groups],
this.accessItemsForm ? this.accessItemsForm.value.workbasketKeyFilter : undefined, this.accessItemsForm ? this.accessItemsForm.value.accessIdFilter : undefined,
this.sortModel this.accessItemsForm ? this.accessItemsForm.value.workbasketKeyFilter : undefined,
).pipe(take(1)).subscribe((accessItemsResource: AccessItemWorkbasketResource) => { this.sortModel
this.setAccessItemsGroups(accessItemsResource ? accessItemsResource.accessItems : []); )
this.requestInProgressService.setRequestInProgress(false); .pipe(take(1))
}, error => { .subscribe(
this.requestInProgressService.setRequestInProgress(false); (accessItemsResource: AccessItemWorkbasketResource) => {
this.notificationService.triggerError(NOTIFICATION_TYPES.FETCH_ERR_2, error); this.setAccessItemsGroups(accessItemsResource ? accessItemsResource.accessItems : []);
}); this.requestInProgressService.setRequestInProgress(false);
},
(error) => {
this.requestInProgressService.setRequestInProgress(false);
this.notificationService.triggerError(NOTIFICATION_TYPES.FETCH_ERR_2, error);
}
);
} }
revokeAccess() { revokeAccess() {
this.notificationService.showDialog( this.notificationService.showDialog(
`You are going to delete all access related: ${ `You are going to delete all access related: ${this.accessIdSelected}. Can you confirm this action?`,
this.accessIdSelected
}. Can you confirm this action?`,
this.onRemoveConfirmed.bind(this) this.onRemoveConfirmed.bind(this)
); );
} }
private onRemoveConfirmed() { private onRemoveConfirmed() {
this.requestInProgressService.setRequestInProgress(true); this.requestInProgressService.setRequestInProgress(true);
this.accessIdsService.removeAccessItemsPermissions(this.accessIdSelected) this.accessIdsService
.pipe(take(1)).subscribe( .removeAccessItemsPermissions(this.accessIdSelected)
.pipe(take(1))
.subscribe(
() => { () => {
this.requestInProgressService.setRequestInProgress(false); this.requestInProgressService.setRequestInProgress(false);
this.notificationService.showToast( this.notificationService.showToast(
NOTIFICATION_TYPES.SUCCESS_ALERT, new Map<string, string>([['accessId', this.accessIdSelected]]) NOTIFICATION_TYPES.SUCCESS_ALERT,
new Map<string, string>([['accessId', this.accessIdSelected]])
); );
this.searchForAccessItemsWorkbaskets(); this.searchForAccessItemsWorkbaskets();
}, },
error => { (error) => {
this.requestInProgressService.setRequestInProgress(false); this.requestInProgressService.setRequestInProgress(false);
this.notificationService.triggerError(NOTIFICATION_TYPES.DELETE_ERR, error); this.notificationService.triggerError(NOTIFICATION_TYPES.DELETE_ERR, error);
} }

View File

@ -1,5 +1,5 @@
.custom-field-row { .custom-field-row {
display:flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
flex-direction: column; flex-direction: column;
height: 40vh; height: 40vh;
@ -9,7 +9,7 @@
.custom-field-wrapper { .custom-field-wrapper {
height: 70px; height: 70px;
padding: 0 15px padding: 0 15px;
} }
.dropdown-menu > li { .dropdown-menu > li {
cursor: pointer; cursor: pointer;

View File

@ -22,8 +22,7 @@ import { NotificationService } from '../../../shared/services/notifications/noti
selector: 'taskana-dummy-detail', selector: 'taskana-dummy-detail',
template: 'dummydetail' template: 'dummydetail'
}) })
class DummyDetailComponent { class DummyDetailComponent {}
}
describe('ClassificationDetailsComponent', () => { describe('ClassificationDetailsComponent', () => {
let component: ClassificationDetailsComponent; let component: ClassificationDetailsComponent;
@ -38,17 +37,22 @@ describe('ClassificationDetailsComponent', () => {
testBed.configureTestingModule({ testBed.configureTestingModule({
imports: [FormsModule, HttpClientModule, AngularSvgIconModule, NgxsModule.forRoot()], imports: [FormsModule, HttpClientModule, AngularSvgIconModule, NgxsModule.forRoot()],
declarations: [ClassificationDetailsComponent, DummyDetailComponent], declarations: [ClassificationDetailsComponent, DummyDetailComponent],
providers: [MasterAndDetailService, RequestInProgressService, ClassificationsService, providers: [
HttpClient, NotificationService, MasterAndDetailService,
RequestInProgressService,
ClassificationsService,
HttpClient,
NotificationService,
ImportExportService, ImportExportService,
{ provide: Location, useValue: locationSpy }, { provide: Location, useValue: locationSpy },
{ provide: Store, useValue: storeSpy }] { provide: Store, useValue: storeSpy }
]
}); });
}; };
beforeEach(done => { beforeEach((done) => {
configureTests(configure).then(testBed => { configureTests(configure).then((testBed) => {
storeSpy.select.and.callFake(selector => { storeSpy.select.and.callFake((selector) => {
switch (selector) { switch (selector) {
case EngineConfigurationSelectors.classificationsCustomisation: case EngineConfigurationSelectors.classificationsCustomisation:
return of({ information: {} }); return of({ information: {} });
@ -99,7 +103,7 @@ describe('ClassificationDetailsComponent', () => {
expect(component).toBeTruthy(); expect(component).toBeTruthy();
}); });
it('should enable editing of key on create and on copy', async done => { it('should enable editing of key on create and on copy', async (done) => {
component.isCreatingNewClassification = true; component.isCreatingNewClassification = true;
await fixture.detectChanges(); await fixture.detectChanges();
expect(fixture.debugElement.nativeElement.querySelector('#classification-key').disabled).toEqual(false); expect(fixture.debugElement.nativeElement.querySelector('#classification-key').disabled).toEqual(false);

View File

@ -17,19 +17,19 @@ import { ClassificationSelectors } from 'app/shared/store/classification-store/c
import { Location } from '@angular/common'; import { Location } from '@angular/common';
import { NOTIFICATION_TYPES } from '../../../shared/models/notifications'; import { NOTIFICATION_TYPES } from '../../../shared/models/notifications';
import { NotificationService } from '../../../shared/services/notifications/notification.service'; import { NotificationService } from '../../../shared/services/notifications/notification.service';
import { ClassificationCategoryImages, import { ClassificationCategoryImages, CustomField, getCustomFields } from '../../../shared/models/customisation';
CustomField,
getCustomFields } from '../../../shared/models/customisation';
import { Classification } from '../../../shared/models/classification'; import { Classification } from '../../../shared/models/classification';
import { customFieldCount } from '../../../shared/models/classification-summary'; import { customFieldCount } from '../../../shared/models/classification-summary';
import { CategoriesResponse } from '../../../shared/services/classification-categories/classification-categories.service'; import { CategoriesResponse } from '../../../shared/services/classification-categories/classification-categories.service';
import { SaveCreatedClassification, import {
SaveCreatedClassification,
RemoveSelectedClassification, RemoveSelectedClassification,
RestoreSelectedClassification, RestoreSelectedClassification,
SaveModifiedClassification, SaveModifiedClassification,
SelectClassification, SelectClassification,
CopyClassification } from '../../../shared/store/classification-store/classification.actions'; CopyClassification
} from '../../../shared/store/classification-store/classification.actions';
@Component({ @Component({
selector: 'taskana-administration-classification-details', selector: 'taskana-administration-classification-details',
@ -63,29 +63,32 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
private notificationsService: NotificationService, private notificationsService: NotificationService,
private importExportService: ImportExportService, private importExportService: ImportExportService,
private store: Store private store: Store
) { ) {}
}
ngOnInit() { ngOnInit() {
this.customFields$ = this.store.select(EngineConfigurationSelectors.classificationsCustomisation).pipe( this.customFields$ = this.store.select(EngineConfigurationSelectors.classificationsCustomisation).pipe(
map(customisation => customisation.information), map((customisation) => customisation.information),
getCustomFields(customFieldCount) getCustomFields(customFieldCount)
); );
this.selectedClassification$.pipe(takeUntil(this.destroy$)) this.selectedClassification$.pipe(takeUntil(this.destroy$)).subscribe((classification) => {
.subscribe(classification => { this.classification = { ...classification };
this.classification = { ...classification }; this.isCreatingNewClassification = typeof this.classification.classificationId === 'undefined';
this.isCreatingNewClassification = typeof this.classification.classificationId === 'undefined';
});
this.importExportService.getImportingFinished().pipe(takeUntil(this.destroy$)).subscribe(() => {
this.store.dispatch(new SelectClassification(this.classification.classificationId));
}); });
this.importExportService
.getImportingFinished()
.pipe(takeUntil(this.destroy$))
.subscribe(() => {
this.store.dispatch(new SelectClassification(this.classification.classificationId));
});
} }
removeClassification() { removeClassification() {
this.notificationsService.showDialog(`You are going to delete classification: ${this.classification.key}. Can you confirm this action?`, this.notificationsService.showDialog(
this.removeClassificationConfirmation.bind(this)); `You are going to delete classification: ${this.classification.key}. Can you confirm this action?`,
this.removeClassificationConfirmation.bind(this)
);
} }
isFieldValid(field: string): boolean { isFieldValid(field: string): boolean {
@ -94,20 +97,23 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
onSubmit() { onSubmit() {
this.formsValidatorService.formSubmitAttempt = true; this.formsValidatorService.formSubmitAttempt = true;
this.formsValidatorService.validateFormInformation(this.classificationForm, this.toogleValidationMap).then(value => { this.formsValidatorService
if (value) { .validateFormInformation(this.classificationForm, this.toogleValidationMap)
this.onSave(); .then((value) => {
} if (value) {
}); this.onSave();
}
});
} }
onRestore() { onRestore() {
this.formsValidatorService.formSubmitAttempt = false; this.formsValidatorService.formSubmitAttempt = false;
this.store.dispatch( this.store
new RestoreSelectedClassification(this.classification.classificationId) .dispatch(new RestoreSelectedClassification(this.classification.classificationId))
).pipe(take(1)).subscribe(() => { .pipe(take(1))
this.notificationsService.showToast(NOTIFICATION_TYPES.INFO_ALERT); .subscribe(() => {
}); this.notificationsService.showToast(NOTIFICATION_TYPES.INFO_ALERT);
});
} }
onCopy() { onCopy() {
@ -123,11 +129,13 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
} }
getCategoryIcon(category: string): Observable<Pair> { getCategoryIcon(category: string): Observable<Pair> {
return this.categoryIcons$.pipe(map( return this.categoryIcons$.pipe(
iconMap => (iconMap[category] map((iconMap) =>
? new Pair(iconMap[category], category) iconMap[category]
: new Pair(iconMap.missing, 'Category does not match with the configuration')) ? new Pair(iconMap[category], category)
)); : new Pair(iconMap.missing, 'Category does not match with the configuration')
)
);
} }
spinnerRunning(value) { spinnerRunning(value) {
@ -147,7 +155,10 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
} }
getAvailableCategories(type: string): Observable<string[]> { getAvailableCategories(type: string): Observable<string[]> {
return this.classificationTypes$.pipe(take(1), map(classTypes => classTypes[type])); return this.classificationTypes$.pipe(
take(1),
map((classTypes) => classTypes[type])
);
} }
ngOnDestroy(): void { ngOnDestroy(): void {
@ -158,26 +169,36 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
private async onSave() { private async onSave() {
this.requestInProgressService.setRequestInProgress(true); this.requestInProgressService.setRequestInProgress(true);
if (typeof this.classification.classificationId === 'undefined') { if (typeof this.classification.classificationId === 'undefined') {
this.store.dispatch( this.store
new SaveCreatedClassification(this.classification) .dispatch(new SaveCreatedClassification(this.classification))
).pipe(take(1)).subscribe(store => { .pipe(take(1))
this.notificationsService.showToast( .subscribe(
NOTIFICATION_TYPES.SUCCESS_ALERT_2, (store) => {
new Map<string, string>([['classificationKey', store.classification.selectedClassification.key]]) this.notificationsService.showToast(
NOTIFICATION_TYPES.SUCCESS_ALERT_2,
new Map<string, string>([['classificationKey', store.classification.selectedClassification.key]])
);
this.location.go(
this.location
.path()
.replace(
/(classifications).*/g,
`classifications/(detail:${store.classification.selectedClassification.classificationId})`
)
);
this.afterRequest();
},
(error) => {
this.notificationsService.triggerError(NOTIFICATION_TYPES.CREATE_ERR, error);
this.afterRequest();
}
); );
this.location.go(this.location.path().replace(
/(classifications).*/g,
`classifications/(detail:${store.classification.selectedClassification.classificationId})`
));
this.afterRequest();
}, error => {
this.notificationsService.triggerError(NOTIFICATION_TYPES.CREATE_ERR, error);
this.afterRequest();
});
} else { } else {
try { try {
this.store.dispatch(new SaveModifiedClassification(this.classification)) this.store
.pipe(take(1)).subscribe(() => { .dispatch(new SaveModifiedClassification(this.classification))
.pipe(take(1))
.subscribe(() => {
this.afterRequest(); this.afterRequest();
this.notificationsService.showToast( this.notificationsService.showToast(
NOTIFICATION_TYPES.SUCCESS_ALERT_3, NOTIFICATION_TYPES.SUCCESS_ALERT_3,
@ -202,11 +223,16 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
} }
this.requestInProgressService.setRequestInProgress(true); this.requestInProgressService.setRequestInProgress(true);
this.store.dispatch(new RemoveSelectedClassification()).pipe(take(1)).subscribe(() => { this.store
this.notificationsService.showToast(NOTIFICATION_TYPES.SUCCESS_ALERT_4, .dispatch(new RemoveSelectedClassification())
new Map<string, string>([['classificationKey', this.classification.key]])); .pipe(take(1))
this.afterRequest(); .subscribe(() => {
}); this.notificationsService.showToast(
NOTIFICATION_TYPES.SUCCESS_ALERT_4,
new Map<string, string>([['classificationKey', this.classification.key]])
);
this.afterRequest();
});
this.location.go(this.location.path().replace(/(classifications).*/g, 'classifications')); this.location.go(this.location.path().replace(/(classifications).*/g, 'classifications'));
} }
} }

View File

@ -7,12 +7,12 @@
border: none; border: none;
} }
.tab-align{ .tab-align {
margin-bottom: 0px; margin-bottom: 0px;
border-bottom: 1px dotted #ddd; border-bottom: 1px dotted #ddd;
padding: 8px 12px 8px 4px; padding: 8px 12px 8px 4px;
&>div{ & > div {
margin: 6px 0px; margin: 6px 0px;
} }
} }
@ -25,10 +25,10 @@ input.filter-input {
} }
.category-filter { .category-filter {
margin: 7px 2px; margin: 7px 2px;
} }
.dropdown-menu-classification{ .dropdown-menu-classification {
margin-left: 15px; margin-left: 15px;
min-width: 0px; min-width: 0px;
} }

View File

@ -28,12 +28,9 @@ import { NotificationService } from '../../../shared/services/notifications/noti
selector: 'taskana-dummy-detail', selector: 'taskana-dummy-detail',
template: 'dummydetail' template: 'dummydetail'
}) })
class DummyDetailComponent { class DummyDetailComponent {}
}
const routes: Routes = [ const routes: Routes = [{ path: ':id', component: DummyDetailComponent }];
{ path: ':id', component: DummyDetailComponent }
];
describe('ClassificationListComponent', () => { describe('ClassificationListComponent', () => {
let component: ClassificationListComponent; let component: ClassificationListComponent;
@ -43,19 +40,35 @@ describe('ClassificationListComponent', () => {
const configure = (testBed: TestBed) => { const configure = (testBed: TestBed) => {
testBed.configureTestingModule({ testBed.configureTestingModule({
declarations: [ClassificationListComponent, ImportExportComponent, ClassificationTypesSelectorComponent, declarations: [
DummyDetailComponent], ClassificationListComponent,
imports: [HttpClientModule, RouterTestingModule.withRoutes(routes), FormsModule, AngularSvgIconModule, NgxsModule.forRoot([]), MatRadioModule], ImportExportComponent,
ClassificationTypesSelectorComponent,
DummyDetailComponent
],
imports: [
HttpClientModule,
RouterTestingModule.withRoutes(routes),
FormsModule,
AngularSvgIconModule,
NgxsModule.forRoot([]),
MatRadioModule
],
providers: [ providers: [
HttpClient, WorkbasketDefinitionService, NotificationService, HttpClient,
ClassificationsService, DomainService, ClassificationDefinitionService, WorkbasketDefinitionService,
RequestInProgressService, ImportExportService NotificationService,
ClassificationsService,
DomainService,
ClassificationDefinitionService,
RequestInProgressService,
ImportExportService
] ]
}); });
}; };
beforeEach(done => { beforeEach((done) => {
configureTests(configure).then(testBed => { configureTests(configure).then((testBed) => {
fixture = testBed.createComponent(ClassificationListComponent); fixture = testBed.createComponent(ClassificationListComponent);
component = fixture.componentInstance; component = fixture.componentInstance;

View File

@ -12,8 +12,10 @@ import { ClassificationSelectors } from 'app/shared/store/classification-store/c
import { Location } from '@angular/common'; import { Location } from '@angular/common';
import { ClassificationCategoryImages } from '../../../shared/models/customisation'; import { ClassificationCategoryImages } from '../../../shared/models/customisation';
import { GetClassifications, import {
CreateClassification } from '../../../shared/store/classification-store/classification.actions'; GetClassifications,
CreateClassification
} from '../../../shared/store/classification-store/classification.actions';
import { DomainService } from '../../../shared/services/domain/domain.service'; import { DomainService } from '../../../shared/services/domain/domain.service';
import { ClassificationSummary } from '../../../shared/models/classification-summary'; import { ClassificationSummary } from '../../../shared/models/classification-summary';
@ -44,40 +46,38 @@ export class ClassificationListComponent implements OnInit, OnDestroy {
private ngxsActions$: Actions, private ngxsActions$: Actions,
private domainService: DomainService private domainService: DomainService
) { ) {
this.ngxsActions$.pipe(ofActionDispatched(GetClassifications), this.ngxsActions$.pipe(ofActionDispatched(GetClassifications), takeUntil(this.destroy$)).subscribe(() => {
takeUntil(this.destroy$)) this.requestInProgress = true;
.subscribe(() => { });
this.requestInProgress = true; this.ngxsActions$.pipe(ofActionCompleted(GetClassifications), takeUntil(this.destroy$)).subscribe(() => {
}); this.requestInProgress = false;
this.ngxsActions$.pipe(ofActionCompleted(GetClassifications), });
takeUntil(this.destroy$))
.subscribe(() => {
this.requestInProgress = false;
});
} }
ngOnInit() { ngOnInit() {
this.classifications$.pipe(takeUntil(this.destroy$)).subscribe(classifications => { this.classifications$.pipe(takeUntil(this.destroy$)).subscribe((classifications) => {
this.classifications = classifications; this.classifications = classifications;
}); });
this.classificationTypeSelected$ this.classificationTypeSelected$.pipe(takeUntil(this.destroy$)).subscribe(() => {
.pipe(takeUntil(this.destroy$)) this.store.dispatch(new GetClassifications());
.subscribe(() => { this.selectedCategory = '';
this.store.dispatch(new GetClassifications()); });
this.selectedCategory = '';
});
this.importExportService.getImportingFinished() this.importExportService
.getImportingFinished()
.pipe(takeUntil(this.destroy$)) .pipe(takeUntil(this.destroy$))
.subscribe(() => { .subscribe(() => {
this.store.dispatch(new GetClassifications()); this.store.dispatch(new GetClassifications());
}); });
// needed, so that the list updates, when domain gets changed (could be placed anywhere and should be removed, when domain is in store) // needed, so that the list updates, when domain gets changed (could be placed anywhere and should be removed, when domain is in store)
this.domainService.getSelectedDomain().pipe(takeUntil(this.destroy$)).subscribe(domain => { this.domainService
this.store.dispatch(GetClassifications); .getSelectedDomain()
}); .pipe(takeUntil(this.destroy$))
.subscribe((domain) => {
this.store.dispatch(GetClassifications);
});
} }
addClassification() { addClassification() {
@ -91,10 +91,10 @@ export class ClassificationListComponent implements OnInit, OnDestroy {
getCategoryIcon(category: string): Observable<Pair> { getCategoryIcon(category: string): Observable<Pair> {
return this.categoryIcons$.pipe( return this.categoryIcons$.pipe(
map( map((iconMap) =>
iconMap => (iconMap[category] iconMap[category]
? new Pair(iconMap[category], category) ? new Pair(iconMap[category], category)
: new Pair(iconMap.missing, 'Category does not match with the configuration')) : new Pair(iconMap.missing, 'Category does not match with the configuration')
) )
); );
} }

View File

@ -10,8 +10,7 @@ import { ClassificationOverviewComponent } from './classification-overview.compo
selector: 'taskana-dummy-detail', selector: 'taskana-dummy-detail',
template: 'dummydetail' template: 'dummydetail'
}) })
export class DummyDetailComponent { export class DummyDetailComponent {}
}
describe('ClassificationOverviewComponent', () => { describe('ClassificationOverviewComponent', () => {
let component: ClassificationOverviewComponent; let component: ClassificationOverviewComponent;
@ -20,21 +19,13 @@ describe('ClassificationOverviewComponent', () => {
let debugElement; let debugElement;
const locationSpy: jasmine.SpyObj<Location> = jasmine.createSpyObj('Location', ['go']); const locationSpy: jasmine.SpyObj<Location> = jasmine.createSpyObj('Location', ['go']);
beforeEach((() => { beforeEach(() => {
const routes: Routes = [ const routes: Routes = [{ path: ':id', component: DummyDetailComponent }];
{ path: ':id', component: DummyDetailComponent }
];
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ declarations: [ClassificationOverviewComponent, DummyDetailComponent],
ClassificationOverviewComponent, imports: [RouterTestingModule.withRoutes(routes), NgxsModule.forRoot()],
DummyDetailComponent], providers: [{ provide: Location, useValue: locationSpy }],
imports: [
RouterTestingModule.withRoutes(routes),
NgxsModule.forRoot()],
providers: [
{ provide: Location, useValue: locationSpy },
],
schemas: [NO_ERRORS_SCHEMA] schemas: [NO_ERRORS_SCHEMA]
}); });
@ -44,7 +35,7 @@ describe('ClassificationOverviewComponent', () => {
router = TestBed.get(Router); router = TestBed.get(Router);
fixture.detectChanges(); fixture.detectChanges();
})); });
it('should create', () => { it('should create', () => {
expect(component).toBeTruthy(); expect(component).toBeTruthy();

View File

@ -4,7 +4,11 @@ import { Observable, Subject } from 'rxjs';
import { Select, Store } from '@ngxs/store'; import { Select, Store } from '@ngxs/store';
import { takeUntil } from 'rxjs/operators'; import { takeUntil } from 'rxjs/operators';
import { ClassificationSelectors } from '../../../shared/store/classification-store/classification.selectors'; import { ClassificationSelectors } from '../../../shared/store/classification-store/classification.selectors';
import { GetClassifications, SelectClassification, CreateClassification } from '../../../shared/store/classification-store/classification.actions'; import {
GetClassifications,
SelectClassification,
CreateClassification
} from '../../../shared/store/classification-store/classification.actions';
import { Classification } from '../../../shared/models/classification'; import { Classification } from '../../../shared/models/classification';
@Component({ @Component({
@ -18,35 +22,28 @@ export class ClassificationOverviewComponent implements OnInit, OnDestroy {
private destroy$ = new Subject<void>(); private destroy$ = new Subject<void>();
routerParams: any; routerParams: any;
constructor( constructor(private route: ActivatedRoute, private store: Store) {}
private route: ActivatedRoute,
private store: Store
) {
}
ngOnInit() { ngOnInit() {
if (this.route.firstChild) { if (this.route.firstChild) {
this.route.firstChild.params this.route.firstChild.params.pipe(takeUntil(this.destroy$)).subscribe((params) => {
.pipe(takeUntil(this.destroy$)) this.routerParams = params;
.subscribe(params => {
this.routerParams = params;
if (this.routerParams.id) { if (this.routerParams.id) {
this.showDetail = true; this.showDetail = true;
this.store.dispatch(new SelectClassification(this.routerParams.id)) this.store
.subscribe(() => this.store.dispatch(new GetClassifications())); .dispatch(new SelectClassification(this.routerParams.id))
} .subscribe(() => this.store.dispatch(new GetClassifications()));
if (this.routerParams.id && this.routerParams.id.indexOf('new-classification') !== -1) { }
this.store.dispatch(new CreateClassification()); if (this.routerParams.id && this.routerParams.id.indexOf('new-classification') !== -1) {
} this.store.dispatch(new CreateClassification());
}); }
});
} }
this.selectedClassification$ this.selectedClassification$.pipe(takeUntil(this.destroy$)).subscribe((selectedClassification) => {
.pipe(takeUntil(this.destroy$)) this.showDetail = !!selectedClassification;
.subscribe(selectedClassification => { });
this.showDetail = !!selectedClassification;
});
} }
ngOnDestroy() { ngOnDestroy() {

View File

@ -14,9 +14,7 @@ describe('ClassificationTypesSelectorComponent', () => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [NgxsModule.forRoot(), MatRadioModule], imports: [NgxsModule.forRoot(), MatRadioModule],
declarations: [ClassificationTypesSelectorComponent], declarations: [ClassificationTypesSelectorComponent],
providers: [ providers: [{ provide: Location, useValue: locationSpy }]
{ provide: Location, useValue: locationSpy },
]
}).compileComponents(); }).compileComponents();
})); }));

View File

@ -15,16 +15,21 @@ describe('ImportExportComponent', () => {
let fixture: ComponentFixture<ImportExportComponent>; let fixture: ComponentFixture<ImportExportComponent>;
let debugElement; let debugElement;
beforeEach(done => { beforeEach((done) => {
const configure = (testBed: TestBed) => { const configure = (testBed: TestBed) => {
testBed.configureTestingModule({ testBed.configureTestingModule({
declarations: [ImportExportComponent], declarations: [ImportExportComponent],
imports: [HttpClientModule, AngularSvgIconModule], imports: [HttpClientModule, AngularSvgIconModule],
providers: [WorkbasketService, ClassificationDefinitionService, WorkbasketDefinitionService, NotificationService, providers: [
ImportExportService] WorkbasketService,
ClassificationDefinitionService,
WorkbasketDefinitionService,
NotificationService,
ImportExportService
]
}); });
}; };
configureTests(configure).then(testBed => { configureTests(configure).then((testBed) => {
fixture = TestBed.createComponent(ImportExportComponent); fixture = TestBed.createComponent(ImportExportComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
debugElement = fixture.debugElement.nativeElement; debugElement = fixture.debugElement.nativeElement;

View File

@ -32,15 +32,12 @@ export class ImportExportComponent implements OnInit {
public uploadservice: UploadService, public uploadservice: UploadService,
private errorsService: NotificationService, private errorsService: NotificationService,
private importExportService: ImportExportService private importExportService: ImportExportService
) { ) {}
}
ngOnInit() { ngOnInit() {
this.domainService.getDomains().subscribe( this.domainService.getDomains().subscribe((data) => {
data => { this.domains = data;
this.domains = data; });
}
);
} }
export(domain = '') { export(domain = '') {

View File

@ -1,5 +1,5 @@
.text-top{ .text-top {
vertical-align: text-top; vertical-align: text-top;
} }
svg-icon.blue.fa-fw { svg-icon.blue.fa-fw {

View File

@ -37,16 +37,18 @@ describe('TaskanaTreeComponent', () => {
testBed.configureTestingModule({ testBed.configureTestingModule({
imports: [AngularSvgIconModule, HttpClientModule, NgxsModule.forRoot()], imports: [AngularSvgIconModule, HttpClientModule, NgxsModule.forRoot()],
declarations: [TreeVendorComponent], declarations: [TreeVendorComponent],
providers: [ClassificationsService, providers: [
ClassificationsService,
{ provide: Location, useValue: locationSpy }, { provide: Location, useValue: locationSpy },
{ provide: Store, useValue: storeSpy }] { provide: Store, useValue: storeSpy }
]
}); });
}; };
beforeEach(done => { beforeEach((done) => {
configureTests(configure).then(testBed => { configureTests(configure).then((testBed) => {
locationSpy.path.and.callFake(() => ''); locationSpy.path.and.callFake(() => '');
storeSpy.select.and.callFake(selector => { storeSpy.select.and.callFake((selector) => {
switch (selector) { switch (selector) {
case ClassificationSelectors.selectedClassificationId: case ClassificationSelectors.selectedClassificationId:
return of('id4'); return of('id4');
@ -96,7 +98,7 @@ describe('TaskanaTreeComponent', () => {
name: 'classification4', name: 'classification4',
description: 'description', description: 'description',
priority: 1, priority: 1,
serviceLevel: 'level', serviceLevel: 'level'
}; };
// using parameter 'any' since getClassification is a private method // using parameter 'any' since getClassification is a private method

View File

@ -1,4 +1,5 @@
import { AfterViewChecked, import {
AfterViewChecked,
Component, Component,
ElementRef, ElementRef,
EventEmitter, EventEmitter,
@ -7,7 +8,8 @@ import { AfterViewChecked,
OnDestroy, OnDestroy,
OnInit, OnInit,
Output, Output,
ViewChild } from '@angular/core'; ViewChild
} from '@angular/core';
import { TreeNodeModel } from 'app/administration/models/tree-node'; import { TreeNodeModel } from 'app/administration/models/tree-node';
import { ITreeOptions, KEYS, TREE_ACTIONS, TreeComponent } from 'angular-tree-component'; import { ITreeOptions, KEYS, TREE_ACTIONS, TreeComponent } from 'angular-tree-component';
@ -24,15 +26,17 @@ import { Classification } from '../../../shared/models/classification';
import { ClassificationsService } from '../../../shared/services/classifications/classifications.service'; import { ClassificationsService } from '../../../shared/services/classifications/classifications.service';
import { ClassificationCategoryImages } from '../../../shared/models/customisation'; import { ClassificationCategoryImages } from '../../../shared/models/customisation';
import { ClassificationSelectors } from '../../../shared/store/classification-store/classification.selectors'; import { ClassificationSelectors } from '../../../shared/store/classification-store/classification.selectors';
import { DeselectClassification, import {
DeselectClassification,
SelectClassification, SelectClassification,
UpdateClassification } from '../../../shared/store/classification-store/classification.actions'; UpdateClassification
} from '../../../shared/store/classification-store/classification.actions';
import { ClassificationTreeService } from '../../services/classification-tree.service'; import { ClassificationTreeService } from '../../services/classification-tree.service';
@Component({ @Component({
selector: 'taskana-administration-tree', selector: 'taskana-administration-tree',
templateUrl: './tree.component.html', templateUrl: './tree.component.html',
styleUrls: ['./tree.component.scss'], styleUrls: ['./tree.component.scss']
}) })
export class TaskanaTreeComponent implements OnInit, AfterViewChecked, OnDestroy { export class TaskanaTreeComponent implements OnInit, AfterViewChecked, OnDestroy {
treeNodes: TreeNodeModel[]; treeNodes: TreeNodeModel[];
@ -75,8 +79,7 @@ export class TaskanaTreeComponent implements OnInit, AfterViewChecked, OnDestroy
private store: Store, private store: Store,
private notificationsService: NotificationService, private notificationsService: NotificationService,
private classificationTreeService: ClassificationTreeService private classificationTreeService: ClassificationTreeService
) { ) {}
}
@HostListener('document:click', ['$event']) @HostListener('document:click', ['$event'])
onDocumentClick(event) { onDocumentClick(event) {
@ -87,11 +90,12 @@ export class TaskanaTreeComponent implements OnInit, AfterViewChecked, OnDestroy
ngOnInit() { ngOnInit() {
const computedTreeNodes$: Observable<TreeNodeModel[]> = this.classifications$.pipe( const computedTreeNodes$: Observable<TreeNodeModel[]> = this.classifications$.pipe(
filter(classifications => typeof (classifications) !== 'undefined'), filter((classifications) => typeof classifications !== 'undefined'),
map(classifications => this.classificationTreeService.transformToTreeNode(classifications)) map((classifications) => this.classificationTreeService.transformToTreeNode(classifications))
); );
combineLatest([this.selectedClassificationId$, computedTreeNodes$]).pipe(takeUntil(this.destroy$)) combineLatest([this.selectedClassificationId$, computedTreeNodes$])
.pipe(takeUntil(this.destroy$))
.subscribe(([selectedClassificationId, treeNodes]) => { .subscribe(([selectedClassificationId, treeNodes]) => {
this.treeNodes = treeNodes; this.treeNodes = treeNodes;
this.selectNodeId = typeof selectedClassificationId !== 'undefined' ? selectedClassificationId : undefined; this.selectNodeId = typeof selectedClassificationId !== 'undefined' ? selectedClassificationId : undefined;
@ -122,8 +126,7 @@ export class TaskanaTreeComponent implements OnInit, AfterViewChecked, OnDestroy
} }
} }
if (this.filterTextOld !== this.filterText if (this.filterTextOld !== this.filterText || this.filterIconOld !== this.filterIcon) {
|| this.filterIconOld !== this.filterIcon) {
this.filterIconOld = this.filterIcon; this.filterIconOld = this.filterIcon;
this.filterTextOld = this.filterText; this.filterTextOld = this.filterText;
this.filterNodes(this.filterText ? this.filterText : '', this.filterIcon); this.filterNodes(this.filterText ? this.filterText : '', this.filterIcon);
@ -166,11 +169,13 @@ export class TaskanaTreeComponent implements OnInit, AfterViewChecked, OnDestroy
} }
getCategoryIcon(category: string): Observable<Pair> { getCategoryIcon(category: string): Observable<Pair> {
return this.categoryIcons$.pipe(map( return this.categoryIcons$.pipe(
iconMap => (iconMap[category] map((iconMap) =>
? new Pair(iconMap[category], category) iconMap[category]
: new Pair(iconMap.missing, 'Category does not match with the configuration')) ? new Pair(iconMap[category], category)
)); : new Pair(iconMap.missing, 'Category does not match with the configuration')
)
);
} }
switchTaskanaSpinner(active: boolean) { switchTaskanaSpinner(active: boolean) {
@ -203,18 +208,20 @@ export class TaskanaTreeComponent implements OnInit, AfterViewChecked, OnDestroy
} }
private filterNodes(text, iconText) { private filterNodes(text, iconText) {
this.tree.treeModel.filterNodes(node => TaskanaTreeComponent.checkNameAndKey(node, text) this.tree.treeModel.filterNodes(
&& TaskanaTreeComponent.checkIcon(node, iconText)); (node) => TaskanaTreeComponent.checkNameAndKey(node, text) && TaskanaTreeComponent.checkIcon(node, iconText)
);
} }
private static checkNameAndKey(node: any, text: string): boolean { private static checkNameAndKey(node: any, text: string): boolean {
return (node.data.name.toUpperCase().includes(text.toUpperCase()) return (
|| node.data.key.toUpperCase().includes(text.toUpperCase())); node.data.name.toUpperCase().includes(text.toUpperCase()) ||
node.data.key.toUpperCase().includes(text.toUpperCase())
);
} }
private static checkIcon(node: any, iconText: string): boolean { private static checkIcon(node: any, iconText: string): boolean {
return (node.data.category.toUpperCase() === iconText.toUpperCase() return node.data.category.toUpperCase() === iconText.toUpperCase() || iconText === '';
|| iconText === '');
} }
private manageTreeState() { private manageTreeState() {
@ -225,10 +232,10 @@ export class TaskanaTreeComponent implements OnInit, AfterViewChecked, OnDestroy
} }
private checkValidElements(event): boolean { private checkValidElements(event): boolean {
return (this.elementRef.nativeElement.contains(event.target) return (
|| this.elementRef.nativeElement === event.target) (this.elementRef.nativeElement.contains(event.target) || this.elementRef.nativeElement === event.target) &&
&& (event.target.localName === 'tree-viewport' (event.target.localName === 'tree-viewport' || event.target.localName === 'taskana-tree')
|| event.target.localName === 'taskana-tree'); );
} }
private getClassification(classificationId: string): Promise<Classification> { private getClassification(classificationId: string): Promise<Classification> {
@ -236,14 +243,13 @@ export class TaskanaTreeComponent implements OnInit, AfterViewChecked, OnDestroy
} }
private updateClassification(classification: Classification) { private updateClassification(classification: Classification) {
this.store.dispatch(new UpdateClassification(classification)) this.store.dispatch(new UpdateClassification(classification)).subscribe(() => {
.subscribe(() => { this.notificationsService.showToast(
this.notificationsService.showToast( NOTIFICATION_TYPES.SUCCESS_ALERT_5,
NOTIFICATION_TYPES.SUCCESS_ALERT_5, new Map<string, string>([['classificationKey', classification.key]])
new Map<string, string>([['classificationKey', classification.key]]) );
); this.switchTaskanaSpinner(false);
this.switchTaskanaSpinner(false); });
});
} }
private collapseParentNodeIfItIsTheLastChild(node: any) { private collapseParentNodeIfItIsTheLastChild(node: any) {

View File

@ -9,13 +9,13 @@ describe('IconTypeComponent', () => {
let fixture: ComponentFixture<IconTypeComponent>; let fixture: ComponentFixture<IconTypeComponent>;
let debugElement; let debugElement;
beforeEach(done => { beforeEach((done) => {
const configure = (testBed: TestBed) => { const configure = (testBed: TestBed) => {
testBed.configureTestingModule({ testBed.configureTestingModule({
imports: [AngularSvgIconModule, HttpClientModule] imports: [AngularSvgIconModule, HttpClientModule]
}); });
}; };
configureTests(configure).then(testBed => { configureTests(configure).then((testBed) => {
fixture = TestBed.createComponent(IconTypeComponent); fixture = TestBed.createComponent(IconTypeComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
debugElement = fixture.debugElement.nativeElement; debugElement = fixture.debugElement.nativeElement;

View File

@ -20,20 +20,28 @@ export class IconTypeComponent implements OnInit {
text: string; text: string;
public static get allTypes(): Map<string, string> { public static get allTypes(): Map<string, string> {
return new Map([['PERSONAL', 'Personal'], ['GROUP', 'Group'], ['CLEARANCE', 'Clearance'], ['TOPIC', 'Topic']]); return new Map([
['PERSONAL', 'Personal'],
['GROUP', 'Group'],
['CLEARANCE', 'Clearance'],
['TOPIC', 'Topic']
]);
} }
ngOnInit() { ngOnInit() {}
}
getIconPath(type: string) { getIconPath(type: string) {
switch (type) { switch (type) {
case 'PERSONAL': return 'user.svg'; case 'PERSONAL':
case 'GROUP': return 'users.svg'; return 'user.svg';
case 'TOPIC': return 'topic.svg'; case 'GROUP':
case 'CLEARANCE': return 'clearance.svg'; return 'users.svg';
default: return 'asterisk.svg'; case 'TOPIC':
return 'topic.svg';
case 'CLEARANCE':
return 'clearance.svg';
default:
return 'asterisk.svg';
} }
} }
} }

View File

@ -1,34 +1,33 @@
@import '../../../../theme/colors'; @import '../../../../theme/colors';
td > input[type="checkbox"] { td > input[type='checkbox'] {
margin-top: 0px; margin-top: 0px;
} }
.panel-body { .panel-body {
overflow-x: auto; overflow-x: auto;
} }
.text-width{ .text-width {
width: 100%; width: 100%;
min-width: 180px; min-width: 180px;
} }
.required-header { .required-header {
width: 200px; width: 200px;
} }
.required-header:after { .required-header:after {
content: ' *';
content:" *"; color: red;
color: red;
} }
td { td {
vertical-align: bottom !important; vertical-align: bottom !important;
&.has-changes { &.has-changes {
border-bottom: 1px solid #f0ad4e;; border-bottom: 1px solid #f0ad4e;
} }
} }
.table > thead > tr > th { .table > thead > tr > th {
max-width: 150px; max-width: 150px;
border-bottom: none; border-bottom: none;
} }
taskana-shared-type-ahead { taskana-shared-type-ahead {
top: 0; top: 0;
} }

View File

@ -34,18 +34,27 @@ describe('WorkbasketAccessItemsComponent', () => {
testBed.configureTestingModule({ testBed.configureTestingModule({
declarations: [WorkbasketAccessItemsComponent], declarations: [WorkbasketAccessItemsComponent],
imports: [ imports: [
FormsModule, AngularSvgIconModule, FormsModule,
HttpClientModule, ReactiveFormsModule, AngularSvgIconModule,
NgxsModule.forRoot([WorkbasketState, EngineConfigurationState])], HttpClientModule,
providers: [WorkbasketService, NotificationService, SavingWorkbasketService, RequestInProgressService, ReactiveFormsModule,
AccessIdsService, FormsValidatorService, ClassificationCategoriesService, NgxsModule.forRoot([WorkbasketState, EngineConfigurationState])
{ provide: Location, useValue: locationSpy }, ],
providers: [
WorkbasketService,
NotificationService,
SavingWorkbasketService,
RequestInProgressService,
AccessIdsService,
FormsValidatorService,
ClassificationCategoriesService,
{ provide: Location, useValue: locationSpy }
] ]
}); });
}; };
beforeEach(done => { beforeEach((done) => {
configureTests(configure).then(testBed => { configureTests(configure).then((testBed) => {
const store: Store = testBed.get(Store); const store: Store = testBed.get(Store);
store.reset([WorkbasketState, EngineConfigurationState]); store.reset([WorkbasketState, EngineConfigurationState]);
@ -59,31 +68,33 @@ describe('WorkbasketAccessItemsComponent', () => {
workbasketService = testBed.get(WorkbasketService); workbasketService = testBed.get(WorkbasketService);
notificationsService = testBed.get(NotificationService); notificationsService = testBed.get(NotificationService);
const workbasketAccessItemsRepresentation: WorkbasketAccessItemsRepresentation = { const workbasketAccessItemsRepresentation: WorkbasketAccessItemsRepresentation = {
accessItems: [{ accessItems: [
accessId: 'accessID1', {
workbasketId: 'id1', accessId: 'accessID1',
workbasketKey: '1', workbasketId: 'id1',
accessItemId: '', workbasketKey: '1',
accessName: '', accessItemId: '',
permRead: false, accessName: '',
permOpen: false, permRead: false,
permAppend: false, permOpen: false,
permTransfer: false, permAppend: false,
permDistribute: false, permTransfer: false,
permCustom1: false, permDistribute: false,
permCustom2: false, permCustom1: false,
permCustom3: false, permCustom2: false,
permCustom4: false, permCustom3: false,
permCustom5: false, permCustom4: false,
permCustom6: false, permCustom5: false,
permCustom7: false, permCustom6: false,
permCustom8: false, permCustom7: false,
permCustom9: false, permCustom8: false,
permCustom10: false, permCustom9: false,
permCustom11: false, permCustom10: false,
permCustom12: false, permCustom11: false,
_links: {}, permCustom12: false,
}], _links: {}
}
],
_links: { self: { href: 'someurl' } } _links: { self: { href: 'someurl' } }
}; };
debugElement = fixture.debugElement.nativeElement; debugElement = fixture.debugElement.nativeElement;

View File

@ -1,4 +1,5 @@
import { Component, import {
Component,
ElementRef, ElementRef,
Input, Input,
OnChanges, OnChanges,
@ -6,7 +7,8 @@ import { Component,
OnInit, OnInit,
QueryList, QueryList,
SimpleChanges, SimpleChanges,
ViewChildren } from '@angular/core'; ViewChildren
} from '@angular/core';
import { Observable, Subject } from 'rxjs'; import { Observable, Subject } from 'rxjs';
import { Select, Store } from '@ngxs/store'; import { Select, Store } from '@ngxs/store';
import { FormArray, FormBuilder, Validators } from '@angular/forms'; import { FormArray, FormBuilder, Validators } from '@angular/forms';
@ -27,8 +29,10 @@ import { takeUntil } from 'rxjs/operators';
import { NOTIFICATION_TYPES } from '../../../shared/models/notifications'; import { NOTIFICATION_TYPES } from '../../../shared/models/notifications';
import { NotificationService } from '../../../shared/services/notifications/notification.service'; import { NotificationService } from '../../../shared/services/notifications/notification.service';
import { AccessItemsCustomisation, CustomField, getCustomFields } from '../../../shared/models/customisation'; import { AccessItemsCustomisation, CustomField, getCustomFields } from '../../../shared/models/customisation';
import { GetWorkbasketAccessItems, import {
UpdateWorkbasketAccessItems } from '../../../shared/store/workbasket-store/workbasket.actions'; GetWorkbasketAccessItems,
UpdateWorkbasketAccessItems
} from '../../../shared/store/workbasket-store/workbasket.actions';
import { WorkbasketSelectors } from '../../../shared/store/workbasket-store/workbasket.selectors'; import { WorkbasketSelectors } from '../../../shared/store/workbasket-store/workbasket.selectors';
@Component({ @Component({
@ -81,8 +85,7 @@ export class WorkbasketAccessItemsComponent implements OnInit, OnChanges, OnDest
private formsValidatorService: FormsValidatorService, private formsValidatorService: FormsValidatorService,
private notificationsService: NotificationService, private notificationsService: NotificationService,
private store: Store private store: Store
) { ) {}
}
get accessItemsGroups(): FormArray { get accessItemsGroups(): FormArray {
return this.AccessItemsForm.get('accessItemsGroups') as FormArray; return this.AccessItemsForm.get('accessItemsGroups') as FormArray;
@ -90,7 +93,7 @@ export class WorkbasketAccessItemsComponent implements OnInit, OnChanges, OnDest
ngOnInit() { ngOnInit() {
this.customFields$ = this.accessItemsCustomization$.pipe(getCustomFields(customFieldCount)); this.customFields$ = this.accessItemsCustomization$.pipe(getCustomFields(customFieldCount));
this.accessItemsRepresentation$.subscribe(accessItemsRepresentation => { this.accessItemsRepresentation$.subscribe((accessItemsRepresentation) => {
if (typeof accessItemsRepresentation !== 'undefined') { if (typeof accessItemsRepresentation !== 'undefined') {
this.accessItemsRepresentation = accessItemsRepresentation; this.accessItemsRepresentation = accessItemsRepresentation;
this.setAccessItemsGroups(accessItemsRepresentation.accessItems); this.setAccessItemsGroups(accessItemsRepresentation.accessItems);
@ -101,7 +104,7 @@ export class WorkbasketAccessItemsComponent implements OnInit, OnChanges, OnDest
} }
ngAfterViewInit() { ngAfterViewInit() {
this.inputs.changes.subscribe(next => { this.inputs.changes.subscribe((next) => {
if (typeof next.last !== 'undefined') { if (typeof next.last !== 'undefined') {
if (this.added) next.last.nativeElement.focus(); if (this.added) next.last.nativeElement.focus();
} }
@ -131,7 +134,8 @@ export class WorkbasketAccessItemsComponent implements OnInit, OnChanges, OnDest
this.requestInProgress = false; this.requestInProgress = false;
}); });
this.savingWorkbaskets.triggeredAccessItemsSaving() this.savingWorkbaskets
.triggeredAccessItemsSaving()
.pipe(takeUntil(this.destroy$)) .pipe(takeUntil(this.destroy$))
.subscribe((savingInformation: SavingInformation) => { .subscribe((savingInformation: SavingInformation) => {
if (this.action === ACTION.COPY) { if (this.action === ACTION.COPY) {
@ -144,8 +148,8 @@ export class WorkbasketAccessItemsComponent implements OnInit, OnChanges, OnDest
} }
setAccessItemsGroups(accessItems: Array<WorkbasketAccessItems>) { setAccessItemsGroups(accessItems: Array<WorkbasketAccessItems>) {
const AccessItemsFormGroups = accessItems.map(accessItem => this.formBuilder.group(accessItem)); const AccessItemsFormGroups = accessItems.map((accessItem) => this.formBuilder.group(accessItem));
AccessItemsFormGroups.forEach(accessItemGroup => { AccessItemsFormGroups.forEach((accessItemGroup) => {
accessItemGroup.controls.accessId.setValidators(Validators.required); accessItemGroup.controls.accessId.setValidators(Validators.required);
}); });
const AccessItemsFormArray = this.formBuilder.array(AccessItemsFormGroups); const AccessItemsFormArray = this.formBuilder.array(AccessItemsFormGroups);
@ -176,7 +180,7 @@ export class WorkbasketAccessItemsComponent implements OnInit, OnChanges, OnDest
permCustom10: false, permCustom10: false,
permCustom11: false, permCustom11: false,
permCustom12: false, permCustom12: false,
_links: {}, _links: {}
}; };
} }
@ -210,18 +214,25 @@ export class WorkbasketAccessItemsComponent implements OnInit, OnChanges, OnDest
onSubmit() { onSubmit() {
this.formsValidatorService.formSubmitAttempt = true; this.formsValidatorService.formSubmitAttempt = true;
this.formsValidatorService.validateFormAccess(this.accessItemsGroups, this.toggleValidationAccessIdMap).then(value => { this.formsValidatorService
if (value) { .validateFormAccess(this.accessItemsGroups, this.toggleValidationAccessIdMap)
this.onSave(); .then((value) => {
} if (value) {
}); this.onSave();
}
});
} }
checkAll(row: number, value: any) { checkAll(row: number, value: any) {
const checkAll = value.target.checked; const checkAll = value.target.checked;
const workbasketAccessItemsObj: WorkbasketAccessItems = this.createWorkbasketAccessItems(); const workbasketAccessItemsObj: WorkbasketAccessItems = this.createWorkbasketAccessItems();
Object.keys(workbasketAccessItemsObj).forEach(property => { Object.keys(workbasketAccessItemsObj).forEach((property) => {
if (property !== 'accessId' && property !== '_links' && property !== 'workbasketId' && property !== 'accessItemId') { if (
property !== 'accessId' &&
property !== '_links' &&
property !== 'workbasketId' &&
property !== 'accessItemId'
) {
this.accessItemsGroups.controls[row].get(property).setValue(checkAll); this.accessItemsGroups.controls[row].get(property).setValue(checkAll);
} }
}); });
@ -234,12 +245,16 @@ export class WorkbasketAccessItemsComponent implements OnInit, OnChanges, OnDest
private onSave() { private onSave() {
this.requestInProgressService.setRequestInProgress(true); this.requestInProgressService.setRequestInProgress(true);
this.store.dispatch(new UpdateWorkbasketAccessItems( this.store
this.accessItemsRepresentation._links.self.href, .dispatch(
this.AccessItemsForm.value.accessItemsGroups new UpdateWorkbasketAccessItems(
)).subscribe(() => { this.accessItemsRepresentation._links.self.href,
this.requestInProgressService.setRequestInProgress(false); this.AccessItemsForm.value.accessItemsGroups
}); )
)
.subscribe(() => {
this.requestInProgressService.setRequestInProgress(false);
});
} }
private setBadge() { private setBadge() {
@ -249,13 +264,13 @@ export class WorkbasketAccessItemsComponent implements OnInit, OnChanges, OnDest
} }
private cloneAccessItems(inputaccessItem): Array<WorkbasketAccessItems> { private cloneAccessItems(inputaccessItem): Array<WorkbasketAccessItems> {
return this.AccessItemsForm.value.accessItemsGroups.map( return this.AccessItemsForm.value.accessItemsGroups.map((accessItems: WorkbasketAccessItems) => ({
(accessItems: WorkbasketAccessItems) => ({ ...accessItems }) ...accessItems
); }));
} }
private setWorkbasketIdForCopy(workbasketId: string) { private setWorkbasketIdForCopy(workbasketId: string) {
this.accessItemsGroups.value.forEach(element => { this.accessItemsGroups.value.forEach((element) => {
delete element.accessItemId; delete element.accessItemId;
element.workbasketId = workbasketId; element.workbasketId = workbasketId;
}); });

View File

@ -33,12 +33,29 @@ import { NotificationService } from '../../../shared/services/notifications/noti
selector: 'taskana-dummy-detail', selector: 'taskana-dummy-detail',
template: 'dummydetail' template: 'dummydetail'
}) })
export class DummyDetailComponent { export class DummyDetailComponent {}
}
function createWorkbasket(workbasketId?, created?, key?, domain?, type?, modified?, name?, description?, function createWorkbasket(
owner?, custom1?, custom2?, custom3?, custom4?, orgLevel1?, orgLevel2?, orgLevel3?, orgLevel4?, workbasketId?,
_links?: Links, markedForDeletion?: boolean) { created?,
key?,
domain?,
type?,
modified?,
name?,
description?,
owner?,
custom1?,
custom2?,
custom3?,
custom4?,
orgLevel1?,
orgLevel2?,
orgLevel3?,
orgLevel4?,
_links?: Links,
markedForDeletion?: boolean
) {
const workbasket: Workbasket = { const workbasket: Workbasket = {
workbasketId, workbasketId,
created, created,
@ -70,29 +87,63 @@ describe('WorkbasketDetailsComponent', () => {
let masterAndDetailService; let masterAndDetailService;
let workbasketService; let workbasketService;
let router; let router;
const workbasket = createWorkbasket('1', '', '', '', ICONTYPES.TOPIC, '', '', '', '', '', '', '', '', '', '', '', '', const workbasket = createWorkbasket(
{}); '1',
'',
'',
'',
ICONTYPES.TOPIC,
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
{}
);
const workbasketSummaryRepresentation: WorkbasketSummaryRepresentation = { workbaskets: [], _links: {}, page: {} }; const workbasketSummaryRepresentation: WorkbasketSummaryRepresentation = { workbaskets: [], _links: {}, page: {} };
const workbasketAccessItemsRepresentation: WorkbasketAccessItemsRepresentation = { accessItems: [], _links: {} }; const workbasketAccessItemsRepresentation: WorkbasketAccessItemsRepresentation = { accessItems: [], _links: {} };
const routes: Routes = [ const routes: Routes = [{ path: '*', component: DummyDetailComponent }];
{ path: '*', component: DummyDetailComponent }
];
beforeEach(done => { beforeEach((done) => {
const configure = (testBed: TestBed) => { const configure = (testBed: TestBed) => {
testBed.configureTestingModule({ testBed.configureTestingModule({
imports: [RouterTestingModule.withRoutes(routes), FormsModule, AngularSvgIconModule, HttpClientModule, ReactiveFormsModule, imports: [
InfiniteScrollModule, NgxsModule.forRoot()], RouterTestingModule.withRoutes(routes),
declarations: [WorkbasketDetailsComponent, WorkbasketInformationComponent, FormsModule,
AngularSvgIconModule,
HttpClientModule,
ReactiveFormsModule,
InfiniteScrollModule,
NgxsModule.forRoot()
],
declarations: [
WorkbasketDetailsComponent,
WorkbasketInformationComponent,
WorkbasketAccessItemsComponent, WorkbasketAccessItemsComponent,
WorkbasketDistributionTargetsComponent, WorkbasketDualListComponent, DummyDetailComponent], WorkbasketDistributionTargetsComponent,
providers: [WorkbasketService, MasterAndDetailService, RequestInProgressService, WorkbasketDualListComponent,
NotificationService, SavingWorkbasketService, ImportExportService] DummyDetailComponent
],
providers: [
WorkbasketService,
MasterAndDetailService,
RequestInProgressService,
NotificationService,
SavingWorkbasketService,
ImportExportService
]
}); });
}; };
configureTests(configure).then(testBed => { configureTests(configure).then((testBed) => {
fixture = TestBed.createComponent(WorkbasketDetailsComponent); fixture = TestBed.createComponent(WorkbasketDetailsComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
debugElement = fixture.debugElement.nativeElement; debugElement = fixture.debugElement.nativeElement;
@ -106,7 +157,9 @@ describe('WorkbasketDetailsComponent', () => {
spyOn(workbasketService, 'getWorkBasket').and.callFake(() => of(workbasket)); spyOn(workbasketService, 'getWorkBasket').and.callFake(() => of(workbasket));
spyOn(workbasketService, 'getWorkBasketAccessItems').and.callFake(() => of(workbasketAccessItemsRepresentation)); spyOn(workbasketService, 'getWorkBasketAccessItems').and.callFake(() => of(workbasketAccessItemsRepresentation));
spyOn(workbasketService, 'getWorkBasketsDistributionTargets').and.callFake(() => of(workbasketSummaryRepresentation)); spyOn(workbasketService, 'getWorkBasketsDistributionTargets').and.callFake(() =>
of(workbasketSummaryRepresentation)
);
done(); done();
}); });
}); });

View File

@ -40,34 +40,34 @@ export class WorkbasketDetailsComponent implements OnInit, OnDestroy {
destroy$ = new Subject<void>(); destroy$ = new Subject<void>();
constructor(private service: WorkbasketService, constructor(
private service: WorkbasketService,
private route: ActivatedRoute, private route: ActivatedRoute,
private router: Router, private router: Router,
private domainService: DomainService, private domainService: DomainService,
private importExportService: ImportExportService, private importExportService: ImportExportService,
private store: Store) { private store: Store
} ) {}
ngOnInit() { ngOnInit() {
this.selectedWorkbasketAndAction$ this.selectedWorkbasketAndAction$.pipe(takeUntil(this.destroy$)).subscribe((selectedWorkbasketAndAction) => {
.pipe(takeUntil(this.destroy$)) this.action = selectedWorkbasketAndAction.action;
.subscribe(selectedWorkbasketAndAction => { if (this.action === ACTION.CREATE) {
this.action = selectedWorkbasketAndAction.action; this.tabSelected = 'information';
if (this.action === ACTION.CREATE) { this.selectedId = undefined;
this.tabSelected = 'information'; this.initWorkbasket();
this.selectedId = undefined; } else if (this.action === ACTION.COPY) {
this.initWorkbasket(); // delete this.workbasket.key;
} else if (this.action === ACTION.COPY) { this.workbasketCopy = this.workbasket;
// delete this.workbasket.key; this.getWorkbasketInformation();
this.workbasketCopy = this.workbasket; } else if (typeof selectedWorkbasketAndAction.selectedWorkbasket !== 'undefined') {
this.getWorkbasketInformation(); this.workbasket = { ...selectedWorkbasketAndAction.selectedWorkbasket };
} else if (typeof selectedWorkbasketAndAction.selectedWorkbasket !== 'undefined') { this.getWorkbasketInformation(this.workbasket);
this.workbasket = { ...selectedWorkbasketAndAction.selectedWorkbasket }; }
this.getWorkbasketInformation(this.workbasket); });
}
});
this.importExportService.getImportingFinished() this.importExportService
.getImportingFinished()
.pipe(takeUntil(this.destroy$)) .pipe(takeUntil(this.destroy$))
.subscribe(() => { .subscribe(() => {
if (this.workbasket) { if (this.workbasket) {
@ -105,15 +105,18 @@ export class WorkbasketDetailsComponent implements OnInit, OnDestroy {
workbasketIdSelected = selectedWorkbasket.workbasketId; workbasketIdSelected = selectedWorkbasket.workbasketId;
} }
this.requestInProgress = true; this.requestInProgress = true;
if (!workbasketIdSelected && this.action === ACTION.CREATE) { // CREATE if (!workbasketIdSelected && this.action === ACTION.CREATE) {
// CREATE
this.workbasket = {}; this.workbasket = {};
this.domainService.getSelectedDomain() this.domainService
.getSelectedDomain()
.pipe(takeUntil(this.destroy$)) .pipe(takeUntil(this.destroy$))
.subscribe(domain => { .subscribe((domain) => {
this.workbasket.domain = domain; this.workbasket.domain = domain;
}); });
this.requestInProgress = false; this.requestInProgress = false;
} else if (!workbasketIdSelected && this.action === ACTION.COPY) { // COPY } else if (!workbasketIdSelected && this.action === ACTION.COPY) {
// COPY
this.workbasket = { ...this.workbasketCopy }; this.workbasket = { ...this.workbasketCopy };
delete this.workbasket.workbasketId; delete this.workbasket.workbasketId;
this.requestInProgress = false; this.requestInProgress = false;
@ -126,9 +129,10 @@ export class WorkbasketDetailsComponent implements OnInit, OnDestroy {
} }
private checkDomainAndRedirect() { private checkDomainAndRedirect() {
this.domainService.getSelectedDomain() this.domainService
.getSelectedDomain()
.pipe(takeUntil(this.destroy$)) .pipe(takeUntil(this.destroy$))
.subscribe(domain => { .subscribe((domain) => {
if (domain !== '' && this.workbasket && this.workbasket.domain !== domain) { if (domain !== '' && this.workbasket && this.workbasket.domain !== domain) {
this.backClicked(); this.backClicked();
} }

View File

@ -1,15 +1,13 @@
.button-margin-top { .button-margin-top {
margin-top: 100px margin-top: 100px;
} }
.list-arrows > button{ .list-arrows > button {
margin: 10px 0px; margin: 10px 0px;
} }
.col-md-5-6 { .col-md-5-6 {
@media (min-width: 992px){ @media (min-width: 992px) {
width: 45.82%; width: 45.82%;
} }
} }

View File

@ -21,18 +21,55 @@ import { InfiniteScrollModule } from 'ngx-infinite-scroll';
import { NgxsModule, Store } from '@ngxs/store'; import { NgxsModule, Store } from '@ngxs/store';
import { WorkbasketDistributionTargetsComponent, Side } from './workbasket-distribution-targets.component'; import { WorkbasketDistributionTargetsComponent, Side } from './workbasket-distribution-targets.component';
import { WorkbasketDualListComponent } from '../workbasket-dual-list/workbasket-dual-list.component'; import { WorkbasketDualListComponent } from '../workbasket-dual-list/workbasket-dual-list.component';
import { NotificationService } from '../../../shared/services/notifications/notification.service'; import { ClassificationSelectors } from '../../../shared/store/classification-store/classification.selectors'; import { NotificationService } from '../../../shared/services/notifications/notification.service';
import { ClassificationSelectors } from '../../../shared/store/classification-store/classification.selectors';
import { WorkbasketSelectors } from '../../../shared/store/workbasket-store/workbasket.selectors'; import { WorkbasketSelectors } from '../../../shared/store/workbasket-store/workbasket.selectors';
describe('WorkbasketDistributionTargetsComponent', () => { describe('WorkbasketDistributionTargetsComponent', () => {
let component: WorkbasketDistributionTargetsComponent; let component: WorkbasketDistributionTargetsComponent;
let fixture: ComponentFixture<WorkbasketDistributionTargetsComponent>; let fixture: ComponentFixture<WorkbasketDistributionTargetsComponent>;
let workbasketService; let workbasketService;
const workbasket = createWorkbasket('1', '', '', '', ICONTYPES.TOPIC, '', '', '', '', '', '', '', '', '', '', '', '', const workbasket = createWorkbasket(
{}); '1',
function createWorkbasket(workbasketId?, created?, key?, domain?, type?, modified?, name?, description?, '',
owner?, custom1?, custom2?, custom3?, custom4?, orgLevel1?, orgLevel2?, orgLevel3?, orgLevel4?, '',
_links?: Links, markedForDeletion?: boolean): Workbasket { '',
ICONTYPES.TOPIC,
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
{}
);
function createWorkbasket(
workbasketId?,
created?,
key?,
domain?,
type?,
modified?,
name?,
description?,
owner?,
custom1?,
custom2?,
custom3?,
custom4?,
orgLevel1?,
orgLevel2?,
orgLevel3?,
orgLevel4?,
_links?: Links,
markedForDeletion?: boolean
): Workbasket {
return { return {
workbasketId, workbasketId,
created, created,
@ -56,7 +93,19 @@ describe('WorkbasketDistributionTargetsComponent', () => {
}; };
} }
function createWorkbasketSummary(workbasketId, key, name, domain, type, description, owner, custom1, custom2, custom3, custom4) { function createWorkbasketSummary(
workbasketId,
key,
name,
domain,
type,
description,
owner,
custom1,
custom2,
custom3,
custom4
) {
const workbasketSummary: WorkbasketSummary = { const workbasketSummary: WorkbasketSummary = {
workbasketId, workbasketId,
key, key,
@ -74,10 +123,8 @@ describe('WorkbasketDistributionTargetsComponent', () => {
} }
const workbasketSummaryResource: WorkbasketSummaryRepresentation = { const workbasketSummaryResource: WorkbasketSummaryRepresentation = {
workbaskets: [ workbaskets: [
createWorkbasketSummary('1', 'key1', 'NAME1', '', 'PERSONAL', createWorkbasketSummary('1', 'key1', 'NAME1', '', 'PERSONAL', 'description 1', 'owner1', '', '', '', ''),
'description 1', 'owner1', '', '', '', ''), createWorkbasketSummary('2', 'key2', 'NAME2', '', 'PERSONAL', 'description 2', 'owner2', '', '', '', '')
createWorkbasketSummary('2', 'key2', 'NAME2', '', 'PERSONAL',
'description 2', 'owner2', '', '', '', ''),
], ],
_links: new LinksWorkbasketSummary({ href: 'url' }), _links: new LinksWorkbasketSummary({ href: 'url' }),
page: {} page: {}
@ -90,17 +137,22 @@ describe('WorkbasketDistributionTargetsComponent', () => {
const storeSpy: jasmine.SpyObj<Store> = jasmine.createSpyObj('Store', ['select', 'dispatch']); const storeSpy: jasmine.SpyObj<Store> = jasmine.createSpyObj('Store', ['select', 'dispatch']);
beforeEach(done => { beforeEach((done) => {
const configure = (testBed: TestBed) => { const configure = (testBed: TestBed) => {
testBed.configureTestingModule({ testBed.configureTestingModule({
imports: [AngularSvgIconModule, HttpClientModule, InfiniteScrollModule, NgxsModule.forRoot()], imports: [AngularSvgIconModule, HttpClientModule, InfiniteScrollModule, NgxsModule.forRoot()],
declarations: [WorkbasketDistributionTargetsComponent, WorkbasketDualListComponent], declarations: [WorkbasketDistributionTargetsComponent, WorkbasketDualListComponent],
providers: [WorkbasketService, NotificationService, SavingWorkbasketService, RequestInProgressService, providers: [
{ provide: Store, useValue: storeSpy }] WorkbasketService,
NotificationService,
SavingWorkbasketService,
RequestInProgressService,
{ provide: Store, useValue: storeSpy }
]
}); });
}; };
configureTests(configure).then(testBed => { configureTests(configure).then((testBed) => {
storeSpy.select.and.callFake(selector => { storeSpy.select.and.callFake((selector) => {
switch (selector) { switch (selector) {
case WorkbasketSelectors.workbasketDistributionTargets: case WorkbasketSelectors.workbasketDistributionTargets:
return of(['distributionTargets', '_links']); return of(['distributionTargets', '_links']);
@ -113,7 +165,9 @@ describe('WorkbasketDistributionTargetsComponent', () => {
component.workbasket = workbasket; component.workbasket = workbasket;
workbasketService = TestBed.get(WorkbasketService); workbasketService = TestBed.get(WorkbasketService);
spyOn(workbasketService, 'getWorkBasketsSummary').and.callFake(() => of(workbasketSummaryResource)); spyOn(workbasketService, 'getWorkBasketsSummary').and.callFake(() => of(workbasketSummaryResource));
spyOn(workbasketService, 'getWorkBasketsDistributionTargets').and.callFake(() => of(workbasketDistributionTargets)); spyOn(workbasketService, 'getWorkBasketsDistributionTargets').and.callFake(() =>
of(workbasketDistributionTargets)
);
component.ngOnChanges({ component.ngOnChanges({
active: new SimpleChange(undefined, 'distributionTargets', true) active: new SimpleChange(undefined, 'distributionTargets', true)
}); });
@ -139,21 +193,19 @@ describe('WorkbasketDistributionTargetsComponent', () => {
let repeteadElemens = false; let repeteadElemens = false;
expect(component.distributionTargetsLeft.length).toBe(2); expect(component.distributionTargetsLeft.length).toBe(2);
expect(component.distributionTargetsRight.length).toBe(2); expect(component.distributionTargetsRight.length).toBe(2);
component.distributionTargetsLeft.forEach(leftElement => { component.distributionTargetsLeft.forEach((leftElement) => {
component.distributionTargetsRight.forEach(rightElement => { component.distributionTargetsRight.forEach((rightElement) => {
if (leftElement.workbasketId === rightElement.workbasketId) { repeteadElemens = true; } if (leftElement.workbasketId === rightElement.workbasketId) {
repeteadElemens = true;
}
}); });
}); });
expect(repeteadElemens).toBeTruthy(); expect(repeteadElemens).toBeTruthy();
}); });
it('should reset distribution target and distribution target selected on reset', () => { it('should reset distribution target and distribution target selected on reset', () => {
component.distributionTargetsLeft.push( component.distributionTargetsLeft.push(createWorkbasketSummary('id4', '', '', '', '', '', '', '', '', '', ''));
createWorkbasketSummary('id4', '', '', '', '', '', '', '', '', '', '') component.distributionTargetsRight.push(createWorkbasketSummary('id5', '', '', '', '', '', '', '', '', '', ''));
);
component.distributionTargetsRight.push(
createWorkbasketSummary('id5', '', '', '', '', '', '', '', '', '', '')
);
expect(component.distributionTargetsLeft.length).toBe(3); expect(component.distributionTargetsLeft.length).toBe(3);
expect(component.distributionTargetsRight.length).toBe(3); expect(component.distributionTargetsRight.length).toBe(3);

View File

@ -1,10 +1,4 @@
import { Component, import { Component, ElementRef, Input, OnChanges, OnDestroy, OnInit, SimpleChanges, ViewChild } from '@angular/core';
ElementRef,
Input,
OnChanges,
OnDestroy, OnInit,
SimpleChanges,
ViewChild } from '@angular/core';
import { Observable, Subject } from 'rxjs'; import { Observable, Subject } from 'rxjs';
import { Workbasket } from 'app/shared/models/workbasket'; import { Workbasket } from 'app/shared/models/workbasket';
@ -24,8 +18,11 @@ import { Select, Store } from '@ngxs/store';
import { take, takeUntil } from 'rxjs/operators'; import { take, takeUntil } from 'rxjs/operators';
import { NOTIFICATION_TYPES } from '../../../shared/models/notifications'; import { NOTIFICATION_TYPES } from '../../../shared/models/notifications';
import { NotificationService } from '../../../shared/services/notifications/notification.service'; import { NotificationService } from '../../../shared/services/notifications/notification.service';
import { GetWorkbasketDistributionTargets, import {
GetWorkbasketsSummary, UpdateWorkbasketDistributionTargets } from '../../../shared/store/workbasket-store/workbasket.actions'; GetWorkbasketDistributionTargets,
GetWorkbasketsSummary,
UpdateWorkbasketDistributionTargets
} from '../../../shared/store/workbasket-store/workbasket.actions';
import { WorkbasketSelectors } from '../../../shared/store/workbasket-store/workbasket.selectors'; import { WorkbasketSelectors } from '../../../shared/store/workbasket-store/workbasket.selectors';
import { WorkbasketStateModel } from '../../../shared/store/workbasket-store/workbasket.state'; import { WorkbasketStateModel } from '../../../shared/store/workbasket-store/workbasket.state';
@ -82,10 +79,10 @@ export class WorkbasketDistributionTargetsComponent implements OnInit, OnChanges
private orientationService: OrientationService, private orientationService: OrientationService,
private notificationsService: NotificationService, private notificationsService: NotificationService,
private store: Store private store: Store
) { } ) {}
ngOnInit() { ngOnInit() {
this.workbasketDistributionTargets$.subscribe(workbasketDistributionTargets => { this.workbasketDistributionTargets$.subscribe((workbasketDistributionTargets) => {
if (typeof workbasketDistributionTargets !== 'undefined') { if (typeof workbasketDistributionTargets !== 'undefined') {
this.distributionTargetsSelectedResource = { ...workbasketDistributionTargets }; this.distributionTargetsSelectedResource = { ...workbasketDistributionTargets };
this.distributionTargetsSelected = this.distributionTargetsSelectedResource.distributionTargets; this.distributionTargetsSelected = this.distributionTargetsSelectedResource.distributionTargets;
@ -120,7 +117,8 @@ export class WorkbasketDistributionTargetsComponent implements OnInit, OnChanges
} }
this.store.dispatch(new GetWorkbasketDistributionTargets(this.workbasket._links.distributionTargets.href)); this.store.dispatch(new GetWorkbasketDistributionTargets(this.workbasket._links.distributionTargets.href));
this.savingWorkbaskets.triggeredDistributionTargetsSaving() this.savingWorkbaskets
.triggeredDistributionTargetsSaving()
.pipe(takeUntil(this.destroy$)) .pipe(takeUntil(this.destroy$))
.subscribe((savingInformation: SavingInformation) => { .subscribe((savingInformation: SavingInformation) => {
if (this.action === ACTION.COPY) { if (this.action === ACTION.COPY) {
@ -129,7 +127,8 @@ export class WorkbasketDistributionTargetsComponent implements OnInit, OnChanges
} }
}); });
this.orientationService.getOrientation() this.orientationService
.getOrientation()
.pipe(takeUntil(this.destroy$)) .pipe(takeUntil(this.destroy$))
.subscribe(() => { .subscribe(() => {
this.calculateNumberItemsList(); this.calculateNumberItemsList();
@ -144,52 +143,73 @@ export class WorkbasketDistributionTargetsComponent implements OnInit, OnChanges
} }
// TODO: Implement this into NGXS // TODO: Implement this into NGXS
this.workbasketService.getWorkBasketsSummary(true) this.workbasketService
.getWorkBasketsSummary(true)
.pipe(takeUntil(this.destroy$)) .pipe(takeUntil(this.destroy$))
.subscribe( .subscribe((distributionTargetsAvailable: WorkbasketSummaryRepresentation) => {
(distributionTargetsAvailable: WorkbasketSummaryRepresentation) => { if (TaskanaQueryParameters.page === 1) {
if (TaskanaQueryParameters.page === 1) { this.distributionTargetsLeft = [];
this.distributionTargetsLeft = []; this.page = distributionTargetsAvailable.page;
this.page = distributionTargetsAvailable.page;
}
if (side === this.side.LEFT) {
this.distributionTargetsLeft.push(...distributionTargetsAvailable.workbaskets);
} else if (side === this.side.RIGHT) {
this.distributionTargetsRight = Object.assign([], distributionTargetsAvailable.workbaskets);
} else {
this.distributionTargetsLeft.push(...distributionTargetsAvailable.workbaskets);
this.distributionTargetsRight = Object.assign([], distributionTargetsAvailable.workbaskets);
this.distributionTargetsClone = Object.assign([], distributionTargetsAvailable.workbaskets);
}
this.onRequest(true);
} }
); if (side === this.side.LEFT) {
this.distributionTargetsLeft.push(...distributionTargetsAvailable.workbaskets);
} else if (side === this.side.RIGHT) {
this.distributionTargetsRight = Object.assign([], distributionTargetsAvailable.workbaskets);
} else {
this.distributionTargetsLeft.push(...distributionTargetsAvailable.workbaskets);
this.distributionTargetsRight = Object.assign([], distributionTargetsAvailable.workbaskets);
this.distributionTargetsClone = Object.assign([], distributionTargetsAvailable.workbaskets);
}
this.onRequest(true);
});
} }
performFilter(dualListFilter: any) { performFilter(dualListFilter: any) {
this.fillDistributionTargets(dualListFilter.side, undefined); this.fillDistributionTargets(dualListFilter.side, undefined);
this.onRequest(false, dualListFilter.side); this.onRequest(false, dualListFilter.side);
this.store.dispatch(new GetWorkbasketsSummary(true, '', '', '', this.store
dualListFilter.filterBy.filterParams.name, dualListFilter.filterBy.filterParams.description, '', .dispatch(
dualListFilter.filterBy.filterParams.owner, dualListFilter.filterBy.filterParams.type, '', new GetWorkbasketsSummary(
dualListFilter.filterBy.filterParams.key, '', true)).subscribe((state: WorkbasketStateModel) => { true,
this.fillDistributionTargets(dualListFilter.side, state.paginatedWorkbasketsSummary.workbaskets); '',
this.onRequest(true, dualListFilter.side); '',
}); '',
dualListFilter.filterBy.filterParams.name,
dualListFilter.filterBy.filterParams.description,
'',
dualListFilter.filterBy.filterParams.owner,
dualListFilter.filterBy.filterParams.type,
'',
dualListFilter.filterBy.filterParams.key,
'',
true
)
)
.subscribe((state: WorkbasketStateModel) => {
this.fillDistributionTargets(dualListFilter.side, state.paginatedWorkbasketsSummary.workbaskets);
this.onRequest(true, dualListFilter.side);
});
} }
onSave() { onSave() {
this.requestInProgressService.setRequestInProgress(true); this.requestInProgressService.setRequestInProgress(true);
this.store.dispatch(new UpdateWorkbasketDistributionTargets( this.store
this.distributionTargetsSelectedResource._links.self.href, .dispatch(
this.getSeletedIds() new UpdateWorkbasketDistributionTargets(
)).subscribe(() => { this.distributionTargetsSelectedResource._links.self.href,
this.requestInProgressService.setRequestInProgress(false); this.getSeletedIds()
return true; )
}, error => { )
this.requestInProgressService.setRequestInProgress(false); .subscribe(
return false; () => {
}); this.requestInProgressService.setRequestInProgress(false);
return true;
},
(error) => {
this.requestInProgressService.setRequestInProgress(false);
return false;
}
);
/* TODO: OLD IMPLEMENTATION, KEPT HERE FOR REFERENCE /* TODO: OLD IMPLEMENTATION, KEPT HERE FOR REFERENCE
this.workbasketService.updateWorkBasketsDistributionTargets( this.workbasketService.updateWorkBasketsDistributionTargets(
this.distributionTargetsSelectedResource._links.self.href, this.getSeletedIds() this.distributionTargetsSelectedResource._links.self.href, this.getSeletedIds()
@ -220,7 +240,10 @@ export class WorkbasketDistributionTargetsComponent implements OnInit, OnChanges
const itemsSelected = this.getSelectedItems(this.distributionTargetsLeft); const itemsSelected = this.getSelectedItems(this.distributionTargetsLeft);
this.distributionTargetsSelected = [...this.distributionTargetsSelected, ...itemsSelected]; this.distributionTargetsSelected = [...this.distributionTargetsSelected, ...itemsSelected];
this.distributionTargetsRight = this.distributionTargetsRight.concat(itemsSelected); this.distributionTargetsRight = this.distributionTargetsRight.concat(itemsSelected);
if (((itemsLeft - itemsSelected.length) <= TaskanaQueryParameters.pageSize) && ((itemsLeft + itemsRight) < this.page.totalElements)) { if (
itemsLeft - itemsSelected.length <= TaskanaQueryParameters.pageSize &&
itemsLeft + itemsRight < this.page.totalElements
) {
this.getNextPage(side); this.getNextPage(side);
} }
this.unselectItems(this.distributionTargetsSelected); this.unselectItems(this.distributionTargetsSelected);
@ -244,9 +267,13 @@ export class WorkbasketDistributionTargetsComponent implements OnInit, OnChanges
if (this.panelBody) { if (this.panelBody) {
const cardHeight = 72; const cardHeight = 72;
const unusedHeight = 100; const unusedHeight = 100;
this.cards = this.orientationService.calculateNumberItemsList( this.cards =
this.panelBody.nativeElement.offsetHeight, cardHeight, unusedHeight, true this.orientationService.calculateNumberItemsList(
) + 1; // TODO: warum +1 this.panelBody.nativeElement.offsetHeight,
cardHeight,
unusedHeight,
true
) + 1; // TODO: warum +1
} }
} }
@ -267,7 +294,7 @@ export class WorkbasketDistributionTargetsComponent implements OnInit, OnChanges
} }
getSelectedItems(originList: any): Array<any> { getSelectedItems(originList: any): Array<any> {
return originList.filter((item: any) => (item.selected === true)); return originList.filter((item: any) => item.selected === true);
} }
unselectItems(originList: any): Array<any> { unselectItems(originList: any): Array<any> {
@ -282,7 +309,7 @@ export class WorkbasketDistributionTargetsComponent implements OnInit, OnChanges
removeSelectedItems(originList: any, selectedItemList) { removeSelectedItems(originList: any, selectedItemList) {
for (let index = originList.length - 1; index >= 0; index--) { for (let index = originList.length - 1; index >= 0; index--) {
if (selectedItemList.some(itemToRemove => (originList[index].workbasketId === itemToRemove.workbasketId))) { if (selectedItemList.some((itemToRemove) => originList[index].workbasketId === itemToRemove.workbasketId)) {
originList.splice(index, 1); originList.splice(index, 1);
} }
} }
@ -293,9 +320,11 @@ export class WorkbasketDistributionTargetsComponent implements OnInit, OnChanges
this.loadingItems = false; this.loadingItems = false;
const inProgress = !finished; const inProgress = !finished;
switch (side) { switch (side) {
case Side.LEFT: this.requestInProgressLeft = inProgress; case Side.LEFT:
this.requestInProgressLeft = inProgress;
break; break;
case Side.RIGHT: this.requestInProgressRight = inProgress; case Side.RIGHT:
this.requestInProgressRight = inProgress;
break; break;
default: default:
this.requestInProgressLeft = inProgress; this.requestInProgressLeft = inProgress;
@ -305,15 +334,19 @@ export class WorkbasketDistributionTargetsComponent implements OnInit, OnChanges
getSeletedIds(): Array<string> { getSeletedIds(): Array<string> {
const distributionTargetsSelelected: Array<string> = []; const distributionTargetsSelelected: Array<string> = [];
this.distributionTargetsSelected.forEach(item => { this.distributionTargetsSelected.forEach((item) => {
distributionTargetsSelelected.push(item.workbasketId); distributionTargetsSelelected.push(item.workbasketId);
}); });
return distributionTargetsSelelected; return distributionTargetsSelelected;
} }
private uncheckSelectAll(side: number) { private uncheckSelectAll(side: number) {
if (side === Side.LEFT && this.selectAllLeft) { this.selectAllLeft = false; } if (side === Side.LEFT && this.selectAllLeft) {
if (side === Side.RIGHT && this.selectAllRight) { this.selectAllRight = false; } this.selectAllLeft = false;
}
if (side === Side.RIGHT && this.selectAllRight) {
this.selectAllRight = false;
}
} }
ngOnDestroy() { ngOnDestroy() {

View File

@ -1,49 +1,48 @@
$selected-item: #e3f3f5; $selected-item: #e3f3f5;
.dual-list { .dual-list {
min-height: 250px; min-height: 250px;
padding: 0px; padding: 0px;
background-color: #f5f5f5; background-color: #f5f5f5;
border: 1px solid #e3e3e3; border: 1px solid #e3e3e3;
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05); -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05); box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
& .row { & .row {
padding: 0px 0px 0px 3px; padding: 0px 0px 0px 3px;
} }
& .row:first { & .row:first {
border-top: 1px solid #ddd; border-top: 1px solid #ddd;
} }
& div.pull-right { & div.pull-right {
margin-right: 17px; margin-right: 17px;
} }
& >.list-group { & > .list-group {
margin-bottom: 0px; margin-bottom: 0px;
margin-top: 0px; margin-top: 0px;
}
& > .list-group > li {
border-left: none;
border-right: none;
}
} overflow-x: hidden;
& > .list-group > li { overflow-y: hidden;
border-left: none;
border-right: none;
}
overflow-x: hidden; @media screen and (max-width: 991px) {
overflow-y: hidden; height: calc((100vh - 241px) / 2);
min-height: 120px;
@media screen and (max-width: 991px){ margin-bottom: 0;
height: calc((100vh - 241px) / 2); }
min-height: 120px; max-height: calc(100vh - 194px);
margin-bottom: 0; margin-bottom: 2px;
}
max-height: calc(100vh - 194px);
margin-bottom: 2px;
} }
.infinite-scroll { .infinite-scroll {
overflow-y: scroll; overflow-y: scroll;
height: calc(100vh - 233px); height: calc(100vh - 233px);
@media screen and (max-width: 991px){ @media screen and (max-width: 991px) {
height: calc((100vh - 315px) / 2); height: calc((100vh - 315px) / 2);
min-height: 83px; min-height: 83px;
} }
@ -54,60 +53,60 @@ $selected-item: #e3f3f5;
} }
.list-group { .list-group {
margin-top: 8px; margin-top: 8px;
} }
ul > li {
ul>li { &:first-child.list-group-item.selected {
&:first-child.list-group-item.selected {
border-color: #ddd; border-color: #ddd;
} }
&.list-group-item.selected { &.list-group-item.selected {
background-color: $selected-item; background-color: $selected-item;
} }
} }
.list-left li { .list-left li {
cursor: pointer; cursor: pointer;
} }
button.no-style{ button.no-style {
background: none; background: none;
border:none; border: none;
} }
.row.list-group { .row.list-group {
margin-left: 2px; margin-left: 2px;
} }
.list-group > li { .list-group > li {
border-left: none; border-left: none;
border-right: none; border-right: none;
} }
a > label{ a > label {
height: 2em; height: 2em;
width: 100%; width: 100%;
} }
dd, dt { dd,
text-overflow: ellipsis; dt {
white-space: nowrap; text-overflow: ellipsis;
overflow: hidden; white-space: nowrap;
overflow: hidden;
} }
dt > i { dt > i {
font-weight: normal; font-weight: normal;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
} }
li > div.row > dl { li > div.row > dl {
margin-bottom: 0px; margin-bottom: 0px;
} }
li.list-group-item:hover, { li.list-group-item:hover {
color: #555; color: #555;
text-decoration: none; text-decoration: none;
background-color: #f5f5f5; background-color: #f5f5f5;
} }

View File

@ -13,9 +13,9 @@ import { Side } from '../workbasket-distribution-targets/workbasket-distribution
export class WorkbasketDualListComponent implements OnInit { export class WorkbasketDualListComponent implements OnInit {
@Input() distributionTargets: WorkbasketSummary[]; @Input() distributionTargets: WorkbasketSummary[];
@Input() distributionTargetsSelected: WorkbasketSummary[]; @Input() distributionTargetsSelected: WorkbasketSummary[];
@Output() performDualListFilter = new EventEmitter<{ filterBy: Filter, side: Side }>(); @Output() performDualListFilter = new EventEmitter<{ filterBy: Filter; side: Side }>();
@Input() requestInProgress = false; @Input() requestInProgress = false;
@Input() loadingItems ? = false; @Input() loadingItems? = false;
@Input() side: Side; @Input() side: Side;
@Input() header: string; @Input() header: string;
@Output() scrolling = new EventEmitter<Side>(); @Output() scrolling = new EventEmitter<Side>();

View File

@ -1,3 +1,3 @@
.dropdown-menu { .dropdown-menu {
min-width: auto; min-width: auto;
} }

View File

@ -23,8 +23,7 @@ import { NotificationService } from '../../../shared/services/notifications/noti
selector: 'taskana-dummy-detail', selector: 'taskana-dummy-detail',
template: 'dummydetail' template: 'dummydetail'
}) })
export class DummyDetailComponent { export class DummyDetailComponent {}
}
const routes: Routes = [ const routes: Routes = [
{ path: ':id', component: DummyDetailComponent, outlet: 'detail' }, { path: ':id', component: DummyDetailComponent, outlet: 'detail' },
@ -44,17 +43,44 @@ describe('WorkbasketInformationComponent', () => {
const configure = (testBed: TestBed) => { const configure = (testBed: TestBed) => {
testBed.configureTestingModule({ testBed.configureTestingModule({
declarations: [WorkbasketInformationComponent, DummyDetailComponent], declarations: [WorkbasketInformationComponent, DummyDetailComponent],
imports: [FormsModule, AngularSvgIconModule, HttpClientModule, RouterTestingModule.withRoutes(routes), imports: [
NgxsModule.forRoot()], FormsModule,
providers: [WorkbasketService, NotificationService, SavingWorkbasketService, AngularSvgIconModule,
RequestInProgressService, FormsValidatorService] HttpClientModule,
RouterTestingModule.withRoutes(routes),
NgxsModule.forRoot()
],
providers: [
WorkbasketService,
NotificationService,
SavingWorkbasketService,
RequestInProgressService,
FormsValidatorService
]
}); });
}; };
function createWorkbasket(workbasketId?, created?, key?, domain?, type?, modified?, name?, description?, function createWorkbasket(
owner?, custom1?, custom2?, custom3?, custom4?, orgLevel1?, orgLevel2?, orgLevel3?, orgLevel4?, workbasketId?,
_links?: Links, markedForDeletion?: boolean) { created?,
key?,
domain?,
type?,
modified?,
name?,
description?,
owner?,
custom1?,
custom2?,
custom3?,
custom4?,
orgLevel1?,
orgLevel2?,
orgLevel3?,
orgLevel4?,
_links?: Links,
markedForDeletion?: boolean
) {
if (!type) { if (!type) {
// eslint-disable-next-line no-param-reassign // eslint-disable-next-line no-param-reassign
type = 'PERSONAL'; type = 'PERSONAL';
@ -83,8 +109,8 @@ describe('WorkbasketInformationComponent', () => {
return workbasket; return workbasket;
} }
beforeEach(done => { beforeEach((done) => {
configureTests(configure).then(testBed => { configureTests(configure).then((testBed) => {
fixture = testBed.createComponent(WorkbasketInformationComponent); fixture = testBed.createComponent(WorkbasketInformationComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
debugElement = fixture.debugElement.nativeElement; debugElement = fixture.debugElement.nativeElement;
@ -119,11 +145,26 @@ describe('WorkbasketInformationComponent', () => {
it('should create a copy of workbasket when workbasket is selected', () => { it('should create a copy of workbasket when workbasket is selected', () => {
expect(component.workbasketClone).toBeUndefined(); expect(component.workbasketClone).toBeUndefined();
component.workbasket = createWorkbasket('id', 'created', 'keyModified', 'domain', ICONTYPES.TOPIC, 'modified', 'name', 'description', component.workbasket = createWorkbasket(
'owner', 'custom1', 'custom2', 'custom3', 'custom4', 'orgLevel1', 'orgLevel2', 'orgLevel3', 'orgLevel4'); 'id',
component.ngOnChanges( 'created',
undefined 'keyModified',
'domain',
ICONTYPES.TOPIC,
'modified',
'name',
'description',
'owner',
'custom1',
'custom2',
'custom3',
'custom4',
'orgLevel1',
'orgLevel2',
'orgLevel3',
'orgLevel4'
); );
component.ngOnChanges(undefined);
fixture.detectChanges(); fixture.detectChanges();
expect(component.workbasket.workbasketId).toEqual(component.workbasketClone.workbasketId); expect(component.workbasket.workbasketId).toEqual(component.workbasketClone.workbasketId);
}); });

View File

@ -1,10 +1,4 @@
import { Component, import { Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges, ViewChild } from '@angular/core';
Input,
OnChanges,
OnDestroy,
OnInit,
SimpleChanges,
ViewChild } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router'; import { ActivatedRoute, Router } from '@angular/router';
import { Observable, Subject, Subscription } from 'rxjs'; import { Observable, Subject, Subscription } from 'rxjs';
import { NgForm } from '@angular/forms'; import { NgForm } from '@angular/forms';
@ -23,20 +17,21 @@ import { map, takeUntil } from 'rxjs/operators';
import { EngineConfigurationSelectors } from 'app/shared/store/engine-configuration-store/engine-configuration.selectors'; import { EngineConfigurationSelectors } from 'app/shared/store/engine-configuration-store/engine-configuration.selectors';
import { NOTIFICATION_TYPES } from '../../../shared/models/notifications'; import { NOTIFICATION_TYPES } from '../../../shared/models/notifications';
import { NotificationService } from '../../../shared/services/notifications/notification.service'; import { NotificationService } from '../../../shared/services/notifications/notification.service';
import { CustomField, import { CustomField, getCustomFields, WorkbasketsCustomisation } from '../../../shared/models/customisation';
getCustomFields, import {
WorkbasketsCustomisation } from '../../../shared/models/customisation'; CopyWorkbasket,
import { CopyWorkbasket, MarkWorkbasketForDeletion, MarkWorkbasketForDeletion,
RemoveDistributionTarget, SaveNewWorkbasket, RemoveDistributionTarget,
UpdateWorkbasket } from '../../../shared/store/workbasket-store/workbasket.actions'; SaveNewWorkbasket,
UpdateWorkbasket
} from '../../../shared/store/workbasket-store/workbasket.actions';
@Component({ @Component({
selector: 'taskana-administration-workbasket-information', selector: 'taskana-administration-workbasket-information',
templateUrl: './workbasket-information.component.html', templateUrl: './workbasket-information.component.html',
styleUrls: ['./workbasket-information.component.scss'] styleUrls: ['./workbasket-information.component.scss']
}) })
export class WorkbasketInformationComponent export class WorkbasketInformationComponent implements OnInit, OnChanges, OnDestroy {
implements OnInit, OnChanges, OnDestroy {
@Input() @Input()
workbasket: Workbasket; workbasket: Workbasket;
@ -68,8 +63,7 @@ implements OnInit, OnChanges, OnDestroy {
private formsValidatorService: FormsValidatorService, private formsValidatorService: FormsValidatorService,
private notificationService: NotificationService, private notificationService: NotificationService,
private store: Store private store: Store
) { ) {}
}
ngOnInit() { ngOnInit() {
this.allTypes = new Map([ this.allTypes = new Map([
@ -79,16 +73,14 @@ implements OnInit, OnChanges, OnDestroy {
['TOPIC', 'Topic'] ['TOPIC', 'Topic']
]); ]);
this.customFields$ = this.workbasketsCustomisation$.pipe( this.customFields$ = this.workbasketsCustomisation$.pipe(
map(customisation => customisation.information), map((customisation) => customisation.information),
getCustomFields(customFieldCount) getCustomFields(customFieldCount)
); );
this.workbasketsCustomisation$ this.workbasketsCustomisation$.pipe(takeUntil(this.destroy$)).subscribe((workbasketsCustomization) => {
.pipe(takeUntil(this.destroy$)) if (workbasketsCustomization.information.owner) {
.subscribe(workbasketsCustomization => { this.lookupField = workbasketsCustomization.information.owner.lookupField;
if (workbasketsCustomization.information.owner) { }
this.lookupField = workbasketsCustomization.information.owner.lookupField; });
}
});
} }
ngOnChanges(changes: SimpleChanges) { ngOnChanges(changes: SimpleChanges) {
@ -106,13 +98,11 @@ implements OnInit, OnChanges, OnDestroy {
onSubmit() { onSubmit() {
this.formsValidatorService.formSubmitAttempt = true; this.formsValidatorService.formSubmitAttempt = true;
this.formsValidatorService this.formsValidatorService.validateFormInformation(this.workbasketForm, this.toogleValidationMap).then((value) => {
.validateFormInformation(this.workbasketForm, this.toogleValidationMap) if (value) {
.then(value => { this.onSave();
if (value) { }
this.onSave(); });
}
});
} }
isFieldValid(field: string): boolean { isFieldValid(field: string): boolean {
@ -146,11 +136,10 @@ implements OnInit, OnChanges, OnDestroy {
this.postNewWorkbasket(); this.postNewWorkbasket();
return; return;
} }
this.store.dispatch(new UpdateWorkbasket(this.workbasket._links.self.href, this.workbasket)) this.store.dispatch(new UpdateWorkbasket(this.workbasket._links.self.href, this.workbasket)).subscribe((state) => {
.subscribe(state => { this.requestInProgressService.setRequestInProgress(false);
this.requestInProgressService.setRequestInProgress(false); this.workbasketClone = { ...this.workbasket };
this.workbasketClone = { ...this.workbasket }; });
});
} }
private beforeRequest() { private beforeRequest() {
@ -164,25 +153,17 @@ implements OnInit, OnChanges, OnDestroy {
private postNewWorkbasket() { private postNewWorkbasket() {
this.addDateToWorkbasket(); this.addDateToWorkbasket();
this.store.dispatch(new SaveNewWorkbasket(this.workbasket)).subscribe( this.store.dispatch(new SaveNewWorkbasket(this.workbasket)).subscribe(() => {
() => { this.afterRequest();
this.afterRequest(); if (this.action === ACTION.COPY) {
if (this.action === ACTION.COPY) { this.savingWorkbasket.triggerDistributionTargetSaving(
this.savingWorkbasket.triggerDistributionTargetSaving( new SavingInformation(this.workbasket._links.distributionTargets.href, this.workbasket.workbasketId)
new SavingInformation( );
this.workbasket._links.distributionTargets.href, this.savingWorkbasket.triggerAccessItemsSaving(
this.workbasket.workbasketId new SavingInformation(this.workbasket._links.accessItems.href, this.workbasket.workbasketId)
) );
);
this.savingWorkbasket.triggerAccessItemsSaving(
new SavingInformation(
this.workbasket._links.accessItems.href,
this.workbasket.workbasketId
)
);
}
} }
); });
} }
private addDateToWorkbasket() { private addDateToWorkbasket() {

View File

@ -1,13 +1,13 @@
.list-group-item { .list-group-item {
padding: 5px 0px 2px 1px; padding: 5px 0px 2px 1px;
border: none; border: none;
} }
.tab-align{ .tab-align {
padding: 8px 12px 8px 4px; padding: 8px 12px 8px 4px;
margin-bottom: 0px; margin-bottom: 0px;
&>div{ & > div {
margin: 6px 0px; margin: 6px 0px;
} }
} }

View File

@ -27,9 +27,7 @@ import { ICONTYPES } from '../../../shared/models/icon-types';
selector: 'taskana-dummy-detail', selector: 'taskana-dummy-detail',
template: 'dummydetail' template: 'dummydetail'
}) })
export class DummyDetailComponent { export class DummyDetailComponent {}
}
describe('WorkbasketListToolbarComponent', () => { describe('WorkbasketListToolbarComponent', () => {
let component: WorkbasketListToolbarComponent; let component: WorkbasketListToolbarComponent;
@ -38,15 +36,20 @@ describe('WorkbasketListToolbarComponent', () => {
let workbasketService; let workbasketService;
let router; let router;
const routes: Routes = [ const routes: Routes = [{ path: ':id', component: DummyDetailComponent, outlet: 'detail' }];
{ path: ':id', component: DummyDetailComponent, outlet: 'detail' }
];
beforeEach(done => { beforeEach((done) => {
const configure = (testBed: TestBed) => { const configure = (testBed: TestBed) => {
testBed.configureTestingModule({ testBed.configureTestingModule({
imports: [FormsModule, ReactiveFormsModule, AngularSvgIconModule, imports: [
HttpClientModule, RouterTestingModule.withRoutes(routes), SharedModule, AppModule], FormsModule,
ReactiveFormsModule,
AngularSvgIconModule,
HttpClientModule,
RouterTestingModule.withRoutes(routes),
SharedModule,
AppModule
],
declarations: [WorkbasketListToolbarComponent, DummyDetailComponent, ImportExportComponent], declarations: [WorkbasketListToolbarComponent, DummyDetailComponent, ImportExportComponent],
providers: [ providers: [
WorkbasketService, WorkbasketService,
@ -56,7 +59,7 @@ describe('WorkbasketListToolbarComponent', () => {
] ]
}); });
}; };
configureTests(configure).then(testBed => { configureTests(configure).then((testBed) => {
fixture = TestBed.createComponent(WorkbasketListToolbarComponent); fixture = TestBed.createComponent(WorkbasketListToolbarComponent);
workbasketService = TestBed.get(WorkbasketService); workbasketService = TestBed.get(WorkbasketService);
router = TestBed.get(Router); router = TestBed.get(Router);
@ -65,12 +68,16 @@ describe('WorkbasketListToolbarComponent', () => {
debugElement = fixture.debugElement.nativeElement; debugElement = fixture.debugElement.nativeElement;
component = fixture.componentInstance; component = fixture.componentInstance;
component.workbaskets = [{ workbasketId: '1', component.workbaskets = [
key: 'key1', {
name: 'NAME1', workbasketId: '1',
description: 'description 1', key: 'key1',
owner: 'owner 1', name: 'NAME1',
type: ICONTYPES.PERSONAL }]; description: 'description 1',
owner: 'owner 1',
type: ICONTYPES.PERSONAL
}
];
component.workbaskets[0].markedForDeletion = false; component.workbaskets[0].markedForDeletion = false;
fixture.detectChanges(); fixture.detectChanges();
@ -90,7 +97,9 @@ describe('WorkbasketListToolbarComponent', () => {
let sort: Sorting; let sort: Sorting;
const compareSort = new Sorting(); const compareSort = new Sorting();
component.performSorting.subscribe(value => { sort = value; }); component.performSorting.subscribe((value) => {
sort = value;
});
component.sorting(compareSort); component.sorting(compareSort);
expect(sort).toBe(compareSort); expect(sort).toBe(compareSort);
}); });
@ -99,7 +108,9 @@ describe('WorkbasketListToolbarComponent', () => {
let filter: Filter; let filter: Filter;
const compareFilter = new Filter(); const compareFilter = new Filter();
component.performFilter.subscribe(value => { filter = value; }); component.performFilter.subscribe((value) => {
filter = value;
});
component.filtering(compareFilter); component.filtering(compareFilter);
expect(filter).toBe(compareFilter); expect(filter).toBe(compareFilter);
}); });

View File

@ -29,9 +29,20 @@ export class WorkbasketListToolbarComponent implements OnInit {
@Output() performFilter = new EventEmitter<Filter>(); @Output() performFilter = new EventEmitter<Filter>();
selectionToImport = TaskanaType.WORKBASKETS; selectionToImport = TaskanaType.WORKBASKETS;
sortingFields = new Map([['name', 'Name'], ['key', 'Key'], ['description', 'Description'], ['owner', 'Owner'], ['type', 'Type']]); sortingFields = new Map([
filteringTypes = new Map([['ALL', 'All'], ['PERSONAL', 'Personal'], ['GROUP', 'Group'], ['name', 'Name'],
['CLEARANCE', 'Clearance'], ['TOPIC', 'Topic']]); ['key', 'Key'],
['description', 'Description'],
['owner', 'Owner'],
['type', 'Type']
]);
filteringTypes = new Map([
['ALL', 'All'],
['PERSONAL', 'Personal'],
['GROUP', 'Group'],
['CLEARANCE', 'Clearance'],
['TOPIC', 'Topic']
]);
filterParams = { name: '', key: '', type: '', description: '', owner: '' }; filterParams = { name: '', key: '', type: '', description: '', owner: '' };
toolbarState = false; toolbarState = false;
@ -49,15 +60,12 @@ export class WorkbasketListToolbarComponent implements OnInit {
private router: Router, private router: Router,
private store: Store, private store: Store,
private location: Location private location: Location
) { ) {}
}
ngOnInit() { ngOnInit() {
this.workbasketActiveAction$ this.workbasketActiveAction$.pipe(takeUntil(this.destroy$)).subscribe((action) => {
.pipe(takeUntil(this.destroy$)) this.action = action;
.subscribe(action => { });
this.action = action;
});
} }
sorting(sort: Sorting) { sorting(sort: Sorting) {

View File

@ -1,37 +1,38 @@
.row.list-group { .row.list-group {
margin-left: 2px; margin-left: 2px;
} }
.list-group > li { .list-group > li {
border-left: none; border-left: none;
border-right: none; border-right: none;
} }
a > label{ a > label {
height: 2em; height: 2em;
width: 100%; width: 100%;
} }
dd, dt { dd,
text-overflow: ellipsis; dt {
white-space: nowrap; text-overflow: ellipsis;
overflow: hidden; white-space: nowrap;
overflow: hidden;
} }
dt > i { dt > i {
font-weight: normal; font-weight: normal;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
} }
li > div.row > dl { li > div.row > dl {
margin-bottom: 0px; margin-bottom: 0px;
} }
li > div.row > dl:first-child { li > div.row > dl:first-child {
margin-left: 15px; margin-left: 15px;
} }
.no-space { .no-space {
border-top: none; border-top: none;
padding: 0px padding: 0px;
} }

View File

@ -28,8 +28,7 @@ import { WorkbasketListComponent } from './workbasket-list.component';
selector: 'taskana-dummy-detail', selector: 'taskana-dummy-detail',
template: 'dummydetail' template: 'dummydetail'
}) })
class DummyDetailComponent { class DummyDetailComponent {}
}
@Component({ @Component({
selector: 'taskana-pagination', selector: 'taskana-pagination',
@ -45,7 +44,19 @@ class PaginationComponent {
@Output() changePage = new EventEmitter<any>(); @Output() changePage = new EventEmitter<any>();
} }
function createWorkbasketSummary(workbasketId, key, name, domain, type, description, owner, custom1, custom2, custom3, custom4) { function createWorkbasketSummary(
workbasketId,
key,
name,
domain,
type,
description,
owner,
custom1,
custom2,
custom3,
custom4
) {
const workbasketSummary: WorkbasketSummary = { const workbasketSummary: WorkbasketSummary = {
workbasketId, workbasketId,
key, key,
@ -63,10 +74,8 @@ function createWorkbasketSummary(workbasketId, key, name, domain, type, descript
} }
const workbasketSummaryResource: WorkbasketSummaryRepresentation = { const workbasketSummaryResource: WorkbasketSummaryRepresentation = {
workbaskets: [ workbaskets: [
createWorkbasketSummary('1', 'key1', 'NAME1', '', 'PERSONAL', createWorkbasketSummary('1', 'key1', 'NAME1', '', 'PERSONAL', 'description 1', 'owner1', '', '', '', ''),
'description 1', 'owner1', '', '', '', ''), createWorkbasketSummary('2', 'key2', 'NAME2', '', 'PERSONAL', 'description 2', 'owner2', '', '', '', '')
createWorkbasketSummary('2', 'key2', 'NAME2', '', 'PERSONAL',
'description 2', 'owner2', '', '', '', ''),
], ],
_links: new LinksWorkbasketSummary({ href: 'url' }), _links: new LinksWorkbasketSummary({ href: 'url' }),
page: {} page: {}
@ -84,21 +93,16 @@ describe('WorkbasketListComponent', () => {
{ path: 'workbaskets', component: DummyDetailComponent } { path: 'workbaskets', component: DummyDetailComponent }
]; ];
beforeEach(done => { beforeEach((done) => {
const configure = (testBed: TestBed) => { const configure = (testBed: TestBed) => {
testBed.configureTestingModule({ testBed.configureTestingModule({
declarations: [ declarations: [
WorkbasketListComponent, WorkbasketListComponent,
DummyDetailComponent, DummyDetailComponent,
WorkbasketListToolbarComponent, WorkbasketListToolbarComponent,
ImportExportComponent, ImportExportComponent
],
imports: [
AngularSvgIconModule,
HttpClientModule,
RouterTestingModule.withRoutes(routes),
NgxsModule.forRoot()
], ],
imports: [AngularSvgIconModule, HttpClientModule, RouterTestingModule.withRoutes(routes), NgxsModule.forRoot()],
providers: [ providers: [
WorkbasketService, WorkbasketService,
WorkbasketDefinitionService, WorkbasketDefinitionService,
@ -108,7 +112,7 @@ describe('WorkbasketListComponent', () => {
] ]
}); });
}; };
configureTests(configure).then(testBed => { configureTests(configure).then((testBed) => {
fixture = TestBed.createComponent(WorkbasketListComponent); fixture = TestBed.createComponent(WorkbasketListComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
Object.defineProperty(component, 'workbasketsSummaryRepresentation$', { writable: true }); Object.defineProperty(component, 'workbasketsSummaryRepresentation$', { writable: true });
@ -121,7 +125,9 @@ describe('WorkbasketListComponent', () => {
debugElement = fixture.debugElement.nativeElement; debugElement = fixture.debugElement.nativeElement;
workbasketService = TestBed.get(WorkbasketService); workbasketService = TestBed.get(WorkbasketService);
const orientationService = TestBed.get(OrientationService); const orientationService = TestBed.get(OrientationService);
workbasketSummarySpy = spyOn(workbasketService, 'getWorkBasketsSummary').and.returnValue(of(workbasketSummaryResource)); workbasketSummarySpy = spyOn(workbasketService, 'getWorkBasketsSummary').and.returnValue(
of(workbasketSummaryResource)
);
spyOn(workbasketService, 'getSelectedWorkBasket').and.returnValue(of('2')); spyOn(workbasketService, 'getSelectedWorkBasket').and.returnValue(of('2'));
spyOn(orientationService, 'getOrientation').and.returnValue(of(undefined)); spyOn(orientationService, 'getOrientation').and.returnValue(of(undefined));
@ -139,15 +145,18 @@ describe('WorkbasketListComponent', () => {
expect(component).toBeTruthy(); expect(component).toBeTruthy();
}); });
it('should have wb-action-toolbar, wb-search-bar, wb-list-container, wb-pagination,' it(
+ ' collapsedMenufilterWb and taskana-filter created in the html', () => { 'should have wb-action-toolbar, wb-search-bar, wb-list-container, wb-pagination,' +
expect(debugElement.querySelector('#wb-action-toolbar')).toBeDefined(); ' collapsedMenufilterWb and taskana-filter created in the html',
expect(debugElement.querySelector('#wb-search-bar')).toBeDefined(); () => {
expect(debugElement.querySelector('#wb-pagination')).toBeDefined(); expect(debugElement.querySelector('#wb-action-toolbar')).toBeDefined();
expect(debugElement.querySelector('#wb-list-container')).toBeDefined(); expect(debugElement.querySelector('#wb-search-bar')).toBeDefined();
expect(debugElement.querySelector('#collapsedMenufilterWb')).toBeDefined(); expect(debugElement.querySelector('#wb-pagination')).toBeDefined();
expect(debugElement.querySelector('taskana-filter')).toBeDefined(); expect(debugElement.querySelector('#wb-list-container')).toBeDefined();
}); expect(debugElement.querySelector('#collapsedMenufilterWb')).toBeDefined();
expect(debugElement.querySelector('taskana-filter')).toBeDefined();
}
);
it('should have rendered sort by: name, id, description, owner and type', () => { it('should have rendered sort by: name, id, description, owner and type', () => {
expect(debugElement.querySelector('#sort-by-name')).toBeDefined(); expect(debugElement.querySelector('#sort-by-name')).toBeDefined();

View File

@ -13,8 +13,11 @@ import { TaskanaQueryParameters } from 'app/shared/util/query-parameters';
import { ImportExportService } from 'app/administration/services/import-export.service'; import { ImportExportService } from 'app/administration/services/import-export.service';
import { Actions, ofActionCompleted, ofActionDispatched, Select, Store } from '@ngxs/store'; import { Actions, ofActionCompleted, ofActionDispatched, Select, Store } from '@ngxs/store';
import { takeUntil } from 'rxjs/operators'; import { takeUntil } from 'rxjs/operators';
import { DeselectWorkbasket, GetWorkbasketsSummary, import {
SelectWorkbasket } from '../../../shared/store/workbasket-store/workbasket.actions'; DeselectWorkbasket,
GetWorkbasketsSummary,
SelectWorkbasket
} from '../../../shared/store/workbasket-store/workbasket.actions';
import { WorkbasketSelectors } from '../../../shared/store/workbasket-store/workbasket.selectors'; import { WorkbasketSelectors } from '../../../shared/store/workbasket-store/workbasket.selectors';
import { Workbasket } from '../../../shared/models/workbasket'; import { Workbasket } from '../../../shared/models/workbasket';
@ -53,47 +56,45 @@ export class WorkbasketListComponent implements OnInit, OnDestroy {
private workbasketService: WorkbasketService, private workbasketService: WorkbasketService,
private orientationService: OrientationService, private orientationService: OrientationService,
private importExportService: ImportExportService, private importExportService: ImportExportService,
private ngxsActions$: Actions, private ngxsActions$: Actions
) { ) {
this.ngxsActions$.pipe(ofActionDispatched(GetWorkbasketsSummary), this.ngxsActions$.pipe(ofActionDispatched(GetWorkbasketsSummary), takeUntil(this.destroy$)).subscribe(() => {
takeUntil(this.destroy$)) this.requestInProgress = true;
.subscribe(() => { });
this.requestInProgress = true; this.ngxsActions$.pipe(ofActionCompleted(GetWorkbasketsSummary), takeUntil(this.destroy$)).subscribe(() => {
}); this.requestInProgress = false;
this.ngxsActions$.pipe(ofActionCompleted(GetWorkbasketsSummary), });
takeUntil(this.destroy$))
.subscribe(() => {
this.requestInProgress = false;
});
} }
ngOnInit() { ngOnInit() {
this.requestInProgress = true; this.requestInProgress = true;
this.selectedWorkbasket$.pipe(takeUntil(this.destroy$)) this.selectedWorkbasket$.pipe(takeUntil(this.destroy$)).subscribe((selectedWorkbasket) => {
.subscribe(selectedWorkbasket => { if (typeof selectedWorkbasket !== 'undefined') {
if (typeof selectedWorkbasket !== 'undefined') { this.selectedId = selectedWorkbasket.workbasketId;
this.selectedId = selectedWorkbasket.workbasketId; } else {
} else { this.selectedId = undefined;
this.selectedId = undefined; }
} });
});
TaskanaQueryParameters.page = this.pageSelected; TaskanaQueryParameters.page = this.pageSelected;
TaskanaQueryParameters.pageSize = this.pageSize; TaskanaQueryParameters.pageSize = this.pageSize;
this.workbasketService.workbasketSavedTriggered() this.workbasketService
.workbasketSavedTriggered()
.pipe(takeUntil(this.destroy$)) .pipe(takeUntil(this.destroy$))
.subscribe(value => { .subscribe((value) => {
this.performRequest(); this.performRequest();
}); });
this.orientationService.getOrientation() this.orientationService
.getOrientation()
.pipe(takeUntil(this.destroy$)) .pipe(takeUntil(this.destroy$))
.subscribe((orientation: Orientation) => { .subscribe((orientation: Orientation) => {
this.refreshWorkbasketList(); this.refreshWorkbasketList();
}); });
this.importExportService.getImportingFinished() this.importExportService
.getImportingFinished()
.pipe(takeUntil(this.destroy$)) .pipe(takeUntil(this.destroy$))
.subscribe((value: Boolean) => { .subscribe((value: Boolean) => {
this.refreshWorkbasketList(); this.refreshWorkbasketList();
@ -125,15 +126,31 @@ export class WorkbasketListComponent implements OnInit, OnDestroy {
refreshWorkbasketList() { refreshWorkbasketList() {
this.cards = this.orientationService.calculateNumberItemsList( this.cards = this.orientationService.calculateNumberItemsList(
window.innerHeight, 72, 170 + this.toolbarElement.nativeElement.offsetHeight, false window.innerHeight,
72,
170 + this.toolbarElement.nativeElement.offsetHeight,
false
); );
this.performRequest(); this.performRequest();
} }
private performRequest(): void { private performRequest(): void {
this.store.dispatch(new GetWorkbasketsSummary(true, this.sort.sortBy, this.sort.sortDirection, '', this.store.dispatch(
this.filterBy.filterParams.name, this.filterBy.filterParams.description, '', this.filterBy.filterParams.owner, new GetWorkbasketsSummary(
this.filterBy.filterParams.type, '', this.filterBy.filterParams.key, '')); true,
this.sort.sortBy,
this.sort.sortDirection,
'',
this.filterBy.filterParams.name,
this.filterBy.filterParams.description,
'',
this.filterBy.filterParams.owner,
this.filterBy.filterParams.type,
'',
this.filterBy.filterParams.key,
''
)
);
TaskanaQueryParameters.pageSize = this.cards; TaskanaQueryParameters.pageSize = this.cards;
} }

View File

@ -12,39 +12,26 @@ import { WorkbasketOverviewComponent } from './workbasket-overview.component';
selector: 'taskana-dummy-detail', selector: 'taskana-dummy-detail',
template: 'dummydetail' template: 'dummydetail'
}) })
export class DummyDetailComponent { export class DummyDetailComponent {}
}
@Component({ @Component({
selector: 'taskana-workbasket-list', selector: 'taskana-workbasket-list',
template: 'dummylist' template: 'dummylist'
}) })
export class DummyListComponent { export class DummyListComponent {}
}
describe('WorkbasketOverviewComponent', () => { describe('WorkbasketOverviewComponent', () => {
let debugElement: any; let debugElement: any;
let component: WorkbasketOverviewComponent; let component: WorkbasketOverviewComponent;
let fixture: ComponentFixture<WorkbasketOverviewComponent>; let fixture: ComponentFixture<WorkbasketOverviewComponent>;
const locationSpy: jasmine.SpyObj<Location> = jasmine.createSpyObj('Location', ['go']); const locationSpy: jasmine.SpyObj<Location> = jasmine.createSpyObj('Location', ['go']);
const routes: Routes = [ const routes: Routes = [{ path: ':id', component: DummyDetailComponent }];
{ path: ':id', component: DummyDetailComponent }
];
beforeEach(async(() => { beforeEach(async(() => {
TestBed.configureTestingModule( TestBed.configureTestingModule({
{ imports: [ imports: [RouterTestingModule.withRoutes(routes), NgxsModule.forRoot()],
RouterTestingModule.withRoutes(routes), declarations: [WorkbasketOverviewComponent, DummyDetailComponent, DummyListComponent],
NgxsModule.forRoot() providers: [{ provide: Location, useValue: locationSpy }],
], schemas: [NO_ERRORS_SCHEMA]
declarations: [ }).compileComponents();
WorkbasketOverviewComponent,
DummyDetailComponent,
DummyListComponent],
providers: [
{ provide: Location, useValue: locationSpy },
],
schemas: [NO_ERRORS_SCHEMA] }
)
.compileComponents();
})); }));
afterEach(() => { afterEach(() => {

View File

@ -5,9 +5,11 @@ import { ActivatedRoute } from '@angular/router';
import { takeUntil } from 'rxjs/operators'; import { takeUntil } from 'rxjs/operators';
import { WorkbasketSelectors } from '../../../shared/store/workbasket-store/workbasket.selectors'; import { WorkbasketSelectors } from '../../../shared/store/workbasket-store/workbasket.selectors';
import { CreateWorkbasket, import {
CreateWorkbasket,
SelectWorkbasket, SelectWorkbasket,
SetActiveAction } from '../../../shared/store/workbasket-store/workbasket.actions'; SetActiveAction
} from '../../../shared/store/workbasket-store/workbasket.actions';
@Component({ @Component({
selector: 'app-workbasket-overview', selector: 'app-workbasket-overview',
@ -20,34 +22,25 @@ export class WorkbasketOverviewComponent implements OnInit {
destroy$ = new Subject<void>(); destroy$ = new Subject<void>();
routerParams: any; routerParams: any;
constructor( constructor(private route: ActivatedRoute, private store: Store) {}
private route: ActivatedRoute,
private store: Store
) {
}
ngOnInit() { ngOnInit() {
if (this.route.firstChild) { if (this.route.firstChild) {
this.route.firstChild.params this.route.firstChild.params.pipe(takeUntil(this.destroy$)).subscribe((params) => {
.pipe(takeUntil(this.destroy$)) this.routerParams = params;
.subscribe(params => { if (this.routerParams.id) {
this.routerParams = params; this.showDetail = true;
if (this.routerParams.id) { if (this.routerParams.id === 'new-workbasket') {
this.showDetail = true; this.store.dispatch(new CreateWorkbasket());
if (this.routerParams.id === 'new-workbasket') { } else {
this.store.dispatch(new CreateWorkbasket()); this.store.dispatch(new SelectWorkbasket(this.routerParams.id));
} else {
this.store.dispatch(new SelectWorkbasket(this.routerParams.id));
}
} }
}); }
}
this.selectedWorkbasketAndAction$
.pipe(takeUntil(this.destroy$))
.subscribe(state => {
this.showDetail = !!state.selectedWorkbasket || state.action === 1;
}); });
}
this.selectedWorkbasketAndAction$.pipe(takeUntil(this.destroy$)).subscribe((state) => {
this.showDetail = !!state.selectedWorkbasket || state.action === 1;
});
} }
ngOnDestroy() { ngOnDestroy() {

View File

@ -1,5 +1,5 @@
import { Classification } from 'app/shared/models/classification'; import { Classification } from 'app/shared/models/classification';
export interface TreeNodeModel extends Classification { export interface TreeNodeModel extends Classification {
children: TreeNodeModel[] children: TreeNodeModel[];
} }

View File

@ -8,11 +8,11 @@ import { Classification } from '../../shared/models/classification';
@Injectable() @Injectable()
export class ClassificationDefinitionService { export class ClassificationDefinitionService {
url = `${environment.taskanaRestUrl}/v1/classification-definitions`; url = `${environment.taskanaRestUrl}/v1/classification-definitions`;
constructor(private httpClient: HttpClient) { } constructor(private httpClient: HttpClient) {}
// GET // GET
async exportClassifications(domain: string) { async exportClassifications(domain: string) {
const domainRequest = (domain ? '' : `?domain=${domain}`); const domainRequest = domain ? '' : `?domain=${domain}`;
const classificationDefinitions = await this.httpClient.get<Classification[]>(this.url + domainRequest).toPromise(); const classificationDefinitions = await this.httpClient.get<Classification[]>(this.url + domainRequest).toPromise();
BlobGenerator.saveFile(classificationDefinitions, `Classifications_${TaskanaDate.getDate()}.json`); BlobGenerator.saveFile(classificationDefinitions, `Classifications_${TaskanaDate.getDate()}.json`);
} }

View File

@ -7,25 +7,27 @@ import { Classification } from '../../shared/models/classification';
}) })
export class ClassificationTreeService { export class ClassificationTreeService {
transformToTreeNode(classifications: Classification[]): TreeNodeModel[] { transformToTreeNode(classifications: Classification[]): TreeNodeModel[] {
const classificationsAsTree: TreeNodeModel[] = classifications.map(c => ({ const classificationsAsTree: TreeNodeModel[] = classifications
...c, .map((c) => ({
children: [] ...c,
})).sort((a: TreeNodeModel, b: TreeNodeModel) => a.key.localeCompare(b.key)); children: []
}))
.sort((a: TreeNodeModel, b: TreeNodeModel) => a.key.localeCompare(b.key));
const roots: TreeNodeModel[] = []; const roots: TreeNodeModel[] = [];
const children: TreeNodeModel[] = []; const children: TreeNodeModel[] = [];
classificationsAsTree.forEach(item => { classificationsAsTree.forEach((item) => {
const parent = item.parentId; const parent = item.parentId;
const target = !parent ? roots : (children[parent] || (children[parent] = [])); const target = !parent ? roots : children[parent] || (children[parent] = []);
target.push(item); target.push(item);
}); });
roots.forEach(parent => this.findChildren(parent, children)); roots.forEach((parent) => this.findChildren(parent, children));
return roots; return roots;
} }
private findChildren(parent: TreeNodeModel, children: TreeNodeModel[]) { private findChildren(parent: TreeNodeModel, children: TreeNodeModel[]) {
if (children[parent.classificationId]) { if (children[parent.classificationId]) {
parent.children = children[parent.classificationId]; parent.children = children[parent.classificationId];
parent.children.forEach(child => this.findChildren(child, children)); parent.children.forEach((child) => this.findChildren(child, children));
} }
} }
} }

View File

@ -2,9 +2,7 @@ import { Injectable } from '@angular/core';
import { Subject, Observable } from 'rxjs'; import { Subject, Observable } from 'rxjs';
export class SavingInformation { export class SavingInformation {
constructor(public url: string, constructor(public url: string, public workbasketId: string) {}
public workbasketId: string) {
}
} }
@Injectable() @Injectable()

View File

@ -9,12 +9,14 @@ import { BlobGenerator } from 'app/shared/util/blob-generator';
export class WorkbasketDefinitionService { export class WorkbasketDefinitionService {
url: string = `${environment.taskanaRestUrl}/v1/workbasket-definitions`; url: string = `${environment.taskanaRestUrl}/v1/workbasket-definitions`;
constructor(private httpClient: HttpClient) { } constructor(private httpClient: HttpClient) {}
// GET // GET
async exportWorkbaskets(domain: string) { async exportWorkbaskets(domain: string) {
const domainRequest = (domain === '' ? domain : `?domain=${domain}`); const domainRequest = domain === '' ? domain : `?domain=${domain}`;
const workbasketDefinitions = await this.httpClient.get<WorkbasketDefinition[]>(this.url + domainRequest).toPromise(); const workbasketDefinitions = await this.httpClient
.get<WorkbasketDefinition[]>(this.url + domainRequest)
.toPromise();
BlobGenerator.saveFile(workbasketDefinitions, `Workbaskets_${TaskanaDate.getDate()}.json`); BlobGenerator.saveFile(workbasketDefinitions, `Workbaskets_${TaskanaDate.getDate()}.json`);
} }
} }

View File

@ -14,22 +14,22 @@ const appRoutes: Routes = [
{ {
canActivate: [BusinessAdminGuard], canActivate: [BusinessAdminGuard],
path: 'administration', path: 'administration',
loadChildren: () => import('./administration/administration.module').then(m => m.AdministrationModule), loadChildren: () => import('./administration/administration.module').then((m) => m.AdministrationModule)
}, },
{ {
canActivate: [MonitorGuard], canActivate: [MonitorGuard],
path: 'monitor', path: 'monitor',
loadChildren: () => import('./monitor/monitor.module').then(m => m.MonitorModule), loadChildren: () => import('./monitor/monitor.module').then((m) => m.MonitorModule)
}, },
{ {
canActivate: [UserGuard], canActivate: [UserGuard],
path: 'workplace', path: 'workplace',
loadChildren: () => import('./workplace/workplace.module').then(m => m.WorkplaceModule) loadChildren: () => import('./workplace/workplace.module').then((m) => m.WorkplaceModule)
}, },
{ {
canActivate: [HistoryGuard], canActivate: [HistoryGuard],
path: 'history', path: 'history',
loadChildren: () => import('./history/history.module').then(m => m.HistoryModule) loadChildren: () => import('./history/history.module').then((m) => m.HistoryModule)
}, },
{ {
path: 'no-role', path: 'no-role',
@ -37,13 +37,13 @@ const appRoutes: Routes = [
}, },
{ {
path: 'administration', path: 'administration',
redirectTo: 'administration/workbaskets', redirectTo: 'administration/workbaskets'
}, },
{ {
path: '**', path: '**',
redirectTo: 'workplace' redirectTo: 'workplace'
}, }
], ]
}, },
{ {
path: 'no-role', path: 'no-role',
@ -52,16 +52,10 @@ const appRoutes: Routes = [
{ {
path: '**', path: '**',
redirectTo: 'taskana/workplace' redirectTo: 'taskana/workplace'
}, }
]; ];
@NgModule({ @NgModule({
imports: [ imports: [RouterModule.forRoot(appRoutes, { useHash: true })],
RouterModule.forRoot( exports: [RouterModule]
appRoutes, { useHash: true }
)
],
exports: [
RouterModule
]
}) })
export class AppRoutingModule { } export class AppRoutingModule {}

View File

@ -13,21 +13,12 @@ describe('AppComponent', () => {
let fixture; let fixture;
let debugElement; let debugElement;
const routes: Routes = [ const routes: Routes = [{ path: 'classifications', component: AppComponent }];
{ path: 'classifications', component: AppComponent }
];
beforeEach(async(() => { beforeEach(async(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ declarations: [AppComponent, NavBarComponent],
AppComponent, NavBarComponent imports: [AngularSvgIconModule, RouterTestingModule.withRoutes(routes), HttpClientModule, SharedModule]
],
imports: [
AngularSvgIconModule,
RouterTestingModule.withRoutes(routes),
HttpClientModule,
SharedModule
]
}).compileComponents(); }).compileComponents();
fixture = TestBed.createComponent(AppComponent); fixture = TestBed.createComponent(AppComponent);
@ -39,19 +30,22 @@ describe('AppComponent', () => {
document.body.removeChild(debugElement); document.body.removeChild(debugElement);
})); }));
it('should create the app', (() => { it('should create the app', () => {
expect(app).toBeTruthy(); expect(app).toBeTruthy();
})); });
it('should render title in a <a> tag', (() => { it('should render title in a <a> tag', () => {
fixture.detectChanges(); fixture.detectChanges();
expect(debugElement.querySelector('ul p a').textContent).toContain('Taskana administration'); expect(debugElement.querySelector('ul p a').textContent).toContain('Taskana administration');
})); });
it('should call Router.navigateByUrl("classifications") and workbasketRoute should be false', (inject([Router], (router: Router) => { it('should call Router.navigateByUrl("classifications") and workbasketRoute should be false', inject(
expect(app.workbasketsRoute).toBe(true); [Router],
fixture.detectChanges(); (router: Router) => {
router.navigateByUrl('/classifications'); expect(app.workbasketsRoute).toBe(true);
expect(app.workbasketsRoute).toBe(false); fixture.detectChanges();
}))); router.navigateByUrl('/classifications');
expect(app.workbasketsRoute).toBe(false);
}
));
}); });

View File

@ -38,9 +38,7 @@ export class AppComponent implements OnInit, OnDestroy {
private formsValidatorService: FormsValidatorService, private formsValidatorService: FormsValidatorService,
private errorService: NotificationService, private errorService: NotificationService,
public uploadService: UploadService public uploadService: UploadService
) { ) {}
}
@HostListener('window:resize', ['$event']) @HostListener('window:resize', ['$event'])
onResize() { onResize() {
@ -48,16 +46,18 @@ export class AppComponent implements OnInit, OnDestroy {
} }
ngOnInit() { ngOnInit() {
this.routerSubscription = this.router.events.subscribe(event => { this.routerSubscription = this.router.events.subscribe((event) => {
if (event instanceof NavigationStart) { if (event instanceof NavigationStart) {
this.selectedRouteService.selectRoute(event); this.selectedRouteService.selectRoute(event);
this.formsValidatorService.formSubmitAttempt = false; this.formsValidatorService.formSubmitAttempt = false;
} }
}); });
this.requestInProgressSubscription = this.requestInProgressService.getRequestInProgress().subscribe((value: boolean) => { this.requestInProgressSubscription = this.requestInProgressService
this.requestInProgress = value; .getRequestInProgress()
}); .subscribe((value: boolean) => {
this.requestInProgress = value;
});
this.selectedRouteSubscription = this.selectedRouteService.getSelectedRoute().subscribe((value: string) => { this.selectedRouteSubscription = this.selectedRouteService.getSelectedRoute().subscribe((value: string) => {
if (value.indexOf('classifications') !== -1) { if (value.indexOf('classifications') !== -1) {
@ -65,7 +65,7 @@ export class AppComponent implements OnInit, OnDestroy {
} }
this.selectedRoute = value; this.selectedRoute = value;
}); });
this.uploadingFileSubscription = this.uploadService.getCurrentProgressValue().subscribe(value => { this.uploadingFileSubscription = this.uploadService.getCurrentProgressValue().subscribe((value) => {
this.currentProgressValue = value; this.currentProgressValue = value;
}); });
} }

View File

@ -66,12 +66,7 @@ const MODULES = [
NgxsReduxDevtoolsPluginModule.forRoot({ disabled: environment.production, maxAge: 25 }) NgxsReduxDevtoolsPluginModule.forRoot({ disabled: environment.production, maxAge: 25 })
]; ];
const DECLARATIONS = [ const DECLARATIONS = [AppComponent, NavBarComponent, UserInformationComponent, NoAccessComponent];
AppComponent,
NavBarComponent,
UserInformationComponent,
NoAccessComponent,
];
export function startupServiceFactory(startupService: StartupService): () => Promise<any> { export function startupServiceFactory(startupService: StartupService): () => Promise<any> {
return (): Promise<any> => startupService.load(); return (): Promise<any> => startupService.load();
@ -102,9 +97,8 @@ export function startupServiceFactory(startupService: StartupService): () => Pro
FormsValidatorService, FormsValidatorService,
UploadService, UploadService,
NotificationService, NotificationService,
ClassificationCategoriesService, ClassificationCategoriesService
], ],
bootstrap: [AppComponent] bootstrap: [AppComponent]
}) })
export class AppModule { export class AppModule {}
}

View File

@ -21,18 +21,28 @@ export const configureTests = (configure: (testBed: TestBed) => void) => {
const testBed = getTestBed(); const testBed = getTestBed();
if (testBed.platform == null) { if (testBed.platform == null) {
testBed.initTestEnvironment( testBed.initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting());
BrowserDynamicTestingModule,
platformBrowserDynamicTesting()
);
} }
configure(testBed); configure(testBed);
testBed.configureTestingModule({ testBed.configureTestingModule({
imports: [BrowserAnimationsModule, SharedModule, FormsModule, ReactiveFormsModule, HttpClientModule, AngularSvgIconModule], imports: [
providers: [{ provide: TaskanaEngineService, useClass: TaskanaEngineServiceMock }, BrowserAnimationsModule,
{ provide: DomainService, useClass: DomainServiceMock }, NotificationService, SharedModule,
RequestInProgressService, OrientationService, SelectedRouteService, FormsValidatorService] FormsModule,
ReactiveFormsModule,
HttpClientModule,
AngularSvgIconModule
],
providers: [
{ provide: TaskanaEngineService, useClass: TaskanaEngineServiceMock },
{ provide: DomainService, useClass: DomainServiceMock },
NotificationService,
RequestInProgressService,
OrientationService,
SelectedRouteService,
FormsValidatorService
]
}); });
return testBed.compileComponents().then(() => testBed); return testBed.compileComponents().then(() => testBed);

View File

@ -1,17 +1,13 @@
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { TaskanaTypeAheadMockComponent } from 'app/shared/components/type-ahead/type-ahead.mock.component'; import { TaskanaTypeAheadMockComponent } from 'app/shared/components/type-ahead/type-ahead.mock.component';
const MODULES = [ const MODULES = [];
];
const DECLARATIONS = [ const DECLARATIONS = [TaskanaTypeAheadMockComponent];
TaskanaTypeAheadMockComponent
];
@NgModule({ @NgModule({
declarations: DECLARATIONS, declarations: DECLARATIONS,
imports: MODULES, imports: MODULES,
providers: [] providers: []
}) })
export class AppTestModule { export class AppTestModule {}
}

View File

@ -10,10 +10,11 @@ const routes: Routes = [
{ {
path: '**', path: '**',
redirectTo: '' redirectTo: ''
}]; }
];
@NgModule({ @NgModule({
imports: [RouterModule.forChild(routes)], imports: [RouterModule.forChild(routes)],
exports: [RouterModule] exports: [RouterModule]
}) })
export class HistoryRoutingModule { } export class HistoryRoutingModule {}

View File

@ -7,13 +7,7 @@ import { HistoryRoutingModule } from './history-routing.module';
import { TaskQueryComponent } from './task-query/task-query.component'; import { TaskQueryComponent } from './task-query/task-query.component';
@NgModule({ @NgModule({
imports: [ imports: [CommonModule, HistoryRoutingModule, SharedModule, FormsModule, ReactiveFormsModule],
CommonModule,
HistoryRoutingModule,
SharedModule,
FormsModule,
ReactiveFormsModule
],
declarations: [TaskQueryComponent] declarations: [TaskQueryComponent]
}) })
export class HistoryModule { } export class HistoryModule {}

View File

@ -14,7 +14,7 @@ import { environment } from 'environments/environment';
export class TaskQueryService { export class TaskQueryService {
private url = environment.taskanaRestUrl; private url = environment.taskanaRestUrl;
constructor(private httpClient: HttpClient) { } constructor(private httpClient: HttpClient) {}
queryTask( queryTask(
orderBy: string = 'created', orderBy: string = 'created',
@ -22,31 +22,33 @@ export class TaskQueryService {
searchForValues: TaskHistoryEventData, searchForValues: TaskHistoryEventData,
allPages: boolean = false allPages: boolean = false
): Observable<TaskHistoryEventResourceData> { ): Observable<TaskHistoryEventResourceData> {
return this.httpClient.get<TaskHistoryEventResourceData>(`${this.url}/v1/task-history-event${this.getQueryParameters( return this.httpClient.get<TaskHistoryEventResourceData>(
orderBy, `${this.url}/v1/task-history-event${this.getQueryParameters(
sortDirection, orderBy,
searchForValues.taskId, sortDirection,
searchForValues.parentBusinessProcessId, searchForValues.taskId,
searchForValues.businessProcessId, searchForValues.parentBusinessProcessId,
searchForValues.eventType, searchForValues.businessProcessId,
searchForValues.userId, searchForValues.eventType,
searchForValues.domain, searchForValues.userId,
searchForValues.workbasketKey, searchForValues.domain,
searchForValues.porCompany, searchForValues.workbasketKey,
searchForValues.porSystem, searchForValues.porCompany,
searchForValues.porInstance, searchForValues.porSystem,
searchForValues.porType, searchForValues.porInstance,
searchForValues.porValue, searchForValues.porType,
searchForValues.taskClassificationKey, searchForValues.porValue,
searchForValues.taskClassificationCategory, searchForValues.taskClassificationKey,
searchForValues.attachmentClassificationKey, searchForValues.taskClassificationCategory,
searchForValues.custom1, searchForValues.attachmentClassificationKey,
searchForValues.custom2, searchForValues.custom1,
searchForValues.custom3, searchForValues.custom2,
searchForValues.custom4, searchForValues.custom3,
searchForValues.created, searchForValues.custom4,
allPages searchForValues.created,
)}`); allPages
)}`
);
} }
private getQueryParameters( private getQueryParameters(
@ -98,7 +100,10 @@ export class TaskQueryService {
parameters.CUSTOM_4_LIKE = custom4; parameters.CUSTOM_4_LIKE = custom4;
parameters.CREATED = created; parameters.CREATED = created;
if (allPages) { delete TaskanaQueryParameters.page; delete TaskanaQueryParameters.pageSize; } if (allPages) {
delete TaskanaQueryParameters.page;
delete TaskanaQueryParameters.pageSize;
}
return TaskanaQueryParameters.getQueryParameters(parameters); return TaskanaQueryParameters.getQueryParameters(parameters);
} }

View File

@ -1,41 +1,41 @@
@import '../../../theme/colors'; @import '../../../theme/colors';
.table { .table {
max-height: calc(100vh - 152px); max-height: calc(100vh - 152px);
padding-right: 15px; padding-right: 15px;
} }
.table-header { .table-header {
background-color: $light-grey; background-color: $light-grey;
cursor: pointer; cursor: pointer;
} }
.table-footer { .table-footer {
display: block; display: block;
} }
.table-cell { .table-cell {
height: 35px; height: 35px;
max-height: 35px; max-height: 35px;
min-height: 35px; min-height: 35px;
} }
.divDate { .divDate {
padding-right: 20px; padding-right: 20px;
} }
.btn-xs{ .btn-xs {
padding: 0px; padding: 0px;
} }
.table .btn { .table .btn {
border: none; border: none;
} }
.icon-space { .icon-space {
margin-right: 20px; margin-right: 20px;
} }
.divTablePagination { .divTablePagination {
margin: 0 auto; margin: 0 auto;
} }

View File

@ -9,8 +9,7 @@ describe('TaskQueryComponent', () => {
beforeEach(async(() => { beforeEach(async(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [TaskQueryComponent] declarations: [TaskQueryComponent]
}) }).compileComponents();
.compileComponents();
})); }));
beforeEach(() => { beforeEach(() => {

View File

@ -31,8 +31,7 @@ export class TaskQueryComponent implements OnInit {
private orientationService: OrientationService, private orientationService: OrientationService,
private requestInProgressService: RequestInProgressService, private requestInProgressService: RequestInProgressService,
private errorsService: NotificationService private errorsService: NotificationService
) { ) {}
}
ngOnInit() { ngOnInit() {
this.orientationSubscription = this.orientationService.getOrientation().subscribe((orientation: Orientation) => { this.orientationSubscription = this.orientationService.getOrientation().subscribe((orientation: Orientation) => {
@ -99,12 +98,18 @@ export class TaskQueryComponent implements OnInit {
} }
isDate(fieldName: string): boolean { isDate(fieldName: string): boolean {
return (fieldName === 'created'); return fieldName === 'created';
} }
filterFieldsToAllowQuerying(fieldName: string): boolean { filterFieldsToAllowQuerying(fieldName: string): boolean {
if (!fieldName || fieldName === 'oldData' || fieldName === 'newData' || fieldName === 'comment' if (
|| fieldName === 'oldValue' || fieldName === 'newValue') { !fieldName ||
fieldName === 'oldData' ||
fieldName === 'newData' ||
fieldName === 'comment' ||
fieldName === 'oldValue' ||
fieldName === 'newValue'
) {
return false; return false;
} }
@ -119,9 +124,17 @@ export class TaskQueryComponent implements OnInit {
} }
filterExpandGroup(fieldName: string): boolean { filterExpandGroup(fieldName: string): boolean {
if (fieldName === 'custom1' || fieldName === 'custom2' || fieldName === 'custom3' || fieldName === 'custom4' if (
|| fieldName === 'oldData' || fieldName === 'newData' || fieldName === 'comment' fieldName === 'custom1' ||
|| fieldName === 'oldValue' || fieldName === 'newValue') { fieldName === 'custom2' ||
fieldName === 'custom3' ||
fieldName === 'custom4' ||
fieldName === 'oldData' ||
fieldName === 'newData' ||
fieldName === 'comment' ||
fieldName === 'oldValue' ||
fieldName === 'newValue'
) {
return true; return true;
} }
return false; return false;
@ -179,21 +192,23 @@ export class TaskQueryComponent implements OnInit {
private performRequest() { private performRequest() {
this.requestInProgressService.setRequestInProgress(true); this.requestInProgressService.setRequestInProgress(true);
this.calculateQueryPages(); this.calculateQueryPages();
this.taskQuerySubscription = this.taskQueryService.queryTask( this.taskQuerySubscription = this.taskQueryService
this.orderBy.sortBy.replace(/([A-Z])|([0-9])/g, g => `-${g[0].toLowerCase()}`), .queryTask(
this.orderBy.sortDirection, this.orderBy.sortBy.replace(/([A-Z])|([0-9])/g, (g) => `-${g[0].toLowerCase()}`),
new TaskHistoryEventData(this.taskQueryForm.value), this.orderBy.sortDirection,
false new TaskHistoryEventData(this.taskQueryForm.value),
).subscribe(taskQueryResource => { false
this.requestInProgressService.setRequestInProgress(false); )
this.taskQueryResource = taskQueryResource.taskHistoryEvents ? taskQueryResource : null; .subscribe((taskQueryResource) => {
this.taskQuery = taskQueryResource.taskHistoryEvents ? taskQueryResource.taskHistoryEvents : null; this.requestInProgressService.setRequestInProgress(false);
}); this.taskQueryResource = taskQueryResource.taskHistoryEvents ? taskQueryResource : null;
this.taskQuery = taskQueryResource.taskHistoryEvents ? taskQueryResource.taskHistoryEvents : null;
});
} }
private initTaskQueryForm() { private initTaskQueryForm() {
const me = this; const me = this;
Object.keys(new TaskHistoryEventData()).forEach(key => { Object.keys(new TaskHistoryEventData()).forEach((key) => {
me.taskQueryForm.addControl(key, new FormControl()); me.taskQueryForm.addControl(key, new FormControl());
}); });
} }
@ -202,7 +217,7 @@ export class TaskQueryComponent implements OnInit {
const rowHeight = 34; const rowHeight = 34;
const unusedHeight = 300; const unusedHeight = 300;
const totalHeight = window.innerHeight; const totalHeight = window.innerHeight;
const cards = Math.round((totalHeight - (unusedHeight)) / rowHeight); const cards = Math.round((totalHeight - unusedHeight) / rowHeight);
TaskanaQueryParameters.page = TaskanaQueryParameters.page ? TaskanaQueryParameters.page : 1; TaskanaQueryParameters.page = TaskanaQueryParameters.page ? TaskanaQueryParameters.page : 1;
TaskanaQueryParameters.pageSize = cards > 0 ? cards : 1; TaskanaQueryParameters.pageSize = cards > 0 ? cards : 1;
} }

View File

@ -9,8 +9,7 @@ describe('ClassificationReportComponent', () => {
beforeEach(async(() => { beforeEach(async(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ClassificationReportComponent] declarations: [ClassificationReportComponent]
}) }).compileComponents();
.compileComponents();
})); }));
beforeEach(() => { beforeEach(() => {

View File

@ -26,8 +26,7 @@ export class ClassificationReportComponent implements OnInit {
constructor( constructor(
private restConnectorService: RestConnectorService, private restConnectorService: RestConnectorService,
private requestInProgressService: RequestInProgressService private requestInProgressService: RequestInProgressService
) { ) {}
}
async ngOnInit() { async ngOnInit() {
this.requestInProgressService.setRequestInProgress(true); this.requestInProgressService.setRequestInProgress(true);

View File

@ -8,11 +8,9 @@ import { Component, OnDestroy, OnInit } from '@angular/core';
export class MonitorComponent implements OnInit, OnDestroy { export class MonitorComponent implements OnInit, OnDestroy {
tabSelected = 'tasks'; tabSelected = 'tasks';
ngOnInit(): void { ngOnInit(): void {}
}
ngOnDestroy(): void { ngOnDestroy(): void {}
}
selectTab(tab) { selectTab(tab) {
this.tabSelected = tab; this.tabSelected = tab;

View File

@ -1,20 +1,20 @@
.report { .report {
margin-top: 20px; margin-top: 20px;
} }
.table-cell--clickable { .table-cell--clickable {
cursor: pointer; cursor: pointer;
} }
.table-row--highlight, .table-row--highlight,
.table-row--hover:hover { .table-row--hover:hover {
background-color: #f9f9f9; background-color: #f9f9f9;
} }
.table-row--highlight > .table-cell { .table-row--highlight > .table-cell {
border-bottom: 2px solid #ddd; border-bottom: 2px solid #ddd;
} }
.table-row--white { .table-row--white {
background-color: white !important; background-color: white !important;
} }

View File

@ -12,24 +12,25 @@ export class ReportTableComponent implements OnInit {
@Input() @Input()
reportData: ReportData; reportData: ReportData;
ngOnInit(): void { ngOnInit(): void {}
}
toggleFold(indexNumber: number, sumRow: boolean = false) { toggleFold(indexNumber: number, sumRow: boolean = false) {
let rows = sumRow ? this.reportData.sumRow : this.reportData.rows; let rows = sumRow ? this.reportData.sumRow : this.reportData.rows;
let index = indexNumber; let index = indexNumber;
const toggleRow = rows[index += 1]; const toggleRow = rows[(index += 1)];
if (toggleRow.depth < this.reportData.meta.rowDesc.length - 1) { if (toggleRow.depth < this.reportData.meta.rowDesc.length - 1) {
const firstChildRow = rows[index += 1]; const firstChildRow = rows[(index += 1)];
firstChildRow.display = !firstChildRow.display; firstChildRow.display = !firstChildRow.display;
const endIndex = rows.findIndex(row => row.depth <= toggleRow.depth); const endIndex = rows.findIndex((row) => row.depth <= toggleRow.depth);
rows = endIndex >= 0 ? rows.slice(0, endIndex) : rows; rows = endIndex >= 0 ? rows.slice(0, endIndex) : rows;
rows.forEach(row => { row.display = firstChildRow.display && row.depth === firstChildRow.depth; }); rows.forEach((row) => {
row.display = firstChildRow.display && row.depth === firstChildRow.depth;
});
this.currentExpHeaders = Math.max( this.currentExpHeaders = Math.max(
...this.reportData.rows.filter(r => r.display).map(r => r.depth), ...this.reportData.rows.filter((r) => r.display).map((r) => r.depth),
...this.reportData.sumRow.filter(r => r.display).map(r => r.depth) ...this.reportData.sumRow.filter((r) => r.display).map((r) => r.depth)
); );
} }
} }

View File

@ -9,8 +9,7 @@ describe('TaskReportComponent', () => {
beforeEach(async(() => { beforeEach(async(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [TaskReportComponent] declarations: [TaskReportComponent]
}) }).compileComponents();
.compileComponents();
})); }));
beforeEach(() => { beforeEach(() => {

View File

@ -6,7 +6,7 @@ import { RequestInProgressService } from '../../../shared/services/request-in-pr
@Component({ @Component({
selector: 'taskana-monitor-task-report', selector: 'taskana-monitor-task-report',
templateUrl: './task-report.component.html', templateUrl: './task-report.component.html',
styleUrls: ['./task-report.component.scss'], styleUrls: ['./task-report.component.scss']
}) })
export class TaskReportComponent implements OnInit { export class TaskReportComponent implements OnInit {
pieChartLabels: string[]; pieChartLabels: string[];
@ -17,14 +17,13 @@ export class TaskReportComponent implements OnInit {
constructor( constructor(
private restConnectorService: RestConnectorService, private restConnectorService: RestConnectorService,
private requestInProgressService: RequestInProgressService private requestInProgressService: RequestInProgressService
) { ) {}
}
async ngOnInit() { async ngOnInit() {
this.requestInProgressService.setRequestInProgress(true); this.requestInProgressService.setRequestInProgress(true);
this.reportData = await this.restConnectorService.getTaskStatusReport().toPromise(); this.reportData = await this.restConnectorService.getTaskStatusReport().toPromise();
this.pieChartLabels = this.reportData.meta.header; this.pieChartLabels = this.reportData.meta.header;
this.reportData.sumRow[0].cells.forEach(c => { this.reportData.sumRow[0].cells.forEach((c) => {
this.pieChartData.push(c); this.pieChartData.push(c);
}); });
this.requestInProgressService.setRequestInProgress(false); this.requestInProgressService.setRequestInProgress(false);

View File

@ -10,8 +10,7 @@ import { RestConnectorService } from '../../services/rest-connector.service';
export class TimestampReportComponent implements OnInit { export class TimestampReportComponent implements OnInit {
reportData: ReportData; reportData: ReportData;
constructor(private restConnectorService: RestConnectorService) { constructor(private restConnectorService: RestConnectorService) {}
}
ngOnInit() { ngOnInit() {
this.restConnectorService.getDailyEntryExitReport().subscribe((data: ReportData) => { this.restConnectorService.getDailyEntryExitReport().subscribe((data: ReportData) => {

View File

@ -9,8 +9,7 @@ describe('WorkbasketReportDueDateComponent', () => {
beforeEach(async(() => { beforeEach(async(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [WorkbasketReportDueDateComponent] declarations: [WorkbasketReportDueDateComponent]
}) }).compileComponents();
.compileComponents();
})); }));
beforeEach(() => { beforeEach(() => {

View File

@ -30,8 +30,7 @@ export class WorkbasketReportDueDateComponent implements OnInit {
constructor( constructor(
private restConnectorService: RestConnectorService, private restConnectorService: RestConnectorService,
private requestInProgressService: RequestInProgressService private requestInProgressService: RequestInProgressService
) { ) {}
}
async ngOnInit() { async ngOnInit() {
this.requestInProgressService.setRequestInProgress(true); this.requestInProgressService.setRequestInProgress(true);

View File

@ -9,8 +9,7 @@ describe('WorkbasketReportPlannedDateComponent', () => {
beforeEach(async(() => { beforeEach(async(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [WorkbasketReportPlannedDateComponent] declarations: [WorkbasketReportPlannedDateComponent]
}) }).compileComponents();
.compileComponents();
})); }));
beforeEach(() => { beforeEach(() => {

View File

@ -23,7 +23,7 @@ export class WorkbasketReportPlannedDateComponent implements OnInit {
lineChartData: Array<ChartData>; lineChartData: Array<ChartData>;
lineChartOptions: any = { lineChartOptions: any = {
responsive: true, responsive: true,
scales: { xAxes: [{}], yAxes: [{}] }, scales: { xAxes: [{}], yAxes: [{}] }
}; };
lineChartColors = ChartColorsDefinition.getColors(); lineChartColors = ChartColorsDefinition.getColors();
@ -31,8 +31,7 @@ export class WorkbasketReportPlannedDateComponent implements OnInit {
constructor( constructor(
private restConnectorService: RestConnectorService, private restConnectorService: RestConnectorService,
private requestInProgressService: RequestInProgressService private requestInProgressService: RequestInProgressService
) { ) {}
}
async ngOnInit() { async ngOnInit() {
this.requestInProgressService.setRequestInProgress(true); this.requestInProgressService.setRequestInProgress(true);

View File

@ -9,8 +9,7 @@ describe('WorkbasketReportQuerySwitcherComponent', () => {
beforeEach(async(() => { beforeEach(async(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [WorkbasketReportQuerySwitcherComponent] declarations: [WorkbasketReportQuerySwitcherComponent]
}) }).compileComponents();
.compileComponents();
})); }));
beforeEach(() => { beforeEach(() => {

View File

@ -9,8 +9,7 @@ describe('WorkbasketReportComponent', () => {
beforeEach(async(() => { beforeEach(async(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [WorkbasketReportComponent] declarations: [WorkbasketReportComponent]
}) }).compileComponents();
.compileComponents();
})); }));
beforeEach(() => { beforeEach(() => {

View File

@ -12,8 +12,7 @@ export class WorkbasketReportComponent implements OnInit {
showMonitorQueryPlannedDate: Boolean; showMonitorQueryPlannedDate: Boolean;
showMonitorQueryDueDate: Boolean; showMonitorQueryDueDate: Boolean;
ngOnInit() { ngOnInit() {}
}
getMetaInformation(metaInformation: MetaInfoData) { getMetaInformation(metaInformation: MetaInfoData) {
this.metaInformation = metaInformation; this.metaInformation = metaInformation;

View File

@ -1,7 +1,8 @@
export class ChartColorsDefinition { export class ChartColorsDefinition {
public static getColors(): Array<any> { public static getColors(): Array<any> {
return [ return [
{ // red {
// red
backgroundColor: 'rgba(215, 40, 40, 0.2)', backgroundColor: 'rgba(215, 40, 40, 0.2)',
borderColor: 'rgba(215, 40, 40, 1)', borderColor: 'rgba(215, 40, 40, 1)',
pointBackgroundColor: 'rgba(215, 40, 40, 1)', pointBackgroundColor: 'rgba(215, 40, 40, 1)',
@ -9,7 +10,8 @@ export class ChartColorsDefinition {
pointHoverBackgroundColor: '#fff', pointHoverBackgroundColor: '#fff',
pointHoverBorderColor: 'rgba(215, 40, 40, 0.8)' pointHoverBorderColor: 'rgba(215, 40, 40, 0.8)'
}, },
{ // yellow {
// yellow
backgroundColor: 'rgba(208, 205, 44, 0.2)', backgroundColor: 'rgba(208, 205, 44, 0.2)',
borderColor: 'rgba(208, 205, 44, 1)', borderColor: 'rgba(208, 205, 44, 1)',
pointBackgroundColor: 'rgba(208, 205, 44, 1)', pointBackgroundColor: 'rgba(208, 205, 44, 1)',
@ -17,7 +19,8 @@ export class ChartColorsDefinition {
pointHoverBackgroundColor: '#fff', pointHoverBackgroundColor: '#fff',
pointHoverBorderColor: 'rgba(208, 205, 44, 0.8)' pointHoverBorderColor: 'rgba(208, 205, 44, 0.8)'
}, },
{ // green {
// green
backgroundColor: 'rgba(45, 205, 44, 0.2)', backgroundColor: 'rgba(45, 205, 44, 0.2)',
borderColor: 'rgba(45, 205, 44, 1)', borderColor: 'rgba(45, 205, 44, 1)',
pointBackgroundColor: 'rgba(45, 205, 44, 1)', pointBackgroundColor: 'rgba(45, 205, 44, 1)',
@ -25,7 +28,8 @@ export class ChartColorsDefinition {
pointHoverBackgroundColor: '#fff', pointHoverBackgroundColor: '#fff',
pointHoverBorderColor: 'rgba(45, 205, 44, 0.8)' pointHoverBorderColor: 'rgba(45, 205, 44, 0.8)'
}, },
{ // blue {
// blue
backgroundColor: 'rgba(45, 45, 201, 0.2)', backgroundColor: 'rgba(45, 45, 201, 0.2)',
borderColor: 'rgba(45, 45, 201, 1)', borderColor: 'rgba(45, 45, 201, 1)',
pointBackgroundColor: 'rgba(45, 45, 201, 1)', pointBackgroundColor: 'rgba(45, 45, 201, 1)',
@ -33,7 +37,8 @@ export class ChartColorsDefinition {
pointHoverBackgroundColor: '#fff', pointHoverBackgroundColor: '#fff',
pointHoverBorderColor: 'rgba(45, 45, 201, 0.8)' pointHoverBorderColor: 'rgba(45, 45, 201, 0.8)'
}, },
{ // cyan {
// cyan
backgroundColor: 'rgba(45, 190, 201, 0.2)', backgroundColor: 'rgba(45, 190, 201, 0.2)',
borderColor: 'rgba(45, 190, 201, 1)', borderColor: 'rgba(45, 190, 201, 1)',
pointBackgroundColor: 'rgba(45, 190, 201, 1)', pointBackgroundColor: 'rgba(45, 190, 201, 1)',
@ -41,7 +46,8 @@ export class ChartColorsDefinition {
pointHoverBackgroundColor: '#fff', pointHoverBackgroundColor: '#fff',
pointHoverBorderColor: 'rgba(45, 190, 201, 0.8)' pointHoverBorderColor: 'rgba(45, 190, 201, 0.8)'
}, },
{ // black-grey {
// black-grey
backgroundColor: 'rgba(37, 35, 38, 0.2)', backgroundColor: 'rgba(37, 35, 38, 0.2)',
borderColor: 'rgba(37, 35, 38, 1)', borderColor: 'rgba(37, 35, 38, 1)',
pointBackgroundColor: 'rgba(37, 35, 38, 1)', pointBackgroundColor: 'rgba(37, 35, 38, 1)',
@ -49,7 +55,8 @@ export class ChartColorsDefinition {
pointHoverBackgroundColor: '#fff', pointHoverBackgroundColor: '#fff',
pointHoverBorderColor: 'rgba(37, 35, 38, 0.8)' pointHoverBorderColor: 'rgba(37, 35, 38, 0.8)'
}, },
{ // orange {
// orange
backgroundColor: 'rgba(221, 125, 0, 0.2)', backgroundColor: 'rgba(221, 125, 0, 0.2)',
borderColor: 'rgba(221, 125, 0, 1)', borderColor: 'rgba(221, 125, 0, 1)',
pointBackgroundColor: 'rgba(221, 125, 0, 1)', pointBackgroundColor: 'rgba(221, 125, 0, 1)',
@ -57,7 +64,8 @@ export class ChartColorsDefinition {
pointHoverBackgroundColor: '#fff', pointHoverBackgroundColor: '#fff',
pointHoverBorderColor: 'rgba(221, 125, 0, 0.8)' pointHoverBorderColor: 'rgba(221, 125, 0, 0.8)'
}, },
{ // lile {
// lile
backgroundColor: 'rgba(180, 137, 255, 0.2)', backgroundColor: 'rgba(180, 137, 255, 0.2)',
borderColor: 'rgba(180, 137, 255, 1)', borderColor: 'rgba(180, 137, 255, 1)',
pointBackgroundColor: 'rgba(180, 137, 255, 1)', pointBackgroundColor: 'rgba(180, 137, 255, 1)',

View File

@ -43,7 +43,7 @@ const DECLARATIONS = [
WorkbasketReportDueDateComponent, WorkbasketReportDueDateComponent,
WorkbasketReportQuerySwitcherComponent, WorkbasketReportQuerySwitcherComponent,
TaskReportComponent, TaskReportComponent,
ClassificationReportComponent, ClassificationReportComponent
]; ];
@NgModule({ @NgModule({
@ -51,5 +51,4 @@ const DECLARATIONS = [
imports: MODULES, imports: MODULES,
providers: [RestConnectorService, MapToIterable] providers: [RestConnectorService, MapToIterable]
}) })
export class MonitorModule { export class MonitorModule {}
}

View File

@ -9,36 +9,36 @@ const monitorUrl = '/v1/monitor/';
@Injectable() @Injectable()
export class RestConnectorService { export class RestConnectorService {
constructor(private httpClient: HttpClient) { constructor(private httpClient: HttpClient) {}
}
getTaskStatusReport(): Observable<ReportData> { getTaskStatusReport(): Observable<ReportData> {
return this.httpClient.get<ReportData>(`${environment.taskanaRestUrl + monitorUrl return this.httpClient.get<ReportData>(
}tasks-status-report?states=READY,CLAIMED,COMPLETED`); `${environment.taskanaRestUrl + monitorUrl}tasks-status-report?states=READY,CLAIMED,COMPLETED`
);
} }
getWorkbasketStatisticsQueryingByDueDate(): Observable<ReportData> { getWorkbasketStatisticsQueryingByDueDate(): Observable<ReportData> {
return this.httpClient.get<ReportData>(`${environment.taskanaRestUrl return this.httpClient.get<ReportData>(
+ monitorUrl}tasks-workbasket-report?states=READY,CLAIMED,COMPLETED`); `${environment.taskanaRestUrl + monitorUrl}tasks-workbasket-report?states=READY,CLAIMED,COMPLETED`
);
} }
getWorkbasketStatisticsQueryingByPlannedDate(): Observable<ReportData> { getWorkbasketStatisticsQueryingByPlannedDate(): Observable<ReportData> {
return this.httpClient.get<ReportData>(`${environment.taskanaRestUrl return this.httpClient.get<ReportData>(
}/v1/monitor/tasks-workbasket-planned-date-report?daysInPast=7&states=READY,CLAIMED,COMPLETED`); `${environment.taskanaRestUrl}/v1/monitor/tasks-workbasket-planned-date-report?daysInPast=7&states=READY,CLAIMED,COMPLETED`
);
} }
getClassificationTasksReport(): Observable<ReportData> { getClassificationTasksReport(): Observable<ReportData> {
return this.httpClient.get<ReportData>(`${environment.taskanaRestUrl return this.httpClient.get<ReportData>(`${environment.taskanaRestUrl + monitorUrl}tasks-classification-report`);
+ monitorUrl}tasks-classification-report`);
} }
getDailyEntryExitReport(): Observable<ReportData> { getDailyEntryExitReport(): Observable<ReportData> {
return this.httpClient.get<ReportData>(`${environment.taskanaRestUrl return this.httpClient.get<ReportData>(`${environment.taskanaRestUrl + monitorUrl}timestamp-report`);
+ monitorUrl}timestamp-report`);
} }
getChartData(source: ReportData): Array<ChartData> { getChartData(source: ReportData): Array<ChartData> {
return source.rows.map(row => { return source.rows.map((row) => {
const rowData = new ChartData(); const rowData = new ChartData();
[rowData.label] = row.desc; [rowData.label] = row.desc;
rowData.data = row.cells; rowData.data = row.cells;

View File

@ -1,6 +1,12 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { BsDatepickerModule, BsDatepickerConfig, ComponentLoaderFactory, PositioningService, BsLocaleService } from 'ngx-bootstrap'; import {
BsDatepickerModule,
BsDatepickerConfig,
ComponentLoaderFactory,
PositioningService,
BsLocaleService
} from 'ngx-bootstrap';
import { DatePickerComponent } from './date-picker.component'; import { DatePickerComponent } from './date-picker.component';
describe('DatePickerComponent', () => { describe('DatePickerComponent', () => {
@ -11,10 +17,8 @@ describe('DatePickerComponent', () => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [BsDatepickerModule], imports: [BsDatepickerModule],
declarations: [DatePickerComponent], declarations: [DatePickerComponent],
providers: [BsDatepickerConfig, ComponentLoaderFactory, PositioningService, providers: [BsDatepickerConfig, ComponentLoaderFactory, PositioningService, BsLocaleService]
BsLocaleService] }).compileComponents();
})
.compileComponents();
})); }));
beforeEach(() => { beforeEach(() => {

View File

@ -9,8 +9,7 @@ describe('DropdownComponent', () => {
beforeEach(async(() => { beforeEach(async(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [DropdownComponent] declarations: [DropdownComponent]
}) }).compileComponents();
.compileComponents();
})); }));
beforeEach(() => { beforeEach(() => {

View File

@ -10,8 +10,7 @@ export class DropdownComponent implements OnInit {
@Input() list: any[]; @Input() list: any[];
@Output() performClassification = new EventEmitter<any>(); @Output() performClassification = new EventEmitter<any>();
ngOnInit(): void { ngOnInit(): void {}
}
selectItem(item: any) { selectItem(item: any) {
this.itemSelected = item; this.itemSelected = item;

View File

@ -9,8 +9,7 @@ describe('FieldErrorDisplayComponent', () => {
beforeEach(async(() => { beforeEach(async(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [FieldErrorDisplayComponent] declarations: [FieldErrorDisplayComponent]
}) }).compileComponents();
.compileComponents();
})); }));
beforeEach(() => { beforeEach(() => {

View File

@ -17,6 +17,5 @@ export class FieldErrorDisplayComponent implements OnInit {
@Input() @Input()
validationTrigger: boolean; validationTrigger: boolean;
ngOnInit() { ngOnInit() {}
}
} }

View File

@ -1,19 +1,19 @@
.dropdown-menu-users { .dropdown-menu-users {
&>li{ & > li {
margin-bottom: 5px; margin-bottom: 5px;
} }
margin-left: 15px; margin-left: 15px;
} }
.list-group-search { .list-group-search {
padding: 0px 15px; padding: 0px 15px;
border-top: 1px solid #ddd; border-top: 1px solid #ddd;
} }
.list-group-search { .list-group-search {
border-top: none; border-top: none;
} }
row.padding { row.padding {
padding: 1px 0px; padding: 1px 0px;
} }
.filter-list { .filter-list {

View File

@ -13,14 +13,14 @@ describe('FilterComponent', () => {
let fixture: ComponentFixture<FilterComponent>; let fixture: ComponentFixture<FilterComponent>;
let debugElement: any; let debugElement: any;
beforeEach(done => { beforeEach((done) => {
const configure = (testBed: TestBed) => { const configure = (testBed: TestBed) => {
testBed.configureTestingModule({ testBed.configureTestingModule({
providers: [MatSnackBar, Overlay], providers: [MatSnackBar, Overlay],
imports: [AngularSvgIconModule, FormsModule, HttpClientModule] imports: [AngularSvgIconModule, FormsModule, HttpClientModule]
}); });
}; };
configureTests(configure).then(testBed => { configureTests(configure).then((testBed) => {
fixture = TestBed.createComponent(FilterComponent); fixture = TestBed.createComponent(FilterComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
component.filterParams = { component.filterParams = {

View File

@ -9,11 +9,20 @@ import { TaskanaType } from 'app/shared/models/taskana-type';
styleUrls: ['./filter.component.scss'] styleUrls: ['./filter.component.scss']
}) })
export class FilterComponent implements OnInit { export class FilterComponent implements OnInit {
@Input() allTypes: Map<string, string> = new Map([['ALL', 'All'], ['PERSONAL', 'Personal'], ['GROUP', 'Group'], @Input() allTypes: Map<string, string> = new Map([
['CLEARANCE', 'Clearance'], ['TOPIC', 'Topic']]); ['ALL', 'All'],
['PERSONAL', 'Personal'],
['GROUP', 'Group'],
['CLEARANCE', 'Clearance'],
['TOPIC', 'Topic']
]);
@Input() allStates: Map<string, string> = new Map([['ALL', 'All'], ['READY', 'Ready'], ['CLAIMED', 'Claimed'], @Input() allStates: Map<string, string> = new Map([
['COMPLETED', 'Completed']]); ['ALL', 'All'],
['READY', 'Ready'],
['CLAIMED', 'Claimed'],
['COMPLETED', 'Completed']
]);
@Input() filterParams = { name: '', key: '', type: '', description: '', owner: '' }; @Input() filterParams = { name: '', key: '', type: '', description: '', owner: '' };
@ -35,15 +44,17 @@ export class FilterComponent implements OnInit {
} }
selectType(type: ICONTYPES) { selectType(type: ICONTYPES) {
this.filter.filterParams.type = (type === ICONTYPES.ALL) ? '' : type; this.filter.filterParams.type = type === ICONTYPES.ALL ? '' : type;
} }
selectState(state: ICONTYPES) { selectState(state: ICONTYPES) {
this.filter.filterParams.state = (state === 'ALL') ? '' : state; this.filter.filterParams.state = state === 'ALL' ? '' : state;
} }
clear() { clear() {
Object.keys(this.filterParams).forEach(key => { this.filterParams[key] = ''; }); Object.keys(this.filterParams).forEach((key) => {
this.filterParams[key] = '';
});
this.initializeFilterModel(); this.initializeFilterModel();
} }
@ -68,6 +79,6 @@ export class FilterComponent implements OnInit {
* @returns {string[]} * @returns {string[]}
*/ */
getUnusedKeys(): string[] { getUnusedKeys(): string[] {
return Object.keys(this.filterParamKeys).filter(key => ['name', 'key', 'type'].indexOf(key) < 0); return Object.keys(this.filterParamKeys).filter((key) => ['name', 'key', 'type'].indexOf(key) < 0);
} }
} }

View File

@ -1,4 +1,3 @@
.center-block.no-detail { .center-block.no-detail {
text-align: center; text-align: center;
} }

View File

@ -12,17 +12,13 @@ import { MasterAndDetailComponent } from './master-and-detail.component';
selector: 'taskana-dummy-master', selector: 'taskana-dummy-master',
template: 'dummymaster' template: 'dummymaster'
}) })
export class DummyMasterComponent { export class DummyMasterComponent {}
}
@Component({ @Component({
selector: 'taskana-dummy-detail', selector: 'taskana-dummy-detail',
template: 'dummydetail' template: 'dummydetail'
}) })
export class DummyDetailComponent { export class DummyDetailComponent {}
}
describe('MasterAndDetailComponent ', () => { describe('MasterAndDetailComponent ', () => {
let component; let component;
@ -51,18 +47,10 @@ describe('MasterAndDetailComponent ', () => {
beforeEach(async(() => { beforeEach(async(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ declarations: [MasterAndDetailComponent, DummyMasterComponent, DummyDetailComponent],
MasterAndDetailComponent, imports: [RouterTestingModule.withRoutes(routes), AngularSvgIconModule, HttpClientModule],
DummyMasterComponent,
DummyDetailComponent],
imports: [
RouterTestingModule.withRoutes(routes),
AngularSvgIconModule,
HttpClientModule
],
providers: [MasterAndDetailService] providers: [MasterAndDetailService]
}) }).compileComponents();
.compileComponents();
fixture = TestBed.createComponent(MasterAndDetailComponent); fixture = TestBed.createComponent(MasterAndDetailComponent);
component = fixture.debugElement.componentInstance; component = fixture.debugElement.componentInstance;

View File

@ -5,8 +5,7 @@ import { MasterAndDetailService } from 'app/shared/services/master-and-detail/ma
@Component({ @Component({
selector: 'taskana-shared-master-and-detail', selector: 'taskana-shared-master-and-detail',
templateUrl: './master-and-detail.component.html', templateUrl: './master-and-detail.component.html',
styleUrls: ['./master-and-detail.component.scss'], styleUrls: ['./master-and-detail.component.scss']
}) })
export class MasterAndDetailComponent implements OnInit { export class MasterAndDetailComponent implements OnInit {
private classifications = 'classifications'; private classifications = 'classifications';
@ -16,13 +15,16 @@ export class MasterAndDetailComponent implements OnInit {
showDetail = false; showDetail = false;
currentRoute = ''; currentRoute = '';
constructor(private route: ActivatedRoute, private router: Router, private masterAndDetailService: MasterAndDetailService) { constructor(
} private route: ActivatedRoute,
private router: Router,
private masterAndDetailService: MasterAndDetailService
) {}
ngOnInit(): void { ngOnInit(): void {
this.showDetail = this.showDetails(); this.showDetail = this.showDetails();
this.masterAndDetailService.setShowDetail(this.showDetail); this.masterAndDetailService.setShowDetail(this.showDetail);
this.router.events.subscribe(event => { this.router.events.subscribe((event) => {
if (event instanceof NavigationStart) { if (event instanceof NavigationStart) {
this.showDetail = this.showDetails(event); this.showDetail = this.showDetails(event);
this.masterAndDetailService.setShowDetail(this.showDetail); this.masterAndDetailService.setShowDetail(this.showDetail);
@ -43,7 +45,7 @@ export class MasterAndDetailComponent implements OnInit {
private checkUrl(url: string): boolean { private checkUrl(url: string): boolean {
this.checkRoute(url); this.checkRoute(url);
return this.detailRoutes.some(routeDetail => url.indexOf(routeDetail) !== -1); return this.detailRoutes.some((routeDetail) => url.indexOf(routeDetail) !== -1);
} }
private checkRoute(url: string) { private checkRoute(url: string) {

View File

@ -1,144 +1,144 @@
@import '../../../../theme/variables'; @import '../../../../theme/variables';
.navbar.main:before { .navbar.main:before {
@include degraded-bar(right, 100%, 3px) @include degraded-bar(right, 100%, 3px);
} }
.navbar-inverse { .navbar-inverse {
border:none; border: none;
background-color: $dark-green; background-color: $dark-green;
box-shadow: 0px 1px 5px -1px black; box-shadow: 0px 1px 5px -1px black;
} }
.navbar-toggle{ .navbar-toggle {
margin: 3px 0px; margin: 3px 0px;
font-size: 20px;
&.logout {
font-size: 20px; font-size: 20px;
&.logout{ }
font-size: 20px;
}
} }
button.navbar-toggle:hover > span{ button.navbar-toggle:hover > span {
color:$aquamarine; color: $aquamarine;
} }
ul.nav > p { ul.nav > p {
white-space: nowrap; white-space: nowrap;
text-overflow: ellipsis; text-overflow: ellipsis;
padding-right: 0px; padding-right: 0px;
} }
.navbar-inverse .navbar-toggle, .navbar-toggle:hover, .navbar-inverse .navbar-toggle:focus { .navbar-inverse .navbar-toggle,
border: none; .navbar-toggle:hover,
background-color: transparent; .navbar-inverse .navbar-toggle:focus {
border: none;
background-color: transparent;
} }
svg-icon.logo { svg-icon.logo {
float: left; float: left;
width: 150px; width: 150px;
height: 50px; height: 50px;
padding: 5px; padding: 5px;
position: initial; position: initial;
} }
h2.navbar-brand{ h2.navbar-brand {
vertical-align: middle; vertical-align: middle;
text-decoration: none; text-decoration: none;
color: white; color: white;
padding: 15px 0px 0px 0px; padding: 15px 0px 0px 0px;
font-size: 20px; font-size: 20px;
} }
.domain-form { .domain-form {
margin: 13px; margin: 13px;
color: white; color: white;
font-size: 18px; font-size: 18px;
> div{ > div {
cursor: pointer; cursor: pointer;
> button { > button {
color: white; color: white;
background-color: $dark-green; background-color: $dark-green;
border: none; border: none;
font-size: 16px; font-size: 16px;
border-bottom: 1px solid $dark-green; border-bottom: 1px solid $dark-green;
margin-left:5px; margin-left: 5px;
}
} }
}
} }
.nav-content{ .nav-content {
margin-top: 5px; margin-top: 5px;
} }
.nav-version { .nav-version {
color: $grey; color: $grey;
position: absolute; position: absolute;
bottom: 5px; bottom: 5px;
font-size: 12px; font-size: 12px;
} }
/* /*
* All side bar links styling. * All side bar links styling.
*/ */
.nav-sidebar > li > a { .nav-sidebar > li > a {
padding-right: 20px; padding-right: 20px;
padding-left: 20px; padding-left: 20px;
} }
.menu > span:hover, .menu > span:hover,
.submenu > span:hover .submenu > span:hover {
{ color: white;
color: white; cursor: pointer;
cursor: pointer;
} }
.sidenav { .sidenav {
position:fixed; position: fixed;
z-index:999; z-index: 999;
box-shadow: none; box-shadow: none;
height: 100%; height: 100%;
background-color: $dark-green; background-color: $dark-green;
box-shadow: 3px 0px 10px -1px $dark-green; box-shadow: 3px 0px 10px -1px $dark-green;
} }
.navbar { .navbar {
height: 52px; height: 52px;
margin-bottom: 0px; margin-bottom: 0px;
} }
.menu,.submenu > span { .menu,
margin-top: 15px; .submenu > span {
font-size: 20px; margin-top: 15px;
width: 100%; font-size: 20px;
font-family: inherit; width: 100%;
font-weight: 500; font-family: inherit;
line-height: 1.1; font-weight: 500;
line-height: 1.1;
} }
.menu,.submenu > span { .menu,
padding-left: 12px; .submenu > span {
color: $grey; padding-left: 12px;
outline: none; color: $grey;
outline: none;
} }
.menu.selected,.submenu.selected { .menu.selected,
background-color: transparent; .submenu.selected {
&> span{ background-color: transparent;
padding-left: 10px; & > span {
border-left: $pallete-green 5px solid; padding-left: 10px;
color: white; border-left: $pallete-green 5px solid;
} color: white;
}
} }
.menu > .submenu{ .menu > .submenu {
margin-left: 30px; margin-left: 30px;
} }
a { a {
color: $grey; color: $grey;
&:hover{ &:hover {
color:white; color: white;
} }
text-decoration: none text-decoration: none;
} }

View File

@ -24,20 +24,13 @@ describe('NavBarComponent', () => {
let debugElement; let debugElement;
let navBar; let navBar;
const routes: Routes = [ const routes: Routes = [{ path: 'classifications', component: NavBarComponent }];
{ path: 'classifications', component: NavBarComponent }
];
beforeEach(done => { beforeEach((done) => {
const configure = (testBed: TestBed) => { const configure = (testBed: TestBed) => {
testBed.configureTestingModule({ testBed.configureTestingModule({
declarations: [NavBarComponent, UserInformationComponent], declarations: [NavBarComponent, UserInformationComponent],
imports: [ imports: [AngularSvgIconModule, HttpClientModule, RouterTestingModule.withRoutes(routes), SharedModule],
AngularSvgIconModule,
HttpClientModule,
RouterTestingModule.withRoutes(routes),
SharedModule
],
providers: [ providers: [
SelectedRouteService, SelectedRouteService,
BusinessAdminGuard, BusinessAdminGuard,
@ -45,10 +38,11 @@ describe('NavBarComponent', () => {
WindowRefService, WindowRefService,
RequestInProgressService, RequestInProgressService,
MatSnackBar, MatSnackBar,
Overlay] Overlay
]
}); });
}; };
configureTests(configure).then(testBed => { configureTests(configure).then((testBed) => {
fixture = TestBed.createComponent(NavBarComponent); fixture = TestBed.createComponent(NavBarComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
debugElement = fixture.debugElement.nativeElement; debugElement = fixture.debugElement.nativeElement;
@ -67,7 +61,7 @@ describe('NavBarComponent', () => {
expect(component).toBeTruthy(); expect(component).toBeTruthy();
}); });
it('should have as title \'\'', (() => { it("should have as title ''", () => {
expect(navBar.title).toEqual(''); expect(navBar.title).toEqual('');
})); });
}); });

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