summaryrefslogtreecommitdiff
path: root/app/assets
diff options
context:
space:
mode:
authorFilipa Lacerda <filipa@gitlab.com>2018-08-03 10:00:48 +0000
committerFilipa Lacerda <filipa@gitlab.com>2018-08-03 10:00:48 +0000
commitb901df220c9411eba4f541ac91b3e275a0dfa1df (patch)
tree5a295fe884ed9a2199eba6dadd089739e5f149be /app/assets
parent972854078bb9d02f857ed95bea1cc3c98c039d2e (diff)
parent19eecd01fada302afe814a485172d699c96d44e8 (diff)
downloadgitlab-ce-b901df220c9411eba4f541ac91b3e275a0dfa1df.tar.gz
Merge branch 'ide-rename-files' into 'master'
Enable renaming files & folders in the Web IDE Closes #44845 See merge request gitlab-org/gitlab-ce!20835
Diffstat (limited to 'app/assets')
-rw-r--r--app/assets/javascripts/ide/components/new_dropdown/index.vue15
-rw-r--r--app/assets/javascripts/ide/components/new_dropdown/modal.vue46
-rw-r--r--app/assets/javascripts/ide/components/repo_file.vue6
-rw-r--r--app/assets/javascripts/ide/constants.js5
-rw-r--r--app/assets/javascripts/ide/services/index.js2
-rw-r--r--app/assets/javascripts/ide/stores/actions.js30
-rw-r--r--app/assets/javascripts/ide/stores/actions/file.js23
-rw-r--r--app/assets/javascripts/ide/stores/actions/tree.js10
-rw-r--r--app/assets/javascripts/ide/stores/getters.js4
-rw-r--r--app/assets/javascripts/ide/stores/mutation_types.js3
-rw-r--r--app/assets/javascripts/ide/stores/mutations.js63
-rw-r--r--app/assets/javascripts/ide/stores/mutations/file.js30
-rw-r--r--app/assets/javascripts/ide/stores/mutations/tree.js11
-rw-r--r--app/assets/javascripts/ide/stores/state.js3
-rw-r--r--app/assets/javascripts/ide/stores/utils.js24
-rw-r--r--app/assets/javascripts/vue_shared/components/gl_modal.vue18
-rw-r--r--app/assets/stylesheets/page_bundles/ide.scss5
17 files changed, 243 insertions, 55 deletions
diff --git a/app/assets/javascripts/ide/components/new_dropdown/index.vue b/app/assets/javascripts/ide/components/new_dropdown/index.vue
index 8eddfa5e455..f02fd6cf7ea 100644
--- a/app/assets/javascripts/ide/components/new_dropdown/index.vue
+++ b/app/assets/javascripts/ide/components/new_dropdown/index.vue
@@ -4,6 +4,7 @@ import icon from '~/vue_shared/components/icon.vue';
import newModal from './modal.vue';
import upload from './upload.vue';
import ItemButton from './button.vue';
+import { modalTypes } from '../../constants';
export default {
components: {
@@ -56,6 +57,7 @@ export default {
this.dropdownOpen = !this.dropdownOpen;
},
},
+ modalTypes,
};
</script>
@@ -74,7 +76,7 @@ export default {
@click.stop="openDropdown()"
>
<icon
- name="hamburger"
+ name="ellipsis_v"
/>
<icon
name="arrow-down"
@@ -106,13 +108,22 @@ export default {
class="d-flex"
icon="folder-new"
icon-classes="mr-2"
- @click="createNewItem('tree')"
+ @click="createNewItem($options.modalTypes.tree)"
/>
</li>
<li class="divider"></li>
</template>
<li>
<item-button
+ :label="__('Rename')"
+ class="d-flex"
+ icon="pencil"
+ icon-classes="mr-2"
+ @click="createNewItem($options.modalTypes.rename)"
+ />
+ </li>
+ <li>
+ <item-button
:label="__('Delete')"
class="d-flex"
icon="remove"
diff --git a/app/assets/javascripts/ide/components/new_dropdown/modal.vue b/app/assets/javascripts/ide/components/new_dropdown/modal.vue
index 833c4b027df..e500ef0e1b5 100644
--- a/app/assets/javascripts/ide/components/new_dropdown/modal.vue
+++ b/app/assets/javascripts/ide/components/new_dropdown/modal.vue
@@ -2,6 +2,7 @@
import { __ } from '~/locale';
import { mapActions, mapState } from 'vuex';
import GlModal from '~/vue_shared/components/gl_modal.vue';
+import { modalTypes } from '../../constants';
export default {
components: {
@@ -13,42 +14,58 @@ export default {
};
},
computed: {
- ...mapState(['newEntryModal']),
+ ...mapState(['entryModal']),
entryName: {
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) {
this.name = val;
},
},
modalTitle() {
- if (this.newEntryModal.type === 'tree') {
+ if (this.entryModal.type === modalTypes.tree) {
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');
},
buttonLabel() {
- if (this.newEntryModal.type === 'tree') {
+ if (this.entryModal.type === modalTypes.tree) {
return __('Create directory');
+ } else if (this.entryModal.type === modalTypes.rename) {
+ return this.entryModal.entry.type === modalTypes.tree ? __('Rename folder') : __('Rename file');
}
return __('Create file');
},
},
methods: {
- ...mapActions(['createTempEntry']),
- createEntryInStore() {
- this.createTempEntry({
- name: this.name,
- type: this.newEntryModal.type,
- });
+ ...mapActions(['createTempEntry', 'renameEntry']),
+ submitForm() {
+ if (this.entryModal.type === modalTypes.rename) {
+ this.renameEntry({
+ path: this.entryModal.entry.path,
+ name: this.entryName,
+ });
+ } else {
+ this.createTempEntry({
+ name: this.name,
+ type: this.entryModal.type,
+ });
+ }
},
focusInput() {
- setTimeout(() => {
- this.$refs.fieldName.focus();
- });
+ this.$refs.fieldName.focus();
+ },
+ closedModal() {
+ this.name = '';
},
},
};
@@ -60,8 +77,9 @@ export default {
:header-title-text="modalTitle"
:footer-primary-button-text="buttonLabel"
footer-primary-button-variant="success"
- @submit="createEntryInStore"
+ @submit="submitForm"
@open="focusInput"
+ @closed="closedModal"
>
<div
class="form-group row"
diff --git a/app/assets/javascripts/ide/components/repo_file.vue b/app/assets/javascripts/ide/components/repo_file.vue
index eb4a927fe0d..dbdf0be2809 100644
--- a/app/assets/javascripts/ide/components/repo_file.vue
+++ b/app/assets/javascripts/ide/components/repo_file.vue
@@ -134,8 +134,7 @@ export default {
.replace(/[/]$/g, '');
// - strip ending "/"
- const filePath = this.file.path
- .replace(/[/]$/g, '');
+ const filePath = this.file.path.replace(/[/]$/g, '');
return filePath === routePath;
},
@@ -194,7 +193,7 @@ export default {
data-container="body"
data-placement="right"
name="file-modified"
- css-classes="prepend-left-5 multi-file-modified"
+ css-classes="prepend-left-5 ide-file-modified"
/>
</span>
<changed-file-icon
@@ -208,7 +207,6 @@ export default {
</span>
<new-dropdown
:type="file.type"
- :branch="file.branchId"
:path="file.path"
:mouse-over="mouseOver"
class="float-right prepend-left-8"
diff --git a/app/assets/javascripts/ide/constants.js b/app/assets/javascripts/ide/constants.js
index 0b514f31467..d3ac57471c9 100644
--- a/app/assets/javascripts/ide/constants.js
+++ b/app/assets/javascripts/ide/constants.js
@@ -53,3 +53,8 @@ export const commitItemIconMap = {
class: 'ide-file-deletion',
},
};
+
+export const modalTypes = {
+ rename: 'rename',
+ tree: 'tree',
+};
diff --git a/app/assets/javascripts/ide/services/index.js b/app/assets/javascripts/ide/services/index.js
index cb93fba1665..f0193d8e8ea 100644
--- a/app/assets/javascripts/ide/services/index.js
+++ b/app/assets/javascripts/ide/services/index.js
@@ -8,7 +8,7 @@ export default {
});
},
getRawFileData(file) {
- if (file.tempFile) {
+ if (file.tempFile && !file.prevPath) {
return Promise.resolve(file.content);
}
diff --git a/app/assets/javascripts/ide/stores/actions.js b/app/assets/javascripts/ide/stores/actions.js
index 2765acada48..aa02dfbddc4 100644
--- a/app/assets/javascripts/ide/stores/actions.js
+++ b/app/assets/javascripts/ide/stores/actions.js
@@ -186,13 +186,39 @@ export const openNewEntryModal = ({ commit }, { type, path = '' }) => {
};
export const deleteEntry = ({ commit, dispatch, state }, path) => {
- dispatch('burstUnusedSeal');
- dispatch('closeFile', state.entries[path]);
+ const entry = 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);
+
+ 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 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/file';
export * from './actions/project';
diff --git a/app/assets/javascripts/ide/stores/actions/file.js b/app/assets/javascripts/ide/stores/actions/file.js
index b343750f789..9e3f5da4676 100644
--- a/app/assets/javascripts/ide/stores/actions/file.js
+++ b/app/assets/javascripts/ide/stores/actions/file.js
@@ -62,14 +62,14 @@ export const setFileActive = ({ commit, state, getters, dispatch }, path) => {
export const getFileData = ({ state, commit, dispatch }, { path, makeFileActive = true }) => {
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 });
+ const url = file.prevPath ? file.url.replace(file.path, file.prevPath) : file.url;
+
return service
- .getFileData(
- `${gon.relative_url_root ? gon.relative_url_root : ''}${file.url.replace('/-/', '/')}`,
- )
+ .getFileData(`${gon.relative_url_root ? gon.relative_url_root : ''}${url.replace('/-/', '/')}`)
.then(({ data, headers }) => {
const normalizedHeaders = normalizeHeaders(headers);
setPageTitle(decodeURI(normalizedHeaders['PAGE-TITLE']));
@@ -101,7 +101,7 @@ export const getRawFileData = ({ state, commit, dispatch }, { path, baseSha }) =
service
.getRawFileData(file)
.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) {
service
.getBaseRawFileData(file, baseSha)
@@ -176,9 +176,22 @@ export const setFileViewMode = ({ commit }, { file, viewMode }) => {
export const discardFileChanges = ({ dispatch, state, commit, getters }, 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.REMOVE_FILE_FROM_CHANGED, path);
+ if (file.prevPath) {
+ dispatch('discardFileChanges', file.prevPath);
+ }
+
if (file.tempFile && file.opened) {
commit(types.TOGGLE_FILE_OPEN, path);
} else if (getters.activeFile && file.path === getters.activeFile.path) {
diff --git a/app/assets/javascripts/ide/stores/actions/tree.js b/app/assets/javascripts/ide/stores/actions/tree.js
index acb6ef5e6d4..9288bbe32f5 100644
--- a/app/assets/javascripts/ide/stores/actions/tree.js
+++ b/app/assets/javascripts/ide/stores/actions/tree.js
@@ -89,3 +89,13 @@ export const getFiles = ({ state, commit, dispatch }, { projectId, branchId } =
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);
+ }
+};
diff --git a/app/assets/javascripts/ide/stores/getters.js b/app/assets/javascripts/ide/stores/getters.js
index 5ce268b0d05..79cdb494e5a 100644
--- a/app/assets/javascripts/ide/stores/getters.js
+++ b/app/assets/javascripts/ide/stores/getters.js
@@ -67,9 +67,9 @@ export const someUncommitedChanges = state =>
!!(state.changedFiles.length || state.stagedFiles.length);
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(
- f => filePathMatches(f, path) && !getChangedFile(state)(f.path),
+ f => filePathMatches(f.path, path) && !getChangedFile(state)(f.path),
).length;
return changedFilesCount + stagedFilesCount;
diff --git a/app/assets/javascripts/ide/stores/mutation_types.js b/app/assets/javascripts/ide/stores/mutation_types.js
index dae60f4d65a..5a7991d2fa7 100644
--- a/app/assets/javascripts/ide/stores/mutation_types.js
+++ b/app/assets/javascripts/ide/stores/mutation_types.js
@@ -77,3 +77,6 @@ export const SET_ERROR_MESSAGE = 'SET_ERROR_MESSAGE';
export const OPEN_NEW_ENTRY_MODAL = 'OPEN_NEW_ENTRY_MODAL';
export const DELETE_ENTRY = 'DELETE_ENTRY';
+export const RENAME_ENTRY = 'RENAME_ENTRY';
+
+export const RESTORE_TREE = 'RESTORE_TREE';
diff --git a/app/assets/javascripts/ide/stores/mutations.js b/app/assets/javascripts/ide/stores/mutations.js
index 799c2f51e8d..d0bf847dbde 100644
--- a/app/assets/javascripts/ide/stores/mutations.js
+++ b/app/assets/javascripts/ide/stores/mutations.js
@@ -131,11 +131,14 @@ export default {
},
[types.UPDATE_FILE_AFTER_COMMIT](state, { file, lastCommit }) {
const changedFile = state.changedFiles.find(f => f.path === file.path);
+ const { prevPath } = file;
Object.assign(state.entries[file.path], {
raw: file.content,
changed: !!changedFile,
staged: false,
+ prevPath: '',
+ moved: false,
lastCommit: Object.assign(state.entries[file.path].lastCommit, {
id: lastCommit.commit.id,
url: lastCommit.commit_path,
@@ -144,6 +147,18 @@ export default {
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) {
Object.assign(state, {
@@ -169,7 +184,11 @@ export default {
},
[types.OPEN_NEW_ENTRY_MODAL](state, { type, path }) {
Object.assign(state, {
- newEntryModal: { type, path },
+ entryModal: {
+ type,
+ path,
+ entry: { ...state.entries[path] },
+ },
});
},
[types.DELETE_ENTRY](state, path) {
@@ -179,8 +198,48 @@ export default {
: state.trees[`${state.currentProjectId}/${state.currentBranchId}`];
entry.deleted = true;
- state.changedFiles = state.changedFiles.concat(entry);
+
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,
...mergeRequestMutation,
diff --git a/app/assets/javascripts/ide/stores/mutations/file.js b/app/assets/javascripts/ide/stores/mutations/file.js
index 9a87d50d6d5..c75add39bcd 100644
--- a/app/assets/javascripts/ide/stores/mutations/file.js
+++ b/app/assets/javascripts/ide/stores/mutations/file.js
@@ -53,15 +53,25 @@ export default {
},
[types.SET_FILE_RAW_DATA](state, { file, raw }) {
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], {
- raw,
- });
+ if (file.tempFile) {
+ 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;
+ } else if (openPendingFile.tempFile) {
+ openPendingFile.content = raw;
}
},
[types.SET_FILE_BASE_RAW_DATA](state, { file, baseRaw }) {
@@ -119,12 +129,14 @@ export default {
[types.DISCARD_FILE_CHANGES](state, path) {
const stagedFile = state.stagedFiles.find(f => f.path === path);
const entry = state.entries[path];
- const { deleted } = entry;
+ const { deleted, prevPath } = entry;
Object.assign(state.entries[path], {
content: stagedFile ? stagedFile.content : state.entries[path].raw,
changed: false,
deleted: false,
+ moved: false,
+ movedPath: '',
});
if (deleted) {
@@ -133,6 +145,12 @@ export default {
: state.trees[`${state.currentProjectId}/${state.currentBranchId}`];
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) {
diff --git a/app/assets/javascripts/ide/stores/mutations/tree.js b/app/assets/javascripts/ide/stores/mutations/tree.js
index 2cf34af9274..eac7441ee54 100644
--- a/app/assets/javascripts/ide/stores/mutations/tree.js
+++ b/app/assets/javascripts/ide/stores/mutations/tree.js
@@ -1,4 +1,5 @@
import * as types from '../mutation_types';
+import { sortTree } from '../utils';
export default {
[types.TOGGLE_TREE_OPEN](state, path) {
@@ -36,4 +37,14 @@ export default {
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));
+ }
+ },
};
diff --git a/app/assets/javascripts/ide/stores/state.js b/app/assets/javascripts/ide/stores/state.js
index 0f32a267469..2371b201f8c 100644
--- a/app/assets/javascripts/ide/stores/state.js
+++ b/app/assets/javascripts/ide/stores/state.js
@@ -26,8 +26,9 @@ export default () => ({
rightPane: null,
links: {},
errorMessage: null,
- newEntryModal: {
+ entryModal: {
type: '',
path: '',
+ entry: {},
},
});
diff --git a/app/assets/javascripts/ide/stores/utils.js b/app/assets/javascripts/ide/stores/utils.js
index bf7ab93ff5e..0ede76fd1e0 100644
--- a/app/assets/javascripts/ide/stores/utils.js
+++ b/app/assets/javascripts/ide/stores/utils.js
@@ -47,6 +47,9 @@ export const dataStructure = () => ({
lastOpenedAt: 0,
mrChange: null,
deleted: false,
+ prevPath: '',
+ movedPath: '',
+ moved: false,
});
export const decorateData = entity => {
@@ -107,7 +110,9 @@ export const setPageTitle = title => {
};
export const commitActionForFile = file => {
- if (file.deleted) {
+ if (file.prevPath) {
+ return 'move';
+ } else if (file.deleted) {
return 'delete';
} else if (file.tempFile) {
return 'create';
@@ -116,15 +121,12 @@ export const commitActionForFile = file => {
return 'update';
};
-export const getCommitFiles = (stagedFiles, deleteTree = false) =>
+export const getCommitFiles = stagedFiles =>
stagedFiles.reduce((acc, file) => {
- if ((file.deleted || deleteTree) && file.type === 'tree') {
- return acc.concat(getCommitFiles(file.tree, true));
- }
+ if (file.moved) return acc;
return acc.concat({
...file,
- deleted: deleteTree || file.deleted,
});
}, []);
@@ -134,9 +136,10 @@ export const createCommitPayload = ({ branch, getters, newBranch, state, rootSta
actions: getCommitFiles(rootState.stagedFiles).map(f => ({
action: commitActionForFile(f),
file_path: f.path,
- content: f.content,
+ previous_path: f.prevPath === '' ? undefined : f.prevPath,
+ content: f.content || undefined,
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,
});
@@ -164,8 +167,7 @@ export const sortTree = sortedTree =>
)
.sort(sortTreesByTypeAndName);
-export const filePathMatches = (f, path) =>
- f.path.replace(new RegExp(`${f.name}$`), '').indexOf(`${path}/`) === 0;
+export const filePathMatches = (filePath, path) => filePath.indexOf(`${path}/`) === 0;
export const getChangesCountForFiles = (files, path) =>
- files.filter(f => filePathMatches(f, path)).length;
+ files.filter(f => filePathMatches(f.path, path)).length;
diff --git a/app/assets/javascripts/vue_shared/components/gl_modal.vue b/app/assets/javascripts/vue_shared/components/gl_modal.vue
index 416eda796a7..b023c5cfeb1 100644
--- a/app/assets/javascripts/vue_shared/components/gl_modal.vue
+++ b/app/assets/javascripts/vue_shared/components/gl_modal.vue
@@ -1,4 +1,6 @@
<script>
+import $ from 'jquery';
+
const buttonVariants = ['danger', 'primary', 'success', 'warning'];
const sizeVariants = ['sm', 'md', 'lg', 'xl'];
@@ -38,6 +40,12 @@ export default {
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: {
emitCancel(event) {
this.$emit('cancel', event);
@@ -45,10 +53,11 @@ export default {
emitSubmit(event) {
this.$emit('submit', event);
},
- opened({ propertyName }) {
- if (propertyName === 'opacity') {
- this.$emit('open');
- }
+ opened() {
+ this.$emit('open');
+ },
+ closed() {
+ this.$emit('closed');
},
},
};
@@ -60,7 +69,6 @@ export default {
class="modal fade"
tabindex="-1"
role="dialog"
- @transitionend="opened"
>
<div
:class="modalSizeClass"
diff --git a/app/assets/stylesheets/page_bundles/ide.scss b/app/assets/stylesheets/page_bundles/ide.scss
index 442aef124d3..58ed5bf6455 100644
--- a/app/assets/stylesheets/page_bundles/ide.scss
+++ b/app/assets/stylesheets/page_bundles/ide.scss
@@ -1377,6 +1377,7 @@
.ide-entry-dropdown-toggle {
padding: $gl-padding-4;
+ color: $gl-text-color;
background-color: $theme-gray-100;
&:hover {
@@ -1389,6 +1390,10 @@
background-color: $blue-500;
outline: 0;
}
+
+ svg {
+ fill: currentColor;
+ }
}
.ide-new-btn .dropdown.show .ide-entry-dropdown-toggle {