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

Introduce basic error handling with apollo local states

parent f4082ab8
No related branches found
No related tags found
2 merge requests!1123Resolve "Finalise Vuetify app as SPA",!1066Translations update from Weblate
......@@ -263,6 +263,12 @@
</v-card>
</v-footer>
</div>
<snackbar
v-if="snackbarItems"
v-for="item in snackbarItems"
:key="item.id"
:snackbar-item="item"
/>
</v-app>
</template>
......@@ -274,6 +280,7 @@ import SidenavSearch from "./components/SidenavSearch.vue";
import CeleryProgressBottom from "./components/celery_progress/CeleryProgressBottom.vue";
import Loading from "./components/Loading.vue";
import BrandLogo from "./components/BrandLogo.vue";
import Snackbar from "./components/Snackbar.vue";
import gqlCurrentUser from "./currentUser.graphql";
import gqlWhoAmI from "./whoAmI.graphql";
......@@ -281,6 +288,7 @@ import gqlMessages from "./messages.graphql";
import gqlSystemProperties from "./systemProperties.graphql";
import gqlCustomMenu from "./customMenu.graphql";
import gqlGlobalPermissions from "./globalPermissions.graphql";
import gqlSnackbarItems from "./snackbarItems.graphql";
export default {
data() {
......@@ -295,6 +303,7 @@ export default {
permissionNames: [],
sideNavMenu: null,
accountMenu: null,
snackbarItems: null,
};
},
methods: {
......@@ -368,6 +377,7 @@ export default {
},
},
apollo: {
systemProperties: gqlSystemProperties,
currentUser: {
query: gqlCurrentUser,
pollInterval: 10000,
......@@ -376,11 +386,14 @@ export default {
query: gqlWhoAmI,
pollInterval: 10000,
},
snackbarItems: {
query: gqlSnackbarItems,
pollInterval: 1000,
},
messages: {
query: gqlMessages,
pollInterval: 1000,
},
systemProperties: gqlSystemProperties,
footerMenu: {
query: gqlCustomMenu,
variables() {
......@@ -444,6 +457,7 @@ export default {
SidenavSearch,
CeleryProgressBottom,
Loading,
Snackbar,
},
};
</script>
......
......@@ -5,8 +5,14 @@ import Vuetify from "@/vuetify";
import "@mdi/font/css/materialdesignicons.css";
import "vuetify/dist/vuetify.min.css";
import ApolloClient from "@/apollo-boost";
import { ApolloClient, HttpLink, from } from "@/apollo-boost";
import VueApollo from "@/vue-apollo";
import { InMemoryCache } from "@/apollo-cache-inmemory";
import { onError } from "@/apollo-link-error";
import gql from '@/graphql-tag';
import gqlSnackbarItems from "./snackbarItems.graphql";
import "./css/global.scss";
import VueI18n from "@/vue-i18n";
......@@ -55,8 +61,72 @@ i18n.registerLocale = function (messages) {
Vue.use(VueApollo);
Vue.use(VueRouter);
export const typeDefs = gql`
type snackbarItem {
id: ID!
message: String!
color: String!
read: Boolean!
}
type Mutation {
checkSnackbarItem(id: ID!): Boolean
}
`;
const cache = new InMemoryCache();
const resolvers = {
Mutation: {
checkSnackbarItem: (_, {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;
},
},
};
function addErrorSnackbarItem (error) {
let uuid = crypto.randomUUID();
cache.writeQuery({
query: gqlSnackbarItems,
data: {
snackbarItems: [
{
__typename: "snackbarItem",
id: uuid,
message: error,
color: "red",
read: false
},
]
},
variables: {
id: uuid
}
});
};
const errorLink = onError(({ graphQLErrors, networkError }) => {
if (graphQLErrors)
graphQLErrors.map(({ message, locations, path }) =>
addErrorSnackbarItem(`[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`),
)
if (networkError) addErrorSnackbarItem(`[Network error]: ${networkError}`)
});
const httpLink = new HttpLink({
uri: window.location.origin + "/django/graphql/"
});
const apolloClient = new ApolloClient({
uri: window.location.origin + "/django/graphql/",
typeDefs,
resolvers,
cache,
link: from([errorLink, httpLink]),
});
import App from "./App.vue";
......
mutation ($id: String!) {
checkSnackbarItem(id: $id) @client
}
<template>
<v-snackbar v-model="!snackbarItem.read" :color="snackbarItem.color">
{{ snackbarItem.message }}
<template v-slot:action="{ attrs }">
<v-btn icon @click="checkSnackbarItem(snackbarItem.id)" ><v-icon>mdi-close</v-icon></v-btn>
</template>
</v-snackbar>
</template>
<script>
import gqlCheckSnackbarItem from "../checkSnackbarItem.graphql"
export default {
name: "Snackbar",
props: {
snackbarItem: {
type: Object,
required: true,
},
},
methods: {
checkSnackbarItem(id) {
this.$apollo.mutate({
mutation: gqlCheckSnackbarItem,
variables: { id }
});
},
},
}
</script>
{
snackbarItems @client {
id
message
color
read
}
}
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