TSK-1469: Update to Angular 11

* TSK-1469: Upgrade to Angular 11

Updated Angular core and cli to 10

Fixed compiler problems with ngxs

update of angular to 11

updated angular material to 11

still some build problems

fixed some errors (hopefully all)

TSK-1469: fixed tests

TSK-1469: incorporated change requests before rebase

* TSK-1469: Rebase fixing

prettier


TSK-1469: Fixed tests failures after rebase

* TSK-1469: small scss fix, but some css broken

* TSK-1469: Style Fixing continues

* TSK-1469: Fixed most styling

* TSK-1469: Fixed e2e tests

* TSK-1469: PR Review css changes


TSK-1469: Review css changes

* TSK-1469: More CSS refinement

Also removed added providedIn and refactored small bits

* TSK-1469: Renamed browserlist to browerslist

as it should be

Co-authored-by: Name <Email>
This commit is contained in:
Tristan2357 2021-06-15 11:22:05 +02:00 committed by GitHub
parent 334d21ba7d
commit 9d0b4999d8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
77 changed files with 11431 additions and 20893 deletions

View File

@ -20,7 +20,7 @@ env:
ARTIFACTS_TASKANA_WEB_NAME: taskana-web
ARTIFACTS_TASKANA_WEB_PATH: web/dist
ARTIFACTS_JACOCO_REPORTS_NAME: jacoco-reports
ARTIFACTS_JACOCO_REPORTS_PATH: '**/jacoco.exec'
ARTIFACTS_JACOCO_REPORTS_PATH: "**/jacoco.exec"
CACHE_WEB_NAME: web
# IMPORTANT: this cannot start with CACHE_MAVEN_NAME's value
@ -103,7 +103,7 @@ jobs:
- name: Install Dependencies
if: steps.web-cache.outputs.cache-hit != 'true'
working-directory: web
run: npm ci
run: yarn ci
# currently this is not working because the angular-tree-component needs core-js ^2.4.1 and we have 3.X.X
#- name: Verify Dependencies
#working-directory: web
@ -111,8 +111,8 @@ jobs:
- name: Compile & build
working-directory: web
run: |
npm run lint
npm run build:prod
yarn lint
yarn build:prod
- name: Build maven artifact
run: ./mvnw -B install -pl :taskana-web -am
- name: Upload taskana-web artifact
@ -159,7 +159,7 @@ jobs:
test_frontend:
runs-on: ubuntu-20.04
name: Test taskana-web
needs: [ compile_frontend, compile_backend ]
needs: [compile_frontend, compile_backend]
steps:
- name: Git checkout
uses: actions/checkout@v2.3.4
@ -184,7 +184,7 @@ jobs:
- name: Install Dependencies
if: steps.web-cache.outputs.cache-hit != 'true'
working-directory: web
run: npm ci
run: yarn ci
- name: Cache maven dependencies
uses: actions/cache@v2.1.6
with:
@ -223,7 +223,7 @@ jobs:
test_backend:
runs-on: ubuntu-20.04
name: Test ${{ matrix.module }} on ${{ matrix.database }}
needs: [ compile_taskana-rest-spring-example-wildfly ]
needs: [compile_taskana-rest-spring-example-wildfly]
strategy:
matrix:
module:
@ -293,7 +293,7 @@ jobs:
test_taskana-rest-spring-example-wildfly:
runs-on: ubuntu-20.04
name: Test taskana-rest-spring-example-wildfly on POSTGRES_10
needs: [ compile_taskana-rest-spring-example-wildfly ]
needs: [compile_taskana-rest-spring-example-wildfly]
steps:
- name: Git checkout
uses: actions/checkout@v2.3.4
@ -321,12 +321,12 @@ jobs:
if: failure()
uses: andymckay/cancel-action@0.2
release_artifacts:
runs-on: ubuntu-20.04
name: Release artifacts to OSS Sonatype
if: github.repository == 'Taskana/taskana' && ( startsWith(github.ref, 'refs/tags') || github.ref == 'refs/heads/master' ) && github.head_ref == ''
needs: [ test_frontend, test_backend, test_taskana-rest-spring-example-wildfly ]
needs:
[test_frontend, test_backend, test_taskana-rest-spring-example-wildfly]
# as documented in the gpg manual (https://www.gnupg.org/documentation/manuals/gnupg/Invoking-GPG_002dAGENT.html)
# we should execute this command before interacting with gpg (otherwise gpg won't work)
env:
@ -395,7 +395,8 @@ jobs:
runs-on: ubuntu-20.04
name: Deploy demo app to IBM Cloud Foundry
if: github.repository == 'Taskana/taskana' && github.ref == 'refs/heads/master' && github.head_ref == ''
needs: [ test_frontend, test_backend, test_taskana-rest-spring-example-wildfly ]
needs:
[test_frontend, test_backend, test_taskana-rest-spring-example-wildfly]
steps:
- name: Git checkout
uses: actions/checkout@v2.3.4
@ -450,12 +451,13 @@ jobs:
name: Upload SonarQube analysis to sonarcloud
# no pull request and not on release
if: github.head_ref == '' && !startsWith(github.ref, 'refs/tags')
needs: [ test_frontend, test_backend, test_taskana-rest-spring-example-wildfly ]
needs:
[test_frontend, test_backend, test_taskana-rest-spring-example-wildfly]
steps:
- name: Git checkout
uses: actions/checkout@v2.3.4
with:
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
- name: Set up JDK ${{ env.JAVA_VERSION }}
uses: actions/setup-java@v2
with:

View File

@ -10,3 +10,4 @@ coverage/**
**/dist/**
out-tsc/**
**/*.html
target/**

View File

@ -20,21 +20,13 @@
"main": "src/main.ts",
"tsConfig": "src/tsconfig.app.json",
"polyfills": "src/polyfills.ts",
"assets": [
"src/assets",
"src/environments/data-sources"
],
"assets": ["src/assets", "src/environments/data-sources"],
"styles": [
"./node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
"./node_modules/bootstrap/dist/css/bootstrap.min.css",
"src/theme/_main.scss",
"src/theme/custom-theme-material.scss"
],
"scripts": [
"node_modules/jquery/dist/jquery.min.js",
"node_modules/popper.js/dist/umd/popper.min.js",
"node_modules/bootstrap/dist/js/bootstrap.min.js"
]
"scripts": []
},
"configurations": {
"production": {
@ -47,7 +39,6 @@
"optimization": true,
"outputHashing": "all",
"sourceMap": true,
"extractCss": true,
"namedChunks": true,
"aot": true,
"extractLicenses": true,
@ -83,10 +74,7 @@
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"src/tsconfig.app.json",
"src/tsconfig.spec.json"
],
"tsConfig": ["src/tsconfig.app.json", "src/tsconfig.spec.json"],
"exclude": []
}
}

View File

@ -1,4 +1,4 @@
{
{
"retries": 2,
"env": {
"loginUrl": "http://localhost:8080/taskana",

View File

@ -1,4 +1,4 @@
{
{
"retries": 2,
"env": {
"appUrl": "http://localhost:4200/#/taskana",

View File

@ -6,8 +6,8 @@ context('TASKANA Classifications', () => {
cy.visitTestClassification();
cy.get('#classification-service-level').clear().type(editedValue);
cy.get('button').contains('Save').click();
cy.get('#classification-service-level').clear({ force: true }).type(editedValue);
cy.get('button').contains('Save').click({ force: true });
cy.get('#classification-service-level').should('have.value', editedValue);
});
@ -17,7 +17,7 @@ context('TASKANA Classifications', () => {
cy.verifyPageLoad('/classifications');
cy.get('button[mattooltip="Filter Category"]')
.click()
.click({ force: true })
.then(() => {
cy.get('.mat-menu-content').contains('MANUAL').click();
cy.get('tree-node-collection').find('tree-node').should('have.length', 8);
@ -29,7 +29,7 @@ context('TASKANA Classifications', () => {
cy.visitTestClassification();
cy.get('#classification-name').clear().type(editedValue);
cy.get('#classification-name').scrollIntoView().clear().type(editedValue);
cy.get('button').contains('Save').click();
cy.get('#classification-name').should('have.value', editedValue);
@ -38,24 +38,20 @@ context('TASKANA Classifications', () => {
it('should be possible to edit the category of a classification', () => {
cy.visitTestClassification();
cy.get('ng-form').find('mat-form-field').find('mat-select[role="listbox"]').click();
cy.get('ng-form').find('mat-form-field mat-select[required]').click({ force: true });
cy.wait(Cypress.env('dropdownWait'));
cy.get('mat-option').contains('PROCESS').click();
cy.get('button').contains('Save').click();
cy.get('mat-option').contains('PROCESS').click({ force: true });
cy.get('button').contains('Save').click({ force: true });
// assure that its process now
cy.get('ng-form')
.find('mat-form-field')
.find('mat-select[role="listbox"]')
.contains('PROCESS')
.should('be.visible');
cy.get('ng-form').find('mat-form-field mat-select[required]').contains('PROCESS').should('be.visible');
// change back to external
cy.get('ng-form').find('mat-form-field').find('mat-select[role="listbox"]').click();
cy.get('ng-form').find('mat-form-field mat-select[required]').click({ force: true });
cy.wait(Cypress.env('dropdownWait'));
cy.get('mat-option').contains('EXTERNAL').should('be.visible').click();
cy.get('mat-option').contains('EXTERNAL').should('be.visible').click({ force: true });
cy.get('button').contains('Save').click();
cy.get('button').contains('Save').click({ force: true });
});
it('should be possible to edit the description of a classification', () => {
@ -63,8 +59,8 @@ context('TASKANA Classifications', () => {
cy.visitTestClassification();
cy.get('#classification-description').clear().type(editedValue);
cy.get('button').contains('Save').click();
cy.get('#classification-description').clear({ force: true }).type(editedValue);
cy.get('button').contains('Save').click({ force: true });
cy.get('#classification-description').should('have.value', editedValue);
});
@ -72,9 +68,9 @@ context('TASKANA Classifications', () => {
it('should be possible to edit the custom classification', () => {
cy.visitTestClassification();
cy.get('#classification-custom-1').clear().type(Cypress.env('testValueClassifications'));
cy.get('#classification-custom-1').clear({ force: true }).type(Cypress.env('testValueClassifications'));
cy.get('button').contains('Save').click();
cy.get('button').contains('Save').click({ force: true });
cy.get('#classification-custom-1').should('have.value', Cypress.env('testValueClassifications'));
});
@ -82,8 +78,10 @@ context('TASKANA Classifications', () => {
it('should be possible to edit the application entry point', () => {
cy.visitTestClassification();
cy.get('#classification-application-entry-point').clear().type(Cypress.env('testValueClassifications'));
cy.get('button').contains('Save').click();
cy.get('#classification-application-entry-point')
.clear({ force: true })
.type(Cypress.env('testValueClassifications'));
cy.get('button').contains('Save').click({ force: true });
cy.get('#classification-application-entry-point').should('have.value', Cypress.env('testValueClassifications'));
});

View File

@ -10,7 +10,5 @@ context('TASKANA History', () => {
} else {
cy.log('History plugin not enabled - No need for testing history functionality');
}
});
});

View File

@ -1,7 +1,5 @@
context('TASKANA Login', () => {
it('should login depending on current configuration', () => {
cy.loginAs('admin');
});
it('should login depending on current configuration', () => {
cy.loginAs('admin');
});
});

View File

@ -9,7 +9,6 @@ context('TASKANA Monitor', () => {
cy.get('canvas.chartjs-render-monitor').should('be.visible');
});
it('should visit taskana workbaskets monitor page', () => {
cy.visit(Cypress.env('appUrl') + '/monitor');
cy.verifyPageLoad('/monitor');
@ -19,7 +18,6 @@ context('TASKANA Monitor', () => {
cy.get('canvas.chartjs-render-monitor').should('be.visible');
});
it('should visit taskana classifications monitor page', () => {
cy.visit(Cypress.env('appUrl') + '/monitor');
cy.verifyPageLoad('/monitor');
@ -29,7 +27,6 @@ context('TASKANA Monitor', () => {
cy.get('canvas.chartjs-render-monitor').should('be.visible');
});
it('should visit taskana timestamp monitor page', () => {
cy.visit(Cypress.env('appUrl') + '/monitor');
cy.verifyPageLoad('/monitor');
@ -38,5 +35,4 @@ context('TASKANA Monitor', () => {
cy.get('nav').find('.mat-tab-label-active').should('contain', 'Timestamp');
cy.contains('TimestampReport').should('be.visible');
});
});

View File

@ -6,7 +6,6 @@ context('TASKANA Workbaskets', () => {
cy.verifyPageLoad('/workbaskets');
});
it('should be able to filter workbaskets by name', () => {
cy.visit(Cypress.env('appUrl') + Cypress.env('adminUrl') + '/workbaskets');
cy.verifyPageLoad('/workbaskets');
@ -19,31 +18,24 @@ context('TASKANA Workbaskets', () => {
});
});
it('should be possible to edit workbasket custom information', () => {
cy.visitTestWorkbasket();
cy.get('#wb-custom-1')
.clear()
.type(Cypress.env('testValueWorkbaskets'));
cy.get('#wb-custom-1').clear().type(Cypress.env('testValueWorkbaskets'));
cy.saveWorkbaskets();
cy.get('#wb-custom-1').should('have.value', Cypress.env('testValueWorkbaskets'));
});
it('should be possible to edit workbasket information orgLevel', () => {
cy.visitTestWorkbasket();
cy.get('input[name="workbasket.orgLevel1"]')
.clear()
.type(Cypress.env('testValueWorkbaskets'));
cy.get('input[name="workbasket.orgLevel1"]').clear().type(Cypress.env('testValueWorkbaskets'));
cy.saveWorkbaskets();
cy.get('input[name="workbasket.orgLevel1"]').should('have.value', Cypress.env('testValueWorkbaskets'));
});
it('should be possible to edit workbasket description', () => {
cy.visitTestWorkbasket();
@ -56,7 +48,6 @@ context('TASKANA Workbaskets', () => {
});
});
it('should be possible to edit the type of a workbasket', () => {
cy.visitTestWorkbasket();
@ -76,7 +67,6 @@ context('TASKANA Workbaskets', () => {
cy.saveWorkbaskets();
});
it('should be possible to add new access', () => {
cy.visitTestWorkbasket();
cy.visitWorkbasketsAccessPage();
@ -84,8 +74,7 @@ context('TASKANA Workbaskets', () => {
cy.get('button[mattooltip="Add new access"')
.click()
.then(() => {
cy.get('mat-form-field').contains('mat-form-field', "Access id").find('input')
.type('teamlead-2');
cy.get('mat-form-field').contains('mat-form-field', 'Access id').find('input').type('teamlead-2');
cy.get('input[aria-label="checkAll"]:first').click();
cy.saveWorkbaskets();
});
@ -94,26 +83,30 @@ context('TASKANA Workbaskets', () => {
cy.get('table#table-access-items > tbody > tr').should('have.length', 2);
});
it('should be possible to add a distribution target', () => {
cy.visitTestWorkbasket();
cy.visitWorkbasketsDistributionTargetsPage();
cy.get('taskana-administration-workbasket-distribution-targets-list[header="Available distribution targets"]').find('mat-list-option:first')
.find('mat-pseudo-checkbox').click()
cy.get('button').contains('Add selected distribution targets').click()
cy.get('taskana-administration-workbasket-distribution-targets-list[header="Available distribution targets"]')
.find('mat-list-option:first')
.find('mat-pseudo-checkbox')
.click();
cy.get('button').contains('Add selected distribution targets').click();
cy.saveWorkbaskets();
cy.visitWorkbasketsDistributionTargetsPage();
cy.get('taskana-administration-workbasket-distribution-targets-list[header="Selected distribution targets"]').find('mat-selection-list').should('not.be.empty');
cy.get('taskana-administration-workbasket-distribution-targets-list[header="Selected distribution targets"]')
.find('mat-selection-list')
.should('not.be.empty');
// undo changes
cy.get('taskana-administration-workbasket-distribution-targets-list[header="Selected distribution targets"]').find('mat-list-option:first')
.find('mat-pseudo-checkbox').click()
cy.get('button').contains('Remove selected distribution target').click()
cy.get('taskana-administration-workbasket-distribution-targets-list[header="Selected distribution targets"]')
.find('mat-list-option:first')
.find('mat-pseudo-checkbox')
.click();
cy.get('button').contains('Remove selected distribution target').click();
cy.saveWorkbaskets();
});
});

View File

@ -15,7 +15,7 @@ Cypress.Commands.add('saveWorkbaskets', () => {
});
Cypress.Commands.add('verifyPageLoad', (path) => {
cy.location('hash', {timeout: 10000}).should('include', path);
cy.location('hash', { timeout: 10000 }).should('include', path);
});
Cypress.Commands.add('visitTestWorkbasket', () => {
@ -25,8 +25,7 @@ Cypress.Commands.add('visitTestWorkbasket', () => {
// since the list is loaded dynamically, we need to explicitly wait 400ms for the results
// in order to avoid errors regarding detached DOM elements although it is a bad practice
cy.wait(400);
cy.get('mat-selection-list').contains(Cypress.env('testValueWorkbasketSelectionName'))
.should('exist').click();
cy.get('mat-selection-list').contains(Cypress.env('testValueWorkbasketSelectionName')).should('exist').click();
cy.visitWorkbasketsInformationPage();
});
@ -34,22 +33,24 @@ Cypress.Commands.add('visitTestClassification', () => {
cy.visit(Cypress.env('appUrl') + Cypress.env('adminUrl') + '/classifications');
cy.verifyPageLoad('/classifications');
cy.get('taskana-administration-tree').contains(Cypress.env('testValueClassificationSelectionName'))
.should('exist').click();
cy.get('taskana-administration-tree')
.contains(Cypress.env('testValueClassificationSelectionName'))
.should('exist')
.click();
});
Cypress.Commands.add('loginAs', (username) => {
if (Cypress.env('isLocal')) {
cy.log('Local development - No need for testing login functionality');
cy.log('Local development - No need for testing login functionality');
} else {
cy.visit(Cypress.env('loginUrl') + '/login');
// not calling verifyPageLoad as we cannot verify via hash in this case
cy.location('pathname', {timeout: 10000}).should('include', '/login');
cy.visit(Cypress.env('loginUrl') + '/login');
// not calling verifyPageLoad as we cannot verify via hash in this case
cy.location('pathname', { timeout: 10000 }).should('include', '/login');
cy.get('#username').type('admin').should('have.value', 'admin');
cy.get('#password').type('admin').should('have.value', 'admin');
cy.get('#login-submit').click();
cy.get('#username').type('admin').should('have.value', 'admin');
cy.get('#password').type('admin').should('have.value', 'admin');
cy.get('#login-submit').click();
cy.verifyPageLoad('/workplace/tasks');
}
cy.verifyPageLoad('/workplace/tasks');
}
});

20308
web/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
{
"name": "taskana",
"version": "1.0.0",
"license": "Novatec gmbh",
"license": "Novatec GmbH",
"scripts": {
"ng": "ng",
"start": "ng serve",
@ -16,60 +16,61 @@
"format:html": "prettier --write \"**/*.{html,}\"",
"e2e-dev": "cypress install && cypress run",
"e2e-dev:open": "cypress install && cypress open",
"e2e-standalone": "cypress install && cypress run --config-file cypress-standalone.json"
"e2e-standalone": "cypress install && cypress run --config-file cypress-standalone.json",
"ci": "yarn install --frozen-lockfile"
},
"private": true,
"resolutions": {
"webpack": "5.21.2"
},
"dependencies": {
"@angular/animations": "9.1.12",
"@angular/cdk": "9.2.4",
"@angular/common": "9.1.12",
"@angular/core": "9.1.12",
"@angular/forms": "9.1.12",
"@angular/material": "9.2.4",
"@angular/platform-browser": "9.1.12",
"@angular/platform-browser-dynamic": "9.1.12",
"@angular/router": "9.1.12",
"@ngxs/devtools-plugin": "3.7.1",
"@angular/animations": "11.1.0",
"@angular/cdk": "11.1.0",
"@angular/common": "11.1.0",
"@angular/core": "11.1.0",
"@angular/forms": "11.1.0",
"@angular/material": "11.1.0",
"@angular/platform-browser": "11.1.0",
"@angular/platform-browser-dynamic": "11.1.0",
"@angular/router": "11.1.0",
"@circlon/angular-tree-component": "10.0.2",
"@ngxs/store": "3.7.1",
"angular-svg-icon": "9.2.0",
"angular-tree-component": "8.5.6",
"bootstrap": "4.6.0",
"angular-svg-icon": "11.0.0",
"chart.js": "2.9.4",
"core-js": "3.8.3",
"file-saver": "1.3.3",
"jquery": "3.5.1",
"file-saver": "2.0.5",
"ng2-charts": "2.4.2",
"ngx-bootstrap": "5.4.0",
"ngx-infinite-scroll": "9.0.0",
"popper.js": "1.16.1",
"ngx-bootstrap": "6.2.0",
"ngx-infinite-scroll": "10.0.1",
"rxjs": "6.6.3",
"tslib": "1.14.1",
"zone.js": "0.10.3"
"tslib": "2.1.0",
"zone.js": "0.11.3"
},
"devDependencies": {
"@angular-builders/custom-webpack": "9.2.0",
"@angular-devkit/build-angular": "0.901.13",
"@angular/cli": "9.1.12",
"@angular/compiler": "9.1.12",
"@angular/compiler-cli": "9.1.12",
"@angular-builders/custom-webpack": "11.0.0",
"@angular-devkit/build-angular": "0.1101.1",
"@angular/cli": "11.1.1",
"@angular/compiler": "11.1.0",
"@angular/compiler-cli": "11.1.0",
"@ngxs/devtools-plugin": "3.7.1",
"@types/jest": "26.0.20",
"@types/node": "14.14.22",
"@typescript-eslint/eslint-plugin": "2.34.0",
"@typescript-eslint/eslint-plugin": "4.14.0",
"@typescript-eslint/eslint-plugin-tslint": "4.14.0",
"@typescript-eslint/parser": "2.34.0",
"compression-webpack-plugin": "4.0.0",
"cypress": "6.5.0",
"@typescript-eslint/parser": "4.14.0",
"compression-webpack-plugin": "7.1.2",
"cypress": "6.3.0",
"cypress-intellij-reporter": "0.0.6",
"eslint": "6.8.0",
"eslint-config-prettier": "6.15.0",
"eslint": "7.18.0",
"eslint-config-prettier": "7.2.0",
"eslint-plugin-import": "2.22.1",
"eslint-plugin-prettier": "3.3.1",
"jest": "26.6.3",
"jest-preset-angular": "8.3.2",
"node-sass": "4.14.1",
"prettier": "2.2.1",
"sass": "1.32.5",
"ts-jest": "26.4.4",
"tslint": "6.1.3",
"typescript": "3.8.3"
"typescript": "4.1.3"
}
}

View File

@ -2,7 +2,8 @@ import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { AngularSvgIconModule } from 'angular-svg-icon';
import { AlertModule, TypeaheadModule } from 'ngx-bootstrap';
import { AlertModule } from 'ngx-bootstrap/alert';
import { TypeaheadModule } from 'ngx-bootstrap/typeahead';
import { SharedModule } from 'app/shared/shared.module';
import { InfiniteScrollModule } from 'ngx-infinite-scroll';
@ -114,7 +115,6 @@ const DECLARATIONS = [
WorkbasketDefinitionService,
ClassificationCategoriesService,
ImportExportService
],
entryComponents: []
]
})
export class AdministrationModule {}

View File

@ -7,7 +7,7 @@ table {
margin-bottom: 10px;
}
::ng-deep .mat-header-cell{
::ng-deep .mat-header-cell {
color: black;
font-weight: bold;
}

View File

@ -15,7 +15,7 @@ import { GetAccessItems } from '../../../shared/store/access-items-management-st
import { MatSnackBarModule } from '@angular/material/snack-bar';
import { MatDialogModule, MatDialogRef } from '@angular/material/dialog';
import { TypeAheadComponent } from '../../../shared/components/type-ahead/type-ahead.component';
import { TypeaheadModule } from 'ngx-bootstrap';
import { TypeaheadModule } from 'ngx-bootstrap/typeahead';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { Direction, Sorting, WorkbasketAccessItemQuerySortParameter } from '../../../shared/models/sorting';
import { StartupService } from '../../../shared/services/startup/startup.service';
@ -35,6 +35,8 @@ import { MatListModule } from '@angular/material/list';
import { MatExpansionModule } from '@angular/material/expansion';
import { MatTableModule } from '@angular/material/table';
jest.mock('angular-svg-icon');
const isFieldValidFn = jest.fn().mockReturnValue(true);
const formValidatorServiceSpy = jest.fn().mockImplementation(
(): Partial<FormsValidatorService> => ({
@ -43,11 +45,9 @@ const formValidatorServiceSpy = jest.fn().mockImplementation(
);
const showDialogFn = jest.fn().mockReturnValue(true);
const notificationServiceSpy = jest.fn().mockImplementation(
(): Partial<NotificationService> => ({
showDialog: showDialogFn
})
);
const notificationServiceSpy: Partial<NotificationService> = {
showDialog: showDialogFn
};
const mockDialogRef = {
close: jasmine.createSpy('close')
@ -107,8 +107,8 @@ describe('AccessItemsManagementComponent', () => {
SvgIconStub
],
providers: [
{ provide: FormsValidatorService, useClass: formValidatorServiceSpy },
{ provide: NotificationService, useClass: notificationServiceSpy },
{ provide: FormsValidatorService, useValue: formValidatorServiceSpy },
{ provide: NotificationService, useValue: notificationServiceSpy },
{ provide: MatDialogRef, useValue: { mockDialogRef } },
RequestInProgressService,
ClassificationCategoriesService,
@ -172,7 +172,10 @@ describe('AccessItemsManagementComponent', () => {
{ accessId: '1', name: 'users' },
{ accessId: '2', name: 'users' }
];
app.sortModel = { 'sort-by': WorkbasketAccessItemQuerySortParameter.ACCESS_ID, order: Direction.DESC };
app.sortModel = {
'sort-by': WorkbasketAccessItemQuerySortParameter.ACCESS_ID,
order: Direction.DESC
};
app.searchForAccessItemsWorkbaskets();
fixture.detectChanges();
let actionDispatched = false;

View File

@ -9,13 +9,11 @@ import { HttpClientTestingModule } from '@angular/common/http/testing';
import { of } from 'rxjs';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
const domainServiceSpy = jest.fn().mockImplementation(
(): Partial<DomainService> => ({
getDomains: jest.fn().mockReturnValue(of(['domain a', 'domain b'])),
getSelectedDomain: jest.fn().mockReturnValue(of('domain a')),
switchDomain: jest.fn()
})
);
const domainServiceSpy: Partial<DomainService> = {
getDomains: jest.fn().mockReturnValue(of(['domain a', 'domain b'])),
getSelectedDomain: jest.fn().mockReturnValue(of('domain a')),
switchDomain: jest.fn()
};
describe('AdministrationOverviewComponent', () => {
let component: AdministrationOverviewComponent;
@ -32,7 +30,7 @@ describe('AdministrationOverviewComponent', () => {
BrowserAnimationsModule
],
declarations: [AdministrationOverviewComponent],
providers: [{ provide: DomainService, useClass: domainServiceSpy }]
providers: [{ provide: DomainService, useValue: domainServiceSpy }]
}).compileComponents();
}));

View File

@ -55,59 +55,45 @@ class TextareaStub {
@Input() ngModel;
}
const classificationServiceSpy = jest.fn().mockImplementation(
(): Partial<ClassificationsService> => ({
getClassification: jest.fn().mockReturnValue(of()),
getClassifications: jest.fn().mockReturnValue(of()),
postClassification: jest.fn().mockReturnValue(of()),
putClassification: jest.fn().mockReturnValue(of()),
deleteClassification: jest.fn().mockReturnValue(of())
})
);
const classificationCategoriesServiceSpy = jest.fn().mockImplementation(
(): Partial<ClassificationCategoriesService> => ({
getCustomisation: jest.fn().mockReturnValue(of())
})
);
const domainServiceSpy = jest.fn().mockImplementation(
(): Partial<DomainService> => ({
getSelectedDomainValue: jest.fn().mockReturnValue(of('A')),
getSelectedDomain: jest.fn().mockReturnValue(of())
})
);
const classificationServiceSpy: Partial<ClassificationsService> = {
getClassification: jest.fn().mockReturnValue(of()),
getClassifications: jest.fn().mockReturnValue(of()),
postClassification: jest.fn().mockReturnValue(of()),
putClassification: jest.fn().mockReturnValue(of()),
deleteClassification: jest.fn().mockReturnValue(of())
};
const classificationCategoriesServiceSpy: Partial<ClassificationCategoriesService> = {
getCustomisation: jest.fn().mockReturnValue(of())
};
const domainServiceSpy: Partial<DomainService> = {
getSelectedDomainValue: jest.fn().mockReturnValue(of('A')),
getSelectedDomain: jest.fn().mockReturnValue(of())
};
const getImportingFinishedFn = jest.fn().mockReturnValue(of(true));
const importExportServiceSpy = jest.fn().mockImplementation(
(): Partial<ImportExportService> => ({
getImportingFinished: getImportingFinishedFn
})
);
const importExportServiceSpy: Partial<ImportExportService> = {
getImportingFinished: getImportingFinishedFn
};
const requestInProgressServiceSpy = jest.fn().mockImplementation(
(): Partial<RequestInProgressService> => ({
setRequestInProgress: jest.fn().mockReturnValue(of()),
getRequestInProgress: jest.fn().mockReturnValue(of(false))
})
);
const requestInProgressServiceSpy: Partial<RequestInProgressService> = {
setRequestInProgress: jest.fn().mockReturnValue(of()),
getRequestInProgress: jest.fn().mockReturnValue(of(false))
};
const validateFormInformationFn = jest.fn().mockImplementation((): Promise<any> => Promise.resolve(true));
const formsValidatorServiceSpy = jest.fn().mockImplementation(
(): Partial<FormsValidatorService> => ({
isFieldValid: jest.fn().mockReturnValue(true),
validateInputOverflow: jest.fn(),
validateFormInformation: validateFormInformationFn,
get inputOverflowObservable(): Observable<Map<string, boolean>> {
return of(new Map<string, boolean>());
}
})
);
const formsValidatorServiceSpy: Partial<FormsValidatorService> = {
isFieldValid: jest.fn().mockReturnValue(true),
validateInputOverflow: jest.fn(),
validateFormInformation: validateFormInformationFn,
get inputOverflowObservable(): Observable<Map<string, boolean>> {
return of(new Map<string, boolean>());
}
};
const notificationServiceSpy = jest.fn().mockImplementation(
(): Partial<NotificationService> => ({
showToast: jest.fn().mockReturnValue(of()),
showDialog: jest.fn().mockReturnValue(of()),
triggerError: jest.fn().mockReturnValue(of())
})
);
const notificationServiceSpy: Partial<NotificationService> = {
showToast: jest.fn().mockReturnValue(of()),
showDialog: jest.fn().mockReturnValue(of()),
triggerError: jest.fn().mockReturnValue(of())
};
describe('ClassificationDetailsComponent', () => {
let fixture: ComponentFixture<ClassificationDetailsComponent>;
@ -135,13 +121,13 @@ describe('ClassificationDetailsComponent', () => {
],
declarations: [ClassificationDetailsComponent, InputStub, FieldErrorDisplayStub, SvgIconStub, TextareaStub],
providers: [
{ provide: ClassificationsService, useClass: classificationServiceSpy },
{ provide: ClassificationCategoriesService, useClass: classificationCategoriesServiceSpy },
{ provide: DomainService, useClass: domainServiceSpy },
{ provide: ImportExportService, useClass: importExportServiceSpy },
{ provide: RequestInProgressService, useClass: requestInProgressServiceSpy },
{ provide: FormsValidatorService, useClass: formsValidatorServiceSpy },
{ provide: NotificationService, useClass: notificationServiceSpy }
{ provide: ClassificationsService, useValue: classificationServiceSpy },
{ provide: ClassificationCategoriesService, useValue: classificationCategoriesServiceSpy },
{ provide: DomainService, useValue: domainServiceSpy },
{ provide: ImportExportService, useValue: importExportServiceSpy },
{ provide: RequestInProgressService, useValue: requestInProgressServiceSpy },
{ provide: FormsValidatorService, useValue: formsValidatorServiceSpy },
{ provide: NotificationService, useValue: notificationServiceSpy }
]
}).compileComponents();

View File

@ -2,6 +2,8 @@
.classification-list {
height: 100%;
line-height: 1.5;
font-size: 1rem;
&__no-items {
text-align: center;

View File

@ -48,36 +48,24 @@ class InputStub {
@Input() ngModel;
}
const classificationServiceSpy = jest.fn().mockImplementation(
(): Partial<ClassificationsService> => ({
getClassification: jest.fn().mockReturnValue(of()),
getClassifications: jest.fn().mockReturnValue(of())
})
);
const classificationCategoriesServiceSpy = jest.fn().mockImplementation(
(): Partial<ClassificationCategoriesService> => ({
getCustomisation: jest.fn().mockReturnValue(of())
})
);
const domainServiceSpy = jest.fn().mockImplementation(
(): Partial<DomainService> => ({
getSelectedDomainValue: jest.fn().mockReturnValue(of()),
getSelectedDomain: jest.fn().mockReturnValue(of())
})
);
const classificationServiceSpy: Partial<ClassificationsService> = {
getClassification: jest.fn().mockReturnValue(of()),
getClassifications: jest.fn().mockReturnValue(of())
};
const classificationCategoriesServiceSpy = jest.fn().mockImplementation(() => jest.fn().mockReturnValue(of()));
const domainServiceSpy: Partial<DomainService> = {
getSelectedDomainValue: jest.fn().mockReturnValue(of()),
getSelectedDomain: jest.fn().mockReturnValue(of())
};
const getImportingFinishedFn = jest.fn().mockReturnValue(of(true));
const importExportServiceSpy = jest.fn().mockImplementation(
(): Partial<ImportExportService> => ({
getImportingFinished: getImportingFinishedFn
})
);
const importExportServiceSpy: Partial<ImportExportService> = {
getImportingFinished: getImportingFinishedFn
};
const requestInProgressServiceSpy = jest.fn().mockImplementation(
(): Partial<RequestInProgressService> => ({
setRequestInProgress: jest.fn().mockReturnValue(of()),
getRequestInProgress: jest.fn().mockReturnValue(of(false))
})
);
const requestInProgressServiceSpy: Partial<RequestInProgressService> = {
setRequestInProgress: jest.fn().mockReturnValue(of()),
getRequestInProgress: jest.fn().mockReturnValue(of(false))
};
describe('ClassificationListComponent', () => {
let fixture: ComponentFixture<ClassificationListComponent>;
@ -106,11 +94,11 @@ describe('ClassificationListComponent', () => {
InputStub
],
providers: [
{ provide: ClassificationsService, useClass: classificationServiceSpy },
{ provide: ClassificationCategoriesService, useClass: classificationCategoriesServiceSpy },
{ provide: DomainService, useClass: domainServiceSpy },
{ provide: ImportExportService, useClass: importExportServiceSpy },
{ provide: RequestInProgressService, useClass: requestInProgressServiceSpy }
{ provide: ClassificationsService, useValue: classificationServiceSpy },
{ provide: ClassificationCategoriesService, useValue: classificationCategoriesServiceSpy },
{ provide: DomainService, useValue: domainServiceSpy },
{ provide: ImportExportService, useValue: importExportServiceSpy },
{ provide: RequestInProgressService, useValue: requestInProgressServiceSpy }
]
}).compileComponents();

View File

@ -5,7 +5,7 @@
<taskana-administration-classification-details *ngIf="showDetail; else showEmptyPage"></taskana-administration-classification-details>
<ng-template #showEmptyPage>
<div class="hidden-xs hidden-sm col-md-8 container-no-items">
<div class="classification-overview__empty-page">
<div class="center-block no-detail">
<h3 class="grey select-classification">Select a classification</h3>
<svg-icon class="img-responsive empty-icon" src="./assets/icons/classification-empty.svg"></svg-icon>

View File

@ -4,6 +4,13 @@
width: 100%;
overflow: hidden;
align-items: stretch;
&__empty-page {
flex-grow: 1;
display: flex;
justify-content: center;
align-items: center;
}
}
taskana-administration-classification-list {
min-width: 500px;

View File

@ -31,18 +31,14 @@ const activatedRouteMock = {
};
const classificationCategoriesServiceSpy = jest.fn();
const classificationServiceSpy = jest.fn().mockImplementation(
(): Partial<ClassificationsService> => ({
getClassification: jest.fn().mockReturnValue(of()),
getClassifications: jest.fn().mockReturnValue(of())
})
);
const domainServiceSpy = jest.fn().mockImplementation(
(): Partial<DomainService> => ({
getSelectedDomainValue: jest.fn().mockReturnValue(of()),
getSelectedDomain: jest.fn().mockReturnValue(of('A'))
})
);
const classificationServiceSpy: Partial<ClassificationsService> = {
getClassification: jest.fn().mockReturnValue(of()),
getClassifications: jest.fn().mockReturnValue(of())
};
const domainServiceSpy: Partial<DomainService> = {
getSelectedDomainValue: jest.fn().mockReturnValue(of()),
getSelectedDomain: jest.fn().mockReturnValue(of('A'))
};
describe('ClassificationOverviewComponent', () => {
let fixture: ComponentFixture<ClassificationOverviewComponent>;
@ -56,9 +52,9 @@ describe('ClassificationOverviewComponent', () => {
imports: [NgxsModule.forRoot([ClassificationState])],
declarations: [ClassificationOverviewComponent, ClassificationDetailsStub, ClassificationListStub, SvgIconStub],
providers: [
{ provide: ClassificationsService, useClass: classificationServiceSpy },
{ provide: ClassificationCategoriesService, useClass: classificationCategoriesServiceSpy },
{ provide: DomainService, useClass: domainServiceSpy },
{ provide: ClassificationsService, useValue: classificationServiceSpy },
{ provide: ClassificationCategoriesService, useValue: classificationCategoriesServiceSpy },
{ provide: DomainService, useValue: domainServiceSpy },
{ provide: ActivatedRoute, useValue: activatedRouteMock }
]
}).compileComponents();

View File

@ -32,9 +32,9 @@ describe('ClassificationTypesSelectorComponent', () => {
],
declarations: [ClassificationTypesSelectorComponent],
providers: [
{ provide: ClassificationsService, useClass: classificationServiceSpy },
{ provide: ClassificationCategoriesService, useClass: classificationCategoriesServiceSpy },
{ provide: DomainService, useClass: domainServiceSpy }
{ provide: ClassificationsService, useValue: classificationServiceSpy },
{ provide: ClassificationCategoriesService, useValue: classificationCategoriesServiceSpy },
{ provide: DomainService, useValue: domainServiceSpy }
]
}).compileComponents();

View File

@ -4,8 +4,8 @@
<mat-icon>cloud_upload</mat-icon>
</button>
<form class="hidden" enctype="multipart/form-data" method="post">
<input #selectedFile type="file" accept=".json" (change)="uploadFile()" class="hide" />
<form class="hide" enctype="multipart/form-data" method="post">
<input #selectedFile type="file" accept=".json" (change)="uploadFile()" class="hidden" />
</form>
<button mat-stroked-button class="mr-1" matTooltip="Export {{parentComponent}}" [matMenuTriggerFor]="menu" [ngClass]="{disabled: uploadService?.isInUse}" title="Export">

View File

@ -12,7 +12,7 @@ import {
} from '@angular/core';
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 '@circlon/angular-tree-component';
import { combineLatest, Observable, Subject } from 'rxjs';
import { filter, map, takeUntil } from 'rxjs/operators';
import { Select, Store } from '@ngxs/store';

View File

@ -94,6 +94,7 @@
.required-header {
width: 200px;
}
.required-header:after {
content: ' *';
color: red;
@ -113,3 +114,7 @@
::ng-deep .mat-form-field-appearance-outline .mat-form-field-flex {
margin-top: 0.7em;
}
table {
border-collapse: collapse;
}

View File

@ -5,7 +5,7 @@ import { Actions, NgxsModule, ofActionDispatched, Store } from '@ngxs/store';
import { Observable, of } from 'rxjs';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { TypeAheadComponent } from '../../../shared/components/type-ahead/type-ahead.component';
import { TypeaheadModule } from 'ngx-bootstrap';
import { TypeaheadModule } from 'ngx-bootstrap/typeahead';
import { RequestInProgressService } from '../../../shared/services/request-in-progress/request-in-progress.service';
import { FormsValidatorService } from '../../../shared/services/forms-validator/forms-validator.service';
import { NotificationService } from '../../../shared/services/notifications/notification.service';
@ -45,31 +45,25 @@ class SpinnerStub {
@Input() positionClass: string;
}
const requestInProgressServiceSpy = jest.fn().mockImplementation(
(): Partial<RequestInProgressService> => ({
setRequestInProgress: jest.fn()
})
);
const requestInProgressServiceSpy: Partial<RequestInProgressService> = {
setRequestInProgress: jest.fn()
};
const showDialogFn = jest.fn().mockReturnValue(true);
const notificationServiceSpy = jest.fn().mockImplementation(
(): Partial<NotificationService> => ({
triggerError: showDialogFn,
showToast: showDialogFn
})
);
const notificationServiceSpy: Partial<NotificationService> = {
triggerError: showDialogFn,
showToast: showDialogFn
};
const validateFormInformationFn = jest.fn().mockImplementation((): Promise<any> => Promise.resolve(true));
const formValidatorServiceSpy = jest.fn().mockImplementation(
(): Partial<FormsValidatorService> => ({
isFieldValid: jest.fn().mockReturnValue(true),
validateInputOverflow: jest.fn(),
validateFormInformation: validateFormInformationFn,
get inputOverflowObservable(): Observable<Map<string, boolean>> {
return of(new Map<string, boolean>());
}
})
);
const formValidatorServiceSpy: Partial<FormsValidatorService> = {
isFieldValid: jest.fn().mockReturnValue(true),
validateInputOverflow: jest.fn(),
validateFormInformation: validateFormInformationFn,
get inputOverflowObservable(): Observable<Map<string, boolean>> {
return of(new Map<string, boolean>());
}
};
describe('WorkbasketAccessItemsComponent', () => {
let fixture: ComponentFixture<WorkbasketAccessItemsComponent>;
@ -99,9 +93,9 @@ describe('WorkbasketAccessItemsComponent', () => {
],
declarations: [WorkbasketAccessItemsComponent, TypeAheadComponent, SpinnerStub],
providers: [
{ provide: RequestInProgressService, useClass: requestInProgressServiceSpy },
{ provide: FormsValidatorService, useClass: formValidatorServiceSpy },
{ provide: NotificationService, useClass: notificationServiceSpy },
{ provide: RequestInProgressService, useValue: requestInProgressServiceSpy },
{ provide: FormsValidatorService, useValue: formValidatorServiceSpy },
{ provide: NotificationService, useValue: notificationServiceSpy },
ClassificationCategoriesService,
WorkbasketService,
DomainService,

View File

@ -50,13 +50,11 @@ class WorkbasketDistributionTargetsStub {
@Input() active: string;
}
const domainServiceSpy = jest.fn().mockImplementation(
(): Partial<DomainService> => ({
getSelectedDomainValue: jest.fn().mockReturnValue(of()),
getSelectedDomain: jest.fn().mockReturnValue(of('A')),
getDomains: jest.fn().mockReturnValue(of())
})
);
const domainServiceSpy: Partial<DomainService> = {
getSelectedDomain: jest.fn().mockReturnValue(of('A')),
getSelectedDomainValue: jest.fn().mockReturnValue(of()),
getDomains: jest.fn().mockReturnValue(of())
};
export const workbasketCopyState = {
selectedWorkbasket: selectedWorkbasketMock,
@ -102,7 +100,7 @@ describe('WorkbasketDetailsComponent', () => {
WorkbasketInformationStub
],
providers: [
{ provide: DomainService, useClass: domainServiceSpy },
{ provide: DomainService, useValue: domainServiceSpy },
ImportExportService,
WorkbasketService,
RequestInProgressService,

View File

@ -35,31 +35,23 @@ class WorkbasketDistributionTargetsListStub {
@Input() allSelected;
}
const domainServiceSpy = jest.fn().mockImplementation(
(): Partial<DomainService> => ({
getSelectedDomainValue: jest.fn().mockReturnValue(of()),
getSelectedDomain: jest.fn().mockReturnValue(of('A')),
getDomains: jest.fn().mockReturnValue(of())
})
);
const domainServiceSpy: Partial<DomainService> = {
getSelectedDomainValue: jest.fn().mockReturnValue(of()),
getSelectedDomain: jest.fn().mockReturnValue(of('A')),
getDomains: jest.fn().mockReturnValue(of())
};
const workbasketServiceSpy = jest.fn().mockImplementation(
(): Partial<WorkbasketService> => ({
getWorkBasketsSummary: jest.fn().mockReturnValue(of()),
getWorkBasketsDistributionTargets: jest.fn().mockReturnValue(of())
})
);
const workbasketServiceSpy: Partial<WorkbasketService> = {
getWorkBasketsSummary: jest.fn().mockReturnValue(of()),
getWorkBasketsDistributionTargets: jest.fn().mockReturnValue(of())
};
const notificationsServiceSpy = jest.fn().mockImplementation(
(): Partial<NotificationService> => ({
showToast: jest.fn().mockReturnValue(true)
})
);
const requestInProgressServiceSpy = jest.fn().mockImplementation(
(): Partial<RequestInProgressService> => ({
setRequestInProgress: jest.fn().mockReturnValue(of())
})
);
const notificationsServiceSpy: Partial<NotificationService> = {
showToast: jest.fn().mockReturnValue(true)
};
const requestInProgressServiceSpy: Partial<RequestInProgressService> = {
setRequestInProgress: jest.fn().mockReturnValue(of())
};
describe('WorkbasketDistributionTargetsComponent', () => {
let fixture: ComponentFixture<WorkbasketDistributionTargetsComponent>;
@ -79,11 +71,11 @@ describe('WorkbasketDistributionTargetsComponent', () => {
],
declarations: [WorkbasketDistributionTargetsComponent, WorkbasketDistributionTargetsListStub],
providers: [
{ provide: WorkbasketService, useClass: workbasketServiceSpy },
{ provide: NotificationService, useClass: notificationsServiceSpy },
{ provide: WorkbasketService, useValue: workbasketServiceSpy },
{ provide: NotificationService, useValue: notificationsServiceSpy },
{ provide: ActivatedRoute, useValue: activatedRouteMock },
{ provide: RequestInProgressService, useClass: requestInProgressServiceSpy },
{ provide: DomainService, useClass: domainServiceSpy }
{ provide: RequestInProgressService, useValue: requestInProgressServiceSpy },
{ provide: DomainService, useValue: domainServiceSpy }
]
}).compileComponents();

View File

@ -21,7 +21,7 @@ import { RouterTestingModule } from '@angular/router/testing';
import { SelectedRouteService } from '../../../shared/services/selected-route/selected-route';
import { ClassificationCategoriesService } from '../../../shared/services/classification-categories/classification-categories.service';
import { ACTION } from '../../../shared/models/action';
import { TypeaheadModule } from 'ngx-bootstrap';
import { TypeaheadModule } from 'ngx-bootstrap/typeahead';
import { TypeAheadComponent } from '../../../shared/components/type-ahead/type-ahead.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { MarkWorkbasketForDeletion, UpdateWorkbasket } from '../../../shared/store/workbasket-store/workbasket.actions';
@ -55,39 +55,33 @@ class IconTypeStub {
}
const triggerWorkbasketSavedFn = jest.fn().mockReturnValue(true);
const workbasketServiceMock = jest.fn().mockImplementation(
(): Partial<WorkbasketService> => ({
triggerWorkBasketSaved: triggerWorkbasketSavedFn,
updateWorkbasket: jest.fn().mockReturnValue(of(true)),
markWorkbasketForDeletion: jest.fn().mockReturnValue(of(true)),
createWorkbasket: jest.fn().mockReturnValue(of({ ...selectedWorkbasketMock })),
getWorkBasket: jest.fn().mockReturnValue(of({ ...selectedWorkbasketMock })),
getWorkBasketAccessItems: jest.fn().mockReturnValue(of()),
getWorkBasketsDistributionTargets: jest.fn().mockReturnValue(of())
})
);
const workbasketServiceMock: Partial<WorkbasketService> = {
triggerWorkBasketSaved: triggerWorkbasketSavedFn,
updateWorkbasket: jest.fn().mockReturnValue(of(true)),
markWorkbasketForDeletion: jest.fn().mockReturnValue(of(true)),
createWorkbasket: jest.fn().mockReturnValue(of({ ...selectedWorkbasketMock })),
getWorkBasket: jest.fn().mockReturnValue(of({ ...selectedWorkbasketMock })),
getWorkBasketAccessItems: jest.fn().mockReturnValue(of()),
getWorkBasketsDistributionTargets: jest.fn().mockReturnValue(of())
};
const isFieldValidFn = jest.fn().mockReturnValue(true);
const validateFormInformationFn = jest.fn().mockImplementation((): Promise<any> => Promise.resolve(true));
const formValidatorServiceSpy = jest.fn().mockImplementation(
(): Partial<FormsValidatorService> => ({
isFieldValid: isFieldValidFn,
validateInputOverflow: jest.fn(),
validateFormInformation: validateFormInformationFn,
get inputOverflowObservable(): Observable<Map<string, boolean>> {
return of(new Map<string, boolean>());
}
})
);
const formValidatorServiceMock: Partial<FormsValidatorService> = {
isFieldValid: isFieldValidFn,
validateInputOverflow: jest.fn(),
validateFormInformation: validateFormInformationFn,
get inputOverflowObservable(): Observable<Map<string, boolean>> {
return of(new Map<string, boolean>());
}
};
const showDialogFn = jest.fn().mockReturnValue(true);
const notificationServiceSpy = jest.fn().mockImplementation(
(): Partial<NotificationService> => ({
showDialog: showDialogFn,
showToast: showDialogFn,
triggerError: showDialogFn
})
);
const notificationServiceMock: Partial<NotificationService> = {
showDialog: showDialogFn,
showToast: showDialogFn,
triggerError: showDialogFn
};
describe('WorkbasketInformationComponent', () => {
let fixture: ComponentFixture<WorkbasketInformationComponent>;
@ -125,9 +119,9 @@ describe('WorkbasketInformationComponent', () => {
RemoveNoneTypePipe
],
providers: [
{ provide: WorkbasketService, useClass: workbasketServiceMock },
{ provide: FormsValidatorService, useClass: formValidatorServiceSpy },
{ provide: NotificationService, useClass: notificationServiceSpy },
{ provide: WorkbasketService, useValue: workbasketServiceMock },
{ provide: FormsValidatorService, useValue: formValidatorServiceMock },
{ provide: NotificationService, useValue: notificationServiceMock },
RequestInProgressService,
DomainService,
SelectedRouteService,

View File

@ -19,12 +19,10 @@ import { RouterTestingModule } from '@angular/router/testing';
import { RequestInProgressService } from '../../../shared/services/request-in-progress/request-in-progress.service';
const getDomainFn = jest.fn().mockReturnValue(true);
const domainServiceMock = jest.fn().mockImplementation(
(): Partial<DomainService> => ({
getDomains: getDomainFn,
getSelectedDomain: jest.fn().mockReturnValue(of('A'))
})
);
const domainServiceMock: Partial<DomainService> = {
getDomains: getDomainFn,
getSelectedDomain: jest.fn().mockReturnValue(of('A'))
};
@Component({ selector: 'taskana-administration-import-export', template: '' })
class ImportExportStub {
@ -44,11 +42,7 @@ class FilterStub {
@Input() isExpanded = false;
}
const requestInProgressServiceSpy = jest.fn().mockImplementation(
(): Partial<RequestInProgressService> => ({
setRequestInProgress: jest.fn().mockReturnValue(of())
})
);
const requestInProgressServiceSpy = jest.fn().mockImplementation(() => jest.fn().mockReturnValue(of()));
describe('WorkbasketListToolbarComponent', () => {
let fixture: ComponentFixture<WorkbasketListToolbarComponent>;
@ -70,8 +64,8 @@ describe('WorkbasketListToolbarComponent', () => {
],
declarations: [WorkbasketListToolbarComponent, ImportExportStub, SortStub, FilterStub],
providers: [
{ provide: DomainService, useClass: domainServiceMock },
{ provide: RequestInProgressService, useClass: requestInProgressServiceSpy },
{ provide: DomainService, useValue: domainServiceMock },
{ provide: RequestInProgressService, useValue: requestInProgressServiceSpy },
WorkbasketService
]
}).compileComponents();

View File

@ -28,45 +28,34 @@ const workbasketSavedTriggeredFn = jest.fn().mockReturnValue(of(1));
const workbasketSummaryFn = jest.fn().mockReturnValue(of({}));
const getWorkbasketFn = jest.fn().mockReturnValue(of(selectedWorkbasketMock));
const getWorkbasketActionToolbarExpansionFn = jest.fn().mockReturnValue(of(false));
const workbasketServiceMock = jest.fn().mockImplementation(
(): Partial<WorkbasketService> => ({
workbasketSavedTriggered: workbasketSavedTriggeredFn,
getWorkBasketsSummary: workbasketSummaryFn,
getWorkBasket: getWorkbasketFn,
getWorkbasketActionToolbarExpansion: getWorkbasketActionToolbarExpansionFn,
getWorkBasketAccessItems: jest.fn().mockReturnValue(of({})),
getWorkBasketsDistributionTargets: jest.fn().mockReturnValue(of({}))
})
);
const workbasketServiceMock: Partial<WorkbasketService> = {
workbasketSavedTriggered: workbasketSavedTriggeredFn,
getWorkBasketsSummary: workbasketSummaryFn,
getWorkBasket: getWorkbasketFn,
getWorkbasketActionToolbarExpansion: getWorkbasketActionToolbarExpansionFn,
getWorkBasketAccessItems: jest.fn().mockReturnValue(of({})),
getWorkBasketsDistributionTargets: jest.fn().mockReturnValue(of({}))
};
const getOrientationFn = jest.fn().mockReturnValue(of('landscape'));
const orientationServiceMock = jest.fn().mockImplementation(
(): Partial<OrientationService> => ({
getOrientation: getOrientationFn,
calculateNumberItemsList: jest.fn().mockReturnValue(1920)
})
);
const orientationServiceMock: Partial<OrientationService> = {
getOrientation: getOrientationFn,
calculateNumberItemsList: jest.fn().mockReturnValue(1920)
};
const getImportingFinishedFn = jest.fn().mockReturnValue(of(true));
const importExportServiceMock = jest.fn().mockImplementation(
(): Partial<ImportExportService> => ({
getImportingFinished: getImportingFinishedFn
})
);
const importExportServiceMock: Partial<ImportExportService> = {
getImportingFinished: jest.fn().mockReturnValue(of(true))
};
const domainServiceSpy = jest.fn().mockImplementation(
(): Partial<DomainService> => ({
getSelectedDomainValue: jest.fn().mockReturnValue(of()),
getSelectedDomain: jest.fn().mockReturnValue(of())
})
);
const domainServiceSpy: Partial<DomainService> = {
getSelectedDomainValue: jest.fn().mockReturnValue(of()),
getSelectedDomain: jest.fn().mockReturnValue(of())
};
const requestInProgressServiceSpy = jest.fn().mockImplementation(
(): Partial<RequestInProgressService> => ({
setRequestInProgress: jest.fn().mockReturnValue(of()),
getRequestInProgress: jest.fn().mockReturnValue(of(false))
})
);
const requestInProgressServiceSpy: Partial<RequestInProgressService> = {
setRequestInProgress: jest.fn().mockReturnValue(of()),
getRequestInProgress: jest.fn().mockReturnValue(of(false))
};
@Component({ selector: 'taskana-administration-workbasket-list-toolbar', template: '' })
class WorkbasketListToolbarStub {
@ -115,11 +104,11 @@ describe('WorkbasketListComponent', () => {
],
declarations: [WorkbasketListComponent, WorkbasketListToolbarStub, IconTypeStub, PaginationStub, SvgIconStub],
providers: [
{ provide: WorkbasketService, useClass: workbasketServiceMock },
{ provide: OrientationService, useClass: orientationServiceMock },
{ provide: ImportExportService, useClass: importExportServiceMock },
{ provide: DomainService, useClass: domainServiceSpy },
{ provide: RequestInProgressService, useClass: requestInProgressServiceSpy }
{ provide: WorkbasketService, useValue: workbasketServiceMock },
{ provide: OrientationService, useValue: orientationServiceMock },
{ provide: ImportExportService, useValue: importExportServiceMock },
{ provide: DomainService, useValue: domainServiceSpy },
{ provide: RequestInProgressService, useValue: requestInProgressServiceSpy }
]
}).compileComponents();

View File

@ -21,20 +21,16 @@ import { MatIconModule } from '@angular/material/icon';
import { take } from 'rxjs/operators';
const showDialogFn = jest.fn().mockReturnValue(true);
const NotificationServiceSpy = jest.fn().mockImplementation(
(): Partial<NotificationService> => ({
triggerError: showDialogFn,
showToast: showDialogFn
})
);
const NotificationServiceSpy: Partial<NotificationService> = {
triggerError: showDialogFn,
showToast: showDialogFn
};
const domainServiceSpy = jest.fn().mockImplementation(
(): Partial<DomainService> => ({
getSelectedDomainValue: jest.fn().mockReturnValue(of()),
getSelectedDomain: jest.fn().mockReturnValue(of('A')),
getDomains: jest.fn().mockReturnValue(of())
})
);
const domainServiceSpy: Partial<DomainService> = {
getSelectedDomainValue: jest.fn().mockReturnValue(of()),
getSelectedDomain: jest.fn().mockReturnValue(of('A')),
getDomains: jest.fn().mockReturnValue(of())
};
const mockActivatedRoute = {
firstChild: {
@ -86,7 +82,7 @@ describe('WorkbasketOverviewComponent', () => {
declarations: [WorkbasketOverviewComponent, WorkbasketListStub, WorkbasketDetailsStub, SvgIconStub],
providers: [
WorkbasketService,
{ provide: NotificationService, useClass: NotificationServiceSpy },
{ provide: NotificationService, useValue: NotificationServiceSpy },
{ provide: ActivatedRoute, useValue: mockActivatedRoute },
{ provide: DomainService, useValue: domainServiceSpy },
DomainService,
@ -152,7 +148,7 @@ describe('WorkbasketOverviewComponent Alternative Params ID', () => {
declarations: [WorkbasketOverviewComponent, WorkbasketListStub, WorkbasketDetailsStub, SvgIconStub],
providers: [
WorkbasketService,
{ provide: NotificationService, useClass: NotificationServiceSpy },
{ provide: NotificationService, useValue: NotificationServiceSpy },
{ provide: ActivatedRoute, useValue: mockActivatedRouteAlternative },
DomainService,
RequestInProgressService,
@ -195,7 +191,7 @@ describe('WorkbasketOverviewComponent No Params', () => {
declarations: [WorkbasketOverviewComponent, WorkbasketListStub, WorkbasketDetailsStub, SvgIconStub],
providers: [
WorkbasketService,
{ provide: NotificationService, useClass: NotificationServiceSpy },
{ provide: NotificationService, useValue: NotificationServiceSpy },
{ provide: ActivatedRoute, useValue: mockActivatedRouteNoParams },
DomainService,
RequestInProgressService,

View File

@ -24,7 +24,7 @@
<div (window:resize)="onResize()">
<div class="taskana-main">
<div class="taskana-main__progress-bar">
<mat-progress-bar [hidden]="!requestInProgress" mode="indeterminate"></mat-progress-bar>
<mat-progress-bar *ngIf="requestInProgress" mode="indeterminate"></mat-progress-bar>
</div>
<router-outlet></router-outlet>
<taskana-shared-progress-spinner

View File

@ -63,7 +63,9 @@ export class AppComponent implements OnInit, OnDestroy {
.getRequestInProgress()
.pipe(takeUntil(this.destroy$))
.subscribe((value: boolean) => {
this.requestInProgress = value;
setTimeout(() => {
this.requestInProgress = value;
});
});
this.selectedRouteService

View File

@ -7,12 +7,22 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { HttpClientModule, HttpClientXsrfModule, HttpXsrfTokenExtractor } from '@angular/common/http';
import { NgxsModule } from '@ngxs/store';
import { NgxsReduxDevtoolsPluginModule } from '@ngxs/devtools-plugin';
import { AlertModule } from 'ngx-bootstrap';
import { AlertModule } from 'ngx-bootstrap/alert';
import { AngularSvgIconModule } from 'angular-svg-icon';
import { TabsModule } from 'ngx-bootstrap/tabs';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { TreeModule } from 'angular-tree-component';
import { TreeModule } from '@circlon/angular-tree-component';
import { SharedModule } from 'app/shared/shared.module';
import { MatSidenavModule } from '@angular/material/sidenav';
import { MatIconModule } from '@angular/material/icon';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatGridListModule } from '@angular/material/grid-list';
import { MatListModule } from '@angular/material/list';
import { MatButtonModule } from '@angular/material/button';
import { MatToolbarModule } from '@angular/material/toolbar';
import { MatProgressBarModule } from '@angular/material/progress-bar';
import { MatSelectModule } from '@angular/material/select';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
/**
* Services
@ -51,16 +61,8 @@ import { UserGuard } from './shared/guards/user.guard';
import { ClassificationCategoriesService } from './shared/services/classification-categories/classification-categories.service';
import { environment } from '../environments/environment';
import { STATES } from './shared/store';
import { MatSidenavModule } from '@angular/material/sidenav';
import { MatIconModule } from '@angular/material/icon';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatGridListModule } from '@angular/material/grid-list';
import { MatListModule } from '@angular/material/list';
import { MatButtonModule } from '@angular/material/button';
import { MatToolbarModule } from '@angular/material/toolbar';
import { MatProgressBarModule } from '@angular/material/progress-bar';
import { MatSelectModule } from '@angular/material/select';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
const DECLARATIONS = [AppComponent, NavBarComponent, UserInformationComponent, NoAccessComponent, SidenavListComponent];
const MODULES = [
TabsModule.forRoot(),
@ -81,45 +83,48 @@ const MODULES = [
MatButtonModule,
MatIconModule,
MatSelectModule,
MatToolbarModule,
MatProgressBarModule,
MatProgressSpinnerModule,
NgxsModule.forRoot(STATES, { developmentMode: !environment.production }),
NgxsReduxDevtoolsPluginModule.forRoot({ disabled: environment.production, maxAge: 25 }),
HttpClientXsrfModule
];
const DECLARATIONS = [AppComponent, NavBarComponent, UserInformationComponent, NoAccessComponent, SidenavListComponent];
const PROVIDERS = [
WindowRefService,
DomainService,
RequestInProgressService,
OrientationService,
SelectedRouteService,
DomainGuard,
BusinessAdminGuard,
MonitorGuard,
UserGuard,
StartupService,
MasterAndDetailService,
TaskanaEngineService,
FormsValidatorService,
UploadService,
NotificationService,
ClassificationCategoriesService,
SidenavService,
{
provide: APP_INITIALIZER,
useFactory: startupServiceFactory,
deps: [StartupService],
multi: true
}
];
@NgModule({
declarations: DECLARATIONS,
imports: MODULES,
providers: PROVIDERS,
bootstrap: [AppComponent]
})
export class AppModule {}
export function startupServiceFactory(startupService: StartupService): () => Promise<any> {
return (): Promise<any> => startupService.load();
}
@NgModule({
declarations: DECLARATIONS,
imports: [MODULES, MatSidenavModule, MatIconModule, MatToolbarModule, MatProgressBarModule, MatProgressSpinnerModule],
providers: [
WindowRefService,
DomainService,
RequestInProgressService,
OrientationService,
SelectedRouteService,
DomainGuard,
BusinessAdminGuard,
MonitorGuard,
UserGuard,
StartupService,
{
provide: APP_INITIALIZER,
useFactory: startupServiceFactory,
deps: [StartupService],
multi: true
},
MasterAndDetailService,
TaskanaEngineService,
FormsValidatorService,
UploadService,
NotificationService,
ClassificationCategoriesService,
SidenavService
],
bootstrap: [AppComponent]
})
export class AppModule {}

View File

@ -10,4 +10,3 @@
width: 100%;
}
}

View File

@ -3,7 +3,7 @@
<h4>{{reportData.meta.name}} ({{reportData.meta.date | dateTimeZone}})</h4>
</div>
<div class="panel-body">
<div style="display: block" class =" col-xs-12 col-md-7 col-md-offset-2">
<div style="display: block">
<canvas baseChart [data]="pieChartData" [labels]="pieChartLabels" [chartType]="pieChartType"></canvas>
</div>
<taskana-monitor-report-table [reportData]="reportData"></taskana-monitor-report-table>

View File

@ -1,28 +1,26 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { AlertModule } from 'ngx-bootstrap';
import { ChartsModule } from 'ng2-charts';
import { TabsModule } from 'ngx-bootstrap/tabs';
import { MatTabsModule } from '@angular/material/tabs';
import { CommonModule } from '@angular/common';
import { HttpClientModule } from '@angular/common/http';
import { FormsModule } from '@angular/forms';
import { MatTabsModule } from '@angular/material/tabs';
import { MatButtonModule } from '@angular/material/button';
import { AlertModule } from 'ngx-bootstrap/alert';
import { TabsModule } from 'ngx-bootstrap/tabs';
import { ChartsModule } from 'ng2-charts';
import { AngularSvgIconModule } from 'angular-svg-icon';
import { MapToIterable } from 'app/shared/pipes/map-to-iterable.pipe';
import { MonitorRoutingModule } from './monitor-routing.module';
import { SharedModule } from '../shared/shared.module';
import { MonitorRoutingModule } from './monitor-routing.module';
import { ReportTableComponent } from './components/report-table/report-table.component';
import { MonitorComponent } from './components/monitor/monitor.component';
import { TaskReportComponent } from './components/task-report/task-report.component';
import { ClassificationReportComponent } from './components/classification-report/classification-report.component';
import { TimestampReportComponent } from './components/timestamp-report/timestamp-report.component';
import { MonitorService } from './services/monitor.service';
import { WorkbasketReportComponent } from './components/workbasket-report/workbasket-report.component';
import { WorkbasketReportPlannedDateComponent } from './components/workbasket-report-planned-date/workbasket-report-planned-date.component';
import { WorkbasketReportDueDateComponent } from './components/workbasket-report-due-date/workbasket-report-due-date.component';
import { MatButtonModule } from '@angular/material/button';
import { MonitorService } from './services/monitor.service';
const MODULES = [
CommonModule,

View File

@ -9,17 +9,15 @@ import { of } from 'rxjs/internal/observable/of';
import { MatIconModule } from '@angular/material/icon';
import { MatToolbarModule } from '@angular/material/toolbar';
const SidenavServiceSpy = jest.fn().mockImplementation(
(): Partial<SidenavService> => ({
toggleSidenav: jest.fn().mockReturnValue(of())
})
);
jest.mock('angular-svg-icon');
const SelectedRouteServiceSpy = jest.fn().mockImplementation(
(): Partial<SelectedRouteService> => ({
getSelectedRoute: jest.fn().mockReturnValue(of())
})
);
const SidenavServiceSpy: Partial<SidenavService> = {
toggleSidenav: jest.fn().mockReturnValue(of())
};
const SelectedRouteServiceSpy: Partial<SelectedRouteService> = {
getSelectedRoute: jest.fn().mockReturnValue(of())
};
@Component({ selector: 'svg-icon', template: '' })
class SvgIconStub {}
@ -28,15 +26,15 @@ describe('NavBarComponent', () => {
let component: NavBarComponent;
let fixture: ComponentFixture<NavBarComponent>;
let debugElement: DebugElement;
var route = '';
let route = '';
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [NavBarComponent, SvgIconStub],
imports: [MatIconModule, HttpClientTestingModule, MatToolbarModule],
providers: [
{ provide: SidenavService, useClass: SidenavServiceSpy },
{ provide: SelectedRouteService, useClass: SelectedRouteServiceSpy }
{ provide: SidenavService, useValue: SidenavServiceSpy },
{ provide: SelectedRouteService, useValue: SelectedRouteServiceSpy }
]
}).compileComponents();
}));

View File

@ -1,4 +1,4 @@
<div *ngIf ="showNoAccess" class="col-xs-12 container-no-access">
<div *ngIf ="showNoAccess" class="container-no-access">
<div class="center-block no-access">
<h3 class="grey">You do not have access to taskana application</h3>
<svg-icon class="img-responsive no-access-icon" src="./assets/icons/noaccess.svg"></svg-icon>

View File

@ -0,0 +1,8 @@
.alert {
color: #a94442;
background-color: #f2dede;
padding: 15px;
margin-bottom: 20px;
border: 1px solid #ebccd1;
border-radius: 4px;
}

View File

@ -27,4 +27,3 @@
}
//TODO: Change color of spinner

View File

@ -17,18 +17,14 @@ import { MatGridListModule } from '@angular/material/grid-list';
import { MatListModule } from '@angular/material/list';
import { MatIconModule } from '@angular/material/icon';
const SidenavServiceSpy = jest.fn().mockImplementation(
(): Partial<SidenavService> => ({
toggleSidenav: jest.fn().mockReturnValue(of())
})
);
const SidenavServiceSpy: Partial<SidenavService> = {
toggleSidenav: jest.fn().mockReturnValue(of())
};
const TaskanaEngingeServiceSpy = jest.fn().mockImplementation(
(): Partial<TaskanaEngineServiceMock> => ({
hasRole: jest.fn().mockReturnValue(of()),
isHistoryProviderEnabled: jest.fn().mockReturnValue(of())
})
);
const TaskanaEngineServiceSpy: Partial<TaskanaEngineServiceMock> = {
hasRole: jest.fn().mockReturnValue(of()),
isHistoryProviderEnabled: jest.fn().mockReturnValue(of())
};
describe('SidenavListComponent', () => {
let component: SidenavListComponent;
@ -51,8 +47,8 @@ describe('SidenavListComponent', () => {
HttpClientTestingModule
],
providers: [
{ provide: SidenavService, useClass: SidenavServiceSpy },
{ provide: TaskanaEngineService, useClass: TaskanaEngingeServiceSpy }
{ provide: SidenavService, useValue: SidenavServiceSpy },
{ provide: TaskanaEngineService, useValue: TaskanaEngineServiceSpy }
]
}).compileComponents();
}));

View File

@ -30,5 +30,4 @@
flex-grow: 1;
min-width: 140px;
}
}

View File

@ -15,12 +15,10 @@ import { MatInputModule } from '@angular/material/input';
import { FormsModule } from '@angular/forms';
import { MatTooltipModule } from '@angular/material/tooltip';
const AccessIdsServiceSpy = jest.fn().mockImplementation(
(): Partial<AccessIdsService> => ({
getAccessItems: jest.fn().mockReturnValue(of()),
searchForAccessId: jest.fn().mockReturnValue(of())
})
);
const AccessIdsServiceSpy: Partial<AccessIdsService> = {
getAccessItems: jest.fn().mockReturnValue(of()),
searchForAccessId: jest.fn().mockReturnValue(of())
};
describe('TypeAheadComponent', () => {
let component: TypeAheadComponent;
@ -43,7 +41,7 @@ describe('TypeAheadComponent', () => {
FormsModule,
BrowserAnimationsModule
],
providers: [{ provide: AccessIdsService, useClass: AccessIdsServiceSpy }]
providers: [{ provide: AccessIdsService, useValue: AccessIdsServiceSpy }]
}).compileComponents();
}));

View File

@ -5,18 +5,15 @@ import { BrowserModule, By } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { TaskanaEngineService } from '../../services/taskana-engine/taskana-engine.service';
import { TaskanaEngineServiceMock } from '../../services/taskana-engine/taskana-engine.mock.service';
import { of } from 'rxjs/internal/observable/of';
import { HttpClientTestingModule } from '@angular/common/http/testing';
const TaskanaEngingeServiceSpy = jest.fn().mockImplementation(
(): Partial<TaskanaEngineServiceMock> => ({
hasRole: jest.fn().mockReturnValue(of()),
isHistoryProviderEnabled: jest.fn().mockReturnValue(of())
})
);
jest.mock('angular-svg-icon');
@Component({ selector: 'svg-icon', template: '' })
class SvgIconStub {}
class SvgIconStub {
@Input() src;
@Input() matTooltip;
}
describe('UserInformationComponent', () => {
let component: UserInformationComponent;
@ -27,7 +24,7 @@ describe('UserInformationComponent', () => {
TestBed.configureTestingModule({
declarations: [UserInformationComponent, SvgIconStub],
imports: [BrowserModule, HttpClientTestingModule, BrowserAnimationsModule],
providers: [{ provide: TaskanaEngineService, useClass: TaskanaEngingeServiceSpy }]
providers: [{ provide: TaskanaEngineService, useClass: TaskanaEngineServiceMock }]
}).compileComponents();
}));

View File

@ -1,7 +1,6 @@
@import 'src/theme/_colors.scss';
.filter {
&__collapsed-filter {
display: flex;
height: 36px;
@ -46,4 +45,3 @@
justify-content: space-between;
}
}

View File

@ -13,8 +13,8 @@ describe('ClassificationCategoriesService', () => {
providers: [ClassificationCategoriesService]
});
categoryService = TestBed.get(ClassificationCategoriesService);
httpMock = TestBed.get(HttpTestingController);
categoryService = TestBed.inject(ClassificationCategoriesService);
httpMock = TestBed.inject(HttpTestingController);
});
it('should insert missing icon into customisation', async(() => {

View File

@ -12,7 +12,9 @@ import { asUrlQueryString } from '../../util/query-parameters-v2';
import { ClassificationQueryFilterParameter } from '../../models/classification-query-filter-parameter';
import { QueryPagingParameter } from '../../models/query-paging-parameter';
@Injectable()
@Injectable({
providedIn: 'root'
})
export class ClassificationsService {
constructor(
private httpClient: HttpClient,

View File

@ -5,7 +5,7 @@ import { BehaviorSubject, Observable } from 'rxjs';
@Injectable()
export class OrientationService {
private lock = false;
private currentOrientation;
private currentOrientation = Orientation.landscape;
public orientation = new BehaviorSubject<Orientation>(this.currentOrientation);
private static detectOrientation(): Orientation {

View File

@ -28,9 +28,9 @@ describe('StartupService', () => {
beforeEach(() => {
const injector = getTestBed();
httpMock = injector.get(HttpTestingController);
httpMock = injector.inject(HttpTestingController);
// UserService provided to the TestBed
service = TestBed.get(StartupService);
service = injector.inject(StartupService);
});
it('should be created', inject([StartupService], () => {

View File

@ -16,7 +16,9 @@ import { WorkbasketQueryFilterParameter } from '../../models/workbasket-query-fi
import { QueryPagingParameter } from '../../models/query-paging-parameter';
import { asUrlQueryString } from '../../util/query-parameters-v2';
@Injectable()
@Injectable({
providedIn: 'root'
})
export class WorkbasketService {
public workBasketSelected = new Subject<string>();
public workBasketSaved = new Subject<number>();

View File

@ -1,16 +1,15 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
import { AngularSvgIconModule } from 'angular-svg-icon';
import { RouterModule } from '@angular/router';
import { TreeModule } from 'angular-tree-component';
import { AlertModule, TypeaheadModule } from 'ngx-bootstrap';
import { TreeModule } from '@circlon/angular-tree-component';
import { AlertModule } from 'ngx-bootstrap/alert';
import { TypeaheadModule } from 'ngx-bootstrap/typeahead';
import { BsDatepickerModule } from 'ngx-bootstrap/datepicker';
import { AccordionModule } from 'ngx-bootstrap/accordion';
import { WorkbasketService } from 'app/shared/services/workbasket/workbasket.service';
import { ClassificationsService } from 'app/shared/services/classifications/classifications.service';
/**
* Components
@ -44,7 +43,6 @@ import { DateTimeZonePipe } from './pipes/date-time-zone.pipe';
* Services
*/
import { HttpClientInterceptor } from './services/http-client-interceptor/http-client-interceptor.service';
import { AccessIdsService } from './services/access-ids/access-ids.service';
import { ToastComponent } from './components/toast/toast.component';
import { DialogPopUpComponent } from './components/popup/dialog-pop-up.component';
import { MatFormFieldModule } from '@angular/material/form-field';
@ -72,7 +70,7 @@ const MODULES = [
MatDialogModule,
MatButtonModule,
RouterModule,
TreeModule.forRoot(),
TreeModule,
MatAutocompleteModule
];
@ -120,11 +118,8 @@ const DECLARATIONS = [
provide: HTTP_INTERCEPTORS,
useClass: HttpClientInterceptor,
multi: true
},
AccessIdsService,
ClassificationsService,
WorkbasketService
}
],
entryComponents: [ToastComponent, DialogPopUpComponent]
entryComponents: [DialogPopUpComponent, ToastComponent]
})
export class SharedModule {}

View File

@ -13,11 +13,13 @@ import { NOTIFICATION_TYPES } from '../../models/notifications';
import { NotificationService } from '../../services/notifications/notification.service';
import { WorkbasketAccessItemsRepresentation } from '../../models/workbasket-access-items-representation';
import { RequestInProgressService } from '../../services/request-in-progress/request-in-progress.service';
import { Injectable } from '@angular/core';
class InitializeStore {
static readonly type = '[Access Items Management] Initializing state';
}
@Injectable()
@State<AccessItemsManagementStateModel>({ name: 'accessItemsManagement' })
export class AccessItemsManagementState implements NgxsAfterBootstrap {
constructor(

View File

@ -25,11 +25,13 @@ import { Classification } from '../../models/classification';
import { ClassificationSummary } from '../../models/classification-summary';
import { ClassificationQueryFilterParameter } from '../../models/classification-query-filter-parameter';
import { ClassificationQuerySortParameter, Direction, Sorting } from '../../models/sorting';
import { Injectable } from '@angular/core';
class InitializeStore {
static readonly type = '[ClassificationState] Initializing state';
}
@Injectable()
@State<ClassificationStateModel>({ name: 'classification' })
export class ClassificationState implements NgxsAfterBootstrap {
constructor(

View File

@ -3,11 +3,12 @@ import { State, NgxsOnInit, StateContext, Action } from '@ngxs/store';
import { ClassificationCategoriesService } from 'app/shared/services/classification-categories/classification-categories.service';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';
import { Injectable } from '@angular/core';
class InitializeStore {
static readonly type = '[EngineConfigurationState] Initializing state';
}
@Injectable()
@State<EngineConfigurationStateModel>({ name: 'engineConfiguration' })
export class EngineConfigurationState implements NgxsOnInit {
constructor(private categoryService: ClassificationCategoriesService) {}

View File

@ -38,11 +38,13 @@ import { WorkbasketType } from '../../models/workbasket-type';
import { TaskanaDate } from '../../util/taskana.date';
import { DomainService } from '../../services/domain/domain.service';
import { ClearWorkbasketFilter } from '../filter-store/filter.actions';
import { Injectable } from '@angular/core';
class InitializeStore {
static readonly type = '[Workbasket] Initializing state';
}
@Injectable()
@State<WorkbasketStateModel>({ name: 'workbasket' })
export class WorkbasketState implements NgxsAfterBootstrap {
constructor(

View File

@ -1,4 +1,4 @@
import { saveAs } from 'file-saver/FileSaver';
import { saveAs } from 'file-saver';
export class BlobGenerator {
public static saveFile(object: Object, fileName: string) {

View File

@ -1,6 +1,7 @@
@import 'src/theme/_colors.scss';
.task-attribute-value {
line-height: 1.5;
&__button--primary {
background-color: $aquamarine;
@ -58,9 +59,12 @@
padding: 0;
}
::ng-deep .task-attribute-value__column--inputs > .mat-form-field-appearance-outline > div.mat-form-field-wrapper > div.mat-form-field-flex > div.mat-form-field-infix {
::ng-deep
.task-attribute-value__column--inputs
> .mat-form-field-appearance-outline
> div.mat-form-field-wrapper
> div.mat-form-field-flex
> div.mat-form-field-infix {
border-top-width: 0;
height: 40px;
}

View File

@ -13,6 +13,7 @@
&__input {
width: 100%;
margin-top: 0.7em;
}
&__spacer {

View File

@ -11,7 +11,7 @@
width: 100%;
display: grid;
grid-template-rows: 1fr 1fr;
grid-template-columns: 1fr ;
grid-template-columns: 1fr;
}
&__badge-message {
@ -58,6 +58,7 @@
&__task-name {
font-size: 1.5rem;
font-weight: 500;
padding: 0 0.5rem 0.5rem 0.5rem;
overflow: hidden;
text-overflow: ellipsis;
@ -65,6 +66,7 @@
grid-area: 2/1;
grid-column-start: 1;
grid-column-end: 2;
margin: 0;
}
&__tab-group-wrapper {

View File

@ -21,3 +21,7 @@
justify-content: space-between;
}
}
::ng-deep .task-information .mat-form-field {
margin-top: 0.7rem;
}

View File

@ -39,7 +39,13 @@
}
}
::ng-deep .task-list-toolbar > .mat-tab-group > .mat-tab-header > .mat-tab-label-container > .mat-tab-list > .mat-tab-labels {
::ng-deep
.task-list-toolbar
> .mat-tab-group
> .mat-tab-header
> .mat-tab-label-container
> .mat-tab-list
> .mat-tab-labels {
background-color: $light-grey;
}

View File

@ -1,7 +1,6 @@
@import 'src/theme/_colors.scss';
.task-list {
&__task {
display: flex;
}
@ -18,12 +17,11 @@
}
}
p {
margin: 0;
overflow: hidden;
text-overflow: ellipsis;
line-height: 1.5;
}
.mat-list-item {
@ -48,4 +46,3 @@ p {
right: 16px;
background-color: $green;
}

View File

@ -51,4 +51,3 @@ iframe {
border: none;
overflow-x: scroll;
}

View File

@ -16,6 +16,9 @@
}
}
.task-status-details .mat-form-field {
margin-top: 0.7rem;
}
.mat-input-element:disabled {
color: gray;

View File

@ -3,7 +3,8 @@ import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
import { AngularSvgIconModule } from 'angular-svg-icon';
import { AlertModule, TypeaheadModule } from 'ngx-bootstrap';
import { AlertModule } from 'ngx-bootstrap/alert';
import { TypeaheadModule } from 'ngx-bootstrap/typeahead';
import { AccordionModule } from 'ngx-bootstrap/accordion';
import { BsDropdownModule } from 'ngx-bootstrap/dropdown';
import { SharedModule } from 'app/shared/shared.module';

View File

@ -1,5 +1,4 @@
@import '../../node_modules/angular-tree-component/dist/angular-tree-component.css';
@import 'bootstrap-3-backward-compatibility';
@import '../../node_modules/@circlon/angular-tree-component/css/angular-tree-component.css';
@import 'variables';
@import 'material_styles';
@ -14,3 +13,5 @@
@import 'mixin/colors';
@import 'progress-bar';
@import 'shameful';
@import 'bootstrap-replacement';

View File

@ -1,3 +1,7 @@
* {
font-family: Roboto, 'Helvetica Neue', sans-serif;
}
.placeholder img {
display: inline-block;
border-radius: 50%;

View File

@ -1,11 +0,0 @@
.dropdown-menu.show,
.modal-backdrop.show,
.fade.show {
display: block;
opacity: 1;
visibility: visible;
}
.modal.fade .modal-dialog {
transform: translate(0, 0);
}

View File

@ -0,0 +1,43 @@
/* * * * * * * * IMPORTANT * * * * * *
PLEASE DO NOT USE
This CSS was created to easily get rid of bootstrap while keeping most of the layout intact
These classes should be replaced and migrated to either component level or global styling
* * * * * * * * * * * * * * * * * * */
h3 {
font-size: 1.75rem;
font-weight: 500;
margin-bottom: 0.5rem;
line-height: 1.2;
}
h4 {
font-size: 1.5rem;
font-weight: 500;
margin-bottom: 0.5rem;
margin-top: 0;
line-height: 1.2;
}
h6 {
font-size: 1rem;
margin: 0;
}
.mr-1,
.mx-1 {
margin-right: 0.25rem !important;
}
*,
:after,
:before {
box-sizing: border-box;
}
img,
svg {
vertical-align: middle;
}

View File

@ -2,7 +2,7 @@
"compileOnSave": false,
"compilerOptions": {
"downlevelIteration": true,
"module": "esnext",
"module": "es2020",
"outDir": "./dist/out-tsc",
"baseUrl": "src",
"sourceMap": true,

View File

@ -5,12 +5,7 @@ module.exports = {
plugins: [
new CompressionPlugin({
test: /\.(js|css|html|svg|txt|eot|otf|ttf|gif)$/,
filename(info) {
let opFile = info.path.split('.'),
opFileType = opFile.pop(),
opFileName = opFile.join('.');
return `${opFileName}.${opFileType}.gzip`;
}
filename: '[name][ext].gzip'
})
]
};

10877
web/yarn.lock Normal file

File diff suppressed because it is too large Load Diff