From d89a6ccf42e7672ca9e0dfd75ce11d7273efae9f Mon Sep 17 00:00:00 2001 From: subinasr Date: Tue, 7 Jul 2026 17:02:36 +0545 Subject: [PATCH 1/2] add(dashboards): bulk reorder mutation --- apps/dashboards/graphql/inputs.py | 6 ++++++ apps/dashboards/graphql/mutations.py | 32 +++++++++++++++++++++++++++- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/apps/dashboards/graphql/inputs.py b/apps/dashboards/graphql/inputs.py index 1d1af58..45f305b 100644 --- a/apps/dashboards/graphql/inputs.py +++ b/apps/dashboards/graphql/inputs.py @@ -17,6 +17,12 @@ class ExternalDashboardCreateInput: is_active: bool = True +@strawberry.input +class ExternalDashboardOrderInput: + id: strawberry.ID + order: int + + @strawberry.input class ExternalDashboardUpdateInput: title: str | None = strawberry.UNSET diff --git a/apps/dashboards/graphql/mutations.py b/apps/dashboards/graphql/mutations.py index 47268f0..c91c9eb 100644 --- a/apps/dashboards/graphql/mutations.py +++ b/apps/dashboards/graphql/mutations.py @@ -1,5 +1,7 @@ import strawberry import strawberry_django +from asgiref.sync import sync_to_async +from django.db import transaction from apps.dashboards.models import CapacityAndResource, ExternalDashboard from apps.dashboards.serializers import CapacityAndResourceSerializer, ExternalDashboardSerializer @@ -7,17 +9,33 @@ from main.graphql.permissions import IsStaffOrAbove from utils.graphql.drf import MutationCustomErrorType from utils.graphql.mutations import ModelMutation -from utils.graphql.types import MutationResponseType +from utils.graphql.types import CustomErrorType, MutationResponseType from .inputs import ( CapacityAndResourceCreateInput, CapacityAndResourceUpdateInput, ExternalDashboardCreateInput, + ExternalDashboardOrderInput, ExternalDashboardUpdateInput, ) from .types import CapacityAndResourceType, ExternalDashboardType +@sync_to_async +def _bulk_update_external_dashboard_order( + order_by_id: dict[str, int], +) -> tuple[CustomErrorType | None, list[ExternalDashboard] | None]: + with transaction.atomic(): + dashboards = list(ExternalDashboard.objects.filter(id__in=order_by_id)) + if len(dashboards) != len(order_by_id): + return MutationCustomErrorType.generate_message("One or more dashboards were not found."), None + for dashboard in dashboards: + dashboard.order = order_by_id[str(dashboard.pk)] + ExternalDashboard.objects.bulk_update(dashboards, ["order"]) + dashboards.sort(key=lambda dashboard: (dashboard.page, dashboard.order)) + return None, dashboards + + @strawberry.type class Mutation: @strawberry_django.mutation(permission_classes=[IsStaffOrAbove]) @@ -56,6 +74,18 @@ async def update_capacity_and_resource( instance = await CapacityAndResource.objects.aget(id=id) return await ModelMutation(CapacityAndResourceSerializer).handle_update_mutation(data, info, instance) + @strawberry_django.mutation(permission_classes=[IsStaffOrAbove]) + async def bulk_update_external_dashboards( + self, + info: Info, + data: list[ExternalDashboardOrderInput], + ) -> MutationResponseType[list[ExternalDashboardType]]: + order_by_id = {str(item.id): item.order for item in data} + errors, dashboards = await _bulk_update_external_dashboard_order(order_by_id) + if errors: + return MutationResponseType(ok=False, errors=errors) + return MutationResponseType(result=dashboards) + @strawberry_django.mutation(permission_classes=[IsStaffOrAbove]) async def add_dashboard_to_home( self, From f8cb4e979b3139696d59849216891c10541b5d59 Mon Sep 17 00:00:00 2001 From: amrit Date: Fri, 10 Jul 2026 14:13:35 +0545 Subject: [PATCH 2/2] fixup! add(dashboards): bulk reorder mutation --- schema.graphql | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/schema.graphql b/schema.graphql index fe0c569..aa329ec 100644 --- a/schema.graphql +++ b/schema.graphql @@ -117,6 +117,8 @@ type AppEnumCollectionUserRole { label: String! } +union BulkUpdateExternalDashboardsPayload = ExternalDashboardTypeListMutationResponseType | OperationInfo + """A Capacity & Resources entry that groups multiple ExternalDashboards.""" input CapacityAndResourceCreateInput { title: String! @@ -408,6 +410,11 @@ input ExternalDashboardOrder @oneOf { title: Ordering } +input ExternalDashboardOrderInput { + id: ID! + order: Int! +} + """Power BI / iframe dashboards embedded across site pages via CMS.""" type ExternalDashboardType { id: ID! @@ -428,6 +435,12 @@ type ExternalDashboardType { pageDisplay: String! } +type ExternalDashboardTypeListMutationResponseType { + ok: Boolean! + errors: CustomErrorType + result: [ExternalDashboardType!] +} + type ExternalDashboardTypeMutationResponseType { ok: Boolean! errors: CustomErrorType @@ -714,6 +727,7 @@ type Mutation { updateExternalDashboard(id: ID!, data: ExternalDashboardUpdateInput!): UpdateExternalDashboardPayload! createCapacityAndResource(data: CapacityAndResourceCreateInput!): CreateCapacityAndResourcePayload! updateCapacityAndResource(id: ID!, data: CapacityAndResourceUpdateInput!): UpdateCapacityAndResourcePayload! + bulkUpdateExternalDashboards(data: [ExternalDashboardOrderInput!]!): BulkUpdateExternalDashboardsPayload! addDashboardToHome(id: ID!): AddDashboardToHomePayload! removeDashboardFromHome(id: ID!): RemoveDashboardFromHomePayload! deleteExternalDashboard(id: ID!): DeleteExternalDashboardPayload!