Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions proxy.conf.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,16 @@ export default {
logLevel: 'debug',
secure: false,
},
'/branding/': {
target: process.env.SEED_HOST ?? 'http://127.0.0.1:8000',
changeOrigin: true,
logLevel: 'debug',
secure: false,
},
'/static/': {
target: process.env.SEED_HOST ?? 'http://127.0.0.1:8000',
changeOrigin: true,
logLevel: 'debug',
secure: false,
},
}
3 changes: 3 additions & 0 deletions public/i18n/en_US.json
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,7 @@
"Data Set": "Data Set",
"Data Set Name": "Data Set Name",
"Data Sets": "Data Sets",
"Data Terms": "Data Terms",
"Data Type": "Data Type",
"Data Types": "Data Types",
"Date": "Date",
Expand Down Expand Up @@ -856,6 +857,7 @@
"Historical Note": "Historical Note",
"Home Energy Score ID": "Home Energy Score ID",
"Hour": "Hour",
"I agree with the": "I agree with the",
"ID": "ID",
"IF_MARKED_AS_DUPLICATE_ADVICE": "<label class=\"label label-danger\">Duplicate<\/label> -- if fields are marked as duplicates they need to be resolved to have different names.",
"IMPORT_ANOTHER_QUESTION": "Would you like to add another file?",
Expand Down Expand Up @@ -1976,6 +1978,7 @@
"You cannot login without agreeing to the terms of this site.": "You cannot login without agreeing to the terms of this site.",
"You have successfully logged out. You may log in again below.": "You have successfully logged out. You may log in again below.",
"You have unsaved changes": "You have unsaved changes",
"You must accept the Data Terms.": "You must accept the Data Terms.",
"You must be an organization owner to view and manage sharing settings.": "You must be an organization owner to view and manage sharing settings.",
"You should be receiving it shortly.": "You should be receiving it shortly.",
"You successfully created the project": "You successfully created the project",
Expand Down
3 changes: 3 additions & 0 deletions public/i18n/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,7 @@
"Data Set": "Conjunto de datos",
"Data Set Name": "Nombre del conjunto de datos",
"Data Sets": "Conjuntos de datos",
"Data Terms": "Términos de datos",
"Data Type": "Tipo de datos",
"Data Types": "Tipos de datos",
"Date": "Fecha",
Expand Down Expand Up @@ -856,6 +857,7 @@
"Historical Note": "Nota histórica",
"Home Energy Score ID": "ID de puntuación energética de la vivienda",
"Hour": "Hora",
"I agree with the": "Estoy de acuerdo con la",
"ID": "ID",
"IF_MARKED_AS_DUPLICATE_ADVICE": "<label class=\"label label-danger\">Duplicados<\/label> -- si los campos se marcan como duplicados, deben resolverse para que tengan nombres diferentes.",
"IMPORT_ANOTHER_QUESTION": "¿Desea añadir otro archivo?",
Expand Down Expand Up @@ -1976,6 +1978,7 @@
"You cannot login without agreeing to the terms of this site.": "No puede iniciar sesión sin aceptar las condiciones de este sitio.",
"You have successfully logged out. You may log in again below.": "Se ha desconectado correctamente. Puede volver a conectarse a continuación.",
"You have unsaved changes": "Tienes cambios sin guardar",
"You must accept the Data Terms.": "Debe aceptar los Términos de Datos.",
"You must be an organization owner to view and manage sharing settings.": "Debes ser el propietario de la organización para ver y administrar la configuración de uso compartido.",
"You should be receiving it shortly.": "Debería recibirlo en breve.",
"You successfully created the project": "Ha creado correctamente el proyecto",
Expand Down
3 changes: 3 additions & 0 deletions public/i18n/fr_CA.json
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,7 @@
"Data Set": "Jeu de données",
"Data Set Name": "Nom du jeu de données",
"Data Sets": "Ensembles de données",
"Data Terms": "Termes de données",
"Data Type": "Type de données",
"Data Types": "Types de données",
"Date": "Date",
Expand Down Expand Up @@ -856,6 +857,7 @@
"Historical Note": "Note historique",
"Home Energy Score ID": "ID de score d'énergie domestique",
"Hour": "Hour",
"I agree with the": "Je suis d'accord avec le",
"ID": "ID",
"IF_MARKED_AS_DUPLICATE_ADVICE": "<label class=\"label label-danger\">Copie<\/label> - si les champs sont marqués comme des doublons, ils doivent être résolus pour avoir des noms différents.",
"IMPORT_ANOTHER_QUESTION": "Voulez-vous ajouter un autre fichier?",
Expand Down Expand Up @@ -1976,6 +1978,7 @@
"You cannot login without agreeing to the terms of this site.": "Vous ne pouvez pas vous connecter sans accepter les termes de ce site.",
"You have successfully logged out. You may log in again below.": "Vous vous êtes déconnecté avec succès. Vous pouvez vous reconnecter ci-dessous.",
"You have unsaved changes": "Vous avez des changements non enregistrés",
"You must accept the Data Terms.": "Vous devez accepter les conditions relatives aux données.",
"You must be an organization owner to view and manage sharing settings.": "Vous devez être propriétaire de l'organisation pour consulter et gérer les paramètres de partage.",
"You should be receiving it shortly.": "Vous devriez le recevoir sous peu.",
"You successfully created the project": "Vous avez réussi à créer le projet",
Expand Down
Binary file added public/images/kc_2.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 1 addition & 8 deletions src/@seed/api/analysis/analysis.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,7 @@ export type AnalysisCreateData = {
}

export type AnalysisServiceType
= | 'BSyncr'
| 'BETTER'
| 'EUI'
| 'CO2'
| 'EEEJ'
| 'Element Statistics'
| 'Building Upgrade Recommendation'
| 'HVAC Metrics'
= 'BSyncr' | 'BETTER' | 'EUI' | 'CO2' | 'EEEJ' | 'Element Statistics' | 'Building Upgrade Recommendation' | 'HVAC Metrics'

// Analysis by View type
export type View = {
Expand Down
11 changes: 11 additions & 0 deletions src/@seed/api/config/config.types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
export type ConfigResponse = {
allow_signup: boolean;
branding: {
logo_url: string;
home_hero_image_url: string;
home_heading: string;
home_text: string;
login_heading: string;
login_text: string;
home_content_mode: string;
};
hidden_navigation: string[];
integrations: { salesforce: boolean; better: boolean };
}
18 changes: 2 additions & 16 deletions src/@seed/api/data-quality/data-quality.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,23 +43,9 @@ export type DataQualityFormGroup = FormGroup<{
}>

export type UnitSymbols
= | 'ft**2'
| 'm**2'
| 'kBtu/ft**2/year'
| 'gal/ft**2/year'
| 'GJ/m**2/year'
| 'MJ/m**2/year'
| 'kWh/m**2/year'
| 'kBtu/m**2/year'
= 'ft**2' | 'm**2' | 'kBtu/ft**2/year' | 'gal/ft**2/year' | 'GJ/m**2/year' | 'MJ/m**2/year' | 'kWh/m**2/year' | 'kBtu/m**2/year'
export type UnitNames
= | 'square feet'
| 'square metres'
| 'kBtu/sq. ft./year'
| 'gal/sq. ft./year'
| 'GJ/m²/year'
| 'MJ/m²/year'
| 'kWh/m²/year'
| 'kBtu/m²/year'
= 'square feet' | 'square metres' | 'kBtu/sq. ft./year' | 'gal/sq. ft./year' | 'GJ/m²/year' | 'MJ/m²/year' | 'kWh/m²/year' | 'kBtu/m²/year'

export type DataQualityResultsResponse = {
data: DataQualityResults[];
Expand Down
3 changes: 1 addition & 2 deletions src/@seed/mock-api/mock-api.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import type { HttpRequest } from '@angular/common/http'
import type { Observable } from 'rxjs'

export type MockApiReplyCallback
= | ((data: { request: HttpRequest<unknown>; urlParams: Record<string, string> }) => [number, unknown] | Observable<unknown>)
| undefined
= ((data: { request: HttpRequest<unknown>; urlParams: Record<string, string> }) => [number, unknown] | Observable<unknown>) | undefined

export type MockApiMethods = 'get' | 'post' | 'patch' | 'delete' | 'put' | 'head' | 'jsonp' | 'options'
21 changes: 20 additions & 1 deletion src/app/app.config.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { DOCUMENT } from '@angular/common'
import { provideHttpClient } from '@angular/common/http'
import type { ApplicationConfig } from '@angular/core'
import { inject, Injectable, isDevMode, provideAppInitializer } from '@angular/core'
Expand All @@ -8,8 +9,9 @@ import { provideAnimations } from '@angular/platform-browser/animations'
import type { RouterStateSnapshot } from '@angular/router'
import { provideRouter, TitleStrategy, UrlSerializer, withInMemoryScrolling, withRouterConfig } from '@angular/router'
import { provideTransloco, TranslocoService } from '@jsverse/transloco'
import { firstValueFrom } from 'rxjs'
import { catchError, firstValueFrom, of, tap } from 'rxjs'
import { provideSEED } from '@seed'
import { ConfigService } from '@seed/api'
import { LowerCaseUrlSerializer } from '@seed/routing/url.serializer'
import { appRoutes } from 'app/app.routes'
import { provideAuth } from 'app/core/auth/auth.provider'
Expand Down Expand Up @@ -82,6 +84,23 @@ export const appConfig: ApplicationConfig = {

return firstValueFrom(translocoService.load(defaultLang))
}),
provideAppInitializer(() => {
const splashLogo = inject(DOCUMENT).querySelector<HTMLImageElement>('seed-splash-screen img')
return firstValueFrom(
inject(ConfigService).config$.pipe(
tap(({ branding }) => {
if (!splashLogo) return
splashLogo.src = branding.logo_url || 'images/logo.svg'
splashLogo.alt = branding.logo_url ? '' : 'SEED Platform logo'
splashLogo.hidden = false
}),
catchError(() => {
if (splashLogo) splashLogo.hidden = false
return of(null)
}),
),
)
}),
provideAuth(),
provideIcons(),
provideSEED({
Expand Down
1 change: 1 addition & 0 deletions src/app/app.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export const appRoutes: Route[] = [
component: LayoutComponent,
resolve: {
initialData: initialDataResolver,
config: configResolver,
},
children: [
{
Expand Down
4 changes: 2 additions & 2 deletions src/app/core/navigation/navigation.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -304,14 +304,14 @@ export class NavigationService {
this.getNavigation()
}

getNavigation(): NavigationItem[] {
getNavigation(hiddenNavigation: string[] = []): NavigationItem[] {
const currentUrl = this._router.url
if (currentUrl.toLowerCase().startsWith('/properties')) {
this.navigation[0].children = this.inventoryChildrenProperties
} else if (currentUrl.toLowerCase().startsWith('/taxlots')) {
this.navigation[0].children = this.inventoryChildrenTaxlots
}
return this.navigation
return this.navigation.filter((item) => !item.id || !hiddenNavigation.includes(item.id))
}

updateBadge(itemId: string, navigationName: string, title: string | number) {
Expand Down
40 changes: 32 additions & 8 deletions src/app/layout/layouts/landing/landing.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -34,20 +34,44 @@
</svg>
<!-- Content -->
<div class="relative z-10 w-full max-w-2xl">
<div class="text-7xl font-bold leading-none text-gray-100">
<div>Welcome to</div>
<div>SEED Platform™</div>
</div>
<div class="text-secondary mt-6 text-lg leading-6 tracking-tight">{{ t('MARKETING_BULLET_1') }}</div>
<div class="text-secondary mt-6 text-lg leading-6 tracking-tight">{{ t('MARKETING_BULLET_2') }}</div>
<div class="text-secondary mt-6 text-lg leading-6 tracking-tight">{{ t('MARKETING_BULLET_3') }}</div>
@if (config$ | async; as config) {
<div class="text-7xl font-bold leading-none text-gray-100">
@if (config.branding.login_heading) {
<div class="break-words text-4xl leading-tight lg:text-5xl">{{ config.branding.login_heading }}</div>
} @else {
<div>Welcome to</div>
<div>SEED Platform™</div>
}
</div>
@if (config.branding.login_text) {
<div class="mt-6 whitespace-pre-line text-lg text-gray-100">{{ config.branding.login_text }}</div>
} @else {
<div class="text-secondary mt-6 text-lg leading-6 tracking-tight">{{ t('MARKETING_BULLET_1') }}</div>
<div class="text-secondary mt-6 text-lg leading-6 tracking-tight">{{ t('MARKETING_BULLET_2') }}</div>
<div class="text-secondary mt-6 text-lg leading-6 tracking-tight">{{ t('MARKETING_BULLET_3') }}</div>
}
}
</div>
</div>
<div class="w-full px-4 py-8 sm:w-auto sm:p-12 md:p-16">
<div class="mx-auto w-full max-w-80 sm:mx-0 sm:w-80">
<div class="pointer-events-none mx-auto w-40 select-none">
<img src="images/logo.svg" alt="SEED Platform logo" />
@if (config$ | async; as config) {
<img [src]="config.branding.logo_url || 'images/logo.svg'" [alt]="config.branding.logo_url ? '' : 'SEED Platform logo'" />
}
</div>
@if (config$ | async; as config) {
@if (config.branding.login_heading || config.branding.login_text) {
<div class="mt-6 break-words text-center md:hidden">
@if (config.branding.login_heading) {
<div class="text-2xl font-bold">{{ config.branding.login_heading }}</div>
}
@if (config.branding.login_text) {
<p class="text-secondary mt-2 whitespace-pre-line">{{ config.branding.login_text }}</p>
}
</div>
}
}
<router-outlet></router-outlet>
</div>
</div>
Expand Down
10 changes: 7 additions & 3 deletions src/app/layout/layouts/landing/landing.component.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import { CdkScrollable } from '@angular/cdk/scrolling'
import { Component, ViewEncapsulation } from '@angular/core'
import { AsyncPipe } from '@angular/common'
import { Component, inject, ViewEncapsulation } from '@angular/core'
import { RouterOutlet } from '@angular/router'
import { ConfigService } from '@seed/api'
import { SEEDLoadingBarComponent } from '@seed/components'
import { SharedImports } from '@seed/directives'

@Component({
selector: 'layout-landing',
templateUrl: './landing.component.html',
encapsulation: ViewEncapsulation.None,
imports: [CdkScrollable, RouterOutlet, SEEDLoadingBarComponent, SharedImports],
imports: [AsyncPipe, CdkScrollable, RouterOutlet, SEEDLoadingBarComponent, SharedImports],
})
export class LandingLayoutComponent {}
export class LandingLayoutComponent {
readonly config$ = inject(ConfigService).config$
}
21 changes: 17 additions & 4 deletions src/app/layout/layouts/main/main.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,30 @@
>
<!-- Navigation header hook -->
<ng-container verticalNavigationContentHeader>
<div class="flex h-20 cursor-pointer items-center justify-center" [routerLink]="['/']" role="button">
<div class="w-14 rounded-md bg-white p-0.5">
<img class="pointer-events-none select-none" src="images/logo.svg" alt="SEED Platform logo" />
<div class="flex h-20 cursor-pointer items-center justify-center" [routerLink]="['/']" aria-label="Dashboard" role="button">
<div
class="rounded-md bg-white p-0.5"
[class.w-14]="!brandingLogoUrl || navigationAppearance === 'dense'"
[class.w-40]="brandingLogoUrl && navigationAppearance === 'default'"
>
<img
class="pointer-events-none max-h-14 w-full select-none object-contain"
[src]="brandingLogoUrl || 'images/logo.svg'"
[alt]="brandingLogoUrl ? '' : 'SEED Platform logo'"
/>
</div>
</div>
</ng-container>

<!-- Navigation footer hook -->
<ng-container verticalNavigationFooter>
<div class="hidden p-5 md:flex">
<button (click)="toggleNavigationAppearance()" mat-icon-button>
<button
[attr.aria-label]="navigationAppearance === 'default' ? 'Collapse navigation' : 'Expand navigation'"
[title]="navigationAppearance === 'default' ? 'Collapse navigation' : 'Expand navigation'"
Comment on lines +32 to +33

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Localized the toggle’s accessible label and tooltip with the existing Transloco Collapse and Expand keys. Commit: 8404462.

(click)="toggleNavigationAppearance()"
mat-icon-button
>
<mat-icon svgIcon="heroicons-outline:arrows-right-left"></mat-icon>
</button>
</div>
Expand Down
40 changes: 40 additions & 0 deletions src/app/layout/layouts/main/main.component.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { TestBed } from '@angular/core/testing'
import { ActivatedRoute, Router } from '@angular/router'
import { NEVER } from 'rxjs'
import { ConfigService, VersionService } from '@seed/api'
import { SeedNavigationService } from '@seed/components'
import { MediaWatcherService } from '@seed/services'
import { NavigationService } from 'app/core/navigation/navigation.service'
import { MainLayoutComponent } from './main.component'

describe('MainLayoutComponent', () => {
it('clears nav hover when collapsing and expands on the next click', () => {
let hovered = true
const handleMouseLeave = jasmine.createSpy('handleMouseLeave').and.callFake(() => {
hovered = false
})

TestBed.configureTestingModule({
providers: [
{ provide: MediaWatcherService, useValue: { onMediaChange$: NEVER } },
{ provide: NavigationService, useValue: { getNavigation: () => [] } },
{ provide: SeedNavigationService, useValue: { getComponent: () => ({ handleMouseLeave }) } },
{ provide: VersionService, useValue: { version$: NEVER } },
{ provide: ConfigService, useValue: { config$: NEVER } },
{ provide: Router, useValue: { events: NEVER } },
{ provide: ActivatedRoute, useValue: {} },
],
})

const component = TestBed.runInInjectionContext(() => new MainLayoutComponent())
component.navigationAppearance = 'default'
component.toggleNavigationAppearance()
expect(component.navigationAppearance).toBe('dense')
expect(hovered).toBeFalse()
expect(handleMouseLeave).toHaveBeenCalledTimes(1)

component.toggleNavigationAppearance()
expect(component.navigationAppearance).toBe('default')
expect(handleMouseLeave).toHaveBeenCalledTimes(1)
})
})
Loading
Loading