Merge branch 'dmp-refactoring' of https://code-repo.d4science.org/MaDgiK-CITE/argos into dmp-refactoring

# Conflicts:
#	dmp-frontend/src/app/ui/supportive-material-editor/supportive-material-editor.component.html
This commit is contained in:
amentis 2023-11-29 15:32:03 +02:00
commit 63a8820681
98 changed files with 9090 additions and 719 deletions

View File

@ -95,6 +95,10 @@ public class Dmp {
public static final String _dmpUsers = "dmpUsers";
private List<Description> descriptions;
public static final String _descriptions = "descriptions";
public UUID getId() {
return id;
}
@ -262,4 +266,12 @@ public class Dmp {
public void setVersionStatus(DmpVersionStatus versionStatus) {
this.versionStatus = versionStatus;
}
public List<Description> getDescriptions() {
return descriptions;
}
public void setDescriptions(List<Description> descriptions) {
this.descriptions = descriptions;
}
}

View File

@ -4,10 +4,7 @@ import eu.eudat.authorization.AuthorizationFlags;
import eu.eudat.convention.ConventionService;
import eu.eudat.data.DmpEntity;
import eu.eudat.model.*;
import eu.eudat.query.DmpBlueprintQuery;
import eu.eudat.query.DmpReferenceQuery;
import eu.eudat.query.DmpUserQuery;
import eu.eudat.query.UserQuery;
import eu.eudat.query.*;
import gr.cite.tools.data.builder.BuilderFactory;
import gr.cite.tools.data.query.QueryFactory;
import gr.cite.tools.exception.MyApplicationException;
@ -69,6 +66,9 @@ public class DmpBuilder extends BaseBuilder<Dmp, DmpEntity> {
FieldSet blueprintFields = fields.extractPrefixed(this.asPrefix(Dmp._blueprint));
Map<UUID, DmpBlueprint> blueprintItemsMap = this.collectDmpBlueprints(blueprintFields, data);
FieldSet descriptionsFields = fields.extractPrefixed(this.asPrefix(Dmp._descriptions));
Map<UUID, List<Description>> descriptionsMap = this.collectDmpDescriptions(descriptionsFields, data);
for (DmpEntity d : data) {
Dmp m = new Dmp();
if (fields.hasField(this.asIndexer(Dmp._id))) m.setId(d.getId());
@ -91,6 +91,7 @@ public class DmpBuilder extends BaseBuilder<Dmp, DmpEntity> {
if (!blueprintFields.isEmpty() && blueprintItemsMap != null && blueprintItemsMap.containsKey(d.getBlueprintId())) m.setBlueprint(blueprintItemsMap.get(d.getBlueprintId()));
if (dmpReferencesMap != null && !dmpReferencesMap.isEmpty() && dmpReferencesMap.containsKey(d.getId())) m.setDmpReferences(dmpReferencesMap.get(d.getId()));
if (dmpUsersMap != null && !dmpUsersMap.isEmpty() && dmpUsersMap.containsKey(d.getId())) m.setDmpUsers(dmpUsersMap.get(d.getId()));
if (descriptionsMap != null && !descriptionsMap.isEmpty() && descriptionsMap.containsKey(d.getId())) m.setDescriptions(descriptionsMap.get(d.getId()));
models.add(m);
}
@ -196,4 +197,23 @@ public class DmpBuilder extends BaseBuilder<Dmp, DmpEntity> {
return itemMap;
}
private Map<UUID, List<Description>> collectDmpDescriptions(FieldSet fields, List<DmpEntity> data) throws MyApplicationException {
if (fields.isEmpty() || data.isEmpty()) return null;
this.logger.debug("checking related - {}", Description.class.getSimpleName());
Map<UUID, List<Description>> itemMap;
FieldSet clone = new BaseFieldSet(fields.getFields()).ensure(this.asIndexer(Description._dmp, Dmp._id));
DmpQuery dmpQuery = this.queryFactory.query(DmpQuery.class).authorize(this.authorize).ids(data.stream().map(DmpEntity::getId).distinct().collect(Collectors.toList()));
DescriptionQuery query = this.queryFactory.query(DescriptionQuery.class).authorize(this.authorize).dmpSubQuery(dmpQuery);
itemMap = this.builderFactory.builder(DescriptionBuilder.class).authorize(this.authorize).asMasterKey(query, clone, x -> x.getDmp().getId());
if (!fields.hasField(this.asIndexer(Description._dmp, Dmp._id))) {
itemMap.values().stream().flatMap(List::stream).filter(x -> x != null && x.getDmp() != null).peek(x -> {
x.getDmp().setId(null);
});
}
return itemMap;
}
}

View File

@ -46,8 +46,8 @@ const appRoutes: Routes = [
}
},
{
path: 'datasets',
loadChildren: () => import('./ui/dataset/dataset.module').then(m => m.DatasetModule),
path: 'descriptions',
loadChildren: () => import('./ui/description/description.module').then(m => m.DescriptionModule),
data: {
breadcrumb: true,
title: 'GENERAL.TITLES.DESCRIPTIONS'

View File

@ -225,10 +225,10 @@ export class AppComponent implements OnInit, AfterViewInit {
// }
initializeServices() {
this.translate.setDefaultLang(this.configurationService.defaultLanguage || 'en');
this.translate.setDefaultLang(this.language.getDefaultLanguagesCode());
this.authentication.currentAccountIsAuthenticated() && this.authentication.getUserProfileCulture() ? this.cultureService.cultureSelected(this.authentication.getUserProfileCulture()) : this.cultureService.cultureSelected(this.configurationService.defaultCulture);
this.authentication.currentAccountIsAuthenticated() && this.authentication.getUserProfileTimezone() ? this.timezoneService.timezoneSelected(this.authentication.getUserProfileTimezone()) : this.timezoneService.timezoneSelected(this.configurationService.defaultTimezone);
this.authentication.currentAccountIsAuthenticated() && this.authentication.getUserProfileLanguage() ? this.language.changeLanguage(this.authentication.getUserProfileLanguage()) : (this.configurationService.defaultLanguage || 'en');
this.authentication.currentAccountIsAuthenticated() && this.authentication.getUserProfileLanguage() ? this.language.changeLanguage(this.authentication.getUserProfileLanguage()) : (this.language.getDefaultLanguagesCode());
}
toggleNavbar(event) {

View File

@ -20,31 +20,31 @@ import { ReloadHelperComponent } from '@app/ui/misc/reload-helper/reload-helper.
import { NavbarModule } from '@app/ui/navbar/navbar.module';
import { SidebarModule } from '@app/ui/sidebar/sidebar.module';
import { MomentUtcDateAdapter } from '@common/date/moment-utc-date-adapter';
import { BaseHttpParams } from '@common/http/base-http-params';
import { CommonHttpModule } from '@common/http/common-http.module';
import { InterceptorType } from '@common/http/interceptors/interceptor-type';
import { CommonUiModule } from '@common/ui/common-ui.module';
import { TranslateCompiler, TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { KeycloakAngularModule, KeycloakService } from 'keycloak-angular';
import { DragulaModule } from 'ng2-dragula';
import { CookieService } from 'ngx-cookie-service';
import { NgcCookieConsentConfig, NgcCookieConsentModule } from 'ngx-cookieconsent';
import { MatomoInitializationMode, NgxMatomoModule } from 'ngx-matomo-client';
import { from } from 'rxjs';
import { AuthService } from './core/services/auth/auth.service';
import { ConfigurationService } from './core/services/configuration/configuration.service';
import { CultureService } from './core/services/culture/culture-service';
import { LanguageHttpService } from './core/services/language/language.http.service';
import { LanguageService } from './core/services/language/language.service';
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';
import { OpenDMPCustomTranslationCompiler } from './utilities/translate/opendmp-custom-translation-compiler';
import { KeycloakAngularModule, KeycloakService } from 'keycloak-angular';
import { BaseHttpParams } from '@common/http/base-http-params';
import { InterceptorType } from '@common/http/interceptors/interceptor-type';
import { from } from 'rxjs';
import { AuthService } from './core/services/auth/auth.service';
// AoT requires an exported function for factories
export function HttpLoaderFactory(http: HttpClient, appConfig: ConfigurationService) {
return new TranslateServerLoader(http, appConfig);
//GK: In case we want the original translation provider uncomment the line below.
//return new TranslateHttpLoader(http, 'assets/i18n/', '.json');
export function HttpLoaderFactory(languageHttpService: LanguageHttpService) {
return new TranslateServerLoader(languageHttpService);
}
const cookieConfig: NgcCookieConsentConfig = {
@ -82,8 +82,10 @@ const appearance: MatFormFieldDefaultOptions = {
// appearance: 'standard'
};
export function InstallationConfigurationFactory(appConfig: ConfigurationService, keycloak: KeycloakService, authService: AuthService) {
return () => appConfig.loadConfiguration().then(x => keycloak.init({
export function InstallationConfigurationFactory(appConfig: ConfigurationService, keycloak: KeycloakService, authService: AuthService, languageService: LanguageService) {
return () => appConfig.loadConfiguration().then(() => {
return languageService.loadAvailableLanguages().toPromise();
}).then(x => keycloak.init({
config: {
url: appConfig.keycloak.address,
realm: appConfig.keycloak.realm,
@ -108,7 +110,7 @@ export function InstallationConfigurationFactory(appConfig: ConfigurationService
]
};
const tokenPromise = keycloak.getToken();
return authService.prepareAuthRequest(from(tokenPromise), {params}).toPromise().catch(error => authService.onAuthenticateError(error));
return authService.prepareAuthRequest(from(tokenPromise), { params }).toPromise().catch(error => authService.onAuthenticateError(error));
}));
}
@ -126,7 +128,7 @@ export function InstallationConfigurationFactory(appConfig: ConfigurationService
loader: {
provide: TranslateLoader,
useFactory: HttpLoaderFactory,
deps: [HttpClient, ConfigurationService]
deps: [LanguageHttpService]
}
}),
HttpClientModule,
@ -161,7 +163,7 @@ export function InstallationConfigurationFactory(appConfig: ConfigurationService
{
provide: APP_INITIALIZER,
useFactory: InstallationConfigurationFactory,
deps: [ConfigurationService, KeycloakService, AuthService],
deps: [ConfigurationService, KeycloakService, AuthService, LanguageService],
multi: true
},
{

View File

@ -1,4 +1,5 @@
export enum DescriptionStatus {
Draft = 0,
Finalized = 1
Finalized = 1,
Canceled = 2
}

View File

@ -0,0 +1,4 @@
export enum DmpAccessType {
Public = 0,
Restricted = 1
}

View File

@ -0,0 +1,4 @@
export enum DmpUserRole {
Owner = 0,
User = 1
}

View File

@ -0,0 +1,4 @@
export enum DmpVersionStatus {
Current = 0,
Previous = 1
}

View File

@ -17,7 +17,7 @@ import { DepositRepositoriesService } from './services/deposit-repositories/depo
import { DescriptionTemplateTypeService } from './services/description-template-type/description-template-type.service';
import { DmpBlueprintService } from './services/dmp/dmp-blueprint.service';
import { DmpInvitationService } from './services/dmp/dmp-invitation.service';
import { DmpService } from './services/dmp/dmp.service';
import { DmpService, DmpServiceNew } 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';
@ -61,7 +61,8 @@ import { UserSettingsService } from './services/user-settings/user-settings.serv
import { UserService } from './services/user/user.service';
import { FileUtils } from './services/utilities/file-utils.service';
import { QueryParamsService } from './services/utilities/query-params.service';
import { LanguageV2Service } from './services/language/language-v2.service';
import { LanguageHttpService } from './services/language/language.http.service';
import { DescriptionService } from './services/description/description.service';
//
//
// This is shared module that provides all the services. Its imported only once on the AppModule.
@ -142,7 +143,9 @@ export class CoreServiceModule {
ReferenceTypeService,
TenantService,
UserService,
LanguageV2Service
LanguageHttpService,
DmpServiceNew,
DescriptionService
],
};
}

View File

@ -3,35 +3,71 @@ import { BaseEntity, BaseEntityPersist } from "@common/base/base-entity.model";
import { Guid } from "@common/types/guid";
import { Dmp } from "../dmp/dmp";
import { DescriptionTemplate } from "../description-template/description-template";
import { DescriptionReference } from "./description-reference";
import { User } from "../user/user";
import { Reference, ReferencePersist } from "../reference/reference";
import { Tag } from "../tag/tag";
export interface Description extends BaseEntity {
label: string;
properties: PropertyDefinition;
status: DescriptionStatus;
description?: String;
dmp: Dmp;
uri: String;
status: DescriptionStatus
createdBy: User;
finalizedAt: Date;
dmpSectionIndex?: number;
template: DescriptionTemplate;
descriptionReferences: DescriptionReference[];
descriptionTags: DescriptionTag[];
template: DescriptionTemplate;
dmp: Dmp;
}
export interface PublicDescription extends BaseEntity {
}
export interface PropertyDefinition {
fields?: DescriptionField[];
}
// registries?: RegistryModel[];
// services?: ServiceModel[];
// dataRepositories?: DataRepositoryModel[];
// tags?: TagModel[];
// externalDatasets?: ExternalDatasetModel[];
// isProfileLatestVersion?: Boolean;
// modified?: Date;
export interface DescriptionField {
key?: string;
value: string;
}
export interface DescriptionReference extends BaseEntity {
description?: Description;
reference?: Reference;
}
export interface DescriptionTag extends BaseEntity {
description?: Description;
tag?: Tag;
}
//
// Persist
//
export interface DescriptionPersist extends BaseEntityPersist {
label: string;
dmpId: Guid;
dmpDescriptionTemplateId: Guid;
descriptionTemplateId: Guid;
status: DescriptionStatus;
description: string;
properties: PropertyDefinitionPersist;
tags: string[];
references: DescriptionReferencePersist[];
}
export interface PropertyDefinitionPersist{
fields: DescriptionFieldPersist[];
}
export interface DescriptionFieldPersist {
key?: string;
value: string;
}
export interface DescriptionReferencePersist extends BaseEntity {
reference?: ReferencePersist;
}

View File

@ -10,12 +10,3 @@ export interface DmpReference extends BaseEntity {
reference?: Reference;
data: String;
}
//
// Persist
//
export interface DmpPersist extends BaseEntityPersist {
dmpId: Guid;
referenceId: Guid;
data: String;
}

View File

@ -5,16 +5,20 @@ import { GrantListingModel } from "../grant/grant-listing";
import { OrganizationModel } from "../organisation/organization";
import { ProjectModel } from "../project/project";
import { ResearcherModel } from "../researcher/researcher";
import { UserModel } from "../user/user";
import { User, UserModel } from "../user/user";
import { UserInfoListingModel } from "../user/user-info-listing";
import { DmpDatasetProfile } from "./dmp-dataset-profile/dmp-dataset-profile";
import { DmpDynamicField } from "./dmp-dynamic-field";
import { DmpExtraField } from "./dmp-extra-field";
import { BaseEntity, BaseEntityPersist } from '@common/base/base-entity.model';
import { Description } from '../description/description';
import { DmpReference } from '../reference/reference';
import { DmpReference, ReferencePersist } from '../reference/reference';
import { DmpVersionStatus } from '@app/core/common/enum/dmp-version-status';
import { DmpAccessType } from '@app/core/common/enum/dmp-access-type';
import { DmpUserRole } from '@app/core/common/enum/dmp-user-role';
import { Guid } from '@common/types/guid';
export interface DmpModel {
export interface DmpModel { //TODO: Delete
id: string;
label: string;
groupId: String;
@ -49,21 +53,25 @@ export interface DmpBlueprint {
export interface Dmp extends BaseEntity {
label: string;
description: String;
version: number;
status: DmpStatus;
versionStatus: DmpVersionStatus;
properties: string;
groupId: String;
description: String;
finalizedAt: Date;
publishedAt: Date;
creator: User;
accessType: DmpAccessType;
blueprint: DmpBlueprint;
dmpDescriptions: Description[];
dmpReferences: DmpReference
lockable: boolean;
language: String;
publicAfter: Date;
dmpReferences: DmpReference[];
dmpUsers: DmpUser[];
descriptions: Description[];
// TODO: delete
// grant: GrantListingModel;
// project: ProjectModel;
// funder: FunderModel;
@ -85,13 +93,53 @@ export interface Dmp extends BaseEntity {
// language: String;
}
export interface DmpUser extends BaseEntity {
dmp: Dmp;
user: User;
role: DmpUserRole;
}
//
// Persist
//
export interface DmpPersist extends BaseEntityPersist {
label: string;
description: String;
version: number;
status: DmpStatus;
groupId: String;
properties: string;
description: String;
language: String;
blueprint: DmpBlueprint;
accessType: DmpAccessType;
references: DmpReferencePersist[];
descriptionTemplates: DmpDescriptionTemplatePersist[];
}
export interface DmpReferencePersist extends BaseEntityPersist {
reference: ReferencePersist;
data: string;
}
export interface DmpDescriptionTemplatePersist extends BaseEntityPersist {
descriptionTemplateGroupId: Guid;
sectionId: Guid;
}
export interface CloneDmpPersist {
id: Guid;
label: string;
description: String;
descriptions: Guid[];
}
export interface NewVersionDmpPersist {
id: Guid;
label: string;
description: String;
blueprintId: Guid;
descriptions: Guid[];
}
export interface DmpUserPersist {
user: Guid;
role: DmpUserRole;
}

View File

@ -1,4 +1,12 @@
export interface TagModel {
import { BaseEntity } from "@common/base/base-entity.model";
import { User } from "../user/user";
export interface TagModel { //TODO: old entity, delete
id: string;
name: string;
}
export interface Tag extends BaseEntity {
label?: string;
createdBy?: User;
}

View File

@ -0,0 +1,35 @@
import { Lookup } from '@common/model/lookup';
import { Guid } from '@common/types/guid';
import { IsActive } from '../common/enum/is-active.enum';
import { DescriptionStatus } from '../common/enum/description-status';
import { DmpLookup } from './dmp.lookup';
export class DescriptionLookup extends Lookup implements DescriptionFilter {
ids: Guid[];
excludedIds: Guid[];
like: string;
createdAfter: Date;
createdBefore: Date;
finalizedAfter: Date;
finalizedBefore: Date;
dmpSubQuery: DmpLookup;
isActive: IsActive[];
statuses: DescriptionStatus[];
constructor() {
super();
}
}
export interface DescriptionFilter {
ids: Guid[];
excludedIds: Guid[];
like: string;
createdAfter: Date;
createdBefore: Date;
finalizedAfter: Date;
finalizedBefore: Date;
dmpSubQuery: DmpLookup;
isActive: IsActive[];
statuses: DescriptionStatus[];
}

View File

@ -0,0 +1,32 @@
import { Lookup } from '@common/model/lookup';
import { Guid } from '@common/types/guid';
import { IsActive } from '../common/enum/is-active.enum';
import { DmpStatus } from '../common/enum/dmp-status';
import { DmpVersionStatus } from '../common/enum/dmp-version-status';
import { DmpAccessType } from '../common/enum/dmp-access-type';
export class DmpLookup extends Lookup implements DmpFilter {
ids: Guid[];
excludedIds: Guid[];
like: string;
isActive: IsActive[];
versionStatuses: DmpVersionStatus[];
statuses: DmpStatus[];
accessTypes: DmpAccessType[];
versions: Number[]
constructor() {
super();
}
}
export interface DmpFilter {
ids: Guid[];
excludedIds: Guid[];
like: string;
isActive: IsActive[];
versionStatuses: DmpVersionStatus[];
statuses: DmpStatus[];
accessTypes: DmpAccessType[];
versions: Number[]
}

View File

@ -47,16 +47,6 @@ export class ConfigurationService extends BaseComponent {
return this._defaultTimezone || 'UTC';
}
private _defaultLanguage: string;
get defaultLanguage(): string {
return this._defaultLanguage;
}
private _availableLanguages: any[] = [];
get availableLanguages(): any[] {
return this._availableLanguages;
}
private _logging: Logging;
get logging(): Logging {
return this._logging;
@ -161,8 +151,6 @@ export class ConfigurationService extends BaseComponent {
this._defaultCulture = config.defaultCulture;
this._defaultBlueprintId = config.defaultBlueprintId;
this._defaultTimezone = config.defaultTimezone;
this._defaultLanguage = config.defaultLanguage;
this._availableLanguages = config.availableLanguages;
this._keycloak = KeycloakConfiguration.parseValue(config.keycloak);
this._logging = Logging.parseValue(config.logging);
this._lockInterval = config.lockInterval;

View File

@ -0,0 +1,110 @@
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { IsActive } from '@app/core/common/enum/is-active.enum';
import { Description, DescriptionPersist, PublicDescription } from '@app/core/model/description/description';
import { DescriptionLookup } from '@app/core/query/description.lookup';
import { MultipleAutoCompleteConfiguration } from '@app/library/auto-complete/multiple/multiple-auto-complete-configuration';
import { SingleAutoCompleteConfiguration } from '@app/library/auto-complete/single/single-auto-complete-configuration';
import { QueryResult } from '@common/model/query-result';
import { FilterService } from '@common/modules/text-filter/filter-service';
import { Guid } from '@common/types/guid';
import { Observable, throwError } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
import { nameof } from 'ts-simple-nameof';
import { ConfigurationService } from '../configuration/configuration.service';
import { BaseHttpV2Service } from '../http/base-http-v2.service';
@Injectable()
export class DescriptionService {
private headers = new HttpHeaders();
constructor(private http: BaseHttpV2Service, private httpClient: HttpClient, private configurationService: ConfigurationService, private filterService: FilterService) {
}
private get apiBase(): string { return `${this.configurationService.server}description`; }
query(q: DescriptionLookup): Observable<QueryResult<Description>> {
const url = `${this.apiBase}/query`;
return this.http.post<QueryResult<Description>>(url, q).pipe(catchError((error: any) => throwError(error)));
}
publicQuery(q: DescriptionLookup): Observable<QueryResult<PublicDescription>> {
const url = `${this.apiBase}/public/query`;
return this.http.post<QueryResult<PublicDescription>>(url, q).pipe(catchError((error: any) => throwError(error)));
}
getSingle(id: Guid, reqFields: string[] = []): Observable<Description> {
const url = `${this.apiBase}/${id}`;
const options = { params: { f: reqFields } };
return this.http
.get<Description>(url, options).pipe(
catchError((error: any) => throwError(error)));
}
getPublicSingle(id: Guid, reqFields: string[] = []): Observable<Description> {
const url = `${this.apiBase}/public/${id}`;
const options = { params: { f: reqFields } };
return this.http
.get<Description>(url, options).pipe(
catchError((error: any) => throwError(error)));
}
persist(item: DescriptionPersist): Observable<Description> {
const url = `${this.apiBase}/persist`;
return this.http
.post<Description>(url, item).pipe(
catchError((error: any) => throwError(error)));
}
delete(id: Guid): Observable<Description> {
const url = `${this.apiBase}/${id}`;
return this.http
.delete<Description>(url).pipe(
catchError((error: any) => throwError(error)));
}
//
// Autocomplete Commons
//
// tslint:disable-next-line: member-ordering
singleAutocompleteConfiguration: SingleAutoCompleteConfiguration = {
initialItems: (data?: any) => this.query(this.buildAutocompleteLookup()).pipe(map(x => x.items)),
filterFn: (searchQuery: string, data?: any) => this.query(this.buildAutocompleteLookup(searchQuery)).pipe(map(x => x.items)),
getSelectedItem: (selectedItem: any) => this.query(this.buildAutocompleteLookup(null, null, [selectedItem])).pipe(map(x => x.items[0])),
displayFn: (item: Description) => item.label,
titleFn: (item: Description) => item.label,
valueAssign: (item: Description) => item.id,
};
// tslint:disable-next-line: member-ordering
multipleAutocompleteConfiguration: MultipleAutoCompleteConfiguration = {
initialItems: (excludedItems: any[], data?: any) => this.query(this.buildAutocompleteLookup(null, excludedItems ? excludedItems : null)).pipe(map(x => x.items)),
filterFn: (searchQuery: string, excludedItems: any[]) => this.query(this.buildAutocompleteLookup(searchQuery, excludedItems)).pipe(map(x => x.items)),
getSelectedItems: (selectedItems: any[]) => this.query(this.buildAutocompleteLookup(null, null, selectedItems)).pipe(map(x => x.items)),
displayFn: (item: Description) => item.label,
titleFn: (item: Description) => item.label,
valueAssign: (item: Description) => item.id,
};
private buildAutocompleteLookup(like?: string, excludedIds?: Guid[], ids?: Guid[]): DescriptionLookup {
const lookup: DescriptionLookup = new DescriptionLookup();
lookup.page = { size: 100, offset: 0 };
if (excludedIds && excludedIds.length > 0) { lookup.excludedIds = excludedIds; }
if (ids && ids.length > 0) { lookup.ids = ids; }
lookup.isActive = [IsActive.Active];
lookup.project = {
fields: [
nameof<Description>(x => x.id),
nameof<Description>(x => x.label)
]
};
lookup.order = { items: [nameof<Description>(x => x.label)] };
if (like) { lookup.like = this.filterService.transformLike(like); }
return lookup;
}
}

View File

@ -1,7 +1,17 @@
import { HttpClient, HttpHeaders, HttpResponse } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { environment } from '../../../../environments/environment';
import { IsActive } from '@app/core/common/enum/is-active.enum';
import { UserInfoListingModel } from '@app/core/model/user/user-info-listing';
import { VersionListingModel } from '@app/core/model/version/version-listing.model';
import { DmpLookup } from '@app/core/query/dmp.lookup';
import { MultipleAutoCompleteConfiguration } from '@app/library/auto-complete/multiple/multiple-auto-complete-configuration';
import { SingleAutoCompleteConfiguration } from '@app/library/auto-complete/single/single-auto-complete-configuration';
import { QueryResult } from '@common/model/query-result';
import { FilterService } from '@common/modules/text-filter/filter-service';
import { Guid } from '@common/types/guid';
import { Observable, throwError } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
import { nameof } from 'ts-simple-nameof';
import { BaseHttpParams } from '../../../../common/http/base-http-params';
import { InterceptorType } from '../../../../common/http/interceptors/interceptor-type';
import { DynamicFieldGrantCriteria } from '../../../models/dynamic-field-grant/DynamicFieldGrantCriteria';
@ -10,17 +20,152 @@ import { DataTableRequest } from '../../model/data-table/data-table-request';
import { DatasetListingModel } from '../../model/dataset/dataset-listing';
import { DatasetProfileModel } from '../../model/dataset/dataset-profile';
import { DatasetsToBeFinalized } from '../../model/dataset/datasets-toBeFinalized';
import { DmpModel } from '../../model/dmp/dmp';
import { CloneDmpPersist, Dmp, DmpModel, DmpPersist, DmpUser, DmpUserPersist, NewVersionDmpPersist } from '../../model/dmp/dmp';
import { DmpListingModel } from '../../model/dmp/dmp-listing';
import { DmpOverviewModel } from '../../model/dmp/dmp-overview';
import { DatasetProfileCriteria } from '../../query/dataset-profile/dataset-profile-criteria';
import { DmpCriteria } from '../../query/dmp/dmp-criteria';
import { ExploreDmpCriteriaModel } from '../../query/explore-dmp/explore-dmp-criteria';
import { RequestItem } from '../../query/request-item';
import { BaseHttpService } from '../http/base-http.service';
import { ConfigurationService } from '../configuration/configuration.service';
import { UserInfoListingModel } from '@app/core/model/user/user-info-listing';
import { VersionListingModel } from '@app/core/model/version/version-listing.model';
import { BaseHttpV2Service } from '../http/base-http-v2.service';
import { BaseHttpService } from '../http/base-http.service';
@Injectable()
export class DmpServiceNew {
private headers = new HttpHeaders();
constructor(private http: BaseHttpV2Service, private httpClient: HttpClient, private configurationService: ConfigurationService, private filterService: FilterService) {
}
private get apiBase(): string { return `${this.configurationService.server}dmp`; }
query(q: DmpLookup): Observable<QueryResult<Dmp>> {
const url = `${this.apiBase}/query`;
return this.http.post<QueryResult<Dmp>>(url, q).pipe(catchError((error: any) => throwError(error)));
}
getSingle(id: Guid, reqFields: string[] = []): Observable<Dmp> {
const url = `${this.apiBase}/${id}`;
const options = { params: { f: reqFields } };
return this.http
.get<Dmp>(url, options).pipe(
catchError((error: any) => throwError(error)));
}
persist(item: DmpPersist): Observable<Dmp> {
const url = `${this.apiBase}/persist`;
return this.http
.post<Dmp>(url, item).pipe(
catchError((error: any) => throwError(error)));
}
delete(id: Guid): Observable<Dmp> {
const url = `${this.apiBase}/${id}`;
return this.http
.delete<Dmp>(url).pipe(
catchError((error: any) => throwError(error)));
}
clone(item: CloneDmpPersist, reqFields: string[] = []): Observable<Dmp> {
const url = `${this.apiBase}/clone`;
const options = { params: { f: reqFields } };
return this.http
.post<Dmp>(url, item).pipe(
catchError((error: any) => throwError(error)));
}
newVersion(item: NewVersionDmpPersist, reqFields: string[] = []): Observable<Dmp> {
const url = `${this.apiBase}/new-version`;
const options = { params: { f: reqFields } };
return this.http
.get<Dmp>(url, options).pipe(
catchError((error: any) => throwError(error)));
}
assignUsers(id: Guid, items: DmpUserPersist[], reqFields: string[] = []): Observable<DmpUser> {
const url = `${this.apiBase}/${id}/assign-users`;
const options = { params: { f: reqFields } };
return this.http
.post<DmpUser>(url, items).pipe(
catchError((error: any) => throwError(error)));
}
downloadXML(id: Guid): Observable<HttpResponse<Blob>> {
const url = `${this.apiBase}/xml/export/${id}`;
let headerXml: HttpHeaders = this.headers.set('Content-Type', 'application/xml');
const params = new BaseHttpParams();
params.interceptorContext = {
excludedInterceptors: [InterceptorType.JSONContentType]
};
return this.httpClient.get(url, { params: params, responseType: 'blob', observe: 'response', headers: headerXml });
}
uploadFile(file: FileList, labelSent: string, reqFields: string[] = []): Observable<DataTableData<Dmp>> {
const url = `${this.apiBase}/xml/import`;
const params = new BaseHttpParams();
params.interceptorContext = {
excludedInterceptors: [InterceptorType.JSONContentType]
};
const formData = new FormData();
formData.append('file', file[0], labelSent);
return this.http.post(url, formData, { params: params });
}
//
// Autocomplete Commons
//
// tslint:disable-next-line: member-ordering
singleAutocompleteConfiguration: SingleAutoCompleteConfiguration = {
initialItems: (data?: any) => this.query(this.buildAutocompleteLookup()).pipe(map(x => x.items)),
filterFn: (searchQuery: string, data?: any) => this.query(this.buildAutocompleteLookup(searchQuery)).pipe(map(x => x.items)),
getSelectedItem: (selectedItem: any) => this.query(this.buildAutocompleteLookup(null, null, [selectedItem])).pipe(map(x => x.items[0])),
displayFn: (item: Dmp) => item.label,
titleFn: (item: Dmp) => item.label,
valueAssign: (item: Dmp) => item.id,
};
// tslint:disable-next-line: member-ordering
multipleAutocompleteConfiguration: MultipleAutoCompleteConfiguration = {
initialItems: (excludedItems: any[], data?: any) => this.query(this.buildAutocompleteLookup(null, excludedItems ? excludedItems : null)).pipe(map(x => x.items)),
filterFn: (searchQuery: string, excludedItems: any[]) => this.query(this.buildAutocompleteLookup(searchQuery, excludedItems)).pipe(map(x => x.items)),
getSelectedItems: (selectedItems: any[]) => this.query(this.buildAutocompleteLookup(null, null, selectedItems)).pipe(map(x => x.items)),
displayFn: (item: Dmp) => item.label,
titleFn: (item: Dmp) => item.label,
valueAssign: (item: Dmp) => item.id,
};
private buildAutocompleteLookup(like?: string, excludedIds?: Guid[], ids?: Guid[]): DmpLookup {
const lookup: DmpLookup = new DmpLookup();
lookup.page = { size: 100, offset: 0 };
if (excludedIds && excludedIds.length > 0) { lookup.excludedIds = excludedIds; }
if (ids && ids.length > 0) { lookup.ids = ids; }
lookup.isActive = [IsActive.Active];
lookup.project = {
fields: [
nameof<Dmp>(x => x.id),
nameof<Dmp>(x => x.label)
]
};
lookup.order = { items: [nameof<Dmp>(x => x.label)] };
if (like) { lookup.like = this.filterService.transformLike(like); }
return lookup;
}
}
//
//
// Pre refactor TODO: delete
//
//
@Injectable()
export class DmpService {

View File

@ -15,7 +15,7 @@ import { BaseHttpV2Service } from '../http/base-http-v2.service';
import { HttpResponse } from '@angular/common/http';
@Injectable()
export class LanguageV2Service {
export class LanguageHttpService {
constructor(private http: BaseHttpV2Service, private configurationService: ConfigurationService, private filterService: FilterService) {
}

View File

@ -1,26 +1,20 @@
import { Injectable } from '@angular/core';
import { BaseService } from '@common/base/base.service';
import { TranslateService } from '@ngx-translate/core';
import { environment } from 'environments/environment';
import { Observable } from 'rxjs';
import { HttpResponse, HttpClient } from '@angular/common/http';
import { BaseHttpService } from '../http/base-http.service';
import { Language } from '@app/models/language/Language';
import { ConfigurationService } from '../configuration/configuration.service';
import { BaseHttpParams } from '@common/http/base-http-params';
import { InterceptorType } from '@common/http/interceptors/interceptor-type';
import { map, takeUntil } from 'rxjs/operators';
import { LanguageHttpService } from './language.http.service';
@Injectable()
export class LanguageService {
export class LanguageService extends BaseService {
private currentLanguage: string;
private get apiBase(): string { return `${this.configurationService.server}language`; }
private availableLanguageCodes: string[];
constructor(
private translate: TranslateService,
private http: HttpClient,
private baseHttp: BaseHttpService,
private configurationService: ConfigurationService
private languageHttpService: LanguageHttpService
) {
this.currentLanguage = this.configurationService.defaultLanguage || 'en';
super();
}
public changeLanguage(lang: string) {
@ -29,31 +23,28 @@ export class LanguageService {
}
public getCurrentLanguage() {
if (this.currentLanguage == null) throw new Error("languages not loaded");
return this.currentLanguage;
}
public getCurrentLanguageJSON(): Observable<HttpResponse<Blob>> {
const params = new BaseHttpParams();
// params.interceptorContext = {
// excludedInterceptors: [
// InterceptorType.AuthToken,
// ]
// };
return this.http.get(`${this.apiBase}/${this.currentLanguage}`, { params: params, responseType: 'blob', observe: 'response' });
public loadAvailableLanguages(): Observable<string[]> {
return this.languageHttpService.queryAvailableCodes(this.languageHttpService.buildAutocompleteLookup())
.pipe(takeUntil(this._destroyed)).pipe(
map((data) => {
this.availableLanguageCodes = data.items;
if (this.availableLanguageCodes.length > 0) this.currentLanguage = this.availableLanguageCodes[0];
return this.availableLanguageCodes;
})
);
}
public updateLanguage(json: string): Observable<String> {
return this.baseHttp.post<string>(`${this.apiBase}/update/${this.currentLanguage}`, json);
public getDefaultLanguagesCode() {
if (this.availableLanguageCodes == null || this.availableLanguageCodes.length == 0) throw new Error("languages not loaded");
return this.availableLanguageCodes[0];
}
public getCurrentLanguageName() {
let result: string = '';
this.configurationService.availableLanguages.forEach(language => {
if (language.value === this.currentLanguage) {
result = this.translate.instant(language.label);
public getAvailableLanguagesCodes() {
if (this.availableLanguageCodes == null) throw new Error("languages not loaded");
return this.availableLanguageCodes;
}
});
return result;
}
}

View File

@ -5,23 +5,23 @@ import { HttpClient } from '@angular/common/http';
import { ConfigurationService } from '../configuration/configuration.service';
import { BaseHttpParams } from '@common/http/base-http-params';
import { InterceptorType } from '@common/http/interceptors/interceptor-type';
import { LanguageHttpService } from './language.http.service';
import { map } from 'rxjs/operators';
import { nameof } from 'ts-simple-nameof';
import { Language } from '@app/core/model/language/language';
export class TranslateServerLoader implements TranslateLoader{
private get apiBase(): string { return `${this.configurationService.server}language`; }
export class TranslateServerLoader implements TranslateLoader {
constructor(
private http: HttpClient,
private configurationService: ConfigurationService
private languageHttpService: LanguageHttpService
) {
}
getTranslation(lang: string): Observable<any> {
const params = new BaseHttpParams();
// params.interceptorContext = {
// excludedInterceptors: [
// InterceptorType.AuthToken,
// ]
// };
return this.http.get(`${this.apiBase}/${lang}`, { params: params });
return this.languageHttpService.getSingleWithCode(lang, [
...nameof<Language>(x => x.id),
nameof<Language>(x => x.code),
nameof<Language>(x => x.payload),
]).pipe(map(x => JSON.parse(x.payload)));
}
}

View File

@ -27,7 +27,7 @@ import { map, takeUntil } from 'rxjs/operators';
import { LanguageEditorResolver } from './language-editor.resolver';
import { LanguageEditorService } from './language-editor.service';
import { LanguageEditorModel } from './language-editor.model';
import { LanguageV2Service } from '@app/core/services/language/language-v2.service';
import { LanguageHttpService } from '@app/core/services/language/language.http.service';
@Component({
@ -76,7 +76,7 @@ export class LanguageEditorComponent extends BaseEditor<LanguageEditorModel, Lan
// Rest dependencies. Inject any other needed deps here:
public authService: AuthService,
public enumUtils: EnumUtils,
private languageV2Service: LanguageV2Service,
private languageV2Service: LanguageHttpService,
private logger: LoggingService,
private languageEditorService: LanguageEditorService,
private fileUtils: FileUtils,

View File

@ -1,7 +1,7 @@
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Language } from '@app/core/model/language/language';
import { LanguageV2Service } from '@app/core/services/language/language-v2.service';
import { LanguageHttpService } from '@app/core/services/language/language.http.service';
import { BreadcrumbService } from '@app/ui/misc/breadcrumb/breadcrumb.service';
import { BaseEditorResolver } from '@common/base/base-editor.resolver';
import { Guid } from '@common/types/guid';
@ -11,7 +11,7 @@ import { nameof } from 'ts-simple-nameof';
@Injectable()
export class LanguageEditorResolver extends BaseEditorResolver {
constructor(private languageV2Service: LanguageV2Service, private breadcrumbService: BreadcrumbService) {
constructor(private languageV2Service: LanguageHttpService, private breadcrumbService: BreadcrumbService) {
super();
}

View File

@ -5,7 +5,7 @@ import { IsActive } from '@app/core/common/enum/is-active.enum';
import { Language } from '@app/core/model/language/language';
import { LanguageLookup } from '@app/core/query/language.lookup';
import { AuthService } from '@app/core/services/auth/auth.service';
import { LanguageV2Service } from '@app/core/services/language/language-v2.service';
import { LanguageHttpService } from '@app/core/services/language/language.http.service';
import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service';
import { EnumUtils } from '@app/core/services/utilities/enum-utils.service';
import { QueryParamsService } from '@app/core/services/utilities/query-params.service';
@ -52,7 +52,7 @@ export class LanguageListingComponent extends BaseListingComponent<Language, Lan
protected uiNotificationService: UiNotificationService,
protected httpErrorHandlingService: HttpErrorHandlingService,
protected queryParamsService: QueryParamsService,
private languageV2Service: LanguageV2Service,
private languageV2Service: LanguageHttpService,
public authService: AuthService,
private pipeService: PipeService,
public enumUtils: EnumUtils,

View File

@ -0,0 +1,17 @@
<div class="dataset-copy-dialog">
<div mat-dialog-title class="row d-flex flex-row">
<div mat-dialog-title class="col-auto">{{'DATASET-WIZARD.DIALOGUE.TITLE' | translate}}</div>
<div class="col-auto ml-auto close-btn" (click)="close()"><mat-icon class="close-icon">close</mat-icon></div>
</div>
<div mat-dialog-content class="confirmation-message">
<mat-form-field class="col-12">
<app-single-auto-complete [formControl]="data.formControl" placeholder="{{'DATASET-WIZARD.DIALOGUE.DMP-SEARCH.PLACEHOLDER' | translate}}" [configuration]="dmpAutoCompleteConfiguration">
</app-single-auto-complete>
</mat-form-field>
<!-- <mat-error *ngIf="data.formControl.hasError('incorrect')">{{getErrorMessage()}}</mat-error> -->
</div>
<div mat-dialog-actions class="row">
<div class="col-auto ml-auto"><button mat-button class="cancel-btn" type="button" (click)="cancel()">{{ data.cancelButton }}</button></div>
<div class="col-auto"><button mat-button class="confirm-btn" type="button" (click)="confirm()">{{ data.confirmButton }}</button></div>
</div>
</div>

View File

@ -0,0 +1,50 @@
.confirmation-message {
padding-bottom: 20px;
}
.close-btn {
cursor: pointer;
}
.dataset-copy-dialog {
margin-bottom: 1.125rem;
}
.cancel-btn {
background: #ffffff 0% 0% no-repeat padding-box;
border: 1px solid #b5b5b5;
border-radius: 30px;
min-width: 101px;
height: 43px;
color: #212121;
font-weight: 500;
}
.confirm-btn {
background: #ffffff 0% 0% no-repeat padding-box;
border: 1px solid var(--primary-color);
border-radius: 30px;
opacity: 1;
min-width: 101px;
height: 43px;
color: var(--primary-color);
font-weight: 500;
}
.confirm-btn:hover {
background-color: var(--primary-color);
color: #ffffff;
}
.close-icon {
cursor: pointer;
// margin-right: 20px;
padding: .4rem;
width: auto !important;
height: auto !important;
}
.close-icon:hover {
background-color: #ECECED !important;
border-radius: 50%;
}

View File

@ -0,0 +1,95 @@
import { map, filter } from 'rxjs/operators';
import { Component } from "@angular/core";
import { MatDialogRef, MAT_DIALOG_DATA } from "@angular/material/dialog";
import { SingleAutoCompleteConfiguration } from "../../../../library/auto-complete/single/single-auto-complete-configuration";
import { Observable } from "rxjs";
import { DataTableRequest } from "../../../../core/model/data-table/data-table-request";
import { DmpCriteria } from "../../../../core/query/dmp/dmp-criteria";
import { DmpListingModel } from "../../../../core/model/dmp/dmp-listing";
import { DmpService } from "../../../../core/services/dmp/dmp.service";
import { Inject } from "@angular/core";
import { DmpModel } from "../../../../core/model/dmp/dmp";
import { TranslateService } from "@ngx-translate/core";
@Component({
selector: 'dataset-copy-dialogue-component',
templateUrl: 'dataset-copy-dialogue.component.html',
styleUrls: ['./dataset-copy-dialogue.component.scss'],
})
export class DatasetCopyDialogueComponent {
dmpAutoCompleteConfiguration: SingleAutoCompleteConfiguration;
dmpModel: DmpModel;
datasetDescriptionTemplateLabel: String;
constructor(
public dialogRef: MatDialogRef<DatasetCopyDialogueComponent>,
public dmpService: DmpService,
public language: TranslateService,
@Inject(MAT_DIALOG_DATA) public data: any
) { }
ngOnInit() {
this.dmpAutoCompleteConfiguration = {
filterFn: this.searchDmp.bind(this),
initialItems: (extraData) => this.searchDmp(''),
displayFn: (item) => item['label'],
titleFn: (item) => item['label'],
};
}
cancel() {
this.dialogRef.close(this.data);
}
confirm() {
this.datasetProfileValidate().subscribe(x => {
if (this.data.datasetProfileExist) {
this.dialogRef.close(this.data);
}
else if (!this.data.datasetProfileExist) {
this.data.formControl.setErrors({ 'incorrect': true });
}
});
}
searchDmp(query: string): Observable<DmpListingModel[]> {
const fields: Array<string> = new Array<string>();
fields.push('asc');
const dmpDataTableRequest: DataTableRequest<DmpCriteria> = new DataTableRequest(0, null, { fields: fields });
dmpDataTableRequest.criteria = new DmpCriteria();
dmpDataTableRequest.criteria.like = query;
dmpDataTableRequest.criteria.datasetTemplates = [this.data.datasetProfileId];
return this.dmpService.getPaged(dmpDataTableRequest, "profiles").pipe(map(x => x.data));
}
datasetProfileValidate() {
return this.dmpService.getSingle(this.data.formControl.value.id).pipe(map(result => result as DmpModel),
map(result => {
this.dmpModel = result
this.dmpModel.profiles.forEach((element) => {
if (element.id == this.data.datasetProfileId) {
this.data.datasetProfileExist = true;
}
})
}));
}
getErrorMessage() {
return this.language.instant('DATASET-WIZARD.DIALOGUE.ERROR-MESSAGE');
}
hasValidDatasetProfile() {
if (this.data.datasetProfileExist) {
return true;
}
else {
return false;
}
}
close() {
this.dialogRef.close(false);
}
}

View File

@ -0,0 +1,18 @@
import { NgModule } from '@angular/core';
import { CommonUiModule } from '@common/ui/common-ui.module';
import { AutoCompleteModule } from '@app/library/auto-complete/auto-complete.module';
import { CommonFormsModule } from '@common/forms/common-forms.module';
import { DatasetCopyDialogueComponent } from './dataset-copy-dialogue.component';
@NgModule({
imports: [
CommonUiModule,
CommonFormsModule,
AutoCompleteModule
],
declarations: [
DatasetCopyDialogueComponent
]
})
export class DatasetCopyDialogModule { }

View File

@ -0,0 +1,107 @@
<form class="dataset-editor" *ngIf="formGroup" [formGroup]="formGroup">
<div class="col-12 intro">
<p>{{'DATASET-EDITOR.TITLE.INTRO' | translate}}</p>
<span>{{'DATASET-EDITOR.TITLE.INTRO-TIP' | translate}}</span>
</div>
<div class="col-12 card">
<!-- Title Field -->
<div class="row">
<div class="col-12">
<div class="heading">1.1 {{'DATASET-EDITOR.FIELDS.TITLE' | translate}}*</div>
<!-- <span class="hint">{{'DATASET-EDITOR.HINT.TITLE' | translate}}</span> -->
<!-- <a class="dmp-link dmp-tour-{{ formGroup.get('id').value + 1 }}" (click)="restartTour(formGroup.get('id').value + 1)">{{'DATASET-EDITOR.FIELDS.DMP' | translate}}</a>
<span class="hint">{{'DATASET-EDITOR.HINT.TITLE-REST' | translate}}</span> -->
<div class="title-form">
<mat-form-field>
<input matInput placeholder="{{'DATASET-EDITOR.FIELDS.TITLE' | translate}}" type="text" name="label" formControlName="label" required>
<mat-error *ngIf="formGroup.get('label').hasError('backendError')"> {{formGroup.get('label').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('label').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
</div>
</div>
<!-- Description field -->
<div class="row">
<div class="col-12">
<div class="heading">1.2 {{'DATASET-EDITOR.FIELDS.DESCRIPTION' | translate}}</div>
<span class="hint">{{'DATASET-EDITOR.HINT.DESCRIPTION' | translate}}</span>
<!-- <span class="hint">{{'DATASET-EDITOR.HINT.TITLE' | translate}}</span>
<a class="dmp-link dmp-tour-{{ formGroup.get('id').value + 2 }}" (click)="restartTour(formGroup.get('id').value + 2)">{{'DATASET-EDITOR.FIELDS.DMP' | translate}}</a>
<span class="hint">{{'DATASET-EDITOR.HINT.TITLE-REST' | translate}}</span> -->
<div class="description-form">
<rich-text-editor-component [parentFormGroup]="formGroup" [controlName]="'description'"
[placeholder]="'DMP-EDITOR.PLACEHOLDER.DESCRIPTION'"
[wrapperClasses]="'full-width editor ' +
((formGroup.get('description').touched && (formGroup.get('description').hasError('required') || formGroup.get('description').hasError('backendError'))) ? 'required' : '')"
[editable]="!formGroup.get('description').disabled">
</rich-text-editor-component>
<div [class]="(formGroup.get('description').touched && (formGroup.get('description').hasError('required') || formGroup.get('description').hasError('backendError'))) ? 'visible' : 'invisible'" class="mat-form-field form-field-subscript-wrapper">
<mat-error *ngIf="formGroup.get('description').hasError('backendError')">{{formGroup.get('description').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('description').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</div>
</div>
</div>
</div>
<!-- Uri field -->
<!-- <div class="row">
<div class="col-12">
<div class="heading">1.3 {{'DATASET-EDITOR.FIELDS.EXTERNAL-LINK' | translate}}</div>
<span class="hint"></span>
<div class="uri-form">
<mat-form-field>
<input matInput placeholder="{{'DATASET-EDITOR.PLACEHOLDER.EXTERNAL-LINK' | translate}}" type="text" name="uri" formControlName="uri">
<mat-error *ngIf="formGroup.get('uri').hasError('backendError')">{{formGroup.get('uri').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('uri').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
</div>
</div> -->
<!-- External Fields -->
<app-dataset-external-references-editor-component [formGroup]="formGroup" [viewOnly]="viewOnly"></app-dataset-external-references-editor-component>
<!-- Template Field -->
<div class="heading">1.4 {{'DATASET-EDITOR.FIELDS.PROFILE' | translate}}*</div>
<div class="profile-form">
<mat-form-field>
<mat-select placeholder="{{'DATASET-WIZARD.FIRST-STEP.PROFILE'| translate}}" [required]="true" [compareWith]="compareWith" formControlName="profile">
<mat-option *ngFor="let profile of availableProfiles" [value]="profile">
<div (click)="checkMinMax($event, profile)">
{{profile.label}}
</div>
</mat-option>
</mat-select>
<mat-error *ngIf="formGroup.get('profile').hasError('backendError')">{{formGroup.get('profile').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('label').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
</div>
</form>
<!-- <div class="container-fluid">
<div class="row dataset-editor" [formGroup]="formGroup">
<div class="col-12">
<div class="row">
<mat-form-field class="col-sm-12 col-md-6">
<input matInput placeholder="{{'DATASET-EDITOR.FIELDS.NAME' | translate}}" type="text" name="label" formControlName="label" required>
<mat-error *ngIf="formGroup.get('label').hasError('backendError')">{{formGroup.get('label').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('label').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
<div class="row" *ngIf="showUri">
<mat-form-field class="col-sm-12 col-md-6">
<input matInput placeholder="{{'DATASET-EDITOR.FIELDS.URI' | translate}}" type="text" name="uri" formControlName="uri">
<mat-error *ngIf="formGroup.get('uri').hasError('backendError')">{{formGroup.get('uri').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('uri').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
<div class="row">
<mat-form-field class="col-sm-12 col-md-6">
<textarea matInput class="description-area" placeholder="{{'DATASET-EDITOR.FIELDS.DESCRIPTION' | translate}}" formControlName="description"></textarea>
<mat-error *ngIf="formGroup.get('description').hasError('backendError')">{{formGroup.get('description').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('description').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
</div>
</div>
</div> -->

View File

@ -0,0 +1,117 @@
.dataset-editor {
.intro {
text-align: left;
font-weight: 400;
letter-spacing: 0px;
color: #212121;
opacity: 1;
margin: 3rem 0rem 3rem 0rem;
}
.heading {
text-align: left;
font-weight: 700;
font-size: 18px;
letter-spacing: 0px;
color: #212121;
opacity: 0.81;
margin-top: 1.625rem;
margin-bottom: 0.625rem;
}
.hint {
text-align: left;
font-weight: 400;
font-size: 16px;
letter-spacing: 0px;
color: #212121;
opacity: 0.81;
margin-bottom: 2.125rem;
}
.title-form,
.description-form,
.profile-form {
text-align: left;
font-weight: 400;
font-size: 16px;
letter-spacing: 0.15px;
color: #7d7d7d;
opacity: 1;
margin-bottom: 1rem;
}
// textarea::placeholder {
// font-style: oblique;
// }
.input-btn {
border: none;
color: #aaaaaa;
background-color: #ffffff00;
cursor: pointer;
}
.input-btn :hover {
color: var(--primary-color-3) !important;
}
.dmp-link {
color: #3fafac;
font-weight: 400;
font-size: 16px;
cursor: pointer;
}
.dmp-link:hover {
text-decoration: underline;
}
}
::ng-deep .title-form .mat-form-field-appearance-outline .mat-form-field-outline {
background: #fafafa !important;
}
::ng-deep .description-form .mat-form-field-appearance-outline .mat-form-field-outline {
background: #fafafa !important;
}
::ng-deep .uri-form .mat-form-field-appearance-outline .mat-form-field-outline {
background: #fafafa !important;
}
::ng-deep .tags-form .mat-form-field-appearance-outline .mat-form-field-outline {
background: #fafafa !important;
}
::ng-deep .profile-form .mat-form-field-appearance-outline .mat-form-field-outline {
background: #fafafa !important;
}
::ng-deep .title-form .mat-form-field-appearance-outline .mat-form-field-infix {
font-size: 1rem;
padding: 0.6em 0 1em 0 !important;
}
::ng-deep .description-form .mat-form-field-appearance-outline .mat-form-field-infix {
// font-size: 1rem;
padding: 0.6em 0 1em 0 !important;
}
::ng-deep .uri-form .mat-form-field-appearance-outline .mat-form-field-infix {
font-size: 1rem;
padding: 0.6em 0 1em 0 !important;
}
::ng-deep .tags-form .mat-form-field-appearance-outline .mat-form-field-infix {
font-size: 1rem;
padding: 0.6em 0 1em 0 !important;
}
::ng-deep .profile-form .mat-form-field-appearance-outline .mat-form-field-infix {
font-size: 1rem;
padding: 0.6em 0 1em 0 !important;
}

View File

@ -0,0 +1,145 @@
import { Component, Input } from '@angular/core';
import { UntypedFormGroup } from '@angular/forms';
import { Router } from '@angular/router';
import { BaseComponent } from '@common/base/base.component';
import { GuidedTourService } from '@app/library/guided-tour/guided-tour.service';
import { GuidedTour, Orientation } from '@app/library/guided-tour/guided-tour.constants';
import { TranslateService } from '@ngx-translate/core';
import { DatasetProfileModel } from '@app/core/model/dataset/dataset-profile';
import { takeUntil } from 'rxjs/operators';
import { DmpBlueprintService } from '@app/core/services/dmp/dmp-blueprint.service';
import { MatDialog } from '@angular/material/dialog';
import { PopupNotificationDialogComponent } from '@app/library/notification/popup/popup-notification.component';
import { Guid } from '@common/types/guid';
import { nameof } from 'ts-simple-nameof';
import { DescriptionTemplatesInSection, DmpBlueprint, DmpBlueprintDefinition, DmpBlueprintDefinitionSection, FieldInSection } from '@app/core/model/dmp-blueprint/dmp-blueprint';
@Component({
selector: 'app-dataset-editor-component',
templateUrl: 'dataset-editor.component.html',
styleUrls: ['./dataset-editor.component.scss']
})
export class DatasetEditorComponent extends BaseComponent {
@Input() formGroup: UntypedFormGroup;
// @Input() formGroup: FormGroup = null;
@Input() availableProfiles: DatasetProfileModel[];
@Input() dmpId: string;
showUri: boolean = false;
dmpText: string = null;
viewOnly = false;
constructor(
private router: Router,
private dmpBlueprintService: DmpBlueprintService,
private dialog: MatDialog,
private guidedTourService: GuidedTourService,
private language: TranslateService
) { super(); }
public dashboardTourDmp: GuidedTour = {
tourId: 'only-dmp-tour',
useOrb: true,
steps: [
{
title: this.dmpText,
content: 'Step 1',
orientation: Orientation.Bottom,
highlightPadding: 3,
isStepUnique: true,
customTopOffset: 8
}
]
};
checkMinMax(event, profile: DatasetProfileModel) {
event.stopPropagation();
const dmpSectionIndex = this.formGroup.get('dmpSectionIndex').value;
const blueprintId = this.formGroup.get('dmp').value.profile.id;
this.dmpBlueprintService.getSingle(blueprintId,
[
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.id)].join('.'),
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.label)].join('.'),
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.description)].join('.'),
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.ordinal)].join('.'),
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.hasTemplates)].join('.'),
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.fields), nameof<FieldInSection>(x => x.id)].join('.'),
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.fields), nameof<FieldInSection>(x => x.category)].join('.'),
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.fields), nameof<FieldInSection>(x => x.dataType)].join('.'),
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.fields), nameof<FieldInSection>(x => x.systemFieldType)].join('.'),
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.fields), nameof<FieldInSection>(x => x.label)].join('.'),
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.fields), nameof<FieldInSection>(x => x.placeholder)].join('.'),
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.fields), nameof<FieldInSection>(x => x.description)].join('.'),
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.fields), nameof<FieldInSection>(x => x.required)].join('.'),
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.fields), nameof<FieldInSection>(x => x.ordinal)].join('.'),
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.descriptionTemplates), nameof<DescriptionTemplatesInSection>(x => x.id)].join('.'),
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.descriptionTemplates), nameof<DescriptionTemplatesInSection>(x => x.descriptionTemplateId)].join('.'),
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.descriptionTemplates), nameof<DescriptionTemplatesInSection>(x => x.label)].join('.'),
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.descriptionTemplates), nameof<DescriptionTemplatesInSection>(x => x.minMultiplicity)].join('.'),
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.descriptionTemplates), nameof<DescriptionTemplatesInSection>(x => x.maxMultiplicity)].join('.'),
]
)
.pipe(takeUntil(this._destroyed))
.subscribe(result => {
const section = result.definition.sections[dmpSectionIndex];
if(section.hasTemplates){
const foundTemplate = section.descriptionTemplates.find(template => template.descriptionTemplateId === Guid.parse(profile.id));
if (foundTemplate !== undefined) {
let count = 0;
if(this.formGroup.get('dmp').value.datasets != null){
for(let dataset of this.formGroup.get('dmp').value.datasets){
if(dataset.dmpSectionIndex === dmpSectionIndex && dataset.profile.id === foundTemplate.descriptionTemplateId){
count++;
}
}
if(count === foundTemplate.maxMultiplicity){
this.dialog.open(PopupNotificationDialogComponent, {
data: {
title: this.language.instant('DATASET-EDITOR.MAX-DESCRIPTION-DIALOG.TITLE'),
message: this.language.instant('DATASET-EDITOR.MAX-DESCRIPTION-DIALOG.MESSAGE')
}, maxWidth: '30em'
});
}
else{
this.formGroup.get('profile').setValue(profile);
}
}
}
else {
this.formGroup.get('profile').setValue(profile);
}
}
else {
this.formGroup.get('profile').setValue(profile);
}
});
}
getDmpText(): string {
return this.language.instant('DMP-LISTING.TEXT-INFO') + '\n\n' +
this.language.instant('DMP-LISTING.TEXT-INFO-QUESTION') + ' ' +
this.language.instant('DMP-LISTING.LINK-ZENODO') + ' ' +
this.language.instant('DMP-LISTING.GET-IDEA');
}
setDashboardTourDmp(label: string): void {
this.dashboardTourDmp.steps[0].title = this.getDmpText();
this.dashboardTourDmp.steps[0].selector = '.dmp-tour-' + label;
}
public restartTour(label: string): void {
this.setDashboardTourDmp(label);
this.guidedTourService.startTour(this.dashboardTourDmp);
}
public cancel(): void {
this.router.navigate(['/datasets']);
}
public compareWith(object1: any, object2: any) {
return object1 && object2 && object1.id === object2.id;
}
}

View File

@ -0,0 +1,382 @@
import { UntypedFormBuilder, UntypedFormGroup, Validators } from "@angular/forms";
import { ExternalDatasetType } from '@app/core/common/enum/external-dataset-type';
import { DataRepositoryModel } from '@app/core/model/data-repository/data-repository';
import { DatasetProfileModel } from '@app/core/model/dataset/dataset-profile';
import { DatasetWizardModel } from '@app/core/model/dataset/dataset-wizard';
import { DmpModel } from '@app/core/model/dmp/dmp';
import { ExternalDatasetModel } from '@app/core/model/external-dataset/external-dataset';
import { RegistryModel } from '@app/core/model/registry/registry';
import { ServiceModel } from '@app/core/model/service/service';
import { TagModel } from '@app/core/model/tag/tag';
import { DatasetDescriptionFormEditorModel } from '@app/ui/misc/dataset-description-form/dataset-description-form.model';
import { BackendErrorValidator } from '@common/forms/validation/custom-validator';
import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model';
import { ValidationContext } from '@common/forms/validation/validation-context';
export class DatasetWizardEditorModel {
public id: string;
public label: string;
public profile: DatasetProfileModel;
public uri: String;
public status: number;
public description: String;
public services: ExternalServiceEditorModel[] = [];
public registries: ExternalRegistryEditorModel[] = [];
public dataRepositories: ExternalDataRepositoryEditorModel[] = [];
public tags: ExternalTagEditorModel[] = [];
public externalDatasets: ExternalDatasetEditorModel[] = [];
public dmp: DmpModel;
public dmpSectionIndex: number;
public datasetProfileDefinition: DatasetDescriptionFormEditorModel;
public validationErrorModel: ValidationErrorModel = new ValidationErrorModel();
public isProfileLatestVersion: Boolean;
public modified: Date;
fromModel(item: DatasetWizardModel): DatasetWizardEditorModel {
this.id = item.id;
this.label = item.label;
this.profile = item.profile;
this.uri = item.uri;
this.status = item.status;
this.description = item.description;
if (item.services) { this.services = item.services.map(x => new ExternalServiceEditorModel().fromModel(x)); }
if (item.registries) { this.registries = item.registries.map(x => new ExternalRegistryEditorModel().fromModel(x)); }
if (item.dataRepositories) { this.dataRepositories = item.dataRepositories.map(x => new ExternalDataRepositoryEditorModel().fromModel(x)); }
if (item.externalDatasets) { this.externalDatasets = item.externalDatasets.map(x => new ExternalDatasetEditorModel().fromModel(x)); }
this.dmp = item.dmp;
this.dmpSectionIndex = item.dmpSectionIndex;
if (item.datasetProfileDefinition) { this.datasetProfileDefinition = new DatasetDescriptionFormEditorModel().fromModel(item.datasetProfileDefinition); }
if (item.tags) { this.tags = item.tags.map(x => new ExternalTagEditorModel().fromModel(x)); }
this.isProfileLatestVersion = item.isProfileLatestVersion;
this.modified = new Date(item.modified);
return this;
}
buildForm(context: ValidationContext = null, disabled: boolean = false): UntypedFormGroup {
if (context == null) { context = this.createValidationContext(); }
const formBuilder = new UntypedFormBuilder();
const formGroup = formBuilder.group({
id: [{ value: this.id, disabled: disabled }, context.getValidation('id').validators],
label: [{ value: this.label, disabled: disabled }, context.getValidation('label').validators],
uri: [{ value: this.uri, disabled: disabled }, context.getValidation('uri').validators],
status: [{ value: this.status, disabled: disabled }, context.getValidation('status').validators],
description: [{ value: this.description, disabled: disabled }, context.getValidation('description').validators],
dmp: [{ value: this.dmp, disabled: disabled }, context.getValidation('dmp').validators],
dmpSectionIndex: [{ value: this.dmpSectionIndex, disabled: disabled }, context.getValidation('dmpSectionIndex').validators],
//externalDatasets: [{ value: this.externalDatasets, disabled: disabled }, context.getValidation('externalDatasets').validators],
tags: [{ value: this.tags, disabled: disabled }, context.getValidation('tags').validators],
//registries: [{ value: this.registries, disabled: disabled }, context.getValidation('registries').validators],
//dataRepositories: [{ value: this.dataRepositories, disabled: disabled }, context.getValidation('dataRepositories').validators],
//services: [{ value: this.services, disabled: disabled }, context.getValidation('services').validators],
profile: [{ value: this.profile, disabled: disabled }, context.getValidation('profile').validators],
modified: [{value: this.modified, disabled: disabled}, context.getValidation('modified').validators]
});
const externalDatasetsFormArray = new Array<UntypedFormGroup>();
//if (this.externalDatasets && this.externalDatasets.length > 0) {
this.externalDatasets.forEach(item => {
externalDatasetsFormArray.push(item.buildForm(context.getValidation('externalDatasets').descendantValidations, disabled));
});
// } else {
// //externalDatasetsFormArray.push(new ExternalDatasetModel().buildForm(context.getValidation('externalDatasets').descendantValidations, disabled));
// }
formGroup.addControl('externalDatasets', formBuilder.array(externalDatasetsFormArray));
// const tagsFormArray = new Array<FormGroup>();
// if (this.tags && this.tags.length > 0) {
// this.tags.forEach(item => {
// tagsFormArray.push(item.buildForm(context.getValidation('tags').descendantValidations, disabled));
// });
// } else {
// //externalDatasetsFormArray.push(new ExternalDatasetModel().buildForm(context.getValidation('externalDatasets').descendantValidations, disabled));
// }
// formGroup.addControl('tags', formBuilder.array(tagsFormArray));
const registriesFormArray = new Array<UntypedFormGroup>();
//if (this.registries && this.registries.length > 0) {
this.registries.forEach(item => {
registriesFormArray.push(item.buildForm(context.getValidation('registries').descendantValidations, disabled));
});
// } else {
// //externalDatasetsFormArray.push(new ExternalDatasetModel().buildForm(context.getValidation('externalDatasets').descendantValidations, disabled));
// }
formGroup.addControl('registries', formBuilder.array(registriesFormArray));
const dataRepositoriesFormArray = new Array<UntypedFormGroup>();
//if (this.dataRepositories && this.dataRepositories.length > 0) {
this.dataRepositories.forEach(item => {
dataRepositoriesFormArray.push(item.buildForm(context.getValidation('dataRepositories').descendantValidations, disabled));
});
// } else {
// //externalDatasetsFormArray.push(new ExternalDatasetModel().buildForm(context.getValidation('externalDatasets').descendantValidations, disabled));
// }
formGroup.addControl('dataRepositories', formBuilder.array(dataRepositoriesFormArray));
const servicesFormArray = new Array<UntypedFormGroup>();
// if (this.services && this.services.length > 0) {
this.services.forEach(item => {
servicesFormArray.push(item.buildForm(context.getValidation('services').descendantValidations, disabled));
});
// } else {
// //externalDatasetsFormArray.push(new ExternalDatasetModel().buildForm(context.getValidation('externalDatasets').descendantValidations, disabled));
// }
formGroup.addControl('services', formBuilder.array(servicesFormArray));
// const tagsFormArray = new Array<FormGroup>();
// this.tags.forEach(item => {
// tagsFormArray.push(item.buildForm(context.getValidation('tags').descendantValidations, disabled));
// });
// formGroup.addControl('tags', formBuilder.array(tagsFormArray));
if (this.datasetProfileDefinition) { formGroup.addControl('datasetProfileDefinition', this.datasetProfileDefinition.buildForm()); }
// formGroup.addControl('profile', this.profile.buildForm());
return formGroup;
}
createValidationContext(): ValidationContext {
const baseContext: ValidationContext = new ValidationContext();
baseContext.validation.push({ key: 'id', validators: [BackendErrorValidator(this.validationErrorModel, 'id')] });
baseContext.validation.push({ key: 'label', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'label')] });
baseContext.validation.push({ key: 'profile', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'profile')] });
baseContext.validation.push({ key: 'uri', validators: [BackendErrorValidator(this.validationErrorModel, 'uri')] });
baseContext.validation.push({ key: 'status', validators: [BackendErrorValidator(this.validationErrorModel, 'status')] });
baseContext.validation.push({ key: 'description', validators: [BackendErrorValidator(this.validationErrorModel, 'description')] });
baseContext.validation.push({ key: 'services', validators: [BackendErrorValidator(this.validationErrorModel, 'services')] });
baseContext.validation.push({ key: 'registries', validators: [BackendErrorValidator(this.validationErrorModel, 'registries')] });
baseContext.validation.push({ key: 'dataRepositories', validators: [BackendErrorValidator(this.validationErrorModel, 'dataRepositories')] });
baseContext.validation.push({ key: 'externalDatasets', validators: [BackendErrorValidator(this.validationErrorModel, 'externalDatasets')] });
baseContext.validation.push({ key: 'dmp', validators: [BackendErrorValidator(this.validationErrorModel, 'dmp')] });
baseContext.validation.push({ key: 'dmpSectionIndex', validators: [BackendErrorValidator(this.validationErrorModel, 'dmpSectionIndex')] });
baseContext.validation.push({ key: 'datasetProfileDefinition', validators: [BackendErrorValidator(this.validationErrorModel, 'datasetProfileDefinition')] });
baseContext.validation.push({ key: 'tags', validators: [BackendErrorValidator(this.validationErrorModel, 'datasetProfileDefinition')] });
baseContext.validation.push({ key: 'modified', validators: []});
return baseContext;
}
}
export class ExternalTagEditorModel {
public abbreviation: String;
public definition: String;
public id: String;
public name: String;
public reference: String;
public uri: String;
constructor(id?: String, name?: String) {
this.id = id;
this.name = name;
}
fromModel(item: TagModel): ExternalTagEditorModel {
this.id = item.id;
this.name = item.name;
return this;
}
buildForm(context: ValidationContext = null, disabled: boolean = false): UntypedFormGroup {
return new UntypedFormBuilder().group({
id: [this.id],
name: [this.name]
});
}
}
export class ExternalServiceEditorModel {
public id: String;
public abbreviation: String;
public definition: String;
public uri: String;
public label: String;
public reference: String;
public source: String;
constructor(abbreviation?: String, definition?: String, id?: String, label?: String, reference?: String, uri?: String, source?: String) {
this.id = id;
this.abbreviation = abbreviation;
this.definition = definition;
this.uri = uri;
this.label = label;
this.reference = reference;
this.source = source;
}
fromModel(item: ServiceModel): ExternalServiceEditorModel {
this.id = item.id;
this.abbreviation = item.abbreviation;
this.definition = item.definition;
this.uri = item.uri;
this.label = item.label;
this.reference = item.reference;
this.source = item.source;
return this;
}
buildForm(context: ValidationContext = null, disabled: boolean = false): UntypedFormGroup {
return new UntypedFormBuilder().group({
id: [this.id],
abbreviation: [this.abbreviation],
label: [this.label, Validators.required],
reference: [this.reference],
uri: [this.uri, Validators.required],
definition: [this.definition],
source: [this.source]
});
}
}
export class ExternalRegistryEditorModel {
public abbreviation: String;
public definition: String;
public id: String;
public label: String;
public reference: String;
public uri: String;
public source: String
constructor(abbreviation?: String, definition?: String, id?: String, label?: String, reference?: String, uri?: String, source?: String) {
this.abbreviation = abbreviation;
this.definition = definition;
this.id = id;
this.label = label;
this.reference = reference;
this.uri = uri;
this.source = source;
}
fromModel(item: RegistryModel): ExternalRegistryEditorModel {
this.abbreviation = item.abbreviation;
this.definition = item.definition;
this.id = item.id;
this.label = item.label;
this.reference = item.pid ? item.pid : item.reference;
this.uri = item.uri;
this.source = item.source
return this;
}
buildForm(context: ValidationContext = null, disabled: boolean = false): UntypedFormGroup {
return new UntypedFormBuilder().group({
id: [this.id],
abbreviation: [this.abbreviation],
label: [this.label, Validators.required],
reference: [this.reference],
uri: [this.uri, Validators.required],
definition: [this.definition],
source: [this.source]
});
}
}
export class ExternalDatasetEditorModel {
public abbreviation: String;
public id: String;
public name: String;
public reference: String;
public type: ExternalDatasetType;
public info: String;
public validationErrorModel: ValidationErrorModel = new ValidationErrorModel();
public source: String;
constructor(id?: string, abbreviation?: string, name?: string, reference?: string, source?: String, info?: string, type?: ExternalDatasetType) {
this.id = id;
this.name = name;
this.abbreviation = abbreviation;
this.reference = reference;
this.info = info;
this.type = type;
this.source = source;
}
fromModel(item: ExternalDatasetModel): ExternalDatasetEditorModel {
this.abbreviation = item.abbreviation;
this.id = item.id;
this.name = item.name;
this.reference = item.reference;
this.type = item.type;
this.info = item.info;
this.source = item.source;
return this;
}
buildForm(context: ValidationContext = null, disabled: boolean = false): UntypedFormGroup {
return new UntypedFormBuilder().group({
id: [this.id],
abbreviation: [this.abbreviation],
name: [this.name, Validators.required],
reference: [this.reference],
type: [this.type],
info: [this.info],
source: [this.source]
});
}
}
export class ExternalDataRepositoryEditorModel {
public id: string;
public name: string;
public abbreviation: string;
public uri: string;
public reference: string;
public info: string;
public created: Date;
public modified: Date;
public source: string;
constructor(id?: string, name?: string, abbreviation?: string, uri?: string, reference?: string, source?: string) {
this.id = id;
this.name = name;
this.abbreviation = abbreviation;
this.uri = uri;
this.reference = reference;
this.source = source;
}
fromModel(item: DataRepositoryModel): ExternalDataRepositoryEditorModel {
this.id = item.id;
this.name = item.name;
this.abbreviation = item.abbreviation;
this.uri = item.uri;
this.info = item.info;
this.reference = item.pid;
this.source = item.source;
return this;
}
buildForm(context: ValidationContext = null, disabled: boolean = false): UntypedFormGroup {
return new UntypedFormBuilder().group({
id: [this.id],
name: [this.name, [Validators.required]],
abbreviation: [this.abbreviation],
uri: [this.uri, [Validators.required]],
info: [this.info],
reference: [this.reference],
source: [this.source]
});
}
}
// export class TagModel implements Serializable<TagModel> {
// public id: string;
// public name: string;
// constructor(id?: string, name?: string) {
// this.id = id;
// this.name = name;
// }
// fromJSONObject(item: any): TagModel {
// this.id = item.id;
// this.name = item.name;
// return this;
// }
// buildForm(context: ValidationContext = null, disabled: boolean = false): FormGroup {
// return new FormBuilder().group({
// id: [this.id],
// name: [this.name]
// });
// }
// }

View File

@ -0,0 +1,288 @@
<div class="main-content">
<div class="container-fluid dataset-wizard">
<form *ngIf="formGroup" [formGroup]="formGroup">
<!-- <form *ngIf="formGroup" [formGroup]="formGroup" (ngSubmit)="formSubmit()"> -->
<!-- Dataset Header -->
<div class="fixed-editor-header">
<div class="card dataset-editor-header">
<div class="col">
<div class="row">
<div class="col info">
<ng-container *ngIf="!viewOnly else viewOnlyTemplate">
<div *ngIf="isNew" class="dataset-title">{{'DMP-EDITOR.TITLE.ADD-DATASET' | translate}}</div>
<div *ngIf="!isNew" class="dataset-title">{{'DMP-EDITOR.TITLE.EDIT-DESCRIPTION' | translate}}</div>
<div class="dataset-subtitle">{{ formGroup.get('label').value }} <span *ngIf="isDirty()" class="dataset-changes">({{'DMP-EDITOR.CHANGES' | translate}})</span></div>
</ng-container>
<ng-template #viewOnlyTemplate>
<div class="dataset-title">{{'DMP-EDITOR.TITLE.PREVIEW-DATASET' | translate}}</div>
</ng-template>
<div class="d-flex flex-direction-row dmp-info">
<div class="col-auto dataset-to-dmp">{{'DATASET-LISTING.TOOLTIP.TO-DMP' | translate}}</div>
<div class="dmp-title p-0">:&nbsp;{{ formGroup.get('dmp').value.label }}</div>
<div class="col-auto d-flex align-items-center">
<a [routerLink]="['/overview/' + formGroup.get('dmp').value.id]" target="_blank" class="pointer open-in-new-icon">
<mat-icon class="size-18">open_in_new</mat-icon>
</a>
</div>
</div>
</div>
<div class="row">
<div class="col-auto d-flex align-items-center">
<button *ngIf="formGroup.get('id').value" [disabled]="isDirty()" [matTooltipDisabled]="!isDirty()"
mat-raised-button class="dataset-export-btn" type="button"
[matMenuTriggerFor]="exportMenu" (click)="$event.stopPropagation();"
[matTooltip]="'DATASET-EDITOR.ACTIONS.DISABLED-EXPORT' | translate">
{{ 'DMP-LISTING.ACTIONS.EXPORT' | translate }}
<mat-icon [disabled]="isDirty()" style="width: 14px;">expand_more</mat-icon>
</button>
<mat-menu #exportMenu="matMenu" xPosition="before">
<button mat-menu-item (click)="downloadPDF(formGroup.get('id').value)">
<i class="fa fa-file-pdf-o pr-2"></i>
<span>{{'GENERAL.FILE-TYPES.PDF' | translate}}</span>
</button>
<button mat-menu-item (click)="downloadDOCX(formGroup.get('id').value)">
<i class="fa fa-file-word-o pr-2"></i>
<span>{{'GENERAL.FILE-TYPES.DOC' | translate}}</span>
</button>
<button mat-menu-item (click)="downloadXML(formGroup.get('id').value)">
<i class="fa fa-file-code-o pr-2"></i>
<span>{{'GENERAL.FILE-TYPES.XML' | translate}}</span>
</button>
</mat-menu>
</div>
<mat-divider *ngIf="formGroup.get('id').value && (!viewOnly || (!lockStatus && !viewOnly) || lockStatus || (hasReversableStatus() && !lockStatus))"
[vertical]="true" class="ml-2 mr-2"></mat-divider>
<div *ngIf="isDirty() && !viewOnly" class="col-auto d-flex align-items-center pr-0">
<button [disabled]="saving" type="button" mat-raised-button class="dataset-discard-btn" (click)="discardChanges()">
{{'DMP-EDITOR.ACTIONS.DISCARD' | translate}}
</button>
</div>
<div class="col-auto d-flex align-items-center">
<button [disabled]="saving" *ngIf="!lockStatus && !viewOnly" mat-raised-button
class="dataset-save-btn mr-2" type="button">
<span class="d-flex flex-row row">
<span (click)="!saving?save():null" class="col">{{ 'DATASET-WIZARD.ACTIONS.SAVE' | translate }}</span>
<mat-divider [vertical]="true"></mat-divider>
<span *ngIf="!saving" class="align-items-center justify-content-center col-4 d-flex"
(click)="$event.stopPropagation();" [matMenuTriggerFor]="menu">
<mat-icon >expand_more</mat-icon>
</span>
<span *ngIf="saving" class="align-items-center justify-content-center col-4 d-flex">
<mat-icon >expand_more</mat-icon>
</span>
</span>
</button>
<mat-menu #menu="matMenu">
<button [disabled]="saving" mat-menu-item (click)="save(saveAnd.close)" type="button">{{ 'DATASET-WIZARD.ACTIONS.SAVE-AND-CLOSE' | translate }}</button>
<button [disabled]="saving" mat-menu-item (click)="save(saveAnd.addNew)" type="button">{{ 'DATASET-WIZARD.ACTIONS.SAVE-AND-ADD' | translate }}</button>
<button [disabled]="saving" mat-menu-item (click)="save()" type="button">{{ 'DATASET-WIZARD.ACTIONS.SAVE-AND-CONTINUE' | translate }}</button>
</mat-menu>
<button [disabled]="saving" *ngIf="!lockStatus && !viewOnly" mat-raised-button class="dataset-save-btn mr-2" type="button" (click)="saveFinalize()">{{ 'DATASET-WIZARD.ACTIONS.FINALIZE' | translate }}</button>
<!-- <button *ngIf="!lockStatus && !viewOnly" mat-raised-button class="dataset-save-btn mr-2" (click)="save()" type="button">{{ 'DATASET-WIZARD.ACTIONS.SAVE' | translate }}</button>
<button *ngIf="!lockStatus && !viewOnly" mat-raised-button class="dataset-save-btn mr-2" (click)="save(saveAnd.close)" type="button">{{ 'DATASET-WIZARD.ACTIONS.SAVE-AND-CLOSE' | translate }}</button>
<button *ngIf="!lockStatus && !viewOnly" mat-raised-button class="dataset-save-btn mr-2" (click)="save(saveAnd.addNew)">{{ 'DATASET-WIZARD.ACTIONS.SAVE-AND-ADD' | translate }}</button> -->
<button [disabled]="saving" *ngIf="lockStatus" mat-raised-button disabled class="dataset-save-btn cursor-default" type="button">{{ 'DMP-OVERVIEW.LOCKED' | translate}}</button>
<button [disabled]="saving" *ngIf="hasReversableStatus() && !lockStatus" mat-raised-button class="dataset-save-btn mr-2" (click)="reverse()" type="button">{{ 'DATASET-WIZARD.ACTIONS.REVERSE' | translate }}</button>
<!-- <button *ngIf="!lockStatus" mat-raised-button class="dataset-save-btn mr-2" (click)="touchForm()" type="button">{{ 'DATASET-WIZARD.ACTIONS.VALIDATE' | translate }}</button> -->
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row editor-content">
<div class="col-auto dataset-stepper">
<div class="stepper-back d-flex flex-direction-row">
<div class="d-flex align-items-center pr-2 back-to-dmp" (click)="backToDmp(formGroup.get('dmp').value.id)">
<mat-icon class="back-icon pointer">chevron_left</mat-icon>
<span class="pointer">{{'DATASET-WIZARD.ACTIONS.BACK-TO' | translate}}</span>
</div>
<div class="col-auto dmp-label ml-3">{{'DATASET-LISTING.TOOLTIP.DMP' | translate}}</div>
</div>
<div class="stepper-title">{{'DMP-EDITOR.STEPPER.USER-GUIDE' | translate}}</div>
<div class="stepper-options" id="stepper-options">
<div class="col stepper-list">
<div (click)="table0fContents.onToCentrySelected()" *ngIf="!datasetInfoValid()" class="main-info" [ngClass]="{'active': this.step === 0, 'text-danger':hintErrors}">0. {{'DMP-EDITOR.STEPPER.MAIN-INFO' | translate}} (2)</div>
<div (click)="table0fContents.onToCentrySelected()" *ngIf="datasetInfoValid()" class="main-info" [ngClass]="{'active': this.step === 0}">0. {{'DMP-EDITOR.STEPPER.MAIN-INFO' | translate}} (<mat-icon class="done-icon">done</mat-icon>)</div>
<div class="row toc-pane-container" #boundary>
<div #spacer></div>
<table-of-contents [visibilityRulesService]="visRulesService" [selectedFieldsetId]="fieldsetIdWithFocus" #table0fContents
[showErrors]="showtocentriesErrors" [TOCENTRY_ID_PREFIX]="TOCENTRY_ID_PREFIX" [hasFocus]="step > 0"
[formGroup]="formGroup" *ngIf="formGroup && formGroup.get('datasetProfileDefinition')" [links]="links"
[boundary]="boundary" [spacer]="spacer" [isActive]="step !== 0" stickyThing (stepFound)="onStepFound($event)"
(currentLinks)="getLinks($event)" (entrySelected)="changeStep($event.entry, $event.execute)"
[visibilityRules]="formGroup.get('datasetProfileDefinition').get('rules').value"></table-of-contents>
</div>
</div>
</div>
<div class="stepper-actions">
<div mat-raised-button type="button" class="col-auto previous stepper-btn mr-2" [ngClass]="{'previous-disabled': this.step === 0}" (click)="previousStep()">
<span class="material-icons">chevron_left</span>
<div>{{'DMP-EDITOR.STEPPER.PREVIOUS' | translate}}</div>
</div>
<div *ngIf="this.step < this.maxStep" mat-raised-button type="button" class="col-auto stepper-btn dataset-next ml-auto" (click)="nextStep()">
<div>{{'DMP-EDITOR.STEPPER.NEXT' | translate}}</div>
<span class="material-icons">chevron_right</span>
</div>
<div *ngIf="!formGroup.get('profile').value" mat-raised-button type="button" class="col-auto stepper-btn dataset-next next-disabled ml-auto">
<div>{{'DMP-EDITOR.STEPPER.NEXT' | translate}}</div>
<span class="material-icons">chevron_right</span>
</div>
<button [disabled]="saving" (click)="save(saveAnd.addNew)" *ngIf="(step === maxStep) && !lockStatus && formGroup.get('profile').value && !viewOnly" mat-raised-button type="button" class="col-auto stepper-btn add-dataset-btn ml-auto">
{{ 'DATASET-WIZARD.ACTIONS.SAVE-AND-ADD' | translate }}
</button>
</div>
<div class="col-auto pr-0">
<app-form-progress-indication class="col-12" *ngIf="formGroup && !viewOnly" [formGroup]="formGroup" [isDatasetEditor]="true"></app-form-progress-indication>
</div>
</div>
<div class="col-auto form" id="dataset-editor-form">
<app-dataset-editor-component [hidden]="this.step !== 0" [formGroup]="formGroup" [dmpId]="formGroup.get('dmp').value.id" [availableProfiles]="availableDescriptionTemplates" (formChanged)="formChanged()"></app-dataset-editor-component>
<app-dataset-description (visibilityRulesInstance)="visRulesService = $event" [TOCENTRY_ID_PREFIX]="TOCENTRY_ID_PREFIX" [hidden]="this.step === 0" *ngIf="formGroup && formGroup.get('datasetProfileDefinition')" [form]="this.formGroup.get('datasetProfileDefinition')" [visibilityRules]="formGroup.get('datasetProfileDefinition').get('rules').value" [datasetProfileId]="formGroup.get('profile').value" [linkToScroll]="linkToScroll" (fieldsetFocusChange)="fieldsetIdWithFocus = $event"></app-dataset-description>
</div>
</div>
</form>
</div>
</div>
<!-- <mat-slide-toggle [(ngModel)]="showtocentriesErrors">
</mat-slide-toggle> -->
<!-- <div class="row">
<div class="col-12">
<button (click)="printForm()">Print form</button>
</div>
<div class="col-12">
<button (click)="printFormValue()">Print form value</button>
</div>
</div> -->
<!-- <div class="main-content">
<div class="container-fluid">
<div class="card dataset-wizard">
<div class="row card-header card-header-plain d-flex">
<div class="col-12 card-desc d-flex flex-column justify-content-center">
<div class="row">
<div class="col d-flex align-items-center flex-wrap-nowrap">
<h4 *ngIf="!isNew" class="card-title">{{datasetWizardModel?.label}}
<span *ngIf="this.formGroup && this.formGroup.dirty"> -
{{ 'GENERAL.STATUSES.EDIT' | translate }}</span>
</h4>
<div *ngIf="isNew" class="card-desc new-dataset d-flex flex-column justify-content-center">
<h4 class="card-title">{{ 'DATASET-WIZARD.TITLE.NEW' | translate }}</h4>
</div>
<div *ngIf="datasetWizardModel && !isNew" class="ml-auto">
<button mat-icon-button [matMenuTriggerFor]="actionsMenu" class="more-icon" *ngIf="!publicMode" (click)="$event.stopImmediatePropagation();">
<mat-icon class="more-horiz">more_horiz</mat-icon>
</button>
<mat-menu #actionsMenu="matMenu">
<button mat-menu-item (click)="openDmpSearchDialogue()" class="menu-item">
<mat-icon>file_copy</mat-icon>{{'DATASET-WIZARD.ACTIONS.COPY-DESCRIPTION' | translate}}
</button>
<button mat-menu-item *ngIf="!viewOnly && !isCopy" (click)="openConfirm(formGroup.get('label').value, formGroup.get('id').value)" class="menu-item">
<mat-icon>delete</mat-icon>{{ 'DATASET-WIZARD.ACTIONS.DELETE' | translate }}
</button>
</mat-menu>
</div>
</div>
<div class="col-auto d-flex flex-wrap p-2" *ngIf="datasetWizardModel && !isNew">
<button mat-raised-button [matMenuTriggerFor]="exportMenu" color="primary" class="lightblue-btn ml-2 export-btn">
{{ 'DMP-LISTING.ACTIONS.EXPORT' | translate }} <mat-icon>arrow_drop_down</mat-icon>
</button>
<mat-menu #exportMenu="matMenu" xPosition="before">
<button mat-menu-item (click)="downloadPDF()">
<i class="fa fa-file-pdf-o pr-2"></i>
<span>{{'GENERAL.FILE-TYPES.PDF' | translate}}</span>
</button>
<button mat-menu-item (click)="downloadDOCX()">
<i class="fa fa-file-word-o pr-2"></i>
<span>{{'GENERAL.FILE-TYPES.DOC' | translate}}</span>
</button>
<button mat-menu-item (click)="downloadXML()">
<i class="fa fa-file-code-o pr-2"></i>
<span>{{'GENERAL.FILE-TYPES.XML' | translate}}</span>
</button>
</mat-menu>
</div>
</div>
</div>
</div>
<form *ngIf="formGroup">
<div class="d-flex flex-column">
<mat-tab-group class="mt-3">
<mat-tab>
<ng-template mat-tab-label class="tab-label">
<i class="material-icons-outlined mr-2">view_agenda</i>
{{'DATASET-PROFILE-EDITOR.STEPS.PAGES.DATASET-DETAILS' | translate}}
</ng-template>
<form *ngIf="formGroup" [formGroup]="formGroup" class="p-3">
<mat-form-field class="col-md-6">
<app-single-auto-complete [required]="true" [formControl]="formGroup.get('dmp')" placeholder="{{'DATASET-EDITOR.FIELDS.DMP' | translate}}" [configuration]="dmpAutoCompleteConfiguration">
</app-single-auto-complete>
</mat-form-field>
<mat-form-field class="col-md-6">
<mat-select placeholder=" {{'DATASET-WIZARD.FIRST-STEP.PROFILE'| translate}}" [required]="true" formControlName="profile">
<mat-option *ngFor="let profile of availableProfiles" [value]="profile">
{{profile.label}}
</mat-option>
</mat-select>
<mat-error *ngIf="formGroup.get('profile').hasError('backendError')">
{{formGroup.get('profile').getError('backendError').message}}</mat-error>
</mat-form-field>
<app-dataset-editor-component [formGroup]="formGroup"></app-dataset-editor-component>
</form>
</mat-tab>
<mat-tab>
<ng-template mat-tab-label>
<mat-icon class="mr-2">work_outline</mat-icon>
{{'DATASET-PROFILE-EDITOR.STEPS.PAGES.EXTERNAL-REFERENCES' | translate}}
</ng-template>
<form *ngIf="formGroup" [formGroup]="formGroup" class="p-3">
<app-dataset-external-references-editor-component [formGroup]="formGroup" [viewOnly]="viewOnly"></app-dataset-external-references-editor-component>
</form>
</mat-tab>
<mat-tab [disabled]="isNew && (formGroup.get('profile').disabled || !(formGroup.get('profile').valid))">
<ng-template mat-tab-label>
<div class="d-flex">
<mat-icon class="mr-2">library_books</mat-icon>
{{'DATASET-PROFILE-EDITOR.STEPS.PAGES.DESCRIPTION' | translate}}
</div>
</ng-template>
<div class="col">
<div class="row toc-pane-container" #boundary>
<div class="col-md-8 h-100 ">
<app-dataset-description-form class="w-100 h-100" *ngIf="formGroup && datasetWizardModel && datasetWizardModel.datasetProfileDefinition" [form]="this.formGroup.get('datasetProfileDefinition')" [visibilityRules]="datasetWizardModel.datasetProfileDefinition.rules" [datasetProfileId]="formGroup.get('profile').value" [linkToScroll]="linkToScroll">
</app-dataset-description-form>
</div>
<div #spacer></div>
<div class="col-md-4">
<table-of-contents class="toc-pane-container" [boundary]="boundary" [spacer]="spacer" stickyThing (stepFound)="onStepFound($event)"></table-of-contents>
</div>
</div>
</div>
</mat-tab>
</mat-tab-group>
<div class="actions">
<mat-icon *ngIf="hasNotReversableStatus() || lockStatus" color="accent" class="align-self-center mr-1">info_outlined</mat-icon>
<div *ngIf="hasNotReversableStatus()" class="align-self-center mr-3">{{'DATASET-WIZARD.ACTIONS.INFO' | translate}}</div>
<div *ngIf="lockStatus" class="align-self-center mr-3">{{'DATASET-WIZARD.ACTIONS.LOCK' | translate}}</div>
<button mat-raised-button (click)="cancel()" type="button" class="cancelButton" color="primary">
{{'DMP-EDITOR.ACTIONS.CANCEL' | translate}}
</button>
<button *ngIf="(datasetWizardModel.status == 0 || isNew) && !lockStatus" mat-raised-button class="saveButton" color="primary" (click)="save();" type="button">{{ 'DATASET-WIZARD.ACTIONS.SAVE' | translate }}</button>
<button *ngIf="(datasetWizardModel.status == 0 || isNew) && !lockStatus" mat-raised-button class="finalizeButton" color="primary" (click)="saveFinalize();" type="button">{{ 'DATASET-WIZARD.ACTIONS.FINALIZE' | translate }}</button>
<div class="fill-space"></div>
<button *ngIf="hasReversableStatus() && !lockStatus" mat-raised-button class="reverseButton" color="primary" (click)="reverse()" type="button">{{ 'DATASET-WIZARD.ACTIONS.REVERSE' | translate }}</button>
</div>
</div>
</form>
</div>
</div>
</div> -->

View File

@ -0,0 +1,524 @@
.main-content {
height: 100vh !important;
margin-top: -80px;
}
.dataset-wizard {
.toc-pane-container {
&.is-sticky ~ .nav-spacer {
height: 500px; // the container size }
// height: calc(100vh - 100px); // the container size }
}
}
.step-container {
margin-top: 1em;
}
.external-item-card {
margin-top: 1em;
}
.external-item-action-row,
.description-action-row {
margin-top: 1em;
}
.deleteButton,
.reverseButton {
margin-top: 15px;
margin-bottom: 15px;
margin-right: 15px;
text-transform: uppercase;
}
.cancelButton {
margin-top: 15px;
margin-bottom: 15px;
margin-right: 15px;
text-transform: uppercase;
}
.saveButton {
margin-top: 15px;
margin-bottom: 15px;
margin-right: 15px;
text-transform: uppercase;
}
.saveAndFinalizeButton {
margin-top: 15px;
margin-bottom: 15px;
margin-right: 15px;
}
.finalizeButton {
margin-top: 15px;
margin-bottom: 15px;
margin-right: 15px;
text-transform: uppercase;
}
.export-btn {
padding-right: 6px;
}
.downloadPDF {
margin-top: 15px;
margin-bottom: 15px;
margin-right: 15px;
}
.downloadXML {
margin-top: 15px;
margin-bottom: 15px;
margin-right: 15px;
}
.downloadDOCX {
margin-top: 15px;
margin-bottom: 15px;
margin-right: 15px;
}
.updateDatasetProfile {
margin-top: 15px;
margin-bottom: 15px;
margin-right: 15px;
}
.actions {
display: flex;
justify-content: flex-end;
}
// .actions > button {
// background-color: #0070c0;
// color: #ffffff;
// text-transform: uppercase;
// }
.more-horiz {
font-size: 28px;
color: #aaaaaa;
}
.more-icon :hover {
color: var(--primary-color-3);
}
.new-dataset {
height: 3.5em;
}
.fixed-editor-header {
// position: fixed;
// width: calc(100% - 310px);
z-index: 3;
background-color: whitesmoke;
}
.dataset-editor-header {
height: 113px;
background: var(--unnamed-color-var(--primary-color)) 0% 0% no-repeat padding-box;
background: var(--secondary-color) 0% 0% no-repeat padding-box;
box-shadow: 0px 3px 6px #00000029;
padding: 0.6rem;
margin: 30px 0px 0px 0px;
border-radius: 4px;
opacity: 1;
.info {
flex: 2;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.dataset-title {
text-align: left;
letter-spacing: 0px;
color: #212121;
opacity: 0.9;
font-size: 14px;
font-weight: 400;
}
.subtitle {
text-align: left;
color: #ffffff;
font-weight: 700;
font-size: 16px;
opacity: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.dataset-subtitle {
text-align: left;
letter-spacing: 0px;
color: #212121;
font-weight: 700;
font-size: 16px;
opacity: 0.9;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.discard-btn {
background: transparent;
border: 1px solid #ffffff;
color: white;
border-radius: 30px;
opacity: 1;
width: 110px;
height: 40px;
display: flex;
justify-content: center;
align-items: center;
}
.save-btn {
background: #ffffff 0% 0% no-repeat padding-box;
border-radius: 30px;
opacity: 1;
width: auto;
min-width: 110px;
height: 40px;
display: flex;
justify-content: center;
align-items: center;
font-weight: 700;
color: var(--primary-color);
}
.dataset-discard-btn {
border: 1px solid #212121;
border-radius: 30px;
opacity: 1;
background-color: transparent;
font-weight: 700;
width: 110px;
height: 40px;
display: flex;
justify-content: center;
align-items: center;
}
.dataset-save-btn, .dataset-export-btn {
background: #ffffff 0% 0% no-repeat padding-box;
border-radius: 30px;
opacity: 1;
width: auto;
min-width: 110px;
height: 40px;
display: flex;
justify-content: center;
align-items: center;
}
.dataset-to-dmp {
display: flex;
align-items: center;
padding: 0;
text-align: left;
font-size: 1rem;
font-weight: 700;
color: var(--primary-color);
line-height: 25px;
}
.dmp-info {
padding-top: 0.75rem;
}
.dmp-label {
min-width: 67px;
height: 37px;
background: var(--primary-color) 0% 0% no-repeat padding-box;
color: white;
border-radius: 4px;
opacity: 1;
display: flex;
align-items: center;
justify-content: center;
}
.dmp-title {
text-align: left;
font-weight: 700;
font-family: "Roboto", sans-serif;
font-size: 1rem;
color: #212121;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
line-height: 25px;
}
.open-in-new-icon {
color: #434343;
opacity: 0.75;
}
.open-in-new-icon:hover {
color: var(--primary-color);
}
.dataset-stepper {
position: fixed;
// height: 100%;
display: flex;
flex-direction: column;
height: calc(100vh - 246px);
// max-width: 366px;
}
.stepper-options {
height: calc(100vh - 600px);
overflow-y: auto;
.main-info {
padding-left: .2rem;
color: #21212194;
font-weight: 400;
cursor: pointer;
}
.main-info:hover {
background-color: #ececec;
border-radius: 6px;
}
}
.stepper-back {
margin-top: 3.125rem;
padding-left: 0.5rem;
font-size: 0.875rem;
letter-spacing: 0px;
color: #848484;
opacity: 1;
}
.stepper-title {
text-align: left;
font-weight: 300;
font-size: 20px;
letter-spacing: 0px;
color: #212121;
opacity: 0.6;
margin: 2.875rem 0rem 2.25rem 0rem;
padding-left: 1rem;
}
.stepper-list {
.toc-pane-container {
// padding-left: 0.2rem;
// overflow-x: hidden;
span {
text-align: left;
font-weight: 400;
letter-spacing: 0px;
color: #212121;
padding: 0.3rem 0.1rem;
opacity: 0.6;
cursor: pointer;
max-width: 290px;
}
}
}
.stepper-list span:hover {
background-color: #ececec;
border-radius: 6px;
}
.stepper-list .active {
color: #212121;
font-weight: 700;
opacity: 1;
}
.stepper-list .active-dataset {
color: #212121;
font-weight: 700;
opacity: 1;
.label {
width: 100%;
height: 27px;
line-height: 27px;
background-color: var(--secondary-color);
color: #5d5d5d;
border-radius: 4px;
font-weight: 400;
font-size: 14px;
justify-content: left;
display: flex;
align-items: center;
padding-left: 0.625rem;
padding-right: 0.625rem;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
display: inline-block;
}
}
.back-to-dmp:hover {
background: #ececec;
border-radius: 6px;
}
.back-icon {
display: inline-flex;
vertical-align: middle;
}
.editor-content {
.form {
// position: relative;
// left: 362px;
// width: calc(100% - 366px);
position: relative;
left: 362px;
width: calc(100% - 366px);
overflow-y: auto;
height: calc(100vh - 218px);
}
}
form {
height: calc(100vh - 124px);
margin-top: 6rem;
}
.stepper-actions {
display: flex;
padding-left: 1rem;
margin-top: auto;
margin-bottom: 0.5rem;
// margin-top: 5rem;
// flex-grow: 8;
}
.stepper-btn {
border-radius: 30px;
opacity: 1;
width: 154px;
height: 40px;
display: flex;
justify-content: center;
align-items: center;
font-size: 14px;
}
.previous {
color: #212121;
background: #f5f5f5 0% 0% no-repeat padding-box;
box-shadow: 0px 3px 6px #1e202029;
border: 2px solid #212121;
font-weight: 500;
cursor: pointer;
}
.add-dataset-btn {
background: var(--secondary-color) 0% 0% no-repeat padding-box;
box-shadow: 0px 3px 6px #1e202029;
font-weight: 500;
word-wrap: break-word;
white-space: normal;
line-height: normal;
}
.next {
background: var(--primary-color) 0% 0% no-repeat padding-box;
color: white;
box-shadow: 0px 3px 6px #1e202029;
font-weight: 400;
cursor: pointer;
}
.dataset-next {
background: var(--secondary-color) 0% 0% no-repeat padding-box;
color: #212121;
box-shadow: 0px 3px 6px #1e202029;
font-weight: 700;
cursor: pointer;
}
.previous-disabled {
border: 1px solid #b5b5b5;
color: #b5b5b5 !important;
cursor: auto !important;
}
.next-disabled {
background: #cbcbcb 0% 0% no-repeat padding-box;
box-shadow: 0px 3px 6px #1e202029;
color: white;
cursor: auto !important;
}
}
mat-icon.size-18 {
width: 18px;
height: 18px;
line-height: 18px;
font-size: 18px;
}
.menu-item {
width: 248px;
}
.toc-pane-container {
&.is-sticky ~ .nav-spacer {
height: 500px; // the container size }
// height: calc(100vh - 100px); // the container size }
}
}
.is-sticky {
margin-top: 70px !important;
}
.done-icon {
display: inline-flex;
vertical-align: middle;
font-size: 16px !important;
height: auto;
width: auto;
}
// ::ng-deep .mat-tab-labels {
// justify-content: space-between;
// }
// ::ng-deep .mat-tab-label-content {
// text-transform: uppercase;
// }
// ::ng-deep .mat-ink-bar {
// background-color: var(--primary-color-3) !important;
// // background-color: #0070c0 !important;
// }
// @media (max-width: 768px) {
// .main-content {
// padding: 30px 0px;
// }
// ::ng-deep .mat-expansion-panel-header {
// min-height: 48px;
// height: auto !important;
// }
// ::ng-deep .mat-expansion-panel-body {
// padding: 0 0px 16px !important;
// }
// ::ng-deep .mat-vertical-content {
// padding: 0 14px 24px 14px !important;
// }
// }

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,489 @@
<form *ngIf="formGroup" [formGroup]="formGroup" class="dataset-external-references-editor">
<!-- Tags -->
<div class="pt-2">
<div class="row">
<div class="col-12 pl-0 pr-0 pb-2 d-flex flex-row">
<h4 class="col-auto heading">1.3 {{'DATASET-EDITOR.FIELDS.TAGS' | translate}}</h4>
</div>
</div>
<div class="tags-form">
<mat-form-field appearance="outline">
<app-multiple-auto-complete [configuration]="tagsAutoCompleteConfiguration" [formControl]="formGroup.get('tags')" placeholder="{{'DATASET-EDITOR.FIELDS.TAGS' | translate}}" [separatorKeysCodes]="separatorKeysCodes"></app-multiple-auto-complete>
</mat-form-field>
</div>
</div>
<!-- Data Repositories -->
<!-- <div class="pt-2">
<div class="row">
<div class="col-12 pl-0 pr-0 pb-2 d-flex flex-row">
<h4 class="col-auto heading">1.5 {{'DATASET-EDITOR.FIELDS.DATAREPOSITORIES' | translate}}</h4>
<div class="col"></div>
<div class="col-auto d-flex align-items-center" *ngIf='!viewOnly'>
<button class="col-auto" mat-raised-button (click)="addDataRepository()">
{{'DATASET-EDITOR.FIELDS.CREATE'|translate}}
</button>
</div>
</div>
</div>
<app-external-item-listing class="col-12" *ngIf="formGroup.get('dataRepositories') && dataRepositoriesTemplate && externalSourcesConfiguration" [options]="externalSourcesConfiguration.dataRepositories" placeholder="{{'DATASET-EDITOR.FIELDS.DATAREPOSITORIES' | translate}}" [parentTemplate]='dataRepositoriesTemplate' [formArray]="formGroup.get('dataRepositories')" [autoCompleteConfiguration]="dataRepositoriesAutoCompleteConfiguration" (onItemChange)="dataRepositoriesOnItemChange($event)">
</app-external-item-listing>
<ng-template #dataRepositoriesTemplate let-suggestion let-i="index" let-callback="function">
<div class="col-12 row align-items-center">
<span class="col">
{{i+1}}) {{suggestion.get('name').value}}
</span>
<div class="col-auto" *ngIf="isInternal(suggestion)">
<mat-form-field>
<input matInput placeholder="{{'DATASET-REFERENCED-MODELS.DATA-REPOSITORY.LABEL' | translate}}" type="text" name="name" [formControl]="suggestion.get('name')">
</mat-form-field>
</div>
<div class="col-auto" *ngIf="isInternal(suggestion)">
<mat-form-field>
<input matInput placeholder="{{'DATASET-REFERENCED-MODELS.DATA-REPOSITORY.ABBREVIATION' | translate}}" type="text" name="abbreviation" [formControl]="suggestion.get('abbreviation')">
</mat-form-field>
</div>
<div class="col-auto" *ngIf="isInternal(suggestion)">
<mat-form-field>
<input matInput placeholder="{{'DATASET-REFERENCED-MODELS.DATA-REPOSITORY.URI' | translate}}" type="text" name="uri" [formControl]="suggestion.get('uri')">
</mat-form-field>
</div>
<div class="col-auto">
<mat-form-field>
<input matInput placeholder="{{'DATASET-EDITOR.FIELDS.DATAREPOSITORIES-INFO' | translate}}" type="text" name="info" [formControl]="suggestion.get('info')">
</mat-form-field>
</div>
<div class="col-auto" *ngIf='!viewOnly && isInternal(suggestion)'>
<button mat-raised-button (click)="updateDataRepository(suggestion)" type="button">
{{ 'DATASET-EDITOR.ACTIONS.UPDATE' | translate }}
</button>
</div>
<div class="col-auto" *ngIf='!viewOnly'>
<button mat-icon-button (click)="callback(i)">
<mat-icon>close</mat-icon>
</button>
</div>
</div>
</ng-template>
</div> -->
<!-- External Datasets -->
<!-- <div class="pt-2">
<div class="row">
<div class="col-12 pl-0 pr-0 pb-2 d-flex flex-row">
<h4 class="col-auto heading">1.6 {{'DATASET-EDITOR.FIELDS.EXTERNAL-DATASETS' | translate}}</h4>
<div class="col"></div>
<div class="col-auto d-flex align-items-center" *ngIf='!viewOnly'><button mat-raised-button (click)="addExternalDataset()">
{{'DATASET-EDITOR.FIELDS.CREATE'|translate}}
</button>
</div>
</div>
<div class="col-12">
<span class="hint">{{'DATASET-EDITOR.FIELDS.EXTERNAL-DATASETS-DESCRIPTION' | translate}}</span>
</div>
</div>
<app-external-item-listing class="col-12" *ngIf="formGroup.get('externalDatasets') && externalDatasetsTemplate && externalSourcesConfiguration" [options]="externalSourcesConfiguration.externalDatasets" placeholder="{{'DATASET-EDITOR.FIELDS.EXTERNAL-DATASETS' | translate}}" [parentTemplate]='externalDatasetsTemplate' [formArray]="formGroup.get('externalDatasets')" [autoCompleteConfiguration]="externalDatasetAutoCompleteConfiguration" (onItemChange)="externalDatasetsOnItemChange($event)">
</app-external-item-listing>
<ng-template #externalDatasetsTemplate let-suggestion let-i="index" let-callback="function">
<div class="col-12 row align-items-center">
<div class="col">
<p>
{{i+1}}) {{suggestion.get('name').value}}
</p>
</div>
<div class="col-auto" *ngIf="isInternal(suggestion)">
<mat-form-field>
<input matInput placeholder="{{'DATASET-REFERENCED-MODELS.EXTERNAL-DATASET.LABEL' | translate}}" type="text" name="name" [formControl]="suggestion.get('name')">
</mat-form-field>
</div>
<div class="col-auto" *ngIf="isInternal(suggestion)">
<mat-form-field>
<input matInput placeholder="{{'DATASET-REFERENCED-MODELS.EXTERNAL-DATASET.ABBREVIATION' | translate}}" type="text" name="abbreviation" [formControl]="suggestion.get('abbreviation')">
</mat-form-field>
</div>
<div class="col-auto">
<mat-form-field>
<input matInput placeholder="{{'DATASET-EDITOR.FIELDS.EXTERNAL-DATASET-INFO' | translate}}" type="text" name="info" [formControl]="suggestion.get('info')">
</mat-form-field>
</div>
<div class="col-auto">
<mat-form-field>
<mat-select placeholder="{{'DATASET-WIZARD.EDITOR.FIELDS.EXTERNAL-DATASET-TYPE' | translate}}" [formControl]="suggestion.get('type')" required>
<mat-option [value]="0">{{'TYPES.EXTERNAL-DATASET-TYPE.SOURCE' | translate}}</mat-option>
<mat-option [value]="1">{{'TYPES.EXTERNAL-DATASET-TYPE.OUTPUT' | translate}}</mat-option>
</mat-select>
<mat-error *ngIf="suggestion.get('type').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
<div class="col-auto" *ngIf='!viewOnly && isInternal(suggestion)'>
<button mat-raised-button (click)="updateExternalDataset(suggestion)" type="button">
{{ 'DATASET-EDITOR.ACTIONS.UPDATE' | translate }}
</button>
</div>
<div class="col-auto">
<button mat-icon-button (click)="callback(i)" *ngIf='!viewOnly'>
<mat-icon>close</mat-icon>
</button>
</div>
</div>
</ng-template>
</div> -->
<!-- Registries -->
<!-- <div class="pt-2">
<div class="row">
<div class="col-12 pl-0 pr-0 pb-2 d-flex flex-row">
<h4 class="col-auto heading">1.7 {{'DATASET-EDITOR.FIELDS.REGISTRIES' | translate}}</h4>
<div class="col"></div>
<div class="col-auto d-flex align-items-center" *ngIf='!viewOnly'><button mat-raised-button (click)="addRegistry()">
{{'DATASET-EDITOR.FIELDS.CREATE'|translate}}
</button>
</div>
</div>
</div>
<app-external-item-listing class="col-12" *ngIf="formGroup.get('registries') && registriesTemplate && externalSourcesConfiguration" [options]="externalSourcesConfiguration.registries" placeholder="{{'DATASET-EDITOR.FIELDS.REGISTRIES' | translate}}" [parentTemplate]='registriesTemplate' [formArray]="formGroup.get('registries')" [autoCompleteConfiguration]="registriesAutoCompleteConfiguration" (onItemChange)="registriesOnItemChange($event)">
</app-external-item-listing>
<ng-template #registriesTemplate let-suggestion let-i="index" let-callback="function">
<div class="col-12 row align-items-center">
<div class="col">
<p>
{{i+1}}) {{suggestion.get('label').value}}
</p>
</div>
<div class="col-auto" *ngIf="isInternal(suggestion)">
<mat-form-field>
<input matInput placeholder="{{'DATASET-REFERENCED-MODELS.REGISTRY.LABEL' | translate}}" type="text" name="label" [formControl]="suggestion.get('label')">
</mat-form-field>
</div>
<div class="col-auto" *ngIf="isInternal(suggestion)">
<mat-form-field>
<input matInput placeholder="{{'DATASET-REFERENCED-MODELS.REGISTRY.ABBREVIATION' | translate}}" type="text" name="abbreviation" [formControl]="suggestion.get('abbreviation')">
</mat-form-field>
</div>
<div class="col-auto" *ngIf="isInternal(suggestion)">
<mat-form-field>
<input matInput placeholder="{{'DATASET-REFERENCED-MODELS.REGISTRY.URI' | translate}}" type="text" name="uri" [formControl]="suggestion.get('uri')">
</mat-form-field>
</div>
<div class="col-auto" *ngIf='!viewOnly && isInternal(suggestion)'>
<button mat-raised-button (click)="updateRegistry(suggestion)" type="button">
{{ 'DATASET-EDITOR.ACTIONS.UPDATE' | translate }}
</button>
</div>
<div class="col-auto">
<button mat-icon-button (click)="callback(i)" *ngIf='!viewOnly'>
<mat-icon>close</mat-icon>
</button>
</div>
</div>
</ng-template>
</div> -->
<!-- Services -->
<!-- <div class="pt-2">
<div class="row">
<div class="col-12 pl-0 pr-0 pb-2 d-flex flex-row">
<h4 class="col-auto heading">1.8 {{'DATASET-EDITOR.FIELDS.SERVICES' | translate}}</h4>
<div class="col"></div>
<div class="col-auto d-flex align-items-center" *ngIf='!viewOnly'>
<button mat-raised-button (click)="addService()">
{{'DATASET-EDITOR.FIELDS.CREATE'|translate}}
</button>
</div>
</div>
</div>
<app-external-item-listing class="col-12" *ngIf="formGroup.get('services') && servicesTemplate && externalSourcesConfiguration" [options]="externalSourcesConfiguration.services" placeholder="{{'DATASET-EDITOR.FIELDS.SERVICES' | translate}}" [parentTemplate]='servicesTemplate' [formArray]="formGroup.get('services')" [autoCompleteConfiguration]="servicesAutoCompleteConfiguration" (onItemChange)="servicesOnItemChange($event)">
</app-external-item-listing>
<ng-template #servicesTemplate let-suggestion let-i="index" let-callback="function">
<div class="col-12 row align-items-center">
<div class="col">
<p>
{{i+1}}) {{suggestion.get('label').value}}
</p>
</div>
<div class="col-auto" *ngIf="isInternal(suggestion)">
<mat-form-field>
<input matInput placeholder="{{'DATASET-REFERENCED-MODELS.SERVICES.LABEL' | translate}}" type="text" name="label" [formControl]="suggestion.get('label')">
</mat-form-field>
</div>
<div class="col-auto" *ngIf="isInternal(suggestion)">
<mat-form-field>
<input matInput placeholder="{{'DATASET-REFERENCED-MODELS.SERVICES.ABBREVIATION' | translate}}" type="text" name="abbreviation" [formControl]="suggestion.get('abbreviation')">
</mat-form-field>
</div>
<div class="col-auto" *ngIf="isInternal(suggestion)">
<mat-form-field>
<input matInput placeholder="{{'DATASET-REFERENCED-MODELS.SERVICES.URI' | translate}}" type="text" name="uri" [formControl]="suggestion.get('uri')">
</mat-form-field>
</div>
<div class="col-auto" *ngIf='!viewOnly && isInternal(suggestion)'>
<button mat-raised-button (click)="updateRegistry(suggestion)" type="button">
{{ 'DATASET-EDITOR.ACTIONS.UPDATE' | translate }}
</button>
</div>
<div class="col-auto">
<button mat-icon-button (click)="callback(i)" *ngIf='!viewOnly'>
<mat-icon>close</mat-icon>
</button>
</div>
</div>
</ng-template>
</div> -->
</form>
<!-- <form *ngIf="formGroup" [formGroup]="formGroup" class="dataset-external-references-editor">
<mat-card class="col-12 external-item-card">
<div class="row">
<div class="col-12 row">
<h4 class="col-auto">{{'DATASET-EDITOR.FIELDS.DATAREPOSITORIES' | translate}}</h4>
<div class="col"></div>
<div class="col-auto" *ngIf='!viewOnly'>
<button class="col-auto" mat-raised-button color="primary" (click)="addDataRepository()">
{{'DATASET-EDITOR.FIELDS.CREATE'|translate}}
</button>
</div>
</div>
</div>
<app-external-item-listing class="col-12" *ngIf="formGroup.get('dataRepositories') && dataRepositoriesTemplate && externalSourcesConfiguration" [options]="externalSourcesConfiguration.dataRepositories" placeholder="{{'DATASET-EDITOR.FIELDS.DATAREPOSITORIES' | translate}}" [parentTemplate]='dataRepositoriesTemplate' [formArray]="formGroup.get('dataRepositories')" [autoCompleteConfiguration]="dataRepositoriesAutoCompleteConfiguration" (onItemChange)="dataRepositoriesOnItemChange($event)">
</app-external-item-listing>
<ng-template #dataRepositoriesTemplate let-suggestion let-i="index" let-callback="function">
<div class="col-12 row align-items-center">
<span class="col">
{{i+1}}) {{suggestion.get('name').value}}
</span>
<div class="col-auto" *ngIf="isInternal(suggestion)">
<mat-form-field>
<input matInput placeholder="{{'DATASET-REFERENCED-MODELS.DATA-REPOSITORY.LABEL' | translate}}" type="text" name="name" [formControl]="suggestion.get('name')">
</mat-form-field>
</div>
<div class="col-auto" *ngIf="isInternal(suggestion)">
<mat-form-field>
<input matInput placeholder="{{'DATASET-REFERENCED-MODELS.DATA-REPOSITORY.ABBREVIATION' | translate}}" type="text" name="abbreviation" [formControl]="suggestion.get('abbreviation')">
</mat-form-field>
</div>
<div class="col-auto" *ngIf="isInternal(suggestion)">
<mat-form-field>
<input matInput placeholder="{{'DATASET-REFERENCED-MODELS.DATA-REPOSITORY.URI' | translate}}" type="text" name="uri" [formControl]="suggestion.get('uri')">
</mat-form-field>
</div>
<div class="col-auto">
<mat-form-field>
<input matInput placeholder="{{'DATASET-EDITOR.FIELDS.DATAREPOSITORIES-INFO' | translate}}" type="text" name="info" [formControl]="suggestion.get('info')">
</mat-form-field>
</div>
<div class="col-auto" *ngIf='!viewOnly && isInternal(suggestion)'>
<button mat-raised-button (click)="updateDataRepository(suggestion)" type="button" color="primary">
{{ 'DATASET-EDITOR.ACTIONS.UPDATE' | translate }}
</button>
</div>
<div class="col-auto" *ngIf='!viewOnly'>
<button mat-icon-button (click)="callback(i)">
<mat-icon>close</mat-icon>
</button>
</div>
</div>
</ng-template>
</mat-card>
<mat-card class="col-12 external-item-card">
<div class="row">
<div class="col-12 row">
<h4 class="col-auto">{{'DATASET-EDITOR.FIELDS.EXTERNAL-DATASETS' | translate}}</h4>
<div class="col"></div>
<div class="col-auto" *ngIf='!viewOnly'><button mat-raised-button color="primary" (click)="addExternalDataset()">
{{'DATASET-EDITOR.FIELDS.CREATE'|translate}}
</button>
</div>
</div>
<div class="col-12">
<span>{{'DATASET-EDITOR.FIELDS.EXTERNAL-DATASETS-DESCRIPTION' | translate}}</span>
</div>
</div>
<app-external-item-listing class="col-12" *ngIf="formGroup.get('externalDatasets') && externalDatasetsTemplate && externalSourcesConfiguration" [options]="externalSourcesConfiguration.externalDatasets" placeholder="{{'DATASET-EDITOR.FIELDS.EXTERNAL-DATASETS' | translate}}" [parentTemplate]='externalDatasetsTemplate' [formArray]="formGroup.get('externalDatasets')" [autoCompleteConfiguration]="externalDatasetAutoCompleteConfiguration" (onItemChange)="externalDatasetsOnItemChange($event)">
</app-external-item-listing>
<ng-template #externalDatasetsTemplate let-suggestion let-i="index" let-callback="function">
<div class="col-12 row align-items-center">
<div class="col">
<p>
{{i+1}}) {{suggestion.get('name').value}}
</p>
</div>
<div class="col-auto" *ngIf="isInternal(suggestion)">
<mat-form-field>
<input matInput placeholder="{{'DATASET-REFERENCED-MODELS.EXTERNAL-DATASET.LABEL' | translate}}" type="text" name="name" [formControl]="suggestion.get('name')">
</mat-form-field>
</div>
<div class="col-auto" *ngIf="isInternal(suggestion)">
<mat-form-field>
<input matInput placeholder="{{'DATASET-REFERENCED-MODELS.EXTERNAL-DATASET.ABBREVIATION' | translate}}" type="text" name="abbreviation" [formControl]="suggestion.get('abbreviation')">
</mat-form-field>
</div>
<div class="col-auto">
<mat-form-field>
<input matInput placeholder="{{'DATASET-EDITOR.FIELDS.EXTERNAL-DATASET-INFO' | translate}}" type="text" name="info" [formControl]="suggestion.get('info')">
</mat-form-field>
</div>
<div class="col-auto">
<mat-form-field>
<mat-select placeholder="{{'DATASET-WIZARD.EDITOR.FIELDS.EXTERNAL-DATASET-TYPE' | translate}}" [formControl]="suggestion.get('type')" required>
<mat-option [value]="0">{{'TYPES.EXTERNAL-DATASET-TYPE.SOURCE' | translate}}</mat-option>
<mat-option [value]="1">{{'TYPES.EXTERNAL-DATASET-TYPE.OUTPUT' | translate}}</mat-option>
</mat-select>
<mat-error *ngIf="suggestion.get('type').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
<div class="col-auto" *ngIf='!viewOnly && isInternal(suggestion)'>
<button mat-raised-button (click)="updateExternalDataset(suggestion)" type="button" color="primary">
{{ 'DATASET-EDITOR.ACTIONS.UPDATE' | translate }}
</button>
</div>
<div class="col-auto">
<button mat-icon-button (click)="callback(i)" *ngIf='!viewOnly'>
<mat-icon>close</mat-icon>
</button>
</div>
</div>
</ng-template>
</mat-card>
<mat-card class="col-12 external-item-card">
<div class="row">
<div class="col-12 row">
<h4 class="col-auto">{{'DATASET-EDITOR.FIELDS.REGISTRIES' | translate}}</h4>
<div class="col"></div>
<div class="col-auto" *ngIf='!viewOnly'><button mat-raised-button color="primary" (click)="addRegistry()">
{{'DATASET-EDITOR.FIELDS.CREATE'|translate}}
</button>
</div>
</div>
</div>
<app-external-item-listing class="col-12" *ngIf="formGroup.get('registries') && registriesTemplate && externalSourcesConfiguration" [options]="externalSourcesConfiguration.registries" placeholder="{{'DATASET-EDITOR.FIELDS.REGISTRIES' | translate}}" [parentTemplate]='registriesTemplate' [formArray]="formGroup.get('registries')" [autoCompleteConfiguration]="registriesAutoCompleteConfiguration" (onItemChange)="registriesOnItemChange($event)">
</app-external-item-listing>
<ng-template #registriesTemplate let-suggestion let-i="index" let-callback="function">
<div class="col-12 row align-items-center">
<div class="col">
<p>
{{i+1}}) {{suggestion.get('label').value}}
</p>
</div>
<div class="col-auto" *ngIf="isInternal(suggestion)">
<mat-form-field>
<input matInput placeholder="{{'DATASET-REFERENCED-MODELS.REGISTRY.LABEL' | translate}}" type="text" name="label" [formControl]="suggestion.get('label')">
</mat-form-field>
</div>
<div class="col-auto" *ngIf="isInternal(suggestion)">
<mat-form-field>
<input matInput placeholder="{{'DATASET-REFERENCED-MODELS.REGISTRY.ABBREVIATION' | translate}}" type="text" name="abbreviation" [formControl]="suggestion.get('abbreviation')">
</mat-form-field>
</div>
<div class="col-auto" *ngIf="isInternal(suggestion)">
<mat-form-field>
<input matInput placeholder="{{'DATASET-REFERENCED-MODELS.REGISTRY.URI' | translate}}" type="text" name="uri" [formControl]="suggestion.get('uri')">
</mat-form-field>
</div>
<div class="col-auto" *ngIf='!viewOnly && isInternal(suggestion)'>
<button mat-raised-button (click)="updateRegistry(suggestion)" type="button" color="primary">
{{ 'DATASET-EDITOR.ACTIONS.UPDATE' | translate }}
</button>
</div>
<div class="col-auto">
<button mat-icon-button (click)="callback(i)" *ngIf='!viewOnly'>
<mat-icon>close</mat-icon>
</button>
</div>
</div>
</ng-template>
</mat-card>
<mat-card class="col-12 external-item-card">
<div class="row">
<div class="col-12 row">
<h4 class="col-auto">{{'DATASET-EDITOR.FIELDS.SERVICES' | translate}}</h4>
<div class="col"></div>
<div class="col-auto" *ngIf='!viewOnly'>
<button mat-raised-button color="primary" (click)="addService()">
{{'DATASET-EDITOR.FIELDS.CREATE'|translate}}
</button>
</div>
</div>
</div>
<app-external-item-listing class="col-12" *ngIf="formGroup.get('services') && servicesTemplate && externalSourcesConfiguration" [options]="externalSourcesConfiguration.services" placeholder="{{'DATASET-EDITOR.FIELDS.SERVICES' | translate}}" [parentTemplate]='servicesTemplate' [formArray]="formGroup.get('services')" [autoCompleteConfiguration]="servicesAutoCompleteConfiguration" (onItemChange)="servicesOnItemChange($event)">
</app-external-item-listing>
<ng-template #servicesTemplate let-suggestion let-i="index" let-callback="function">
<div class="col-12 row align-items-center">
<div class="col">
<p>
{{i+1}}) {{suggestion.get('label').value}}
</p>
</div>
<div class="col-auto" *ngIf="isInternal(suggestion)">
<mat-form-field>
<input matInput placeholder="{{'DATASET-REFERENCED-MODELS.SERVICES.LABEL' | translate}}" type="text" name="label" [formControl]="suggestion.get('label')">
</mat-form-field>
</div>
<div class="col-auto" *ngIf="isInternal(suggestion)">
<mat-form-field>
<input matInput placeholder="{{'DATASET-REFERENCED-MODELS.SERVICES.ABBREVIATION' | translate}}" type="text" name="abbreviation" [formControl]="suggestion.get('abbreviation')">
</mat-form-field>
</div>
<div class="col-auto" *ngIf="isInternal(suggestion)">
<mat-form-field>
<input matInput placeholder="{{'DATASET-REFERENCED-MODELS.SERVICES.URI' | translate}}" type="text" name="uri" [formControl]="suggestion.get('uri')">
</mat-form-field>
</div>
<div class="col-auto" *ngIf='!viewOnly && isInternal(suggestion)'>
<button mat-raised-button (click)="updateRegistry(suggestion)" type="button" color="primary">
{{ 'DATASET-EDITOR.ACTIONS.UPDATE' | translate }}
</button>
</div>
<div class="col-auto">
<button mat-icon-button (click)="callback(i)" *ngIf='!viewOnly'>
<mat-icon>close</mat-icon>
</button>
</div>
</div>
</ng-template>
</mat-card>
<mat-card class="col-12 external-item-card">
<div class="row">
<div class="col-12 row">
<h4 class="col-auto">{{'DATASET-EDITOR.FIELDS.TAGS' | translate}}</h4>
</div>
</div> -->
<!-- <app-external-item-listing *ngIf="formGroup.get('tags') && tagsTemplate && externalSourcesConfiguration" [options]="externalSourcesConfiguration.tags" placeholder="{{'DATASET-EDITOR.FIELDS.TAGS' | translate}}" [parentTemplate]='tagsTemplate' [formArray]="formGroup.get('tags')" [autoCompleteConfiguration]="tagsAutoCompleteConfiguration" (onItemChange)="tagsOnItemChange($event)">
</app-external-item-listing> -->
<!-- <mat-form-field>
<mat-chip-list #chipList [disabled]="viewOnly">
<mat-chip *ngFor="let tag of formGroup.get('tags').value"
[removable]="true" (removed)="removeTag(tag)">
{{tag.name}}
<mat-icon matChipRemove *ngIf="!viewOnly">cancel</mat-icon>
</mat-chip>
<input matInput [disabled]="viewOnly" placeholder="{{'DATASET-EDITOR.FIELDS.TAGS' | translate}}"
[matChipInputFor]="chipList"
[matChipInputSeparatorKeyCodes]="separatorKeysCodes"
[matChipInputAddOnBlur]="true"
(matChipInputTokenEnd)="addTag($event)">
</mat-chip-list>
</mat-form-field>
<ng-template #tagsTemplate let-suggestion let-i="index" let-callback="function">
<div class="col-12 row align-items-center">
<div class="col">
<p>
{{i+1}}) {{suggestion.get('name').value}}
</p>
</div>
<div class="col-auto">
<button mat-icon-button (click)="callback(i)" *ngIf='!viewOnly'>
<mat-icon>close</mat-icon>
</button>
</div>
</div>
</ng-template>
</mat-card>
</form> -->

View File

@ -0,0 +1,35 @@
.dataset-external-references-editor {
.heading {
text-align: left;
font-weight: 700;
font-size: 18px;
letter-spacing: 0px;
color: #212121;
opacity: 0.81;
margin-top: 1.625rem;
margin-bottom: 0.625rem;
}
.hint {
text-align: left;
font-weight: 400;
font-size: 16px;
letter-spacing: 0px;
color: #212121;
opacity: 0.81;
margin-bottom: 2.125rem;
}
.external-item-card {
margin-bottom: 1em;
}
}
::ng-deep .tags-form .mat-form-field-appearance-outline .mat-form-field-outline {
background: #fafafa !important;
}
::ng-deep .tags-form .mat-form-field-appearance-outline .mat-form-field-infix {
font-size: 1rem;
padding: 0.6em 0 1em 0 !important;
}

View File

@ -0,0 +1,341 @@
import { Component, Input, OnInit, Output, EventEmitter } from '@angular/core';
import { UntypedFormArray, UntypedFormGroup } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { Router } from '@angular/router';
import { ExternalSourceItemModel } from '@app/core/model/external-sources/external-source-item';
import { ExternalSourcesConfiguration } from '@app/core/model/external-sources/external-sources-configuration';
import { DataRepositoryCriteria } from '@app/core/query/data-repository/data-repository-criteria';
import { ExternalDatasetCriteria } from '@app/core/query/external-dataset/external-dataset-criteria';
import { RegistryCriteria } from '@app/core/query/registry/registry-criteria';
import { RequestItem } from '@app/core/query/request-item';
import { ServiceCriteria } from '@app/core/query/service/service-criteria';
import { TagCriteria } from '@app/core/query/tag/tag-criteria';
import { ExternalSourcesConfigurationService } from '@app/core/services/external-sources/external-sources-configuration.service';
import { ExternalSourcesService } from '@app/core/services/external-sources/external-sources.service';
import { SingleAutoCompleteConfiguration } from '@app/library/auto-complete/single/single-auto-complete-configuration';
import { ExternalDataRepositoryEditorModel, ExternalDatasetEditorModel, ExternalRegistryEditorModel, ExternalServiceEditorModel, ExternalTagEditorModel } from '@app/ui/dataset/dataset-wizard/dataset-wizard-editor.model';
import { DatasetExternalDataRepositoryDialogEditorComponent } from '@app/ui/dataset/dataset-wizard/external-references/editors/data-repository/dataset-external-data-repository-dialog-editor.component';
import { DatasetExternalDatasetDialogEditorComponent } from '@app/ui/dataset/dataset-wizard/external-references/editors/external-dataset/dataset-external-dataset-dialog-editor.component';
import { DatasetExternalRegistryDialogEditorComponent } from '@app/ui/dataset/dataset-wizard/external-references/editors/registry/dataset-external-registry-dialog-editor.component';
import { DatasetExternalServiceDialogEditorComponent } from '@app/ui/dataset/dataset-wizard/external-references/editors/service/dataset-external-service-dialog-editor.component';
import { BaseComponent } from '@common/base/base.component';
import { TranslateService } from '@ngx-translate/core';
import { Observable } from 'rxjs';
import { takeUntil, map } from 'rxjs/operators';
import { ENTER, COMMA } from '@angular/cdk/keycodes';
import { MatChipInputEvent } from '@angular/material/chips';
import { isNullOrUndefined } from '@app/utilities/enhancers/utils';
import { ExternalDataRepositoryService } from '@app/core/services/external-sources/data-repository/extternal-data-repository.service';
import { ExternalDatasetService } from '@app/core/services/external-sources/dataset/external-dataset.service';
import { ExternalRegistryService } from '@app/core/services/external-sources/registry/external-registry.service';
import { ExternalServiceService } from '@app/core/services/external-sources/service/external-service.service';
import { MultipleAutoCompleteConfiguration } from '@app/library/auto-complete/multiple/multiple-auto-complete-configuration';
@Component({
selector: 'app-dataset-external-references-editor-component',
templateUrl: 'dataset-external-references-editor.component.html',
styleUrls: ['./dataset-external-references-editor.component.scss']
})
export class DatasetExternalReferencesEditorComponent extends BaseComponent implements OnInit {
@Input() formGroup: UntypedFormGroup = null;
@Input() viewOnly = false;
@Output() formChanged: EventEmitter<any> = new EventEmitter();
public filteringTagsAsync = false;
public filteredTags: ExternalSourceItemModel[];
readonly separatorKeysCodes: number[] = [ENTER, COMMA];
externalDatasetAutoCompleteConfiguration: SingleAutoCompleteConfiguration = {
filterFn: this.searchDatasetExternalDatasets.bind(this),
initialItems: (type) => this.searchDatasetExternalDatasets('', type),//.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1),
displayFn: (item) => item ? item.name : null,
titleFn: (item) => item ? item.name : null,
subtitleFn: (item) => item.source ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.source : item.tag ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.tag : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE')
};
registriesAutoCompleteConfiguration: SingleAutoCompleteConfiguration = {
filterFn: this.searchDatasetExternalRegistries.bind(this),
initialItems: (type) => this.searchDatasetExternalRegistries('', type),
displayFn: (item) => item ? item.name : null,
titleFn: (item) => item ? item.name : null,
subtitleFn: (item) => item.source ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.source : item.tag ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.tag : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE')
};
dataRepositoriesAutoCompleteConfiguration: SingleAutoCompleteConfiguration = {
filterFn: this.searchDatasetExternalDataRepositories.bind(this),
initialItems: (type) => this.searchDatasetExternalDataRepositories('', type),
displayFn: (item) => item ? item.name : null,
titleFn: (item) => item ? item.name : null,
subtitleFn: (item) => item.source ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.source : item.tag ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.tag : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE')
};
servicesAutoCompleteConfiguration: SingleAutoCompleteConfiguration = {
filterFn: this.searchDatasetExternalServices.bind(this),
initialItems: (type) => this.searchDatasetExternalServices('', type),
displayFn: (item) => item ? item.label : null,
titleFn: (item) => item ? item.label : null,
subtitleFn: (item) => item.source ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.source : item.tag ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.tag : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE')
};
tagsAutoCompleteConfiguration: MultipleAutoCompleteConfiguration = {
filterFn: this.filterTags.bind(this),
initialItems: (excludedItems: any[]) => this.filterTags('').pipe(map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))),
displayFn: (item) => this.showTag(item),
titleFn: (item) => item['name'],
valueAssign: (item) => this.addTag(item)
};
externalSourcesConfiguration: ExternalSourcesConfiguration;
// new AutoCompleteConfiguration(this.externalSourcesService.searchDatasetRepository.bind(this.externalSourcesService),
constructor(
private dialog: MatDialog,
private router: Router,
private language: TranslateService,
private externalSourcesService: ExternalSourcesService,
private externalSourcesConfigurationService: ExternalSourcesConfigurationService,
private externalDataRepositoryService: ExternalDataRepositoryService,
private externalDatasetService: ExternalDatasetService,
private externalRegistryService: ExternalRegistryService,
private externalServiceService: ExternalServiceService,
) { super(); }
ngOnInit() {
this.externalSourcesConfigurationService.getExternalSourcesConfiguration()
.pipe(takeUntil(this._destroyed))
.subscribe(result => {
this.externalSourcesConfiguration = result;
this.externalSourcesConfiguration.dataRepositories.push({ key: '', label: 'All' });
this.externalSourcesConfiguration.externalDatasets.push({ key: '', label: 'All' });
this.externalSourcesConfiguration.registries.push({ key: '', label: 'All' });
this.externalSourcesConfiguration.services.push({ key: '', label: 'All' });
if (!isNullOrUndefined(this.externalSourcesConfiguration.tags)) {
this.externalSourcesConfiguration.tags.push({ key: '', label: 'All' });
} else {
this.externalSourcesConfiguration.tags = [{ key: '', label: 'All' }];
}
});
this.formGroup.valueChanges
.pipe(takeUntil(this._destroyed))
.subscribe(val => {
this.formChanged.emit(val);
});
}
public cancel(): void {
this.router.navigate(['/datasets']);
}
externalDatasetsOnItemChange(event) {
const externalDatasetModel = new ExternalDatasetEditorModel(event.id, event.abbreviation, event.name, event.pid ? event.pid : event.reference, event.source);
(<UntypedFormArray>this.formGroup.get('externalDatasets')).push(externalDatasetModel.buildForm());
}
registriesOnItemChange(event) {
const registryModel = new ExternalRegistryEditorModel(event.abbreviation, event.definition, event.id, event.name, event.pid ? event.pid : event.reference, event.uri, event.source);
(<UntypedFormArray>this.formGroup.get('registries')).push(registryModel.buildForm());
}
servicesOnItemChange(event) {
const serviceModel = new ExternalServiceEditorModel(event.abbreviation, event.definition, event.id, event.label, event.reference, event.uri);
(<UntypedFormArray>this.formGroup.get('services')).push(serviceModel.buildForm());
}
tagsOnItemChange(event) {
const tagModel = new ExternalTagEditorModel(event.id, event.name);
(<UntypedFormArray>this.formGroup.get('tags')).push(tagModel.buildForm());
}
dataRepositoriesOnItemChange(event) {
const dataRepositoryModel = new ExternalDataRepositoryEditorModel(event.id, event.name, event.abbreviation, event.uri, event.pid, event.source);
(<UntypedFormArray>this.formGroup.get('dataRepositories')).push(dataRepositoryModel.buildForm());
}
addDataRepository() {
const dialogRef = this.dialog.open(DatasetExternalDataRepositoryDialogEditorComponent, {
width: '500px',
restoreFocus: false,
data: {}
});
dialogRef.afterClosed()
.pipe(takeUntil(this._destroyed))
.subscribe(result => {
if (!result) { return; }
const dataRepositoryModel = new ExternalDataRepositoryEditorModel(result.id, result.name, result.abbreviation, result.uri, result.pid, result.source);
(<UntypedFormArray>this.formGroup.get('dataRepositories')).push(dataRepositoryModel.buildForm());
});
}
addRegistry() {
const dialogRef = this.dialog.open(DatasetExternalRegistryDialogEditorComponent, {
width: '500px',
restoreFocus: false,
data: {}
});
dialogRef.afterClosed()
.pipe(takeUntil(this._destroyed))
.subscribe(result => {
if (!result) { return; }
const registryModel = new ExternalRegistryEditorModel(result.abbreviation, result.definition, result.id, result.label, result.reference, result.uri, result.source);
(<UntypedFormArray>this.formGroup.get('registries')).push(registryModel.buildForm());
});
}
addExternalDataset() {
const dialogRef = this.dialog.open(DatasetExternalDatasetDialogEditorComponent, {
width: '500px',
restoreFocus: false,
data: {}
});
dialogRef.afterClosed()
.pipe(takeUntil(this._destroyed))
.subscribe(result => {
if (!result) { return; }
const externalDatasetModel = new ExternalDatasetEditorModel(result.id, result.abbreviation, result.name, result.reference, result.source);
(<UntypedFormArray>this.formGroup.get('externalDatasets')).push(externalDatasetModel.buildForm());
});
}
addService() {
const dialogRef = this.dialog.open(DatasetExternalServiceDialogEditorComponent, {
width: '500px',
restoreFocus: false,
data: {}
});
dialogRef.afterClosed()
.pipe(takeUntil(this._destroyed))
.subscribe(result => {
if (!result) { return; }
const serviceModel = new ExternalServiceEditorModel(result.abbreviation, result.definition, result.id, result.label, result.reference, result.uri, result.source);
(<UntypedFormArray>this.formGroup.get('services')).push(serviceModel.buildForm());
});
}
searchDatasetExternalDatasets(query: string, type: string): Observable<ExternalSourceItemModel[]> {
const requestItem: RequestItem<ExternalDatasetCriteria> = new RequestItem();
requestItem.criteria = new ExternalDatasetCriteria();
requestItem.criteria.like = query;
requestItem.criteria.type = type;
return this.externalSourcesService.searchDatasetSExternalDatasetservice(requestItem);
}
searchDatasetExternalDataRepositories(query: string, type: string): Observable<ExternalSourceItemModel[]> {
const requestItem: RequestItem<DataRepositoryCriteria> = new RequestItem();
requestItem.criteria = new DataRepositoryCriteria();
requestItem.criteria.like = query;
requestItem.criteria.type = type;
return this.externalSourcesService.searchDatasetRepository(requestItem);
}
searchDatasetExternalRegistries(query: string, type: string): Observable<ExternalSourceItemModel[]> {
const requestItem: RequestItem<RegistryCriteria> = new RequestItem();
requestItem.criteria = new RegistryCriteria();
requestItem.criteria.like = query;
requestItem.criteria.type = type;
return this.externalSourcesService.searchDatasetRegistry(requestItem);
}
searchDatasetExternalServices(query: string, type: string): Observable<ExternalSourceItemModel[]> {
const requestItem: RequestItem<ServiceCriteria> = new RequestItem();
requestItem.criteria = new ServiceCriteria();
requestItem.criteria.like = query;
requestItem.criteria.type = type;
return this.externalSourcesService.searchDatasetService(requestItem);
}
searchDatasetTags(query: string, type: string): Observable<ExternalSourceItemModel[]> {
const requestItem: RequestItem<TagCriteria> = new RequestItem();
requestItem.criteria = new TagCriteria();
requestItem.criteria.like = query;
requestItem.criteria.type = type;
return this.externalSourcesService.searchDatasetTags(requestItem);
}
removeTag(tag: any) {
(<UntypedFormArray>this.formGroup.get('tags')).removeAt(((<UntypedFormArray>this.formGroup.get('tags')).value as any[]).indexOf(tag));
}
addTag(ev: any) {
let item: ExternalTagEditorModel;
//this.filteredTags = this.formGroup.get('tags').value;
if (typeof ev === 'string') {
item = new ExternalTagEditorModel('', ev);
} else {
item = ev;
}
if (item.name !== '' ) {
return item;
}
}
isInternal(element: any): boolean {
if (element.get('source') == null) {
// console.log(element);
}
return element.get('source').value === 'Internal';
}
updateDataRepository(dataRepository: UntypedFormGroup) {
this.externalDataRepositoryService.create(dataRepository.value)
.pipe(takeUntil(this._destroyed))
.subscribe(
(result) => {
dataRepository.setValue(result);
}
);
}
updateExternalDataset(externalDataset: UntypedFormGroup) {
this.externalDatasetService.create(externalDataset.value)
.pipe(takeUntil(this._destroyed))
.subscribe(
(result) => {
externalDataset.setValue(result);
}
);
}
updateRegistry(registry: UntypedFormGroup) {
this.externalRegistryService.create(registry.value)
.pipe(takeUntil(this._destroyed))
.subscribe(
(result) => {
registry.setValue(result);
}
);
}
updateService(service: UntypedFormGroup) {
this.externalServiceService.create(service.value)
.pipe(takeUntil(this._destroyed))
.subscribe(
(result) => {
service.setValue(result);
}
);
}
filterTags(value: string): Observable<ExternalSourceItemModel[]> {
this.filteringTagsAsync = true;
const requestItem: RequestItem<TagCriteria> = new RequestItem();
const criteria: TagCriteria = new TagCriteria();
criteria.like = value;
requestItem.criteria = criteria;
return this.externalSourcesService.searchDatasetTags(requestItem);
}
showTag(ev: any) {
if (typeof ev === 'string') {
return ev;
} else {
return ev.name;
}
}
}

View File

@ -0,0 +1,28 @@
<form *ngIf="formGroup" [formGroup]="formGroup">
<div class="row d-flex flex-row">
<div mat-dialog-title class="col-auto">
{{'DATASET-REFERENCED-MODELS.DATA-REPOSITORY.TITLE' | translate}}
</div>
<div class="col-auto ml-auto close-btn" (click)="close()">
<mat-icon>close</mat-icon>
</div>
</div>
<div mat-dialog-content class="row">
<mat-form-field class="col-auto">
<input matInput formControlName="name" placeholder="{{'DATASET-REFERENCED-MODELS.DATA-REPOSITORY.LABEL' | translate}}" required>
<mat-error *ngIf="formGroup.get('name').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
<mat-form-field class="col-auto">
<input matInput formControlName="abbreviation" placeholder="{{'DATASET-REFERENCED-MODELS.DATA-REPOSITORY.ABBREVIATION' | translate}}" required>
<mat-error *ngIf="formGroup.get('abbreviation').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
<mat-form-field class="col-auto">
<input matInput formControlName="uri" placeholder="{{'DATASET-REFERENCED-MODELS.DATA-REPOSITORY.URI' | translate}}" required>
<mat-error *ngIf="formGroup.get('uri').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
<div mat-dialog-actions class="row">
<div class="ml-auto col-auto"><button mat-raised-button type="button" mat-dialog-close>Cancel</button></div>
<div class="col-auto"><button mat-raised-button color="primary" (click)="send()" type="button">Save</button></div>
</div>
</form>

View File

@ -0,0 +1,42 @@
import { Component, Inject, OnInit } from '@angular/core';
import { UntypedFormGroup } from '@angular/forms';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { ExternalDataRepositoryService } from '@app/core/services/external-sources/data-repository/extternal-data-repository.service';
import { ExternalDataRepositoryEditorModel } from '@app/ui/dataset/dataset-wizard/dataset-wizard-editor.model';
import { BaseComponent } from '@common/base/base.component';
import { FormService } from '@common/forms/form-service';
import { takeUntil } from 'rxjs/operators';
@Component({
templateUrl: 'dataset-external-data-repository-dialog-editor.component.html',
styleUrls: ['./dataset-external-data-repository-dialog-editor.component.scss']
})
export class DatasetExternalDataRepositoryDialogEditorComponent extends BaseComponent implements OnInit {
public formGroup: UntypedFormGroup;
constructor(
private externalDataRepositoryService: ExternalDataRepositoryService,
public dialogRef: MatDialogRef<DatasetExternalDataRepositoryDialogEditorComponent>,
@Inject(MAT_DIALOG_DATA) public data: any,
private formService: FormService
) { super(); }
ngOnInit(): void {
const datarepo = new ExternalDataRepositoryEditorModel();
this.formGroup = datarepo.buildForm();
}
send(value: any) {
this.formService.touchAllFormFields(this.formGroup);
if (!this.formGroup.valid) { return; }
this.externalDataRepositoryService.create(this.formGroup.value)
.pipe(takeUntil(this._destroyed))
.subscribe(
(item) => this.dialogRef.close(item)
);
}
close() {
this.dialogRef.close(false);
}
}

View File

@ -0,0 +1,24 @@
<form *ngIf="formGroup" [formGroup]="formGroup">
<div class="row d-flex flex-row">
<div mat-dialog-title class="col-auto">
{{'DATASET-REFERENCED-MODELS.EXTERNAL-DATASET.TITLE' | translate}}
</div>
<div class="col-auto ml-auto close-btn" (click)="close()">
<mat-icon>close</mat-icon>
</div>
</div>
<div mat-dialog-content class="row">
<mat-form-field class="col-auto">
<input matInput formControlName="name" placeholder="{{'DATASET-REFERENCED-MODELS.EXTERNAL-DATASET.LABEL' | translate}}" required>
<mat-error *ngIf="formGroup.get('name').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
<mat-form-field class="col-auto">
<input matInput formControlName="abbreviation" placeholder="{{'DATASET-REFERENCED-MODELS.EXTERNAL-DATASET.ABBREVIATION' | translate}}" required>
<mat-error *ngIf="formGroup.get('abbreviation').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
<div mat-dialog-actions class="row">
<div class="ml-auto col-auto"><button mat-raised-button mat-dialog-close type="button">Cancel</button></div>
<div class="col-auto"><button mat-raised-button color="primary" (click)="send()" type="button">Save</button></div>
</div>
</form>

View File

@ -0,0 +1,42 @@
import { Component, Inject, OnInit } from '@angular/core';
import { UntypedFormGroup } from '@angular/forms';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { ExternalDatasetService } from '@app/core/services/external-sources/dataset/external-dataset.service';
import { ExternalDatasetEditorModel } from '@app/ui/dataset/dataset-wizard/dataset-wizard-editor.model';
import { BaseComponent } from '@common/base/base.component';
import { takeUntil } from 'rxjs/operators';
import { FormService } from '@common/forms/form-service';
@Component({
templateUrl: 'dataset-external-dataset-dialog-editor.component.html',
styleUrls: ['./dataset-external-dataset-dialog-editor.component.scss']
})
export class DatasetExternalDatasetDialogEditorComponent extends BaseComponent implements OnInit {
public formGroup: UntypedFormGroup;
constructor(
private externalDatasetService: ExternalDatasetService,
public dialogRef: MatDialogRef<DatasetExternalDatasetDialogEditorComponent>,
@Inject(MAT_DIALOG_DATA) public data: any,
private formService: FormService
) { super(); }
ngOnInit(): void {
const externalDatasetModel = new ExternalDatasetEditorModel();
this.formGroup = externalDatasetModel.buildForm();
}
send(value: any) {
this.formService.touchAllFormFields(this.formGroup);
if (!this.formGroup.valid) { return; }
this.externalDatasetService.create(this.formGroup.value)
.pipe(takeUntil(this._destroyed))
.subscribe(
(item) => this.dialogRef.close(item)
);
}
close() {
this.dialogRef.close(false);
}
}

View File

@ -0,0 +1,28 @@
<form *ngIf="formGroup" [formGroup]="formGroup">
<div class="row d-flex flex-row">
<div mat-dialog-title class="col-auto">
{{'DATASET-REFERENCED-MODELS.REGISTRY.TITLE' | translate}}
</div>
<div class="col-auto ml-auto close-btn" (click)="close()">
<mat-icon>close</mat-icon>
</div>
</div>
<div mat-dialog-content class="row">
<mat-form-field class="col-auto">
<input matInput formControlName="label" placeholder="{{'DATASET-REFERENCED-MODELS.REGISTRY.LABEL' | translate}}" required>
<mat-error *ngIf="formGroup.get('label').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
<mat-form-field class="col-auto">
<input matInput formControlName="abbreviation" placeholder="{{'DATASET-REFERENCED-MODELS.REGISTRY.ABBREVIATION' | translate}}" required>
<mat-error *ngIf="formGroup.get('abbreviation').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
<mat-form-field class="col-auto">
<input matInput formControlName="uri" placeholder="{{'DATASET-REFERENCED-MODELS.REGISTRY.URI' | translate}}" required>
<mat-error *ngIf="formGroup.get('uri').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
<div mat-dialog-actions class="row">
<div class="ml-auto col-auto"><button mat-raised-button mat-dialog-close type="button">Cancel</button></div>
<div class="col-auto"><button mat-raised-button color="primary" (click)="send()" type="button">Save</button></div>
</div>
</form>

View File

@ -0,0 +1,42 @@
import { Component, Inject, OnInit } from '@angular/core';
import { UntypedFormGroup } from '@angular/forms';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { ExternalRegistryService } from '@app/core/services/external-sources/registry/external-registry.service';
import { ExternalRegistryEditorModel } from '@app/ui/dataset/dataset-wizard/dataset-wizard-editor.model';
import { BaseComponent } from '@common/base/base.component';
import { FormService } from '@common/forms/form-service';
import { takeUntil } from 'rxjs/operators';
@Component({
templateUrl: 'dataset-external-registry-dialog-editor.component.html',
styleUrls: ['./dataset-external-registry-dialog-editor.component.scss']
})
export class DatasetExternalRegistryDialogEditorComponent extends BaseComponent implements OnInit {
public formGroup: UntypedFormGroup;
constructor(
private externalRegistryService: ExternalRegistryService,
public dialogRef: MatDialogRef<DatasetExternalRegistryDialogEditorComponent>,
@Inject(MAT_DIALOG_DATA) public data: any,
private formService: FormService
) { super(); }
ngOnInit(): void {
const registryModel = new ExternalRegistryEditorModel();
this.formGroup = registryModel.buildForm();
}
send(value: any) {
this.formService.touchAllFormFields(this.formGroup);
if (!this.formGroup.valid) { return; }
this.externalRegistryService.create(this.formGroup.value)
.pipe(takeUntil(this._destroyed))
.subscribe(
(item) => this.dialogRef.close(item)
);
}
close() {
this.dialogRef.close(false);
}
}

View File

@ -0,0 +1,28 @@
<form *ngIf="formGroup" [formGroup]="formGroup">
<div class="row d-flex flex-row">
<div mat-dialog-title class="col-auto">
{{'DATASET-REFERENCED-MODELS.SERVICES.TITLE' | translate}}
</div>
<div class="col-auto ml-auto close-btn" (click)="close()">
<mat-icon>close</mat-icon>
</div>
</div>
<div mat-dialog-content class="row">
<mat-form-field class="col-auto">
<input matInput formControlName="label" placeholder="{{'DATASET-REFERENCED-MODELS.SERVICES.LABEL' | translate}}" required>
<mat-error *ngIf="formGroup.get('label').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
<mat-form-field class="col-auto">
<input matInput formControlName="abbreviation" placeholder="{{'DATASET-REFERENCED-MODELS.SERVICES.ABBREVIATION' | translate}}" required>
<mat-error *ngIf="formGroup.get('abbreviation').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
<mat-form-field class="col-auto">
<input matInput formControlName="uri" placeholder="{{'DATASET-REFERENCED-MODELS.SERVICES.URI' | translate}}" required>
<mat-error *ngIf="formGroup.get('uri').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
<div mat-dialog-actions class="row">
<div class="ml-auto col-auto"><button mat-raised-button mat-dialog-close type="button">Cancel</button></div>
<div class="col-auto"><button mat-raised-button color="primary" (click)="send()" type="button">Save</button></div>
</div>
</form>

View File

@ -0,0 +1,42 @@
import { Component, Inject, OnInit } from '@angular/core';
import { UntypedFormGroup } from '@angular/forms';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { ExternalServiceService } from '@app/core/services/external-sources/service/external-service.service';
import { ExternalServiceEditorModel } from '@app/ui/dataset/dataset-wizard/dataset-wizard-editor.model';
import { BaseComponent } from '@common/base/base.component';
import { takeUntil } from 'rxjs/operators';
import { FormService } from '@common/forms/form-service';
@Component({
templateUrl: 'dataset-external-service-dialog-editor.component.html',
styleUrls: ['./dataset-external-service-dialog-editor.component.scss']
})
export class DatasetExternalServiceDialogEditorComponent extends BaseComponent implements OnInit {
public formGroup: UntypedFormGroup;
constructor(
private externalServiceService: ExternalServiceService,
public dialogRef: MatDialogRef<DatasetExternalServiceDialogEditorComponent>,
@Inject(MAT_DIALOG_DATA) public data: any,
private formService: FormService
) { super(); }
ngOnInit(): void {
const serviceModel = new ExternalServiceEditorModel();
this.formGroup = serviceModel.buildForm();
}
send() {
this.formService.touchAllFormFields(this.formGroup);
if (!this.formGroup.valid) { return; }
this.externalServiceService.create(this.formGroup.value)
.pipe(takeUntil(this._destroyed))
.subscribe(
(item) => this.dialogRef.close(item)
);
}
close() {
this.dialogRef.close(false);
}
}

View File

@ -0,0 +1,57 @@
<div class="template-container">
<div mat-dialog-title class="row d-flex m-0 header">
<span class="template-title align-self-center">{{'DATASET-CREATE-WIZARD.PREFILL-STEP.TITLE' | translate}}</span>
<span class="ml-auto align-self-center" (click)="closeDialog()"><mat-icon
class="close-icon">close</mat-icon></span>
</div>
<div *ngIf="progressIndication" class="progress-bar">
<mat-progress-bar color="primary" mode="indeterminate"></mat-progress-bar>
</div>
<div mat-dialog-content *ngIf="prefillForm" [formGroup]="prefillForm" class="definition-content">
<div class="row d-flex align-items-center justify-content-center">
<div class="pb-4 pl-4 pr-4">
{{'DATASET-CREATE-WIZARD.PREFILL-STEP.HINT' | translate}}
</div>
</div>
<div class="row d-flex align-items-center justify-content-center" [class.pb-4]="isPrefilled">
<button mat-raised-button type="button" class="empty-btn"
(click)="closeDialog()">{{'DATASET-CREATE-WIZARD.PREFILL-STEP.MANUALLY' | translate}}</button>
<div class="ml-2 mr-2">{{'DATASET-CREATE-WIZARD.PREFILL-STEP.OR' | translate}}</div>
<button mat-raised-button type="button" class="prefill-btn"
(click)="isPrefilled = true">{{'DATASET-CREATE-WIZARD.PREFILL-STEP.PREFILL' | translate}}</button>
</div>
<div *ngIf="isPrefilled" class="row">
<div class="col-12 pl-0 pr-0 pb-2 d-flex flex-row">
<h4 class="col-auto heading">{{'DATASET-CREATE-WIZARD.PREFILL-STEP.PROFILE' | translate}}</h4>
</div>
<mat-form-field class="col-md-12">
<mat-select placeholder="{{'DATASET-CREATE-WIZARD.PREFILL-STEP.PROFILE'| translate}}" [required]="true" [compareWith]="compareWith" formControlName="profile">
<mat-option *ngFor="let profile of data.availableProfiles" [value]="profile">
<div (click)="checkMinMax($event, profile)">
{{profile.label}}
</div>
</mat-option>
</mat-select>
<mat-error *ngIf="prefillForm.get('profile').hasError('backendError')">{{prefillForm.get('profile').getError('backendError').message}}</mat-error>
</mat-form-field>
</div>
<div *ngIf="isPrefilled" class="row">
<div class="col-12 pl-0 pr-0 pb-2 d-flex flex-row">
<h4 class="col-auto heading">{{'DATASET-CREATE-WIZARD.PREFILL-STEP.PREFILLED-DATASET' | translate}}</h4>
</div>
<mat-form-field class="col-md-12">
<app-single-auto-complete [required]="true" [formControl]="prefillForm.get('prefill')"
placeholder="{{'DATASET-CREATE-WIZARD.PREFILL-STEP.SEARCH' | translate}}"
[configuration]="prefillAutoCompleteConfiguration">
</app-single-auto-complete>
</mat-form-field>
</div>
</div>
<div *ngIf="isPrefilled">
<div class="col-auto d-flex pb-4 pt-2">
<button mat-raised-button type="button" class="prefill-btn ml-auto" [disabled]="prefillForm.invalid"
(click)="next()">{{'DATASET-CREATE-WIZARD.PREFILL-STEP.NEXT' | translate}}</button>
</div>
</div>
</div>

View File

@ -0,0 +1,57 @@
.template-container {
.header {
display: flex;
width: 100%;
height: 60px;
background-color: var(--secondary-color);
color: #212121;
font-size: 1.25rem;
}
.template-title {
margin-left: 37px;
white-space: nowrap;
width: 480px;
overflow: hidden;
text-overflow: ellipsis;
}
.close-icon {
cursor: pointer;
margin-right: 20px;
}
.close-icon:hover {
background-color: #fefefe6e !important;
border-radius: 50%;
}
.definition-content {
display: block;
margin: 0;
padding: 25px;
}
.empty-btn, .prefill-btn {
background: var(--secondary-color) 0 0 no-repeat padding-box;
border: 1px solid var(--secondary-color);
border-radius: 30px;
opacity: 1;
min-width: 101px;
height: 43px;
color: #212121;
font-weight: 500;
}
.prefill-btn:disabled {
background: #a1a1a1 0 0 no-repeat padding-box;
border: 1px solid #a1a1a1;
opacity: 0.5;
}
.empty-btn {
background: #ffffff 0 0 no-repeat padding-box;
border: 1px solid #a1a1a1;
}
}

View File

@ -0,0 +1,200 @@
import { Component, Inject, OnInit } from "@angular/core";
import { UntypedFormBuilder, UntypedFormGroup, Validators } from "@angular/forms";
import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from "@angular/material/dialog";
import { DatasetProfileModel } from "@app/core/model/dataset/dataset-profile";
import { Prefilling } from "@app/core/model/dataset/prefilling";
import { DescriptionTemplatesInSection, DmpBlueprint, DmpBlueprintDefinition, DmpBlueprintDefinitionSection, FieldInSection } from "@app/core/model/dmp-blueprint/dmp-blueprint";
import { DmpBlueprintService } from "@app/core/services/dmp/dmp-blueprint.service";
import { PrefillingService } from "@app/core/services/prefilling.service";
import { ProgressIndicationService } from "@app/core/services/progress-indication/progress-indication-service";
import { SingleAutoCompleteConfiguration } from "@app/library/auto-complete/single/single-auto-complete-configuration";
import { PopupNotificationDialogComponent } from "@app/library/notification/popup/popup-notification.component";
import { BaseComponent } from "@common/base/base.component";
import { Guid } from "@common/types/guid";
import { TranslateService } from "@ngx-translate/core";
import { Observable } from "rxjs";
import { map, takeUntil } from "rxjs/operators";
import { nameof } from "ts-simple-nameof";
@Component({
selector: 'prefill-dataset-component',
templateUrl: 'prefill-dataset.component.html',
styleUrls: ['prefill-dataset.component.scss']
})
export class PrefillDatasetComponent extends BaseComponent implements OnInit {
progressIndication = false;
prefillAutoCompleteConfiguration: SingleAutoCompleteConfiguration;
isPrefilled: boolean = false;
prefillForm: UntypedFormGroup;
constructor(public dialogRef: MatDialogRef<PrefillDatasetComponent>,
private prefillingService: PrefillingService,
private dmpBlueprintService: DmpBlueprintService,
private dialog: MatDialog,
private language: TranslateService,
private progressIndicationService: ProgressIndicationService,
private fb: UntypedFormBuilder,
@Inject(MAT_DIALOG_DATA) public data: any) {
super();
}
ngOnInit() {
this.progressIndicationService.getProgressIndicationObservable().pipe(takeUntil(this._destroyed)).subscribe(x => {
setTimeout(() => { this.progressIndication = x; });
});
this.prefillForm = this.fb.group({
type: this.fb.control(false),
profile: this.fb.control('', Validators.required),
prefill: this.fb.control(null, Validators.required)
})
if (this.data.availableProfiles && this.data.availableProfiles.length === 1) {
this.addProfileIfUsedLessThanMax(this.data.availableProfiles[0]);
}
this.prefillAutoCompleteConfiguration = {
filterFn: this.searchDatasets.bind(this),
loadDataOnStart: false,
displayFn: (item) => (item['name'].length > 60) ? (item['name'].substr(0, 60) + "...") : item['name'],
titleFn: (item) => item['name'],
subtitleFn: (item) => item['pid']
};
}
addProfileIfUsedLessThanMax(profile: DatasetProfileModel) {
const dmpSectionIndex = this.data.datasetFormGroup.get('dmpSectionIndex').value;
const blueprintId = this.data.datasetFormGroup.get('dmp').value.profile.id;
this.dmpBlueprintService.getSingle(blueprintId, this.getBlueprintDefinitionFields())
.pipe(takeUntil(this._destroyed))
.subscribe(result => {
const section = result.definition.sections[dmpSectionIndex];
if (section.hasTemplates) {
const foundTemplate = section.descriptionTemplates.find(template => template.descriptionTemplateId === Guid.parse(profile.id));
if (foundTemplate !== undefined) {
let count = 0;
if (this.data.datasetFormGroup.get('dmp').value.datasets != null) {
for (let dataset of this.data.datasetFormGroup.get('dmp').value.datasets) {
if (dataset.dmpSectionIndex === dmpSectionIndex && dataset.profile.id === foundTemplate.descriptionTemplateId) {
count++;
}
}
if (count < foundTemplate.maxMultiplicity) {
this.prefillForm.get('profile').patchValue(profile);
}
}
}
else {
this.prefillForm.get('profile').patchValue(profile);
}
}
else {
this.prefillForm.get('profile').patchValue(profile);
}
});
}
checkMinMax(event, profile: DatasetProfileModel) {
event.stopPropagation();
const dmpSectionIndex = this.data.datasetFormGroup.get('dmpSectionIndex').value;
const blueprintId = this.data.datasetFormGroup.get('dmp').value.profile.id;
this.dmpBlueprintService.getSingle(blueprintId, this.getBlueprintDefinitionFields())
.pipe(takeUntil(this._destroyed))
.subscribe(result => {
const section = result.definition.sections[dmpSectionIndex];
if (section.hasTemplates) {
const foundTemplate = section.descriptionTemplates.find(template => template.descriptionTemplateId === Guid.parse(profile.id));
if (foundTemplate !== undefined) {
let count = 0;
if (this.data.datasetFormGroup.get('dmp').value.datasets != null) {
for (let dataset of this.data.datasetFormGroup.get('dmp').value.datasets) {
if (dataset.dmpSectionIndex === dmpSectionIndex && dataset.profile.id === foundTemplate.descriptionTemplateId) {
count++;
}
}
if (count === foundTemplate.maxMultiplicity) {
this.dialog.open(PopupNotificationDialogComponent, {
data: {
title: this.language.instant('DATASET-EDITOR.MAX-DESCRIPTION-DIALOG.TITLE'),
message: this.language.instant('DATASET-EDITOR.MAX-DESCRIPTION-DIALOG.MESSAGE')
}, maxWidth: '30em'
});
}
else {
this.prefillForm.get('profile').setValue(profile);
}
}
}
else {
this.prefillForm.get('profile').setValue(profile);
}
}
else {
this.prefillForm.get('profile').setValue(profile);
}
});
}
private getBlueprintDefinitionFields() {
return [
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.id)].join('.'),
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.label)].join('.'),
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.description)].join('.'),
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.ordinal)].join('.'),
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.hasTemplates)].join('.'),
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.fields), nameof<FieldInSection>(x => x.id)].join('.'),
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.fields), nameof<FieldInSection>(x => x.category)].join('.'),
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.fields), nameof<FieldInSection>(x => x.dataType)].join('.'),
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.fields), nameof<FieldInSection>(x => x.systemFieldType)].join('.'),
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.fields), nameof<FieldInSection>(x => x.label)].join('.'),
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.fields), nameof<FieldInSection>(x => x.placeholder)].join('.'),
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.fields), nameof<FieldInSection>(x => x.description)].join('.'),
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.fields), nameof<FieldInSection>(x => x.required)].join('.'),
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.fields), nameof<FieldInSection>(x => x.ordinal)].join('.'),
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.descriptionTemplates), nameof<DescriptionTemplatesInSection>(x => x.id)].join('.'),
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.descriptionTemplates), nameof<DescriptionTemplatesInSection>(x => x.descriptionTemplateId)].join('.'),
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.descriptionTemplates), nameof<DescriptionTemplatesInSection>(x => x.label)].join('.'),
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.descriptionTemplates), nameof<DescriptionTemplatesInSection>(x => x.minMultiplicity)].join('.'),
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.descriptionTemplates), nameof<DescriptionTemplatesInSection>(x => x.maxMultiplicity)].join('.'),
]
}
public compareWith(object1: any, object2: any) {
return object1 && object2 && object1.id === object2.id;
}
searchDatasets(query: string): Observable<Prefilling[]> {
return this.prefillingService.getPrefillingList(query).pipe(map(prefilling => prefilling.sort((a, b) => {
if (a.name > b.name) {
return 1;
} else if (a.name < b.name) {
return -1;
} else {
return 0;
}
})));
}
next() {
if (this.isPrefilled) {
if (this.prefillForm.get('prefill').value.data == null) {
this.prefillingService.getPrefillingDataset(this.prefillForm.get('prefill').value.pid, this.prefillForm.get('profile').value.id, this.prefillForm.get('prefill').value.key).subscribe(wizard => {
wizard.profile = this.prefillForm.get('profile').value;
this.closeDialog(wizard);
});
}
else {
this.prefillingService.getPrefillingDatasetUsingData(this.prefillForm.get('prefill').value.data, this.prefillForm.get('profile').value.id, this.prefillForm.get('prefill').value.key).subscribe(wizard => {
wizard.profile = this.prefillForm.get('profile').value;
this.closeDialog(wizard);
});
}
} else {
this.closeDialog();
}
}
closeDialog(result = null): void {
this.dialogRef.close(result);
}
}

View File

@ -0,0 +1,78 @@
import { NgModule } from '@angular/core';
import { FormattingModule } from '@app/core/formatting.module';
import { AutoCompleteModule } from '@app/library/auto-complete/auto-complete.module';
import { ExportMethodDialogModule } from '@app/library/export-method-dialog/export-method-dialog.module';
import { RichTextEditorModule } from "@app/library/rich-text-editor/rich-text-editor.module";
import { UrlListingModule } from '@app/library/url-listing/url-listing.module';
// import { DescriptionEditorComponent } from '@app/ui/description/description-wizard/description-editor/description-editor.component';
// import { DescriptionWizardComponent } from '@app/ui/description/description-wizard/description-wizard.component';
// import { DescriptionExternalReferencesEditorComponent } from '@app/ui/description/description-wizard/external-references/description-external-references-editor.component';
// import { DescriptionExternalDataRepositoryDialogEditorComponent } from '@app/ui/description/description-wizard/external-references/editors/data-repository/description-external-data-repository-dialog-editor.component';
// import { DescriptionExternalDescriptionDialogEditorComponent } from '@app/ui/description/description-wizard/external-references/editors/external-description/description-external-description-dialog-editor.component';
// import { DescriptionExternalRegistryDialogEditorComponent } from '@app/ui/description/description-wizard/external-references/editors/registry/description-external-registry-dialog-editor.component';
// import { DescriptionExternalServiceDialogEditorComponent } from '@app/ui/description/description-wizard/external-references/editors/service/description-external-service-dialog-editor.component';
// import { PrefillDescriptionComponent } from "@app/ui/description/description-wizard/prefill-description/prefill-description.component";
import { DescriptionRoutingModule } from '@app/ui/description/description.routing';
// import { DescriptionCriteriaComponent } from '@app/ui/description/listing/criteria/description-criteria.component';
// import { DescriptionUploadDialogue } from '@app/ui/description/listing/criteria/description-upload-dialogue/description-upload-dialogue.component';
import { DescriptionListingComponent } from '@app/ui/description/listing/description-listing.component';
import { DescriptionListingItemComponent } from '@app/ui/description/listing/listing-item/description-listing-item.component';
// import { DescriptionDescriptionFormModule } from '@app/ui/misc/description-description-form/description-description-form.module';
// import { TableOfContentsModule } from '@app/ui/misc/description-description-form/tableOfContentsMaterial/table-of-contents.module';
import { ExternalSourcesModule } from '@app/ui/misc/external-sources/external-sources.module';
import { CommonFormsModule } from '@common/forms/common-forms.module';
import { FormValidationErrorsDialogModule } from '@common/forms/form-validation-errors-dialog/form-validation-errors-dialog.module';
import { ConfirmationDialogModule } from '@common/modules/confirmation-dialog/confirmation-dialog.module';
import { CommonUiModule } from '@common/ui/common-ui.module';
import { AngularStickyThingsModule } from '@w11k/angular-sticky-things';
// import { FormProgressIndicationModule } from '../misc/description-description-form/components/form-progress-indication/form-progress-indication.module';
// import { DescriptionCopyDialogModule } from './description-wizard/description-copy-dialogue/description-copy-dialogue.module';
// import { DescriptionCriteriaDialogComponent } from './listing/criteria/description-criteria-dialogue/description-criteria-dialog.component';
// import { DescriptionOverviewModule } from './overview/description-overview.module';
@NgModule({
imports: [
CommonUiModule,
CommonFormsModule,
UrlListingModule,
FormattingModule,
ConfirmationDialogModule,
AutoCompleteModule,
ExternalSourcesModule,
ExportMethodDialogModule,
// DescriptionDescriptionFormModule,
// TableOfContentsModule,
AngularStickyThingsModule,
DescriptionRoutingModule,
FormValidationErrorsDialogModule,
// DescriptionCopyDialogModule,
// DescriptionOverviewModule,
// FormProgressIndicationModule,
RichTextEditorModule
],
declarations: [
DescriptionListingComponent,
// DescriptionCriteriaComponent,
// DescriptionWizardComponent,
// DescriptionEditorComponent,
// DescriptionExternalReferencesEditorComponent,
// DescriptionExternalDataRepositoryDialogEditorComponent,
// DescriptionExternalDescriptionDialogEditorComponent,
// DescriptionExternalRegistryDialogEditorComponent,
// DescriptionExternalServiceDialogEditorComponent,
// DescriptionUploadDialogue,
DescriptionListingItemComponent,
// DescriptionCriteriaDialogComponent,
// PrefillDescriptionComponent
],
exports: [
// DescriptionExternalReferencesEditorComponent,
// DescriptionExternalDataRepositoryDialogEditorComponent,
// DescriptionExternalDescriptionDialogEditorComponent,
// DescriptionExternalRegistryDialogEditorComponent,
// DescriptionExternalServiceDialogEditorComponent,
// DescriptionEditorComponent,
// DescriptionDescriptionFormModule
]
})
export class DescriptionModule { }

View File

@ -0,0 +1,129 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { CanDeactivateGuard } from '@app/library/deactivate/can-deactivate.guard';
import { AuthGuard } from '../../core/auth-guard.service';
// import { DescriptionWizardComponent } from './description-wizard/description-wizard.component';
import { DescriptionListingComponent } from './listing/description-listing.component';
// import { DescriptionOverviewComponent } from './overview/description-overview.component';
const routes: Routes = [
{
path: '',
component: DescriptionListingComponent,
// canActivate: [AuthGuard],
data: {
breadcrumb: true
},
},
{
path: 'dmp/:dmpId',
component: DescriptionListingComponent,
canActivate: [AuthGuard],
data: {
breadcrumb: true
},
},
// {
// path: 'new/:dmpId/:dmpSectionIndex',
// component: DescriptionWizardComponent,
// canActivate: [AuthGuard],
// data: {
// breadcrumb: true,
// title: 'GENERAL.TITLES.DATASET-NEW'
// },
// canDeactivate:[CanDeactivateGuard]
// },
// {
// path: 'edit/:id',
// component: DescriptionWizardComponent,
// canActivate: [AuthGuard],
// data: {
// breadcrumb: true,
// public: false,
// title: 'GENERAL.TITLES.DATASET-EDIT'
// },
// canDeactivate:[CanDeactivateGuard]
// },
// {
// path: 'edit/:id/finalize',
// component: DescriptionWizardComponent,
// canActivate: [AuthGuard],
// data: {
// breadcrumb: true,
// public: false,
// title: 'GENERAL.TITLES.DATASET-EDIT',
// finalize: true
// },
// canDeactivate:[CanDeactivateGuard]
// },
// {
// path: 'publicEdit/:publicId',
// component: DescriptionWizardComponent,
// //canActivate: [AuthGuard],
// data: {
// public: true,
// title: 'GENERAL.TITLES.DATASET-PUBLIC-EDIT'
// },
// canDeactivate:[CanDeactivateGuard]
// },
// {
// path: 'new',
// component: DescriptionWizardComponent,
// canActivate: [AuthGuard],
// data: {
// breadcrumb: true,
// title: 'GENERAL.TITLES.DATASET-NEW'
// },
// canDeactivate:[CanDeactivateGuard]
// },
{
path: 'dmp/:dmpId',
component: DescriptionListingComponent,
canActivate: [AuthGuard],
data: {
breadcrumb: true
},
},
// {
// path: 'copy/:id',
// component: DescriptionWizardComponent,
// canActivate: [AuthGuard],
// data: {
// breadcrumb: true,
// title: 'GENERAL.TITLES.DATASET-COPY'
// },
// canDeactivate:[CanDeactivateGuard]
// },
// {
// path: 'profileupdate/:updateId',
// component: DescriptionWizardComponent,
// canActivate: [AuthGuard],
// data: {
// breadcrumb: true,
// title: 'GENERAL.TITLES.DATASET-UPDATE'
// },
// canDeactivate:[CanDeactivateGuard]
// },
// {
// path: 'overview/:id',
// component: DescriptionOverviewComponent,
// data: {
// breadcrumb: true,
// title: 'GENERAL.TITLES.DATASET-OVERVIEW'
// },
// },
// {
// path: 'publicOverview/:publicId',
// component: DescriptionOverviewComponent,
// data: {
// breadcrumb: true,
// title: 'GENERAL.TITLES.DATASET-OVERVIEW'
// },
// }
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class DescriptionRoutingModule { }

View File

@ -0,0 +1,2 @@
<a class="col-auto d-flex pointer" (click)="onClose()"><span class="ml-auto mt-3 material-icons clear-icon">clear</span></a>
<app-dataset-criteria-component [isPublic]="data.isPublic" [status]="data.status" [criteriaFormGroup]="data.formGroup" (filtersChanged)="onFiltersChanged($event)"></app-dataset-criteria-component>

View File

@ -0,0 +1,20 @@
.clear-icon {
cursor: pointer;
color: #212121;
padding: 0.4rem;
}
.clear-icon:hover {
background-color: #ececec !important;
border-radius: 50%;
padding: 0.4rem;
}
:host ::ng-deep .mat-form-field-wrapper {
background-color: white !important;
padding-bottom: 0 !important;
}
:host ::ng-deep .mat-form-field-appearance-outline .mat-form-field-infix {
padding: 0.3rem 0rem 0.6rem 0rem !important;
}

View File

@ -0,0 +1,44 @@
import { HttpClient } from '@angular/common/http';
import { Component, Inject, OnInit, ViewChild } from '@angular/core';
import { UntypedFormGroup } from '@angular/forms';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { DatasetCriteria } from '@app/core/query/dataset/dataset-criteria';
import { MatomoService } from '@app/core/services/matomo/matomo-service';
import { DatasetCriteriaComponent } from '../dataset-criteria.component';
@Component({
selector: 'dataset-criteria-dialog-component',
templateUrl: './dataset-criteria-dialog.component.html',
styleUrls: ['./dataset-criteria-dialog.component.scss']
})
export class DatasetCriteriaDialogComponent implements OnInit {
@ViewChild(DatasetCriteriaComponent, { static: true }) criteria: DatasetCriteriaComponent;
constructor(
public dialogRef: MatDialogRef<DatasetCriteriaDialogComponent>,
private httpClient: HttpClient,
private matomoService: MatomoService,
@Inject(MAT_DIALOG_DATA) public data: { isPublic: boolean, status: Number, criteria: DatasetCriteria, formGroup: UntypedFormGroup, updateDataFn: Function }
) {
}
ngOnInit() {
this.matomoService.trackPageView('Dataset Criteria');
this.criteria.setCriteria(this.data.criteria);
}
onNoClick(): void {
this.dialogRef.close();
}
onClose(): void {
this.dialogRef.close();
}
onFiltersChanged(event) {
this.data.updateDataFn(this.criteria);
}
}

View File

@ -0,0 +1,200 @@
<div class="dmp-criteria">
<div class="filters">
<div class="row justify-content-center">
<div class="col-10">
<h6 class="criteria-title">{{'CRITERIA.FILTERS'| translate}}</h6>
</div>
</div>
<div class="row justify-content-center">
<!-- Search Filter-->
<!-- <mat-form-field class="col-11 search">
<input matInput placeholder="{{'CRITERIA.GRANTS.LIKE'| translate}}" name="grantCriteriaLike"
[formControl]="formGroup.get('like')">
<mat-error *ngIf="formGroup.get('like').hasError('backendError')">
{{formGroup.get('like').getError('backendError').message}}</mat-error>
<mat-icon matSuffix class="style-icon">search</mat-icon>
</mat-form-field> -->
<!-- End of Search Filter -->
<!-- Status Filter-->
<div class="col-10" *ngIf="!isPublic">
<h6 class="category-title">{{'CRITERIA.DATA-SETS.STATUS'| translate}}</h6>
<mat-radio-group aria-label="Select an option" [formControl]="formGroup.get('status')">
<mat-list-item>
<mat-radio-button value="null" [checked]="!formGroup.get('status').value">{{ 'TYPES.DATASET-STATUS.ANY' | translate }}</mat-radio-button>
</mat-list-item>
<mat-list-item>
<mat-radio-button value="0">{{ 'TYPES.DATASET-STATUS.DRAFT' | translate }}</mat-radio-button>
</mat-list-item>
<mat-list-item>
<mat-radio-button value="1">{{ 'TYPES.DATASET-STATUS.FINALISED' | translate }}</mat-radio-button>
</mat-list-item>
</mat-radio-group>
<hr>
</div>
<!-- End of Status Filter-->
<!-- Grant Status -->
<div class="col-10" *ngIf="isPublic">
<h6 class="category-title">{{ 'FACET-SEARCH.GRANT-STATUS.TITLE' | translate }}</h6>
<mat-radio-group [formControl]="formGroup.get('grantStatus')">
<mat-list-item>
<mat-radio-button checked value="null" [checked]="!formGroup.get('grantStatus').value">{{ 'FACET-SEARCH.GRANT-STATUS.OPTIONS.ANY' | translate }}</mat-radio-button>
</mat-list-item>
<mat-list-item>
<mat-radio-button value="0">{{ 'FACET-SEARCH.GRANT-STATUS.OPTIONS.ACTIVE' | translate }}</mat-radio-button>
</mat-list-item>
<mat-list-item>
<mat-radio-button value="1">{{ 'FACET-SEARCH.GRANT-STATUS.OPTIONS.INACTIVE' | translate }}</mat-radio-button>
</mat-list-item>
</mat-radio-group>
<hr>
</div>
<!-- End of Grant Status -->
<!-- Related Dataset Templates Filters -->
<div class="col-10">
<h6 class="category-title">{{'CRITERIA.DATA-SETS.RELATED-DATASET-TEMPLATES' | translate}}</h6>
<mat-form-field class="mb-4">
<mat-label>{{'CRITERIA.DATA-SETS.SELECT-DATASET-TEMPLATES' | translate }}</mat-label>
<app-multiple-auto-complete [formControl]="formGroup.get('datasetTemplates')" [configuration]="datasetTemplateAutoCompleteConfiguration">
</app-multiple-auto-complete>
</mat-form-field>
<hr>
</div>
<!-- End of Related Dataset Templates Filters -->
<!-- Related DMP Filters -->
<div class="col-10">
<h6 class="category-title">{{'CRITERIA.DATA-SETS.RELATED-DMP' | translate}}</h6>
<mat-form-field class="mb-4">
<mat-label>{{'CRITERIA.DATA-SETS.SELECT-DMP' | translate }}</mat-label>
<app-multiple-auto-complete [formControl]="formGroup.get('groupIds')" [configuration]="dmpAutoCompleteConfiguration">
</app-multiple-auto-complete>
</mat-form-field>
<hr>
</div>
<!-- End of Related DMP Filters -->
<!-- All Versions Filter-->
<div class="col-10" *ngIf="!isPublic">
<h6 class="category-title">{{'CRITERIA.DATA-SETS.ALL-VERSIONS'| translate}}</h6>
<mat-slide-toggle [formControl]="formGroup.get('allVersions')"></mat-slide-toggle>
<hr>
</div>
<!-- End of All Versions Filter-->
<!-- Related Grant Filters -->
<div class="col-10">
<h6 class="category-title">{{'CRITERIA.DATA-SETS.RELATED-GRANT' | translate}}</h6>
<mat-form-field class="mb-4">
<mat-label>{{'CRITERIA.DATA-SETS.SELECT-GRANTS' | translate }}</mat-label>
<app-multiple-auto-complete [formControl]="formGroup.get('grants')" [configuration]="grantAutoCompleteConfiguration">
</app-multiple-auto-complete>
</mat-form-field>
<hr>
</div>
<!-- End of Related Grants Filters -->
<!-- Related Collaborators Filters -->
<div class="col-10" *ngIf="!isPublic">
<h6 class="category-title">{{'CRITERIA.DATA-SETS.RELATED-COLLABORATORS' | translate}}</h6>
<mat-form-field class="mb-4">
<mat-label>{{'CRITERIA.DATA-SETS.SELECT-COLLABORATORS' | translate }}</mat-label>
<app-multiple-auto-complete [formControl]="formGroup.get('collaborators')" [configuration]="collaboratorsAutoCompleteConfiguration">
</app-multiple-auto-complete>
</mat-form-field>
<hr>
</div>
<!-- End of Related Collaborators Filters -->
<!-- Role Filter -->
<div class="col-10" *ngIf="isAuthenticated()">
<h6 class="category-title">{{'CRITERIA.DATA-SETS.ROLE' | translate }}</h6>
<mat-radio-group aria-label="Select an option" [formControl]="formGroup.get('role')">
<mat-list-item>
<mat-radio-button checked value="null" [checked]="!formGroup.get('role').value">{{ 'TYPES.DATASET-ROLE.ANY' | translate }}</mat-radio-button>
</mat-list-item>
<mat-list-item>
<mat-radio-button value="0">{{ 'TYPES.DATASET-ROLE.OWNER' | translate }}</mat-radio-button>
</mat-list-item>
<mat-list-item>
<mat-radio-button value="1">{{ 'TYPES.DATASET-ROLE.MEMBER' | translate }}</mat-radio-button>
</mat-list-item>
</mat-radio-group>
<hr>
</div>
<!-- End of Role Filter -->
<!-- Related Organization Filter -->
<div class="col-10">
<h6 class="category-title">{{'CRITERIA.DATA-SETS.ORGANIZATION' | translate }}</h6>
<mat-form-field class="mb-4">
<mat-label>{{'CRITERIA.DATA-SETS.SELECT-ORGANIZATIONS' | translate}}</mat-label>
<app-multiple-auto-complete [formControl]="formGroup.get('organisations')" [configuration]="organisationAutoCompleteConfiguration">
</app-multiple-auto-complete>
</mat-form-field>
<hr>
</div>
<!-- End of Related Organization Filter -->
<!-- Tags Filter -->
<div class="col-10">
<h6 class="category-title">{{'CRITERIA.DATA-SETS.TAGS' | translate }}</h6>
<mat-form-field class="mb-4">
<mat-label>{{'CRITERIA.DATA-SETS.SELECT-TAGS' | translate}}</mat-label>
<app-multiple-auto-complete [formControl]="formGroup.get('tags')" [configuration]="tagsAutoCompleteConfiguration">
</app-multiple-auto-complete>
</mat-form-field>
</div>
<!-- End of Tags Filter -->
<!-- Import Button -->
<!-- <div class="col-10 import">
<button class="importButton" mat-raised-button color="primary" (click)="fileSave($event)"
type="button col-auto">
{{'DMP-UPLOAD.ACTIONS.IMPORT' | translate}}
</button>
</div> -->
</div>
</div>
</div>
<!-- <form class="dataset-criteria">
<mat-card class="mat-card">
<mat-card-header>
<mat-card-title>
<h4>{{'CRITERIA.FILTERS'| translate}}</h4>
</mat-card-title>
<div class="col"></div>
<button class="importButton" mat-raised-button color="primary" (click)="fileImport($event)" type="button col-auto">
{{'DATASET-UPLOAD.ACTIONS.IMPORT' | translate}}
</button>
</mat-card-header>
<div class="row">
<mat-form-field class="col-md-3">
<input matInput placeholder=" {{'CRITERIA.DATA-SETS.LIKE'| translate}}" name="datasetCriteriaName" [(ngModel)]="criteria.like"
(ngModelChange)="controlModified()">
</mat-form-field>
<mat-form-field class="col-md-3">
<app-multiple-auto-complete placeholder="{{'CRITERIA.DMP.LIKE'| translate}}" name="dmpCriteriaName" [(ngModel)]="criteria.dmpIds"
(ngModelChange)="controlModified()" [configuration]="dmpAutoCompleteConfiguration"></app-multiple-auto-complete>
</mat-form-field>
<mat-form-field class="col-md-3">
<mat-select placeholder=" {{'CRITERIA.DATA-SETS.STATUS'| translate}}" name="datasetCriteriastatus" [(ngModel)]="criteria.status"
(ngModelChange)="controlModified()">
<mat-option [value]="null">{{'CRITERIA.DATA-SETS.NONE'| translate}}</mat-option>
<mat-option [value]="statuses.Draft">{{enumUtils.toDatasetStatusString(statuses.Draft)}}</mat-option>
<mat-option [value]="statuses.Finalized">{{enumUtils.toDatasetStatusString(statuses.Finalized)}}</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field class="col-md-3">
<app-multiple-auto-complete name="datasetCriteriaTags" [(ngModel)]="criteria.tags" (ngModelChange)="controlModified()" placeholder="{{'CRITERIA.DATA-SETS.TAGS' | translate}}"
[configuration]="tagsAutoCompleteConfiguration"></app-multiple-auto-complete>
</mat-form-field>
</div>
</mat-card>
</form> -->

View File

@ -0,0 +1,56 @@
.search ::ng-deep.mat-form-field-infix {
margin-left: 1em;
}
.category-title {
color: black;
// color: #089dbb;
margin-top: 8px;
margin-bottom: 12px;
text-transform: none;
font-size: 1rem;
font-weight: 400;
}
.import {
margin: 10px;
padding: 0px;
}
.filters {
// border: 1px solid #e4e4e4;
// border-radius: 5px;
}
.criteria-title {
color: black;
font-weight: 500;
text-transform: none;
font-size: 1.25rem;
margin-bottom: 1.5em;
opacity: 0.8;
}
.filters-title {
width: 93px;
// color: #089dbb;
color: var(--primary-color-2);
background-color: white;
padding: 0px 20px;
margin-top: -10px;
margin-left: 20px;
text-transform: uppercase;
}
.style-icon {
color: #adadad;
}
::ng-deep .search-form .mat-form-field-wrapper {
background-color: white !important;
padding-bottom: 0 !important;
}
::ng-deep .mat-form-field-appearance-outline .mat-form-field-infix {
padding: 0.3rem 0rem 0.6rem 0rem !important;
}

View File

@ -0,0 +1,339 @@
import { Component, Input, OnInit, Output, EventEmitter } from '@angular/core';
import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { MatSnackBar } from '@angular/material/snack-bar';
import { Router } from '@angular/router';
import { DatasetStatus } from '@app/core/common/enum/dataset-status';
import { DataTableData } from '@app/core/model/data-table/data-table-data';
import { DataTableRequest } from '@app/core/model/data-table/data-table-request';
import { DmpListingModel } from '@app/core/model/dmp/dmp-listing';
import { ExternalSourceItemModel } from '@app/core/model/external-sources/external-source-item';
import { DatasetProfileCriteria } from '@app/core/query/dataset-profile/dataset-profile-criteria';
import { DatasetCriteria } from '@app/core/query/dataset/dataset-criteria';
import { DmpCriteria } from '@app/core/query/dmp/dmp-criteria';
import { GrantCriteria } from '@app/core/query/grant/grant-criteria';
import { OrganisationCriteria } from '@app/core/query/organisation/organisation-criteria';
import { RequestItem } from '@app/core/query/request-item';
import { TagCriteria } from '@app/core/query/tag/tag-criteria';
import { UserCriteria } from '@app/core/query/user/user-criteria';
import { DatasetWizardService } from '@app/core/services/dataset-wizard/dataset-wizard.service';
import { DatasetService } from '@app/core/services/dataset/dataset.service';
import { DmpService } from '@app/core/services/dmp/dmp.service';
import { ExternalSourcesService } from '@app/core/services/external-sources/external-sources.service';
import { GrantService } from '@app/core/services/grant/grant.service';
import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service';
import { OrganisationService } from '@app/core/services/organisation/organisation.service';
import { UserServiceOld } from '@app/core/services/user/user.service-old';
import { EnumUtils } from '@app/core/services/utilities/enum-utils.service';
import { MultipleAutoCompleteConfiguration } from '@app/library/auto-complete/multiple/multiple-auto-complete-configuration';
import { DatasetUploadDialogue } from '@app/ui/dataset/listing/criteria/dataset-upload-dialogue/dataset-upload-dialogue.component';
import { BaseCriteriaComponent } from '@app/ui/misc/criteria/base-criteria.component';
import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model';
import { TranslateService } from '@ngx-translate/core';
import { Observable } from 'rxjs';
import { map, takeUntil } from 'rxjs/operators';
import { AuthService } from '@app/core/services/auth/auth.service';
import { isNullOrUndefined } from '@app/utilities/enhancers/utils';
import { ExploreDmpCriteriaModel } from '@app/core/query/explore-dmp/explore-dmp-criteria';
import { DatasetProfileModel } from '@app/core/model/dataset/dataset-profile';
@Component({
selector: 'app-dataset-criteria-component',
templateUrl: './dataset-criteria.component.html',
styleUrls: ['./dataset-criteria.component.scss']
})
export class DatasetCriteriaComponent extends BaseCriteriaComponent implements OnInit {
@Input() dmpSearchEnabled;
@Input() status;
@Input() isPublic: boolean;
@Input() criteriaFormGroup: UntypedFormGroup;
@Output() filtersChanged: EventEmitter<any> = new EventEmitter();
public criteria: any;
public filteringTagsAsync = false;
public filteredTags: ExternalSourceItemModel[];
statuses = DatasetStatus;
options: UntypedFormGroup;
public formGroup = new UntypedFormBuilder().group({
like: new UntypedFormControl(),
groupIds: new UntypedFormControl(),
grants: new UntypedFormControl(),
status: new UntypedFormControl(),
role: new UntypedFormControl(),
organisations: new UntypedFormControl(),
collaborators: new UntypedFormControl(),
datasetTemplates: new UntypedFormControl(),
tags: new UntypedFormControl(),
allVersions: new UntypedFormControl(),
grantStatus: new UntypedFormControl()
});
tagsAutoCompleteConfiguration = {
filterFn: this.filterTags.bind(this),
initialItems: (excludedItems: any[]) => this.filterTags('').pipe(map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))),
displayFn: (item) => item['name'],
titleFn: (item) => item['name']
};
datasetTemplateAutoCompleteConfiguration: MultipleAutoCompleteConfiguration = {
filterFn: this.filterDatasetTemplate.bind(this),
initialItems: (excludedItems: any[]) => this.filterDatasetTemplate('').pipe(map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))),
displayFn: (item) => item['label'],
titleFn: (item) => item['label'],
subtitleFn: (item) => item['description']
};
dmpAutoCompleteConfiguration = {
filterFn: (x, excluded) => this.filterDmps(x).pipe(map(x => x.data)),
initialItems: (extraData) => this.filterDmps('').pipe(map(x => x.data)),
displayFn: (item) => item['label'],
titleFn: (item) => item['label']
};
collaboratorsAutoCompleteConfiguration: MultipleAutoCompleteConfiguration = {
filterFn: this.filterCollaborators.bind(this),
initialItems: (excludedItems: any[]) => this.filterCollaborators('').pipe(map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))),
displayFn: (item) => item['name'],
titleFn: (item) => item['name']
};
grantAutoCompleteConfiguration: MultipleAutoCompleteConfiguration = {
filterFn: this.filterGrant.bind(this),
initialItems: (excludedItems: any[]) => this.filterGrant('').pipe(map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))),
displayFn: (item) => item['label'],
titleFn: (item) => item['label']
};
organisationAutoCompleteConfiguration: MultipleAutoCompleteConfiguration = {
filterFn: this.filterOrganisations.bind(this),
initialItems: (excludedItems: any[]) => this.filterOrganisations('').pipe(map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))),
displayFn: (item) => item['name'],
titleFn: (item) => item['name']
}
constructor(
private externalSourcesService: ExternalSourcesService,
public enumUtils: EnumUtils,
public dmpService: DmpService,
public datasetWizardService: DatasetWizardService,
private dialog: MatDialog,
private snackBar: MatSnackBar,
private uiNotificationService: UiNotificationService,
private router: Router,
private language: TranslateService,
public grantService: GrantService,
private organisationService: OrganisationService,
private userService: UserServiceOld,
private datasetService: DatasetService,
fb: UntypedFormBuilder,
private authService: AuthService
) {
super(new ValidationErrorModel());
// this.options = fb.group({
// status: new FormControl(),
// floatLabel: 'auto',
// });
}
ngOnInit() {
super.ngOnInit();
// This if is just for passing label on chips of dialog
if (this.formGroup && this.criteriaFormGroup) {
this.formGroup.get('datasetTemplates').setValue(this.criteriaFormGroup.get('datasetTemplates').value);
this.formGroup.get('groupIds').setValue(this.criteriaFormGroup.get('groupIds').value);
this.formGroup.get('grants').setValue(this.criteriaFormGroup.get('grants').value);
this.formGroup.get('collaborators').setValue(this.criteriaFormGroup.get('collaborators').value);
this.formGroup.get('organisations').setValue(this.criteriaFormGroup.get('organisations').value);
this.formGroup.get('tags').setValue(this.criteriaFormGroup.get('tags').value);
}
this.formGroup.get('like').valueChanges
.pipe(takeUntil(this._destroyed))
.subscribe(x => this.controlModified());
this.formGroup.get('groupIds').valueChanges
.pipe(takeUntil(this._destroyed))
.subscribe(x => this.controlModified());
this.formGroup.get('grants').valueChanges
.pipe(takeUntil(this._destroyed))
.subscribe(x => this.controlModified());
this.formGroup.get('status').valueChanges
.pipe(takeUntil(this._destroyed))
.subscribe(x => this.controlModified());
this.formGroup.get('role').valueChanges
.pipe(takeUntil(this._destroyed))
.subscribe(x => this.controlModified());
this.formGroup.get('organisations').valueChanges
.pipe(takeUntil(this._destroyed))
.subscribe(x => this.controlModified());
this.formGroup.get('collaborators').valueChanges
.pipe(takeUntil(this._destroyed))
.subscribe(x => this.controlModified());
this.formGroup.get('datasetTemplates').valueChanges
.pipe(takeUntil(this._destroyed))
.subscribe(x => this.controlModified());
this.formGroup.get('allVersions').valueChanges
.pipe(takeUntil(this._destroyed))
.subscribe(x => this.controlModified());
this.formGroup.get('tags').valueChanges
.pipe(takeUntil(this._destroyed))
.subscribe(x => this.controlModified());
this.formGroup.get('grantStatus').valueChanges
.pipe(takeUntil(this._destroyed))
.subscribe(x => this.controlModified());
// if (this.criteria == null) { this.criteria = {}; }
// this.formGroup.patchValue({'status': this.status !== undefined ? this.status : 'null'});
}
setCriteria(criteria: DatasetCriteria): void {
this.formGroup.get('like').patchValue(criteria.like);
this.formGroup.get('groupIds').patchValue(criteria.groupIds);
this.formGroup.get('grants').patchValue(criteria.grants);
this.formGroup.get('status').patchValue(criteria.status);
this.formGroup.get('role').patchValue(criteria.role);
this.formGroup.get('collaborators').patchValue(criteria.collaborators);
this.formGroup.get('datasetTemplates').patchValue(criteria.datasetTemplates);
this.formGroup.get('allVersions').patchValue(criteria.allVersions);
this.formGroup.get('tags').patchValue(criteria.tags);
this.formGroup.get('grantStatus').patchValue(criteria.grantStatus);
// this.criteria = criteria;
}
controlModified(): void {
this.clearErrorModel();
this.filtersChanged.emit();
if (this.refreshCallback != null &&
(this.formGroup.get('like').value == null || this.formGroup.get('like').value.length === 0 || this.formGroup.get('like').value.length > 2)
) {
setTimeout(() => this.refreshCallback(true));
}
// if (this.refreshCallback != null &&
// (this.criteria.like == null || this.criteria.like.length === 0 || this.criteria.like.length > 2)
// ) {
// this.refreshCallback();
// }
}
filterTags(value: string): Observable<ExternalSourceItemModel[]> {
this.filteredTags = undefined;
this.filteringTagsAsync = true;
const requestItem: RequestItem<TagCriteria> = new RequestItem();
const criteria: TagCriteria = new TagCriteria();
criteria.like = value;
requestItem.criteria = criteria;
return this.externalSourcesService.searchDatasetTags(requestItem);
}
filterDatasetTemplate(query: string): Observable<any[]> {
const fields: Array<string> = new Array<string>();
fields.push('asc');
const datasetTemplateRequestItem: DataTableRequest<DatasetProfileCriteria> = new DataTableRequest(0, null, { fields: fields });
datasetTemplateRequestItem.criteria = new DatasetProfileCriteria();
datasetTemplateRequestItem.criteria.like = query;
if (this.isPublic) {
return this.datasetService.getDatasetProfiles(datasetTemplateRequestItem);
} else {
return this.datasetService.getDatasetProfilesUsedPaged(datasetTemplateRequestItem).pipe(map(x => x.data));
}
}
filterDmps(value: string): Observable<DataTableData<DmpListingModel>> {
const fields: Array<string> = new Array<string>();
fields.push('asc');
// if (this.isPublic) {
// const dmpDataTableRequest: DataTableRequest<ExploreDmpCriteriaModel> = new DataTableRequest(0, null, { fields: fields });
// dmpDataTableRequest.criteria = new ExploreDmpCriteriaModel();
// dmpDataTableRequest.criteria.like = value;
// return this.dmpService.getPublicPaged(dmpDataTableRequest, "autocomplete");
// } else {
const dmpDataTableRequest: DataTableRequest<DmpCriteria> = new DataTableRequest(0, null, { fields: fields });
dmpDataTableRequest.criteria = new DmpCriteria();
dmpDataTableRequest.criteria.like = value;
if (this.isPublic) {
dmpDataTableRequest.criteria.isPublic = true;
dmpDataTableRequest.criteria.onlyPublic = true;
}
return this.dmpService.getPaged(dmpDataTableRequest, "autocomplete");
// }
}
filterGrant(query: string) {
const fields: Array<string> = new Array<string>();
fields.push('asc');
const grantRequestItem: DataTableRequest<GrantCriteria> = new DataTableRequest(0, null, { fields: fields });
grantRequestItem.criteria = new GrantCriteria();
grantRequestItem.criteria.like = query;
if (this.isPublic) {
return this.grantService.getPublicPaged(grantRequestItem).pipe(map(x => x.data));
} else {
return this.grantService.getPaged(grantRequestItem, "autocomplete").pipe(map(x => x.data));
}
}
filterOrganisations(value: string) {
const fields: Array<string> = new Array<string>();
fields.push('asc');
const dataTableRequest: DataTableRequest<OrganisationCriteria> = new DataTableRequest(0, null, { fields: fields });
dataTableRequest.criteria = new OrganisationCriteria();
dataTableRequest.criteria.labelLike = value;
if (this.isPublic) {
return this.organisationService.searchPublicOrganisations(dataTableRequest).pipe(map(x => x.data));
} else {
return this.organisationService.searchInternalOrganisations(dataTableRequest).pipe(map(x => x.data));
}
}
filterCollaborators(query: string) {
const fields: Array<string> = new Array<string>();
fields.push('asc');
const collaboratorsRequestItem: DataTableRequest<UserCriteria> = new DataTableRequest(0, null, { fields: fields });
collaboratorsRequestItem.criteria = new UserCriteria();
collaboratorsRequestItem.criteria.collaboratorLike = query;
return this.userService.getCollaboratorsPaged(collaboratorsRequestItem).pipe(map(x => x.data));
}
fileImport(event) {
const dialogRef = this.dialog.open(DatasetUploadDialogue, {
data: {
fileList: FileList,
success: Boolean,
datasetTitle: String,
dmpId: String,
datasetProfileId: String,
dmpSearchEnabled: this.dmpSearchEnabled,
criteria: this.criteria
}
});
dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => {
if (result && result.success) {
this.datasetWizardService.uploadXml(result.fileList, result.datasetTitle, result.dmpId, result.datasetProfileId)
.pipe(takeUntil(this._destroyed))
.subscribe(
complete => this.onCallbackSuccess(),
error => this.onCallbackError(error)
);
}
})
}
onCallbackSuccess(): void {
this.uiNotificationService.snackBarNotification(this.language.instant('DATASET-UPLOAD.SNACK-BAR.SUCCESSFUL-CREATION'), SnackBarNotificationLevel.Success);
this.router.navigate(['/plans']);
}
onCallbackError(error: any) {
this.uiNotificationService.snackBarNotification(this.language.instant('DATASET-UPLOAD.SNACK-BAR.UNSUCCESSFUL'), SnackBarNotificationLevel.Success);
}
isAuthenticated(): boolean {
return this.authService.currentAccountIsAuthenticated();
}
}

View File

@ -0,0 +1,42 @@
<div class="confirmation-dialog">
<div class="row">
<div class="confirmation-message col align-self-center">
<h4>{{'DATASET-UPLOAD.TITLE' | translate}}</h4>
</div>
<div class="col-auto">
<button mat-icon-button class="col-auto" (click)="fileInput.click()" type="button">
<mat-icon color="primary">attach_file</mat-icon>
</button>
<input class="hidden" #fileInput type="file" (change)="uploadFile($event)" accept="text/xml">
</div>
</div>
<div class="row">
<mat-form-field class="col-12">
<input class="uploadInput" [(ngModel)]="datasetTitle" [disabled]="disableDatasetName()" matInput placeholder="{{'DATASET-UPLOAD.PLACEHOLDER' | translate}}"
name="uploadFileInput">
</mat-form-field>
<mat-form-field class="col-12">
<app-single-auto-complete [required]="true" [(ngModel)]="dmp" (ngModelChange)="controlModified()" placeholder="{{'CRITERIA.DMP.LIKE' | translate}}"
[configuration]="dmpAutoCompleteConfiguration" [disabled]="disableDmpSearch()">
</app-single-auto-complete>
</mat-form-field>
<mat-form-field class="col-md-12">
<mat-select placeholder=" {{'DATASET-UPLOAD.DATASET-PROFILE.SELECT'| translate}}" [required]="true" [(value)]="datasetProfile"
[disabled]="disableDatasetProfile()">
<mat-option *ngFor="let datasetProfile of availableProfiles" [value]="datasetProfile">
{{datasetProfile.label}}
</mat-option>
</mat-select>
</mat-form-field>
<div class="col-auto">
<button mat-raised-button type="button" (click)="cancel()">{{'DATASET-UPLOAD.ACTIONS.CANCEL' | translate}}</button>
</div>
<div class="col"></div>
<div class="col-auto">
<button mat-raised-button color="primary" type="button" (click)="confirm()" [disabled]="disableButton()">{{'DATASET-UPLOAD.ACTIONS.IMPORT' | translate}}</button>
</div>
</div>
</div>

View File

@ -0,0 +1,21 @@
.confirmation-dialog {
.confirmation-message {
padding-bottom: 20px;
}
.hidden {
display: none;
}
.uploadButton {
float: right;
}
.col-md-6 {
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: center;
margin: -4px;
}
}

View File

@ -0,0 +1,157 @@
import { Component, Inject, OnInit } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { DataTableData } from '@app/core/model/data-table/data-table-data';
import { DataTableRequest } from '@app/core/model/data-table/data-table-request';
import { DatasetProfileModel } from '@app/core/model/dataset/dataset-profile';
import { DmpModel } from '@app/core/model/dmp/dmp';
import { DmpListingModel } from '@app/core/model/dmp/dmp-listing';
import { DatasetProfileCriteria } from '@app/core/query/dataset-profile/dataset-profile-criteria';
import { DatasetCriteria } from '@app/core/query/dataset/dataset-criteria';
import { DmpCriteria } from '@app/core/query/dmp/dmp-criteria';
import { RequestItem } from '@app/core/query/request-item';
import { DatasetWizardService } from '@app/core/services/dataset-wizard/dataset-wizard.service';
import { DmpService } from '@app/core/services/dmp/dmp.service';
import { BaseCriteriaComponent } from '@app/ui/misc/criteria/base-criteria.component';
import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model';
import { Observable } from 'rxjs';
import { map, takeUntil } from 'rxjs/operators';
@Component({
selector: 'dataset-upload-dialogue',
templateUrl: './dataset-upload-dialogue.component.html',
styleUrls: ['./dataset-upload-dialogue.component.scss']
})
export class DatasetUploadDialogue extends BaseCriteriaComponent implements OnInit {
public dialogueCriteria: any;
datasetTitle: string;
dmp: DmpModel;
datasetProfile: DatasetProfileModel;
availableProfiles: DatasetProfileModel[] = [];
dmpAutoCompleteConfiguration = {
filterFn: (x, excluded) => this.filterDmps(x).pipe(map(x => x.data)),
initialItems: (extraData) => this.filterDmps('').pipe(map(x => x.data)),
displayFn: (item) => item['label'],
titleFn: (item) => item['label']
};
constructor(
public dialogRef: MatDialogRef<DatasetUploadDialogue>,
public dmpService: DmpService,
private datasetWizardService: DatasetWizardService,
@Inject(MAT_DIALOG_DATA) public data: any,
) { super(new ValidationErrorModel()); }
ngOnInit() {
super.ngOnInit();
if (this.dialogueCriteria == null) { this.dialogueCriteria = {}; }
if (!this.data.dmpSearchEnabled) {
this.dialogueCriteria = this.data.criteria;
this.dmp = this.dialogueCriteria.dmpIds[0];
this.loadDatasetProfiles();
}
}
cancel() {
this.data.success = false;
this.dialogRef.close(this.data)
}
confirm() {
this.data.success = true;
this.data.datasetTitle = this.datasetTitle;
this.data.dmpId = this.dmp.id;
this.data.datasetProfileId = this.datasetProfile.id;
this.dialogRef.close(this.data);
}
uploadFile(event) {
const fileList: FileList = event.target.files
this.data.fileList = fileList;
if (this.data.fileList.length > 0) {
this.datasetTitle = fileList.item(0).name;
}
}
filterDmps(value: string): Observable<DataTableData<DmpListingModel>> {
const fields: Array<string> = new Array<string>();
fields.push('asc');
const dmpDataTableRequest: DataTableRequest<DmpCriteria> = new DataTableRequest(0, null, { fields: fields });
dmpDataTableRequest.criteria = new DmpCriteria();
dmpDataTableRequest.criteria.like = value;
return this.dmpService.getPaged(dmpDataTableRequest, "autocomplete");
}
controlModified(): void {
this.loadDatasetProfiles();
if (!this.dmp) {
this.availableProfiles = [];
}
this.clearErrorModel();
if (this.refreshCallback != null &&
(this.dialogueCriteria.like == null || this.dialogueCriteria.like.length === 0 || this.dialogueCriteria.like.length > 2)
) {
this.refreshCallback();
}
}
loadDatasetProfiles() {
const datasetProfileRequestItem: RequestItem<DatasetProfileCriteria> = new RequestItem();
datasetProfileRequestItem.criteria = new DatasetProfileCriteria();
if (this.dmp) {
datasetProfileRequestItem.criteria.id = this.dmp.id;
}
if (datasetProfileRequestItem.criteria.id) {
this.datasetWizardService.getAvailableProfiles(datasetProfileRequestItem)
.pipe(takeUntil(this._destroyed))
.subscribe(items => {
this.availableProfiles = items;
if (this.availableProfiles.length === 1) {
this.datasetProfile = this.availableProfiles[0];
}
});
}
}
setCriteriaDialogue(criteria: DatasetCriteria): void {
this.dialogueCriteria = criteria;
}
disableButton() {
if (!(this.data.fileList.length > 0) || !this.dmp) {
return true;
}
else {
return false;
}
}
disableDatasetName() {
if (!(this.data.fileList.length > 0)) {
return true;
}
else {
return false;
}
}
disableDmpSearch() {
if (!(this.data.fileList.length > 0) || !this.data.dmpSearchEnabled) {
return true;
}
else {
return false;
}
}
disableDatasetProfile() {
if (!this.dmp || (!this.data.dmpSearchEnabled && !(this.data.fileList.length > 0)) || (!this.data.dmpSearchEnabled && this.availableProfiles.length === 1)) {
return true;
}
else {
return false;
}
}
}

View File

@ -0,0 +1,78 @@
<div class="main-content listing-main-container h-100">
<div class="container-fluid">
<div class="d-flex flex-direction-row">
<div *ngIf="hasListingItems && listingItems && listingItems.length === 0 && !hasLikeCriteria()" class="card mt-0">
<!-- <div class="card mt-0" [style.display]="isVisible ? 'block' : 'none'"> -->
<!-- <a class="col-auto d-flex" (click)="closeCard()"><span class="ml-auto pt-3 material-icons clear-icon">clear</span></a> -->
<div class="card-content info-text mb-0">
<p>{{'DATASET-LISTING.TEXT-INFO' | translate}} <u class="pointer" [routerLink]="['/explore']">{{'DATASET-LISTING.LINK-PUBLIC-DATASETS' | translate}}</u> {{'DATASET-LISTING.TEXT-INFO-REST' | translate}}</p>
<p class="mt-4 pt-2">{{'DATASET-LISTING.TEXT-INFO-PAR' | translate}}
<div class="d-flex">
<button mat-raised-button class="add-description align-self-center yellow-btn" (click)="addNewDescription()">
{{'DASHBOARD.ACTIONS.ADD-DESCRIPTION' | translate}}
</button>
<img class="col-auto ml-auto laptop-img" src="../../../assets/images/dashboard-popup.png">
</div>
</div>
</div>
<p *ngIf="listingItems && listingItems.length > 0 || this.lookup.like" class="col-auto header-title">{{(isPublic ? 'GENERAL.TITLES.EXPLORE' : 'GENERAL.TITLES.DESCRIPTIONS') | translate}}</p>
<div *ngIf="listingItems && listingItems.length > 0 && !isPublic || this.lookup.like" class="ml-auto">
<div class="col-auto">
<button mat-raised-button class="add-description align-self-center yellow-btn" (click)="addNewDescription()">
{{'DASHBOARD.ACTIONS.ADD-DESCRIPTION' | translate}}
</button>
</div>
</div>
<div *ngIf="listingItems && listingItems.length > 0 || this.lookup.like" class="filter-btn" [style.right]="dialog.getDialogById('filters') ? '446px' : '0px'" [style.width]="scrollbar ? '57px' : '37px'" (click)="openFiltersDialog()">
<button mat-raised-button class="p-0">
<mat-icon class="mr-4">filter_alt</mat-icon>
</button>
</div>
</div>
<div>
<div class="listing row pb-2">
<div *ngIf="listingItems && listingItems.length > 0 || this.lookup.like" class="col-md-12">
<div class="d-flex flex-direction-row pt-4">
<!-- Sort by -->
<span class="d-flex align-items-center">{{'DMP-LISTING.SORT-BY' | translate}}:</span>
<mat-form-field class="sort-form col-auto pr-0">
<mat-select placeholder="{{'CRITERIA.LIKE'| translate}}" [formControl]="formGroup.get('order')">
<mat-option *ngIf="!isPublic" [value]="order.MODIFIED">{{enumUtils.toRecentActivityOrderString(order.MODIFIED)}}</mat-option>
<mat-option *ngIf="isPublic" [value]="order.DATASETPUBLISHED">{{enumUtils.toRecentActivityOrderString(order.DATASETPUBLISHED)}}</mat-option>
<mat-option [value]="order.LABEL">{{enumUtils.toRecentActivityOrderString(order.LABEL)}}</mat-option>
<mat-option *ngIf="!isPublic" [value]="order.STATUS">{{enumUtils.toRecentActivityOrderString(order.STATUS)}}</mat-option>
<!-- <mat-option [value]="order.CREATED">{{enumUtils.toRecentActivityOrderString(order.CREATED)}}</mat-option> -->
</mat-select>
</mat-form-field>
<!-- End of Sort by -->
<div class="d-flex flex-row ml-auto">
<!-- Guided Tour -->
<div *ngIf="!isPublic" class="center-content" (click)="restartTour()">
{{ 'GENERAL.ACTIONS.TAKE-A-TOUR'| translate }}
</div>
<!-- End of Guided Tour -->
<!-- Search Filter-->
<mat-form-field class="search-form ml-auto col-auto" floatLabel="never">
<mat-icon matSuffix>search</mat-icon>
<input matInput placeholder="{{'CRITERIA.DATA-SETS.LIKE'| translate}}" name="likeCriteria" [formControl]="formGroup.get('like')">
<mat-error *ngIf="formGroup.get('like').hasError('backendError')">{{formGroup.get('like').getError('backendError').message}}</mat-error>
</mat-form-field>
<!-- End of Search Filter -->
</div>
</div>
</div>
<div class="col-md-12 col-sm-12 col-md-9">
<div *ngFor="let item of listingItems; let i = index">
<app-description-listing-item-component [isPublic]="isPublic" [description]="item" [showDivider]="i != (listingItems.length - 1)"></app-description-listing-item-component>
</div>
<div *ngIf="listingItems && listingItems.length > 0 && this.lookup?.page?.offset < this.totalCount - 1 && this.pageSize < this.totalCount - 1" class="d-flex justify-content-center">
<button type="button" class="btn-load-more" (click)="loadMore()">{{'GENERAL.ACTIONS.LOAD-MORE' | translate}}</button>
</div>
</div>
<div *ngIf="hasListingItems && listingItems && listingItems.length === 0 && this.lookup.like !== ''" class="col-md-12 d-flex justify-content-center pt-4 mt-4 mb-4 pb-4">
<span class="empty-list">{{'DATASET-LISTING.EMPTY-LIST' | translate}}</span>
</div>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,265 @@
@import "node_modules/bootstrap/scss/functions";
@import "node_modules/bootstrap/scss/variables";
@import "node_modules/bootstrap/scss/mixins/_breakpoints";
@include media-breakpoint-down(sm) {
.lightblue-btn {
font-size: 12px;
}
::ng-deep .mat-paginator-container {
height: auto !important;
}
}
.header-image {
background: url("/assets/images/new-dashboard-bg.png") no-repeat;
background-size: cover;
margin-top: 70px;
min-height: 15em;
position: relative;
}
.header-title {
text-align: left;
font-size: 1.25rem;
font-weight: 300;
color: #212121;
padding: 0px;
}
.header-text-container {
background: rgba(255, 255, 255, 0.7);
position: absolute;
bottom: 0px;
padding-left: 5em;
padding-right: 10em;
padding-top: 2em;
padding-bottom: 2em;
}
.explore-dmp-content {
padding: 30px 15px;
}
.main-content {
background-color: #f5f5f5;
padding-top: 4.68rem;
padding-bottom: 3rem;
padding-left: 3rem;
padding-right: 3rem;
margin: 0;
display: flex;
flex-grow: 1;
}
.card {
background: #ffffff 0% 0% no-repeat padding-box;
box-shadow: 0px 3px 6px #00000029;
border-radius: 4px;
// width: 987px;
margin-bottom: 3.75rem;
/* height: 407px; */
opacity: 1;
}
.card-title {
text-align: left;
font: Bold 20px/30px Roboto;
letter-spacing: 0px;
color: #212121;
padding-left: 40px;
/* padding-top: 40px; */
padding-right: 55px;
opacity: 1;
}
.card-content {
text-align: left;
font-weight: 300;
letter-spacing: 0px;
color: #212121;
padding-left: 40px;
padding-top: 36px;
// padding-bottom: 36px;
padding-right: 55px;
opacity: 1;
}
.clear-icon {
cursor: pointer;
color: #212121;
padding: 0.4rem;
}
.clear-icon:hover {
background-color: #ececec !important;
border-radius: 50%;
padding: 0.4rem;
}
.normal-btn {
min-width: 162px;
max-width: 256px;
height: 40px;
cursor: pointer;
background: var(--primary-color) 0% 0% no-repeat padding-box;
box-shadow: 0px 3px 6px #1e202029;
border-radius: 30px;
border: none;
color: #ffffff;
opacity: 1;
line-height: 1;
font-size: 0.87rem;
padding: 0.62rem 1.87rem;
margin-left: 40px;
}
.yellow-btn {
min-width: 162px;
max-width: 256px;
height: 40px;
cursor: pointer;
background: var(--secondary-color) 0% 0% no-repeat padding-box;
border-radius: 30px;
opacity: 1;
border: none;
color: #000000;
opacity: 1;
line-height: 1;
font-size: 0.87rem;
padding: 0.62rem 1.87rem;
font-weight: 700;
}
.info-text {
text-align: left;
font-weight: 300;
font-size: 1rem;
letter-spacing: 0px;
color: #212121;
}
.filter-btn {
position: fixed;
right: 0px;
z-index: 100;
width: 37px;
}
.filter-btn button {
color: white;
background-color: var(--primary-color-2);
width: 37px;
height: 45px;
}
.center-content {
width: 100%;
min-width: 10rem;
margin: auto;
padding: 0 15px;
text-align: right;
font-size: 0.875rem;
font-weight: 600;
letter-spacing: 0.02rem;
color: #2d72d6;
cursor: pointer;
}
.search-form {
// font-size: 12px;
text-align: left;
width: 20rem;
}
.search-form mat-icon {
color: var(--primary-color);
}
.empty-list {
text-align: center;
font-weight: 300;
font-size: 1.25rem;
letter-spacing: 0px;
color: #212121;
opacity: 0.6;
}
.pointer:hover {
color: var(--primary-color-3);
}
::ng-deep .search-form .mat-form-field-wrapper {
background-color: white !important;
padding-bottom: 0 !important;
}
::ng-deep .sort-form .mat-form-field-wrapper {
background-color: white !important;
padding-bottom: 0 !important;
}
:host ::ng-deep .mat-form-field-appearance-outline .mat-form-field-infix {
padding: 0.3rem 0rem 0.6rem 0rem !important;
}
:host ::ng-deep .mat-paginator-container {
flex-direction: row-reverse !important;
justify-content: space-between !important;
background-color: #f6f6f6;
height: 30px;
min-height: 30px !important;
}
:host ::ng-deep .mat-paginator-page-size {
height: 43px;
}
:host ::ng-deep .mat-icon-button {
height: 30px !important;
font-size: 12px !important;
}
:host ::ng-deep .mat-paginator-range-label {
margin: 15px 32px 0 24px !important;
}
:host ::ng-deep .mat-paginator-range-actions {
width: auto !important;
min-width: 55% !important;
min-height: 43px !important;
justify-content: space-between;
}
:host ::ng-deep .mat-paginator-navigation-previous {
margin-left: auto !important;
}
::ng-deep .mat-ripple-element {
background-color: #2e74b649 !important;
}
::ng-deep .mat-radio-container {
border-radius: 1em;
background: white;
}
::ng-deep .mat-radio-button .mat-radio-outer-circle {
border: 1px solid #aaaaaa;
}
::ng-deep .mat-radio-button.mat-accent.mat-radio-checked .mat-radio-outer-circle {
border-color: #777777;
// border-color: var(--primary-color-3);
}
::ng-deep .mat-radio-button.mat-accent .mat-radio-inner-circle {
// color: var(--primary-color-3);
// background-color: var(--primary-color-3);
color: #777777;
background-color: #777777;
}
.mat-radio-button.mat-accent .mat-radio-ripple .mat-ripple-element {
background-color: #2e74b649;
}

View File

@ -0,0 +1,321 @@
import { HttpClient } from '@angular/common/http';
import { Component, OnInit, ViewChild } from '@angular/core';
import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { MatPaginator } from '@angular/material/paginator';
import { MatSort } from '@angular/material/sort';
import { ActivatedRoute, Params, Router } from '@angular/router';
import { DescriptionStatus } from '@app/core/common/enum/description-status';
import { RecentActivityOrder } from '@app/core/common/enum/recent-activity-order';
import { DataTableRequest } from '@app/core/model/data-table/data-table-request';
import { Description } from '@app/core/model/description/description';
import { DescriptionLookup } from '@app/core/query/description.lookup';
import { DmpLookup } from '@app/core/query/dmp.lookup';
import { AuthService } from '@app/core/services/auth/auth.service';
import { DescriptionService } from '@app/core/services/description/description.service';
import { DmpService } from '@app/core/services/dmp/dmp.service';
import { MatomoService } from '@app/core/services/matomo/matomo-service';
import { EnumUtils } from '@app/core/services/utilities/enum-utils.service';
import { GuidedTour, Orientation } from '@app/library/guided-tour/guided-tour.constants';
import { GuidedTourService } from '@app/library/guided-tour/guided-tour.service';
import { StartNewDmpDialogComponent } from '@app/ui/dmp/start-new-dmp-dialogue/start-new-dmp-dialog.component';
// import { IBreadCrumbComponent } from '@app/ui/misc/breadcrumb/definition/IBreadCrumbComponent';
// import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item';
import { isNullOrUndefined } from '@app/utilities/enhancers/utils';
import { BaseComponent } from '@common/base/base.component';
import { Guid } from '@common/types/guid';
import { TranslateService } from '@ngx-translate/core';
import { Observable, of as observableOf } from 'rxjs';
import { debounceTime, takeUntil } from 'rxjs/operators';
import { nameof } from 'ts-simple-nameof';
@Component({
selector: 'app-description-listing-component',
templateUrl: 'description-listing.component.html',
styleUrls: ['./description-listing.component.scss']
})
export class DescriptionListingComponent extends BaseComponent implements OnInit {//IBreadCrumbComponent
@ViewChild(MatPaginator, { static: true }) _paginator: MatPaginator;
@ViewChild(MatSort) sort: MatSort;
// @ViewChild(DescriptionCriteriaComponent, { static: true }) criteria: DescriptionCriteriaComponent;
// breadCrumbs: Observable<BreadcrumbItem[]>;
titlePrefix: String;
dmpId: string;
status: Number;
totalCount: number;
dmpSearchEnabled = true;
listingItems: Description[] = [];
hasListingItems = null;
isPublic: boolean = false;
public isVisible = true
pageSize: number = 5;
lookup: DescriptionLookup = new DescriptionLookup();
criteriaFormGroup: UntypedFormGroup;
public formGroup = new UntypedFormBuilder().group({
like: new UntypedFormControl(),
order: new UntypedFormControl()
});
scrollbar: boolean;
order = RecentActivityOrder;
dmpText: string;
descriptionText: string;
constructor(
private descriptionService: DescriptionService,
private router: Router,
private route: ActivatedRoute,
public dialog: MatDialog,
private dmpService: DmpService,
private language: TranslateService,
private authService: AuthService,
public enumUtils: EnumUtils,
private authentication: AuthService,
private guidedTourService: GuidedTourService,
private httpClient: HttpClient,
private matomoService: MatomoService
) {
super();
}
ngOnInit() {
this.matomoService.trackPageView('Descriptions');
this.isPublic = this.router.url === '/explore';
if (this.isPublic) {
this.formGroup.get('order').setValue(this.order.DATASETPUBLISHED);
} else {
this.formGroup.get('order').setValue(this.order.MODIFIED);
}
if (!this.isPublic && !this.authService.currentAccountIsAuthenticated()) {
this.router.navigateByUrl("/explore");
}
this.route.params
.pipe(takeUntil(this._destroyed))
.subscribe(async (params: Params) => {
const queryParams = this.route.snapshot.queryParams;
this.dmpId = queryParams['dmpId'];
this.status = queryParams['status'];
this.lookup.page = { size: this.pageSize, offset: 0 };
this.lookup.order = { items: ['-' + nameof<Description>(x => x.updatedAt)] };
if (this.dmpId != null && Guid.isGuid(this.dmpId)) {
this.dmpSearchEnabled = false;
//const dmp = await this.dmpService.getSingle(this.dmpId).toPromise();
this.lookup.dmpSubQuery = new DmpLookup();
this.lookup.dmpSubQuery.ids = [Guid.parse(this.dmpId)];
this.refresh(this.lookup);
if (params['dmpLabel'] !== undefined) {
this.titlePrefix = 'for ' + params['dmpLabel'];
}
}
if (this.status != null && this.status == DescriptionStatus.Draft) { //TODO: chack if actually used
this.lookup.statuses = [DescriptionStatus.Draft]
}
this.refresh(this.lookup);
});
this.formGroup.get('like').valueChanges
.pipe(takeUntil(this._destroyed), debounceTime(500))
.subscribe(x => this.controlModified());
this.formGroup.get('order').valueChanges
.pipe(takeUntil(this._destroyed))
.subscribe(x => {
const fields: Array<string> = [((this.formGroup.get('order').value === 'status') || (this.formGroup.get('order').value === 'label') ? '' : "-") + this.formGroup.get('order').value];
this.lookup.order = { items: fields };
this.lookup.page = { size: this.pageSize, offset: 0 };
this.refresh(this.lookup);
});
}
ngAfterContentChecked(): void {
this.scrollbar = this.hasScrollbar();
}
public dashboardTour: GuidedTour = {
tourId: 'dmp-description-tour',
useOrb: true,
steps: [
{
selector: '.dmp-tour',
content: 'Step 1',
orientation: Orientation.Right,
isStepUnique: false
},
{
selector: '.description-tour',
content: 'Step 2',
orientation: Orientation.Right,
isStepUnique: false
}
]
};
public isAuthenticated(): boolean {
return this.authService.currentAccountIsAuthenticated();
}
controlModified(): void {
this.lookup.like = this.formGroup.get("like").value;
this.lookup.page = { size: this.pageSize, offset: 0 };
this.refresh(this.lookup);
}
refresh(lookup: DescriptionLookup) {
lookup.project = {
fields: [
nameof<Description>(x => x.id),
nameof<Description>(x => x.label),
]
};
this.descriptionService.query(lookup).pipe(takeUntil(this._destroyed))
.subscribe(result => {
if (!result) { return []; }
// if (this._paginator.pageIndex === 0) { this.totalCount = result.totalCount; }
this.totalCount = result.count;
if (lookup?.page?.offset === 0) this.listingItems = [];
this.listingItems = result.items;
this.hasListingItems = true;
});
}
openFiltersDialog(): void {
//TODO: Add filters dialog
// const dialogRef = this.dialog.open(DescriptionCriteriaDialogComponent, {
// width: '456px',
// height: '100%',
// id: 'filters',
// restoreFocus: false,
// data: {
// isPublic: this.isPublic,
// status: this.status,
// criteria: this.criteria,
// formGroup: this.criteriaFormGroup,
// // criteria: this.grantId ? this.criteria : this.getDefaultCriteria(),
// updateDataFn: this.updateDataFn.bind(this)
// },
// position: { right: '0px;' },
// panelClass: 'dialog-side-panel'
// });
// dialogRef.afterClosed().subscribe(result => {
// });
}
// updateDataFn(criteria: DescriptionCriteriaComponent): void {
// this.criteriaFormGroup = criteria.formGroup;
// this.toDescriptionCriteria(criteria);
// this.refresh();
// }
// toDescriptionCriteria(criteria: DescriptionCriteriaComponent) {
// let formGroup = criteria.formGroup;
// this.criteria = {
// like: formGroup.get("like").value,
// status: formGroup.get("status").value,
// allVersions: formGroup.get("allVersions").value,
// role: formGroup.get("role").value
// }
// if (formGroup.get("tags") && formGroup.get("tags").value) {
// this.criteria.tags = formGroup.get("tags").value.map(x => (<ExternalTagEditorModel>x));
// }
// if (formGroup.get("collaborators") && formGroup.get("collaborators").value) {
// this.criteria.collaborators = formGroup.get("collaborators").value.map(x => x.id);
// }
// if (formGroup.get("dmpIds") && formGroup.get("dmpIds").value) {
// this.criteria.dmpIds = formGroup.get("dmpIds").value.map(x => x.id);
// }
// if (formGroup.get("groupIds") && formGroup.get("groupIds").value) {
// this.criteria.groupIds = formGroup.get("groupIds").value.map(x => x.groupId);
// }
// if (formGroup.get("grants") && formGroup.get("grants").value) {
// this.criteria.grants = formGroup.get("grants").value.map(x => x.id);
// }
// if (formGroup.get("organisations") && formGroup.get("organisations").value) {
// this.criteria.organisations = formGroup.get("organisations").value.map(x => x.id);
// }
// if (formGroup.get("descriptionTemplates") && formGroup.get("descriptionTemplates").value) {
// this.criteria.descriptionTemplates = formGroup.get("descriptionTemplates").value.map(x => x.id)
// }
// if (formGroup.get("grantStatus") && formGroup.get("grantStatus").value) {
// this.criteria.grantStatus = formGroup.get("grantStatus").value;
// }
// this.criteria.isPublic = this.isPublic;
// }
hasScrollbar(): boolean {
return document.getElementById("main-page").scrollHeight > document.documentElement.clientHeight
}
public restartTour(): void {
this.setDashboardTourDmpText();
this.setDashboardTourDescriptionText();
this.guidedTourService.startTour(this.dashboardTour);
}
public setDashboardTourDmpText(): void {
this.dmpText = this.language.instant('DMP-LISTING.TEXT-INFO') + '\n\n' +
this.language.instant('DMP-LISTING.TEXT-INFO-QUESTION') + ' ' +
this.language.instant('DMP-LISTING.LINK-ZENODO') + ' ' +
this.language.instant('DMP-LISTING.GET-IDEA');
this.dashboardTour.steps[0].title = this.dmpText;
}
public setDashboardTourDescriptionText(): void {
this.descriptionText = this.language.instant('DATASET-LISTING.TEXT-INFO') +
this.language.instant('DATASET-LISTING.LINK-PUBLIC-DATASETS') + ' ' +
this.language.instant('DATASET-LISTING.TEXT-INFO-REST') + '\n\n' +
this.language.instant('DATASET-LISTING.TEXT-INFO-PAR');
this.dashboardTour.steps[1].title = this.descriptionText;
}
openNewDmpDialog() {
if (this.dialog.openDialogs.length > 0) {
this.dialog.closeAll();
}
else {
const dialogRef = this.dialog.open(StartNewDmpDialogComponent, {
disableClose: false,
data: {
isDialog: true
}
});
}
}
addNewDescription() {
//TODO: Add new description dialog
// const dialogRef = this.dialog.open(StartNewDescriptionDialogComponent, {
// disableClose: false,
// restoreFocus: false,
// data: {
// startNewDmp: false,
// formGroup: new DescriptionWizardEditorModel().buildForm()
// }
// });
// dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => {
// if (result) {
// if (result.startNewDmp) {
// this.openNewDmpDialog();
// } else {
// this.router.navigate(['/plans', 'edit', result.formGroup.get('dmp').value.id]);
// }
// }
// });
}
hasLikeCriteria(): boolean {
return this.lookup.like !== undefined && this.lookup.like !== null;
}
}

View File

@ -0,0 +1,55 @@
<div class="description-card">
<a [routerLink]="getItemLink()" class="pointer">
<div class="d-flex flex-direction-row">
<div class="col-auto description-label">{{'DATASET-LISTING.DESCRIPTION' | translate}}</div>
<div *ngIf="!isPublic" class="col-auto ml-auto edited-date">{{'DATASET-LISTING.STATES.EDITED' | translate}}: {{description.modified | dateTimeCultureFormatter: "d MMMM y"}}</div>
<div *ngIf="isPublic" class="col-auto ml-auto edited-date">{{'DATASET-LISTING.STATES.PUBLISHED' | translate}}: {{description.dmpPublishedAt | dateTimeCultureFormatter: "d MMMM y"}}</div>
</div>
<div *ngIf="description.status === 1" class="col-auto description-title">{{description.label}}</div>
<div *ngIf="description.status === 0" class="col-auto description-title-draft">{{description.label}}</div>
<div class="description-subtitle">
<span *ngIf="isUserDescriptionRelated()" class="col-auto">{{ roleDisplay(description.users) }}</span>
<span *ngIf="isUserDescriptionRelated()">.</span>
<!-- <span class="col-auto" *ngIf="description.status === 1 && description.public === true"><span class="material-icons icon-align">public</span>{{'DATASET-LISTING.STATES.PUBLIC' | translate}}</span> -->
<!-- <span *ngIf="description.status === 1 && description.public === false" class="col-auto"><span class="material-icons icon-align">done</span>{{ enumUtils.toDmpStatusString(description.status) }}</span> -->
<span *ngIf="description.status === 0" class=" col-auto draft"><span class="material-icons icon-align">create</span>{{ enumUtils.toDmpStatusString(description.status) }}</span>
<span>.</span>
<!-- <span class="col">{{'DATASET-LISTING.COLUMNS.GRANT' | translate}}: {{description.grant}}</span> -->
</div>
<div class="d-flex flex-direction-row pt-3 pb-3">
<div class="col-auto description-subtitle pr-0">{{'DATASET-LISTING.TOOLTIP.PART-OF' | translate}}
<div class="col-auto dmp-label ml-3">{{'DATASET-LISTING.TOOLTIP.DMP' | translate}}</div>
</div>
<div class="col dmp-title">{{description.dmp}}</div>
</div>
</a>
<div class="description-card-actions">
<a class="col-auto border-right pointer" [matMenuTriggerFor]="exportMenu"><span class="material-icons icon-align pr-2">open_in_new</span>{{'DATASET-LISTING.ACTIONS.EXPORT' | translate}}</a>
<a class="col-auto border-right pointer" *ngIf="isUserOwner" (click)="openShareDialog(description.dmpId, description.dmp)"><span class="material-icons icon-align pr-2">group_add</span>{{'DATASET-LISTING.ACTIONS.INVITE-SHORT' | translate}}</a>
<a class="col-auto border-right pointer" *ngIf="isAuthenticated()" (click)="openDmpSearchDialogue(description)"><span class="material-icons icon-align pr-2">file_copy</span>{{'DATASET-WIZARD.ACTIONS.COPY-DESCRIPTION' | translate}}</a>
<a class="col-auto border-right pointer" *ngIf="isAuthenticated() && isUserDescriptionRelated()" (click)="deleteClicked(description.id)"><span class="material-icons icon-align pr-2">delete</span>{{ 'DATASET-WIZARD.ACTIONS.DELETE' | translate }}</a>
</div>
<mat-menu #actionsMenu="matMenu">
<button *ngIf="isAuthenticated()" mat-menu-item (click)="openDmpSearchDialogue(description)" class="menu-item">
<mat-icon>file_copy</mat-icon>{{'DATASET-WIZARD.ACTIONS.COPY-DESCRIPTION' | translate}}
</button>
<button *ngIf="isUserDescriptionRelated()" mat-menu-item (click)="deleteClicked(description.id)" class="menu-item">
<mat-icon>delete</mat-icon>{{ 'DATASET-WIZARD.ACTIONS.DELETE' | translate }}
</button>
</mat-menu>
<mat-menu #exportMenu="matMenu" xPosition="before">
<button mat-menu-item (click)="downloadPDF(description)">
<i class="fa fa-file-pdf-o pr-2"></i>
<span>{{'GENERAL.FILE-TYPES.PDF' | translate}}</span>
</button>
<button mat-menu-item (click)="downloadDOCX(description)">
<i class="fa fa-file-word-o pr-2"></i>
<span>{{'GENERAL.FILE-TYPES.DOC' | translate}}</span>
</button>
<button mat-menu-item (click)="downloadXML(description)">
<i class="fa fa-file-code-o pr-2"></i>
<span>{{'GENERAL.FILE-TYPES.XML' | translate}}</span>
</button>
</mat-menu>
</div>

View File

@ -0,0 +1,261 @@
.gray-container {
letter-spacing: 5px;
color: #aaaaaa;
}
.container-header {
display: flex;
align-items: baseline;
margin-top: 0px;
text-transform: uppercase;
}
.container-header p {
letter-spacing: 5px;
color: #aaaaaa;
padding-top: 10px;
margin-bottom: 0px;
}
.container-header :hover {
color: var(--primary-color-3);
}
h4 {
display: inline;
padding-left: 1em;
color: #333333;
}
h4 > span {
text-transform: uppercase;
}
.title h4 {
padding-left: 30px;
line-height: 2em;
}
.about-item {
display: flex;
flex-wrap: wrap;
}
.links :hover {
color: var(--primary-color-3);
}
.about-item .length {
color: var(--primary-color-3);
}
.about-item .title {
margin: 2px 10px;
// text-transform: uppercase;
}
.about-item p {
margin-left: auto;
margin-bottom: 0px;
padding-top: 7px;
color: #aaaaaa;
}
p {
color: #333333;
}
.storage :hover {
color: var(--primary-color-3);
}
.draft-bookmark {
color: #e7e6e6;
}
.finalized-bookmark {
color: #08bd63;
}
.dmp-card,
.description-card {
min-width: 712px;
/* min-height: 308px; */
background: #ffffff 0% 0% no-repeat padding-box;
box-shadow: 0px 3px 6px #0000001a;
border-radius: 4px;
opacity: 1;
margin-top: 2.43rem;
margin-bottom: 1rem;
}
.remove-border-bottom ::ng-deep .mat-tab-header {
border-bottom: none;
}
input[type="text"] {
background: #fafafa 0% 0% no-repeat padding-box;
border: 1px solid #d1d1d1;
border-radius: 4px;
opacity: 1;
width: 347px;
height: 56px;
font-family: Arial, FontAwesome;
padding-left: 15px;
}
.edited-date {
text-align: left;
font-weight: 300;
font-family: "Roboto", sans-serif;
line-height: 2.4;
letter-spacing: 0px;
color: #212121;
opacity: 0.6;
}
.dmp-label {
background: var(--primary-color) 0% 0% no-repeat padding-box;
border-radius: 4px 0px;
opacity: 1;
min-width: 67px;
height: 37px;
color: #ffffff;
line-height: 2.4;
}
.description-label {
width: auto;
height: 37px;
background: var(--secondary-color) 0% 0% no-repeat padding-box;
border-radius: 4px 0px;
text-align: left;
line-height: 2.8;
font-size: 0.875rem;
font-weight: 400;
letter-spacing: 0px;
color: #212121;
}
.dmp-title,
.description-title {
text-align: left;
font-weight: 600;
font-family: "Roboto", sans-serif;
font-size: 1rem;
// opacity: 0.81;
padding-top: 0.75rem;
padding-bottom: 0.55rem;
color: #212121;
}
.description-subtitle,
.dmp-subtitle {
display: flex;
flex-direction: row;
text-align: left;
font-weight: 400;
font-family: "Roboto", sans-serif;
font-size: 0.875rem;
opacity: 1;
align-items: center;
color: #848484;
}
.dmp-title-draft,
.description-title-draft {
text-align: left;
font-weight: 600;
font-family: "Roboto", sans-serif;
font-size: 1rem;
// opacity: 0.81;
padding-top: 0.75rem;
padding-bottom: 0.55rem;
color: #f16868;
}
.icon-align {
display: inline-flex;
vertical-align: middle;
// line-height: .9em;
// padding-bottom: 0.4rem;
}
.dmp-subtitle,
.description-subtitle {
.icon-align {
display: inline-flex;
vertical-align: top;
margin-right: .2rem;
line-height: .95em;
}
}
.description-card-actions,
.dmp-card-actions {
display: flex;
flex-direction: row;
border-top: 1px solid #dbdbdb;
line-height: 4;
color: #848484;
}
.description-card-actions a,
.dmp-card-actions a {
color: #848484 !important;
text-decoration: none !important;
}
.description-card-actions a:hover,
.dmp-card-actions a:hover {
color: var(--primary-color) !important;
}
.dmp-description-descriptions-title {
color: #000000;
opacity: 0.6;
padding-top: 1.5rem;
padding-bottom: 0.8rem;
}
.dmp-description-descriptions-name {
color: #000000;
opacity: 0.6;
font-weight: 700;
}
.show-more {
color: black !important;
}
.show-more:hover {
color: var(--primary-color) !important;
}
.btn-load-more {
border: 2px solid #212121;
border-radius: 30px;
opacity: 1;
min-width: 132px;
width: auto;
height: 40px;
margin-top: 4.125rem;
}
.btn-load-more:hover {
background-color: black;
color: white;
}
.draft {
color: #f16868;
}
.pointer {
cursor: pointer;
}
::ng-deep .mat-menu-panel {
max-width: 282px !important;
}

View File

@ -0,0 +1,268 @@
import { Location } from '@angular/common';
import { HttpClient } from '@angular/common/http';
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { UntypedFormControl } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { Router } from '@angular/router';
import { Role } from '@app/core/common/enum/role';
import { AuthService } from '@app/core/services/auth/auth.service';
import { LockService } from '@app/core/services/lock/lock.service';
import { MatomoService } from '@app/core/services/matomo/matomo-service';
import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service';
import { EnumUtils } from '@app/core/services/utilities/enum-utils.service';
import { FileUtils } from '@app/core/services/utilities/file-utils.service';
import { DmpInvitationDialogComponent } from '@app/ui/dmp/invitation/dmp-invitation-dialog.component';
import { BaseComponent } from '@common/base/base.component';
import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component';
import { TranslateService } from '@ngx-translate/core';
import * as FileSaver from 'file-saver';
import { takeUntil } from 'rxjs/operators';
import { DescriptionStatus } from '../../../../core/common/enum/description-status';
import { Description } from '@app/core/model/description/description';
import { DescriptionService } from '@app/core/services/description/description.service';
import { IsActive } from '@app/core/common/enum/is-active.enum';
import { Guid } from '@common/types/guid';
@Component({
selector: 'app-description-listing-item-component',
templateUrl: './description-listing-item.component.html',
styleUrls: ['./description-listing-item.component.scss']
})
export class DescriptionListingItemComponent extends BaseComponent implements OnInit {
@Input() description: Description;
@Input() showDivider: boolean = true;
@Input() isPublic: boolean = false;
@Output() onClick: EventEmitter<Description> = new EventEmitter();
isDraft: boolean;
isDeleted: boolean;
isUserOwner: boolean;
constructor(
private router: Router,
public enumUtils: EnumUtils,
private descriptionService: DescriptionService,
public dialog: MatDialog,
private language: TranslateService,
private authService: AuthService,
private uiNotificationService: UiNotificationService,
private lockService: LockService,
private location: Location,
private httpClient: HttpClient,
private matomoService: MatomoService,
private fileUtils: FileUtils
) {
super();
}
ngOnInit() {
this.matomoService.trackPageView('Description Listing Item');
if (this.description.isActive === IsActive.Inactive) {
this.isDeleted = true;
} else if (this.description.status === DescriptionStatus.Draft) {
this.isDraft = true;
this.isDeleted = false;
this.setIsUserOwner();
} else {
this.isDraft = false;
this.isDeleted = false;
this.setIsUserOwner();
}
}
setIsUserOwner() {
if (this.description) {
const principalId: string = this.authService.userId()?.toString();
//TODO: add user to description objects
//if (principalId) this.isUserOwner = !!this.description.users.find(x => (x.role === Role.Owner) && (principalId === x.id));
}
}
public isAuthenticated(): boolean {
return this.authService.currentAccountIsAuthenticated();
}
getItemLink(): string[] {
// return this.isPublic ? [`/descriptions/publicEdit/${this.description.id}`] : [`/descriptions/edit/${this.description.id}`];
return this.isPublic ? ['/descriptions/publicOverview/' + this.description.id] : ['/descriptions/overview/' + this.description.id];
}
getDmpLink(): string[] {
return this.isPublic ? [`/explore-plans/publicOverview/${this.description.dmp.id}`] : [`/plans/edit/${this.description.dmp.id}`];
}
downloadPDF(description: Description): void {
//TODO: add file transformer service
// this.descriptionService.downloadPDF(description.id as string)
// .pipe(takeUntil(this._destroyed))
// .subscribe(response => {
// const blob = new Blob([response.body], { type: 'application/pdf' });
// const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
// FileSaver.saveAs(blob, filename);
// this.matomoService.trackDownload('descriptions', "pdf", description.id);
// });
}
downloadDOCX(description: Description): void {
//TODO: add file transformer service
// this.descriptionService.downloadDOCX(description.id as string)
// .pipe(takeUntil(this._destroyed))
// .subscribe(response => {
// const blob = new Blob([response.body], { type: 'application/msword' });
// const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
// FileSaver.saveAs(blob, filename);
// this.matomoService.trackDownload('descriptions', "docx", description.id);
// });
}
downloadXML(description: Description): void {
//TODO: add file transformer service
// this.descriptionService.downloadXML(description.id as string)
// .pipe(takeUntil(this._destroyed))
// .subscribe(response => {
// const blob = new Blob([response.body], { type: 'application/xml' });
// const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
// FileSaver.saveAs(blob, filename);
// this.matomoService.trackDownload('descriptions', "xml", description.id);
// });
}
openShareDialog(dmpRowId: any, dmpRowName: any) {
// TODO: This is a shared component. Put it in a seperate module.
const dialogRef = this.dialog.open(DmpInvitationDialogComponent, {
// height: '250px',
// width: '700px',
autoFocus: false,
restoreFocus: false,
data: {
dmpId: dmpRowId,
dmpName: dmpRowName
}
});
}
openDmpSearchDialogue(description: Description) {
// TODO: add this.
// const formControl = new UntypedFormControl();
// const dialogRef = this.dialog.open(DescriptionCopyDialogueComponent, {
// width: '500px',
// restoreFocus: false,
// data: {
// formControl: formControl,
// descriptionId: description.id,
// descriptionProfileId: description.profile.id,
// descriptionProfileExist: false,
// confirmButton: this.language.instant('DATASET-WIZARD.DIALOGUE.COPY'),
// cancelButton: this.language.instant('DATASET-WIZARD.DIALOGUE.CANCEL')
// }
// });
// dialogRef.afterClosed().pipe(takeUntil(this._destroyed))
// .subscribe(result => {
// if (result && result.descriptionProfileExist) {
// const newDmpId = result.formControl.value.id;
// this.router.navigate(['/descriptions/copy/' + result.descriptionId], { queryParams: { newDmpId: newDmpId } });
// }
// });
}
deleteClicked(id: Guid) {
this.lockService.checkLockStatus(id.toString()).pipe(takeUntil(this._destroyed))
.subscribe(lockStatus => {
if (!lockStatus) {
this.openDeleteDialog(id);
} else {
this.openLockedByUserDialog();
}
});
}
openDeleteDialog(id: Guid): void {
const dialogRef = this.dialog.open(ConfirmationDialogComponent, {
maxWidth: '300px',
restoreFocus: false,
data: {
message: this.language.instant('GENERAL.CONFIRMATION-DIALOG.DELETE-ITEM'),
confirmButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.DELETE'),
cancelButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CANCEL'),
isDeleteConfirmation: true
}
});
dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => {
if (result) {
this.descriptionService.delete(id)
.pipe(takeUntil(this._destroyed))
.subscribe(
complete => this.onDeleteCallbackSuccess(),
error => this.onDeleteCallbackError(error)
);
}
});
}
openLockedByUserDialog() {
const dialogRef = this.dialog.open(ConfirmationDialogComponent, {
maxWidth: '400px',
restoreFocus: false,
data: {
message: this.language.instant('DATASET-WIZARD.ACTIONS.LOCK')
}
});
}
reloadPage(): void {
const path = this.location.path();
this.router.navigateByUrl('/reload', { skipLocationChange: true }).then(() => {
this.router.navigate([path]);
});
}
onDeleteCallbackSuccess(): void {
this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-DELETE'), SnackBarNotificationLevel.Success);
this.reloadPage();
}
onDeleteCallbackError(error) {
this.uiNotificationService.snackBarNotification(error.error.message ? error.error.message : this.language.instant('GENERAL.SNACK-BAR.UNSUCCESSFUL-DELETE'), SnackBarNotificationLevel.Error);
}
roleDisplay(value: any) {
const principalId: string = this.authService.userId()?.toString();
let role: number;
if (principalId) {
value.forEach(element => {
if (principalId === element.id) {
role = element.role;
}
});
}
if (role === 0) {
return this.language.instant('DMP-LISTING.OWNER');
}
else if (role === 1) {
return this.language.instant('DMP-LISTING.MEMBER');
}
else {
return this.language.instant('DMP-LISTING.OWNER');
}
}
isUserDescriptionRelated() {
//TODO: add user to description objects
const principalId: string = this.authService.userId()?.toString();
let isRelated: boolean = false;
// if (this.description && principalId) {
// this.description.users.forEach(element => {
// if (element.id === principalId) {
// isRelated = true;
// }
// })
// }
return isRelated;
}
}

View File

@ -0,0 +1,186 @@
<div class="main-content dataset-overview pl-5 pr-5">
<div class="container-fluid pl-0 pr-0">
<div *ngIf="dataset">
<a class="row mb-2 pl-1" (click)="goBack()" role="button">
<mat-icon class="back-icon pointer">chevron_left</mat-icon>
<p class="label-txt pointer">{{'DMP-WIZARD.ACTIONS.BACK' | translate}}</p>
</a>
<div class="row">
<div class="col-md-8 col-lg-8 pl-4">
<div class="row">
<span class="col-auto dataset-logo">{{ 'NAV-BAR.DESCRIPTION' | translate }}</span>
<p class="col dataset-label p-0 ml-3 mb-0">{{ dataset.label }}</p>
</div>
<div class="row d-flex align-items-center mt-3 mb-4 label-txt">
<div *ngIf="isUserDatasetRelated()" class="d-flex">
<p class="ml-0 mb-0 label2-txt">
{{ roleDisplayFromList(dataset.users) }}
</p>
</div>
<span *ngIf="isUserDatasetRelated()" class="ml-2 mr-2">.</span>
<!-- UNCOMMENT TO ADD PRIVATE ICON -->
<!-- <span *ngIf="isUserDatasetRelated() && (dataset.public || !dataset.public || lockStatus)" class="ml-2 mr-2">.</span> -->
<div *ngIf="dataset.public" class="d-flex flex-row">
<mat-icon class="status-icon">public</mat-icon>
{{'DMP-OVERVIEW.PUBLIC' | translate}}
</div>
<span *ngIf="dataset.public" class="ml-2 mr-2">.</span>
<!-- UNCOMMENT TO ADD PRIVATE ICON -->
<!-- <div *ngIf="!dataset.public" class="d-flex flex-row">
<mat-icon class="status-icon">public_off</mat-icon>
{{'DMP-OVERVIEW.PRIVATE' | translate}}
</div>
<span *ngIf="!dataset.public" class="ml-2 mr-2">.</span> -->
<div *ngIf="lockStatus" class="d-flex flex-row">
<mat-icon class="status-icon">lock_outline</mat-icon>
{{'DMP-OVERVIEW.LOCKED' | translate}}
</div>
<span *ngIf="lockStatus" class="ml-2 mr-2">.</span>
<div class="d-flex mr-2">{{'GENERAL.STATUSES.EDIT' | translate}} :
<!-- {{dataset.modified | date:'longDate':'+0200': this.language.store.currentLang }} -->
{{dataset.modified | dateTimeCultureFormatter: "d MMMM y"}}
</div>
<div class="d-flex ml-2 mr-4">
<div *ngIf="dataset.status" class="d-flex flex-row uppercase">
<mat-icon class="status-icon check-icon">check</mat-icon>
{{'TYPES.DATASET-STATUS.FINALISED' | translate}}
</div>
</div>
</div>
<div class="row mb-4 pb-3">
<button *ngIf="isDraftDataset(dataset) && !lockStatus" (click)="editClicked(dataset)" mat-mini-fab class="mr-3 actions-btn" matTooltip="{{'DMP-LISTING.ACTIONS.EDIT' | translate}}" matTooltipPosition="above">
<mat-icon class="mat-mini-fab-icon">create</mat-icon>
</button>
<button *ngIf="isAuthenticated()" (click)="openDmpSearchDialogue()" mat-mini-fab class="mr-3 actions-btn" matTooltip="{{'DMP-LISTING.ACTIONS.CLONE' | translate}}" matTooltipPosition="above">
<mat-icon class="mat-mini-fab-icon">content_copy</mat-icon>
</button>
<button *ngIf="isUserDatasetRelated() && !lockStatus" (click)="deleteClicked()" mat-mini-fab class="mr-3 actions-btn" matTooltip="{{'DMP-LISTING.ACTIONS.DELETE' | translate}}" matTooltipPosition="above">
<mat-icon class="mat-mini-fab-icon">delete</mat-icon>
</button>
</div>
<div class="row header">{{'DATASET-LISTING.TOOLTIP.PART-OF' | translate}}</div>
<div class="row ">
<button class="dmp-btn" (click)="dmpClicked(dataset.dmp)">
<div class="dmp-btn-label">
{{ this.dataset.dmp.label }}
</div>
<mat-icon>launch</mat-icon>
</button>
</div>
<div *ngIf="dataset.grant">
<div class="row header">{{'DMP-OVERVIEW.GRANT' | translate}}</div>
<div class="row dataset-label">{{ dataset.grant.label }}</div>
</div>
<div class="row header">{{'DMP-OVERVIEW.RESEARCHERS' | translate}}</div>
<div class="row">
<div *ngFor="let researcher of researchers; let last = last">
<span *ngIf="isOrcid(researcher.reference)">
<a href="{{ getOrcidPathForResearcher(researcher.reference) }}" target="blank" class="researcher">
<div class="id-btn">&nbsp;</div>
<div *ngIf="!last">{{ researcher.name }}, </div>
<div *ngIf="last">{{ researcher.name }}</div>
</a>
</span>
<span *ngIf="!isOrcid(researcher.reference)">
<div *ngIf="!last">{{ researcher.name }}, </div>
<div *ngIf="last">{{ researcher.name }}</div>
</span>
</div>
<span *ngIf="!researchers || researchers.length === 0" class="material-icons">horizontal_rule</span>
</div>
<div class="row header">{{'DATASET-LISTING.COLUMNS.DESCRIPTION' | translate}}</div>
<div class="row" *ngIf="dataset.description">
<p class="desc-txt" [innerHTML]="dataset.description"></p>
</div>
<div class="row" *ngIf="!dataset.description">
<span class="material-icons">horizontal_rule</span>
</div>
</div>
<div class="col-md-4 col-lg-4 p-0">
<div class="frame mb-3 pt-4 pl-3 pr-5 pb-1">
<div *ngIf="!dataset.status && isDraftDataset(dataset) && !lockStatus">
<div class="row ml-0 mr-0 pl-4 d-flex align-items-center" (click)="finalize(dataset)">
<button mat-mini-fab class="finalize-btn">
<mat-icon class="mat-mini-fab-icon check-icon">check</mat-icon>
</button>
<p class="mb-0 pl-2 frame-txt">{{ 'DMP-LISTING.ACTIONS.FINALIZE' | translate }}</p>
</div>
<div class="row ml-0 mr-0 pl-4 d-flex align-items-center">
<hr class="hr-line">
</div>
</div>
<div *ngIf="hasReversableStatus(dataset)" class="row ml-0 mr-0 pl-4 pb-3 d-flex align-items-center" (click)="reverse(dataset)">
<button mat-mini-fab class="frame-btn">
<mat-icon class="mat-mini-fab-icon">unarchive</mat-icon>
</button>
<p class="mb-0 mr-0 pl-2 frame-txt">{{ 'DATASET-WIZARD.ACTIONS.REVERSE' | translate }}</p>
</div>
<div class="row ml-0 mr-0 pl-4 pb-3 d-flex align-items-center">
<button mat-mini-fab class="frame-btn" [matMenuTriggerFor]="exportMenu">
<mat-icon class="mat-mini-fab-icon">open_in_new</mat-icon>
</button>
<p class="mb-0 mr-0 pl-2 frame-txt" [matMenuTriggerFor]="exportMenu">
{{ 'DMP-LISTING.ACTIONS.EXPORT' | translate }}</p>
</div>
<!-- <div *ngIf="!dataset.public && showPublishButton(dataset) && isUserOwner" class="row ml-0 mr-0 pl-4 pb-3 d-flex align-items-center" (click)="publish(dataset.id)">
<button mat-mini-fab class="frame-btn">
<mat-icon class="mat-mini-fab-icon">public</mat-icon>
</button>
<p class="mb-0 pl-2 frame-txt">{{ 'DMP-LISTING.ACTIONS.MAKE-PUBLIC' | translate }}</p>
</div> -->
<mat-menu #exportMenu="matMenu" xPosition="before">
<button mat-menu-item (click)="downloadPDF(dataset.id)">
<i class="fa fa-file-pdf-o pr-2"></i>
<span>{{'GENERAL.FILE-TYPES.PDF' | translate}}</span>
</button>
<button mat-menu-item (click)="downloadDocx(dataset.id)">
<i class="fa fa-file-word-o pr-2"></i>
<span>{{'GENERAL.FILE-TYPES.DOC' | translate}}</span>
</button>
<button mat-menu-item (click)="downloadXml(dataset.id)">
<i class="fa fa-file-code-o pr-2"></i>
<span>{{'GENERAL.FILE-TYPES.XML' | translate}}</span>
</button>
<!-- GK: NO-->
<!-- <button mat-menu-item (click)="downloadJson(dataset.id)">
<i class="fa fa-file-o pr-2"></i>
<span>{{'GENERAL.FILE-TYPES.JSON' | translate}}</span>
</button> -->
</mat-menu>
</div>
<div class="frame mb-3 pt-4 pl-3 pr-3 pb-1">
<div class="row ml-0 mr-0 pl-4 pb-3">
<p class="header">{{ 'DATASET-OVERVIEW.DESCRIPTION-AUTHORS' | translate }}</p>
</div>
<div class="row ml-0 mr-0 pl-4 ml-2 pb-3 d-flex align-items-center">
<div *ngFor="let user of dataset.users" class="row authors">
<div class="d-flex flex-row">
<button class="account_btn mr-3 pl-0">
<mat-icon class="account-icon">account_circle</mat-icon>
</button>
<div>
<p class="authors-label">{{ user.name }}
<span *ngIf="isUserAuthor(user.id)">
({{ 'DMP-OVERVIEW.YOU' | translate }})</span>
</p>
<p class="authors-role">{{ roleDisplay(user) }}</p>
</div>
</div>
<button *ngIf="isUserOwner && !dataset.status && user.role" (click)="removeUserFromDmp(user)" class="remove-btn">{{ 'GENERAL.CONFIRMATION-DIALOG.ACTIONS.REMOVE' | translate}}</button>
</div>
</div>
<div *ngIf="isUserOwner" class="row mt-3 mb-3 d-flex align-items-center justify-content-center">
<button mat-raised-button class="invite-btn" (click)="openShareDialog(dataset.dmp.id, dataset.dmp.label)">
<mat-icon>group_add</mat-icon>
{{'DMP-LISTING.ACTIONS.INVITE-SHORT' | translate}}
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,301 @@
.container-fluid {
margin: 2em 4em;
padding: 2em;
}
.dataset-overview {
// margin-top: 5rem;
}
// ********ICONS********
.back-icon {
opacity: 0.4;
}
.mat-mini-fab {
width: 2.5em;
height: 2.5em;
color: #212121;
background-color: var(--secondary-color);
}
.mat-mini-fab-icon,
.status-icon {
font-size: 1.2em;
}
.actions-btn:hover,
.finalize-btn:hover {
background-color: var(--primary-color);
color: #ffffff;
}
.status-icon {
color: #a7a7a7;
}
.check-icon {
font-weight: bold;
}
.account-icon {
font-size: 2.5em;
}
// ********BUTTONS********
.version-btn {
// width: 6.7em;
height: 1.8em;
border: 1px solid #707070;
border-radius: 4px;
background-color: transparent;
}
.id-btn {
background: url("../../../../assets/images/NoPath.png") no-repeat center;
width: 1em;
margin-right: 0.3em;
align-self: center;
}
.dmp-btn {
width: 35em;
min-height: 2.3em;
background-color: var(--primary-color);
border-radius: 4px;
flex-direction: row;
justify-content: space-between;
border: none;
}
.dmp-btn,
.dmp-btn > mat-icon {
color: #ffffff;
// opacity: 0.8;
}
.show-more-btn {
width: 31.6em;
padding: 0 1em;
background-color: #ffffff00;
color: var(--primary-color);
font-weight: 700;
}
.frame-btn {
border: 1px solid #212121;
color: black;
background: #ffffff;
}
.finalize-btn {
// border: 1px solid var(--secondary-color);
background: #f5db71;
}
.frame-btn,
.finalize-btn {
box-shadow: 0px 2px 6px #00000029;
}
.remove-btn {
border: none;
background-color: transparent;
font-size: 0.875em;
font-weight: bold;
margin-left: auto;
}
.invite-btn {
width: 9.4em;
height: 2.9em;
background: #ffffff;
box-shadow: 0px 3px 6px #1e202029;
border: 2px solid #212121;
border-radius: 30px;
}
.account_btn {
background: white;
color: #d5d5d5;
border: none;
height: 2.9em;
}
// ********TEXT********
.dataset-logo {
width: 6em;
height: 2.6em;
background: var(--secondary-color);
border-radius: 4px;
font-size: 0.875em;
// color: #212121;
// color: black;
// opacity: 0.75;
}
.label-txt {
font-size: 0.875em;
}
.label2-txt {
font-size: 1em;
}
.label-txt,
.label2-txt {
color: #848484;
font-weight: 400;
}
.dataset-label {
font-weight: bold;
width: auto;
}
.uppercase {
text-transform: uppercase;
}
.researcher {
font-size: 0.875em;
color: var(--primary-color);
padding-right: 0.5em;
align-self: center;
}
.header {
opacity: 0.6;
margin-top: 1em;
margin-bottom: 0.5em;
}
.dataset-label,
.header {
font-size: 1.25em;
color: #212121;
}
.desc-txt {
width: 48.25em;
font-size: 1em;
color: #212121;
margin-bottom: 1.875em;
}
.dmp-btn-label {
margin-right: 1em;
overflow: hidden;
color: #ffffff;
opacity: 0.8;
text-align: left;
}
.doi-label {
font-size: 1em;
color: #212121;
opacity: 0.6;
margin-bottom: 0.3em;
}
.doi-txt {
font-size: 0.8em;
letter-spacing: 0.009em;
color: #7d7d7d;
width: 12em;
height: 1em;
overflow: hidden;
border: none;
padding: 0px;
}
.doi-panel {
height: 3.5em;
background: #fafafa;
border: 1px solid #d1d1d1;
border-radius: 4px;
flex-direction: row;
justify-content: space-between;
}
.doi-link {
color: white;
}
.frame {
background: #ffffff;
box-shadow: 0px 1px 5px #00000026;
border-radius: 4px;
overflow: hidden;
}
.frame-txt {
color: #000000;
}
.frame-txt,
.finalize-txt {
font-size: 0.75em;
font-weight: bold;
letter-spacing: 0px;
text-transform: uppercase;
cursor: pointer;
}
.hr-line {
border: 1px solid #dbdbdb;
// width: 274px;
// width: 17em;
width: 100%;
}
.authors {
display: flex;
flex-direction: row;
justify-content: space-between;
width: 100%;
}
.authors-label {
font-size: 0.875em;
color: #212121;
height: 1.4em;
margin-bottom: 0px;
}
.authors-role {
font-size: 0.875em;
color: #a8a8a8;
height: 1.4em;
margin-bottom: 0px;
}
// ********CENTER ELEMENTS********
.mat-mini-fab,
.mat-mini-fab-icon,
.actions-btn,
.status-icon,
.dataset-logo,
.frame-btn,
.finalize-btn {
display: flex;
justify-content: center;
align-items: center;
}
.dataset-label,
.dmp-btn,
.doi-panel,
.researcher {
display: flex;
align-items: center;
}
.show-more-btn {
display: flex;
justify-content: center;
}

View File

@ -0,0 +1,549 @@
import { Component, OnInit } from '@angular/core';
import { DatasetOverviewModel } from '@app/core/model/dataset/dataset-overview';
import { BaseComponent } from '@common/base/base.component';
// import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item';
import { Location } from '@angular/common';
import { HttpClient } from '@angular/common/http';
import { UntypedFormControl } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { ActivatedRoute, Params, Router } from '@angular/router';
import { DatasetStatus } from '@app/core/common/enum/dataset-status';
import { DmpStatus } from '@app/core/common/enum/dmp-status';
import { Role } from '@app/core/common/enum/role';
import { DatasetWizardModel } from '@app/core/model/dataset/dataset-wizard';
import { DmpOverviewModel } from '@app/core/model/dmp/dmp-overview';
import { ResearcherModel } from '@app/core/model/researcher/researcher';
import { UserInfoListingModel } from '@app/core/model/user/user-info-listing';
import { AuthService } from '@app/core/services/auth/auth.service';
import { ConfigurationService } from '@app/core/services/configuration/configuration.service';
import { DatasetWizardService } from '@app/core/services/dataset-wizard/dataset-wizard.service';
import { DatasetService } from '@app/core/services/dataset/dataset.service';
import { DmpService } from '@app/core/services/dmp/dmp.service';
import { LockService } from '@app/core/services/lock/lock.service';
import { MatomoService } from '@app/core/services/matomo/matomo-service';
import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service';
import { UserServiceOld } from '@app/core/services/user/user.service-old';
import { FileUtils } from '@app/core/services/utilities/file-utils.service';
import { PopupNotificationDialogComponent } from '@app/library/notification/popup/popup-notification.component';
import { DmpInvitationDialogComponent } from '@app/ui/dmp/invitation/dmp-invitation-dialog.component';
import { Oauth2DialogService } from '@app/ui/misc/oauth2-dialog/service/oauth2-dialog.service';
import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component';
import { TranslateService } from '@ngx-translate/core';
import * as FileSaver from 'file-saver';
import { filter, takeUntil } from 'rxjs/operators';
import { DatasetCopyDialogueComponent } from '../dataset-wizard/dataset-copy-dialogue/dataset-copy-dialogue.component';
@Component({
selector: 'app-dataset-overview',
templateUrl: './dataset-overview.component.html',
styleUrls: ['./dataset-overview.component.scss']
})
export class DatasetOverviewComponent extends BaseComponent implements OnInit {
dataset: DatasetOverviewModel;
// datasetWizardEditorModel: DatasetWizardEditorModel;
datasetWizardModel: DatasetWizardModel;
isNew = true;
isFinalized = false;
isPublicView = true;
hasPublishButton: boolean = true;
// breadCrumbs: Observable<BreadcrumbItem[]> = observableOf();
isUserOwner: boolean;
expand = false;
researchers: ResearcherModel[];
users: UserInfoListingModel[];
lockStatus: Boolean;
constructor(
private route: ActivatedRoute,
private router: Router,
private datasetService: DatasetService,
private translate: TranslateService,
private authentication: AuthService,
private dialog: MatDialog,
private language: TranslateService,
private uiNotificationService: UiNotificationService,
private configurationService: ConfigurationService,
private oauth2DialogService: Oauth2DialogService,
private userService: UserServiceOld,
private dmpService: DmpService,
private location: Location,
private datasetWizardService: DatasetWizardService,
private lockService: LockService,
private httpClient: HttpClient,
private matomoService: MatomoService,
private fileUtils: FileUtils
) {
super();
}
ngOnInit() {
this.matomoService.trackPageView('Dataset Overview');
// Gets dataset data using parameter id
this.route.params
.pipe(takeUntil(this._destroyed))
.subscribe((params: Params) => {
const itemId = params['id'];
const publicId = params['publicId'];
if (itemId != null) {
this.isNew = false;
this.isPublicView = false;
this.datasetService.getOverviewSingle(itemId)
.pipe(takeUntil(this._destroyed))
.subscribe(data => {
this.dataset = data;
this.researchers = this.dataset.dmp.researchers;
this.users = this.dataset.dmp.users;
this.checkLockStatus(this.dataset.id);
this.setIsUserOwner();
// const breadCrumbs = [];
// breadCrumbs.push({ parentComponentName: null, label: this.language.instant('NAV-BAR.MY-DATASET-DESCRIPTIONS'), url: "/datasets" });
// breadCrumbs.push({ parentComponentName: 'DatasetListingComponent', label: this.dataset.label, url: '/datasets/overview/' + this.dataset.id });
// this.breadCrumbs = observableOf(breadCrumbs);
}, (error: any) => {
if (error.status === 404) {
return this.onFetchingDeletedCallbackError('/datasets/');
}
if (error.status === 403) {
return this.onFetchingForbiddenCallbackError('/datasets/');
}
});
}
else if (publicId != null) {
this.isNew = false;
this.isFinalized = true;
this.isPublicView = true;
this.datasetService.getOverviewSinglePublic(publicId)
.pipe(takeUntil(this._destroyed))
.subscribe(data => {
this.dataset = data;
this.researchers = this.dataset.dmp.researchers;
this.users = this.dataset.dmp.users;
// const breadCrumbs = [];
// breadCrumbs.push({ parentComponentName: null, label: this.language.instant('NAV-BAR.PUBLIC DATASETS'), url: "/explore" });
// breadCrumbs.push({ parentComponentName: 'DatasetListingComponent', label: this.dataset.label, url: '/datasets/publicOverview/' + this.dataset.id });
// this.breadCrumbs = observableOf(breadCrumbs);
}, (error: any) => {
if (error.status === 404) {
return this.onFetchingDeletedCallbackError('/explore');
}
if (error.status === 403) {
return this.onFetchingForbiddenCallbackError('/explore');
}
});
}
});
}
checkLockStatus(id: string) {
this.lockService.checkLockStatus(id).pipe(takeUntil(this._destroyed))
.subscribe(lockStatus => {
this.lockStatus = lockStatus
if (lockStatus) {
this.dialog.open(PopupNotificationDialogComponent, {
data: {
title: this.language.instant('DATASET-OVERVIEW.LOCKED.TITLE'),
message: this.language.instant('DATASET-OVERVIEW.LOCKED.MESSAGE')
}, maxWidth: '30em'
});
}
});
}
onFetchingDeletedCallbackError(redirectRoot: string) {
this.uiNotificationService.snackBarNotification(this.language.instant('DATASET-OVERVIEW.ERROR.DELETED-DATASET'), SnackBarNotificationLevel.Error);
this.router.navigate([redirectRoot]);
}
onFetchingForbiddenCallbackError(redirectRoot: string) {
this.uiNotificationService.snackBarNotification(this.language.instant('DATASET-OVERVIEW.ERROR.FORBIDEN-DATASET'), SnackBarNotificationLevel.Error);
this.router.navigate([redirectRoot]);
}
goBack(): void {
this.location.back();
}
reloadPage(): void {
const path = this.location.path();
this.router.navigateByUrl('/reload', { skipLocationChange: true }).then(() => this.router.navigate([path]));
}
setIsUserOwner() {
if (this.dataset) {
const principalId: string = this.authentication.userId()?.toString();
if (principalId) this.isUserOwner = !!this.dataset.users.find(x => (x.role === Role.Owner) && (principalId === x.id));
}
}
isUserAuthor(userId: string): boolean {
if (this.isAuthenticated()) {
const principalId: string = this.authentication.userId()?.toString();
return userId === principalId;
} else return false;
}
isUserDatasetRelated() {
const principalId: string = this.authentication.userId()?.toString();
let isRelated: boolean = false;
if (this.dataset && principalId) {
this.dataset.users.forEach(element => {
if (element.id === principalId) {
isRelated = true;
}
})
}
return isRelated;
}
roleDisplay(value: UserInfoListingModel) {
if (value.role === Role.Owner) {
return this.translate.instant('DMP-LISTING.OWNER');
} else if (value.role === Role.Member) {
return this.translate.instant('DMP-LISTING.MEMBER');
} else {
return this.translate.instant('DMP-LISTING.OWNER');
}
}
roleDisplayFromList(value: UserInfoListingModel[]) {
const principalId: string = this.authentication.userId()?.toString();
let role: number;
if (principalId) {
value.forEach(element => {
if (principalId === element.id) {
role = element.role;
}
});
}
if (role === Role.Owner) {
return this.translate.instant('DMP-LISTING.OWNER');
} else if (role === Role.Member) {
return this.translate.instant('DMP-LISTING.MEMBER');
} else {
return this.translate.instant('DMP-LISTING.OWNER');
}
}
openShareDialog(rowId: any, rowName: any) {
const dialogRef = this.dialog.open(DmpInvitationDialogComponent, {
autoFocus: false,
restoreFocus: false,
data: {
dmpId: rowId,
dmpName: rowName
}
});
}
public isAuthenticated(): boolean {
return this.authentication.currentAccountIsAuthenticated();
}
isDraftDataset(dataset: DatasetOverviewModel) {
return dataset.status == DatasetStatus.Draft;
}
isFinalizedDataset(dataset: DatasetOverviewModel) {
return dataset.status == DatasetStatus.Finalized;
}
editClicked(dataset: DatasetOverviewModel) {
if (dataset.public) {
this.router.navigate(['/datasets/publicEdit/', dataset.id]);
// let url = this.router.createUrlTree(['/datasets/publicEdit/', dataset.id]);
// window.open(url.toString(), '_blank');
} else {
this.router.navigate(['/datasets/edit/', dataset.id]);
// let url = this.router.createUrlTree(['/datasets/edit/', dataset.id]);
// let url = this.router.createUrlTree(['/plans/edit/', dataset.dmp.id], { queryParams: { dataset: dataset.id } });
// window.open(url.toString(), '_blank');
}
}
deleteClicked() {
const dialogRef = this.dialog.open(ConfirmationDialogComponent, {
maxWidth: '300px',
data: {
message: this.language.instant('GENERAL.CONFIRMATION-DIALOG.DELETE-ITEM'),
confirmButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.DELETE'),
cancelButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CANCEL'),
isDeleteConfirmation: true
}
});
dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => {
if (result) {
this.datasetService.delete(this.dataset.id)
.pipe(takeUntil(this._destroyed))
.subscribe(
complete => {
this.onDeleteCallbackSuccess();
},
error => this.onDeleteCallbackError(error)
);
}
});
}
dmpClicked(dmp: DmpOverviewModel) {
if (this.isPublicView) {
this.router.navigate(['/explore-plans/publicOverview/' + dmp.id]);
} else {
this.router.navigate(['/plans/overview/' + dmp.id]);
}
}
onDeleteCallbackSuccess(): void {
this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-DELETE'), SnackBarNotificationLevel.Success);
this.router.navigate(['/datasets']);
}
onDeleteCallbackError(error) {
this.uiNotificationService.snackBarNotification(error.error.message ? error.error.message : this.language.instant('GENERAL.SNACK-BAR.UNSUCCESSFUL-DELETE'), SnackBarNotificationLevel.Error);
}
onUpdateCallbackSuccess(): void {
this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-UPDATE'), SnackBarNotificationLevel.Success);
this.reloadPage();
}
onUpdateCallbackError(error) {
this.uiNotificationService.snackBarNotification(error.error.message ? this.tryTranslate(error.error.message) : this.language.instant('DATASET-UPLOAD.SNACK-BAR.UNSUCCESSFUL'), SnackBarNotificationLevel.Error);
}
tryTranslate(errorMessage: string): string {
return errorMessage.replace('Field value of', this.language.instant('Field value of'))
.replace('must be filled', this.language.instant('must be filled'));
}
public getOrcidPath(): string {
return this.configurationService.orcidPath;
}
isOrcid(reference: string) {
const head = reference.split(':')[0];
return head === 'orcid';
}
getOrcidPathForResearcher(reference: string): string {
const path = this.getOrcidPath();
const userId = reference.split(':')[1];
return path + userId;
}
downloadPDF(id: string) {
this.datasetService.downloadPDF(id)
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/pdf' });
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('datasets', "pdf", id);
});
}
downloadDocx(id: string) {
this.datasetService.downloadDocx(id)
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/msword' });
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('datasets', "docx", id);
});
}
downloadXml(id: string) {
this.datasetService.downloadXML(id)
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/xml' });
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('datasets', "xml", id);
});
}
//GK: NO
// downloadJson(id: string) {
// this.datasetService.downloadJson(id)
// .pipe(takeUntil(this._destroyed))
// .subscribe(response => {
// const blob = new Blob([response.body], { type: 'application/json' });
// const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
// FileSaver.saveAs(blob, filename);
// })
// }
openDmpSearchDialogue() {
const formControl = new UntypedFormControl();
const dialogRef = this.dialog.open(DatasetCopyDialogueComponent, {
width: '500px',
restoreFocus: false,
data: {
formControl: formControl,
datasetId: this.dataset.id,
datasetProfileId: this.dataset.datasetTemplate.id,
datasetProfileExist: false,
confirmButton: this.language.instant('DATASET-WIZARD.DIALOGUE.COPY'),
cancelButton: this.language.instant('DATASET-WIZARD.DIALOGUE.CANCEL')
}
});
dialogRef.afterClosed().pipe(takeUntil(this._destroyed))
.subscribe(result => {
if (result && result.datasetProfileExist) {
const newDmpId = result.formControl.value.id;
this.router.navigate(['/datasets/copy/' + result.datasetId], { queryParams: { newDmpId: newDmpId } });
// let url = this.router.createUrlTree(['/datasets/copy/', result.datasetId, { newDmpId: newDmpId }])
// window.open(url.toString(), '_blank')
}
});
}
updateUsers() {
return this.dmpService.updateUsers(this.dataset.dmp.id, this.users).pipe(takeUntil(this._destroyed))
.subscribe(
complete => {
this.onUpdateCallbackSuccess();
},
error => this.onUpdateCallbackError(error)
);
}
removeUserFromDmp(user: UserInfoListingModel) {
const dialogRef = this.dialog.open(ConfirmationDialogComponent, {
data: {
message: this.language.instant('GENERAL.CONFIRMATION-DIALOG.DELETE-USER'),
confirmButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.REMOVE'),
cancelButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CANCEL'),
isDeleteConfirmation: false
}
});
dialogRef.afterClosed().subscribe(result => {
if (result) {
const index = this.users.findIndex(x => x.id === user.id);
if (index > -1) {
this.users.splice(index, 1);
}
this.updateUsers();
}
});
}
showPublishButton(dataset: DatasetOverviewModel) {
return this.isFinalizedDataset(dataset) && !dataset.public && this.hasPublishButton;
}
// publish(id: String) {
// const dialogRef = this.dialog.open(ConfirmationDialogComponent, {
// maxWidth: '500px',
// restoreFocus: false,
// data: {
// message: this.language.instant('GENERAL.CONFIRMATION-DIALOG.PUBLISH-ITEM'),
// privacyPolicyNames: this.language.instant('GENERAL.CONFIRMATION-DIALOG.PRIVACY-POLICY-NAMES'),
// confirmButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CONFIRM'),
// cancelButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CANCEL'),
// isDeleteConfirmation: false
// }
// });
// dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => {
// if (result) {
// this.datasetService.publish(id)
// .pipe(takeUntil(this._destroyed))
// .subscribe(() => {
// this.hasPublishButton = false;
// this.reloadPage();
// });
// }
// });
// }
finalize(dataset: DatasetOverviewModel) {
this.dialog.open(ConfirmationDialogComponent, {
data: {
message: this.language.instant('DATASET-OVERVIEW.FINALISE-POPUP.MESSAGE'),
confirmButton: this.language.instant('DATASET-OVERVIEW.FINALISE-POPUP.CONFIRM'),
cancelButton: this.language.instant('DATASET-OVERVIEW.FINALISE-POPUP.CANCEL'),
},
maxWidth: '30em'
})
.afterClosed()
.pipe(
filter(x => x),
takeUntil(this._destroyed)
)
.subscribe(_ => {
this.router.navigate(['datasets', 'edit', dataset.id, 'finalize']);
})
// const dialogRef = this.dialog.open(ConfirmationDialogComponent, {
// restoreFocus: false,
// data: {
// message: this.language.instant('GENERAL.CONFIRMATION-DIALOG.FINALIZE-ITEM'),
// confirmButton: this.language.instant('QUICKWIZARD.SAVE-DIALOG.ACTIONS.AFFIRMATIVE'),
// cancelButton: this.language.instant('QUICKWIZARD.SAVE-DIALOG.ACTIONS.NEGATIVE'),
// isDeleteConfirmation: false
// }
// });
// dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => {
// if (result) {
// this.datasetWizardService.getSingle(dataset.id)
// .pipe(takeUntil(this._destroyed))
// .subscribe(data => {
// this.datasetWizardModel = data;
// this.datasetWizardModel.status = DatasetStatus.Finalized;
// this.datasetWizardService.createDataset(this.datasetWizardModel)
// .pipe(takeUntil(this._destroyed))
// .subscribe(
// data => this.onUpdateCallbackSuccess(),
// error => this.onUpdateCallbackError(error)
// );
// });
// }
// });
}
hasReversableStatus(dataset: DatasetOverviewModel): boolean {
return dataset.dmp.status == DmpStatus.Draft && dataset.status == DatasetStatus.Finalized
}
reverse(dataset: DatasetOverviewModel) {
const dialogRef = this.dialog.open(ConfirmationDialogComponent, {
restoreFocus: false,
data: {
message: this.language.instant('GENERAL.CONFIRMATION-DIALOG.UNFINALIZE-ITEM'),
confirmButton: this.language.instant('QUICKWIZARD.SAVE-DIALOG.ACTIONS.AFFIRMATIVE'),
cancelButton: this.language.instant('QUICKWIZARD.SAVE-DIALOG.ACTIONS.NEGATIVE'),
isDeleteConfirmation: false
}
});
dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => {
if (result) {
this.datasetWizardService.getSingle(dataset.id)
.pipe(takeUntil(this._destroyed))
.subscribe(data => {
this.datasetWizardModel = data;
this.datasetWizardModel.status = DatasetStatus.Draft;
this.datasetWizardService.createDataset(this.datasetWizardModel)
.pipe(takeUntil(this._destroyed))
.subscribe(
data => this.onUpdateCallbackSuccess(),
error => this.onUpdateCallbackError(error)
);
});
}
});
}
}

View File

@ -0,0 +1,25 @@
import { NgModule } from '@angular/core';
import { FormattingModule } from '@app/core/formatting.module';
import { AutoCompleteModule } from '@app/library/auto-complete/auto-complete.module';
import { ConfirmationDialogModule } from '@common/modules/confirmation-dialog/confirmation-dialog.module';
import { ExportMethodDialogModule } from '@app/library/export-method-dialog/export-method-dialog.module';
import { UrlListingModule } from '@app/library/url-listing/url-listing.module';
import { CommonFormsModule } from '@common/forms/common-forms.module';
import { CommonUiModule } from '@common/ui/common-ui.module';
import { DatasetOverviewComponent } from './dataset-overview.component';
@NgModule({
imports: [
CommonUiModule,
CommonFormsModule,
UrlListingModule,
ConfirmationDialogModule,
ExportMethodDialogModule,
FormattingModule,
AutoCompleteModule
],
declarations: [
DatasetOverviewComponent
]
})
export class DatasetOverviewModule { }

View File

@ -8,11 +8,10 @@ import { MatSort } from '@angular/material/sort';
import { ActivatedRoute, Router } from '@angular/router';
import { RecentActivityOrder } from '@app/core/common/enum/recent-activity-order';
import { DataTableRequest } from '@app/core/model/data-table/data-table-request';
import { DmpListingModel } from '@app/core/model/dmp/dmp-listing';
import { GrantListingModel } from '@app/core/model/grant/grant-listing';
import { DmpCriteria } from '@app/core/query/dmp/dmp-criteria';
import { AuthService } from '@app/core/services/auth/auth.service';
import { DmpService } from '@app/core/services/dmp/dmp.service';
import { DmpService, DmpServiceNew } from '@app/core/services/dmp/dmp.service';
import { GrantService } from "@app/core/services/grant/grant.service";
import { MatomoService } from '@app/core/services/matomo/matomo-service';
import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service';
@ -31,6 +30,9 @@ import { Observable, of as observableOf } from 'rxjs';
import { debounceTime, takeUntil } from 'rxjs/operators';
import { DmpCriteriaDialogComponent } from './criteria/dmp-criteria-dialog.component';
import { DmpUploadDialogue } from './upload-dialogue/dmp-upload-dialogue.component';
import { DmpLookup } from '@app/core/query/dmp.lookup';
import { Dmp } from '@app/core/model/dmp/dmp';
import { nameof } from 'ts-simple-nameof';
@Component({
selector: 'app-dmp-listing-component',
@ -49,7 +51,7 @@ export class DmpListingComponent extends BaseComponent implements OnInit { //IBr
showGrant: boolean;
titlePrefix: string;
totalCount: number;
listingItems: DmpListingModel[] = [];
listingItems: Dmp[] = [];
allVersions: boolean = false;
groupLabel: string;
isPublic: boolean = false;
@ -73,6 +75,7 @@ export class DmpListingComponent extends BaseComponent implements OnInit { //IBr
constructor(
private dmpService: DmpService,
private dmpServiceNew: DmpServiceNew,
private router: Router,
private route: ActivatedRoute,
public dialogAnimation: NgDialogAnimationService,
@ -233,13 +236,6 @@ export class DmpListingComponent extends BaseComponent implements OnInit { //IBr
}
public refresh(resetPages = false) {
// if (this._paginator.pageSize === undefined) this._paginator.pageSize = 10;
// if (resetPages) this._paginator.pageIndex = 0;
// const startIndex = this._paginator.pageIndex * this._paginator.pageSize;
// let fields: Array<string> = new Array();
// if (this.sort && this.sort.active) { fields = this.sort.direction === 'asc' ? ['+' + this.sort.active] : ['-' + this.sort.active]; }
// fields.push('-modified');
const fields: Array<string> = [((this.formGroup.get('order').value === 'status') || (this.formGroup.get('order').value === 'label') ? '+' : "-") + this.formGroup.get('order').value];
this.startIndex = 0;
@ -247,47 +243,81 @@ export class DmpListingComponent extends BaseComponent implements OnInit { //IBr
this.setPublicCriteria();
request.criteria = this.criteria;
this.dmpService.getPaged(request, "listing").pipe(takeUntil(this._destroyed)).subscribe(result => {
if (!result) { return []; }
result.data.map(item => {
item['datasets'].map(dmp => {
dmp.url = 'datasets/edit/' + dmp.url;
dmp.all = 'datasets/dmp/' + item.id;
return dmp;
});
return item;
});
this.listingItems = result.data;
let lookup: DmpLookup = new DmpLookup();
lookup.project = {
fields: [
nameof<Dmp>(x => x.id),
nameof<Dmp>(x => x.label),
]
};
this.dmpServiceNew.query(lookup).pipe(takeUntil(this._destroyed))
.subscribe(result => {
if (!result) { return; }
// result.data.map(item => {
// item['datasets'].map(dmp => {
// dmp.url = 'datasets/edit/' + dmp.url;
// dmp.all = 'datasets/dmp/' + item.id;
// return dmp;
// });
// return item;
// });
this.listingItems = result.items;
this.hasListingItems = true;
if (!this.isPublic && this.listingItems.length === 0 && !this.hasCriteria() && !this.hasLikeCriteria()) {
this.openTour();
}
this.totalCount = result.totalCount;
this.totalCount = result.count;
});
// const fields: Array<string> = [((this.formGroup.get('order').value === 'status') || (this.formGroup.get('order').value === 'label') ? '+' : "-") + this.formGroup.get('order').value];
// this.startIndex = 0;
// const request = new DataTableRequest<DmpCriteria>(this.startIndex, this.pageSize, { fields: fields });
// this.setPublicCriteria();
// request.criteria = this.criteria;
// this.dmpService
// this.dmpService.getPaged(request, "listing").pipe(takeUntil(this._destroyed)).subscribe(result => {
// if (!result) { return []; }
// result.data.map(item => {
// item['datasets'].map(dmp => {
// dmp.url = 'datasets/edit/' + dmp.url;
// dmp.all = 'datasets/dmp/' + item.id;
// return dmp;
// });
// return item;
// });
// this.listingItems = result.data;
// this.hasListingItems = true;
// if (!this.isPublic && this.listingItems.length === 0 && !this.hasCriteria() && !this.hasLikeCriteria()) {
// this.openTour();
// }
// this.totalCount = result.totalCount;
// });
}
public loadMore() {
this.startIndex = this.startIndex + this.pageSize;
// const fields: Array<string> = ["-modified"];
const fields: Array<string> = [((this.formGroup.get('order').value === 'status') || (this.formGroup.get('order').value === 'label') ? '+' : "-") + this.formGroup.get('order').value];
const request = new DataTableRequest<DmpCriteria>(this.startIndex, this.pageSize, { fields: fields });
this.setPublicCriteria();
request.criteria = this.criteria;
// this.startIndex = this.startIndex + this.pageSize;
// // const fields: Array<string> = ["-modified"];
// const fields: Array<string> = [((this.formGroup.get('order').value === 'status') || (this.formGroup.get('order').value === 'label') ? '+' : "-") + this.formGroup.get('order').value];
// const request = new DataTableRequest<DmpCriteria>(this.startIndex, this.pageSize, { fields: fields });
// this.setPublicCriteria();
// request.criteria = this.criteria;
this.dmpService.getPaged(request, "listing").pipe(takeUntil(this._destroyed)).subscribe(result => {
if (!result) { return []; }
result.data.map(item => {
item['datasets'].map(dmp => {
dmp.url = 'datasets/edit/' + dmp.url;
dmp.all = 'datasets/dmp/' + item.id;
return dmp;
});
return item;
});
// this.listingItems = this.listingItems.concat(result.data);
this.listingItems = this.mergeTwoSortedLists(this.listingItems, result.data, this.formGroup.get('order').value);
this.hasListingItems = true;
});
// this.dmpService.getPaged(request, "listing").pipe(takeUntil(this._destroyed)).subscribe(result => {
// if (!result) { return []; }
// result.data.map(item => {
// item['datasets'].map(dmp => {
// dmp.url = 'datasets/edit/' + dmp.url;
// dmp.all = 'datasets/dmp/' + item.id;
// return dmp;
// });
// return item;
// });
// // this.listingItems = this.listingItems.concat(result.data);
// this.listingItems = this.mergeTwoSortedLists(this.listingItems, result.data, this.formGroup.get('order').value);
// this.hasListingItems = true;
// });
}
pageThisEvent(event) {
@ -315,7 +345,7 @@ export class DmpListingComponent extends BaseComponent implements OnInit { //IBr
this.refresh();
}
// rowClicked(dmp: DmpListingModel) {
// rowClicked(dmp: Dmp) {
// this.router.navigate(['/plans/overview/' + dmp.id]);
// }
@ -464,62 +494,62 @@ export class DmpListingComponent extends BaseComponent implements OnInit { //IBr
return document.getElementById("main-page").scrollHeight > document.documentElement.clientHeight
}
private mergeTwoSortedLists(arr1: DmpListingModel[], arr2: DmpListingModel[], order: string): DmpListingModel[] {
let merged = [];
let index1 = 0;
let index2 = 0;
let current = 0;
// private mergeTwoSortedLists(arr1: Dmp[], arr2: Dmp[], order: string): Dmp[] {
// let merged = [];
// let index1 = 0;
// let index2 = 0;
// let current = 0;
while (current < (arr1.length + arr2.length)) {
// while (current < (arr1.length + arr2.length)) {
let isArr1Depleted = index1 >= arr1.length;
let isArr2Depleted = index2 >= arr2.length;
// let isArr1Depleted = index1 >= arr1.length;
// let isArr2Depleted = index2 >= arr2.length;
if (order === 'modified') {
if (!isArr1Depleted && (isArr2Depleted || (new Date(arr1[index1].modifiedTime) > new Date(arr2[index2].modifiedTime)))) {
merged[current] = arr1[index1];
index1++;
} else {
merged[current] = arr2[index2];
index2++;
}
} else if (order === 'created') {
if (!isArr1Depleted && (isArr2Depleted || (new Date(arr1[index1].creationTime) > new Date(arr2[index2].creationTime)))) {
merged[current] = arr1[index1];
index1++;
} else {
merged[current] = arr2[index2];
index2++;
}
} else if (order === 'label') {
if (!isArr1Depleted && (isArr2Depleted || (arr1[index1].label.localeCompare(arr2[index2].label)))) {
merged[current] = arr1[index1];
index1++;
} else {
merged[current] = arr2[index2];
index2++;
}
} else if (order === 'status') {
if (!isArr1Depleted && (isArr2Depleted || (arr1[index1].status < arr2[index2].status))) {
merged[current] = arr1[index1];
index1++;
} else {
merged[current] = arr2[index2];
index2++;
}
} else if (order === "publishedAt") {
if (!isArr1Depleted && (isArr2Depleted || (new Date(arr1[index1].publishedAt) > new Date(arr2[index2].publishedAt)))) {
merged[current] = arr1[index1];
index1++;
} else {
merged[current] = arr2[index2];
index2++;
}
}
current++;
}
return merged;
}
// if (order === 'modified') {
// if (!isArr1Depleted && (isArr2Depleted || (new Date(arr1[index1].modifiedTime) > new Date(arr2[index2].modifiedTime)))) {
// merged[current] = arr1[index1];
// index1++;
// } else {
// merged[current] = arr2[index2];
// index2++;
// }
// } else if (order === 'created') {
// if (!isArr1Depleted && (isArr2Depleted || (new Date(arr1[index1].creationTime) > new Date(arr2[index2].creationTime)))) {
// merged[current] = arr1[index1];
// index1++;
// } else {
// merged[current] = arr2[index2];
// index2++;
// }
// } else if (order === 'label') {
// if (!isArr1Depleted && (isArr2Depleted || (arr1[index1].label.localeCompare(arr2[index2].label)))) {
// merged[current] = arr1[index1];
// index1++;
// } else {
// merged[current] = arr2[index2];
// index2++;
// }
// } else if (order === 'status') {
// if (!isArr1Depleted && (isArr2Depleted || (arr1[index1].status < arr2[index2].status))) {
// merged[current] = arr1[index1];
// index1++;
// } else {
// merged[current] = arr2[index2];
// index2++;
// }
// } else if (order === "publishedAt") {
// if (!isArr1Depleted && (isArr2Depleted || (new Date(arr1[index1].publishedAt) > new Date(arr2[index2].publishedAt)))) {
// merged[current] = arr1[index1];
// index1++;
// } else {
// merged[current] = arr2[index2];
// index2++;
// }
// }
// current++;
// }
// return merged;
// }
public setDashboardTourDmpText(): void {
this.dmpText = this.language.instant('DMP-LISTING.TEXT-INFO') + '\n\n' +
@ -547,69 +577,3 @@ export class DmpListingComponent extends BaseComponent implements OnInit { //IBr
return this.criteria.like !== undefined && this.criteria.like !== null;
}
}
// export class DmpDataSource extends DataSource<DmpListingModel> {
// totalCount = 0;
// constructor(
// private _service: DmpService,
// private _paginator: MatPaginator,
// private _sort: MatSort,
// private _criteria: DmpCriteriaComponent,
// private itemId
// ) {
// super();
// }
// connect(): Observable<DmpListingModel[]> {
// const displayDataChanges = [
// this._paginator.page
// ];
// return Observable.merge(...displayDataChanges)
// .startWith(null)
// .switchMap(() => {
// const startIndex = this._paginator.pageIndex * this._paginator.pageSize;
// let fields: Array<string> = new Array();
// if (this._sort.active) { fields = this._sort.direction === 'asc' ? ['+' + this._sort.active] : ['-' + this._sort.active]; }
// const request = new DataTableRequest<DmpCriteria>(startIndex, this._paginator.pageSize, { fields: fields });
// request.criteria = this._criteria.formGroup.value;
// if (this.itemId) {
// request.criteria.groupIds = [this.itemId];
// request.criteria.allVersions = true;
// }
// return this._service.getPaged(request, "listing");
// })
// /*.catch((error: any) => {
// this._snackBar.openFromComponent(SnackBarNotificationComponent, {
// data: { message: 'GENERAL.SNACK-BAR.FORMS-BAD-REQUEST', language: this._languageService },
// duration: 3000,
// extraClasses: ['snackbar-warning']
// });
// return Observable.of(null);
// })*/
// .map(result => {
// result.data = result.data;
// return result;
// })
// .map(result => {
// return result;
// })
// .map(result => {
// if (!result) { return []; }
// if (this._paginator.pageIndex === 0) { this.totalCount = result.totalCount; }
// return result.data.map(item => {
// item['datasets'].map(dmp => {
// dmp.url = 'datasets/edit/' + dmp.url;
// dmp.all = 'datasets/dmp/' + item.id;
// return dmp;
// });
// return item;
// });
// });
// }
// disconnect() {
// }
// }

View File

@ -2,30 +2,30 @@
<a [routerLink]="isPublic ? ['/explore-plans/publicOverview/' + dmp.id] : ['/plans/overview/' + dmp.id]" class="pointer">
<div class="d-flex flex-direction-row">
<div class="col-auto dmp-label">{{ 'DMP-LISTING.DMP' | translate }}</div>
<div *ngIf="!isPublic" class="col-auto ml-auto edited-date">{{ 'DMP-LISTING.EDITED' | translate }}: {{ dmp.modifiedTime | dateTimeCultureFormatter: "d MMMM y" }}</div>
<div *ngIf="!isPublic" class="col-auto ml-auto edited-date">{{ 'DMP-LISTING.EDITED' | translate }}: {{ dmp.updatedAt | dateTimeCultureFormatter: "d MMMM y" }}</div>
<div *ngIf="isPublic" class="col-auto ml-auto edited-date">{{ 'DMP-LISTING.PUBLISHED' | translate }}: {{ dmp.publishedAt | dateTimeCultureFormatter: "d MMMM y" }}</div>
</div>
<div class="col-auto" [ngClass]="{'dmp-title': !isDraft, 'dmp-title-draft': isDraft}">{{dmp.label}}</div>
<div class="dmp-subtitle">
<span *ngIf="isUserDMPRelated()" class="col-auto">{{ roleDisplay(dmp.users) }}</span>
<span *ngIf="isUserDMPRelated()">.</span>
<span class="col-auto" *ngIf="dmp.status === 1 && dmp.public === true"><span class="material-icons icon-align">public</span>{{'TYPES.DMP-VISIBILITY.PUBLIC' | translate}}</span>
<span *ngIf="dmp.status === 1 && dmp.public === false" class="col-auto"><span class="material-icons icon-align">done</span>{{ enumUtils.toDmpStatusString(dmp.status) }}</span>
<span *ngIf="dmp.status === 0" class=" col-auto draft"><span class="material-icons icon-align">create</span>{{ enumUtils.toDmpStatusString(dmp.status) }}</span>
<span class="col-auto" *ngIf="dmp.status === dmpStatusEnum.Finalized && isPublic"><span class="material-icons icon-align">public</span>{{'TYPES.DMP-VISIBILITY.PUBLIC' | translate}}</span>
<span *ngIf="dmp.status === dmpStatusEnum.Finalized && !isPublic" class="col-auto"><span class="material-icons icon-align">done</span>{{ enumUtils.toDmpStatusString(dmp.status) }}</span>
<span *ngIf="dmp.status === dmpStatusEnum.Draft" class=" col-auto draft"><span class="material-icons icon-align">create</span>{{ enumUtils.toDmpStatusString(dmp.status) }}</span>
<span>.</span>
<span class="col-auto">{{'DMP-LISTING.VERSION' | translate}} {{dmp.version}}</span>
<span>.</span>
<span class="col">{{ 'DMP-LISTING.GRANT' | translate }}: {{dmp.grant}}</span>
<!-- <span class="col">{{ 'DMP-LISTING.GRANT' | translate }}: {{dmp.grant}}</span> -->
</div>
<div class="col-auto dmp-dataset-descriptions-title">{{'DMP-LISTING.CONTAINED-DESCRIPTIONS' | translate}}: ({{ dmp.datasets.length }})
<div class="col-auto dmp-dataset-descriptions-title">{{'DMP-LISTING.CONTAINED-DESCRIPTIONS' | translate}}: ({{ dmp.descriptions.length }})
</div>
<div *ngFor="let dataset of dmp.datasets; let i = index; let last = last" [ngClass]="{'pb-3': i === dmp.datasets.length - 1}">
<div *ngFor="let dataset of dmp.descriptions; let i = index; let last = last" [ngClass]="{'pb-3': i === dmp.descriptions.length - 1}">
<div *ngIf="i < 3">
<div class="col-auto dmp-dataset-descriptions-name" *ngIf="!last && i !== 2">{{dataset.label}},</div>
<div class="col-auto dmp-dataset-descriptions-name" *ngIf="last || i == 2">{{dataset.label}}</div>
</div>
</div>
<a class="d-flex justify-content-center pb-3 show-more" *ngIf="dmp.datasets.length > 3" [routerLink]="isPublic ? ['/explore-plans/publicOverview/' + dmp.id] : ['/plans/overview/' + dmp.id]"><u>{{'GENERAL.ACTIONS.SHOW-MORE' | translate}}</u></a>
<a class="d-flex justify-content-center pb-3 show-more" *ngIf="dmp.descriptions.length > 3" [routerLink]="isPublic ? ['/explore-plans/publicOverview/' + dmp.id] : ['/plans/overview/' + dmp.id]"><u>{{'GENERAL.ACTIONS.SHOW-MORE' | translate}}</u></a>
</a>
<div class="dmp-card-actions">
<a class="col-auto border-right pointer" [matMenuTriggerFor]="exportMenu"><span class="material-icons icon-align pr-2">open_in_new</span>{{'DMP-LISTING.ACTIONS.EXPORT' | translate}}</a>
@ -68,92 +68,3 @@
</button>
</mat-menu>
</div>
<!-- <div class="listing-item">
<a [routerLink]="isPublic ? ['/explore-plans/publicOverview/' + dmp.id] : ['/plans/overview/' + dmp.id]">
<div class="col">
<div class="row">
<div class="col-12 gray-container container-header">
<p>{{dmp.grantAbbreviation}}</p>
<button *ngIf="isDraft" mat-icon-button [matMenuTriggerFor]="actionsMenu" class="ml-auto" (click)="$event.preventDefault(); $event.stopPropagation();">
<mat-icon class="more-horiz">more_horiz</mat-icon>
</button>
<mat-menu #actionsMenu="matMenu">
<button mat-menu-item (click)="editClicked(dmp.id)" class="menu-item" *ngIf="!isPublic">
<mat-icon>edit</mat-icon>{{ 'DMP-LISTING.ACTIONS.EDIT' | translate }}
</button>
<button mat-menu-item (click)="openShareDialog(dmp.id,dmp.label)" *ngIf="!isPublic">
<mat-icon>share</mat-icon>{{'DMP-LISTING.ACTIONS.INVITE' | translate}}
</button>
<button mat-menu-item (click)="addDataset(dmp.id)" *ngIf="!isPublic">
<mat-icon>add</mat-icon>{{'DMP-LISTING.ACTIONS.ADD-DATASET' | translate}}
</button>
<button mat-menu-item (click)="showDatasets(dmp.id, dmp.label)">
<mat-icon>list</mat-icon>{{'DMP-LISTING.ACTIONS.DATASETS' | translate}}
</button>
<button mat-menu-item (click)="viewVersions(dmp.groupId, dmp.label)">
<mat-icon>library_books</mat-icon>{{'DMP-LISTING.ACTIONS.VIEW-VERSION' | translate}}
</button>
</mat-menu>
</div>
</div>
<div class="row">
<div class="col-auto">
<mat-icon *ngIf="isDraft" matTooltip="{{'DMP-LISTING.TOOLTIP.DMP-STATUS.DRAFT' | translate}}" class="draft-icon">
lock_open
</mat-icon>
<mat-icon *ngIf="isFinalized && !isPublished" matTooltip="{{'DMP-LISTING.TOOLTIP.DMP-STATUS.FINALIZED' | translate}}" class="lock-icon">
lock
</mat-icon>
<div *ngIf="isPublished" class="outer-circle"><div class="inner-circle" matTooltip="{{'DMP-LISTING.TOOLTIP.DMP-STATUS.PUBLISHED' | translate}}"></div></div>
</div>
<div class="col">
<div class="row d-flex flex-wrap">
<div class="col pl-0">
<h4 class="title pl-0" *ngIf="isDraft">
<span>{{ 'TYPES.DMP.DRAFT' | translate }}:</span> {{dmp.label}}
</h4>
<h4 class="title pl-0" *ngIf="!isDraft">{{dmp.label}}</h4>
</div>
</div>
<div class="row">
<div class="col-auto pl-0">
<p class="mt-1 description">{{dmp.description}}</p>
</div>
<div class="col-auto about-item ml-auto">
<p>{{'DMP-LISTING.COLUMNS.VERSION' | translate}} : {{dmp.version}}</p>
</div>
</div>
<div class="row">
<div class="col-auto about-item pl-0" *ngIf="!isPublic">
<mat-icon class="gray-icon pt-2" matTooltip="{{'DMP-LISTING.TOOLTIP.LEVEL-OF-ACCESS' | translate}}">
settings
</mat-icon>
<h4 class="mt-1 ml-1 mr-3 p-1 role">{{roleDisplay(dmp.users).toUpperCase()}}</h4>
</div>
<div class="col-auto about-item" [ngClass]="isPublic ? 'pl-0' : ''">
<a class="datasets-counter" [routerLink]="isPublic ? ['/explore-plans/publicEdit/' + dmp.id] : ['/plans/edit/' + dmp.id]" [queryParams]="{ tab: 'datasetDescriptions' }">
<mat-icon class="gray-icon pt-2" matTooltip="{{'DMP-LISTING.TOOLTIP.INVOLVED-DATASETS' | translate}}">
storage
</mat-icon>
<h4 class="mt-1 ml-1 mr-3 p-1">{{dmp.datasets.length}}</h4>
</a>
</div>
<div class="col-auto about-item pt-2 pl-0">
<mat-icon class="gray-icon" matTooltip="{{'DMP-LISTING.TOOLTIP.TEMPLATES-INVOLVED' | translate}}">assignment</mat-icon>
<div *ngFor="let profile of dmp.associatedProfiles" class="pb-1">
<div matTooltip="{{profile.label}}" class="chip ml-2 mr-2">{{profile.label}}</div>
</div>
</div>
<div class="col-auto about-item ml-auto">
<p *ngIf="isDraft">{{'DMP-BLUEPRINT-LISTING.COLUMNS.LAST-EDITED' | translate}} {{dmp.modifiedTime | date: "shortDate"}}</p>
<p *ngIf="isFinalized && !isPublished">{{'TYPES.DMP.FINALISED' | translate}} {{dmp.finalizedAt | date: "shortDate"}}</p>
<p *ngIf="isPublished">{{'DMP-BLUEPRINT-LISTING.COLUMNS.PUBLISHED' | translate}} {{dmp.publishedAt | date: "shortDate"}}</p>
</div>
</div>
</div>
</div>
</div>
</a>
</div> -->
<!-- <mat-divider *ngIf="showDivider"></mat-divider> -->

View File

@ -8,7 +8,7 @@ import { DmpBlueprintSectionFieldCategory } from '@app/core/common/enum/dmp-blue
import { DmpBlueprintSystemFieldType } from '@app/core/common/enum/dmp-blueprint-system-field-type';
import { Role } from '@app/core/common/enum/role';
import { DescriptionTemplatesInSection, DmpBlueprint, DmpBlueprintDefinition, DmpBlueprintDefinitionSection, FieldInSection } from '@app/core/model/dmp-blueprint/dmp-blueprint';
import { DmpModel } from '@app/core/model/dmp/dmp';
import { Dmp, DmpModel } from '@app/core/model/dmp/dmp';
import { DmpBlueprintService } from '@app/core/services/dmp/dmp-blueprint.service';
import { DmpService } from '@app/core/services/dmp/dmp.service';
import { LockService } from '@app/core/services/lock/lock.service';
@ -25,7 +25,6 @@ import * as FileSaver from 'file-saver';
import { map, takeUntil } from 'rxjs/operators';
import { nameof } from 'ts-simple-nameof';
import { DmpStatus } from '../../../../core/common/enum/dmp-status';
import { DmpListingModel } from '../../../../core/model/dmp/dmp-listing';
import { AuthService } from '../../../../core/services/auth/auth.service';
import { CloneDialogComponent } from '../../clone/clone-dialog/clone-dialog.component';
import { DmpEditorModel } from '../../editor/dmp-editor.model';
@ -34,6 +33,7 @@ import { FunderFormModel } from '../../editor/grant-tab/funder-form-model';
import { GrantTabModel } from '../../editor/grant-tab/grant-tab-model';
import { ProjectFormModel } from '../../editor/grant-tab/project-form-model';
import { DmpInvitationDialogComponent } from '../../invitation/dmp-invitation-dialog.component';
import { DmpUserRole } from '@app/core/common/enum/dmp-user-role';
@Component({
selector: 'app-dmp-listing-item-component',
@ -42,16 +42,17 @@ import { DmpInvitationDialogComponent } from '../../invitation/dmp-invitation-di
})
export class DmpListingItemComponent extends BaseComponent implements OnInit {
@Input() dmp: DmpListingModel;
@Input() dmp: Dmp;
@Input() showDivider: boolean = true;
@Input() isPublic: boolean;
@Output() onClick: EventEmitter<DmpListingModel> = new EventEmitter();
@Output() onClick: EventEmitter<Dmp> = new EventEmitter();
isDraft: boolean;
isFinalized: boolean;
isPublished: boolean;
dmpModel: DmpEditorModel;
dmpFormGroup: UntypedFormGroup;
dmpStatusEnum = DmpStatus;
constructor(
private router: Router,
@ -81,7 +82,7 @@ export class DmpListingItemComponent extends BaseComponent implements OnInit {
this.isDraft = false;
this.isFinalized = true;
this.isPublished = false;
if (this.dmp.public == true) { this.isPublished = true }
// if (this.dmp.public == true) { this.isPublished = true }
}
}
@ -110,29 +111,17 @@ export class DmpListingItemComponent extends BaseComponent implements OnInit {
this.router.navigate(['/datasets/dmp/' + rowId, { dmpLabel: rowLabel }]);
}
viewVersions(rowId: String, rowLabel: String, dmp: DmpListingModel) {
if (dmp.public && !this.isUserOwner(dmp)) {
let url = this.router.createUrlTree(['/explore-plans/versions/', rowId, { groupLabel: rowLabel }]);
window.open(url.toString(), '_blank');
// this.router.navigate(['/explore-plans/versions/' + rowId], { queryParams: { groupLabel: rowLabel } });
} else {
let url = this.router.createUrlTree(['/plans/versions/', rowId, { groupLabel: rowLabel }]);
window.open(url.toString(), '_blank');
// this.router.navigate(['/plans/versions/' + rowId], { queryParams: { groupLabel: rowLabel } });
viewVersions(rowId: String, rowLabel: String, dmp: Dmp) {
// if (dmp.public && !this.isUserOwner(dmp)) {
// let url = this.router.createUrlTree(['/explore-plans/versions/', rowId, { groupLabel: rowLabel }]);
// window.open(url.toString(), '_blank');
// // this.router.navigate(['/explore-plans/versions/' + rowId], { queryParams: { groupLabel: rowLabel } });
// } else {
// let url = this.router.createUrlTree(['/plans/versions/', rowId, { groupLabel: rowLabel }]);
// window.open(url.toString(), '_blank');
// // this.router.navigate(['/plans/versions/' + rowId], { queryParams: { groupLabel: rowLabel } });
// }
}
}
// itemClicked() {
// this.onClick.emit(this.dmp);
// }
// grantClicked(grantId: String) {
// this.router.navigate(['/grants/edit/' + grantId]);
// }
// datasetClicked(dmpId: string) {
// this.router.navigate(['/plans/edit/' + dmpId], { queryParams: { tab: "datasetDescriptions" } });
// }
roleDisplay(value: any) {
const principalId: string = this.authentication.userId()?.toString();
@ -159,41 +148,41 @@ export class DmpListingItemComponent extends BaseComponent implements OnInit {
const principalId: string = this.authentication.userId()?.toString();
let isRelated: boolean = false;
if (this.dmp && principalId) {
this.dmp.users.forEach(element => {
if (element.id === principalId) {
isRelated = true;
}
})
// this.dmp.users.forEach(element => {
// if (element.id === principalId) {
// isRelated = true;
// }
// })
}
return isRelated;
}
cloneOrNewVersionClicked(dmp: DmpListingModel, isNewVersion: boolean) {
this.dmpService.getSingle(dmp.id).pipe(map(data => data as DmpModel))
.pipe(takeUntil(this._destroyed))
.subscribe(data => {
this.dmpModel = new DmpEditorModel();
this.dmpModel.grant = new GrantTabModel();
this.dmpModel.project = new ProjectFormModel();
this.dmpModel.funder = new FunderFormModel();
this.dmpModel.extraProperties = new ExtraPropertiesFormModel();
this.dmpModel.fromModel(data);
this.dmpModel.status = DmpStatus.Draft;
this.dmpFormGroup = this.dmpModel.buildForm();
cloneOrNewVersionClicked(dmp: Dmp, isNewVersion: boolean) {
// this.dmpService.getSingle(dmp.id).pipe(map(data => data as DmpModel))
// .pipe(takeUntil(this._destroyed))
// .subscribe(data => {
// this.dmpModel = new DmpEditorModel();
// this.dmpModel.grant = new GrantTabModel();
// this.dmpModel.project = new ProjectFormModel();
// this.dmpModel.funder = new FunderFormModel();
// this.dmpModel.extraProperties = new ExtraPropertiesFormModel();
// this.dmpModel.fromModel(data);
// this.dmpModel.status = DmpStatus.Draft;
// this.dmpFormGroup = this.dmpModel.buildForm();
if (!isNullOrUndefined(this.dmpFormGroup.get('profile').value)) {
this.getBlueprintDefinition(Guid.parse(this.dmpFormGroup.get('profile').value), result => {
this.checkForGrant(result.definition);
this.checkForFunder(result.definition);
this.checkForProject(result.definition);
});
}
// if (!isNullOrUndefined(this.dmpFormGroup.get('profile').value)) {
// this.getBlueprintDefinition(Guid.parse(this.dmpFormGroup.get('profile').value), result => {
// this.checkForGrant(result.definition);
// this.checkForFunder(result.definition);
// this.checkForProject(result.definition);
// });
// }
if (!isNewVersion) {
this.dmpFormGroup.get('label').setValue(dmp.label + " New");
}
this.openCloneDialog(isNewVersion);
});
// if (!isNewVersion) {
// this.dmpFormGroup.get('label').setValue(dmp.label + " New");
// }
// this.openCloneDialog(isNewVersion);
// });
}
private getBlueprintDefinition(blueprintId: Guid, successFunction) {
@ -281,25 +270,25 @@ export class DmpListingItemComponent extends BaseComponent implements OnInit {
cancelButton: this.language.instant('DMP-EDITOR.CLONE-DIALOG.CANCEL'),
}
});
dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => {
if (result) {
if (!isNewVersion) {
this.dmpService.clone(this.dmpFormGroup.getRawValue(), this.dmp.id)
.pipe(takeUntil(this._destroyed))
.subscribe(
complete => this.onCloneOrNewVersionCallbackSuccess(complete),
error => this.onCloneOrNewVersionCallbackError(error)
);
} else if (isNewVersion) {
this.dmpService.newVersion(this.dmpFormGroup.getRawValue(), this.dmp.id)
.pipe(takeUntil(this._destroyed))
.subscribe(
complete => this.onCloneOrNewVersionCallbackSuccess(complete),
error => this.onCloneOrNewVersionCallbackError(error)
);
}
}
});
// dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => {
// if (result) {
// if (!isNewVersion) {
// this.dmpService.clone(this.dmpFormGroup.getRawValue(), this.dmp.id)
// .pipe(takeUntil(this._destroyed))
// .subscribe(
// complete => this.onCloneOrNewVersionCallbackSuccess(complete),
// error => this.onCloneOrNewVersionCallbackError(error)
// );
// } else if (isNewVersion) {
// this.dmpService.newVersion(this.dmpFormGroup.getRawValue(), this.dmp.id)
// .pipe(takeUntil(this._destroyed))
// .subscribe(
// complete => this.onCloneOrNewVersionCallbackSuccess(complete),
// error => this.onCloneOrNewVersionCallbackError(error)
// );
// }
// }
// });
}
// newVersion(id: String, label: String) {
@ -307,53 +296,53 @@ export class DmpListingItemComponent extends BaseComponent implements OnInit {
// window.open(url.toString(), '_blank');
// }
downloadXml(id: string) {
this.dmpService.downloadXML(id)
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/xml' });
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
downloadXml(id: Guid) {
// this.dmpService.downloadXML(id)
// .pipe(takeUntil(this._destroyed))
// .subscribe(response => {
// const blob = new Blob([response.body], { type: 'application/xml' });
// const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "xml", id);
});
// FileSaver.saveAs(blob, filename);
// this.matomoService.trackDownload('dmps', "xml", id);
// });
}
downloadDocx(id: string) {
this.dmpService.downloadDocx(id)
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/msword' });
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
downloadDocx(id: Guid) {
// this.dmpService.downloadDocx(id)
// .pipe(takeUntil(this._destroyed))
// .subscribe(response => {
// const blob = new Blob([response.body], { type: 'application/msword' });
// const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "docx", id);
});
// FileSaver.saveAs(blob, filename);
// this.matomoService.trackDownload('dmps', "docx", id);
// });
}
downloadPDF(id: string) {
this.dmpService.downloadPDF(id)
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/pdf' });
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
downloadPDF(id: Guid) {
// this.dmpService.downloadPDF(id)
// .pipe(takeUntil(this._destroyed))
// .subscribe(response => {
// const blob = new Blob([response.body], { type: 'application/pdf' });
// const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "pdf", id);
});
// FileSaver.saveAs(blob, filename);
// this.matomoService.trackDownload('dmps', "pdf", id);
// });
}
downloadJson(id: string) {
this.dmpService.downloadJson(id)
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/json' });
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "json", id);
}, async error => {
this.onExportCallbackError(error);
});
downloadJson(id: Guid) {
// this.dmpService.downloadJson(id)
// .pipe(takeUntil(this._destroyed))
// .subscribe(response => {
// const blob = new Blob([response.body], { type: 'application/json' });
// const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
// FileSaver.saveAs(blob, filename);
// this.matomoService.trackDownload('dmps', "json", id);
// }, async error => {
// this.onExportCallbackError(error);
// });
}
async onExportCallbackError(error: any) {
@ -406,7 +395,7 @@ export class DmpListingItemComponent extends BaseComponent implements OnInit {
});
}
isDraftDmp(activity: DmpListingModel) {
isDraftDmp(activity: Dmp) {
return activity.status == DmpStatus.Draft;
}
@ -440,8 +429,8 @@ export class DmpListingItemComponent extends BaseComponent implements OnInit {
this.uiNotificationService.snackBarNotification(error.error.message ? error.error.message : this.language.instant('GENERAL.SNACK-BAR.UNSUCCESSFUL-UPDATE'), SnackBarNotificationLevel.Error);
}
isUserOwner(activity: DmpListingModel): boolean {
const principalId: string = this.authentication.userId()?.toString();
if (principalId) return !!activity.users.find(x => (x.role === Role.Owner) && (principalId === x.id));
isUserOwner(dmp: Dmp): boolean {
const principalId: Guid = this.authentication.userId();
if (principalId) return !!dmp.dmpUsers.find(x => (x.role === DmpUserRole.Owner) && (principalId === x.id));
}
}

View File

@ -1,5 +1,5 @@
<mat-button-toggle-group class="lang-menu" vertical (change)="onLanguageSelected($event)" [value]="this.getCurrentLanguage().value">
<mat-button-toggle-group class="lang-menu" vertical (change)="onLanguageSelected($event)" [value]="this.getCurrentLanguage()">
<div *ngFor="let lang of languages">
<mat-button-toggle class="lang-button" [value]="lang.value">{{lang.label | translate}}</mat-button-toggle>
<mat-button-toggle class="lang-button" [value]="lang">{{'GENERAL.LANGUAGES.' + lang | translate}}</mat-button-toggle>
</div>
</mat-button-toggle-group>

View File

@ -6,6 +6,8 @@ import { UserServiceOld } from '@app/core/services/user/user.service-old';
import { takeUntil } from 'rxjs/operators';
import { BaseComponent } from '@common/base/base.component';
import { ConfigurationService } from '@app/core/services/configuration/configuration.service';
import { MatButtonToggleChange } from '@angular/material/button-toggle';
import { UserService } from '@app/core/services/user/user.service';
@Component({
selector: 'app-language',
@ -15,47 +17,49 @@ import { ConfigurationService } from '@app/core/services/configuration/configura
export class LanguageComponent extends BaseComponent implements OnInit {
@Output() languageChange: EventEmitter<any> = new EventEmitter();
languages = [];
languages: string[] = [];
constructor(
private router: Router,
private authentication: AuthService,
private languageService: LanguageService,
private userService: UserServiceOld,
private configurationService:ConfigurationService
private userService: UserService,
private languageService: LanguageService
) {
super();
this.languages = this.configurationService.availableLanguages;
this.languages = this.languageService.getAvailableLanguagesCodes();
}
ngOnInit() {
this.languageChange.emit(this.getCurrentLanguage().value)
this.languageChange.emit(this.getCurrentLanguage())
}
public isAuthenticated(): boolean {
return this.authentication.currentAccountIsAuthenticated();
}
public getCurrentLanguage(): any {
const lang = this.languages.find(lang => lang.value === this.languageService.getCurrentLanguage());
public getCurrentLanguage(): string {
const lang = this.languages.find(lang => lang === this.languageService.getCurrentLanguage());
return lang;
}
onLanguageSelected(selectedLanguage: any) {
onLanguageSelected(selectedLanguage: MatButtonToggleChange) {
if (this.isAuthenticated()) {
const langMap = new Map<string, string>();
langMap.set('language', selectedLanguage.value);
this.userService.updateUserSettings({ language: this.languages.find(lang => lang.value === selectedLanguage.value) })
.pipe(takeUntil(this._destroyed))
.subscribe((response) => {
//TODO: refactor - save language selection to user profile
// this.userService.updateUserSettings({ language: this.languages.find(lang => lang === selectedLanguage.value) })
// .pipe(takeUntil(this._destroyed))
// .subscribe((response) => {
// this.languageService.changeLanguage(selectedLanguage.value);
// this.authentication.refresh()
// .pipe(takeUntil(this._destroyed))
// .subscribe(innerResponse => { this.router.navigateByUrl(this.router.url); });
// },
// error => {
// console.log(error);
// });
this.languageService.changeLanguage(selectedLanguage.value);
this.authentication.refresh()
.pipe(takeUntil(this._destroyed))
.subscribe(innerResponse => { this.router.navigateByUrl(this.router.url); });
},
error => {
console.log(error);
});
this.router.navigateByUrl(this.router.url);
} else {
this.languageService.changeLanguage(selectedLanguage.value);
this.router.navigateByUrl(this.router.url);

View File

@ -54,8 +54,8 @@ export class NavbarComponent extends BaseComponent implements OnInit {
super();
this.location = location;
this.sidebarVisible = false;
this.languages = this.configurationService.availableLanguages;
this.selectedLanguage = this.configurationService.defaultLanguage || 'en';
this.languages = this.languageService.getAvailableLanguagesCodes();
this.selectedLanguage = this.languageService.getDefaultLanguagesCode();
}
ngOnInit() {

View File

@ -4,32 +4,32 @@
<div *ngIf="showItem(groupMenuItem);">
<hr *ngIf="!firstGroup">
<mat-list-item routerLinkActive="active" [routerLinkActiveOptions]="{exact: true}" *ngFor="let groupMenuRoute of groupMenuItem.routes; let first = first" class="nav-item" [ngClass]="{'mt-4': first && firstGroup}">
<a class="new-dmp nav-link nav-row" *ngIf="groupMenuRoute.path !== '/contact-support' && groupMenuRoute.path !== '/co-branding' && groupMenuRoute.path !== '/feedback' && groupMenuRoute.path !== '/datasets'" [routerLink]="[groupMenuRoute.path]" [ngClass]="{'dmp-tour': groupMenuRoute.path == '/plans'}">
<i class="material-icons icon">{{ groupMenuRoute.icon }}</i>
<i *ngIf="groupMenuRoute.path == '/plans'" class="material-icons icon-mask">person</i>
<a class="new-dmp nav-link nav-row" *ngIf="groupMenuRoute.path !== '/contact-support' && groupMenuRoute.path !== '/co-branding' && groupMenuRoute.path !== '/feedback' && groupMenuRoute.path !== '/descriptions'" [routerLink]="[groupMenuRoute.path]" [ngClass]="{'dmp-tour': groupMenuRoute.path == '/plans'}">
<i class="material-symbols-outlined icon">{{ groupMenuRoute.icon }}</i>
<i *ngIf="groupMenuRoute.path == '/plans'" class="material-symbols-outlined icon-mask">person</i>
<span [ngClass]="{'pl-0': groupMenuRoute.path == '/plans'}">{{groupMenuRoute.title | translate}}</span>
</a>
<a class="nav-link nav-row dataset-tour" *ngIf="groupMenuRoute.path === '/datasets'" [routerLink]="[groupMenuRoute.path]">
<a class="nav-link nav-row dataset-tour" *ngIf="groupMenuRoute.path === '/descriptions'" [routerLink]="[groupMenuRoute.path]">
<span class="inner-line"></span>
<i class="material-icons icon">{{ groupMenuRoute.icon }}</i>
<i class="material-icons icon-mask">person</i>
<i class="material-symbols-outlined icon">{{ groupMenuRoute.icon }}</i>
<i class="material-symbols-outlined icon-mask">person</i>
<span class="pl-0">{{groupMenuRoute.title | translate}}</span>
</a>
<a class="nav-link nav-row" *ngIf="groupMenuRoute.path === '/co-branding'" href="/splash/resources/co-branding.html">
<i class="material-icons icon">{{ groupMenuRoute.icon }}</i>
<span>{{groupMenuRoute.title | translate}} <span class="material-icons icon-external">open_in_new</span></span>
<i class="material-symbols-outlined icon">{{ groupMenuRoute.icon }}</i>
<span>{{groupMenuRoute.title | translate}} <span class="material-symbols-outlined icon-external">open_in_new</span></span>
</a>
<a class="nav-link nav-row" *ngIf="groupMenuRoute.path === '/contact-support' && this.isAuthenticated()" [routerLink]="[groupMenuRoute.path]">
<i class="material-icons icon">{{ groupMenuRoute.icon }}</i>
<i class="material-symbols-outlined icon">{{ groupMenuRoute.icon }}</i>
<span>{{groupMenuRoute.title | translate}}</span>
</a>
<a class="nav-link nav-row" *ngIf="groupMenuRoute.path === '/contact-support' && !this.isAuthenticated()" href="/splash/contact.html">
<i class="material-icons icon">{{ groupMenuRoute.icon }}</i>
<span>{{groupMenuRoute.title | translate}} <span class="material-icons icon-external">open_in_new</span></span>
<i class="material-symbols-outlined icon">{{ groupMenuRoute.icon }}</i>
<span>{{groupMenuRoute.title | translate}} <span class="material-symbols-outlined icon-external">open_in_new</span></span>
</a>
<a class="nav-link nav-row" *ngIf="groupMenuRoute.path === '/feedback'" (click)="openFeedback(groupMenuRoute)">
<i class="material-icons icon">{{ groupMenuRoute.icon }}</i>
<span>{{groupMenuRoute.title | translate}} <span class="material-icons icon-external">open_in_new</span></span>
<i class="material-symbols-outlined icon">{{ groupMenuRoute.icon }}</i>
<span>{{groupMenuRoute.title | translate}} <span class="material-symbols-outlined icon-external">open_in_new</span></span>
</a>
</mat-list-item>
</div>

View File

@ -30,7 +30,7 @@ export const GENERAL_ROUTES: RouteInfo[] = [
];
export const DMP_ROUTES: RouteInfo[] = [
{ path: '/plans', title: 'SIDE-BAR.MY-DMPS', icon: 'library_books' },
{ path: '/datasets', title: 'SIDE-BAR.MY-DESCRIPTIONS', icon: 'dns' },
{ path: '/descriptions', title: 'SIDE-BAR.MY-DESCRIPTIONS', icon: 'dns' },
// { path: '/quick-wizard', title: 'SIDE-BAR.QUICK-WIZARD', icon: 'play_circle_outline' },
// { path: '/plans/new', title: 'SIDE-BAR.ADD-EXPERT', icon: 'playlist_add' }
];
@ -51,18 +51,18 @@ export const PUBLIC_ROUTES: RouteInfo[] = [
export const ADMIN_ROUTES: RouteInfo[] = [
{ path: '/dmp-blueprints', title: 'SIDE-BAR.DMP-BLUEPRINTS', icon: 'library_books' },
{ path: '/description-templates', title: 'SIDE-BAR.DESCRIPTION-TEMPLATES', icon: 'library_books' },
{ path: '/description-template-type', title: 'SIDE-BAR.DESCRIPTION-TEMPLATE-TYPES', icon: 'library_books' },
{ path: '/references', title: 'SIDE-BAR.REFERENCES', icon: 'library_books' },
{ path: '/reference-type', title: 'SIDE-BAR.REFERENCE-TYPES', icon: 'library_books' },
{ path: '/tenants', title: 'SIDE-BAR.TENANTS', icon: 'library_books' },
{ path: '/description-templates', title: 'SIDE-BAR.DESCRIPTION-TEMPLATES', icon: 'description' },
{ path: '/description-template-type', title: 'SIDE-BAR.DESCRIPTION-TEMPLATE-TYPES', icon: 'stack' },
{ path: '/references', title: 'SIDE-BAR.REFERENCES', icon: 'dataset_linked' },
{ path: '/reference-type', title: 'SIDE-BAR.REFERENCE-TYPES', icon: 'add_link' },
{ path: '/tenants', title: 'SIDE-BAR.TENANTS', icon: 'tenancy' },
{ path: '/users', title: 'SIDE-BAR.USERS', icon: 'people' },
{ path: '/languages', title: 'SIDE-BAR.LANGUAGES', icon: 'language' },
{ path: '/supportive-material', title: 'SIDE-BAR.SUPPORTIVE-MATERIAL', icon: 'import_contacts' }
];
export const DATASET_TEMPLATE_ROUTES: RouteInfo[] = [
{ path: '/description-templates', title: 'SIDE-BAR.DESCRIPTION-TEMPLATES', icon: 'library_books' }
{ path: '/description-templates', title: 'SIDE-BAR.DESCRIPTION-TEMPLATES', icon: 'description' }
];
export const INFO_ROUTES: RouteInfo[] = [

View File

@ -1,13 +1,10 @@
<div class="supportive-material-editor">
<form *ngIf="formGroup" (ngSubmit)="formSubmit()">
<div>
<mat-card class="col-md-8 offset-md-2">
<mat-card-header>
<mat-card-title>{{'SUPPORTIVE-MATERIAL-EDITOR.TITLE' | translate}}</mat-card-title>
</mat-card-header>
<div>
<div class ="material">
<mat-form-field>
<mat-card class="col-md-8 offset-md-2 p-3">
<div class="row">
<div class="col">
<mat-form-field class="w-100">
<mat-label>{{'SUPPORTIVE-MATERIAL-EDITOR.FIELDS.MATERIAL-TYPE' | translate}}</mat-label>
<mat-select (selectionChange)="selectedMaterialChanged($event.value)" name="type" [formControl]="formGroup.get('type')" required>
<mat-option *ngFor="let type of supportiveMaterialTypeEnum" [value]="type">
@ -18,10 +15,10 @@
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
<div class ="lang">
<mat-form-field>
<div class="col">
<mat-form-field class="w-100">
<mat-label>{{'SUPPORTIVE-MATERIAL-EDITOR.FIELDS.LANGUAGE' | translate}}</mat-label>
<mat-select (selectionChange)="selectedLangChanged($event.value)" name= "languageCode" [formControl]="formGroup.get('languageCode')">
<mat-select (selectionChange)="selectedLangChanged($event.value)" name="languageCode" [formControl]="formGroup.get('languageCode')">
<mat-option *ngFor="let languageCode of availableLanguageCodes" [value]="languageCode">
{{languageCode}}
</mat-option>
@ -31,9 +28,9 @@
</mat-form-field>
</div>
</div>
<!-- <mat-card-title><div>{{selectedMaterial.name | translate}}</div></mat-card-title> -->
<mat-card-content *ngIf="formGroup.get('type').value>=0 && formGroup.get('languageCode').value">
<editor [init]="{
<div class="row" *ngIf="formGroup.get('type').value != null && formGroup.get('languageCode').value">
<div class="col">
<editor class="w-100" [init]="{
base_url: '/tinymce',
suffix: '.min',
height: 800,
@ -53,7 +50,8 @@
alignleft aligncenter alignright alignjustify | \
bullist numlist outdent indent | code codesample | searchreplace | preview | removeformat | help'
}" [formControl]="formGroup.get('payload')"></editor>
</mat-card-content>
</div>
</div>
</mat-card>
<button mat-fab class="mat-fab-bottom-right save-btn" matTooltip="{{'SUPPORTIVE-MATERIAL-EDITOR.ACTIONS.SAVE' | translate}}" type="submit">
<mat-icon class="mat-24">save</mat-icon>

View File

@ -30,7 +30,7 @@ import { SupportiveMaterialEditorResolver } from './supportive-material-editor.r
import { IsActive } from '@app/core/common/enum/is-active.enum';
import { AppPermission } from '@app/core/common/enum/permission.enum';
import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component';
import { LanguageV2Service } from '@app/core/services/language/language-v2.service';
import { LanguageHttpService } from '@app/core/services/language/language.http.service';
import { nameof } from 'ts-simple-nameof';
import { Language } from '@app/core/model/language/language';
import { LanguageLookup } from '@app/core/query/language.lookup';
@ -69,7 +69,7 @@ export class SupportiveMaterialEditorComponent extends BaseEditor<SupportiveMate
public enumUtils: EnumUtils,
private supportiveMaterialService: SupportiveMaterialService,
private languageService: LanguageService,
private languageV2Service: LanguageV2Service,
private languageV2Service: LanguageHttpService,
private logger: LoggingService,
private supportiveMaterialEditorService: SupportiveMaterialEditorService,
private fileUtils: FileUtils,

View File

@ -85,7 +85,7 @@ export class UserProfileComponent extends BaseComponent implements OnInit, OnDes
private matomoService: MatomoService
) {
super();
this.languages = this.configurationService.availableLanguages;
this.languages = this.languageService.getAvailableLanguagesCodes();
}
ngOnInit() {
@ -99,7 +99,7 @@ export class UserProfileComponent extends BaseComponent implements OnInit, OnDes
//result['additionalinfo'] = JSON.parse(result['additionalinfo']);
this.userProfileEditorModel = new UserProfileEditorModel().fromModel(result);
this.formGroup = this.userProfileEditorModel.buildForm(this.configurationService.availableLanguages);
this.formGroup = this.userProfileEditorModel.buildForm(this.languageService.getAvailableLanguagesCodes());
// this.formGroup = new FormBuilder().group({
// language: new FormControl(result['language'] ? availableLanguages.filter(x => x.value === result['language']['value']).pop() : '', [Validators.required]),
// timezone: new FormControl(result['timezone'], [Validators.required]),

View File

@ -7,49 +7,6 @@
"Url": "localhost:5000/"
},
"defaultCulture": "en-US",
"defaultLanguage": "en",
"availableLanguages": [
{
"label": "GENERAL.LANGUAGES.ENGLISH",
"value": "en"
},
{
"label": "GENERAL.LANGUAGES.GREEK",
"value": "gr"
},
{
"label": "GENERAL.LANGUAGES.SPANISH",
"value": "es"
},
{
"label": "GENERAL.LANGUAGES.GERMAN",
"value": "de"
},
{
"label": "GENERAL.LANGUAGES.TURKISH",
"value": "tr"
},
{
"label": "GENERAL.LANGUAGES.SLOVAK",
"value": "sk"
},
{
"label": "GENERAL.LANGUAGES.SERBIAN",
"value": "sr"
},
{
"label": "GENERAL.LANGUAGES.PORTUGUESE",
"value": "pt"
},
{
"label": "GENERAL.LANGUAGES.CROATIAN",
"value": "hr"
},
{
"label": "GENERAL.LANGUAGES.POLISH",
"value": "pl"
}
],
"defaultBlueprintId": "86635178-36a6-484f-9057-a934e4eeecd5",
"keycloak": {
"enabled": true,

View File

@ -182,16 +182,16 @@
"DOC": "Dokument"
},
"LANGUAGES": {
"ENGLISH": "Englisch",
"GREEK": "Griechisch",
"SPANISH": "Spanisch",
"GERMAN": "German",
"TURKISH": "Turkish",
"SLOVAK": "Slovak",
"SERBIAN": "Serbian",
"PORTUGUESE": "Portuguese",
"CROATIAN": "Croatian",
"POLISH": "Polish"
"en": "Englisch",
"gr": "Griechisch",
"es": "Spanisch",
"de": "German",
"tr": "Turkish",
"sk": "Slovak",
"sr": "Serbian",
"pt": "Portuguese",
"hr": "Croatian",
"pl": "Polish"
}
},
"COOKIE": {

View File

@ -183,16 +183,16 @@
"DOC": "Document"
},
"LANGUAGES": {
"ENGLISH": "English",
"GREEK": "Greek",
"SPANISH": "Spanish",
"GERMAN": "German",
"TURKISH": "Turkish",
"SLOVAK": "Slovak",
"SERBIAN": "Serbian",
"PORTUGUESE": "Portuguese",
"CROATIAN": "Croatian",
"POLISH": "Polish"
"en": "English",
"gr": "Greek",
"es": "Spanish",
"de": "German",
"tr": "Turkish",
"sk": "Slovak",
"sr": "Serbian",
"pt": "Portuguese",
"hr": "Croatian",
"pl": "Polish"
}
},
"HYBRID-LISTING": {

View File

@ -182,16 +182,16 @@
"DOC": "Documento"
},
"LANGUAGES": {
"ENGLISH": "Inglés",
"GREEK": "Griego",
"SPANISH": "Español",
"GERMAN": "Alemán",
"TURKISH": "Turco",
"SLOVAK": "Eslovaco",
"SERBIAN": "Serbio",
"PORTUGUESE": "Portugués",
"CROATIAN": "Croatian",
"POLISH": "Polish"
"en": "Inglés",
"gr": "Griego",
"es": "Español",
"de": "Alemán",
"tr": "Turco",
"sk": "Eslovaco",
"sr": "Serbio",
"pt": "Portugués",
"hr": "Croatian",
"pl": "Polish"
}
},
"COOKIE": {

View File

@ -182,16 +182,16 @@
"DOC": "Document"
},
"LANGUAGES": {
"ENGLISH": "Αγγλικά",
"GREEK": "Ελληνικά",
"SPANISH": "Ισπανικά",
"GERMAN": "Γερμανικά",
"TURKISH": "Τούρκικα",
"SLOVAK": "Σλοβάκικα",
"SERBIAN": "Σερβικά",
"PORTUGUESE": "Πορτογαλικά",
"CROATIAN": "Κροατικά",
"POLISH": "Πολωνικά"
"en": "Αγγλικά",
"gr": "Ελληνικά",
"es": "Ισπανικά",
"de": "Γερμανικά",
"tr": "Τούρκικα",
"sk": "Σλοβάκικα",
"sr": "Σερβικά",
"pt": "Πορτογαλικά",
"hr": "Κροατικά",
"pl": "Πολωνικά"
}
},
"COOKIE": {

View File

@ -182,16 +182,16 @@
"DOC": "DOCX"
},
"LANGUAGES": {
"ENGLISH": "Engleski",
"GREEK": "Grčki",
"SPANISH": "Španjolski",
"GERMAN": "Njemački",
"TURKISH": "Turski",
"SLOVAK": "Slovački",
"SERBIAN": "Srpski",
"PORTUGUESE": "Portugalski",
"CROATIAN": "Hrvatski",
"POLISH": "Poljski"
"en": "Engleski",
"gr": "Grčki",
"es": "Španjolski",
"de": "Njemački",
"tr": "Turski",
"sk": "Slovački",
"sr": "Srpski",
"pt": "Portugalski",
"hr": "Hrvatski",
"pl": "Poljski"
}
},
"COOKIE": {

View File

@ -182,16 +182,16 @@
"DOC": "Dokument"
},
"LANGUAGES": {
"ENGLISH": "Angielski",
"GREEK": "Grecki",
"SPANISH": "Hiszpański",
"GERMAN": "Niemiecki",
"TURKISH": "Turecki",
"SLOVAK": "Słowacki",
"SERBIAN": "Serbski",
"PORTUGUESE": "Portugalski",
"CROATIAN": "Chorwacki",
"POLISH": "Polski"
"en": "Angielski",
"gr": "Grecki",
"es": "Hiszpański",
"de": "Niemiecki",
"tr": "Turecki",
"sk": "Słowacki",
"sr": "Serbski",
"pt": "Portugalski",
"hr": "Chorwacki",
"pl": "Polski"
}
},
"COOKIE": {

View File

@ -182,16 +182,16 @@
"DOC": "DOCX"
},
"LANGUAGES": {
"ENGLISH": "Inglês",
"GREEK": "Grego",
"SPANISH": "Espanhol",
"GERMAN": "Alemão",
"TURKISH": "Turco",
"SLOVAK": "Eslovaco",
"SERBIAN": "Sérvio",
"PORTUGUESE": "Português",
"CROATIAN": "Croatian",
"POLISH": "Polish"
"en": "Inglês",
"gr": "Grego",
"es": "Espanhol",
"de": "Alemão",
"tr": "Turco",
"sk": "Eslovaco",
"sr": "Sérvio",
"pt": "Português",
"hr": "Croatian",
"pl": "Polish"
}
},
"COOKIE": {

View File

@ -182,16 +182,16 @@
"DOC": "Dokument"
},
"LANGUAGES": {
"ENGLISH": "Angličtina",
"GREEK": "Gréčtina",
"SPANISH": "Španielčtina",
"GERMAN": "Nemečina",
"TURKISH": "Turečtina",
"SLOVAK": "Slovenčina",
"SERBIAN": "Serbian",
"PORTUGUESE": "Portuguese",
"CROATIAN": "Croatian",
"POLISH": "Polish"
"en": "Angličtina",
"gr": "Gréčtina",
"es": "Španielčtina",
"de": "Nemečina",
"tr": "Turečtina",
"sk": "Slovenčina",
"sr": "Serbian",
"pt": "Portuguese",
"hr": "Croatian",
"pl": "Polish"
}
},
"COOKIE": {

View File

@ -182,16 +182,16 @@
"DOC": "Dokument"
},
"LANGUAGES": {
"ENGLISH": "engleski",
"GREEK": "grčki",
"SPANISH": "španski",
"GERMAN": "nemački",
"TURKISH": "turski",
"SLOVAK": "slovački",
"SERBIAN": "Serbian",
"PORTUGUESE": "Portuguese",
"CROATIAN": "Croatian",
"POLISH": "Polish"
"en": "engleski",
"gr": "grčki",
"es": "španski",
"de": "nemački",
"tr": "turski",
"sk": "slovački",
"sr": "Serbian",
"pt": "Portuguese",
"hr": "Croatian",
"pl": "Polish"
}
},
"COOKIE": {

View File

@ -182,16 +182,16 @@
"DOC": "Belge"
},
"LANGUAGES": {
"ENGLISH": "İngilizce",
"GREEK": "Yunanca",
"SPANISH": "İspanyolca",
"GERMAN": "Almanca",
"TURKISH": "Türkçe",
"SLOVAK": "Slovakça",
"SERBIAN": "Sırpça",
"PORTUGUESE": "Portekizce",
"CROATIAN": "Croatian",
"POLISH": "Polish"
"en": "İngilizce",
"gr": "Yunanca",
"es": "İspanyolca",
"de": "Almanca",
"tr": "Türkçe",
"sk": "Slovakça",
"sr": "Sırpça",
"pt": "Portekizce",
"hr": "Croatian",
"pl": "Polish"
}
},
"COOKIE": {

View File

@ -16,7 +16,7 @@
<script type="text/javascript" src="//platform.linkedin.com/in.js"></script>
<!-- Fonts and icons -->
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/latest/css/font-awesome.min.css" rel="stylesheet">
<link href='https://fonts.googleapis.com/css?family=Roboto:400,500,700,300|Material+Icons|Material+Icons+Outlined|Material+Icons+Two+Tone' rel='stylesheet' type='text/css'>
<link href='https://fonts.googleapis.com/css?family=Roboto:400,500,700,300|Material+Icons|Material+Icons+Outlined|Material+Icons+Two+Tone|Material+Symbols+Outlined' rel='stylesheet' type='text/css'>
<!-- Hammer.js -->
</head>