Merge branch 'DEVELOP' of ssh://git.eclipse.org:29418/openk-usermodules/org.eclipse.openk-usermodules.contactBaseData.frontend into KON-37-rechte-rollen
diff --git a/i18n/contacts.de.json b/i18n/contacts.de.json
index dbe91b2..2fc1b31 100644
--- a/i18n/contacts.de.json
+++ b/i18n/contacts.de.json
@@ -19,7 +19,11 @@
"Department": "Abteilung",
"CommunicationsDataList": "Kommunikationskanäle",
"ContactPersonList": "Ansprechpartner",
- "CommunicationsDataList": "Kommunikationskanäle",
- "ModuleAssignment": "Modulzuordnung"
+ "ModuleAssignment": "Modulzuordnung",
+ "AllModuleAssignments": "Alle Modulzuordnungen",
+ "WithoutModuleAssignment": "Keine Modulzuordnung",
+ "DSGVO-advanced-filter": "DSGVO - Filtererweiterung",
+ "DSGVO-advanced-filter-deletion-lock-exceeded": "Filterung nach Kontakten mit abgelaufener Löschsperre",
+ "DSGVO-advanced-filter-expiring-data-in-past": "Filterung nach Kontakten mit überschrittenem Ablaufdatum"
}
}
diff --git a/i18n/general.de.json b/i18n/general.de.json
index 4d1ea25..b4f5024 100644
--- a/i18n/general.de.json
+++ b/i18n/general.de.json
@@ -30,9 +30,11 @@
"Deletion": "Möchten Sie den Datensatz wirklich löschen?",
"SubmitBtn": "Ja",
"CancelBtn": "Nein",
+ "Anonymization": "Wollen Sie diesen Kontakt wirklich anonymisieren? Dieser Vorgang kann nicht rückgängig gemacht werden. Sämtliche zu diesem Kontakt gehörenden Daten werden anonymisiert. Diese Daten können nicht wiederhergestellt werden.",
"Action": {
"delete": "Datensatz löschen",
- "edit": "Änderung verwerfen"
+ "edit": "Änderung verwerfen",
+ "anonymize": "Kontakt anonymisieren"
}
},
"Tools": "Tools",
diff --git a/package.json b/package.json
index 602c2b6..67da642 100644
--- a/package.json
+++ b/package.json
@@ -17,9 +17,8 @@
"sy-post-build": "node hooks/post-build.js",
"sy-build": "npm run sy-pre-build && ng build --base-href /contactdatabase/ --prod --aot && npm run sy-post-build",
"sy-build-noprod": "npm run sy-pre-build && ng build --base-href /contactdatabase/ && npm run sy-post-build",
- "start-in-docker": "npm run sy-pre-start && ng serve --optimization=false --vendor-chunk --common-chunk --host=0.0.0.0 --disableHostCheck=true --proxy-config proxy-docker.conf.json",
- "start-in-docker-unsecure": "npm run sy-pre-start && ng serve --optimization=false --vendor-chunk --common-chunk --host=0.0.0.0 --disableHostCheck=true --proxy-config proxy-docker-unsecure.conf.json"
-
+ "start-in-docker": "npm run sy-pre-start && ng serve --optimization=false --vendor-chunk --common-chunk --host=0.0.0.0 --disableHostCheck=true --proxy-config proxy-docker.conf.json",
+ "start-in-docker-unsecure": "npm run sy-pre-start && ng serve --optimization=false --vendor-chunk --common-chunk --host=0.0.0.0 --disableHostCheck=true --proxy-config proxy-docker-unsecure.conf.json"
},
"private": true,
"dependencies": {
diff --git a/src/app/pages/company/company-details/company-details.component.html b/src/app/pages/company/company-details/company-details.component.html
index 547ca31..0833496 100644
--- a/src/app/pages/company/company-details/company-details.component.html
+++ b/src/app/pages/company/company-details/company-details.component.html
@@ -79,10 +79,14 @@
</div>
<!-- buttons -->
- <button *visibleByRight type="button" class="btn btn-success" (click)="companyDetailsSandBox.persistCompany()">{{ 'SaveBtn' | translate }}</button>
- <button type="button" class="btn btn-primary cancel-button" routerLink="/overview">
- {{ 'CancelBtn' | translate }}
- </button>
+ <div class="row justify-content-between">
+ <div>
+ <button *visibleByRight type="button" class="btn btn-success company-buttons" (click)="companyDetailsSandBox.persistCompany()">{{ 'SaveBtn' | translate }}</button>
+ <button type="button" class="btn btn-primary cancel-button company-buttons" routerLink="/overview">
+ {{ 'CancelBtn' | translate }}
+ </button>
+ </div>
+ </div>
</div>
</form>
diff --git a/src/app/pages/company/company-details/company-details.component.scss b/src/app/pages/company/company-details/company-details.component.scss
index 7f6bfc9..35a3e5c 100644
--- a/src/app/pages/company/company-details/company-details.component.scss
+++ b/src/app/pages/company/company-details/company-details.component.scss
@@ -10,8 +10,8 @@
*
* SPDX-License-Identifier: EPL-2.0
********************************************************************************/
-.btn-success {
- margin-right: 16px;
+.company-buttons {
+ margin: 16px;
}
.expandable-body-container {
display: flex;
diff --git a/src/app/pages/company/company-details/contact-person-details/communications-data-details/communications-data-details.component.spec.ts b/src/app/pages/company/company-details/contact-person-details/communications-data-details/communications-data-details.component.spec.ts
index f4c15c2..f27366b 100644
--- a/src/app/pages/company/company-details/contact-person-details/communications-data-details/communications-data-details.component.spec.ts
+++ b/src/app/pages/company/company-details/contact-person-details/communications-data-details/communications-data-details.component.spec.ts
@@ -11,27 +11,26 @@
* SPDX-License-Identifier: EPL-2.0
********************************************************************************/
import { async } from '@angular/core/testing';
-import { CompanyCommunicationsDataDetailsComponent } from '@pages/company/company-details/communications-data-details/communications-data-details.component';
+import { ContactPersonCommunicationsDataDetailsComponent } from '@pages/company/company-details/contact-person-details/communications-data-details/communications-data-details.component';
-describe('CompanyCommunicationsDataDetailsComponent', () => {
- let component: CompanyCommunicationsDataDetailsComponent;
- let companySandbox: any;
+describe('ContactPersonCommunicationsDataDetailsComponent', () => {
+ let component: ContactPersonCommunicationsDataDetailsComponent;
+ let sandbox: any;
let communicationTypesSandbox: any;
beforeEach(async(() => {
- companySandbox = {
+ sandbox = {
registerCommunicationsDataEvents() {},
registerCompanyEvents() {},
endSubscriptions() {},
clearCommunicationsData() {},
} as any;
- communicationTypesSandbox = {
- } as any;
+ communicationTypesSandbox = {} as any;
}));
beforeEach(() => {
- component = new CompanyCommunicationsDataDetailsComponent(companySandbox, communicationTypesSandbox);
+ component = new ContactPersonCommunicationsDataDetailsComponent(sandbox, communicationTypesSandbox);
});
it('should create', () => {
@@ -39,8 +38,8 @@
});
it('should call registerCommunicationsDataEvents and clearCommunicationsData onInit', () => {
- const spy1 = spyOn(companySandbox, 'registerCommunicationsDataEvents');
- const spy2 = spyOn(companySandbox, 'clearCommunicationsData');
+ const spy1 = spyOn(sandbox, 'registerCommunicationsDataEvents');
+ const spy2 = spyOn(sandbox, 'clearCommunicationsData');
component.ngOnInit();
expect(spy1).toHaveBeenCalled();
expect(spy2).toHaveBeenCalled();
diff --git a/src/app/pages/company/company-details/contact-person-details/communications-data-list/communications-data-list.component.spec.ts b/src/app/pages/company/company-details/contact-person-details/communications-data-list/communications-data-list.component.spec.ts
index 61ecbba..abb265b 100644
--- a/src/app/pages/company/company-details/contact-person-details/communications-data-list/communications-data-list.component.spec.ts
+++ b/src/app/pages/company/company-details/contact-person-details/communications-data-list/communications-data-list.component.spec.ts
@@ -11,15 +11,15 @@
* SPDX-License-Identifier: EPL-2.0
********************************************************************************/
import { async } from '@angular/core/testing';
-import { CompanyCommunicationsDataListComponent } from '@pages/company/company-details/communications-data-list/communications-data-list.component';
+import { ContactPersonCommunicationsDataListComponent } from '@pages/company/company-details/contact-person-details/communications-data-list/communications-data-list.component';
import { of } from 'rxjs/observable/of';
-describe('CompanyCommunicationsDataListComponent', () => {
- let component: CompanyCommunicationsDataListComponent;
- let companySandbox: any;
+describe('ContactPersonCommunicationsDataListComponent', () => {
+ let component: ContactPersonCommunicationsDataListComponent;
+ let contactPersonDetailsSandbox: any;
beforeEach(async(() => {
- companySandbox = {
+ contactPersonDetailsSandbox = {
registerCommunicationsDataEvents() {},
registerCompanyEvents() {},
endSubscriptions() {},
@@ -29,7 +29,7 @@
}));
beforeEach(() => {
- component = new CompanyCommunicationsDataListComponent(companySandbox);
+ component = new ContactPersonCommunicationsDataListComponent(contactPersonDetailsSandbox);
});
it('should create', () => {
@@ -53,7 +53,7 @@
});
it('should deleteCommunicationsData if BusEvents is delete', () => {
- const spy = spyOn(companySandbox, 'deleteCommunicationsData');
+ const spy = spyOn(contactPersonDetailsSandbox, 'deleteCommunicationsData');
const event: any = { type: 'delete', data: { id: 'id' } };
component.gridOptions.context.eventSubject = of(event);
component.ngOnInit();
@@ -62,7 +62,7 @@
});
it('should call newCommunicationsData in response to createNewCommunicationsDataForm', () => {
- const spy = spyOn(companySandbox, 'newCommunicationsData');
+ const spy = spyOn(contactPersonDetailsSandbox, 'newCommunicationsData');
const spyEmit = spyOn(component.createNewCompany, 'emit');
component.createNewCommunicationsDataForm();
diff --git a/src/app/pages/company/company-details/contact-person-details/contact-person-details.component.html b/src/app/pages/company/company-details/contact-person-details/contact-person-details.component.html
index 57c0d23..a8ed1a0 100644
--- a/src/app/pages/company/company-details/contact-person-details/contact-person-details.component.html
+++ b/src/app/pages/company/company-details/contact-person-details/contact-person-details.component.html
@@ -106,17 +106,24 @@
</div>
<!-- buttons -->
- <button *visibleByRight type="button" class="btn btn-success" (click)="contactPersonDetailSandbox.saveContactPersonDetails()">
- {{ 'SaveBtn' | translate }}
- </button>
+ <div class="row justify-content-between">
+ <div>
+ <button *visibleByRight type="button" class="btn btn-success person-buttons" (click)="contactPersonDetailSandbox.saveContactPersonDetails()">
+ {{ 'SaveBtn' | translate }}
+ </button>
- <button type="button" class="btn btn-primary cancel-button" (click)="contactPersonDetailSandbox.navigateBackToCompany()">
- {{ 'ContactPerson.CompanyBtn' | translate }}
- </button>
+ <button type="button" class="btn btn-primary person-buttons" (click)="contactPersonDetailSandbox.navigateBackToCompany()">
+ {{ 'ContactPerson.CompanyBtn' | translate }}
+ </button>
- <button type="button" class="btn btn-primary cancel-button" routerLink="/overview">
- {{ 'ContactPerson.ContactOverviewBtn' | translate }}
- </button>
+ <button type="button" class="btn btn-primary person-buttons" routerLink="/overview">
+ {{ 'ContactPerson.ContactOverviewBtn' | translate }}
+ </button>
+ </div>
+ <div class="person-buttons" *ngIf="contactPersonDetailSandbox.contactPersonContactId">
+ <app-anonymizer [contactId]="contactPersonDetailSandbox.contactPersonContactId"></app-anonymizer>
+ </div>
+ </div>
</div>
</form>
diff --git a/src/app/pages/company/company-details/contact-person-details/contact-person-details.component.scss b/src/app/pages/company/company-details/contact-person-details/contact-person-details.component.scss
index 4cdef80..9de3904 100644
--- a/src/app/pages/company/company-details/contact-person-details/contact-person-details.component.scss
+++ b/src/app/pages/company/company-details/contact-person-details/contact-person-details.component.scss
@@ -10,8 +10,8 @@
*
* SPDX-License-Identifier: EPL-2.0
********************************************************************************/
-.cancel-button {
- margin-right: 16px;
+.person-buttons {
+ margin: 16px;
}
.expandable-body-container {
display: flex;
diff --git a/src/app/pages/company/company-details/contact-person-details/contact-person-details.resolver.spec.ts b/src/app/pages/company/company-details/contact-person-details/contact-person-details.resolver.spec.ts
new file mode 100644
index 0000000..a503008
--- /dev/null
+++ b/src/app/pages/company/company-details/contact-person-details/contact-person-details.resolver.spec.ts
@@ -0,0 +1,81 @@
+/********************************************************************************
+ * Copyright (c) 2020 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ ********************************************************************************/
+import { ContactPersonDetailsResolver } from '@pages/company/company-details/contact-person-details/contact-person-details.resolver';
+
+describe('CompanyDetailsResolver', () => {
+ let component: ContactPersonDetailsResolver;
+ let contactPersonDetailsSandbox: any;
+ let salutationsSandbox: any;
+ let personTypesSandbox: any;
+ let communicationTypesSandbox: any;
+ let addressTypesSandbox: any;
+ let userModuleAssignmentSandbox: any;
+
+ beforeEach(() => {
+ contactPersonDetailsSandbox = {
+ companyContactId: null,
+ loadContactPersonDetails() {},
+ loadContactPersonAddresses() {},
+ newContactPerson() {},
+ } as any;
+
+ communicationTypesSandbox = {
+ loadCommunicationTypes() {},
+ } as any;
+
+ userModuleAssignmentSandbox = {
+ loadFilteredUserModuleTypes() {},
+ loadUserModuleAssignments() {},
+ } as any;
+
+ addressTypesSandbox = {
+ loadAddressTypes() {},
+ } as any;
+
+ salutationsSandbox = {
+ loadSalutations() {},
+ } as any;
+
+ personTypesSandbox = {
+ loadPersonTypes() {},
+ } as any;
+ });
+
+ beforeEach(() => {
+ component = new ContactPersonDetailsResolver(
+ contactPersonDetailsSandbox,
+ salutationsSandbox,
+ personTypesSandbox,
+ communicationTypesSandbox,
+ addressTypesSandbox,
+ userModuleAssignmentSandbox
+ );
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+
+ it('should ccc', () => {
+ let ar: any = { params: { contactId: 'ID' } };
+ component.resolve(ar);
+ expect(contactPersonDetailsSandbox.companyContactId).toBe(ar.params.contactId);
+ });
+
+ it('should call clear if create a new contact-person', () => {
+ const spy = spyOn(contactPersonDetailsSandbox, 'newContactPerson');
+ let ar: any = { params: { contactPersonId: undefined } };
+ component.resolve(ar);
+ expect(spy).toHaveBeenCalled();
+ });
+});
diff --git a/src/app/pages/contacts/contacts-api-client.ts b/src/app/pages/contacts/contacts-api-client.ts
index e431d36..f1eb052 100644
--- a/src/app/pages/contacts/contacts-api-client.ts
+++ b/src/app/pages/contacts/contacts-api-client.ts
@@ -1,4 +1,4 @@
- /********************************************************************************
+/********************************************************************************
* Copyright (c) 2020 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
@@ -22,19 +22,38 @@
@Injectable()
@DefaultHeaders({
- 'Accept': 'application/json',
+ Accept: 'application/json',
'Content-Type': 'application/json',
})
export class ContactsApiClient extends HttpService {
public getContacts(request: PageRequestInterface = null): Observable<PageModel<Contact>> {
let modifiedContacts: ModifiedContacts = null;
- if(request != null){
+ if (request != null) {
modifiedContacts = request.queryParameter || {};
- return this._getContactsPage(modifiedContacts.searchText, modifiedContacts.contactTypeId, modifiedContacts.sort, request.pageNumber ? (request.pageNumber - 1) : 0, request.pageSize);
+ return this._getContactsPage(
+ modifiedContacts.searchText,
+ modifiedContacts.contactTypeId,
+ modifiedContacts.sort,
+ modifiedContacts.moduleName,
+ modifiedContacts.withoutAssignedModule,
+ modifiedContacts.expiringDataInPast,
+ modifiedContacts.deletionLockExceeded,
+ request.pageNumber ? request.pageNumber - 1 : 0,
+ request.pageSize
+ );
} else {
- return this._getContactsPage(modifiedContacts.searchText, modifiedContacts.contactTypeId, modifiedContacts.sort, 1, 3);
+ return this._getContactsPage(
+ modifiedContacts.searchText,
+ modifiedContacts.contactTypeId,
+ modifiedContacts.sort,
+ modifiedContacts.moduleName,
+ modifiedContacts.withoutAssignedModule,
+ modifiedContacts.expiringDataInPast,
+ modifiedContacts.deletionLockExceeded,
+ 1,
+ 3
+ );
}
-
}
/**
@@ -42,7 +61,17 @@
*/
@GET('/contacts')
@Adapter(ContactsService.gridPageAdapter)
- private _getContactsPage(@Query('searchText') searchtext: string, @Query('contactType') contactTypeId: string, @Query('sort') sort: string, @Query('page') pageNumber: number, @Query('size') pageSize: number): Observable<any> {
+ private _getContactsPage(
+ @Query('searchText') searchtext: string,
+ @Query('contactType') contactTypeId: string,
+ @Query('sort') sort: string,
+ @Query('moduleName') moduleName: string,
+ @Query('withoutAssignedModule') withoutAssignedModule: boolean,
+ @Query('expiringDataInPast') expiringDataInPast: boolean,
+ @Query('deletionLockExceeded') deletionLockExceeded: boolean,
+ @Query('page') pageNumber: number,
+ @Query('size') pageSize: number
+ ): Observable<any> {
return null;
}
@@ -62,4 +91,9 @@
public putContactDetails(@Path('id') id: number, @Body() editedContact: Contact): Observable<Contact> {
return null;
}
+
+ @PUT('/contacts/{id}/anonymize')
+ public anonymizeContact(@Path('id') id: string): Observable<void> {
+ return null;
+ }
}
diff --git a/src/app/pages/contacts/contacts-list/contacts-list.component.html b/src/app/pages/contacts/contacts-list/contacts-list.component.html
index ba03537..2524723 100644
--- a/src/app/pages/contacts/contacts-list/contacts-list.component.html
+++ b/src/app/pages/contacts/contacts-list/contacts-list.component.html
@@ -16,34 +16,72 @@
</div>
<div class="contacts-grid-wrapper" body>
<div class="diverse-options">
- <div class="searching diverse-options-item">
- <div class="search-options">
- <input
- type="text"
- class="item"
- id="searchText"
- placeholder="Suche"
- (keyup)="setModifiedContactsSearchText($event.target.value); searchContacts($event)"
- />
+ <div class="search-options diverse-options-item">
+ <input
+ type="text"
+ class="item"
+ id="search-text"
+ placeholder="Suche"
+ (keyup)="setModifiedContactsSearchText($event.target.value); searchContacts($event)"
+ />
- <select
- [required]="false"
- type="text"
- class="form-control item"
- (change)="setModifiedContactsContactTypeId($event.target.value); searchContacts($event)"
+ <select
+ [required]="false"
+ type="text"
+ class="form-control item"
+ (change)="setModifiedContactsContactTypeId($event.target.value); searchContacts($event)"
+ >
+ <option value="{{ INTERNAL_PERSON }}">{{ 'Contacts.InternalContact' | translate }}</option>
+ <option value="{{ EXTERNAL_PERSON }}">{{ 'Contacts.ExternalContact' | translate }}</option>
+ <option value="{{ COMPANY }}">{{ 'Contacts.Company' | translate }}</option>
+ <option value="{{ CONTACT_PERSON }}">{{ 'Contacts.ContactPersonList' | translate }}</option>
+ <option value="" selected>{{ 'Contacts.AllContactTypes' | translate }}</option>
+ </select>
+
+ <div class="dsgvo-filter-container search-btn">
+ <button
+ type="button"
+ class="btn btn-default btn-sm"
+ (click)="isDSGVOFilterAdvancedVisible = !isDSGVOFilterAdvancedVisible"
+ title="{{ 'Contacts.DSGVO-advanced-filter' | translate }}"
>
- <option value="{{ INTERNAL_PERSON }}">{{ 'Contacts.InternalContact' | translate }}</option>
- <option value="{{ EXTERNAL_PERSON }}">{{ 'Contacts.ExternalContact' | translate }}</option>
- <option value="{{ COMPANY }}">{{ 'Contacts.Company' | translate }}</option>
- <option value="" selected>{{ 'Contacts.AllContactTypes' | translate }}</option>
- </select>
+ DSGVO
+ </button>
+ <div class="dsgvo-filter-options" *ngIf="isDSGVOFilterAdvancedVisible">
+ <select
+ [required]="false"
+ type="text"
+ class="form-control"
+ style="margin-right: 12px;"
+ (change)="setModifiedContactsModuleAssignmentFilter($event.target.value); searchContacts($event)"
+ >
+ <option *ngFor="let moduleType of userModuleAssignmentSandbox.userModuleTypes$ | async" [value]="moduleType.id">{{ moduleType.id }}</option>
+ <option [value]="'-1'">{{ 'Contacts.WithoutModuleAssignment' | translate }}</option>
+ <option [value]="''" selected>{{ 'Contacts.AllModuleAssignments' | translate }}</option>
+ </select>
- <div class="search-btn">
- <button type="button" class="btn btn-default btn-sm" (click)="searchContacts($event)" title="suchen">
- <em class="fa fa-search fa-lg " aria-hidden="true "></em>
- </button>
+ <div class="dsgvo-filter-item custom-control custom-switch" title="{{ 'Contacts.DSGVO-advanced-filter-expiring-data-in-past' | translate }}">
+ <input type="checkbox" class="custom-control-input" id="expiry-date" (change)="setModifiedContactsExpiryDateFilter(); searchContacts($event)" />
+ <label class="custom-control-label" style="position: 0px;" for="expiry-date"></label>
+ </div>
+
+ <div class="dsgvo-filter-item custom-control custom-switch" title="{{ 'Contacts.DSGVO-advanced-filter-deletion-lock-exceeded' | translate }}">
+ <input
+ type="checkbox"
+ class="custom-control-input"
+ id="deletion-lock-until"
+ (change)="setModifiedContactsDeletionLockExceedFilter(); searchContacts($event)"
+ />
+ <label class="custom-control-label" for="deletion-lock-until"></label>
+ </div>
</div>
</div>
+
+ <div class="search-btn">
+ <button type="button" class="btn btn-default btn-sm" (click)="searchContacts($event)" title="suchen">
+ <em class="fa fa-search fa-lg " aria-hidden="true "></em>
+ </button>
+ </div>
</div>
<div class="sorting-options diverse-options-item">
diff --git a/src/app/pages/contacts/contacts-list/contacts-list.component.scss b/src/app/pages/contacts/contacts-list/contacts-list.component.scss
index 83462b7..7b3ad89 100644
--- a/src/app/pages/contacts/contacts-list/contacts-list.component.scss
+++ b/src/app/pages/contacts/contacts-list/contacts-list.component.scss
@@ -46,24 +46,23 @@
margin-right: 2px;
}
-.searching {
- display: flex;
- flex-wrap: nowrap;
- justify-content: flex-start;
-}
-
.search-options {
display: flex;
flex-wrap: nowrap;
justify-content: flex-start;
align-items: center;
+ flex-grow: 1;
}
.item {
- min-width: 170px;
+ flex-basis: 185px;
margin: 5px;
}
+#search-text {
+ max-width: 160px;
+}
+
.search-btn {
display: flex;
align-items: center;
@@ -80,6 +79,7 @@
flex-wrap: nowrap;
justify-content: flex-start;
align-items: center;
+ min-width: 380px;
}
.diverse-btn {
@@ -102,3 +102,21 @@
margin-right: 2px;
margin-bottom: 2px;
}
+.dsgvo-filter-container {
+ display: flex;
+ flex-direction: row;
+ flex-wrap: nowrap;
+ justify-content: flex-start;
+ justify-self: center;
+}
+.dsgvo-filter-options {
+ display: flex;
+ flex-direction: row;
+ flex-wrap: nowrap;
+ justify-content: flex-start;
+ align-items: center;
+ flex-grow: 1;
+}
+.dsgvo-filter-item {
+ margin: 4px 0px 0px 12px;
+}
diff --git a/src/app/pages/contacts/contacts-list/contacts-list.component.spec.ts b/src/app/pages/contacts/contacts-list/contacts-list.component.spec.ts
index 295e22f..222b05f 100644
--- a/src/app/pages/contacts/contacts-list/contacts-list.component.spec.ts
+++ b/src/app/pages/contacts/contacts-list/contacts-list.component.spec.ts
@@ -17,11 +17,12 @@
describe('ContactsListComponent', () => {
let component: ContactsListComponent;
let contactsSandbox: any = {};
+ let userModuleAssignmentSandbox: any = {};
let router: any = {};
beforeEach(() => {
router = { navigateByUrl() {}, navigate() {} } as any;
- component = new ContactsListComponent(contactsSandbox, router);
+ component = new ContactsListComponent(contactsSandbox, userModuleAssignmentSandbox, router);
});
it('should create', () => {
@@ -170,7 +171,7 @@
expect((component as any)._sortingOrder).toBe('asc');
});
- it('checks if function _setModifiedContactsSortProperty() works', () => {
+ it('checks if function _setModifiedContactsSort() works', () => {
component.setSortingContactType('name');
(component as any)._setModifiedContactsSort();
expect(component.modifiedContacts.sort).toBe('name,asc');
@@ -183,4 +184,31 @@
(component as any)._setModifiedContactsSort();
expect(component.modifiedContacts.sort).toBe(null);
});
+
+ it('checks if function setModifiedContactsExpiryDateFilter() works', () => {
+ expect(component.modifiedContacts.expiringDataInPast).toBeFalsy();
+ component.setModifiedContactsExpiryDateFilter();
+ expect(component.modifiedContacts.expiringDataInPast).toBeTruthy();
+ });
+
+ it('checks if function setModifiedContactsDeletionLockExceedFilter() works', () => {
+ expect(component.modifiedContacts.deletionLockExceeded).toBeFalsy();
+ component.setModifiedContactsDeletionLockExceedFilter();
+ expect(component.modifiedContacts.deletionLockExceeded).toBeTruthy();
+ });
+
+ it('checks if function setModifiedContactsModuleAssignmentFilter() works', () => {
+ let moduleName = '-1';
+ component.setModifiedContactsModuleAssignmentFilter(moduleName);
+ expect(component.modifiedContacts.moduleName).toBe(null);
+ expect(component.modifiedContacts.withoutAssignedModule).toBeTruthy();
+ moduleName = '';
+ component.setModifiedContactsModuleAssignmentFilter(moduleName);
+ expect(component.modifiedContacts.moduleName).toBe(null);
+ expect(component.modifiedContacts.withoutAssignedModule).toBeFalsy();
+ moduleName = 'Betriebstagebuch';
+ component.setModifiedContactsModuleAssignmentFilter(moduleName);
+ expect(component.modifiedContacts.moduleName).toBe(moduleName);
+ expect(component.modifiedContacts.withoutAssignedModule).toBeFalsy();
+ });
});
diff --git a/src/app/pages/contacts/contacts-list/contacts-list.component.ts b/src/app/pages/contacts/contacts-list/contacts-list.component.ts
index 99b8d8d..8576d49 100644
--- a/src/app/pages/contacts/contacts-list/contacts-list.component.ts
+++ b/src/app/pages/contacts/contacts-list/contacts-list.component.ts
@@ -17,6 +17,7 @@
import { Router } from '@angular/router';
import { Globals } from '@shared/constants/globals';
import { ModifiedContacts } from '@shared/models/modifiedContacts.model';
+import { UserModuleAssignmentSandBox } from '@shared/components/list-details-view/user-module-assignment/user-module-assignment.sandbox';
@Component({
selector: 'app-contacts-list',
@@ -31,14 +32,18 @@
public readonly INTERNAL_PERSON = Globals.CONTACT_TYPE_ID.INTERNAL_PERSON;
public readonly EXTERNAL_PERSON = Globals.CONTACT_TYPE_ID.EXTERNAL_PERSON;
public readonly COMPANY = Globals.CONTACT_TYPE_ID.COMPANY;
+ public readonly CONTACT_PERSON = Globals.CONTACT_TYPE_ID.CONTACT_PERSON;
public columnDefinition: any = CONTACTS_COLDEF;
public modifiedContacts: ModifiedContacts = new ModifiedContacts();
+ public isDSGVOFilterAdvancedVisible = false;
private _sortingOrder: string = 'asc';
private _sortingContactType: string = '';
+ private _expiringDataInPast = false;
+ private _deletionLockExceeded = false;
- constructor(public contactsSandbox: ContactsSandbox, private router: Router) {
+ constructor(public contactsSandbox: ContactsSandbox, public userModuleAssignmentSandbox: UserModuleAssignmentSandBox, private router: Router) {
super();
}
@@ -104,6 +109,32 @@
this.modifiedContacts.contactTypeId = contactTypeId;
}
+ public setModifiedContactsModuleAssignmentFilter(moduleName: string) {
+ if (moduleName === '-1') {
+ //show contacts without module assignments
+ this.modifiedContacts.moduleName = null;
+ this.modifiedContacts.withoutAssignedModule = true;
+ } else if (moduleName == '') {
+ //show contacts with all module assignments
+ this.modifiedContacts.moduleName = null;
+ this.modifiedContacts.withoutAssignedModule = false;
+ } else {
+ //show contacts with specific module assignments
+ this.modifiedContacts.moduleName = moduleName;
+ this.modifiedContacts.withoutAssignedModule = false;
+ }
+ }
+
+ public setModifiedContactsExpiryDateFilter() {
+ this._expiringDataInPast = !this._expiringDataInPast;
+ this.modifiedContacts.expiringDataInPast = this._expiringDataInPast;
+ }
+
+ public setModifiedContactsDeletionLockExceedFilter() {
+ this._deletionLockExceeded = !this._deletionLockExceeded;
+ this.modifiedContacts.deletionLockExceeded = this._deletionLockExceeded;
+ }
+
public setSortingContactType(sortingContactType: string) {
this._sortingContactType = sortingContactType;
}
diff --git a/src/app/pages/persons/external-person/external-person-details/external-person-details.component.html b/src/app/pages/persons/external-person/external-person-details/external-person-details.component.html
index c7687e6..d03ec35 100644
--- a/src/app/pages/persons/external-person/external-person-details/external-person-details.component.html
+++ b/src/app/pages/persons/external-person/external-person-details/external-person-details.component.html
@@ -109,12 +109,19 @@
</div>
<!-- buttons -->
- <button *visibleByRight type="button" class="btn btn-success" (click)="externalPersonSandBox.persistExternalPerson()">
- {{ 'SaveBtn' | translate }}
- </button>
- <button type="button" class="btn btn-primary cancel-button" routerLink="/overview">
- {{ 'CancelBtn' | translate }}
- </button>
+ <div class="row justify-content-between">
+ <div>
+ <button *visibleByRight type="button" class="btn btn-success person-buttons" (click)="externalPersonSandBox.persistExternalPerson()">
+ {{ 'SaveBtn' | translate }}
+ </button>
+ <button type="button" class="btn btn-primary person-buttons cancel-button" routerLink="/overview">
+ {{ 'CancelBtn' | translate }}
+ </button>
+ </div>
+ <div class="person-buttons" *ngIf="externalPersonSandBox.externalPersonContactId">
+ <app-anonymizer [contactId]="externalPersonSandBox.externalPersonContactId"></app-anonymizer>
+ </div>
+ </div>
</div>
</form>
diff --git a/src/app/pages/persons/external-person/external-person-details/external-person-details.component.scss b/src/app/pages/persons/external-person/external-person-details/external-person-details.component.scss
index b78a7c2..d73298c 100644
--- a/src/app/pages/persons/external-person/external-person-details/external-person-details.component.scss
+++ b/src/app/pages/persons/external-person/external-person-details/external-person-details.component.scss
@@ -10,42 +10,42 @@
*
* SPDX-License-Identifier: EPL-2.0
********************************************************************************/
-.cancel-button {
- margin-left: 16px;
+.person-buttons {
+ margin: 16px;
}
.expandable-body-container {
- display: flex;
- flex-direction: row;
- height: 100%;
+ display: flex;
+ flex-direction: row;
+ height: 100%;
}
.table-detail-view-address {
- height: 756px;
- width: 461px;
+ height: 756px;
+ width: 461px;
}
.table-view-address {
- height: 711px;
- flex-grow: 1;
+ height: 711px;
+ flex-grow: 1;
}
.expandable-address .collapse5 {
- height: 758px;
+ height: 758px;
}
.table-detail-view-communication {
- height: 296px;
- width: 461px;
+ height: 296px;
+ width: 461px;
}
.table-view-communication {
- height: 263px;
+ height: 263px;
flex-grow: 1;
}
.expandable-communication .collapse5 {
- height: 310px;
+ height: 310px;
}
-.table-detail-view-module-assignment{
- height: 336px;
+.table-detail-view-module-assignment {
+ height: 336px;
width: 461px;
min-width: 461px;
}
-.table-view-module-assignment{
+.table-view-module-assignment {
height: 290px;
flex-grow: 1;
}
diff --git a/src/app/pages/persons/internal-person/internal-person-details/internal-person-details.component.html b/src/app/pages/persons/internal-person/internal-person-details/internal-person-details.component.html
index 5f50a27..29a9637 100644
--- a/src/app/pages/persons/internal-person/internal-person-details/internal-person-details.component.html
+++ b/src/app/pages/persons/internal-person/internal-person-details/internal-person-details.component.html
@@ -189,12 +189,19 @@
</div>
<!-- buttons -->
- <button *visibleByRight type="button" class="btn btn-success" (click)="internalPersonSandBox.persistInternalPerson()">
- {{ 'SaveBtn' | translate }}
- </button>
- <button type="button" class="btn btn-primary cancel-button" routerLink="/overview">
- {{ 'CancelBtn' | translate }}
- </button>
+ <div class="row justify-content-between">
+ <div>
+ <button *visibleByRight type="button" class="btn btn-success person-buttons" (click)="internalPersonSandBox.persistInternalPerson()">
+ {{ 'SaveBtn' | translate }}
+ </button>
+ <button type="button" class="btn btn-primary person-buttons cancel-button" routerLink="/overview">
+ {{ 'CancelBtn' | translate }}
+ </button>
+ </div>
+ <div class="person-buttons" *ngIf="internalPersonSandBox.internalPersonContactId">
+ <app-anonymizer [contactId]="internalPersonSandBox.internalPersonContactId"></app-anonymizer>
+ </div>
+ </div>
</div>
</form>
diff --git a/src/app/pages/persons/internal-person/internal-person-details/internal-person-details.component.scss b/src/app/pages/persons/internal-person/internal-person-details/internal-person-details.component.scss
index 0615b03..d73298c 100644
--- a/src/app/pages/persons/internal-person/internal-person-details/internal-person-details.component.scss
+++ b/src/app/pages/persons/internal-person/internal-person-details/internal-person-details.component.scss
@@ -10,8 +10,8 @@
*
* SPDX-License-Identifier: EPL-2.0
********************************************************************************/
-.btn-success {
- margin-right: 16px;
+.person-buttons {
+ margin: 16px;
}
.expandable-body-container {
display: flex;
diff --git a/src/app/shared/components/anonymizer/anonymizer.component.html b/src/app/shared/components/anonymizer/anonymizer.component.html
new file mode 100644
index 0000000..a8ab33b
--- /dev/null
+++ b/src/app/shared/components/anonymizer/anonymizer.component.html
@@ -0,0 +1,15 @@
+<!-- /********************************************************************************
+* Copyright (c) 2020 Contributors to the Eclipse Foundation
+*
+* See the NOTICE file(s) distributed with this work for additional
+* information regarding copyright ownership.
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License v. 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/ -->
+<p>
+ <button type="button" class="btn btn-warning" (click)="anonymizeContact()">Anonymisieren</button>
+</p>
diff --git a/src/app/shared/components/anonymizer/anonymizer.component.scss b/src/app/shared/components/anonymizer/anonymizer.component.scss
new file mode 100644
index 0000000..c37e40b
--- /dev/null
+++ b/src/app/shared/components/anonymizer/anonymizer.component.scss
@@ -0,0 +1,12 @@
+/********************************************************************************
+ * Copyright (c) 2020 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ ********************************************************************************/
diff --git a/src/app/shared/components/anonymizer/anonymizer.component.spec.ts b/src/app/shared/components/anonymizer/anonymizer.component.spec.ts
new file mode 100644
index 0000000..07642e4
--- /dev/null
+++ b/src/app/shared/components/anonymizer/anonymizer.component.spec.ts
@@ -0,0 +1,41 @@
+/********************************************************************************
+ * Copyright (c) 2020 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ ********************************************************************************/
+import { AnonymizerComponent } from '@shared/components/anonymizer/anonymizer.component';
+
+describe('AnonymizerComponent', () => {
+ let component: AnonymizerComponent;
+ const sandbox: any = {
+ anonymizeContact: () => {},
+ endSubscriptions: () => {},
+ };
+
+ beforeEach(() => {
+ component = new AnonymizerComponent(sandbox);
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+
+ it('should transfer anonymizeContact call to sandbox', () => {
+ const spy: any = spyOn(sandbox, 'anonymizeContact');
+ component.anonymizeContact();
+ expect(spy).toHaveBeenCalled();
+ });
+
+ it('should reset component', () => {
+ component.contactId = 'x';
+ component.ngOnDestroy();
+ expect(component.contactId).toBe(null);
+ });
+});
diff --git a/src/app/shared/components/anonymizer/anonymizer.component.ts b/src/app/shared/components/anonymizer/anonymizer.component.ts
new file mode 100644
index 0000000..b843de9
--- /dev/null
+++ b/src/app/shared/components/anonymizer/anonymizer.component.ts
@@ -0,0 +1,34 @@
+/********************************************************************************
+ * Copyright (c) 2020 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ ********************************************************************************/
+import { AnonymizerSandbox } from '@shared/components/anonymizer/anonymizer.sandbox';
+import { Component, Input } from '@angular/core';
+
+@Component({
+ selector: 'app-anonymizer',
+ templateUrl: './anonymizer.component.html',
+ styleUrls: ['./anonymizer.component.scss'],
+})
+export class AnonymizerComponent {
+ @Input() contactId: string;
+
+ constructor(private _sandbox: AnonymizerSandbox) {}
+
+ public anonymizeContact() {
+ this._sandbox.anonymizeContact(this.contactId);
+ }
+
+ ngOnDestroy() {
+ this._sandbox.endSubscriptions();
+ this.contactId = null;
+ }
+}
diff --git a/src/app/shared/components/anonymizer/anonymizer.sandbox.spec.ts b/src/app/shared/components/anonymizer/anonymizer.sandbox.spec.ts
new file mode 100644
index 0000000..f40b89f
--- /dev/null
+++ b/src/app/shared/components/anonymizer/anonymizer.sandbox.spec.ts
@@ -0,0 +1,46 @@
+/********************************************************************************
+ * Copyright (c) 2020 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ ********************************************************************************/
+import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
+import { AnonymizerSandbox } from '@shared/components/anonymizer/anonymizer.sandbox';
+import { Store, ActionsSubject } from '@ngrx/store';
+import { State } from '@shared/store';
+import { of } from 'rxjs';
+import { Router } from '@angular/router';
+
+describe('AnonymizerSandbox', () => {
+ let service: AnonymizerSandbox;
+ let appState: Store<State>;
+ let actionSubject: ActionsSubject;
+ let router: Router;
+ let modalService: NgbModal;
+
+ beforeEach(() => {
+ appState = { dispatch: () => {}, pipe: () => of(true), select: () => of(true) } as any;
+ actionSubject = { pipe: () => of(true) } as any;
+ router = { navigateByUrl() {} } as any;
+ modalService = { open() {} } as any;
+ spyOn(appState, 'dispatch').and.callFake(() => {});
+
+ service = new AnonymizerSandbox(appState, actionSubject, router, modalService);
+ });
+
+ it('should create SalutationsSandbox service', () => {
+ expect(service).toBeTruthy();
+ });
+
+ it('should open modal before anonymizing an contact', () => {
+ spyOn(service['modalService'], 'open').and.returnValue({ componentInstance: { title: '' }, result: { then: () => of(true) } } as any);
+ service.anonymizeContact('x');
+ expect(modalService.open).toHaveBeenCalled();
+ });
+});
diff --git a/src/app/shared/components/anonymizer/anonymizer.sandbox.ts b/src/app/shared/components/anonymizer/anonymizer.sandbox.ts
new file mode 100644
index 0000000..15084e4
--- /dev/null
+++ b/src/app/shared/components/anonymizer/anonymizer.sandbox.ts
@@ -0,0 +1,44 @@
+/********************************************************************************
+ * Copyright (c) 2020 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ ********************************************************************************/
+import { Injectable } from '@angular/core';
+import { BaseSandbox } from '@shared/sandbox/base.sandbox';
+import { Store, ActionsSubject } from '@ngrx/store';
+import * as store from '@shared/store';
+import * as contactsActions from '@shared/store/actions/contacts.action';
+import { ofType } from '@ngrx/effects';
+import { takeUntil } from 'rxjs/operators';
+import { Router } from '@angular/router';
+import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
+import { SafetyQueryDialogComponent } from '@shared/components/dialogs/safety-query-dialog/safety-query-dialog.component';
+
+@Injectable()
+export class AnonymizerSandbox extends BaseSandbox {
+ constructor(protected appState$: Store<store.State>, protected actionsSubject: ActionsSubject, protected router: Router, protected modalService: NgbModal) {
+ super(appState$);
+ this.actionsSubject.pipe(ofType(contactsActions.anonymizeContactSuccess), takeUntil(this._endSubscriptions$)).subscribe(() => {
+ this.router.navigateByUrl(`/overview`);
+ });
+ }
+
+ public anonymizeContact(contactId: string): void {
+ const modalRef = this.modalService.open(SafetyQueryDialogComponent);
+ modalRef.componentInstance.title = 'ConfirmDialog.Action.anonymize';
+ modalRef.componentInstance.body = 'ConfirmDialog.Anonymization';
+ modalRef.result.then(
+ () => {
+ this.appState$.dispatch(contactsActions.anonymizeContact({ payload: contactId }));
+ },
+ () => {}
+ );
+ }
+}
diff --git a/src/app/shared/components/expandable/expandable.component.html b/src/app/shared/components/expandable/expandable.component.html
index bf2c334..d952ee5 100644
--- a/src/app/shared/components/expandable/expandable.component.html
+++ b/src/app/shared/components/expandable/expandable.component.html
@@ -11,19 +11,18 @@
* SPDX-License-Identifier: EPL-2.0
********************************************************************************/ -->
<div class="panel panel-default" style="width:100%;">
- <div class="panel-heading">
- <h4 class="panel-title">
- <a data-toggle="collapse">
- <i *ngIf="isExpandedStatus" class="fa fa-chevron-up" aria-hidden="true"></i>
- <i *ngIf="!isExpandedStatus" class="fa fa-chevron-down" aria-hidden="true"></i>
- </a>
- <a data-toggle="collapse" href="#{{collapseId}}" (click)="isExpandedStatus = !isExpandedStatus">
- <ng-content select="[header]"></ng-content>
- </a>
-
- </h4>
- </div>
- <div *ngIf="isExpandedStatus" id="{{collapseId}}" class="collapse5 panel-collapse collapse in" [ngClass]="{'in': !isStatusCollapsed }">
- <ng-content class="bodyContent" select="[body]"></ng-content>
- </div>
+ <div class="panel-heading">
+ <h4 class="panel-title">
+ <a data-toggle="collapse">
+ <em *ngIf="isExpandedStatus" class="fa fa-chevron-up" aria-hidden="true"></em>
+ <em *ngIf="!isExpandedStatus" class="fa fa-chevron-down" aria-hidden="true"></em>
+ </a>
+ <a data-toggle="collapse" href="#{{ collapseId }}" (click)="isExpandedStatus = !isExpandedStatus">
+ <ng-content select="[header]"></ng-content>
+ </a>
+ </h4>
+ </div>
+ <div *ngIf="isExpandedStatus" id="{{ collapseId }}" class="collapse5 panel-collapse collapse in" [ngClass]="{ in: !isStatusCollapsed }">
+ <ng-content class="bodyContent" select="[body]"></ng-content>
+ </div>
</div>
diff --git a/src/app/shared/components/index.ts b/src/app/shared/components/index.ts
index dd0c87a..1834bdf 100644
--- a/src/app/shared/components/index.ts
+++ b/src/app/shared/components/index.ts
@@ -44,6 +44,8 @@
import { NgbDatepickerModule, NgbDateParserFormatter } from '@ng-bootstrap/ng-bootstrap';
import { NgbDateCustomParserFormatter } from '@shared/pipes/ngb-date-custom-parser-formatter';
import { DateCellRendererComponent } from '@shared/components/cell-renderer/date-cell-renderer/date-cell-renderer.component';
+import { AnonymizerComponent } from '@shared/components/anonymizer/anonymizer.component';
+import { AnonymizerSandbox } from '@shared/components/anonymizer/anonymizer.sandbox';
export const COMPONENTS = [
SpinnerComponent,
@@ -62,6 +64,7 @@
UserModuleAssignmentDataDetailsComponent,
UserModuleAssignmentDataListComponent,
DateCellRendererComponent,
+ AnonymizerComponent,
];
@NgModule({
@@ -97,6 +100,7 @@
UserModuleAssignmentsService,
DatePipe,
{ provide: NgbDateParserFormatter, useClass: NgbDateCustomParserFormatter },
+ AnonymizerSandbox,
],
})
export class ComponentsModule {}
diff --git a/src/app/shared/components/list-details-view/user-module-assignment/details/details.component.html b/src/app/shared/components/list-details-view/user-module-assignment/details/details.component.html
index 69931c7..013a253 100644
--- a/src/app/shared/components/list-details-view/user-module-assignment/details/details.component.html
+++ b/src/app/shared/components/list-details-view/user-module-assignment/details/details.component.html
@@ -31,7 +31,7 @@
<div class="input-group col-sm-7">
<div class="input-group-prepend">
<button class="btn btn-outline-primary calendar" (click)="expiringDateCalendar.toggle()" type="button">
- <i class="fa fa-calendar"></i>
+ <em class="fa fa-calendar"></em>
</button>
</div>
<input
@@ -49,7 +49,7 @@
/>
<div class="input-group-append">
<button class="btn btn-outline-primary calendar" (click)="reset('expiringDate')" type="button">
- <i class="fa fa-times-circle" aria-hidden="true"></i>
+ <em class="fa fa-times-circle" aria-hidden="true"></em>
</button>
</div>
</div>
@@ -61,7 +61,7 @@
<div class="input-group col-sm-7">
<div class="input-group-prepend">
<button class="btn btn-outline-primary calendar" (click)="deletionLockUntilCalendar.toggle()" type="button">
- <i class="fa fa-calendar"></i>
+ <em class="fa fa-calendar"></em>
</button>
</div>
<input
@@ -79,7 +79,7 @@
/>
<div class="input-group-append">
<button class="btn btn-outline-primary calendar" (click)="reset('deletionLockUntil')" type="button">
- <i class="fa fa-times-circle" aria-hidden="true"></i>
+ <em class="fa fa-times-circle" aria-hidden="true"></em>
</button>
</div>
</div>
diff --git a/src/app/shared/models/modifiedContacts.model.ts b/src/app/shared/models/modifiedContacts.model.ts
index 886e071..e7817a9 100644
--- a/src/app/shared/models/modifiedContacts.model.ts
+++ b/src/app/shared/models/modifiedContacts.model.ts
@@ -1,15 +1,17 @@
import { Contact } from '@shared/models';
export class ModifiedContacts {
+ public searchText: string = null;
+ public contactTypeId: string = '';
+ public sort: string = null;
+ public moduleName: string = null;
+ public withoutAssignedModule: boolean = null;
+ public expiringDataInPast: boolean = null;
+ public deletionLockExceeded: boolean = null;
- public searchText: string = null;
- public contactTypeId: string = '';
- public sort: string = null;
-
- public constructor(data: any = null) {
- Object.keys(data || {})
- .filter(property => this.hasOwnProperty(property))
- .forEach(property => (this[property] = data[property]));
- }
+ public constructor(data: any = null) {
+ Object.keys(data || {})
+ .filter(property => this.hasOwnProperty(property))
+ .forEach(property => (this[property] = data[property]));
}
-
\ No newline at end of file
+}
diff --git a/src/app/shared/store/actions/contacts.action.ts b/src/app/shared/store/actions/contacts.action.ts
index bcf6753..826eef0 100644
--- a/src/app/shared/store/actions/contacts.action.ts
+++ b/src/app/shared/store/actions/contacts.action.ts
@@ -28,3 +28,7 @@
export const loadContactsPage = createAction('[Contacts] Load Page', props<ILoadContactsPage>());
export const loadContactsPageSuccess = createAction('[Contacts] Load Page Success', props<ILoadContactsPageSuccess>());
export const loadContactsPageFail = createAction('[Contacts] Load Page Fail', props<ILoadContactsPageFail>());
+
+export const anonymizeContact = createAction('[Contact] Anonymize', props<{ payload: string }>());
+export const anonymizeContactSuccess = createAction('[Contact] Anonymize Success');
+export const anonymizeContactFail = createAction('[Contact] Anonymize Fail', props<{ payload: string }>());
diff --git a/src/app/shared/store/effects/contacts.effect.ts b/src/app/shared/store/effects/contacts.effect.ts
index c0021c5..a273757 100644
--- a/src/app/shared/store/effects/contacts.effect.ts
+++ b/src/app/shared/store/effects/contacts.effect.ts
@@ -1,4 +1,4 @@
- /********************************************************************************
+/********************************************************************************
* Copyright (c) 2020 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
@@ -25,11 +25,11 @@
export class ContactsEffects {
/* paged list */
getContactsPage$: any = createEffect(() =>
- this.actions$.pipe(
+ this._actions$.pipe(
ofType(contactsActions.loadContactsPage),
map(action => action['payload']),
switchMap((request: PageRequestInterface) => {
- return this.contactsApiClient.getContacts(request).pipe(
+ return this._contactsApiClient.getContacts(request).pipe(
map(contacts => contactsActions.loadContactsPageSuccess({ payload: contacts })),
catchError(error => of(contactsActions.loadContactsPageFail({ payload: error })))
);
@@ -37,5 +37,18 @@
)
);
- constructor(private actions$: Actions, private contactsApiClient: ContactsApiClient) {}
+ anonymizeContact$: any = createEffect(() =>
+ this._actions$.pipe(
+ ofType(contactsActions.anonymizeContact),
+ map(action => action['payload']),
+ switchMap((id: string) => {
+ return this._contactsApiClient.anonymizeContact(id).pipe(
+ map(() => contactsActions.anonymizeContactSuccess()),
+ catchError(error => of(contactsActions.anonymizeContactFail({ payload: error })))
+ );
+ })
+ )
+ );
+
+ constructor(private _actions$: Actions, private _contactsApiClient: ContactsApiClient) {}
}
diff --git a/src/app/shared/store/effects/contacts.effects.spec.ts b/src/app/shared/store/effects/contacts.effects.spec.ts
index 681a430..9d4c8ec 100644
--- a/src/app/shared/store/effects/contacts.effects.spec.ts
+++ b/src/app/shared/store/effects/contacts.effects.spec.ts
@@ -1,4 +1,4 @@
- /********************************************************************************
+/********************************************************************************
* Copyright (c) 2020 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
@@ -13,27 +13,24 @@
import { PageRequestInterface } from '@shared/models/page/page-request.interface';
import { take } from 'rxjs/operators';
import { ContactsEffects } from '@shared/store/effects/contacts.effect';
-import { Subject, of, throwError } from 'rxjs';
+import { Subject, of, throwError, Observable } from 'rxjs';
import { Contact } from '@shared/models';
import * as contactsActions from '@shared/store/actions/contacts.action';
import { ContactsApiClient } from '@pages/contacts/contacts-api-client';
import { PageModel } from '@shared/models/page/page.model';
-
describe('Contacts Effects', () => {
-
let effects: ContactsEffects;
let actions$: Subject<any>;
let apiClient: ContactsApiClient;
- let apiResponse = new PageModel<Contact>(
- {
- content: [new Contact({id: "1"})]
- }
- ) as any;
+ let apiResponse = new PageModel<Contact>({
+ content: [new Contact({ id: '1' })],
+ }) as any;
beforeEach(() => {
apiClient = {
- getContacts() {}
+ getContacts() {},
+ anonymizeContact() {},
} as any;
actions$ = new Subject();
effects = new ContactsEffects(actions$, apiClient);
@@ -43,36 +40,47 @@
expect(effects).toBeTruthy();
});
- it('should equal loadContactsPageSuccess after getContactsPage', (done) => {
- let request = {payload: {
+ it('should equal loadContactsPageSuccess after getContactsPage', done => {
+ let request = {
+ payload: {
pageNumber: 1,
pageSize: 3,
- } as PageRequestInterface
- }
+ } as PageRequestInterface,
+ };
spyOn(apiClient, 'getContacts').and.returnValue(of(apiResponse));
effects.getContactsPage$.pipe(take(1)).subscribe(result => {
- expect(result).toEqual(contactsActions.loadContactsPageSuccess({payload: apiResponse}));
+ expect(result).toEqual(contactsActions.loadContactsPageSuccess({ payload: apiResponse }));
});
done();
actions$.next(contactsActions.loadContactsPage(request));
});
- it('should equal loadContactsPageFail after getContactsPage Error', (done) => {
- let request = {payload: {
+ it('should equal loadContactsPageFail after getContactsPage Error', done => {
+ let request = {
+ payload: {
pageNumber: 1,
pageSize: 3,
- } as PageRequestInterface
- }
+ } as PageRequestInterface,
+ };
spyOn(apiClient, 'getContacts').and.returnValue(throwError('x'));
effects.getContactsPage$.pipe(take(1)).subscribe(result => {
- expect(result).toEqual(contactsActions.loadContactsPageFail({payload: 'x'}));
+ expect(result).toEqual(contactsActions.loadContactsPageFail({ payload: 'x' }));
});
done();
actions$.next(contactsActions.loadContactsPage(request));
});
+ it('should successfully process on anonymizeContact action', done => {
+ apiResponse = new Observable<void>();
+ spyOn(apiClient, 'anonymizeContact').and.returnValue(of(apiResponse));
+ effects.anonymizeContact$.pipe(take(1)).subscribe(result => {
+ expect(result).toEqual(contactsActions.anonymizeContactSuccess());
+ });
+ done();
+ actions$.next(contactsActions.anonymizeContact({ payload: 'x' }));
+ });
});