Skip to content
Snippets Groups Projects
Commit 75c02edb authored by GitLab Bot's avatar GitLab Bot
Browse files

Merge remote-tracking branch 'upstream/master' into ce-to-ee-2018-05-03

# Conflicts:
#	LICENSE

[ci skip]
parents 2963bc01 622aeea9
No related branches found
No related tags found
No related merge requests found
Showing
with 233 additions and 38 deletions
Loading
Loading
@@ -41,7 +41,7 @@ gem 'omniauth-auth0', '~> 2.0.0'
gem 'omniauth-azure-oauth2', '~> 0.0.9'
gem 'omniauth-cas3', '~> 1.1.4'
gem 'omniauth-facebook', '~> 4.0.0'
gem 'omniauth-github', '~> 1.1.1'
gem 'omniauth-github', '~> 1.3'
gem 'omniauth-gitlab', '~> 1.0.2'
gem 'omniauth-google-oauth2', '~> 0.5.3'
gem 'omniauth-kerberos', '~> 0.3.0', group: :kerberos
Loading
Loading
Loading
Loading
@@ -575,9 +575,9 @@ GEM
omniauth (~> 1.2)
omniauth-facebook (4.0.0)
omniauth-oauth2 (~> 1.2)
omniauth-github (1.1.2)
omniauth (~> 1.0)
omniauth-oauth2 (~> 1.1)
omniauth-github (1.3.0)
omniauth (~> 1.5)
omniauth-oauth2 (>= 1.4.0, < 2.0)
omniauth-gitlab (1.0.2)
omniauth (~> 1.0)
omniauth-oauth2 (~> 1.0)
Loading
Loading
@@ -1151,7 +1151,7 @@ DEPENDENCIES
omniauth-azure-oauth2 (~> 0.0.9)
omniauth-cas3 (~> 1.1.4)
omniauth-facebook (~> 4.0.0)
omniauth-github (~> 1.1.1)
omniauth-github (~> 1.3)
omniauth-gitlab (~> 1.0.2)
omniauth-google-oauth2 (~> 0.5.3)
omniauth-kerberos (~> 0.3.0)
Loading
Loading
Loading
Loading
@@ -23,6 +23,7 @@ granted any other rights beyond what is expressly stated herein. Subject to the
foregoing, it is forbidden to copy, merge, publish, distribute, sublicense,
and/or sell the Software.
 
<<<<<<< HEAD
This EE License applies only to the part of this Software that is not
distributed as part of GitLab Community Edition (CE), and that is not a file
that produces client-side JavaScript, in whole or in part. Any part of this
Loading
Loading
@@ -42,6 +43,9 @@ THE SOFTWARE.
For all third party components incorporated into the GitLab Software, those
components are licensed under the original license provided by the owner of the
applicable component.
=======
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
>>>>>>> upstream/master
 
---
 
Loading
Loading
Loading
Loading
@@ -43,7 +43,7 @@ export default {
return `${this.changedIcon}-solid`;
},
changedIconClass() {
return `multi-${this.changedIcon} prepend-left-5 pull-left`;
return `multi-${this.changedIcon} pull-left`;
},
tooltipTitle() {
if (!this.showTooltip) return undefined;
Loading
Loading
@@ -79,13 +79,7 @@ export default {
class="ide-file-changed-icon"
>
<icon
v-if="file.staged && showStagedIcon"
:name="stagedIcon"
:size="12"
:css-classes="changedIconClass"
/>
<icon
v-if="file.changed || file.tempFile || (file.staged && !showStagedIcon)"
v-if="file.changed || file.tempFile || file.staged"
:name="changedIcon"
:size="12"
:css-classes="changedIconClass"
Loading
Loading
Loading
Loading
@@ -36,7 +36,7 @@ export default {
return this.file.tempFile ? `file-addition${prefix}` : `file-modified${prefix}`;
},
iconClass() {
return `multi-file-${this.file.tempFile ? 'additions' : 'modified'} append-right-8`;
return `multi-file-${this.file.tempFile ? 'addition' : 'modified'} append-right-8`;
},
},
methods: {
Loading
Loading
<script>
import { mapActions } from 'vuex';
import skeletonLoadingContainer from '~/vue_shared/components/skeleton_loading_container.vue';
import fileIcon from '~/vue_shared/components/file_icon.vue';
import { mapActions, mapGetters } from 'vuex';
import { n__, __, sprintf } from '~/locale';
import tooltip from '~/vue_shared/directives/tooltip';
import SkeletonLoadingContainer from '~/vue_shared/components/skeleton_loading_container.vue';
import Icon from '~/vue_shared/components/icon.vue';
import FileIcon from '~/vue_shared/components/file_icon.vue';
import router from '../ide_router';
import newDropdown from './new_dropdown/index.vue';
import fileStatusIcon from './repo_file_status_icon.vue';
import changedFileIcon from './changed_file_icon.vue';
import mrFileIcon from './mr_file_icon.vue';
import NewDropdown from './new_dropdown/index.vue';
import FileStatusIcon from './repo_file_status_icon.vue';
import ChangedFileIcon from './changed_file_icon.vue';
import MrFileIcon from './mr_file_icon.vue';
 
export default {
name: 'RepoFile',
directives: {
tooltip,
},
components: {
skeletonLoadingContainer,
newDropdown,
fileStatusIcon,
fileIcon,
changedFileIcon,
mrFileIcon,
SkeletonLoadingContainer,
NewDropdown,
FileStatusIcon,
FileIcon,
ChangedFileIcon,
MrFileIcon,
Icon,
},
props: {
file: {
Loading
Loading
@@ -29,6 +36,34 @@ export default {
},
},
computed: {
...mapGetters([
'getChangesInFolder',
'getUnstagedFilesCountForPath',
'getStagedFilesCountForPath',
]),
folderUnstagedCount() {
return this.getUnstagedFilesCountForPath(this.file.path);
},
folderStagedCount() {
return this.getStagedFilesCountForPath(this.file.path);
},
changesCount() {
return this.getChangesInFolder(this.file.path);
},
folderChangesTooltip() {
if (this.changesCount === 0) return undefined;
if (this.folderUnstagedCount > 0 && this.folderStagedCount === 0) {
return n__('%d unstaged change', '%d unstaged changes', this.folderUnstagedCount);
} else if (this.folderUnstagedCount === 0 && this.folderStagedCount > 0) {
return n__('%d staged change', '%d staged changes', this.folderStagedCount);
}
return sprintf(__('%{unstaged} unstaged and %{staged} staged changes'), {
unstaged: this.folderUnstagedCount,
staged: this.folderStagedCount,
});
},
isTree() {
return this.file.type === 'tree';
},
Loading
Loading
@@ -48,10 +83,19 @@ export default {
'is-open': this.file.opened,
};
},
showTreeChangesCount() {
return this.isTree && this.changesCount > 0 && !this.file.opened;
},
showChangedFileIcon() {
return this.file.changed || this.file.tempFile || this.file.staged;
},
},
updated() {
if (this.file.type === 'blob' && this.file.active) {
this.$el.scrollIntoView();
this.$el.scrollIntoView({
behavior: 'smooth',
block: 'nearest',
});
}
},
methods: {
Loading
Loading
@@ -101,8 +145,23 @@ export default {
<mr-file-icon
v-if="file.mrChange"
/>
<span
v-if="showTreeChangesCount"
class="ide-tree-changes"
>
{{ changesCount }}
<icon
v-tooltip
:title="folderChangesTooltip"
data-container="body"
data-placement="right"
name="file-modified"
:size="12"
css-classes="prepend-left-5 multi-file-modified"
/>
</span>
<changed-file-icon
v-if="file.changed || file.tempFile || file.staged"
v-else-if="showChangedFileIcon"
:file="file"
:show-tooltip="true"
:show-staged-icon="true"
Loading
Loading
import { __ } from '~/locale';
import { getChangesCountForFiles, filePathMatches } from './utils';
 
export const activeFile = state => state.openFiles.find(file => file.active) || null;
 
Loading
Loading
@@ -55,7 +56,23 @@ export const allBlobs = state =>
}, [])
.sort((a, b) => b.lastOpenedAt - a.lastOpenedAt);
 
export const getChangedFile = state => path => state.changedFiles.find(f => f.path === path);
export const getStagedFile = state => path => state.stagedFiles.find(f => f.path === path);
 
export const getChangesInFolder = state => path => {
const changedFilesCount = state.changedFiles.filter(f => filePathMatches(f, path)).length;
const stagedFilesCount = state.stagedFiles.filter(
f => filePathMatches(f, path) && !getChangedFile(state)(f.path),
).length;
return changedFilesCount + stagedFilesCount;
};
export const getUnstagedFilesCountForPath = state => path =>
getChangesCountForFiles(state.changedFiles, path);
export const getStagedFilesCountForPath = state => path =>
getChangesCountForFiles(state.stagedFiles, path);
// prevent babel-plugin-rewire from generating an invalid default during karma tests
export default () => {};
Loading
Loading
@@ -33,7 +33,6 @@ export const dataStructure = () => ({
raw: '',
content: '',
parentTreeUrl: '',
parentPath: '',
renderError: false,
base64: false,
editorRow: 1,
Loading
Loading
@@ -43,6 +42,7 @@ export const dataStructure = () => ({
viewMode: 'edit',
previewMode: null,
size: 0,
parentPath: null,
lastOpenedAt: 0,
});
 
Loading
Loading
@@ -83,7 +83,6 @@ export const decorateData = entity => {
opened,
active,
parentTreeUrl,
parentPath,
changed,
renderError,
content,
Loading
Loading
@@ -91,6 +90,7 @@ export const decorateData = entity => {
previewMode,
file_lock,
html,
parentPath,
};
};
 
Loading
Loading
@@ -137,3 +137,9 @@ export const sortTree = sortedTree =>
}),
)
.sort(sortTreesByTypeAndName);
export const filePathMatches = (f, path) =>
f.path.replace(new RegExp(`${f.name}$`), '').indexOf(`${path}/`) === 0;
export const getChangesCountForFiles = (files, path) =>
files.filter(f => filePathMatches(f, path)).length;
Loading
Loading
@@ -603,14 +603,14 @@
}
}
 
.multi-file-additions,
.multi-file-additions-solid {
fill: $green-500;
.multi-file-addition,
.multi-file-addition-solid {
color: $green-500;
}
 
.multi-file-modified,
.multi-file-modified-solid {
fill: $orange-500;
color: $orange-500;
}
 
.multi-file-commit-list-collapsed {
Loading
Loading
@@ -991,6 +991,12 @@
resize: none;
}
 
.ide-tree-changes {
display: flex;
align-items: center;
font-size: 12px;
}
.ide-new-modal-label {
line-height: 34px;
}
Loading
Loading
@@ -35,7 +35,7 @@
= link_to avatar_icon_for_user(@user, 400), target: '_blank', rel: 'noopener noreferrer' do
= image_tag avatar_icon_for_user(@user, 90), class: "avatar s90", alt: ''
 
.user-info
.user-info.prepend-left-default.append-right-default
.cover-title
= @user.name
 
Loading
Loading
---
title: Add padding to profile description
merge_request: 18663
author: George Tsiolis
type: changed
---
title: Output some useful information when running the rails console
merge_request: 18697
author:
type: added
# rubocop:disable Rails/Output
if defined?(Rails::Console)
# note that this will not print out when using `spring`
justify = 15
puts "-------------------------------------------------------------------------------------"
puts " Gitlab:".ljust(justify) + "#{Gitlab::VERSION} (#{Gitlab::REVISION})"
puts " Gitlab Shell:".ljust(justify) + Gitlab::Shell.new.version
puts " #{Gitlab::Database.adapter_name}:".ljust(justify) + Gitlab::Database.version
puts "-------------------------------------------------------------------------------------"
end
Loading
Loading
@@ -48,6 +48,33 @@ describe('RepoFile', () => {
});
});
 
describe('folder', () => {
it('renders changes count inside folder', () => {
const f = {
...file('folder'),
path: 'testing',
type: 'tree',
branchId: 'master',
projectId: 'project',
};
store.state.changedFiles.push({
...file('fileName'),
path: 'testing/fileName',
});
createComponent({
file: f,
level: 0,
});
const treeChangesEl = vm.$el.querySelector('.ide-tree-changes');
expect(treeChangesEl).not.toBeNull();
expect(treeChangesEl.textContent).toContain('1');
});
});
describe('locked file', () => {
let f;
 
Loading
Loading
@@ -72,8 +99,7 @@ describe('RepoFile', () => {
 
it('renders a tooltip', () => {
expect(
vm.$el.querySelector('.ide-file-name span:nth-child(2)').dataset
.originalTitle,
vm.$el.querySelector('.ide-file-name span:nth-child(2)').dataset.originalTitle,
).toContain('Locked by testuser');
});
});
Loading
Loading
Loading
Loading
@@ -84,4 +84,67 @@ describe('IDE store getters', () => {
expect(getters.allBlobs(localState)[0].name).toBe('blob');
});
});
describe('getChangesInFolder', () => {
it('returns length of changed files for a path', () => {
localState.changedFiles.push(
{
path: 'test/index',
name: 'index',
},
{
path: 'app/123',
name: '123',
},
);
expect(getters.getChangesInFolder(localState)('test')).toBe(1);
});
it('returns length of changed & staged files for a path', () => {
localState.changedFiles.push(
{
path: 'test/index',
name: 'index',
},
{
path: 'testing/123',
name: '123',
},
);
localState.stagedFiles.push(
{
path: 'test/123',
name: '123',
},
{
path: 'test/index',
name: 'index',
},
{
path: 'testing/12345',
name: '12345',
},
);
expect(getters.getChangesInFolder(localState)('test')).toBe(2);
});
it('returns length of changed & tempFiles files for a path', () => {
localState.changedFiles.push(
{
path: 'test/index',
name: 'index',
},
{
path: 'test/newfile',
name: 'newfile',
tempFile: true,
},
);
expect(getters.getChangesInFolder(localState)('test')).toBe(2);
});
});
});
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment