Commit d13ed9eb authored by Natalia Tepluhina's avatar Natalia Tepluhina

Merge branch '212560-sse-load-file-content' into 'master'

Populate Static Site Editor Vuex Store with page source content

See merge request gitlab-org/gitlab!28481
parents 0f9003c7 1b15b3b8
<script> <script>
import { mapState, mapActions } from 'vuex'; import { mapState, mapGetters, mapActions } from 'vuex';
import { GlSkeletonLoader } from '@gitlab/ui'; import { GlSkeletonLoader } from '@gitlab/ui';
import EditArea from './edit_area.vue'; import EditArea from './edit_area.vue';
...@@ -10,7 +10,8 @@ export default { ...@@ -10,7 +10,8 @@ export default {
GlSkeletonLoader, GlSkeletonLoader,
}, },
computed: { computed: {
...mapState(['content', 'isContentLoaded', 'isLoadingContent']), ...mapState(['content', 'isLoadingContent']),
...mapGetters(['isContentLoaded']),
}, },
mounted() { mounted() {
this.loadContent(); this.loadContent();
......
...@@ -3,7 +3,11 @@ import StaticSiteEditor from './components/static_site_editor.vue'; ...@@ -3,7 +3,11 @@ import StaticSiteEditor from './components/static_site_editor.vue';
import createStore from './store'; import createStore from './store';
const initStaticSiteEditor = el => { const initStaticSiteEditor = el => {
const store = createStore(); const { projectId, path: sourcePath } = el.dataset;
const store = createStore({
initialState: { projectId, sourcePath },
});
return new Vue({ return new Vue({
el, el,
......
import createFlash from '~/flash';
import { __ } from '~/locale';
import * as mutationTypes from './mutation_types';
import loadSourceContent from '~/static_site_editor/services/load_source_content';
export const loadContent = ({ commit, state: { sourcePath, projectId } }) => {
commit(mutationTypes.LOAD_CONTENT);
return loadSourceContent({ sourcePath, projectId })
.then(data => commit(mutationTypes.RECEIVE_CONTENT_SUCCESS, data))
.catch(() => {
commit(mutationTypes.RECEIVE_CONTENT_ERROR);
createFlash(__('An error ocurred while loading your content. Please try again.'));
});
};
export default () => {};
// eslint-disable-next-line import/prefer-default-export
export const isContentLoaded = ({ content }) => Boolean(content);
import Vuex from 'vuex'; import Vuex from 'vuex';
import Vue from 'vue'; import Vue from 'vue';
import createState from './state'; import createState from './state';
import * as getters from './getters';
import * as actions from './actions';
import mutations from './mutations';
Vue.use(Vuex); Vue.use(Vuex);
const createStore = ({ initialState } = {}) => { const createStore = ({ initialState } = {}) => {
return new Vuex.Store({ return new Vuex.Store({
state: createState(initialState), state: createState(initialState),
getters,
actions,
mutations,
}); });
}; };
......
export const LOAD_CONTENT = 'loadContent';
export const RECEIVE_CONTENT_SUCCESS = 'receiveContentSuccess';
export const RECEIVE_CONTENT_ERROR = 'receiveContentError';
import * as types from './mutation_types';
export default {
[types.LOAD_CONTENT](state) {
state.isLoadingContent = true;
},
[types.RECEIVE_CONTENT_SUCCESS](state, { title, content }) {
state.isLoadingContent = false;
state.title = title;
state.content = content;
},
[types.RECEIVE_CONTENT_ERROR](state) {
state.isLoadingContent = false;
},
};
const createState = (initialState = {}) => ({ const createState = (initialState = {}) => ({
projectId: null,
sourcePath: null,
isLoadingContent: false, isLoadingContent: false,
isContentLoaded: false,
content: '', content: '',
title: '',
...initialState, ...initialState,
}); });
......
...@@ -2090,6 +2090,9 @@ msgstr "" ...@@ -2090,6 +2090,9 @@ msgstr ""
msgid "An error occurred. Please try again." msgid "An error occurred. Please try again."
msgstr "" msgstr ""
msgid "An error ocurred while loading your content. Please try again."
msgstr ""
msgid "An instance-level serverless domain already exists." msgid "An instance-level serverless domain already exists."
msgstr "" msgstr ""
......
...@@ -17,11 +17,15 @@ describe('StaticSiteEditor', () => { ...@@ -17,11 +17,15 @@ describe('StaticSiteEditor', () => {
let store; let store;
let loadContentActionMock; let loadContentActionMock;
const buildStore = (initialState = {}) => { const buildStore = ({ initialState, getters } = {}) => {
loadContentActionMock = jest.fn(); loadContentActionMock = jest.fn();
store = new Vuex.Store({ store = new Vuex.Store({
state: createState(initialState), state: createState(initialState),
getters: {
isContentLoaded: () => false,
...getters,
},
actions: { actions: {
loadContent: loadContentActionMock, loadContent: loadContentActionMock,
}, },
...@@ -56,7 +60,7 @@ describe('StaticSiteEditor', () => { ...@@ -56,7 +60,7 @@ describe('StaticSiteEditor', () => {
const content = 'edit area content'; const content = 'edit area content';
beforeEach(() => { beforeEach(() => {
buildStore({ content, isContentLoaded: true }); buildStore({ initialState: { content }, getters: { isContentLoaded: () => true } });
buildWrapper(); buildWrapper();
}); });
...@@ -70,7 +74,7 @@ describe('StaticSiteEditor', () => { ...@@ -70,7 +74,7 @@ describe('StaticSiteEditor', () => {
}); });
it('displays skeleton loader while loading content', () => { it('displays skeleton loader while loading content', () => {
buildStore({ isLoadingContent: true }); buildStore({ initialState: { isLoadingContent: true } });
buildWrapper(); buildWrapper();
expect(wrapper.find(GlSkeletonLoader).exists()).toBe(true); expect(wrapper.find(GlSkeletonLoader).exists()).toBe(true);
......
import testAction from 'helpers/vuex_action_helper';
import createState from '~/static_site_editor/store/state';
import * as actions from '~/static_site_editor/store/actions';
import * as mutationTypes from '~/static_site_editor/store/mutation_types';
import loadSourceContent from '~/static_site_editor/services/load_source_content';
import createFlash from '~/flash';
import {
projectId,
sourcePath,
sourceContentTitle as title,
sourceContent as content,
} from '../mock_data';
jest.mock('~/flash');
jest.mock('~/static_site_editor/services/load_source_content', () => jest.fn());
describe('Static Site Editor Store actions', () => {
let state;
beforeEach(() => {
state = createState({
projectId,
sourcePath,
});
});
describe('loadContent', () => {
describe('on success', () => {
const payload = { title, content };
beforeEach(() => {
loadSourceContent.mockResolvedValueOnce(payload);
});
it('commits receiveContentSuccess', () => {
testAction(
actions.loadContent,
null,
state,
[
{ type: mutationTypes.LOAD_CONTENT },
{ type: mutationTypes.RECEIVE_CONTENT_SUCCESS, payload },
],
[],
);
expect(loadSourceContent).toHaveBeenCalledWith({ projectId, sourcePath });
});
});
describe('on error', () => {
const expectedMutations = [
{ type: mutationTypes.LOAD_CONTENT },
{ type: mutationTypes.RECEIVE_CONTENT_ERROR },
];
beforeEach(() => {
loadSourceContent.mockRejectedValueOnce();
});
it('commits receiveContentError', () => {
testAction(actions.loadContent, null, state, expectedMutations);
});
it('displays flash communicating error', () => {
return testAction(actions.loadContent, null, state, expectedMutations).then(() => {
expect(createFlash).toHaveBeenCalledWith(
'An error ocurred while loading your content. Please try again.',
);
});
});
});
});
});
import createState from '~/static_site_editor/store/state';
import { isContentLoaded } from '~/static_site_editor/store/getters';
import { sourceContent as content } from '../mock_data';
describe('Static Site Editor Store getters', () => {
describe('isContentLoaded', () => {
it('returns true when content is not empty', () => {
expect(isContentLoaded(createState({ content }))).toBe(true);
});
it('returns false when content is empty', () => {
expect(isContentLoaded(createState({ content: '' }))).toBe(false);
});
});
});
import createState from '~/static_site_editor/store/state';
import mutations from '~/static_site_editor/store/mutations';
import * as types from '~/static_site_editor/store/mutation_types';
import { sourceContentTitle as title, sourceContent as content } from '../mock_data';
describe('Static Site Editor Store mutations', () => {
let state;
beforeEach(() => {
state = createState();
});
describe('loadContent', () => {
beforeEach(() => {
mutations[types.LOAD_CONTENT](state);
});
it('sets isLoadingContent to true', () => {
expect(state.isLoadingContent).toBe(true);
});
});
describe('receiveContentSuccess', () => {
const payload = { title, content };
beforeEach(() => {
mutations[types.RECEIVE_CONTENT_SUCCESS](state, payload);
});
it('sets current state to LOADING', () => {
expect(state.isLoadingContent).toBe(false);
});
it('sets title', () => {
expect(state.title).toBe(payload.title);
});
it('sets content', () => {
expect(state.content).toBe(payload.content);
});
});
describe('receiveContentError', () => {
beforeEach(() => {
mutations[types.RECEIVE_CONTENT_ERROR](state);
});
it('sets current state to LOADING_ERROR', () => {
expect(state.isLoadingContent).toBe(false);
});
});
});
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