Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion migrations_lockfile.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ preprod: 0010_actual_drop_preprod_artifact_analysis_file_id_col

replays: 0006_add_bulk_delete_job

sentry: 0946_add_has_mcp_insights_flag
sentry: 0947_add_dashboard_widget_snapshot_model

social_auth: 0003_social_auth_json_field

Expand Down
53 changes: 53 additions & 0 deletions src/sentry/migrations/0947_add_dashboard_widget_snapshot_model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Generated by Django 5.2.1 on 2025-07-14 14:27

import django.db.models.deletion
from django.db import migrations

import sentry.db.models.fields.bounded
import sentry.db.models.fields.foreignkey
import sentry.db.models.fields.jsonfield
from sentry.new_migrations.migrations import CheckedMigration


class Migration(CheckedMigration):
# This flag is used to mark that a migration shouldn't be automatically run in production.
# This should only be used for operations where it's safe to run the migration after your
# code has deployed. So this should not be used for most operations that alter the schema
# of a table.
# Here are some things that make sense to mark as post deployment:
# - Large data migrations. Typically we want these to be run manually so that they can be
# monitored and not block the deploy for a long period of time while they run.
# - Adding indexes to large tables. Since this can take a long time, we'd generally prefer to
# run this outside deployments so that we don't block them. Note that while adding an index
# is a schema change, it's completely safe to run the operation after the code has deployed.
# Once deployed, run these manually via: https://develop.sentry.dev/database-migrations/#migration-deployment

is_post_deployment = False

dependencies = [
("sentry", "0946_add_has_mcp_insights_flag"),
]

operations = [
migrations.CreateModel(
name="DashboardWidgetSnapshot",
fields=[
(
"id",
sentry.db.models.fields.bounded.BoundedBigAutoField(
primary_key=True, serialize=False
),
),
("data", sentry.db.models.fields.jsonfield.JSONField(default=dict)),
(
"widget",
sentry.db.models.fields.foreignkey.FlexibleForeignKey(
on_delete=django.db.models.deletion.CASCADE, to="sentry.dashboardwidget"
),
),
],
options={
"abstract": False,
},
),
]
8 changes: 8 additions & 0 deletions src/sentry/models/dashboard_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,14 @@ class Meta:
__repr__ = sane_repr("extraction_state", "spec_hashes")


@region_silo_model
class DashboardWidgetSnapshot(Model):
__relocation_scope__ = RelocationScope.Organization

widget = FlexibleForeignKey("sentry.DashboardWidget")
data: models.Field[dict[str, Any], dict[str, Any]] = JSONField()


@region_silo_model
class DashboardWidget(Model):
"""
Expand Down
5 changes: 5 additions & 0 deletions src/sentry/testutils/helpers/backups.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
DashboardWidget,
DashboardWidgetQuery,
DashboardWidgetQueryOnDemand,
DashboardWidgetSnapshot,
DashboardWidgetTypes,
)
from sentry.models.dynamicsampling import CustomDynamicSamplingRule
Expand Down Expand Up @@ -586,6 +587,10 @@ def create_exhaustive_organization(
extraction_state=DashboardWidgetQueryOnDemand.OnDemandExtractionState.DISABLED_NOT_APPLICABLE,
spec_hashes=[],
)
DashboardWidgetSnapshot.objects.create(
widget=widget,
data={"test": "data"},
)
DashboardTombstone.objects.create(organization=org, slug=f"test-tombstone-in-{slug}")

# *Search
Expand Down
Loading