Skip to content
Snippets Groups Projects
Commit bc21c371 authored by Hangzhi Yu's avatar Hangzhi Yu
Browse files

Manage snackbar items (for GraphQL errors) with root data instead of apollo state management

parent be8f2649
No related branches found
No related tags found
1 merge request!1123Resolve "Finalise Vuetify app as SPA"
......@@ -10,8 +10,6 @@ import { InMemoryCache } from "@/apollo-cache-inmemory";
import gql from "@/graphql-tag";
import gqlSnackbarItems from "../components/app/snackbarItems.graphql";
// Cache for GraphQL query results in memory and persistent across sessions
const cache = new InMemoryCache();
await persistCache({
......@@ -19,66 +17,6 @@ await persistCache({
storage: new LocalStorageWrapper(window.localStorage),
});
/**
* Type definitions for Apollo/s local state management
* cf. https://www.apollographql.com/docs/react/local-state/local-state-management/
*/
const typeDefs = gql`
type snackbarItem {
id: ID!
messageKey: String!
color: String!
read: Boolean!
}
type globalState {
contentLoading: Boolean!
browserTitle: String
}
type Mutation {
toggleSnackbarItem(id: ID!): Boolean
}
`;
/** Resolvers for local state management */
const resolvers = {
Mutation: {
/** Toggle snackbar item read or unread, given its ID */
toggleSnackbarItem: (_, { id }, { cache }) => {
const data = cache.readQuery({ query: gqlSnackbarItems });
const currentItem = data.snackbarItems.find((item) => item.id === id);
currentItem.read = !currentItem.read;
cache.writeQuery({ query: gqlSnackbarItems, data });
return currentItem.read;
},
},
};
/**
* Utility function to add a snackbar on GraphQL errors.
*/
function addErrorSnackbarItem(messageKey) {
let uuid = crypto.randomUUID();
cache.writeQuery({
query: gqlSnackbarItems,
data: {
snackbarItems: [
{
__typename: "snackbarItem",
id: uuid,
messageKey: messageKey,
color: "red",
read: false,
},
],
},
variables: {
id: uuid,
},
});
}
/**
* Construct the GraphQL endpoint URI.
*
......@@ -104,8 +42,6 @@ const links = [
/** Upstream Apollo GraphQL client */
const apolloClient = new ApolloClient({
typeDefs,
resolvers,
cache,
link: from(links),
});
......@@ -124,7 +60,12 @@ const apolloOpts = {
console.error("GraphQL query error:", err.message);
}
// Add a snackbar on all errors returned by the GraphQL endpoint
addErrorSnackbarItem("graphql.snackbar_error_message");
vm.$root.snackbarItems.push({
id: crypto.randomUUID(),
timeout: 5000,
messageKey: "graphql.snackbar_error_message",
color: "red",
});
}
if (networkError) {
// Set app offline globally on network errors
......
......@@ -182,13 +182,11 @@
</v-card>
</v-footer>
</div>
<div v-if="snackbarItems">
<snackbar-item
v-for="item in snackbarItems"
:key="item.id"
:snackbar-item="item"
/>
</div>
<snackbar-item
v-for="item in $root.snackbarItems"
:key="item.id"
:snackbar-item="item"
/>
<v-snackbar v-model="needRefresh" v-if="!refreshDismissed">
{{ $t("service_worker.new_version_available") }}
......@@ -216,7 +214,6 @@ import SnackbarItem from "./SnackbarItem.vue";
import gqlWhoAmI from "./whoAmI.graphql";
import gqlMessages from "./messages.graphql";
import gqlSystemProperties from "./systemProperties.graphql";
import gqlSnackbarItems from "./snackbarItems.graphql";
import useRegisterSWMixin from "../../mixins/useRegisterSW";
import offlineMixin from "../../mixins/offline";
......@@ -229,7 +226,6 @@ export default {
whoAmI: null,
systemProperties: null,
messages: null,
snackbarItems: null,
};
},
apollo: {
......@@ -243,10 +239,6 @@ export default {
},
pollInterval: 10000,
},
snackbarItems: {
query: gqlSnackbarItems,
pollInterval: 1000,
},
messages: {
query: gqlMessages,
pollInterval: 1000,
......
<template>
<v-snackbar :value="!snackbarItem.read" :color="snackbarItem.color">
<v-snackbar
v-model="visible"
:color="snackbarItem.color"
:timeout="snackbarItem.timeout"
@input="deleteSnackbarItem"
>
{{ $t(snackbarItem.messageKey) }}
<template #action="{ attrs }">
<v-btn icon @click="toggleSnackbarItem(snackbarItem.id)"
<v-btn icon @click="deleteSnackbarItem"
><v-icon>mdi-close</v-icon>
</v-btn>
</template>
......@@ -10,10 +15,13 @@
</template>
<script>
import gqlCheckSnackbarItem from "./toggleSnackbarItem.graphql";
export default {
name: "SnackbarItem",
data() {
return {
visible: true,
};
},
props: {
snackbarItem: {
type: Object,
......@@ -21,11 +29,10 @@ export default {
},
},
methods: {
toggleSnackbarItem(id) {
this.$apollo.mutate({
mutation: gqlCheckSnackbarItem,
variables: { id },
});
deleteSnackbarItem() {
this.$root.snackbarItems = this.$root.snackbarItems.filter(
(obj) => obj.id !== this.snackbarItem.id
);
},
},
};
......
{
snackbarItems @client {
id
messageKey
color
read
}
}
mutation ($id: String!) {
toggleSnackbarItem(id: $id) @client
}
......@@ -50,6 +50,7 @@ const app = new Vue({
contentLoading: false,
offline: false,
backgroundActive: true,
snackbarItems: [],
}),
router,
i18n,
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment