Move to Apollo v3

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
Thomas Citharel
2021-05-12 18:10:07 +02:00
parent 7cb40bd9e2
commit e96dcc42b9
51 changed files with 1247 additions and 817 deletions

View File

@@ -10,8 +10,13 @@
:show-detail-icon="false"
paginated
backend-pagination
:current-page.sync="page"
:aria-next-label="$t('Next page')"
:aria-previous-label="$t('Previous page')"
:aria-page-label="$t('Page')"
:aria-current-label="$t('Current page')"
:total="relayFollowers.total"
:per-page="perPage"
:per-page="FOLLOWERS_PER_PAGE"
@page-change="onFollowersPageChange"
checkable
checkbox-position="left"
@@ -123,14 +128,33 @@
</div>
</template>
<script lang="ts">
import { Component, Mixins } from "vue-property-decorator";
import { Component, Mixins, Ref } from "vue-property-decorator";
import { SnackbarProgrammatic as Snackbar } from "buefy";
import { formatDistanceToNow } from "date-fns";
import { ACCEPT_RELAY, REJECT_RELAY } from "../../graphql/admin";
import {
ACCEPT_RELAY,
REJECT_RELAY,
RELAY_FOLLOWERS,
} from "../../graphql/admin";
import { IFollower } from "../../types/actor/follower.model";
import RelayMixin from "../../mixins/relay";
import RouteName from "@/router/name";
import { Paginate } from "@/types/paginate";
const FOLLOWERS_PER_PAGE = 10;
@Component({
apollo: {
relayFollowers: {
query: RELAY_FOLLOWERS,
variables() {
return {
page: this.page,
limit: FOLLOWERS_PER_PAGE,
};
},
},
},
metaInfo() {
return {
title: this.$t("Followers") as string,
@@ -143,14 +167,36 @@ export default class Followers extends Mixins(RelayMixin) {
formatDistanceToNow = formatDistanceToNow;
async acceptRelays(): Promise<void> {
await this.checkedRows.forEach((row: IFollower) => {
relayFollowers: Paginate<IFollower> = { elements: [], total: 0 };
checkedRows: IFollower[] = [];
FOLLOWERS_PER_PAGE = FOLLOWERS_PER_PAGE;
@Ref("table") readonly table!: any;
toggle(row: Record<string, unknown>): void {
this.table.toggleDetails(row);
}
get page(): number {
return parseInt((this.$route.query.page as string) || "1", 10);
}
set page(page: number) {
this.pushRouter(RouteName.RELAY_FOLLOWERS, {
page: page.toString(),
});
}
acceptRelays(): void {
this.checkedRows.forEach((row: IFollower) => {
this.acceptRelay(`${row.actor.preferredUsername}@${row.actor.domain}`);
});
}
async rejectRelays(): Promise<void> {
await this.checkedRows.forEach((row: IFollower) => {
rejectRelays(): void {
this.checkedRows.forEach((row: IFollower) => {
this.rejectRelay(`${row.actor.preferredUsername}@${row.actor.domain}`);
});
}
@@ -196,5 +242,19 @@ export default class Followers extends Mixins(RelayMixin) {
get checkedRowsHaveAtLeastOneToApprove(): boolean {
return this.checkedRows.some((checkedRow) => !checkedRow.approved);
}
async onFollowersPageChange(page: number): Promise<void> {
this.page = page;
try {
await this.$apollo.queries.relayFollowers.fetchMore({
variables: {
page: this.page,
limit: FOLLOWERS_PER_PAGE,
},
});
} catch (err) {
console.error(err);
}
}
}
</script>

View File

@@ -32,8 +32,13 @@
:show-detail-icon="false"
paginated
backend-pagination
:current-page.sync="page"
:aria-next-label="$t('Next page')"
:aria-previous-label="$t('Previous page')"
:aria-page-label="$t('Page')"
:aria-current-label="$t('Current page')"
:total="relayFollowings.total"
:per-page="perPage"
:per-page="FOLLOWINGS_PER_PAGE"
@page-change="onFollowingsPageChange"
checkable
checkbox-position="left"
@@ -127,7 +132,7 @@
</b-button>
</template>
</b-table>
<b-message type="is-danger" v-if="relayFollowings.elements.length === 0">{{
<b-message type="is-danger" v-if="relayFollowings.total === 0">{{
$t("You don't follow any instances yet.")
}}</b-message>
</div>
@@ -139,8 +144,31 @@ import { formatDistanceToNow } from "date-fns";
import { ADD_RELAY, REMOVE_RELAY } from "../../graphql/admin";
import { IFollower } from "../../types/actor/follower.model";
import RelayMixin from "../../mixins/relay";
import { RELAY_FOLLOWINGS } from "@/graphql/admin";
import { Paginate } from "@/types/paginate";
import RouteName from "@/router/name";
import {
ApolloCache,
FetchResult,
InMemoryCache,
Reference,
} from "@apollo/client/core";
import gql from "graphql-tag";
const FOLLOWINGS_PER_PAGE = 10;
@Component({
apollo: {
relayFollowings: {
query: RELAY_FOLLOWINGS,
variables() {
return {
page: this.page,
limit: FOLLOWINGS_PER_PAGE,
};
},
},
},
metaInfo() {
return {
title: this.$t("Followings") as string,
@@ -155,16 +183,78 @@ export default class Followings extends Mixins(RelayMixin) {
formatDistanceToNow = formatDistanceToNow;
relayFollowings: Paginate<IFollower> = { elements: [], total: 0 };
FOLLOWINGS_PER_PAGE = FOLLOWINGS_PER_PAGE;
checkedRows: IFollower[] = [];
get page(): number {
return parseInt((this.$route.query.page as string) || "1", 10);
}
set page(page: number) {
this.pushRouter(RouteName.RELAY_FOLLOWINGS, {
page: page.toString(),
});
}
async onFollowingsPageChange(page: number): Promise<void> {
this.page = page;
try {
await this.$apollo.queries.relayFollowings.fetchMore({
variables: {
page: this.page,
limit: FOLLOWINGS_PER_PAGE,
},
});
} catch (err) {
console.error(err);
}
}
async followRelay(e: Event): Promise<void> {
e.preventDefault();
try {
await this.$apollo.mutate({
await this.$apollo.mutate<{ relayFollowings: Paginate<IFollower> }>({
mutation: ADD_RELAY,
variables: {
address: this.newRelayAddress.trim(), // trim to fix copy and paste domain name spaces and tabs
},
update(cache: ApolloCache<InMemoryCache>, { data }: FetchResult) {
cache.modify({
fields: {
relayFollowings(
existingFollowings = { elements: [], total: 0 },
{ readField }
) {
const newFollowingRef = cache.writeFragment({
id: `${data?.addRelay.__typename}:${data?.addRelay.id}`,
data: data?.addRelay,
fragment: gql`
fragment NewFollowing on Follower {
id
}
`,
});
if (
existingFollowings.elements.some(
(ref: Reference) =>
readField("id", ref) === data?.addRelay.id
)
) {
return existingFollowings;
}
return {
total: existingFollowings.total + 1,
elements: [newFollowingRef, ...existingFollowings.elements],
};
},
},
broadcast: false,
});
},
});
await this.$apollo.queries.relayFollowings.refetch();
this.newRelayAddress = "";
} catch (err) {
Snackbar.open({
@@ -175,21 +265,35 @@ export default class Followings extends Mixins(RelayMixin) {
}
}
async removeRelays(): Promise<void> {
await this.checkedRows.forEach((row: IFollower) => {
this.removeRelay(
`${row.targetActor.preferredUsername}@${row.targetActor.domain}`
);
removeRelays(): void {
this.checkedRows.forEach((row: IFollower) => {
this.removeRelay(row);
});
}
async removeRelay(address: string): Promise<void> {
async removeRelay(follower: IFollower): Promise<void> {
const address = `${follower.targetActor.preferredUsername}@${follower.targetActor.domain}`;
try {
await this.$apollo.mutate({
mutation: REMOVE_RELAY,
variables: {
address,
},
update(cache: ApolloCache<InMemoryCache>) {
cache.modify({
fields: {
relayFollowings(existingFollowingRefs, { readField }) {
return {
total: existingFollowingRefs.total - 1,
elements: existingFollowingRefs.elements.filter(
(followingRef: Reference) =>
follower.id !== readField("id", followingRef)
),
};
},
},
});
},
});
await this.$apollo.queries.relayFollowings.refetch();
this.checkedRows = [];

View File

@@ -279,7 +279,7 @@ export default class Comment extends Vue {
const { event } = eventData;
const { comments } = event;
const parentCommentIndex = comments.findIndex(
(oldComment) => oldComment.id === parentId
(oldComment: IComment) => oldComment.id === parentId
);
const parentComment = comments[parentCommentIndex];
if (!parentComment) return;

View File

@@ -88,6 +88,7 @@ import {
import { CURRENT_ACTOR_CLIENT } from "../../graphql/actor";
import { IPerson } from "../../types/actor";
import { IEvent } from "../../types/event.model";
import { ApolloCache, FetchResult, InMemoryCache } from "@apollo/client/core";
@Component({
apollo: {
@@ -157,7 +158,7 @@ export default class CommentTree extends Vue {
? comment.inReplyToComment.id
: null,
},
update: (store, { data }) => {
update: (store: ApolloCache<InMemoryCache>, { data }: FetchResult) => {
if (data == null) return;
const newComment = data.createComment;
@@ -249,7 +250,7 @@ export default class CommentTree extends Vue {
variables: {
commentId: comment.id,
},
update: (store, { data }) => {
update: (store: ApolloCache<InMemoryCache>, { data }: FetchResult) => {
if (data == null) return;
const deletedCommentId = data.deleteComment.id;

View File

@@ -1,10 +1,10 @@
import { UPLOAD_MEDIA } from "@/graphql/upload";
import apolloProvider from "@/vue-apollo";
import ApolloClient from "apollo-client";
import { NormalizedCacheObject } from "apollo-cache-inmemory";
import { ApolloClient } from "@apollo/client/core/ApolloClient";
import { Plugin } from "prosemirror-state";
import { EditorView } from "prosemirror-view";
import Image from "@tiptap/extension-image";
import { NormalizedCacheObject } from "@apollo/client/cache";
/* eslint-disable class-methods-use-this */

View File

@@ -2,11 +2,11 @@ import { SEARCH_PERSONS } from "@/graphql/search";
import { VueRenderer } from "@tiptap/vue-2";
import tippy from "tippy.js";
import MentionList from "./MentionList.vue";
import ApolloClient from "apollo-client";
import { NormalizedCacheObject } from "apollo-cache-inmemory";
import { ApolloClient } from "@apollo/client/core/ApolloClient";
import apolloProvider from "@/vue-apollo";
import { IPerson } from "@/types/actor";
import pDebounce from "p-debounce";
import { NormalizedCacheObject } from "@apollo/client/cache/inmemory/types";
const client =
apolloProvider.defaultClient as ApolloClient<NormalizedCacheObject>;

View File

@@ -234,7 +234,9 @@ export default class NavBar extends Vue {
query: IDENTITIES,
});
if (data) {
this.identities = data.identities.map((identity) => new Person(identity));
this.identities = data.identities.map(
(identity: IPerson) => new Person(identity)
);
// If we don't have any identities, the user has validated their account,
// is logging for the first time but didn't create an identity somehow

View File

@@ -134,6 +134,7 @@ import { addLocalUnconfirmedAnonymousParticipation } from "@/services/AnonymousP
import { EventJoinOptions, ParticipantRole } from "@/types/enums";
import RouteName from "@/router/name";
import { IParticipant } from "../../types/participant.model";
import { ApolloCache, FetchResult, InMemoryCache } from "@apollo/client/core";
@Component({
apollo: {
@@ -195,7 +196,10 @@ export default class ParticipationWithoutAccount extends Vue {
message: this.anonymousParticipation.message,
locale: this.$i18n.locale,
},
update: (store, { data: updateData }) => {
update: (
store: ApolloCache<InMemoryCache>,
{ data: updateData }: FetchResult
) => {
if (updateData == null) {
console.error(
"Cannot update event participant cache, because of data null value."