-
-
-
{{ 'ABOUT.TITLE' | translate}}
-
-
-
-
-
{{ 'ABOUT.MAIN-CONTENT'| translate}}
-
-
-
-
-
{{ 'ABOUT.CONTRIBUTORS'| translate}}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/dmp-frontend/src/app/about/components/about.component.ts b/dmp-frontend/src/app/about/components/about.component.ts
deleted file mode 100644
index 586736b5a..000000000
--- a/dmp-frontend/src/app/about/components/about.component.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-import { Component, ViewEncapsulation, OnInit } from '@angular/core';
-import { ActivatedRoute, Router } from '@angular/router';
-import { TranslateService } from '@ngx-translate/core';
-
-@Component({
- selector: 'app-about',
- templateUrl: './about.component.html',
- styleUrls: ['./about.component.scss'],
- providers: [],
- encapsulation: ViewEncapsulation.None
-})
-export class AboutComponent implements OnInit {
-
- constructor() {
-
- }
-
- ngOnInit() {
- }
-
-}
-
diff --git a/dmp-frontend/src/app/app-routing.module.ts b/dmp-frontend/src/app/app-routing.module.ts
index c7e7d0e6f..7c8ff7c18 100644
--- a/dmp-frontend/src/app/app-routing.module.ts
+++ b/dmp-frontend/src/app/app-routing.module.ts
@@ -1,116 +1,103 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
-import { HomepageComponent } from './homepage/homepage.component';
-import { AuthGuard } from './shared/guards/auth.guard';
-import { WelcomepageComponent } from './welcomepage/welcomepage.component';
-import { B2AccessLoginComponent } from './user-management/login/b2access/b2access-login.component';
const appRoutes: Routes = [
- {
- path: 'datasets',
- loadChildren: './datasets/dataset.module#DatasetModule',
- data: {
- breadcrumb: true
- },
- //canActivate: [AuthGuard]
- },
- {
- path: 'about',
- loadChildren: './about/about.module#AboutModule',
- data: {
- breadcrumb: true
- },
- canActivate: [AuthGuard]
- },
- {
- path: 'projects',
- loadChildren: './projects/projects.module#ProjectsModule',
- data: {
- breadcrumb: true
- },
- canActivate: [AuthGuard]
- },
- {
- path: 'dmps',
- loadChildren: './dmps/dmps.module#DataManagementPlanModule',
- data: {
- breadcrumb: true
- },
- canActivate: [AuthGuard]
- },
- {
- path: 'dmp-profiles',
- loadChildren: './dmp-profiles/dmp-profile.module#DataManagamentPlanProfileModule',
- data: {
- breadcrumb: true
- },
- canActivate: [AuthGuard]
- },
- {
- path: 'dataset-profile',
- loadChildren: './dataset-profile-form/dataset-profile.module#DatasetProfileModule',
- data: {
- breadcrumb: true
- },
- canActivate: [AuthGuard]
- },
- {
- path: 'home',
- component: HomepageComponent,
- data: {
- breadcrumb: false
- },
- canActivate: [AuthGuard]
- },
{
path: '',
- redirectTo: '/welcome',
+ redirectTo: '/home',
data: {
breadcrumbs: false
},
pathMatch: 'full'
},
+ {
+ path: 'explore',
+ loadChildren: './ui/explore-dataset/explore-dataset.module#ExploreDatasetModule',
+ data: {
+ breadcrumb: true
+ }
+ },
+ {
+ path: 'datasets',
+ loadChildren: './ui/dataset/dataset.module#DatasetModule',
+ data: {
+ breadcrumb: true
+ }
+ },
+ {
+ path: 'about',
+ loadChildren: './ui/about/about.module#AboutModule',
+ data: {
+ breadcrumb: true
+ }
+ },
+ {
+ path: 'projects',
+ loadChildren: './ui/project/project.module#ProjectModule',
+ data: {
+ breadcrumb: true
+ }
+ },
+ {
+ path: 'plans',
+ loadChildren: './ui/dmp/dmp.module#DmpModule',
+ data: {
+ breadcrumb: true
+ }
+ },
+ {
+ path: 'dmp-profiles',
+ loadChildren: './ui/admin/dmp-profile/dmp-profile.module#DmpProfileModule',
+ data: {
+ breadcrumb: true
+ }
+ },
+ {
+ path: 'dataset-profiles',
+ loadChildren: './ui/admin/dataset-profile/dataset-profile.module#DatasetProfileModule',
+ data: {
+ breadcrumb: true
+ }
+ },
+ {
+ path: 'home',
+ loadChildren: './ui/dashboard/dashboard.module#DashboardModule',
+ data: {
+ breadcrumb: true
+ }
+ },
{
path: 'unauthorized',
- loadChildren: './unauthorized/unauthorized.module#UnauthorizedModule',
+ loadChildren: './ui/misc/unauthorized/unauthorized.module#UnauthorizedModule',
data: {
breadcrumb: true
},
},
{
path: 'users',
- loadChildren: './users/users.module#UsersModule',
+ loadChildren: './ui/admin/user/user.module#UserModule',
data: {
breadcrumb: true
},
},
{
- path: 'welcome',
- component: WelcomepageComponent,
+ path: 'login',
+ loadChildren: './ui/auth/login/login.module#LoginModule',
data: {
- breadcrumb: false
+ breadcrumb: true
},
},
- {
- path: 'api/oauth/authorized/b2access',
- component: B2AccessLoginComponent,
- data: {
- },
- }
+ // {
+ // path: 'api/oauth/authorized/b2access',
+ // component: B2AccessLoginComponent,
+ // data: {
+ // },
+ // }
];
@NgModule({
- imports: [
- RouterModule.forRoot(
- appRoutes
- , {
- useHash: false
- }
- )
- ],
- exports: [
- RouterModule
- ]
+ imports: [RouterModule.forRoot(appRoutes)],
+ exports: [RouterModule],
})
export class AppRoutingModule { }
diff --git a/dmp-frontend/src/app/app.component.scss b/dmp-frontend/src/app/app.component.scss
index 66b04b0f7..685fdd3b2 100644
--- a/dmp-frontend/src/app/app.component.scss
+++ b/dmp-frontend/src/app/app.component.scss
@@ -1,15 +1,12 @@
-.example-container {
- background: rgb(250, 248, 248);
-}
-
.fixed {
- position: fixed;
- top: 0; /* Sets the sticky toolbar to be on top */
+ position: fixed;
+ top: 0;
+ /* Sets the sticky toolbar to be on top */
z-index: 1000;
width: 100%;
}
-.main-container{
+.main-container {
margin-top: 64px;
padding-top: 10px;
}
diff --git a/dmp-frontend/src/app/app.component.ts b/dmp-frontend/src/app/app.component.ts
index 90b32b12a..691f7651a 100644
--- a/dmp-frontend/src/app/app.component.ts
+++ b/dmp-frontend/src/app/app.component.ts
@@ -1,23 +1,20 @@
-import { Component, OnInit, ViewEncapsulation } from '@angular/core';
-import { Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, ActivatedRoute, NavigationExtras, NavigationEnd } from '@angular/router';
+import { Component, OnInit } from '@angular/core';
+import { ActivatedRoute, NavigationEnd, Router } from '@angular/router';
import { TranslateService } from '@ngx-translate/core';
-import { LanguageResolverService } from './services/language-resolver/language-resolver.service';
-import { BreadCrumbResolverService } from './services/breadcrumb/breadcrumb-resolver.service';
import { Observable } from 'rxjs';
-import { AuthService } from './services/auth/auth.service';
-import { CultureService } from './utilities/culture/culture-service';
import { environment } from '../environments/environment';
+import { AuthService } from './core/services/auth/auth.service';
+import { CultureService } from './core/services/culture/culture-service';
+import { BreadCrumbResolverService } from './ui/misc/breadcrumb/service/breadcrumb.service';
declare const gapi: any;
-
declare var $: any;
+
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
- styleUrls: ['./app.component.scss'],
- providers: [],
- encapsulation: ViewEncapsulation.None
+ styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
@@ -30,7 +27,6 @@ export class AppComponent implements OnInit {
private route: ActivatedRoute,
private authentication: AuthService,
private translate: TranslateService,
- private languageService: LanguageResolverService,
private breadCrumbResolverService: BreadCrumbResolverService,
private cultureService: CultureService
) {
@@ -68,7 +64,7 @@ export class AppComponent implements OnInit {
}
goToDMPs() {
- this.router.navigate(['/dmps'], { queryParams: { /*refresh : Math.random() ,returnUrl: this.state.url*/ } });
+ this.router.navigate(['/plans'], { queryParams: { /*refresh : Math.random() ,returnUrl: this.state.url*/ } });
}
goToProjects() {
diff --git a/dmp-frontend/src/app/app.module.ts b/dmp-frontend/src/app/app.module.ts
index 6e548c553..2bdcd5e35 100644
--- a/dmp-frontend/src/app/app.module.ts
+++ b/dmp-frontend/src/app/app.module.ts
@@ -1,63 +1,36 @@
-import { CommonModule } from '@angular/common';
+import { OverlayModule } from '@angular/cdk/overlay';
import { HttpClient, HttpClientModule } from '@angular/common/http';
import { LOCALE_ID, NgModule } from '@angular/core';
-import { FormsModule, ReactiveFormsModule } from '@angular/forms';
-import { HttpModule } from '@angular/http';
-import { MAT_DATE_LOCALE } from '@angular/material';
+import { DateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE } from '@angular/material';
+import { MatMomentDateModule, MAT_MOMENT_DATE_FORMATS } from '@angular/material-moment-adapter';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
-import { environment } from '../environments/environment';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
-import { HomepageComponent } from './homepage/homepage.component';
-import { PageNotFoundComponent } from './not-found.component';
-import { AuthService } from './services/auth/auth.service';
-import { BreadCrumbResolverService } from './services/breadcrumb/breadcrumb-resolver.service';
-import { DashboardService } from './services/dashboard/dashboard.service';
-import { HelpContentService } from './services/help-content/help-content.service';
-import { LanguageResolverService } from './services/language-resolver/language-resolver.service';
-import { LanguageService } from './services/language/language.service';
-import { AuthGuard } from './shared/guards/auth.guard';
-import { AsideHelpContentComponent, HelpContentComponent } from './shared/help-content/help-content.component';
-import { MaterialModule } from './shared/material/material.module';
-import { SharedModule } from './shared/shared.module';
-import { LoginModule } from './user-management/login.module';
-import { B2AccessLoginComponent } from './user-management/login/b2access/b2access-login.component';
-import { LoginOptions } from './user-management/utilties/LoginOptions';
-import { RecentActivityComponent } from './users/activity/recent-activity.component';
-import { BaseHttpService } from './utilities/cite-http-service-module/base-http.service';
-import { BaseHttpModule } from './utilities/cite-http-service-module/cite-http.module';
-import { CultureService } from './utilities/culture/culture-service';
-import { UrlUtilities } from './utilities/UrlUtilities';
-import { WelcomepageComponent } from './welcomepage/welcomepage.component';
-
-
+import { MomentUtcDateAdapter } from './common/date/moment-utc-date-adapter';
+import { CommonHttpModule } from './common/http/common-http.module';
+import { CommonUiModule } from './common/ui/common-ui.module';
+import { CoreServiceModule } from './core/core-service.module';
+import { CultureService } from './core/services/culture/culture-service';
+import { NotificationModule } from './library/notification/notification.module';
+import { BreadcrumbModule } from './ui/misc/breadcrumb/breadcrumb.module';
+import { HelpContentModule } from './ui/misc/help-content/help-content.module';
+import { NavigationModule } from './ui/misc/navigation/navigation.module';
+// AoT requires an exported function for factories
+export function HttpLoaderFactory(http: HttpClient) {
+ return new TranslateHttpLoader(http, 'assets/i18n/', '.json');
+}
@NgModule({
- declarations: [
- AppComponent,
- PageNotFoundComponent,
- HomepageComponent,
- RecentActivityComponent,
- WelcomepageComponent,
- HelpContentComponent,
- AsideHelpContentComponent,
- B2AccessLoginComponent,
- ],
imports: [
BrowserModule,
- ReactiveFormsModule,
- FormsModule,
- HttpModule,
- HttpClientModule,
- BaseHttpModule.forRoot(),
-
- CommonModule,
- AppRoutingModule,
BrowserAnimationsModule,
+ CoreServiceModule.forRoot(),
+ AppRoutingModule,
+ CommonUiModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
@@ -65,66 +38,33 @@ import { WelcomepageComponent } from './welcomepage/welcomepage.component';
deps: [HttpClient]
}
}),
- BrowserAnimationsModule,
- MaterialModule,
- SharedModule,
-
- LoginModule.forRoot({
- loginProviders: [
- LoginOptions.facebookOauth,
- LoginOptions.googleOauth,
- LoginOptions.linkedInOauth,
- LoginOptions.twitterOauth,
- LoginOptions.b2Access
- ],
- facebookConfiguration: { clientId: environment.loginProviders.facebookConfiguration.clientId },
- googleConfiguration: { clientId: environment.loginProviders.googleConfiguration.clientId },
- linkedInConfiguration: {
- clientId: environment.loginProviders.linkedInConfiguration.clientId,
- oauthUrl: environment.loginProviders.linkedInConfiguration.oauthUrl,
- redirectUri: environment.loginProviders.linkedInConfiguration.redirectUri,
- },
- twitterConfiguration: {
- clientId: environment.loginProviders.twitterConfiguration.clientId,
- oauthUrl: environment.loginProviders.twitterConfiguration.oauthUrl
- },
- b2accessConfiguration: {
- clientId: environment.loginProviders.b2accessConfiguration.clientId,
- oauthUrl: environment.loginProviders.b2accessConfiguration.oauthUrl,
- redirectUri: environment.loginProviders.b2accessConfiguration.redirectUri
- }
- }),
-
+ HttpClientModule,
+ OverlayModule,
+ CommonHttpModule,
+ MatMomentDateModule,
+ //Ui
+ NotificationModule,
+ NavigationModule,
+ BreadcrumbModule,
+ HelpContentModule
+ ],
+ declarations: [
+ AppComponent
],
providers: [
- AuthGuard,
- AuthService,
- BaseHttpService,
- UrlUtilities,
- DashboardService,
- HelpContentService,
- LanguageService,
- LanguageResolverService,
- BreadCrumbResolverService,
- CultureService,
{
provide: MAT_DATE_LOCALE,
deps: [CultureService],
- useFactory: (cultureService) => cultureService.getCurrentCulture()
+ useFactory: (cultureService) => cultureService.getCurrentCulture().name
},
+ { provide: MAT_DATE_FORMATS, useValue: MAT_MOMENT_DATE_FORMATS },
+ { provide: DateAdapter, useClass: MomentUtcDateAdapter },
{
provide: LOCALE_ID,
deps: [CultureService],
- useFactory: (cultureService) => cultureService.getCurrentCulture()
+ useFactory: (cultureService) => cultureService.getCurrentCulture().name
},
],
bootstrap: [AppComponent]
})
-export class AppModule {
- constructor() {
- }
-}
-
-export function HttpLoaderFactory(httpClient: HttpClient) {
- return new TranslateHttpLoader(httpClient, 'assets/lang/', '.json');
-}
+export class AppModule { }
\ No newline at end of file
diff --git a/dmp-frontend/src/app/common/date/moment-utc-date-adapter.ts b/dmp-frontend/src/app/common/date/moment-utc-date-adapter.ts
new file mode 100644
index 000000000..66903147f
--- /dev/null
+++ b/dmp-frontend/src/app/common/date/moment-utc-date-adapter.ts
@@ -0,0 +1,44 @@
+import { Inject, Injectable, Optional } from '@angular/core';
+import { MAT_DATE_LOCALE } from '@angular/material';
+import { MomentDateAdapter } from '@angular/material-moment-adapter';
+import * as moment from 'moment';
+import { Moment } from 'moment';
+
+@Injectable()
+export class MomentUtcDateAdapter extends MomentDateAdapter {
+
+ constructor(@Optional() @Inject(MAT_DATE_LOCALE) dateLocale: string) {
+ super(dateLocale);
+ }
+
+ // selected from datepicker
+ createDate(year: number, month: number, date: number): Moment {
+ // Moment.js will create an invalid date if any of the components are out of bounds, but we
+ // explicitly check each case so we can throw more descriptive errors.
+ if (month < 0 || month > 11) {
+ throw Error(`Invalid month index "${month}". Month index has to be between 0 and 11.`);
+ }
+
+ if (date < 1) {
+ throw Error(`Invalid date "${date}". Date has to be greater than 0.`);
+ }
+
+ const result = moment.utc({ year, month, date }).locale(this.locale);
+
+ // If the result isn't valid, the date must have been out of bounds for this month.
+ if (!result.isValid()) {
+ throw Error(`Invalid date "${date}" for month with index "${month}".`);
+ }
+
+ return result;
+ }
+
+ // manually writing on the textbox
+ parse(value: any, parseFormat: string | string[]): Moment | null {
+ const initialParse = super.parse(value, parseFormat);
+ if (!initialParse.isValid()) { return initialParse; }
+
+ const result = moment.utc({ year: initialParse.year(), month: initialParse.month(), date: initialParse.date() }).locale(this.locale);
+ return result;
+ }
+}
diff --git a/dmp-frontend/src/app/common/forms/common-forms.module.ts b/dmp-frontend/src/app/common/forms/common-forms.module.ts
new file mode 100644
index 000000000..13f128841
--- /dev/null
+++ b/dmp-frontend/src/app/common/forms/common-forms.module.ts
@@ -0,0 +1,14 @@
+import { NgModule } from '@angular/core';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+
+@NgModule({
+ imports: [
+ FormsModule,
+ ReactiveFormsModule,
+ ],
+ exports: [
+ FormsModule,
+ ReactiveFormsModule,
+ ]
+})
+export class CommonFormsModule { }
diff --git a/dmp-frontend/src/app/common/forms/validation/custom-validator.ts b/dmp-frontend/src/app/common/forms/validation/custom-validator.ts
new file mode 100644
index 000000000..ee70c8eaf
--- /dev/null
+++ b/dmp-frontend/src/app/common/forms/validation/custom-validator.ts
@@ -0,0 +1,32 @@
+import { AbstractControl, FormGroup, ValidatorFn, Validators } from '@angular/forms';
+import { ValidationErrorModel } from './error-model/validation-error-model';
+
+export function BackendErrorValidator(errorModel: ValidationErrorModel, propertyName: string): ValidatorFn {
+ return (control: AbstractControl): { [key: string]: any } => {
+ const error: String = errorModel.getError(propertyName);
+ return error ? { 'backendError': { message: error } } : null;
+ };
+}
+
+export function E164PhoneValidator(): ValidatorFn {
+ return Validators.pattern('^\\+?[1-9]\\d{1,14}$');
+}
+
+// Getter is required because the index of each element is not fixed (array does not always follow LIFO)
+export function BackendArrayErrorValidator(errorModel: ValidationErrorModel, propertyNameGetter: () => string): ValidatorFn {
+ return (control: AbstractControl): { [key: string]: any } => {
+ const error: String = errorModel.getError(propertyNameGetter());
+ return error ? { 'backendError': { message: error } } : null;
+ };
+}
+
+export function CustomErrorValidator(errorModel: ValidationErrorModel, propertyNames: string[]): ValidatorFn {
+ return (control: AbstractControl): { [key: string]: any } => {
+ const error: String = errorModel.getErrors(propertyNames);
+ return error ? { 'customError': { message: error } } : null;
+ };
+}
+
+export function PasswordMatchValidator(formGroup: FormGroup) {
+ return formGroup.get('password').value === formGroup.get('passwordConfirm').value ? null : { 'passwordMismatch': true };
+}
diff --git a/dmp-frontend/src/app/common/forms/validation/error-model/validation-error-model.ts b/dmp-frontend/src/app/common/forms/validation/error-model/validation-error-model.ts
new file mode 100644
index 000000000..21eec2772
--- /dev/null
+++ b/dmp-frontend/src/app/common/forms/validation/error-model/validation-error-model.ts
@@ -0,0 +1,90 @@
+import { Serializable } from '../../../types/json/serializable';
+
+export class ValidationErrorModel implements Serializable