Skip to content

chore: live tail mode for config changes#2980

Open
yashmehrotra wants to merge 1 commit intomainfrom
live-tail
Open

chore: live tail mode for config changes#2980
yashmehrotra wants to merge 1 commit intomainfrom
live-tail

Conversation

@yashmehrotra
Copy link
Copy Markdown
Member

@yashmehrotra yashmehrotra commented Apr 7, 2026

Fixes #2925

Summary by CodeRabbit

Release Notes

  • New Features
    • Live mode toggle added for real-time configuration change monitoring, automatically polling for updates every 5 seconds.
    • Timestamp-based filtering introduced to track configuration changes from specific insertion times.
    • Real-time change data tracking enhanced with automatic deduplication and continuous accumulation of new changes.

@vercel
Copy link
Copy Markdown

vercel bot commented Apr 7, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
aws-preview Ready Ready Preview Apr 7, 2026 6:28am
flanksource-ui Ready Ready Preview Apr 7, 2026 6:28am

Request Review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 7, 2026

Walkthrough

The changes introduce a "Live" tailing mode for configuration changes pages. They add an optional from_inserted_at parameter throughout the query layer (hooks, services, types) and UI components to enable incremental polling and accumulation of new changes since a specified timestamp.

Changes

Cohort / File(s) Summary
Query Hooks
src/api/query-hooks/useConfigChangesHooks.ts
Updated both useGetAllConfigsChangesQuery and useGetConfigChangesByIDQuery to accept optional from_inserted_at parameter and pass it through to underlying service calls.
Services & Types
src/api/services/configs.ts, src/api/types/configs.ts
Extended GetConfigsRelatedChangesParams type with optional from_inserted_at field, updated getConfigsChanges function to conditionally include it in POST payload, and added inserted_at field to ConfigChange interface.
Filter Components
src/components/Configs/Changes/ConfigChangesFilters/ConfigChangesFilters.tsx, src/components/Configs/Changes/ConfigsRelatedChanges/FilterBar/ConfigRelatedChangesFilters.tsx
Both components now accept optional extra prop to render additional UI elements (e.g., Live toggle) within the filter controls container.
Page Components
src/pages/config/ConfigChangesPage.tsx, src/pages/config/details/ConfigDetailsChangesPage.tsx
Implemented Live tailing mode with state management (liveTail, tailCursor, tailedChanges), polling logic using from_inserted_at with 5-second refetch intervals, deduplication of accumulated changes, and UI toggle binding via extra prop on filter components.

Sequence Diagram

sequenceDiagram
    participant User
    participant Page as ConfigChangesPage
    participant Hook as useGetAllConfigsChangesQuery
    participant Service as getConfigsChanges
    participant API as Backend API
    
    User->>Page: Click "Live" Toggle
    activate Page
    Note over Page: Initialize tailCursor from newest inserted_at
    
    Page->>Hook: Call with from_inserted_at: tailCursor
    activate Hook
    Hook->>Service: Forward from_inserted_at parameter
    activate Service
    Service->>API: POST with from_inserted_at in payload
    activate API
    API-->>Service: Return changes since cursor
    deactivate API
    deactivate Service
    Hook-->>Page: Return polled changes
    deactivate Hook
    
    Note over Page: Deduplicate changes by id<br/>Accumulate in tailedChanges<br/>Advance tailCursor to newest timestamp
    
    Page->>Page: Render merged base + tailed changes
    deactivate Page
    
    Note over Page: Wait 5 seconds
    Page->>Page: Repeat polling with updated cursor
Loading

Possibly related issues

  • Issue #2925: Directly addresses the implementation of "Live" or "Tail Mode" functionality for config changes using from_inserted_at timestamp-based polling to fetch incremental updates.

Suggested reviewers

  • moshloop
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'chore: live tail mode for config changes' accurately describes the main feature added across the changeset: a Live mode that enables incremental polling of config changes.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch live-tail
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch live-tail

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@yashmehrotra yashmehrotra requested a review from moshloop April 7, 2026 06:28
Copy link
Copy Markdown
Contributor

@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: 2

🧹 Nitpick comments (1)
src/pages/config/details/ConfigDetailsChangesPage.tsx (1)

11-19: getNewestInsertedAt helper is duplicated across pages.

This helper function is identical in both ConfigChangesPage.tsx and ConfigDetailsChangesPage.tsx. Consider extracting it to a shared utility module to improve maintainability.

Also applies to: 21-29

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

In `@src/pages/config/details/ConfigDetailsChangesPage.tsx` around lines 11 - 19,
The getNewestInsertedAt helper is duplicated; extract it into a shared utility
(e.g., export function getNewestInsertedAt(changes: ConfigChange[]): string |
undefined) and replace the copies in ConfigDetailsChangesPage and
ConfigChangesPage with an import from that new module; ensure the new util
exports the same signature and any required types (ConfigChange) or
import/export the type from its original location so both components compile
without changing behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/pages/config/ConfigChangesPage.tsx`:
- Around line 96-118: The mapping uses non-null assertions on optional fields
(config_id, type, name) in baseChanges and tailedWithConfig; replace those
assertions with defensive handling by either filtering out entries missing
required fields before mapping or constructing the config object only when
change.config_id, change.type, and change.name are present (e.g., return
undefined or skip the item if any are missing), and ensure baseIds/uniqueTailed
logic works with the possibly filtered arrays; update the transformation that
builds config (in baseChanges and tailedWithConfig) to handle undefined values
safely rather than using the ! operator.

In `@src/pages/config/details/ConfigDetailsChangesPage.tsx`:
- Around line 80-96: The mapping for baseChanges and tailedWithConfig is using
non-null assertions on change.config_id, change.type, and change.name which can
throw if the API returns incomplete records; update the mapping logic in
ConfigDetailsChangesPage (functions/vars: baseChanges and tailedWithConfig) to
either filter out changes missing required fields (e.g., drop entries where any
of config_id/type/name is null/undefined) or provide safe fallbacks (e.g., id:
change.config_id ?? 'unknown', type: change.type ?? 'unknown', name: change.name
?? 'Unnamed') before constructing the config object so runtime errors are
avoided.

---

Nitpick comments:
In `@src/pages/config/details/ConfigDetailsChangesPage.tsx`:
- Around line 11-19: The getNewestInsertedAt helper is duplicated; extract it
into a shared utility (e.g., export function getNewestInsertedAt(changes:
ConfigChange[]): string | undefined) and replace the copies in
ConfigDetailsChangesPage and ConfigChangesPage with an import from that new
module; ensure the new util exports the same signature and any required types
(ConfigChange) or import/export the type from its original location so both
components compile without changing behavior.
🪄 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: 8d18ca48-c849-4e94-b69c-3b4868d0fe21

📥 Commits

Reviewing files that changed from the base of the PR and between 8f6de84 and f2dbd90.

📒 Files selected for processing (7)
  • src/api/query-hooks/useConfigChangesHooks.ts
  • src/api/services/configs.ts
  • src/api/types/configs.ts
  • src/components/Configs/Changes/ConfigChangesFilters/ConfigChangesFilters.tsx
  • src/components/Configs/Changes/ConfigsRelatedChanges/FilterBar/ConfigRelatedChangesFilters.tsx
  • src/pages/config/ConfigChangesPage.tsx
  • src/pages/config/details/ConfigDetailsChangesPage.tsx

Comment on lines +96 to +118
const baseChanges = (data?.changes ?? []).map((change) => ({
...change,
config: {
id: change.config_id!,
type: change.type!,
name: change.name!,
deleted_at: change.deleted_at
}
}));

const tailedWithConfig = tailedChanges.map((change) => ({
...change,
config: {
id: changes.config_id!,
type: changes.type!,
name: changes.name!,
deleted_at: changes.deleted_at
id: change.config_id!,
type: change.type!,
name: change.name!,
deleted_at: change.deleted_at
}
}));

const totalChanges = data?.total ?? 0;
const baseIds = new Set(baseChanges.map((c) => c.id));
const uniqueTailed = tailedWithConfig.filter((c) => !baseIds.has(c.id));
const changes = [...uniqueTailed, ...baseChanges];
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.

⚠️ Potential issue | 🟡 Minor

Same non-null assertion concern as ConfigDetailsChangesPage.tsx.

The mapping logic uses non-null assertions on optional fields (config_id, type, name). Apply the same defensive handling as suggested for the other page.

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

In `@src/pages/config/ConfigChangesPage.tsx` around lines 96 - 118, The mapping
uses non-null assertions on optional fields (config_id, type, name) in
baseChanges and tailedWithConfig; replace those assertions with defensive
handling by either filtering out entries missing required fields before mapping
or constructing the config object only when change.config_id, change.type, and
change.name are present (e.g., return undefined or skip the item if any are
missing), and ensure baseIds/uniqueTailed logic works with the possibly filtered
arrays; update the transformation that builds config (in baseChanges and
tailedWithConfig) to handle undefined values safely rather than using the !
operator.

Comment on lines +80 to +96
const baseChanges = (data?.changes ?? []).map((change) => ({
...change,
config: {
id: changes.config_id!,
type: changes.type!,
name: changes.name!
id: change.config_id!,
type: change.type!,
name: change.name!
}
}));

const totalChanges = data?.total ?? 0;
const tailedWithConfig = tailedChanges.map((change) => ({
...change,
config: {
id: change.config_id!,
type: change.type!,
name: change.name!
}
}));
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.

⚠️ Potential issue | 🟡 Minor

Non-null assertions may cause runtime errors if API returns incomplete data.

The code uses non-null assertions (!) on config_id, type, and name properties which are typed as optional in ConfigChange. If the API returns changes without these fields, this will result in undefined values being assigned.

Consider adding fallback values or filtering out incomplete records:

Proposed defensive handling
  const baseChanges = (data?.changes ?? []).map((change) => ({
    ...change,
    config: {
-     id: change.config_id!,
-     type: change.type!,
-     name: change.name!
+     id: change.config_id ?? "",
+     type: change.type ?? "",
+     name: change.name ?? ""
    }
  }));

  const tailedWithConfig = tailedChanges.map((change) => ({
    ...change,
    config: {
-     id: change.config_id!,
-     type: change.type!,
-     name: change.name!
+     id: change.config_id ?? "",
+     type: change.type ?? "",
+     name: change.name ?? ""
    }
  }));
📝 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 baseChanges = (data?.changes ?? []).map((change) => ({
...change,
config: {
id: changes.config_id!,
type: changes.type!,
name: changes.name!
id: change.config_id!,
type: change.type!,
name: change.name!
}
}));
const totalChanges = data?.total ?? 0;
const tailedWithConfig = tailedChanges.map((change) => ({
...change,
config: {
id: change.config_id!,
type: change.type!,
name: change.name!
}
}));
const baseChanges = (data?.changes ?? []).map((change) => ({
...change,
config: {
id: change.config_id ?? "",
type: change.type ?? "",
name: change.name ?? ""
}
}));
const tailedWithConfig = tailedChanges.map((change) => ({
...change,
config: {
id: change.config_id ?? "",
type: change.type ?? "",
name: change.name ?? ""
}
}));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/config/details/ConfigDetailsChangesPage.tsx` around lines 80 - 96,
The mapping for baseChanges and tailedWithConfig is using non-null assertions on
change.config_id, change.type, and change.name which can throw if the API
returns incomplete records; update the mapping logic in ConfigDetailsChangesPage
(functions/vars: baseChanges and tailedWithConfig) to either filter out changes
missing required fields (e.g., drop entries where any of config_id/type/name is
null/undefined) or provide safe fallbacks (e.g., id: change.config_id ??
'unknown', type: change.type ?? 'unknown', name: change.name ?? 'Unnamed')
before constructing the config object so runtime errors are avoided.

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.

Config Changes - Live/"Tail Mode" Mode

1 participant