-
+
-
-
-
+
+
+
+
-
-
+
General
+
-
-
+
+ Key
+
+
+
+
{{lengthError}}
+
-
-
-
-
+
+
+ Name
+
+
+
+
{{lengthError}}
+
-
-
-
-
+
+
+
+ Service Level
+
+
+
+
{{lengthError}}
+
+
+
+
+ Priority
+
+
+
+
+
+
-
-
+
+
+
+
+
+ Domain
+
+
+
+
+
+
+
+ Category
+
+
+
+
+ {{this.classification.category}}
+
+
+
+ {{category}}
+
+
+
+
+
+
+
+
+ Application entry point
+
+
+
+
{{lengthError}}
+
+
+
+ Description
+
+
+
+
{{lengthError}}
+
+
-
+
diff --git a/web/src/app/administration/components/classification-details/classification-details.component.scss b/web/src/app/administration/components/classification-details/classification-details.component.scss
index 3e435f07c..be6a2fd56 100644
--- a/web/src/app/administration/components/classification-details/classification-details.component.scss
+++ b/web/src/app/administration/components/classification-details/classification-details.component.scss
@@ -1,22 +1,114 @@
@import 'src/theme/_colors.scss';
-.custom-field-row {
- display: flex;
- flex-wrap: wrap;
- flex-direction: column;
- height: 40vh;
+.classification-details {
width: 100%;
- margin: 0;
+ height: calc(100vh - 100px);
+ overflow-y: auto;
}
-.custom-field-wrapper {
- height: 70px;
- padding: 0 15px;
+.classification-details__wrapper {
+ position: relative;
}
-.dropdown-menu > li {
+
+
+/* ACTION TOOLBAR */
+.classification-details__headline {
+ padding-top: 0.5rem;
+}
+.classification-details__action-toolbar {
+ width: calc(100% - 450px);
+ position: fixed;
+ padding: 12px 32px 12px 24px;
+ background-color: #fff;
+ display: flex;
+ box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06);
+ justify-content: space-between;
+ flex-wrap: wrap;
+ z-index: 10;
+}
+
+.action-toolbar__button {
+ margin-top: 0.25rem;
+ margin-right: 6px;
+ background-color: #fff;
+}
+
+.action-toolbar__dropdown {
+ border-color: $transparent-grey;
+ border-bottom-style: solid;
+ border-width: 1px;
+}
+
+.action-toolbar__save-button {
+ background-color: $aquamarine;
+ color: white;
+}
+
+.button__green-blue {
+ color: $aquamarine;
+}
+
+.button__red {
+ color: $invalid;
+}
+
+
+/* DETAILED FIELDS */
+
+.classification__detailed-fields {
+ padding: 15px;
+ display: flex;
+ flex-direction: column;
+}
+
+.classification-details__subheading {
+ font-weight: bold;
+ padding-left: 15px;
+ margin-bottom: 0;
+}
+
+.classification-details__horizontal-line {
+ margin: 5px 5px 25px 5px;
+ border-top-color: #555;
+ border-top-width: 1.35px;
+}
+
+.classification-details__domain-and-category {
+ position: relative;
+ display: flex;
+ justify-content: space-between;
+ padding-bottom: 16px;
+}
+
+.domain-and-category__domain-checkbox {
+ position: absolute;
+ top: 64px;
+ left: 12px;
+ font-size: 14px;
+ color: #555;
+}
+.domain-and-category__domain-checkbox-icon {
cursor: pointer;
+ margin-top: 2px;
+ font-size: 20px;
+}
+.domain-and-category__category-icon {
+ fill: #555;
+ margin-right: 5px;
+ top: -2px;
+}
+
+.classification-details__service-and-priority {
+ display: flex;
+ justify-content: space-between;
+}
+
+.classification-details__mat-form-field {
+ width: 70%;
+ margin-right: 10px;
}
input:invalid.dirty {
border-color: $invalid;
}
+
diff --git a/web/src/app/administration/components/classification-details/classification-details.component.spec.ts b/web/src/app/administration/components/classification-details/classification-details.component.spec.ts
index 2713daf7f..98b544aa3 100644
--- a/web/src/app/administration/components/classification-details/classification-details.component.spec.ts
+++ b/web/src/app/administration/components/classification-details/classification-details.component.spec.ts
@@ -4,7 +4,7 @@ import { Observable, of } from 'rxjs';
import { ClassificationCategoriesService } from '../../../shared/services/classification-categories/classification-categories.service';
import { DomainService } from '../../../shared/services/domain/domain.service';
import { ImportExportService } from '../../services/import-export.service';
-import { async, ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { Actions, NgxsModule, ofActionDispatched, Store } from '@ngxs/store';
import { ClassificationState } from '../../../shared/store/classification-store/classification.state';
import { EngineConfigurationState } from '../../../shared/store/engine-configuration-store/engine-configuration.state';
@@ -13,9 +13,6 @@ import { ClassificationDetailsComponent } from './classification-details.compone
import { FormsModule } from '@angular/forms';
import { RequestInProgressService } from '../../../shared/services/request-in-progress/request-in-progress.service';
import { FormsValidatorService } from '../../../shared/services/forms-validator/forms-validator.service';
-import { MatSnackBarModule } from '@angular/material/snack-bar';
-import { MatDialogModule } from '@angular/material/dialog';
-import { NumberPickerComponent } from '../../../shared/components/number-picker/number-picker.component';
import { NotificationService } from '../../../shared/services/notifications/notification.service';
import {
CopyClassification,
@@ -24,6 +21,15 @@ import {
SaveCreatedClassification,
SaveModifiedClassification
} from '../../../shared/store/classification-store/classification.actions';
+import { MatIconModule } from '@angular/material/icon';
+import { MatDividerModule } from '@angular/material/divider';
+import { MatFormFieldModule } from '@angular/material/form-field';
+import { MatOptionModule } from '@angular/material/core';
+import { MatSelectModule } from '@angular/material/select';
+import { MatMenuModule } from '@angular/material/menu';
+import { MatInputModule } from '@angular/material/input';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+import { By } from '@angular/platform-browser';
@Component({ selector: 'taskana-shared-spinner', template: '' })
class SpinnerStub {
@@ -116,15 +122,20 @@ describe('ClassificationDetailsComponent', () => {
imports: [
NgxsModule.forRoot([ClassificationState, EngineConfigurationState]),
FormsModule,
- MatSnackBarModule,
- MatDialogModule
+ MatIconModule,
+ MatDividerModule,
+ MatFormFieldModule,
+ MatInputModule,
+ MatOptionModule,
+ MatSelectModule,
+ MatMenuModule,
+ BrowserAnimationsModule
],
declarations: [
ClassificationDetailsComponent,
SpinnerStub,
InputStub,
FieldErrorDisplayStub,
- NumberPickerComponent,
SvgIconStub,
TextareaStub
],
@@ -247,7 +258,7 @@ describe('ClassificationDetailsComponent', () => {
component.spinnerIsRunning = true;
component.classification = {};
fixture.detectChanges();
- expect(debugElement.nativeElement.querySelector('.classification__menu-bar')).toBeFalsy();
+ expect(debugElement.nativeElement.querySelector('.classification-details__action-toolbar')).toBeFalsy();
expect(debugElement.nativeElement.querySelector('.classification__detailed-fields')).toBeFalsy();
});
@@ -255,12 +266,12 @@ describe('ClassificationDetailsComponent', () => {
component.spinnerIsRunning = false;
component.classification = null;
fixture.detectChanges();
- expect(debugElement.nativeElement.querySelector('.classification__menu-bar')).toBeFalsy();
+ expect(debugElement.nativeElement.querySelector('.classification-details__action-toolbar')).toBeFalsy();
expect(debugElement.nativeElement.querySelector('.classification__detailed-fields')).toBeFalsy();
});
it('should show details when classification exists and spinner is not running', () => {
- expect(debugElement.nativeElement.querySelector('.classification__menu-bar')).toBeTruthy();
+ expect(debugElement.nativeElement.querySelector('.classification-details__action-toolbar')).toBeTruthy();
expect(debugElement.nativeElement.querySelector('.classification__detailed-fields')).toBeTruthy();
});
@@ -269,7 +280,7 @@ describe('ClassificationDetailsComponent', () => {
component.classification = { name: 'Recommendation', type: 'DOCUMENT' };
component.isCreatingNewClassification = true;
fixture.detectChanges();
- const headline = debugElement.nativeElement.querySelector('.classification__headline');
+ const headline = debugElement.nativeElement.querySelector('.classification-details__headline');
expect(headline).toBeTruthy();
expect(headline.textContent).toContain('Recommendation');
expect(headline.textContent).toContain('DOCUMENT');
@@ -278,19 +289,22 @@ describe('ClassificationDetailsComponent', () => {
expect(badgeMessage.textContent.trim()).toBe('Creating new classification');
});
- it('should call onSubmit() when button is clicked', () => {
- const button = debugElement.nativeElement.querySelector('.classification__menu-bar').children[0];
+ it('should call onSubmit() when button is clicked', async () => {
+ const button = debugElement.nativeElement.querySelector('.action-toolbar__save-button');
expect(button).toBeTruthy();
- expect(button.title).toBe('Save');
+ expect(button.textContent).toContain('Save');
+ expect(button.textContent).toContain('save');
component.onSubmit = jest.fn().mockImplementation();
button.click();
expect(component.onSubmit).toHaveBeenCalled();
});
it('should restore selected classification when button is clicked', async () => {
- const button = debugElement.nativeElement.querySelector('.classification__menu-bar').children[1];
+ const button = debugElement.nativeElement.querySelector('.classification-details__action-toolbar').children[1]
+ .children[1];
expect(button).toBeTruthy();
- expect(button.title).toBe('Restore Previous Version');
+ expect(button.textContent).toContain('Undo Changes');
+ expect(button.textContent).toContain('restore');
let isActionDispatched = false;
actions$.pipe(ofActionDispatched(RestoreSelectedClassification)).subscribe(() => (isActionDispatched = true));
@@ -298,22 +312,39 @@ describe('ClassificationDetailsComponent', () => {
expect(isActionDispatched).toBe(true);
});
- it('should call onCopy() when button is clicked', () => {
- const button = debugElement.nativeElement.querySelector('.classification__menu-bar').children[2];
+ it('should display button to show more actions', () => {
+ const button = debugElement.nativeElement.querySelector('#action-toolbar__more-buttons');
expect(button).toBeTruthy();
- expect(button.title).toBe('Copy');
- component.onCopy = jest.fn().mockImplementation();
button.click();
+ fixture.detectChanges();
+ const buttonsInDropdown = debugElement.queryAll(By.css('.action-toolbar__dropdown'));
+ expect(buttonsInDropdown.length).toEqual(3);
+ });
+
+ it('should call onCopy() when button is clicked', () => {
+ const button = debugElement.nativeElement.querySelector('#action-toolbar__more-buttons');
+ expect(button).toBeTruthy();
+ button.click();
+ fixture.detectChanges();
+ const copyButton = debugElement.queryAll(By.css('.action-toolbar__dropdown'))[0];
+ expect(copyButton.nativeElement.textContent).toContain('content_copy');
+ expect(copyButton.nativeElement.textContent).toContain('Copy');
+ component.onCopy = jest.fn().mockImplementation();
+ copyButton.nativeElement.click();
expect(component.onCopy).toHaveBeenCalled();
});
it('should call onRemoveClassification() when button is clicked', () => {
- const button = debugElement.nativeElement.querySelector('.classification__menu-bar').children[3];
+ const button = debugElement.nativeElement.querySelector('#action-toolbar__more-buttons');
expect(button).toBeTruthy();
- expect(button.title).toBe('Delete');
+ button.click();
+ fixture.detectChanges();
+ const deleteButton = debugElement.queryAll(By.css('.action-toolbar__dropdown'))[1];
+ expect(deleteButton.nativeElement.textContent).toContain('delete');
+ expect(deleteButton.nativeElement.textContent).toContain('Delete');
const onRemoveClassificationSpy = jest.spyOn(component, 'onRemoveClassification');
- button.click();
+ deleteButton.nativeElement.click();
expect(onRemoveClassificationSpy).toHaveBeenCalled();
onRemoveClassificationSpy.mockReset();
@@ -323,27 +354,54 @@ describe('ClassificationDetailsComponent', () => {
expect(showDialogSpy).toHaveBeenCalled();
});
+ it('should call onClose() when button is clicked', () => {
+ const button = debugElement.nativeElement.querySelector('#action-toolbar__more-buttons');
+ expect(button).toBeTruthy();
+ button.click();
+ fixture.detectChanges();
+ const closeButton = debugElement.queryAll(By.css('.action-toolbar__dropdown'))[2];
+ expect(closeButton.nativeElement.textContent).toContain('close');
+ expect(closeButton.nativeElement.textContent).toContain('close');
+ component.onCloseClassification = jest.fn().mockImplementation();
+ closeButton.nativeElement.click();
+ expect(component.onCloseClassification).toHaveBeenCalled();
+ });
+
/* DETAILED FIELDS */
it('should display field-error-display component', () => {
expect(debugElement.nativeElement.querySelector('taskana-shared-field-error-display')).toBeTruthy();
});
- it('should display number-picker component', () => {
- expect(debugElement.nativeElement.querySelector('taskana-shared-number-picker')).toBeTruthy();
+ it('should display form field for key', () => {
+ expect(debugElement.nativeElement.querySelector('#classification-key')).toBeTruthy();
});
- it('should select category when button is clicked', () => {
- component.classification.category = 'A';
- component.getAvailableCategories = jest.fn().mockImplementation((type) => of(['B', 'C']));
- fixture.detectChanges();
- const button = debugElement.nativeElement.querySelector('.detailed-fields__categories');
- expect(button).toBeTruthy();
- button.click();
- expect(component.classification.category).toBe('B');
+ it('should display form field for name', () => {
+ expect(debugElement.nativeElement.querySelector('#classification-name')).toBeTruthy();
+ });
+
+ it('should display form field for service level', () => {
+ expect(debugElement.nativeElement.querySelector('#classification-service-level')).toBeTruthy();
+ });
+
+ it('should display form field for priority', () => {
+ expect(debugElement.nativeElement.querySelector('#classification-priority')).toBeTruthy();
+ });
+
+ it('should display form field for domain', () => {
+ expect(debugElement.nativeElement.querySelector('#classification-domain')).toBeTruthy();
+ });
+
+ it('should display form field for application entry point', () => {
+ expect(debugElement.nativeElement.querySelector('#classification-application-entry-point')).toBeTruthy();
+ });
+
+ it('should display form field for description', () => {
+ expect(debugElement.nativeElement.querySelector('#classification-description')).toBeTruthy();
});
it('should change isValidInDomain when button is clicked', () => {
- const button = debugElement.nativeElement.querySelector('.detailed-fields__domain').children[2];
+ const button = debugElement.nativeElement.querySelector('.domain-and-category__domain-checkbox-icon').parentNode;
expect(button).toBeTruthy();
component.classification.isValidInDomain = false;
button.click();
diff --git a/web/src/app/administration/components/classification-details/classification-details.component.ts b/web/src/app/administration/components/classification-details/classification-details.component.ts
index 4829ffcae..7c75bac35 100644
--- a/web/src/app/administration/components/classification-details/classification-details.component.ts
+++ b/web/src/app/administration/components/classification-details/classification-details.component.ts
@@ -28,7 +28,8 @@ import {
RestoreSelectedClassification,
SaveModifiedClassification,
SelectClassification,
- CopyClassification
+ CopyClassification,
+ DeselectClassification
} from '../../../shared/store/classification-store/classification.actions';
@Component({
@@ -43,7 +44,6 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
@Select(ClassificationSelectors.selectCategories) categories$: Observable
;
@Select(EngineConfigurationSelectors.selectCategoryIcons) categoryIcons$: Observable;
@Select(ClassificationSelectors.selectedClassificationType) selectedClassificationType$: Observable;
- @Select(ClassificationSelectors.selectClassificationTypesObject) classificationTypes$: Observable;
@Select(ClassificationSelectors.selectedClassification) selectedClassification$: Observable;
@Select(ClassificationSelectors.getBadgeMessage) badgeMessage$: Observable;
@@ -127,8 +127,8 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
}
}
- selectCategory(category: string) {
- this.classification.category = category;
+ onCloseClassification() {
+ this.store.dispatch(new DeselectClassification());
}
getCategoryIcon(category: string): Observable {
@@ -157,13 +157,6 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
return `custom${customNumber}`;
}
- getAvailableCategories(type: string): Observable {
- return this.classificationTypes$.pipe(
- take(1),
- map((classTypes) => classTypes[type])
- );
- }
-
async onSave() {
this.requestInProgressService.setRequestInProgress(true);
if (typeof this.classification.classificationId === 'undefined') {
diff --git a/web/src/app/administration/components/classification-list/classification-list.component.html b/web/src/app/administration/components/classification-list/classification-list.component.html
index 5d864668d..ce4a96596 100644
--- a/web/src/app/administration/components/classification-list/classification-list.component.html
+++ b/web/src/app/administration/components/classification-list/classification-list.component.html
@@ -1,63 +1,73 @@
-
+
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
+
+
+
+
-
+
+
+
+
+
-
-
-
-
-
-
There are no classifications
-
-
-
+
+
+ Filter classification
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
There are no classifications
+
+
diff --git a/web/src/app/administration/components/classification-list/classification-list.component.scss b/web/src/app/administration/components/classification-list/classification-list.component.scss
index d5850021b..5da580153 100644
--- a/web/src/app/administration/components/classification-list/classification-list.component.scss
+++ b/web/src/app/administration/components/classification-list/classification-list.component.scss
@@ -1,38 +1,53 @@
-.classification-list-full-height {
+@import 'src/theme/_colors.scss';
+
+.classification-list {
height: calc(100vh - 55px);
+ width: 450px;
}
-
-.list-group-item {
- padding: 5px 0px 2px 1px;
+.classification-list__action-toolbar {
+ padding: 0 16px;
+ min-height: 68px;
+ box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06);
+}
+.classification-list__action-buttons {
+ display: flex;
border: none;
+ margin-bottom: 0;
+ padding: 16px 4px 8px 4px;
+}
+.action-toolbar__add-button {
+ background-color: $aquamarine;
+ color: white;
}
-.tab-align {
- margin-bottom: 0px;
- border-bottom: 1px dotted #ddd;
- padding: 8px 12px 8px 4px;
- & > div {
- margin: 6px 0px;
- }
+.classification-list__import-export {
+ display: flex;
+}
+.classification-list__filter {
+ display: flex;
}
-input.filter-input {
- border: solid 1px grey;
- margin: 10px 2px;
- height: 32px;
+.classification-list__category-filter {
+ padding-top: 7px;
+}
+.category-filter__icons {
+ height: 33px;
+ width: 16px;
+}
+.category-filter__categories {
+ fill: #555;
+ margin: 0;
+ top: -2px;
+}
+
+.filter__input {
width: 100%;
- padding-left: 10px;
+ margin-right: 12px;
}
-
-.category-filter {
- margin: 7px 2px;
+.filter__input-field {
+ width: 100% !important;
}
-
-.dropdown-menu-classification {
- margin-left: 15px;
- min-width: 0px;
-}
-
-div.category-filter svg-icon {
- position: initial;
+.classification-list__no-items {
+ text-align: center;
+ padding-top: 150px;
}
diff --git a/web/src/app/administration/components/classification-list/classification-list.component.spec.ts b/web/src/app/administration/components/classification-list/classification-list.component.spec.ts
index ce666fdb2..e55b90125 100644
--- a/web/src/app/administration/components/classification-list/classification-list.component.spec.ts
+++ b/web/src/app/administration/components/classification-list/classification-list.component.spec.ts
@@ -12,6 +12,12 @@ import { ImportExportService } from '../../services/import-export.service';
import { Observable, of } from 'rxjs';
import { CreateClassification } from '../../../shared/store/classification-store/classification.actions';
import { EngineConfigurationState } from '../../../shared/store/engine-configuration-store/engine-configuration.state';
+import { MatIconModule } from '@angular/material/icon';
+import { MatMenuModule } from '@angular/material/menu';
+import { MatFormFieldModule } from '@angular/material/form-field';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+import { MatInputModule } from '@angular/material/input';
+import { By } from '@angular/platform-browser';
@Component({ selector: 'taskana-administration-import-export', template: '' })
class ImportExportStub {
@@ -76,7 +82,14 @@ describe('ClassificationListComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
- imports: [NgxsModule.forRoot([ClassificationState, EngineConfigurationState])],
+ imports: [
+ NgxsModule.forRoot([ClassificationState, EngineConfigurationState]),
+ MatIconModule,
+ MatMenuModule,
+ MatFormFieldModule,
+ MatInputModule,
+ BrowserAnimationsModule
+ ],
declarations: [
ClassificationListComponent,
ClassificationTypesSelectorStub,
@@ -113,7 +126,7 @@ describe('ClassificationListComponent', () => {
/* HTML: ACTION TOOLBAR */
it('should call CreateClassification when add-classification button is clicked', async () => {
- const button = debugElement.nativeElement.querySelector('.add-classification-button');
+ const button = debugElement.nativeElement.querySelector('.action-toolbar__add-button');
expect(button).toBeTruthy();
let actionDispatched = false;
actions$.pipe(ofActionDispatched(CreateClassification)).subscribe(() => (actionDispatched = true));
@@ -125,7 +138,9 @@ describe('ClassificationListComponent', () => {
expect(debugElement.nativeElement.querySelector('taskana-administration-import-export')).toBeTruthy();
});
- it('should display classification-types-selector component', () => {
+ it('should display classification-types-selector component when showFilter is true', () => {
+ component.showFilter = true;
+ fixture.detectChanges();
const typesSelectorComponent = debugElement.nativeElement.querySelector(
'taskana-administration-classification-types-selector'
);
@@ -133,31 +148,43 @@ describe('ClassificationListComponent', () => {
});
/* HTML: FILTER */
- it('should display specific icon when selectedCategory is true', () => {
- component.selectedCategory = 'EXTERNAL';
+ it('should display filter input field when showFilter is true', () => {
+ component.showFilter = true;
fixture.detectChanges();
- expect(debugElement.nativeElement.querySelector('.selected-category')).toBeTruthy();
+ const button = debugElement.nativeElement.querySelector('.filter__input-field');
+ expect(button).toBeTruthy();
+ expect(button.textContent).toBe('Filter classification');
});
- it('should display universal icon for categories when selectedCategory is false', () => {
- expect(debugElement.nativeElement.querySelector('svg-icon.no-selected-category')).toBeTruthy();
+ it('should display filter button when showFilter is true', () => {
+ component.showFilter = true;
+ fixture.detectChanges();
+ const button = debugElement.nativeElement.querySelector('.category-filter__filter-button');
+ expect(button).toBeTruthy();
+ expect(button.textContent).toBe('filter_list');
});
it('should change selectedCategory property when button is clicked', () => {
+ component.showFilter = true;
+ fixture.detectChanges();
+ const filterButton = debugElement.nativeElement.querySelector('.category-filter__filter-button');
+ filterButton.click();
+ fixture.detectChanges();
component.selectedCategory = 'EXTERNAL';
- const button = debugElement.nativeElement.querySelector('.category-all');
- button.click();
+ const allButton = debugElement.query(By.css('.category-filter__all-button'));
+ expect(allButton).toBeTruthy();
+ allButton.nativeElement.click();
expect(component.selectedCategory).toBe('');
});
it('should display list of categories which can be selected', () => {
- expect(debugElement.nativeElement.querySelector('.category-all').textContent.trim()).toBe('All');
-
- const categories = fixture.debugElement.nativeElement.getElementsByClassName('category-list');
- expect(categories.length).toBe(3);
- expect(categories[0].textContent.trim()).toBe('EXTERNAL');
- expect(categories[1].textContent.trim()).toBe('MANUAL');
- expect(categories[2].textContent.trim()).toBe('AUTOMATIC');
+ component.showFilter = true;
+ fixture.detectChanges();
+ const filterButton = debugElement.nativeElement.querySelector('.category-filter__filter-button');
+ filterButton.click();
+ fixture.detectChanges();
+ const matMenu = debugElement.queryAll(By.css('.category-filter__categories'));
+ expect(matMenu.length).toBe(4);
});
/* HTML: CLASSIFICATION TREE */
@@ -172,10 +199,9 @@ describe('ClassificationListComponent', () => {
});
it('should display icon and text when no classifications exist', () => {
- const noClassifications = debugElement.nativeElement.querySelector('.no-classifications');
- expect(noClassifications.childNodes.length).toBe(2);
+ const noClassifications = debugElement.nativeElement.querySelector('.classification-list__no-items');
+ expect(noClassifications.childNodes.length).toBe(1);
expect(noClassifications.childNodes[0].textContent).toBe('There are no classifications');
- expect(noClassifications.childNodes[1].tagName).toBe('SVG-ICON');
});
/* TS: getCategoryIcon() */
diff --git a/web/src/app/administration/components/classification-list/classification-list.component.ts b/web/src/app/administration/components/classification-list/classification-list.component.ts
index 8595be053..1cfa96dea 100644
--- a/web/src/app/administration/components/classification-list/classification-list.component.ts
+++ b/web/src/app/administration/components/classification-list/classification-list.component.ts
@@ -29,6 +29,7 @@ export class ClassificationListComponent implements OnInit, OnDestroy {
requestInProgress = true;
inputValue: string;
selectedCategory = '';
+ showFilter = false;
@Select(ClassificationSelectors.classificationTypes) classificationTypes$: Observable
;
@Select(ClassificationSelectors.selectedClassificationType) classificationTypeSelected$: Observable;
@@ -85,18 +86,25 @@ export class ClassificationListComponent implements OnInit, OnDestroy {
this.location.go(this.location.path().replace(/(classifications).*/g, 'classifications/new-classification'));
}
+ getCategoryIcon(category: string): Observable {
+ return this.categoryIcons$.pipe(
+ map((iconMap) => {
+ if (category === '') {
+ return new Pair(iconMap['all'], 'All');
+ }
+ return iconMap[category]
+ ? new Pair(iconMap[category], category)
+ : new Pair(iconMap.missing, 'Category does not match with the configuration');
+ })
+ );
+ }
+
selectCategory(category: string) {
this.selectedCategory = category;
}
- getCategoryIcon(category: string): Observable {
- return this.categoryIcons$.pipe(
- map((iconMap) =>
- iconMap[category]
- ? new Pair(iconMap[category], category)
- : new Pair(iconMap.missing, 'Category does not match with the configuration')
- )
- );
+ displayFilter() {
+ this.showFilter = !this.showFilter;
}
ngOnDestroy() {
diff --git a/web/src/app/administration/components/classification-overview/classification-overview.component.html b/web/src/app/administration/components/classification-overview/classification-overview.component.html
index 27979c5fa..9de312344 100644
--- a/web/src/app/administration/components/classification-overview/classification-overview.component.html
+++ b/web/src/app/administration/components/classification-overview/classification-overview.component.html
@@ -1,10 +1,8 @@
-
-
-
-
-
-
-
+
+
+
+
+
diff --git a/web/src/app/administration/components/classification-overview/classification-overview.component.scss b/web/src/app/administration/components/classification-overview/classification-overview.component.scss
index e69de29bb..1799977d8 100644
--- a/web/src/app/administration/components/classification-overview/classification-overview.component.scss
+++ b/web/src/app/administration/components/classification-overview/classification-overview.component.scss
@@ -0,0 +1,10 @@
+.classification-overview {
+ display: flex;
+ flex-direction: row;
+ width: 100%;
+ overflow: hidden;
+ align-items: stretch;
+}
+taskana-administration-classification-details {
+ width: 100%
+}
diff --git a/web/src/app/administration/components/classification-types-selector/classification-types-selector.component.html b/web/src/app/administration/components/classification-types-selector/classification-types-selector.component.html
index f13235b9c..a114ae956 100644
--- a/web/src/app/administration/components/classification-types-selector/classification-types-selector.component.html
+++ b/web/src/app/administration/components/classification-types-selector/classification-types-selector.component.html
@@ -1,17 +1,8 @@
-
-
-
-
-
+
+ Type
+
+
+ {{ classificationType }}
+
+
+
diff --git a/web/src/app/administration/components/classification-types-selector/classification-types-selector.component.scss b/web/src/app/administration/components/classification-types-selector/classification-types-selector.component.scss
index 1d51e6080..70ea10d7a 100644
--- a/web/src/app/administration/components/classification-types-selector/classification-types-selector.component.scss
+++ b/web/src/app/administration/components/classification-types-selector/classification-types-selector.component.scss
@@ -1,3 +1,6 @@
+mat-form-field {
+ max-width: 120px !important;
+}
.radio-group {
display: flex;
flex-direction: column;
diff --git a/web/src/app/administration/components/classification-types-selector/classification-types-selector.component.spec.ts b/web/src/app/administration/components/classification-types-selector/classification-types-selector.component.spec.ts
index 75bf7cbbc..d9331bdf5 100644
--- a/web/src/app/administration/components/classification-types-selector/classification-types-selector.component.spec.ts
+++ b/web/src/app/administration/components/classification-types-selector/classification-types-selector.component.spec.ts
@@ -3,12 +3,14 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { DebugElement } from '@angular/core';
import { NgxsModule, Store } from '@ngxs/store';
import { ClassificationState } from '../../../shared/store/classification-store/classification.state';
-import { MatRadioButton, MatRadioGroup } from '@angular/material/radio';
import { ClassificationsService } from '../../../shared/services/classifications/classifications.service';
import { ClassificationCategoriesService } from '../../../shared/services/classification-categories/classification-categories.service';
import { DomainService } from '../../../shared/services/domain/domain.service';
-import { MatRippleModule } from '@angular/material/core';
import { classificationStateMock } from '../../../shared/store/mock-data/mock-store';
+import { MatFormFieldModule } from '@angular/material/form-field';
+import { MatSelectModule } from '@angular/material/select';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+import { By } from '@angular/platform-browser';
const classificationServiceSpy = jest.fn();
const classificationCategoriesServiceSpy = jest.fn();
@@ -17,13 +19,18 @@ const domainServiceSpy = jest.fn();
describe('ClassificationTypesSelectorComponent', () => {
let fixture: ComponentFixture
;
let debugElement: DebugElement;
- let app: ClassificationTypesSelectorComponent;
+ let component: ClassificationTypesSelectorComponent;
let store: Store;
beforeEach(async(() => {
TestBed.configureTestingModule({
- imports: [NgxsModule.forRoot([ClassificationState]), MatRippleModule],
- declarations: [ClassificationTypesSelectorComponent, MatRadioButton, MatRadioGroup],
+ imports: [
+ NgxsModule.forRoot([ClassificationState]),
+ MatFormFieldModule,
+ MatSelectModule,
+ BrowserAnimationsModule
+ ],
+ declarations: [ClassificationTypesSelectorComponent],
providers: [
{ provide: ClassificationsService, useClass: classificationServiceSpy },
{ provide: ClassificationCategoriesService, useClass: classificationCategoriesServiceSpy },
@@ -33,7 +40,7 @@ describe('ClassificationTypesSelectorComponent', () => {
fixture = TestBed.createComponent(ClassificationTypesSelectorComponent);
debugElement = fixture.debugElement;
- app = fixture.debugElement.componentInstance;
+ component = fixture.debugElement.componentInstance;
store = TestBed.inject(Store);
store.reset({
...store.snapshot(),
@@ -43,18 +50,28 @@ describe('ClassificationTypesSelectorComponent', () => {
}));
it('should create the app', () => {
- expect(app).toBeTruthy();
+ expect(component).toBeTruthy();
+ });
+
+ it('should display form-field for types-selector', () => {
+ const button = debugElement.nativeElement.getElementsByClassName('types-selector');
+ expect(button).toBeTruthy();
});
it('should display selected classification type', () => {
- const button = fixture.debugElement.nativeElement.getElementsByClassName('selected-type');
- expect(button[0].textContent.trim()).toBe('DOCUMENT');
+ fixture.detectChanges();
+ const button = debugElement.nativeElement.querySelector('.types-selector__selected-type');
+ expect(button.textContent).toBe('DOCUMENT');
});
- it('should display list of classification types', () => {
- const radioButtons = fixture.debugElement.nativeElement.getElementsByClassName('classification-types');
- expect(radioButtons.length).toBe(2);
- expect(radioButtons[0].textContent.trim()).toBe('TASK');
- expect(radioButtons[1].textContent.trim()).toBe('DOCUMENT');
+ it('should display dropdown with 2 objects', () => {
+ const dropdownButton = debugElement.nativeElement.querySelector('.types-selector__selected-type');
+ expect(dropdownButton).toBeTruthy();
+ dropdownButton.click();
+ fixture.detectChanges();
+ const options = debugElement.queryAll(By.css('.types-selector__options'));
+ expect(options.length).toBe(2);
+ expect(options[0].nativeElement.textContent.trim()).toBe('TASK');
+ expect(options[1].nativeElement.textContent.trim()).toBe('DOCUMENT');
});
});
diff --git a/web/src/app/administration/components/import-export/import-export.component.html b/web/src/app/administration/components/import-export/import-export.component.html
index 54f64efa5..0627a65fd 100644
--- a/web/src/app/administration/components/import-export/import-export.component.html
+++ b/web/src/app/administration/components/import-export/import-export.component.html
@@ -1,23 +1,23 @@
-