Skip to content

feat: add multi-tab support to dashboards#1283

Open
NaveenCode wants to merge 11 commits intomainfrom
feature/dashboard_tabs
Open

feat: add multi-tab support to dashboards#1283
NaveenCode wants to merge 11 commits intomainfrom
feature/dashboard_tabs

Conversation

@NaveenCode
Copy link
Copy Markdown
Contributor

@NaveenCode NaveenCode commented Mar 27, 2026

Summary

Added tabs JSONField to the Dashboard model to store per-tab layout and components
Created DashboardTabSchema Pydantic schema to validate tab structure (id, title, layout_config, components)
Updated DashboardUpdate schema to accept an optional tabs list for saving tab state
Updated DashboardResponse schema to return tabs in API responses
DashboardService.create_dashboard() now initializes every new dashboard with a default tab ("Untitled Tab 1") with empty layout and components
DashboardService.update_dashboard() handles saving tabs by converting Pydantic models to dicts before JSON storage
Updated dashboard copy (duplicate) logic in native API to deep-copy tabs and remap filter IDs in both layout_config and components of each tab so copied dashboards have correct references

** Tasks Completed **

Create a new dashboard — verify it is saved with a single default tab in the DB (tabs field)
Update a dashboard with multiple tabs — verify all tab data (title, layout, components) is persisted correctly
Copy/duplicate a dashboard with tabs and filters — verify filter IDs in tab layout and components are remapped to the new filter IDs
Fetch a dashboard via GET — verify tabs array is returned in the response
Existing dashboards without tabs field load correctly (empty tabs: [] returned)
Verify no regression on existing layout/components/filter endpoints

Summary by CodeRabbit

  • New Features

    • Dashboards now support multiple tabs; each tab stores its own layout and components and is returned in API responses.
    • Dashboard creation and updates handle tabs (new dashboards get a default tab).
    • Dashboard duplication preserves and remaps per-tab state and filter associations.
  • Chores

    • Migration and a management command (with a --dry-run option) to migrate existing dashboards to the tabs format.
  • Tests

    • Added tests covering tab creation, updates, duplication, and filter remapping.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 27, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds persisted per-dashboard tabs via a new JSONField, updated schemas and service handling, a migration command to convert existing dashboards to tabs, and enhances dashboard duplication to deep-copy tabs and remap per-tab layout and filter component references.

Changes

Cohort / File(s) Summary
Data Model & Migration
ddpui/migrations/0153_add_dashboard_tabs.py, ddpui/models/dashboard.py
Add tabs JSONField (default: empty list) to Dashboard and include tabs in Dashboard.to_json; migration adds the field with help text.
Schema Definitions
ddpui/schemas/dashboard_schema.py
Add DashboardTabSchema (id, title, layout_config, components); extend DashboardUpdate and DashboardResponse to accept/return tabs.
Service Layer
ddpui/services/dashboard_service.py
On create, generate a timestamp-based default tab and persist tabs; on update, accept and persist provided tabs.
Management Command
ddpui/management/commands/migrate_dashboards_to_tabs.py
New migrate_dashboards_to_tabs command with --dry-run to convert existing dashboards into a single default tab, skipping already-migrated or empty dashboards and clearing top-level layout/components.
Dashboard Duplication Logic
ddpui/api/dashboard_native_api.py
Enhance duplication to deep-copy tabs; rebuild each tab’s layout_config and components while remapping filter-{old}filter-{new} keys and updating components[...].config.filterId accordingly.
Tests
ddpui/tests/api_tests/test_dashboard_native_api.py, ddpui/tests/services/test_dashboard_service.py
Add tests for duplication with tabs and filter remapping; add tests for create/update behavior around default and provided tabs.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant API as Dashboard API
    participant Service as Duplication Service
    participant DB as Database

    Client->>API: POST /dashboards/{id}/duplicate
    API->>Service: validate request, load original dashboard
    Service->>DB: fetch dashboard (includes tabs, layout_config, components)
    DB-->>Service: return dashboard data
    Service->>Service: deep-copy top-level layout/components and build filter_id mapping
    Service->>Service: for each tab: deep-copy layout_config, rewrite "i" filter-* ids, rename component keys, update component.config.filterId
    Service->>DB: save new dashboard with remapped tabs and components
    DB-->>Service: saved dashboard
    Service->>API: return duplicated dashboard
    API-->>Client: 201 Created with new dashboard payload
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

  • Dalgo v2 beta release #1090: Modifies the same dashboard duplication logic in ddpui/api/dashboard_native_api.py to support filter-id remapping; likely directly related to these tab-aware duplication changes.

Suggested reviewers

  • Ishankoradia
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: add multi-tab support to dashboards' clearly and concisely summarizes the main change—adding multi-tab functionality to the dashboard system.
Docstring Coverage ✅ Passed Docstring coverage is 86.67% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/dashboard_tabs

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.

Copy link
Copy Markdown

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

🧹 Nitpick comments (2)
ddpui/schemas/dashboard_schema.py (1)

25-36: Tab schema is well-defined.

The schema correctly captures all required tab fields. The comment mentions "max 50 chars" for title but no validation enforces it. Consider adding Field(max_length=50) if this constraint should be enforced at the API level.

The RUF012 warnings about mutable defaults are false positives—Pydantic safely handles mutable defaults by creating new instances per model.

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

In `@ddpui/schemas/dashboard_schema.py` around lines 25 - 36, DashboardTabSchema
currently documents a 50-char limit for the title but does not enforce it;
update the title field in DashboardTabSchema to use pydantic Field with
max_length=50 (e.g., replace the plain annotation for title with a
Field(max_length=50)) so the API-level validation enforces the constraint, and
leave layout_config and components as-is since Pydantic handles mutable defaults
per-instance.
ddpui/api/dashboard_native_api.py (1)

245-282: Tab duplication logic looks correct.

The filter ID remapping within tabs correctly mirrors the dashboard-level remapping. The or [] guard at line 247 properly handles pre-existing dashboards with NULL tabs.

Minor optimization: the copy.deepcopy(component_data) at line 260 is redundant since the entire tabs list was already deep-copied at line 247.

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

In `@ddpui/api/dashboard_native_api.py` around lines 245 - 282, Remove the
redundant deep copy of component data inside the tab loop: instead of
new_component_data = copy.deepcopy(component_data) (in the loop that iterates
over component_id/component_data), assign the already deep-copied component data
directly (e.g., new_component_data = component_data) because
original_dashboard.tabs was deep-copied earlier; update the assignment where you
modify new_component_data["config"]["filterId"] accordingly so you don't perform
an unnecessary deepcopy.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@ddpui/models/dashboard.py`:
- Around line 73-77: The file fails black formatting; run the formatter and
commit the changes: run `black ddpui/models/dashboard.py` (or `pre-commit run
--all-files`) to reformat the `tabs = models.JSONField(...)` declaration and
surrounding code so the `JSONField` default and help_text conform to black
style, then stage and commit the reformatted file.
- Line 143: The to_json() output can include "tabs": None for pre-existing
dashboards which breaks Pydantic validation (DashboardResponse expects
List[DashboardTabSchema]); update the to_json() method (reference: to_json and
self.tabs) to coerce None to an empty list (e.g., use self.tabs or [] before
returning) so the returned dict always contains a list for "tabs" and satisfies
DashboardResponse/DashboardTabSchema validation.

In `@ddpui/schemas/dashboard_schema.py`:
- Line 80: The tabs field on DashboardSchema can still end up as an explicit
None if Dashboard.to_json() returns {"tabs": None}; update the Dashboard.to_json
method (symbol: Dashboard.to_json) to return self.tabs or [] so it never emits
None for tabs, and also consider setting the schema field tabs (symbol:
DashboardTabSchema / tabs on DashboardSchema) to use a default factory (empty
list) to guard against explicit nulls.

---

Nitpick comments:
In `@ddpui/api/dashboard_native_api.py`:
- Around line 245-282: Remove the redundant deep copy of component data inside
the tab loop: instead of new_component_data = copy.deepcopy(component_data) (in
the loop that iterates over component_id/component_data), assign the already
deep-copied component data directly (e.g., new_component_data = component_data)
because original_dashboard.tabs was deep-copied earlier; update the assignment
where you modify new_component_data["config"]["filterId"] accordingly so you
don't perform an unnecessary deepcopy.

In `@ddpui/schemas/dashboard_schema.py`:
- Around line 25-36: DashboardTabSchema currently documents a 50-char limit for
the title but does not enforce it; update the title field in DashboardTabSchema
to use pydantic Field with max_length=50 (e.g., replace the plain annotation for
title with a Field(max_length=50)) so the API-level validation enforces the
constraint, and leave layout_config and components as-is since Pydantic handles
mutable defaults per-instance.
🪄 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: 3d2b617a-4b67-40bb-85b1-67bd0818579b

📥 Commits

Reviewing files that changed from the base of the PR and between 7a283d2 and d7dd1cd.

📒 Files selected for processing (5)
  • ddpui/api/dashboard_native_api.py
  • ddpui/migrations/0153_add_dashboard_tabs.py
  • ddpui/models/dashboard.py
  • ddpui/schemas/dashboard_schema.py
  • ddpui/services/dashboard_service.py

Comment thread ddpui/models/dashboard.py
Comment thread ddpui/models/dashboard.py Outdated
Comment thread ddpui/schemas/dashboard_schema.py
Copy link
Copy Markdown

@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

🧹 Nitpick comments (3)
ddpui/management/commands/migrate_dashboards_to_tabs.py (3)

58-71: Consider using UUID for tab IDs and wrapping in a transaction.

Two concerns with this migration block:

  1. Tab ID collision: int(time.time() * 1000) could produce duplicate IDs if multiple dashboards are processed within the same millisecond. A UUID would be safer and consistent with common practices.

  2. Transaction safety: If an error occurs mid-iteration, some dashboards will be migrated while others won't. Wrapping in transaction.atomic() provides rollback capability on failure.

Proposed fix

Add import at top:

import uuid
from django.db import transaction

Then wrap the migration logic:

+        with transaction.atomic():
             for dashboard in all_dashboards:
                 # Skip if already has tabs
                 if dashboard.tabs and len(dashboard.tabs) > 0:
                     skipped_count += 1
                     continue
 
                 # ... (skip logic) ...
 
                 if dry_run:
                     # ... (dry run output) ...
                 else:
                     # Create default tab with existing data
                     default_tab = {
-                        "id": f"tab-{int(time.time() * 1000)}",
+                        "id": f"tab-{uuid.uuid4().hex[:12]}",
                         "title": "Untitled Tab 1",
                         "layout_config": dashboard.layout_config or [],
                         "components": dashboard.components or {},
                     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ddpui/management/commands/migrate_dashboards_to_tabs.py` around lines 58 -
71, Replace the millisecond timestamp ID and unguarded save with a UUID and an
atomic transaction: import uuid and from django.db import transaction, generate
the tab id with uuid.uuid4() when building default_tab (the dict assigned to
default_tab and later assigned to dashboard.tabs), and wrap the
creation/update/save sequence (the block that sets dashboard.tabs,
dashboard.layout_config, dashboard.components and calls dashboard.save()) inside
a transaction.atomic() context so the migration for each dashboard is rolled
back on error.

27-27: Use .iterator() for memory efficiency with large datasets.

Dashboard.objects.all() loads all records into memory. For a one-time migration with potentially many dashboards, using .iterator() avoids loading the entire queryset at once.

Proposed fix
-        all_dashboards = Dashboard.objects.all()
+        all_dashboards = Dashboard.objects.all().iterator()
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ddpui/management/commands/migrate_dashboards_to_tabs.py` at line 27, Replace
the eager queryset in the migration command so it doesn't load all Dashboard
rows into memory: change the use of Dashboard.objects.all() assigned to
all_dashboards to use Dashboard.objects.all().iterator() (or simply
Dashboard.objects.iterator()) in the migration logic
(migrate_dashboards_to_tabs.py where all_dashboards is used) so the iteration
over dashboards is streamed and memory-efficient.

68-71: Consider preserving original data until migration is verified.

Clearing layout_config and components immediately makes this migration irreversible. If an issue is discovered post-migration, the original data is lost.

Consider either:

  1. Adding a --preserve-original flag that keeps the root-level data for verification purposes.
  2. Documenting that a database backup should be taken before running this migration.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ddpui/management/commands/migrate_dashboards_to_tabs.py` around lines 68 -
71, The migration currently overwrites dashboard.layout_config and
dashboard.components irreversibly; add a CLI option --preserve-original to the
management Command (add_arguments) so when set the code copies the existing
values into backup attributes (for example store
dashboard.original_layout_config and dashboard.original_components or a JSON
blob like dashboard._backup_data) before assigning dashboard.tabs =
[default_tab] and clearing layout_config/components, and only clear them when
the flag is false; also update the Command help text to document the new flag
and ensure dashboard.save() persists the backup fields so originals can be
verified and restored if needed.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@ddpui/management/commands/migrate_dashboards_to_tabs.py`:
- Around line 1-4: The file fails the Black pre-commit check; run the Black
formatter on ddpui/management/commands/migrate_dashboards_to_tabs.py (e.g.,
`black ddpui/management/commands/migrate_dashboards_to_tabs.py`) to reformat
imports and spacing around the module-level code so the file passes CI, then
re-run tests/commit; ensure the module-level imports (time, BaseCommand,
Dashboard) and any surrounding whitespace adhere to Black's rules and no other
code changes in functions/classes (e.g., class Command) are introduced.

---

Nitpick comments:
In `@ddpui/management/commands/migrate_dashboards_to_tabs.py`:
- Around line 58-71: Replace the millisecond timestamp ID and unguarded save
with a UUID and an atomic transaction: import uuid and from django.db import
transaction, generate the tab id with uuid.uuid4() when building default_tab
(the dict assigned to default_tab and later assigned to dashboard.tabs), and
wrap the creation/update/save sequence (the block that sets dashboard.tabs,
dashboard.layout_config, dashboard.components and calls dashboard.save()) inside
a transaction.atomic() context so the migration for each dashboard is rolled
back on error.
- Line 27: Replace the eager queryset in the migration command so it doesn't
load all Dashboard rows into memory: change the use of Dashboard.objects.all()
assigned to all_dashboards to use Dashboard.objects.all().iterator() (or simply
Dashboard.objects.iterator()) in the migration logic
(migrate_dashboards_to_tabs.py where all_dashboards is used) so the iteration
over dashboards is streamed and memory-efficient.
- Around line 68-71: The migration currently overwrites dashboard.layout_config
and dashboard.components irreversibly; add a CLI option --preserve-original to
the management Command (add_arguments) so when set the code copies the existing
values into backup attributes (for example store
dashboard.original_layout_config and dashboard.original_components or a JSON
blob like dashboard._backup_data) before assigning dashboard.tabs =
[default_tab] and clearing layout_config/components, and only clear them when
the flag is false; also update the Command help text to document the new flag
and ensure dashboard.save() persists the backup fields so originals can be
verified and restored 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: d4d8896b-bacb-432f-86c7-904d25b8cead

📥 Commits

Reviewing files that changed from the base of the PR and between d7dd1cd and 6b5f3c1.

📒 Files selected for processing (1)
  • ddpui/management/commands/migrate_dashboards_to_tabs.py

Comment thread ddpui/management/commands/migrate_dashboards_to_tabs.py
Copy link
Copy Markdown

@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

🧹 Nitpick comments (1)
ddpui/schemas/dashboard_schema.py (1)

34-35: Replace mutable defaults in DashboardTabSchema with default_factory.

Lines 34-35 use []/{} as class-level defaults. Use Field(default_factory=...) to avoid mutable-default pitfalls and satisfy RUF012.

Suggested fix
 from typing import Optional, List
+from pydantic import Field
@@
-    layout_config: List[dict] = []  # Grid positions for this tab
-    components: dict = {}  # Component configs for this tab
+    layout_config: List[dict] = Field(default_factory=list)  # Grid positions for this tab
+    components: dict = Field(default_factory=dict)  # Component configs for this tab
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ddpui/schemas/dashboard_schema.py` around lines 34 - 35, DashboardTabSchema
uses class-level mutable defaults for layout_config and components; update those
attributes to use pydantic Field with default_factory to avoid mutable-default
pitfalls: replace layout_config: List[dict] = [] with layout_config: List[dict]
= Field(default_factory=list) and replace components: dict = {} with components:
dict = Field(default_factory=dict); ensure Field is imported from pydantic and
keep the existing type annotations (List, dict) or adjust to Dict/Mapping if
desired.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@ddpui/management/commands/migrate_dashboards_to_tabs.py`:
- Around line 28-33: The code currently materializes Dashboard.objects.all()
into all_dashboards which can blow memory; change the loop to stream dashboards
in manageable chunks by replacing Dashboard.objects.all() with a streaming
queryset (e.g.,
Dashboard.objects.only('<fields_needed>').iterator(chunk_size=1000) or use
values_list/values with batch sizes) and iterate that instead in the for
dashboard in ... loop; preserve migrated_count and skipped_count logic but
ensure you only fetch the fields required for the migration (use only() or
values_list on the Dashboard model) to minimize memory use.

---

Nitpick comments:
In `@ddpui/schemas/dashboard_schema.py`:
- Around line 34-35: DashboardTabSchema uses class-level mutable defaults for
layout_config and components; update those attributes to use pydantic Field with
default_factory to avoid mutable-default pitfalls: replace layout_config:
List[dict] = [] with layout_config: List[dict] = Field(default_factory=list) and
replace components: dict = {} with components: dict =
Field(default_factory=dict); ensure Field is imported from pydantic and keep the
existing type annotations (List, dict) or adjust to Dict/Mapping if desired.
🪄 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: 81b014ee-0ef5-4b56-9df1-201fc15427e5

📥 Commits

Reviewing files that changed from the base of the PR and between e085886 and 1df7062.

📒 Files selected for processing (3)
  • ddpui/management/commands/migrate_dashboards_to_tabs.py
  • ddpui/models/dashboard.py
  • ddpui/schemas/dashboard_schema.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • ddpui/models/dashboard.py

Comment thread ddpui/management/commands/migrate_dashboards_to_tabs.py Outdated
Copy link
Copy Markdown

@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)
ddpui/tests/api_tests/test_dashboard_native_api.py (1)

670-670: Use iterator access over list materialization for first key retrieval.

Line 670 unnecessarily materializes all dictionary keys into a list only to access the first element. This is inefficient and non-idiomatic.

♻️ Suggested refactor
-        new_filter_key = list(new_tab.components.keys())[0]
+        new_filter_key = next(iter(new_tab.components))
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ddpui/tests/api_tests/test_dashboard_native_api.py` at line 670, The test
currently materializes all keys via list(new_tab.components.keys()) to get the
first key; replace that with iterator access to avoid building a list by using
next(iter(new_tab.components)) (or next(iter(new_tab.components.keys()))) and
assign to new_filter_key so the first key is retrieved idiomatically and
efficiently; update the reference in test_dashboard_native_api where
new_filter_key is set.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@ddpui/tests/api_tests/test_dashboard_native_api.py`:
- Line 680: Run the project's formatter and pre-commit hooks (e.g., black and
pre-commit) on ddpui/tests/api_tests/test_dashboard_native_api.py and commit the
resulting changes so CI's Black hook passes; specifically ensure the assertion
line referencing
new_tab.components[f"filter-{new_filter_id}"]["config"]["filterId"] is formatted
according to Black's rules and that you staged and committed the reformatted
file before pushing.

In `@ddpui/tests/services/test_dashboard_service.py`:
- Line 39: Run the project formatter (Black) or pre-commit hooks locally and
commit the resulting changes to stop CI from reformatting this file;
specifically reformat the import line that currently reads "from
ddpui.schemas.dashboard_schema import DashboardCreate, DashboardUpdate,
DashboardTabSchema" in ddpui/tests/services/test_dashboard_service.py (and any
other affected lines noted at 513) so the file matches Black's style, then add
and commit those formatting changes.

---

Nitpick comments:
In `@ddpui/tests/api_tests/test_dashboard_native_api.py`:
- Line 670: The test currently materializes all keys via
list(new_tab.components.keys()) to get the first key; replace that with iterator
access to avoid building a list by using next(iter(new_tab.components)) (or
next(iter(new_tab.components.keys()))) and assign to new_filter_key so the first
key is retrieved idiomatically and efficiently; update the reference in
test_dashboard_native_api where new_filter_key is set.
🪄 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: 8bd42dc4-c027-47e7-85be-d900f54538bc

📥 Commits

Reviewing files that changed from the base of the PR and between 1df7062 and 7df5ba8.

📒 Files selected for processing (2)
  • ddpui/tests/api_tests/test_dashboard_native_api.py
  • ddpui/tests/services/test_dashboard_service.py

Comment thread ddpui/tests/api_tests/test_dashboard_native_api.py
Comment thread ddpui/tests/services/test_dashboard_service.py
updated_components[new_component_id] = new_component_data

# Update the dashboard with the corrected layout_config and components
# Copy tabs and update filter IDs inside each tab
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.

I dont understand this. once migration is done isn't this will be just dead code?

The migration command clears root-level layout_config/components and moves everything into tabs, but the frontend save still sends both . Can we make
tabs the single source of truth and stop using root-level fields for tabbed dashboards

"""
# Generate default tab for new dashboard
default_tab = {
"id": f"tab-{int(time.time() * 1000)}",
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.

do we really need this? dashboard id will be different right?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, the Dashboard id is different from the tab id.
Dashboard id identifies the dashboard, and Tab id identifies
which tab within that dashboard. A dashboard can have multiple tabs, so we need
a way to reference each one.

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.

2 participants