diff --git a/aleksis/core/frontend/app/apollo.js b/aleksis/core/frontend/app/apollo.js index a7dbba4b1a53695430a62f922313654cfa9ef99c..a78ef2247b9e6235373a128f9d1f6717de388af4 100644 --- a/aleksis/core/frontend/app/apollo.js +++ b/aleksis/core/frontend/app/apollo.js @@ -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 diff --git a/aleksis/core/frontend/components/app/App.vue b/aleksis/core/frontend/components/app/App.vue index 9c114d06c93947d41e07d1973627c373540063de..ab6abeb05ac8816e2e9f3423ba7fe69b74aa33b3 100644 --- a/aleksis/core/frontend/components/app/App.vue +++ b/aleksis/core/frontend/components/app/App.vue @@ -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, diff --git a/aleksis/core/frontend/components/app/SnackbarItem.vue b/aleksis/core/frontend/components/app/SnackbarItem.vue index 95eeb13ab10367e5d7576dd22247e6c7c33993da..ee442c44f99d9e1222ca80f0cd8f9beda49d0c65 100644 --- a/aleksis/core/frontend/components/app/SnackbarItem.vue +++ b/aleksis/core/frontend/components/app/SnackbarItem.vue @@ -1,8 +1,13 @@ <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 + ); }, }, }; diff --git a/aleksis/core/frontend/components/app/snackbarItems.graphql b/aleksis/core/frontend/components/app/snackbarItems.graphql deleted file mode 100644 index c31423e87179649f7d29e80edc32c84e54490ee1..0000000000000000000000000000000000000000 --- a/aleksis/core/frontend/components/app/snackbarItems.graphql +++ /dev/null @@ -1,8 +0,0 @@ -{ - snackbarItems @client { - id - messageKey - color - read - } -} diff --git a/aleksis/core/frontend/components/app/toggleSnackbarItem.graphql b/aleksis/core/frontend/components/app/toggleSnackbarItem.graphql deleted file mode 100644 index 2badaf3185ce7ecb9c16b8ffd12ba5f6cff0f34b..0000000000000000000000000000000000000000 --- a/aleksis/core/frontend/components/app/toggleSnackbarItem.graphql +++ /dev/null @@ -1,3 +0,0 @@ -mutation ($id: String!) { - toggleSnackbarItem(id: $id) @client -} diff --git a/aleksis/core/frontend/index.js b/aleksis/core/frontend/index.js index a11198e6c6ec23cee4d93a286eae07fc85060bf5..9bc91c8fb33fa7609b5c5923ac57f69a754248a1 100644 --- a/aleksis/core/frontend/index.js +++ b/aleksis/core/frontend/index.js @@ -50,6 +50,7 @@ const app = new Vue({ contentLoading: false, offline: false, backgroundActive: true, + snackbarItems: [], }), router, i18n, diff --git a/aleksis/core/frontend/mixins/aleksis.js b/aleksis/core/frontend/mixins/aleksis.js index 396345dcbc988334823ffaead235d66cedd7eb65..036e2eac71db6304bba88e2a01c3cfbe33edca51 100644 --- a/aleksis/core/frontend/mixins/aleksis.js +++ b/aleksis/core/frontend/mixins/aleksis.js @@ -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) {