diff --git a/client/package-lock.json b/client/package-lock.json index ea90a3f5..207e0786 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -2909,11 +2909,6 @@ "@types/node": "*" } }, - "@types/zen-observable": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/@types/zen-observable/-/zen-observable-0.8.3.tgz", - "integrity": "sha512-fbF6oTd4sGGy0xjHPKAt+eS2CrxJ3+6gQ3FGcBoIJR2TLAyCkCyI8JqZNy+FeON0AhVgNJoUumVoZQjBFUqHkw==" - }, "@typescript-eslint/eslint-plugin": { "version": "5.10.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.10.0.tgz", @@ -3368,15 +3363,6 @@ "integrity": "sha512-ZkVeqEmRpBV2GHvjjUZqEai2PpUbuq8Bqd//vEYsp63J8WyexI8ppCqVS3Zs0QADf6aWuPdU+0XsPI647PVlQA==", "dev": true }, - "@wry/context": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/@wry/context/-/context-0.4.4.tgz", - "integrity": "sha512-LrKVLove/zw6h2Md/KZyWxIkFM6AoyKp71OqpH9Hiip1csjPVoD3tPxlbQUNxEnHENks3UGgNpSBCAfq9KWuag==", - "requires": { - "@types/node": ">=6", - "tslib": "^1.9.3" - } - }, "@wry/equality": { "version": "0.1.11", "resolved": "https://registry.npmjs.org/@wry/equality/-/equality-0.1.11.tgz", @@ -3683,42 +3669,6 @@ "picomatch": "^2.0.4" } }, - "apollo-cache": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/apollo-cache/-/apollo-cache-1.3.5.tgz", - "integrity": "sha512-1XoDy8kJnyWY/i/+gLTEbYLnoiVtS8y7ikBr/IfmML4Qb+CM7dEEbIUOjnY716WqmZ/UpXIxTfJsY7rMcqiCXA==", - "requires": { - "apollo-utilities": "^1.3.4", - "tslib": "^1.10.0" - } - }, - "apollo-cache-inmemory": { - "version": "1.6.6", - "resolved": "https://registry.npmjs.org/apollo-cache-inmemory/-/apollo-cache-inmemory-1.6.6.tgz", - "integrity": "sha512-L8pToTW/+Xru2FFAhkZ1OA9q4V4nuvfoPecBM34DecAugUZEBhI2Hmpgnzq2hTKZ60LAMrlqiASm0aqAY6F8/A==", - "requires": { - "apollo-cache": "^1.3.5", - "apollo-utilities": "^1.3.4", - "optimism": "^0.10.0", - "ts-invariant": "^0.4.0", - "tslib": "^1.10.0" - } - }, - "apollo-client": { - "version": "2.6.10", - "resolved": "https://registry.npmjs.org/apollo-client/-/apollo-client-2.6.10.tgz", - "integrity": "sha512-jiPlMTN6/5CjZpJOkGeUV0mb4zxx33uXWdj/xQCfAMkuNAC3HN7CvYDyMHHEzmcQ5GV12LszWoQ/VlxET24CtA==", - "requires": { - "@types/zen-observable": "^0.8.0", - "apollo-cache": "1.3.5", - "apollo-link": "^1.0.0", - "apollo-utilities": "1.3.4", - "symbol-observable": "^1.0.2", - "ts-invariant": "^0.4.0", - "tslib": "^1.10.0", - "zen-observable": "^0.8.0" - } - }, "apollo-link": { "version": "1.2.14", "resolved": "https://registry.npmjs.org/apollo-link/-/apollo-link-1.2.14.tgz", @@ -3730,36 +3680,6 @@ "zen-observable-ts": "^0.8.21" } }, - "apollo-link-error": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/apollo-link-error/-/apollo-link-error-1.1.13.tgz", - "integrity": "sha512-jAZOOahJU6bwSqb2ZyskEK1XdgUY9nkmeclCrW7Gddh1uasHVqmoYc4CKdb0/H0Y1J9lvaXKle2Wsw/Zx1AyUg==", - "requires": { - "apollo-link": "^1.2.14", - "apollo-link-http-common": "^0.2.16", - "tslib": "^1.9.3" - } - }, - "apollo-link-http": { - "version": "1.5.17", - "resolved": "https://registry.npmjs.org/apollo-link-http/-/apollo-link-http-1.5.17.tgz", - "integrity": "sha512-uWcqAotbwDEU/9+Dm9e1/clO7hTB2kQ/94JYcGouBVLjoKmTeJTUPQKcJGpPwUjZcSqgYicbFqQSoJIW0yrFvg==", - "requires": { - "apollo-link": "^1.2.14", - "apollo-link-http-common": "^0.2.16", - "tslib": "^1.9.3" - } - }, - "apollo-link-http-common": { - "version": "0.2.16", - "resolved": "https://registry.npmjs.org/apollo-link-http-common/-/apollo-link-http-common-0.2.16.tgz", - "integrity": "sha512-2tIhOIrnaF4UbQHf7kjeQA/EmSorB7+HyJIIrUjJOKBgnXwuexi8aMecRlqTIDWcyVXCeqLhUnztMa6bOH/jTg==", - "requires": { - "apollo-link": "^1.2.14", - "ts-invariant": "^0.4.0", - "tslib": "^1.9.3" - } - }, "apollo-utilities": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/apollo-utilities/-/apollo-utilities-1.3.4.tgz", @@ -15333,14 +15253,6 @@ "is-wsl": "^1.1.0" } }, - "optimism": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/optimism/-/optimism-0.10.3.tgz", - "integrity": "sha512-9A5pqGoQk49H6Vhjb9kPgAeeECfUDF6aIICbMDL23kDLStBn1MWk3YvcZ4xWF9CsSf6XEgvRLkXy4xof/56vVw==", - "requires": { - "@wry/context": "^0.4.0" - } - }, "optimize-css-assets-webpack-plugin": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/optimize-css-assets-webpack-plugin/-/optimize-css-assets-webpack-plugin-6.0.1.tgz", @@ -19717,7 +19629,8 @@ "symbol-observable": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", - "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==" + "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==", + "dev": true }, "symbol-tree": { "version": "3.2.4", diff --git a/client/package.json b/client/package.json index cff2688b..6c060204 100644 --- a/client/package.json +++ b/client/package.json @@ -83,7 +83,7 @@ "vee-validate": "^3.4.14", "vue": "^2.6.14", "vue-analytics": "^5.16.2", - "vue-apollo": "^3.0.0-beta.16", + "vue-apollo": "^3.1.0", "vue-loader": "^15.9.8", "vue-matomo": "^3.13.4-0", "vue-router": "^3.5.3", diff --git a/client/src/graphql/cache.js b/client/src/graphql/cache.js index ad4f1c54..0cf4a240 100644 --- a/client/src/graphql/cache.js +++ b/client/src/graphql/cache.js @@ -6,6 +6,13 @@ const scrollToElementVar = makeVar(''); const currentFilterVar = makeVar(''); const helloEmailVar = makeVar(''); +const idToRefFactory = (__typename) => (_, {args, toReference}) => { + return toReference({ + __typename, + id: args.id + }); + }; + const typePolicies = { // https://www.apollographql.com/docs/react/local-state/managing-state-with-field-policies/#example Query: { @@ -38,15 +45,44 @@ const typePolicies = { email: helloEmailVar() }; } - } + }, - } + + // these used to be in cacheRedirects, now here + // contentBlock: (_, args, {getCacheKey}) => getCacheKey({__typename: 'ContentBlockNode', id: args.id}), + contentBlock: { + read: idToRefFactory('ContentBlockNode') + // read(_, {args, toReference}) { + // return toReference({ + // __typename: 'ContentBlockNode', + // id: args.id + // }); + // } + } + }, + // chapter: (_, args, {getCacheKey}) => getCacheKey({__typename: 'ChapterNode', id: args.id}), + chapter: {read: idToRefFactory('ChapterNode')}, + assignment: {read: idToRefFactory('AssignmentNode')}, + objective: {read: idToRefFactory('ObjectiveNode')}, + objectiveGroup: {read: idToRefFactory('ObjectiveGroupNode')}, + projectEntry: {read: idToRefFactory('ProjectEntryNode')}, + // 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}), }, }; + +const possibleTypes = { + ContentBlockInterface: ['ContentBlockNode', 'SnapshotContentBlockNode'], + ChapterInterface: ['ChapterNode', 'SnapshotChapterNode'] +}; + 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, + possibleTypes, // todo: document what this does, or link the doc for it at least dataIdFromObject: obj => { switch (obj.__typename) { @@ -59,14 +95,9 @@ const cache = new InMemoryCache({ } }, // todo: document what this does, or link the doc for it at least + // todo: this is deprecated, it's now included in typePolicies 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}); diff --git a/client/src/graphql/gql/fragments/contentBlockParts.gql b/client/src/graphql/gql/fragments/contentBlockParts.gql index 13938c55..b2728f47 100644 --- a/client/src/graphql/gql/fragments/contentBlockParts.gql +++ b/client/src/graphql/gql/fragments/contentBlockParts.gql @@ -18,5 +18,4 @@ fragment ContentBlockParts on ContentBlockNode { id name } - } diff --git a/client/src/graphql/gql/queries/modules/moduleDetailsQuery.gql b/client/src/graphql/gql/queries/modules/moduleDetailsQuery.gql index e9598934..ae684dbf 100644 --- a/client/src/graphql/gql/queries/modules/moduleDetailsQuery.gql +++ b/client/src/graphql/gql/queries/modules/moduleDetailsQuery.gql @@ -24,8 +24,8 @@ query ModuleDetailsQuery($slug: String, $id: ID) { chapters { ...ChapterParts contentBlocks { - ...ContentBlockInterfaceParts ...ContentBlockParts + ...ContentBlockInterfaceParts } } } diff --git a/client/src/graphql/resolvers.js b/client/src/graphql/resolvers.js index ea63cb90..2734a92c 100644 --- a/client/src/graphql/resolvers.js +++ b/client/src/graphql/resolvers.js @@ -1,5 +1,3 @@ -import SCROLL_POSITION from '@/graphql/gql/local/scrollPosition.gql'; -import HELLO_EMAIL from '@/graphql/gql/local/helloEmail.gql'; import { currentFilterVar, helloEmailVar, diff --git a/client/src/pages/module/module.vue b/client/src/pages/module/module.vue index dc3f5137..8cd0908f 100644 --- a/client/src/pages/module/module.vue +++ b/client/src/pages/module/module.vue @@ -87,35 +87,42 @@ let {me} = store.readQuery({ query, }); - me.lastModule = { - id, - slug, - __typename: 'ModuleNode', - }; + // me.lastModule = { + // id, + // slug, + // __typename: 'ModuleNode', + // }; - if (!me.recentModules || !me.recentModules.edges) { - me.recentModules = { - __typename: 'ModuleNodeConnection', - edges: [], - }; - } - const foundIndex = me.recentModules.edges.findIndex(edge => edge.node.slug === lastModule.slug); - let edges = me.recentModules.edges; + let edges = [...me.recentModules.edges]; + const foundIndex = edges.findIndex(edge => edge.node.slug === slug); if (foundIndex > -1) { edges = [...edges.slice(0, foundIndex), ...edges.slice(foundIndex + 1, edges.length)]; } - me.recentModules.edges = [ + edges = [ { node: lastModule, __typename: 'ModuleNodeEdge', }, ...edges.slice(0, 2), ]; + const recentModules = { + __typename: 'ModuleNodeConnection', + edges + }; + const data = { + me: { + ...me, + recentModules, + lastModule: { + ...lastModule, + // todo: do we really need this? shouldn't the lastModule property already include this? + '__typename': 'ModuleNode' + } + } + }; store.writeQuery({ query, - data: { - me, - }, + data }); }, diff --git a/client/src/pages/topic-page.vue b/client/src/pages/topic-page.vue index efc4fa80..79a92934 100644 --- a/client/src/pages/topic-page.vue +++ b/client/src/pages/topic-page.vue @@ -125,9 +125,14 @@ update(store, {data: {updateLastTopic: {topic}}}) { if (topic) { const query = ME_QUERY; - const data = store.readQuery({query}); - if (data) { - data.me.lastTopic = topic; + const {me} = store.readQuery({query}); + if (me) { + const data = { + me: { + ...me, + lastTopic: topic + } + }; store.writeQuery({query, data}); } }