Commit e5170caa authored by Stan Hu's avatar Stan Hu

Merge branch 'master' into tc-hotfix-geo-cursor-gaps

parents 81264452 63e4129d
...@@ -572,13 +572,12 @@ setup-test-env: ...@@ -572,13 +572,12 @@ setup-test-env:
- vendor/gitaly-ruby - vendor/gitaly-ruby
danger-review: danger-review:
image: registry.gitlab.com/gitlab-org/gitaly/dangercontainer:latest image: registry.gitlab.com/gitlab-org/gitlab-build-images:danger
stage: test stage: test
allow_failure: true allow_failure: true
before_script:
- source scripts/utils.sh
- retry gem install danger --no-ri --no-rdoc
cache: {} cache: {}
dependencies: []
before_script: []
only: only:
variables: variables:
- $DANGER_GITLAB_API_TOKEN - $DANGER_GITLAB_API_TOKEN
......
Please view this file on the master branch, on stable branches it's out of date. Please view this file on the master branch, on stable branches it's out of date.
## 11.1.3 (2018-07-27)
### Fixed (1 change)
- Resolve Environments dropdown is showing on the cluster health page. !6528
## 11.1.2 (2018-07-26)
### Security (1 change)
- Don't expose project names in EE counters.
## 11.1.1 (2018-07-23) ## 11.1.1 (2018-07-23)
### Fixed (2 changes) ### Fixed (2 changes)
...@@ -75,6 +89,13 @@ Please view this file on the master branch, on stable branches it's out of date. ...@@ -75,6 +89,13 @@ Please view this file on the master branch, on stable branches it's out of date.
- Geo - Make Geo repository verification flag opt-out by default. !6369 - Geo - Make Geo repository verification flag opt-out by default. !6369
## 11.0.5 (2018-07-26)
### Security (1 change)
- Don't expose project names in EE counters.
## 11.0.4 (2018-07-17) ## 11.0.4 (2018-07-17)
- No changes. - No changes.
......
...@@ -2,6 +2,42 @@ ...@@ -2,6 +2,42 @@
documentation](doc/development/changelog.md) for instructions on adding your own documentation](doc/development/changelog.md) for instructions on adding your own
entry. entry.
## 11.1.3 (2018-07-27)
### Fixed (8 changes, 1 of them is from the community)
- Rework some projects table indexes around repository_storage field. !20377
- Fix navigation to First and Next discussion on MR Changes tab. !20434
- Fix showing outdated discussions on Changes tab. !20445
- Fix autosave and ESC confirmation issues for MR discussions. !20569
- Fix rendering of the context lines in MR diffs page. !20642
- Don't overflow project/group dropdown results. !20704 (gfyoung)
- Fixed IDE not opening JSON files. !20798
- Disable Gitaly timeouts when creating or restoring backups. !20810
### Performance (1 change)
- Reduces the client side memory footprint on merge requests. !20744
## 11.1.2 (2018-07-26)
### Security (4 changes)
- Adding CSRF protection to Hooks test action.
- Don't expose project names in GitHub counters.
- Don't expose project names in various counters.
- Fixed XSS in branch name in Web IDE.
### Fixed (1 change)
- Escapes milestone and label's names on flash notice when promoting them.
### Performance (1 change)
- Fix slow Markdown rendering. !20820
## 11.1.1 (2018-07-23) ## 11.1.1 (2018-07-23)
### Fixed (2 changes) ### Fixed (2 changes)
...@@ -253,6 +289,20 @@ entry. ...@@ -253,6 +289,20 @@ entry.
- Use monospaced font for MR diff commit link ref on GFM. - Use monospaced font for MR diff commit link ref on GFM.
## 11.0.5 (2018-07-26)
### Security (4 changes)
- Don't expose project names in various counters.
- Don't expose project names in GitHub counters.
- Adding CSRF protection to Hooks test action.
- Fixed XSS in branch name in Web IDE.
### Fixed (1 change)
- Escapes milestone and label's names on flash notice when promoting them.
## 11.0.4 (2018-07-17) ## 11.0.4 (2018-07-17)
### Security (1 change) ### Security (1 change)
......
...@@ -402,7 +402,8 @@ GEM ...@@ -402,7 +402,8 @@ GEM
googleauth (>= 0.5.1, < 0.7) googleauth (>= 0.5.1, < 0.7)
gssapi (1.2.0) gssapi (1.2.0)
ffi (>= 1.0.1) ffi (>= 1.0.1)
haml (4.0.7) haml (5.0.4)
temple (>= 0.8.0)
tilt tilt
haml_lint (0.26.0) haml_lint (0.26.0)
haml (>= 4.0, < 5.1) haml (>= 4.0, < 5.1)
......
...@@ -93,7 +93,7 @@ export default { ...@@ -93,7 +93,7 @@ export default {
<icon <icon
:size="16" :size="16"
class="prepend-left-8 append-right-8" class="prepend-left-8 append-right-8"
name="doc_image" name="doc-image"
aria-hidden="true" aria-hidden="true"
/> />
</div> </div>
......
...@@ -3,6 +3,7 @@ import tooltip from '~/vue_shared/directives/tooltip'; ...@@ -3,6 +3,7 @@ import tooltip from '~/vue_shared/directives/tooltip';
import Icon from '~/vue_shared/components/icon.vue'; import Icon from '~/vue_shared/components/icon.vue';
import { pluralize } from '~/lib/utils/text_utility'; import { pluralize } from '~/lib/utils/text_utility';
import { __, sprintf } from '~/locale'; import { __, sprintf } from '~/locale';
import { getCommitIconMap } from '../utils';
export default { export default {
components: { components: {
...@@ -34,16 +35,14 @@ export default { ...@@ -34,16 +35,14 @@ export default {
}, },
computed: { computed: {
changedIcon() { changedIcon() {
const suffix = this.file.staged && !this.showStagedIcon ? '-solid' : ''; const suffix = !this.file.changed && this.file.staged && !this.showStagedIcon ? '-solid' : '';
return this.file.tempFile && !this.forceModifiedIcon
? `file-addition${suffix}` if (this.forceModifiedIcon) return `file-modified${suffix}`;
: `file-modified${suffix}`;
}, return `${getCommitIconMap(this.file).icon}${suffix}`;
stagedIcon() {
return `${this.changedIcon}-solid`;
}, },
changedIconClass() { changedIconClass() {
return `multi-${this.changedIcon} float-left`; return `ide-${this.changedIcon} float-left`;
}, },
tooltipTitle() { tooltipTitle() {
if (!this.showTooltip) return undefined; if (!this.showTooltip) return undefined;
...@@ -66,6 +65,9 @@ export default { ...@@ -66,6 +65,9 @@ export default {
return undefined; return undefined;
}, },
showIcon() {
return this.file.changed || this.file.tempFile || this.file.staged || this.file.deleted;
},
}, },
}; };
</script> </script>
...@@ -79,7 +81,7 @@ export default { ...@@ -79,7 +81,7 @@ export default {
class="ide-file-changed-icon" class="ide-file-changed-icon"
> >
<icon <icon
v-if="file.changed || file.tempFile || file.staged" v-if="showIcon"
:name="changedIcon" :name="changedIcon"
:size="12" :size="12"
:css-classes="changedIconClass" :css-classes="changedIconClass"
......
...@@ -5,6 +5,7 @@ import Icon from '~/vue_shared/components/icon.vue'; ...@@ -5,6 +5,7 @@ import Icon from '~/vue_shared/components/icon.vue';
import StageButton from './stage_button.vue'; import StageButton from './stage_button.vue';
import UnstageButton from './unstage_button.vue'; import UnstageButton from './unstage_button.vue';
import { viewerTypes } from '../../constants'; import { viewerTypes } from '../../constants';
import { getCommitIconMap } from '../../utils';
export default { export default {
components: { components: {
...@@ -42,11 +43,12 @@ export default { ...@@ -42,11 +43,12 @@ export default {
}, },
computed: { computed: {
iconName() { iconName() {
const prefix = this.stagedList ? '-solid' : ''; const suffix = this.stagedList ? '-solid' : '';
return this.file.tempFile ? `file-addition${prefix}` : `file-modified${prefix}`;
return `${getCommitIconMap(this.file).icon}${suffix}`;
}, },
iconClass() { iconClass() {
return `multi-file-${this.file.tempFile ? 'addition' : 'modified'} append-right-8`; return `${getCommitIconMap(this.file).class} append-right-8`;
}, },
fullKey() { fullKey() {
return `${this.keyPrefix}-${this.file.key}`; return `${this.keyPrefix}-${this.file.key}`;
...@@ -67,6 +69,8 @@ export default { ...@@ -67,6 +69,8 @@ export default {
'stageChange', 'stageChange',
]), ]),
openFileInEditor() { openFileInEditor() {
if (this.file.type === 'tree') return null;
return this.openPendingTab({ return this.openPendingTab({
file: this.file, file: this.file,
keyPrefix: this.keyPrefix, keyPrefix: this.keyPrefix,
......
...@@ -56,7 +56,7 @@ export default { ...@@ -56,7 +56,7 @@ export default {
> >
<icon <icon
:size="12" :size="12"
name="more" name="ellipsis_h"
/> />
</button> </button>
<div class="dropdown-menu dropdown-menu-right"> <div class="dropdown-menu dropdown-menu-right">
......
...@@ -10,7 +10,7 @@ export default { ...@@ -10,7 +10,7 @@ export default {
EditorModeDropdown, EditorModeDropdown,
}, },
computed: { computed: {
...mapGetters(['currentMergeRequest']), ...mapGetters(['currentMergeRequest', 'activeFile']),
...mapState(['viewer', 'currentMergeRequestId']), ...mapState(['viewer', 'currentMergeRequestId']),
showLatestChangesText() { showLatestChangesText() {
return !this.currentMergeRequestId || this.viewer === viewerTypes.diff; return !this.currentMergeRequestId || this.viewer === viewerTypes.diff;
...@@ -23,12 +23,20 @@ export default { ...@@ -23,12 +23,20 @@ export default {
}, },
}, },
mounted() { mounted() {
if (this.activeFile && this.activeFile.pending && !this.activeFile.deleted) {
this.$router.push(`/project${this.activeFile.url}`, () => {
this.updateViewer('editor');
});
} else if (this.activeFile && this.activeFile.deleted) {
this.resetOpenFiles();
}
this.$nextTick(() => { this.$nextTick(() => {
this.updateViewer(this.currentMergeRequestId ? viewerTypes.mr : viewerTypes.diff); this.updateViewer(this.currentMergeRequestId ? viewerTypes.mr : viewerTypes.diff);
}); });
}, },
methods: { methods: {
...mapActions(['updateViewer']), ...mapActions(['updateViewer', 'resetOpenFiles']),
}, },
}; };
</script> </script>
...@@ -36,7 +44,6 @@ export default { ...@@ -36,7 +44,6 @@ export default {
<template> <template>
<ide-tree-list <ide-tree-list
:viewer-type="viewer" :viewer-type="viewer"
:disable-action-dropdown="true"
header-class="ide-review-header" header-class="ide-review-header"
> >
<template <template
......
...@@ -17,14 +17,18 @@ export default { ...@@ -17,14 +17,18 @@ export default {
...mapGetters(['currentProject', 'currentTree', 'activeFile']), ...mapGetters(['currentProject', 'currentTree', 'activeFile']),
}, },
mounted() { mounted() {
if (this.activeFile && this.activeFile.pending) { if (!this.activeFile) return;
if (this.activeFile.pending && !this.activeFile.deleted) {
this.$router.push(`/project${this.activeFile.url}`, () => { this.$router.push(`/project${this.activeFile.url}`, () => {
this.updateViewer('editor'); this.updateViewer('editor');
}); });
} else if (this.activeFile.deleted) {
this.resetOpenFiles();
} }
}, },
methods: { methods: {
...mapActions(['updateViewer', 'openNewEntryModal', 'createTempEntry']), ...mapActions(['updateViewer', 'openNewEntryModal', 'createTempEntry', 'resetOpenFiles']),
}, },
}; };
</script> </script>
......
...@@ -22,11 +22,6 @@ export default { ...@@ -22,11 +22,6 @@ export default {
required: false, required: false,
default: null, default: null,
}, },
disableActionDropdown: {
type: Boolean,
required: false,
default: false,
},
}, },
computed: { computed: {
...mapState(['currentBranchId']), ...mapState(['currentBranchId']),
...@@ -69,7 +64,6 @@ export default { ...@@ -69,7 +64,6 @@ export default {
:key="file.key" :key="file.key"
:file="file" :file="file"
:level="0" :level="0"
:disable-action-dropdown="disableActionDropdown"
/> />
</template> </template>
</div> </div>
......
...@@ -13,7 +13,7 @@ export default { ...@@ -13,7 +13,7 @@ export default {
ItemButton, ItemButton,
}, },
props: { props: {
branch: { type: {
type: String, type: String,
required: true, required: true,
}, },
...@@ -45,7 +45,7 @@ export default { ...@@ -45,7 +45,7 @@ export default {
}, },
}, },
methods: { methods: {
...mapActions(['createTempEntry', 'openNewEntryModal']), ...mapActions(['createTempEntry', 'openNewEntryModal', 'deleteEntry']),
createNewItem(type) { createNewItem(type) {
this.openNewEntryModal({ type, path: this.path }); this.openNewEntryModal({ type, path: this.path });
this.dropdownOpen = false; this.dropdownOpen = false;
...@@ -82,6 +82,7 @@ export default { ...@@ -82,6 +82,7 @@ export default {
ref="dropdownMenu" ref="dropdownMenu"
class="dropdown-menu dropdown-menu-right" class="dropdown-menu dropdown-menu-right"
> >
<template v-if="type === 'tree'">
<li> <li>
<item-button <item-button
:label="__('New file')" :label="__('New file')"
...@@ -106,6 +107,17 @@ export default { ...@@ -106,6 +107,17 @@ export default {
@click="createNewItem('tree')" @click="createNewItem('tree')"
/> />
</li> </li>
<li class="divider"></li>
</template>
<li>
<item-button
:label="__('Delete')"
class="d-flex"
icon="remove"
icon-classes="mr-2"
@click="deleteEntry(path)"
/>
</li>
</ul> </ul>
</div> </div>
</div> </div>
......
...@@ -44,7 +44,7 @@ export default { ...@@ -44,7 +44,7 @@ export default {
}, },
}, },
mounted() { mounted() {
if (this.lastOpenedFile) { if (this.lastOpenedFile && this.lastOpenedFile.type !== 'tree') {
this.openPendingTab({ this.openPendingTab({
file: this.lastOpenedFile, file: this.lastOpenedFile,
keyPrefix: this.lastOpenedFile.changed ? stageKeys.unstaged : stageKeys.staged, keyPrefix: this.lastOpenedFile.changed ? stageKeys.unstaged : stageKeys.staged,
......
...@@ -87,7 +87,9 @@ export default { ...@@ -87,7 +87,9 @@ export default {
this.editor.updateDimensions(); this.editor.updateDimensions();
}, },
viewer() { viewer() {
if (!this.file.pending) {
this.createEditorInstance(); this.createEditorInstance();
}
}, },
panelResizing() { panelResizing() {
if (!this.panelResizing) { if (!this.panelResizing) {
...@@ -109,6 +111,7 @@ export default { ...@@ -109,6 +111,7 @@ export default {
}, },
methods: { methods: {
...mapActions([ ...mapActions([
'getFileData',
'getRawFileData', 'getRawFileData',
'changeFileContent', 'changeFileContent',
'setFileLanguage', 'setFileLanguage',
...@@ -123,10 +126,16 @@ export default { ...@@ -123,10 +126,16 @@ export default {
this.editor.clearEditor(); this.editor.clearEditor();
this.getFileData({
path: this.file.path,
makeFileActive: false,
})
.then(() =>
this.getRawFileData({ this.getRawFileData({
path: this.file.path, path: this.file.path,
baseSha: this.currentMergeRequest ? this.currentMergeRequest.baseCommitSha : '', baseSha: this.currentMergeRequest ? this.currentMergeRequest.baseCommitSha : '',
}) }),
)
.then(() => { .then(() => {
this.createEditorInstance(); this.createEditorInstance();
}) })
...@@ -246,6 +255,8 @@ export default { ...@@ -246,6 +255,8 @@ export default {
ref="editor" ref="editor"
:class="{ :class="{
'is-readonly': isCommitModeActive, 'is-readonly': isCommitModeActive,
'is-deleted': file.deleted,
'is-added': file.tempFile
}" }"
class="multi-file-editor-holder" class="multi-file-editor-holder"
> >
......
...@@ -34,11 +34,6 @@ export default { ...@@ -34,11 +34,6 @@ export default {
type: Number, type: Number,
required: true, required: true,
}, },
disableActionDropdown: {
type: Boolean,
required: false,
default: false,
},
}, },
data() { data() {
return { return {
...@@ -212,8 +207,7 @@ export default { ...@@ -212,8 +207,7 @@ export default {
/> />
</span> </span>
<new-dropdown <new-dropdown
v-if="isTree && !disableActionDropdown" :type="file.type"
:project-id="file.projectId"
:branch="file.branchId" :branch="file.branchId"
:path="file.path" :path="file.path"
:mouse-over="mouseOver" :mouse-over="mouseOver"
......
...@@ -37,7 +37,7 @@ export default { ...@@ -37,7 +37,7 @@ export default {
return this.fileHasChanged ? !this.tabMouseOver : false; return this.fileHasChanged ? !this.tabMouseOver : false;
}, },
fileHasChanged() { fileHasChanged() {
return this.tab.changed || this.tab.tempFile || this.tab.staged; return this.tab.changed || this.tab.tempFile || this.tab.staged || this.tab.deleted;
}, },
}, },
...@@ -71,7 +71,8 @@ export default { ...@@ -71,7 +71,8 @@ export default {
<template> <template>
<li <li
:class="{ :class="{
active: tab.active active: tab.active,
disabled: tab.pending
}" }"
@click="clickFile(tab)" @click="clickFile(tab)"
@mouseover="mouseOverTab" @mouseover="mouseOverTab"
...@@ -105,7 +106,6 @@ export default { ...@@ -105,7 +106,6 @@ export default {
<changed-file-icon <changed-file-icon
v-else v-else
:file="tab" :file="tab"
:force-modified-icon="true"
/> />
</button> </button>
</li> </li>
......
...@@ -38,3 +38,18 @@ export const stageKeys = { ...@@ -38,3 +38,18 @@ export const stageKeys = {
unstaged: 'unstaged', unstaged: 'unstaged',
staged: 'staged', staged: 'staged',
}; };
export const commitItemIconMap = {
addition: {
icon: 'file-addition',
class: 'ide-file-addition',
},
modified: {
icon: 'file-modified',
class: 'ide-file-modified',
},
deleted: {
icon: 'file-deletion',
class: 'ide-file-deletion',
},
};
...@@ -7,7 +7,7 @@ export default class Model { ...@@ -7,7 +7,7 @@ export default class Model {
this.disposable = new Disposable(); this.disposable = new Disposable();
this.file = file; this.file = file;
this.head = head; this.head = head;
this.content = file.content !== '' ? file.content : file.raw; this.content = file.content !== '' || file.deleted ? file.content : file.raw;
this.disposable.add( this.disposable.add(
(this.originalModel = monacoEditor.createModel( (this.originalModel = monacoEditor.createModel(
......
...@@ -18,7 +18,7 @@ export default { ...@@ -18,7 +18,7 @@ export default {
return axios return axios
.get(file.rawPath, { .get(file.rawPath, {
params: { format: 'json' }, transformResponse: [f => f],
}) })
.then(({ data }) => data); .then(({ data }) => data);
}, },
...@@ -33,7 +33,7 @@ export default { ...@@ -33,7 +33,7 @@ export default {
return axios return axios
.get(file.rawPath.replace(`/raw/${file.branchId}/${file.path}`, `/raw/${sha}/${file.path}`), { .get(file.rawPath.replace(`/raw/${file.branchId}/${file.path}`, `/raw/${sha}/${file.path}`), {
params: { format: 'json' }, transformResponse: [f => f],
}) })
.then(({ data }) => data); .then(({ data }) => data);
}, },
......
...@@ -185,6 +185,14 @@ export const openNewEntryModal = ({ commit }, { type, path = '' }) => { ...@@ -185,6 +185,14 @@ export const openNewEntryModal = ({ commit }, { type, path = '' }) => {
$('#ide-new-entry').modal('show'); $('#ide-new-entry').modal('show');
}; };
export const deleteEntry = ({ commit, dispatch, state }, path) => {
dispatch('burstUnusedSeal');
dispatch('closeFile', state.entries[path]);
commit(types.DELETE_ENTRY, path);
};
export const resetOpenFiles = ({ commit }) => commit(types.RESET_OPEN_FILES);
export * from './actions/tree'; export * from './actions/tree';
export * from './actions/file'; export * from './actions/file';
export * from './actions/project'; export * from './actions/project';
......
...@@ -61,7 +61,11 @@ export const setFileActive = ({ commit, state, getters, dispatch }, path) => { ...@@ -61,7 +61,11 @@ 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();
commit(types.TOGGLE_LOADING, { entry: file }); commit(types.TOGGLE_LOADING, { entry: file });
return service return service
.getFileData( .getFileData(
`${gon.relative_url_root ? gon.relative_url_root : ''}${file.url.replace('/-/', '/')}`, `${gon.relative_url_root ? gon.relative_url_root : ''}${file.url.replace('/-/', '/')}`,
...@@ -71,7 +75,7 @@ export const getFileData = ({ state, commit, dispatch }, { path, makeFileActive ...@@ -71,7 +75,7 @@ export const getFileData = ({ state, commit, dispatch }, { path, makeFileActive
setPageTitle(decodeURI(normalizedHeaders['PAGE-TITLE'])); setPageTitle(decodeURI(normalizedHeaders['PAGE-TITLE']));
commit(types.SET_FILE_DATA, { data, file }); commit(types.SET_FILE_DATA, { data, file });
commit(types.TOGGLE_FILE_OPEN, path); if (makeFileActive) commit(types.TOGGLE_FILE_OPEN, path);
if (makeFileActive) dispatch('setFileActive', path); if (makeFileActive) dispatch('setFileActive', path);
commit(types.TOGGLE_LOADING, { entry: file }); commit(types.TOGGLE_LOADING, { entry: file });
}) })
...@@ -97,7 +101,7 @@ export const getRawFileData = ({ state, commit, dispatch }, { path, baseSha }) = ...@@ -97,7 +101,7 @@ export const getRawFileData = ({ state, commit, dispatch }, { path, baseSha }) =
service service
.getRawFileData(file) .getRawFileData(file)
.then(raw => { .then(raw => {
commit(types.SET_FILE_RAW_DATA, { file, raw }); if (!file.tempFile) 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)
......
...@@ -21,14 +21,12 @@ export const showTreeEntry = ({ commit, dispatch, state }, path) => { ...@@ -21,14 +21,12 @@ export const showTreeEntry = ({ commit, dispatch, state }, path) => {
export const handleTreeEntryAction = ({ commit, dispatch }, row) => { export const handleTreeEntryAction = ({ commit, dispatch }, row) => {
if (row.type === 'tree') { if (row.type === 'tree') {
dispatch('toggleTreeOpen', row.path); dispatch('toggleTreeOpen', row.path);
} else if (row.type === 'blob' && (row.opened || row.changed)) { } else if (row.type === 'blob') {
if (row.changed && !row.opened) { if (!row.opened) {
commit(types.TOGGLE_FILE_OPEN, row.path); commit(types.TOGGLE_FILE_OPEN, row.path);
} }
dispatch('setFileActive', row.path); dispatch('setFileActive', row.path);
} else {
dispatch('getFileData', { path: row.path });
} }
dispatch('showTreeEntry', row.path); dispatch('showTreeEntry', row.path);
......
...@@ -174,12 +174,14 @@ export const commitChanges = ({ commit, state, getters, dispatch, rootState, roo ...@@ -174,12 +174,14 @@ export const commitChanges = ({ commit, state, getters, dispatch, rootState, roo
dispatch('updateActivityBarView', activityBarViews.edit, { root: true }); dispatch('updateActivityBarView', activityBarViews.edit, { root: true });
dispatch('updateViewer', 'editor', { root: true }); dispatch('updateViewer', 'editor', { root: true });
if (rootGetters.activeFile) {
router.push( router.push(
`/project/${rootState.currentProjectId}/blob/${getters.branchName}/-/${ `/project/${rootState.currentProjectId}/blob/${getters.branchName}/-/${
rootGetters.activeFile.path rootGetters.activeFile.path
}`, }`,
); );
} }
}
}) })
.then(() => dispatch('updateCommitAction', consts.COMMIT_TO_CURRENT_BRANCH)) .then(() => dispatch('updateCommitAction', consts.COMMIT_TO_CURRENT_BRANCH))
.then(() => .then(() =>
......
import { sprintf, n__ } from '../../../../locale'; import { sprintf, n__, __ } from '../../../../locale';
import * as consts from './constants'; import * as consts from './constants';
const BRANCH_SUFFIX_COUNT = 5; const BRANCH_SUFFIX_COUNT = 5;
const createTranslatedTextForFiles = (files, text) => {
if (!files.length) return null;
return sprintf(n__('%{text} %{files}', '%{text} %{files} files', files.length), {
files: files.reduce((acc, val) => acc.concat(val.path), []).join(', '),
text,
});
};
export const discardDraftButtonDisabled = state => export const discardDraftButtonDisabled = state =>
state.commitMessage === '' || state.submitCommitLoading; state.commitMessage === '' || state.submitCommitLoading;
...@@ -29,14 +37,16 @@ export const branchName = (state, getters, rootState) => { ...@@ -29,14 +37,16 @@ export const branchName = (state, getters, rootState) => {
export const preBuiltCommitMessage = (state, _, rootState) => { export const preBuiltCommitMessage = (state, _, rootState) => {
if (state.commitMessage) return state.commitMessage; if (state.commitMessage) return state.commitMessage;
const files = (rootState.stagedFiles.length const files = rootState.stagedFiles.length ? rootState.stagedFiles : rootState.changedFiles;
? rootState.stagedFiles const modifiedFiles = files.filter(f => !f.deleted);
: rootState.changedFiles const deletedFiles = files.filter(f => f.deleted);
).reduce((acc, val) => acc.concat(val.path), []);
return sprintf(n__('Update %{files}', 'Update %{files} files', files.length), { return [
files: files.join(', '), createTranslatedTextForFiles(modifiedFiles, __('Update')),
}); createTranslatedTextForFiles(deletedFiles, __('Deleted')),
]
.filter(t => t)
.join('\n');
}; };
// prevent babel-plugin-rewire from generating an invalid default during karma tests // prevent babel-plugin-rewire from generating an invalid default during karma tests
......
...@@ -76,3 +76,4 @@ export const RESET_OPEN_FILES = 'RESET_OPEN_FILES'; ...@@ -76,3 +76,4 @@ export const RESET_OPEN_FILES = 'RESET_OPEN_FILES';
export const SET_ERROR_MESSAGE = 'SET_ERROR_MESSAGE'; 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';
/* eslint-disable no-param-reassign */
import * as types from './mutation_types'; import * as types from './mutation_types';
import projectMutations from './mutations/project'; import projectMutations from './mutations/project';
import mergeRequestMutation from './mutations/merge_request'; import mergeRequestMutation from './mutations/merge_request';
...@@ -171,6 +172,16 @@ export default { ...@@ -171,6 +172,16 @@ export default {
newEntryModal: { type, path }, newEntryModal: { type, path },
}); });
}, },
[types.DELETE_ENTRY](state, path) {
const entry = state.entries[path];
const parent = entry.parentPath
? state.entries[entry.parentPath]
: 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);
},
...projectMutations, ...projectMutations,
...mergeRequestMutation, ...mergeRequestMutation,
...fileMutations, ...fileMutations,
......
/* eslint-disable no-param-reassign */ /* eslint-disable no-param-reassign */
import * as types from '../mutation_types'; import * as types from '../mutation_types';
import { sortTree } from '../utils';
import { diffModes } from '../../constants'; import { diffModes } from '../../constants';
export default { export default {
...@@ -51,9 +52,17 @@ export default { ...@@ -51,9 +52,17 @@ export default {
}); });
}, },
[types.SET_FILE_RAW_DATA](state, { file, raw }) { [types.SET_FILE_RAW_DATA](state, { file, raw }) {
const openPendingFile = state.openFiles.find(
f => f.path === file.path && f.pending && !f.tempFile,
);
Object.assign(state.entries[file.path], { Object.assign(state.entries[file.path], {
raw, raw,
}); });
if (openPendingFile) {
openPendingFile.raw = raw;
}
}, },
[types.SET_FILE_BASE_RAW_DATA](state, { file, baseRaw }) { [types.SET_FILE_BASE_RAW_DATA](state, { file, baseRaw }) {
Object.assign(state.entries[file.path], { Object.assign(state.entries[file.path], {
...@@ -109,11 +118,22 @@ export default { ...@@ -109,11 +118,22 @@ 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 { deleted } = 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,
}); });
if (deleted) {
const parent = entry.parentPath
? state.entries[entry.parentPath]
: state.trees[`${state.currentProjectId}/${state.currentBranchId}`];
parent.tree = sortTree(parent.tree.concat(entry));
}
}, },
[types.ADD_FILE_TO_CHANGED](state, path) { [types.ADD_FILE_TO_CHANGED](state, path) {
Object.assign(state, { Object.assign(state, {
......
...@@ -46,6 +46,7 @@ export const dataStructure = () => ({ ...@@ -46,6 +46,7 @@ export const dataStructure = () => ({
parentPath: null, parentPath: null,
lastOpenedAt: 0, lastOpenedAt: 0,
mrChange: null, mrChange: null,
deleted: false,
}); });
export const decorateData = entity => { export const decorateData = entity => {
...@@ -105,15 +106,37 @@ export const setPageTitle = title => { ...@@ -105,15 +106,37 @@ export const setPageTitle = title => {
document.title = title; document.title = title;
}; };
export const commitActionForFile = file => {
if (file.deleted) {
return 'delete';
} else if (file.tempFile) {
return 'create';
}
return 'update';
};
export const getCommitFiles = (stagedFiles, deleteTree = false) =>
stagedFiles.reduce((acc, file) => {
if ((file.deleted || deleteTree) && file.type === 'tree') {
return acc.concat(getCommitFiles(file.tree, true));
}
return acc.concat({
...file,
deleted: deleteTree || file.deleted,
});
}, []);
export const createCommitPayload = ({ branch, getters, newBranch, state, rootState }) => ({ export const createCommitPayload = ({ branch, getters, newBranch, state, rootState }) => ({
branch, branch,
commit_message: state.commitMessage || getters.preBuiltCommitMessage, commit_message: state.commitMessage || getters.preBuiltCommitMessage,
actions: rootState.stagedFiles.map(f => ({ actions: getCommitFiles(rootState.stagedFiles).map(f => ({
action: f.tempFile ? 'create' : 'update', action: commitActionForFile(f),
file_path: f.path, file_path: f.path,
content: f.content, content: f.content,
encoding: f.base64 ? 'base64' : 'text', encoding: f.base64 ? 'base64' : 'text',
last_commit_id: newBranch ? undefined : f.lastCommitSha, last_commit_id: newBranch || f.deleted ? undefined : f.lastCommitSha,
})), })),
start_branch: newBranch ? rootState.currentBranchId : undefined, start_branch: newBranch ? rootState.currentBranchId : undefined,
}); });
......
import { commitItemIconMap } from './constants';
// eslint-disable-next-line import/prefer-default-export
export const getCommitIconMap = file => {
if (file.deleted) {
return commitItemIconMap.deleted;
} else if (file.tempFile) {
return commitItemIconMap.addition;
}
return commitItemIconMap.modified;
};
...@@ -98,6 +98,11 @@ export default { ...@@ -98,6 +98,11 @@ export default {
type: String, type: String,
required: true, required: true,
}, },
showEnvironmentDropdown: {
type: Boolean,
required: false,
default: true,
},
}, },
data() { data() {
return { return {
...@@ -126,9 +131,25 @@ export default { ...@@ -126,9 +131,25 @@ export default {
}, },
mounted() { mounted() {
this.resizeThrottled = _.throttle(this.resize, 600); this.resizeThrottled = _.throttle(this.resize, 600);
this.servicePromises = [
this.service
.getGraphsData()
.then(data => this.store.storeMetrics(data))
.catch(() => Flash(s__('Metrics|There was an error while retrieving metrics'))),
this.service
.getDeploymentData()
.then(data => this.store.storeDeploymentData(data))
.catch(() => Flash(s__('Metrics|There was an error getting deployment information.'))),
];
if (!this.hasMetrics) { if (!this.hasMetrics) {
this.state = 'gettingStarted'; this.state = 'gettingStarted';
} else { } else {
if (this.showEnvironmentDropdown) {
this.servicePromises.push(this.service
.getEnvironmentsData()
.then((data) => this.store.storeEnvironmentsData(data))
.catch(() => Flash(s__('Metrics|There was an error getting environments information.'))));
}
this.getGraphsData(); this.getGraphsData();
window.addEventListener('resize', this.resizeThrottled, false); window.addEventListener('resize', this.resizeThrottled, false);
} }
...@@ -136,17 +157,7 @@ export default { ...@@ -136,17 +157,7 @@ export default {
methods: { methods: {
getGraphsData() { getGraphsData() {
this.state = 'loading'; this.state = 'loading';
Promise.all([ Promise.all(this.servicePromises)
this.service.getGraphsData().then(data => this.store.storeMetrics(data)),
this.service
.getDeploymentData()
.then(data => this.store.storeDeploymentData(data))
.catch(() => Flash(s__('Metrics|There was an error getting deployment information.'))),
this.service
.getEnvironmentsData()
.then(data => this.store.storeEnvironmentsData(data))
.catch(() => Flash(s__('Metrics|There was an error getting environments information.'))),
])
.then(() => { .then(() => {
if (this.store.groups.length < 1) { if (this.store.groups.length < 1) {
this.state = 'noData'; this.state = 'noData';
...@@ -180,7 +191,10 @@ export default { ...@@ -180,7 +191,10 @@ export default {
v-if="!showEmptyState" v-if="!showEmptyState"
class="prometheus-graphs prepend-top-10" class="prometheus-graphs prepend-top-10"
> >
<div class="environments d-flex align-items-center"> <div
v-if="showEnvironmentDropdown"
class="environments d-flex align-items-center"
>
{{ s__('Metrics|Environment') }} {{ s__('Metrics|Environment') }}
<div class="dropdown prepend-left-10"> <div class="dropdown prepend-left-10">
<button <button
......
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
}, },
computed: { computed: {
className() { className() {
return `drag${this.side}`; return `drag-${this.side}`;
}, },
cursorStyle() { cursorStyle() {
if (this.enabled) { if (this.enabled) {
...@@ -44,8 +44,15 @@ ...@@ -44,8 +44,15 @@
methods: { methods: {
resetSize(e) { resetSize(e) {
e.preventDefault(); e.preventDefault();
this.$emit('resize-start', this.size);
this.size = this.startSize; this.size = this.startSize;
this.$emit('update:size', this.size); this.$emit('update:size', this.size);
// End resizing on next tick so that listeners can react to DOM changes
this.$nextTick(() => {
this.$emit('resize-end', this.size);
});
}, },
startDrag(e) { startDrag(e) {
if (this.enabled) { if (this.enabled) {
...@@ -84,7 +91,7 @@ ...@@ -84,7 +91,7 @@
<div <div
:class="className" :class="className"
:style="cursorStyle" :style="cursorStyle"
class="dragHandle" class="drag-handle"
@mousedown="startDrag" @mousedown="startDrag"
@dblclick="resetSize" @dblclick="resetSize"
></div> ></div>
......
...@@ -38,27 +38,12 @@ export default { ...@@ -38,27 +38,12 @@ export default {
required: false, required: false,
default: () => [], default: () => [],
}, },
allIssues: {
type: Array,
required: false,
default: () => [],
},
component: { component: {
type: String, type: String,
required: false, required: false,
default: '', default: '',
}, },
}, },
data() {
return {
isFullReportVisible: false,
};
},
methods: {
openFullReport() {
this.isFullReportVisible = true;
},
},
}; };
</script> </script>
<template> <template>
...@@ -72,14 +57,6 @@ export default { ...@@ -72,14 +57,6 @@ export default {
class="js-mr-code-new-issues" class="js-mr-code-new-issues"
/> />
<issues-block
v-if="isFullReportVisible"
:component="component"
:issues="allIssues"
:status="$options.failed"
class="js-mr-code-all-issues"
/>
<issues-block <issues-block
v-if="neutralIssues.length" v-if="neutralIssues.length"
:component="component" :component="component"
...@@ -95,14 +72,5 @@ export default { ...@@ -95,14 +72,5 @@ export default {
:status="$options.success" :status="$options.success"
class="js-mr-code-resolved-issues" class="js-mr-code-resolved-issues"
/> />
<button
v-if="allIssues.length && !isFullReportVisible"
type="button"
class="btn-link btn-blank prepend-left-10 js-expand-full-list break-link"
@click="openFullReport"
>
{{ s__("ciReport|Show complete code vulnerabilities report") }}
</button>
</div> </div>
</template> </template>
...@@ -59,11 +59,6 @@ export default { ...@@ -59,11 +59,6 @@ export default {
required: false, required: false,
default: () => [], default: () => [],
}, },
allIssues: {
type: Array,
required: false,
default: () => [],
},
infoText: { infoText: {
type: [String, Boolean], type: [String, Boolean],
required: false, required: false,
...@@ -142,18 +137,10 @@ export default { ...@@ -142,18 +137,10 @@ export default {
</script> </script>
<template> <template>
<section class="media-section"> <section class="media-section">
<div <div class="media">
class="media" <status-icon :status="statusIconName" />
> <div class="media-body space-children d-flex flex-align-self-center">
<status-icon <span class="js-code-text code-text">
:status="statusIconName"
/>
<div
class="media-body space-children d-flex flex-align-self-center"
>
<span
class="js-code-text code-text"
>
{{ headerText }} {{ headerText }}
<popover <popover
...@@ -163,10 +150,12 @@ export default { ...@@ -163,10 +150,12 @@ export default {
/> />
</span> </span>
<slot name="actionButtons"></slot>
<button <button
v-if="isCollapsible" v-if="isCollapsible"
type="button" type="button"
class="js-collapse-btn btn bt-default float-right btn-sm" class="js-collapse-btn btn float-right btn-sm"
@click="toggleCollapsed" @click="toggleCollapsed"
> >
{{ collapseText }} {{ collapseText }}
...@@ -184,7 +173,6 @@ export default { ...@@ -184,7 +173,6 @@ export default {
:unresolved-issues="unresolvedIssues" :unresolved-issues="unresolvedIssues"
:resolved-issues="resolvedIssues" :resolved-issues="resolvedIssues"
:neutral-issues="neutralIssues" :neutral-issues="neutralIssues"
:all-issues="allIssues"
:component="component" :component="component"
/> />
</slot> </slot>
......
...@@ -567,9 +567,6 @@ ...@@ -567,9 +567,6 @@
border-bottom: 1px solid $white-normal; border-bottom: 1px solid $white-normal;
.mx-auto { .mx-auto {
margin: 8px 0;
text-align: center;
.tanuki-logo, .tanuki-logo,
img { img {
height: 36px; height: 36px;
......
...@@ -874,3 +874,5 @@ $font-family-monospace: $monospace-font; ...@@ -874,3 +874,5 @@ $font-family-monospace: $monospace-font;
$input-line-height: 20px; $input-line-height: 20px;
$btn-line-height: 20px; $btn-line-height: 20px;
$table-accent-bg: $gray-light; $table-accent-bg: $gray-light;
$card-border-color: $border-color;
$card-cap-bg: $gray-light;
@import 'framework/variables';
@import 'framework/mixins';
.project-refs-form, .project-refs-form,
.project-refs-target-form { .project-refs-target-form {
display: inline-block; display: inline-block;
...@@ -74,6 +77,7 @@ ...@@ -74,6 +77,7 @@
.ide-file-icon-holder { .ide-file-icon-holder {
display: flex; display: flex;
align-items: center; align-items: center;
color: $theme-gray-700;
} }
.ide-file-changed-icon { .ide-file-changed-icon {
...@@ -161,12 +165,23 @@ ...@@ -161,12 +165,23 @@
background-color: $white-light; background-color: $white-light;
border-bottom-color: $white-light; border-bottom-color: $white-light;
} }
&:not(.disabled) {
.multi-file-tab {
cursor: pointer;
}
}
&.disabled {
.multi-file-tab-close {
cursor: default;
}
}
} }
} }
.multi-file-tab { .multi-file-tab {
@include str-truncated(141px); @include str-truncated(141px);
cursor: pointer;
svg { svg {
vertical-align: middle; vertical-align: middle;
...@@ -241,6 +256,38 @@ ...@@ -241,6 +256,38 @@
} }
} }
.is-deleted {
.editor.modified {
.margin-view-overlays,
.lines-content,
.decorationsOverviewRuler {
// !important to override monaco inline styles
display: none !important;
}
}
.diffOverviewRuler.modified {
// !important to override monaco inline styles
display: none !important;
}
}
.is-added {
.editor.original {
.margin-view-overlays,
.lines-content,
.decorationsOverviewRuler {
// !important to override monaco inline styles
display: none !important;
}
}
.diffOverviewRuler.original {
// !important to override monaco inline styles
display: none !important;
}
}
.monaco-diff-editor.vs { .monaco-diff-editor.vs {
.editor.modified { .editor.modified {
box-shadow: none; box-shadow: none;
...@@ -557,16 +604,21 @@ ...@@ -557,16 +604,21 @@
} }
} }
.multi-file-addition, .ide-file-addition,
.multi-file-addition-solid { .ide-file-addition-solid {
color: $green-500; color: $green-500;
} }
.multi-file-modified, .ide-file-modified,
.multi-file-modified-solid { .ide-file-modified-solid {
color: $orange-500; color: $orange-500;
} }
.ide-file-deletion,
.ide-file-deletion-solid {
color: $red-500;
}
.multi-file-commit-list-collapsed { .multi-file-commit-list-collapsed {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
...@@ -781,18 +833,21 @@ ...@@ -781,18 +833,21 @@
} }
} }
.dragHandle { .drag-handle {
position: absolute; position: absolute;
top: 0; top: 0;
bottom: 0; bottom: 0;
width: 1px; width: 4px;
background-color: $white-dark;
&.dragright { &:hover {
background-color: $white-normal;
}
&.drag-right {
right: 0; right: 0;
} }
&.dragleft { &.drag-left {
left: 0; left: 0;
} }
} }
...@@ -1014,6 +1069,10 @@ ...@@ -1014,6 +1069,10 @@
.ide-new-btn { .ide-new-btn {
margin-left: auto; margin-left: auto;
} }
button {
color: $gl-text-color;
}
} }
.ide-sidebar-branch-title { .ide-sidebar-branch-title {
......
...@@ -199,6 +199,7 @@ ...@@ -199,6 +199,7 @@
.block { .block {
width: 100%; width: 100%;
word-break: break-word;
&:last-child { &:last-child {
border-bottom: 1px solid $border-gray-normal; border-bottom: 1px solid $border-gray-normal;
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
svg { svg {
vertical-align: middle; vertical-align: middle;
top: -1px;
} }
} }
......
...@@ -856,18 +856,6 @@ ...@@ -856,18 +856,6 @@
} }
} }
.meter-container {
background: $border-gray-light;
border-radius: 3px;
.meter-fill {
max-width: 100%;
height: 5px;
border-radius: 3px;
background: $gl-primary;
}
}
.compare-display-container { .compare-display-container {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
......
...@@ -22,8 +22,8 @@ ...@@ -22,8 +22,8 @@
height: 16px; height: 16px;
background-size: cover; background-size: cover;
&.gl-snippet-icon-doc_code { background-position: 0 0; } &.gl-snippet-icon-doc-code { background-position: 0 0; }
&.gl-snippet-icon-doc_text { background-position: 0 -16px; } &.gl-snippet-icon-doc-text { background-position: 0 -16px; }
&.gl-snippet-icon-download { background-position: 0 -32px; } &.gl-snippet-icon-download { background-position: 0 -32px; }
} }
......
...@@ -4,13 +4,17 @@ class Projects::CommitsController < Projects::ApplicationController ...@@ -4,13 +4,17 @@ class Projects::CommitsController < Projects::ApplicationController
include ExtractsPath include ExtractsPath
include RendersCommits include RendersCommits
before_action :whitelist_query_limiting before_action :whitelist_query_limiting, except: :commits_root
before_action :require_non_empty_project before_action :require_non_empty_project
before_action :assign_ref_vars before_action :assign_ref_vars, except: :commits_root
before_action :authorize_download_code! before_action :authorize_download_code!
before_action :set_commits before_action :set_commits, except: :commits_root
before_action :set_request_format, only: :show before_action :set_request_format, only: :show
def commits_root
redirect_to project_commits_path(@project, @project.default_branch)
end
def show def show
@merge_request = MergeRequestsFinder.new(current_user, project_id: @project.id).execute.opened @merge_request = MergeRequestsFinder.new(current_user, project_id: @project.id).execute.opened
.find_by(source_project: @project, source_branch: @ref, target_branch: @repository.root_ref) .find_by(source_project: @project, source_branch: @ref, target_branch: @repository.root_ref)
......
...@@ -7,7 +7,7 @@ class Admin::ProjectsFinder ...@@ -7,7 +7,7 @@ class Admin::ProjectsFinder
end end
def execute def execute
items = Project.without_deleted.with_statistics items = Project.without_deleted.with_statistics.with_route
items = by_namespace_id(items) items = by_namespace_id(items)
items = by_visibilty_level(items) items = by_visibilty_level(items)
items = by_with_push(items) items = by_with_push(items)
...@@ -16,7 +16,7 @@ class Admin::ProjectsFinder ...@@ -16,7 +16,7 @@ class Admin::ProjectsFinder
items = by_archived(items) items = by_archived(items)
items = by_personal(items) items = by_personal(items)
items = by_name(items) items = by_name(items)
items = items.includes(namespace: [:owner]) items = items.includes(namespace: [:owner, :route])
sort(items).page(params[:page]) sort(items).page(params[:page])
end end
......
...@@ -7,5 +7,5 @@ class GitlabSchema < GraphQL::Schema ...@@ -7,5 +7,5 @@ class GitlabSchema < GraphQL::Schema
query(Types::QueryType) query(Types::QueryType)
default_max_page_size 100 default_max_page_size 100
# mutation(Types::MutationType) mutation(Types::MutationType)
end end
# frozen_string_literal: true
module Mutations
class BaseMutation < GraphQL::Schema::RelayClassicMutation
field :errors, [GraphQL::STRING_TYPE],
null: false,
description: "Reasons why the mutation failed."
def current_user
context[:current_user]
end
end
end
module Mutations
module ResolvesProject
extend ActiveSupport::Concern
def resolve_project(full_path:)
resolver.resolve(full_path: full_path)
end
def resolver
Resolvers::ProjectResolver.new(object: nil, context: context)
end
end
end
module Mutations
module MergeRequests
class Base < BaseMutation
include Gitlab::Graphql::Authorize::AuthorizeResource
include Mutations::ResolvesProject
argument :project_path, GraphQL::ID_TYPE,
required: true,
description: "The project the merge request to mutate is in"
argument :iid, GraphQL::ID_TYPE,
required: true,
description: "The iid of the merge request to mutate"
field :merge_request,
Types::MergeRequestType,
null: true,
description: "The merge request after mutation"
authorize :update_merge_request
private
def find_object(project_path:, iid:)
project = resolve_project(full_path: project_path)
resolver = Resolvers::MergeRequestResolver.new(object: project, context: context)
resolver.resolve(iid: iid)
end
end
end
end
# frozen_string_literal: true
module Mutations
module MergeRequests
class SetWip < Base
graphql_name 'MergeRequestSetWip'
argument :wip,
GraphQL::BOOLEAN_TYPE,
required: true,
description: <<~DESC
Whether or not to set the merge request as a WIP.
DESC
def resolve(project_path:, iid:, wip: nil)
merge_request = authorized_find!(project_path: project_path, iid: iid)
project = merge_request.project
::MergeRequests::UpdateService.new(project, current_user, wip_event: wip_event(merge_request, wip))
.execute(merge_request)
{
merge_request: merge_request,
errors: merge_request.errors.full_messages
}
end
private
def wip_event(merge_request, wip)
wip ? 'wip' : 'unwip'
end
end
end
end
# frozen_string_literal: true
module Types module Types
class MutationType < BaseObject class MutationType < BaseObject
include Gitlab::Graphql::MountMutation
graphql_name "Mutation" graphql_name "Mutation"
# TODO: Add Mutations as fields mount_mutation Mutations::MergeRequests::SetWip
end end
end end
...@@ -112,7 +112,7 @@ module ButtonHelper ...@@ -112,7 +112,7 @@ module ButtonHelper
def geo_button(modal_target: nil) def geo_button(modal_target: nil)
data = { placement: 'bottom', container: 'body', toggle: 'modal', target: modal_target } data = { placement: 'bottom', container: 'body', toggle: 'modal', target: modal_target }
content_tag :button, content_tag :button,
sprite_icon('geo-nodes', size: 15), sprite_icon('location-dot', size: 15),
class: 'btn btn-geo has-tooltip', class: 'btn btn-geo has-tooltip',
data: data, data: data,
type: :button, type: :button,
......
...@@ -11,6 +11,7 @@ module EnvironmentsHelper ...@@ -11,6 +11,7 @@ module EnvironmentsHelper
{ {
"settings-path" => edit_project_service_path(project, 'prometheus'), "settings-path" => edit_project_service_path(project, 'prometheus'),
"clusters-path" => project_clusters_path(project), "clusters-path" => project_clusters_path(project),
"current-environment-name": environment.name,
"documentation-path" => help_page_path('administration/monitoring/prometheus/index.md'), "documentation-path" => help_page_path('administration/monitoring/prometheus/index.md'),
"empty-getting-started-svg-path" => image_path('illustrations/monitoring/getting_started.svg'), "empty-getting-started-svg-path" => image_path('illustrations/monitoring/getting_started.svg'),
"empty-loading-svg-path" => image_path('illustrations/monitoring/loading.svg'), "empty-loading-svg-path" => image_path('illustrations/monitoring/loading.svg'),
......
...@@ -10,7 +10,7 @@ module HooksHelper ...@@ -10,7 +10,7 @@ module HooksHelper
trigger_human_name = trigger.to_s.tr('_', ' ').camelize trigger_human_name = trigger.to_s.tr('_', ' ').camelize
link_to path, rel: 'nofollow' do link_to path, rel: 'nofollow', method: :post do
content_tag(:span, trigger_human_name) content_tag(:span, trigger_human_name)
end end
end end
......
...@@ -116,7 +116,7 @@ module SnippetsHelper ...@@ -116,7 +116,7 @@ module SnippetsHelper
raw_project_snippet_url(@snippet.project, @snippet) raw_project_snippet_url(@snippet.project, @snippet)
end end
link_to external_snippet_icon('doc_code'), snippet_raw_url, class: 'btn', target: '_blank', rel: 'noopener noreferrer', title: 'Open raw' link_to external_snippet_icon('doc-code'), snippet_raw_url, class: 'btn', target: '_blank', rel: 'noopener noreferrer', title: 'Open raw'
end end
def embedded_snippet_download_button def embedded_snippet_download_button
......
...@@ -90,34 +90,17 @@ module Routable ...@@ -90,34 +90,17 @@ module Routable
end end
def full_name def full_name
if route && route.name.present? route&.name || build_full_name
@full_name ||= route.name # rubocop:disable Gitlab/ModuleWithInstanceVariables
else
update_route if persisted?
build_full_name
end
end end
# Every time `project.namespace.becomes(Namespace)` is called for polymorphic_path,
# a new instance is instantiated, and we end up duplicating the same query to retrieve
# the route. Caching this per request ensures that even if we have multiple instances,
# we will not have to duplicate work, avoiding N+1 queries in some cases.
def full_path def full_path
return uncached_full_path unless RequestStore.active? && persisted? route&.path || build_full_path
RequestStore[full_path_key] ||= uncached_full_path
end end
def full_path_components def full_path_components
full_path.split('/') full_path.split('/')
end end
def expires_full_path_cache
RequestStore.delete(full_path_key) if RequestStore.active?
@full_path = nil # rubocop:disable Gitlab/ModuleWithInstanceVariables
end
def build_full_path def build_full_path
if parent && path if parent && path
parent.full_path + '/' + path parent.full_path + '/' + path
...@@ -138,16 +121,6 @@ module Routable ...@@ -138,16 +121,6 @@ module Routable
self.errors[:path].concat(route_path_errors) if route_path_errors self.errors[:path].concat(route_path_errors) if route_path_errors
end end
def uncached_full_path
if route && route.path.present?
@full_path ||= route.path # rubocop:disable Gitlab/ModuleWithInstanceVariables
else
update_route if persisted?
build_full_path
end
end
def full_name_changed? def full_name_changed?
name_changed? || parent_changed? name_changed? || parent_changed?
end end
...@@ -156,10 +129,6 @@ module Routable ...@@ -156,10 +129,6 @@ module Routable
path_changed? || parent_changed? path_changed? || parent_changed?
end end
def full_path_key
@full_path_key ||= "routable/full_path/#{self.class.name}/#{self.id}"
end
def build_full_name def build_full_name
if parent && name if parent && name
parent.human_name + ' / ' + name parent.human_name + ' / ' + name
...@@ -168,18 +137,9 @@ module Routable ...@@ -168,18 +137,9 @@ module Routable
end end
end end
def update_route
return if Gitlab::Database.read_only?
prepare_route
route.save
end
def prepare_route def prepare_route
route || build_route(source: self) route || build_route(source: self)
route.path = build_full_path route.path = build_full_path
route.name = build_full_name route.name = build_full_name
@full_path = nil # rubocop:disable Gitlab/ModuleWithInstanceVariables
@full_name = nil # rubocop:disable Gitlab/ModuleWithInstanceVariables
end end
end end
...@@ -11,8 +11,6 @@ module Storage ...@@ -11,8 +11,6 @@ module Storage
Namespace.find(parent_id_was) # raise NotFound early if needed Namespace.find(parent_id_was) # raise NotFound early if needed
end end
expires_full_path_cache
move_repositories move_repositories
if parent_changed? if parent_changed?
......
class DeployToken < ActiveRecord::Base class DeployToken < ActiveRecord::Base
include Expirable include Expirable
include TokenAuthenticatable include TokenAuthenticatable
include PolicyActor
add_authentication_token_field :token add_authentication_token_field :token
prepend EE::DeployToken
AVAILABLE_SCOPES = %i(read_repository read_registry).freeze AVAILABLE_SCOPES = %i(read_repository read_registry).freeze
GITLAB_DEPLOY_TOKEN_NAME = 'gitlab-deploy-token'.freeze GITLAB_DEPLOY_TOKEN_NAME = 'gitlab-deploy-token'.freeze
...@@ -60,10 +59,6 @@ class DeployToken < ActiveRecord::Base ...@@ -60,10 +59,6 @@ class DeployToken < ActiveRecord::Base
write_attribute(:expires_at, value.presence || Forever.date) write_attribute(:expires_at, value.presence || Forever.date)
end end
def admin?
false
end
private private
def ensure_at_least_one_scope def ensure_at_least_one_scope
......
...@@ -305,7 +305,6 @@ class Namespace < ActiveRecord::Base ...@@ -305,7 +305,6 @@ class Namespace < ActiveRecord::Base
def write_projects_repository_config def write_projects_repository_config
all_projects.find_each do |project| all_projects.find_each do |project|
project.expires_full_path_cache # we need to clear cache to validate renames correctly
project.write_repository_config project.write_repository_config
end end
end end
......
...@@ -1256,8 +1256,6 @@ class Project < ActiveRecord::Base ...@@ -1256,8 +1256,6 @@ class Project < ActiveRecord::Base
return true if skip_disk_validation return true if skip_disk_validation
return false unless repository_storage return false unless repository_storage
expires_full_path_cache # we need to clear cache to validate renames correctly
# Check if repository with same path already exists on disk we can # Check if repository with same path already exists on disk we can
# skip this for the hashed storage because the path does not change # skip this for the hashed storage because the path does not change
if legacy_storage? && repository_with_same_path_already_exists? if legacy_storage? && repository_with_same_path_already_exists?
...@@ -1636,7 +1634,6 @@ class Project < ActiveRecord::Base ...@@ -1636,7 +1634,6 @@ class Project < ActiveRecord::Base
# When we import a project overwriting the original project, there # When we import a project overwriting the original project, there
# is a move operation. In that case we don't want to send the instructions. # is a move operation. In that case we don't want to send the instructions.
send_move_instructions(full_path_was) unless import_started? send_move_instructions(full_path_was) unless import_started?
expires_full_path_cache
self.old_path_with_namespace = full_path_was self.old_path_with_namespace = full_path_was
SystemHooksService.new.execute_hooks_for(self, :rename) SystemHooksService.new.execute_hooks_for(self, :rename)
......
...@@ -50,13 +50,13 @@ class RemoteMirror < ActiveRecord::Base ...@@ -50,13 +50,13 @@ class RemoteMirror < ActiveRecord::Base
state :failed state :failed
after_transition any => :started do |remote_mirror, _| after_transition any => :started do |remote_mirror, _|
Gitlab::Metrics.add_event(:remote_mirrors_running, path: remote_mirror.project.full_path) Gitlab::Metrics.add_event(:remote_mirrors_running)
remote_mirror.update(last_update_started_at: Time.now) remote_mirror.update(last_update_started_at: Time.now)
end end
after_transition started: :finished do |remote_mirror, _| after_transition started: :finished do |remote_mirror, _|
Gitlab::Metrics.add_event(:remote_mirrors_finished, path: remote_mirror.project.full_path) Gitlab::Metrics.add_event(:remote_mirrors_finished)
timestamp = Time.now timestamp = Time.now
remote_mirror.update!( remote_mirror.update!(
...@@ -65,7 +65,7 @@ class RemoteMirror < ActiveRecord::Base ...@@ -65,7 +65,7 @@ class RemoteMirror < ActiveRecord::Base
end end
after_transition started: :failed do |remote_mirror, _| after_transition started: :failed do |remote_mirror, _|
Gitlab::Metrics.add_event(:remote_mirrors_failed, path: remote_mirror.project.full_path) Gitlab::Metrics.add_event(:remote_mirrors_failed)
remote_mirror.update(last_update_at: Time.now) remote_mirror.update(last_update_at: Time.now)
end end
......
...@@ -1034,7 +1034,7 @@ class Repository ...@@ -1034,7 +1034,7 @@ class Repository
end end
def repository_event(event, tags = {}) def repository_event(event, tags = {})
Gitlab::Metrics.add_event(event, { path: full_path }.merge(tags)) Gitlab::Metrics.add_event(event, tags)
end end
def initialize_raw_repository def initialize_raw_repository
......
...@@ -22,14 +22,4 @@ class BasePolicy < DeclarativePolicy::Base ...@@ -22,14 +22,4 @@ class BasePolicy < DeclarativePolicy::Base
# This is prevented in some cases in `gitlab-ee` # This is prevented in some cases in `gitlab-ee`
rule { default }.enable :read_cross_project rule { default }.enable :read_cross_project
# EE Extensions
with_scope :user
condition(:auditor, score: 0) { @user&.auditor? }
with_scope :user
condition(:support_bot, score: 0) { @user&.support_bot? }
with_scope :global
condition(:license_block) { License.block_changes? }
end end
# frozen_string_literal: true
# Include this module if we want to pass something else than the user to
# check policies. This defines several methods which the policy checker
# would call and check.
module PolicyActor
extend ActiveSupport::Concern
prepend EE::PolicyActor
def blocked?
false
end
def admin?
false
end
def external?
false
end
def internal?
false
end
def access_locked?
false
end
def required_terms_not_accepted?
false
end
def can_create_group
false
end
end
...@@ -11,12 +11,17 @@ class PipelineSerializer < BaseSerializer ...@@ -11,12 +11,17 @@ class PipelineSerializer < BaseSerializer
:retryable_builds, :retryable_builds,
:cancelable_statuses, :cancelable_statuses,
:trigger_requests, :trigger_requests,
:project,
{ triggered_by_pipeline: [:project, :user] }, { triggered_by_pipeline: [:project, :user] },
{ triggered_pipelines: [:project, :user] }, { triggered_pipelines: [:project, :user] },
:manual_actions, :manual_actions,
:artifacts, :artifacts,
{ pending_builds: :project } {
pending_builds: :project,
project: [:route, { namespace: :route }],
artifacts: {
project: [:route, { namespace: :route }]
}
}
]) ])
end end
......
...@@ -79,7 +79,6 @@ module Projects ...@@ -79,7 +79,6 @@ module Projects
Gitlab::PagesTransfer.new.move_project(project.path, @old_namespace.full_path, @new_namespace.full_path) Gitlab::PagesTransfer.new.move_project(project.path, @old_namespace.full_path, @new_namespace.full_path)
project.old_path_with_namespace = @old_path project.old_path_with_namespace = @old_path
project.expires_full_path_cache
write_repository_config(@new_path) write_repository_config(@new_path)
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
- if project.archived - if project.archived
%span.badge.badge-warning archived %span.badge.badge-warning archived
.title .title
= link_to [:admin, project.namespace.becomes(Namespace), project] do = link_to(admin_namespace_project_path(project.namespace, project)) do
.dash-project-avatar .dash-project-avatar
.avatar-container.s40 .avatar-container.s40
= project_icon(project, alt: '', class: 'avatar project-avatar s40') = project_icon(project, alt: '', class: 'avatar project-avatar s40')
......
- @body_class = 'ide' - @body_class = 'ide'
- page_title 'IDE' - page_title 'IDE'
- content_for :page_specific_javascripts do
= stylesheet_link_tag 'page_bundles/ide'
#ide.ide-loading{ data: {"empty-state-svg-path" => image_path('illustrations/multi_file_editor_empty.svg'), #ide.ide-loading{ data: {"empty-state-svg-path" => image_path('illustrations/multi_file_editor_empty.svg'),
"no-changes-state-svg-path" => image_path('illustrations/multi-editor_no_changes_empty.svg'), "no-changes-state-svg-path" => image_path('illustrations/multi-editor_no_changes_empty.svg'),
"committed-state-svg-path" => image_path('illustrations/multi-editor_all_changes_committed_empty.svg'), "committed-state-svg-path" => image_path('illustrations/multi-editor_all_changes_committed_empty.svg'),
......
...@@ -3,6 +3,11 @@ ...@@ -3,6 +3,11 @@
- site_name = "GitLab" - site_name = "GitLab"
%head{ prefix: "og: http://ogp.me/ns#" } %head{ prefix: "og: http://ogp.me/ns#" }
%meta{ charset: "utf-8" } %meta{ charset: "utf-8" }
- if Feature.enabled?('asset_host_prefetch') && ActionController::Base.asset_host
%link{ rel: 'dns-prefetch', href: ActionController::Base.asset_host }
%link{ rel: 'preconnnect', href: ActionController::Base.asset_host, crossorigin: '' }
%meta{ 'http-equiv' => 'X-UA-Compatible', content: 'IE=edge' } %meta{ 'http-equiv' => 'X-UA-Compatible', content: 'IE=edge' }
-# Open Graph - http://ogp.me/ -# Open Graph - http://ogp.me/
......
...@@ -67,5 +67,5 @@ ...@@ -67,5 +67,5 @@
%button.navbar-toggler.d-block.d-sm-none{ type: 'button' } %button.navbar-toggler.d-block.d-sm-none{ type: 'button' }
%span.sr-only= _("Toggle navigation") %span.sr-only= _("Toggle navigation")
= sprite_icon('more', size: 12, css_class: 'more-icon js-navbar-toggle-right') = sprite_icon('ellipsis_h', size: 12, css_class: 'more-icon js-navbar-toggle-right')
= sprite_icon('close', size: 12, css_class: 'close-icon js-navbar-toggle-left') = sprite_icon('close', size: 12, css_class: 'close-icon js-navbar-toggle-left')
...@@ -78,4 +78,4 @@ ...@@ -78,4 +78,4 @@
- if Gitlab::Geo.secondary? && Gitlab::Geo.primary_node_configured? - if Gitlab::Geo.secondary? && Gitlab::Geo.primary_node_configured?
%li %li
= link_to Gitlab::Geo.primary_node.url, title: 'Go to primary node', data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do = link_to Gitlab::Geo.primary_node.url, title: 'Go to primary node', data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
= sprite_icon('geo-nodes', size: 18) = sprite_icon('location-dot', size: 18)
...@@ -181,7 +181,7 @@ ...@@ -181,7 +181,7 @@
= nav_link(controller: :geo_nodes) do = nav_link(controller: :geo_nodes) do
= link_to admin_geo_nodes_path do = link_to admin_geo_nodes_path do
.nav-icon-container .nav-icon-container
= sprite_icon('geo-nodes') = sprite_icon('location-dot')
%span.nav-item-name %span.nav-item-name
Geo Nodes Geo Nodes
%ul.sidebar-sub-level-items.is-fly-out-only %ul.sidebar-sub-level-items.is-fly-out-only
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
= nav_link(path: ['groups#show', 'groups#activity', 'groups#subgroups', 'analytics#show'], html_options: { class: 'home' }) do = nav_link(path: ['groups#show', 'groups#activity', 'groups#subgroups', 'analytics#show'], html_options: { class: 'home' }) do
= link_to group_path(@group) do = link_to group_path(@group) do
.nav-icon-container .nav-icon-container
= sprite_icon('project') = sprite_icon('home')
%span.nav-item-name %span.nav-item-name
= _('Overview') = _('Overview')
......
...@@ -122,7 +122,7 @@ ...@@ -122,7 +122,7 @@
= nav_link(controller: :gpg_keys) do = nav_link(controller: :gpg_keys) do
= link_to profile_gpg_keys_path do = link_to profile_gpg_keys_path do
.nav-icon-container .nav-icon-container
= sprite_icon('key-2') = sprite_icon('key-modern')
%span.nav-item-name %span.nav-item-name
= _('GPG Keys') = _('GPG Keys')
%ul.sidebar-sub-level-items.is-fly-out-only %ul.sidebar-sub-level-items.is-fly-out-only
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
= nav_link(path: sidebar_projects_paths, html_options: { class: 'home' }) do = nav_link(path: sidebar_projects_paths, html_options: { class: 'home' }) do
= link_to project_path(@project), class: 'shortcuts-project' do = link_to project_path(@project), class: 'shortcuts-project' do
.nav-icon-container .nav-icon-container
= sprite_icon('project') = sprite_icon('home')
%span.nav-item-name %span.nav-item-name
= _('Project') = _('Project')
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
= nav_link(controller: sidebar_repository_paths) do = nav_link(controller: sidebar_repository_paths) do
= link_to project_tree_path(@project), class: 'shortcuts-tree' do = link_to project_tree_path(@project), class: 'shortcuts-tree' do
.nav-icon-container .nav-icon-container
= sprite_icon('doc_text') = sprite_icon('doc-text')
%span.nav-item-name %span.nav-item-name
= _('Repository') = _('Repository')
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
= s_('Branches|protected') = s_('Branches|protected')
- if @project.mirror_ever_updated_successfully? && @repository.diverged_from_upstream?(branch.name) - if @project.mirror_ever_updated_successfully? && @repository.diverged_from_upstream?(branch.name)
%span.badge.badge-danger.has-tooltip{ data: { html: "true", title: branch_diverged_tooltip_message } } %span.badge.badge-danger.prepend-left-5.has-tooltip{ data: { html: "true", title: branch_diverged_tooltip_message } }
= icon('exclamation-triangle') = icon('exclamation-triangle')
= s_('Branches|diverged from upstream') = s_('Branches|diverged from upstream')
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
.gitlab-embed-snippets .gitlab-embed-snippets
.js-file-title.file-title-flex-parent .js-file-title.file-title-flex-parent
.file-header-content .file-header-content
= external_snippet_icon('doc_text') = external_snippet_icon('doc-text')
%strong.file-title-name %strong.file-title-name
%a.gitlab-embedded-snippets-title{ href: url_for(only_path: false, overwrite_params: nil) } %a.gitlab-embedded-snippets-title{ href: url_for(only_path: false, overwrite_params: nil) }
......
...@@ -22,7 +22,7 @@ module Gitlab ...@@ -22,7 +22,7 @@ module Gitlab
importer_class.new(object, project, client).execute importer_class.new(object, project, client).execute
counter.increment(project: project.full_path) counter.increment
end end
def counter def counter
......
...@@ -23,9 +23,7 @@ class RepositoryForkWorker ...@@ -23,9 +23,7 @@ class RepositoryForkWorker
def fork_repository(target_project, source_repository_storage_name, source_disk_path) def fork_repository(target_project, source_repository_storage_name, source_disk_path)
return unless start_fork(target_project) return unless start_fork(target_project)
Gitlab::Metrics.add_event(:fork_repository, Gitlab::Metrics.add_event(:fork_repository)
source_path: source_disk_path,
target_path: target_project.disk_path)
result = gitlab_shell.fork_repository(source_repository_storage_name, source_disk_path, result = gitlab_shell.fork_repository(source_repository_storage_name, source_disk_path,
target_project.repository_storage, target_project.disk_path) target_project.repository_storage, target_project.disk_path)
......
...@@ -11,9 +11,7 @@ class RepositoryImportWorker ...@@ -11,9 +11,7 @@ class RepositoryImportWorker
return unless start_import(project) return unless start_import(project)
Gitlab::Metrics.add_event(:import_repository, Gitlab::Metrics.add_event(:import_repository)
import_url: project.import_url,
path: project.full_path)
service = Projects::ImportService.new(project, project.creator) service = Projects::ImportService.new(project, project.creator)
result = service.execute result = service.execute
......
---
title: Redirect commits to root if no ref is provided (31576)
merge_request: 20738
author: Kia Mei Somabes
type: added
---
title: Rework some projects table indexes around repository_storage field
merge_request: 20377
author:
type: fixed
---
title: Increase width of Web IDE sidebar resize handles
merge_request: 20818
author:
type: fixed
---
title: Fix new MR card styles
merge_request: 20822
author:
type: fixed
---
title: Fix navigation to First and Next discussion on MR Changes tab
merge_request: 20434
author:
type: fixed
---
title: DNS prefetching if asset_host for CDN hosting is set
merge_request: 20781
author:
type: performance
---
title: Fix rendering of the context lines in MR diffs page
merge_request: 20642
author:
type: fixed
---
title: Fix autosave and ESC confirmation issues for MR discussions
merge_request: 20569
author:
type: fixed
---
title: Fix showing outdated discussions on Changes tab
merge_request: 20445
author:
type: fixed
---
title: Add the first mutations for merge requests to GraphQL
merge_request: 20443
author:
type: added
---
title: Don't expose project names in various counters
merge_request:
author:
type: security
---
title: Removes "show all" on reports and adds an actionButtons slot
merge_request: 20855
author:
type: changed
---
title: Enabled deletion of files in the Web IDE
merge_request:
author:
type: added
---
title: Don't expose project names in GitHub counters
merge_request:
author:
type: security
---
title: Don't overflow project/group dropdown results
merge_request: 20704
author: gfyoung
type: fixed
---
title: Adding CSRF protection to Hooks test action
merge_request:
author:
type: security
--- ---
title: Fix slow Markdown rendering title: Bump haml gem to 5.0.4
merge_request: 20820 merge_request: 20847
author: author:
type: performance type: performance
---
title: Stop dynamically creating project and namespace routes
merge_request: 20313
author:
type: performance
---
title: Reduces the client side memory footprint on merge requests
merge_request: 20744
author:
type: performance
---
title: Wrap job name on pipeline job sidebar
merge_request: 20804
author: George Tsiolis
type: changed
---
title: Disable Gitaly timeouts when creating or restoring backups
merge_request: 20810
author:
type: fixed
...@@ -45,10 +45,12 @@ module Gitlab ...@@ -45,10 +45,12 @@ module Gitlab
#{config.root}/app/models/members #{config.root}/app/models/members
#{config.root}/app/models/project_services #{config.root}/app/models/project_services
#{config.root}/app/workers/concerns #{config.root}/app/workers/concerns
#{config.root}/app/policies/concerns
#{config.root}/app/services/concerns #{config.root}/app/services/concerns
#{config.root}/app/serializers/concerns #{config.root}/app/serializers/concerns
#{config.root}/app/finders/concerns #{config.root}/app/finders/concerns
#{config.root}/app/graphql/resolvers/concerns]) #{config.root}/app/graphql/resolvers/concerns
#{config.root}/app/graphql/mutations/concerns])
config.generators.templates.push("#{config.root}/generator_templates") config.generators.templates.push("#{config.root}/generator_templates")
...@@ -146,6 +148,7 @@ module Gitlab ...@@ -146,6 +148,7 @@ module Gitlab
config.assets.precompile << "notify.css" config.assets.precompile << "notify.css"
config.assets.precompile << "mailers/*.css" config.assets.precompile << "mailers/*.css"
config.assets.precompile << "xterm/xterm.css" config.assets.precompile << "xterm/xterm.css"
config.assets.precompile << "page_bundles/ide.css"
config.assets.precompile << "performance_bar.css" config.assets.precompile << "performance_bar.css"
config.assets.precompile << "lib/ace.js" config.assets.precompile << "lib/ace.js"
config.assets.precompile << "test.css" config.assets.precompile << "test.css"
......
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.
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.
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