Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
f8f24ae
refactor for ag grid
perryr16 Jun 24, 2025
3fe9cfe
temp - register ag gird in main.ts
perryr16 Jun 25, 2025
d1f8d1f
renove unused class
perryr16 Jun 25, 2025
b968b64
datasets grid
perryr16 Jun 25, 2025
38e8698
rename
perryr16 Jun 25, 2025
eed0813
route rename to datasets
perryr16 Jun 25, 2025
5c3410b
dataset grid, dummy actions
perryr16 Jun 26, 2025
e9127d9
merge main
perryr16 Jun 26, 2025
491088c
icons
perryr16 Jun 26, 2025
3740ead
basic upload to mapping
perryr16 Jun 26, 2025
ac8e658
ptl data upload modal fxnal
perryr16 Jun 27, 2025
afcb9e3
import data to mapping
perryr16 Jun 27, 2025
c7a99b4
help component
perryr16 Jun 27, 2025
e0fc3fc
mapping table dev
perryr16 Jun 27, 2025
a34db5c
merge main
perryr16 Jun 27, 2025
1b9c0fb
debug
perryr16 Jun 27, 2025
4a270ea
mapping table fxns and styles
perryr16 Jun 30, 2025
c9fc081
validate data mapping
perryr16 Jul 1, 2025
966a8e2
save mapping step
perryr16 Jul 2, 2025
b3517a1
uploaded data, step4 issues
perryr16 Jul 2, 2025
bd0eb0b
link to ptl step4
perryr16 Jul 2, 2025
0ddd228
merge
perryr16 Jul 2, 2025
35b97d4
Merge branch 'main' into feat/data-upload
perryr16 Jul 3, 2025
e0dae9a
subprogress fxnal
perryr16 Jul 3, 2025
f2d8998
whole xls upload fxnal
perryr16 Jul 3, 2025
cd6f9f0
styles
perryr16 Jul 3, 2025
75f0864
autocomplete not subset
perryr16 Jul 3, 2025
90cc539
steps not editable
perryr16 Jul 3, 2025
c8118c1
select all count
perryr16 Jul 7, 2025
f380c2f
rounded btns
perryr16 Jul 7, 2025
5aacc7b
styles
perryr16 Jul 7, 2025
e4b8b2a
data quality results modal
perryr16 Jul 7, 2025
a48db62
fetch and apply profile
perryr16 Jul 8, 2025
aba8394
save profi;e
perryr16 Jul 8, 2025
8ec5e37
profiles fxnal
perryr16 Jul 9, 2025
f191f38
hook up delete taxlots from inv list
perryr16 Jul 9, 2025
3c22220
upload props and taxlots related
perryr16 Jul 9, 2025
0c974dc
show both taxlot and property results
perryr16 Jul 9, 2025
327e632
several bug fixes, features, styles
perryr16 Jul 9, 2025
2f5d86c
prettier
perryr16 Jul 9, 2025
7b0d32c
lint
perryr16 Jul 9, 2025
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
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@ import type { HttpErrorResponse } from '@angular/common/http'
import { HttpClient } from '@angular/common/http'
import { inject, Injectable } from '@angular/core'
import type { Observable } from 'rxjs'
import { catchError, map, ReplaySubject } from 'rxjs'
import { catchError, map, ReplaySubject, tap } from 'rxjs'
import { ErrorService } from '@seed/services'
import { SnackBarService } from 'app/core/snack-bar/snack-bar.service'
import { UserService } from '../user'
import type {
ColumnMapping,
ColumnMappingProfile,
ColumnMappingProfileDeleteResponse,
ColumnMappingProfilesRequest,
ColumnMappingProfileType,
ColumnMappingProfileUpdateResponse,
ColumnMappingSuggestionResponse,
} from './column_mapping_profile.types'
Expand All @@ -20,6 +22,7 @@ export class ColumnMappingProfileService {
private _userService = inject(UserService)
private _profiles = new ReplaySubject<ColumnMappingProfile[]>(1)
private _errorService = inject(ErrorService)
private _snackBar = inject(SnackBarService)

profiles$ = this._profiles.asObservable()

Expand All @@ -30,9 +33,13 @@ export class ColumnMappingProfileService {
})
}

getProfiles(org_id: number): Observable<ColumnMappingProfile[]> {
const url = `/api/v3/column_mapping_profiles/filter/?organization_id=${org_id}`
return this._httpClient.post<ColumnMappingProfilesRequest>(url, {}).pipe(
getProfiles(orgId: number, columnMappingProfileTypes: ColumnMappingProfileType[] = []): Observable<ColumnMappingProfile[]> {
const url = `/api/v3/column_mapping_profiles/filter/?organization_id=${orgId}`
const data: Record<string, unknown> = {}
if (columnMappingProfileTypes.length) {
data.profile_type = columnMappingProfileTypes
}
return this._httpClient.post<ColumnMappingProfilesRequest>(url, data).pipe(
map((response) => {
this._profiles.next(response.data)
return response.data
Expand All @@ -44,8 +51,8 @@ export class ColumnMappingProfileService {
)
}

updateMappings(org_id: number, profile_id: number, mappings: ColumnMapping[]): Observable<ColumnMappingProfile> {
const url = `/api/v3/column_mapping_profiles/${profile_id}/?organization_id=${org_id}`
updateMappings(orgId: number, profile_id: number, mappings: ColumnMapping[]): Observable<ColumnMappingProfile> {
const url = `/api/v3/column_mapping_profiles/${profile_id}/?organization_id=${orgId}`
return this._httpClient.put<ColumnMappingProfileUpdateResponse>(url, { mappings }).pipe(
map((response) => {
return response.data
Expand All @@ -56,20 +63,21 @@ export class ColumnMappingProfileService {
)
}

update(org_id: number, profile: ColumnMappingProfile): Observable<ColumnMappingProfile> {
const url = `/api/v3/column_mapping_profiles/${profile.id}/?organization_id=${org_id}`
return this._httpClient.put<ColumnMappingProfileUpdateResponse>(url, { name: profile.name }).pipe(
update(orgId: number, profile: ColumnMappingProfile): Observable<ColumnMappingProfile> {
const url = `/api/v3/column_mapping_profiles/${profile.id}/?organization_id=${orgId}`
return this._httpClient.put<ColumnMappingProfileUpdateResponse>(url, profile).pipe(
map((response) => {
return response.data
}),
tap(() => { this._snackBar.success('Profile updated successfully') }),
catchError((error: HttpErrorResponse) => {
return this._errorService.handleError(error, 'Error updating profile')
}),
)
}

delete(org_id: number, profile_id: number): Observable<ColumnMappingProfileDeleteResponse> {
const url = `/api/v3/column_mapping_profiles/${profile_id}/?organization_id=${org_id}`
delete(orgId: number, profile_id: number): Observable<ColumnMappingProfileDeleteResponse> {
const url = `/api/v3/column_mapping_profiles/${profile_id}/?organization_id=${orgId}`
return this._httpClient.delete<ColumnMappingProfileDeleteResponse>(url).pipe(
map((response) => {
return response
Expand All @@ -80,17 +88,18 @@ export class ColumnMappingProfileService {
)
}

create(org_id: number, profile: ColumnMappingProfile): Observable<ColumnMappingProfileUpdateResponse> {
const url = `/api/v3/column_mapping_profiles/?organization_id=${org_id}`
create(orgId: number, profile: ColumnMappingProfile): Observable<ColumnMappingProfileUpdateResponse> {
const url = `/api/v3/column_mapping_profiles/?organization_id=${orgId}`
return this._httpClient.post<ColumnMappingProfileUpdateResponse>(url, { ...profile }).pipe(
tap(() => { this._snackBar.success('Profile created successfully') }),
catchError((error: HttpErrorResponse) => {
return this._errorService.handleError(error, 'Error creating profile')
}),
)
}

export(org_id: number, profile_id: number) {
const url = `/api/v3/column_mapping_profiles/${profile_id}/csv/?organization_id=${org_id}`
export(orgId: number, profile_id: number) {
const url = `/api/v3/column_mapping_profiles/${profile_id}/csv/?organization_id=${orgId}`
return this._httpClient.get(url, { responseType: 'text' }).pipe(
map((response) => {
return new Blob([response], { type: 'text/csv;charset: utf-8' })
Expand All @@ -101,8 +110,8 @@ export class ColumnMappingProfileService {
)
}

suggestions(org_id: number, headers: string[]) {
const url = `/api/v3/column_mapping_profiles/suggestions/?organization_id=${org_id}`
suggestions(orgId: number, headers: string[]) {
const url = `/api/v3/column_mapping_profiles/suggestions/?organization_id=${orgId}`
return this._httpClient.post<ColumnMappingSuggestionResponse>(url, { headers }).pipe(
map((response) => {
return response.data
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,5 @@ export type ColumnMappingSuggestionResponse = {
status: string;
data: Record<string, ['PropertyState' | 'TaxLotState', string, number]>;
}

export type ColumnMappingProfileType = 'Normal' | 'BuildingSync Default' | 'BuildingSync Custom'
32 changes: 22 additions & 10 deletions src/@seed/api/cycle/cycle.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ import { HttpClient } from '@angular/common/http'
import { inject, Injectable } from '@angular/core'
import type { Observable } from 'rxjs'
import { BehaviorSubject, catchError, map, take, tap } from 'rxjs'
import { OrganizationService } from '@seed/api/organization'
import { ErrorService } from '@seed/services'
import { SnackBarService } from 'app/core/snack-bar/snack-bar.service'
import { UserService } from '../user'
import type { Cycle, CycleResponse, CyclesResponse } from './cycle.types'

@Injectable({ providedIn: 'root' })
export class CycleService {
private _httpClient = inject(HttpClient)
private _organizationService = inject(OrganizationService)
private _userService = inject(UserService)
private _snackBar = inject(SnackBarService)
private _errorService = inject(ErrorService)
private _cycles = new BehaviorSubject<Cycle[]>([])
Expand All @@ -20,21 +20,20 @@ export class CycleService {
cycles$ = this._cycles.asObservable()

constructor() {
this._organizationService.currentOrganization$
this._userService.currentOrganizationId$
.pipe(
tap(({ org_id }) => {
this.get(org_id)
tap((orgId) => {
this.getCycles(orgId)
}),
)
.subscribe()
}

get(orgId: number) {
getCycles(orgId: number) {
const url = `/api/v3/cycles/?organization_id=${orgId}`
this._httpClient
.get<CyclesResponse>(url)
.pipe(
take(1),
map(({ cycles }) => cycles),
tap((cycles) => {
this._cycles.next(cycles)
Expand All @@ -46,12 +45,25 @@ export class CycleService {
.subscribe()
}

getCycle(orgId: number, cycleId: number): Observable<Cycle> {
const url = `/api/v3/cycles/${cycleId}?organization_id=${orgId}`
return this._httpClient
.get<CycleResponse>(url)
.pipe(
take(1),
map(({ cycles }) => cycles),
catchError((error: HttpErrorResponse) => {
return this._errorService.handleError(error, 'Error fetching cycles')
}),
)
}

post({ data, orgId }): Observable<CycleResponse | null> {
const url = `/api/v3/cycles/?organization_id=${orgId}`
return this._httpClient.post<CycleResponse>(url, data).pipe(
tap((response) => {
this._snackBar.success(`Created Cycle ${response.cycles.name}`)
this.get(orgId as number)
this.getCycles(orgId as number)
}),
catchError((error: HttpErrorResponse) => {
return this._errorService.handleError(error, 'Error creating cycle')
Expand All @@ -64,7 +76,7 @@ export class CycleService {
return this._httpClient.put<CycleResponse>(url, data).pipe(
tap((response) => {
this._snackBar.success(`Updated Cycle ${response.cycles.name}`)
this.get(orgId as number)
this.getCycles(orgId as number)
}),
catchError((error: HttpErrorResponse) => {
return this._errorService.handleError(error, 'Error updating cycle')
Expand All @@ -76,7 +88,7 @@ export class CycleService {
const url = `/api/v3/cycles/${id}/?organization_id=${orgId}`
return this._httpClient.delete(url).pipe(
tap(() => {
this.get(orgId)
this.getCycles(orgId)
}),
catchError((error: HttpErrorResponse) => {
return this._errorService.handleError(error, 'Error deleting cycle')
Expand Down
39 changes: 37 additions & 2 deletions src/@seed/api/data-quality/data-quality.service.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { HttpClient, type HttpErrorResponse } from '@angular/common/http'
import { inject, Injectable } from '@angular/core'
import { catchError, type Observable, ReplaySubject, switchMap, tap } from 'rxjs'
import { catchError, map, type Observable, ReplaySubject, switchMap, tap } from 'rxjs'
import { OrganizationService } from '@seed/api/organization'
import { ErrorService } from '@seed/services'
import { SnackBarService } from 'app/core/snack-bar/snack-bar.service'
import type { Rule } from './data-quality.types'
import type { DQCProgressResponse } from '../progress'
import type { DataQualityResults, DataQualityResultsResponse, Rule } from './data-quality.types'

@Injectable({ providedIn: 'root' })
export class DataQualityService {
Expand Down Expand Up @@ -79,4 +80,38 @@ export class DataQualityService {
}),
)
}

startDataQualityCheckForImportFile(orgId: number, importFileId: number): Observable<DQCProgressResponse> {
const url = `/api/v3/import_files/${importFileId}/start_data_quality_checks/?organization_id=${orgId}`
return this._httpClient.post<DQCProgressResponse>(url, {})
.pipe(
catchError((error: HttpErrorResponse) => {
return this._errorService.handleError(error, 'Error starting data quality checks for import file')
}),
)
}

startDataQualityCheckForOrg(orgId: number, property_view_ids: number[], taxlot_view_ids: number[], goal_id: number): Observable<DQCProgressResponse> {
const url = `/api/v3/data_quality_checks/${orgId}/start/`
const data = {
property_view_ids,
taxlot_view_ids,
goal_id,
}
return this._httpClient.post<DQCProgressResponse>(url, data).pipe(
catchError((error: HttpErrorResponse) => {
return this._errorService.handleError(error, 'Error fetching data quality results for organization')
}),
)
}

getDataQualityResults(orgId: number, runId: number): Observable<DataQualityResults[]> {
const url = `/api/v3/data_quality_checks/results/?organization_id=${orgId}&run_id=${runId}`
return this._httpClient.get<DataQualityResultsResponse>(url).pipe(
map(({ data }) => data),
catchError((error: HttpErrorResponse) => {
return this._errorService.handleError(error, 'Error fetching data quality results')
}),
)
}
}
21 changes: 21 additions & 0 deletions src/@seed/api/data-quality/data-quality.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,24 @@ export type UnitNames =
| 'MJ/m²/year'
| 'kWh/m²/year'
| 'kBtu/m²/year'

export type DataQualityResultsResponse = {
data: DataQualityResults[];
}

export type DataQualityResults = {
[key: string]: unknown;
data_quality_results: DataQualityResult[];
}

export type DataQualityResult = {
condition: string;
detailed_message: string;
field: string;
formatted_field: string;
label: string;
message: string;
severity: string;
table_name: string;
value: unknown;
}
Loading