Read about our upcoming Code of Conduct on this issue

Commit 379927ac authored by Shinya Maeda's avatar Shinya Maeda
Browse files

Merge branch 'live-trace-v2' into live-trace-v2-efficient-destroy-all

......@@ -72,3 +72,4 @@ eslint-report.html
/locale/**/*.time_stamp
/.rspec
/plugins/*
/.gitlab_pages_secret
......@@ -110,7 +110,7 @@ stages:
# Jobs that only need to pull cache
.dedicated-no-docs-pull-cache-job: &dedicated-no-docs-pull-cache-job
<<: *dedicated-runner
<<: *except-docs-and-qa
<<: *except-docs
<<: *pull-cache
dependencies:
- setup-test-env
......@@ -122,6 +122,10 @@ stages:
variables:
SETUP_DB: "false"
.dedicated-no-docs-and-no-qa-pull-cache-job: &dedicated-no-docs-and-no-qa-pull-cache-job
<<: *dedicated-no-docs-pull-cache-job
<<: *except-docs-and-qa
.rake-exec: &rake-exec
<<: *dedicated-no-docs-no-db-pull-cache-job
script:
......@@ -222,7 +226,7 @@ stages:
- master@gitlab/gitlab-ee
.gitlab-setup: &gitlab-setup
<<: *dedicated-no-docs-pull-cache-job
<<: *dedicated-no-docs-and-no-qa-pull-cache-job
<<: *use-pg
variables:
CREATE_DB_USER: "true"
......@@ -262,12 +266,12 @@ stages:
# DB migration, rollback, and seed jobs
.db-migrate-reset: &db-migrate-reset
<<: *dedicated-no-docs-pull-cache-job
<<: *dedicated-no-docs-and-no-qa-pull-cache-job
script:
- bundle exec rake db:migrate:reset
.migration-paths: &migration-paths
<<: *dedicated-no-docs-pull-cache-job
<<: *dedicated-no-docs-and-no-qa-pull-cache-job
variables:
CREATE_DB_USER: "true"
script:
......@@ -647,7 +651,7 @@ migration:path-mysql:
<<: *use-mysql
.db-rollback: &db-rollback
<<: *dedicated-no-docs-pull-cache-job
<<: *dedicated-no-docs-and-no-qa-pull-cache-job
script:
- bundle exec rake db:migrate VERSION=20170523121229
- bundle exec rake db:migrate
......@@ -670,7 +674,7 @@ gitlab:setup-mysql:
# Frontend-related jobs
gitlab:assets:compile:
<<: *dedicated-no-docs-no-db-pull-cache-job
<<: *dedicated-no-docs-and-no-qa-pull-cache-job
dependencies: []
variables:
NODE_ENV: "production"
......@@ -691,7 +695,7 @@ gitlab:assets:compile:
- webpack-report/
karma:
<<: *dedicated-no-docs-pull-cache-job
<<: *dedicated-no-docs-and-no-qa-pull-cache-job
<<: *use-pg
dependencies:
- compile-assets
......@@ -815,7 +819,7 @@ coverage:
- coverage/assets/
lint:javascript:report:
<<: *dedicated-no-docs-no-db-pull-cache-job
<<: *dedicated-no-docs-and-no-qa-pull-cache-job
stage: post-test
dependencies:
- compile-assets
......
......@@ -25,12 +25,12 @@ _This notice should stay as the first item in the CONTRIBUTING.md file._
- [Workflow labels](#workflow-labels)
- [Type labels (~"feature proposal", ~bug, ~customer, etc.)](#type-labels-feature-proposal-bug-customer-etc)
- [Subject labels (~wiki, ~"container registry", ~ldap, ~api, etc.)](#subject-labels-wiki-container-registry-ldap-api-etc)
- [Team labels (~"CI/CD", ~Discussion, ~Edge, ~Platform, etc.)](#team-labels-cicd-discussion-edge-platform-etc)
- [Team labels (~"CI/CD", ~Discussion, ~Quality, ~Platform, etc.)](#team-labels-cicd-discussion-quality-platform-etc)
- [Milestone labels (~Deliverable, ~Stretch, ~"Next Patch Release")](#milestone-labels-deliverable-stretch-next-patch-release)
- [Priority labels (~Deliverable, ~Stretch, ~"Next Patch Release")](#bug-priority-labels-p1-p2-p3-etc)
- [Severity labels (~Deliverable, ~Stretch, ~"Next Patch Release")](#bug-severity-labels-s1-s2-s3-etc)
- [Label for community contributors (~"Accepting Merge Requests")](#label-for-community-contributors-accepting-merge-requests)
- [Implement design & UI elements](#implement-design-ui-elements)
- [Implement design & UI elements](#implement-design--ui-elements)
- [Issue tracker](#issue-tracker)
- [Issue triaging](#issue-triaging)
- [Feature proposals](#feature-proposals)
......@@ -114,7 +114,7 @@ is a great place to start. Issues with a lower weight (1 or 2) are deemed
suitable for beginners. These issues will be of reasonable size and challenge,
for anyone to start contributing to GitLab. If you have any questions or need help visit [Getting Help](https://about.gitlab.com/getting-help/#discussion) to
learn how to communicate with GitLab. If you're looking for a Gitter or Slack channel
please consider we favor
please consider we favor
[asynchronous communication](https://about.gitlab.com/handbook/communication/#internal-communication) over real time communication. Thanks for your contribution!
## Workflow labels
......@@ -127,7 +127,7 @@ Most issues will have labels for at least one of the following:
- Type: ~"feature proposal", ~bug, ~customer, etc.
- Subject: ~wiki, ~"container registry", ~ldap, ~api, ~frontend, etc.
- Team: ~"CI/CD", ~Discussion, ~Edge, ~Platform, etc.
- Team: ~"CI/CD", ~Discussion, ~Quality, ~Platform, etc.
- Milestone: ~Deliverable, ~Stretch, ~"Next Patch Release"
- Priority: ~P1, ~P2, ~P3, ~P4
- Severity: ~S1, ~S2, ~S3, ~S4
......@@ -171,13 +171,13 @@ Examples of subject labels are ~wiki, ~"container registry", ~ldap, ~api,
Subject labels are always all-lowercase.
### Team labels (~"CI/CD", ~Discussion, ~Edge, ~Platform, etc.)
### Team labels (~"CI/CD", ~Discussion, ~Quality, ~Platform, etc.)
Team labels specify what team is responsible for this issue.
Assigning a team label makes sure issues get the attention of the appropriate
people.
The current team labels are ~Build, ~"CI/CD", ~Discussion, ~Documentation, ~Edge,
The current team labels are ~Build, ~"CI/CD", ~Discussion, ~Documentation, ~Quality,
~Geo, ~Gitaly, ~Monitoring, ~Platform, ~Release, ~"Security Products" and ~"UX".
The descriptions on the [labels page][labels-page] explain what falls under the
......@@ -199,12 +199,12 @@ release. There are three levels of Milestone labels:
- ~Stretch: Issues that are a stretch goal for delivering in the current
milestone. If these issues are not done in the current release, they will
strongly be considered for the next release.
- ~"Next Patch Release": Issues to put in the next patch release. Work on these
- ~"Next Patch Release": Issues to put in the next patch release. Work on these
first, and add the "Pick Into X" label to the merge request, along with the
appropriate milestone.
Each issue scheduled for the current milestone should be labeled ~Deliverable
or ~"Stretch". Any open issue for a previous milestone should be labeled
or ~"Stretch". Any open issue for a previous milestone should be labeled
~"Next Patch Release", or otherwise rescheduled to a different milestone.
### Bug Priority labels (~P1, ~P2, ~P3 & etc.)
......@@ -221,16 +221,16 @@ This label documents the planned timeline & urgency which is used to measure aga
#### Specific Priority guidance
| Label | Availability / Performance |
| Label | Availability / Performance |
|-------|--------------------------------------------------------------|
| ~P1 | |
| ~P1 | |
| ~P2 | The issue is (almost) guaranteed to occur in the near future |
| ~P3 | The issue is likely to occur in the near future |
| ~P4 | The issue _may_ occur but it's not likely |
### Bug Severity labels (~S1, ~S2, ~S3 & etc.)
Severity labels help us clearly communicate the impact of a ~bug on users.
Severity labels help us clearly communicate the impact of a ~bug on users.
| Label | Meaning | Impact of the defect | Example |
|-------|-------------------|-------------------------------------------------------|---------|
......@@ -241,9 +241,9 @@ Severity labels help us clearly communicate the impact of a ~bug on users.
#### Specific Severity guidance
| Label | Security Impact |
| Label | Security Impact |
|-------|-------------------------------------------------------------------|
| ~S1 | >50% customers impacted (possible company extinction level event) |
| ~S1 | >50% customers impacted (possible company extinction level event) |
| ~S2 | Multiple customers impacted (but not apocalyptic) |
| ~S3 | A single customer impacted |
| ~S4 | No customer impact, or expected impact within 30 days |
......@@ -727,4 +727,3 @@ available at [http://contributor-covenant.org/version/1/1/0/](http://contributor
[^1]: Please note that specs other than JavaScript specs are considered backend
code.
\ No newline at end of file
......@@ -283,7 +283,6 @@ gem 'batch-loader', '~> 1.2.1'
gem 'peek', '~> 1.0.1'
gem 'peek-gc', '~> 0.0.2'
gem 'peek-mysql2', '~> 1.1.0', group: :mysql
gem 'peek-performance_bar', '~> 1.3.0'
gem 'peek-pg', '~> 1.3.0', group: :postgres
gem 'peek-rblineprof', '~> 0.2.0'
gem 'peek-redis', '~> 1.2.0'
......
......@@ -603,8 +603,6 @@ GEM
atomic (>= 1.0.0)
mysql2
peek
peek-performance_bar (1.3.1)
peek (>= 0.1.0)
peek-pg (1.3.0)
concurrent-ruby
concurrent-ruby-ext
......@@ -1130,7 +1128,6 @@ DEPENDENCIES
peek (~> 1.0.1)
peek-gc (~> 0.0.2)
peek-mysql2 (~> 1.1.0)
peek-performance_bar (~> 1.3.0)
peek-pg (~> 1.3.0)
peek-rblineprof (~> 0.2.0)
peek-redis (~> 1.2.0)
......
......@@ -26,11 +26,18 @@ export default {
required: false,
default: false,
},
forceModifiedIcon: {
type: Boolean,
required: false,
default: false,
},
},
computed: {
changedIcon() {
const suffix = this.file.staged && !this.showStagedIcon ? '-solid' : '';
return this.file.tempFile ? `file-addition${suffix}` : `file-modified${suffix}`;
return this.file.tempFile && !this.forceModifiedIcon
? `file-addition${suffix}`
: `file-modified${suffix}`;
},
stagedIcon() {
return `${this.changedIcon}-solid`;
......
<script>
import { mapActions } from 'vuex';
import icon from '~/vue_shared/components/icon.vue';
import newModal from './modal.vue';
import upload from './upload.vue';
import { mapActions } from 'vuex';
import icon from '~/vue_shared/components/icon.vue';
import newModal from './modal.vue';
import upload from './upload.vue';
export default {
components: {
icon,
newModal,
upload,
export default {
components: {
icon,
newModal,
upload,
},
props: {
branch: {
type: String,
required: true,
},
props: {
branch: {
type: String,
required: true,
},
path: {
type: String,
required: true,
},
path: {
type: String,
required: true,
},
data() {
return {
openModal: false,
modalType: '',
dropdownOpen: false,
};
},
data() {
return {
openModal: false,
modalType: '',
dropdownOpen: false,
};
},
watch: {
dropdownOpen() {
this.$nextTick(() => {
this.$refs.dropdownMenu.scrollIntoView();
});
},
methods: {
...mapActions([
'createTempEntry',
]),
createNewItem(type) {
this.modalType = type;
this.openModal = true;
this.dropdownOpen = false;
},
hideModal() {
this.openModal = false;
},
openDropdown() {
this.dropdownOpen = !this.dropdownOpen;
},
},
methods: {
...mapActions(['createTempEntry']),
createNewItem(type) {
this.modalType = type;
this.openModal = true;
this.dropdownOpen = false;
},
};
hideModal() {
this.openModal = false;
},
openDropdown() {
this.dropdownOpen = !this.dropdownOpen;
},
},
};
</script>
<template>
......@@ -71,7 +76,10 @@
css-classes="pull-left"
/>
</button>
<ul class="dropdown-menu dropdown-menu-right">
<ul
class="dropdown-menu dropdown-menu-right"
ref="dropdownMenu"
>
<li>
<a
href="#"
......
......@@ -40,13 +40,6 @@ export default {
return __('Create file');
},
formLabelName() {
if (this.type === 'tree') {
return __('Directory name');
}
return __('File name');
},
},
mounted() {
this.$refs.fieldName.focus();
......@@ -82,8 +75,8 @@ export default {
@submit.prevent="createEntryInStore"
>
<fieldset class="form-group append-bottom-0">
<label class="label-light col-sm-3">
{{ formLabelName }}
<label class="label-light col-sm-3 ide-new-modal-label">
{{ __('Name') }}
</label>
<div class="col-sm-9">
<input
......
......@@ -97,7 +97,7 @@ export default {
:file="file"
/>
</span>
<span class="pull-right">
<span class="pull-right ide-file-icon-holder">
<mr-file-icon
v-if="file.mrChange"
/>
......@@ -106,7 +106,8 @@ export default {
:file="file"
:show-tooltip="true"
:show-staged-icon="true"
class="prepend-top-5 pull-right"
:force-modified-icon="true"
class="pull-right"
/>
</span>
<new-dropdown
......
......@@ -84,6 +84,7 @@ export default {
<changed-file-icon
v-else
:file="tab"
:force-modified-icon="true"
/>
</button>
......
......@@ -33,10 +33,7 @@ export const setPanelCollapsedStatus = ({ commit }, { side, collapsed }) => {
}
};
export const toggleRightPanelCollapsed = (
{ dispatch, state },
e = undefined,
) => {
export const toggleRightPanelCollapsed = ({ dispatch, state }, e = undefined) => {
if (e) {
$(e.currentTarget)
.tooltip('hide')
......@@ -77,7 +74,7 @@ export const createTempEntry = (
}
worker.addEventListener('message', ({ data }) => {
const { file } = data;
const { file, parentPath } = data;
worker.terminate();
......@@ -93,6 +90,10 @@ export const createTempEntry = (
dispatch('setFileActive', file.path);
}
if (parentPath && !state.entries[parentPath].opened) {
commit(types.TOGGLE_TREE_OPEN, parentPath);
}
resolve(file);
});
......@@ -137,6 +138,14 @@ export const updateDelayViewerUpdated = ({ commit }, delay) => {
commit(types.UPDATE_DELAY_VIEWER_CHANGE, delay);
};
export const updateTempFlagForEntry = ({ commit, dispatch, state }, { file, tempFile }) => {
commit(types.UPDATE_TEMP_FLAG, { path: file.path, tempFile });
if (file.parentPath) {
dispatch('updateTempFlagForEntry', { file: state.entries[file.parentPath], tempFile });
}
};
export const toggleFileFinder = ({ commit }, fileFindVisible) =>
commit(types.TOGGLE_FILE_FINDER, fileFindVisible);
......
......@@ -63,7 +63,7 @@ export const getFileData = ({ state, commit, dispatch }, { path, makeFileActive
const file = state.entries[path];
commit(types.TOGGLE_LOADING, { entry: file });
return service
.getFileData(file.url)
.getFileData(`${gon.relative_url_root ? gon.relative_url_root : ''}${file.url}`)
.then(res => {
const pageTitle = decodeURI(normalizeHeaders(res.headers)['PAGE-TITLE']);
setPageTitle(pageTitle);
......
......@@ -110,6 +110,17 @@ export const updateFilesAfterCommit = (
{ root: true },
);
commit(
rootTypes.TOGGLE_FILE_CHANGED,
{
file,
changed: false,
},
{ root: true },
);
dispatch('updateTempFlagForEntry', { file, tempFile: false }, { root: true });
eventHub.$emit(`editor.update.model.content.${file.key}`, {
content: file.content,
changed: !!changedFile,
......
......@@ -59,4 +59,5 @@ export const UPDATE_FILE_AFTER_COMMIT = 'UPDATE_FILE_AFTER_COMMIT';
export const ADD_PENDING_TAB = 'ADD_PENDING_TAB';
export const REMOVE_PENDING_TAB = 'REMOVE_PENDING_TAB';
export const UPDATE_TEMP_FLAG = 'UPDATE_TEMP_FLAG';
export const TOGGLE_FILE_FINDER = 'TOGGLE_FILE_FINDER';
......@@ -4,6 +4,7 @@ import mergeRequestMutation from './mutations/merge_request';
import fileMutations from './mutations/file';
import treeMutations from './mutations/tree';
import branchMutations from './mutations/branch';
import { sortTree } from './utils';
export default {
[types.SET_INITIAL_DATA](state, data) {
......@@ -73,7 +74,7 @@ export default {
f => foundEntry.tree.find(e => e.path === f.path) === undefined,
);
Object.assign(foundEntry, {
tree: foundEntry.tree.concat(tree),
tree: sortTree(foundEntry.tree.concat(tree)),
});
}
......@@ -86,10 +87,16 @@ export default {
if (!foundEntry) {
Object.assign(state.trees[`${projectId}/${branchId}`], {
tree: state.trees[`${projectId}/${branchId}`].tree.concat(data.treeList),
tree: sortTree(state.trees[`${projectId}/${branchId}`].tree.concat(data.treeList)),
});
}
},
[types.UPDATE_TEMP_FLAG](state, { path, tempFile }) {
Object.assign(state.entries[path], {
tempFile,
changed: tempFile,
});
},
[types.UPDATE_VIEWER](state, viewer) {
Object.assign(state, {
viewer,
......
......@@ -33,6 +33,7 @@ export const dataStructure = () => ({
raw: '',
content: '',
parentTreeUrl: '',
parentPath: '',
renderError: false,
base64: false,
editorRow: 1,
......@@ -65,6 +66,7 @@ export const decorateData = entity => {
previewMode,
file_lock,
html,
parentPath = '',
} = entity;
return {
......@@ -81,6 +83,7 @@ export const decorateData = entity => {
opened,
active,
parentTreeUrl,
parentPath,
changed,
renderError,
content,
......@@ -121,8 +124,8 @@ const sortTreesByTypeAndName = (a, b) => {
} else if (a.type === 'blob' && b.type === 'tree') {
return 1;
}
if (a.name.toLowerCase() < b.name.toLowerCase()) return -1;
if (a.name.toLowerCase() > b.name.toLowerCase()) return 1;
if (a.name < b.name) return -1;
if (a.name > b.name) return 1;
return 0;
};
......
......@@ -6,6 +6,7 @@ self.addEventListener('message', e => {
const treeList = [];
let file;
let parentPath;
const entries = data.reduce((acc, path) => {
const pathSplit = path.split('/');
const blobName = pathSplit.pop().trim();
......@@ -17,6 +18,8 @@ self.addEventListener('message', e => {
const foundEntry = acc[folderPath];
if (!foundEntry) {
parentPath = parentFolder ? parentFolder.path : null;
const tree = decorateData({
projectId,
branchId,
......@@ -29,6 +32,7 @@ self.addEventListener('message', e => {
tempFile,
changed: tempFile,
opened: tempFile,
parentPath,
});
Object.assign(acc, {
......@@ -52,6 +56,8 @@ self.addEventListener('message', e => {
if (blobName !== '') {
const fileFolder = acc[pathSplit.join('/')];
parentPath = fileFolder ? fileFolder.path : null;
file = decorateData({
projectId,
branchId,
......@@ -66,6 +72,7 @@ self.addEventListener('message', e => {
content,
base64,
previewMode: viewerInformationForPath(blobName),
parentPath,
});
Object.assign(acc, {
......@@ -86,5 +93,6 @@ self.addEventListener('message', e => {
entries,
treeList: sortTree(treeList),
file,
parentPath,
});
});
......@@ -12,7 +12,8 @@ import ModalStore from './boards/stores/modal_store';
export default class MilestoneSelect {
constructor(currentProject, els, options = {}) {
if (currentProject !== null) {
this.currentProject = typeof currentProject === 'string' ? JSON.parse(currentProject) : currentProject;
this.currentProject =
typeof currentProject === 'string' ? JSON.parse(currentProject) : currentProject;
}
this.init(els, options);
......@@ -26,7 +27,10 @@ export default class MilestoneSelect {
}
$els.each((i, dropdown) => {
let milestoneLinkNoneTemplate, milestoneLinkTemplate, selectedMilestone, selectedMilestoneDefault;
let milestoneLinkNoneTemplate,
milestoneLinkTemplate,
selectedMilestone,
selectedMilestoneDefault;
const $dropdown = $(dropdown);
const projectId = $dropdown.data('projectId');
const milestonesUrl = $dropdown.data('milestones');
......@@ -46,45 +50,47 @@ export default class MilestoneSelect {
const $sidebarCollapsedValue = $block.find('.sidebar-collapsed-icon');
const $value = $block.find('.value');
const $loading = $block.find('.block-loading').fadeOut();