def get_attrs(self, item_list, user): item_dict = {i.id: i for i in item_list} prefetch_related_objects(item_list, "created_by") widgets = (DashboardWidget.objects.filter( dashboard_id__in=item_dict.keys()).order_by("order").values( "dashboard_id", "order", "display_type", "detail", "id")) result = defaultdict(lambda: { "widget_display": [], "widget_preview": [], "created_by": {} }) for widget in widgets: dashboard = item_dict[widget["dashboard_id"]] display_type = DashboardWidgetDisplayTypes.get_type_name( widget["display_type"]) result[dashboard]["widget_display"].append(display_type) for widget in widgets: dashboard = item_dict[widget["dashboard_id"]] widget_preview = { "displayType": DashboardWidgetDisplayTypes.get_type_name( widget["display_type"]), "layout": None, } if widget.get("detail"): detail = json.loads(widget["detail"]) if detail.get("layout"): widget_preview["layout"] = detail["layout"] result[dashboard]["widget_preview"].append(widget_preview) user_serializer = UserSerializer() serialized_users = { user["id"]: user for user in serialize( [ dashboard.created_by for dashboard in item_list if dashboard.created_by ], user=user, serializer=user_serializer, ) } for dashboard in item_dict.values(): result[dashboard]["created_by"] = serialized_users.get( str(dashboard.created_by_id)) return result
class DashboardWidgetSerializer(CamelSnakeSerializer): # Is a string because output serializers also make it a string. id = serializers.CharField(required=False) title = serializers.CharField(required=False, max_length=255) display_type = serializers.ChoiceField( choices=DashboardWidgetDisplayTypes.as_text_choices(), required=False) interval = serializers.CharField(required=False, max_length=10) queries = DashboardWidgetQuerySerializer(many=True, required=False) def validate_display_type(self, display_type): return DashboardWidgetDisplayTypes.get_id_for_type_name(display_type) validate_id = validate_id def validate_interval(self, interval): if parse_stats_period(interval) is None: raise serializers.ValidationError("Invalid interval") return interval def validate(self, data): if not data.get("id"): if not data.get("queries"): raise serializers.ValidationError({ "queries": "One or more queries are required to create a widget" }) if not data.get("title"): raise serializers.ValidationError( {"title": "Title is required during creation."}) if data.get("display_type") is None: raise serializers.ValidationError({ "displayType": "displayType is required during creation." }) return data
def serialize(self, obj, attrs, user, **kwargs): return { "id": str(obj.id), "title": obj.title, "displayType": DashboardWidgetDisplayTypes.get_type_name(obj.display_type), # Default value until a backfill can be done. "interval": str(obj.interval or "5m"), "dateCreated": obj.date_added, "dashboardId": str(obj.dashboard_id), "queries": attrs["queries"], "limit": obj.limit, # Default to discover type if null "widgetType": DashboardWidgetTypes.get_type_name(obj.widget_type) or DashboardWidgetTypes.TYPE_NAMES[0], "layout": obj.detail.get("layout") if obj.detail else None, }
def test_widget_preview_field_contains_display_type_and_layout(self): expected_layout = {"x": 1, "y": 0, "w": 1, "h": 1, "minH": 2} DashboardWidget.objects.create( dashboard=self.dashboard, order=0, title="Widget 1", display_type=DashboardWidgetDisplayTypes.LINE_CHART, widget_type=DashboardWidgetTypes.DISCOVER, interval="1d", detail={"layout": expected_layout}, ) response = self.do_request("get", self.url, data={"query": "1"}) assert response.status_code == 200, response.content assert len(response.data) == 1 dashboard_data = response.data[0] assert "widgetPreview" in dashboard_data assert len(dashboard_data["widgetPreview"]) == 1 widget_data = dashboard_data["widgetPreview"][0] assert widget_data[ "displayType"] == DashboardWidgetDisplayTypes.get_type_name( DashboardWidgetDisplayTypes.LINE_CHART) assert widget_data["layout"] == expected_layout
class DashboardWidgetSerializer(CamelSnakeSerializer): # Is a string because output serializers also make it a string. id = serializers.CharField(required=False) title = serializers.CharField(required=False, max_length=255) display_type = serializers.ChoiceField( choices=DashboardWidgetDisplayTypes.as_text_choices(), required=False) interval = serializers.CharField(required=False, max_length=10) queries = DashboardWidgetQuerySerializer(many=True, required=False) widget_type = serializers.ChoiceField( choices=DashboardWidgetTypes.as_text_choices(), required=False) def validate_display_type(self, display_type): return DashboardWidgetDisplayTypes.get_id_for_type_name(display_type) def validate_widget_type(self, widget_type): return DashboardWidgetTypes.get_id_for_type_name(widget_type) validate_id = validate_id def validate_interval(self, interval): if parse_stats_period(interval) is None: raise serializers.ValidationError("Invalid interval") return interval def validate(self, data): query_errors = [] has_query_error = False if data.get("queries"): # Check each query to see if they have an issue or discover error depending on the type of the widget for query in data.get("queries"): if (data.get("widget_type") == DashboardWidgetTypes.ISSUE and "issue_query_error" in query): query_errors.append(query["issue_query_error"]) has_query_error = True elif ("widget_type" not in data or data.get("widget_type") == DashboardWidgetTypes.DISCOVER ) and "discover_query_error" in query: query_errors.append(query["discover_query_error"]) has_query_error = True else: query_errors.append({}) if has_query_error: raise serializers.ValidationError({"queries": query_errors}) if not data.get("id"): if not data.get("queries"): raise serializers.ValidationError({ "queries": "One or more queries are required to create a widget" }) if not data.get("title"): raise serializers.ValidationError( {"title": "Title is required during creation."}) if data.get("display_type") is None: raise serializers.ValidationError({ "displayType": "displayType is required during creation." }) return data
def assert_serialized_widget(self, data, expected_widget): if "id" in data: assert data["id"] == six.text_type(expected_widget.id) if "title" in data: assert data["title"] == expected_widget.title if "displayType" in data: assert data[ "displayType"] == DashboardWidgetDisplayTypes.get_type_name( expected_widget.display_type)
def serialize(self, obj, attrs, user, **kwargs): return { "id": six.text_type(obj.id), "title": obj.title, "displayType": DashboardWidgetDisplayTypes.get_type_name(obj.display_type), "dateCreated": obj.date_added, "dashboardId": six.text_type(obj.dashboard_id), "queries": attrs["queries"], }
def serialize(self, obj, attrs, user, **kwargs): return { "id": six.text_type(obj.id), "title": obj.title, "displayType": DashboardWidgetDisplayTypes.get_type_name(obj.display_type), # Default value until a backfill can be done. "interval": six.text_type(obj.interval or "5m"), "dateCreated": obj.date_added, "dashboardId": six.text_type(obj.dashboard_id), "queries": attrs["queries"], }
def assert_equal_dashboards(self, dashboard, data): assert data["id"] == str(dashboard.id) assert data["title"] == dashboard.title assert data["createdBy"]["id"] == str(dashboard.created_by.id) widgets = self.get_widgets(dashboard.id) widget_displays = [] for widget in widgets: widget_displays.append(DashboardWidgetDisplayTypes.get_type_name(widget.display_type)) assert data["widgetDisplay"] == widget_displays assert "widgets" not in data
def get_attrs(self, item_list, user): item_dict = {i.id: i for i in item_list} widgets = list( DashboardWidget.objects.filter(dashboard_id__in=item_dict.keys()). order_by("order").values_list("dashboard_id", "order", "display_type")) result = defaultdict(lambda: {"widget_display": []}) for dashboard_id, _, display_type in widgets: dashboard = item_dict[dashboard_id] display_type = DashboardWidgetDisplayTypes.get_type_name( display_type) result[dashboard]["widget_display"].append(display_type) return result
class DashboardWidgetSerializer(CamelSnakeSerializer): # Is a string because output serializers also make it a string. id = serializers.CharField(required=False) title = serializers.CharField(required=False) display_type = serializers.ChoiceField( choices=DashboardWidgetDisplayTypes.as_text_choices(), required=False) queries = DashboardWidgetQuerySerializer(many=True, required=False) def validate_display_type(self, display_type): return DashboardWidgetDisplayTypes.get_id_for_type_name(display_type) validate_id = validate_id def validate(self, data): if not data.get("id") and not data.get("queries"): raise serializers.ValidationError( "One or more queries are required to create a widget") return data
def test_widget_preview_still_provides_display_type_if_no_layout(self): DashboardWidget.objects.create( dashboard=self.dashboard, order=0, title="Widget 1", display_type=DashboardWidgetDisplayTypes.LINE_CHART, widget_type=DashboardWidgetTypes.DISCOVER, interval="1d", ) response = self.do_request("get", self.url, data={"query": "1"}) assert response.status_code == 200, response.content assert len(response.data) == 1 dashboard_data = response.data[0] assert "widgetPreview" in dashboard_data assert len(dashboard_data["widgetPreview"]) == 1 widget_data = dashboard_data["widgetPreview"][0] assert widget_data[ "displayType"] == DashboardWidgetDisplayTypes.get_type_name( DashboardWidgetDisplayTypes.LINE_CHART) assert widget_data["layout"] is None
def validate_display_type(self, display_type): return DashboardWidgetDisplayTypes.get_id_for_type_name(display_type)
def is_table_display_type(display_type): return (display_type == DashboardWidgetDisplayTypes.as_text_choices()[ DashboardWidgetDisplayTypes.TABLE][0])