From 2c0adc86706fb2691f60b10c6fb4486e43394261 Mon Sep 17 00:00:00 2001 From: Massedil Date: Wed, 17 Dec 2025 14:15:19 +0100 Subject: [PATCH] clear memory cache for instances statistics when appropriate Add a loading state to buttons InstanceView Automatically refresh DashboardView data Fixes #1915 --- lib/graphql/resolvers/admin.ex | 6 + lib/service/statistics/statistics.ex | 4 + src/views/Admin/DashboardView.vue | 10 +- src/views/Admin/InstanceView.vue | 146 ++++++++++-------- .../__snapshots__/instanceView.spec.ts.snap | 4 +- 5 files changed, 102 insertions(+), 68 deletions(-) diff --git a/lib/graphql/resolvers/admin.ex b/lib/graphql/resolvers/admin.ex index 15f1e2fc1..7d8759716 100644 --- a/lib/graphql/resolvers/admin.ex +++ b/lib/graphql/resolvers/admin.ex @@ -608,6 +608,8 @@ defmodule Mobilizon.GraphQL.Resolvers.Admin do def remove_relay(_parent, %{address: address}, %{context: %{current_user: %User{role: role}}}) when is_admin(role) do with {:ok, _activity, follow} <- Relay.unfollow(address) do + Statistics.clear_cached_value(:instance_followers) + Statistics.clear_cached_value(:instance_followings) {:ok, follow} end end @@ -621,6 +623,8 @@ defmodule Mobilizon.GraphQL.Resolvers.Admin do ) when is_admin(role) do with {:ok, _activity, follow} <- Relay.accept(address) do + Statistics.clear_cached_value(:instance_followers) + Statistics.clear_cached_value(:instance_followings) {:ok, follow} end end @@ -634,6 +638,8 @@ defmodule Mobilizon.GraphQL.Resolvers.Admin do ) when is_admin(role) do with {:ok, _activity, follow} <- Relay.reject(address) do + Statistics.clear_cached_value(:instance_followers) + Statistics.clear_cached_value(:instance_followings) {:ok, follow} end end diff --git a/lib/service/statistics/statistics.ex b/lib/service/statistics/statistics.ex index 51ee216aa..5c1c8a2f4 100644 --- a/lib/service/statistics/statistics.ex +++ b/lib/service/statistics/statistics.ex @@ -20,6 +20,10 @@ defmodule Mobilizon.Service.Statistics do end end + def clear_cached_value(key) do + Cachex.del(:statistics, key) + end + defp create_cache(:local_users) do Users.count_users() end diff --git a/src/views/Admin/DashboardView.vue b/src/views/Admin/DashboardView.vue index dc65b560a..b56d17fda 100644 --- a/src/views/Admin/DashboardView.vue +++ b/src/views/Admin/DashboardView.vue @@ -50,7 +50,7 @@ " :to="{ name: RouteName.INSTANCES, - query: { followStatus: InstanceFilterFollowStatus.FOLLOWING }, + query: { followStatus: InstanceFilterFollowStatus.THEY_FOLLOW_US }, }" /> @@ -98,7 +98,11 @@ import GroupCard from "@/components/Group/GroupCard.vue"; import EventCard from "@/components/Event/EventCard.vue"; const { result: dashboardResult } = useQuery<{ dashboard: IDashboard }>( - DASHBOARD + DASHBOARD, + {}, + { + fetchPolicy: "cache-and-network", + } ); const dashboard = computed(() => dashboardResult.value?.dashboard); diff --git a/src/views/Admin/InstanceView.vue b/src/views/Admin/InstanceView.vue index a08ddad16..708ecdd50 100644 --- a/src/views/Admin/InstanceView.vue +++ b/src/views/Admin/InstanceView.vue @@ -119,35 +119,41 @@ ) " > - - - +
- - +

{{ t("This instance doesn't follow yours.") }}

@@ -222,24 +232,25 @@ const notifier = inject("notifier"); const { t } = useI18n({ useScope: "global" }); -const { mutate: acceptInstance, onError: onAcceptInstanceError } = useMutation( - ACCEPT_RELAY, - () => ({ - update(cache: ApolloCache) { - cache.writeFragment({ - id: cache.identify(instance.value as unknown as Reference), - fragment: gql` - fragment InstanceFollowerStatus on Instance { - followerStatus - } - `, - data: { - followerStatus: InstanceFollowStatus.APPROVED, - }, - }); - }, - }) -); +const { + mutate: acceptInstance, + loading: acceptInstanceLoading, + onError: onAcceptInstanceError, +} = useMutation(ACCEPT_RELAY, () => ({ + update(cache: ApolloCache) { + cache.writeFragment({ + id: cache.identify(instance.value as unknown as Reference), + fragment: gql` + fragment InstanceFollowerStatus on Instance { + followerStatus + } + `, + data: { + followerStatus: InstanceFollowStatus.APPROVED, + }, + }); + }, +})); onAcceptInstanceError((error) => { if (error.graphQLErrors && error.graphQLErrors.length > 0) { @@ -250,24 +261,25 @@ onAcceptInstanceError((error) => { /** * Reject instance follow */ -const { mutate: rejectInstance, onError: onRejectInstanceError } = useMutation( - REJECT_RELAY, - () => ({ - update(cache: ApolloCache) { - cache.writeFragment({ - id: cache.identify(instance.value as unknown as Reference), - fragment: gql` - fragment InstanceFollowerStatus on Instance { - followerStatus - } - `, - data: { - followerStatus: InstanceFollowStatus.NONE, - }, - }); - }, - }) -); +const { + mutate: rejectInstance, + loading: rejectInstanceLoading, + onError: onRejectInstanceError, +} = useMutation(REJECT_RELAY, () => ({ + update(cache: ApolloCache) { + cache.writeFragment({ + id: cache.identify(instance.value as unknown as Reference), + fragment: gql` + fragment InstanceFollowerStatus on Instance { + followerStatus + } + `, + data: { + followerStatus: InstanceFollowStatus.NONE, + }, + }); + }, +})); onRejectInstanceError((error) => { if (error.graphQLErrors && error.graphQLErrors.length > 0) { @@ -275,8 +287,11 @@ onRejectInstanceError((error) => { } }); -const { mutate: followInstanceMutation, onError: onFollowInstanceError } = - useMutation<{ addInstance: IInstance }>(ADD_INSTANCE); +const { + mutate: followInstanceMutation, + loading: followInstanceLoading, + onError: onFollowInstanceError, +} = useMutation<{ addInstance: IInstance }>(ADD_INSTANCE); onFollowInstanceError((error) => { if (error.graphQLErrors && error.graphQLErrors.length > 0) { @@ -292,22 +307,25 @@ const followInstance = async (e: Event): Promise => { /** * Stop following instance */ -const { mutate: removeInstanceFollow, onError: onRemoveInstanceFollowError } = - useMutation(REMOVE_RELAY, () => ({ - update(cache: ApolloCache) { - cache.writeFragment({ - id: cache.identify(instance.value as unknown as Reference), - fragment: gql` - fragment InstanceFollowedStatus on Instance { - followedStatus - } - `, - data: { - followedStatus: InstanceFollowStatus.NONE, - }, - }); - }, - })); +const { + mutate: removeInstanceFollow, + loading: removeInstanceFollowLoading, + onError: onRemoveInstanceFollowError, +} = useMutation(REMOVE_RELAY, () => ({ + update(cache: ApolloCache) { + cache.writeFragment({ + id: cache.identify(instance.value as unknown as Reference), + fragment: gql` + fragment InstanceFollowedStatus on Instance { + followedStatus + } + `, + data: { + followedStatus: InstanceFollowStatus.NONE, + }, + }); + }, +})); onRemoveInstanceFollowError((error) => { if (error.graphQLErrors && error.graphQLErrors.length > 0) { diff --git a/tests/unit/specs/views/admin/__snapshots__/instanceView.spec.ts.snap b/tests/unit/specs/views/admin/__snapshots__/instanceView.spec.ts.snap index 4fe140f73..59dda5cc9 100644 --- a/tests/unit/specs/views/admin/__snapshots__/instanceView.spec.ts.snap +++ b/tests/unit/specs/views/admin/__snapshots__/instanceView.spec.ts.snap @@ -21,7 +21,9 @@ exports[`InstanceView > Show simple 1`] = `
-
+