Commit 25f9a50a authored by Enrique Alcantara's avatar Enrique Alcantara

Add file client-side resolver

Create a client-side resolver to
retrieve a file content using the GraphQL
API

Use the file client-side resolver
to fetch the page source content
parent f2a60225
import { s__ } from '~/locale'; import { s__, __ } from '~/locale';
export const BRANCH_SUFFIX_COUNT = 8; export const BRANCH_SUFFIX_COUNT = 8;
export const DEFAULT_TARGET_BRANCH = 'master'; export const DEFAULT_TARGET_BRANCH = 'master';
...@@ -10,5 +10,8 @@ export const SUBMIT_CHANGES_COMMIT_ERROR = s__( ...@@ -10,5 +10,8 @@ export const SUBMIT_CHANGES_COMMIT_ERROR = s__(
export const SUBMIT_CHANGES_MERGE_REQUEST_ERROR = s__( export const SUBMIT_CHANGES_MERGE_REQUEST_ERROR = s__(
'StaticSiteEditor|Could not create merge request.', 'StaticSiteEditor|Could not create merge request.',
); );
export const LOAD_CONTENT_ERROR = __(
'An error ocurred while loading your content. Please try again.',
);
export const DEFAULT_HEADING = s__('StaticSiteEditor|Static site editor'); export const DEFAULT_HEADING = s__('StaticSiteEditor|Static site editor');
...@@ -3,18 +3,29 @@ import VueApollo from 'vue-apollo'; ...@@ -3,18 +3,29 @@ import VueApollo from 'vue-apollo';
import createDefaultClient from '~/lib/graphql'; import createDefaultClient from '~/lib/graphql';
import typeDefs from './typedefs.graphql'; import typeDefs from './typedefs.graphql';
import fileResolver from './resolvers/file';
Vue.use(VueApollo); Vue.use(VueApollo);
const createApolloProvider = data => { const createApolloProvider = appData => {
const defaultClient = createDefaultClient( const defaultClient = createDefaultClient(
{}, {
Project: {
file: fileResolver,
},
},
{ {
typeDefs, typeDefs,
}, },
); );
defaultClient.cache.writeData({ defaultClient.cache.writeData({
data, data: {
appData: {
__typename: 'AppData',
...appData,
},
},
}); });
return new VueApollo({ return new VueApollo({
......
query appData { query appData {
isSupportedContent @client appData @client {
isSupportedContent
project
sourcePath
returnUrl
}
} }
query sourceContent($project: ID!, $sourcePath: String!) {
project(fullPath: $project) {
fullPath,
file(path: $sourcePath) @client {
title
content
}
}
}
import loadSourceContent from '../../services/load_source_content';
const fileResolver = ({ fullPath: projectId }, { path: sourcePath }) => {
return loadSourceContent({ projectId, sourcePath }).then(sourceContent => ({
// eslint-disable-next-line @gitlab/require-i18n-strings
__typename: 'File',
...sourceContent,
}));
};
export default fileResolver;
extend type Query { type File {
title: String
content: String!
}
extend type Project {
file(path: ID!): File
}
type AppData {
isSupportedContent: Boolean! isSupportedContent: Boolean!
project: String! project: String!
returnUrl: String returnUrl: String
sourcePath: String! sourcePath: String!
username: String! username: String!
} }
extend type Query {
appData: AppData!
}
...@@ -12,6 +12,11 @@ import InvalidContentMessage from '../components/invalid_content_message.vue'; ...@@ -12,6 +12,11 @@ import InvalidContentMessage from '../components/invalid_content_message.vue';
import SubmitChangesError from '../components/submit_changes_error.vue'; import SubmitChangesError from '../components/submit_changes_error.vue';
import appDataQuery from '../graphql/queries/app_data.query.graphql'; import appDataQuery from '../graphql/queries/app_data.query.graphql';
import sourceContentQuery from '../graphql/queries/source_content.query.graphql';
import createFlash from '~/flash';
import { LOAD_CONTENT_ERROR } from '../constants';
export default { export default {
components: { components: {
...@@ -26,9 +31,31 @@ export default { ...@@ -26,9 +31,31 @@ export default {
}, },
mixins: [glFeatureFlagsMixin()], mixins: [glFeatureFlagsMixin()],
apollo: { apollo: {
isSupportedContent: { appData: {
query: appDataQuery, query: appDataQuery,
}, },
sourceContent: {
query: sourceContentQuery,
update: ({
project: {
file: { title, content },
},
}) => {
return { title, content };
},
variables() {
return {
project: this.appData.project,
sourcePath: this.appData.sourcePath,
};
},
skip() {
return !this.appData.isSupportedContent;
},
error() {
createFlash(LOAD_CONTENT_ERROR);
},
},
}, },
computed: { computed: {
...mapState([ ...mapState([
...@@ -44,7 +71,7 @@ export default { ...@@ -44,7 +71,7 @@ export default {
...mapGetters(['contentChanged']), ...mapGetters(['contentChanged']),
}, },
mounted() { mounted() {
if (this.isSupportedContent) { if (this.appData.isSupportedContent) {
this.loadContent(); this.loadContent();
} }
}, },
...@@ -66,7 +93,7 @@ export default { ...@@ -66,7 +93,7 @@ export default {
/> />
<!-- Main view --> <!-- Main view -->
<template v-else-if="isSupportedContent"> <template v-else-if="appData.isSupportedContent">
<div v-if="isLoadingContent" class="w-50 h-50"> <div v-if="isLoadingContent" class="w-50 h-50">
<gl-skeleton-loader :width="500" :height="102"> <gl-skeleton-loader :width="500" :height="102">
<rect width="500" height="16" rx="4" /> <rect width="500" height="16" rx="4" />
......
import createFlash from '~/flash'; import createFlash from '~/flash';
import { __ } from '~/locale';
import * as mutationTypes from './mutation_types'; import * as mutationTypes from './mutation_types';
import loadSourceContent from '~/static_site_editor/services/load_source_content'; import loadSourceContent from '~/static_site_editor/services/load_source_content';
import submitContentChanges from '~/static_site_editor/services/submit_content_changes'; import submitContentChanges from '~/static_site_editor/services/submit_content_changes';
import { LOAD_CONTENT_ERROR } from '../constants';
export const loadContent = ({ commit, state: { sourcePath, projectId } }) => { export const loadContent = ({ commit, state: { sourcePath, projectId } }) => {
commit(mutationTypes.LOAD_CONTENT); commit(mutationTypes.LOAD_CONTENT);
...@@ -12,7 +13,7 @@ export const loadContent = ({ commit, state: { sourcePath, projectId } }) => { ...@@ -12,7 +13,7 @@ export const loadContent = ({ commit, state: { sourcePath, projectId } }) => {
.then(data => commit(mutationTypes.RECEIVE_CONTENT_SUCCESS, data)) .then(data => commit(mutationTypes.RECEIVE_CONTENT_SUCCESS, data))
.catch(() => { .catch(() => {
commit(mutationTypes.RECEIVE_CONTENT_ERROR); commit(mutationTypes.RECEIVE_CONTENT_ERROR);
createFlash(__('An error ocurred while loading your content. Please try again.')); createFlash(LOAD_CONTENT_ERROR);
}); });
}; };
......
import fileResolver from '~/static_site_editor/graphql/resolvers/file';
import loadSourceContent from '~/static_site_editor/services/load_source_content';
import {
projectId,
sourcePath,
sourceContentTitle as title,
sourceContent as content,
} from '../../mock_data';
jest.mock('~/static_site_editor/services/load_source_content', () => jest.fn());
describe('static_site_editor/graphql/resolvers/file', () => {
it('returns file content and title when fetching file successfully', () => {
loadSourceContent.mockResolvedValueOnce({ title, content });
return fileResolver({ fullPath: projectId }, { path: sourcePath }).then(file => {
expect(file).toEqual({
__typename: 'File',
title,
content,
});
});
});
});
...@@ -66,7 +66,7 @@ describe('static_site_editor/pages/home', () => { ...@@ -66,7 +66,7 @@ describe('static_site_editor/pages/home', () => {
}); });
}; };
const buildWrapper = (data = { isSupportedContent: true }) => { const buildWrapper = (data = { appData: { isSupportedContent: true } }) => {
wrapper = shallowMount(Home, { wrapper = shallowMount(Home, {
localVue, localVue,
store, store,
...@@ -196,7 +196,7 @@ describe('static_site_editor/pages/home', () => { ...@@ -196,7 +196,7 @@ describe('static_site_editor/pages/home', () => {
}); });
it('displays invalid content message when content is not supported', () => { it('displays invalid content message when content is not supported', () => {
buildWrapper({ isSupportedContent: false }); buildWrapper({ appData: { isSupportedContent: false } });
expect(findInvalidContentMessage().exists()).toBe(true); expect(findInvalidContentMessage().exists()).toBe(true);
}); });
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment