Skip to content

Add configuring status banner and auto-configure redesign#1689

Merged
lyubov-voloshko merged 5 commits intorocket-admin:mainfrom
karinakharchenko:dashboard-configuring-banner
Mar 26, 2026
Merged

Add configuring status banner and auto-configure redesign#1689
lyubov-voloshko merged 5 commits intorocket-admin:mainfrom
karinakharchenko:dashboard-configuring-banner

Conversation

@karinakharchenko
Copy link
Contributor

@karinakharchenko karinakharchenko commented Mar 25, 2026

Summary

  • Redesign auto-configure page: centered card with concentric spinning rings, indeterminate progress bar, and "Open tables" CTA
  • Add full-width status banner directly below nav bar: shows "Configuring tables" with progress animation while setup runs, swaps to green "All tables configured" when done
  • Hide "New: AI Configuration" alert while configuration is in progress
  • Add dot indicators next to table names in sidebar (green = configured, blue pulsing = still configuring)
  • Add ConfigurationStateService — singleton service that fires the setup API and survives navigation; shows a success snackbar when done
  • Active table in sidebar now highlighted with light blue background

Test plan

  • Navigate to /auto-configure/:id — verify card UI with spinner and progress bar
  • Click "Open tables" — verify status banner appears below nav, AI config alert is hidden
  • Wait for configuration to finish — verify success snackbar appears
  • Check sidebar dot indicators reflect table state
  • Verify light and dark mode for all new elements

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Dashboard shows a “Configuring tables” status banner with animated progress while setup runs.
    • New persistent auto-configuration view with custom spinner, indeterminate progress bar, and an “Open tables” CTA that proceeds to the dashboard.
  • Style

    • Reworked card-based layout, responsive/mobile adjustments and dark-mode styling.
    • New animated loading primitives (spinning rings and progress animations).
  • Bug Fixes

    • Simplified loading flow; previous alternate error UI is no longer shown.

…d sidebar dot indicators

- Redesign auto-configure page with centered card, spinning rings, and indeterminate progress bar
- Add full-width status banner below nav showing configuring/done state
- Hide AI config alert while configuration is in progress
- Add dot indicators in sidebar: green = configured, blue pulsing = configuring
- Add ConfigurationStateService to manage config state across navigation
- Show success snackbar when configuration completes in background

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings March 25, 2026 13:27
@CLAassistant
Copy link

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@coderabbitai
Copy link

coderabbitai bot commented Mar 25, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6a4c5849-131f-4582-ac70-3f69641e2db4

📥 Commits

Reviewing files that changed from the base of the PR and between 7127e06 and 4b7cf8c.

📒 Files selected for processing (4)
  • frontend/src/app/components/auto-configure/auto-configure.component.css
  • frontend/src/app/components/dashboard/dashboard.component.css
  • frontend/src/app/components/dashboard/dashboard.component.html
  • frontend/src/app/components/dashboard/dashboard.component.ts
✅ Files skipped from review due to trivial changes (1)
  • frontend/src/app/components/dashboard/dashboard.component.css
🚧 Files skipped from review as they are similar to previous changes (2)
  • frontend/src/app/components/dashboard/dashboard.component.ts
  • frontend/src/app/components/auto-configure/auto-configure.component.css

📝 Walkthrough

Walkthrough

Extracts auto-configuration API logic into a new ConfigurationStateService, updates AutoConfigure UI to a card-based spinner/progress layout, tracks configuration state in dashboard and table models, and centralizes start/isConfiguring flow for per-connection setup.

Changes

Cohort / File(s) Summary
Auto-configure component
frontend/src/app/components/auto-configure/auto-configure.component.css, frontend/src/app/components/auto-configure/auto-configure.component.html, frontend/src/app/components/auto-configure/auto-configure.component.ts
Replaced BEM .auto-configure styles with .page/.card, added spinner and progress-bar CSS; template now renders a static card with custom spinner/progress and a single CTA (removed conditional loading/error branches); TS removed local ApiService logic, made ngOnInit(): Promise<void> and delegates to ConfigurationStateService (removed loading/errorMessage).
Configuration state service
frontend/src/app/services/configuration-state.service.ts
New root-provided ConfigurationStateService managing per-connection in-progress set via BehaviorSubject<Set<string>>. Exposes startConfiguring(connectionId): Promise<boolean> (deduplicates concurrent starts, runs API call, shows snackbars) and isConfiguring(connectionId): boolean.
Dashboard component
frontend/src/app/components/dashboard/dashboard.component.css, frontend/src/app/components/dashboard/dashboard.component.html, frontend/src/app/components/dashboard/dashboard.component.ts
Added .status-banner CSS and template conditional banner that renders when isConfiguring is true; injected ConfigurationStateService and added public isConfiguring: boolean assigned from _configState.isConfiguring(connectionID). Adjusted alert visibility to hide during configuration.
Table list styles
frontend/src/app/components/dashboard/db-tables-list/db-tables-list.component.css
Removed .folder-name.editing and .enter-icon styles; changed .table-link to display: flex and added .table-link_active styling for active-state spacing and border radius.
Table model
frontend/src/app/models/table.ts
Extended TableProperties with optional flags configured?: boolean and configuring?: boolean.
sequenceDiagram
    actor User
    participant AutoCfg as AutoConfigureComponent
    participant ConfigState as ConfigurationStateService
    participant Api as ApiService
    participant Dashboard as DashboardComponent

    User->>AutoCfg: open auto-configure page / start flow
    AutoCfg->>ConfigState: startConfiguring(connectionId)
    alt duplicate start
        ConfigState-->>AutoCfg: resolves false (already running)
    else first start
        ConfigState->>ConfigState: add connectionId to in-progress set, emit
        ConfigState->>Api: GET /ai/v2/setup/{connectionId}
        Api-->>ConfigState: success / error
        ConfigState->>ConfigState: show snackbar (success or error)
        ConfigState->>ConfigState: remove connectionId from set, emit
        ConfigState-->>AutoCfg: resolves true/false
        AutoCfg->>Dashboard: navigate to /dashboard/{connectionId}
        Dashboard->>ConfigState: isConfiguring(connectionId)
        ConfigState-->>Dashboard: current boolean
        Dashboard->>Dashboard: render banner if true
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 Hop-hop — I spun a ring and nudged the state,

One service now keeps each connection straight.
Cards glow, progress bars hum in a line,
Dashboards peek in to see who's in design.
A carrot-sized cheer — configuration's fine!

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Add configuring status banner and auto-configure redesign' accurately summarizes the main changes: adding a status banner UI component and redesigning the auto-configure page layout and functionality.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Security Check ✅ Passed The pull request adheres to OWASP security guidelines and does not reduce overall project security through proper authentication, authorization, and XSS prevention.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces a new “auto-configure in background” UX flow: starting configuration from /auto-configure/:connection-id, then showing ongoing/done status inside the dashboard UI while setup runs.

Changes:

  • Added ConfigurationStateService to kick off the setup API and track “configuring” state across navigation.
  • Updated dashboard to render a full-width status banner during configuration and hide the AI Configuration alert while configuring.
  • Added sidebar table dot indicators and adjusted active-table styling; redesigned the auto-configure page UI.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
frontend/src/app/services/configuration-state.service.ts New singleton service to start setup and manage “configuring” state + completion snackbar.
frontend/src/app/models/table.ts Extends TableProperties with optional configured / configuring flags.
frontend/src/app/components/dashboard/db-tables-list/db-tables-list.component.html Adds dot indicator element with configured/configuring class bindings.
frontend/src/app/components/dashboard/db-tables-list/db-tables-list.component.css Styles dot indicators, converts table links to flex, tweaks active styling.
frontend/src/app/components/dashboard/dashboard.component.ts Wires in ConfigurationStateService and adds dashboard-level configuration flags.
frontend/src/app/components/dashboard/dashboard.component.html Adds status banner and hides AI-config alert during configuration.
frontend/src/app/components/dashboard/dashboard.component.css Adds status banner styling (light/dark).
frontend/src/app/components/auto-configure/auto-configure.component.ts Switches to using ConfigurationStateService and removes direct API call + spinner module.
frontend/src/app/components/auto-configure/auto-configure.component.html Replaces conditional spinner/error UI with new centered card layout.
frontend/src/app/components/auto-configure/auto-configure.component.css Adds new page/card/spinner/progress styling.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +31 to +34
await this._api.get<string>(`/ai/v2/setup/${connectionId}`, { responseType: 'text' });
this._notifications.showSuccessSnackbar('All tables have been configured.');
} catch {
this._notifications.showSuccessSnackbar('Configuration could not be completed.');
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

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

ApiService.get() returns null on HTTP errors and already handles notifications internally; it does not throw. As written, _runSetup will show the success snackbar even when the request failed (because await this._api.get(...) can resolve to null). Handle a null result as a failure (or use an API method that returns status), and show an error snackbar/message on failure to avoid misleading users and double-notifications.

Suggested change
await this._api.get<string>(`/ai/v2/setup/${connectionId}`, { responseType: 'text' });
this._notifications.showSuccessSnackbar('All tables have been configured.');
} catch {
this._notifications.showSuccessSnackbar('Configuration could not be completed.');
const result = await this._api.get<string>(`/ai/v2/setup/${connectionId}`, { responseType: 'text' });
if (result !== null) {
this._notifications.showSuccessSnackbar('All tables have been configured.');
}
} catch {
// Errors are handled by ApiService; avoid showing a misleading success snackbar here.

Copilot uses AI. Check for mistakes.
await this._api.get<string>(`/ai/v2/setup/${connectionId}`, { responseType: 'text' });
this._notifications.showSuccessSnackbar('All tables have been configured.');
} catch {
this._notifications.showSuccessSnackbar('Configuration could not be completed.');
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

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

Both the success and failure paths call showSuccessSnackbar(...). On failures, this should use showErrorSnackbar(...) (or surface the underlying API error message) so users get the correct severity and wording.

Suggested change
this._notifications.showSuccessSnackbar('Configuration could not be completed.');
this._notifications.showErrorSnackbar('Configuration could not be completed.');

Copilot uses AI. Check for mistakes.
Comment on lines +17 to +20
const current = this._configuring.value;
current.add(connectionId);
this._configuring.next(current);

Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

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

startConfiguring mutates the existing Set instance from the BehaviorSubject and re-emits the same reference. This can lead to missed updates for consumers using reference checks (e.g., distinctUntilChanged) and makes state harder to reason about. Prefer emitting a new Set instance each time you add/remove IDs (immutable update pattern).

Copilot uses AI. Check for mistakes.
Comment on lines +141 to +143
// Check if auto-configure is running for this connection
this.isConfiguring = this._configState.isConfiguring(this.connectionID);

Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

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

isConfiguring is only read once in ngOnInit, so the dashboard won’t update when configuration finishes (banner stays stuck, AI alert stays hidden). Consider exposing an observable/signal from ConfigurationStateService and subscribing (or converting to a signal) to keep isConfiguring reactive, and set configurationDone when the run completes.

Copilot uses AI. Check for mistakes.
Comment on lines +59 to +66
} @else if (configurationDone) {
<div class="status-banner status-banner--done">
<mat-icon class="status-banner__icon">check_circle</mat-icon>
<div class="status-banner__body">
<strong class="status-banner__title">All tables configured</strong>
<span class="status-banner__subtitle">Everything is ready to use.</span>
</div>
</div>
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

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

configurationDone is introduced but never set anywhere in the component, so the “All tables configured” banner can never render. Either wire this up to ConfigurationStateService completion events/state, or remove the dead branch/state.

Suggested change
} @else if (configurationDone) {
<div class="status-banner status-banner--done">
<mat-icon class="status-banner__icon">check_circle</mat-icon>
<div class="status-banner__body">
<strong class="status-banner__title">All tables configured</strong>
<span class="status-banner__subtitle">Everything is ready to use.</span>
</div>
</div>

Copilot uses AI. Check for mistakes.
Comment on lines +166 to +167
'table-dot--configured': table.configured,
'table-dot--configuring': table.configuring
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

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

table.configuring is used to drive the pulsing dot, but there’s no code in the repo assigning a configuring flag to TableProperties (only configured appears to come from the API). As a result, the “still configuring” indicator will never show. Either populate table.configuring when building tableFolders (e.g., from ConfigurationStateService/API response), or remove the class binding until the state is implemented.

Suggested change
'table-dot--configured': table.configured,
'table-dot--configuring': table.configuring
'table-dot--configured': table.configured

Copilot uses AI. Check for mistakes.
Comment on lines +7 to +41
@Injectable({ providedIn: 'root' })
export class ConfigurationStateService {
private _api = inject(ApiService);
private _notifications = inject(NotificationsService);
private _configuring = new BehaviorSubject<Set<string>>(new Set());

/** Start configuring — fires the API and manages state. Returns immediately. */
startConfiguring(connectionId: string): void {
if (this._configuring.value.has(connectionId)) return;

const current = this._configuring.value;
current.add(connectionId);
this._configuring.next(current);

this._runSetup(connectionId);
}

/** Check if a connection is currently being configured */
isConfiguring(connectionId: string): boolean {
return this._configuring.value.has(connectionId);
}

private async _runSetup(connectionId: string): Promise<void> {
try {
await this._api.get<string>(`/ai/v2/setup/${connectionId}`, { responseType: 'text' });
this._notifications.showSuccessSnackbar('All tables have been configured.');
} catch {
this._notifications.showSuccessSnackbar('Configuration could not be completed.');
} finally {
const current = this._configuring.value;
current.delete(connectionId);
this._configuring.next(current);
}
}
}
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

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

New ConfigurationStateService behavior isn’t covered by unit tests (success, failure, and state transitions). This repo has extensive service-level specs; adding a spec for this service would help prevent regressions (e.g., ensuring API failures don’t show success and that configuring state clears).

Copilot uses AI. Check for mistakes.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Nitpick comments (4)
frontend/src/app/components/auto-configure/auto-configure.component.css (1)

137-151: Consider avoiding !important for button styles.

The !important declarations on .card__cta could be replaced with higher specificity selectors to avoid potential cascading issues.

♻️ Alternative approach
-.card__cta {
+.card .card__cta {
 	flex-shrink: 0;
-	background: `#2563eb` !important;
-	color: `#fff` !important;
+	background: `#2563eb`;
+	color: `#fff`;
 	border-radius: 8px;
 	font-weight: 600;
 	font-size: 14px;
 	padding: 0 20px;
 	height: 40px;
 	text-decoration: none;
 }

-.card__cta:hover {
-	background: `#1d4ed8` !important;
+.card .card__cta:hover {
+	background: `#1d4ed8`;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/app/components/auto-configure/auto-configure.component.css`
around lines 137 - 151, Replace the use of `!important` on the `.card__cta` and
`.card__cta:hover` rules by increasing selector specificity or using a scoped
parent class instead of forcing styles, e.g., target the button with a more
specific selector like a wrapper class plus `.card__cta` (or add a modifier
class) and move the background and color declarations there so they override
competing rules; update `.card__cta` and `.card__cta:hover` declarations to
remove `!important` once the selectors are made more specific and verify the
styles still apply in all contexts.
frontend/src/app/components/dashboard/dashboard.component.css (1)

185-197: Consider using CSS variables for consistent theming.

The status banner uses hardcoded hex colors (e.g., #2563eb, #16a34a) while other elements in this file use CSS variables like var(--color-accentedPalette-500). This inconsistency may cause issues if the app supports dynamic themes beyond the light/dark mode media query.

♻️ Example of using CSS variables
 .status-banner {
 	display: flex;
 	align-items: center;
 	gap: 12px;
 	padding: 12px 20px;
 	width: 100%;
 	border: none;
-	border-left: 3px solid `#2563eb`;
+	border-left: 3px solid var(--status-banner-accent, `#2563eb`);
 	border-radius: 0;
-	background: `#ebf2ff`;
+	background: var(--status-banner-bg, `#ebf2ff`);
 	font-size: 13px;
-	color: `#1e293b`;
+	color: var(--status-banner-text, `#1e293b`);
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/app/components/dashboard/dashboard.component.css` around lines
185 - 197, The .status-banner CSS block uses hardcoded hex colors; replace those
literals with CSS variables (e.g., use existing vars like
--color-accentedPalette-500 for the border and --color-accentedPalette-50 for
the background or add new variables like --status-banner-border,
--status-banner-bg, --status-banner-text) so theming stays consistent; update
the .status-banner rule to reference these variables and ensure the variables
are defined in the global :root (or theme-specific) stylesheet so light/dark or
dynamic themes override them properly.
frontend/src/app/services/configuration-state.service.ts (1)

11-11: Consider using Angular Signals instead of BehaviorSubject.

As per coding guidelines, new code should use Angular Signals for state management. This would also address the Set mutation issue since signals have built-in change detection.

♻️ Proposed refactor using Signals
-import { inject, Injectable } from '@angular/core';
-import { BehaviorSubject } from 'rxjs';
+import { inject, Injectable, signal, computed } from '@angular/core';

 import { ApiService } from './api.service';
 import { NotificationsService } from './notifications.service';

 `@Injectable`({ providedIn: 'root' })
 export class ConfigurationStateService {
 	private _api = inject(ApiService);
 	private _notifications = inject(NotificationsService);
-	private _configuring = new BehaviorSubject<Set<string>>(new Set());
+	private _configuring = signal<Set<string>>(new Set());

 	startConfiguring(connectionId: string): void {
-		if (this._configuring.value.has(connectionId)) return;
+		if (this._configuring().has(connectionId)) return;

-		const current = this._configuring.value;
-		current.add(connectionId);
-		this._configuring.next(current);
+		this._configuring.update(set => new Set(set).add(connectionId));

 		this._runSetup(connectionId);
 	}

 	isConfiguring(connectionId: string): boolean {
-		return this._configuring.value.has(connectionId);
+		return this._configuring().has(connectionId);
 	}

 	private async _runSetup(connectionId: string): Promise<void> {
 		try {
 			await this._api.get<string>(`/ai/v2/setup/${connectionId}`, { responseType: 'text' });
 			this._notifications.showSuccessSnackbar('All tables have been configured.');
 		} catch {
-			this._notifications.showSuccessSnackbar('Configuration could not be completed.');
+			this._notifications.showErrorSnackbar('Configuration could not be completed.');
 		} finally {
-			const current = this._configuring.value;
-			current.delete(connectionId);
-			this._configuring.next(current);
+			this._configuring.update(set => {
+				const updated = new Set(set);
+				updated.delete(connectionId);
+				return updated;
+			});
 		}
 	}
 }

Based on learnings: "Use Angular Signals for state management in all new code instead of BehaviorSubject"

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/app/services/configuration-state.service.ts` at line 11, Replace
the BehaviorSubject-based state with an Angular Signal: change the _configuring
member in ConfigurationStateService to a Signal<Set<string>> initialized via
signal(new Set()), import signal from `@angular/core`, and update all places that
previously called _configuring.next(...) or subscribed to it to instead
read/update the signal (e.g., read via _configuring() and update by assigning a
new Set copy such as creating new Set([..._configuring(), item]) or new
Set([..._configuring()].filter(...)) to avoid mutating the existing Set); ensure
any public accessors or consumers use the signal getter or a computed/read-only
signal as appropriate.
frontend/src/app/components/dashboard/dashboard.component.ts (1)

26-26: Consider using inject() function pattern for new dependencies.

The existing codebase uses constructor injection, so this is consistent. However, coding guidelines prefer the inject() function pattern for new code:

private _configState = inject(ConfigurationStateService);

This is a minor stylistic suggestion given the existing patterns in the file.

Also applies to: 113-113

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/app/components/dashboard/dashboard.component.ts` at line 26,
Replace the new constructor-injected ConfigurationStateService with the inject()
pattern: add a private _configState = inject(ConfigurationStateService) field
(ensure inject is imported from '@angular/core'), remove
ConfigurationStateService from the DashboardComponent constructor parameters,
and update any references that relied on the constructor param to use the new
_configState field (e.g., where ConfigurationStateService was referenced inside
methods or properties).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@frontend/src/app/components/dashboard/dashboard.component.html`:
- Around line 51-53: The banner renders links using selectedTableName which may
be undefined, producing broken routes; update the template in
dashboard.component.html to guard those links by checking selectedTableName (or
providing a safe fallback) before rendering: either wrap the <a> elements (or
the entire status-banner__subtitle span) with an *ngIf="selectedTableName" or
conditionally disable/hide the anchors, or build the routerLink only when
selectedTableName is truthy; reference the routerLink bindings that use
connectionID and selectedTableName to locate and change the anchors.

In `@frontend/src/app/components/dashboard/dashboard.component.ts`:
- Around line 103-104: The configurationDone flag in DashboardComponent is never
updated; subscribe to the ConfigurationStateService's completion signal (e.g.,
an observable or event like configurationCompleted$ / isAllTablesConfigured)
inside the DashboardComponent class and set this.configurationDone = true when
the service emits completion; ensure you create the subscription in ngOnInit (or
the existing init flow that uses isConfiguring), store the Subscription, and
unsubscribe in ngOnDestroy to avoid leaks so the banner can show "All tables
configured" correctly.
- Around line 140-142: isConfiguring is only read once in ngOnInit using
_configState.isConfiguring(this.connectionID) (a synchronous boolean) so the
dashboard never updates; also configurationDone is declared but never used.
Update the config state service (_configState) to expose an Observable (e.g.,
configuring$ or getConfiguring(connectionId): Observable<boolean>) that emits
when a connection's configuration status changes, then in
DashboardComponent.ngOnInit subscribe to that Observable (using
this.connectionID) and update the component property (replace the one-time
assignment to isConfiguring); finally remove the unused configurationDone
declaration. Ensure you reference _configState, isConfiguring, and connectionID
when wiring the Observable and subscription.

In `@frontend/src/app/services/configuration-state.service.ts`:
- Around line 33-34: In the catch block of the configuration state flow, replace
the incorrect success notification call
this._notifications.showSuccessSnackbar('Configuration could not be completed.')
with the error notifier this._notifications.showErrorSnackbar(...) so failures
display an error snackbar; locate the catch that contains
this._notifications.showSuccessSnackbar and swap to showErrorSnackbar while
keeping the existing message (or a clearer error message) so users see a proper
error notification.
- Around line 17-19: The current code mutates the existing Set held in the
BehaviorSubject (this._configuring) which can prevent subscribers from seeing
updates; instead create and emit a new Set instance when adding and when
removing: for the add path replace current.add(connectionId);
this._configuring.next(current); with const next = new Set(current);
next.add(connectionId); this._configuring.next(next); and in the finally/remove
path do const next = new Set(this._configuring.value);
next.delete(connectionId); this._configuring.next(next); so you always emit a
new Set reference.

---

Nitpick comments:
In `@frontend/src/app/components/auto-configure/auto-configure.component.css`:
- Around line 137-151: Replace the use of `!important` on the `.card__cta` and
`.card__cta:hover` rules by increasing selector specificity or using a scoped
parent class instead of forcing styles, e.g., target the button with a more
specific selector like a wrapper class plus `.card__cta` (or add a modifier
class) and move the background and color declarations there so they override
competing rules; update `.card__cta` and `.card__cta:hover` declarations to
remove `!important` once the selectors are made more specific and verify the
styles still apply in all contexts.

In `@frontend/src/app/components/dashboard/dashboard.component.css`:
- Around line 185-197: The .status-banner CSS block uses hardcoded hex colors;
replace those literals with CSS variables (e.g., use existing vars like
--color-accentedPalette-500 for the border and --color-accentedPalette-50 for
the background or add new variables like --status-banner-border,
--status-banner-bg, --status-banner-text) so theming stays consistent; update
the .status-banner rule to reference these variables and ensure the variables
are defined in the global :root (or theme-specific) stylesheet so light/dark or
dynamic themes override them properly.

In `@frontend/src/app/components/dashboard/dashboard.component.ts`:
- Line 26: Replace the new constructor-injected ConfigurationStateService with
the inject() pattern: add a private _configState =
inject(ConfigurationStateService) field (ensure inject is imported from
'@angular/core'), remove ConfigurationStateService from the DashboardComponent
constructor parameters, and update any references that relied on the constructor
param to use the new _configState field (e.g., where ConfigurationStateService
was referenced inside methods or properties).

In `@frontend/src/app/services/configuration-state.service.ts`:
- Line 11: Replace the BehaviorSubject-based state with an Angular Signal:
change the _configuring member in ConfigurationStateService to a
Signal<Set<string>> initialized via signal(new Set()), import signal from
`@angular/core`, and update all places that previously called
_configuring.next(...) or subscribed to it to instead read/update the signal
(e.g., read via _configuring() and update by assigning a new Set copy such as
creating new Set([..._configuring(), item]) or new
Set([..._configuring()].filter(...)) to avoid mutating the existing Set); ensure
any public accessors or consumers use the signal getter or a computed/read-only
signal as appropriate.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1f613e25-dc9e-488d-87b7-91ec707f8bdb

📥 Commits

Reviewing files that changed from the base of the PR and between 333512e and 2022059.

📒 Files selected for processing (10)
  • frontend/src/app/components/auto-configure/auto-configure.component.css
  • frontend/src/app/components/auto-configure/auto-configure.component.html
  • frontend/src/app/components/auto-configure/auto-configure.component.ts
  • frontend/src/app/components/dashboard/dashboard.component.css
  • frontend/src/app/components/dashboard/dashboard.component.html
  • frontend/src/app/components/dashboard/dashboard.component.ts
  • frontend/src/app/components/dashboard/db-tables-list/db-tables-list.component.css
  • frontend/src/app/components/dashboard/db-tables-list/db-tables-list.component.html
  • frontend/src/app/models/table.ts
  • frontend/src/app/services/configuration-state.service.ts

Comment on lines +51 to +53
<span class="status-banner__subtitle">Some tables may look incomplete while setup is running. You can adjust column types, display formats and filters in
<a class="status-banner__link" routerLink="/table-settings/{{connectionID}}/{{selectedTableName}}">Settings</a> and
<a class="status-banner__link" routerLink="/widgets/{{connectionID}}/{{selectedTableName}}">UI widgets</a> after setup finishes.</span>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check how selectedTableName is initialized in dashboard.component.ts
ast-grep --pattern $'class DashboardComponent {
  $$$
  selectedTableName$_
  $$$
}'

# Also check if there's a guard or default value
rg -n 'selectedTableName' --type=ts -C3 frontend/src/app/components/dashboard/dashboard.component.ts

Repository: rocket-admin/rocketadmin

Length of output: 4138


🏁 Script executed:

# Show the context around the banner (lines 46-67) to see the `@if` condition
sed -n '40,70p' frontend/src/app/components/dashboard/dashboard.component.html

Repository: rocket-admin/rocketadmin

Length of output: 1694


🏁 Script executed:

# Search for isConfiguring initialization and usage in the component
rg -n 'isConfiguring' --type=ts -B2 -A2 frontend/src/app/components/dashboard/dashboard.component.ts | head -80

Repository: rocket-admin/rocketadmin

Length of output: 453


🏁 Script executed:

# Get the complete ngOnInit method to understand initialization order
sed -n '130,220p' frontend/src/app/components/dashboard/dashboard.component.ts

Repository: rocket-admin/rocketadmin

Length of output: 2992


🏁 Script executed:

# Check for `@for` loops in the dashboard template to see if track functions are used
rg -n '@for' frontend/src/app/components/dashboard/dashboard.component.html -A1

Repository: rocket-admin/rocketadmin

Length of output: 50


🏁 Script executed:

# Check for any loop constructs (*ngFor or `@for`) in the dashboard template
rg -n '(\*ngFor|@for)' frontend/src/app/components/dashboard/dashboard.component.html

Repository: rocket-admin/rocketadmin

Length of output: 50


🏁 Script executed:

# Check if there are any guards or null checks around the banner links
# Look at the complete template around the banner section
sed -n '46,68p' frontend/src/app/components/dashboard/dashboard.component.html

Repository: rocket-admin/rocketadmin

Length of output: 1406


Add guard to prevent rendering broken links when selectedTableName is undefined.

The banner displays when isConfiguring is true, but selectedTableName is initialized asynchronously and may be undefined when the banner first renders. This generates broken links like /table-settings/{connectionID}/undefined. Either guard the links with an @if (selectedTableName) condition or ensure selectedTableName has a default value before the banner displays.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/app/components/dashboard/dashboard.component.html` around lines
51 - 53, The banner renders links using selectedTableName which may be
undefined, producing broken routes; update the template in
dashboard.component.html to guard those links by checking selectedTableName (or
providing a safe fallback) before rendering: either wrap the <a> elements (or
the entire status-banner__subtitle span) with an *ngIf="selectedTableName" or
conditionally disable/hide the anchors, or build the routerLink only when
selectedTableName is truthy; reference the routerLink bindings that use
connectionID and selectedTableName to locate and change the anchors.

Comment on lines +103 to +104
public isConfiguring: boolean = false;
public configurationDone: boolean = false;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

configurationDone is declared but never updated.

The configurationDone field is initialized to false but there's no code in this component that sets it to true when configuration completes. This appears incomplete.

If the banner should show "All tables configured" upon completion, the component needs a mechanism to receive that notification from ConfigurationStateService.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/app/components/dashboard/dashboard.component.ts` around lines
103 - 104, The configurationDone flag in DashboardComponent is never updated;
subscribe to the ConfigurationStateService's completion signal (e.g., an
observable or event like configurationCompleted$ / isAllTablesConfigured) inside
the DashboardComponent class and set this.configurationDone = true when the
service emits completion; ensure you create the subscription in ngOnInit (or the
existing init flow that uses isConfiguring), store the Subscription, and
unsubscribe in ngOnDestroy to avoid leaks so the banner can show "All tables
configured" correctly.

Comment on lines +140 to +142

// Check if auto-configure is running for this connection
this.isConfiguring = this._configState.isConfiguring(this.connectionID);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Check ConfigurationStateService for public observables or subscription mechanisms

# Search for public observables or asObservable() patterns
rg -n -A 5 'asObservable|public.*\$|configuring\$|pipe\(' --type=ts -g '**/configuration-state.service.ts'

# Also check the full service implementation
cat frontend/src/app/services/configuration-state.service.ts

Repository: rocket-admin/rocketadmin

Length of output: 1479


🏁 Script executed:

# Check the full dashboard component to see how isConfiguring is used
cat -n frontend/src/app/components/dashboard/dashboard.component.ts | head -200

# Search for usage of isConfiguring and configurationDone in the template or component
rg -n 'isConfiguring|configurationDone' frontend/src/app/components/dashboard/dashboard.component.ts -A 2

Repository: rocket-admin/rocketadmin

Length of output: 9332


🏁 Script executed:

# Check the dashboard template
cat -n frontend/src/app/components/dashboard/dashboard.component.html | grep -i 'isConfiguring\|configurationDone' -B 2 -A 2

# Also search for any other references to these properties
rg -n 'isConfiguring|configurationDone' frontend/src/app/components/dashboard/ --type=html

Repository: rocket-admin/rocketadmin

Length of output: 1253


🏁 Script executed:

# Check if startConfiguring is called from dashboard
rg -n 'startConfiguring' frontend/src/app/components/dashboard/ -A 3

# Also search for any other mechanism that might update isConfiguring
rg -n 'isConfiguring\s*=' frontend/src/app/components/dashboard/ -A 2

Repository: rocket-admin/rocketadmin

Length of output: 383


🏁 Script executed:

# Search for where startConfiguring might be called
rg -n 'startConfiguring' frontend/src/app/ --type=ts -B 2 -A 2

# Also check if there's any mechanism that watches the configuration state
rg -n 'asObservable\|subscribe.*configuring' frontend/src/app/ --type=ts

Repository: rocket-admin/rocketadmin

Length of output: 1026


🏁 Script executed:

# Check if configurationDone is ever set
rg -n 'configurationDone\s*=' frontend/src/app/ --type=ts

# Check the auto-configure component to understand the full flow
cat -n frontend/src/app/components/auto-configure/auto-configure.component.ts

Repository: rocket-admin/rocketadmin

Length of output: 1283


Dashboard won't react to configuration state changes.

isConfiguring is set once in ngOnInit() as a snapshot. The service's isConfiguring() method returns a synchronous boolean, not an Observable. When configuration completes, the dashboard won't be notified and the UI will remain stale.

Additionally, configurationDone (line 104) is declared but never assigned, making it unused dead code.

The service should expose an Observable (e.g., configuring$) that the dashboard subscribes to, enabling real-time updates when configuration starts or completes.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/app/components/dashboard/dashboard.component.ts` around lines
140 - 142, isConfiguring is only read once in ngOnInit using
_configState.isConfiguring(this.connectionID) (a synchronous boolean) so the
dashboard never updates; also configurationDone is declared but never used.
Update the config state service (_configState) to expose an Observable (e.g.,
configuring$ or getConfiguring(connectionId): Observable<boolean>) that emits
when a connection's configuration status changes, then in
DashboardComponent.ngOnInit subscribe to that Observable (using
this.connectionID) and update the component property (replace the one-time
assignment to isConfiguring); finally remove the unused configurationDone
declaration. Ensure you reference _configState, isConfiguring, and connectionID
when wiring the Observable and subscription.

Comment on lines +17 to +19
const current = this._configuring.value;
current.add(connectionId);
this._configuring.next(current);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Mutating the same Set reference may not trigger subscriber updates.

The code mutates the existing Set and emits the same object reference. BehaviorSubject subscribers using default change detection may not detect this update since the reference hasn't changed.

🛠️ Proposed fix: Create a new Set instance
-		const current = this._configuring.value;
-		current.add(connectionId);
-		this._configuring.next(current);
+		const updated = new Set(this._configuring.value);
+		updated.add(connectionId);
+		this._configuring.next(updated);

Apply the same pattern in the finally block (lines 36-38):

-			const current = this._configuring.value;
-			current.delete(connectionId);
-			this._configuring.next(current);
+			const updated = new Set(this._configuring.value);
+			updated.delete(connectionId);
+			this._configuring.next(updated);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const current = this._configuring.value;
current.add(connectionId);
this._configuring.next(current);
const updated = new Set(this._configuring.value);
updated.add(connectionId);
this._configuring.next(updated);
Suggested change
const current = this._configuring.value;
current.add(connectionId);
this._configuring.next(current);
const updated = new Set(this._configuring.value);
updated.delete(connectionId);
this._configuring.next(updated);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/app/services/configuration-state.service.ts` around lines 17 -
19, The current code mutates the existing Set held in the BehaviorSubject
(this._configuring) which can prevent subscribers from seeing updates; instead
create and emit a new Set instance when adding and when removing: for the add
path replace current.add(connectionId); this._configuring.next(current); with
const next = new Set(current); next.add(connectionId);
this._configuring.next(next); and in the finally/remove path do const next = new
Set(this._configuring.value); next.delete(connectionId);
this._configuring.next(next); so you always emit a new Set reference.

Comment on lines +33 to +34
} catch {
this._notifications.showSuccessSnackbar('Configuration could not be completed.');
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Bug: Error notification uses success snackbar.

The catch block calls showSuccessSnackbar for an error case. This should use showErrorSnackbar to properly indicate failure to the user.

🐛 Proposed fix
 		} catch {
-			this._notifications.showSuccessSnackbar('Configuration could not be completed.');
+			this._notifications.showErrorSnackbar('Configuration could not be completed.');
 		} finally {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
} catch {
this._notifications.showSuccessSnackbar('Configuration could not be completed.');
} catch {
this._notifications.showErrorSnackbar('Configuration could not be completed.');
} finally {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/app/services/configuration-state.service.ts` around lines 33 -
34, In the catch block of the configuration state flow, replace the incorrect
success notification call this._notifications.showSuccessSnackbar('Configuration
could not be completed.') with the error notifier
this._notifications.showErrorSnackbar(...) so failures display an error
snackbar; locate the catch that contains this._notifications.showSuccessSnackbar
and swap to showErrorSnackbar while keeping the existing message (or a clearer
error message) so users see a proper error notification.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@frontend/src/app/components/auto-configure/auto-configure.component.ts`:
- Around line 20-30: ngOnInit currently awaits
_configState.startConfiguring(connectionId) then unconditionally calls
_router.navigate which can run after the component is destroyed and ignores
startConfiguring's boolean result; implement OnDestroy and add a private
destroyed flag (or a Subject used with takeUntil) to guard post-destruction
work, await startConfiguring and check its return value (only navigate on true),
and before calling _router.navigate verify the component is not destroyed (e.g.,
if (!this._destroyed) or until-notification) to prevent redundant/flicker
navigation; update the class to implement OnDestroy and set the flag (or
complete the Subject) in ngOnDestroy.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 65e2006a-1f58-40ae-b003-8942ae519fe0

📥 Commits

Reviewing files that changed from the base of the PR and between 2022059 and 1001747.

📒 Files selected for processing (2)
  • frontend/src/app/components/auto-configure/auto-configure.component.ts
  • frontend/src/app/services/configuration-state.service.ts
✅ Files skipped from review due to trivial changes (1)
  • frontend/src/app/services/configuration-state.service.ts

Comment on lines +20 to 30
async ngOnInit(): Promise<void> {
const connectionId = this._route.snapshot.paramMap.get('connection-id');
if (!connectionId) {
this._router.navigate(['/connections-list']);
return;
}

this.connectionId.set(connectionId);
this._configure(connectionId);
}

private async _configure(connectionId: string): Promise<void> {
const result = await this._api.get<string>(`/ai/v2/setup/${connectionId}`, { responseType: 'text' });

if (result !== null) {
this._router.navigate([`/dashboard/${connectionId}`]);
} else {
this.loading.set(false);
this.errorMessage.set('Auto-configuration could not be completed. You can still configure your tables manually.');
}
await this._configState.startConfiguring(connectionId);
this._router.navigate(['/dashboard', connectionId]);
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Guard against post-destruction navigation and consider checking the return value.

Two concerns with the current flow:

  1. Post-destruction navigation: If the user clicks "Open tables" and navigates to the dashboard before startConfiguring completes, this component is destroyed but the await continues. Line 29 will still execute after the promise resolves, potentially causing a redundant navigation or flicker.

  2. Ignored return value: startConfiguring returns false on failure (per ConfigurationStateService), but the component navigates unconditionally. If failed configurations should be handled differently (e.g., stay on page), this needs adjustment.

🛡️ Proposed fix to prevent post-destruction navigation
 export class AutoConfigureComponent implements OnInit {
 	private _route = inject(ActivatedRoute);
 	private _router = inject(Router);
 	private _configState = inject(ConfigurationStateService);
+	private _destroyed = false;

 	protected connectionId = signal<string | null>(null);

 	async ngOnInit(): Promise<void> {
 		const connectionId = this._route.snapshot.paramMap.get('connection-id');
 		if (!connectionId) {
 			this._router.navigate(['/connections-list']);
 			return;
 		}

 		this.connectionId.set(connectionId);
 		await this._configState.startConfiguring(connectionId);
-		this._router.navigate(['/dashboard', connectionId]);
+		if (!this._destroyed) {
+			this._router.navigate(['/dashboard', connectionId]);
+		}
 	}
+
+	ngOnDestroy(): void {
+		this._destroyed = true;
+	}
 }

Note: You'll need to add OnDestroy to the imports and implements clause.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/app/components/auto-configure/auto-configure.component.ts`
around lines 20 - 30, ngOnInit currently awaits
_configState.startConfiguring(connectionId) then unconditionally calls
_router.navigate which can run after the component is destroyed and ignores
startConfiguring's boolean result; implement OnDestroy and add a private
destroyed flag (or a Subject used with takeUntil) to guard post-destruction
work, await startConfiguring and check its return value (only navigate on true),
and before calling _router.navigate verify the component is not destroyed (e.g.,
if (!this._destroyed) or until-notification) to prevent redundant/flicker
navigation; update the class to implement OnDestroy and set the flag (or
complete the Subject) in ngOnDestroy.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@frontend/src/app/components/dashboard/db-tables-list/db-tables-list.component.css`:
- Around line 703-707: The .table-link_active rule only sets
radius/margins/padding so the active row has no background highlight; update the
CSS for .table-link_active to include an explicit light-blue background-color
(use the project token/var if available) so the entire row shows the expected
highlight while preserving border-radius, margin and padding; also ensure the
text color remains accessible against the new background (adjust color or use
existing .table-link_active text rule if needed).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: dc06d23d-35f7-40d6-bb7e-1db77b2affc5

📥 Commits

Reviewing files that changed from the base of the PR and between 1001747 and 7127e06.

📒 Files selected for processing (3)
  • frontend/src/app/components/dashboard/dashboard.component.css
  • frontend/src/app/components/dashboard/dashboard.component.html
  • frontend/src/app/components/dashboard/db-tables-list/db-tables-list.component.css
✅ Files skipped from review due to trivial changes (1)
  • frontend/src/app/components/dashboard/dashboard.component.css
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/src/app/components/dashboard/dashboard.component.html

Comment on lines +703 to +707
.table-link_active {
border-radius: 4px;
margin: 0 -12px;
padding: 0 12px;
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Active row highlight is incomplete (missing background color).

Line 703–707 applies spacing/radius only, so the active state does not get the expected light-blue row highlight—only text color changes later. Please add an explicit background for .table-link_active.

🎯 Proposed fix
 .table-link_active {
 	border-radius: 4px;
 	margin: 0 -12px;
 	padding: 0 12px;
+	background-color: var(--color-accentedPalette-50);
 }
+
+@media (prefers-color-scheme: dark) {
+	.table-link_active {
+		background-color: rgba(33, 150, 243, 0.18);
+	}
+}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
.table-link_active {
border-radius: 4px;
margin: 0 -12px;
padding: 0 12px;
}
.table-link_active {
border-radius: 4px;
margin: 0 -12px;
padding: 0 12px;
background-color: var(--color-accentedPalette-50);
}
`@media` (prefers-color-scheme: dark) {
.table-link_active {
background-color: rgba(33, 150, 243, 0.18);
}
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@frontend/src/app/components/dashboard/db-tables-list/db-tables-list.component.css`
around lines 703 - 707, The .table-link_active rule only sets
radius/margins/padding so the active row has no background highlight; update the
CSS for .table-link_active to include an explicit light-blue background-color
(use the project token/var if available) so the entire row shows the expected
highlight while preserving border-radius, margin and padding; also ensure the
text color remains accessible against the new background (adjust color or use
existing .table-link_active text rule if needed).

@lyubov-voloshko lyubov-voloshko merged commit b1de66e into rocket-admin:main Mar 26, 2026
7 of 9 checks passed
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.

4 participants