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
7 changes: 7 additions & 0 deletions public/i18n/en_US.json
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@
"Associated Building Tax Lot ID": "Associated Building Tax Lot ID",
"Associated Tax Lot ID": "Associated Tax Lot ID",
"Associated Tax Lot IDs": "Associated Tax Lot IDs",
"At least one of the following Property fields is required: {{fields}}": "At least one of the following Property fields is required: {{fields}}",
"Audit Template": "Audit Template",
"Audit Template Building ID": "Audit Template Building ID",
"Audit Template City ID": "Audit Template City ID",
Expand Down Expand Up @@ -303,6 +304,7 @@
"Column Profiles": "Column Profiles",
"Column Settings": "Column Settings",
"Column mappings": "Column mappings",
"Column name": "Column name",
"Column representing number of transactions per property.": "Column representing number of transactions per property.",
"Column storing the compliance cycle year for each property": "Column storing the compliance cycle year for each property",
"Columns": "Columns",
Expand Down Expand Up @@ -411,6 +413,8 @@
"Create new data set": "Create new data set",
"Create new label": "Create new label",
"Create new sub-organization": "Create new sub-organization",
"Create new {{type}}": "Create New {{type}}",
"Create {{ali}} {{type}} in Cycle {{cycle}}?": "Create {{ali}} {{type}} in Cycle {{cycle}}?",
"Created": "Created",
"Cross Cycles": "Cross Cycles",
"Cross-Cycles": "Cross-Cycles",
Expand All @@ -436,6 +440,7 @@
"Cycle Name Benchmark Field": "Cycle Name Benchmark Field",
"Cycle Selection": "Cycle Selection",
"Cycle Start": "Cycle Start",
"Cycle is required": "Cycle is required",
"Cycle selection and goal details can be customized by clicking the Configure Goals button below.": "Cycle selection and goal details can be customized by clicking the Configure Goals button below.",
"Cycle updated.": "Cycle updated.",
"Cycle used as the baseline for calculations": "Cycle used as the baseline for calculations",
Expand Down Expand Up @@ -680,6 +685,7 @@
"Exported": "Exported",
"Exporting properties to your Audit Template account": "Exporting properties to your Audit Template account",
"Exporting selected properties...": "Exporting selected properties...",
"Extra Data": "Extra Data",
"Extra columns to display alongside the calculated columns": "Extra columns to display alongside the calculated columns",
"FACILITIES_PLAN_INTRO": "Use the settings below to configure a Facilities Plan to identify facilities that account for a specified percentage of the organization's overall energy use. Originally developed to help identify covered facilities for Section 432 of the Energy Independence and Security Act of 2007 (EISA 432), but can be used for other planning purposes. This section contains the core required settings. Additional configurations can be made per access level or cycle in the Facilities Plan tab of the Insights section.",
"FAILED_GEOCODE_INVALID_MAPQUEST_API_KEY": "Geocoding failed - Your MapQuest API Key is invalid. Update your MapQuest API Key or disable geocoding in Organization Settings.",
Expand Down Expand Up @@ -1340,6 +1346,7 @@
"Remove User from Organizatio": "Remove User from Organizatio",
"Remove User from Organization": "Remove User from Organization",
"Remove buildings from project": "Remove buildings from project",
"Remove column": "Remove column",
"Remove inventory and organizations": "Remove inventory and organizations",
"Removing buildings from project": "Removing buildings from project",
"Rename": "Rename",
Expand Down
7 changes: 7 additions & 0 deletions public/i18n/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@
"Associated Building Tax Lot ID": "Número de identificación fiscal del edificio asociado",
"Associated Tax Lot ID": "ID de parcela fiscal asociada",
"Associated Tax Lot IDs": "CIF asociados",
"At least one of the following Property fields is required: {{fields}}": "Se requiere al menos uno de los siguientes campos de propiedad: {{fields}}",
"Audit Template": "Plantilla de auditoría",
"Audit Template Building ID": "Plantilla de auditoría ID del edificio",
"Audit Template City ID": "Plantilla de auditoría ID de ciudad",
Expand Down Expand Up @@ -303,6 +304,7 @@
"Column Profiles": "Perfiles de columna",
"Column Settings": "Ajustes de columna",
"Column mappings": "Mapeos de columnas",
"Column name": "Nombre de la columna",
"Column representing number of transactions per property.": "Columna que representa el número de transacciones por propiedad.",
"Column storing the compliance cycle year for each property": "Columna que almacena el año del ciclo de cumplimiento para cada propiedad.",
"Columns": "Columnas",
Expand Down Expand Up @@ -411,6 +413,8 @@
"Create new data set": "Crear un nuevo conjunto de datos",
"Create new label": "Crear nueva etiqueta",
"Create new sub-organization": "Crear una nueva suborganización",
"Create new {{type}}": "Crear Nuevo {{type}}",
"Create {{ali}} {{type}} in Cycle {{cycle}}?": "Crear {{ali}} {{type}} en ciclo {{cycle}}¿",
"Created": "Creado",
"Cross Cycles": "Ciclos cruzados",
"Cross-Cycles": "Ciclos cruzados",
Expand All @@ -436,6 +440,7 @@
"Cycle Name Benchmark Field": "Campo de referencia del nombre del ciclo",
"Cycle Selection": "Selección de ciclos",
"Cycle Start": "Inicio del ciclo",
"Cycle is required": "Se requiere ciclo",
"Cycle selection and goal details can be customized by clicking the Configure Goals button below.": "La selección del ciclo y los detalles del objetivo se pueden personalizar haciendo clic en el botón Configurar objetivos que aparece a continuación.",
"Cycle updated.": "Ciclo actualizado.",
"Cycle used as the baseline for calculations": "Ciclo utilizado como base para los cálculos.",
Expand Down Expand Up @@ -680,6 +685,7 @@
"Exported": "Exportado",
"Exporting properties to your Audit Template account": "Exportación de propiedades a su cuenta de Plantilla de Auditoría",
"Exporting selected properties...": "Exportar propiedades seleccionadas...",
"Extra Data": "Datos adicionales",
"Extra columns to display alongside the calculated columns": "Columnas adicionales para mostrar junto a las columnas calculadas.",
"FACILITIES_PLAN_INTRO": "Utilice la configuración que se muestra a continuación para configurar un Plan de Instalaciones que identifique aquellas instalaciones que representan un porcentaje específico del consumo energético total de la organización. Originalmente desarrollado para ayudar a identificar las instalaciones cubiertas por la Sección 432 de la Ley de Independencia y Seguridad Energética de 2007 (EISA 432), puede utilizarse para otros fines de planificación. Esta sección contiene la configuración básica obligatoria. Se pueden realizar configuraciones adicionales por nivel de acceso o ciclo en la pestaña Plan de Instalaciones de la sección Información.",
"FAILED_GEOCODE_INVALID_MAPQUEST_API_KEY": "Error de geocodificación - Su clave API de MapQuest no es válida. Actualice su clave API de MapQuest o desactive la geocodificación en los ajustes de la organización.",
Expand Down Expand Up @@ -1340,6 +1346,7 @@
"Remove User from Organizatio": "Eliminar usuario de la organización",
"Remove User from Organization": "Eliminar usuario de la organización",
"Remove buildings from project": "Retirar edificios del proyecto",
"Remove column": "Eliminar columna",
"Remove inventory and organizations": "Eliminar inventario y organizaciones",
"Removing buildings from project": "Retirada de edificios del proyecto",
"Rename": "Renombrar",
Expand Down
7 changes: 7 additions & 0 deletions public/i18n/fr_CA.json
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@
"Associated Building Tax Lot ID": "ID de lot d'impôt du bâtiment associé",
"Associated Tax Lot ID": "ID de lot d'impôt associé",
"Associated Tax Lot IDs": "IDs des lots d'impôt associé",
"At least one of the following Property fields is required: {{fields}}": "Au moins un des champs de propriété suivants est obligatoire : {{fields}}",
"Audit Template": "Modèle d'audit",
"Audit Template Building ID": "Audit Template ID de bâtiment",
"Audit Template City ID": "Modèle d'audit ID de ville",
Expand Down Expand Up @@ -303,6 +304,7 @@
"Column Profiles": "Profils de colonnes",
"Column Settings": "Paramètres de colonne",
"Column mappings": "Mappages de colonnes",
"Column name": "Nom de la colonne",
"Column representing number of transactions per property.": "Colonne représentant le nombre de transactions par propriété.",
"Column storing the compliance cycle year for each property": "Colonne indiquant l'année du cycle de conformité pour chaque propriété",
"Columns": "Colonnes",
Expand Down Expand Up @@ -411,6 +413,8 @@
"Create new data set": "Créer un nouveau jeu de données",
"Create new label": "Créer une nouvelle étiquette",
"Create new sub-organization": "Créer une nouvelle sous-organisation",
"Create new {{type}}": "Créer Un(e) {{type}}",
"Create {{ali}} {{type}} in Cycle {{cycle}}?": "Créer {{ali}} {{type}} en cycle {{cycle}}?",
"Created": "Créé",
"Cross Cycles": "Cross Cycles",
"Cross-Cycles": "Entre les Cycles",
Expand All @@ -436,6 +440,7 @@
"Cycle Name Benchmark Field": "Nom du cycle Champ de référence",
"Cycle Selection": "Sélection des cycles",
"Cycle Start": "Démarrage du cycle",
"Cycle is required": "Le vélo est nécessaire",
"Cycle selection and goal details can be customized by clicking the Configure Goals button below.": "La sélection des cycles et les détails des objectifs peuvent être personnalisés en cliquant sur le bouton Configurer les objectifs ci-dessous.",
"Cycle updated.": "Cycle mis à jour.",
"Cycle used as the baseline for calculations": "Cycle utilisé comme référence pour les calculs",
Expand Down Expand Up @@ -680,6 +685,7 @@
"Exported": "Exporté",
"Exporting properties to your Audit Template account": "Exporter des propriétés vers votre compte de modèle d'audit",
"Exporting selected properties...": "Exportation des propriétés sélectionnées...",
"Extra Data": "Données supplémentaires",
"Extra columns to display alongside the calculated columns": "Colonnes supplémentaires à afficher à côté des colonnes calculées",
"FACILITIES_PLAN_INTRO": "Utilisez les paramètres ci-dessous pour configurer un plan d'infrastructures afin d'identifier les installations qui représentent un pourcentage spécifié de la consommation énergétique totale de l'organisation. Initialement conçu pour identifier les installations concernées par l'article 432 de la loi de 2007 sur l'indépendance et la sécurité énergétiques (EISA 432), cet outil peut également servir à d'autres fins de planification. Cette section présente les paramètres de base obligatoires. Des configurations supplémentaires peuvent être effectuées par niveau d'accès ou par cycle dans l'onglet « Plan d'infrastructures » de la section « Informations ».",
"FAILED_GEOCODE_INVALID_MAPQUEST_API_KEY": "Échec du géocodage : votre clé API MapQuest n'est pas valide. Mettez à jour votre clé API MapQuest ou désactivez le géocodage dans les paramètres de l'organisation.",
Expand Down Expand Up @@ -1340,6 +1346,7 @@
"Remove User from Organizatio": "Supprimer l'utilisateur de l'organisation",
"Remove User from Organization": "Supprimer l'utilisateur de l'organisation",
"Remove buildings from project": "Supprimer les bâtiments du projet",
"Remove column": "Supprimer la colonne",
"Remove inventory and organizations": "Supprimer l'inventaire et les organisations",
"Removing buildings from project": "Retrait des bâtiments du projet",
"Rename": "Renommer",
Expand Down
9 changes: 7 additions & 2 deletions src/@seed/api/inventory/inventory.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -294,12 +294,17 @@ export class InventoryService {
inventoryType: InventoryType,
viewId: number | null = null,
): Observable<FormCreateResponse> {
const url = `/api/v3/${inventoryType}/form_create/`
const url = `/api/v3/${inventoryType}/`
const params: Record<string, number> = { organization_id: this.orgId }
if (viewId !== null) {
params.related_view_id = viewId
}
return this._httpClient.post<FormCreateResponse>(url, data, { params }).pipe(
return this._httpClient.post<Record<string, unknown>>(url, data, { params }).pipe(
map((r) => ({
status: r.status as string,
// normalize property_view_id / taxlot_view_id to view_id
view_id: (r.property_view_id ?? r.taxlot_view_id ?? r.view_id ?? null) as number | null,
})),
catchError((error: HttpErrorResponse) => {
return this._errorService.handleError(error, `Error creating ${inventoryType === 'taxlots' ? 'tax lot' : 'property'}`)
}),
Expand Down
117 changes: 113 additions & 4 deletions src/app/modules/inventory-detail/timeline/timeline.component.html
Original file line number Diff line number Diff line change
@@ -1,11 +1,120 @@
<seed-page
[config]="{
title: 'Property',
subTitle: viewDisplayField$ | async,
title: type === 'taxlots' ? 'Tax Lot' : 'Property',
titleIcon: 'fa-solid:timeline',
breadcrumbs: ['Property', 'Timeline'],
breadcrumbs: [type === 'taxlots' ? 'Tax Lot' : 'Property', 'Timeline'],
sideNavToggle: true,
}"
>
<seed-not-found message="Timeline in development..." icon="fa-solid:triangle-exclamation"></seed-not-found>
<div class="m-5 flex flex-col gap-4">
<!-- Controls -->
<div class="flex items-center justify-between">
<div class="text-secondary text-sm">{{ timeline.length }} cycle(s)</div>
<div class="flex items-center gap-3">
<span class="text-secondary text-sm">Sort:</span>
<button class="text-sm" (click)="toggleSort()" mat-stroked-button>
{{ sortDesc ? 'Oldest to Newest' : 'Newest to Oldest' }}
Comment on lines +12 to +16
</button>
</div>
</div>

@if (loading) {
<mat-progress-bar mode="indeterminate"></mat-progress-bar>
} @else if (!timeline.length) {
<div class="text-secondary py-8 text-center text-sm">No timeline events found.</div>
} @else {
<!-- Cycle groups -->
@for (cycle of timeline; track cycle.cycle) {
<mat-expansion-panel class="bg-card" expanded>
<mat-expansion-panel-header>
<mat-panel-title class="font-semibold">{{ cycleNameById[cycle.cycle] ?? 'Cycle ' + cycle.cycle }}</mat-panel-title>
<mat-panel-description class="text-secondary text-xs">{{ cycle.events.length }} event(s)</mat-panel-description>
</mat-expansion-panel-header>

<div class="flex flex-col gap-2 pt-1">
@for (event of cycle.events; track event.id) {
<mat-expansion-panel class="border !shadow-none">
<mat-expansion-panel-header>
<mat-panel-title class="flex items-center gap-3 text-sm">
<mat-icon class="shrink-0 icon-size-4" [svgIcon]="eventIcon[event.event_type]"></mat-icon>
<span class="font-medium">{{ eventLabel[event.event_type] }}</span>
<span class="text-secondary">{{ event.modified | date: 'yyyy-MM-dd HH:mm' }}</span>
@if (userName(event.user_id)) {
<span class="text-secondary">{{ userName(event.user_id) }}</span>
}
@if (event.audit_date) {
<span class="text-secondary">Audit: {{ event.audit_date }}</span>
}
@if (event.analysis) {
<span class="text-secondary">{{ event.analysis.service }}</span>
}
</mat-panel-title>
</mat-expansion-panel-header>

<!-- NoteEvent detail -->
@if (event.event_type === 'NoteEvent' && event.note) {
<div class="rounded bg-gray-50 p-3 text-sm dark:bg-gray-800">
<div class="text-secondary mb-1 text-xs">{{ event.note.updated | date: 'yyyy-MM-dd HH:mm' }}</div>
<p class="whitespace-pre-wrap">{{ event.note.text }}</p>
</div>
}

<!-- AnalysisEvent detail -->
@if (event.event_type === 'AnalysisEvent' && event.analysis) {
<div class="rounded bg-gray-50 p-3 text-sm dark:bg-gray-800">
<dl class="grid grid-cols-[auto_1fr] gap-x-4 gap-y-1">
<dt class="text-secondary">Name</dt>
<dd class="font-medium">{{ event.analysis.name }}</dd>
<dt class="text-secondary">Service</dt>
<dd>{{ event.analysis.service }}</dd>
<dt class="text-secondary">Created</dt>
<dd>{{ event.analysis.created_at | date: 'yyyy-MM-dd' }}</dd>
@if (formatDuration(event.analysis.start_time, event.analysis.end_time)) {
<dt class="text-secondary">Duration</dt>
<dd>{{ formatDuration(event.analysis.start_time, event.analysis.end_time) }}</dd>
}
@if (event.analysis.status) {
<dt class="text-secondary">Status</dt>
<dd>{{ event.analysis.status }}</dd>
}
</dl>
</div>
}

<!-- ATEvent detail: scenarios + measures -->
@if (event.event_type === 'ATEvent' && event.scenarios?.length) {
<mat-accordion multi>
@for (scenario of event.scenarios; track scenario.id) {
<mat-expansion-panel class="bg-card border-t !shadow-none">
<mat-expansion-panel-header>
<mat-panel-title class="text-sm font-medium">{{ scenario.name }}</mat-panel-title>
<mat-panel-description class="flex gap-4 text-xs">
<span>Elec: {{ scenario.annual_electricity_savings ?? 'N/A' }} kBtu</span>
<span>{{ scenario.measures?.length ?? 0 }} measure(s)</span>
</mat-panel-description>
</mat-expansion-panel-header>
@if (scenario.measures?.length) {
<div class="flex flex-col gap-1 text-sm">
@for (measure of scenario.measures; track $index) {
<div class="flex gap-3 border-b py-1 text-xs last:border-0">
<span class="text-secondary w-28 shrink-0">{{ measure['category'] }}</span>
<span class="font-medium">{{ measure['display_name'] }}</span>
<span class="text-secondary ml-auto">{{ measure['implementation_status'] }}</span>
</div>
}
</div>
} @else {
<div class="text-secondary text-sm">No measures.</div>
}
</mat-expansion-panel>
}
</mat-accordion>
}
</mat-expansion-panel>
}
</div>
</mat-expansion-panel>
}
}
</div>
</seed-page>
Loading
Loading