Commit 86db303f authored by Stan Hu's avatar Stan Hu

Merge branch 'ce-to-ee-2018-08-03' into 'master'

CE upstream - 2018-08-03 18:21 UTC

Closes gitlab-ce#49862

See merge request gitlab-org/gitlab-ee!6789
parents 9e821920 78e34c67
...@@ -774,7 +774,7 @@ GEM ...@@ -774,7 +774,7 @@ GEM
retriable (3.1.1) retriable (3.1.1)
rinku (2.0.0) rinku (2.0.0)
rotp (2.1.2) rotp (2.1.2)
rouge (3.1.1) rouge (3.2.0)
rqrcode (0.7.0) rqrcode (0.7.0)
chunky_png chunky_png
rqrcode-rails3 (0.1.7) rqrcode-rails3 (0.1.7)
......
...@@ -783,7 +783,7 @@ GEM ...@@ -783,7 +783,7 @@ GEM
retriable (3.1.1) retriable (3.1.1)
rinku (2.0.0) rinku (2.0.0)
rotp (2.1.2) rotp (2.1.2)
rouge (3.1.1) rouge (3.2.0)
rqrcode (0.7.0) rqrcode (0.7.0)
chunky_png chunky_png
rqrcode-rails3 (0.1.7) rqrcode-rails3 (0.1.7)
......
...@@ -4,6 +4,7 @@ import icon from '~/vue_shared/components/icon.vue'; ...@@ -4,6 +4,7 @@ import icon from '~/vue_shared/components/icon.vue';
import newModal from './modal.vue'; import newModal from './modal.vue';
import upload from './upload.vue'; import upload from './upload.vue';
import ItemButton from './button.vue'; import ItemButton from './button.vue';
import { modalTypes } from '../../constants';
export default { export default {
components: { components: {
...@@ -56,6 +57,7 @@ export default { ...@@ -56,6 +57,7 @@ export default {
this.dropdownOpen = !this.dropdownOpen; this.dropdownOpen = !this.dropdownOpen;
}, },
}, },
modalTypes,
}; };
</script> </script>
...@@ -74,7 +76,7 @@ export default { ...@@ -74,7 +76,7 @@ export default {
@click.stop="openDropdown()" @click.stop="openDropdown()"
> >
<icon <icon
name="hamburger" name="ellipsis_v"
/> />
<icon <icon
name="arrow-down" name="arrow-down"
...@@ -106,11 +108,20 @@ export default { ...@@ -106,11 +108,20 @@ export default {
class="d-flex" class="d-flex"
icon="folder-new" icon="folder-new"
icon-classes="mr-2" icon-classes="mr-2"
@click="createNewItem('tree')" @click="createNewItem($options.modalTypes.tree)"
/> />
</li> </li>
<li class="divider"></li> <li class="divider"></li>
</template> </template>
<li>
<item-button
:label="__('Rename')"
class="d-flex"
icon="pencil"
icon-classes="mr-2"
@click="createNewItem($options.modalTypes.rename)"
/>
</li>
<li> <li>
<item-button <item-button
:label="__('Delete')" :label="__('Delete')"
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
import { __ } from '~/locale'; import { __ } from '~/locale';
import { mapActions, mapState } from 'vuex'; import { mapActions, mapState } from 'vuex';
import GlModal from '~/vue_shared/components/gl_modal.vue'; import GlModal from '~/vue_shared/components/gl_modal.vue';
import { modalTypes } from '../../constants';
export default { export default {
components: { components: {
...@@ -13,42 +14,58 @@ export default { ...@@ -13,42 +14,58 @@ export default {
}; };
}, },
computed: { computed: {
...mapState(['newEntryModal']), ...mapState(['entryModal']),
entryName: { entryName: {
get() { get() {
return this.name || (this.newEntryModal.path !== '' ? `${this.newEntryModal.path}/` : ''); if (this.entryModal.type === modalTypes.rename) {
return this.name || this.entryModal.entry.name;
}
return this.name || (this.entryModal.path !== '' ? `${this.entryModal.path}/` : '');
}, },
set(val) { set(val) {
this.name = val; this.name = val;
}, },
}, },
modalTitle() { modalTitle() {
if (this.newEntryModal.type === 'tree') { if (this.entryModal.type === modalTypes.tree) {
return __('Create new directory'); return __('Create new directory');
} else if (this.entryModal.type === modalTypes.rename) {
return this.entryModal.entry.type === modalTypes.tree ? __('Rename folder') : __('Rename file');
} }
return __('Create new file'); return __('Create new file');
}, },
buttonLabel() { buttonLabel() {
if (this.newEntryModal.type === 'tree') { if (this.entryModal.type === modalTypes.tree) {
return __('Create directory'); return __('Create directory');
} else if (this.entryModal.type === modalTypes.rename) {
return this.entryModal.entry.type === modalTypes.tree ? __('Rename folder') : __('Rename file');
} }
return __('Create file'); return __('Create file');
}, },
}, },
methods: { methods: {
...mapActions(['createTempEntry']), ...mapActions(['createTempEntry', 'renameEntry']),
createEntryInStore() { submitForm() {
this.createTempEntry({ if (this.entryModal.type === modalTypes.rename) {
name: this.name, this.renameEntry({
type: this.newEntryModal.type, path: this.entryModal.entry.path,
}); name: this.entryName,
});
} else {
this.createTempEntry({
name: this.name,
type: this.entryModal.type,
});
}
}, },
focusInput() { focusInput() {
setTimeout(() => { this.$refs.fieldName.focus();
this.$refs.fieldName.focus(); },
}); closedModal() {
this.name = '';
}, },
}, },
}; };
...@@ -60,8 +77,9 @@ export default { ...@@ -60,8 +77,9 @@ export default {
:header-title-text="modalTitle" :header-title-text="modalTitle"
:footer-primary-button-text="buttonLabel" :footer-primary-button-text="buttonLabel"
footer-primary-button-variant="success" footer-primary-button-variant="success"
@submit="createEntryInStore" @submit="submitForm"
@open="focusInput" @open="focusInput"
@closed="closedModal"
> >
<div <div
class="form-group row" class="form-group row"
......
...@@ -134,8 +134,7 @@ export default { ...@@ -134,8 +134,7 @@ export default {
.replace(/[/]$/g, ''); .replace(/[/]$/g, '');
// - strip ending "/" // - strip ending "/"
const filePath = this.file.path const filePath = this.file.path.replace(/[/]$/g, '');
.replace(/[/]$/g, '');
return filePath === routePath; return filePath === routePath;
}, },
...@@ -194,7 +193,7 @@ export default { ...@@ -194,7 +193,7 @@ export default {
data-container="body" data-container="body"
data-placement="right" data-placement="right"
name="file-modified" name="file-modified"
css-classes="prepend-left-5 multi-file-modified" css-classes="prepend-left-5 ide-file-modified"
/> />
</span> </span>
<changed-file-icon <changed-file-icon
...@@ -208,7 +207,6 @@ export default { ...@@ -208,7 +207,6 @@ export default {
</span> </span>
<new-dropdown <new-dropdown
:type="file.type" :type="file.type"
:branch="file.branchId"
:path="file.path" :path="file.path"
:mouse-over="mouseOver" :mouse-over="mouseOver"
class="float-right prepend-left-8" class="float-right prepend-left-8"
......
...@@ -53,3 +53,8 @@ export const commitItemIconMap = { ...@@ -53,3 +53,8 @@ export const commitItemIconMap = {
class: 'ide-file-deletion', class: 'ide-file-deletion',
}, },
}; };
export const modalTypes = {
rename: 'rename',
tree: 'tree',
};
...@@ -8,7 +8,7 @@ export default { ...@@ -8,7 +8,7 @@ export default {
}); });
}, },
getRawFileData(file) { getRawFileData(file) {
if (file.tempFile) { if (file.tempFile && !file.prevPath) {
return Promise.resolve(file.content); return Promise.resolve(file.content);
} }
......
...@@ -186,13 +186,39 @@ export const openNewEntryModal = ({ commit }, { type, path = '' }) => { ...@@ -186,13 +186,39 @@ export const openNewEntryModal = ({ commit }, { type, path = '' }) => {
}; };
export const deleteEntry = ({ commit, dispatch, state }, path) => { export const deleteEntry = ({ commit, dispatch, state }, path) => {
dispatch('burstUnusedSeal'); const entry = state.entries[path];
dispatch('closeFile', state.entries[path]);
if (state.unusedSeal) dispatch('burstUnusedSeal');
if (entry.opened) dispatch('closeFile', entry);
if (entry.type === 'tree') {
entry.tree.forEach(f => dispatch('deleteEntry', f.path));
}
commit(types.DELETE_ENTRY, path); commit(types.DELETE_ENTRY, path);
if (entry.parentPath && state.entries[entry.parentPath].tree.length === 0) {
dispatch('deleteEntry', entry.parentPath);
}
}; };
export const resetOpenFiles = ({ commit }) => commit(types.RESET_OPEN_FILES); export const resetOpenFiles = ({ commit }) => commit(types.RESET_OPEN_FILES);
export const renameEntry = ({ dispatch, commit, state }, { path, name, entryPath = null }) => {
const entry = state.entries[entryPath || path];
commit(types.RENAME_ENTRY, { path, name, entryPath });
if (entry.type === 'tree') {
state.entries[entryPath || path].tree.forEach(f =>
dispatch('renameEntry', { path, name, entryPath: f.path }),
);
}
if (!entryPath) {
dispatch('deleteEntry', path);
}
};
export * from './actions/tree'; export * from './actions/tree';
export * from './actions/file'; export * from './actions/file';
export * from './actions/project'; export * from './actions/project';
......
...@@ -62,14 +62,14 @@ export const setFileActive = ({ commit, state, getters, dispatch }, path) => { ...@@ -62,14 +62,14 @@ export const setFileActive = ({ commit, state, getters, dispatch }, path) => {
export const getFileData = ({ state, commit, dispatch }, { path, makeFileActive = true }) => { export const getFileData = ({ state, commit, dispatch }, { path, makeFileActive = true }) => {
const file = state.entries[path]; const file = state.entries[path];
if (file.raw || file.tempFile) return Promise.resolve(); if (file.raw || (file.tempFile && !file.prevPath)) return Promise.resolve();
commit(types.TOGGLE_LOADING, { entry: file }); commit(types.TOGGLE_LOADING, { entry: file });
const url = file.prevPath ? file.url.replace(file.path, file.prevPath) : file.url;
return service return service
.getFileData( .getFileData(`${gon.relative_url_root ? gon.relative_url_root : ''}${url.replace('/-/', '/')}`)
`${gon.relative_url_root ? gon.relative_url_root : ''}${file.url.replace('/-/', '/')}`,
)
.then(({ data, headers }) => { .then(({ data, headers }) => {
const normalizedHeaders = normalizeHeaders(headers); const normalizedHeaders = normalizeHeaders(headers);
setPageTitle(decodeURI(normalizedHeaders['PAGE-TITLE'])); setPageTitle(decodeURI(normalizedHeaders['PAGE-TITLE']));
...@@ -101,7 +101,7 @@ export const getRawFileData = ({ state, commit, dispatch }, { path, baseSha }) = ...@@ -101,7 +101,7 @@ export const getRawFileData = ({ state, commit, dispatch }, { path, baseSha }) =
service service
.getRawFileData(file) .getRawFileData(file)
.then(raw => { .then(raw => {
if (!file.tempFile) commit(types.SET_FILE_RAW_DATA, { file, raw }); if (!(file.tempFile && !file.prevPath)) commit(types.SET_FILE_RAW_DATA, { file, raw });
if (file.mrChange && file.mrChange.new_file === false) { if (file.mrChange && file.mrChange.new_file === false) {
service service
.getBaseRawFileData(file, baseSha) .getBaseRawFileData(file, baseSha)
...@@ -176,9 +176,22 @@ export const setFileViewMode = ({ commit }, { file, viewMode }) => { ...@@ -176,9 +176,22 @@ export const setFileViewMode = ({ commit }, { file, viewMode }) => {
export const discardFileChanges = ({ dispatch, state, commit, getters }, path) => { export const discardFileChanges = ({ dispatch, state, commit, getters }, path) => {
const file = state.entries[path]; const file = state.entries[path];
if (file.deleted && file.parentPath) {
dispatch('restoreTree', file.parentPath);
}
if (file.movedPath) {
commit(types.DISCARD_FILE_CHANGES, file.movedPath);
commit(types.REMOVE_FILE_FROM_CHANGED, file.movedPath);
}
commit(types.DISCARD_FILE_CHANGES, path); commit(types.DISCARD_FILE_CHANGES, path);
commit(types.REMOVE_FILE_FROM_CHANGED, path); commit(types.REMOVE_FILE_FROM_CHANGED, path);
if (file.prevPath) {
dispatch('discardFileChanges', file.prevPath);
}
if (file.tempFile && file.opened) { if (file.tempFile && file.opened) {
commit(types.TOGGLE_FILE_OPEN, path); commit(types.TOGGLE_FILE_OPEN, path);
} else if (getters.activeFile && file.path === getters.activeFile.path) { } else if (getters.activeFile && file.path === getters.activeFile.path) {
......
...@@ -89,3 +89,13 @@ export const getFiles = ({ state, commit, dispatch }, { projectId, branchId } = ...@@ -89,3 +89,13 @@ export const getFiles = ({ state, commit, dispatch }, { projectId, branchId } =
resolve(); resolve();
} }
}); });
export const restoreTree = ({ dispatch, commit, state }, path) => {
const entry = state.entries[path];
commit(types.RESTORE_TREE, path);
if (entry.parentPath) {
dispatch('restoreTree', entry.parentPath);
}
};
...@@ -67,9 +67,9 @@ export const someUncommitedChanges = state => ...@@ -67,9 +67,9 @@ export const someUncommitedChanges = state =>
!!(state.changedFiles.length || state.stagedFiles.length); !!(state.changedFiles.length || state.stagedFiles.length);
export const getChangesInFolder = state => path => { export const getChangesInFolder = state => path => {
const changedFilesCount = state.changedFiles.filter(f => filePathMatches(f, path)).length; const changedFilesCount = state.changedFiles.filter(f => filePathMatches(f.path, path)).length;
const stagedFilesCount = state.stagedFiles.filter( const stagedFilesCount = state.stagedFiles.filter(
f => filePathMatches(f, path) && !getChangedFile(state)(f.path), f => filePathMatches(f.path, path) && !getChangedFile(state)(f.path),
).length; ).length;
return changedFilesCount + stagedFilesCount; return changedFilesCount + stagedFilesCount;
......
...@@ -77,3 +77,6 @@ export const SET_ERROR_MESSAGE = 'SET_ERROR_MESSAGE'; ...@@ -77,3 +77,6 @@ export const SET_ERROR_MESSAGE = 'SET_ERROR_MESSAGE';
export const OPEN_NEW_ENTRY_MODAL = 'OPEN_NEW_ENTRY_MODAL'; export const OPEN_NEW_ENTRY_MODAL = 'OPEN_NEW_ENTRY_MODAL';
export const DELETE_ENTRY = 'DELETE_ENTRY'; export const DELETE_ENTRY = 'DELETE_ENTRY';
export const RENAME_ENTRY = 'RENAME_ENTRY';
export const RESTORE_TREE = 'RESTORE_TREE';
...@@ -131,11 +131,14 @@ export default { ...@@ -131,11 +131,14 @@ export default {
}, },
[types.UPDATE_FILE_AFTER_COMMIT](state, { file, lastCommit }) { [types.UPDATE_FILE_AFTER_COMMIT](state, { file, lastCommit }) {
const changedFile = state.changedFiles.find(f => f.path === file.path); const changedFile = state.changedFiles.find(f => f.path === file.path);
const { prevPath } = file;
Object.assign(state.entries[file.path], { Object.assign(state.entries[file.path], {
raw: file.content, raw: file.content,
changed: !!changedFile, changed: !!changedFile,
staged: false, staged: false,
prevPath: '',
moved: false,
lastCommit: Object.assign(state.entries[file.path].lastCommit, { lastCommit: Object.assign(state.entries[file.path].lastCommit, {
id: lastCommit.commit.id, id: lastCommit.commit.id,
url: lastCommit.commit_path, url: lastCommit.commit_path,
...@@ -144,6 +147,18 @@ export default { ...@@ -144,6 +147,18 @@ export default {
updatedAt: lastCommit.commit.authored_date, updatedAt: lastCommit.commit.authored_date,
}), }),
}); });
if (prevPath) {
// Update URLs after file has moved
const regex = new RegExp(`${prevPath}$`);
Object.assign(state.entries[file.path], {
rawPath: file.rawPath.replace(regex, file.path),
permalink: file.permalink.replace(regex, file.path),
commitsPath: file.commitsPath.replace(regex, file.path),
blamePath: file.blamePath.replace(regex, file.path),
});
}
}, },
[types.BURST_UNUSED_SEAL](state) { [types.BURST_UNUSED_SEAL](state) {
Object.assign(state, { Object.assign(state, {
...@@ -169,7 +184,11 @@ export default { ...@@ -169,7 +184,11 @@ export default {
}, },
[types.OPEN_NEW_ENTRY_MODAL](state, { type, path }) { [types.OPEN_NEW_ENTRY_MODAL](state, { type, path }) {
Object.assign(state, { Object.assign(state, {
newEntryModal: { type, path }, entryModal: {
type,
path,
entry: { ...state.entries[path] },
},
}); });
}, },
[types.DELETE_ENTRY](state, path) { [types.DELETE_ENTRY](state, path) {
...@@ -179,8 +198,48 @@ export default { ...@@ -179,8 +198,48 @@ export default {
: state.trees[`${state.currentProjectId}/${state.currentBranchId}`]; : state.trees[`${state.currentProjectId}/${state.currentBranchId}`];
entry.deleted = true; entry.deleted = true;
state.changedFiles = state.changedFiles.concat(entry);
parent.tree = parent.tree.filter(f => f.path !== entry.path); parent.tree = parent.tree.filter(f => f.path !== entry.path);
if (entry.type === 'blob') {
state.changedFiles = state.changedFiles.concat(entry);
}
},
[types.RENAME_ENTRY](state, { path, name, entryPath = null }) {
const oldEntry = state.entries[entryPath || path];
const nameRegex =
!entryPath && oldEntry.type === 'blob'
? new RegExp(`${oldEntry.name}$`)
: new RegExp(`^${path}`);
const newPath = oldEntry.path.replace(nameRegex, name);
const parentPath = oldEntry.parentPath ? oldEntry.parentPath.replace(nameRegex, name) : '';
state.entries[newPath] = {
...oldEntry,
id: newPath,
key: `${name}-${oldEntry.type}-${oldEntry.id}`,
path: newPath,
name: entryPath ? oldEntry.name : name,
tempFile: true,
prevPath: oldEntry.path,
url: oldEntry.url.replace(new RegExp(`${oldEntry.path}/?$`), newPath),
tree: [],
parentPath,
raw: '',
};
oldEntry.moved = true;
oldEntry.movedPath = newPath;
const parent = parentPath
? state.entries[parentPath]
: state.trees[`${state.currentProjectId}/${state.currentBranchId}`];
const newEntry = state.entries[newPath];
parent.tree = sortTree(parent.tree.concat(newEntry));
if (newEntry.type === 'blob') {
state.changedFiles = state.changedFiles.concat(newEntry);
}
}, },
...projectMutations, ...projectMutations,
...mergeRequestMutation, ...mergeRequestMutation,
......
...@@ -53,15 +53,25 @@ export default { ...@@ -53,15 +53,25 @@ export default {
}, },
[types.SET_FILE_RAW_DATA](state, { file, raw }) { [types.SET_FILE_RAW_DATA](state, { file, raw }) {
const openPendingFile = state.openFiles.find( const openPendingFile = state.openFiles.find(
f => f.path === file.path && f.pending && !f.tempFile, f => f.path === file.path && f.pending && !(f.tempFile && !f.prevPath),
); );
Object.assign(state.entries[file.path], { if (file.tempFile) {
raw, Object.assign(state.entries[file.path], {
}); content: raw,
});
} else {
Object.assign(state.entries[file.path], {
raw,
});
}
if (openPendingFile) { if (!openPendingFile) return;
if (!openPendingFile.tempFile) {
openPendingFile.raw = raw; openPendingFile.raw = raw;
} else if (openPendingFile.tempFile) {
openPendingFile.content = raw;
} }
}, },
[types.SET_FILE_BASE_RAW_DATA](state, { file, baseRaw }) { [types.SET_FILE_BASE_RAW_DATA](state, { file, baseRaw }) {
...@@ -119,12 +129,14 @@ export default { ...@@ -119,12 +129,14 @@ export default {
[types.DISCARD_FILE_CHANGES](state, path) { [types.DISCARD_FILE_CHANGES](state, path) {
const stagedFile = state.stagedFiles.find(f => f.path === path); const stagedFile = state.stagedFiles.find(f => f.path === path);
const entry = state.entries[path]; const entry = state.entries[path];
const { deleted } = entry; const { deleted, prevPath } = entry;
Object.assign(state.entries[path], { Object.assign(state.entries[path], {
content: stagedFile ? stagedFile.content : state.entries[path].raw, content: stagedFile ? stagedFile.content : state.entries[path].raw,
changed: false, changed: false,
deleted: false, deleted: false,
moved: false,
movedPath: '',
}); });
if (deleted) { if (deleted) {
...@@ -133,6 +145,12 @@ export default { ...@@ -133,6 +145,12 @@ export default {
: state.trees[`${state.currentProjectId}/${state.currentBranchId}`]; : state.trees[`${state.currentProjectId}/${state.currentBranchId}`];
parent.tree = sortTree(parent.tree.concat(entry)); parent.tree = sortTree(parent.tree.concat(entry));
} else if (prevPath) {
const parent = entry.parentPath
? state.entries[entry.parentPath]
: state.trees[`${state.currentProjectId}/${state.currentBranchId}`];
parent.tree = parent.tree.filter(f => f.path !== path);
} }
}, },
[types.ADD_FILE_TO_CHANGED](state, path) { [types.ADD_FILE_TO_CHANGED](state, path) {
......
import * as types from '../mutation_types'; import * as types from '../mutation_types';
import { sortTree } from '../utils';
export default { export default {
[types.TOGGLE_TREE_OPEN](state, path) { [types.TOGGLE_TREE_OPEN](state, path) {
...@@ -36,4 +37,14 @@ export default { ...@@ -36,4 +37,14 @@ export default {
changedFiles: [], changedFiles: [],
}); });
}, },
[types.RESTORE_TREE](state, path) {
const entry = state.entries[path];
const parent = entry.parentPath
? state.entries[entry.parentPath]
: state.trees[`${state.currentProjectId}/${state.currentBranchId}`];
if (!parent.tree.find(f => f.path === path)) {
parent.tree = sortTree(parent.tree.concat(entry));
}
},
}; };
...@@ -26,8 +26,9 @@ export default () => ({ ...@@ -26,8 +26,9 @@ export default () => ({
rightPane: null, rightPane: null,
links: {}, links: {},
errorMessage: null, errorMessage: null,
newEntryModal: { entryModal: {
type: '', type: '',
path: '', path: '',
entry: {},
}, },
}); });
...@@ -47,6 +47,9 @@ export const dataStructure = () => ({ ...@@ -47,6 +47,9 @@ export const dataStructure = () => ({
lastOpenedAt: 0, lastOpenedAt: 0,
mrChange: null, mrChange: null,
deleted: false, deleted: false,
prevPath: '',
movedPath: '',
moved: false,
}); });
export const decorateData = entity => { export const decorateData = entity => {
...@@ -107,7 +110,9 @@ export const setPageTitle = title => { ...@@ -107,7 +110,9 @@ export const setPageTitle = title => {
}; };
export const commitActionForFile = file => { export const commitActionForFile = file => {
if (file.deleted) { if (file.prevPath) {
return 'move';
} else if (file.deleted) {
return 'delete'; return 'delete';
} else if (file.tempFile) { } else if (file.tempFile) {
return 'create'; return 'create';
...@@ -116,15 +121,12 @@ export const commitActionForFile = file => { ...@@ -116,15 +121,12 @@ export const commitActionForFile = file => {
return 'update'; return 'update';
}; };
export const getCommitFiles = (stagedFiles, deleteTree = false) => export const getCommitFiles = stagedFiles =>
stagedFiles.reduce((acc, file) => { stagedFiles.reduce((acc, file) => {
if ((file.deleted || deleteTree) && file.type === 'tree') { if (file.moved) return acc;
return acc.concat(getCommitFiles(file.tree, true));
}
return acc.concat({ return acc.concat({
...file, ...file,
deleted: deleteTree || file.deleted,
}); });
}, []); }, []);
...@@ -134,9 +136,10 @@ export const createCommitPayload = ({ branch, getters, newBranch, state, rootSta ...@@ -134,9 +136,10 @@ export const createCommitPayload = ({ branch, getters, newBranch, state, rootSta
actions: getCommitFiles(rootState.stagedFiles).map(f => ({ actions: getCommitFiles(rootState.stagedFiles).map(f => ({
action: commitActionForFile(f), action: commitActionForFile(f),
file_path: f.path, file_path: f.path,
content: f.content, previous_path: f.prevPath === '' ? undefined : f.prevPath,
content: f.content || undefined,
encoding: f.base64 ? 'base64' : 'text', encoding: f.base64 ? 'base64' : 'text',
last_commit_id: newBranch || f.deleted ? undefined : f.lastCommitSha, last_commit_id: newBranch || f.deleted || f.prevPath ? undefined : f.lastCommitSha,
})), })),
start_branch: newBranch ? rootState.currentBranchId : undefined, start_branch: newBranch ? rootState.currentBranchId : undefined,
}); });
...@@ -164,8 +167,7 @@ export const sortTree = sortedTree => ...@@ -164,8 +167,7 @@ export const sortTree = sortedTree =>
) )
.sort(sortTreesByTypeAndName); .sort(sortTreesByTypeAndName);
export const filePathMatches = (f, path) => export const filePathMatches = (filePath, path) => filePath.indexOf(`${path}/`) === 0;
f.path.replace(new RegExp(`${f.name}$`), '').indexOf(`${path}/`) === 0;
export const getChangesCountForFiles = (files, path) => export const getChangesCountForFiles = (files, path) =>
files.filter(f => filePathMatches(f, path)).length; files.filter(f => filePathMatches(f.path, path)).length;
<script> <script>
import $ from 'jquery';
const buttonVariants = ['danger', 'primary', 'success', 'warning']; const buttonVariants = ['danger', 'primary', 'success', 'warning'];
const sizeVariants = ['sm', 'md', 'lg', 'xl']; const sizeVariants = ['sm', 'md', 'lg', 'xl'];
...@@ -38,6 +40,12 @@ export default { ...@@ -38,6 +40,12 @@ export default {
return this.modalSize === 'md' ? '' : `modal-${this.modalSize}`; return this.modalSize === 'md' ? '' : `modal-${this.modalSize}`;
}, },
}, },
mounted() {
$(this.$el).on('shown.bs.modal', this.opened).on('hidden.bs.modal', this.closed);
},
beforeDestroy() {
$(this.$el).off('shown.bs.modal', this.opened).off('hidden.bs.modal', this.closed);
},
methods: { methods: {
emitCancel(event) { emitCancel(event) {
this.$emit('cancel', event); this.$emit('cancel', event);
...@@ -45,10 +53,11 @@ export default { ...@@ -45,10 +53,11 @@ export default {
emitSubmit(event) { emitSubmit(event) {
this.$emit('submit', event); this.$emit('submit', event);
}, },
opened({ propertyName }) { opened() {
if (propertyName === 'opacity') { this.$emit('open');
this.$emit('open'); },
} closed() {
this.$emit('closed');
}, },
}, },
}; };
...@@ -60,7 +69,6 @@ export default { ...@@ -60,7 +69,6 @@ export default {
class="modal fade" class="modal fade"
tabindex="-1" tabindex="-1"
role="dialog" role="dialog"
@transitionend="opened"
> >
<div <div
:class="modalSizeClass" :class="modalSizeClass"
......
...@@ -72,6 +72,15 @@ export default { ...@@ -72,6 +72,15 @@ export default {
is-new is-new
/> />
<issues-block
v-if="newIssues.length"
:component="component"
:issues="newIssues"
class="js-mr-code-new-issues"
status="failed"
is-new
/>
<issues-block <issues-block
v-if="unresolvedIssues.length" v-if="unresolvedIssues.length"
:component="component" :component="component"
......
...@@ -1377,6 +1377,7 @@ ...@@ -1377,6 +1377,7 @@
.ide-entry-dropdown-toggle { .ide-entry-dropdown-toggle {
padding: $gl-padding-4; padding: $gl-padding-4;
color: $gl-text-color;
background-color: $theme-gray-100; background-color: $theme-gray-100;
&:hover { &:hover {
...@@ -1389,6 +1390,10 @@ ...@@ -1389,6 +1390,10 @@
background-color: $blue-500; background-color: $blue-500;
outline: 0; outline: 0;
} }
svg {
fill: currentColor;
}
} }
.ide-new-btn .dropdown.show .ide-entry-dropdown-toggle { .ide-new-btn .dropdown.show .ide-entry-dropdown-toggle {
......
...@@ -109,24 +109,6 @@ ...@@ -109,24 +109,6 @@
line-height: 21px; line-height: 21px;
} }
.last-commit {
@include str-truncated(506px);
.fa-angle-right {
margin-left: 5px;
}
@include media-breakpoint-only(md) {
@include str-truncated(450px);
}
}
.commit-history-link-spacer {
margin: 0 10px;
color: $white-normal;
}
&:hover:not(.tree-truncated-warning) { &:hover:not(.tree-truncated-warning) {
td { td {
background-color: $row-hover; background-color: $row-hover;
......
...@@ -108,6 +108,7 @@ class ApplicationController < ActionController::Base ...@@ -108,6 +108,7 @@ class ApplicationController < ActionController::Base
def append_info_to_payload(payload) def append_info_to_payload(payload)
super super
payload[:remote_ip] = request.remote_ip payload[:remote_ip] = request.remote_ip
logged_user = auth_user logged_user = auth_user
...@@ -122,12 +123,16 @@ class ApplicationController < ActionController::Base ...@@ -122,12 +123,16 @@ class ApplicationController < ActionController::Base
end end
end end
##
# Controllers such as GitHttpController may use alternative methods # Controllers such as GitHttpController may use alternative methods
# (e.g. tokens) to authenticate the user, whereas Devise sets current_user # (e.g. tokens) to authenticate the user, whereas Devise sets current_user.
#
def auth_user def auth_user
return current_user if current_user.present? if user_signed_in?
current_user
return try(:authenticated_user) else
try(:authenticated_user)
end
end end
# This filter handles personal access tokens, and atom requests with rss tokens # This filter handles personal access tokens, and atom requests with rss tokens
......
# frozen_string_literal: true
class ApplicationSetting class ApplicationSetting
class Term < ActiveRecord::Base class Term < ActiveRecord::Base
include CacheMarkdownField include CacheMarkdownField
......
# frozen_string_literal: true
class GroupBadge < Badge class GroupBadge < Badge
belongs_to :group belongs_to :group
......
# frozen_string_literal: true
class ProjectBadge < Badge class ProjectBadge < Badge
belongs_to :project belongs_to :project
......
# frozen_string_literal: true
module BlobViewer module BlobViewer
module Auxiliary module Auxiliary
extend ActiveSupport::Concern extend ActiveSupport::Concern
......
# frozen_string_literal: true
module BlobViewer module BlobViewer
class Balsamiq < Base class Balsamiq < Base
include Rich include Rich
......
# frozen_string_literal: true
module BlobViewer module BlobViewer
class Base class Base
PARTIAL_PATH_PREFIX = 'projects/blob/viewers'.freeze PARTIAL_PATH_PREFIX = 'projects/blob/viewers'.freeze
......
# frozen_string_literal: true
module BlobViewer module BlobViewer
class BinarySTL < Base class BinarySTL < Base
include Rich include Rich
......
# frozen_string_literal: true
module BlobViewer module BlobViewer
class Cartfile < DependencyManager class Cartfile < DependencyManager
include Static include Static
......
# frozen_string_literal: true
module BlobViewer module BlobViewer
class Changelog < Base class Changelog < Base
include Auxiliary include Auxiliary
......
# frozen_string_literal: true
module BlobViewer module BlobViewer
module ClientSide module ClientSide
extend ActiveSupport::Concern extend ActiveSupport::Concern
......
# frozen_string_literal: true
module BlobViewer module BlobViewer
class ComposerJson < DependencyManager class ComposerJson < DependencyManager
include ServerSide include ServerSide
......
# frozen_string_literal: true
module BlobViewer module BlobViewer
class Contributing < Base class Contributing < Base
include Auxiliary include Auxiliary
......
# frozen_string_literal: true
module BlobViewer module BlobViewer
class DependencyManager < Base class DependencyManager < Base
include Auxiliary include Auxiliary
......
# frozen_string_literal: true
module BlobViewer module BlobViewer
class Download < Base class Download < Base
include Simple include Simple
......
# frozen_string_literal: true
module BlobViewer module BlobViewer
class Empty < Base class Empty < Base
include Simple include Simple
......
# frozen_string_literal: true
module BlobViewer module BlobViewer
class Gemfile < DependencyManager class Gemfile < DependencyManager
include Static include Static
......
# frozen_string_literal: true
module BlobViewer module BlobViewer
class Gemspec < DependencyManager class Gemspec < DependencyManager
include ServerSide include ServerSide
......
# frozen_string_literal: true
module BlobViewer module BlobViewer
class GitlabCiYml < Base class GitlabCiYml < Base
include ServerSide include ServerSide
......
# frozen_string_literal: true
module BlobViewer module BlobViewer
class GodepsJson < DependencyManager class GodepsJson < DependencyManager
include Static include Static
......
# frozen_string_literal: true
module BlobViewer module BlobViewer
class Image < Base class Image < Base
include Rich include Rich
......
# frozen_string_literal: true
module BlobViewer module BlobViewer
class License < Base class License < Base
include Auxiliary include Auxiliary
......
# frozen_string_literal: true
module BlobViewer module BlobViewer
class Markup < Base class Markup < Base
include Rich include Rich
......
# frozen_string_literal: true
module BlobViewer module BlobViewer
class Notebook < Base class Notebook < Base
include Rich include Rich
......
# frozen_string_literal: true
module BlobViewer module BlobViewer
class PackageJson < DependencyManager class PackageJson < DependencyManager
include ServerSide include ServerSide
......
# frozen_string_literal: true
module BlobViewer module BlobViewer
class PDF < Base class PDF < Base
include Rich include Rich
......
# frozen_string_literal: true
module BlobViewer module BlobViewer
class Podfile < DependencyManager class Podfile < DependencyManager
include Static include Static
......
# frozen_string_literal: true
module BlobViewer module BlobViewer
class Podspec < DependencyManager class Podspec < DependencyManager
include ServerSide include ServerSide
......
# frozen_string_literal: true
module BlobViewer module BlobViewer
class PodspecJson < Podspec class PodspecJson < Podspec
self.file_types = %i(podspec_json) self.file_types = %i(podspec_json)
......
# frozen_string_literal: true
module BlobViewer module BlobViewer
class Readme < Base class Readme < Base
include Auxiliary include Auxiliary
......
# frozen_string_literal: true
module BlobViewer module BlobViewer
class RequirementsTxt < DependencyManager class RequirementsTxt < DependencyManager
include Static include Static
......
# frozen_string_literal: true
module BlobViewer module BlobViewer
module Rich module Rich
extend ActiveSupport::Concern extend ActiveSupport::Concern
......
# frozen_string_literal: true
module BlobViewer module BlobViewer
class RouteMap < Base class RouteMap < Base
include ServerSide include ServerSide
......
# frozen_string_literal: true
module BlobViewer module BlobViewer
module ServerSide module ServerSide
extend ActiveSupport::Concern extend ActiveSupport::Concern
......
# frozen_string_literal: true
module BlobViewer module BlobViewer
module Simple module Simple
extend ActiveSupport::Concern extend ActiveSupport::Concern
......
# frozen_string_literal: true
module BlobViewer module BlobViewer
class Sketch < Base class Sketch < Base
include Rich include Rich
......
# frozen_string_literal: true
module BlobViewer module BlobViewer
module Static module Static
extend ActiveSupport::Concern extend ActiveSupport::Concern
......
# frozen_string_literal: true
module BlobViewer module BlobViewer
class SVG < Base class SVG < Base
include Rich include Rich
......
# frozen_string_literal: true
module BlobViewer module BlobViewer
class Text < Base class Text < Base
include Simple include Simple
......
# frozen_string_literal: true
module BlobViewer module BlobViewer
class TextSTL < BinarySTL class TextSTL < BinarySTL
self.binary = false self.binary = false
......
# frozen_string_literal: true
module BlobViewer module BlobViewer
class Video < Base class Video < Base
include Rich include Rich
......
# frozen_string_literal: true
module BlobViewer module BlobViewer
class YarnLock < DependencyManager class YarnLock < DependencyManager
include Static include Static
......
# frozen_string_literal: true
module Ci module Ci
class ArtifactBlob class ArtifactBlob
include BlobLike include BlobLike
......
# frozen_string_literal: true
module Ci module Ci
class Build < CommitStatus class Build < CommitStatus
prepend ArtifactMigratable prepend ArtifactMigratable
......
# frozen_string_literal: true
module Ci module Ci
# The purpose of this class is to store Build related data that can be disposed. # The purpose of this class is to store Build related data that can be disposed.
# Data that should be persisted forever, should be stored with Ci::Build model. # Data that should be persisted forever, should be stored with Ci::Build model.
......
# frozen_string_literal: true
module Ci module Ci
# The purpose of this class is to store Build related runner session. # The purpose of this class is to store Build related runner session.
# Data will be removed after transitioning from running to any state. # Data will be removed after transitioning from running to any state.
......
# frozen_string_literal: true
module Ci module Ci
class BuildTraceChunk < ActiveRecord::Base class BuildTraceChunk < ActiveRecord::Base
include FastDestroyAll include FastDestroyAll
......
# frozen_string_literal: true
module Ci module Ci
module BuildTraceChunks module BuildTraceChunks
class Database class Database
......
# frozen_string_literal: true
module Ci module Ci
module BuildTraceChunks module BuildTraceChunks
class Fog class Fog
......
# frozen_string_literal: true
module Ci module Ci
module BuildTraceChunks module BuildTraceChunks
class Redis class Redis
......
# frozen_string_literal: true
module Ci module Ci
class BuildTraceSection < ActiveRecord::Base class BuildTraceSection < ActiveRecord::Base
extend Gitlab::Ci::Model extend Gitlab::Ci::Model
......
# frozen_string_literal: true
module Ci module Ci
class BuildTraceSectionName < ActiveRecord::Base class BuildTraceSectionName < ActiveRecord::Base
extend Gitlab::Ci::Model extend Gitlab::Ci::Model
......
# frozen_string_literal: true
module Ci module Ci
## ##
# This domain model is a representation of a group of jobs that are related # This domain model is a representation of a group of jobs that are related
......
# frozen_string_literal: true
module Ci module Ci
class GroupVariable < ActiveRecord::Base class GroupVariable < ActiveRecord::Base
extend Gitlab::Ci::Model extend Gitlab::Ci::Model
......
# frozen_string_literal: true
module Ci module Ci
class JobArtifact < ActiveRecord::Base class JobArtifact < ActiveRecord::Base
prepend EE::Ci::JobArtifact prepend EE::Ci::JobArtifact
......
# frozen_string_literal: true
module Ci module Ci
# Currently this is artificial object, constructed dynamically # Currently this is artificial object, constructed dynamically
# We should migrate this object to actual database record in the future # We should migrate this object to actual database record in the future
......
# frozen_string_literal: true
module Ci module Ci
class Pipeline < ActiveRecord::Base class Pipeline < ActiveRecord::Base
extend Gitlab::Ci::Model extend Gitlab::Ci::Model
......
# frozen_string_literal: true
module Ci module Ci
class PipelineSchedule < ActiveRecord::Base class PipelineSchedule < ActiveRecord::Base
extend Gitlab::Ci::Model extend Gitlab::Ci::Model
......
# frozen_string_literal: true
module Ci module Ci
class PipelineScheduleVariable < ActiveRecord::Base class PipelineScheduleVariable < ActiveRecord::Base
extend Gitlab::Ci::Model extend Gitlab::Ci::Model
......
# frozen_string_literal: true
module Ci module Ci
class PipelineVariable < ActiveRecord::Base class PipelineVariable < ActiveRecord::Base
extend Gitlab::Ci::Model extend Gitlab::Ci::Model
......
# frozen_string_literal: true
module Ci module Ci
class Runner < ActiveRecord::Base class Runner < ActiveRecord::Base
extend Gitlab::Ci::Model extend Gitlab::Ci::Model
......
# frozen_string_literal: true
module Ci module Ci
class RunnerNamespace < ActiveRecord::Base class RunnerNamespace < ActiveRecord::Base
extend Gitlab::Ci::Model extend Gitlab::Ci::Model
......
# frozen_string_literal: true
module Ci module Ci
class RunnerProject < ActiveRecord::Base class RunnerProject < ActiveRecord::Base
extend Gitlab::Ci::Model extend Gitlab::Ci::Model
......
# frozen_string_literal: true
module Ci module Ci
class Stage < ActiveRecord::Base class Stage < ActiveRecord::Base
extend Gitlab::Ci::Model extend Gitlab::Ci::Model
......
# frozen_string_literal: true
module Ci module Ci
class Trigger < ActiveRecord::Base class Trigger < ActiveRecord::Base
extend Gitlab::Ci::Model extend Gitlab::Ci::Model
......
# frozen_string_literal: true
module Ci module Ci
class TriggerRequest < ActiveRecord::Base class TriggerRequest < ActiveRecord::Base
extend Gitlab::Ci::Model extend Gitlab::Ci::Model
......
# frozen_string_literal: true
module Ci module Ci
class Variable < ActiveRecord::Base class Variable < ActiveRecord::Base
extend Gitlab::Ci::Model extend Gitlab::Ci::Model
......
# frozen_string_literal: true
module Clusters module Clusters
module Applications module Applications
class Helm < ActiveRecord::Base class Helm < ActiveRecord::Base
......
# frozen_string_literal: true
module Clusters module Clusters
module Applications module Applications
class Ingress < ActiveRecord::Base class Ingress < ActiveRecord::Base
......
# frozen_string_literal: true
module Clusters module Clusters
module Applications module Applications
class Jupyter < ActiveRecord::Base class Jupyter < ActiveRecord::Base
......
# frozen_string_literal: true
module Clusters module Clusters
module Applications module Applications
class Prometheus < ActiveRecord::Base class Prometheus < ActiveRecord::Base
......
# frozen_string_literal: true
module Clusters module Clusters
module Applications module Applications
class Runner < ActiveRecord::Base class Runner < ActiveRecord::Base
......
# frozen_string_literal: true
module Clusters module Clusters
class Cluster < ActiveRecord::Base class Cluster < ActiveRecord::Base
prepend EE::Clusters::Cluster prepend EE::Clusters::Cluster
......
# frozen_string_literal: true
module Clusters module Clusters
module Concerns module Concerns
module ApplicationCore module ApplicationCore
......
# frozen_string_literal: true
module Clusters module Clusters
module Concerns module Concerns
module ApplicationData module ApplicationData
......
# frozen_string_literal: true
module Clusters module Clusters
module Concerns module Concerns
module ApplicationStatus module ApplicationStatus
......
# frozen_string_literal: true
module Clusters module Clusters
module Platforms module Platforms
class Kubernetes < ActiveRecord::Base class Kubernetes < ActiveRecord::Base
......
# frozen_string_literal: true
module Clusters module Clusters
class Project < ActiveRecord::Base class Project < ActiveRecord::Base
self.table_name = 'cluster_projects' self.table_name = 'cluster_projects'
......
# frozen_string_literal: true
module Clusters module Clusters
module Providers module Providers
class Gcp < ActiveRecord::Base class Gcp < ActiveRecord::Base
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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