# Conflicts:
#	dmp-frontend/src/app/ui/user-guide/user-guide-content/user-guide-content.component.ts
AdminTemplateRedesign
apapachristou 3 years ago
commit f94d4bad2b

@ -1,6 +1,8 @@
package eu.eudat.controllers;
import eu.eudat.logic.security.claims.ClaimedAuthorities;
import eu.eudat.models.data.helpers.responses.ResponseItem;
import eu.eudat.models.data.security.Principal;
import eu.eudat.models.data.userguide.UserGuide;
import eu.eudat.types.ApiMessageCode;
import org.springframework.beans.factory.annotation.Autowired;
@ -19,6 +21,8 @@ import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static eu.eudat.types.Authorities.ADMIN;
@RestController
@CrossOrigin
@RequestMapping(value = {"/api/userguide/"})
@ -31,13 +35,16 @@ public class UserGuideController {
this.environment = environment;
}
@RequestMapping(path = "current", method = RequestMethod.GET )
public ResponseEntity getUserGuide() throws IOException {
@RequestMapping(path = "{lang}", method = RequestMethod.GET )
public ResponseEntity getUserGuide(@PathVariable(name = "lang") String lang) throws IOException {
Stream<Path> walk = Files.walk(Paths.get(this.environment.getProperty("userguide.path")));
List<String> result = walk.filter(Files::isRegularFile)
.map(Path::toString).collect(Collectors.toList());
String fileName = result.get(0);
String fileName = result.stream().filter(guide -> guide.contains("_" + lang)).findFirst().orElse(null);
if (fileName == null) {
fileName = result.stream().filter(guide -> guide.contains("_en")).findFirst().get();
}
InputStream is = new FileInputStream(fileName);
String[] filepath = fileName.split("\\.")[0].split("\\\\");
@ -60,7 +67,7 @@ public class UserGuideController {
@RequestMapping(value = "current", method = RequestMethod.POST)
public @ResponseBody
ResponseEntity<ResponseItem<String>> updateGuide(@RequestBody UserGuide guide) throws Exception {
ResponseEntity<ResponseItem<String>> updateGuide(@RequestBody UserGuide guide, @ClaimedAuthorities(claims = {ADMIN}) Principal principal) throws Exception {
String fileName = this.environment.getProperty("userguide.path") + guide.getName() + ".html";
OutputStream os = new FileOutputStream(fileName);
os.write(guide.getHtml().getBytes());

@ -7,10 +7,21 @@ import java.util.HashMap;
import java.util.Map;
public class DataRepositoriesData extends FieldData<DataRepositoriesData> {
private Boolean multiAutoComplete;
public Boolean getMultiAutoComplete() {
return multiAutoComplete;
}
public void setMultiAutoComplete(Boolean multiAutoComplete) {
this.multiAutoComplete = multiAutoComplete;
}
@Override
public DataRepositoriesData fromData(Object data) {
if (data != null) {
this.setLabel((String) ((Map<String, Object>) data).get("label"));
this.setMultiAutoComplete(((Map<String, Object>) data).get("multiAutoComplete") != null ? (Boolean) ((Map<String, Object>) data).get("multiAutoComplete") : false);
}
return this;
}
@ -24,12 +35,16 @@ public class DataRepositoriesData extends FieldData<DataRepositoriesData> {
public Element toXml(Document doc) {
Element root = doc.createElement("data");
root.setAttribute("label", this.getLabel());
if (this.getMultiAutoComplete() != null) {
root.setAttribute("multiAutoComplete", this.getMultiAutoComplete().toString());
}
return root;
}
@Override
public DataRepositoriesData fromXml(Element item) {
this.setLabel(item != null ? item.getAttribute("label") : "");
this.setMultiAutoComplete(Boolean.parseBoolean(item.getAttribute("multiAutoComplete")));
return this;
}
@ -37,6 +52,7 @@ public class DataRepositoriesData extends FieldData<DataRepositoriesData> {
public Map<String, Object> toMap(Element item) {
HashMap dataMap = new HashMap();
dataMap.put("label", item != null ? item.getAttribute("label") : "");
dataMap.put("multiAutoComplete", item != null ? item.getAttribute("multiAutoComplete") : false);
return dataMap;
}
}

@ -7,10 +7,21 @@ import java.util.HashMap;
import java.util.Map;
public class ExternalDatasetsData extends FieldData<ExternalDatasetsData> {
private Boolean multiAutoComplete;
public Boolean getMultiAutoComplete() {
return multiAutoComplete;
}
public void setMultiAutoComplete(Boolean multiAutoComplete) {
this.multiAutoComplete = multiAutoComplete;
}
@Override
public ExternalDatasetsData fromData(Object data) {
if (data != null) {
this.setLabel((String) ((Map<String, Object>) data).get("label"));
this.setMultiAutoComplete(((Map<String, Object>) data).get("multiAutoComplete") != null ? (Boolean) ((Map<String, Object>) data).get("multiAutoComplete") : false);
}
return this;
}
@ -24,12 +35,16 @@ public class ExternalDatasetsData extends FieldData<ExternalDatasetsData> {
public Element toXml(Document doc) {
Element root = doc.createElement("data");
root.setAttribute("label", this.getLabel());
if (this.getMultiAutoComplete() != null) {
root.setAttribute("multiAutoComplete", this.getMultiAutoComplete().toString());
}
return root;
}
@Override
public ExternalDatasetsData fromXml(Element item) {
this.setLabel(item != null ? item.getAttribute("label") : "");
this.setMultiAutoComplete(Boolean.parseBoolean(item.getAttribute("multiAutoComplete")));
return this;
}
@ -37,6 +52,7 @@ public class ExternalDatasetsData extends FieldData<ExternalDatasetsData> {
public Map<String, Object> toMap(Element item) {
HashMap dataMap = new HashMap();
dataMap.put("label", item != null ? item.getAttribute("label") : "");
dataMap.put("multiAutoComplete", item != null ? item.getAttribute("multiAutoComplete") : false);
return dataMap;
}
}

@ -7,10 +7,21 @@ import java.util.HashMap;
import java.util.Map;
public class OrganizationsData extends FieldData<OrganizationsData> {
private Boolean multiAutoComplete;
public Boolean getMultiAutoComplete() {
return multiAutoComplete;
}
public void setMultiAutoComplete(Boolean multiAutoComplete) {
this.multiAutoComplete = multiAutoComplete;
}
@Override
public OrganizationsData fromData(Object data) {
if (data != null) {
this.setLabel((String) ((Map<String, Object>) data).get("label"));
this.setMultiAutoComplete(((Map<String, Object>) data).get("multiAutoComplete") != null ? (Boolean) ((Map<String, Object>) data).get("multiAutoComplete") : false);
}
return this;
}
@ -24,12 +35,16 @@ public class OrganizationsData extends FieldData<OrganizationsData> {
public Element toXml(Document doc) {
Element root = doc.createElement("data");
root.setAttribute("label", this.getLabel());
if (this.getMultiAutoComplete() != null) {
root.setAttribute("multiAutoComplete", this.getMultiAutoComplete().toString());
}
return root;
}
@Override
public OrganizationsData fromXml(Element item) {
this.setLabel(item != null ? item.getAttribute("label") : "");
this.setMultiAutoComplete(Boolean.parseBoolean(item.getAttribute("multiAutoComplete")));
return this;
}
@ -37,6 +52,7 @@ public class OrganizationsData extends FieldData<OrganizationsData> {
public Map<String, Object> toMap(Element item) {
HashMap dataMap = new HashMap();
dataMap.put("label", item != null ? item.getAttribute("label") : "");
dataMap.put("multiAutoComplete", item != null ? item.getAttribute("multiAutoComplete") : false);
return dataMap;
}
}

@ -7,10 +7,21 @@ import java.util.HashMap;
import java.util.Map;
public class RegistriesData extends FieldData<RegistriesData> {
private Boolean multiAutoComplete;
public Boolean getMultiAutoComplete() {
return multiAutoComplete;
}
public void setMultiAutoComplete(Boolean multiAutoComplete) {
this.multiAutoComplete = multiAutoComplete;
}
@Override
public RegistriesData fromData(Object data) {
if (data != null) {
this.setLabel((String) ((Map<String, Object>) data).get("label"));
this.setMultiAutoComplete((Boolean) ((Map<String, Object>) data).get("multiAutoComplete"));
}
return this;
}
@ -24,12 +35,16 @@ public class RegistriesData extends FieldData<RegistriesData> {
public Element toXml(Document doc) {
Element root = doc.createElement("data");
root.setAttribute("label", this.getLabel());
if (this.getMultiAutoComplete() != null) {
root.setAttribute("multiAutoComplete", this.getMultiAutoComplete().toString());
}
return root;
}
@Override
public RegistriesData fromXml(Element item) {
this.setLabel(item != null ? item.getAttribute("label") : "");
this.setMultiAutoComplete(Boolean.parseBoolean(item.getAttribute("multiAutoComplete")));
return this;
}
@ -37,6 +52,7 @@ public class RegistriesData extends FieldData<RegistriesData> {
public Map<String, Object> toMap(Element item) {
HashMap dataMap = new HashMap();
dataMap.put("label", item != null ? item.getAttribute("label") : "");
dataMap.put("multiAutoComplete", item != null ? item.getAttribute("multiAutoComplete") : false);
return dataMap;
}
}

@ -7,10 +7,21 @@ import java.util.HashMap;
import java.util.Map;
public class ResearcherData extends FieldData<ResearcherData> {
private Boolean multiAutoComplete;
public Boolean getMultiAutoComplete() {
return multiAutoComplete;
}
public void setMultiAutoComplete(Boolean multiAutoComplete) {
this.multiAutoComplete = multiAutoComplete;
}
@Override
public ResearcherData fromData(Object data) {
if (data != null) {
this.setLabel((String) ((Map<String, Object>) data).get("label"));
this.setMultiAutoComplete(((Map<String, Object>) data).get("multiAutoComplete") != null ? (Boolean) ((Map<String, Object>) data).get("multiAutoComplete") : false);
}
return this;
}
@ -24,12 +35,16 @@ public class ResearcherData extends FieldData<ResearcherData> {
public Element toXml(Document doc) {
Element root = doc.createElement("data");
root.setAttribute("label", this.getLabel());
if (this.getMultiAutoComplete() != null) {
root.setAttribute("multiAutoComplete", this.getMultiAutoComplete().toString());
}
return root;
}
@Override
public ResearcherData fromXml(Element item) {
this.setLabel(item != null ? item.getAttribute("label") : "");
this.setMultiAutoComplete(Boolean.parseBoolean(item.getAttribute("multiAutoComplete")));
return this;
}
@ -37,6 +52,7 @@ public class ResearcherData extends FieldData<ResearcherData> {
public Map<String, Object> toMap(Element item) {
HashMap dataMap = new HashMap();
dataMap.put("label", item != null ? item.getAttribute("label") : "");
dataMap.put("multiAutoComplete", item != null ? item.getAttribute("multiAutoComplete") : false);
return dataMap;
}
}

@ -7,10 +7,21 @@ import java.util.HashMap;
import java.util.Map;
public class ServicesData extends FieldData<ServicesData> {
private Boolean multiAutoComplete;
public Boolean getMultiAutoComplete() {
return multiAutoComplete;
}
public void setMultiAutoComplete(Boolean multiAutoComplete) {
this.multiAutoComplete = multiAutoComplete;
}
@Override
public ServicesData fromData(Object data) {
if (data != null) {
this.setLabel((String) ((Map<String, Object>) data).get("label"));
this.setMultiAutoComplete(((Map<String, Object>) data).get("multiAutoComplete") != null ? (Boolean) ((Map<String, Object>) data).get("multiAutoComplete") : false);
}
return this;
}
@ -24,12 +35,16 @@ public class ServicesData extends FieldData<ServicesData> {
public Element toXml(Document doc) {
Element root = doc.createElement("data");
root.setAttribute("label", this.getLabel());
if (this.getMultiAutoComplete() != null) {
root.setAttribute("multiAutoComplete", this.getMultiAutoComplete().toString());
}
return root;
}
@Override
public ServicesData fromXml(Element item) {
this.setLabel(item != null ? item.getAttribute("label") : "");
this.setMultiAutoComplete(Boolean.parseBoolean(item.getAttribute("multiAutoComplete")));
return this;
}
@ -37,6 +52,7 @@ public class ServicesData extends FieldData<ServicesData> {
public Map<String, Object> toMap(Element item) {
HashMap dataMap = new HashMap();
dataMap.put("label", item != null ? item.getAttribute("label") : "");
dataMap.put("multiAutoComplete", item != null ? item.getAttribute("multiAutoComplete") : false);
return dataMap;
}
}

@ -35,6 +35,7 @@
"ngx-cookieconsent": "^2.2.3",
"ngx-dropzone": "^2.2.2",
"ngx-guided-tour": "^1.1.10",
"ngx-matomo": "^0.1.4",
"rxjs": "^6.3.2",
"tinymce": "^5.4.2",
"tslib": "^1.10.0",

@ -16,6 +16,8 @@ import { LanguageService } from './core/services/language/language.service';
import { ConfigurationService } from './core/services/configuration/configuration.service';
import { Location } from '@angular/common';
import { MatomoInjector } from 'ngx-matomo';
import { MatomoService } from './core/services/matomo/matomo-service';
declare const gapi: any;
@ -46,9 +48,11 @@ export class AppComponent implements OnInit {
private ccService: NgcCookieConsentService,
private language: LanguageService,
private configurationService: ConfigurationService,
private location: Location
private location: Location,
private matomoService: MatomoService
) {
this.initializeServices();
this.matomoService.init();
this.helpContentEnabled = configurationService.helpService.enabled;
}

@ -1,7 +1,8 @@
import { OverlayModule } from '@angular/cdk/overlay';
import { HttpClient, HttpClientModule } from '@angular/common/http';
import { LOCALE_ID, NgModule, APP_INITIALIZER } from '@angular/core';
import { LOCALE_ID, NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { MatFormFieldDefaultOptions, MAT_FORM_FIELD_DEFAULT_OPTIONS } from '@angular/material';
import { MatMomentDateModule, MAT_MOMENT_DATE_FORMATS } from '@angular/material-moment-adapter';
import { DateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE } from '@angular/material/core';
import { BrowserModule, Title } from '@angular/platform-browser';
@ -23,16 +24,14 @@ import { MomentUtcDateAdapter } from '@common/date/moment-utc-date-adapter';
import { CommonHttpModule } from '@common/http/common-http.module';
import { CommonUiModule } from '@common/ui/common-ui.module';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
import { environment } from 'environments/environment';
import { CookieService } from 'ngx-cookie-service';
import { NgcCookieConsentConfig, NgcCookieConsentModule } from 'ngx-cookieconsent';
import { TranslateServerLoader } from './core/services/language/server.loader';
import { BaseHttpService } from './core/services/http/base-http.service';
import { MatomoModule } from 'ngx-matomo';
import { ConfigurationService } from './core/services/configuration/configuration.service';
import { Oauth2DialogModule } from './ui/misc/oauth2-dialog/oauth2-dialog.module';
import { MAT_FORM_FIELD_DEFAULT_OPTIONS, MatFormFieldDefaultOptions } from '@angular/material';
import { TranslateServerLoader } from './core/services/language/server.loader';
import { MatomoService } from './core/services/matomo/matomo-service';
import { GuidedTourModule } from './library/guided-tour/guided-tour.module';
import { Oauth2DialogModule } from './ui/misc/oauth2-dialog/oauth2-dialog.module';
// AoT requires an exported function for factories
export function HttpLoaderFactory(http: HttpClient, appConfig: ConfigurationService) {
@ -95,6 +94,7 @@ const appearance: MatFormFieldDefaultOptions = {
CommonHttpModule,
MatMomentDateModule,
LoginModule,
MatomoModule,
//Ui
NotificationModule,
NavigationModule,
@ -131,7 +131,8 @@ const appearance: MatFormFieldDefaultOptions = {
useValue: appearance
},
Title,
CookieService
CookieService,
MatomoService
],
bootstrap: [AppComponent]
})

@ -1,8 +1,14 @@
import { ModuleWithProviders, NgModule, Optional, SkipSelf, APP_INITIALIZER } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { APP_INITIALIZER, ModuleWithProviders, NgModule, Optional, SkipSelf } from '@angular/core';
import { CookieService } from 'ngx-cookie-service';
import { AdminAuthGuard } from './admin-auth-guard.service';
import { AuthGuard } from './auth-guard.service';
import { AuthService } from './services/auth/auth.service';
import { ConfigurationService } from './services/configuration/configuration.service';
import { ContactSupportService } from './services/contact-support/contact-support.service';
import { CultureService } from './services/culture/culture-service';
import { LanguageInfoService } from './services/culture/language-info-service';
import { CurrencyService } from './services/currency/currency.service';
import { DashboardService } from './services/dashboard/dashboard.service';
import { DatasetProfileService } from './services/dataset-profile/dataset-profile.service';
import { DatasetWizardService } from './services/dataset-wizard/dataset-wizard.service';
@ -11,6 +17,7 @@ import { DatasetService } from './services/dataset/dataset.service';
import { DmpInvitationService } from './services/dmp/dmp-invitation.service';
import { DmpProfileService } from './services/dmp/dmp-profile.service';
import { DmpService } from './services/dmp/dmp.service';
import { EmailConfirmationService } from './services/email-confirmation/email-confirmation.service';
import { ExternalDataRepositoryService } from './services/external-sources/data-repository/extternal-data-repository.service';
import { ExternalDatasetService } from './services/external-sources/dataset/external-dataset.service';
import { ExternalSourcesConfigurationService } from './services/external-sources/external-sources-configuration.service';
@ -18,32 +25,25 @@ import { ExternalSourcesService } from './services/external-sources/external-sou
import { ExternalRegistryService } from './services/external-sources/registry/external-registry.service';
import { ExternalResearcherService } from './services/external-sources/researcher/external-researcher.service';
import { ExternalServiceService } from './services/external-sources/service/external-service.service';
import { FunderService } from './services/funder/funder.service';
import { GrantFileUploadService } from './services/grant/grant-file-upload.service';
import { GrantService } from './services/grant/grant.service';
import { BaseHttpService } from './services/http/base-http.service';
import { LanguageService } from './services/language/language.service';
import { LockService } from './services/lock/lock.service';
import { LoggingService } from './services/logging/logging-service';
import { MergeEmailConfirmationService } from './services/merge-email-confirmation/merge-email-confirmation.service';
import { UiNotificationService } from './services/notification/ui-notification-service';
import { OrganisationService } from './services/organisation/organisation.service';
import { ProgressIndicationService } from './services/progress-indication/progress-indication-service';
import { GrantFileUploadService } from './services/grant/grant-file-upload.service';
import { GrantService } from './services/grant/grant.service';
import { ProjectService } from './services/project/project.service';
import { QuickWizardService } from './services/quick-wizard/quick-wizard.service';
import { SearchBarService } from './services/search-bar/search-bar.service';
import { TimezoneService } from './services/timezone/timezone-service';
import { UserGuideService } from './services/user-guide/user-guide.service';
import { UserService } from './services/user/user.service';
import { CollectionUtils } from './services/utilities/collection-utils.service';
import { TypeUtils } from './services/utilities/type-utils.service';
import { QuickWizardService } from './services/quick-wizard/quick-wizard.service';
import { OrganisationService } from './services/organisation/organisation.service';
import { EmailConfirmationService } from './services/email-confirmation/email-confirmation.service';
import { FunderService } from './services/funder/funder.service';
import { ContactSupportService } from './services/contact-support/contact-support.service';
import { LanguageService } from './services/language/language.service';
import { AdminAuthGuard } from './admin-auth-guard.service';
import { LockService } from './services/lock/lock.service';
import { UserGuideService } from './services/user-guide/user-guide.service';
import { ConfigurationService } from './services/configuration/configuration.service';
import { HttpClient } from '@angular/common/http';
import { LanguageInfoService } from './services/culture/language-info-service';
import { CurrencyService } from './services/currency/currency.service';
import { MergeEmailConfirmationService } from './services/merge-email-confirmation/merge-email-confirmation.service';
//
//
// This is shared module that provides all the services. Its imported only once on the AppModule.

@ -71,19 +71,19 @@ export interface DmpsAutoCompleteFieldData extends FieldData {
}
export interface ExternalDatasetsFieldData extends FieldData {
multiAutoComplete: boolean;
}
export interface DataRepositoriesFieldData extends FieldData {
multiAutoComplete: boolean;
}
export interface RegistriesFieldData extends FieldData {
multiAutoComplete: boolean;
}
export interface ServicesFieldData extends FieldData {
multiAutoComplete: boolean;
}
export interface TagsFieldData extends FieldData {

@ -11,7 +11,7 @@ import { HttpClient } from '@angular/common/http';
@Injectable({
providedIn: 'root',
})
})
export class ConfigurationService extends BaseComponent {
constructor(private http: HttpClient) { super(); }
@ -52,12 +52,12 @@ export class ConfigurationService extends BaseComponent {
}
private _guideAssets: string;
get guideAssets():string {
get guideAssets(): string {
return this._guideAssets;
}
private _allowOrganizationCreator: boolean;
get allowOrganizationCreator():boolean {
get allowOrganizationCreator(): boolean {
return this._allowOrganizationCreator;
}
@ -76,6 +76,21 @@ export class ConfigurationService extends BaseComponent {
return this._orcidPath;
}
private _matomoEnabled: boolean;
get matomoEnabled(): boolean {
return this._matomoEnabled;
}
private _matomoSiteUrl: string;
get matomoSiteUrl(): string {
return this._matomoSiteUrl;
}
private _matomoSiteId: number;
get matomoSiteId(): number {
return this._matomoSiteId;
}
public loadConfiguration(): Promise<any> {
return new Promise((r, e) => {
@ -114,6 +129,11 @@ export class ConfigurationService extends BaseComponent {
this._doiLink = config.doiLink;
this._useSplash = config.useSplash;
this._orcidPath = config.orcidPath;
if (config.matomo) {
this._matomoEnabled = config.matomo.enabled;
this._matomoSiteUrl = config.matomo.url;
this._matomoSiteId = config.matomo.siteId;
}
}
}

@ -0,0 +1,39 @@
import { Injectable } from '@angular/core';
import { MatomoInjector, MatomoTracker } from 'ngx-matomo';
import { AuthService } from '../auth/auth.service';
import { ConfigurationService } from '../configuration/configuration.service';
@Injectable()
export class MatomoService {
constructor(
private configurationService: ConfigurationService,
private matomoInjector: MatomoInjector,
private matomoTracker: MatomoTracker,
private authService: AuthService
) {
}
init() {
if (this.configurationService.matomoEnabled) {
this.matomoInjector.init(this.configurationService.matomoSiteUrl, this.configurationService.matomoSiteId);
}
}
trackPageView(customTitle?: string): void {
if (this.configurationService.matomoEnabled) {
var principal = this.authService.current();
this.matomoTracker.setUserId(principal ? principal.id : null);
this.matomoTracker.trackPageView(customTitle);
}
}
trackSiteSearch(keyword: string, category?: string, resultsCount?: number): void {
if (this.configurationService.matomoEnabled) {
var principal = this.authService.current();
this.matomoTracker.setUserId(principal ? principal.id : null);
this.matomoTracker.trackSiteSearch(keyword, category, resultsCount);
}
}
}

@ -19,8 +19,8 @@ export class UserGuideService {
this.userGuideUrl = `${configurationService.server}userguide`;
}
public getUserGuide(): Observable<HttpResponse<Blob>> {
return this.http.get(`${this.userGuideUrl}/current`, { responseType: 'blob', observe: 'response', headers: {'Content-type': 'text/html',
public getUserGuide(lang: string): Observable<HttpResponse<Blob>> {
return this.http.get(`${this.userGuideUrl}/${lang}`, { responseType: 'blob', observe: 'response', headers: {'Content-type': 'text/html',
'Accept': 'text/html',
'Access-Control-Allow-Origin': this.configurationService.app,
'Access-Control-Allow-Credentials': 'true'} });

@ -1,19 +1,22 @@
import { FormGroup } from '@angular/forms';
import { FieldDataEditorModel } from './field-data-editor-model';
import { DatePickerFieldData, ExternalDatasetsFieldData, DataRepositoriesFieldData } from '../../../../../core/model/dataset-profile-definition/field-data/field-data';
import { DataRepositoriesFieldData } from '../../../../../core/model/dataset-profile-definition/field-data/field-data';
export class DataRepositoriesDataEditorModel extends FieldDataEditorModel<DataRepositoriesDataEditorModel> {
public label: string;
public multiAutoComplete: boolean;
buildForm(disabled: boolean = false, skipDisable: Array<String> = []): FormGroup {
const formGroup = this.formBuilder.group({
label: [{ value: this.label, disabled: (disabled && !skipDisable.includes('DataRepositoriesDataEditorModel.label')) }]
label: [{ value: this.label, disabled: (disabled && !skipDisable.includes('ServicesDataEditorModel.label')) }],
multiAutoComplete: [{ value: this.multiAutoComplete, disabled: (disabled && !skipDisable.includes('ServicesDataEditorModel.multiAutoComplete')) }]
});
return formGroup;
}
fromModel(item: DataRepositoriesFieldData): DataRepositoriesDataEditorModel {
this.label = item.label;
this.multiAutoComplete = item.multiAutoComplete;
return this;
}
}

@ -1,6 +1,6 @@
import { FormGroup } from '@angular/forms';
import { FieldDataEditorModel } from './field-data-editor-model';
import { DatePickerFieldData, ExternalDatasetsFieldData, DataRepositoriesFieldData, RegistriesFieldData, ServicesFieldData, TagsFieldData, ResearchersFieldData, OrganizationsFieldData, DatasetIdentifierFieldData } from '../../../../../core/model/dataset-profile-definition/field-data/field-data';
import { DatasetIdentifierFieldData } from '../../../../../core/model/dataset-profile-definition/field-data/field-data';
export class DatasetIdentifierDataEditorModel extends FieldDataEditorModel<DatasetIdentifierDataEditorModel> {
public label: string;

@ -1,19 +1,22 @@
import { FormGroup } from '@angular/forms';
import { FieldDataEditorModel } from './field-data-editor-model';
import { DatePickerFieldData, ExternalDatasetsFieldData } from '../../../../../core/model/dataset-profile-definition/field-data/field-data';
import { ExternalDatasetsFieldData } from '../../../../../core/model/dataset-profile-definition/field-data/field-data';
export class ExternalDatasetsDataEditorModel extends FieldDataEditorModel<ExternalDatasetsDataEditorModel> {
public label: string;
public multiAutoComplete: boolean;
buildForm(disabled: boolean = false, skipDisable: Array<String> = []): FormGroup {
const formGroup = this.formBuilder.group({
label: [{ value: this.label, disabled: (disabled && !skipDisable.includes('ExternalDatasetsDataEditorModel.label')) }]
label: [{ value: this.label, disabled: (disabled && !skipDisable.includes('ServicesDataEditorModel.label')) }],
multiAutoComplete: [{ value: this.multiAutoComplete, disabled: (disabled && !skipDisable.includes('ServicesDataEditorModel.multiAutoComplete')) }]
});
return formGroup;
}
fromModel(item: ExternalDatasetsFieldData): ExternalDatasetsDataEditorModel {
this.label = item.label;
this.multiAutoComplete = item.multiAutoComplete;
return this;
}
}

@ -1,6 +1,6 @@
import { FormGroup } from '@angular/forms';
import { FieldDataEditorModel } from './field-data-editor-model';
import { DatePickerFieldData, ExternalDatasetsFieldData, DataRepositoriesFieldData, RegistriesFieldData, ServicesFieldData, TagsFieldData, ResearchersFieldData, OrganizationsFieldData } from '../../../../../core/model/dataset-profile-definition/field-data/field-data';
import { OrganizationsFieldData } from '../../../../../core/model/dataset-profile-definition/field-data/field-data';
export class OrganizationsDataEditorModel extends FieldDataEditorModel<OrganizationsDataEditorModel> {
public label: string;

@ -1,19 +1,22 @@
import { FormGroup } from '@angular/forms';
import { FieldDataEditorModel } from './field-data-editor-model';
import { DatePickerFieldData, ExternalDatasetsFieldData, DataRepositoriesFieldData, RegistriesFieldData } from '../../../../../core/model/dataset-profile-definition/field-data/field-data';
import { RegistriesFieldData } from '../../../../../core/model/dataset-profile-definition/field-data/field-data';
export class RegistriesDataEditorModel extends FieldDataEditorModel<RegistriesDataEditorModel> {
public label: string;
public multiAutoComplete: boolean;
buildForm(disabled: boolean = false, skipDisable: Array<String> = []): FormGroup {
const formGroup = this.formBuilder.group({
label: [{ value: this.label, disabled: (disabled && !skipDisable.includes('RegistriesDataEditorModel.label')) }]
label: [{ value: this.label, disabled: (disabled && !skipDisable.includes('ServicesDataEditorModel.label')) }],
multiAutoComplete: [{ value: this.multiAutoComplete, disabled: (disabled && !skipDisable.includes('ServicesDataEditorModel.multiAutoComplete')) }]
});
return formGroup;
}
fromModel(item: RegistriesFieldData): RegistriesDataEditorModel {
this.label = item.label;
this.multiAutoComplete = item.multiAutoComplete;
return this;
}
}

@ -1,6 +1,6 @@
import { FormGroup } from '@angular/forms';
import { FieldDataEditorModel } from './field-data-editor-model';
import { DatePickerFieldData, ExternalDatasetsFieldData, DataRepositoriesFieldData, RegistriesFieldData, ServicesFieldData, TagsFieldData, ResearchersFieldData } from '../../../../../core/model/dataset-profile-definition/field-data/field-data';
import { ResearchersFieldData } from '../../../../../core/model/dataset-profile-definition/field-data/field-data';
export class ResearchersDataEditorModel extends FieldDataEditorModel<ResearchersDataEditorModel> {
public label: string;

@ -1,19 +1,22 @@
import { FormGroup } from '@angular/forms';
import { FieldDataEditorModel } from './field-data-editor-model';
import { DatePickerFieldData, ExternalDatasetsFieldData, DataRepositoriesFieldData, RegistriesFieldData, ServicesFieldData } from '../../../../../core/model/dataset-profile-definition/field-data/field-data';
import { ServicesFieldData } from '../../../../../core/model/dataset-profile-definition/field-data/field-data';
export class ServicesDataEditorModel extends FieldDataEditorModel<ServicesDataEditorModel> {
public label: string;
public multiAutoComplete: boolean;
buildForm(disabled: boolean = false, skipDisable: Array<String> = []): FormGroup {
const formGroup = this.formBuilder.group({
label: [{ value: this.label, disabled: (disabled && !skipDisable.includes('ServicesDataEditorModel.label')) }]
label: [{ value: this.label, disabled: (disabled && !skipDisable.includes('ServicesDataEditorModel.label')) }],
multiAutoComplete: [{ value: this.multiAutoComplete, disabled: (disabled && !skipDisable.includes('ServicesDataEditorModel.multiAutoComplete')) }]
});
return formGroup;
}
fromModel(item: ServicesFieldData): ServicesDataEditorModel {
this.label = item.label;
this.multiAutoComplete = item.multiAutoComplete;
return this;
}
}

@ -1,6 +1,6 @@
import { FormGroup } from '@angular/forms';
import { FieldDataEditorModel } from './field-data-editor-model';
import { DatePickerFieldData, ExternalDatasetsFieldData, DataRepositoriesFieldData, RegistriesFieldData, ServicesFieldData, TagsFieldData } from '../../../../../core/model/dataset-profile-definition/field-data/field-data';
import { TagsFieldData } from '../../../../../core/model/dataset-profile-definition/field-data/field-data';
export class TagsDataEditorModel extends FieldDataEditorModel<TagsDataEditorModel> {
public label: string;

@ -1,9 +1,12 @@
<div class="row" *ngIf="form.get('data')">
<h5 style="font-weight: bold" class="col-12">{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-DATE-PICKER-TITLE'
| translate}}</h5>
<mat-checkbox class="col-auto" [formControl]="this.form.get('data').get('multiAutoComplete')">
{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-MULTIPLE-AUTOCOMPLETE' | translate}}
</mat-checkbox>
<mat-form-field class="col-12">
<input matInput type="string"
placeholder="{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-CHECKBOX-PLACEHOLDER' | translate}}"
[formControl]="form.get('data').get('label')">
</mat-form-field>
</div>
</div>

@ -1,9 +1,13 @@
<div class="row" *ngIf="form.get('data')">
<h5 style="font-weight: bold" class="col-12">{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-DATE-PICKER-TITLE'
| translate}}</h5>
<mat-checkbox class="col-auto" [formControl]="this.form.get('data').get('multiAutoComplete')">
{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-MULTIPLE-AUTOCOMPLETE' | translate}}
</mat-checkbox>
<mat-form-field class="col-12">
<input matInput type="string"
placeholder="{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-CHECKBOX-PLACEHOLDER' | translate}}"
[formControl]="form.get('data').get('label')">
</mat-form-field>
</div>
</div>

@ -1,9 +1,13 @@
<div class="row" *ngIf="form.get('data')">
<h5 style="font-weight: bold" class="col-12">{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-DATE-PICKER-TITLE'
| translate}}</h5>
<mat-checkbox class="col-auto" [formControl]="this.form.get('data').get('multiAutoComplete')">
{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-MULTIPLE-AUTOCOMPLETE' | translate}}
</mat-checkbox>
<mat-form-field class="col-12">
<input matInput type="string"
placeholder="{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-CHECKBOX-PLACEHOLDER' | translate}}"
[formControl]="form.get('data').get('label')">
</mat-form-field>
</div>
</div>

@ -1,9 +1,12 @@
<div class="row" *ngIf="form.get('data')">
<h5 style="font-weight: bold" class="col-12">{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-DATE-PICKER-TITLE'
| translate}}</h5>
<mat-checkbox class="col-auto" [formControl]="this.form.get('data').get('multiAutoComplete')">
{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-MULTIPLE-AUTOCOMPLETE' | translate}}
</mat-checkbox>
<mat-form-field class="col-12">
<input matInput type="string"
placeholder="{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-CHECKBOX-PLACEHOLDER' | translate}}"
[formControl]="form.get('data').get('label')">
</mat-form-field>
</div>
</div>

@ -1,9 +1,12 @@
<div class="row" *ngIf="form.get('data')">
<h5 style="font-weight: bold" class="col-12">{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-DATE-PICKER-TITLE'
| translate}}</h5>
<mat-checkbox class="col-auto" [formControl]="this.form.get('data').get('multiAutoComplete')">
{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-MULTIPLE-AUTOCOMPLETE' | translate}}
</mat-checkbox>
<mat-form-field class="col-12">
<input matInput type="string"
placeholder="{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-CHECKBOX-PLACEHOLDER' | translate}}"
[formControl]="form.get('data').get('label')">
</mat-form-field>
</div>
</div>

@ -1,9 +1,12 @@
<div class="row" *ngIf="form.get('data')">
<h5 style="font-weight: bold" class="col-12">{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-DATE-PICKER-TITLE'
| translate}}</h5>
<mat-checkbox class="col-auto" [formControl]="this.form.get('data').get('multiAutoComplete')">
{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-MULTIPLE-AUTOCOMPLETE' | translate}}
</mat-checkbox>
<mat-form-field class="col-12">
<input matInput type="string"
placeholder="{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-CHECKBOX-PLACEHOLDER' | translate}}"
[formControl]="form.get('data').get('label')">
</mat-form-field>
</div>
</div>

@ -25,7 +25,7 @@
display: flex;
justify-content: center;
align-items: center;
width: 67px;
min-width: 67px;
height: 28px;
color: #00c4ff;
background: #d3f5ff 0% 0% no-repeat padding-box;
@ -35,13 +35,15 @@
opacity: 1;
margin-top: 0.5em;
margin-bottom: 0.5em;
padding-left: 10px;
padding-right: 10px;
}
.manager {
display: flex;
justify-content: center;
align-items: center;
width: 90px;
min-width: 90px;
height: 28px;
color: #568b5a;
background: #9dd1a1 0% 0% no-repeat padding-box;
@ -51,13 +53,15 @@
opacity: 1;
margin-top: 0.5em;
margin-bottom: 0.5em;
padding-left: 10px;
padding-right: 10px;
}
.admin {
display: flex;
justify-content: center;
align-items: center;
width: 77px;
min-width: 77px;
height: 28px;
color: #ff3d33;
background: #ffd5d3 0% 0% no-repeat padding-box;
@ -67,6 +71,8 @@
opacity: 1;
margin-top: 0.5em;
margin-bottom: 0.5em;
padding-left: 10px;
padding-right: 10px;
}
}

@ -15,7 +15,7 @@
<ng-container cdkColumnDef="avatar">
<mat-header-cell *matHeaderCellDef></mat-header-cell>
<mat-cell *matCellDef="let row">
<img mat-card-avatar *ngIf="row.avatarUrl" class="my-mat-card-avatar" [src]="row.avatarUrl">
<img mat-card-avatar *ngIf="row.avatarUrl" class="my-mat-card-avatar" [src]="row.avatarUrl" (error)="this.setDefaultAvatar($event)">
<img mat-card-avatar *ngIf="!row.avatarUrl" class="my-mat-card-avatar" [src]="'assets/images/profile-placeholder.png'">
</mat-cell>
</ng-container>

@ -182,6 +182,10 @@ export class UserListingComponent extends BaseComponent implements OnInit, After
return filename;
}
public setDefaultAvatar(ev: Event) {
(ev.target as HTMLImageElement).src = 'assets/images/profile-placeholder.png';
}
// public principalHasAvatar(): boolean {
// return this.authentication.current().avatarUrl != null && this.authentication.current().avatarUrl.length > 0;
// }

@ -17,6 +17,7 @@ import { FormControl } from '@angular/forms';
import { OrcidUser } from '@app/core/model/orcid/orcidUser';
import { ZenodoToken } from '@app/core/model/zenodo/zenodo-token.model';
import { LoginInfo } from '@app/core/model/auth/login-info';
import { MatomoService } from '@app/core/services/matomo/matomo-service';
/// <reference types="gapi" />
/// <reference types="facebook-js-sdk" />
@ -52,10 +53,12 @@ export class LoginComponent extends BaseComponent implements OnInit, AfterViewIn
private configurationService: ConfigurationService,
private mergeLoginService: MergeLoginService,
private oauth2DialogService: Oauth2DialogService,
private httpClient: HttpClient
private httpClient: HttpClient,
private matomoService: MatomoService
) { super(); }
ngOnInit(): void {
this.matomoService.trackPageView('loginPage');
this.route.queryParams
.pipe(takeUntil(this._destroyed))
.subscribe((params: Params) => {

@ -34,6 +34,7 @@ import { TranslateService } from '@ngx-translate/core';
import { UiNotificationService, SnackBarNotificationLevel } from '@app/core/services/notification/ui-notification-service';
import { GuidedTourService } from '@app/library/guided-tour/guided-tour.service';
import { GuidedTour, Orientation } from '@app/library/guided-tour/guided-tour.constants';
import { MatomoService } from '@app/core/services/matomo/matomo-service';
@Component({
@ -86,7 +87,8 @@ export class DashboardComponent extends BaseComponent implements OnInit, IBreadC
private dialog: MatDialog,
private language: TranslateService,
private uiNotificationService: UiNotificationService,
private guidedTourService: GuidedTourService
private guidedTourService: GuidedTourService,
private matomoService: MatomoService
) {
super();
// this.dashboardStatisticsData.totalDataManagementPlanCount = 0;
@ -96,6 +98,7 @@ export class DashboardComponent extends BaseComponent implements OnInit, IBreadC
ngOnInit() {
this.matomoService.trackPageView('Home Dashboard');
// if (this.isAuthenticated()) {
// this.userService.getRecentActivity()
// .pipe(takeUntil(this._destroyed))

@ -138,11 +138,18 @@
<div *ngSwitchCase="datasetProfileFieldViewStyleEnum.ExternalDatasets" class="col-12">
<div class="row">
<mat-form-field class="col-md-12">
<div *ngIf="form.get('data').value.multiAutoComplete">
<app-multiple-auto-complete placeholder="{{ form.get('data').value.label | translate }}" [formControl]="form.get('value')"
[configuration]="externalDatasetAutoCompleteConfiguration">
</app-multiple-auto-complete>
</div>
<div *ngIf="!(form.get('data').value.multiAutoComplete)">
<app-single-auto-complete placeholder="{{ form.get('data').value.label | translate }}" [formControl]="form.get('value')"
[configuration]="externalDatasetAutoCompleteConfiguration" [required]="form.get('validationRequired').value">
</app-single-auto-complete>
<mat-error *ngIf="form.get('value').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}
</mat-error>
</div>
<mat-hint>{{ "TYPES.DATASET-PROFILE-COMBO-BOX-TYPE.EXTERNAL-SOURCE-HINT" | translate }}</mat-hint>
</mat-form-field>
</div>
@ -151,11 +158,18 @@
<div *ngSwitchCase="datasetProfileFieldViewStyleEnum.DataRepositories" class="col-12">
<div class="row">
<mat-form-field class="col-md-12">
<div *ngIf="form.get('data').value.multiAutoComplete">
<app-multiple-auto-complete placeholder="{{ form.get('data').value.label | translate }}" [formControl]="form.get('value')"
[configuration]="dataRepositoriesAutoCompleteConfiguration">
</app-multiple-auto-complete>
</div>
<div *ngIf="!(form.get('data').value.multiAutoComplete)">
<app-single-auto-complete placeholder="{{ form.get('data').value.label | translate }}" [formControl]="form.get('value')"
[configuration]="dataRepositoriesAutoCompleteConfiguration" [required]="form.get('validationRequired').value">
</app-single-auto-complete>
<mat-error *ngIf="form.get('value').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}
</mat-error>
</div>
<mat-hint>{{ "TYPES.DATASET-PROFILE-COMBO-BOX-TYPE.EXTERNAL-SOURCE-HINT" | translate }}</mat-hint>
</mat-form-field>
</div>
@ -164,11 +178,18 @@
<div *ngSwitchCase="datasetProfileFieldViewStyleEnum.Registries" class="col-12">
<div class="row">
<mat-form-field class="col-md-12">
<div *ngIf="form.get('data').value.multiAutoComplete">
<app-multiple-auto-complete placeholder="{{ form.get('data').value.label | translate }}" [formControl]="form.get('value')"
[configuration]="registriesAutoCompleteConfiguration">
</app-multiple-auto-complete>
</div>
<div *ngIf="!(form.get('data').value.multiAutoComplete)">
<app-single-auto-complete placeholder="{{ form.get('data').value.label | translate }}" [formControl]="form.get('value')"
[configuration]="registriesAutoCompleteConfiguration" [required]="form.get('validationRequired').value">
</app-single-auto-complete>
<mat-error *ngIf="form.get('value').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}
</mat-error>
</div>
<mat-hint>{{ "TYPES.DATASET-PROFILE-COMBO-BOX-TYPE.EXTERNAL-SOURCE-HINT" | translate }}</mat-hint>
</mat-form-field>
</div>
@ -177,11 +198,18 @@
<div *ngSwitchCase="datasetProfileFieldViewStyleEnum.Services" class="col-12">
<div class="row">
<mat-form-field class="col-md-12">
<div *ngIf="form.get('data').value.multiAutoComplete">
<app-multiple-auto-complete placeholder="{{ form.get('data').value.label | translate }}" [formControl]="form.get('value')"
[configuration]="servicesAutoCompleteConfiguration">
</app-multiple-auto-complete>
</div>
<div *ngIf="!(form.get('data').value.multiAutoComplete)">
<app-single-auto-complete placeholder="{{ form.get('data').value.label | translate }}" [formControl]="form.get('value')"
[configuration]="servicesAutoCompleteConfiguration" [required]="form.get('validationRequired').value">
</app-single-auto-complete>
<mat-error *ngIf="form.get('value').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}
</mat-error>
</div>
<mat-hint>{{ "TYPES.DATASET-PROFILE-COMBO-BOX-TYPE.EXTERNAL-SOURCE-HINT" | translate }}</mat-hint>
</mat-form-field>
</div>

@ -9,6 +9,8 @@ import { Router } from '@angular/router';
import { isNullOrUndefined } from 'util';
import { environment } from 'environments/environment';
import { ConfigurationService } from '@app/core/services/configuration/configuration.service';
import { AuthService } from '@app/core/services/auth/auth.service';
import { LanguageService } from '@app/core/services/language/language.service';
@Component({
selector: 'app-user-guide-editor',
@ -23,7 +25,8 @@ export class UserGuideEditorComponent extends BaseComponent implements OnInit {
private uiNotificationService: UiNotificationService,
private translate: TranslateService,
private router: Router,
private configurationService: ConfigurationService
private configurationService: ConfigurationService,
private languageService: LanguageService
) { super(); }
ngOnInit() {
@ -32,7 +35,7 @@ export class UserGuideEditorComponent extends BaseComponent implements OnInit {
name: [''],
html: ['']
});
this.userGuideService.getUserGuide().pipe(takeUntil(this._destroyed)).subscribe(data => {
this.userGuideService.getUserGuide(this.languageService.getCurrentLanguage()).pipe(takeUntil(this._destroyed)).subscribe(data => {
const contentDispositionHeader = data.headers.get('Content-Disposition');
const filename = contentDispositionHeader.split(';')[1].trim().split('=')[1].replace(/"/g, '');

@ -3,6 +3,7 @@ import { UserGuideService } from '@app/core/services/user-guide/user-guide.servi
import { BaseComponent } from '@common/base/base.component';
import { takeUntil } from 'rxjs/internal/operators/takeUntil';
import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';
import { LanguageService } from '@app/core/services/language/language.service';
@Component({
selector: 'app-user-guide-content',
@ -18,20 +19,18 @@ export class UserGuideContentComponent extends BaseComponent implements OnInit,
constructor(
private userGuideService: UserGuideService,
private sanitizer: DomSanitizer
private sanitizer: DomSanitizer,
private languageService: LanguageService
) { super(); }
ngOnInit() {
this.scrollEvent = ((ev) => this.scroll(ev));
this.userGuideService.getUserGuide()
this.userGuideService.getUserGuide(this.languageService.getCurrentLanguage())
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'text/html' });
this.readBlob(blob);
// this.guideHTMLUrl = URL.createObjectURL(blob);
this.guideHTMLUrl = this.sanitizer.bypassSecurityTrustResourceUrl(URL.createObjectURL(blob));
console.log(this.guideHTMLUrl)
});
}

@ -48,6 +48,11 @@
"enabled": true,
"logLevels": ["debug", "info", "warning", "error"]
},
"matomo": {
"enabled": true,
"url": "https://beta.analytics.openaire.eu/",
"siteId": 361
},
"lockInterval": 60000,
"guideAssets": "assets/images/guide",
"allowOrganizationCreator": true,

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save