diff --git a/src/Web/ClientApp/angular.json b/src/Web/ClientApp/angular.json index 70bf65cef..b493959a7 100644 --- a/src/Web/ClientApp/angular.json +++ b/src/Web/ClientApp/angular.json @@ -94,7 +94,7 @@ "src/assets" ], "styles": [ - "src/styles.css" + "src/styles.scss" ], "scripts": [] } diff --git a/src/Web/ClientApp/src/app/_interfaces/app-config.ts b/src/Web/ClientApp/src/app/_interfaces/app-config.ts new file mode 100644 index 000000000..0dfd1e76f --- /dev/null +++ b/src/Web/ClientApp/src/app/_interfaces/app-config.ts @@ -0,0 +1,3 @@ +export interface AppConfig { + title?: string; +} diff --git a/src/Web/ClientApp/src/app/_services/app-config.service.ts b/src/Web/ClientApp/src/app/_services/app-config.service.ts new file mode 100644 index 000000000..2cd9607af --- /dev/null +++ b/src/Web/ClientApp/src/app/_services/app-config.service.ts @@ -0,0 +1,33 @@ +import { HttpClient } from "@angular/common/http"; +import { Injectable } from "@angular/core"; +import { AppConfig } from "../_interfaces/app-config"; + +@Injectable({ providedIn: 'root' }) +export class AppConfigService { + private config: any; + + constructor(private readonly http: HttpClient) { } + + load(defaults?: AppConfig): Promise { + return new Promise(resolve => { + this.http.get('/assets/config.json').subscribe( + { + next: (response) => { + console.log('using server-side configuration') + this.config = Object.assign({}, defaults || {}, response || {}); + resolve(this.config); + }, + error: () => { + console.log('using default configuration'); + this.config = Object.assign({}, defaults || {}); + resolve(this.config); + } + } + ); + }); + } + + get title() : string { + return this.config.title; + } +} diff --git a/src/Web/ClientApp/src/app/app-routing.module.ts b/src/Web/ClientApp/src/app/app-routing.module.ts index f73553e9f..2553011e2 100644 --- a/src/Web/ClientApp/src/app/app-routing.module.ts +++ b/src/Web/ClientApp/src/app/app-routing.module.ts @@ -1,5 +1,7 @@ -import { NgModule } from "@angular/core"; -import { RouterModule, Routes } from "@angular/router"; +import { Injectable, NgModule } from "@angular/core"; +import { Title } from "@angular/platform-browser"; +import { RouterModule, RouterStateSnapshot, Routes, TitleStrategy } from "@angular/router"; +import { environment } from "src/environments/environment"; import { LoginComponent } from "./components/account/login/login.component"; import { RegisterComponent } from "./components/account/register/register.component"; import { ListComponent } from "./components/application/list/list.component"; @@ -8,21 +10,39 @@ import { ChannelComponent } from "./components/channel/channel.component"; import { NotFoundComponent } from "./components/not-found/not-found.component"; import { StyleguideComponent } from "./components/styleguide/styleguide.component"; import { AuthGuard } from "./_helpers/auth.guard"; +import { AppConfigService } from "./_services/app-config.service"; const routes: Routes = [ - { path: '404', component: NotFoundComponent }, - { path: 'channel/:id', component: ChannelComponent, canActivate: [AuthGuard] }, - { path: 'app/new', component: NewComponent, canActivate: [AuthGuard] }, - { path: 'login', component: LoginComponent }, - { path: 'register', component: RegisterComponent }, - { path: 'styleguide', component: StyleguideComponent }, - { path: '', component: ListComponent, canActivate: [AuthGuard] }, - { path: '**', redirectTo: '404' } + { path: '404', component: NotFoundComponent, title: 'Not Found' }, + { path: 'channel/:id', component: ChannelComponent, canActivate: [AuthGuard], title: 'Overview' }, + { path: 'app/new', component: NewComponent, canActivate: [AuthGuard], title: 'Create a new App' }, + { path: 'login', component: LoginComponent, title: 'Log in' }, + { path: 'register', component: RegisterComponent , title: 'Sign up' }, + { path: 'styleguide', component: StyleguideComponent, title: 'Style Guide' }, + { path: '', component: ListComponent, canActivate: [AuthGuard], title: 'Dashboard' }, + { path: '**', redirectTo: '404' } ]; +@Injectable() +export class TemplatePageTitleStrategy extends TitleStrategy { + constructor(private readonly title: Title, private readonly appConfigService: AppConfigService) { + super(); + } + + override updateTitle(routerState: RouterStateSnapshot) { + const title = this.buildTitle(routerState); + if (title !== undefined) { + this.title.setTitle(`${this.appConfigService.title} | ${title}`); + } + } +} + @NgModule({ imports: [RouterModule.forRoot(routes, { useHash: true })], - exports: [RouterModule] + exports: [RouterModule], + providers: [ + {provide: TitleStrategy, useClass: TemplatePageTitleStrategy}, + ] }) export class AppRoutingModule { } diff --git a/src/Web/ClientApp/src/app/app.component.ts b/src/Web/ClientApp/src/app/app.component.ts index 3a866e6eb..85e4a9f64 100644 --- a/src/Web/ClientApp/src/app/app.component.ts +++ b/src/Web/ClientApp/src/app/app.component.ts @@ -1,4 +1,5 @@ import { Component } from '@angular/core'; +import { AppConfigService } from './_services/app-config.service'; @Component({ selector: 'app-root', @@ -6,5 +7,7 @@ import { Component } from '@angular/core'; styleUrls: ['./app.component.scss'] }) export class AppComponent { - title = 'Hippo'; + constructor(private readonly appConfigService: AppConfigService) { } + + title = this.appConfigService.title; } diff --git a/src/Web/ClientApp/src/app/app.module.ts b/src/Web/ClientApp/src/app/app.module.ts index 5822d6c0d..7ddd6fb14 100644 --- a/src/Web/ClientApp/src/app/app.module.ts +++ b/src/Web/ClientApp/src/app/app.module.ts @@ -1,4 +1,4 @@ -import { NgModule } from '@angular/core'; +import { APP_INITIALIZER, NgModule } from '@angular/core'; import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; import { BrowserModule } from '@angular/platform-browser'; import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; @@ -20,11 +20,11 @@ import { NewComponent } from './components/application/new/new.component'; import { NewComponent as NewChannelComponent } from './components/channel/new/new.component'; import { ChannelComponent } from './components/channel/channel.component'; import { HealthCheckComponent } from './components/health-check/health-check.component'; -import { environment } from './../environments/environment'; import { SettingsComponent } from './components/application/settings/settings.component'; import { LogsComponent } from './components/channel/logs/logs.component'; import { OverviewComponent } from './components/channel/overview/overview.component'; import { NgxJdenticonModule, JDENTICON_CONFIG } from 'ngx-jdenticon'; +import { AppConfigService } from './_services/app-config.service'; export function apiConfigFactory(): Configuration { const params: ConfigurationParameters = { @@ -78,6 +78,12 @@ export function apiConfigFactory(): Configuration { useValue: { replaceMode: "observe" } + }, + { + provide: APP_INITIALIZER, + multi: true, + deps: [AppConfigService], + useFactory: (appConfigService : AppConfigService) => () => appConfigService.load() } ], bootstrap: [AppComponent] diff --git a/src/Web/ClientApp/src/app/components/account/login/login.component.html b/src/Web/ClientApp/src/app/components/account/login/login.component.html index 256e97458..6f0ee01f6 100644 --- a/src/Web/ClientApp/src/app/components/account/login/login.component.html +++ b/src/Web/ClientApp/src/app/components/account/login/login.component.html @@ -1,4 +1,4 @@ -

Log in to Hippo

+

Log in

@@ -16,7 +16,7 @@

Log in to Hip
+ class="input" placeholder="Enter your username here" />
Username is required.
@@ -28,7 +28,7 @@

Log in to Hip
+ class="input" />
Password is required.
diff --git a/src/Web/ClientApp/src/app/components/account/register/register.component.html b/src/Web/ClientApp/src/app/components/account/register/register.component.html index e7b4c372b..372fe8cfa 100644 --- a/src/Web/ClientApp/src/app/components/account/register/register.component.html +++ b/src/Web/ClientApp/src/app/components/account/register/register.component.html @@ -15,7 +15,7 @@
+ class="input" />
Username is required.
@@ -27,7 +27,7 @@
+ class="input" />
Password is required.
Password must be at least 6 characters long.
@@ -43,7 +43,7 @@
+ class="input" />
Password is required.
Password must be at least 6 characters long.
diff --git a/src/Web/ClientApp/src/app/components/navbar/navbar.component.css b/src/Web/ClientApp/src/app/components/navbar/navbar.component.css index d89332961..83cd410f4 100644 --- a/src/Web/ClientApp/src/app/components/navbar/navbar.component.css +++ b/src/Web/ClientApp/src/app/components/navbar/navbar.component.css @@ -2,3 +2,11 @@ margin: 2rem 4rem; font-size: 1.25rem; } + +.navbar-brand { + padding-left: 1rem; +} + +.navbar-end { + padding-right: 1rem; +} diff --git a/src/Web/ClientApp/src/app/components/navbar/navbar.component.html b/src/Web/ClientApp/src/app/components/navbar/navbar.component.html index 34ff80679..858d81d81 100644 --- a/src/Web/ClientApp/src/app/components/navbar/navbar.component.html +++ b/src/Web/ClientApp/src/app/components/navbar/navbar.component.html @@ -1,7 +1,9 @@ -