clear memory cache for instances statistics when appropriate
Add a loading state to buttons InstanceView Automatically refresh DashboardView data Fixes #1915
This commit is contained in:
@@ -608,6 +608,8 @@ defmodule Mobilizon.GraphQL.Resolvers.Admin do
|
|||||||
def remove_relay(_parent, %{address: address}, %{context: %{current_user: %User{role: role}}})
|
def remove_relay(_parent, %{address: address}, %{context: %{current_user: %User{role: role}}})
|
||||||
when is_admin(role) do
|
when is_admin(role) do
|
||||||
with {:ok, _activity, follow} <- Relay.unfollow(address) do
|
with {:ok, _activity, follow} <- Relay.unfollow(address) do
|
||||||
|
Statistics.clear_cached_value(:instance_followers)
|
||||||
|
Statistics.clear_cached_value(:instance_followings)
|
||||||
{:ok, follow}
|
{:ok, follow}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -621,6 +623,8 @@ defmodule Mobilizon.GraphQL.Resolvers.Admin do
|
|||||||
)
|
)
|
||||||
when is_admin(role) do
|
when is_admin(role) do
|
||||||
with {:ok, _activity, follow} <- Relay.accept(address) do
|
with {:ok, _activity, follow} <- Relay.accept(address) do
|
||||||
|
Statistics.clear_cached_value(:instance_followers)
|
||||||
|
Statistics.clear_cached_value(:instance_followings)
|
||||||
{:ok, follow}
|
{:ok, follow}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -634,6 +638,8 @@ defmodule Mobilizon.GraphQL.Resolvers.Admin do
|
|||||||
)
|
)
|
||||||
when is_admin(role) do
|
when is_admin(role) do
|
||||||
with {:ok, _activity, follow} <- Relay.reject(address) do
|
with {:ok, _activity, follow} <- Relay.reject(address) do
|
||||||
|
Statistics.clear_cached_value(:instance_followers)
|
||||||
|
Statistics.clear_cached_value(:instance_followings)
|
||||||
{:ok, follow}
|
{:ok, follow}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -20,6 +20,10 @@ defmodule Mobilizon.Service.Statistics do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def clear_cached_value(key) do
|
||||||
|
Cachex.del(:statistics, key)
|
||||||
|
end
|
||||||
|
|
||||||
defp create_cache(:local_users) do
|
defp create_cache(:local_users) do
|
||||||
Users.count_users()
|
Users.count_users()
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -50,7 +50,7 @@
|
|||||||
"
|
"
|
||||||
:to="{
|
:to="{
|
||||||
name: RouteName.INSTANCES,
|
name: RouteName.INSTANCES,
|
||||||
query: { followStatus: InstanceFilterFollowStatus.FOLLOWING },
|
query: { followStatus: InstanceFilterFollowStatus.THEY_FOLLOW_US },
|
||||||
}"
|
}"
|
||||||
/>
|
/>
|
||||||
<LinkedNumberDashboardTile
|
<LinkedNumberDashboardTile
|
||||||
@@ -60,7 +60,7 @@
|
|||||||
"
|
"
|
||||||
:to="{
|
:to="{
|
||||||
name: RouteName.INSTANCES,
|
name: RouteName.INSTANCES,
|
||||||
query: { followStatus: InstanceFilterFollowStatus.FOLLOWED },
|
query: { followStatus: InstanceFilterFollowStatus.WE_FOLLOW_THEM },
|
||||||
}"
|
}"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -98,7 +98,11 @@ import GroupCard from "@/components/Group/GroupCard.vue";
|
|||||||
import EventCard from "@/components/Event/EventCard.vue";
|
import EventCard from "@/components/Event/EventCard.vue";
|
||||||
|
|
||||||
const { result: dashboardResult } = useQuery<{ dashboard: IDashboard }>(
|
const { result: dashboardResult } = useQuery<{ dashboard: IDashboard }>(
|
||||||
DASHBOARD
|
DASHBOARD,
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
fetchPolicy: "cache-and-network",
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const dashboard = computed(() => dashboardResult.value?.dashboard);
|
const dashboard = computed(() => dashboardResult.value?.dashboard);
|
||||||
|
|||||||
@@ -119,35 +119,41 @@
|
|||||||
)
|
)
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<button
|
<o-button
|
||||||
@click="
|
@click="
|
||||||
removeInstanceFollow({
|
removeInstanceFollow({
|
||||||
address: instance?.relayAddress,
|
address: instance?.relayAddress,
|
||||||
})
|
})
|
||||||
"
|
"
|
||||||
|
:loading="removeInstanceFollowLoading"
|
||||||
v-if="instance.followedStatus == InstanceFollowStatus.APPROVED"
|
v-if="instance.followedStatus == InstanceFollowStatus.APPROVED"
|
||||||
|
variant="primary"
|
||||||
class="bg-primary hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-gray-400 focus:ring-offset-2 focus:ring-offset-gray-50 text-white hover:text-white font-semibold h-12 px-6 rounded-lg w-full flex items-center justify-center sm:w-auto"
|
class="bg-primary hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-gray-400 focus:ring-offset-2 focus:ring-offset-gray-50 text-white hover:text-white font-semibold h-12 px-6 rounded-lg w-full flex items-center justify-center sm:w-auto"
|
||||||
>
|
>
|
||||||
{{ t("Stop following instance") }}
|
{{ t("Stop following instance") }}
|
||||||
</button>
|
</o-button>
|
||||||
<button
|
<o-button
|
||||||
@click="
|
@click="
|
||||||
removeInstanceFollow({
|
removeInstanceFollow({
|
||||||
address: instance?.relayAddress,
|
address: instance?.relayAddress,
|
||||||
})
|
})
|
||||||
"
|
"
|
||||||
|
:loading="removeInstanceFollowLoading"
|
||||||
v-else-if="instance.followedStatus == InstanceFollowStatus.PENDING"
|
v-else-if="instance.followedStatus == InstanceFollowStatus.PENDING"
|
||||||
|
variant="primary"
|
||||||
class="bg-primary hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-gray-400 focus:ring-offset-2 focus:ring-offset-gray-50 text-white hover:text-white font-semibold h-12 px-6 rounded-lg w-full flex items-center justify-center sm:w-auto"
|
class="bg-primary hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-gray-400 focus:ring-offset-2 focus:ring-offset-gray-50 text-white hover:text-white font-semibold h-12 px-6 rounded-lg w-full flex items-center justify-center sm:w-auto"
|
||||||
>
|
>
|
||||||
{{ t("Cancel follow request") }}
|
{{ t("Cancel follow request") }}
|
||||||
</button>
|
</o-button>
|
||||||
<button
|
<o-button
|
||||||
@click="followInstance"
|
@click="followInstance"
|
||||||
|
:loading="followInstanceLoading"
|
||||||
v-else
|
v-else
|
||||||
|
variant="primary"
|
||||||
class="bg-primary hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-gray-400 focus:ring-offset-2 focus:ring-offset-gray-50 text-white hover:text-white font-semibold h-12 px-6 rounded-lg w-full flex items-center justify-center sm:w-auto"
|
class="bg-primary hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-gray-400 focus:ring-offset-2 focus:ring-offset-gray-50 text-white hover:text-white font-semibold h-12 px-6 rounded-lg w-full flex items-center justify-center sm:w-auto"
|
||||||
>
|
>
|
||||||
{{ t("Follow instance") }}
|
{{ t("Follow instance") }}
|
||||||
</button>
|
</o-button>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-else
|
v-else
|
||||||
@@ -158,31 +164,35 @@
|
|||||||
<div
|
<div
|
||||||
class="border bg-white dark:bg-mbz-purple-500 dark:border-mbz-purple-700 p-6 shadow-md rounded-md flex flex-col gap-2 justify-center"
|
class="border bg-white dark:bg-mbz-purple-500 dark:border-mbz-purple-700 p-6 shadow-md rounded-md flex flex-col gap-2 justify-center"
|
||||||
>
|
>
|
||||||
<button
|
<o-button
|
||||||
@click="
|
@click="
|
||||||
acceptInstance({
|
acceptInstance({
|
||||||
address: instance?.relayAddress,
|
address: instance?.relayAddress,
|
||||||
})
|
})
|
||||||
"
|
"
|
||||||
|
:loading="acceptInstanceLoading"
|
||||||
v-if="instance.followerStatus == InstanceFollowStatus.PENDING"
|
v-if="instance.followerStatus == InstanceFollowStatus.PENDING"
|
||||||
|
variant="primary"
|
||||||
class="bg-green-700 hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-gray-400 focus:ring-offset-2 focus:ring-offset-gray-50 text-white hover:text-white font-semibold h-12 px-6 rounded-lg w-full flex items-center justify-center sm:w-auto"
|
class="bg-green-700 hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-gray-400 focus:ring-offset-2 focus:ring-offset-gray-50 text-white hover:text-white font-semibold h-12 px-6 rounded-lg w-full flex items-center justify-center sm:w-auto"
|
||||||
>
|
>
|
||||||
{{ t("Accept follow") }}
|
{{ t("Accept follow") }}
|
||||||
</button>
|
</o-button>
|
||||||
<button
|
<o-button
|
||||||
@click="
|
@click="
|
||||||
rejectInstance({
|
rejectInstance({
|
||||||
address: instance?.relayAddress,
|
address: instance?.relayAddress,
|
||||||
})
|
})
|
||||||
"
|
"
|
||||||
|
:loading="rejectInstanceLoading"
|
||||||
v-if="
|
v-if="
|
||||||
instance.followerStatus == InstanceFollowStatus.PENDING ||
|
instance.followerStatus == InstanceFollowStatus.PENDING ||
|
||||||
instance.followerStatus == InstanceFollowStatus.APPROVED
|
instance.followerStatus == InstanceFollowStatus.APPROVED
|
||||||
"
|
"
|
||||||
|
variant="primary"
|
||||||
class="bg-red-700 hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-gray-400 focus:ring-offset-2 focus:ring-offset-gray-50 text-white hover:text-white font-semibold h-12 px-6 rounded-lg w-full flex items-center justify-center sm:w-auto"
|
class="bg-red-700 hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-gray-400 focus:ring-offset-2 focus:ring-offset-gray-50 text-white hover:text-white font-semibold h-12 px-6 rounded-lg w-full flex items-center justify-center sm:w-auto"
|
||||||
>
|
>
|
||||||
{{ t("Reject follow") }}
|
{{ t("Reject follow") }}
|
||||||
</button>
|
</o-button>
|
||||||
<p v-if="instance.followerStatus == InstanceFollowStatus.NONE">
|
<p v-if="instance.followerStatus == InstanceFollowStatus.NONE">
|
||||||
{{ t("This instance doesn't follow yours.") }}
|
{{ t("This instance doesn't follow yours.") }}
|
||||||
</p>
|
</p>
|
||||||
@@ -222,24 +232,25 @@ const notifier = inject<Notifier>("notifier");
|
|||||||
|
|
||||||
const { t } = useI18n({ useScope: "global" });
|
const { t } = useI18n({ useScope: "global" });
|
||||||
|
|
||||||
const { mutate: acceptInstance, onError: onAcceptInstanceError } = useMutation(
|
const {
|
||||||
ACCEPT_RELAY,
|
mutate: acceptInstance,
|
||||||
() => ({
|
loading: acceptInstanceLoading,
|
||||||
update(cache: ApolloCache<any>) {
|
onError: onAcceptInstanceError,
|
||||||
cache.writeFragment({
|
} = useMutation(ACCEPT_RELAY, () => ({
|
||||||
id: cache.identify(instance.value as unknown as Reference),
|
update(cache: ApolloCache<any>) {
|
||||||
fragment: gql`
|
cache.writeFragment({
|
||||||
fragment InstanceFollowerStatus on Instance {
|
id: cache.identify(instance.value as unknown as Reference),
|
||||||
followerStatus
|
fragment: gql`
|
||||||
}
|
fragment InstanceFollowerStatus on Instance {
|
||||||
`,
|
followerStatus
|
||||||
data: {
|
}
|
||||||
followerStatus: InstanceFollowStatus.APPROVED,
|
`,
|
||||||
},
|
data: {
|
||||||
});
|
followerStatus: InstanceFollowStatus.APPROVED,
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
);
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
onAcceptInstanceError((error) => {
|
onAcceptInstanceError((error) => {
|
||||||
if (error.graphQLErrors && error.graphQLErrors.length > 0) {
|
if (error.graphQLErrors && error.graphQLErrors.length > 0) {
|
||||||
@@ -250,24 +261,25 @@ onAcceptInstanceError((error) => {
|
|||||||
/**
|
/**
|
||||||
* Reject instance follow
|
* Reject instance follow
|
||||||
*/
|
*/
|
||||||
const { mutate: rejectInstance, onError: onRejectInstanceError } = useMutation(
|
const {
|
||||||
REJECT_RELAY,
|
mutate: rejectInstance,
|
||||||
() => ({
|
loading: rejectInstanceLoading,
|
||||||
update(cache: ApolloCache<any>) {
|
onError: onRejectInstanceError,
|
||||||
cache.writeFragment({
|
} = useMutation(REJECT_RELAY, () => ({
|
||||||
id: cache.identify(instance.value as unknown as Reference),
|
update(cache: ApolloCache<any>) {
|
||||||
fragment: gql`
|
cache.writeFragment({
|
||||||
fragment InstanceFollowerStatus on Instance {
|
id: cache.identify(instance.value as unknown as Reference),
|
||||||
followerStatus
|
fragment: gql`
|
||||||
}
|
fragment InstanceFollowerStatus on Instance {
|
||||||
`,
|
followerStatus
|
||||||
data: {
|
}
|
||||||
followerStatus: InstanceFollowStatus.NONE,
|
`,
|
||||||
},
|
data: {
|
||||||
});
|
followerStatus: InstanceFollowStatus.NONE,
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
);
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
onRejectInstanceError((error) => {
|
onRejectInstanceError((error) => {
|
||||||
if (error.graphQLErrors && error.graphQLErrors.length > 0) {
|
if (error.graphQLErrors && error.graphQLErrors.length > 0) {
|
||||||
@@ -275,8 +287,11 @@ onRejectInstanceError((error) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const { mutate: followInstanceMutation, onError: onFollowInstanceError } =
|
const {
|
||||||
useMutation<{ addInstance: IInstance }>(ADD_INSTANCE);
|
mutate: followInstanceMutation,
|
||||||
|
loading: followInstanceLoading,
|
||||||
|
onError: onFollowInstanceError,
|
||||||
|
} = useMutation<{ addInstance: IInstance }>(ADD_INSTANCE);
|
||||||
|
|
||||||
onFollowInstanceError((error) => {
|
onFollowInstanceError((error) => {
|
||||||
if (error.graphQLErrors && error.graphQLErrors.length > 0) {
|
if (error.graphQLErrors && error.graphQLErrors.length > 0) {
|
||||||
@@ -292,22 +307,25 @@ const followInstance = async (e: Event): Promise<void> => {
|
|||||||
/**
|
/**
|
||||||
* Stop following instance
|
* Stop following instance
|
||||||
*/
|
*/
|
||||||
const { mutate: removeInstanceFollow, onError: onRemoveInstanceFollowError } =
|
const {
|
||||||
useMutation(REMOVE_RELAY, () => ({
|
mutate: removeInstanceFollow,
|
||||||
update(cache: ApolloCache<any>) {
|
loading: removeInstanceFollowLoading,
|
||||||
cache.writeFragment({
|
onError: onRemoveInstanceFollowError,
|
||||||
id: cache.identify(instance.value as unknown as Reference),
|
} = useMutation(REMOVE_RELAY, () => ({
|
||||||
fragment: gql`
|
update(cache: ApolloCache<any>) {
|
||||||
fragment InstanceFollowedStatus on Instance {
|
cache.writeFragment({
|
||||||
followedStatus
|
id: cache.identify(instance.value as unknown as Reference),
|
||||||
}
|
fragment: gql`
|
||||||
`,
|
fragment InstanceFollowedStatus on Instance {
|
||||||
data: {
|
followedStatus
|
||||||
followedStatus: InstanceFollowStatus.NONE,
|
}
|
||||||
},
|
`,
|
||||||
});
|
data: {
|
||||||
},
|
followedStatus: InstanceFollowStatus.NONE,
|
||||||
}));
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
onRemoveInstanceFollowError((error) => {
|
onRemoveInstanceFollowError((error) => {
|
||||||
if (error.graphQLErrors && error.graphQLErrors.length > 0) {
|
if (error.graphQLErrors && error.graphQLErrors.length > 0) {
|
||||||
|
|||||||
@@ -21,7 +21,9 @@ exports[`InstanceView > Show simple 1`] = `
|
|||||||
</section>
|
</section>
|
||||||
<section>
|
<section>
|
||||||
<div class="mt-3 grid xl:grid-cols-2 gap-4">
|
<div class="mt-3 grid xl:grid-cols-2 gap-4">
|
||||||
<div class="border bg-white dark:bg-mbz-purple-500 dark:border-mbz-purple-700 p-6 shadow-md rounded-md flex flex-col gap-2 justify-center"><button class="bg-primary hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-gray-400 focus:ring-offset-2 focus:ring-offset-gray-50 text-white hover:text-white font-semibold h-12 px-6 rounded-lg w-full flex items-center justify-center sm:w-auto">Follow instance</button></div>
|
<div class="border bg-white dark:bg-mbz-purple-500 dark:border-mbz-purple-700 p-6 shadow-md rounded-md flex flex-col gap-2 justify-center"><button data-oruga="button" type="button" role="button" tabindex="0" class="o-button o-button--primary bg-primary hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-gray-400 focus:ring-offset-2 focus:ring-offset-gray-50 text-white hover:text-white font-semibold h-12 px-6 rounded-lg w-full flex items-center justify-center sm:w-auto"><span class="o-button__wrapper"><!----><span class="o-button__label">Follow instance</span>
|
||||||
|
<!----></span>
|
||||||
|
</button></div>
|
||||||
<div class="border bg-white dark:bg-mbz-purple-500 dark:border-mbz-purple-700 p-6 shadow-md rounded-md flex flex-col gap-2 justify-center">
|
<div class="border bg-white dark:bg-mbz-purple-500 dark:border-mbz-purple-700 p-6 shadow-md rounded-md flex flex-col gap-2 justify-center">
|
||||||
<!--v-if-->
|
<!--v-if-->
|
||||||
<!--v-if-->
|
<!--v-if-->
|
||||||
|
|||||||
Reference in New Issue
Block a user