Skip to content
Snippets Groups Projects
Verified Commit 93bc8cea authored by Nik | Klampfradler's avatar Nik | Klampfradler
Browse files

Merge branch '759-finalise-vuetify-app-as-spa' of...

Merge branch '759-finalise-vuetify-app-as-spa' of edugit.org:AlekSIS/official/AlekSIS-Core into 759-finalise-vuetify-app-as-spa
parents 27860514 beb79dde
No related branches found
No related tags found
1 merge request!1123Resolve "Finalise Vuetify app as SPA"
Pipeline #108345 failed
......@@ -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,
......
......@@ -19,6 +19,9 @@ const aleksisMixin = {
});
},
},
mounted() {
this.$root.contentLoading = false;
},
beforeDestroy() {
// Unregister all safely added event listeners as to not leak them
for (let trackedEvent in this.$data.$_aleksis_safeTrackedEvents) {
......
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