Skip to content

Portfolio summary implementation - #79

Open
kflemin wants to merge 26 commits into
mainfrom
portfolio-summary
Open

Portfolio summary implementation#79
kflemin wants to merge 26 commits into
mainfrom
portfolio-summary

Conversation

@kflemin

@kflemin kflemin commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

No description provided.

haneslinger and others added 15 commits January 28, 2026 12:39
…ry-merge

# Conflicts:
#	cspell.json
#	package.json
#	pnpm-lock.yaml
#	src/app/modules/organizations/settings/salesforce-building-integration/salesforce-building-integration.component.ts
- Resolve merge conflicts with main (cspell.json, package.json,
  pnpm-lock.yaml, salesforce-building-integration component) by keeping
  main's newer Salesforce Building Integration implementation (BB
  Salesforce support, barrel imports) under the PR's renamed path.
- Convert new API/component imports to the @seed/api and MaterialImports
  barrels per project convention; register goal and salesforce-portfolio
  in the @seed/api barrel index.
- Fix missing salesforce-login/salesforce-portfolio-integration .scss
  files referenced by styleUrl (never committed) by dropping the
  styleUrl instead.
- Add full Transloco translation coverage for all new UI strings across
  the portfolio summary, configure-goals, add-cycle,
  salesforce-portfolio-integration and salesforce-login templates.
- Fix several crashes found via live testing against a real backend:
  - ConfigureGoalsDialogComponent.save() threw when Salesforce
    integration was not enabled / no partner was selected.
  - AddCycleDialogComponent.submit() threw when no annual report was
    selected (Salesforce not enabled).
  - PortfolioSummaryComponent.createChart() threw when a goal had no
    weighted EUI data yet.
  - PortfolioSummaryComponent.openAddCycle() threw because cycle_goals
    was never initialized/fetched.
  - Removed a stray {{ chart }} interpolation inside the results canvas
    that rendered "[object Object]".
- Add GoalService.getCycleGoals() and call it when selecting/updating a
  goal so previously created cycle goals load after a refresh (the
  Goal API response never embeds cycle_goals).
- Remove leftover console.log debug statements.

Verified with pnpm lint / pnpm build, and by standing up a throwaway
Django backend (docker) with seeded data and exercising the goal
create/edit, add-cycle, and Salesforce settings flows via Playwright.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ry-merge

# Conflicts:
#	public/i18n/en_US.json
- Remove an erroneous p-80 (320px) padding class on the CycleGoal side
  summary table, which was causing huge, uneven whitespace around that
  card. Drop the redundant duplicate p-10 alongside p-4 on the goal
  summary card for the same reason.
- Add px-3 py-1 cell padding to the summary table so label/value
  columns aren't flush against each other.
- Wrap the page content in the same content mx-5 my-2 container used by
  sibling insights pages (Program Overview, Property Insights, Default
  Reports) instead of leaving it unpadded/flush with the page edge.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

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.

Pull request overview

Implements the Insights “Portfolio Summary” feature area, including goal configuration workflows, Salesforce portfolio sync UI/service plumbing, and related inventory-grid/action enhancements.

Changes:

  • Added a full Portfolio Summary page (goal selection, cycle comparison, goal notes editing, exports) plus supporting dialogs (configure goals, add/edit cycle, bulk edit notes, sync-to-Salesforce review).
  • Introduced new API clients/types for Goals and Salesforce Portfolio, and extended existing services (labels, inventory, audit-template, bb-salesforce config handling).
  • Updated org settings routing/navigation for the Salesforce building integration page; added an OAuth callback route/component for Salesforce login.

Reviewed changes

Copilot reviewed 59 out of 64 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
src/app/modules/salesforce-login/salesforce-login.component.ts New Salesforce OAuth callback component to exchange code for token and redirect.
src/app/modules/salesforce-login/salesforce-login.component.spec.ts Adds a basic unit test for the Salesforce login callback component.
src/app/modules/salesforce-login/salesforce-login.component.html Adds a translated “Logging in…” loading message.
src/app/modules/organizations/settings/settings.routes.ts Renames Salesforce settings route to salesforce-building-integration and switches component.
src/app/modules/organizations/settings/settings.component.ts Updates settings nav link to new Salesforce settings route.
src/app/modules/organizations/settings/salesforce-building-integration/salesforce-building-integration.component.ts Renames/refactors Salesforce settings component and adjusts bb-salesforce config save behavior.
src/app/modules/organizations/settings/salesforce-building-integration/salesforce-building-integration.component.html Minor formatting update to seed-page config binding.
src/app/modules/organizations/settings/salesforce-building-integration/modal/index.ts Barrel export for Salesforce mapping modals.
src/app/modules/organizations/settings/salesforce-building-integration/modal/form-modal.component.ts Adds create/edit Salesforce field mapping modal.
src/app/modules/organizations/settings/salesforce-building-integration/modal/form-modal.component.html Template for Salesforce mapping create/edit modal.
src/app/modules/organizations/settings/salesforce-building-integration/modal/delete-modal.component.ts Adds delete-confirm modal for Salesforce field mappings.
src/app/modules/organizations/settings/salesforce-building-integration/modal/delete-modal.component.html Template for Salesforce mapping delete confirmation modal.
src/app/modules/inventory-list/summary/summary.component.ts Formatting-only refactors in requestColumns and filter matcher logic.
src/app/modules/inventory-list/list/inventory.component.html Passes cycles into grid actions component.
src/app/modules/inventory-list/list/grid/label-header.component.ts New ag-grid header component for toggling label column expansion.
src/app/modules/inventory-list/list/grid/grid.component.ts Adds label column expand/collapse behavior and new compact label rendering.
src/app/modules/inventory-list/list/grid/grid.component.html Provides ag-grid context to support header-driven label toggling.
src/app/modules/inventory-list/list/grid/actions.component.ts Adds audit-template export/import modals and Salesforce update action wiring.
src/app/modules/inventory-list/list/grid/actions.component.html Enables Audit Template and Salesforce menu items conditionally and wires actions.
src/app/modules/inventory-list/list/actions/index.ts Exports newly added audit-template action modals.
src/app/modules/inventory-list/list/actions/audit-template-import-modal.component.ts New modal to import audit-template submissions into inventory with progress tracking.
src/app/modules/inventory-list/list/actions/audit-template-import-modal.component.html Template for audit-template import modal.
src/app/modules/inventory-list/list/actions/audit-template-export-modal.component.ts New modal to export selected properties to Audit Template with progress tracking.
src/app/modules/inventory-list/list/actions/audit-template-export-modal.component.html Template for audit-template export modal.
src/app/modules/insights/portfolio-summary/sync-salesforce-dialog/sync-salesforce-dialog.component.ts New dialog to compare SEED vs Salesforce and sync current/historical reports.
src/app/modules/insights/portfolio-summary/sync-salesforce-dialog/sync-salesforce-dialog.component.spec.ts Comprehensive unit tests for sync-salesforce dialog logic.
src/app/modules/insights/portfolio-summary/sync-salesforce-dialog/sync-salesforce-dialog.component.html Sync-to-Salesforce dialog UI (loading/error states, comparison tables, actions).
src/app/modules/insights/portfolio-summary/sync-salesforce-dialog/index.ts Barrel export for sync-salesforce dialog.
src/app/modules/insights/portfolio-summary/portfolio-summary.types.ts Adds Portfolio Summary dialog/context types.
src/app/modules/insights/portfolio-summary/portfolio-summary.component.spec.ts Adds extensive unit test coverage for Portfolio Summary component logic.
src/app/modules/insights/portfolio-summary/portfolio-summary.component.html Implements the full Portfolio Summary page UI and interactions.
src/app/modules/insights/portfolio-summary/portfolio-summary-label-header.component.ts New label header for Portfolio Summary grids (expand/collapse per column).
src/app/modules/insights/portfolio-summary/portfolio-summary-header-menu.component.ts New ag-grid header menu component using CDK Overlay for sort/pin/hide.
src/app/modules/insights/portfolio-summary/portfolio-summary-header-menu.component.html Template for Portfolio Summary header menu overlay.
src/app/modules/insights/portfolio-summary/index.ts Re-exports Portfolio Summary types in addition to component.
src/app/modules/insights/portfolio-summary/configure-goals-dialog/index.ts Barrel export for configure-goals dialog.
src/app/modules/insights/portfolio-summary/configure-goals-dialog/configure-goals-dialog.component.ts Adds goal creation/editing/deletion dialog (incl. Salesforce partner/goal association).
src/app/modules/insights/portfolio-summary/configure-goals-dialog/configure-goals-dialog.component.html Template for goal configuration dialog.
src/app/modules/insights/portfolio-summary/bulk-edit-goal-notes-modal.component.ts Adds bulk edit modal for goal notes fields across selected properties.
src/app/modules/insights/portfolio-summary/bulk-edit-goal-notes-modal.component.html Template for bulk edit goal notes modal.
src/app/modules/insights/portfolio-summary/add-cycle-dialog/index.ts Barrel export for add-cycle dialog.
src/app/modules/insights/portfolio-summary/add-cycle-dialog/add-cycle-dialog.component.ts Adds add/edit cycle dialog (incl. optional Salesforce annual report association).
src/app/modules/insights/portfolio-summary/add-cycle-dialog/add-cycle-dialog.component.html Template for add/edit cycle dialog.
src/app/modules/insights/facilities-plan/facilities-plan.component.spec.ts Formatting-only changes in tests.
src/app/modules/datasets/pairing/pairing.component.ts Formatting-only change to drag column definition.
src/app/app.routes.ts Adds /salesforce-login route for Salesforce OAuth callback.
src/@seed/api/salesforce/salesforce.types.ts Changes bb_salesforce_configs response shape type.
src/@seed/api/salesforce/bb-salesforce.service.ts Updates bb-salesforce config parsing and update signature to match new API behavior.
src/@seed/api/salesforce-portfolio/salesforce-portfolio.types.ts New types for Salesforce portfolio config/token/partners/annual reports endpoints.
src/@seed/api/salesforce-portfolio/salesforce-portfolio.service.ts New service for Salesforce portfolio endpoints (login/token/partners/annual reports).
src/@seed/api/salesforce-portfolio/index.ts Barrel export for Salesforce portfolio API package.
src/@seed/api/label/label.types.ts Adds PropertyViewLabel type.
src/@seed/api/label/label.service.ts Adds listByCycleGoal call for property view labels.
src/@seed/api/inventory/inventory.service.ts Adds updateSalesforce endpoint wrapper for inventory updates.
src/@seed/api/index.ts Exports new goal and salesforce-portfolio API packages.
src/@seed/api/goal/index.ts Barrel export for new goal API package.
src/@seed/api/goal/goal.types.ts Adds goal/cycle-goal/portfolio-summary/notes/salesforce-summary type definitions.
src/@seed/api/goal/goal.service.ts Adds goal CRUD + portfolio summary + property list + Salesforce sync service methods.
src/@seed/api/audit-template/audit-template.service.ts Adds batch export/import endpoints returning progress_key.
public/i18n/fr_CA.json Adds translations for new Portfolio Summary and related UI strings.
public/i18n/es.json Adds translations for new Portfolio Summary and related UI strings.
public/i18n/en_US.json Adds new keys for Portfolio Summary UI; removes some existing keys.
.spelling.dic Adds domain terms (e.g., kbtu, euis) to spelling dictionary.
Suppressed comments (5)

src/app/modules/salesforce-login/salesforce-login.component.ts:26

  • ngOnInit unconditionally calls getToken with params.code cast to string. If the callback is hit without a code (or with an error param), this will call the API with an invalid value. Guard against missing code and prefer org_id when available.
    src/@seed/api/salesforce-portfolio/salesforce-portfolio.service.ts:75
  • getAnnualReports is typed as getPartnersResponse (SalesforcePartner[]), but the endpoint is for Annual Reports. This will cause type errors at call sites (and can mask real response-shape issues). Use getAnnualReportsResponse for both the return type and HttpClient generic (and consider a more specific error message).
  getAnnualReports(goalId: number): Observable<getPartnersResponse> {
    const url = `/api/v3/bb_salesforce/annual_report/?organization_id=${this.orgId}&goal_id=${goalId}`
    return this._httpClient.get<getPartnersResponse>(url).pipe(
      map((response) => response),
      catchError((error: HttpErrorResponse) => {
        return this._errorService.handleError(error, `Error fetching summary: ${error.message}`)
      }),
    )

src/@seed/api/goal/goal.service.ts:80

  • editedGoal is implicitly typed as any here. With noImplicitAny enabled this will fail to compile; even without it, it defeats type safety for payload construction. Type it as a Partial (or a narrower payload type) to keep API calls typed.
  editGoal(goalId: number, editedGoal, orgId: number): Observable<Goal> {

src/@seed/api/goal/goal.service.ts:89

  • newGoal is implicitly typed as any here. With noImplicitAny enabled this will fail to compile; type it as Partial (or a dedicated create payload type) to keep this call type-safe.
  createGoal(newGoal, orgId: number): Observable<Goal> {

public/i18n/en_US.json:74

  • Several i18n keys were removed from en_US.json but are still referenced in code (e.g., inventory-create.component.ts translates 'Access Level Instance is required', 'Cycle is required', and 'Duplicate columns are not allowed'). Removing these keys will cause missing-translation behavior in the UI. Please restore the removed keys (or update the callers to use the new keys).
  "Access Level": "Access Level",
  "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:": "Access Level Instance:",
  "Access Level Instances": "Access Level Instances",
  "Access Level Instances Errors": "Access Level Instances Errors",
  "Access Level Tree": "Access Level Tree",

Comment thread src/app/modules/salesforce-login/salesforce-login.component.ts
Comment thread src/app/modules/salesforce-login/salesforce-login.component.spec.ts
Comment thread src/@seed/api/salesforce-portfolio/salesforce-portfolio.service.ts
Comment thread src/@seed/api/goal/goal.service.ts
Comment thread src/app/modules/inventory-list/list/grid/grid.component.ts
Comment thread src/app/modules/inventory-list/list/grid/grid.component.ts Outdated
Comment thread public/i18n/es.json
kflemin and others added 5 commits August 3, 2026 20:54
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot AI and others added 2 commits August 4, 2026 02:57
Co-authored-by: kflemin <2205659+kflemin@users.noreply.github.com>
…spose overlay and unsubscribe

Co-authored-by: kflemin <2205659+kflemin@users.noreply.github.com>

Copilot AI left a comment

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.

Pull request overview

Copilot reviewed 59 out of 64 changed files in this pull request and generated 1 comment.

Suppressed comments (13)

src/app/modules/salesforce-login/salesforce-login.component.ts:28

  • Router.navigate is using a relative navigation array (no leading /), which will append to the current salesforce-login route. Also params.code as string will pass undefined when the query param is missing. Guard against a missing code and navigate to an absolute path (this also makes use of the currently-unused EMPTY import).
    src/app/modules/inventory-list/list/grid/grid.component.ts:280
  • The collapsed label “color bar” uses hard-coded hex colors via LABEL_COLOR_MAP. The codebase already defines label colors via the global .label theme classes (src/styles/styles.scss:129-161), so hard-coding hex values here risks theme drift. You can build the mini-bars by applying the existing .label color classes and overriding padding/margins inline.
    src/app/modules/inventory-list/list/grid/grid.component.ts:20
  • LABEL_COLOR_MAP hard-codes hex colors (and will be unused if the renderer uses .label classes). Since label coloring is already centralized in src/styles/styles.scss under .label, removing this constant avoids theme drift and prevents an unused-const lint failure.
    src/@seed/api/salesforce-portfolio/salesforce-portfolio.service.ts:73
  • getAnnualReports has the wrong response type (getPartnersResponse). This makes the method unsafe to consume and currently leaves the imported getAnnualReportsResponse unused. The endpoint returns { status, results: AnnualReport[] }, so the method should use getAnnualReportsResponse for both the Observable and the HttpClient generic.
  getAnnualReports(goalId: number): Observable<getPartnersResponse> {
    const url = `/api/v3/bb_salesforce/annual_report/?organization_id=${this.orgId}&goal_id=${goalId}`
    return this._httpClient.get<getPartnersResponse>(url).pipe(
      map((response) => response),
      catchError((error: HttpErrorResponse) => {

src/app/modules/inventory-list/list/actions/audit-template-import-modal.component.ts:41

  • The progress polling subscription created in onSubmit() is not tied to the dialog lifecycle. If the user closes the modal while polling is in progress, the polling can continue in the background. Add takeUntil(this._unsubscribeAll$) to cancel it on destroy.
    src/app/modules/inventory-list/list/actions/audit-template-export-modal.component.ts:34
  • The export progress polling subscription is not cancelled on dialog destroy, so it can continue running after the modal is closed. Add takeUntil(this._unsubscribeAll$) to the polling chain.
    src/app/modules/inventory-list/list/grid/actions.component.ts:56
  • _auditTemplateService is injected but never used, which will trigger an unused private member lint error.
    src/app/modules/inventory-list/summary/summary.component.ts:223
  • The assignment formatting here (const requestColumns with = on the next line) is inconsistent with the surrounding code and is likely to fail Prettier formatting checks. Reformat the ternary to the standard multi-line style used elsewhere in this file.
    src/app/modules/inventory-list/summary/summary.component.ts:1018
  • This assignment formatting (const valueText with = on the next line) is inconsistent with the file’s existing style and likely to be rewritten by Prettier. Reformat to the usual multi-line ternary layout for readability and to avoid formatting churn.
    src/@seed/api/goal/goal.service.ts:96
  • editedGoal and newGoal are implicitly any, which will fail under the repo’s TypeScript strictness/linting. Type these payload parameters (e.g., Partial<Goal>), since callers pass partial update/create payloads.
  editGoal(goalId: number, editedGoal, orgId: number): Observable<Goal> {
    const url = `/api/v3/goals/${goalId}/?organization_id=${orgId}`
    return this._httpClient.put<Goal>(url, editedGoal).pipe(
      catchError((error: HttpErrorResponse) => {
        return this._errorService.handleError(error, `Error fetching summary: ${error.message}`)

src/app/modules/inventory-list/list/actions/audit-template-import-modal.component.ts:6

  • _unsubscribeAll$ is defined and completed in ngOnDestroy, but the observable chain in onSubmit() doesn’t use it. Import takeUntil so the long-running progress polling can be cancelled if the dialog is closed/destroyed.

This issue also appears on line 37 of the same file.
src/app/modules/inventory-list/list/actions/audit-template-export-modal.component.ts:5

  • Like the import modal, this dialog defines _unsubscribeAll$ but doesn’t use it in the polling observable chain. Import takeUntil so the export progress polling can be cancelled when the dialog is destroyed.

This issue also appears on line 30 of the same file.
src/app/modules/inventory-list/list/grid/actions.component.ts:8

  • AuditTemplateService is imported but not used in this component (and _auditTemplateService is never referenced). This will fail linting under unused-import/member rules.

This issue also appears on line 56 of the same file.

Comment thread src/app/modules/inventory-list/list/grid/grid.component.ts
kflemin and others added 4 commits August 4, 2026 22:39
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@kflemin
kflemin requested a review from nllong August 5, 2026 02:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants