Commit 4631ad9e authored by Phil Hughes's avatar Phil Hughes

EE port of make-ide-ce

parent 3551d6a3
<script> <script>
import { mapState } from 'vuex'; import { mapState } from 'vuex';
import { sprintf, __ } from '~/locale'; import { sprintf, __ } from '~/locale';
import * as consts from 'ee/ide/stores/modules/commit/constants'; import * as consts from '../../stores/modules/commit/constants';
import RadioGroup from './radio_group.vue'; import RadioGroup from './radio_group.vue';
export default { export default {
......
<script> <script>
import { mapActions } from 'vuex'; import { mapActions } from 'vuex';
import router from 'ee/ide/ide_router';
import icon from '~/vue_shared/components/icon.vue'; import icon from '~/vue_shared/components/icon.vue';
import router from '../../ide_router';
export default { export default {
components: { components: {
......
...@@ -5,9 +5,8 @@ import icon from '~/vue_shared/components/icon.vue'; ...@@ -5,9 +5,8 @@ import icon from '~/vue_shared/components/icon.vue';
import modal from '~/vue_shared/components/modal.vue'; import modal from '~/vue_shared/components/modal.vue';
import LoadingButton from '~/vue_shared/components/loading_button.vue'; import LoadingButton from '~/vue_shared/components/loading_button.vue';
import commitFilesList from './commit_sidebar/list.vue'; import commitFilesList from './commit_sidebar/list.vue';
import * as consts from '../stores/modules/commit/constants';
import * as consts from 'ee/ide/stores/modules/commit/constants'; // eslint-disable-line import/first import Actions from './commit_sidebar/actions.vue';
import Actions from 'ee/ide/components/commit_sidebar/actions.vue'; // eslint-disable-line import/first
export default { export default {
components: { components: {
......
...@@ -3,9 +3,8 @@ ...@@ -3,9 +3,8 @@
import fileIcon from '~/vue_shared/components/file_icon.vue'; import fileIcon from '~/vue_shared/components/file_icon.vue';
import icon from '~/vue_shared/components/icon.vue'; import icon from '~/vue_shared/components/icon.vue';
import fileStatusIcon from './repo_file_status_icon.vue';
import fileStatusIcon from 'ee/ide/components/repo_file_status_icon.vue'; import changedFileIcon from './changed_file_icon.vue';
import changedFileIcon from 'ee/ide/components/changed_file_icon.vue';
export default { export default {
components: { components: {
......
/* global monaco */ /* global monaco */
import Disposable from './disposable'; import Disposable from './disposable';
import eventHub from '../../eventhub';
import eventHub from 'ee/ide/eventhub'; // eslint-disable-line import/first
export default class Model { export default class Model {
constructor(monaco, file) { constructor(monaco, file) {
...@@ -11,16 +10,16 @@ export default class Model { ...@@ -11,16 +10,16 @@ export default class Model {
this.content = file.content !== '' ? file.content : file.raw; this.content = file.content !== '' ? file.content : file.raw;
this.disposable.add( this.disposable.add(
this.originalModel = this.monaco.editor.createModel( (this.originalModel = this.monaco.editor.createModel(
this.file.raw, this.file.raw,
undefined, undefined,
new this.monaco.Uri(null, null, `original/${this.file.path}`), new this.monaco.Uri(null, null, `original/${this.file.path}`),
), )),
this.model = this.monaco.editor.createModel( (this.model = this.monaco.editor.createModel(
this.content, this.content,
undefined, undefined,
new this.monaco.Uri(null, null, this.file.path), new this.monaco.Uri(null, null, this.file.path),
), )),
); );
this.events = new Map(); this.events = new Map();
...@@ -29,7 +28,10 @@ export default class Model { ...@@ -29,7 +28,10 @@ export default class Model {
this.dispose = this.dispose.bind(this); this.dispose = this.dispose.bind(this);
eventHub.$on(`editor.update.model.dispose.${this.file.path}`, this.dispose); eventHub.$on(`editor.update.model.dispose.${this.file.path}`, this.dispose);
eventHub.$on(`editor.update.model.content.${this.file.path}`, this.updateContent); eventHub.$on(
`editor.update.model.content.${this.file.path}`,
this.updateContent,
);
} }
get url() { get url() {
...@@ -63,9 +65,7 @@ export default class Model { ...@@ -63,9 +65,7 @@ export default class Model {
onChange(cb) { onChange(cb) {
this.events.set( this.events.set(
this.path, this.path,
this.disposable.add( this.disposable.add(this.model.onDidChangeContent(e => cb(this, e))),
this.model.onDidChangeContent(e => cb(this, e)),
),
); );
} }
...@@ -78,7 +78,13 @@ export default class Model { ...@@ -78,7 +78,13 @@ export default class Model {
this.disposable.dispose(); this.disposable.dispose();
this.events.clear(); this.events.clear();
eventHub.$off(`editor.update.model.dispose.${this.file.path}`, this.dispose); eventHub.$off(
eventHub.$off(`editor.update.model.content.${this.file.path}`, this.updateContent); `editor.update.model.dispose.${this.file.path}`,
this.dispose,
);
eventHub.$off(
`editor.update.model.content.${this.file.path}`,
this.updateContent,
);
} }
} }
import eventHub from 'ee/ide/eventhub'; import eventHub from '../../eventhub';
import Disposable from './disposable'; import Disposable from './disposable';
import Model from './model'; import Model from './model';
...@@ -26,7 +26,10 @@ export default class ModelManager { ...@@ -26,7 +26,10 @@ export default class ModelManager {
this.models.set(model.path, model); this.models.set(model.path, model);
this.disposable.add(model); this.disposable.add(model);
eventHub.$on(`editor.update.model.dispose.${file.path}`, this.removeCachedModel.bind(this, file)); eventHub.$on(
`editor.update.model.dispose.${file.path}`,
this.removeCachedModel.bind(this, file),
);
return model; return model;
} }
...@@ -34,7 +37,10 @@ export default class ModelManager { ...@@ -34,7 +37,10 @@ export default class ModelManager {
removeCachedModel(file) { removeCachedModel(file) {
this.models.delete(file.path); this.models.delete(file.path);
eventHub.$off(`editor.update.model.dispose.${file.path}`, this.removeCachedModel); eventHub.$off(
`editor.update.model.dispose.${file.path}`,
this.removeCachedModel,
);
} }
dispose() { dispose() {
......
import { normalizeHeaders } from '~/lib/utils/common_utils'; import { normalizeHeaders } from '~/lib/utils/common_utils';
import flash from '~/flash'; import flash from '~/flash';
import eventHub from 'ee/ide/eventhub'; import eventHub from '../../eventhub';
import service from '../../services'; import service from '../../services';
import * as types from '../mutation_types'; import * as types from '../mutation_types';
import router from '../../ide_router'; import router from '../../ide_router';
......
...@@ -4,8 +4,7 @@ import state from './state'; ...@@ -4,8 +4,7 @@ import state from './state';
import * as actions from './actions'; import * as actions from './actions';
import * as getters from './getters'; import * as getters from './getters';
import mutations from './mutations'; import mutations from './mutations';
import commitModule from './modules/commit';
import commitModule from 'ee/ide/stores/modules/commit'; // eslint-disable-line import/first
Vue.use(Vuex); Vue.use(Vuex);
......
import $ from 'jquery'; import $ from 'jquery';
import { sprintf, __ } from '~/locale'; import { sprintf, __ } from '~/locale';
import * as rootTypes from 'ee/ide/stores/mutation_types';
import { createCommitPayload, createNewMergeRequestUrl } from 'ee/ide/stores/utils';
import router from 'ee/ide/ide_router';
import service from 'ee/ide/services';
import flash from '~/flash'; import flash from '~/flash';
import { stripHtml } from '~/lib/utils/text_utility'; import { stripHtml } from '~/lib/utils/text_utility';
import * as rootTypes from '../../mutation_types';
import { createCommitPayload, createNewMergeRequestUrl } from '../../utils';
import router from '../../../ide_router';
import service from '../../../services';
import * as types from './mutation_types'; import * as types from './mutation_types';
import * as consts from './constants'; import * as consts from './constants';
import eventHub from '../../../eventhub';
import eventHub from 'ee/ide/eventhub'; // eslint-disable-line import/first
export const updateCommitMessage = ({ commit }, message) => { export const updateCommitMessage = ({ commit }, message) => {
commit(types.UPDATE_COMMIT_MESSAGE, message); commit(types.UPDATE_COMMIT_MESSAGE, message);
...@@ -29,16 +28,18 @@ export const updateBranchName = ({ commit }, branchName) => { ...@@ -29,16 +28,18 @@ export const updateBranchName = ({ commit }, branchName) => {
export const setLastCommitMessage = ({ rootState, commit }, data) => { export const setLastCommitMessage = ({ rootState, commit }, data) => {
const currentProject = rootState.projects[rootState.currentProjectId]; const currentProject = rootState.projects[rootState.currentProjectId];
const commitStats = data.stats ? const commitStats = data.stats
sprintf( ? sprintf(__('with %{additions} additions, %{deletions} deletions.'), {
__('with %{additions} additions, %{deletions} deletions.'), additions: data.stats.additions, // eslint-disable-line indent
{ additions: data.stats.additions, deletions: data.stats.deletions }, deletions: data.stats.deletions, // eslint-disable-line indent
) }) // eslint-disable-line indent
: ''; : '';
const commitMsg = sprintf( const commitMsg = sprintf(
__('Your changes have been committed. Commit %{commitId} %{commitStats}'), __('Your changes have been committed. Commit %{commitId} %{commitStats}'),
{ {
commitId: `<a href="${currentProject.web_url}/commit/${data.short_id}" class="commit-sha">${data.short_id}</a>`, commitId: `<a href="${currentProject.web_url}/commit/${
data.short_id
}" class="commit-sha">${data.short_id}</a>`,
commitStats, commitStats,
}, },
false, false,
...@@ -53,7 +54,9 @@ export const checkCommitStatus = ({ rootState }) => ...@@ -53,7 +54,9 @@ export const checkCommitStatus = ({ rootState }) =>
.then(({ data }) => { .then(({ data }) => {
const { id } = data.commit; const { id } = data.commit;
const selectedBranch = const selectedBranch =
rootState.projects[rootState.currentProjectId].branches[rootState.currentBranchId]; rootState.projects[rootState.currentProjectId].branches[
rootState.currentBranchId
];
if (selectedBranch.workingReference !== id) { if (selectedBranch.workingReference !== id) {
return true; return true;
...@@ -61,7 +64,16 @@ export const checkCommitStatus = ({ rootState }) => ...@@ -61,7 +64,16 @@ export const checkCommitStatus = ({ rootState }) =>
return false; return false;
}) })
.catch(() => flash(__('Error checking branch data. Please try again.'), 'alert', document, null, false, true)); .catch(() =>
flash(
__('Error checking branch data. Please try again.'),
'alert',
document,
null,
false,
true,
),
);
export const updateFilesAfterCommit = ( export const updateFilesAfterCommit = (
{ commit, dispatch, state, rootState, rootGetters }, { commit, dispatch, state, rootState, rootGetters },
...@@ -78,55 +90,92 @@ export const updateFilesAfterCommit = ( ...@@ -78,55 +90,92 @@ export const updateFilesAfterCommit = (
}, },
}; };
commit(rootTypes.SET_BRANCH_WORKING_REFERENCE, { commit(
rootTypes.SET_BRANCH_WORKING_REFERENCE,
{
projectId: rootState.currentProjectId, projectId: rootState.currentProjectId,
branchId: rootState.currentBranchId, branchId: rootState.currentBranchId,
reference: data.id, reference: data.id,
}, { root: true }); },
{ root: true },
);
rootState.changedFiles.forEach((entry) => { rootState.changedFiles.forEach(entry => {
commit(rootTypes.SET_LAST_COMMIT_DATA, { commit(
rootTypes.SET_LAST_COMMIT_DATA,
{
entry, entry,
lastCommit, lastCommit,
}, { root: true }); },
{ root: true },
);
eventHub.$emit(`editor.update.model.content.${entry.path}`, entry.content); eventHub.$emit(`editor.update.model.content.${entry.path}`, entry.content);
commit(rootTypes.SET_FILE_RAW_DATA, { commit(
rootTypes.SET_FILE_RAW_DATA,
{
file: entry, file: entry,
raw: entry.content, raw: entry.content,
}, { root: true }); },
{ root: true },
);
commit(rootTypes.TOGGLE_FILE_CHANGED, { commit(
rootTypes.TOGGLE_FILE_CHANGED,
{
file: entry, file: entry,
changed: false, changed: false,
}, { root: true }); },
{ root: true },
);
}); });
commit(rootTypes.REMOVE_ALL_CHANGES_FILES, null, { root: true }); commit(rootTypes.REMOVE_ALL_CHANGES_FILES, null, { root: true });
if (state.commitAction === consts.COMMIT_TO_NEW_BRANCH) { if (state.commitAction === consts.COMMIT_TO_NEW_BRANCH) {
router.push(`/project/${rootState.currentProjectId}/blob/${branch}/${rootGetters.activeFile.path}`); router.push(
`/project/${rootState.currentProjectId}/blob/${branch}/${
rootGetters.activeFile.path
}`,
);
} }
dispatch('updateCommitAction', consts.COMMIT_TO_CURRENT_BRANCH); dispatch('updateCommitAction', consts.COMMIT_TO_CURRENT_BRANCH);
}; };
export const commitChanges = ({ commit, state, getters, dispatch, rootState }) => { export const commitChanges = ({
commit,
state,
getters,
dispatch,
rootState,
}) => {
const newBranch = state.commitAction !== consts.COMMIT_TO_CURRENT_BRANCH; const newBranch = state.commitAction !== consts.COMMIT_TO_CURRENT_BRANCH;
const payload = createCommitPayload(getters.branchName, newBranch, state, rootState); const payload = createCommitPayload(
const getCommitStatus = newBranch ? Promise.resolve(false) : dispatch('checkCommitStatus'); getters.branchName,
newBranch,
state,
rootState,
);
const getCommitStatus = newBranch
? Promise.resolve(false)
: dispatch('checkCommitStatus');
commit(types.UPDATE_LOADING, true); commit(types.UPDATE_LOADING, true);
return getCommitStatus.then(branchChanged => new Promise((resolve) => { return getCommitStatus
.then(
branchChanged =>
new Promise(resolve => {
if (branchChanged) { if (branchChanged) {
// show the modal with a Bootstrap call // show the modal with a Bootstrap call
$('#ide-create-branch-modal').modal('show'); $('#ide-create-branch-modal').modal('show');
} else { } else {
resolve(); resolve();
} }
})) }),
)
.then(() => service.commit(rootState.currentProjectId, payload)) .then(() => service.commit(rootState.currentProjectId, payload))
.then(({ data }) => { .then(({ data }) => {
commit(types.UPDATE_LOADING, false); commit(types.UPDATE_LOADING, false);
...@@ -150,10 +199,13 @@ export const commitChanges = ({ commit, state, getters, dispatch, rootState }) = ...@@ -150,10 +199,13 @@ export const commitChanges = ({ commit, state, getters, dispatch, rootState }) =
{ root: true }, { root: true },
); );
} else { } else {
dispatch('updateFilesAfterCommit', { data, branch: getters.branchName }); dispatch('updateFilesAfterCommit', {
data,
branch: getters.branchName,
});
} }
}) })
.catch((err) => { .catch(err => {
let errMsg = __('Error committing changes. Please try again.'); let errMsg = __('Error committing changes. Please try again.');
if (err.response.data && err.response.data.message) { if (err.response.data && err.response.data.message) {
errMsg += ` (${stripHtml(err.response.data.message)})`; errMsg += ` (${stripHtml(err.response.data.message)})`;
......
class IdeController < ApplicationController class IdeController < ApplicationController
layout 'nav_only' layout 'nav_only'
before_action :check_ide_available!
def index def index
end end
private
def check_ide_available!
render_404 unless License.feature_available?(:ide)
end
end end
...@@ -2,8 +2,6 @@ ...@@ -2,8 +2,6 @@
- @content_class = "limit-container-width" unless fluid_layout - @content_class = "limit-container-width" unless fluid_layout
= form_for @user, url: profile_preferences_path, remote: true, method: :put, html: { class: 'row prepend-top-default js-preferences-form' } do |f| = form_for @user, url: profile_preferences_path, remote: true, method: :put, html: { class: 'row prepend-top-default js-preferences-form' } do |f|
= render "profiles/preferences/ide", f: f
.col-lg-4.application-theme .col-lg-4.application-theme
%h4.prepend-top-0 %h4.prepend-top-0
GitLab navigation theme GitLab navigation theme
......
...@@ -78,11 +78,8 @@ ...@@ -78,11 +78,8 @@
= render 'projects/find_file_link' = render 'projects/find_file_link'
-## EE-specific
- if show_new_ide?(@project)
= succeed " " do = succeed " " do
= link_to ide_edit_path(@project, @id), class: 'btn btn-default' do = link_to ide_edit_path(@project, @id), class: 'btn btn-default' do
= _('Web IDE') = _('Web IDE')
-## EE-specific
= render 'projects/buttons/download', project: @project, ref: @ref = render 'projects/buttons/download', project: @project, ref: @ref
...@@ -77,10 +77,8 @@ Rails.application.routes.draw do ...@@ -77,10 +77,8 @@ Rails.application.routes.draw do
# UserCallouts # UserCallouts
resources :user_callouts, only: [:create] resources :user_callouts, only: [:create]
## EE-specific
get 'ide' => 'ide#index' get 'ide' => 'ide#index'
get 'ide/*vueroute' => 'ide#index', format: false get 'ide/*vueroute' => 'ide#index', format: false
## EE-specific
end end
# Koding route # Koding route
......
...@@ -9,12 +9,14 @@ const StatsWriterPlugin = require('webpack-stats-plugin').StatsWriterPlugin; ...@@ -9,12 +9,14 @@ const StatsWriterPlugin = require('webpack-stats-plugin').StatsWriterPlugin;
const CopyWebpackPlugin = require('copy-webpack-plugin'); const CopyWebpackPlugin = require('copy-webpack-plugin');
const CompressionPlugin = require('compression-webpack-plugin'); const CompressionPlugin = require('compression-webpack-plugin');
const NameAllModulesPlugin = require('name-all-modules-plugin'); const NameAllModulesPlugin = require('name-all-modules-plugin');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; const BundleAnalyzerPlugin = require('webpack-bundle-analyzer')
.BundleAnalyzerPlugin;
const WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin'); const WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin');
const ROOT_PATH = path.resolve(__dirname, '..'); const ROOT_PATH = path.resolve(__dirname, '..');
const IS_PRODUCTION = process.env.NODE_ENV === 'production'; const IS_PRODUCTION = process.env.NODE_ENV === 'production';
const IS_DEV_SERVER = process.argv.join(' ').indexOf('webpack-dev-server') !== -1; const IS_DEV_SERVER =
process.argv.join(' ').indexOf('webpack-dev-server') !== -1;
const DEV_SERVER_HOST = process.env.DEV_SERVER_HOST || 'localhost'; const DEV_SERVER_HOST = process.env.DEV_SERVER_HOST || 'localhost';
const DEV_SERVER_PORT = parseInt(process.env.DEV_SERVER_PORT, 10) || 3808; const DEV_SERVER_PORT = parseInt(process.env.DEV_SERVER_PORT, 10) || 3808;
const DEV_SERVER_LIVERELOAD = process.env.DEV_SERVER_LIVERELOAD !== 'false'; const DEV_SERVER_LIVERELOAD = process.env.DEV_SERVER_LIVERELOAD !== 'false';
...@@ -27,10 +29,10 @@ let watchAutoEntries = []; ...@@ -27,10 +29,10 @@ let watchAutoEntries = [];
function generateEntries() { function generateEntries() {
// generate automatic entry points // generate automatic entry points
const autoEntries = {}; const autoEntries = {};
const pageEntries = glob.sync('pages/**/index.js', { cwd: path.join(ROOT_PATH, 'app/assets/javascripts') }); const pageEntries = glob.sync('pages/**/index.js', {
watchAutoEntries = [ cwd: path.join(ROOT_PATH, 'app/assets/javascripts'),
path.join(ROOT_PATH, 'app/assets/javascripts/pages/'), });
]; watchAutoEntries = [path.join(ROOT_PATH, 'app/assets/javascripts/pages/')];
function generateAutoEntries(path, prefix = '.') { function generateAutoEntries(path, prefix = '.') {
const chunkPath = path.replace(/\/index\.js$/, ''); const chunkPath = path.replace(/\/index\.js$/, '');
...@@ -38,12 +40,16 @@ function generateEntries() { ...@@ -38,12 +40,16 @@ function generateEntries() {
autoEntries[chunkName] = `${prefix}/${path}`; autoEntries[chunkName] = `${prefix}/${path}`;
} }
pageEntries.forEach(( path ) => generateAutoEntries(path)); pageEntries.forEach(path => generateAutoEntries(path));
// EE-specific auto entries // EE-specific auto entries
const eePageEntries = glob.sync('pages/**/index.js', { cwd: path.join(ROOT_PATH, 'ee/app/assets/javascripts') }); const eePageEntries = glob.sync('pages/**/index.js', {
eePageEntries.forEach(( path ) => generateAutoEntries(path, 'ee')); cwd: path.join(ROOT_PATH, 'ee/app/assets/javascripts'),
watchAutoEntries.concat(path.join(ROOT_PATH, 'ee/app/assets/javascripts/pages/')); });
eePageEntries.forEach(path => generateAutoEntries(path, 'ee'));
watchAutoEntries.concat(
path.join(ROOT_PATH, 'ee/app/assets/javascripts/pages/'),
);
autoEntriesCount = Object.keys(autoEntries).length; autoEntriesCount = Object.keys(autoEntries).length;
...@@ -52,9 +58,7 @@ function generateEntries() { ...@@ -52,9 +58,7 @@ function generateEntries() {
main: './main.js', main: './main.js',
raven: './raven/index.js', raven: './raven/index.js',
webpack_runtime: './webpack.js', webpack_runtime: './webpack.js',
ide: './ide/index.js',
// EE-only
ide: 'ee/ide/index.js',
}; };
return Object.assign(manualEntries, autoEntries); return Object.assign(manualEntries, autoEntries);
...@@ -68,8 +72,12 @@ const config = { ...@@ -68,8 +72,12 @@ const config = {
output: { output: {
path: path.join(ROOT_PATH, 'public/assets/webpack'), path: path.join(ROOT_PATH, 'public/assets/webpack'),
publicPath: '/assets/webpack/', publicPath: '/assets/webpack/',
filename: IS_PRODUCTION ? '[name].[chunkhash].bundle.js' : '[name].bundle.js', filename: IS_PRODUCTION
chunkFilename: IS_PRODUCTION ? '[name].[chunkhash].chunk.js' : '[name].chunk.js', ? '[name].[chunkhash].bundle.js'
: '[name].bundle.js',
chunkFilename: IS_PRODUCTION
? '[name].[chunkhash].chunk.js'
: '[name].chunk.js',
}, },
module: { module: {
...@@ -98,8 +106,8 @@ const config = { ...@@ -98,8 +106,8 @@ const config = {
{ {
loader: 'worker-loader', loader: 'worker-loader',
options: { options: {
inline: true inline: true,
} },
}, },
{ loader: 'babel-loader' }, { loader: 'babel-loader' },
], ],
...@@ -110,7 +118,7 @@ const config = { ...@@ -110,7 +118,7 @@ const config = {
loader: 'file-loader', loader: 'file-loader',
options: { options: {
name: '[name].[hash].[ext]', name: '[name].[hash].[ext]',
} },
}, },
{ {
test: /katex.css$/, test: /katex.css$/,
...@@ -120,8 +128,8 @@ const config = { ...@@ -120,8 +128,8 @@ const config = {
{ {
loader: 'css-loader', loader: 'css-loader',
options: { options: {
name: '[name].[hash].[ext]' name: '[name].[hash].[ext]',
} },
}, },
], ],
}, },
...@@ -131,15 +139,18 @@ const config = { ...@@ -131,15 +139,18 @@ const config = {
loader: 'file-loader', loader: 'file-loader',
options: { options: {
name: '[name].[hash].[ext]', name: '[name].[hash].[ext]',
} },
}, },
{ {
test: /monaco-editor\/\w+\/vs\/loader\.js$/, test: /monaco-editor\/\w+\/vs\/loader\.js$/,
use: [ use: [
{ loader: 'exports-loader', options: 'l.global' }, { loader: 'exports-loader', options: 'l.global' },
{ loader: 'imports-loader', options: 'l=>{},this=>l,AMDLoader=>this,module=>undefined' }, {
loader: 'imports-loader',
options: 'l=>{},this=>l,AMDLoader=>this,module=>undefined',
},
], ],
} },
], ],
noParse: [/monaco-editor\/\w+\/vs\//], noParse: [/monaco-editor\/\w+\/vs\//],
...@@ -157,10 +168,10 @@ const config = { ...@@ -157,10 +168,10 @@ const config = {
source: false, source: false,
chunks: false, chunks: false,
modules: false, modules: false,
assets: true assets: true,
}); });
return JSON.stringify(stats, null, 2); return JSON.stringify(stats, null, 2);
} },
}), }),
// prevent pikaday from including moment.js // prevent pikaday from including moment.js
...@@ -177,7 +188,7 @@ const config = { ...@@ -177,7 +188,7 @@ const config = {
new NameAllModulesPlugin(), new NameAllModulesPlugin(),
// assign deterministic chunk ids // assign deterministic chunk ids
new webpack.NamedChunksPlugin((chunk) => { new webpack.NamedChunksPlugin(chunk => {
if (chunk.name) { if (chunk.name) {
return chunk.name; return chunk.name;
} }
...@@ -194,9 +205,12 @@ const config = { ...@@ -194,9 +205,12 @@ const config = {
const pagesBase = path.join(ROOT_PATH, 'app/assets/javascripts/pages'); const pagesBase = path.join(ROOT_PATH, 'app/assets/javascripts/pages');
if (m.resource.indexOf(pagesBase) === 0) { if (m.resource.indexOf(pagesBase) === 0) {
moduleNames.push(path.relative(pagesBase, m.resource) moduleNames.push(
path
.relative(pagesBase, m.resource)
.replace(/\/index\.[a-z]+$/, '') .replace(/\/index\.[a-z]+$/, '')
.replace(/\//g, '__')); .replace(/\//g, '__'),
);
} else { } else {
moduleNames.push(path.relative(m.context, m.resource)); moduleNames.push(path.relative(m.context, m.resource));
} }
...@@ -204,7 +218,8 @@ const config = { ...@@ -204,7 +218,8 @@ const config = {
chunk.forEachModule(collectModuleNames); chunk.forEachModule(collectModuleNames);
const hash = crypto.createHash('sha256') const hash = crypto
.createHash('sha256')
.update(moduleNames.join('_')) .update(moduleNames.join('_'))
.digest('hex'); .digest('hex');
...@@ -222,10 +237,17 @@ const config = { ...@@ -222,10 +237,17 @@ const config = {
// copy pre-compiled vendor libraries verbatim // copy pre-compiled vendor libraries verbatim
new CopyWebpackPlugin([ new CopyWebpackPlugin([
{ {
from: path.join(ROOT_PATH, `node_modules/monaco-editor/${IS_PRODUCTION ? 'min' : 'dev'}/vs`), from: path.join(
ROOT_PATH,
`node_modules/monaco-editor/${IS_PRODUCTION ? 'min' : 'dev'}/vs`,
),
to: 'monaco-editor/vs', to: 'monaco-editor/vs',
transform: function(content, path) { transform: function(content, path) {
if (/\.js$/.test(path) && !/worker/i.test(path) && !/typescript/i.test(path)) { if (
/\.js$/.test(path) &&
!/worker/i.test(path) &&
!/typescript/i.test(path)
) {
return ( return (
'(function(){\n' + '(function(){\n' +
'var define = this.define, require = this.require;\n' + 'var define = this.define, require = this.require;\n' +
...@@ -235,8 +257,8 @@ const config = { ...@@ -235,8 +257,8 @@ const config = {
); );
} }
return content; return content;
} },
} },
]), ]),
], ],
...@@ -244,20 +266,20 @@ const config = { ...@@ -244,20 +266,20 @@ const config = {
extensions: ['.js'], extensions: ['.js'],
alias: { alias: {
'~': path.join(ROOT_PATH, 'app/assets/javascripts'), '~': path.join(ROOT_PATH, 'app/assets/javascripts'),
'emojis': path.join(ROOT_PATH, 'fixtures/emojis'), emojis: path.join(ROOT_PATH, 'fixtures/emojis'),
'empty_states': path.join(ROOT_PATH, 'app/views/shared/empty_states'), empty_states: path.join(ROOT_PATH, 'app/views/shared/empty_states'),
'icons': path.join(ROOT_PATH, 'app/views/shared/icons'), icons: path.join(ROOT_PATH, 'app/views/shared/icons'),
'images': path.join(ROOT_PATH, 'app/assets/images'), images: path.join(ROOT_PATH, 'app/assets/images'),
'vendor': path.join(ROOT_PATH, 'vendor/assets/javascripts'), vendor: path.join(ROOT_PATH, 'vendor/assets/javascripts'),
'vue$': 'vue/dist/vue.esm.js', vue$: 'vue/dist/vue.esm.js',
'spec': path.join(ROOT_PATH, 'spec/javascripts'), spec: path.join(ROOT_PATH, 'spec/javascripts'),
// EE-only // EE-only
'ee': path.join(ROOT_PATH, 'ee/app/assets/javascripts'), ee: path.join(ROOT_PATH, 'ee/app/assets/javascripts'),
'ee_empty_states': path.join(ROOT_PATH, 'ee/app/views/shared/empty_states'), ee_empty_states: path.join(ROOT_PATH, 'ee/app/views/shared/empty_states'),
'ee_icons': path.join(ROOT_PATH, 'ee/app/views/shared/icons'), ee_icons: path.join(ROOT_PATH, 'ee/app/views/shared/icons'),
'ee_images': path.join(ROOT_PATH, 'ee/app/assets/images'), ee_images: path.join(ROOT_PATH, 'ee/app/assets/images'),
} },
}, },
// sqljs requires fs // sqljs requires fs
...@@ -272,14 +294,14 @@ if (IS_PRODUCTION) { ...@@ -272,14 +294,14 @@ if (IS_PRODUCTION) {
new webpack.NoEmitOnErrorsPlugin(), new webpack.NoEmitOnErrorsPlugin(),
new webpack.LoaderOptionsPlugin({ new webpack.LoaderOptionsPlugin({
minimize: true, minimize: true,
debug: false debug: false,
}), }),
new webpack.optimize.UglifyJsPlugin({ new webpack.optimize.UglifyJsPlugin({
sourceMap: true sourceMap: true,
}), }),
new webpack.DefinePlugin({ new webpack.DefinePlugin({
'process.env': { NODE_ENV: JSON.stringify('production') } 'process.env': { NODE_ENV: JSON.stringify('production') },
}) }),
); );
// compression can require a lot of compute time and is disabled in CI // compression can require a lot of compute time and is disabled in CI
...@@ -297,7 +319,7 @@ if (IS_DEV_SERVER) { ...@@ -297,7 +319,7 @@ if (IS_DEV_SERVER) {
headers: { 'Access-Control-Allow-Origin': '*' }, headers: { 'Access-Control-Allow-Origin': '*' },
stats: 'errors-only', stats: 'errors-only',
hot: DEV_SERVER_LIVERELOAD, hot: DEV_SERVER_LIVERELOAD,
inline: DEV_SERVER_LIVERELOAD inline: DEV_SERVER_LIVERELOAD,
}; };
config.plugins.push( config.plugins.push(
// watch node_modules for changes if we encounter a missing module compile error // watch node_modules for changes if we encounter a missing module compile error
...@@ -313,12 +335,14 @@ if (IS_DEV_SERVER) { ...@@ -313,12 +335,14 @@ if (IS_DEV_SERVER) {
]; ];
// report our auto-generated bundle count // report our auto-generated bundle count
console.log(`${autoEntriesCount} entries from '/pages' automatically added to webpack output.`); console.log(
`${autoEntriesCount} entries from '/pages' automatically added to webpack output.`,
);
callback(); callback();
}) });
},
}, },
}
); );
if (DEV_SERVER_LIVERELOAD) { if (DEV_SERVER_LIVERELOAD) {
config.plugins.push(new webpack.HotModuleReplacementPlugin()); config.plugins.push(new webpack.HotModuleReplacementPlugin());
...@@ -333,7 +357,7 @@ if (WEBPACK_REPORT) { ...@@ -333,7 +357,7 @@ if (WEBPACK_REPORT) {
openAnalyzer: false, openAnalyzer: false,
reportFilename: path.join(ROOT_PATH, 'webpack-report/index.html'), reportFilename: path.join(ROOT_PATH, 'webpack-report/index.html'),
statsFilename: path.join(ROOT_PATH, 'webpack-report/stats.json'), statsFilename: path.join(ROOT_PATH, 'webpack-report/stats.json'),
}) }),
); );
} }
......
module IdeHelper
def show_new_ide?(project)
cookies["new_repo"] == "true" && project.feature_available?(:ide)
end
def ide_edit_button(project = @project, ref = @ref, path = @path, options = {})
return unless show_new_ide?(project)
return unless blob = readable_blob(options, path, project, ref)
common_classes = "btn js-edit-ide #{options[:extra_class]}"
edit_button_tag(blob,
common_classes,
_('Web IDE'),
ide_edit_path(project, ref, path, options),
project,
ref)
end
end
- if License.feature_available?(:ide)
.col-lg-4
%h4.prepend-top-0
Web IDE (Beta)
%p
Enable the new web IDE on this device to make it possible to open and edit multiple files with a single commit.
- if Gitlab::CurrentSettings.should_check_namespace_plan?
Available for public GitLab.com projects or those using Gold.
.col-lg-8.multi-file-editor-options
= label_tag do
.preview.append-bottom-10= image_tag "multi-editor-off.png"
= f.radio_button :multi_file, "off", checked: true
Off
= label_tag do
.preview.append-bottom-10= image_tag "multi-editor-on.png"
= f.radio_button :multi_file, "on", checked: false
On
.col-sm-12
%hr
...@@ -5,13 +5,9 @@ feature 'Multi-file editor new directory', :js do ...@@ -5,13 +5,9 @@ feature 'Multi-file editor new directory', :js do
let(:project) { create(:project, :repository) } let(:project) { create(:project, :repository) }
before do before do
stub_licensed_features(ide: true)
project.add_master(user) project.add_master(user)
sign_in(user) sign_in(user)
set_cookie('new_repo', 'true')
visit project_tree_path(project, :master) visit project_tree_path(project, :master)
wait_for_requests wait_for_requests
......
...@@ -5,13 +5,9 @@ feature 'Multi-file editor new file', :js do ...@@ -5,13 +5,9 @@ feature 'Multi-file editor new file', :js do
let(:project) { create(:project, :repository) } let(:project) { create(:project, :repository) }
before do before do
stub_licensed_features(ide: true)
project.add_master(user) project.add_master(user)
sign_in(user) sign_in(user)
set_cookie('new_repo', 'true')
visit project_path(project) visit project_path(project)
wait_for_requests wait_for_requests
......
...@@ -7,13 +7,9 @@ feature 'Multi-file editor upload file', :js do ...@@ -7,13 +7,9 @@ feature 'Multi-file editor upload file', :js do
let(:img_file) { File.join(Rails.root, 'spec', 'fixtures', 'dk.png') } let(:img_file) { File.join(Rails.root, 'spec', 'fixtures', 'dk.png') }
before do before do
stub_licensed_features(ide: true)
project.add_master(user) project.add_master(user)
sign_in(user) sign_in(user)
set_cookie('new_repo', 'true')
visit project_tree_path(project, :master) visit project_tree_path(project, :master)
wait_for_requests wait_for_requests
......
import Vue from 'vue'; import Vue from 'vue';
import changedFileIcon from 'ee/ide/components/changed_file_icon.vue'; import changedFileIcon from '~/ide/components/changed_file_icon.vue';
import createComponent from 'spec/helpers/vue_mount_component_helper'; import createComponent from 'spec/helpers/vue_mount_component_helper';
describe('IDE changed file icon', () => { describe('IDE changed file icon', () => {
......
import Vue from 'vue'; import Vue from 'vue';
import store from 'ee/ide/stores'; import store from '~/ide/stores';
import commitActions from 'ee/ide/components/commit_sidebar/actions.vue'; import commitActions from '~/ide/components/commit_sidebar/actions.vue';
import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
import { resetStore } from 'spec/ide/helpers'; import { resetStore } from 'spec/ide/helpers';
describe('IDE commit sidebar actions', () => { describe('IDE commit sidebar actions', () => {
let vm; let vm;
beforeEach((done) => { beforeEach(done => {
const Component = Vue.extend(commitActions); const Component = Vue.extend(commitActions);
vm = createComponentWithStore(Component, store); vm = createComponentWithStore(Component, store);
......
import Vue from 'vue'; import Vue from 'vue';
import store from 'ee/ide/stores'; import store from '~/ide/stores';
import listCollapsed from 'ee/ide/components/commit_sidebar/list_collapsed.vue'; import listCollapsed from '~/ide/components/commit_sidebar/list_collapsed.vue';
import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
import { file } from '../../helpers'; import { file } from '../../helpers';
......
import Vue from 'vue'; import Vue from 'vue';
import listItem from 'ee/ide/components/commit_sidebar/list_item.vue'; import listItem from '~/ide/components/commit_sidebar/list_item.vue';
import router from 'ee/ide/ide_router'; import router from '~/ide/ide_router';
import mountComponent from 'spec/helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
import { file } from '../../helpers'; import { file } from '../../helpers';
...@@ -23,7 +23,9 @@ describe('Multi-file editor commit sidebar list item', () => { ...@@ -23,7 +23,9 @@ describe('Multi-file editor commit sidebar list item', () => {
}); });
it('renders file path', () => { it('renders file path', () => {
expect(vm.$el.querySelector('.multi-file-commit-list-path').textContent.trim()).toBe(f.path); expect(
vm.$el.querySelector('.multi-file-commit-list-path').textContent.trim(),
).toBe(f.path);
}); });
it('calls discardFileChanges when clicking discard button', () => { it('calls discardFileChanges when clicking discard button', () => {
......
import Vue from 'vue'; import Vue from 'vue';
import store from 'ee/ide/stores'; import store from '~/ide/stores';
import commitSidebarList from 'ee/ide/components/commit_sidebar/list.vue'; import commitSidebarList from '~/ide/components/commit_sidebar/list.vue';
import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
import { file } from '../../helpers'; import { file } from '../../helpers';
...@@ -25,7 +25,7 @@ describe('Multi-file editor commit sidebar list', () => { ...@@ -25,7 +25,7 @@ describe('Multi-file editor commit sidebar list', () => {
}); });
describe('with a list of files', () => { describe('with a list of files', () => {
beforeEach((done) => { beforeEach(done => {
const f = file('file name'); const f = file('file name');
f.changed = true; f.changed = true;
vm.fileList.push(f); vm.fileList.push(f);
...@@ -39,7 +39,7 @@ describe('Multi-file editor commit sidebar list', () => { ...@@ -39,7 +39,7 @@ describe('Multi-file editor commit sidebar list', () => {
}); });
describe('collapsed', () => { describe('collapsed', () => {
beforeEach((done) => { beforeEach(done => {
vm.$store.state.rightPanelCollapsed = true; vm.$store.state.rightPanelCollapsed = true;
Vue.nextTick(done); Vue.nextTick(done);
......
import Vue from 'vue'; import Vue from 'vue';
import store from 'ee/ide/stores'; import store from '~/ide/stores';
import radioGroup from 'ee/ide/components/commit_sidebar/radio_group.vue'; import radioGroup from '~/ide/components/commit_sidebar/radio_group.vue';
import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
import { resetStore } from 'spec/ide/helpers'; import { resetStore } from 'spec/ide/helpers';
describe('IDE commit sidebar radio group', () => { describe('IDE commit sidebar radio group', () => {
let vm; let vm;
beforeEach((done) => { beforeEach(done => {
const Component = Vue.extend(radioGroup); const Component = Vue.extend(radioGroup);
store.state.commit.commitAction = '2'; store.state.commit.commitAction = '2';
...@@ -33,7 +33,7 @@ describe('IDE commit sidebar radio group', () => { ...@@ -33,7 +33,7 @@ describe('IDE commit sidebar radio group', () => {
expect(vm.$el.textContent).toContain('test'); expect(vm.$el.textContent).toContain('test');
}); });
it('uses slot if label is not present', (done) => { it('uses slot if label is not present', done => {
vm.$destroy(); vm.$destroy();
vm = new Vue({ vm = new Vue({
...@@ -59,7 +59,7 @@ describe('IDE commit sidebar radio group', () => { ...@@ -59,7 +59,7 @@ describe('IDE commit sidebar radio group', () => {
}); });
}); });
it('updates store when changing radio button', (done) => { it('updates store when changing radio button', done => {
vm.$el.querySelector('input').dispatchEvent(new Event('change')); vm.$el.querySelector('input').dispatchEvent(new Event('change'));
Vue.nextTick(() => { Vue.nextTick(() => {
...@@ -69,7 +69,7 @@ describe('IDE commit sidebar radio group', () => { ...@@ -69,7 +69,7 @@ describe('IDE commit sidebar radio group', () => {
}); });
}); });
it('renders helpText tooltip', (done) => { it('renders helpText tooltip', done => {
vm.helpText = 'help text'; vm.helpText = 'help text';
Vue.nextTick(() => { Vue.nextTick(() => {
...@@ -83,7 +83,7 @@ describe('IDE commit sidebar radio group', () => { ...@@ -83,7 +83,7 @@ describe('IDE commit sidebar radio group', () => {
}); });
describe('with input', () => { describe('with input', () => {
beforeEach((done) => { beforeEach(done => {
vm.$destroy(); vm.$destroy();
const Component = Vue.extend(radioGroup); const Component = Vue.extend(radioGroup);
...@@ -106,7 +106,7 @@ describe('IDE commit sidebar radio group', () => { ...@@ -106,7 +106,7 @@ describe('IDE commit sidebar radio group', () => {
expect(vm.$el.querySelector('.form-control')).not.toBeNull(); expect(vm.$el.querySelector('.form-control')).not.toBeNull();
}); });
it('hides input when commitAction doesnt match value', (done) => { it('hides input when commitAction doesnt match value', done => {
store.state.commit.commitAction = '2'; store.state.commit.commitAction = '2';
Vue.nextTick(() => { Vue.nextTick(() => {
...@@ -115,7 +115,7 @@ describe('IDE commit sidebar radio group', () => { ...@@ -115,7 +115,7 @@ describe('IDE commit sidebar radio group', () => {
}); });
}); });
it('updates branch name in store on input', (done) => { it('updates branch name in store on input', done => {
const input = vm.$el.querySelector('.form-control'); const input = vm.$el.querySelector('.form-control');
input.value = 'testing-123'; input.value = 'testing-123';
input.dispatchEvent(new Event('input')); input.dispatchEvent(new Event('input'));
......
import Vue from 'vue'; import Vue from 'vue';
import store from 'ee/ide/stores'; import store from '~/ide/stores';
import ideContextBar from 'ee/ide/components/ide_context_bar.vue'; import ideContextBar from '~/ide/components/ide_context_bar.vue';
import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
describe('Multi-file editor right context bar', () => { describe('Multi-file editor right context bar', () => {
...@@ -24,7 +24,7 @@ describe('Multi-file editor right context bar', () => { ...@@ -24,7 +24,7 @@ describe('Multi-file editor right context bar', () => {
}); });
describe('collapsed', () => { describe('collapsed', () => {
beforeEach((done) => { beforeEach(done => {
vm.$store.state.rightPanelCollapsed = true; vm.$store.state.rightPanelCollapsed = true;
Vue.nextTick(done); Vue.nextTick(done);
......
import Vue from 'vue'; import Vue from 'vue';
import ideExternalLinks from 'ee/ide/components/ide_external_links.vue'; import ideExternalLinks from '~/ide/components/ide_external_links.vue';
import createComponent from 'spec/helpers/vue_mount_component_helper'; import createComponent from 'spec/helpers/vue_mount_component_helper';
describe('ide external links component', () => { describe('ide external links component', () => {
......
import Vue from 'vue'; import Vue from 'vue';
import ideRepoTree from 'ee/ide/components/ide_repo_tree.vue'; import ideRepoTree from '~/ide/components/ide_repo_tree.vue';
import createComponent from '../../helpers/vue_mount_component_helper'; import createComponent from '../../helpers/vue_mount_component_helper';
import { file } from '../helpers'; import { file } from '../helpers';
...@@ -29,11 +29,13 @@ describe('IdeRepoTree', () => { ...@@ -29,11 +29,13 @@ describe('IdeRepoTree', () => {
expect(vm.$el.querySelector('.file')).not.toBeNull(); expect(vm.$el.querySelector('.file')).not.toBeNull();
}); });
it('renders 3 loading files if tree is loading', (done) => { it('renders 3 loading files if tree is loading', done => {
tree.loading = true; tree.loading = true;
vm.$nextTick(() => { vm.$nextTick(() => {
expect(vm.$el.querySelectorAll('.multi-file-loading-container').length).toEqual(3); expect(
vm.$el.querySelectorAll('.multi-file-loading-container').length,
).toEqual(3);
done(); done();
}); });
......
import Vue from 'vue'; import Vue from 'vue';
import store from 'ee/ide/stores'; import store from '~/ide/stores';
import ideSidebar from 'ee/ide/components/ide_side_bar.vue'; import ideSidebar from '~/ide/components/ide_side_bar.vue';
import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
import { resetStore } from '../helpers'; import { resetStore } from '../helpers';
...@@ -20,15 +20,21 @@ describe('IdeSidebar', () => { ...@@ -20,15 +20,21 @@ describe('IdeSidebar', () => {
}); });
it('renders a sidebar', () => { it('renders a sidebar', () => {
expect(vm.$el.querySelector('.multi-file-commit-panel-inner')).not.toBeNull(); expect(
vm.$el.querySelector('.multi-file-commit-panel-inner'),
).not.toBeNull();
}); });
it('renders loading icon component', (done) => { it('renders loading icon component', done => {
vm.$store.state.loading = true; vm.$store.state.loading = true;
vm.$nextTick(() => { vm.$nextTick(() => {
expect(vm.$el.querySelector('.multi-file-loading-container')).not.toBeNull(); expect(
expect(vm.$el.querySelectorAll('.multi-file-loading-container').length).toBe(3); vm.$el.querySelector('.multi-file-loading-container'),
).not.toBeNull();
expect(
vm.$el.querySelectorAll('.multi-file-loading-container').length,
).toBe(3);
done(); done();
}); });
......
import Vue from 'vue'; import Vue from 'vue';
import store from 'ee/ide/stores'; import store from '~/ide/stores';
import ide from 'ee/ide/components/ide.vue'; import ide from '~/ide/components/ide.vue';
import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
import { file, resetStore } from '../helpers'; import { file, resetStore } from '../helpers';
...@@ -27,7 +27,7 @@ describe('ide component', () => { ...@@ -27,7 +27,7 @@ describe('ide component', () => {
expect(vm.$el.querySelector('.panel-right')).toBeNull(); expect(vm.$el.querySelector('.panel-right')).toBeNull();
}); });
it('renders panel right when files are open', (done) => { it('renders panel right when files are open', done => {
vm.$store.state.trees['abcproject/mybranch'] = { vm.$store.state.trees['abcproject/mybranch'] = {
tree: [file()], tree: [file()],
}; };
......
import Vue from 'vue'; import Vue from 'vue';
import store from 'ee/ide/stores'; import store from '~/ide/stores';
import newDropdown from 'ee/ide/components/new_dropdown/index.vue'; import newDropdown from '~/ide/components/new_dropdown/index.vue';
import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
import { resetStore } from '../../helpers'; import { resetStore } from '../../helpers';
......
import Vue from 'vue'; import Vue from 'vue';
import modal from 'ee/ide/components/new_dropdown/modal.vue'; import modal from '~/ide/components/new_dropdown/modal.vue';
import createComponent from 'spec/helpers/vue_mount_component_helper'; import createComponent from 'spec/helpers/vue_mount_component_helper';
describe('new file modal component', () => { describe('new file modal component', () => {
...@@ -10,7 +10,7 @@ describe('new file modal component', () => { ...@@ -10,7 +10,7 @@ describe('new file modal component', () => {
vm.$destroy(); vm.$destroy();
}); });
['tree', 'blob'].forEach((type) => { ['tree', 'blob'].forEach(type => {
describe(type, () => { describe(type, () => {
beforeEach(() => { beforeEach(() => {
vm = createComponent(Component, { vm = createComponent(Component, {
...@@ -25,19 +25,25 @@ describe('new file modal component', () => { ...@@ -25,19 +25,25 @@ describe('new file modal component', () => {
it(`sets modal title as ${type}`, () => { it(`sets modal title as ${type}`, () => {
const title = type === 'tree' ? 'directory' : 'file'; const title = type === 'tree' ? 'directory' : 'file';
expect(vm.$el.querySelector('.modal-title').textContent.trim()).toBe(`Create new ${title}`); expect(vm.$el.querySelector('.modal-title').textContent.trim()).toBe(
`Create new ${title}`,
);
}); });
it(`sets button label as ${type}`, () => { it(`sets button label as ${type}`, () => {
const title = type === 'tree' ? 'directory' : 'file'; const title = type === 'tree' ? 'directory' : 'file';
expect(vm.$el.querySelector('.btn-success').textContent.trim()).toBe(`Create ${title}`); expect(vm.$el.querySelector('.btn-success').textContent.trim()).toBe(
`Create ${title}`,
);
}); });
it(`sets form label as ${type}`, () => { it(`sets form label as ${type}`, () => {
const title = type === 'tree' ? 'Directory' : 'File'; const title = type === 'tree' ? 'Directory' : 'File';
expect(vm.$el.querySelector('.label-light').textContent.trim()).toBe(`${title} name`); expect(vm.$el.querySelector('.label-light').textContent.trim()).toBe(
`${title} name`,
);
}); });
describe('createEntryInStore', () => { describe('createEntryInStore', () => {
...@@ -59,11 +65,15 @@ describe('new file modal component', () => { ...@@ -59,11 +65,15 @@ describe('new file modal component', () => {
it('focuses field on mount', () => { it('focuses field on mount', () => {
document.body.innerHTML += '<div class="js-test"></div>'; document.body.innerHTML += '<div class="js-test"></div>';
vm = createComponent(Component, { vm = createComponent(
Component,
{
type: 'tree', type: 'tree',
branchId: 'master', branchId: 'master',
path: '', path: '',
}, '.js-test'); },
'.js-test',
);
expect(document.activeElement).toBe(vm.$refs.fieldName); expect(document.activeElement).toBe(vm.$refs.fieldName);
......
import Vue from 'vue'; import Vue from 'vue';
import upload from 'ee/ide/components/new_dropdown/upload.vue'; import upload from '~/ide/components/new_dropdown/upload.vue';
import createComponent from 'spec/helpers/vue_mount_component_helper'; import createComponent from 'spec/helpers/vue_mount_component_helper';
describe('new dropdown upload', () => { describe('new dropdown upload', () => {
......
import Vue from 'vue'; import Vue from 'vue';
import store from 'ee/ide/stores'; import store from '~/ide/stores';
import service from 'ee/ide/services'; import service from '~/ide/services';
import repoCommitSection from 'ee/ide/components/repo_commit_section.vue'; import repoCommitSection from '~/ide/components/repo_commit_section.vue';
import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
import getSetTimeoutPromise from 'spec/helpers/set_timeout_promise_helper'; import getSetTimeoutPromise from 'spec/helpers/set_timeout_promise_helper';
import { file, resetStore } from '../helpers'; import { file, resetStore } from '../helpers';
...@@ -31,22 +31,26 @@ describe('RepoCommitSection', () => { ...@@ -31,22 +31,26 @@ describe('RepoCommitSection', () => {
vm.$store.state.rightPanelCollapsed = false; vm.$store.state.rightPanelCollapsed = false;
vm.$store.state.currentBranch = 'master'; vm.$store.state.currentBranch = 'master';
vm.$store.state.changedFiles = [file('file1'), file('file2')]; vm.$store.state.changedFiles = [file('file1'), file('file2')];
vm.$store.state.changedFiles.forEach(f => Object.assign(f, { vm.$store.state.changedFiles.forEach(f =>
Object.assign(f, {
changed: true, changed: true,
content: 'testing', content: 'testing',
})); }),
);
return vm.$mount(); return vm.$mount();
} }
beforeEach((done) => { beforeEach(done => {
vm = createComponent(); vm = createComponent();
spyOn(service, 'getTreeData').and.returnValue(Promise.resolve({ spyOn(service, 'getTreeData').and.returnValue(
Promise.resolve({
headers: { headers: {
'page-title': 'test', 'page-title': 'test',
}, },
json: () => Promise.resolve({ json: () =>
Promise.resolve({
last_commit_path: 'last_commit_path', last_commit_path: 'last_commit_path',
parent_tree_url: 'parent_tree_url', parent_tree_url: 'parent_tree_url',
path: '/', path: '/',
...@@ -54,7 +58,8 @@ describe('RepoCommitSection', () => { ...@@ -54,7 +58,8 @@ describe('RepoCommitSection', () => {
blobs: [{ name: 'blob' }], blobs: [{ name: 'blob' }],
submodules: [{ name: 'submodule' }], submodules: [{ name: 'submodule' }],
}), }),
})); }),
);
Vue.nextTick(done); Vue.nextTick(done);
}); });
...@@ -75,27 +80,35 @@ describe('RepoCommitSection', () => { ...@@ -75,27 +80,35 @@ describe('RepoCommitSection', () => {
committedStateSvgPath: 'svg', committedStateSvgPath: 'svg',
}).$mount(); }).$mount();
expect(vm.$el.querySelector('.js-empty-state').textContent.trim()).toContain('No changes'); expect(
expect(vm.$el.querySelector('.js-empty-state img').getAttribute('src')).toBe('nochangessvg'); vm.$el.querySelector('.js-empty-state').textContent.trim(),
).toContain('No changes');
expect(
vm.$el.querySelector('.js-empty-state img').getAttribute('src'),
).toBe('nochangessvg');
}); });
}); });
it('renders a commit section', () => { it('renders a commit section', () => {
const changedFileElements = [...vm.$el.querySelectorAll('.multi-file-commit-list li')]; const changedFileElements = [
...vm.$el.querySelectorAll('.multi-file-commit-list li'),
];
const submitCommit = vm.$el.querySelector('form .btn'); const submitCommit = vm.$el.querySelector('form .btn');
expect(vm.$el.querySelector('.multi-file-commit-form')).not.toBeNull(); expect(vm.$el.querySelector('.multi-file-commit-form')).not.toBeNull();
expect(changedFileElements.length).toEqual(2); expect(changedFileElements.length).toEqual(2);
changedFileElements.forEach((changedFile, i) => { changedFileElements.forEach((changedFile, i) => {
expect(changedFile.textContent.trim()).toContain(vm.$store.state.changedFiles[i].path); expect(changedFile.textContent.trim()).toContain(
vm.$store.state.changedFiles[i].path,
);
}); });
expect(submitCommit.disabled).toBeTruthy(); expect(submitCommit.disabled).toBeTruthy();
expect(submitCommit.querySelector('.fa-spinner.fa-spin')).toBeNull(); expect(submitCommit.querySelector('.fa-spinner.fa-spin')).toBeNull();
}); });
it('updates commitMessage in store on input', (done) => { it('updates commitMessage in store on input', done => {
const textarea = vm.$el.querySelector('textarea'); const textarea = vm.$el.querySelector('textarea');
textarea.value = 'testing commit message'; textarea.value = 'testing commit message';
...@@ -104,7 +117,9 @@ describe('RepoCommitSection', () => { ...@@ -104,7 +117,9 @@ describe('RepoCommitSection', () => {
getSetTimeoutPromise() getSetTimeoutPromise()
.then(() => { .then(() => {
expect(vm.$store.state.commit.commitMessage).toBe('testing commit message'); expect(vm.$store.state.commit.commitMessage).toBe(
'testing commit message',
);
}) })
.then(done) .then(done)
.catch(done.fail); .catch(done.fail);
...@@ -112,10 +127,12 @@ describe('RepoCommitSection', () => { ...@@ -112,10 +127,12 @@ describe('RepoCommitSection', () => {
describe('discard draft button', () => { describe('discard draft button', () => {
it('hidden when commitMessage is empty', () => { it('hidden when commitMessage is empty', () => {
expect(vm.$el.querySelector('.multi-file-commit-form .btn-default')).toBeNull(); expect(
vm.$el.querySelector('.multi-file-commit-form .btn-default'),
).toBeNull();
}); });
it('resets commitMessage when clicking discard button', (done) => { it('resets commitMessage when clicking discard button', done => {
vm.$store.state.commit.commitMessage = 'testing commit message'; vm.$store.state.commit.commitMessage = 'testing commit message';
getSetTimeoutPromise() getSetTimeoutPromise()
...@@ -124,7 +141,9 @@ describe('RepoCommitSection', () => { ...@@ -124,7 +141,9 @@ describe('RepoCommitSection', () => {
}) })
.then(Vue.nextTick) .then(Vue.nextTick)
.then(() => { .then(() => {
expect(vm.$store.state.commit.commitMessage).not.toBe('testing commit message'); expect(vm.$store.state.commit.commitMessage).not.toBe(
'testing commit message',
);
}) })
.then(done) .then(done)
.catch(done.fail); .catch(done.fail);
...@@ -136,7 +155,7 @@ describe('RepoCommitSection', () => { ...@@ -136,7 +155,7 @@ describe('RepoCommitSection', () => {
spyOn(vm, 'commitChanges'); spyOn(vm, 'commitChanges');
}); });
it('calls commitChanges', (done) => { it('calls commitChanges', done => {
vm.$store.state.commit.commitMessage = 'testing commit message'; vm.$store.state.commit.commitMessage = 'testing commit message';
getSetTimeoutPromise() getSetTimeoutPromise()
......
import Vue from 'vue'; import Vue from 'vue';
import store from 'ee/ide/stores'; import store from '~/ide/stores';
import repoEditor from 'ee/ide/components/repo_editor.vue'; import repoEditor from '~/ide/components/repo_editor.vue';
import monacoLoader from 'ee/ide/monaco_loader'; import monacoLoader from '~/ide/monaco_loader';
import Editor from 'ee/ide/lib/editor'; import Editor from '~/ide/lib/editor';
import { createComponentWithStore } from '../../helpers/vue_mount_component_helper'; import { createComponentWithStore } from '../../helpers/vue_mount_component_helper';
import { file, resetStore } from '../helpers'; import { file, resetStore } from '../helpers';
describe('RepoEditor', () => { describe('RepoEditor', () => {
let vm; let vm;
beforeEach((done) => { beforeEach(done => {
const f = file(); const f = file();
const RepoEditor = Vue.extend(repoEditor); const RepoEditor = Vue.extend(repoEditor);
...@@ -39,7 +39,7 @@ describe('RepoEditor', () => { ...@@ -39,7 +39,7 @@ describe('RepoEditor', () => {
Editor.editorInstance.modelManager.dispose(); Editor.editorInstance.modelManager.dispose();
}); });
it('renders an ide container', (done) => { it('renders an ide container', done => {
Vue.nextTick(() => { Vue.nextTick(() => {
expect(vm.shouldHideEditor).toBeFalsy(); expect(vm.shouldHideEditor).toBeFalsy();
...@@ -48,7 +48,7 @@ describe('RepoEditor', () => { ...@@ -48,7 +48,7 @@ describe('RepoEditor', () => {
}); });
describe('when open file is binary and not raw', () => { describe('when open file is binary and not raw', () => {
beforeEach((done) => { beforeEach(done => {
vm.file.binary = true; vm.file.binary = true;
vm.$nextTick(done); vm.$nextTick(done);
...@@ -64,7 +64,7 @@ describe('RepoEditor', () => { ...@@ -64,7 +64,7 @@ describe('RepoEditor', () => {
}); });
describe('createEditorInstance', () => { describe('createEditorInstance', () => {
it('calls createInstance when viewer is editor', (done) => { it('calls createInstance when viewer is editor', done => {
spyOn(vm.editor, 'createInstance'); spyOn(vm.editor, 'createInstance');
vm.createEditorInstance(); vm.createEditorInstance();
...@@ -76,7 +76,7 @@ describe('RepoEditor', () => { ...@@ -76,7 +76,7 @@ describe('RepoEditor', () => {
}); });
}); });
it('calls createDiffInstance when viewer is diff', (done) => { it('calls createDiffInstance when viewer is diff', done => {
vm.$store.state.viewer = 'diff'; vm.$store.state.viewer = 'diff';
spyOn(vm.editor, 'createDiffInstance'); spyOn(vm.editor, 'createDiffInstance');
...@@ -124,7 +124,7 @@ describe('RepoEditor', () => { ...@@ -124,7 +124,7 @@ describe('RepoEditor', () => {
expect(vm.model.events.size).toBe(1); expect(vm.model.events.size).toBe(1);
}); });
it('updates state when model content changed', (done) => { it('updates state when model content changed', done => {
vm.model.setValue('testing 123'); vm.model.setValue('testing 123');
setTimeout(() => { setTimeout(() => {
......
import Vue from 'vue'; import Vue from 'vue';
import repoFileButtons from 'ee/ide/components/repo_file_buttons.vue'; import repoFileButtons from '~/ide/components/repo_file_buttons.vue';
import createVueComponent from '../../helpers/vue_mount_component_helper'; import createVueComponent from '../../helpers/vue_mount_component_helper';
import { file } from '../helpers'; import { file } from '../helpers';
...@@ -23,7 +23,7 @@ describe('RepoFileButtons', () => { ...@@ -23,7 +23,7 @@ describe('RepoFileButtons', () => {
vm.$destroy(); vm.$destroy();
}); });
it('renders Raw, Blame, History, Permalink and Preview toggle', (done) => { it('renders Raw, Blame, History, Permalink and Preview toggle', done => {
vm = createComponent(); vm = createComponent();
vm.$nextTick(() => { vm.$nextTick(() => {
...@@ -37,7 +37,9 @@ describe('RepoFileButtons', () => { ...@@ -37,7 +37,9 @@ describe('RepoFileButtons', () => {
expect(blame.textContent.trim()).toEqual('Blame'); expect(blame.textContent.trim()).toEqual('Blame');
expect(history.href).toMatch(`/${activeFile.commitsPath}`); expect(history.href).toMatch(`/${activeFile.commitsPath}`);
expect(history.textContent.trim()).toEqual('History'); expect(history.textContent.trim()).toEqual('History');
expect(vm.$el.querySelector('.permalink').textContent.trim()).toEqual('Permalink'); expect(vm.$el.querySelector('.permalink').textContent.trim()).toEqual(
'Permalink',
);
done(); done();
}); });
......
import Vue from 'vue'; import Vue from 'vue';
import store from 'ee/ide/stores'; import store from '~/ide/stores';
import repoFile from 'ee/ide/components/repo_file.vue'; import repoFile from '~/ide/components/repo_file.vue';
import router from 'ee/ide/ide_router'; import router from '~/ide/ide_router';
import { createComponentWithStore } from '../../helpers/vue_mount_component_helper'; import { createComponentWithStore } from '../../helpers/vue_mount_component_helper';
import { file } from '../helpers'; import { file } from '../helpers';
......
import Vue from 'vue'; import Vue from 'vue';
import store from 'ee/ide/stores'; import store from '~/ide/stores';
import repoLoadingFile from 'ee/ide/components/repo_loading_file.vue'; import repoLoadingFile from '~/ide/components/repo_loading_file.vue';
import { resetStore } from '../helpers'; import { resetStore } from '../helpers';
describe('RepoLoadingFile', () => { describe('RepoLoadingFile', () => {
...@@ -22,7 +22,7 @@ describe('RepoLoadingFile', () => { ...@@ -22,7 +22,7 @@ describe('RepoLoadingFile', () => {
} }
function assertColumns(columns) { function assertColumns(columns) {
columns.forEach((column) => { columns.forEach(column => {
const container = column.querySelector('.animation-container'); const container = column.querySelector('.animation-container');
const lines = [...container.querySelectorAll(':scope > div')]; const lines = [...container.querySelectorAll(':scope > div')];
...@@ -46,7 +46,7 @@ describe('RepoLoadingFile', () => { ...@@ -46,7 +46,7 @@ describe('RepoLoadingFile', () => {
assertColumns(columns); assertColumns(columns);
}); });
it('renders 1 column of animated LoC if isMini', (done) => { it('renders 1 column of animated LoC if isMini', done => {
vm = createComponent(); vm = createComponent();
vm.$store.state.leftPanelCollapsed = true; vm.$store.state.leftPanelCollapsed = true;
vm.$store.state.openFiles.push('test'); vm.$store.state.openFiles.push('test');
......
import Vue from 'vue'; import Vue from 'vue';
import store from 'ee/ide/stores'; import store from '~/ide/stores';
import repoTab from 'ee/ide/components/repo_tab.vue'; import repoTab from '~/ide/components/repo_tab.vue';
import router from 'ee/ide/ide_router'; import router from '~/ide/ide_router';
import { file, resetStore } from '../helpers'; import { file, resetStore } from '../helpers';
describe('RepoTab', () => { describe('RepoTab', () => {
...@@ -62,7 +62,7 @@ describe('RepoTab', () => { ...@@ -62,7 +62,7 @@ describe('RepoTab', () => {
expect(vm.closeFile).toHaveBeenCalledWith(vm.tab.path); expect(vm.closeFile).toHaveBeenCalledWith(vm.tab.path);
}); });
it('changes icon on hover', (done) => { it('changes icon on hover', done => {
const tab = file(); const tab = file();
tab.changed = true; tab.changed = true;
vm = createComponent({ vm = createComponent({
...@@ -112,13 +112,15 @@ describe('RepoTab', () => { ...@@ -112,13 +112,15 @@ describe('RepoTab', () => {
}); });
it('renders a tooltip', () => { it('renders a tooltip', () => {
expect(vm.$el.querySelector('span:nth-child(2)').dataset.originalTitle).toContain('Locked by testuser'); expect(
vm.$el.querySelector('span:nth-child(2)').dataset.originalTitle,
).toContain('Locked by testuser');
}); });
}); });
describe('methods', () => { describe('methods', () => {
describe('closeTab', () => { describe('closeTab', () => {
it('closes tab if file has changed', (done) => { it('closes tab if file has changed', done => {
const tab = file(); const tab = file();
tab.changed = true; tab.changed = true;
tab.opened = true; tab.opened = true;
...@@ -140,7 +142,7 @@ describe('RepoTab', () => { ...@@ -140,7 +142,7 @@ describe('RepoTab', () => {
}); });
}); });
it('closes tab when clicking close btn', (done) => { it('closes tab when clicking close btn', done => {
const tab = file('lose'); const tab = file('lose');
tab.opened = true; tab.opened = true;
vm = createComponent({ vm = createComponent({
......
import Vue from 'vue'; import Vue from 'vue';
import repoTabs from 'ee/ide/components/repo_tabs.vue'; import repoTabs from '~/ide/components/repo_tabs.vue';
import createComponent from '../../helpers/vue_mount_component_helper'; import createComponent from '../../helpers/vue_mount_component_helper';
import { file } from '../helpers'; import { file } from '../helpers';
......
import { decorateData } from 'ee/ide/stores/utils'; import { decorateData } from '~/ide/stores/utils';
import state from 'ee/ide/stores/state'; import state from '~/ide/stores/state';
import commitState from 'ee/ide/stores/modules/commit/state'; import commitState from '~/ide/stores/modules/commit/state';
export const resetStore = (store) => { export const resetStore = store => {
const newState = { const newState = {
...state(), ...state(),
commit: commitState(), commit: commitState(),
...@@ -10,7 +10,8 @@ export const resetStore = (store) => { ...@@ -10,7 +10,8 @@ export const resetStore = (store) => {
store.replaceState(newState); store.replaceState(newState);
}; };
export const file = (name = 'name', id = name, type = '') => decorateData({ export const file = (name = 'name', id = name, type = '') =>
decorateData({
id, id,
type, type,
icon: 'icon', icon: 'icon',
...@@ -18,4 +19,4 @@ export const file = (name = 'name', id = name, type = '') => decorateData({ ...@@ -18,4 +19,4 @@ export const file = (name = 'name', id = name, type = '') => decorateData({
name, name,
path: name, path: name,
lastCommit: {}, lastCommit: {},
}); });
import Disposable from 'ee/ide/lib/common/disposable'; import Disposable from '~/ide/lib/common/disposable';
describe('Multi-file editor library disposable class', () => { describe('Multi-file editor library disposable class', () => {
let instance; let instance;
......
/* global monaco */ /* global monaco */
import eventHub from 'ee/ide/eventhub'; import eventHub from '~/ide/eventhub';
import monacoLoader from 'ee/ide/monaco_loader'; import monacoLoader from '~/ide/monaco_loader';
import ModelManager from 'ee/ide/lib/common/model_manager'; import ModelManager from '~/ide/lib/common/model_manager';
import { file } from '../../helpers'; import { file } from '../../helpers';
describe('Multi-file editor library model manager', () => { describe('Multi-file editor library model manager', () => {
let instance; let instance;
beforeEach((done) => { beforeEach(done => {
monacoLoader(['vs/editor/editor.main'], () => { monacoLoader(['vs/editor/editor.main'], () => {
instance = new ModelManager(monaco); instance = new ModelManager(monaco);
...@@ -55,7 +55,10 @@ describe('Multi-file editor library model manager', () => { ...@@ -55,7 +55,10 @@ describe('Multi-file editor library model manager', () => {
instance.addModel(f); instance.addModel(f);
expect(eventHub.$on).toHaveBeenCalledWith(`editor.update.model.dispose.${f.path}`, jasmine.anything()); expect(eventHub.$on).toHaveBeenCalledWith(
`editor.update.model.dispose.${f.path}`,
jasmine.anything(),
);
}); });
}); });
...@@ -99,7 +102,10 @@ describe('Multi-file editor library model manager', () => { ...@@ -99,7 +102,10 @@ describe('Multi-file editor library model manager', () => {
instance.removeCachedModel(f); instance.removeCachedModel(f);
expect(eventHub.$off).toHaveBeenCalledWith(`editor.update.model.dispose.${f.path}`, jasmine.anything()); expect(eventHub.$off).toHaveBeenCalledWith(
`editor.update.model.dispose.${f.path}`,
jasmine.anything(),
);
}); });
}); });
......
/* global monaco */ /* global monaco */
import eventHub from 'ee/ide/eventhub'; import eventHub from '~/ide/eventhub';
import monacoLoader from 'ee/ide/monaco_loader'; import monacoLoader from '~/ide/monaco_loader';
import Model from 'ee/ide/lib/common/model'; import Model from '~/ide/lib/common/model';
import { file } from '../../helpers'; import { file } from '../../helpers';
describe('Multi-file editor library model', () => { describe('Multi-file editor library model', () => {
let model; let model;
beforeEach((done) => { beforeEach(done => {
spyOn(eventHub, '$on').and.callThrough(); spyOn(eventHub, '$on').and.callThrough();
monacoLoader(['vs/editor/editor.main'], () => { monacoLoader(['vs/editor/editor.main'], () => {
...@@ -27,7 +27,10 @@ describe('Multi-file editor library model', () => { ...@@ -27,7 +27,10 @@ describe('Multi-file editor library model', () => {
}); });
it('adds eventHub listener', () => { it('adds eventHub listener', () => {
expect(eventHub.$on).toHaveBeenCalledWith(`editor.update.model.dispose.${model.file.path}`, jasmine.anything()); expect(eventHub.$on).toHaveBeenCalledWith(
`editor.update.model.dispose.${model.file.path}`,
jasmine.anything(),
);
}); });
describe('path', () => { describe('path', () => {
...@@ -64,7 +67,7 @@ describe('Multi-file editor library model', () => { ...@@ -64,7 +67,7 @@ describe('Multi-file editor library model', () => {
expect(model.events.keys().next().value).toBe('path'); expect(model.events.keys().next().value).toBe('path');
}); });
it('calls callback on change', (done) => { it('calls callback on change', done => {
const spy = jasmine.createSpy(); const spy = jasmine.createSpy();
model.onChange(spy); model.onChange(spy);
...@@ -101,7 +104,10 @@ describe('Multi-file editor library model', () => { ...@@ -101,7 +104,10 @@ describe('Multi-file editor library model', () => {
model.dispose(); model.dispose();
expect(eventHub.$off).toHaveBeenCalledWith(`editor.update.model.dispose.${model.file.path}`, jasmine.anything()); expect(eventHub.$off).toHaveBeenCalledWith(
`editor.update.model.dispose.${model.file.path}`,
jasmine.anything(),
);
}); });
}); });
}); });
/* global monaco */ /* global monaco */
import monacoLoader from 'ee/ide/monaco_loader'; import monacoLoader from '~/ide/monaco_loader';
import editor from 'ee/ide/lib/editor'; import editor from '~/ide/lib/editor';
import DecorationsController from 'ee/ide/lib/decorations/controller'; import DecorationsController from '~/ide/lib/decorations/controller';
import Model from 'ee/ide/lib/common/model'; import Model from '~/ide/lib/common/model';
import { file } from '../../helpers'; import { file } from '../../helpers';
describe('Multi-file editor library decorations controller', () => { describe('Multi-file editor library decorations controller', () => {
...@@ -10,7 +10,7 @@ describe('Multi-file editor library decorations controller', () => { ...@@ -10,7 +10,7 @@ describe('Multi-file editor library decorations controller', () => {
let controller; let controller;
let model; let model;
beforeEach((done) => { beforeEach(done => {
monacoLoader(['vs/editor/editor.main'], () => { monacoLoader(['vs/editor/editor.main'], () => {
editorInstance = editor.create(monaco); editorInstance = editor.create(monaco);
editorInstance.createInstance(document.createElement('div')); editorInstance.createInstance(document.createElement('div'));
...@@ -36,7 +36,9 @@ describe('Multi-file editor library decorations controller', () => { ...@@ -36,7 +36,9 @@ describe('Multi-file editor library decorations controller', () => {
}); });
it('returns decorations by model URL', () => { it('returns decorations by model URL', () => {
controller.addDecorations(model, 'key', [{ decoration: 'decorationValue' }]); controller.addDecorations(model, 'key', [
{ decoration: 'decorationValue' },
]);
const decorations = controller.getAllDecorationsForModel(model); const decorations = controller.getAllDecorationsForModel(model);
...@@ -46,20 +48,28 @@ describe('Multi-file editor library decorations controller', () => { ...@@ -46,20 +48,28 @@ describe('Multi-file editor library decorations controller', () => {
describe('addDecorations', () => { describe('addDecorations', () => {
it('caches decorations in a new map', () => { it('caches decorations in a new map', () => {
controller.addDecorations(model, 'key', [{ decoration: 'decorationValue' }]); controller.addDecorations(model, 'key', [
{ decoration: 'decorationValue' },
]);
expect(controller.decorations.size).toBe(1); expect(controller.decorations.size).toBe(1);
}); });
it('does not create new cache model', () => { it('does not create new cache model', () => {
controller.addDecorations(model, 'key', [{ decoration: 'decorationValue' }]); controller.addDecorations(model, 'key', [
controller.addDecorations(model, 'key', [{ decoration: 'decorationValue2' }]); { decoration: 'decorationValue' },
]);
controller.addDecorations(model, 'key', [
{ decoration: 'decorationValue2' },
]);
expect(controller.decorations.size).toBe(1); expect(controller.decorations.size).toBe(1);
}); });
it('caches decorations by model URL', () => { it('caches decorations by model URL', () => {
controller.addDecorations(model, 'key', [{ decoration: 'decorationValue' }]); controller.addDecorations(model, 'key', [
{ decoration: 'decorationValue' },
]);
expect(controller.decorations.size).toBe(1); expect(controller.decorations.size).toBe(1);
expect(controller.decorations.keys().next().value).toBe('path'); expect(controller.decorations.keys().next().value).toBe('path');
...@@ -68,7 +78,9 @@ describe('Multi-file editor library decorations controller', () => { ...@@ -68,7 +78,9 @@ describe('Multi-file editor library decorations controller', () => {
it('calls decorate method', () => { it('calls decorate method', () => {
spyOn(controller, 'decorate'); spyOn(controller, 'decorate');
controller.addDecorations(model, 'key', [{ decoration: 'decorationValue' }]); controller.addDecorations(model, 'key', [
{ decoration: 'decorationValue' },
]);
expect(controller.decorate).toHaveBeenCalled(); expect(controller.decorate).toHaveBeenCalled();
}); });
...@@ -80,7 +92,10 @@ describe('Multi-file editor library decorations controller', () => { ...@@ -80,7 +92,10 @@ describe('Multi-file editor library decorations controller', () => {
controller.decorate(model); controller.decorate(model);
expect(controller.editor.instance.deltaDecorations).toHaveBeenCalledWith([], []); expect(controller.editor.instance.deltaDecorations).toHaveBeenCalledWith(
[],
[],
);
}); });
it('caches decorations', () => { it('caches decorations', () => {
...@@ -102,7 +117,9 @@ describe('Multi-file editor library decorations controller', () => { ...@@ -102,7 +117,9 @@ describe('Multi-file editor library decorations controller', () => {
describe('dispose', () => { describe('dispose', () => {
it('clears cached decorations', () => { it('clears cached decorations', () => {
controller.addDecorations(model, 'key', [{ decoration: 'decorationValue' }]); controller.addDecorations(model, 'key', [
{ decoration: 'decorationValue' },
]);
controller.dispose(); controller.dispose();
...@@ -110,7 +127,9 @@ describe('Multi-file editor library decorations controller', () => { ...@@ -110,7 +127,9 @@ describe('Multi-file editor library decorations controller', () => {
}); });
it('clears cached editorDecorations', () => { it('clears cached editorDecorations', () => {
controller.addDecorations(model, 'key', [{ decoration: 'decorationValue' }]); controller.addDecorations(model, 'key', [
{ decoration: 'decorationValue' },
]);
controller.dispose(); controller.dispose();
......
/* global monaco */ /* global monaco */
import monacoLoader from 'ee/ide/monaco_loader'; import monacoLoader from '~/ide/monaco_loader';
import editor from 'ee/ide/lib/editor'; import editor from '~/ide/lib/editor';
import ModelManager from 'ee/ide/lib/common/model_manager'; import ModelManager from '~/ide/lib/common/model_manager';
import DecorationsController from 'ee/ide/lib/decorations/controller'; import DecorationsController from '~/ide/lib/decorations/controller';
import DirtyDiffController, { getDiffChangeType, getDecorator } from 'ee/ide/lib/diff/controller'; import DirtyDiffController, {
import { computeDiff } from 'ee/ide/lib/diff/diff'; getDiffChangeType,
getDecorator,
} from '~/ide/lib/diff/controller';
import { computeDiff } from '~/ide/lib/diff/diff';
import { file } from '../../helpers'; import { file } from '../../helpers';
describe('Multi-file editor library dirty diff controller', () => { describe('Multi-file editor library dirty diff controller', () => {
...@@ -14,7 +17,7 @@ describe('Multi-file editor library dirty diff controller', () => { ...@@ -14,7 +17,7 @@ describe('Multi-file editor library dirty diff controller', () => {
let decorationsController; let decorationsController;
let model; let model;
beforeEach((done) => { beforeEach(done => {
monacoLoader(['vs/editor/editor.main'], () => { monacoLoader(['vs/editor/editor.main'], () => {
editorInstance = editor.create(monaco); editorInstance = editor.create(monaco);
editorInstance.createInstance(document.createElement('div')); editorInstance.createInstance(document.createElement('div'));
...@@ -38,7 +41,7 @@ describe('Multi-file editor library dirty diff controller', () => { ...@@ -38,7 +41,7 @@ describe('Multi-file editor library dirty diff controller', () => {
}); });
describe('getDiffChangeType', () => { describe('getDiffChangeType', () => {
['added', 'removed', 'modified'].forEach((type) => { ['added', 'removed', 'modified'].forEach(type => {
it(`returns ${type}`, () => { it(`returns ${type}`, () => {
const change = { const change = {
[type]: true, [type]: true,
...@@ -50,15 +53,15 @@ describe('Multi-file editor library dirty diff controller', () => { ...@@ -50,15 +53,15 @@ describe('Multi-file editor library dirty diff controller', () => {
}); });
describe('getDecorator', () => { describe('getDecorator', () => {
['added', 'removed', 'modified'].forEach((type) => { ['added', 'removed', 'modified'].forEach(type => {
it(`returns with linesDecorationsClassName for ${type}`, () => { it(`returns with linesDecorationsClassName for ${type}`, () => {
const change = { const change = {
[type]: true, [type]: true,
}; };
expect( expect(getDecorator(change).options.linesDecorationsClassName).toBe(
getDecorator(change).options.linesDecorationsClassName, `dirty-diff dirty-diff-${type}`,
).toBe(`dirty-diff dirty-diff-${type}`); );
}); });
it('returns with line numbers', () => { it('returns with line numbers', () => {
...@@ -118,7 +121,9 @@ describe('Multi-file editor library dirty diff controller', () => { ...@@ -118,7 +121,9 @@ describe('Multi-file editor library dirty diff controller', () => {
controller.reDecorate(model); controller.reDecorate(model);
expect(controller.decorationsController.decorate).toHaveBeenCalledWith(model); expect(controller.decorationsController.decorate).toHaveBeenCalledWith(
model,
);
}); });
}); });
...@@ -128,23 +133,33 @@ describe('Multi-file editor library dirty diff controller', () => { ...@@ -128,23 +133,33 @@ describe('Multi-file editor library dirty diff controller', () => {
controller.decorate({ data: { changes: [], path: 'path' } }); controller.decorate({ data: { changes: [], path: 'path' } });
expect(controller.decorationsController.addDecorations).toHaveBeenCalledWith(model, 'dirtyDiff', jasmine.anything()); expect(
controller.decorationsController.addDecorations,
).toHaveBeenCalledWith(model, 'dirtyDiff', jasmine.anything());
}); });
it('adds decorations into editor', () => { it('adds decorations into editor', () => {
const spy = spyOn(controller.decorationsController.editor.instance, 'deltaDecorations'); const spy = spyOn(
controller.decorationsController.editor.instance,
'deltaDecorations',
);
controller.decorate({ data: { changes: computeDiff('123', '1234'), path: 'path' } }); controller.decorate({
data: { changes: computeDiff('123', '1234'), path: 'path' },
});
expect(spy).toHaveBeenCalledWith([], [{ expect(spy).toHaveBeenCalledWith(
range: new monaco.Range( [],
1, 1, 1, 1, [
), {
range: new monaco.Range(1, 1, 1, 1),
options: { options: {
isWholeLine: true, isWholeLine: true,
linesDecorationsClassName: 'dirty-diff dirty-diff-modified', linesDecorationsClassName: 'dirty-diff dirty-diff-modified',
}, },
}]); },
],
);
}); });
}); });
...@@ -166,11 +181,16 @@ describe('Multi-file editor library dirty diff controller', () => { ...@@ -166,11 +181,16 @@ describe('Multi-file editor library dirty diff controller', () => {
}); });
it('removes worker event listener', () => { it('removes worker event listener', () => {
spyOn(controller.dirtyDiffWorker, 'removeEventListener').and.callThrough(); spyOn(
controller.dirtyDiffWorker,
'removeEventListener',
).and.callThrough();
controller.dispose(); controller.dispose();
expect(controller.dirtyDiffWorker.removeEventListener).toHaveBeenCalledWith('message', jasmine.anything()); expect(
controller.dirtyDiffWorker.removeEventListener,
).toHaveBeenCalledWith('message', jasmine.anything());
}); });
}); });
}); });
import { computeDiff } from 'ee/ide/lib/diff/diff'; import { computeDiff } from '~/ide/lib/diff/diff';
describe('Multi-file editor library diff calculator', () => { describe('Multi-file editor library diff calculator', () => {
describe('computeDiff', () => { describe('computeDiff', () => {
......
import editorOptions from 'ee/ide/lib/editor_options'; import editorOptions from '~/ide/lib/editor_options';
describe('Multi-file editor library editor options', () => { describe('Multi-file editor library editor options', () => {
it('returns an array', () => { it('returns an array', () => {
......
/* global monaco */ /* global monaco */
import monacoLoader from 'ee/ide/monaco_loader'; import monacoLoader from '~/ide/monaco_loader';
import editor from 'ee/ide/lib/editor'; import editor from '~/ide/lib/editor';
import { file } from '../helpers'; import { file } from '../helpers';
describe('Multi-file editor library', () => { describe('Multi-file editor library', () => {
......
import monacoContext from 'monaco-editor/dev/vs/loader'; import monacoContext from 'monaco-editor/dev/vs/loader';
import monacoLoader from 'ee/ide/monaco_loader'; import monacoLoader from '~/ide/monaco_loader';
describe('MonacoLoader', () => { describe('MonacoLoader', () => {
it('calls require.config and exports require', () => { it('calls require.config and exports require', () => {
expect(monacoContext.require.getConfig()).toEqual(jasmine.objectContaining({ expect(monacoContext.require.getConfig()).toEqual(
jasmine.objectContaining({
paths: { paths: {
vs: `${__webpack_public_path__}monaco-editor/vs`, // eslint-disable-line camelcase vs: `${__webpack_public_path__}monaco-editor/vs`, // eslint-disable-line camelcase
}, },
})); }),
);
expect(monacoLoader).toBe(monacoContext.require); expect(monacoLoader).toBe(monacoContext.require);
}); });
}); });
import Vue from 'vue'; import Vue from 'vue';
import store from 'ee/ide/stores'; import store from '~/ide/stores';
import service from 'ee/ide/services'; import service from '~/ide/services';
import router from 'ee/ide/ide_router'; import router from '~/ide/ide_router';
import eventHub from 'ee/ide/eventhub'; import eventHub from '~/ide/eventhub';
import { file, resetStore } from '../../helpers'; import { file, resetStore } from '../../helpers';
describe('Multi-file store file actions', () => { describe('Multi-file store file actions', () => {
......
import Vue from 'vue'; import Vue from 'vue';
import store from 'ee/ide/stores'; import store from '~/ide/stores';
import service from 'ee/ide/services'; import service from '~/ide/services';
import router from 'ee/ide/ide_router'; import router from '~/ide/ide_router';
import { file, resetStore } from '../../helpers'; import { file, resetStore } from '../../helpers';
describe('Multi-file store tree actions', () => { describe('Multi-file store tree actions', () => {
...@@ -35,26 +35,32 @@ describe('Multi-file store tree actions', () => { ...@@ -35,26 +35,32 @@ describe('Multi-file store tree actions', () => {
describe('getFiles', () => { describe('getFiles', () => {
beforeEach(() => { beforeEach(() => {
spyOn(service, 'getFiles').and.returnValue(Promise.resolve({ spyOn(service, 'getFiles').and.returnValue(
json: () => Promise.resolve([ Promise.resolve({
json: () =>
Promise.resolve([
'file.txt', 'file.txt',
'folder/fileinfolder.js', 'folder/fileinfolder.js',
'folder/subfolder/fileinsubfolder.js', 'folder/subfolder/fileinsubfolder.js',
]), ]),
})); }),
);
}); });
it('calls service getFiles', (done) => { it('calls service getFiles', done => {
store.dispatch('getFiles', basicCallParameters) store
.dispatch('getFiles', basicCallParameters)
.then(() => { .then(() => {
expect(service.getFiles).toHaveBeenCalledWith('', 'master'); expect(service.getFiles).toHaveBeenCalledWith('', 'master');
done(); done();
}).catch(done.fail); })
.catch(done.fail);
}); });
it('adds data into tree', (done) => { it('adds data into tree', done => {
store.dispatch('getFiles', basicCallParameters) store
.dispatch('getFiles', basicCallParameters)
.then(() => { .then(() => {
projectTree = store.state.trees['abcproject/master']; projectTree = store.state.trees['abcproject/master'];
expect(projectTree.tree.length).toBe(2); expect(projectTree.tree.length).toBe(2);
...@@ -62,10 +68,13 @@ describe('Multi-file store tree actions', () => { ...@@ -62,10 +68,13 @@ describe('Multi-file store tree actions', () => {
expect(projectTree.tree[0].tree[1].name).toBe('fileinfolder.js'); expect(projectTree.tree[0].tree[1].name).toBe('fileinfolder.js');
expect(projectTree.tree[1].type).toBe('blob'); expect(projectTree.tree[1].type).toBe('blob');
expect(projectTree.tree[0].tree[0].tree[0].type).toBe('blob'); expect(projectTree.tree[0].tree[0].tree[0].type).toBe('blob');
expect(projectTree.tree[0].tree[0].tree[0].name).toBe('fileinsubfolder.js'); expect(projectTree.tree[0].tree[0].tree[0].name).toBe(
'fileinsubfolder.js',
);
done(); done();
}).catch(done.fail); })
.catch(done.fail);
}); });
}); });
...@@ -77,30 +86,38 @@ describe('Multi-file store tree actions', () => { ...@@ -77,30 +86,38 @@ describe('Multi-file store tree actions', () => {
store.state.entries[tree.path] = tree; store.state.entries[tree.path] = tree;
}); });
it('toggles the tree open', (done) => { it('toggles the tree open', done => {
store.dispatch('toggleTreeOpen', tree.path).then(() => { store
.dispatch('toggleTreeOpen', tree.path)
.then(() => {
expect(tree.opened).toBeTruthy(); expect(tree.opened).toBeTruthy();
done(); done();
}).catch(done.fail); })
.catch(done.fail);
}); });
}); });
describe('getLastCommitData', () => { describe('getLastCommitData', () => {
beforeEach(() => { beforeEach(() => {
spyOn(service, 'getTreeLastCommit').and.returnValue(Promise.resolve({ spyOn(service, 'getTreeLastCommit').and.returnValue(
Promise.resolve({
headers: { headers: {
'more-logs-url': null, 'more-logs-url': null,
}, },
json: () => Promise.resolve([{ json: () =>
Promise.resolve([
{
type: 'tree', type: 'tree',
file_name: 'testing', file_name: 'testing',
commit: { commit: {
message: 'commit message', message: 'commit message',
authored_date: '123', authored_date: '123',
}, },
}]), },
})); ]),
}),
);
store.state.trees['abcproject/mybranch'] = { store.state.trees['abcproject/mybranch'] = {
tree: [], tree: [],
...@@ -111,35 +128,45 @@ describe('Multi-file store tree actions', () => { ...@@ -111,35 +128,45 @@ describe('Multi-file store tree actions', () => {
projectTree.lastCommitPath = 'lastcommitpath'; projectTree.lastCommitPath = 'lastcommitpath';
}); });
it('calls service with lastCommitPath', (done) => { it('calls service with lastCommitPath', done => {
store.dispatch('getLastCommitData', projectTree) store
.dispatch('getLastCommitData', projectTree)
.then(() => { .then(() => {
expect(service.getTreeLastCommit).toHaveBeenCalledWith('lastcommitpath'); expect(service.getTreeLastCommit).toHaveBeenCalledWith(
'lastcommitpath',
);
done(); done();
}).catch(done.fail); })
.catch(done.fail);
}); });
it('updates trees last commit data', (done) => { it('updates trees last commit data', done => {
store.dispatch('getLastCommitData', projectTree) store
.dispatch('getLastCommitData', projectTree)
.then(Vue.nextTick) .then(Vue.nextTick)
.then(() => { .then(() => {
expect(projectTree.tree[0].lastCommit.message).toBe('commit message'); expect(projectTree.tree[0].lastCommit.message).toBe('commit message');
done(); done();
}).catch(done.fail); })
.catch(done.fail);
}); });
it('does not update entry if not found', (done) => { it('does not update entry if not found', done => {
projectTree.tree[0].name = 'a'; projectTree.tree[0].name = 'a';
store.dispatch('getLastCommitData', projectTree) store
.dispatch('getLastCommitData', projectTree)
.then(Vue.nextTick) .then(Vue.nextTick)
.then(() => { .then(() => {
expect(projectTree.tree[0].lastCommit.message).not.toBe('commit message'); expect(projectTree.tree[0].lastCommit.message).not.toBe(
'commit message',
);
done(); done();
}).catch(done.fail); })
.catch(done.fail);
}); });
}); });
}); });
import * as urlUtils from '~/lib/utils/url_utility'; import * as urlUtils from '~/lib/utils/url_utility';
import store from 'ee/ide/stores'; import store from '~/ide/stores';
import router from 'ee/ide/ide_router'; import router from '~/ide/ide_router';
import { resetStore, file } from '../helpers'; import { resetStore, file } from '../helpers';
describe('Multi-file store actions', () => { describe('Multi-file store actions', () => {
......
import * as getters from 'ee/ide/stores/getters'; import * as getters from '~/ide/stores/getters';
import state from 'ee/ide/stores/state'; import state from '~/ide/stores/state';
import { file } from '../helpers'; import { file } from '../helpers';
describe('Multi-file store getters', () => { describe('Multi-file store getters', () => {
......
import store from 'ee/ide/stores'; import store from '~/ide/stores';
import service from 'ee/ide/services'; import service from '~/ide/services';
import router from 'ee/ide/ide_router'; import router from '~/ide/ide_router';
import * as urlUtils from '~/lib/utils/url_utility'; import * as urlUtils from '~/lib/utils/url_utility';
import eventHub from 'ee/ide/eventhub'; import eventHub from '~/ide/eventhub';
import * as consts from 'ee/ide/stores/modules/commit/constants'; import * as consts from '~/ide/stores/modules/commit/constants';
import { resetStore, file } from 'spec/ide/helpers'; import { resetStore, file } from 'spec/ide/helpers';
describe('IDE commit module actions', () => { describe('IDE commit module actions', () => {
...@@ -16,8 +16,9 @@ describe('IDE commit module actions', () => { ...@@ -16,8 +16,9 @@ describe('IDE commit module actions', () => {
}); });
describe('updateCommitMessage', () => { describe('updateCommitMessage', () => {
it('updates store with new commit message', (done) => { it('updates store with new commit message', done => {
store.dispatch('commit/updateCommitMessage', 'testing') store
.dispatch('commit/updateCommitMessage', 'testing')
.then(() => { .then(() => {
expect(store.state.commit.commitMessage).toBe('testing'); expect(store.state.commit.commitMessage).toBe('testing');
}) })
...@@ -27,10 +28,11 @@ describe('IDE commit module actions', () => { ...@@ -27,10 +28,11 @@ describe('IDE commit module actions', () => {
}); });
describe('discardDraft', () => { describe('discardDraft', () => {
it('resets commit message to blank', (done) => { it('resets commit message to blank', done => {
store.state.commit.commitMessage = 'testing'; store.state.commit.commitMessage = 'testing';
store.dispatch('commit/discardDraft') store
.dispatch('commit/discardDraft')
.then(() => { .then(() => {
expect(store.state.commit.commitMessage).not.toBe('testing'); expect(store.state.commit.commitMessage).not.toBe('testing');
}) })
...@@ -40,8 +42,9 @@ describe('IDE commit module actions', () => { ...@@ -40,8 +42,9 @@ describe('IDE commit module actions', () => {
}); });
describe('updateCommitAction', () => { describe('updateCommitAction', () => {
it('updates store with new commit action', (done) => { it('updates store with new commit action', done => {
store.dispatch('commit/updateCommitAction', '1') store
.dispatch('commit/updateCommitAction', '1')
.then(() => { .then(() => {
expect(store.state.commit.commitAction).toBe('1'); expect(store.state.commit.commitAction).toBe('1');
}) })
...@@ -51,8 +54,9 @@ describe('IDE commit module actions', () => { ...@@ -51,8 +54,9 @@ describe('IDE commit module actions', () => {
}); });
describe('updateBranchName', () => { describe('updateBranchName', () => {
it('updates store with new branch name', (done) => { it('updates store with new branch name', done => {
store.dispatch('commit/updateBranchName', 'branch-name') store
.dispatch('commit/updateBranchName', 'branch-name')
.then(() => { .then(() => {
expect(store.state.commit.newBranchName).toBe('branch-name'); expect(store.state.commit.newBranchName).toBe('branch-name');
}) })
...@@ -73,8 +77,9 @@ describe('IDE commit module actions', () => { ...@@ -73,8 +77,9 @@ describe('IDE commit module actions', () => {
}); });
}); });
it('updates commit message with short_id', (done) => { it('updates commit message with short_id', done => {
store.dispatch('commit/setLastCommitMessage', { short_id: '123' }) store
.dispatch('commit/setLastCommitMessage', { short_id: '123' })
.then(() => { .then(() => {
expect(store.state.lastCommitMsg).toContain( expect(store.state.lastCommitMsg).toContain(
'Your changes have been committed. Commit <a href="http://testing/commit/123" class="commit-sha">123</a>', 'Your changes have been committed. Commit <a href="http://testing/commit/123" class="commit-sha">123</a>',
...@@ -84,8 +89,9 @@ describe('IDE commit module actions', () => { ...@@ -84,8 +89,9 @@ describe('IDE commit module actions', () => {
.catch(done.fail); .catch(done.fail);
}); });
it('updates commit message with stats', (done) => { it('updates commit message with stats', done => {
store.dispatch('commit/setLastCommitMessage', { store
.dispatch('commit/setLastCommitMessage', {
short_id: '123', short_id: '123',
stats: { stats: {
additions: '1', additions: '1',
...@@ -93,7 +99,9 @@ describe('IDE commit module actions', () => { ...@@ -93,7 +99,9 @@ describe('IDE commit module actions', () => {
}, },
}) })
.then(() => { .then(() => {
expect(store.state.lastCommitMsg).toBe('Your changes have been committed. Commit <a href="http://testing/commit/123" class="commit-sha">123</a> with 1 additions, 2 deletions.'); expect(store.state.lastCommitMsg).toBe(
'Your changes have been committed. Commit <a href="http://testing/commit/123" class="commit-sha">123</a> with 1 additions, 2 deletions.',
);
}) })
.then(done) .then(done)
.catch(done.fail); .catch(done.fail);
...@@ -113,31 +121,40 @@ describe('IDE commit module actions', () => { ...@@ -113,31 +121,40 @@ describe('IDE commit module actions', () => {
}; };
}); });
it('calls service', (done) => { it('calls service', done => {
spyOn(service, 'getBranchData').and.returnValue(Promise.resolve({ spyOn(service, 'getBranchData').and.returnValue(
Promise.resolve({
data: { data: {
commit: { id: '123' }, commit: { id: '123' },
}, },
})); }),
);
store.dispatch('commit/checkCommitStatus') store
.dispatch('commit/checkCommitStatus')
.then(() => { .then(() => {
expect(service.getBranchData).toHaveBeenCalledWith('abcproject', 'master'); expect(service.getBranchData).toHaveBeenCalledWith(
'abcproject',
'master',
);
done(); done();
}) })
.catch(done.fail); .catch(done.fail);
}); });
it('returns true if current ref does not equal returned ID', (done) => { it('returns true if current ref does not equal returned ID', done => {
spyOn(service, 'getBranchData').and.returnValue(Promise.resolve({ spyOn(service, 'getBranchData').and.returnValue(
Promise.resolve({
data: { data: {
commit: { id: '123' }, commit: { id: '123' },
}, },
})); }),
);
store.dispatch('commit/checkCommitStatus') store
.then((val) => { .dispatch('commit/checkCommitStatus')
.then(val => {
expect(val).toBeTruthy(); expect(val).toBeTruthy();
done(); done();
...@@ -145,15 +162,18 @@ describe('IDE commit module actions', () => { ...@@ -145,15 +162,18 @@ describe('IDE commit module actions', () => {
.catch(done.fail); .catch(done.fail);
}); });
it('returns false if current ref equals returned ID', (done) => { it('returns false if current ref equals returned ID', done => {
spyOn(service, 'getBranchData').and.returnValue(Promise.resolve({ spyOn(service, 'getBranchData').and.returnValue(
Promise.resolve({
data: { data: {
commit: { id: '1' }, commit: { id: '1' },
}, },
})); }),
);
store.dispatch('commit/checkCommitStatus') store
.then((val) => { .dispatch('commit/checkCommitStatus')
.then(val => {
expect(val).toBeFalsy(); expect(val).toBeFalsy();
done(); done();
...@@ -198,13 +218,14 @@ describe('IDE commit module actions', () => { ...@@ -198,13 +218,14 @@ describe('IDE commit module actions', () => {
}); });
store.state.openFiles = store.state.changedFiles; store.state.openFiles = store.state.changedFiles;
store.state.changedFiles.forEach((changedFile) => { store.state.changedFiles.forEach(changedFile => {
store.state.entries[changedFile.path] = changedFile; store.state.entries[changedFile.path] = changedFile;
}); });
}); });
it('updates stores working reference', (done) => { it('updates stores working reference', done => {
store.dispatch('commit/updateFilesAfterCommit', { store
.dispatch('commit/updateFilesAfterCommit', {
data, data,
branch, branch,
}) })
...@@ -217,13 +238,14 @@ describe('IDE commit module actions', () => { ...@@ -217,13 +238,14 @@ describe('IDE commit module actions', () => {
.catch(done.fail); .catch(done.fail);
}); });
it('resets all files changed status', (done) => { it('resets all files changed status', done => {
store.dispatch('commit/updateFilesAfterCommit', { store
.dispatch('commit/updateFilesAfterCommit', {
data, data,
branch, branch,
}) })
.then(() => { .then(() => {
store.state.openFiles.forEach((entry) => { store.state.openFiles.forEach(entry => {
expect(entry.changed).toBeFalsy(); expect(entry.changed).toBeFalsy();
}); });
}) })
...@@ -231,8 +253,9 @@ describe('IDE commit module actions', () => { ...@@ -231,8 +253,9 @@ describe('IDE commit module actions', () => {
.catch(done.fail); .catch(done.fail);
}); });
it('removes all changed files', (done) => { it('removes all changed files', done => {
store.dispatch('commit/updateFilesAfterCommit', { store
.dispatch('commit/updateFilesAfterCommit', {
data, data,
branch, branch,
}) })
...@@ -243,8 +266,9 @@ describe('IDE commit module actions', () => { ...@@ -243,8 +266,9 @@ describe('IDE commit module actions', () => {
.catch(done.fail); .catch(done.fail);
}); });
it('sets files commit data', (done) => { it('sets files commit data', done => {
store.dispatch('commit/updateFilesAfterCommit', { store
.dispatch('commit/updateFilesAfterCommit', {
data, data,
branch, branch,
}) })
...@@ -255,8 +279,9 @@ describe('IDE commit module actions', () => { ...@@ -255,8 +279,9 @@ describe('IDE commit module actions', () => {
.catch(done.fail); .catch(done.fail);
}); });
it('updates raw content for changed file', (done) => { it('updates raw content for changed file', done => {
store.dispatch('commit/updateFilesAfterCommit', { store
.dispatch('commit/updateFilesAfterCommit', {
data, data,
branch, branch,
}) })
...@@ -267,22 +292,27 @@ describe('IDE commit module actions', () => { ...@@ -267,22 +292,27 @@ describe('IDE commit module actions', () => {
.catch(done.fail); .catch(done.fail);
}); });
it('emits changed event for file', (done) => { it('emits changed event for file', done => {
store.dispatch('commit/updateFilesAfterCommit', { store
.dispatch('commit/updateFilesAfterCommit', {
data, data,
branch, branch,
}) })
.then(() => { .then(() => {
expect(eventHub.$emit).toHaveBeenCalledWith(`editor.update.model.content.${f.path}`, f.content); expect(eventHub.$emit).toHaveBeenCalledWith(
`editor.update.model.content.${f.path}`,
f.content,
);
}) })
.then(done) .then(done)
.catch(done.fail); .catch(done.fail);
}); });
it('pushes route to new branch if commitAction is new branch', (done) => { it('pushes route to new branch if commitAction is new branch', done => {
store.state.commit.commitAction = consts.COMMIT_TO_NEW_BRANCH; store.state.commit.commitAction = consts.COMMIT_TO_NEW_BRANCH;
store.dispatch('commit/updateFilesAfterCommit', { store
.dispatch('commit/updateFilesAfterCommit', {
data, data,
branch, branch,
}) })
...@@ -295,15 +325,18 @@ describe('IDE commit module actions', () => { ...@@ -295,15 +325,18 @@ describe('IDE commit module actions', () => {
.catch(done.fail); .catch(done.fail);
}); });
it('resets stores commit actions', (done) => { it('resets stores commit actions', done => {
store.state.commit.commitAction = consts.COMMIT_TO_NEW_BRANCH; store.state.commit.commitAction = consts.COMMIT_TO_NEW_BRANCH;
store.dispatch('commit/updateFilesAfterCommit', { store
.dispatch('commit/updateFilesAfterCommit', {
data, data,
branch, branch,
}) })
.then(() => { .then(() => {
expect(store.state.commit.commitAction).not.toBe(consts.COMMIT_TO_NEW_BRANCH); expect(store.state.commit.commitAction).not.toBe(
consts.COMMIT_TO_NEW_BRANCH,
);
}) })
.then(done) .then(done)
.catch(done.fail); .catch(done.fail);
...@@ -330,7 +363,7 @@ describe('IDE commit module actions', () => { ...@@ -330,7 +363,7 @@ describe('IDE commit module actions', () => {
store.state.changedFiles[0].active = true; store.state.changedFiles[0].active = true;
store.state.openFiles = store.state.changedFiles; store.state.openFiles = store.state.changedFiles;
store.state.openFiles.forEach((f) => { store.state.openFiles.forEach(f => {
store.state.entries[f.path] = f; store.state.entries[f.path] = f;
}); });
...@@ -344,7 +377,8 @@ describe('IDE commit module actions', () => { ...@@ -344,7 +377,8 @@ describe('IDE commit module actions', () => {
describe('success', () => { describe('success', () => {
beforeEach(() => { beforeEach(() => {
spyOn(service, 'commit').and.returnValue(Promise.resolve({ spyOn(service, 'commit').and.returnValue(
Promise.resolve({
data: { data: {
id: '123456', id: '123456',
short_id: '123', short_id: '123',
...@@ -355,95 +389,116 @@ describe('IDE commit module actions', () => { ...@@ -355,95 +389,116 @@ describe('IDE commit module actions', () => {
deletions: '2', deletions: '2',
}, },
}, },
})); }),
);
}); });
it('calls service', (done) => { it('calls service', done => {
store.dispatch('commit/commitChanges') store
.dispatch('commit/commitChanges')
.then(() => { .then(() => {
expect(service.commit).toHaveBeenCalledWith('abcproject', { expect(service.commit).toHaveBeenCalledWith('abcproject', {
branch: jasmine.anything(), branch: jasmine.anything(),
commit_message: 'testing 123', commit_message: 'testing 123',
actions: [{ actions: [
{
action: 'update', action: 'update',
file_path: jasmine.anything(), file_path: jasmine.anything(),
content: jasmine.anything(), content: jasmine.anything(),
encoding: jasmine.anything(), encoding: jasmine.anything(),
}], },
],
start_branch: 'master', start_branch: 'master',
}); });
done(); done();
}).catch(done.fail); })
.catch(done.fail);
}); });
it('pushes router to new route', (done) => { it('pushes router to new route', done => {
store.dispatch('commit/commitChanges') store
.dispatch('commit/commitChanges')
.then(() => { .then(() => {
expect(router.push).toHaveBeenCalledWith( expect(router.push).toHaveBeenCalledWith(
`/project/${store.state.currentProjectId}/blob/${store.getters['commit/newBranchName']}/changed`, `/project/${store.state.currentProjectId}/blob/${
store.getters['commit/newBranchName']
}/changed`,
); );
done(); done();
}).catch(done.fail); })
.catch(done.fail);
}); });
it('sets last Commit Msg', (done) => { it('sets last Commit Msg', done => {
store.dispatch('commit/commitChanges') store
.dispatch('commit/commitChanges')
.then(() => { .then(() => {
expect(store.state.lastCommitMsg).toBe( expect(store.state.lastCommitMsg).toBe(
'Your changes have been committed. Commit <a href="webUrl/commit/123" class="commit-sha">123</a> with 1 additions, 2 deletions.', 'Your changes have been committed. Commit <a href="webUrl/commit/123" class="commit-sha">123</a> with 1 additions, 2 deletions.',
); );
done(); done();
}).catch(done.fail); })
.catch(done.fail);
}); });
it('adds commit data to changed files', (done) => { it('adds commit data to changed files', done => {
store.dispatch('commit/commitChanges') store
.dispatch('commit/commitChanges')
.then(() => { .then(() => {
expect(store.state.openFiles[0].lastCommit.message).toBe('test message'); expect(store.state.openFiles[0].lastCommit.message).toBe(
'test message',
);
done(); done();
}).catch(done.fail); })
.catch(done.fail);
}); });
it('redirects to new merge request page', (done) => { it('redirects to new merge request page', done => {
spyOn(eventHub, '$on'); spyOn(eventHub, '$on');
store.state.commit.commitAction = '3'; store.state.commit.commitAction = '3';
store.dispatch('commit/commitChanges') store
.dispatch('commit/commitChanges')
.then(() => { .then(() => {
expect(urlUtils.visitUrl).toHaveBeenCalledWith( expect(urlUtils.visitUrl).toHaveBeenCalledWith(
`webUrl/merge_requests/new?merge_request[source_branch]=${store.getters['commit/newBranchName']}&merge_request[target_branch]=master`, `webUrl/merge_requests/new?merge_request[source_branch]=${
store.getters['commit/newBranchName']
}&merge_request[target_branch]=master`,
); );
done(); done();
}).catch(done.fail); })
.catch(done.fail);
}); });
}); });
describe('failed', () => { describe('failed', () => {
beforeEach(() => { beforeEach(() => {
spyOn(service, 'commit').and.returnValue(Promise.resolve({ spyOn(service, 'commit').and.returnValue(
Promise.resolve({
data: { data: {
message: 'failed message', message: 'failed message',
}, },
})); }),
);
}); });
it('shows failed message', (done) => { it('shows failed message', done => {
store.dispatch('commit/commitChanges') store
.dispatch('commit/commitChanges')
.then(() => { .then(() => {
const alert = document.querySelector('.flash-container'); const alert = document.querySelector('.flash-container');
expect(alert.textContent.trim()).toBe( expect(alert.textContent.trim()).toBe('failed message');
'failed message',
);
done(); done();
}).catch(done.fail); })
.catch(done.fail);
}); });
}); });
}); });
......
import commitState from 'ee/ide/stores/modules/commit/state'; import commitState from '~/ide/stores/modules/commit/state';
import * as consts from 'ee/ide/stores/modules/commit/constants'; import * as consts from '~/ide/stores/modules/commit/constants';
import * as getters from 'ee/ide/stores/modules/commit/getters'; import * as getters from '~/ide/stores/modules/commit/getters';
describe('IDE commit module getters', () => { describe('IDE commit module getters', () => {
let state; let state;
...@@ -38,26 +38,34 @@ describe('IDE commit module getters', () => { ...@@ -38,26 +38,34 @@ describe('IDE commit module getters', () => {
}; };
it('returns false when discardDraftButtonDisabled is false & changedFiles is not empty', () => { it('returns false when discardDraftButtonDisabled is false & changedFiles is not empty', () => {
expect(getters.commitButtonDisabled(state, localGetters, rootState)).toBeFalsy(); expect(
getters.commitButtonDisabled(state, localGetters, rootState),
).toBeFalsy();
}); });
it('returns true when discardDraftButtonDisabled is false & changedFiles is empty', () => { it('returns true when discardDraftButtonDisabled is false & changedFiles is empty', () => {
rootState.changedFiles.length = 0; rootState.changedFiles.length = 0;
expect(getters.commitButtonDisabled(state, localGetters, rootState)).toBeTruthy(); expect(
getters.commitButtonDisabled(state, localGetters, rootState),
).toBeTruthy();
}); });
it('returns true when discardDraftButtonDisabled is true', () => { it('returns true when discardDraftButtonDisabled is true', () => {
localGetters.discardDraftButtonDisabled = true; localGetters.discardDraftButtonDisabled = true;
expect(getters.commitButtonDisabled(state, localGetters, rootState)).toBeTruthy(); expect(
getters.commitButtonDisabled(state, localGetters, rootState),
).toBeTruthy();
}); });
it('returns true when discardDraftButtonDisabled is false & changedFiles is not empty', () => { it('returns true when discardDraftButtonDisabled is false & changedFiles is not empty', () => {
localGetters.discardDraftButtonDisabled = false; localGetters.discardDraftButtonDisabled = false;
rootState.changedFiles.length = 0; rootState.changedFiles.length = 0;
expect(getters.commitButtonDisabled(state, localGetters, rootState)).toBeTruthy(); expect(
getters.commitButtonDisabled(state, localGetters, rootState),
).toBeTruthy();
}); });
}); });
...@@ -65,7 +73,9 @@ describe('IDE commit module getters', () => { ...@@ -65,7 +73,9 @@ describe('IDE commit module getters', () => {
it('includes username, currentBranchId, patch & random number', () => { it('includes username, currentBranchId, patch & random number', () => {
gon.current_username = 'username'; gon.current_username = 'username';
const branch = getters.newBranchName(state, null, { currentBranchId: 'testing' }); const branch = getters.newBranchName(state, null, {
currentBranchId: 'testing',
});
expect(branch).toMatch(/username-testing-patch-\d{5}$/); expect(branch).toMatch(/username-testing-patch-\d{5}$/);
}); });
...@@ -89,7 +99,7 @@ describe('IDE commit module getters', () => { ...@@ -89,7 +99,7 @@ describe('IDE commit module getters', () => {
expect(getters.branchName(state, null, rootState)).toBe('master'); expect(getters.branchName(state, null, rootState)).toBe('master');
}); });
['COMMIT_TO_NEW_BRANCH', 'COMMIT_TO_NEW_BRANCH_MR'].forEach((type) => { ['COMMIT_TO_NEW_BRANCH', 'COMMIT_TO_NEW_BRANCH_MR'].forEach(type => {
describe(type, () => { describe(type, () => {
beforeEach(() => { beforeEach(() => {
Object.assign(state, { Object.assign(state, {
...@@ -98,7 +108,9 @@ describe('IDE commit module getters', () => { ...@@ -98,7 +108,9 @@ describe('IDE commit module getters', () => {
}); });
it('uses newBranchName when not empty', () => { it('uses newBranchName when not empty', () => {
expect(getters.branchName(state, localGetters, rootState)).toBe('state-newBranchName'); expect(getters.branchName(state, localGetters, rootState)).toBe(
'state-newBranchName',
);
}); });
it('uses getters newBranchName when state newBranchName is empty', () => { it('uses getters newBranchName when state newBranchName is empty', () => {
...@@ -106,7 +118,9 @@ describe('IDE commit module getters', () => { ...@@ -106,7 +118,9 @@ describe('IDE commit module getters', () => {
newBranchName: '', newBranchName: '',
}); });
expect(getters.branchName(state, localGetters, rootState)).toBe('newBranchName'); expect(getters.branchName(state, localGetters, rootState)).toBe(
'newBranchName',
);
}); });
}); });
}); });
......
import commitState from 'ee/ide/stores/modules/commit/state'; import commitState from '~/ide/stores/modules/commit/state';
import mutations from 'ee/ide/stores/modules/commit/mutations'; import mutations from '~/ide/stores/modules/commit/mutations';
describe('IDE commit module mutations', () => { describe('IDE commit module mutations', () => {
let state; let state;
......
import mutations from 'ee/ide/stores/mutations/branch'; import mutations from '~/ide/stores/mutations/branch';
import state from 'ee/ide/stores/state'; import state from '~/ide/stores/state';
describe('Multi-file store branch mutations', () => { describe('Multi-file store branch mutations', () => {
let localState; let localState;
......
import mutations from 'ee/ide/stores/mutations/file'; import mutations from '~/ide/stores/mutations/file';
import state from 'ee/ide/stores/state'; import state from '~/ide/stores/state';
import { file } from '../../helpers'; import { file } from '../../helpers';
describe('Multi-file store file mutations', () => { describe('Multi-file store file mutations', () => {
......
import mutations from 'ee/ide/stores/mutations/tree'; import mutations from '~/ide/stores/mutations/tree';
import state from 'ee/ide/stores/state'; import state from '~/ide/stores/state';
import { file } from '../../helpers'; import { file } from '../../helpers';
describe('Multi-file store tree mutations', () => { describe('Multi-file store tree mutations', () => {
...@@ -26,7 +26,8 @@ describe('Multi-file store tree mutations', () => { ...@@ -26,7 +26,8 @@ describe('Multi-file store tree mutations', () => {
}); });
describe('SET_DIRECTORY_DATA', () => { describe('SET_DIRECTORY_DATA', () => {
const data = [{ const data = [
{
name: 'tree', name: 'tree',
}, },
{ {
...@@ -34,7 +35,8 @@ describe('Multi-file store tree mutations', () => { ...@@ -34,7 +35,8 @@ describe('Multi-file store tree mutations', () => {
}, },
{ {
name: 'blob', name: 'blob',
}]; },
];
it('adds directory data', () => { it('adds directory data', () => {
localState.trees['project/master'] = { localState.trees['project/master'] = {
......
import mutations from 'ee/ide/stores/mutations'; import mutations from '~/ide/stores/mutations';
import state from 'ee/ide/stores/state'; import state from '~/ide/stores/state';
import { file } from '../helpers'; import { file } from '../helpers';
describe('Multi-file store mutations', () => { describe('Multi-file store mutations', () => {
......
import * as utils from 'ee/ide/stores/utils'; import * as utils from '~/ide/stores/utils';
describe('Multi-file store utils', () => { describe('Multi-file store utils', () => {
describe('setPageTitle', () => { describe('setPageTitle', () => {
...@@ -13,11 +13,14 @@ describe('Multi-file store utils', () => { ...@@ -13,11 +13,14 @@ describe('Multi-file store utils', () => {
let localState; let localState;
beforeEach(() => { beforeEach(() => {
localState = [{ localState = [
{
path: '1', path: '1',
}, { },
{
path: '2', path: '2',
}]; },
];
}); });
it('finds in the index of an entry by path', () => { it('finds in the index of an entry by path', () => {
...@@ -34,13 +37,16 @@ describe('Multi-file store utils', () => { ...@@ -34,13 +37,16 @@ describe('Multi-file store utils', () => {
beforeEach(() => { beforeEach(() => {
localState = { localState = {
tree: [{ tree: [
{
type: 'tree', type: 'tree',
name: 'test', name: 'test',
}, { },
{
type: 'blob', type: 'blob',
name: 'file', name: 'file',
}], },
],
}; };
}); });
......
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