Update apollo version, replace local state handling

This commit is contained in:
Ramon Wenger 2022-01-26 15:46:09 +01:00
parent 5b105958e2
commit a85296a628
11 changed files with 162 additions and 135 deletions

View File

@ -34,11 +34,6 @@
"@babel/runtime": "^7.5.4",
"@iam4x/cypress-graphql-mock": "0.0.1",
"@vue/composition-api": "^1.4.2",
"apollo-cache-inmemory": "^1.6.5",
"apollo-client": "^2.6.8",
"apollo-link": "^1.2.13",
"apollo-link-error": "^1.1.12",
"apollo-link-http": "^1.5.16",
"appolo": "^6.0.19",
"autoprefixer": "^7.1.2",
"babel-helper-vue-jsx-merge-props": "^2.0.3",

View File

@ -13,7 +13,7 @@
<script>
import {INTERDISCIPLINARY, LANGUAGE_COMMUNICATION, SOCIETY} from '@/consts/instrument.consts';
import INSTRUMENT_FILTER_QUERY from 'gql/local/instrumentFiler.gql';
import INSTRUMENT_FILTER_QUERY from 'gql/local/instrumentFilter.gql';
const ChevronRight = () => import(/* webpackChunkName: "icons" */'@/components/icons/ChevronRight');
export default {
@ -61,7 +61,6 @@
}
// eslint-disable-next-line
const [_, identifier] = this.instrumentFilter.currentFilter.split(':');
console.log(identifier, this.type);
return this.type === identifier;
},
typeClass() {

View File

@ -26,8 +26,7 @@
import FilterEntry from '@/components/instruments/FilterEntry';
import SET_FILTER_MUTATION from 'gql/local/mutations/setInstrumentFilter.gql';
import INSTRUMENT_FILTER_QUERY from 'gql/local/instrumentFiler.gql';
const ChevronRight = () => import(/* webpackChunkName: "icons" */'@/components/icons/ChevronRight');
import INSTRUMENT_FILTER_QUERY from 'gql/local/instrumentFilter.gql';
export default {
props: {
@ -46,7 +45,6 @@
},
components: {
FilterEntry,
ChevronRight,
},
apollo: {

104
client/src/graphql/cache.js Normal file
View File

@ -0,0 +1,104 @@
import {makeVar, defaultDataIdFromObject, InMemoryCache} from '@apollo/client/core';
const showNavigationSidebarVar = makeVar(false);
const showProfileSidebarVar = makeVar(false);
const scrollToElementVar = makeVar('');
const currentFilterVar = makeVar('');
const helloEmailVar = makeVar('');
const typePolicies = {
// https://www.apollographql.com/docs/react/local-state/managing-state-with-field-policies/#example
Query: {
fields: {
sidebar: {
read() {
return {
profile: showProfileSidebarVar(),
navigation: showNavigationSidebarVar()
};
}
} ,
scrollPosition: {
read() {
return {
scrollTo: scrollToElementVar()
};
}
},
instrumentFilter: {
read() {
return {
currentFilter: currentFilterVar()
};
}
},
helloEmail: {
read() {
return {
email: helloEmailVar()
};
}
}
}
},
};
const cache = new InMemoryCache({
// used to 'override' the behavior in resolving different types. We use it for local state management
// https://www.apollographql.com/docs/react/local-state/managing-state-with-field-policies/#example
typePolicies,
// todo: document what this does, or link the doc for it at least
dataIdFromObject: obj => {
switch (obj.__typename) {
case 'InstrumentNode':
case 'ModuleNode':
case 'RoomEntryNode':
return `${obj.__typename}:${obj.slug}`;
default:
return defaultDataIdFromObject(obj);
}
},
// todo: document what this does, or link the doc for it at least
cacheRedirects: {
Query: {
contentBlock: (_, args, {getCacheKey}) => getCacheKey({__typename: 'ContentBlockNode', id: args.id}),
chapter: (_, args, {getCacheKey}) => getCacheKey({__typename: 'ChapterNode', id: args.id}),
assignment: (_, args, {getCacheKey}) => getCacheKey({__typename: 'AssignmentNode', id: args.id}),
objective: (_, args, {getCacheKey}) => getCacheKey({__typename: 'ObjectiveNode', id: args.id}),
objectiveGroup: (_, args, {getCacheKey}) => getCacheKey({__typename: 'ObjectiveGroupNode', id: args.id}),
projectEntry: (_, args, {getCacheKey}) => getCacheKey({__typename: 'ProjectEntryNode', id: args.id}),
project: (_, args, {getCacheKey}) => {
if (args.slug) {
return getCacheKey({__typename: 'ProjectNode', id: args.slug});
} else {
return getCacheKey({__typename: 'ProjectNode', id: args.id});
}
},
},
},
});
// TODO: Monkey-patching in a fix for an open issue suggesting that
// `readQuery` should return null or undefined if the query is not yet in the
// cache: https://github.com/apollographql/apollo-feature-requests/issues/1
// probably not needed any more, as per https://github.com/apollographql/apollo-client/pull/7098
// cache.originalReadQuery = cache.readQuery;
// cache.readQuery = (...args) => {
// try {
// return cache.originalReadQuery(...args);
// } catch (err) {
// console.error(err);
// return undefined;
// }
// };
export {
showProfileSidebarVar,
showNavigationSidebarVar,
scrollToElementVar,
currentFilterVar,
helloEmailVar,
cache
};
export default cache;

View File

@ -1,36 +1,14 @@
import {defaultDataIdFromObject, InMemoryCache} from 'apollo-cache-inmemory';
import {createHttpLink} from 'apollo-link-http';
import {onError} from 'apollo-link-error';
import {ApolloClient} from 'apollo-client';
import {ApolloLink, Observable} from 'apollo-link';
import {onError} from '@apollo/client/link/error';
import {
ApolloClient,
ApolloLink,
createHttpLink,
} from '@apollo/client/core';
import fetch from 'unfetch';
import {typeDefs} from '@/graphql/typedefs';
import {resolvers} from '@/graphql/resolvers';
import cache from './cache';
const writeLocalCache = cache => {
// we use the cache as our local state
cache.writeData({
data: {
scrollPosition: {
__typename: 'ScrollPosition',
scrollTo: '',
},
sidebar: {
__typename: 'Sidebar',
profile: false,
navigation: false,
},
helloEmail: {
__typename: 'HelloEmail',
email: '',
},
instrumentFilter: {
__typename: 'InstrumentFilter',
currentFilter: 'abc'
}
},
});
};
export default function (uri, networkErrorCallback) {
const httpLink = createHttpLink({
@ -44,11 +22,10 @@ export default function (uri, networkErrorCallback) {
});
const consoleLink = new ApolloLink((operation, forward) => {
// console.log(`starting request for ${operation.operationName}`);
return forward(operation).map((data) => {
// console.log(`ending request for ${operation.operationName}`);
console.log('operation', operation);
return forward(operation).map(data => {
console.log('data', data);
return data;
});
});
@ -66,10 +43,11 @@ export default function (uri, networkErrorCallback) {
return forward(operation);
});
const errorLink = onError(({response, operation, networkError, graphQLErrors}) => {
const errorLink = onError(({networkError, graphQLErrors, forward, operation}) => {
// const observable = forward(operation);
if (networkError && networkErrorCallback) {
networkErrorCallback(networkError.statusCode);
return Observable.of();
// return observable;
}
if (graphQLErrors) {
@ -85,68 +63,23 @@ export default function (uri, networkErrorCallback) {
*/
if (networkError && networkError.name === 'ServerParseError') {
// workaround found here: https://github.com/apollographql/apollo-link/issues/855#issuecomment-485764697
return Observable.of();
// return observable;
}
});
const composedLink = ApolloLink.from([createOmitTypenameLink, consoleLink, errorLink, httpLink]);
const cache = new InMemoryCache({
dataIdFromObject: obj => {
switch (obj.__typename) {
case 'InstrumentNode':
case 'ModuleNode':
case 'RoomEntryNode':
return `${obj.__typename}:${obj.slug}`;
default:
return defaultDataIdFromObject(obj);
}
},
cacheRedirects: {
Query: {
contentBlock: (_, args, {getCacheKey}) => getCacheKey({__typename: 'ContentBlockNode', id: args.id}),
chapter: (_, args, {getCacheKey}) => getCacheKey({__typename: 'ChapterNode', id: args.id}),
assignment: (_, args, {getCacheKey}) => getCacheKey({__typename: 'AssignmentNode', id: args.id}),
objective: (_, args, {getCacheKey}) => getCacheKey({__typename: 'ObjectiveNode', id: args.id}),
objectiveGroup: (_, args, {getCacheKey}) => getCacheKey({__typename: 'ObjectiveGroupNode', id: args.id}),
projectEntry: (_, args, {getCacheKey}) => getCacheKey({__typename: 'ProjectEntryNode', id: args.id}),
project: (_, args, {getCacheKey}) => {
if (args.slug) {
return getCacheKey({__typename: 'ProjectNode', id: args.slug});
} else {
return getCacheKey({__typename: 'ProjectNode', id: args.id});
}
},
},
},
});
// TODO: Monkey-patching in a fix for an open issue suggesting that
// `readQuery` should return null or undefined if the query is not yet in the
// cache: https://github.com/apollographql/apollo-feature-requests/issues/1
cache.originalReadQuery = cache.readQuery;
cache.readQuery = (...args) => {
try {
return cache.originalReadQuery(...args);
} catch (err) {
console.error(err);
return undefined;
}
};
writeLocalCache(cache);
const composedLink = ApolloLink.from([
consoleLink,
createOmitTypenameLink,
errorLink,
httpLink
]);
// Create the apollo client
const client = new ApolloClient({
return new ApolloClient({
link: composedLink,
// link: httpLink,
cache,
connectToDevTools: true,
typeDefs,
resolvers,
});
client.onResetStore(() => {
writeLocalCache(cache);
});
return client;
}

View File

@ -1,39 +1,48 @@
import SCROLL_POSITION from '@/graphql/gql/local/scrollPosition.gql';
import HELLO_EMAIL from '@/graphql/gql/local/helloEmail.gql';
import SIDEBAR from '@/graphql/gql/local/sidebar.gql';
import INSTRUMENT_FILTER from '@/graphql/gql/local/instrumentFiler.gql';
import {
currentFilterVar,
helloEmailVar,
scrollToElementVar,
showNavigationSidebarVar,
showProfileSidebarVar,
} from '@/graphql/cache';
// todo: this probably can all be done with the apollo vars in the calling components, but that might need a rewrite of
// the parts where the mutation is called and then read. But maybe it works by itself already
export const resolvers = {
Mutation: {
scrollTo: (_, {scrollTo}, {cache}) => {
const data = cache.readQuery({query: SCROLL_POSITION});
data.scrollPosition.scrollTo = scrollTo;
cache.writeQuery({query: SCROLL_POSITION, data});
return data.scrollPosition;
scrollTo: (_, {scrollTo}) => {
scrollToElementVar(scrollTo);
return {
scrollTo: scrollToElementVar()
};
},
helloEmail: (_, {email}, {cache}) => {
const data = cache.readQuery({query: HELLO_EMAIL});
data.helloEmail.email = email;
cache.writeQuery({query: HELLO_EMAIL, data});
return data.helloEmail;
helloEmail: (_, {email}) => {
helloEmailVar(email);
return {
email: helloEmailVar()
};
},
setInstrumentFilter: (_, {filter}, {cache}) => {
const data = cache.readQuery({query: INSTRUMENT_FILTER});
data.instrumentFilter.currentFilter = filter;
cache.writeQuery({query: INSTRUMENT_FILTER, data});
return data.instrumentFilter;
setInstrumentFilter: (_, {filter}) => {
currentFilterVar(filter);
return {
currentFilter: currentFilterVar()
};
},
toggleSidebar: (_, {sidebar: {profile, navigation}}, {cache}) => {
const data = cache.readQuery({query: SIDEBAR});
toggleSidebar: (_, {sidebar: {profile, navigation}}) => {
if (typeof profile !== 'undefined') {
data.sidebar.profile = profile;
showProfileSidebarVar(profile);
}
if (typeof navigation !== 'undefined') {
data.sidebar.navigation = navigation;
showNavigationSidebarVar(navigation);
}
cache.writeQuery({query: SIDEBAR, data});
return data.sidebar;
return {
navigation: showNavigationSidebarVar(),
profile: showProfileSidebarVar()
};
},
// todo: does this still work?
deleteModuleNodes: (_, _query, {cache}) => {
Object.keys(cache.data.data)
.filter(prop => prop.indexOf('ModuleNode:') === 0)

View File

@ -19,7 +19,7 @@ export default {
apollo: {
sidebar: {
query: SIDEBAR
query: SIDEBAR,
}
},

View File

@ -56,8 +56,7 @@
</script>
<style scoped lang="scss">
@import "@/styles/_variables.scss";
@import "@/styles/_functions.scss";
@import "~styles/helpers";
.instrument {
&__title {

View File

@ -22,8 +22,7 @@
import InstrumentFilter from '@/components/instruments/InstrumentFilter';
import InstrumentEntry from '@/components/instruments/InstrumentEntry';
import INSTRUMENTS_QUERY from '@/graphql/gql/queries/instrumentsQuery.gql';
import INSTRUMENT_FILTER_QUERY from 'gql/local/instrumentFiler.gql';
import INSTRUMENT_FILTER_QUERY from 'gql/local/instrumentFilter.gql';
export default {
components: {

View File

@ -35,15 +35,6 @@
};
},
created() {
this.$log.debug('**** module.vue created ****');
this.$log.debug(`||| module id ${this.module.id} |||`);
},
mounted() {
this.$log.debug('**** module.vue mounted ****');
this.$log.debug(`||| module id ${this.module.id} |||`);
},
apollo: {
module() {
return {