Commit d8317ed6 authored by GitLab Bot's avatar GitLab Bot

Merge remote-tracking branch 'upstream/master' into ce-to-ee-2018-01-11

# Conflicts:
#	app/assets/javascripts/boards/components/board_card.vue
#	app/assets/javascripts/clusters/components/application_row.vue
#	app/assets/javascripts/commit/pipelines/pipelines_table.vue
#	app/assets/javascripts/cycle_analytics/components/stage_code_component.vue
#	app/assets/javascripts/cycle_analytics/components/stage_component.vue
#	app/assets/javascripts/cycle_analytics/components/stage_plan_component.vue
#	app/assets/javascripts/cycle_analytics/components/stage_review_component.vue
#	app/assets/javascripts/cycle_analytics/components/stage_staging_component.vue
#	app/assets/javascripts/cycle_analytics/components/stage_test_component.vue
#	app/assets/javascripts/dispatcher.js
#	app/assets/javascripts/environments/components/environment_actions.vue
#	app/assets/javascripts/environments/components/environment_external_url.vue
#	app/assets/javascripts/environments/components/environment_item.vue
#	app/assets/javascripts/environments/components/environment_monitoring.vue
#	app/assets/javascripts/environments/components/environment_rollback.vue
#	app/assets/javascripts/environments/components/environment_stop.vue
#	app/assets/javascripts/environments/components/environment_terminal_button.vue
#	app/assets/javascripts/environments/components/environments_table.vue
#	app/assets/javascripts/environments/folder/environments_folder_view.vue
#	app/assets/javascripts/groups/components/app.vue
#	app/assets/javascripts/groups/components/item_actions.vue
#	app/assets/javascripts/groups/components/item_stats_value.vue
#	app/assets/javascripts/ide/components/ide_project_branches_tree.vue
#	app/assets/javascripts/ide/components/ide_side_bar.vue
#	app/assets/javascripts/ide/components/repo_editor.vue
#	app/assets/javascripts/ide/components/repo_preview.vue
#	app/assets/javascripts/ide/components/repo_tab.vue
#	app/assets/javascripts/issue_show/components/app.vue
#	app/assets/javascripts/monitoring/components/dashboard.vue
#	app/assets/javascripts/monitoring/components/graph.vue
#	app/assets/javascripts/monitoring/components/graph/flag.vue
#	app/assets/javascripts/notebook/cells/markdown.vue
#	app/assets/javascripts/notes/components/comment_form.vue
#	app/assets/javascripts/notes/components/note_attachment.vue
#	app/assets/javascripts/notes/components/note_form.vue
#	app/assets/javascripts/notes/components/noteable_note.vue
#	app/assets/javascripts/pipelines/components/async_button.vue
#	app/assets/javascripts/pipelines/components/graph/action_component.vue
#	app/assets/javascripts/pipelines/components/graph/graph_component.vue
#	app/assets/javascripts/pipelines/components/graph/stage_column_component.vue
#	app/assets/javascripts/pipelines/components/header_component.vue
#	app/assets/javascripts/pipelines/components/pipelines_table_row.vue
#	app/assets/javascripts/pipelines/components/stage.vue
#	app/assets/javascripts/projects/permissions/components/settings_panel.vue
#	app/assets/javascripts/registry/components/table_registry.vue
#	app/assets/javascripts/sidebar/components/confidential/confidential_issue_sidebar.vue
#	app/assets/javascripts/sidebar/components/lock/edit_form.vue
#	app/assets/javascripts/sidebar/components/lock/lock_issue_sidebar.vue
#	app/assets/javascripts/sidebar/components/subscriptions/sidebar_subscriptions.vue
#	app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.vue
#	app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue
#	app/assets/javascripts/vue_shared/components/ci_icon.vue
#	app/assets/javascripts/vue_shared/components/header_ci_component.vue
#	app/assets/javascripts/vue_shared/components/issue/issue_warning.vue
#	app/assets/javascripts/vue_shared/components/loading_button.vue
#	app/assets/javascripts/vue_shared/components/markdown/field.vue
#	app/assets/javascripts/vue_shared/components/markdown/toolbar.vue
#	app/assets/javascripts/vue_shared/components/modal.vue
#	app/assets/javascripts/vue_shared/components/recaptcha_modal.vue
#	app/assets/javascripts/vue_shared/components/table_pagination.vue
#	app/views/layouts/header/_default.html.haml
#	db/schema.rb
#	doc/development/fe_guide/style_guide_js.md
#	doc/topics/git/index.md
#	doc/user/project/clusters/index.md
#	features/support/env.rb
#	qa/qa/page/menu/admin.rb
#	qa/qa/scenario/test/sanity/selectors.rb
#	yarn.lock

[ci skip]
parents 633591fb 4fbe2a00
...@@ -8,7 +8,8 @@ ...@@ -8,7 +8,8 @@
"plugins": [ "plugins": [
["istanbul", { ["istanbul", {
"exclude": [ "exclude": [
"spec/javascripts/**/*" "spec/javascripts/**/*",
"app/assets/javascripts/locale/**/app.js"
] ]
}], }],
["transform-define", { ["transform-define", {
......
...@@ -629,6 +629,7 @@ codequality: ...@@ -629,6 +629,7 @@ codequality:
paths: [codeclimate.json] paths: [codeclimate.json]
sast: sast:
<<: *except-docs
image: registry.gitlab.com/gitlab-org/gl-sast:latest image: registry.gitlab.com/gitlab-org/gl-sast:latest
before_script: [] before_script: []
script: script:
......
app/assets/images/multi-editor-on.png

5.34 KB | W: | H:

app/assets/images/multi-editor-on.png

3.88 KB | W: | H:

app/assets/images/multi-editor-on.png
app/assets/images/multi-editor-on.png
app/assets/images/multi-editor-on.png
app/assets/images/multi-editor-on.png
  • 2-up
  • Swipe
  • Onion skin
...@@ -35,9 +35,12 @@ export default { ...@@ -35,9 +35,12 @@ export default {
type: String, type: String,
default: '', default: '',
}, },
<<<<<<< HEAD
groupId: { groupId: {
type: Number, type: Number,
}, },
=======
>>>>>>> upstream/master
}, },
data() { data() {
return { return {
......
...@@ -67,8 +67,13 @@ ...@@ -67,8 +67,13 @@
// Avoid the potential for the real-time data to say APPLICATION_INSTALLABLE but // Avoid the potential for the real-time data to say APPLICATION_INSTALLABLE but
// we already made a request to install and are just waiting for the real-time // we already made a request to install and are just waiting for the real-time
// to sync up. // to sync up.
<<<<<<< HEAD
return (this.status !== APPLICATION_INSTALLABLE && return (this.status !== APPLICATION_INSTALLABLE &&
this.status !== APPLICATION_ERROR) || this.status !== APPLICATION_ERROR) ||
=======
return (this.status !== APPLICATION_INSTALLABLE
&& this.status !== APPLICATION_ERROR) ||
>>>>>>> upstream/master
this.requestStatus === REQUEST_LOADING || this.requestStatus === REQUEST_LOADING ||
this.requestStatus === REQUEST_SUCCESS; this.requestStatus === REQUEST_SUCCESS;
}, },
......
...@@ -7,6 +7,10 @@ ...@@ -7,6 +7,10 @@
mixins: [ mixins: [
pipelinesMixin, pipelinesMixin,
], ],
<<<<<<< HEAD
=======
>>>>>>> upstream/master
props: { props: {
endpoint: { endpoint: {
type: String, type: String,
......
...@@ -43,8 +43,12 @@ ...@@ -43,8 +43,12 @@
</h5> </h5>
<a <a
:href="mergeRequest.url" :href="mergeRequest.url"
<<<<<<< HEAD
class="issue-link" class="issue-link"
> >
=======
class="issue-link">
>>>>>>> upstream/master
!{{ mergeRequest.iid }} !{{ mergeRequest.iid }}
</a> </a>
&middot; &middot;
...@@ -52,8 +56,12 @@ ...@@ -52,8 +56,12 @@
{{ s__('OpenedNDaysAgo|Opened') }} {{ s__('OpenedNDaysAgo|Opened') }}
<a <a
:href="mergeRequest.url" :href="mergeRequest.url"
<<<<<<< HEAD
class="issue-date" class="issue-date"
> >
=======
class="issue-date">
>>>>>>> upstream/master
{{ mergeRequest.createdAt }} {{ mergeRequest.createdAt }}
</a> </a>
</span> </span>
...@@ -61,8 +69,12 @@ ...@@ -61,8 +69,12 @@
{{ s__('ByAuthor|by') }} {{ s__('ByAuthor|by') }}
<a <a
:href="mergeRequest.author.webUrl" :href="mergeRequest.author.webUrl"
<<<<<<< HEAD
class="issue-author-link" class="issue-author-link"
> >
=======
class="issue-author-link">
>>>>>>> upstream/master
{{ mergeRequest.author.name }} {{ mergeRequest.author.name }}
</a> </a>
</span> </span>
......
...@@ -47,18 +47,26 @@ ...@@ -47,18 +47,26 @@
<a <a
:href="issue.url" :href="issue.url"
class="issue-link" class="issue-link"
<<<<<<< HEAD
> >
#{{ issue.iid }} #{{ issue.iid }}
</a> </a>
=======
>#{{ issue.iid }}</a>
>>>>>>> upstream/master
&middot; &middot;
<span> <span>
{{ s__('OpenedNDaysAgo|Opened') }} {{ s__('OpenedNDaysAgo|Opened') }}
<a <a
:href="issue.url" :href="issue.url"
class="issue-date" class="issue-date"
<<<<<<< HEAD
> >
{{ issue.createdAt }} {{ issue.createdAt }}
</a> </a>
=======
>{{ issue.createdAt }}</a>
>>>>>>> upstream/master
</span> </span>
<span> <span>
{{ s__('ByAuthor|by') }} {{ s__('ByAuthor|by') }}
......
...@@ -57,9 +57,13 @@ ...@@ -57,9 +57,13 @@
<a <a
:href="commit.commitUrl" :href="commit.commitUrl"
class="commit-hash-link commit-sha" class="commit-hash-link commit-sha"
<<<<<<< HEAD
> >
{{ commit.shortSha }} {{ commit.shortSha }}
</a> </a>
=======
>{{ commit.shortSha }}</a>
>>>>>>> upstream/master
{{ s__('FirstPushedBy|pushed by') }} {{ s__('FirstPushedBy|pushed by') }}
<a <a
:href="commit.author.webUrl" :href="commit.author.webUrl"
......
...@@ -46,9 +46,13 @@ ...@@ -46,9 +46,13 @@
<a <a
:href="mergeRequest.url" :href="mergeRequest.url"
class="issue-link" class="issue-link"
<<<<<<< HEAD
> >
!{{ mergeRequest.iid }} !{{ mergeRequest.iid }}
</a> </a>
=======
>!{{ mergeRequest.iid }}</a>
>>>>>>> upstream/master
&middot; &middot;
<span> <span>
{{ s__('OpenedNDaysAgo|Opened') }} {{ s__('OpenedNDaysAgo|Opened') }}
......
...@@ -63,7 +63,12 @@ ...@@ -63,7 +63,12 @@
</a> </a>
<span <span
class="icon-branch" class="icon-branch"
<<<<<<< HEAD
v-html="iconBranch"> v-html="iconBranch">
=======
v-html="iconBranch"
>
>>>>>>> upstream/master
</span> </span>
<a <a
:href="build.commitUrl" :href="build.commitUrl"
......
...@@ -80,16 +80,24 @@ ...@@ -80,16 +80,24 @@
</span> </span>
<a <a
:href="build.commitUrl" :href="build.commitUrl"
<<<<<<< HEAD
class="commit-sha" class="commit-sha"
> >
=======
class="commit-sha">
>>>>>>> upstream/master
{{ build.shortSha }} {{ build.shortSha }}
</a> </a>
</h5> </h5>
<span> <span>
<a <a
:href="build.url" :href="build.url"
<<<<<<< HEAD
class="issue-date" class="issue-date"
> >
=======
class="issue-date">
>>>>>>> upstream/master
{{ build.date }} {{ build.date }}
</a> </a>
</span> </span>
......
...@@ -580,6 +580,7 @@ import initLDAPGroupsSelect from 'ee/ldap_groups_select'; // eslint-disable-line ...@@ -580,6 +580,7 @@ import initLDAPGroupsSelect from 'ee/ldap_groups_select'; // eslint-disable-line
import('./pages/search/show') import('./pages/search/show')
.then(callDefault) .then(callDefault)
.catch(fail); .catch(fail);
<<<<<<< HEAD
new UserCallout(); new UserCallout();
break; break;
case 'projects:mirrors:show': case 'projects:mirrors:show':
...@@ -591,6 +592,8 @@ import initLDAPGroupsSelect from 'ee/ldap_groups_select'; // eslint-disable-line ...@@ -591,6 +592,8 @@ import initLDAPGroupsSelect from 'ee/ldap_groups_select'; // eslint-disable-line
break; break;
case 'admin:audit_logs:index': case 'admin:audit_logs:index':
import(/* webpackChunkName: "ee_audit_logs" */ 'ee/pages/admin/audit_logs').then(m => m.default()).catch(fail); import(/* webpackChunkName: "ee_audit_logs" */ 'ee/pages/admin/audit_logs').then(m => m.default()).catch(fail);
=======
>>>>>>> upstream/master
break; break;
case 'projects:settings:repository:show': case 'projects:settings:repository:show':
new UsersSelect(); new UsersSelect();
...@@ -700,11 +703,15 @@ import initLDAPGroupsSelect from 'ee/ldap_groups_select'; // eslint-disable-line ...@@ -700,11 +703,15 @@ import initLDAPGroupsSelect from 'ee/ldap_groups_select'; // eslint-disable-line
.then(callDefault) .then(callDefault)
.catch(fail); .catch(fail);
break; break;
<<<<<<< HEAD
case 'edit': case 'edit':
import(/* webpackChunkName: "ee_admin_groups_edit" */ 'ee/pages/admin/groups/edit').then(m => m.default()).catch(fail); import(/* webpackChunkName: "ee_admin_groups_edit" */ 'ee/pages/admin/groups/edit').then(m => m.default()).catch(fail);
break; break;
} }
=======
}
>>>>>>> upstream/master
break; break;
case 'projects': case 'projects':
import('./pages/admin/projects') import('./pages/admin/projects')
...@@ -728,11 +735,14 @@ import initLDAPGroupsSelect from 'ee/ldap_groups_select'; // eslint-disable-line ...@@ -728,11 +735,14 @@ import initLDAPGroupsSelect from 'ee/ldap_groups_select'; // eslint-disable-line
import('./pages/admin/abuse_reports') import('./pages/admin/abuse_reports')
.then(callDefault) .then(callDefault)
.catch(fail); .catch(fail);
<<<<<<< HEAD
break; break;
case 'geo_nodes': case 'geo_nodes':
import(/* webpackChunkName: 'geo_node_form' */ './geo/geo_node_form') import(/* webpackChunkName: 'geo_node_form' */ './geo/geo_node_form')
.then(geoNodeForm => geoNodeForm.default($('.js-geo-node-form'))) .then(geoNodeForm => geoNodeForm.default($('.js-geo-node-form')))
.catch(() => {}); .catch(() => {});
=======
>>>>>>> upstream/master
break; break;
} }
break; break;
......
...@@ -12,7 +12,10 @@ ...@@ -12,7 +12,10 @@
components: { components: {
loadingIcon, loadingIcon,
}, },
<<<<<<< HEAD
=======
>>>>>>> upstream/master
props: { props: {
actions: { actions: {
type: Array, type: Array,
...@@ -69,7 +72,12 @@ ...@@ -69,7 +72,12 @@
<span v-html="playIconSvg"></span> <span v-html="playIconSvg"></span>
<i <i
class="fa fa-caret-down" class="fa fa-caret-down"
<<<<<<< HEAD
aria-hidden="true"> aria-hidden="true">
=======
aria-hidden="true"
>
>>>>>>> upstream/master
</i> </i>
<loading-icon v-if="isLoading" /> <loading-icon v-if="isLoading" />
</span> </span>
...@@ -78,8 +86,12 @@ ...@@ -78,8 +86,12 @@
<ul class="dropdown-menu dropdown-menu-align-right"> <ul class="dropdown-menu dropdown-menu-align-right">
<li <li
v-for="(action, i) in actions" v-for="(action, i) in actions"
<<<<<<< HEAD
:key="i" :key="i"
> >
=======
:key="i">
>>>>>>> upstream/master
<button <button
type="button" type="button"
class="js-manual-action-link no-btn btn" class="js-manual-action-link no-btn btn"
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
import { s__ } from '../../locale'; import { s__ } from '../../locale';
/** /**
<<<<<<< HEAD
* Renders the external url link in environments table. * Renders the external url link in environments table.
*/ */
export default { export default {
...@@ -16,6 +17,20 @@ ...@@ -16,6 +17,20 @@
required: true, required: true,
}, },
}, },
=======
* Renders the external url link in environments table.
*/
export default {
directives: {
tooltip,
},
props: {
externalUrl: {
type: String,
required: true,
},
},
>>>>>>> upstream/master
computed: { computed: {
title() { title() {
......
<script> <script>
/** /**
<<<<<<< HEAD
* Renders the Monitoring (Metrics) link in environments table. * Renders the Monitoring (Metrics) link in environments table.
*/ */
=======
* Renders the Monitoring (Metrics) link in environments table.
*/
>>>>>>> upstream/master
import tooltip from '../../vue_shared/directives/tooltip'; import tooltip from '../../vue_shared/directives/tooltip';
export default { export default {
directives: { directives: {
tooltip, tooltip,
<<<<<<< HEAD
}, },
props: { props: {
monitoringUrl: { monitoringUrl: {
...@@ -14,6 +20,16 @@ ...@@ -14,6 +20,16 @@
required: true, required: true,
}, },
}, },
=======
},
props: {
monitoringUrl: {
type: String,
required: true,
},
},
>>>>>>> upstream/master
computed: { computed: {
title() { title() {
......
<script> <script>
/** /**
<<<<<<< HEAD
* Renders Rollback or Re deploy button in environments table depending * Renders Rollback or Re deploy button in environments table depending
* of the provided property `isLastDeployment`. * of the provided property `isLastDeployment`.
* *
* Makes a post request when the button is clicked. * Makes a post request when the button is clicked.
*/ */
=======
* Renders Rollback or Re deploy button in environments table depending
* of the provided property `isLastDeployment`.
*
* Makes a post request when the button is clicked.
*/
>>>>>>> upstream/master
import eventHub from '../event_hub'; import eventHub from '../event_hub';
import loadingIcon from '../../vue_shared/components/loading_icon.vue'; import loadingIcon from '../../vue_shared/components/loading_icon.vue';
...@@ -12,11 +20,24 @@ ...@@ -12,11 +20,24 @@
components: { components: {
loadingIcon, loadingIcon,
}, },
<<<<<<< HEAD
=======
>>>>>>> upstream/master
props: { props: {
retryUrl: { retryUrl: {
type: String, type: String,
default: '', default: '',
}, },
<<<<<<< HEAD
isLastDeployment: {
type: Boolean,
default: true,
},
},
=======
isLastDeployment: { isLastDeployment: {
type: Boolean, type: Boolean,
...@@ -24,6 +45,7 @@ ...@@ -24,6 +45,7 @@
}, },
}, },
>>>>>>> upstream/master
data() { data() {
return { return {
isLoading: false, isLoading: false,
......
<script> <script>
/** /**
<<<<<<< HEAD
* Renders the stop "button" that allows stop an environment. * Renders the stop "button" that allows stop an environment.
* Used in environments table. * Used in environments table.
*/ */
=======
* Renders the stop "button" that allows stop an environment.
* Used in environments table.
*/
>>>>>>> upstream/master
import eventHub from '../event_hub'; import eventHub from '../event_hub';
import loadingIcon from '../../vue_shared/components/loading_icon.vue'; import loadingIcon from '../../vue_shared/components/loading_icon.vue';
import tooltip from '../../vue_shared/directives/tooltip'; import tooltip from '../../vue_shared/directives/tooltip';
...@@ -10,10 +16,18 @@ ...@@ -10,10 +16,18 @@
export default { export default {
components: { components: {
loadingIcon, loadingIcon,
<<<<<<< HEAD
}, },
directives: { directives: {
tooltip, tooltip,
}, },
=======
},
directives: {
tooltip,
},
>>>>>>> upstream/master
props: { props: {
stopUrl: { stopUrl: {
......
<script> <script>
/** /**
<<<<<<< HEAD
* Renders a terminal button to open a web terminal. * Renders a terminal button to open a web terminal.
* Used in environments table. * Used in environments table.
*/ */
=======
* Renders a terminal button to open a web terminal.
* Used in environments table.
*/
>>>>>>> upstream/master
import terminalIconSvg from 'icons/_icon_terminal.svg'; import terminalIconSvg from 'icons/_icon_terminal.svg';
import tooltip from '../../vue_shared/directives/tooltip'; import tooltip from '../../vue_shared/directives/tooltip';
export default { export default {
directives: { directives: {
tooltip, tooltip,
<<<<<<< HEAD
}, },
props: { props: {
terminalPath: { terminalPath: {
...@@ -22,6 +29,23 @@ ...@@ -22,6 +29,23 @@
terminalIconSvg, terminalIconSvg,
}; };
}, },
=======
},
props: {
terminalPath: {
type: String,
required: false,
default: '',
},
},
data() {
return {
terminalIconSvg,
};
},
>>>>>>> upstream/master
computed: { computed: {
title() { title() {
......
...@@ -32,7 +32,6 @@ export default { ...@@ -32,7 +32,6 @@ export default {
default: false, default: false,
}, },
}, },
methods: { methods: {
folderUrl(model) { folderUrl(model) {
return `${window.location.pathname}/folders/${model.folderName}`; return `${window.location.pathname}/folders/${model.folderName}`;
...@@ -88,8 +87,12 @@ export default { ...@@ -88,8 +87,12 @@ export default {
</div> </div>
<template <template
v-for="(model, i) in environments" v-for="(model, i) in environments"
<<<<<<< HEAD
:model="model" :model="model"
> >
=======
:model="model">
>>>>>>> upstream/master
<div <div
is="environment-item" is="environment-item"
:model="model" :model="model"
...@@ -97,6 +100,7 @@ export default { ...@@ -97,6 +100,7 @@ export default {
:can-read-environment="canReadEnvironment" :can-read-environment="canReadEnvironment"
:key="i" :key="i"
/> />
<<<<<<< HEAD
<div <div
v-if="model.hasDeployBoard && model.isDeployBoardVisible" v-if="model.hasDeployBoard && model.isDeployBoardVisible"
...@@ -111,14 +115,20 @@ export default { ...@@ -111,14 +115,20 @@ export default {
/> />
</div> </div>
</div> </div>
=======
>>>>>>> upstream/master
<template <template
v-if="shouldRenderFolderContent(model)" v-if="shouldRenderFolderContent(model)"
> >
<div <div
v-if="model.isLoadingFolderContent" v-if="model.isLoadingFolderContent"
<<<<<<< HEAD
:key="i" :key="i"
> >
=======
:key="i">
>>>>>>> upstream/master
<loading-icon size="2" /> <loading-icon size="2" />
</div> </div>
......
...@@ -29,7 +29,10 @@ ...@@ -29,7 +29,10 @@
required: true, required: true,
}, },
}, },
<<<<<<< HEAD
=======
>>>>>>> upstream/master
methods: { methods: {
successCallback(resp) { successCallback(resp) {
this.saveData(resp); this.saveData(resp);
......
<script> <script>
/* global Flash */ /* global Flash */
import { s__ } from '~/locale';
import loadingIcon from '~/vue_shared/components/loading_icon.vue';
import modal from '~/vue_shared/components/modal.vue';
import { getParameterByName } from '~/lib/utils/common_utils';
import { mergeUrlParams } from '~/lib/utils/url_utility';
import eventHub from '../event_hub'; import eventHub from '../event_hub';
import { getParameterByName } from '../../lib/utils/common_utils';
import loadingIcon from '../../vue_shared/components/loading_icon.vue';
import { COMMON_STR } from '../constants'; import { COMMON_STR } from '../constants';
import { mergeUrlParams } from '../../lib/utils/url_utility';
import groupsComponent from './groups.vue'; import groupsComponent from './groups.vue';
export default { export default {
components: { components: {
loadingIcon, loadingIcon,
modal,
groupsComponent, groupsComponent,
}, },
props: { props: {
...@@ -32,6 +36,10 @@ export default { ...@@ -32,6 +36,10 @@ export default {
isLoading: true, isLoading: true,
isSearchEmpty: false, isSearchEmpty: false,
searchEmptyMessage: '', searchEmptyMessage: '',
showModal: false,
groupLeaveConfirmationMessage: '',
targetGroup: null,
targetParentGroup: null,
}; };
}, },
computed: { computed: {
...@@ -48,7 +56,11 @@ export default { ...@@ -48,7 +56,11 @@ export default {
eventHub.$on('fetchPage', this.fetchPage); eventHub.$on('fetchPage', this.fetchPage);
eventHub.$on('toggleChildren', this.toggleChildren); eventHub.$on('toggleChildren', this.toggleChildren);
<<<<<<< HEAD
eventHub.$on('leaveGroup', this.leaveGroup); eventHub.$on('leaveGroup', this.leaveGroup);
=======
eventHub.$on('showLeaveGroupModal', this.showLeaveGroupModal);
>>>>>>> upstream/master
eventHub.$on('updatePagination', this.updatePagination); eventHub.$on('updatePagination', this.updatePagination);
eventHub.$on('updateGroups', this.updateGroups); eventHub.$on('updateGroups', this.updateGroups);
}, },
...@@ -58,7 +70,11 @@ export default { ...@@ -58,7 +70,11 @@ export default {
beforeDestroy() { beforeDestroy() {
eventHub.$off('fetchPage', this.fetchPage); eventHub.$off('fetchPage', this.fetchPage);
eventHub.$off('toggleChildren', this.toggleChildren); eventHub.$off('toggleChildren', this.toggleChildren);
<<<<<<< HEAD
eventHub.$off('leaveGroup', this.leaveGroup); eventHub.$off('leaveGroup', this.leaveGroup);
=======
eventHub.$off('showLeaveGroupModal', this.showLeaveGroupModal);
>>>>>>> upstream/master
eventHub.$off('updatePagination', this.updatePagination); eventHub.$off('updatePagination', this.updatePagination);
eventHub.$off('updateGroups', this.updateGroups); eventHub.$off('updateGroups', this.updateGroups);
}, },
...@@ -141,14 +157,23 @@ export default { ...@@ -141,14 +157,23 @@ export default {
parentGroup.isOpen = false; parentGroup.isOpen = false;
} }
}, },
leaveGroup(group, parentGroup) { showLeaveGroupModal(group, parentGroup) {
const targetGroup = group; this.targetGroup = group;
targetGroup.isBeingRemoved = true; this.targetParentGroup = parentGroup;
this.service.leaveGroup(targetGroup.leavePath) this.showModal = true;
this.groupLeaveConfirmationMessage = s__(`GroupsTree|Are you sure you want to leave the "${group.fullName}" group?`);
},
hideLeaveGroupModal() {
this.showModal = false;
},
leaveGroup() {
this.showModal = false;
this.targetGroup.isBeingRemoved = true;
this.service.leaveGroup(this.targetGroup.leavePath)
.then(res => res.json()) .then(res => res.json())
.then((res) => { .then((res) => {
$.scrollTo(0); $.scrollTo(0);
this.store.removeGroup(targetGroup, parentGroup); this.store.removeGroup(this.targetGroup, this.targetParentGroup);
Flash(res.notice, 'notice'); Flash(res.notice, 'notice');
}) })
.catch((err) => { .catch((err) => {
...@@ -157,7 +182,7 @@ export default { ...@@ -157,7 +182,7 @@ export default {
message = COMMON_STR.LEAVE_FORBIDDEN; message = COMMON_STR.LEAVE_FORBIDDEN;
} }
Flash(message); Flash(message);
targetGroup.isBeingRemoved = false; this.targetGroup.isBeingRemoved = false;
}); });
}, },
updatePagination(headers) { updatePagination(headers) {
...@@ -190,5 +215,14 @@ export default { ...@@ -190,5 +215,14 @@ export default {
:search-empty-message="searchEmptyMessage" :search-empty-message="searchEmptyMessage"
:page-info="pageInfo" :page-info="pageInfo"
/> />
<modal
v-show="showModal"
:primary-button-label="__('Leave')"
kind="warning"
:title="__('Are you sure?')"
:text="groupLeaveConfirmationMessage"
@cancel="hideLeaveGroupModal"
@submit="leaveGroup"
/>
</div> </div>
</template> </template>
<script> <script>
<<<<<<< HEAD
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import tooltip from '~/vue_shared/directives/tooltip'; import tooltip from '~/vue_shared/directives/tooltip';
import icon from '~/vue_shared/components/icon.vue'; import icon from '~/vue_shared/components/icon.vue';
...@@ -10,10 +11,30 @@ ...@@ -10,10 +11,30 @@
components: { components: {
icon, icon,
modal, modal,
=======
import tooltip from '~/vue_shared/directives/tooltip';
import icon from '~/vue_shared/components/icon.vue';
import eventHub from '../event_hub';
import { COMMON_STR } from '../constants';
export default {
components: {
icon,
},
directives: {
tooltip,
},
props: {
parentGroup: {
type: Object,
required: false,
default: () => ({}),
>>>>>>> upstream/master
}, },
directives: { directives: {
tooltip, tooltip,
}, },
<<<<<<< HEAD
props: { props: {
parentGroup: { parentGroup: {
type: Object, type: Object,
...@@ -24,12 +45,19 @@ ...@@ -24,12 +45,19 @@
type: Object, type: Object,
required: true, required: true,
}, },
=======
},
computed: {
leaveBtnTitle() {
return COMMON_STR.LEAVE_BTN_TITLE;
>>>>>>> upstream/master
}, },
data() { data() {
return { return {
modalStatus: false, modalStatus: false,
}; };
}, },
<<<<<<< HEAD
computed: { computed: {
leaveBtnTitle() { leaveBtnTitle() {
return COMMON_STR.LEAVE_BTN_TITLE; return COMMON_STR.LEAVE_BTN_TITLE;
...@@ -51,6 +79,15 @@ ...@@ -51,6 +79,15 @@
}, },
}, },
}; };
=======
},
methods: {
onLeaveGroup() {
eventHub.$emit('showLeaveGroupModal', this.group, this.parentGroup);
},
},
};
>>>>>>> upstream/master
</script> </script>
<template> <template>
...@@ -78,14 +115,5 @@ ...@@ -78,14 +115,5 @@
class="leave-group btn no-expand"> class="leave-group btn no-expand">
<icon name="leave"/> <icon name="leave"/>
</a> </a>
<modal
v-show="modalStatus"
:primary-button-label="__('Leave')"
kind="warning"
:title="__('Are you sure?')"
:text="__('Are you sure you want to leave this group?')"
:body="leaveConfirmationMessage"
@submit="leaveGroup"
/>
</div> </div>
</template> </template>
...@@ -30,11 +30,19 @@ ...@@ -30,11 +30,19 @@
default: 'bottom', default: 'bottom',
}, },
/** /**
<<<<<<< HEAD
* value could either be number or string * value could either be number or string
* as `memberCount` is always passed as string * as `memberCount` is always passed as string
* while `subgroupCount` & `projectCount` * while `subgroupCount` & `projectCount`
* are always number * are always number
*/ */
=======
* value could either be number or string
* as `memberCount` is always passed as string
* while `subgroupCount` & `projectCount`
* are always number
*/
>>>>>>> upstream/master
value: { value: {
type: [Number, String], type: [Number, String],
required: false, required: false,
......
...@@ -41,7 +41,11 @@ export default { ...@@ -41,7 +41,11 @@ export default {
</div> </div>
</div> </div>
<div> <div>
<<<<<<< HEAD
<repo-tree :tree-id="branch.treeId"/> <repo-tree :tree-id="branch.treeId"/>
=======
<repo-tree :tree-id="branch.treeId" />
>>>>>>> upstream/master
</div> </div>
</div> </div>
</template> </template>
...@@ -73,7 +73,12 @@ ...@@ -73,7 +73,12 @@
<div <div
class="multi-file-loading-container" class="multi-file-loading-container"
v-for="n in 3" v-for="n in 3"
<<<<<<< HEAD
:key="n"> :key="n">
=======
:key="n"
>
>>>>>>> upstream/master
<skeleton-loading-container /> <skeleton-loading-container />
</div> </div>
</template> </template>
......
...@@ -17,7 +17,11 @@ export default { ...@@ -17,7 +17,11 @@ export default {
'panelResizing', 'panelResizing',
]), ]),
shouldHideEditor() { shouldHideEditor() {
<<<<<<< HEAD
return this.activeFile && this.activeFile.binary && !this.activeFile.raw; return this.activeFile && this.activeFile.binary && !this.activeFile.raw;
=======
return this.activeFile.binary && !this.activeFile.raw;
>>>>>>> upstream/master
}, },
}, },
watch: { watch: {
......
...@@ -61,11 +61,18 @@ ...@@ -61,11 +61,18 @@
v-else v-else
class="vertical-center render-error"> class="vertical-center render-error">
<p class="text-center"> <p class="text-center">
<<<<<<< HEAD
The source could not be displayed because a rendering error occurred. You can The source could not be displayed because a rendering error occurred. You can
<a <a
:href="activeFile.rawPath" :href="activeFile.rawPath"
download download
>download</a> it instead. >download</a> it instead.
=======
The source could not be displayed because a rendering error occurred.
You can <a
:href="activeFile.rawPath"
download>download</a> it instead.
>>>>>>> upstream/master
</p> </p>
</div> </div>
</div> </div>
......
<script> <script>
import { mapActions } from 'vuex'; import { mapActions } from 'vuex';
<<<<<<< HEAD
import fileStatusIcon from './repo_file_status_icon.vue'; import fileStatusIcon from './repo_file_status_icon.vue';
=======
>>>>>>> upstream/master
import fileIcon from '../../vue_shared/components/file_icon.vue'; import fileIcon from '../../vue_shared/components/file_icon.vue';
export default { export default {
components: { components: {
<<<<<<< HEAD
fileStatusIcon, fileStatusIcon,
=======
>>>>>>> upstream/master
fileIcon, fileIcon,
}, },
props: { props: {
......
...@@ -267,6 +267,10 @@ ...@@ -267,6 +267,10 @@
:project-path="projectPath" :project-path="projectPath"
:project-namespace="projectNamespace" :project-namespace="projectNamespace"
:show-delete-button="showDeleteButton" :show-delete-button="showDeleteButton"
<<<<<<< HEAD
=======
:can-attach-file="canAttachFile"
>>>>>>> upstream/master
:enable-autocomplete="enableAutocomplete" :enable-autocomplete="enableAutocomplete"
/> />
......
...@@ -55,6 +55,7 @@ ...@@ -55,6 +55,7 @@
eventHub.$off('toggleAspectRatio', this.toggleAspectRatio); eventHub.$off('toggleAspectRatio', this.toggleAspectRatio);
eventHub.$off('hoverChanged', this.hoverChanged); eventHub.$off('hoverChanged', this.hoverChanged);
window.removeEventListener('resize', this.resizeThrottled, false); window.removeEventListener('resize', this.resizeThrottled, false);
<<<<<<< HEAD
}, },
mounted() { mounted() {
...@@ -65,8 +66,19 @@ ...@@ -65,8 +66,19 @@
this.getGraphsData(); this.getGraphsData();
window.addEventListener('resize', this.resizeThrottled, false); window.addEventListener('resize', this.resizeThrottled, false);
} }
=======
>>>>>>> upstream/master
}, },
mounted() {
this.resizeThrottled = _.throttle(this.resize, 600);
if (!this.hasMetrics) {
this.state = 'gettingStarted';
} else {
this.getGraphsData();
window.addEventListener('resize', this.resizeThrottled, false);
}
},
methods: { methods: {
getGraphsData() { getGraphsData() {
this.state = 'loading'; this.state = 'loading';
......
...@@ -259,7 +259,12 @@ ...@@ -259,7 +259,12 @@
<svg <svg
class="graph-data" class="graph-data"
:viewBox="innerViewBox" :viewBox="innerViewBox"
<<<<<<< HEAD
ref="graphData"> ref="graphData">
=======
ref="graphData"
>
>>>>>>> upstream/master
<graph-path <graph-path
v-for="(path, index) in timeSeries" v-for="(path, index) in timeSeries"
:key="index" :key="index"
......
<script> <script>
import { dateFormat, timeFormat } from '../../utils/date_time_formatters'; import { dateFormat, timeFormat } from '../../utils/date_time_formatters';
import { formatRelevantDigits } from '../../../lib/utils/number_utils'; import { formatRelevantDigits } from '../../../lib/utils/number_utils';
import Icon from '../../../vue_shared/components/icon.vue'; import icon from '../../../vue_shared/components/icon.vue';
export default { export default {
components: { components: {
<<<<<<< HEAD
Icon, Icon,
=======
icon,
>>>>>>> upstream/master
}, },
props: { props: {
currentXCoordinate: { currentXCoordinate: {
......
...@@ -93,8 +93,12 @@ ...@@ -93,8 +93,12 @@
<prompt /> <prompt />
<div <div
class="markdown" class="markdown"
<<<<<<< HEAD
v-html="markdown" v-html="markdown"
> >
=======
v-html="markdown">
>>>>>>> upstream/master
</div> </div>
</div> </div>
</template> </template>
......
...@@ -307,8 +307,12 @@ js-gfm-input js-autosize markdown-area js-vue-textarea" ...@@ -307,8 +307,12 @@ js-gfm-input js-autosize markdown-area js-vue-textarea"
<div class="note-form-actions"> <div class="note-form-actions">
<div <div
class="pull-left btn-group class="pull-left btn-group
<<<<<<< HEAD
append-right-10 comment-type-dropdown js-comment-type-dropdown droplab-dropdown" append-right-10 comment-type-dropdown js-comment-type-dropdown droplab-dropdown"
> >
=======
append-right-10 comment-type-dropdown js-comment-type-dropdown droplab-dropdown">
>>>>>>> upstream/master
<button <button
@click.prevent="handleSave()" @click.prevent="handleSave()"
:disabled="isSubmitButtonDisabled" :disabled="isSubmitButtonDisabled"
......
...@@ -30,8 +30,12 @@ ...@@ -30,8 +30,12 @@
rel="noopener noreferrer"> rel="noopener noreferrer">
<i <i
class="fa fa-paperclip" class="fa fa-paperclip"
<<<<<<< HEAD
aria-hidden="true" aria-hidden="true"
> >
=======
aria-hidden="true">
>>>>>>> upstream/master
</i> </i>
{{ attachment.filename }} {{ attachment.filename }}
</a> </a>
......
...@@ -116,8 +116,12 @@ ...@@ -116,8 +116,12 @@
<template> <template>
<div <div
ref="editNoteForm" ref="editNoteForm"
<<<<<<< HEAD
class="note-edit-form current-note-edit-form" class="note-edit-form current-note-edit-form"
> >
=======
class="note-edit-form current-note-edit-form">
>>>>>>> upstream/master
<div <div
v-if="conflictWhileEditing" v-if="conflictWhileEditing"
class="js-conflict-edit-warning alert alert-danger"> class="js-conflict-edit-warning alert alert-danger">
......
...@@ -51,6 +51,10 @@ ...@@ -51,6 +51,10 @@
return `note_${this.note.id}`; return `note_${this.note.id}`;
}, },
}, },
<<<<<<< HEAD
=======
>>>>>>> upstream/master
created() { created() {
eventHub.$on('enterEditMode', ({ noteId }) => { eventHub.$on('enterEditMode', ({ noteId }) => {
if (noteId === this.note.id) { if (noteId === this.note.id) {
...@@ -59,6 +63,10 @@ ...@@ -59,6 +63,10 @@
} }
}); });
}, },
<<<<<<< HEAD
=======
>>>>>>> upstream/master
methods: { methods: {
...mapActions([ ...mapActions([
'deleteNote', 'deleteNote',
......
<script> <script>
<<<<<<< HEAD
/* eslint-disable no-alert, vue/require-default-prop */ /* eslint-disable no-alert, vue/require-default-prop */
=======
/* eslint-disable no-alert */
>>>>>>> upstream/master
import eventHub from '../event_hub'; import eventHub from '../event_hub';
import loadingIcon from '../../vue_shared/components/loading_icon.vue'; import loadingIcon from '../../vue_shared/components/loading_icon.vue';
...@@ -9,6 +13,7 @@ ...@@ -9,6 +13,7 @@
directives: { directives: {
tooltip, tooltip,
}, },
<<<<<<< HEAD
components: { components: {
loadingIcon, loadingIcon,
...@@ -54,6 +59,52 @@ ...@@ -54,6 +59,52 @@
if (this.confirmActionMessage && confirm(this.confirmActionMessage)) { if (this.confirmActionMessage && confirm(this.confirmActionMessage)) {
this.makeRequest(); this.makeRequest();
} else if (!this.confirmActionMessage) { } else if (!this.confirmActionMessage) {
=======
components: {
loadingIcon,
},
props: {
endpoint: {
type: String,
required: true,
},
title: {
type: String,
required: true,
},
icon: {
type: String,
required: true,
},
cssClass: {
type: String,
required: true,
},
confirmActionMessage: {
type: String,
required: false,
default: '',
},
},
data() {
return {
isLoading: false,
};
},
computed: {
iconClass() {
return `fa fa-${this.icon}`;
},
buttonClass() {
return `btn ${this.cssClass}`;
},
},
methods: {
onClick() {
if (this.confirmActionMessage !== '' && confirm(this.confirmActionMessage)) {
this.makeRequest();
} else if (this.confirmActionMessage === '') {
>>>>>>> upstream/master
this.makeRequest(); this.makeRequest();
} }
}, },
......
...@@ -14,6 +14,10 @@ ...@@ -14,6 +14,10 @@
directives: { directives: {
tooltip, tooltip,
}, },
<<<<<<< HEAD
=======
>>>>>>> upstream/master
props: { props: {
tooltipText: { tooltipText: {
type: String, type: String,
......
...@@ -63,7 +63,8 @@ ...@@ -63,7 +63,8 @@
* target the click event of this component. * target the click event of this component.
*/ */
stopDropdownClickPropagation() { stopDropdownClickPropagation() {
$(this.$el.querySelectorAll('.js-grouped-pipeline-dropdown a.mini-pipeline-graph-dropdown-item')) $(this.$el
.querySelectorAll('.js-grouped-pipeline-dropdown a.mini-pipeline-graph-dropdown-item'))
.on('click', (e) => { .on('click', (e) => {
e.stopPropagation(); e.stopPropagation();
}); });
......
<script> <script>
import loadingIcon from '~/vue_shared/components/loading_icon.vue'; import loadingIcon from '~/vue_shared/components/loading_icon.vue';
<<<<<<< HEAD
import linkedPipelinesColumn from './linked_pipelines_column.vue'; import linkedPipelinesColumn from './linked_pipelines_column.vue';
=======
>>>>>>> upstream/master
import stageColumnComponent from './stage_column_component.vue'; import stageColumnComponent from './stage_column_component.vue';
export default { export default {
components: { components: {
<<<<<<< HEAD
linkedPipelinesColumn, linkedPipelinesColumn,
stageColumnComponent, stageColumnComponent,
loadingIcon, loadingIcon,
}, },
=======
stageColumnComponent,
loadingIcon,
},
>>>>>>> upstream/master
props: { props: {
isLoading: { isLoading: {
type: Boolean, type: Boolean,
...@@ -100,7 +110,10 @@ ...@@ -100,7 +110,10 @@
:key="stage.name" :key="stage.name"
:stage-connector-class="stageConnectorClass(index, stage)" :stage-connector-class="stageConnectorClass(index, stage)"
:is-first-column="isFirstColumn(index)" :is-first-column="isFirstColumn(index)"
<<<<<<< HEAD
:has-triggered-by="hasTriggeredBy" :has-triggered-by="hasTriggeredBy"
=======
>>>>>>> upstream/master
/> />
</ul> </ul>
......
...@@ -13,11 +13,25 @@ ...@@ -13,11 +13,25 @@
required: true, required: true,
}, },
<<<<<<< HEAD
jobs: { jobs: {
type: Array, type: Array,
required: true, required: true,
}, },
=======
props: {
title: {
type: String,
required: true,
},
jobs: {
type: Array,
required: true,
},
>>>>>>> upstream/master
isFirstColumn: { isFirstColumn: {
type: Boolean, type: Boolean,
required: false, required: false,
...@@ -29,20 +43,33 @@ ...@@ -29,20 +43,33 @@
required: false, required: false,
default: '', default: '',
}, },
<<<<<<< HEAD
hasTriggeredBy: { hasTriggeredBy: {
type: Boolean, type: Boolean,
required: true, required: true,
}, },
=======
>>>>>>> upstream/master
}, },
methods: { methods: {
firstJob(list) { firstJob(list) {
return list[0]; return list[0];
}, },
<<<<<<< HEAD
jobId(job) {
return `ci-badge-${job.name}`;
=======
jobId(job) { jobId(job) {
return `ci-badge-${job.name}`; return `ci-badge-${job.name}`;
}, },
buildConnnectorClass(index) {
return index === 0 && !this.isFirstColumn ? 'left-connector' : '';
>>>>>>> upstream/master
},
}, },
}; };
</script> </script>
...@@ -59,10 +86,16 @@ ...@@ -59,10 +86,16 @@
v-for="(job, index) in jobs" v-for="(job, index) in jobs"
:key="job.id" :key="job.id"
class="build" class="build"
<<<<<<< HEAD
:class="{ :class="{
'left-connector': index === 0 && (!isFirstColumn || hasTriggeredBy) 'left-connector': index === 0 && (!isFirstColumn || hasTriggeredBy)
}" }"
:id="jobId(job)"> :id="jobId(job)">
=======
:class="buildConnnectorClass(index)"
:id="jobId(job)"
>
>>>>>>> upstream/master
<div class="curve"></div> <div class="curve"></div>
......
...@@ -19,11 +19,15 @@ ...@@ -19,11 +19,15 @@
required: true, required: true,
}, },
}, },
<<<<<<< HEAD
=======
>>>>>>> upstream/master
data() { data() {
return { return {
actions: this.getActions(), actions: this.getActions(),
}; };
<<<<<<< HEAD
}, },
computed: { computed: {
...@@ -63,6 +67,47 @@ ...@@ -63,6 +67,47 @@
}); });
} }
=======
},
computed: {
status() {
return this.pipeline.details && this.pipeline.details.status;
},
shouldRenderContent() {
return !this.isLoading && Object.keys(this.pipeline).length;
},
},
watch: {
pipeline() {
this.actions = this.getActions();
},
},
methods: {
postAction(action) {
const index = this.actions.indexOf(action);
this.$set(this.actions[index], 'isLoading', true);
eventHub.$emit('headerPostAction', action);
},
getActions() {
const actions = [];
if (this.pipeline.retry_path) {
actions.push({
label: 'Retry',
path: this.pipeline.retry_path,
cssClass: 'js-retry-button btn btn-inverted-secondary',
type: 'button',
isLoading: false,
});
}
>>>>>>> upstream/master
if (this.pipeline.cancel_path) { if (this.pipeline.cancel_path) {
actions.push({ actions.push({
label: 'Cancel running', label: 'Cancel running',
......
...@@ -250,7 +250,8 @@ ...@@ -250,7 +250,8 @@
<div <div
class="blank-state-row" class="blank-state-row"
v-if="shouldRenderNoPipelinesMessage"> v-if="shouldRenderNoPipelinesMessage"
>
<div class="blank-state-center"> <div class="blank-state-center">
<h2 class="blank-state-title js-blank-state-title">No pipelines to show.</h2> <h2 class="blank-state-title js-blank-state-title">No pipelines to show.</h2>
</div> </div>
......
...@@ -223,8 +223,12 @@ ...@@ -223,8 +223,12 @@
<div class="table-section section-10 commit-link"> <div class="table-section section-10 commit-link">
<div <div
class="table-mobile-header" class="table-mobile-header"
<<<<<<< HEAD
role="rowheader" role="rowheader"
> >
=======
role="rowheader">
>>>>>>> upstream/master
Status Status
</div> </div>
<div class="table-mobile-content"> <div class="table-mobile-content">
......
...@@ -50,7 +50,13 @@ ...@@ -50,7 +50,13 @@
computed: { computed: {
dropdownClass() { dropdownClass() {
<<<<<<< HEAD
return this.dropdownContent.length > 0 ? 'js-builds-dropdown-container' : 'js-builds-dropdown-loading'; return this.dropdownContent.length > 0 ? 'js-builds-dropdown-container' : 'js-builds-dropdown-loading';
=======
return this.dropdownContent.length > 0 ?
'js-builds-dropdown-container' :
'js-builds-dropdown-loading';
>>>>>>> upstream/master
}, },
triggerButtonClass() { triggerButtonClass() {
...@@ -162,7 +168,8 @@ ...@@ -162,7 +168,8 @@
<ul <ul
class="dropdown-menu mini-pipeline-graph-dropdown-menu js-builds-dropdown-container" class="dropdown-menu mini-pipeline-graph-dropdown-menu js-builds-dropdown-container"
aria-labelledby="stageDropdown"> aria-labelledby="stageDropdown"
>
<li <li
:class="dropdownClass" :class="dropdownClass"
......
<script> <script>
<<<<<<< HEAD
/* eslint-disable vue/require-default-prop */ /* eslint-disable vue/require-default-prop */
=======
>>>>>>> upstream/master
import projectFeatureSetting from './project_feature_setting.vue'; import projectFeatureSetting from './project_feature_setting.vue';
import projectFeatureToggle from '../../../vue_shared/components/toggle_button.vue'; import projectFeatureToggle from '../../../vue_shared/components/toggle_button.vue';
import projectSettingRow from './project_setting_row.vue'; import projectSettingRow from './project_setting_row.vue';
...@@ -12,6 +15,7 @@ ...@@ -12,6 +15,7 @@
projectFeatureToggle, projectFeatureToggle,
projectSettingRow, projectSettingRow,
}, },
<<<<<<< HEAD
props: { props: {
currentSettings: { currentSettings: {
type: Object, type: Object,
...@@ -51,6 +55,51 @@ ...@@ -51,6 +55,51 @@
}, },
}, },
=======
props: {
currentSettings: {
type: Object,
required: true,
},
canChangeVisibilityLevel: {
type: Boolean,
required: false,
default: false,
},
allowedVisibilityOptions: {
type: Array,
required: false,
default: () => [0, 10, 20],
},
lfsAvailable: {
type: Boolean,
required: false,
default: false,
},
registryAvailable: {
type: Boolean,
required: false,
default: false,
},
visibilityHelpPath: {
type: String,
required: false,
default: '',
},
lfsHelpPath: {
type: String,
required: false,
default: '',
},
registryHelpPath: {
type: String,
required: false,
default: '',
},
},
>>>>>>> upstream/master
data() { data() {
const defaults = { const defaults = {
visibilityOptions, visibilityOptions,
...@@ -118,6 +167,32 @@ ...@@ -118,6 +167,32 @@
} }
}, },
<<<<<<< HEAD
=======
watch: {
visibilityLevel(value, oldValue) {
if (value === visibilityOptions.PRIVATE) {
// when private, features are restricted to "only team members"
this.issuesAccessLevel = Math.min(10, this.issuesAccessLevel);
this.repositoryAccessLevel = Math.min(10, this.repositoryAccessLevel);
this.mergeRequestsAccessLevel = Math.min(10, this.mergeRequestsAccessLevel);
this.buildsAccessLevel = Math.min(10, this.buildsAccessLevel);
this.wikiAccessLevel = Math.min(10, this.wikiAccessLevel);
this.snippetsAccessLevel = Math.min(10, this.snippetsAccessLevel);
this.highlightChanges();
} else if (oldValue === visibilityOptions.PRIVATE) {
// if changing away from private, make enabled features more permissive
if (this.issuesAccessLevel > 0) this.issuesAccessLevel = 20;
if (this.repositoryAccessLevel > 0) this.repositoryAccessLevel = 20;
if (this.mergeRequestsAccessLevel > 0) this.mergeRequestsAccessLevel = 20;
if (this.buildsAccessLevel > 0) this.buildsAccessLevel = 20;
if (this.wikiAccessLevel > 0) this.wikiAccessLevel = 20;
if (this.snippetsAccessLevel > 0) this.snippetsAccessLevel = 20;
this.highlightChanges();
}
},
>>>>>>> upstream/master
repositoryAccessLevel(value, oldValue) { repositoryAccessLevel(value, oldValue) {
if (value < oldValue) { if (value < oldValue) {
// sub-features cannot have more premissive access level // sub-features cannot have more premissive access level
...@@ -140,6 +215,7 @@ ...@@ -140,6 +215,7 @@
if (value === 0) toggleHiddenClassBySelector('.issues-feature', true); if (value === 0) toggleHiddenClassBySelector('.issues-feature', true);
else if (oldValue === 0) toggleHiddenClassBySelector('.issues-feature', false); else if (oldValue === 0) toggleHiddenClassBySelector('.issues-feature', false);
}, },
<<<<<<< HEAD
mergeRequestsAccessLevel(value, oldValue) { mergeRequestsAccessLevel(value, oldValue) {
if (value === 0) toggleHiddenClassBySelector('.merge-requests-feature', true); if (value === 0) toggleHiddenClassBySelector('.merge-requests-feature', true);
...@@ -164,7 +240,33 @@ ...@@ -164,7 +240,33 @@
}, },
}, },
}; };
=======
mergeRequestsAccessLevel(value, oldValue) {
if (value === 0) toggleHiddenClassBySelector('.merge-requests-feature', true);
else if (oldValue === 0) toggleHiddenClassBySelector('.merge-requests-feature', false);
},
buildsAccessLevel(value, oldValue) {
if (value === 0) toggleHiddenClassBySelector('.builds-feature', true);
else if (oldValue === 0) toggleHiddenClassBySelector('.builds-feature', false);
},
},
>>>>>>> upstream/master
methods: {
highlightChanges() {
this.highlightChangesClass = true;
this.$nextTick(() => {
this.highlightChangesClass = false;
});
},
visibilityAllowed(option) {
return this.allowedVisibilityOptions.includes(option);
},
},
};
</script> </script>
<template> <template>
......
...@@ -96,7 +96,12 @@ ...@@ -96,7 +96,12 @@
<span <span
v-tooltip v-tooltip
:title="item.revision" :title="item.revision"
<<<<<<< HEAD
data-placement="bottom"> data-placement="bottom">
=======
data-placement="bottom"
>
>>>>>>> upstream/master
{{ item.shortRevision }} {{ item.shortRevision }}
</span> </span>
</td> </td>
...@@ -121,10 +126,19 @@ ...@@ -121,10 +126,19 @@
:aria-label="s__('ContainerRegistry|Remove tag')" :aria-label="s__('ContainerRegistry|Remove tag')"
data-container="body" data-container="body"
v-tooltip v-tooltip
<<<<<<< HEAD
@click="handleDeleteRegistry(item)"> @click="handleDeleteRegistry(item)">
<i <i
class="fa fa-trash" class="fa fa-trash"
aria-hidden="true"> aria-hidden="true">
=======
@click="handleDeleteRegistry(item)"
>
<i
class="fa fa-trash"
aria-hidden="true"
>
>>>>>>> upstream/master
</i> </i>
</button> </button>
</td> </td>
......
...@@ -39,7 +39,14 @@ ...@@ -39,7 +39,14 @@
updateConfidentialAttribute(confidential) { updateConfidentialAttribute(confidential) {
this.service.update('issue', { confidential }) this.service.update('issue', { confidential })
.then(() => location.reload()) .then(() => location.reload())
<<<<<<< HEAD
.catch(() => new Flash('Something went wrong trying to change the confidentiality of this issue')); .catch(() => new Flash('Something went wrong trying to change the confidentiality of this issue'));
=======
.catch(() => {
Flash(`Something went wrong trying to
change the confidentiality of this issue`);
});
>>>>>>> upstream/master
}, },
}, },
}; };
......
...@@ -33,8 +33,12 @@ ...@@ -33,8 +33,12 @@
<div class="dropdown-menu sidebar-item-warning-message"> <div class="dropdown-menu sidebar-item-warning-message">
<p <p
class="text" class="text"
<<<<<<< HEAD
v-if="isLocked" v-if="isLocked"
> >
=======
v-if="isLocked">
>>>>>>> upstream/master
Unlock this {{ issuableDisplayName }}? Unlock this {{ issuableDisplayName }}?
<strong>Everyone</strong> <strong>Everyone</strong>
will be able to comment. will be able to comment.
...@@ -42,8 +46,12 @@ ...@@ -42,8 +46,12 @@
<p <p
class="text" class="text"
<<<<<<< HEAD
v-else v-else
> >
=======
v-else>
>>>>>>> upstream/master
Lock this {{ issuableDisplayName }}? Lock this {{ issuableDisplayName }}?
Only Only
<strong>project members</strong> <strong>project members</strong>
......
<script> <script>
<<<<<<< HEAD
import Flash from '~/flash'; import Flash from '~/flash';
=======
import Flash from '../../../flash';
>>>>>>> upstream/master
import editForm from './edit_form.vue'; import editForm from './edit_form.vue';
import issuableMixin from '../../../vue_shared/mixins/issuable'; import issuableMixin from '../../../vue_shared/mixins/issuable';
import Icon from '../../../vue_shared/components/icon.vue'; import Icon from '../../../vue_shared/components/icon.vue';
...@@ -12,6 +16,10 @@ ...@@ -12,6 +16,10 @@
mixins: [ mixins: [
issuableMixin, issuableMixin,
], ],
<<<<<<< HEAD
=======
>>>>>>> upstream/master
props: { props: {
isLocked: { isLocked: {
required: true, required: true,
...@@ -36,6 +44,23 @@ ...@@ -36,6 +44,23 @@
return this.isLocked ? 'lock' : 'lock-open'; return this.isLocked ? 'lock' : 'lock-open';
}, },
<<<<<<< HEAD
isLockDialogOpen() {
return this.mediator.store.isLockDialogOpen;
},
},
methods: {
toggleForm() {
this.mediator.store.isLockDialogOpen = !this.mediator.store.isLockDialogOpen;
},
=======
computed: {
lockIcon() {
return this.isLocked ? 'lock' : 'lock-open';
},
isLockDialogOpen() { isLockDialogOpen() {
return this.mediator.store.isLockDialogOpen; return this.mediator.store.isLockDialogOpen;
}, },
...@@ -46,12 +71,18 @@ ...@@ -46,12 +71,18 @@
this.mediator.store.isLockDialogOpen = !this.mediator.store.isLockDialogOpen; this.mediator.store.isLockDialogOpen = !this.mediator.store.isLockDialogOpen;
}, },
>>>>>>> upstream/master
updateLockedAttribute(locked) { updateLockedAttribute(locked) {
this.mediator.service.update(this.issuableType, { this.mediator.service.update(this.issuableType, {
discussion_locked: locked, discussion_locked: locked,
}) })
.then(() => location.reload()) .then(() => location.reload())
<<<<<<< HEAD
.catch(() => Flash(this.__(`Something went wrong trying to change the locked state of this ${this.issuableDisplayName}`))); .catch(() => Flash(this.__(`Something went wrong trying to change the locked state of this ${this.issuableDisplayName}`)));
=======
.catch(() => Flash(this.__(`Something went wrong trying to
change the locked state of this ${this.issuableDisplayName}`)));
>>>>>>> upstream/master
}, },
}, },
}; };
......
...@@ -101,7 +101,8 @@ ...@@ -101,7 +101,8 @@
<div <div
v-for="participant in visibleParticipants" v-for="participant in visibleParticipants"
:key="participant.id" :key="participant.id"
class="participants-author js-participants-author"> class="participants-author js-participants-author"
>
<a <a
class="author_link" class="author_link"
:href="participant.web_url" :href="participant.web_url"
......
...@@ -20,15 +20,20 @@ export default { ...@@ -20,15 +20,20 @@ export default {
store: new Store(), store: new Store(),
}; };
}, },
<<<<<<< HEAD
created() { created() {
eventHub.$on('toggleSubscription', this.onToggleSubscription); eventHub.$on('toggleSubscription', this.onToggleSubscription);
}, },
=======
created() {
eventHub.$on('toggleSubscription', this.onToggleSubscription);
},
>>>>>>> upstream/master
beforeDestroy() { beforeDestroy() {
eventHub.$off('toggleSubscription', this.onToggleSubscription); eventHub.$off('toggleSubscription', this.onToggleSubscription);
}, },
methods: { methods: {
onToggleSubscription() { onToggleSubscription() {
this.mediator.toggleSubscription() this.mediator.toggleSubscription()
......
...@@ -11,7 +11,10 @@ ...@@ -11,7 +11,10 @@
pipelineStage, pipelineStage,
ciIcon, ciIcon,
icon, icon,
<<<<<<< HEAD
linkedPipelinesMiniList, linkedPipelinesMiniList,
=======
>>>>>>> upstream/master
}, },
props: { props: {
pipeline: { pipeline: {
...@@ -98,6 +101,7 @@ ...@@ -98,6 +101,7 @@
{{ pipeline.commit.short_id }}</a>. {{ pipeline.commit.short_id }}</a>.
<span class="mr-widget-pipeline-graph"> <span class="mr-widget-pipeline-graph">
<<<<<<< HEAD
<span class="stage-cell"> <span class="stage-cell">
<linked-pipelines-mini-list <linked-pipelines-mini-list
v-if="triggeredBy.length" v-if="triggeredBy.length"
...@@ -120,13 +124,25 @@ ...@@ -120,13 +124,25 @@
v-if="triggered.length" v-if="triggered.length"
:triggered="triggered" :triggered="triggered"
/> />
=======
<span
class="stage-cell"
v-if="hasStages"
>
<div
v-for="(stage, i) in pipeline.details.stages"
:key="i"
class="stage-container dropdown js-mini-pipeline-graph"
>
<pipeline-stage :stage="stage" />
</div>
>>>>>>> upstream/master
</span> </span>
</span> </span>
<template v-if="pipeline.coverage"> <template v-if="pipeline.coverage">
Coverage {{ pipeline.coverage }}% Coverage {{ pipeline.coverage }}%
</template> </template>
</div> </div>
</template> </template>
</div> </div>
......
...@@ -107,8 +107,12 @@ ...@@ -107,8 +107,12 @@
<template v-if="!mr.rebaseInProgress && mr.canPushToSourceBranch && !isMakingRequest"> <template v-if="!mr.rebaseInProgress && mr.canPushToSourceBranch && !isMakingRequest">
<div <div
class="accept-merge-holder clearfix class="accept-merge-holder clearfix
<<<<<<< HEAD
js-toggle-container accept-action media space-children" js-toggle-container accept-action media space-children"
> >
=======
js-toggle-container accept-action media space-children">
>>>>>>> upstream/master
<button <button
type="button" type="button"
class="btn btn-sm btn-reopen btn-success" class="btn btn-sm btn-reopen btn-success"
......
...@@ -27,7 +27,10 @@ ...@@ -27,7 +27,10 @@
components: { components: {
icon, icon,
}, },
<<<<<<< HEAD
=======
>>>>>>> upstream/master
props: { props: {
status: { status: {
type: Object, type: Object,
......
...@@ -6,12 +6,21 @@ ...@@ -6,12 +6,21 @@
import userAvatarImage from './user_avatar/user_avatar_image.vue'; import userAvatarImage from './user_avatar/user_avatar_image.vue';
/** /**
<<<<<<< HEAD
* Renders header component for job and pipeline page based on UI mockups * Renders header component for job and pipeline page based on UI mockups
* *
* Used in: * Used in:
* - job show page * - job show page
* - pipeline show page * - pipeline show page
*/ */
=======
* Renders header component for job and pipeline page based on UI mockups
*
* Used in:
* - job show page
* - pipeline show page
*/
>>>>>>> upstream/master
export default { export default {
components: { components: {
ciIconBadge, ciIconBadge,
...@@ -127,7 +136,12 @@ ...@@ -127,7 +136,12 @@
v-if="action.type === 'link'" v-if="action.type === 'link'"
:href="action.path" :href="action.path"
:class="action.cssClass" :class="action.cssClass"
<<<<<<< HEAD
:key="i"> :key="i">
=======
:key="i"
>
>>>>>>> upstream/master
{{ action.label }} {{ action.label }}
</a> </a>
......
...@@ -5,7 +5,10 @@ ...@@ -5,7 +5,10 @@
components: { components: {
icon, icon,
}, },
<<<<<<< HEAD
=======
>>>>>>> upstream/master
props: { props: {
isLocked: { isLocked: {
type: Boolean, type: Boolean,
......
<script> <script>
/* eslint-disable vue/require-default-prop */ /* eslint-disable vue/require-default-prop */
<<<<<<< HEAD
/* This is a re-usable vue component for rendering a button /* This is a re-usable vue component for rendering a button
that will probably be sending off ajax requests and need that will probably be sending off ajax requests and need
to show the loading status by setting the `loading` option. to show the loading status by setting the `loading` option.
...@@ -49,6 +50,58 @@ ...@@ -49,6 +50,58 @@
this.$emit('click', e); this.$emit('click', e);
}, },
}, },
=======
/* This is a re-usable vue component for rendering a button
that will probably be sending off ajax requests and need
to show the loading status by setting the `loading` option.
This can also be used for initial page load when you don't
know the action of the button yet by setting
`loading: true, label: undefined`.
Sample configuration:
<loading-button
:loading="true"
:label="Hello"
@click="..."
/>
*/
import loadingIcon from './loading_icon.vue';
export default {
components: {
loadingIcon,
},
props: {
loading: {
type: Boolean,
required: false,
default: false,
},
disabled: {
type: Boolean,
required: false,
default: false,
},
label: {
type: String,
required: false,
},
containerClass: {
type: String,
required: false,
default: 'btn btn-align-content',
},
},
methods: {
onClick(e) {
this.$emit('click', e);
},
},
>>>>>>> upstream/master
}; };
</script> </script>
......
...@@ -30,6 +30,14 @@ ...@@ -30,6 +30,14 @@
type: String, type: String,
required: false, required: false,
default: '', default: '',
<<<<<<< HEAD
=======
},
canAttachFile: {
type: Boolean,
required: false,
default: true,
>>>>>>> upstream/master
}, },
enableAutocomplete: { enableAutocomplete: {
type: Boolean, type: Boolean,
...@@ -121,7 +129,8 @@ ...@@ -121,7 +129,8 @@
/> />
<div <div
class="md-write-holder" class="md-write-holder"
v-show="!previewMarkdown"> v-show="!previewMarkdown"
>
<div class="zen-backdrop"> <div class="zen-backdrop">
<slot name="textarea"></slot> <slot name="textarea"></slot>
<a <a
...@@ -137,6 +146,10 @@ ...@@ -137,6 +146,10 @@
<markdown-toolbar <markdown-toolbar
:markdown-docs-path="markdownDocsPath" :markdown-docs-path="markdownDocsPath"
:quick-actions-docs-path="quickActionsDocsPath" :quick-actions-docs-path="quickActionsDocsPath"
<<<<<<< HEAD
=======
:can-attach-file="canAttachFile"
>>>>>>> upstream/master
/> />
</div> </div>
</div> </div>
......
...@@ -71,13 +71,15 @@ ...@@ -71,13 +71,15 @@
class="js-preview-link" class="js-preview-link"
href="#md-preview-holder" href="#md-preview-holder"
tabindex="-1" tabindex="-1"
@click.prevent="previewMarkdownTab($event)"> @click.prevent="previewMarkdownTab($event)"
>
Preview Preview
</a> </a>
</li> </li>
<li <li
class="md-header-toolbar" class="md-header-toolbar"
:class="{ active: !previewMarkdown }"> :class="{ active: !previewMarkdown }"
>
<toolbar-button <toolbar-button
tag="**" tag="**"
button-title="Add bold text" button-title="Add bold text"
...@@ -125,7 +127,8 @@ ...@@ -125,7 +127,8 @@
data-container="body" data-container="body"
tabindex="-1" tabindex="-1"
title="Go full screen" title="Go full screen"
type="button"> type="button"
>
<icon <icon
name="screen-full" name="screen-full"
/> />
......
...@@ -16,7 +16,15 @@ ...@@ -16,7 +16,15 @@
return this.quickActionsDocsPath !== ''; return this.quickActionsDocsPath !== '';
}, },
}, },
<<<<<<< HEAD
=======
computed: {
hasQuickActionsDocsPath() {
return this.quickActionsDocsPath !== '';
},
},
>>>>>>> upstream/master
}; };
</script> </script>
...@@ -27,7 +35,8 @@ ...@@ -27,7 +35,8 @@
<a <a
:href="markdownDocsPath" :href="markdownDocsPath"
target="_blank" target="_blank"
tabindex="-1"> tabindex="-1"
>
Markdown is supported Markdown is supported
</a> </a>
</template> </template>
......
<script> <script>
<<<<<<< HEAD
/* eslint-disable vue/require-default-prop */ /* eslint-disable vue/require-default-prop */
export default { export default {
...@@ -67,6 +68,75 @@ ...@@ -67,6 +68,75 @@
}, },
}, },
=======
/* eslint-disable vue/require-default-prop */
export default {
name: 'Modal',
props: {
id: {
type: String,
required: false,
},
title: {
type: String,
required: false,
},
text: {
type: String,
required: false,
},
hideFooter: {
type: Boolean,
required: false,
default: false,
},
kind: {
type: String,
required: false,
default: 'primary',
},
modalDialogClass: {
type: String,
required: false,
default: '',
},
closeKind: {
type: String,
required: false,
default: 'default',
},
closeButtonLabel: {
type: String,
required: false,
default: 'Cancel',
},
primaryButtonLabel: {
type: String,
required: false,
default: '',
},
submitDisabled: {
type: Boolean,
required: false,
default: false,
},
},
computed: {
btnKindClass() {
return {
[`btn-${this.kind}`]: true,
};
},
btnCancelKindClass() {
return {
[`btn-${this.closeKind}`]: true,
};
},
},
>>>>>>> upstream/master
methods: { methods: {
emitCancel(event) { emitCancel(event) {
this.$emit('cancel', event); this.$emit('cancel', event);
......
<script> <script>
import modal from './modal.vue'; import modal from './modal.vue';
<<<<<<< HEAD
export default { export default {
name: 'RecaptchaModal', name: 'RecaptchaModal',
components: { components: {
modal, modal,
}, },
=======
export default {
name: 'RecaptchaModal',
>>>>>>> upstream/master
props: { components: {
html: { modal,
type: String,
required: false,
default: '',
}, },
},
data() { props: {
return { html: {
script: {}, type: String,
scriptSrc: 'https://www.google.com/recaptcha/api.js', required: false,
}; default: '',
}, },
},
<<<<<<< HEAD
watch: { watch: {
html() { html() {
this.appendRecaptchaScript(); this.appendRecaptchaScript();
...@@ -32,36 +35,62 @@ export default { ...@@ -32,36 +35,62 @@ export default {
mounted() { mounted() {
window.recaptchaDialogCallback = this.submit.bind(this); window.recaptchaDialogCallback = this.submit.bind(this);
}, },
=======
data() {
return {
script: {},
scriptSrc: 'https://www.google.com/recaptcha/api.js',
};
},
>>>>>>> upstream/master
methods: { watch: {
appendRecaptchaScript() { html() {
this.removeRecaptchaScript(); this.appendRecaptchaScript();
},
},
const script = document.createElement('script'); mounted() {
script.src = this.scriptSrc; window.recaptchaDialogCallback = this.submit.bind(this);
script.classList.add('js-recaptcha-script'); },
script.async = true;
script.defer = true;
this.script = script; methods: {
appendRecaptchaScript() {
this.removeRecaptchaScript();
document.body.appendChild(script); const script = document.createElement('script');
}, script.src = this.scriptSrc;
script.classList.add('js-recaptcha-script');
script.async = true;
script.defer = true;
removeRecaptchaScript() { this.script = script;
if (this.script instanceof Element) this.script.remove();
},
close() { document.body.appendChild(script);
this.removeRecaptchaScript(); },
this.$emit('close');
},
<<<<<<< HEAD
submit() { submit() {
this.$el.querySelector('form').submit(); this.$el.querySelector('form').submit();
}, },
}, },
}; };
=======
removeRecaptchaScript() {
if (this.script instanceof Element) this.script.remove();
},
close() {
this.removeRecaptchaScript();
this.$emit('close');
},
submit() {
this.$el.querySelector('form').submit();
},
},
};
>>>>>>> upstream/master
</script> </script>
<template> <template>
......
...@@ -13,12 +13,15 @@ ...@@ -13,12 +13,15 @@
props: { props: {
/** /**
This function will take the information given by the pagination component This function will take the information given by the pagination component
<<<<<<< HEAD
Here is an example `change` method: Here is an example `change` method:
change(pagenum) { change(pagenum) {
gl.utils.visitUrl(`?page=${pagenum}`); gl.utils.visitUrl(`?page=${pagenum}`);
}, },
=======
>>>>>>> upstream/master
*/ */
change: { change: {
type: Function, type: Function,
......
...@@ -18,14 +18,9 @@ ...@@ -18,14 +18,9 @@
margin: $gl-padding 0; margin: $gl-padding 0;
&.limited-width-container .file-content { &.limited-width-container .file-content {
max-width: $limited-layout-width-sm; max-width: $limited-layout-width;
margin-left: auto; margin-left: auto;
margin-right: auto; margin-right: auto;
@media (min-width: $screen-md-min) {
padding-top: 64px;
padding-bottom: 64px;
}
} }
} }
...@@ -128,7 +123,7 @@ ...@@ -128,7 +123,7 @@
} }
&.wiki { &.wiki {
padding: 30px $gl-padding; padding: $gl-padding;
} }
&.blob-no-preview { &.blob-no-preview {
......
...@@ -16,12 +16,6 @@ ...@@ -16,12 +16,6 @@
display: inline-block; display: inline-block;
} }
@media (min-width: $screen-md-min) {
.blob-viewer[data-type="rich"] {
margin: 20px;
}
}
.ide-view { .ide-view {
display: flex; display: flex;
height: calc(100vh - #{$header-height}); height: calc(100vh - #{$header-height});
......
class Projects::Clusters::GcpController < Projects::ApplicationController class Projects::Clusters::GcpController < Projects::ApplicationController
before_action :authorize_read_cluster! before_action :authorize_read_cluster!
before_action :authorize_google_api, except: [:login] before_action :authorize_google_api, except: [:login]
before_action :authorize_google_project_billing, only: [:new] before_action :authorize_google_project_billing, only: [:new, :create]
before_action :authorize_create_cluster!, only: [:new, :create] before_action :authorize_create_cluster!, only: [:new, :create]
before_action :verify_billing, only: [:create]
def login def login
begin begin
...@@ -23,24 +24,34 @@ class Projects::Clusters::GcpController < Projects::ApplicationController ...@@ -23,24 +24,34 @@ class Projects::Clusters::GcpController < Projects::ApplicationController
end end
def create def create
@cluster = ::Clusters::CreateService
.new(project, current_user, create_params)
.execute(token_in_session)
if @cluster.persisted?
redirect_to project_cluster_path(project, @cluster)
else
render :new
end
end
private
def verify_billing
case google_project_billing_status case google_project_billing_status
when 'true' when 'true'
@cluster = ::Clusters::CreateService return
.new(project, current_user, create_params)
.execute(token_in_session)
return redirect_to project_cluster_path(project, @cluster) if @cluster.persisted?
when 'false' when 'false'
flash[:error] = _('Please enable billing for one of your projects to be able to create a cluster.') flash[:alert] = _('Please <a href=%{link_to_billing} target="_blank" rel="noopener noreferrer">enable billing for one of your projects to be able to create a cluster</a>, then try again.').html_safe % { link_to_billing: "https://console.cloud.google.com/freetrial?utm_campaign=2018_cpanel&utm_source=gitlab&utm_medium=referral" }
else else
flash[:error] = _('We could not verify that one of your projects on GCP has billing enabled. Please try again.') flash[:alert] = _('We could not verify that one of your projects on GCP has billing enabled. Please try again.')
end end
@cluster = ::Clusters::Cluster.new(create_params)
render :new render :new
end end
private
def create_params def create_params
params.require(:cluster).permit( params.require(:cluster).permit(
:enabled, :enabled,
......
...@@ -46,7 +46,7 @@ module BlobHelper ...@@ -46,7 +46,7 @@ module BlobHelper
end end
def ide_edit_text def ide_edit_text
"#{_('Multi Edit')} <span class='label label-primary'>#{_('Beta')}</span>".html_safe "#{_('Web IDE')}"
end end
def ide_blob_link(project = @project, ref = @ref, path = @path, options = {}) def ide_blob_link(project = @project, ref = @ref, path = @path, options = {})
......
...@@ -49,6 +49,7 @@ class MergeRequestDiff < ActiveRecord::Base ...@@ -49,6 +49,7 @@ class MergeRequestDiff < ActiveRecord::Base
ensure_commit_shas ensure_commit_shas
save_commits save_commits
save_diffs save_diffs
save
keep_around_commits keep_around_commits
end end
...@@ -56,7 +57,6 @@ class MergeRequestDiff < ActiveRecord::Base ...@@ -56,7 +57,6 @@ class MergeRequestDiff < ActiveRecord::Base
self.start_commit_sha ||= merge_request.target_branch_sha self.start_commit_sha ||= merge_request.target_branch_sha
self.head_commit_sha ||= merge_request.source_branch_sha self.head_commit_sha ||= merge_request.source_branch_sha
self.base_commit_sha ||= find_base_sha self.base_commit_sha ||= find_base_sha
save
end end
# Override head_commit_sha to keep compatibility with merge request diff # Override head_commit_sha to keep compatibility with merge request diff
...@@ -195,7 +195,7 @@ class MergeRequestDiff < ActiveRecord::Base ...@@ -195,7 +195,7 @@ class MergeRequestDiff < ActiveRecord::Base
end end
def commits_count def commits_count
merge_request_diff_commits.size super || merge_request_diff_commits.size
end end
private private
...@@ -264,13 +264,16 @@ class MergeRequestDiff < ActiveRecord::Base ...@@ -264,13 +264,16 @@ class MergeRequestDiff < ActiveRecord::Base
new_attributes[:state] = :overflow if diff_collection.overflow? new_attributes[:state] = :overflow if diff_collection.overflow?
end end
update(new_attributes) assign_attributes(new_attributes)
end end
def save_commits def save_commits
MergeRequestDiffCommit.create_bulk(self.id, compare.commits.reverse) MergeRequestDiffCommit.create_bulk(self.id, compare.commits.reverse)
merge_request_diff_commits.reload # merge_request_diff_commits.reload is preferred way to reload associated
# objects but it returns cached result for some reason in this case
commits = merge_request_diff_commits(true)
self.commits_count = commits.size
end end
def repository def repository
......
...@@ -1160,7 +1160,7 @@ class Project < ActiveRecord::Base ...@@ -1160,7 +1160,7 @@ class Project < ActiveRecord::Base
def change_head(branch) def change_head(branch)
if repository.branch_exists?(branch) if repository.branch_exists?(branch)
repository.before_change_head repository.before_change_head
repository.write_ref('HEAD', "refs/heads/#{branch}") repository.raw_repository.write_ref('HEAD', "refs/heads/#{branch}", shell: false)
repository.copy_gitattributes(branch) repository.copy_gitattributes(branch)
repository.after_change_head repository.after_change_head
reload_default_branch reload_default_branch
......
...@@ -267,7 +267,7 @@ class Repository ...@@ -267,7 +267,7 @@ class Repository
# This will still fail if the file is corrupted (e.g. 0 bytes) # This will still fail if the file is corrupted (e.g. 0 bytes)
begin begin
write_ref(keep_around_ref_name(sha), sha) raw_repository.write_ref(keep_around_ref_name(sha), sha, shell: false)
rescue Rugged::ReferenceError => ex rescue Rugged::ReferenceError => ex
Rails.logger.error "Unable to create #{REF_KEEP_AROUND} reference for repository #{path}: #{ex}" Rails.logger.error "Unable to create #{REF_KEEP_AROUND} reference for repository #{path}: #{ex}"
rescue Rugged::OSError => ex rescue Rugged::OSError => ex
...@@ -281,10 +281,6 @@ class Repository ...@@ -281,10 +281,6 @@ class Repository
ref_exists?(keep_around_ref_name(sha)) ref_exists?(keep_around_ref_name(sha))
end end
def write_ref(ref_path, sha)
rugged.references.create(ref_path, sha, force: true)
end
def diverging_commit_counts(branch) def diverging_commit_counts(branch)
root_ref_hash = raw_repository.commit(root_ref).id root_ref_hash = raw_repository.commit(root_ref).id
cache.fetch(:"diverging_commit_counts_#{branch.name}") do cache.fetch(:"diverging_commit_counts_#{branch.name}") do
......
...@@ -2,7 +2,10 @@ class CheckGcpProjectBillingService ...@@ -2,7 +2,10 @@ class CheckGcpProjectBillingService
def execute(token) def execute(token)
client = GoogleApi::CloudPlatform::Client.new(token, nil) client = GoogleApi::CloudPlatform::Client.new(token, nil)
client.projects_list.select do |project| client.projects_list.select do |project|
client.projects_get_billing_info(project.name).billingEnabled begin
client.projects_get_billing_info(project.project_id).billing_enabled
rescue
end
end end
end end
end end
...@@ -24,7 +24,7 @@ module Issues ...@@ -24,7 +24,7 @@ module Issues
@new_issue = create_new_issue @new_issue = create_new_issue
rewrite_notes rewrite_notes
rewrite_award_emoji rewrite_issue_award_emoji
add_note_moved_from add_note_moved_from
# Old issue tasks # Old issue tasks
...@@ -76,7 +76,7 @@ module Issues ...@@ -76,7 +76,7 @@ module Issues
end end
def rewrite_notes def rewrite_notes
@old_issue.notes.find_each do |note| @old_issue.notes_with_associations.find_each do |note|
new_note = note.dup new_note = note.dup
new_params = { project: @new_project, noteable: @new_issue, new_params = { project: @new_project, noteable: @new_issue,
note: rewrite_content(new_note.note), note: rewrite_content(new_note.note),
...@@ -84,13 +84,19 @@ module Issues ...@@ -84,13 +84,19 @@ module Issues
updated_at: note.updated_at } updated_at: note.updated_at }
new_note.update(new_params) new_note.update(new_params)
rewrite_award_emoji(note, new_note)
end end
end end
def rewrite_award_emoji def rewrite_issue_award_emoji
@old_issue.award_emoji.each do |award| rewrite_award_emoji(@old_issue, @new_issue)
end
def rewrite_award_emoji(old_awardable, new_awardable)
old_awardable.award_emoji.each do |award|
new_award = award.dup new_award = award.dup
new_award.awardable = @new_issue new_award.awardable = new_awardable
new_award.save new_award.save
end end
end end
......
...@@ -156,13 +156,9 @@ module MergeRequests ...@@ -156,13 +156,9 @@ module MergeRequests
end end
def assign_title_from_issue def assign_title_from_issue
return unless issue return unless issue && issue.is_a?(Issue)
merge_request.title = merge_request.title = "Resolve \"#{issue.title}\""
case issue
when Issue then "Resolve \"#{issue.title}\""
when ExternalIssue then "Resolve #{issue.title}"
end
end end
def issue_iid def issue_iid
......
module MergeRequests module MergeRequests
class RebaseService < MergeRequests::WorkingCopyBaseService class RebaseService < MergeRequests::WorkingCopyBaseService
REBASE_ERROR = 'Rebase failed. Please rebase locally'.freeze
def execute(merge_request) def execute(merge_request)
@merge_request = merge_request @merge_request = merge_request
if rebase if rebase
success success
else else
error('Failed to rebase. Should be done manually') error(REBASE_ERROR)
end end
end end
...@@ -22,8 +24,8 @@ module MergeRequests ...@@ -22,8 +24,8 @@ module MergeRequests
true true
rescue => e rescue => e
log_error('Failed to rebase branch:') log_error(REBASE_ERROR, save_message_on_model: true)
log_error(e.message, save_message_on_model: true) log_error(e.message)
false false
end end
end end
......
<<<<<<< HEAD
%header.navbar.navbar-gitlab.navbar-gitlab-new.qa-navbar %header.navbar.navbar-gitlab.navbar-gitlab-new.qa-navbar
=======
%header.navbar.navbar-gitlab.qa-navbar
>>>>>>> upstream/master
%a.sr-only.gl-accessibility{ href: "#content-body", tabindex: "1" } Skip to content %a.sr-only.gl-accessibility{ href: "#content-body", tabindex: "1" } Skip to content
.container-fluid .container-fluid
.header-content .header-content
...@@ -56,8 +60,6 @@ ...@@ -56,8 +60,6 @@
= link_to "Profile", current_user, class: 'profile-link', data: { user: current_user.username } = link_to "Profile", current_user, class: 'profile-link', data: { user: current_user.username }
%li %li
= link_to "Settings", profile_path = link_to "Settings", profile_path
%li
= link_to "Turn on multi edit", profile_preferences_path
- if current_user - if current_user
%li %li
= link_to "Help", help_path = link_to "Help", help_path
......
...@@ -5,8 +5,8 @@ ...@@ -5,8 +5,8 @@
= form_for @user, url: profile_preferences_path, remote: true, method: :put, html: { class: 'row prepend-top-default js-preferences-form' } do |f| = form_for @user, url: profile_preferences_path, remote: true, method: :put, html: { class: 'row prepend-top-default js-preferences-form' } do |f|
.col-lg-4 .col-lg-4
%h4.prepend-top-0 %h4.prepend-top-0
GitLab multi file editor Web IDE (Beta)
%p Unlock an additional editing experience which makes it possible to edit and commit multiple files %p Enable the new web IDE on this device to make it possible to open and edit multiple files with a single commit
.col-lg-8.multi-file-editor-options .col-lg-8.multi-file-editor-options
= label_tag do = label_tag do
.preview.append-bottom-10= image_tag "multi-editor-off.png" .preview.append-bottom-10= image_tag "multi-editor-off.png"
......
...@@ -30,12 +30,13 @@ ...@@ -30,12 +30,13 @@
%li %li
= link_to project_new_blob_path(@project, @project.default_branch || 'master') do = link_to project_new_blob_path(@project, @project.default_branch || 'master') do
#{ _('New file') } #{ _('New file') }
%li - unless @project.empty_repo?
= link_to new_project_branch_path(@project) do %li
#{ _('New branch') } = link_to new_project_branch_path(@project) do
%li #{ _('New branch') }
= link_to new_project_tag_path(@project) do %li
#{ _('New tag') } = link_to new_project_tag_path(@project) do
#{ _('New tag') }
- elsif current_user && current_user.already_forked?(@project) - elsif current_user && current_user.already_forked?(@project)
%li %li
= link_to project_new_blob_path(@project, @project.default_branch || 'master') do = link_to project_new_blob_path(@project, @project.default_branch || 'master') do
......
...@@ -4,11 +4,11 @@ ...@@ -4,11 +4,11 @@
= s_('ClusterIntegration|Please make sure that your Google account meets the following requirements:') = s_('ClusterIntegration|Please make sure that your Google account meets the following requirements:')
%ul %ul
%li %li
- link_to_kubernetes_engine = link_to(s_('ClusterIntegration|access to Google Kubernetes Engine'), 'https://console.cloud.google.com', target: '_blank', rel: 'noopener noreferrer') - link_to_kubernetes_engine = link_to(s_('ClusterIntegration|access to Google Kubernetes Engine'), 'https://console.cloud.google.com/freetrial?utm_campaign=2018_cpanel&utm_source=gitlab&utm_medium=referral', target: '_blank', rel: 'noopener noreferrer')
= s_('ClusterIntegration|Your account must have %{link_to_kubernetes_engine}').html_safe % { link_to_kubernetes_engine: link_to_kubernetes_engine } = s_('ClusterIntegration|Your account must have %{link_to_kubernetes_engine}').html_safe % { link_to_kubernetes_engine: link_to_kubernetes_engine }
%li %li
- link_to_requirements = link_to(s_('ClusterIntegration|meets the requirements'), 'https://cloud.google.com/kubernetes-engine/docs/quickstart', target: '_blank', rel: 'noopener noreferrer') - link_to_requirements = link_to(s_('ClusterIntegration|meets the requirements'), 'https://cloud.google.com/kubernetes-engine/docs/quickstart?utm_campaign=2018_cpanel&utm_source=gitlab&utm_medium=referral', target: '_blank', rel: 'noopener noreferrer')
= s_('ClusterIntegration|Make sure your account %{link_to_requirements} to create clusters').html_safe % { link_to_requirements: link_to_requirements } = s_('ClusterIntegration|Make sure your account %{link_to_requirements} to create clusters').html_safe % { link_to_requirements: link_to_requirements }
%li %li
- link_to_container_project = link_to(s_('ClusterIntegration|Google Kubernetes Engine project'), 'https://console.cloud.google.com/home/dashboard', target: '_blank', rel: 'noopener noreferrer') - link_to_container_project = link_to(s_('ClusterIntegration|Google Kubernetes Engine project'), 'https://console.cloud.google.com/home/dashboard?utm_campaign=2018_cpanel&utm_source=gitlab&utm_medium=referral', target: '_blank', rel: 'noopener noreferrer')
= s_('ClusterIntegration|This account must have permissions to create a cluster in the %{link_to_container_project} specified below').html_safe % { link_to_container_project: link_to_container_project } = s_('ClusterIntegration|This account must have permissions to create a cluster in the %{link_to_container_project} specified below').html_safe % { link_to_container_project: link_to_container_project }
- @content_class = "limit-container-width" unless fluid_layout - @content_class = "limit-container-width" unless fluid_layout
- add_to_breadcrumbs "Clusters", project_clusters_path(@project) - add_to_breadcrumbs "Clusters", project_clusters_path(@project)
- breadcrumb_title @cluster.id - breadcrumb_title @cluster.name
- page_title _("Cluster") - page_title _("Cluster")
- expanded = Rails.env.test? - expanded = Rails.env.test?
......
...@@ -35,3 +35,6 @@ ...@@ -35,3 +35,6 @@
- if diff_file.mode_changed? - if diff_file.mode_changed?
%small %small
#{diff_file.a_mode}#{diff_file.b_mode} #{diff_file.a_mode}#{diff_file.b_mode}
- if diff_file.stored_externally? && diff_file.external_storage == :lfs
%span.label.label-lfs.append-right-5 LFS
...@@ -4,7 +4,7 @@ class CheckGcpProjectBillingWorker ...@@ -4,7 +4,7 @@ class CheckGcpProjectBillingWorker
include ApplicationWorker include ApplicationWorker
include ClusterQueue include ClusterQueue
LEASE_TIMEOUT = 15.seconds.to_i LEASE_TIMEOUT = 3.seconds.to_i
SESSION_KEY_TIMEOUT = 5.minutes SESSION_KEY_TIMEOUT = 5.minutes
BILLING_TIMEOUT = 1.hour BILLING_TIMEOUT = 1.hour
...@@ -23,13 +23,13 @@ class CheckGcpProjectBillingWorker ...@@ -23,13 +23,13 @@ class CheckGcpProjectBillingWorker
end end
def self.redis_shared_state_key_for(token) def self.redis_shared_state_key_for(token)
"gitlab:gcp:#{token.hash}:billing_enabled" "gitlab:gcp:#{Digest::SHA1.hexdigest(token)}:billing_enabled"
end end
def perform(token_key) def perform(token_key)
return unless token_key return unless token_key
token = self.get_session_token(token_key) token = self.class.get_session_token(token_key)
return unless token return unless token
return unless try_obtain_lease_for(token) return unless try_obtain_lease_for(token)
......
---
title: Default merge request title is set correctly again when external issue tracker is activated
merge_request: 16356
author: Ben305
type: fixed
---
title: Store number of commits in merge_request_diffs table.
merge_request:
author:
type: performance
---
title: Add `pipelines` endpoint to merge requests API
merge_request: 15454
author: Tony Rom <thetonyrom@gmail.com>
type: added
---
title: Hide new branch and tag links for projects with an empty repo
merge_request:
author:
type: fixed
---
title: Display user friendly error message if rebase fails.
merge_request:
author:
type: fixed
---
title: Make project README containers wider on fixed layout
merge_request: 16181
author: Takuya Noguchi
type: fixed
---
title: Make modal dialog common for Groups tree app
merge_request: 16311
author:
type: fixed
---
title: Make rich blob viewer wider for PC
merge_request: 16262
author: Takuya Noguchi
type: fixed
---
title: Fix web ide user preferences copy and buttons
merge_request: 41789
author:
type: other
---
title: Add rake task to check integrity of uploaded files
merge_request:
author:
type: added
---
title: Fix bug where award emojis would be lost when moving issues between projects
merge_request:
author:
type: fixed
class AddCommitsCountToMergeRequestDiff < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
MIGRATION = 'AddMergeRequestDiffCommitsCount'.freeze
BATCH_SIZE = 5000
DELAY_INTERVAL = 5.minutes.to_i
class MergeRequestDiff < ActiveRecord::Base
self.table_name = 'merge_request_diffs'
include ::EachBatch
end
disable_ddl_transaction!
def up
add_column :merge_request_diffs, :commits_count, :integer
say 'Populating the MergeRequestDiff `commits_count`'
queue_background_migration_jobs_by_range_at_intervals(MergeRequestDiff, MIGRATION, DELAY_INTERVAL, batch_size: BATCH_SIZE)
end
def down
remove_column :merge_request_diffs, :commits_count
end
end
...@@ -11,7 +11,11 @@ ...@@ -11,7 +11,11 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
<<<<<<< HEAD
ActiveRecord::Schema.define(version: 20180105233807) do ActiveRecord::Schema.define(version: 20180105233807) do
=======
ActiveRecord::Schema.define(version: 20180105212544) do
>>>>>>> upstream/master
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"
...@@ -1401,6 +1405,7 @@ ActiveRecord::Schema.define(version: 20180105233807) do ...@@ -1401,6 +1405,7 @@ ActiveRecord::Schema.define(version: 20180105233807) do
t.string "real_size" t.string "real_size"
t.string "head_commit_sha" t.string "head_commit_sha"
t.string "start_commit_sha" t.string "start_commit_sha"
t.integer "commits_count"
end end
add_index "merge_request_diffs", ["merge_request_id", "id"], name: "index_merge_request_diffs_on_merge_request_id_and_id", using: :btree add_index "merge_request_diffs", ["merge_request_id", "id"], name: "index_merge_request_diffs_on_merge_request_id_and_id", using: :btree
......
...@@ -66,3 +66,15 @@ On the sign in page there should now be a Crowd tab in the sign in form. ...@@ -66,3 +66,15 @@ On the sign in page there should now be a Crowd tab in the sign in form.
[reconfigure]: ../restart_gitlab.md#omnibus-gitlab-reconfigure [reconfigure]: ../restart_gitlab.md#omnibus-gitlab-reconfigure
[restart]: ../restart_gitlab.md#installations-from-source [restart]: ../restart_gitlab.md#installations-from-source
## Troubleshooting
If you see an error message like the one below when you sign in after Crowd authentication is configured, you may want to consult the Crowd administrator for the Crowd log file to know the exact cause:
```
could not authorize you from Crowd because invalid credentials
```
Please make sure the Crowd users who need to login to GitLab are authorized to [the application](#configure-a-new-crowd-application) in the step of **Authorisation**. This could be verified by try "Authentication test" for Crowd as of 2.11.
![Example Crowd application authorisation configuration](img/crowd_application_authorisation.png)
\ No newline at end of file
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