Skip to content
Open
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
16 changes: 16 additions & 0 deletions public/i18n/en_US.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
"Access Level Instance": "Access Level Instance",
"Access Level Instance Information": "Access Level Instance Information",
"Access Level Instance Tree": "Access Level Instance Tree",
"Access Level Instance is required": "Access Level Instance is required",
"Access Level Instance:": "Access Level Instance:",
"Access Level Instances": "Access Level Instances",
"Access Level Instances Errors": "Access Level Instances Errors",
Expand Down Expand Up @@ -155,6 +156,8 @@
"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}}",
"At least one of the following Tax Lot fields is required: {{fields}}": "At least one of the following Tax Lot fields is required: {{fields}}",
"Audit Template": "Audit Template",
"Audit Template Building ID": "Audit Template Building ID",
"Audit Template Email": "Audit Template Email",
Expand Down Expand Up @@ -278,6 +281,7 @@
"Column Profiles": "Column Profiles",
"Column Settings": "Column Settings",
"Column mappings": "Column mappings",
"Column name": "Column name",
"Columns": "Columns",
"Columns to Include in Reports x axis options": "Columns to Include in Reports x axis options",
"Columns to Include in Reports y axis options": "Columns to Include in Reports y axis options",
Expand Down Expand Up @@ -346,8 +350,10 @@
"Create Organization": "Create Organization",
"Create Profile": "Create Profile",
"Create Project": "Create Project",
"Create Property": "Create Property",
"Create Service for System": "Create Service for System",
"Create System": "Create System",
"Create Tax Lot": "Create Tax Lot",
"Create UBID": "Create UBID",
"Create User": "Create User",
"Create Your Account": "Create Your Account",
Expand All @@ -373,6 +379,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 @@ -395,6 +403,7 @@
"Cycle Name": "Cycle Name",
"Cycle Name Benchmark Field": "Cycle Name Benchmark Field",
"Cycle Selection": "Cycle Selection",
"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:": "Cycle:",
Expand Down Expand Up @@ -504,6 +513,8 @@
"Drag the columns below to change the order that they appear in your Buildings List table.": "Drag the columns below to change the order that they appear in your Buildings List table.",
"Drag to here": "Drag to here",
"Duplicate": "Duplicate",
"Duplicate columns are not allowed": "Duplicate columns are not allowed",
"Duplicate record exists": "Duplicate record exists",
"Duplicates": "Duplicates",
"EDIT_GOAL_NOTES": "Edit Fields for the Selected Properties",
"EMAIL_TEMPLATE_EXAMPLE": "\"Your building's latitude and longitude is \\{\\{latitude\\}\\}, \\{\\{longitude\\}\\}!\"",
Expand Down Expand Up @@ -611,6 +622,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",
"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.",
"FAILED_GEOCODE_MAPQUEST_API_KEY_ERROR": "Geocoding failed - Your MapQuest API Key is either invalid or at its limit. Update your MapQuest API Key or disable geocoding in Organization Settings.",
"FAIR_BENCHMARK_RATIO_HELP": "The fair ratio of Total EUI to Benchmark Total EUI value to use. Ratio = Total EUI\/Benchmark EUI",
Expand Down Expand Up @@ -888,6 +900,7 @@
"Matched Tax Lots": "Matched Tax Lots",
"Matched!": "Matched!",
"Matching Column List Profiles": "Matching Column List Profiles",
"Matching Criteria": "Matching Criteria",
"Matching Criteria Preview": "Matching Criteria Preview",
"Matching Detail": "Matching Detail",
"Matching Detail Settings": "Matching Detail Settings",
Expand Down Expand Up @@ -1183,6 +1196,7 @@
"Remove User": "Remove User",
"Remove User from Organizatio": "Remove User from Organizatio",
"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 Expand Up @@ -1415,6 +1429,7 @@
"Successful Exports": "Successful Exports",
"Successful upload!": "Successful upload!",
"Successfully Uploaded": "Successfully Uploaded",
"Successfully created {{type}}": "Successfully created {{type}}",
"Summary": "Summary",
"Switch Profiles": "Switch Profiles",
"System": "System",
Expand Down Expand Up @@ -1612,6 +1627,7 @@
"Using your current browser will prevent you from accessing features on our website. Use the links below to download a new browser or upgrade your existing browser.": "Using your current browser will prevent you from accessing features on our website. Use the links below to download a new browser or upgrade your existing browser.",
"Valid": "Valid",
"Valid email required": "Valid email required",
"Value": "Value",
"Version": "Version",
"View Compliance Tracking": "View Compliance Tracking",
"View Project": "View Project",
Expand Down
19 changes: 19 additions & 0 deletions src/@seed/api/inventory/inventory.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ import type {
CrossCyclesResponse,
DeleteParams,
FilterResponse,
FormCreateResponse,
GenericView,
GenericViewsResponse,
InventoryDisplayType,
InventoryExportData,
InventoryFormCreateData,
InventoryType,
InventoryTypeGoal,
NewProfileData,
Expand Down Expand Up @@ -287,6 +289,23 @@ export class InventoryService {
)
}

createInventory(
data: InventoryFormCreateData,
inventoryType: InventoryType,
viewId: number | null = null,
): Observable<FormCreateResponse> {
const url = `/api/v3/${inventoryType}/form_create/`
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(
catchError((error: HttpErrorResponse) => {
return this._errorService.handleError(error, `Error creating ${inventoryType === 'taxlots' ? 'tax lot' : 'property'}`)
}),
)
}

uploadPropertyDocument(orgId: number, viewId: number, file: File, fileExt: PropertyDocumentExtension): Observable<unknown> {
const url = `/api/v3/properties/${viewId}/upload_inventory_document/?organization_id=${orgId}`
const formData = new FormData()
Expand Down
16 changes: 16 additions & 0 deletions src/app/core/navigation/navigation.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ export class NavigationService {
type: 'basic',
exactMatch: true,
},
{
id: 'properties/create',
link: '/properties/create',
title: 'Create Property',
icon: 'fa-solid:plus',
type: 'basic',
exactMatch: true,
},
{
id: 'properties/column-list-profiles',
link: '/properties/column-list-profiles',
Expand Down Expand Up @@ -72,6 +80,14 @@ export class NavigationService {
type: 'basic',
exactMatch: true,
},
{
id: 'taxlots/create',
link: '/taxlots/create',
title: 'Create Tax Lot',
icon: 'fa-solid:plus',
type: 'basic',
exactMatch: true,
},
{
id: 'taxlots/column-list-profiles',
link: '/taxlots/column-list-profiles',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<seed-modal-header [title]="data.title" [close]="close.bind(this)" titleIcon="fa-solid:building"></seed-modal-header>

<div class="mx-4 my-5">{{ data.body }}</div>

<div class="flex justify-end gap-2">
<mat-dialog-actions>
<button (click)="onSubmit()" mat-raised-button color="primary">
<mat-icon class="icon-size-4" [svgIcon]="data.confirmIcon"></mat-icon>
{{ data.confirmText }}
</button>
</mat-dialog-actions>
<mat-dialog-actions>
<button (click)="close()" mat-stroked-button>{{ 'Cancel' | transloco }}</button>
</mat-dialog-actions>
</div>
23 changes: 23 additions & 0 deletions src/app/modules/inventory/create/create-confirm-modal.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Component, inject } from '@angular/core'
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'
import { TranslocoPipe } from '@jsverse/transloco'
import { ModalHeaderComponent } from '@seed/components'
import { MaterialImports } from '@seed/materials'

@Component({
selector: 'seed-inventory-create-confirm-modal',
templateUrl: './create-confirm-modal.component.html',
imports: [MaterialImports, ModalHeaderComponent, TranslocoPipe],
})
export class CreateConfirmModalComponent {
private _dialogRef = inject(MatDialogRef<CreateConfirmModalComponent>)
data = inject(MAT_DIALOG_DATA) as { title: string; body: string; confirmText: string; confirmIcon: string }

onSubmit() {
this.close(true)
}

close(confirmed = false) {
this._dialogRef.close(confirmed)
}
}
129 changes: 129 additions & 0 deletions src/app/modules/inventory/create/inventory-create.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
<seed-page *transloco="let t" [config]="{ title: t(titleKey), titleIcon: 'fa-solid:building' }">
<div class="flex flex-col gap-6 p-6 sm:p-10">
<!-- Errors + Save -->
<div class="flex items-start justify-between gap-4">
<div class="flex-1">
@if (formErrors.length) {
<seed-alert [showIcon]="false" type="error" appearance="outline">
<ul class="list-disc">
@for (message of formErrors; track $index) {
<li class="ml-6">{{ message }}</li>
}
</ul>
</seed-alert>
}
</div>
<button [disabled]="!loaded || !valid || formErrors.length > 0 || creating" (click)="save()" mat-flat-button color="primary">
<mat-icon class="icon-size-4" svgIcon="fa-solid:floppy-disk"></mat-icon>
<span class="ml-2">{{ t('Save') }}</span>
</button>
</div>

<!-- Config selects -->
<form class="flex flex-wrap gap-4" [formGroup]="configForm">
<mat-form-field class="w-64" subscriptSizing="dynamic">
<mat-label>{{ t('Access Level') }}</mat-label>
<mat-select formControlName="access_level">
@for (level of accessLevelNames; track level) {
<mat-option [value]="level">{{ level }}</mat-option>
}
</mat-select>
</mat-form-field>

<mat-form-field class="w-64" subscriptSizing="dynamic">
<mat-label>{{ t('Level Instance') }}</mat-label>
<mat-select formControlName="access_level_instance">
@for (ali of accessLevelInstances; track ali.id) {
<mat-option [value]="ali.id">{{ ali.name }}</mat-option>
}
</mat-select>
</mat-form-field>

<mat-form-field class="w-64" subscriptSizing="dynamic">
<mat-label>{{ t('Cycle') }}</mat-label>
<mat-select formControlName="cycle">
@for (cycle of cycles; track cycle.id) {
<mat-option [value]="cycle.id">{{ cycle.name }}</mat-option>
}
</mat-select>
</mat-form-field>
</form>

<!-- Profile + column set buttons -->
<div class="flex flex-wrap items-center gap-4 border-t pt-4">
<mat-form-field class="w-64" subscriptSizing="dynamic">
<mat-label>{{ t('Column List Profile') }}</mat-label>
<mat-select [value]="selectedProfileId" (selectionChange)="changeProfile($event.value)">
@for (profile of profiles; track profile.id) {
<mat-option [value]="profile.id">{{ profile.name }}</mat-option>
}
</mat-select>
</mat-form-field>
<button (click)="setColumns('canonical')" mat-stroked-button>{{ t('All Canonical Fields') }}</button>
<button (click)="setColumns('extra')" mat-stroked-button>{{ t('All Extra Data Fields') }}</button>
<button (click)="setColumns('reset')" mat-stroked-button>{{ t('Reset') }}</button>
</div>

<!-- Column rows -->
<div class="border-t pt-4">
<table class="w-full">
<thead>
<tr class="text-secondary border-b text-left text-sm">
<th class="p-2">{{ t('Inventory Type') }}</th>
<th class="p-2">{{ t('Column') }}</th>
<th class="p-2">{{ t('Value') }}</th>
<th class="p-2 text-center">{{ t('Matching Criteria') }}</th>
<th class="p-2 text-center">{{ t('Extra Data') }}</th>
<th class="p-2">{{ t('Data Type') }}</th>
<th class="p-2"></th>
</tr>
</thead>
<tbody>
@for (row of rows; track row.id; let i = $index) {
<tr [class.bg-red-100]="row.is_duplicate" [class.dark:bg-red-900]="row.is_duplicate">
<td class="align-middle p-2">{{ row.table_name.slice(0, -5) }}</td>
<td class="min-w-48 p-2">
<mat-form-field class="w-full" subscriptSizing="dynamic">
<input
[formControl]="row.ctrl"
[matAutocomplete]="auto"
[placeholder]="t('Column name')"
[attr.aria-label]="t('Column name')"
matInput
autocomplete="off"
/>
<mat-autocomplete #auto="matAutocomplete" [displayWith]="displayColumn">
@for (option of row.filtered; track option.id) {
<mat-option [value]="option">{{ option.display_name }}</mat-option>
}
</mat-autocomplete>
</mat-form-field>
</td>
<td class="min-w-48 p-2">
<mat-form-field class="w-full" subscriptSizing="dynamic">
<input [(ngModel)]="row.value" [attr.aria-label]="t('Value')" (ngModelChange)="validate()" matInput />
</mat-form-field>
</td>
<td class="p-2 text-center">
<mat-checkbox [checked]="row.is_matching_criteria" disabled></mat-checkbox>
</td>
<td class="p-2 text-center">
<mat-checkbox [checked]="row.is_extra_data" disabled></mat-checkbox>
</td>
<td class="align-middle p-2">{{ row.data_type }}</td>
<td class="p-2 text-center">
<button [attr.aria-label]="t('Remove column')" (click)="removeColumn(i)" mat-icon-button color="warn">
<mat-icon svgIcon="fa-solid:xmark"></mat-icon>
</button>
</td>
</tr>
}
</tbody>
</table>
<button class="mt-4" (click)="addColumn()" mat-stroked-button>
<mat-icon class="icon-size-4" svgIcon="fa-solid:plus"></mat-icon>
<span class="ml-2">{{ t('Add Column') }}</span>
</button>
</div>
</div>
</seed-page>
Loading
Loading