Skip to content

refactor: move widget properties from dashboard to saved query#1554

Merged
Artuomka merged 1 commit into
mainfrom
backend_dashboards_properties-rework
Feb 3, 2026
Merged

refactor: move widget properties from dashboard to saved query#1554
Artuomka merged 1 commit into
mainfrom
backend_dashboards_properties-rework

Conversation

@Artuomka

@Artuomka Artuomka commented Feb 3, 2026

Copy link
Copy Markdown
Collaborator
  • Removed widget_type, chart_type, name, description, and widget_options from the dashboard widget entity and DTOs.
  • Added widget_type, chart_type, and widget_options to the saved_db_query entity and DTOs.
  • Updated use cases for creating and updating dashboard widgets to reflect the new structure.
  • Adjusted tests to accommodate changes in widget creation and updating workflows.
  • Created a migration to alter the database schema accordingly.

- Removed widget_type, chart_type, name, description, and widget_options from the dashboard widget entity and DTOs.
- Added widget_type, chart_type, and widget_options to the saved_db_query entity and DTOs.
- Updated use cases for creating and updating dashboard widgets to reflect the new structure.
- Adjusted tests to accommodate changes in widget creation and updating workflows.
- Created a migration to alter the database schema accordingly.
Copilot AI review requested due to automatic review settings February 3, 2026 11:26
@Artuomka Artuomka enabled auto-merge February 3, 2026 11:27

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR refactors the dashboard widget system by moving visualization properties (widget_type, chart_type, name, description, and widget_options) from the dashboard_widget table to the saved_db_query table. This architectural change means widgets now obtain their display properties through their associated saved query rather than storing them directly.

Changes:

  • Moved widget visualization properties from dashboard widgets to saved queries
  • Created database migration to alter schema accordingly
  • Updated DTOs, entities, use cases, and tests to reflect new architecture

Reviewed changes

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

Show a summary per file
File Description
backend/src/migrations/1770116525022-MovedDashboardWidgetPropertiesToSavedQuery.ts Database migration dropping columns from dashboard_widget and adding them to saved_db_query
backend/src/entities/visualizations/dashboard-widget/dashboard-widget.entity.ts Removed widget_type, chart_type, name, description, and widget_options columns and lifecycle hooks
backend/src/entities/visualizations/saved-db-query/saved-db-query.entity.ts Added widget_type, chart_type, and widget_options columns with JSON serialization hooks
backend/src/entities/visualizations/dashboard-widget/dto/*.dto.ts Removed visualization properties from widget DTOs
backend/src/entities/visualizations/saved-db-query/dto/*.dto.ts Added visualization properties to saved query DTOs
backend/src/entities/visualizations/dashboard-widget/use-cases/*.use.case.ts Removed visualization property handling from widget use cases
backend/src/entities/visualizations/saved-db-query/use-cases/*.use.case.ts Added visualization property handling to saved query use cases
backend/test/ava-tests/saas-tests/dashboard-e2e.test.ts Updated tests to create widgets without properties and attach queries
backend/test/ava-tests/non-saas-tests/non-saas-dashboard-e2e.test.ts Updated tests to match new widget creation workflow
backend/test/ava-tests/saas-tests/saved-database-queries-e2e.test.ts Added widget_type to all saved query test cases

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

Comment on lines +7 to +11
await queryRunner.query(`ALTER TABLE "dashboard_widget" DROP COLUMN "widget_options"`);
await queryRunner.query(`ALTER TABLE "dashboard_widget" DROP COLUMN "widget_type"`);
await queryRunner.query(`ALTER TABLE "dashboard_widget" DROP COLUMN "name"`);
await queryRunner.query(`ALTER TABLE "dashboard_widget" DROP COLUMN "description"`);
await queryRunner.query(`ALTER TABLE "dashboard_widget" DROP COLUMN "chart_type"`);

Copilot AI Feb 3, 2026

Copy link

Choose a reason for hiding this comment

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

This migration will cause data loss for existing dashboard widgets. The migration drops columns from dashboard_widget (lines 7-11) without first migrating the existing data to the saved_db_query table. If there are existing widgets with these properties, their data will be permanently lost.

A proper migration should:

  1. First, copy existing widget data to their associated saved queries
  2. Handle widgets that don't have an associated saved query
  3. Then drop the columns from dashboard_widget

Consider adding data migration logic or documenting that this is a breaking change requiring a fresh database.

Copilot uses AI. Check for mistakes.
await queryRunner.query(`ALTER TABLE "dashboard_widget" DROP COLUMN "name"`);
await queryRunner.query(`ALTER TABLE "dashboard_widget" DROP COLUMN "description"`);
await queryRunner.query(`ALTER TABLE "dashboard_widget" DROP COLUMN "chart_type"`);
await queryRunner.query(`ALTER TABLE "saved_db_query" ADD "widget_type" character varying NOT NULL`);

Copilot AI Feb 3, 2026

Copy link

Choose a reason for hiding this comment

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

The widget_type column is added as NOT NULL without a default value on line 12. If there are existing records in the saved_db_query table, this ALTER TABLE statement will fail because existing rows won't have a value for this required column. Either provide a default value or ensure existing records are updated before making this column NOT NULL.

Suggested change
await queryRunner.query(`ALTER TABLE "saved_db_query" ADD "widget_type" character varying NOT NULL`);
await queryRunner.query(`ALTER TABLE "saved_db_query" ADD "widget_type" character varying`);

Copilot uses AI. Check for mistakes.
Comment on lines +36 to +37
@Column('json', { default: null, nullable: true })
widget_options: string | null;

Copilot AI Feb 3, 2026

Copy link

Choose a reason for hiding this comment

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

The widget_options property is declared as string | null but the lifecycle hooks treat it as an object. After @AfterLoad() on line 78, the property will contain a parsed object, not a string. This type inconsistency can lead to type safety issues throughout the codebase. Consider either:

  1. Declaring the type as Record<string, unknown> | null and handling the serialization differently
  2. Using a transformer to handle the JSON conversion automatically
  3. Creating separate internal/external properties for type safety

Copilot uses AI. Check for mistakes.
newQuery.description = description || null;
newQuery.widget_type = widget_type;
newQuery.chart_type = chart_type || null;
newQuery.widget_options = widget_options ? (widget_options as unknown as string) : null;

Copilot AI Feb 3, 2026

Copy link

Choose a reason for hiding this comment

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

The type casting widget_options as unknown as string is problematic. The incoming widget_options is typed as Record<string, unknown> in the data structure, but it's being cast to string here. The entity's @BeforeInsert() hook will handle the JSON stringification, so casting to string is incorrect and could cause issues. This line should simply assign the value without type casting: newQuery.widget_options = widget_options || null;

Suggested change
newQuery.widget_options = widget_options ? (widget_options as unknown as string) : null;
newQuery.widget_options = widget_options || null;

Copilot uses AI. Check for mistakes.
foundQuery.chart_type = chart_type;
}
if (widget_options !== undefined) {
foundQuery.widget_options = widget_options ? (widget_options as unknown as string) : null;

Copilot AI Feb 3, 2026

Copy link

Choose a reason for hiding this comment

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

The same type casting issue exists here as in the create use case. The type casting widget_options as unknown as string is problematic since the @BeforeUpdate() hook in the entity will handle JSON stringification. This line should simply assign the value: foundQuery.widget_options = widget_options || null;

Suggested change
foundQuery.widget_options = widget_options ? (widget_options as unknown as string) : null;
foundQuery.widget_options = widget_options || null;

Copilot uses AI. Check for mistakes.
Comment on lines 595 to 600
const createWidget = await request(app.getHttpServer())
.post(`/dashboard/${dashboardId}/widget/${connectionId}`)
.send({
widget_type: 'table',
name: 'Query Result Widget',
query_id: queryId,
})
.set('Cookie', token)

Copilot AI Feb 3, 2026

Copy link

Choose a reason for hiding this comment

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

The test creates a widget with a query_id but doesn't verify that the associated query's properties (widget_type, chart_type, widget_options) are accessible. Consider adding a test that fetches the dashboard and verifies the widget can retrieve its visualization properties through the query relation, or fetch the widget with its query data included to ensure the relationship is properly configured.

Copilot uses AI. Check for mistakes.
@Artuomka Artuomka merged commit b1bc842 into main Feb 3, 2026
25 checks passed
@Artuomka Artuomka deleted the backend_dashboards_properties-rework branch February 3, 2026 11:34
@Artuomka Artuomka removed the request for review from Copilot March 23, 2026 22:43
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