Merge branch 'update-droplab-to-webpack-version' into new-resolvable-discussion
This commit is contained in:
commit
2f22890d42
229 changed files with 1849 additions and 1048 deletions
|
@ -20,6 +20,7 @@ import eventHub from '../eventhub';
|
|||
list: {
|
||||
type: Object,
|
||||
required: false,
|
||||
default: () => ({}),
|
||||
},
|
||||
rootPath: {
|
||||
type: String,
|
||||
|
@ -31,6 +32,26 @@ import eventHub from '../eventhub';
|
|||
default: false,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
cardUrl() {
|
||||
return `${this.issueLinkBase}/${this.issue.id}`;
|
||||
},
|
||||
assigneeUrl() {
|
||||
return `${this.rootPath}${this.issue.assignee.username}`;
|
||||
},
|
||||
assigneeUrlTitle() {
|
||||
return `Assigned to ${this.issue.assignee.name}`;
|
||||
},
|
||||
avatarUrlTitle() {
|
||||
return `Avatar for ${this.issue.assignee.name}`;
|
||||
},
|
||||
issueId() {
|
||||
return `#${this.issue.id}`;
|
||||
},
|
||||
showLabelFooter() {
|
||||
return this.issue.labels.find(l => this.showLabel(l)) !== undefined;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
showLabel(label) {
|
||||
if (!this.list) return true;
|
||||
|
@ -67,35 +88,41 @@ import eventHub from '../eventhub';
|
|||
},
|
||||
template: `
|
||||
<div>
|
||||
<h4 class="card-title">
|
||||
<i
|
||||
class="fa fa-eye-slash confidential-icon"
|
||||
v-if="issue.confidential"></i>
|
||||
<a
|
||||
:href="issueLinkBase + '/' + issue.id"
|
||||
:title="issue.title">
|
||||
{{ issue.title }}
|
||||
</a>
|
||||
</h4>
|
||||
<div class="card-footer">
|
||||
<span
|
||||
class="card-number"
|
||||
v-if="issue.id">
|
||||
#{{ issue.id }}
|
||||
</span>
|
||||
<div class="card-header">
|
||||
<h4 class="card-title">
|
||||
<i
|
||||
class="fa fa-eye-slash confidential-icon"
|
||||
v-if="issue.confidential"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<a
|
||||
class="js-no-trigger"
|
||||
:href="cardUrl"
|
||||
:title="issue.title">{{ issue.title }}</a>
|
||||
<span
|
||||
class="card-number"
|
||||
v-if="issue.id"
|
||||
>
|
||||
{{ issueId }}
|
||||
</span>
|
||||
</h4>
|
||||
<a
|
||||
class="card-assignee has-tooltip js-no-trigger"
|
||||
:href="rootPath + issue.assignee.username"
|
||||
:title="'Assigned to ' + issue.assignee.name"
|
||||
:href="assigneeUrl"
|
||||
:title="assigneeUrlTitle"
|
||||
v-if="issue.assignee"
|
||||
data-container="body">
|
||||
data-container="body"
|
||||
>
|
||||
<img
|
||||
class="avatar avatar-inline s20 js-no-trigger"
|
||||
:src="issue.assignee.avatar"
|
||||
width="20"
|
||||
height="20"
|
||||
:alt="'Avatar for ' + issue.assignee.name" />
|
||||
:alt="avatarUrlTitle"
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
<div class="card-footer" v-if="showLabelFooter">
|
||||
<button
|
||||
class="label color-label has-tooltip js-no-trigger"
|
||||
v-for="label in issue.labels"
|
||||
|
|
|
@ -8,10 +8,8 @@ Vue.use(VueResource);
|
|||
|
||||
/**
|
||||
* Commits View > Pipelines Tab > Pipelines Table.
|
||||
* Merge Request View > Pipelines Tab > Pipelines Table.
|
||||
*
|
||||
* Renders Pipelines table in pipelines tab in the commits show view.
|
||||
* Renders Pipelines table in pipelines tab in the merge request show view.
|
||||
*/
|
||||
|
||||
$(() => {
|
||||
|
@ -20,13 +18,14 @@ $(() => {
|
|||
gl.commits.pipelines = gl.commits.pipelines || {};
|
||||
|
||||
if (gl.commits.PipelinesTableBundle) {
|
||||
document.querySelector('#commit-pipeline-table-view').removeChild(this.pipelinesTableBundle.$el);
|
||||
gl.commits.PipelinesTableBundle.$destroy(true);
|
||||
}
|
||||
|
||||
const pipelineTableViewEl = document.querySelector('#commit-pipeline-table-view');
|
||||
gl.commits.pipelines.PipelinesTableBundle = new CommitPipelinesTable();
|
||||
|
||||
if (pipelineTableViewEl && pipelineTableViewEl.dataset.disableInitialization === undefined) {
|
||||
gl.commits.pipelines.PipelinesTableBundle.$mount(pipelineTableViewEl);
|
||||
gl.commits.pipelines.PipelinesTableBundle = new CommitPipelinesTable().$mount();
|
||||
document.querySelector('#commit-pipeline-table-view').appendChild(gl.commits.pipelines.PipelinesTableBundle.$el);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import Vue from 'vue';
|
||||
import Visibility from 'visibilityjs';
|
||||
import PipelinesTableComponent from '../../vue_shared/components/pipelines_table';
|
||||
import PipelinesService from '../../vue_pipelines_index/services/pipelines_service';
|
||||
import PipelineStore from '../../vue_pipelines_index/stores/pipelines_store';
|
||||
|
@ -7,6 +8,7 @@ import EmptyState from '../../vue_pipelines_index/components/empty_state';
|
|||
import ErrorState from '../../vue_pipelines_index/components/error_state';
|
||||
import '../../lib/utils/common_utils';
|
||||
import '../../vue_shared/vue_resource_interceptor';
|
||||
import Poll from '../../lib/utils/poll';
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -20,6 +22,7 @@ import '../../vue_shared/vue_resource_interceptor';
|
|||
*/
|
||||
|
||||
export default Vue.component('pipelines-table', {
|
||||
|
||||
components: {
|
||||
'pipelines-table-component': PipelinesTableComponent,
|
||||
'error-state': ErrorState,
|
||||
|
@ -42,6 +45,7 @@ export default Vue.component('pipelines-table', {
|
|||
state: store.state,
|
||||
isLoading: false,
|
||||
hasError: false,
|
||||
isMakingRequest: false,
|
||||
};
|
||||
},
|
||||
|
||||
|
@ -64,17 +68,41 @@ export default Vue.component('pipelines-table', {
|
|||
*
|
||||
*/
|
||||
beforeMount() {
|
||||
this.endpoint = this.$el.dataset.endpoint;
|
||||
this.helpPagePath = this.$el.dataset.helpPagePath;
|
||||
const element = document.querySelector('#commit-pipeline-table-view');
|
||||
|
||||
this.endpoint = element.dataset.endpoint;
|
||||
this.helpPagePath = element.dataset.helpPagePath;
|
||||
this.service = new PipelinesService(this.endpoint);
|
||||
|
||||
this.fetchPipelines();
|
||||
this.poll = new Poll({
|
||||
resource: this.service,
|
||||
method: 'getPipelines',
|
||||
successCallback: this.successCallback,
|
||||
errorCallback: this.errorCallback,
|
||||
notificationCallback: this.setIsMakingRequest,
|
||||
});
|
||||
|
||||
if (!Visibility.hidden()) {
|
||||
this.isLoading = true;
|
||||
this.poll.makeRequest();
|
||||
}
|
||||
|
||||
Visibility.change(() => {
|
||||
if (!Visibility.hidden()) {
|
||||
this.poll.restart();
|
||||
} else {
|
||||
this.poll.stop();
|
||||
}
|
||||
});
|
||||
|
||||
eventHub.$on('refreshPipelines', this.fetchPipelines);
|
||||
},
|
||||
|
||||
beforeUpdate() {
|
||||
if (this.state.pipelines.length && this.$children) {
|
||||
if (this.state.pipelines.length &&
|
||||
this.$children &&
|
||||
!this.isMakingRequest &&
|
||||
!this.isLoading) {
|
||||
this.store.startTimeAgoLoops.call(this, Vue);
|
||||
}
|
||||
},
|
||||
|
@ -83,21 +111,35 @@ export default Vue.component('pipelines-table', {
|
|||
eventHub.$off('refreshPipelines');
|
||||
},
|
||||
|
||||
destroyed() {
|
||||
this.poll.stop();
|
||||
},
|
||||
|
||||
methods: {
|
||||
fetchPipelines() {
|
||||
this.isLoading = true;
|
||||
|
||||
return this.service.getPipelines()
|
||||
.then(response => response.json())
|
||||
.then((json) => {
|
||||
// depending of the endpoint the response can either bring a `pipelines` key or not.
|
||||
const pipelines = json.pipelines || json;
|
||||
this.store.storePipelines(pipelines);
|
||||
this.isLoading = false;
|
||||
})
|
||||
.catch(() => {
|
||||
this.hasError = true;
|
||||
this.isLoading = false;
|
||||
});
|
||||
.then(response => this.successCallback(response))
|
||||
.catch(() => this.errorCallback());
|
||||
},
|
||||
|
||||
successCallback(resp) {
|
||||
const response = resp.json();
|
||||
|
||||
// depending of the endpoint the response can either bring a `pipelines` key or not.
|
||||
const pipelines = response.pipelines || response;
|
||||
this.store.storePipelines(pipelines);
|
||||
this.isLoading = false;
|
||||
},
|
||||
|
||||
errorCallback() {
|
||||
this.hasError = true;
|
||||
this.isLoading = false;
|
||||
},
|
||||
|
||||
setIsMakingRequest(isMakingRequest) {
|
||||
this.isMakingRequest = isMakingRequest;
|
||||
},
|
||||
},
|
||||
|
||||
|
|
|
@ -38,9 +38,35 @@ showTooltip = function(target, title) {
|
|||
};
|
||||
|
||||
$(function() {
|
||||
var clipboard;
|
||||
|
||||
clipboard = new Clipboard('[data-clipboard-target], [data-clipboard-text]');
|
||||
const clipboard = new Clipboard('[data-clipboard-target], [data-clipboard-text]');
|
||||
clipboard.on('success', genericSuccess);
|
||||
return clipboard.on('error', genericError);
|
||||
clipboard.on('error', genericError);
|
||||
|
||||
// This a workaround around ClipboardJS limitations to allow the context-specific copy/pasting of plain text or GFM.
|
||||
// The Ruby `clipboard_button` helper sneaks a JSON hash with `text` and `gfm` keys into the `data-clipboard-text`
|
||||
// attribute that ClipboardJS reads from.
|
||||
// When ClipboardJS creates a new `textarea` (directly inside `body`, with a `readonly` attribute`), sets its value
|
||||
// to the value of this data attribute, focusses on it, and finally programmatically issues the 'Copy' command,
|
||||
// this code intercepts the copy command/event at the last minute to deconstruct this JSON hash and set the
|
||||
// `text/plain` and `text/x-gfm` copy data types to the intended values.
|
||||
$(document).on('copy', 'body > textarea[readonly]', function(e) {
|
||||
const clipboardData = e.originalEvent.clipboardData;
|
||||
if (!clipboardData) return;
|
||||
|
||||
const text = e.target.value;
|
||||
|
||||
let json;
|
||||
try {
|
||||
json = JSON.parse(text);
|
||||
} catch (ex) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!json.text || !json.gfm) return;
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
clipboardData.setData('text/plain', json.text);
|
||||
clipboardData.setData('text/x-gfm', json.gfm);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -13,10 +13,6 @@ class Diff {
|
|||
|
||||
$diffFile.each((index, file) => new gl.ImageFile(file));
|
||||
|
||||
if (this.diffViewType() === 'parallel') {
|
||||
$('.content-wrapper .container-fluid').removeClass('container-limited');
|
||||
}
|
||||
|
||||
if (!isBound) {
|
||||
$(document)
|
||||
.on('click', '.js-unfold', this.handleClickUnfold.bind(this))
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
/* global Search */
|
||||
/* global Admin */
|
||||
/* global NamespaceSelects */
|
||||
/* global ShortcutsDashboardNavigation */
|
||||
/* global Project */
|
||||
/* global ProjectAvatar */
|
||||
/* global CompareAutocomplete */
|
||||
|
@ -378,7 +377,6 @@ const ShortcutsBlob = require('./shortcuts_blob');
|
|||
break;
|
||||
case 'dashboard':
|
||||
case 'root':
|
||||
shortcut_handler = new ShortcutsDashboardNavigation();
|
||||
new UserCallout();
|
||||
break;
|
||||
case 'groups':
|
||||
|
|
|
@ -31,12 +31,6 @@ export default Vue.component('environment-folder-view', {
|
|||
cssContainerClass: environmentsData.cssClass,
|
||||
canCreateDeployment: environmentsData.canCreateDeployment,
|
||||
canReadEnvironment: environmentsData.canReadEnvironment,
|
||||
|
||||
// svgs
|
||||
commitIconSvg: environmentsData.commitIconSvg,
|
||||
playIconSvg: environmentsData.playIconSvg,
|
||||
terminalIconSvg: environmentsData.terminalIconSvg,
|
||||
|
||||
// Pagination Properties,
|
||||
paginationInformation: {},
|
||||
pageNumber: 1,
|
||||
|
@ -163,9 +157,6 @@ export default Vue.component('environment-folder-view', {
|
|||
:environments="state.environments"
|
||||
:can-create-deployment="canCreateDeploymentParsed"
|
||||
:can-read-environment="canReadEnvironmentParsed"
|
||||
:play-icon-svg="playIconSvg"
|
||||
:terminal-icon-svg="terminalIconSvg"
|
||||
:commit-icon-svg="commitIconSvg"
|
||||
:service="service"/>
|
||||
|
||||
<table-pagination v-if="state.paginationInformation && state.paginationInformation.totalPages > 1"
|
||||
|
|
|
@ -55,6 +55,7 @@ require('./filtered_search_dropdown');
|
|||
|
||||
renderContent() {
|
||||
const dropdownData = [];
|
||||
|
||||
[].forEach.call(this.input.closest('.filtered-search-box-input-container').querySelectorAll('.dropdown-menu'), (dropdownMenu) => {
|
||||
const { icon, hint, tag, type } = dropdownMenu.dataset;
|
||||
if (icon && hint && tag) {
|
||||
|
|
|
@ -65,7 +65,6 @@ export default class Poll {
|
|||
this.makeRequest();
|
||||
}, pollInterval);
|
||||
}
|
||||
|
||||
this.options.successCallback(response);
|
||||
}
|
||||
|
||||
|
@ -76,8 +75,14 @@ export default class Poll {
|
|||
notificationCallback(true);
|
||||
|
||||
return resource[method](data)
|
||||
.then(response => this.checkConditions(response))
|
||||
.catch(error => errorCallback(error));
|
||||
.then((response) => {
|
||||
this.checkConditions(response);
|
||||
notificationCallback(false);
|
||||
})
|
||||
.catch((error) => {
|
||||
notificationCallback(false);
|
||||
errorCallback(error);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -90,6 +90,7 @@ import './flash';
|
|||
.on('click', this.clickTab);
|
||||
}
|
||||
|
||||
// Used in tests
|
||||
unbindEvents() {
|
||||
$(document)
|
||||
.off('shown.bs.tab', '.merge-request-tabs a[data-toggle="tab"]', this.tabShown)
|
||||
|
@ -99,9 +100,11 @@ import './flash';
|
|||
.off('click', this.clickTab);
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.unbindEvents();
|
||||
destroyPipelinesView() {
|
||||
if (this.commitPipelinesTable) {
|
||||
document.querySelector('#commit-pipeline-table-view')
|
||||
.removeChild(this.commitPipelinesTable.$el);
|
||||
|
||||
this.commitPipelinesTable.$destroy();
|
||||
}
|
||||
}
|
||||
|
@ -128,6 +131,7 @@ import './flash';
|
|||
this.loadCommits($target.attr('href'));
|
||||
this.expandView();
|
||||
this.resetViewContainer();
|
||||
this.destroyPipelinesView();
|
||||
} else if (this.isDiffAction(action)) {
|
||||
this.loadDiff($target.attr('href'));
|
||||
if (Breakpoints.get().getBreakpointSize() !== 'lg') {
|
||||
|
@ -136,12 +140,14 @@ import './flash';
|
|||
if (this.diffViewType() === 'parallel') {
|
||||
this.expandViewContainer();
|
||||
}
|
||||
this.destroyPipelinesView();
|
||||
} else if (action === 'pipelines') {
|
||||
this.resetViewContainer();
|
||||
this.loadPipelines();
|
||||
this.mountPipelinesView();
|
||||
} else {
|
||||
this.expandView();
|
||||
this.resetViewContainer();
|
||||
this.destroyPipelinesView();
|
||||
}
|
||||
if (this.setUrl) {
|
||||
this.setCurrentAction(action);
|
||||
|
@ -227,16 +233,12 @@ import './flash';
|
|||
});
|
||||
}
|
||||
|
||||
loadPipelines() {
|
||||
if (this.pipelinesLoaded) {
|
||||
return;
|
||||
}
|
||||
const pipelineTableViewEl = document.querySelector('#commit-pipeline-table-view');
|
||||
// Could already be mounted from the `pipelines_bundle`
|
||||
if (pipelineTableViewEl) {
|
||||
this.commitPipelinesTable = new CommitPipelinesTable().$mount(pipelineTableViewEl);
|
||||
}
|
||||
this.pipelinesLoaded = true;
|
||||
mountPipelinesView() {
|
||||
this.commitPipelinesTable = new CommitPipelinesTable().$mount();
|
||||
// $mount(el) replaces the el with the new rendered component. We need it in order to mount
|
||||
// it everytime this tab is clicked - https://vuejs.org/v2/api/#vm-mount
|
||||
document.querySelector('#commit-pipeline-table-view')
|
||||
.appendChild(this.commitPipelinesTable.$el);
|
||||
}
|
||||
|
||||
loadDiff(source) {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, quotes, prefer-arrow-callback, consistent-return, object-shorthand, no-unused-vars, one-var, one-var-declaration-per-line, no-else-return, comma-dangle, max-len */
|
||||
/* global Mousetrap */
|
||||
/* global findFileURL */
|
||||
import findAndFollowLink from './shortcuts_dashboard_navigation';
|
||||
|
||||
(function() {
|
||||
var bind = function(fn, me) { return function() { return fn.apply(me, arguments); }; };
|
||||
|
@ -14,11 +15,33 @@
|
|||
}
|
||||
Mousetrap.bind('?', this.onToggleHelp);
|
||||
Mousetrap.bind('s', Shortcuts.focusSearch);
|
||||
Mousetrap.bind('f', (function(_this) {
|
||||
return function(e) {
|
||||
return _this.focusFilter(e);
|
||||
};
|
||||
})(this));
|
||||
Mousetrap.bind('f', (e => this.focusFilter(e)));
|
||||
|
||||
const $globalDropdownMenu = $('.global-dropdown-menu');
|
||||
const $globalDropdownToggle = $('.global-dropdown-toggle');
|
||||
|
||||
$('.global-dropdown').on('hide.bs.dropdown', () => {
|
||||
$globalDropdownMenu.removeClass('shortcuts');
|
||||
});
|
||||
|
||||
Mousetrap.bind('n', () => {
|
||||
$globalDropdownMenu.toggleClass('shortcuts');
|
||||
$globalDropdownToggle.trigger('click');
|
||||
|
||||
if (!$globalDropdownMenu.is(':visible')) {
|
||||
$globalDropdownToggle.blur();
|
||||
}
|
||||
});
|
||||
|
||||
Mousetrap.bind('shift+t', () => findAndFollowLink('.shortcuts-todos'));
|
||||
Mousetrap.bind('shift+a', () => findAndFollowLink('.dashboard-shortcuts-activity'));
|
||||
Mousetrap.bind('shift+i', () => findAndFollowLink('.dashboard-shortcuts-issues'));
|
||||
Mousetrap.bind('shift+m', () => findAndFollowLink('.dashboard-shortcuts-merge_requests'));
|
||||
Mousetrap.bind('shift+p', () => findAndFollowLink('.dashboard-shortcuts-projects'));
|
||||
Mousetrap.bind('shift+g', () => findAndFollowLink('.dashboard-shortcuts-groups'));
|
||||
Mousetrap.bind('shift+l', () => findAndFollowLink('.dashboard-shortcuts-milestones'));
|
||||
Mousetrap.bind('shift+s', () => findAndFollowLink('.dashboard-shortcuts-snippets'));
|
||||
|
||||
Mousetrap.bind(['ctrl+shift+p', 'command+shift+p'], this.toggleMarkdownPreview);
|
||||
if (typeof findFileURL !== "undefined" && findFileURL !== null) {
|
||||
Mousetrap.bind('t', function() {
|
||||
|
|
|
@ -1,43 +1,12 @@
|
|||
/* eslint-disable func-names, space-before-function-paren, max-len, one-var, no-var, no-restricted-syntax, vars-on-top, no-use-before-define, no-param-reassign, new-cap, no-underscore-dangle, wrap-iife, prefer-arrow-callback, consistent-return, no-return-assign */
|
||||
/* global Mousetrap */
|
||||
/* global Shortcuts */
|
||||
/**
|
||||
* Helper function that finds the href of the fiven selector and updates the location.
|
||||
*
|
||||
* @param {String} selector
|
||||
*/
|
||||
export default (selector) => {
|
||||
const link = document.querySelector(selector).getAttribute('href');
|
||||
|
||||
require('./shortcuts');
|
||||
|
||||
(function() {
|
||||
var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||
hasProp = {}.hasOwnProperty;
|
||||
|
||||
this.ShortcutsDashboardNavigation = (function(superClass) {
|
||||
extend(ShortcutsDashboardNavigation, superClass);
|
||||
|
||||
function ShortcutsDashboardNavigation() {
|
||||
ShortcutsDashboardNavigation.__super__.constructor.call(this);
|
||||
Mousetrap.bind('g a', function() {
|
||||
return ShortcutsDashboardNavigation.findAndFollowLink('.dashboard-shortcuts-activity');
|
||||
});
|
||||
Mousetrap.bind('g i', function() {
|
||||
return ShortcutsDashboardNavigation.findAndFollowLink('.dashboard-shortcuts-issues');
|
||||
});
|
||||
Mousetrap.bind('g m', function() {
|
||||
return ShortcutsDashboardNavigation.findAndFollowLink('.dashboard-shortcuts-merge_requests');
|
||||
});
|
||||
Mousetrap.bind('g t', function() {
|
||||
return ShortcutsDashboardNavigation.findAndFollowLink('.shortcuts-todos');
|
||||
});
|
||||
Mousetrap.bind('g p', function() {
|
||||
return ShortcutsDashboardNavigation.findAndFollowLink('.dashboard-shortcuts-projects');
|
||||
});
|
||||
}
|
||||
|
||||
ShortcutsDashboardNavigation.findAndFollowLink = function(selector) {
|
||||
var link;
|
||||
link = $(selector).attr('href');
|
||||
if (link) {
|
||||
return window.location = link;
|
||||
}
|
||||
};
|
||||
|
||||
return ShortcutsDashboardNavigation;
|
||||
})(Shortcuts);
|
||||
}).call(window);
|
||||
if (link) {
|
||||
window.location = link;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* eslint-disable func-names, space-before-function-paren, max-len, no-var, one-var, no-restricted-syntax, vars-on-top, no-use-before-define, no-param-reassign, new-cap, no-underscore-dangle, wrap-iife, prefer-arrow-callback, consistent-return, no-return-assign */
|
||||
/* global Mousetrap */
|
||||
/* global Shortcuts */
|
||||
import findAndFollowLink from './shortcuts_dashboard_navigation';
|
||||
|
||||
require('./shortcuts');
|
||||
|
||||
|
@ -13,59 +14,23 @@ require('./shortcuts');
|
|||
|
||||
function ShortcutsNavigation() {
|
||||
ShortcutsNavigation.__super__.constructor.call(this);
|
||||
Mousetrap.bind('g p', function() {
|
||||
return ShortcutsNavigation.findAndFollowLink('.shortcuts-project');
|
||||
});
|
||||
Mousetrap.bind('g e', function() {
|
||||
return ShortcutsNavigation.findAndFollowLink('.shortcuts-project-activity');
|
||||
});
|
||||
Mousetrap.bind('g f', function() {
|
||||
return ShortcutsNavigation.findAndFollowLink('.shortcuts-tree');
|
||||
});
|
||||
Mousetrap.bind('g c', function() {
|
||||
return ShortcutsNavigation.findAndFollowLink('.shortcuts-commits');
|
||||
});
|
||||
Mousetrap.bind('g b', function() {
|
||||
return ShortcutsNavigation.findAndFollowLink('.shortcuts-builds');
|
||||
});
|
||||
Mousetrap.bind('g n', function() {
|
||||
return ShortcutsNavigation.findAndFollowLink('.shortcuts-network');
|
||||
});
|
||||
Mousetrap.bind('g g', function() {
|
||||
return ShortcutsNavigation.findAndFollowLink('.shortcuts-repository-charts');
|
||||
});
|
||||
Mousetrap.bind('g i', function() {
|
||||
return ShortcutsNavigation.findAndFollowLink('.shortcuts-issues');
|
||||
});
|
||||
Mousetrap.bind('g l', function() {
|
||||
ShortcutsNavigation.findAndFollowLink('.shortcuts-issue-boards');
|
||||
});
|
||||
Mousetrap.bind('g m', function() {
|
||||
return ShortcutsNavigation.findAndFollowLink('.shortcuts-merge_requests');
|
||||
});
|
||||
Mousetrap.bind('g t', function() {
|
||||
return ShortcutsNavigation.findAndFollowLink('.shortcuts-todos');
|
||||
});
|
||||
Mousetrap.bind('g w', function() {
|
||||
return ShortcutsNavigation.findAndFollowLink('.shortcuts-wiki');
|
||||
});
|
||||
Mousetrap.bind('g s', function() {
|
||||
return ShortcutsNavigation.findAndFollowLink('.shortcuts-snippets');
|
||||
});
|
||||
Mousetrap.bind('i', function() {
|
||||
return ShortcutsNavigation.findAndFollowLink('.shortcuts-new-issue');
|
||||
});
|
||||
Mousetrap.bind('g p', () => findAndFollowLink('.shortcuts-project'));
|
||||
Mousetrap.bind('g e', () => findAndFollowLink('.shortcuts-project-activity'));
|
||||
Mousetrap.bind('g f', () => findAndFollowLink('.shortcuts-tree'));
|
||||
Mousetrap.bind('g c', () => findAndFollowLink('.shortcuts-commits'));
|
||||
Mousetrap.bind('g j', () => findAndFollowLink('.shortcuts-builds'));
|
||||
Mousetrap.bind('g n', () => findAndFollowLink('.shortcuts-network'));
|
||||
Mousetrap.bind('g d', () => findAndFollowLink('.shortcuts-repository-charts'));
|
||||
Mousetrap.bind('g i', () => findAndFollowLink('.shortcuts-issues'));
|
||||
Mousetrap.bind('g b', () => findAndFollowLink('.shortcuts-issue-boards'));
|
||||
Mousetrap.bind('g m', () => findAndFollowLink('.shortcuts-merge_requests'));
|
||||
Mousetrap.bind('g t', () => findAndFollowLink('.shortcuts-todos'));
|
||||
Mousetrap.bind('g w', () => findAndFollowLink('.shortcuts-wiki'));
|
||||
Mousetrap.bind('g s', () => findAndFollowLink('.shortcuts-snippets'));
|
||||
Mousetrap.bind('i', () => findAndFollowLink('.shortcuts-new-issue'));
|
||||
this.enabledHelp.push('.hidden-shortcut.project');
|
||||
}
|
||||
|
||||
ShortcutsNavigation.findAndFollowLink = function(selector) {
|
||||
var link;
|
||||
link = $(selector).attr('href');
|
||||
if (link) {
|
||||
return window.location = link;
|
||||
}
|
||||
};
|
||||
|
||||
return ShortcutsNavigation;
|
||||
})(Shortcuts);
|
||||
}).call(window);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import Vue from 'vue';
|
||||
import Visibility from 'visibilityjs';
|
||||
import PipelinesService from './services/pipelines_service';
|
||||
import eventHub from './event_hub';
|
||||
import PipelinesTableComponent from '../vue_shared/components/pipelines_table';
|
||||
|
@ -7,6 +8,7 @@ import EmptyState from './components/empty_state';
|
|||
import ErrorState from './components/error_state';
|
||||
import NavigationTabs from './components/navigation_tabs';
|
||||
import NavigationControls from './components/nav_controls';
|
||||
import Poll from '../lib/utils/poll';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
|
@ -47,6 +49,7 @@ export default {
|
|||
pagenum: 1,
|
||||
isLoading: false,
|
||||
hasError: false,
|
||||
isMakingRequest: false,
|
||||
};
|
||||
},
|
||||
|
||||
|
@ -120,18 +123,49 @@ export default {
|
|||
tagsPath: this.tagsPath,
|
||||
};
|
||||
},
|
||||
|
||||
pageParameter() {
|
||||
return gl.utils.getParameterByName('page') || this.pagenum;
|
||||
},
|
||||
|
||||
scopeParameter() {
|
||||
return gl.utils.getParameterByName('scope') || this.apiScope;
|
||||
},
|
||||
},
|
||||
|
||||
created() {
|
||||
this.service = new PipelinesService(this.endpoint);
|
||||
|
||||
this.fetchPipelines();
|
||||
const poll = new Poll({
|
||||
resource: this.service,
|
||||
method: 'getPipelines',
|
||||
data: { page: this.pageParameter, scope: this.scopeParameter },
|
||||
successCallback: this.successCallback,
|
||||
errorCallback: this.errorCallback,
|
||||
notificationCallback: this.setIsMakingRequest,
|
||||
});
|
||||
|
||||
if (!Visibility.hidden()) {
|
||||
this.isLoading = true;
|
||||
poll.makeRequest();
|
||||
}
|
||||
|
||||
Visibility.change(() => {
|
||||
if (!Visibility.hidden()) {
|
||||
poll.restart();
|
||||
} else {
|
||||
poll.stop();
|
||||
}
|
||||
});
|
||||
|
||||
eventHub.$on('refreshPipelines', this.fetchPipelines);
|
||||
},
|
||||
|
||||
beforeUpdate() {
|
||||
if (this.state.pipelines.length && this.$children) {
|
||||
if (this.state.pipelines.length &&
|
||||
this.$children &&
|
||||
!this.isMakingRequest &&
|
||||
!this.isLoading) {
|
||||
this.store.startTimeAgoLoops.call(this, Vue);
|
||||
}
|
||||
},
|
||||
|
@ -154,27 +188,35 @@ export default {
|
|||
},
|
||||
|
||||
fetchPipelines() {
|
||||
const pageNumber = gl.utils.getParameterByName('page') || this.pagenum;
|
||||
const scope = gl.utils.getParameterByName('scope') || this.apiScope;
|
||||
if (!this.isMakingRequest) {
|
||||
this.isLoading = true;
|
||||
|
||||
this.isLoading = true;
|
||||
return this.service.getPipelines(scope, pageNumber)
|
||||
.then(resp => ({
|
||||
headers: resp.headers,
|
||||
body: resp.json(),
|
||||
}))
|
||||
.then((response) => {
|
||||
this.store.storeCount(response.body.count);
|
||||
this.store.storePipelines(response.body.pipelines);
|
||||
this.store.storePagination(response.headers);
|
||||
})
|
||||
.then(() => {
|
||||
this.isLoading = false;
|
||||
})
|
||||
.catch(() => {
|
||||
this.hasError = true;
|
||||
this.isLoading = false;
|
||||
});
|
||||
this.service.getPipelines({ scope: this.scopeParameter, page: this.pageParameter })
|
||||
.then(response => this.successCallback(response))
|
||||
.catch(() => this.errorCallback());
|
||||
}
|
||||
},
|
||||
|
||||
successCallback(resp) {
|
||||
const response = {
|
||||
headers: resp.headers,
|
||||
body: resp.json(),
|
||||
};
|
||||
|
||||
this.store.storeCount(response.body.count);
|
||||
this.store.storePipelines(response.body.pipelines);
|
||||
this.store.storePagination(response.headers);
|
||||
|
||||
this.isLoading = false;
|
||||
},
|
||||
|
||||
errorCallback() {
|
||||
this.hasError = true;
|
||||
this.isLoading = false;
|
||||
},
|
||||
|
||||
setIsMakingRequest(isMakingRequest) {
|
||||
this.isMakingRequest = isMakingRequest;
|
||||
},
|
||||
},
|
||||
|
||||
|
|
|
@ -26,7 +26,8 @@ export default class PipelinesService {
|
|||
this.pipelines = Vue.resource(endpoint);
|
||||
}
|
||||
|
||||
getPipelines(scope, page) {
|
||||
getPipelines(data = {}) {
|
||||
const { scope, page } = data;
|
||||
return this.pipelines.get({ scope, page });
|
||||
}
|
||||
|
||||
|
|
|
@ -187,6 +187,15 @@
|
|||
}
|
||||
}
|
||||
|
||||
.shortcut-mappings {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&.shortcuts .shortcut-mappings {
|
||||
display: inline-block;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
ul {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
|
|
@ -446,10 +446,8 @@
|
|||
}
|
||||
}
|
||||
|
||||
.filter-dropdown-item.droplab-item-active {
|
||||
.btn {
|
||||
@extend %filter-dropdown-item-btn-hover;
|
||||
}
|
||||
.filter-dropdown-item.droplab-item-active .btn {
|
||||
@extend %filter-dropdown-item-btn-hover;
|
||||
}
|
||||
|
||||
.filter-dropdown-loading {
|
||||
|
|
|
@ -1,15 +1,18 @@
|
|||
.timeline {
|
||||
@include basic-list;
|
||||
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
.timeline-entry {
|
||||
padding: $gl-padding $gl-btn-padding 11px;
|
||||
padding: $gl-padding $gl-btn-padding 14px;
|
||||
border-color: $white-normal;
|
||||
color: $gl-text-color;
|
||||
border-bottom: 1px solid $border-white-light;
|
||||
|
||||
.timeline-entry-inner {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
&:target {
|
||||
background: $line-target-blue;
|
||||
}
|
||||
|
|
|
@ -197,7 +197,7 @@
|
|||
|
||||
.card {
|
||||
position: relative;
|
||||
padding: 10px $gl-padding;
|
||||
padding: 11px 10px 11px $gl-padding;
|
||||
background: $white-light;
|
||||
border-radius: $border-radius-default;
|
||||
box-shadow: 0 1px 2px $issue-boards-card-shadow;
|
||||
|
@ -217,6 +217,8 @@
|
|||
}
|
||||
|
||||
.confidential-icon {
|
||||
position: relative;
|
||||
top: 1px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
|
@ -224,34 +226,43 @@
|
|||
.card-title {
|
||||
margin: 0;
|
||||
font-size: 1em;
|
||||
line-height: inherit;
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
color: $gl-text-color;
|
||||
word-wrap: break-word;
|
||||
margin-right: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
min-height: 20px;
|
||||
|
||||
.card-assignee {
|
||||
margin-left: auto;
|
||||
margin-right: 5px;
|
||||
padding-left: 10px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.card-footer {
|
||||
margin-top: 5px;
|
||||
line-height: 25px;
|
||||
margin: 0 0 5px;
|
||||
|
||||
.label {
|
||||
margin-right: 5px;
|
||||
font-size: (14px / $issue-boards-font-size) * 1em;
|
||||
}
|
||||
|
||||
.card-assignee {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
margin-top: 5px;
|
||||
margin-right: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.card-number {
|
||||
margin-right: 5px;
|
||||
font-size: 12px;
|
||||
color: $gl-text-color-secondary;
|
||||
}
|
||||
|
||||
.issue-boards-search {
|
||||
|
|
|
@ -16,6 +16,15 @@ ul.notes {
|
|||
|
||||
.timeline-icon {
|
||||
float: left;
|
||||
|
||||
svg {
|
||||
width: 18px;
|
||||
height: auto;
|
||||
fill: $gray-darkest;
|
||||
position: absolute;
|
||||
left: 30px;
|
||||
top: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.timeline-content {
|
||||
|
@ -33,117 +42,6 @@ ul.notes {
|
|||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.system-note {
|
||||
font-size: 14px;
|
||||
padding: 0;
|
||||
clear: both;
|
||||
|
||||
&.timeline-entry::after {
|
||||
clear: none;
|
||||
}
|
||||
|
||||
.system-note-message {
|
||||
display: inline;
|
||||
|
||||
&::first-letter {
|
||||
text-transform: lowercase;
|
||||
}
|
||||
|
||||
a {
|
||||
color: $gl-link-color;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
p {
|
||||
display: inline;
|
||||
margin: 0;
|
||||
|
||||
&::first-letter {
|
||||
text-transform: lowercase;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.timeline-content {
|
||||
padding: 14px 10px;
|
||||
}
|
||||
|
||||
.note-body {
|
||||
overflow: hidden;
|
||||
|
||||
.system-note-commit-list-toggler {
|
||||
color: $gl-link-color;
|
||||
display: none;
|
||||
padding: 10px 0 0;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
|
||||
&:hover {
|
||||
color: $gl-link-color;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
.note-text {
|
||||
& p:first-child {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&.system-note-commit-list {
|
||||
max-height: 70px;
|
||||
overflow: hidden;
|
||||
display: block;
|
||||
|
||||
ul {
|
||||
margin: 3px 0 3px 16px !important;
|
||||
|
||||
.gfm-commit {
|
||||
font-family: $monospace_font;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
p:first-child {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
width: 100%;
|
||||
height: 67px;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
background: linear-gradient(rgba($white-light, 0.1) -100px, $white-light 100%);
|
||||
}
|
||||
|
||||
&.hide-shade {
|
||||
max-height: 100%;
|
||||
overflow: auto;
|
||||
|
||||
&::after {
|
||||
display: none;
|
||||
background: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.timeline-icon {
|
||||
display: none;
|
||||
|
||||
.avatar {
|
||||
visibility: hidden;
|
||||
|
||||
.discussion-body & {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.discussion-body {
|
||||
padding-top: 15px;
|
||||
}
|
||||
|
@ -239,7 +137,109 @@ ul.notes {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.system-note {
|
||||
font-size: 14px;
|
||||
padding: 0;
|
||||
clear: both;
|
||||
|
||||
&.timeline-entry::after {
|
||||
clear: none;
|
||||
}
|
||||
|
||||
.system-note-message {
|
||||
display: inline;
|
||||
|
||||
&::first-letter {
|
||||
text-transform: lowercase;
|
||||
}
|
||||
|
||||
a {
|
||||
color: $gl-link-color;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
p {
|
||||
display: inline;
|
||||
margin: 0;
|
||||
|
||||
&::first-letter {
|
||||
text-transform: lowercase;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.timeline-content {
|
||||
padding: 14px 10px;
|
||||
}
|
||||
|
||||
.note-header {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.note-body {
|
||||
overflow: hidden;
|
||||
|
||||
.system-note-commit-list-toggler {
|
||||
color: $gl-link-color;
|
||||
display: none;
|
||||
padding: 10px 0 0;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
|
||||
&:hover {
|
||||
color: $gl-link-color;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
.note-text {
|
||||
& p:first-child {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&.system-note-commit-list {
|
||||
max-height: 70px;
|
||||
overflow: hidden;
|
||||
display: block;
|
||||
|
||||
ul {
|
||||
margin: 3px 0 3px 16px !important;
|
||||
|
||||
.gfm-commit {
|
||||
font-family: $monospace_font;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
p:first-child {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
width: 100%;
|
||||
height: 67px;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
background: linear-gradient(rgba($white-light, 0.1) -100px, $white-light 100%);
|
||||
}
|
||||
|
||||
&.hide-shade {
|
||||
max-height: 100%;
|
||||
overflow: auto;
|
||||
|
||||
&::after {
|
||||
display: none;
|
||||
background: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -36,6 +36,8 @@ class Projects::CommitController < Projects::ApplicationController
|
|||
respond_to do |format|
|
||||
format.html
|
||||
format.json do
|
||||
Gitlab::PollingInterval.set_header(response, interval: 10_000)
|
||||
|
||||
render json: PipelineSerializer
|
||||
.new(project: @project, user: @current_user)
|
||||
.represent(@pipelines)
|
||||
|
|
|
@ -233,6 +233,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController
|
|||
end
|
||||
|
||||
format.json do
|
||||
Gitlab::PollingInterval.set_header(response, interval: 10_000)
|
||||
|
||||
render json: PipelineSerializer
|
||||
.new(project: @project, user: @current_user)
|
||||
.represent(@pipelines)
|
||||
|
@ -246,6 +248,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController
|
|||
format.json do
|
||||
define_pipelines_vars
|
||||
|
||||
Gitlab::PollingInterval.set_header(response, interval: 10_000)
|
||||
|
||||
render json: {
|
||||
pipelines: PipelineSerializer
|
||||
.new(project: @project, user: @current_user)
|
||||
|
|
|
@ -29,6 +29,8 @@ class Projects::PipelinesController < Projects::ApplicationController
|
|||
respond_to do |format|
|
||||
format.html
|
||||
format.json do
|
||||
Gitlab::PollingInterval.set_header(response, interval: 10_000)
|
||||
|
||||
render json: {
|
||||
pipelines: PipelineSerializer
|
||||
.new(project: @project, user: @current_user)
|
||||
|
@ -114,7 +116,7 @@ class Projects::PipelinesController < Projects::ApplicationController
|
|||
end
|
||||
|
||||
def pipeline
|
||||
@pipeline ||= project.pipelines.find_by!(id: params[:id])
|
||||
@pipeline ||= project.pipelines.find_by!(id: params[:id]).present(current_user: current_user)
|
||||
end
|
||||
|
||||
def commit
|
||||
|
|
|
@ -23,7 +23,7 @@ class Projects::PipelinesSettingsController < Projects::ApplicationController
|
|||
def update_params
|
||||
params.require(:project).permit(
|
||||
:runners_token, :builds_enabled, :build_allow_git_fetch, :build_timeout_in_minutes, :build_coverage_regex,
|
||||
:public_builds
|
||||
:public_builds, :auto_cancel_pending_pipelines
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -102,7 +102,7 @@ module BlobHelper
|
|||
if Gitlab::MarkupHelper.previewable?(filename)
|
||||
'Preview'
|
||||
else
|
||||
'Preview Changes'
|
||||
'Preview changes'
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -210,13 +210,13 @@ module BlobHelper
|
|||
end
|
||||
|
||||
def copy_file_path_button(file_path)
|
||||
clipboard_button(clipboard_text: file_path, class: 'btn-clipboard btn-transparent prepend-left-5', title: 'Copy file path to clipboard')
|
||||
clipboard_button(text: file_path, gfm: "`#{file_path}`", class: 'btn-clipboard btn-transparent prepend-left-5', title: 'Copy file path to clipboard')
|
||||
end
|
||||
|
||||
def copy_blob_content_button(blob)
|
||||
return if markup?(blob.name)
|
||||
|
||||
clipboard_button(clipboard_target: ".blob-content[data-blob-id='#{blob.id}']", class: "btn btn-sm", title: "Copy content to clipboard")
|
||||
clipboard_button(target: ".blob-content[data-blob-id='#{blob.id}']", class: "btn btn-sm", title: "Copy content to clipboard")
|
||||
end
|
||||
|
||||
def open_raw_file_button(path)
|
||||
|
|
|
@ -1,23 +1,42 @@
|
|||
module ButtonHelper
|
||||
# Output a "Copy to Clipboard" button
|
||||
#
|
||||
# data - Data attributes passed to `content_tag`
|
||||
# data - Data attributes passed to `content_tag` (default: {}):
|
||||
# :text - Text to copy (optional)
|
||||
# :gfm - GitLab Flavored Markdown to copy, if different from `text` (optional)
|
||||
# :target - Selector for target element to copy from (optional)
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# # Define the clipboard's text
|
||||
# clipboard_button(clipboard_text: "Foo")
|
||||
# clipboard_button(text: "Foo")
|
||||
# # => "<button class='...' data-clipboard-text='Foo'>...</button>"
|
||||
#
|
||||
# # Define the target element
|
||||
# clipboard_button(clipboard_target: "div#foo")
|
||||
# clipboard_button(target: "div#foo")
|
||||
# # => "<button class='...' data-clipboard-target='div#foo'>...</button>"
|
||||
#
|
||||
# See http://clipboardjs.com/#usage
|
||||
def clipboard_button(data = {})
|
||||
css_class = data[:class] || 'btn-clipboard btn-transparent'
|
||||
title = data[:title] || 'Copy to clipboard'
|
||||
|
||||
# This supports code in app/assets/javascripts/copy_to_clipboard.js that
|
||||
# works around ClipboardJS limitations to allow the context-specific copy/pasting of plain text or GFM.
|
||||
if text = data.delete(:text)
|
||||
data[:clipboard_text] =
|
||||
if gfm = data.delete(:gfm)
|
||||
{ text: text, gfm: gfm }
|
||||
else
|
||||
text
|
||||
end
|
||||
end
|
||||
|
||||
target = data.delete(:target)
|
||||
data[:clipboard_target] = target if target
|
||||
|
||||
data = { toggle: 'tooltip', placement: 'bottom', container: 'body' }.merge(data)
|
||||
|
||||
content_tag :button,
|
||||
icon('clipboard', 'aria-hidden': 'true'),
|
||||
class: "btn #{css_class}",
|
||||
|
|
26
app/helpers/system_note_helper.rb
Normal file
26
app/helpers/system_note_helper.rb
Normal file
|
@ -0,0 +1,26 @@
|
|||
module SystemNoteHelper
|
||||
ICON_NAMES_BY_ACTION = {
|
||||
'commit' => 'icon_commit',
|
||||
'merge' => 'icon_merge',
|
||||
'merged' => 'icon_merged',
|
||||
'opened' => 'icon_status_open',
|
||||
'closed' => 'icon_status_closed',
|
||||
'time_tracking' => 'icon_stopwatch',
|
||||
'assignee' => 'icon_user',
|
||||
'title' => 'icon_pencil',
|
||||
'task' => 'icon_check_square_o',
|
||||
'label' => 'icon_tags',
|
||||
'cross_reference' => 'icon_random',
|
||||
'branch' => 'icon_code_fork',
|
||||
'confidential' => 'icon_eye_slash',
|
||||
'visible' => 'icon_eye',
|
||||
'milestone' => 'icon_clock_o',
|
||||
'discussion' => 'icon_comment_o',
|
||||
'moved' => 'icon_arrow_circle_o_right'
|
||||
}.freeze
|
||||
|
||||
def icon_for_system_note(note)
|
||||
icon_name = ICON_NAMES_BY_ACTION[note.system_note_metadata&.action]
|
||||
custom_icon(icon_name) if icon_name
|
||||
end
|
||||
end
|
|
@ -103,18 +103,13 @@ module Ci
|
|||
end
|
||||
|
||||
def playable?
|
||||
project.builds_enabled? && has_commands? &&
|
||||
action? && manual?
|
||||
action? && manual?
|
||||
end
|
||||
|
||||
def action?
|
||||
self.when == 'manual'
|
||||
end
|
||||
|
||||
def has_commands?
|
||||
commands.present?
|
||||
end
|
||||
|
||||
def play(current_user)
|
||||
# Try to queue a current build
|
||||
if self.enqueue
|
||||
|
@ -131,8 +126,7 @@ module Ci
|
|||
end
|
||||
|
||||
def retryable?
|
||||
project.builds_enabled? && has_commands? &&
|
||||
(success? || failed? || canceled?)
|
||||
success? || failed? || canceled?
|
||||
end
|
||||
|
||||
def retried?
|
||||
|
|
|
@ -4,14 +4,25 @@ module Ci
|
|||
include HasStatus
|
||||
include Importable
|
||||
include AfterCommitQueue
|
||||
include Presentable
|
||||
|
||||
belongs_to :project
|
||||
belongs_to :user
|
||||
belongs_to :auto_canceled_by, class_name: 'Ci::Pipeline'
|
||||
|
||||
has_many :auto_canceled_pipelines, class_name: 'Ci::Pipeline', foreign_key: 'auto_canceled_by_id'
|
||||
has_many :auto_canceled_jobs, class_name: 'CommitStatus', foreign_key: 'auto_canceled_by_id'
|
||||
|
||||
has_many :statuses, class_name: 'CommitStatus', foreign_key: :commit_id
|
||||
has_many :builds, foreign_key: :commit_id
|
||||
has_many :trigger_requests, dependent: :destroy, foreign_key: :commit_id
|
||||
|
||||
has_many :pending_builds, -> { pending }, foreign_key: :commit_id, class_name: 'Ci::Build'
|
||||
has_many :retryable_builds, -> { latest.failed_or_canceled }, foreign_key: :commit_id, class_name: 'Ci::Build'
|
||||
has_many :cancelable_statuses, -> { cancelable }, foreign_key: :commit_id, class_name: 'CommitStatus'
|
||||
has_many :manual_actions, -> { latest.manual_actions }, foreign_key: :commit_id, class_name: 'Ci::Build'
|
||||
has_many :artifacts, -> { latest.with_artifacts_not_expired }, foreign_key: :commit_id, class_name: 'Ci::Build'
|
||||
|
||||
delegate :id, to: :project, prefix: true
|
||||
|
||||
validates :sha, presence: { unless: :importing? }
|
||||
|
@ -65,6 +76,10 @@ module Ci
|
|||
pipeline.update_duration
|
||||
end
|
||||
|
||||
before_transition canceled: any - [:canceled] do |pipeline|
|
||||
pipeline.auto_canceled_by = nil
|
||||
end
|
||||
|
||||
after_transition [:created, :pending] => :running do |pipeline|
|
||||
pipeline.run_after_commit { PipelineMetricsWorker.perform_async(id) }
|
||||
end
|
||||
|
@ -82,6 +97,8 @@ module Ci
|
|||
|
||||
pipeline.run_after_commit do
|
||||
PipelineHooksWorker.perform_async(id)
|
||||
Ci::ExpirePipelineCacheService.new(project, nil)
|
||||
.execute(pipeline)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -160,10 +177,6 @@ module Ci
|
|||
end
|
||||
end
|
||||
|
||||
def artifacts
|
||||
builds.latest.with_artifacts_not_expired.includes(project: [:namespace])
|
||||
end
|
||||
|
||||
def valid_commit_sha
|
||||
if self.sha == Gitlab::Git::BLANK_SHA
|
||||
self.errors.add(:sha, " cant be 00000000 (branch removal)")
|
||||
|
@ -200,27 +213,37 @@ module Ci
|
|||
!tag?
|
||||
end
|
||||
|
||||
def manual_actions
|
||||
builds.latest.manual_actions.includes(project: [:namespace])
|
||||
end
|
||||
|
||||
def stuck?
|
||||
builds.pending.includes(:project).any?(&:stuck?)
|
||||
pending_builds.any?(&:stuck?)
|
||||
end
|
||||
|
||||
def retryable?
|
||||
builds.latest.failed_or_canceled.any?(&:retryable?)
|
||||
retryable_builds.any?
|
||||
end
|
||||
|
||||
def cancelable?
|
||||
statuses.cancelable.any?
|
||||
cancelable_statuses.any?
|
||||
end
|
||||
|
||||
def auto_canceled?
|
||||
canceled? && auto_canceled_by_id?
|
||||
end
|
||||
|
||||
def cancel_running
|
||||
Gitlab::OptimisticLocking.retry_lock(
|
||||
statuses.cancelable) do |cancelable|
|
||||
cancelable.find_each(&:cancel)
|
||||
Gitlab::OptimisticLocking.retry_lock(cancelable_statuses) do |cancelable|
|
||||
cancelable.find_each do |job|
|
||||
yield(job) if block_given?
|
||||
job.cancel
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def auto_cancel_running(pipeline)
|
||||
update(auto_canceled_by: pipeline)
|
||||
|
||||
cancel_running do |job|
|
||||
job.auto_canceled_by = pipeline
|
||||
end
|
||||
end
|
||||
|
||||
def retry_failed(current_user)
|
||||
|
|
|
@ -7,6 +7,7 @@ class CommitStatus < ActiveRecord::Base
|
|||
|
||||
belongs_to :project
|
||||
belongs_to :pipeline, class_name: 'Ci::Pipeline', foreign_key: :commit_id
|
||||
belongs_to :auto_canceled_by, class_name: 'Ci::Pipeline'
|
||||
belongs_to :user
|
||||
|
||||
delegate :commit, to: :pipeline
|
||||
|
@ -137,6 +138,10 @@ class CommitStatus < ActiveRecord::Base
|
|||
false
|
||||
end
|
||||
|
||||
def auto_canceled?
|
||||
canceled? && auto_canceled_by_id?
|
||||
end
|
||||
|
||||
# Added in 9.0 to keep backward compatibility for projects exported in 8.17
|
||||
# and prior.
|
||||
def gl_project_id
|
||||
|
|
|
@ -76,6 +76,7 @@ module HasStatus
|
|||
scope :canceled, -> { where(status: 'canceled') }
|
||||
scope :skipped, -> { where(status: 'skipped') }
|
||||
scope :manual, -> { where(status: 'manual') }
|
||||
scope :created_or_pending, -> { where(status: [:created, :pending]) }
|
||||
scope :running_or_pending, -> { where(status: [:running, :pending]) }
|
||||
scope :finished, -> { where(status: [:success, :failed, :canceled]) }
|
||||
scope :failed_or_canceled, -> { where(status: [:failed, :canceled]) }
|
||||
|
|
|
@ -172,6 +172,8 @@ class Project < ActiveRecord::Base
|
|||
has_many :environments, dependent: :destroy
|
||||
has_many :deployments, dependent: :destroy
|
||||
|
||||
has_many :active_runners, -> { active }, through: :runner_projects, source: :runner, class_name: 'Ci::Runner'
|
||||
|
||||
accepts_nested_attributes_for :variables, allow_destroy: true
|
||||
accepts_nested_attributes_for :project_feature
|
||||
|
||||
|
@ -260,6 +262,8 @@ class Project < ActiveRecord::Base
|
|||
scope :with_builds_enabled, -> { with_feature_enabled(:builds) }
|
||||
scope :with_issues_enabled, -> { with_feature_enabled(:issues) }
|
||||
|
||||
enum auto_cancel_pending_pipelines: { disabled: 0, enabled: 1 }
|
||||
|
||||
# project features may be "disabled", "internal" or "enabled". If "internal",
|
||||
# they are only available to team members. This scope returns projects where
|
||||
# the feature is either enabled, or internal with permission for the user.
|
||||
|
@ -1085,15 +1089,15 @@ class Project < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def shared_runners
|
||||
shared_runners_available? ? Ci::Runner.shared : Ci::Runner.none
|
||||
@shared_runners ||= shared_runners_available? ? Ci::Runner.shared : Ci::Runner.none
|
||||
end
|
||||
|
||||
def active_shared_runners
|
||||
@active_shared_runners ||= shared_runners.active
|
||||
end
|
||||
|
||||
def any_runners?(&block)
|
||||
if runners.active.any?(&block)
|
||||
return true
|
||||
end
|
||||
|
||||
shared_runners.active.any?(&block)
|
||||
active_runners.any?(&block) || active_shared_runners.any?(&block)
|
||||
end
|
||||
|
||||
def valid_runners_token?(token)
|
||||
|
|
|
@ -11,5 +11,11 @@ module Ci
|
|||
def erased_by_name
|
||||
erased_by.name if erased_by_user?
|
||||
end
|
||||
|
||||
def status_title
|
||||
if auto_canceled?
|
||||
"Job is redundant and is auto-canceled by Pipeline ##{auto_canceled_by_id}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
11
app/presenters/ci/pipeline_presenter.rb
Normal file
11
app/presenters/ci/pipeline_presenter.rb
Normal file
|
@ -0,0 +1,11 @@
|
|||
module Ci
|
||||
class PipelinePresenter < Gitlab::View::Presenter::Delegated
|
||||
presents :pipeline
|
||||
|
||||
def status_title
|
||||
if auto_canceled?
|
||||
"Pipeline is redundant and is auto-canceled by Pipeline ##{auto_canceled_by_id}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -69,13 +69,13 @@ class PipelineEntity < Grape::Entity
|
|||
alias_method :pipeline, :object
|
||||
|
||||
def can_retry?
|
||||
pipeline.retryable? &&
|
||||
can?(request.user, :update_pipeline, pipeline)
|
||||
can?(request.user, :update_pipeline, pipeline) &&
|
||||
pipeline.retryable?
|
||||
end
|
||||
|
||||
def can_cancel?
|
||||
pipeline.cancelable? &&
|
||||
can?(request.user, :update_pipeline, pipeline)
|
||||
can?(request.user, :update_pipeline, pipeline) &&
|
||||
pipeline.cancelable?
|
||||
end
|
||||
|
||||
def detailed_status
|
||||
|
|
|
@ -13,7 +13,15 @@ class PipelineSerializer < BaseSerializer
|
|||
|
||||
def represent(resource, opts = {})
|
||||
if resource.is_a?(ActiveRecord::Relation)
|
||||
resource = resource.includes(project: :namespace)
|
||||
resource = resource.preload([
|
||||
:retryable_builds,
|
||||
:cancelable_statuses,
|
||||
:trigger_requests,
|
||||
:project,
|
||||
{ pending_builds: :project },
|
||||
{ manual_actions: :project },
|
||||
{ artifacts: :project }
|
||||
])
|
||||
end
|
||||
|
||||
if paginated?
|
||||
|
|
|
@ -53,6 +53,8 @@ module Ci
|
|||
.execute(pipeline)
|
||||
end
|
||||
|
||||
cancel_pending_pipelines if project.auto_cancel_pending_pipelines?
|
||||
|
||||
pipeline.tap(&:process!)
|
||||
end
|
||||
|
||||
|
@ -63,6 +65,22 @@ module Ci
|
|||
pipeline.git_commit_message =~ /\[(ci[ _-]skip|skip[ _-]ci)\]/i
|
||||
end
|
||||
|
||||
def cancel_pending_pipelines
|
||||
Gitlab::OptimisticLocking.retry_lock(auto_cancelable_pipelines) do |cancelables|
|
||||
cancelables.find_each do |cancelable|
|
||||
cancelable.auto_cancel_running(pipeline)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def auto_cancelable_pipelines
|
||||
project.pipelines
|
||||
.where(ref: pipeline.ref)
|
||||
.where.not(id: pipeline.id)
|
||||
.where.not(sha: project.repository.sha_from_ref(pipeline.ref))
|
||||
.created_or_pending
|
||||
end
|
||||
|
||||
def commit
|
||||
@commit ||= project.commit(origin_sha || origin_ref)
|
||||
end
|
||||
|
|
49
app/services/ci/expire_pipeline_cache_service.rb
Normal file
49
app/services/ci/expire_pipeline_cache_service.rb
Normal file
|
@ -0,0 +1,49 @@
|
|||
module Ci
|
||||
class ExpirePipelineCacheService < BaseService
|
||||
attr_reader :pipeline
|
||||
|
||||
def execute(pipeline)
|
||||
@pipeline = pipeline
|
||||
store = Gitlab::EtagCaching::Store.new
|
||||
|
||||
store.touch(project_pipelines_path)
|
||||
store.touch(commit_pipelines_path) if pipeline.commit
|
||||
store.touch(new_merge_request_pipelines_path)
|
||||
merge_requests_pipelines_paths.each { |path| store.touch(path) }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def project_pipelines_path
|
||||
Gitlab::Routing.url_helpers.namespace_project_pipelines_path(
|
||||
project.namespace,
|
||||
project,
|
||||
format: :json)
|
||||
end
|
||||
|
||||
def commit_pipelines_path
|
||||
Gitlab::Routing.url_helpers.pipelines_namespace_project_commit_path(
|
||||
project.namespace,
|
||||
project,
|
||||
pipeline.commit.id,
|
||||
format: :json)
|
||||
end
|
||||
|
||||
def new_merge_request_pipelines_path
|
||||
Gitlab::Routing.url_helpers.new_namespace_project_merge_request_path(
|
||||
project.namespace,
|
||||
project,
|
||||
format: :json)
|
||||
end
|
||||
|
||||
def merge_requests_pipelines_paths
|
||||
pipeline.merge_requests.collect do |merge_request|
|
||||
Gitlab::Routing.url_helpers.pipelines_namespace_project_merge_request_path(
|
||||
project.namespace,
|
||||
project,
|
||||
merge_request,
|
||||
format: :json)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -7,9 +7,7 @@ module Ci
|
|||
raise Gitlab::Access::AccessDeniedError
|
||||
end
|
||||
|
||||
pipeline.builds.latest.failed_or_canceled.find_each do |build|
|
||||
next unless build.retryable?
|
||||
|
||||
pipeline.retryable_builds.find_each do |build|
|
||||
Ci::RetryBuildService.new(project, current_user)
|
||||
.reprocess(build)
|
||||
end
|
||||
|
|
|
@ -30,5 +30,5 @@
|
|||
= link_to 'Block user', block_admin_user_path(user), data: {confirm: 'USER WILL BE BLOCKED! Are you sure?'}, method: :put, class: "btn btn-sm btn-block"
|
||||
- else
|
||||
.btn.btn-sm.disabled.btn-block
|
||||
Already Blocked
|
||||
Already blocked
|
||||
= link_to 'Remove report', [:admin, abuse_report], remote: true, method: :delete, class: "btn btn-sm btn-block btn-close js-remove-tr"
|
||||
|
|
|
@ -148,7 +148,7 @@
|
|||
Sign-in enabled
|
||||
- if omniauth_enabled? && button_based_providers.any?
|
||||
.form-group
|
||||
= f.label :enabled_oauth_sign_in_sources, 'Enabled OAuth Sign-In sources', class: 'control-label col-sm-2'
|
||||
= f.label :enabled_oauth_sign_in_sources, 'Enabled OAuth sign-in sources', class: 'control-label col-sm-2'
|
||||
.col-sm-10
|
||||
.btn-group{ data: { toggle: 'buttons' } }
|
||||
- oauth_providers_checkboxes.each do |source|
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
%p.light
|
||||
System OAuth applications don't belong to any user and can only be managed by admins
|
||||
%hr
|
||||
%p= link_to 'New Application', new_admin_application_path, class: 'btn btn-success'
|
||||
%p= link_to 'New application', new_admin_application_path, class: 'btn btn-success'
|
||||
%table.table.table-striped
|
||||
%thead
|
||||
%tr
|
||||
|
|
|
@ -125,7 +125,7 @@
|
|||
= link_to admin_projects_path do
|
||||
%h1= number_with_delimiter(Project.cached_count)
|
||||
%hr
|
||||
= link_to('New Project', new_project_path, class: "btn btn-new")
|
||||
= link_to('New project', new_project_path, class: "btn btn-new")
|
||||
.col-sm-4
|
||||
.light-well.well-centered
|
||||
%h4 Users
|
||||
|
@ -133,7 +133,7 @@
|
|||
= link_to admin_users_path do
|
||||
%h1= number_with_delimiter(User.count)
|
||||
%hr
|
||||
= link_to 'New User', new_admin_user_path, class: "btn btn-new"
|
||||
= link_to 'New user', new_admin_user_path, class: "btn btn-new"
|
||||
.col-sm-4
|
||||
.light-well.well-centered
|
||||
%h4 Groups
|
||||
|
@ -141,7 +141,7 @@
|
|||
= link_to admin_groups_path do
|
||||
%h1= number_with_delimiter(Group.count)
|
||||
%hr
|
||||
= link_to 'New Group', new_admin_group_path, class: "btn btn-new"
|
||||
= link_to 'New group', new_admin_group_path, class: "btn btn-new"
|
||||
|
||||
.row.prepend-top-10
|
||||
.col-md-4
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
%h3.page-title.deploy-keys-title
|
||||
Public deploy keys (#{@deploy_keys.count})
|
||||
.pull-right
|
||||
= link_to 'New Deploy Key', new_admin_deploy_key_path, class: 'btn btn-new btn-sm btn-inverted'
|
||||
= link_to 'New deploy key', new_admin_deploy_key_path, class: 'btn btn-new btn-sm btn-inverted'
|
||||
|
||||
- if @deploy_keys.any?
|
||||
.table-holder.deploy-keys-list
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
= link_to admin_groups_path(sort: sort_value_largest_group, name: project_name) do
|
||||
= sort_title_largest_group
|
||||
= link_to new_admin_group_path, class: "btn btn-new" do
|
||||
New Group
|
||||
New group
|
||||
%ul.content-list
|
||||
= render @groups
|
||||
|
||||
|
|
|
@ -116,7 +116,7 @@
|
|||
group members
|
||||
%span.badge= @group.members.size
|
||||
.pull-right
|
||||
= link_to icon('pencil-square-o', text: 'Manage Access'), polymorphic_url([@group, :members]), class: "btn btn-xs"
|
||||
= link_to icon('pencil-square-o', text: 'Manage access'), polymorphic_url([@group, :members]), class: "btn btn-xs"
|
||||
%ul.well-list.group-users-list.content-list
|
||||
= render partial: 'shared/members/member', collection: @members, as: :member, locals: { show_controls: false }
|
||||
.panel-footer
|
||||
|
|
|
@ -51,7 +51,7 @@
|
|||
= f.check_box :enable_ssl_verification
|
||||
%strong Enable SSL verification
|
||||
.form-actions
|
||||
= f.submit "Add System Hook", class: "btn btn-create"
|
||||
= f.submit "Add system hook", class: "btn btn-create"
|
||||
%hr
|
||||
|
||||
- if @hooks.any?
|
||||
|
@ -62,7 +62,7 @@
|
|||
- @hooks.each do |hook|
|
||||
%li
|
||||
.controls
|
||||
= link_to 'Test Hook', admin_hook_test_path(hook), class: "btn btn-sm"
|
||||
= link_to 'Test hook', admin_hook_test_path(hook), class: "btn btn-sm"
|
||||
= link_to 'Remove', admin_hook_path(hook), data: { confirm: 'Are you sure?' }, method: :delete, class: "btn btn-remove btn-sm"
|
||||
.monospace= hook.url
|
||||
%div
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
- page_title "Identities", @user.name, "Users"
|
||||
= render 'admin/users/head'
|
||||
|
||||
= link_to 'New Identity', new_admin_user_identity_path, class: 'pull-right btn btn-new'
|
||||
= link_to 'New identity', new_admin_user_identity_path, class: 'pull-right btn btn-new'
|
||||
- if @identities.present?
|
||||
.table-holder
|
||||
%table.table
|
||||
|
|
|
@ -159,7 +159,7 @@
|
|||
%span.badge= @group_members.size
|
||||
.pull-right
|
||||
= link_to admin_group_path(@group), class: 'btn btn-xs' do
|
||||
= icon('pencil-square-o', text: 'Manage Access')
|
||||
= icon('pencil-square-o', text: 'Manage access')
|
||||
%ul.well-list.content-list
|
||||
= render partial: 'shared/members/member', collection: @group_members, as: :member, locals: { show_controls: false }
|
||||
.panel-footer
|
||||
|
@ -173,7 +173,7 @@
|
|||
project members
|
||||
%span.badge= @project.users.size
|
||||
.pull-right
|
||||
= link_to icon('pencil-square-o', text: 'Manage Access'), polymorphic_url([@project, :members]), class: "btn btn-xs"
|
||||
= link_to icon('pencil-square-o', text: 'Manage access'), polymorphic_url([@project, :members]), class: "btn btn-xs"
|
||||
%ul.well-list.project_members.content-list
|
||||
= render partial: 'shared/members/member', collection: @project_members, as: :member, locals: { show_controls: false }
|
||||
.panel-footer
|
||||
|
|
|
@ -35,5 +35,5 @@
|
|||
= link_to 'Block user', block_admin_user_path(user), data: {confirm: 'USER WILL BE BLOCKED! Are you sure?'}, method: :put, class: "btn btn-xs"
|
||||
- else
|
||||
.btn.btn-xs.disabled
|
||||
Already Blocked
|
||||
Already blocked
|
||||
= link_to 'Remove log', [:admin, spam_log], remote: true, method: :delete, class: "btn btn-xs btn-close js-remove-tr"
|
||||
|
|
|
@ -37,6 +37,6 @@
|
|||
- if user.can_be_removed? && can?(current_user, :destroy_user, @user)
|
||||
%li.divider
|
||||
%li
|
||||
= link_to 'Delete User', [:admin, user], data: { confirm: "USER #{user.name} WILL BE REMOVED! All issues, merge requests and groups linked to this user will also be removed! Consider cancelling this deletion and blocking the user instead. Are you sure?" },
|
||||
= link_to 'Delete user', [:admin, user], data: { confirm: "USER #{user.name} WILL BE REMOVED! All issues, merge requests and groups linked to this user will also be removed! Consider cancelling this deletion and blocking the user instead. Are you sure?" },
|
||||
class: 'btn btn-remove btn-block',
|
||||
method: :delete
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
= sort_title_recently_updated
|
||||
= link_to admin_users_path(sort: sort_value_oldest_updated, filter: params[:filter]) do
|
||||
= sort_title_oldest_updated
|
||||
= link_to 'New User', new_admin_user_path, class: 'btn btn-new btn-search'
|
||||
= link_to 'New user', new_admin_user_path, class: 'btn btn-new btn-search'
|
||||
|
||||
.nav-block
|
||||
%ul.nav-links.wide.scrolling-tabs.white.scrolling-tabs
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
- status = local_assigns.fetch(:status)
|
||||
- link = local_assigns.fetch(:link, true)
|
||||
- css_classes = "ci-status ci-#{status.group}"
|
||||
- link = local_assigns.fetch(:link, true)
|
||||
- title = local_assigns.fetch(:title, nil)
|
||||
- css_classes = "ci-status ci-#{status.group} #{'has-tooltip' if title.present?}"
|
||||
|
||||
- if link && status.has_details?
|
||||
= link_to status.details_path, class: css_classes do
|
||||
= link_to status.details_path, class: css_classes, title: title do
|
||||
= custom_icon(status.icon)
|
||||
= status.text
|
||||
- else
|
||||
%span{ class: css_classes }
|
||||
%span{ class: css_classes, title: title }
|
||||
= custom_icon(status.icon)
|
||||
= status.text
|
||||
|
|
|
@ -11,4 +11,4 @@
|
|||
= render 'shared/groups/dropdown'
|
||||
- if current_user.can_create_group?
|
||||
= link_to new_group_path, class: "btn btn-new" do
|
||||
New Group
|
||||
New group
|
||||
|
|
|
@ -19,4 +19,4 @@
|
|||
= render 'shared/projects/dropdown'
|
||||
- if current_user.can_create_project?
|
||||
= link_to new_project_path, class: 'btn btn-new' do
|
||||
New Project
|
||||
New project
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
.nav-controls
|
||||
= link_to params.merge(rss_url_options), class: 'btn has-tooltip', title: 'Subscribe' do
|
||||
= icon('rss')
|
||||
= render 'shared/new_project_item_select', path: 'issues/new', label: "New Issue"
|
||||
= render 'shared/new_project_item_select', path: 'issues/new', label: "New issue"
|
||||
|
||||
= render 'shared/issuable/filter', type: :issues
|
||||
= render 'shared/issues'
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
.top-area
|
||||
= render 'shared/issuable/nav', type: :merge_requests
|
||||
.nav-controls
|
||||
= render 'shared/new_project_item_select', path: 'merge_requests/new', label: "New Merge Request"
|
||||
= render 'shared/new_project_item_select', path: 'merge_requests/new', label: "New merge request"
|
||||
|
||||
= render 'shared/issuable/filter', type: :merge_requests
|
||||
= render 'shared/merge_requests'
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
= render 'shared/milestones_filter', counts: @milestone_states
|
||||
|
||||
.nav-controls
|
||||
= render 'shared/new_project_item_select', path: 'milestones/new', label: 'New Milestone', include_groups: true
|
||||
= render 'shared/new_project_item_select', path: 'milestones/new', label: 'New milestone', include_groups: true
|
||||
|
||||
.milestones
|
||||
%ul.content-list
|
||||
|
|
|
@ -10,5 +10,5 @@
|
|||
#{time_ago_with_tooltip(event.created_at)}
|
||||
|
||||
.pull-right
|
||||
= link_to new_mr_path_from_push_event(event), title: "New Merge Request", class: "btn btn-info btn-sm" do
|
||||
Create Merge Request
|
||||
= link_to new_mr_path_from_push_event(event), title: "New merge request", class: "btn btn-info btn-sm" do
|
||||
Create merge request
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
= custom_icon("icon_status_closed")
|
||||
- else
|
||||
.profile-icon.fork-icon
|
||||
= custom_icon("code_fork")
|
||||
= custom_icon("icon_code_fork")
|
||||
|
||||
.event-title
|
||||
%span{ class: event.action_name }
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
.profile-icon
|
||||
= custom_icon("comment_o")
|
||||
= custom_icon("icon_comment_o")
|
||||
|
||||
.event-title
|
||||
= event.action_name
|
||||
|
|
|
@ -51,4 +51,4 @@
|
|||
%strong Removed group can not be restored!
|
||||
|
||||
.form-actions
|
||||
= link_to 'Remove Group', @group, data: {confirm: 'Removed group can not be restored! Are you sure?'}, method: :delete, class: "btn btn-remove"
|
||||
= link_to 'Remove group', @group, data: {confirm: 'Removed group can not be restored! Are you sure?'}, method: :delete, class: "btn btn-remove"
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
= icon('rss')
|
||||
%span.icon-label
|
||||
Subscribe
|
||||
= render 'shared/new_project_item_select', path: 'issues/new', label: "New Issue"
|
||||
= render 'shared/new_project_item_select', path: 'issues/new', label: "New issue"
|
||||
|
||||
= render 'shared/issuable/filter', type: :issues
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
.nav-controls
|
||||
- if can?(current_user, :admin_milestones, @group)
|
||||
= link_to new_group_milestone_path(@group), class: "btn btn-new" do
|
||||
New Milestone
|
||||
New milestone
|
||||
|
||||
.row-content-block
|
||||
Only milestones from
|
||||
|
|
|
@ -39,5 +39,5 @@
|
|||
= render "shared/milestones/form_dates", f: f
|
||||
|
||||
.form-actions
|
||||
= f.submit 'Create Milestone', class: "btn-create btn"
|
||||
= f.submit 'Create milestone', class: "btn-create btn"
|
||||
= link_to "Cancel", group_milestones_path(@group), class: "btn btn-cancel"
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
- if can? current_user, :admin_group, @group
|
||||
.controls
|
||||
= link_to new_project_path(namespace_id: @group.id), class: "btn btn-sm btn-success" do
|
||||
New Project
|
||||
New project
|
||||
%ul.well-list
|
||||
- @projects.each do |project|
|
||||
%li
|
||||
|
|
|
@ -15,6 +15,10 @@
|
|||
%tr
|
||||
%th
|
||||
%th Global Shortcuts
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key n
|
||||
%td Main Navigation
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key s
|
||||
|
@ -39,24 +43,46 @@
|
|||
.key
|
||||
%i.fa.fa-arrow-up
|
||||
%td Edit last comment (when focused on an empty textarea)
|
||||
%tbody
|
||||
%tr
|
||||
%th
|
||||
%th Project Files browsing
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key
|
||||
%i.fa.fa-arrow-up
|
||||
%td Move selection up
|
||||
.key shift t
|
||||
%td
|
||||
Go to todos
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key
|
||||
%i.fa.fa-arrow-down
|
||||
%td Move selection down
|
||||
.key shift a
|
||||
%td
|
||||
Go to the activity feed
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key enter
|
||||
%td Open Selection
|
||||
.key shift p
|
||||
%td
|
||||
Go to projects
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key shift i
|
||||
%td
|
||||
Go to issues
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key shift m
|
||||
%td
|
||||
Go to merge requests
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key shift g
|
||||
%td
|
||||
Go to groups
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key shift l
|
||||
%td
|
||||
Go to milestones
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key shift s
|
||||
%td
|
||||
Go to snippets
|
||||
%tbody
|
||||
%tr
|
||||
%th
|
||||
|
@ -79,51 +105,8 @@
|
|||
%td.shortcut
|
||||
.key esc
|
||||
%td Go back
|
||||
%tbody
|
||||
%tr
|
||||
%th
|
||||
%th Project File
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key y
|
||||
%td Go to file permalink
|
||||
|
||||
.col-lg-4
|
||||
%table.shortcut-mappings
|
||||
%tbody.hidden-shortcut.project{ style: 'display:none' }
|
||||
%tr
|
||||
%th
|
||||
%th Global Dashboard
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key g
|
||||
.key a
|
||||
%td
|
||||
Go to the activity feed
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key g
|
||||
.key p
|
||||
%td
|
||||
Go to projects
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key g
|
||||
.key i
|
||||
%td
|
||||
Go to issues
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key g
|
||||
.key m
|
||||
%td
|
||||
Go to merge requests
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key g
|
||||
.key t
|
||||
%td
|
||||
Go to todos
|
||||
%tbody
|
||||
%tr
|
||||
%th
|
||||
|
@ -155,7 +138,7 @@
|
|||
%tr
|
||||
%td.shortcut
|
||||
.key g
|
||||
.key b
|
||||
.key j
|
||||
%td
|
||||
Go to jobs
|
||||
%tr
|
||||
|
@ -167,7 +150,7 @@
|
|||
%tr
|
||||
%td.shortcut
|
||||
.key g
|
||||
.key g
|
||||
.key d
|
||||
%td
|
||||
Go to repository charts
|
||||
%tr
|
||||
|
@ -179,7 +162,7 @@
|
|||
%tr
|
||||
%td.shortcut
|
||||
.key g
|
||||
.key l
|
||||
.key b
|
||||
%td
|
||||
Go to issue boards
|
||||
%tr
|
||||
|
@ -194,6 +177,12 @@
|
|||
.key s
|
||||
%td
|
||||
Go to snippets
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key g
|
||||
.key w
|
||||
%td
|
||||
Go to wiki
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key t
|
||||
|
@ -202,6 +191,33 @@
|
|||
%td.shortcut
|
||||
.key i
|
||||
%td New issue
|
||||
|
||||
%tbody
|
||||
%tr
|
||||
%th
|
||||
%th Project Files browsing
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key
|
||||
%i.fa.fa-arrow-up
|
||||
%td Move selection up
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key
|
||||
%i.fa.fa-arrow-down
|
||||
%td Move selection down
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key enter
|
||||
%td Open Selection
|
||||
%tbody
|
||||
%tr
|
||||
%th
|
||||
%th Project File
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key y
|
||||
%td Go to file permalink
|
||||
.col-lg-4
|
||||
%table.shortcut-mappings
|
||||
%tbody.hidden-shortcut.network{ style: 'display:none' }
|
||||
|
|
|
@ -225,7 +225,7 @@
|
|||
%ul.dropdown-menu
|
||||
%li
|
||||
%a{ href: "#" }
|
||||
Dropdown Option
|
||||
Dropdown option
|
||||
.dropdown.inline.pull-right
|
||||
%button.dropdown-menu-toggle{ type: 'button', data: { toggle: 'dropdown' } }
|
||||
Dropdown
|
||||
|
@ -233,7 +233,7 @@
|
|||
%ul.dropdown-menu.dropdown-menu-align-right
|
||||
%li
|
||||
%a{ href: "#" }
|
||||
Dropdown Option
|
||||
Dropdown option
|
||||
.example
|
||||
%div
|
||||
.dropdown.inline
|
||||
|
@ -243,7 +243,7 @@
|
|||
%ul.dropdown-menu.dropdown-menu-selectable
|
||||
%li
|
||||
%a.is-active{ href: "#" }
|
||||
Dropdown Option
|
||||
Dropdown option
|
||||
.example
|
||||
%div
|
||||
.dropdown.inline
|
||||
|
@ -262,26 +262,26 @@
|
|||
%ul
|
||||
%li
|
||||
%a.is-active{ href: "#" }
|
||||
Dropdown Option
|
||||
Dropdown option
|
||||
%li
|
||||
%a{ href: "#" }
|
||||
Dropdown Option
|
||||
Dropdown option
|
||||
%li.divider
|
||||
%li
|
||||
%a{ href: "#" }
|
||||
Dropdown Option
|
||||
Dropdown option
|
||||
%li
|
||||
%a{ href: "#" }
|
||||
Dropdown Option
|
||||
Dropdown option
|
||||
%li
|
||||
%a{ href: "#" }
|
||||
Dropdown Option
|
||||
Dropdown option
|
||||
%li
|
||||
%a{ href: "#" }
|
||||
Dropdown Option
|
||||
Dropdown option
|
||||
%li
|
||||
%a{ href: "#" }
|
||||
Dropdown Option
|
||||
Dropdown option
|
||||
.dropdown-footer
|
||||
%strong Tip:
|
||||
If an author is not a member of this project, you can still filter by his name while using the search field.
|
||||
|
@ -301,26 +301,26 @@
|
|||
%ul
|
||||
%li
|
||||
%a.is-active{ href: "#" }
|
||||
Dropdown Option
|
||||
Dropdown option
|
||||
%li
|
||||
%a{ href: "#" }
|
||||
Dropdown Option
|
||||
Dropdown option
|
||||
%li.divider
|
||||
%li
|
||||
%a{ href: "#" }
|
||||
Dropdown Option
|
||||
Dropdown option
|
||||
%li
|
||||
%a{ href: "#" }
|
||||
Dropdown Option
|
||||
Dropdown option
|
||||
%li
|
||||
%a{ href: "#" }
|
||||
Dropdown Option
|
||||
Dropdown option
|
||||
%li
|
||||
%a{ href: "#" }
|
||||
Dropdown Option
|
||||
Dropdown option
|
||||
%li
|
||||
%a{ href: "#" }
|
||||
Dropdown Option
|
||||
Dropdown option
|
||||
.dropdown-footer
|
||||
%strong Tip:
|
||||
If an author is not a member of this project, you can still filter by his name while using the search field.
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
To import a GitHub project, you first need to authorize GitLab to access
|
||||
the list of your GitHub repositories:
|
||||
|
||||
= link_to 'List Your GitHub Repositories', status_import_github_path, class: 'btn btn-success'
|
||||
= link_to 'List your GitHub repositories', status_import_github_path, class: 'btn btn-success'
|
||||
|
||||
%hr
|
||||
|
||||
|
@ -28,7 +28,7 @@
|
|||
= form_tag personal_access_token_import_github_path, method: :post, class: 'form-inline' do
|
||||
.form-group
|
||||
= text_field_tag :personal_access_token, '', class: 'form-control', placeholder: "Personal Access Token", size: 40
|
||||
= submit_tag 'List Your GitHub Repositories', class: 'btn btn-success'
|
||||
= submit_tag 'List your GitHub repositories', class: 'btn btn-success'
|
||||
|
||||
- unless github_import_configured?
|
||||
%hr
|
||||
|
|
|
@ -29,11 +29,11 @@
|
|||
- if current_user
|
||||
- if session[:impersonator_id]
|
||||
%li.impersonation
|
||||
= link_to admin_impersonation_path, method: :delete, title: "Stop Impersonation", aria: { label: 'Stop Impersonation' }, data: { toggle: 'tooltip', placement: 'bottom', container: 'body' } do
|
||||
= link_to admin_impersonation_path, method: :delete, title: "Stop impersonation", aria: { label: 'Stop impersonation' }, data: { toggle: 'tooltip', placement: 'bottom', container: 'body' } do
|
||||
= icon('user-secret fw')
|
||||
- if current_user.is_admin?
|
||||
%li
|
||||
= link_to admin_root_path, title: 'Admin Area', aria: { label: "Admin Area" }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
|
||||
= link_to admin_root_path, title: 'Admin area', aria: { label: "Admin area" }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
|
||||
= icon('wrench fw')
|
||||
- if current_user.can_create_project?
|
||||
%li
|
||||
|
|
|
@ -1,10 +1,18 @@
|
|||
%ul
|
||||
= nav_link(path: ['root#index', 'projects#trending', 'projects#starred', 'dashboard/projects#index'], html_options: {class: "#{project_tab_class} home"}) do
|
||||
= link_to dashboard_projects_path, title: 'Projects', class: 'dashboard-shortcuts-projects' do
|
||||
.shortcut-mappings
|
||||
.key
|
||||
= icon('arrow-up', 'aria-label' => 'hidden')
|
||||
P
|
||||
%span
|
||||
Projects
|
||||
= nav_link(path: 'dashboard#activity') do
|
||||
= link_to activity_dashboard_path, class: 'dashboard-shortcuts-activity', title: 'Activity' do
|
||||
.shortcut-mappings
|
||||
.key
|
||||
= icon('arrow-up', 'aria-label' => 'hidden')
|
||||
A
|
||||
%span
|
||||
Activity
|
||||
- if koding_enabled?
|
||||
|
@ -13,25 +21,45 @@
|
|||
%span
|
||||
Koding
|
||||
= nav_link(controller: [:groups, 'groups/milestones', 'groups/group_members']) do
|
||||
= link_to dashboard_groups_path, title: 'Groups' do
|
||||
= link_to dashboard_groups_path, class: 'dashboard-shortcuts-groups', title: 'Groups' do
|
||||
.shortcut-mappings
|
||||
.key
|
||||
= icon('arrow-up', 'aria-label' => 'hidden')
|
||||
G
|
||||
%span
|
||||
Groups
|
||||
= nav_link(controller: 'dashboard/milestones') do
|
||||
= link_to dashboard_milestones_path, title: 'Milestones' do
|
||||
= link_to dashboard_milestones_path, class: 'dashboard-shortcuts-milestones', title: 'Milestones' do
|
||||
.shortcut-mappings
|
||||
.key
|
||||
= icon('arrow-up', 'aria-label' => 'hidden')
|
||||
L
|
||||
%span
|
||||
Milestones
|
||||
= nav_link(path: 'dashboard#issues') do
|
||||
= link_to assigned_issues_dashboard_path, title: 'Issues', class: 'dashboard-shortcuts-issues' do
|
||||
.shortcut-mappings
|
||||
.key
|
||||
= icon('arrow-up', 'aria-label' => 'hidden')
|
||||
I
|
||||
%span
|
||||
Issues
|
||||
.badge= number_with_delimiter(cached_assigned_issuables_count(current_user, :issues, :opened))
|
||||
= nav_link(path: 'dashboard#merge_requests') do
|
||||
= link_to assigned_mrs_dashboard_path, title: 'Merge Requests', class: 'dashboard-shortcuts-merge_requests' do
|
||||
.shortcut-mappings
|
||||
.key
|
||||
= icon('arrow-up', 'aria-label' => 'hidden')
|
||||
M
|
||||
%span
|
||||
Merge Requests
|
||||
.badge= number_with_delimiter(cached_assigned_issuables_count(current_user, :merge_requests, :opened))
|
||||
= nav_link(controller: 'dashboard/snippets') do
|
||||
= link_to dashboard_snippets_path, title: 'Snippets' do
|
||||
= link_to dashboard_snippets_path, class: 'dashboard-shortcuts-snippets', title: 'Snippets' do
|
||||
.shortcut-mappings
|
||||
.key
|
||||
= icon('arrow-up', 'aria-label' => 'hidden')
|
||||
S
|
||||
%span
|
||||
Snippets
|
||||
%li.divider
|
||||
|
|
|
@ -49,14 +49,14 @@
|
|||
%p
|
||||
Status: #{current_user.two_factor_enabled? ? 'Enabled' : 'Disabled'}
|
||||
- if current_user.two_factor_enabled?
|
||||
= link_to 'Manage Two-Factor Authentication', profile_two_factor_auth_path, class: 'btn btn-info'
|
||||
= link_to 'Manage two-factor authentication', profile_two_factor_auth_path, class: 'btn btn-info'
|
||||
= link_to 'Disable', profile_two_factor_auth_path,
|
||||
method: :delete,
|
||||
data: { confirm: "Are you sure? This will invalidate your registered applications and U2F devices." },
|
||||
class: 'btn btn-danger'
|
||||
- else
|
||||
.append-bottom-10
|
||||
= link_to 'Enable Two-Factor Authentication', profile_two_factor_auth_path, class: 'btn btn-success'
|
||||
= link_to 'Enable two-factor authentication', profile_two_factor_auth_path, class: 'btn btn-success'
|
||||
|
||||
%hr
|
||||
- if button_based_providers.any?
|
||||
|
|
|
@ -33,17 +33,17 @@
|
|||
%li
|
||||
= @primary
|
||||
%span.pull-right
|
||||
%span.label.label-success Primary Email
|
||||
%span.label.label-success Primary email
|
||||
- if @primary === current_user.public_email
|
||||
%span.label.label-info Public Email
|
||||
%span.label.label-info Public email
|
||||
- if @primary === current_user.notification_email
|
||||
%span.label.label-info Notification Email
|
||||
%span.label.label-info Notification email
|
||||
- @emails.each do |email|
|
||||
%li
|
||||
= email.email
|
||||
%span.pull-right
|
||||
- if email.email === current_user.public_email
|
||||
%span.label.label-info Public Email
|
||||
%span.label.label-info Public email
|
||||
- if email.email === current_user.notification_email
|
||||
%span.label.label-info Notification Email
|
||||
%span.label.label-info Notification email
|
||||
= link_to 'Remove', profile_email_path(email), data: { confirm: 'Are you sure?'}, method: :delete, class: 'btn btn-sm btn-warning prepend-left-10'
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
Your New Personal Access Token
|
||||
.form-group
|
||||
= text_field_tag 'created-personal-access-token', flash[:personal_access_token], readonly: true, class: "form-control", 'aria-describedby' => "created-personal-access-token-help-block"
|
||||
= clipboard_button(clipboard_text: flash[:personal_access_token], title: "Copy personal access token to clipboard", placement: "left")
|
||||
= clipboard_button(text: flash[:personal_access_token], title: "Copy personal access token to clipboard", placement: "left")
|
||||
%span#created-personal-access-token-help-block.help-block.text-danger Make sure you save it - you won't be able to access it again.
|
||||
|
||||
%hr
|
||||
|
|
|
@ -44,7 +44,7 @@
|
|||
= label_tag :pin_code, nil, class: "label-light"
|
||||
= text_field_tag :pin_code, nil, class: "form-control", required: true
|
||||
.prepend-top-default
|
||||
= submit_tag 'Register with Two-Factor App', class: 'btn btn-success'
|
||||
= submit_tag 'Register with two-factor app', class: 'btn btn-success'
|
||||
|
||||
%hr
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
.form-actions
|
||||
= button_tag 'Commit Changes', class: 'btn commit-btn js-commit-button btn-create'
|
||||
= button_tag 'Commit changes', class: 'btn commit-btn js-commit-button btn-create'
|
||||
= link_to 'Cancel', cancel_path,
|
||||
class: 'btn btn-cancel', data: {confirm: leave_edit_message}
|
||||
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
= link_to namespace_project_find_file_path(@project.namespace, @project, @ref), class: 'btn btn-grouped shortcuts-find-file', rel: 'nofollow' do
|
||||
= icon('search')
|
||||
%span Find File
|
||||
%span Find file
|
||||
|
|
|
@ -10,9 +10,9 @@
|
|||
- if @project && event.project != @project
|
||||
%span at
|
||||
%strong= link_to_project event.project
|
||||
= clipboard_button(clipboard_text: event.ref_name, class: 'btn-clipboard btn-transparent', title: 'Copy branch to clipboard')
|
||||
= clipboard_button(text: event.ref_name, class: 'btn-clipboard btn-transparent', title: 'Copy branch to clipboard')
|
||||
#{time_ago_with_tooltip(event.created_at)}
|
||||
|
||||
.pull-right
|
||||
= link_to new_mr_path_from_push_event(event), title: "New Merge Request", class: "btn btn-info btn-sm" do
|
||||
Create Merge Request
|
||||
= link_to new_mr_path_from_push_event(event), title: "New merge request", class: "btn btn-info btn-sm" do
|
||||
Create merge request
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
-# only show normal/blame view links for text files
|
||||
- if blob_text_viewable?(blob)
|
||||
- if current_page? namespace_project_blame_path(@project.namespace, @project, @id)
|
||||
= link_to 'Normal View', namespace_project_blob_path(@project.namespace, @project, @id),
|
||||
= link_to 'Normal view', namespace_project_blob_path(@project.namespace, @project, @id),
|
||||
class: 'btn btn-sm'
|
||||
- else
|
||||
= link_to 'Blame', namespace_project_blame_path(@project.namespace, @project, @id),
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
.template-type-selector.js-template-type-selector-wrap.hidden
|
||||
= dropdown_tag("Choose type", options: { toggle_class: 'btn js-template-type-selector', title: "Choose a template type" } )
|
||||
.license-selector.js-license-selector-wrap.js-template-selector-wrap.hidden
|
||||
= dropdown_tag("Apply a License template", options: { toggle_class: 'btn js-license-selector', title: "Apply a license", filter: true, placeholder: "Filter", data: { data: licenses_for_select, project: @project.name, fullname: @project.namespace.human_name } } )
|
||||
= dropdown_tag("Apply a license template", options: { toggle_class: 'btn js-license-selector', title: "Apply a license", filter: true, placeholder: "Filter", data: { data: licenses_for_select, project: @project.name, fullname: @project.namespace.human_name } } )
|
||||
.gitignore-selector.js-gitignore-selector-wrap.js-template-selector-wrap.hidden
|
||||
= dropdown_tag("Apply a .gitignore template", options: { toggle_class: 'btn js-gitignore-selector', title: "Apply a template", filter: true, placeholder: "Filter", data: { data: gitignore_names } } )
|
||||
.gitlab-ci-yml-selector.js-gitlab-ci-yml-selector-wrap.js-template-selector-wrap.hidden
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
.controls.hidden-xs<
|
||||
- if merge_project && create_mr_button?(@repository.root_ref, branch.name)
|
||||
= link_to create_mr_path(@repository.root_ref, branch.name), class: 'btn btn-default' do
|
||||
Merge Request
|
||||
Merge request
|
||||
|
||||
- if branch.name != @repository.root_ref
|
||||
= link_to namespace_project_compare_index_path(@project.namespace, @project, from: @repository.root_ref, to: branch.name), class: "btn btn-default #{'prepend-left-10' unless merge_project}", method: :post, title: "Compare" do
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
- pipeline = @build.pipeline
|
||||
|
||||
.content-block.build-header.top-area
|
||||
.header-content
|
||||
= render 'ci/status/badge', status: @build.detailed_status(current_user), link: false
|
||||
= render 'ci/status/badge', status: @build.detailed_status(current_user), link: false, title: @build.status_title
|
||||
Job
|
||||
%strong.js-build-id ##{@build.id}
|
||||
in pipeline
|
||||
= link_to pipeline_path(@build.pipeline) do
|
||||
%strong ##{@build.pipeline.id}
|
||||
= link_to pipeline_path(pipeline) do
|
||||
%strong ##{pipeline.id}
|
||||
for commit
|
||||
= link_to namespace_project_commit_path(@project.namespace, @project, @build.pipeline.sha) do
|
||||
%strong= @build.pipeline.short_sha
|
||||
= link_to namespace_project_commit_path(@project.namespace, @project, pipeline.sha) do
|
||||
%strong= pipeline.short_sha
|
||||
from
|
||||
= link_to namespace_project_commits_path(@project.namespace, @project, @build.ref) do
|
||||
%code
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
= link_to 'Get started with CI/CD Pipelines', help_page_path('ci/quick_start/README'), class: 'btn btn-info'
|
||||
|
||||
= link_to ci_lint_path, class: 'btn btn-default' do
|
||||
%span CI Lint
|
||||
%span CI lint
|
||||
|
||||
.content-list.builds-content-list
|
||||
= render "table", builds: @builds, project: @project
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
- job = build.present(current_user: current_user)
|
||||
- pipeline = job.pipeline
|
||||
- admin = local_assigns.fetch(:admin, false)
|
||||
- ref = local_assigns.fetch(:ref, nil)
|
||||
- commit_sha = local_assigns.fetch(:commit_sha, nil)
|
||||
|
@ -8,101 +10,101 @@
|
|||
|
||||
%tr.build.commit{ class: ('retried' if retried) }
|
||||
%td.status
|
||||
= render "ci/status/badge", status: build.detailed_status(current_user)
|
||||
= render "ci/status/badge", status: job.detailed_status(current_user), title: job.status_title
|
||||
|
||||
%td.branch-commit
|
||||
- if can?(current_user, :read_build, build)
|
||||
= link_to namespace_project_build_url(build.project.namespace, build.project, build) do
|
||||
%span.build-link ##{build.id}
|
||||
- if can?(current_user, :read_build, job)
|
||||
= link_to namespace_project_build_url(job.project.namespace, job.project, job) do
|
||||
%span.build-link ##{job.id}
|
||||
- else
|
||||
%span.build-link ##{build.id}
|
||||
%span.build-link ##{job.id}
|
||||
|
||||
- if ref
|
||||
- if build.ref
|
||||
- if job.ref
|
||||
.icon-container
|
||||
= build.tag? ? icon('tag') : icon('code-fork')
|
||||
= link_to build.ref, namespace_project_commits_path(build.project.namespace, build.project, build.ref), class: "monospace branch-name"
|
||||
= job.tag? ? icon('tag') : icon('code-fork')
|
||||
= link_to job.ref, namespace_project_commits_path(job.project.namespace, job.project, job.ref), class: "monospace branch-name"
|
||||
- else
|
||||
.light none
|
||||
.icon-container.commit-icon
|
||||
= custom_icon("icon_commit")
|
||||
|
||||
- if commit_sha
|
||||
= link_to build.short_sha, namespace_project_commit_path(build.project.namespace, build.project, build.sha), class: "commit-id monospace"
|
||||
= link_to job.short_sha, namespace_project_commit_path(job.project.namespace, job.project, job.sha), class: "commit-id monospace"
|
||||
|
||||
- if build.stuck?
|
||||
- if job.stuck?
|
||||
= icon('warning', class: 'text-warning has-tooltip', title: 'Job is stuck. Check runners.')
|
||||
|
||||
- if retried
|
||||
= icon('refresh', class: 'text-warning has-tooltip', title: 'Job was retried')
|
||||
|
||||
.label-container
|
||||
- if build.tags.any?
|
||||
- build.tags.each do |tag|
|
||||
- if job.tags.any?
|
||||
- job.tags.each do |tag|
|
||||
%span.label.label-primary
|
||||
= tag
|
||||
- if build.try(:trigger_request)
|
||||
- if job.try(:trigger_request)
|
||||
%span.label.label-info triggered
|
||||
- if build.try(:allow_failure)
|
||||
- if job.try(:allow_failure)
|
||||
%span.label.label-danger allowed to fail
|
||||
- if build.action?
|
||||
- if job.action?
|
||||
%span.label.label-info manual
|
||||
|
||||
- if pipeline_link
|
||||
%td
|
||||
= link_to pipeline_path(build.pipeline) do
|
||||
%span.pipeline-id ##{build.pipeline.id}
|
||||
= link_to pipeline_path(pipeline) do
|
||||
%span.pipeline-id ##{pipeline.id}
|
||||
%span by
|
||||
- if build.pipeline.user
|
||||
= user_avatar(user: build.pipeline.user, size: 20)
|
||||
- if pipeline.user
|
||||
= user_avatar(user: pipeline.user, size: 20)
|
||||
- else
|
||||
%span.monospace API
|
||||
|
||||
- if admin
|
||||
%td
|
||||
- if build.project
|
||||
= link_to build.project.name_with_namespace, admin_namespace_project_path(build.project.namespace, build.project)
|
||||
- if job.project
|
||||
= link_to job.project.name_with_namespace, admin_namespace_project_path(job.project.namespace, job.project)
|
||||
%td
|
||||
- if build.try(:runner)
|
||||
= runner_link(build.runner)
|
||||
- if job.try(:runner)
|
||||
= runner_link(job.runner)
|
||||
- else
|
||||
.light none
|
||||
|
||||
- if stage
|
||||
%td
|
||||
= build.stage
|
||||
= job.stage
|
||||
|
||||
%td
|
||||
= build.name
|
||||
= job.name
|
||||
|
||||
%td
|
||||
- if build.duration
|
||||
- if job.duration
|
||||
%p.duration
|
||||
= custom_icon("icon_timer")
|
||||
= duration_in_numbers(build.duration)
|
||||
= duration_in_numbers(job.duration)
|
||||
|
||||
- if build.finished_at
|
||||
- if job.finished_at
|
||||
%p.finished-at
|
||||
= icon("calendar")
|
||||
%span= time_ago_with_tooltip(build.finished_at)
|
||||
%span= time_ago_with_tooltip(job.finished_at)
|
||||
|
||||
%td.coverage
|
||||
- if build.try(:coverage)
|
||||
#{build.coverage}%
|
||||
- if job.try(:coverage)
|
||||
#{job.coverage}%
|
||||
|
||||
%td
|
||||
.pull-right
|
||||
- if can?(current_user, :read_build, build) && build.artifacts?
|
||||
= link_to download_namespace_project_build_artifacts_path(build.project.namespace, build.project, build), rel: 'nofollow', download: '', title: 'Download artifacts', class: 'btn btn-build' do
|
||||
- if can?(current_user, :read_build, job) && job.artifacts?
|
||||
= link_to download_namespace_project_build_artifacts_path(job.project.namespace, job.project, job), rel: 'nofollow', download: '', title: 'Download artifacts', class: 'btn btn-build' do
|
||||
= icon('download')
|
||||
- if can?(current_user, :update_build, build)
|
||||
- if build.active?
|
||||
= link_to cancel_namespace_project_build_path(build.project.namespace, build.project, build, return_to: request.original_url), method: :post, title: 'Cancel', class: 'btn btn-build' do
|
||||
- if can?(current_user, :update_build, job)
|
||||
- if job.active?
|
||||
= link_to cancel_namespace_project_build_path(job.project.namespace, job.project, job, return_to: request.original_url), method: :post, title: 'Cancel', class: 'btn btn-build' do
|
||||
= icon('remove', class: 'cred')
|
||||
- elsif allow_retry
|
||||
- if build.playable? && !admin
|
||||
= link_to play_namespace_project_build_path(build.project.namespace, build.project, build, return_to: request.original_url), method: :post, title: 'Play', class: 'btn btn-build' do
|
||||
- if job.playable? && !admin
|
||||
= link_to play_namespace_project_build_path(job.project.namespace, job.project, job, return_to: request.original_url), method: :post, title: 'Play', class: 'btn btn-build' do
|
||||
= custom_icon('icon_play')
|
||||
- elsif build.retryable?
|
||||
= link_to retry_namespace_project_build_path(build.project.namespace, build.project, build, return_to: request.original_url), method: :post, title: 'Retry', class: 'btn btn-build' do
|
||||
- elsif job.retryable?
|
||||
= link_to retry_namespace_project_build_path(job.project.namespace, job.project, job, return_to: request.original_url), method: :post, title: 'Retry', class: 'btn btn-build' do
|
||||
= icon('repeat')
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
.page-content-header
|
||||
.header-main-content
|
||||
%strong Commit #{@commit.short_id}
|
||||
= clipboard_button(clipboard_text: @commit.id, title: "Copy commit SHA to clipboard")
|
||||
= clipboard_button(text: @commit.id, title: "Copy commit SHA to clipboard")
|
||||
%span.hidden-xs authored
|
||||
#{time_ago_with_tooltip(@commit.authored_date)}
|
||||
%span by
|
||||
|
@ -20,7 +20,7 @@
|
|||
= icon('comment')
|
||||
= @notes_count
|
||||
= link_to namespace_project_tree_path(@project.namespace, @project, @commit), class: "btn btn-default append-right-10 hidden-xs hidden-sm" do
|
||||
Browse Files
|
||||
Browse files
|
||||
.dropdown.inline
|
||||
%a.btn.btn-default.dropdown-toggle{ data: { toggle: "dropdown" } }
|
||||
%span Options
|
||||
|
|
|
@ -37,6 +37,6 @@
|
|||
.commit-actions.flex-row.hidden-xs
|
||||
- if commit.status(ref)
|
||||
= render_commit_status(commit, ref: ref)
|
||||
= clipboard_button(clipboard_text: commit.id, title: "Copy commit SHA to clipboard")
|
||||
= clipboard_button(text: commit.id, title: "Copy commit SHA to clipboard")
|
||||
= link_to commit.short_id, namespace_project_commit_path(project.namespace, project, commit), class: "commit-short-id btn btn-transparent"
|
||||
= link_to_browse_code(project, commit)
|
||||
|
|
|
@ -18,16 +18,16 @@
|
|||
.block-controls.hidden-xs.hidden-sm
|
||||
- if @merge_request.present?
|
||||
.control
|
||||
= link_to "View Open Merge Request", namespace_project_merge_request_path(@project.namespace, @project, @merge_request), class: 'btn'
|
||||
= link_to "View open merge request", namespace_project_merge_request_path(@project.namespace, @project, @merge_request), class: 'btn'
|
||||
- elsif create_mr_button?(@repository.root_ref, @ref)
|
||||
.control
|
||||
= link_to "Create Merge Request", create_mr_path(@repository.root_ref, @ref), class: 'btn btn-success'
|
||||
= link_to "Create merge request", create_mr_path(@repository.root_ref, @ref), class: 'btn btn-success'
|
||||
|
||||
.control
|
||||
= form_tag(namespace_project_commits_path(@project.namespace, @project, @id), method: :get, class: 'commits-search-form') do
|
||||
= search_field_tag :search, params[:search], { placeholder: 'Filter by commit message', id: 'commits-search', class: 'form-control search-text-input input-short', spellcheck: false }
|
||||
.control
|
||||
= link_to namespace_project_commits_path(@project.namespace, @project, @ref, rss_url_options), title: "Commits Feed", class: 'btn' do
|
||||
= link_to namespace_project_commits_path(@project.namespace, @project, @ref, rss_url_options), title: "Commits feed", class: 'btn' do
|
||||
= icon("rss")
|
||||
|
||||
%div{ id: dom_id(@project) }
|
||||
|
|
|
@ -21,6 +21,6 @@
|
|||
|
||||
= button_tag "Compare", class: "btn btn-create commits-compare-btn"
|
||||
- if @merge_request.present?
|
||||
= link_to "View Open Merge Request", namespace_project_merge_request_path(@project.namespace, @project, @merge_request), class: 'prepend-left-10 btn'
|
||||
= link_to "View open merge request", namespace_project_merge_request_path(@project.namespace, @project, @merge_request), class: 'prepend-left-10 btn'
|
||||
- elsif create_mr_button?
|
||||
= link_to "Create Merge Request", create_mr_path, class: 'prepend-left-10 btn'
|
||||
= link_to "Create merge request", create_mr_path, class: 'prepend-left-10 btn'
|
||||
|
|
|
@ -8,7 +8,4 @@
|
|||
|
||||
#environments-folder-list-view{ data: { "can-create-deployment" => can?(current_user, :create_deployment, @project).to_s,
|
||||
"can-read-environment" => can?(current_user, :read_environment, @project).to_s,
|
||||
"css-class" => container_class,
|
||||
"commit-icon-svg" => custom_icon("icon_commit"),
|
||||
"terminal-icon-svg" => custom_icon("icon_terminal"),
|
||||
"play-icon-svg" => custom_icon("icon_play") } }
|
||||
"css-class" => container_class } }
|
||||
|
|
|
@ -22,4 +22,4 @@
|
|||
%p
|
||||
= link_to new_namespace_project_fork_path(@project.namespace, @project), title: "Fork", class: "btn" do
|
||||
%i.fa.fa-code-fork
|
||||
Try to Fork again
|
||||
Try to fork again
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
.email-modal-input-group.input-group
|
||||
= text_field_tag :issue_email, email, class: "monospace js-select-on-focus form-control", readonly: true
|
||||
.input-group-btn
|
||||
= clipboard_button(clipboard_target: '#issue_email')
|
||||
= clipboard_button(target: '#issue_email')
|
||||
%p
|
||||
The subject will be used as the title of the new issue, and the message will be the description.
|
||||
|
||||
|
|
|
@ -24,9 +24,9 @@
|
|||
issue: { assignee_id: issues_finder.assignee.try(:id),
|
||||
milestone_id: issues_finder.milestones.first.try(:id) }),
|
||||
class: "btn btn-new",
|
||||
title: "New Issue",
|
||||
title: "New issue",
|
||||
id: "new_issue_link" do
|
||||
New Issue
|
||||
New issue
|
||||
= render 'shared/issuable/search_bar', type: :issues
|
||||
|
||||
.issues-holder
|
||||
|
|
|
@ -53,5 +53,6 @@
|
|||
|
||||
:javascript
|
||||
var merge_request = new MergeRequest({
|
||||
action: "#{(@show_changes_tab ? 'new/diffs' : 'new')}"
|
||||
action: "#{(@show_changes_tab ? 'new/diffs' : 'new')}",
|
||||
setUrl: false,
|
||||
});
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
%p
|
||||
%strong Step 1.
|
||||
Fetch and check out the branch for this merge request
|
||||
= clipboard_button(clipboard_target: "pre#merge-info-1", title: "Copy commands to clipboard")
|
||||
= clipboard_button(target: "pre#merge-info-1", title: "Copy commands to clipboard")
|
||||
%pre.dark#merge-info-1
|
||||
- if @merge_request.for_fork?
|
||||
:preserve
|
||||
|
@ -25,7 +25,7 @@
|
|||
%p
|
||||
%strong Step 3.
|
||||
Merge the branch and fix any conflicts that come up
|
||||
= clipboard_button(clipboard_target: "pre#merge-info-3", title: "Copy commands to clipboard")
|
||||
= clipboard_button(target: "pre#merge-info-3", title: "Copy commands to clipboard")
|
||||
%pre.dark#merge-info-3
|
||||
- if @merge_request.for_fork?
|
||||
:preserve
|
||||
|
@ -38,7 +38,7 @@
|
|||
%p
|
||||
%strong Step 4.
|
||||
Push the result of the merge to GitLab
|
||||
= clipboard_button(clipboard_target: "pre#merge-info-4", title: "Copy commands to clipboard")
|
||||
= clipboard_button(target: "pre#merge-info-4", title: "Copy commands to clipboard")
|
||||
%pre.dark#merge-info-4
|
||||
:preserve
|
||||
git push origin #{h @merge_request.target_branch}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
- if can_remove_source_branch
|
||||
= link_to namespace_project_branch_path(@merge_request.source_project.namespace, @merge_request.source_project, @merge_request.source_branch), remote: true, method: :delete, class: "btn btn-default remove_source_branch" do
|
||||
= icon('trash-o')
|
||||
Remove Source Branch
|
||||
Remove source branch
|
||||
- if mr_can_be_reverted
|
||||
= revert_commit_link(@merge_request.merge_commit, namespace_project_merge_request_path(@project.namespace, @project, @merge_request), btn_class: "close")
|
||||
- if mr_can_be_cherry_picked
|
||||
|
|
|
@ -10,24 +10,24 @@
|
|||
- if @pipeline && @pipeline.active?
|
||||
%span.btn-group
|
||||
= button_tag class: "btn btn-info js-merge-when-pipeline-succeeds-button merge-when-pipeline-succeeds" do
|
||||
Merge When Pipeline Succeeds
|
||||
Merge when pipeline succeeds
|
||||
- unless @project.only_allow_merge_if_pipeline_succeeds?
|
||||
= button_tag class: "btn btn-info dropdown-toggle", 'data-toggle' => 'dropdown' do
|
||||
= icon('caret-down')
|
||||
%span.sr-only
|
||||
Select Merge Moment
|
||||
Select merge moment
|
||||
%ul.js-merge-dropdown.dropdown-menu.dropdown-menu-right{ role: 'menu' }
|
||||
%li
|
||||
= link_to "#", class: "merge_when_pipeline_succeeds" do
|
||||
= icon('check fw')
|
||||
Merge When Pipeline Succeeds
|
||||
Merge when pipeline succeeds
|
||||
%li
|
||||
= link_to "#", class: "accept-merge-request" do
|
||||
= icon('warning fw')
|
||||
Merge Immediately
|
||||
Merge immediately
|
||||
- else
|
||||
= f.button class: "btn btn-grouped js-merge-button accept-merge-request" do
|
||||
Accept Merge Request
|
||||
Accept merge request
|
||||
- if @merge_request.force_remove_source_branch?
|
||||
.accept-control
|
||||
The source branch will be removed.
|
||||
|
|
|
@ -26,8 +26,8 @@
|
|||
- if remove_source_branch_button
|
||||
= link_to merge_namespace_project_merge_request_path(@merge_request.target_project.namespace, @merge_request.target_project, @merge_request, merge_params(@merge_request)), remote: true, method: :post, class: "btn btn-grouped btn-primary btn-sm remove_source_branch" do
|
||||
= icon('times')
|
||||
Remove Source Branch When Merged
|
||||
Remove source branch when merged
|
||||
|
||||
- if user_can_cancel_automatic_merge
|
||||
= link_to cancel_merge_when_pipeline_succeeds_namespace_project_merge_request_path(@merge_request.target_project.namespace, @merge_request.target_project, @merge_request), remote: true, method: :post, class: "btn btn-grouped btn-sm" do
|
||||
Cancel Automatic Merge
|
||||
Cancel automatic merge
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
.nav-controls
|
||||
= render 'shared/milestones_sort_dropdown'
|
||||
- if can?(current_user, :admin_milestone, @project)
|
||||
= link_to new_namespace_project_milestone_path(@project.namespace, @project), class: 'btn btn-new', title: 'New Milestone' do
|
||||
New Milestone
|
||||
= link_to new_namespace_project_milestone_path(@project.namespace, @project), class: 'btn btn-new', title: 'New milestone' do
|
||||
New milestone
|
||||
|
||||
.milestones
|
||||
%ul.content-list
|
||||
|
|
|
@ -23,9 +23,9 @@
|
|||
.milestone-buttons
|
||||
- if can?(current_user, :admin_milestone, @project)
|
||||
- if @milestone.active?
|
||||
= link_to 'Close Milestone', namespace_project_milestone_path(@project.namespace, @project, @milestone, milestone: {state_event: :close }), method: :put, class: "btn btn-close btn-nr btn-grouped"
|
||||
= link_to 'Close milestone', namespace_project_milestone_path(@project.namespace, @project, @milestone, milestone: {state_event: :close }), method: :put, class: "btn btn-close btn-nr btn-grouped"
|
||||
- else
|
||||
= link_to 'Reopen Milestone', namespace_project_milestone_path(@project.namespace, @project, @milestone, milestone: {state_event: :activate }), method: :put, class: "btn btn-reopen btn-nr btn-grouped"
|
||||
= link_to 'Reopen milestone', namespace_project_milestone_path(@project.namespace, @project, @milestone, milestone: {state_event: :activate }), method: :put, class: "btn btn-reopen btn-nr btn-grouped"
|
||||
|
||||
= link_to edit_namespace_project_milestone_path(@project.namespace, @project, @milestone), class: "btn btn-grouped btn-nr" do
|
||||
Edit
|
||||
|
|
|
@ -9,6 +9,6 @@
|
|||
.note-form-actions.clearfix
|
||||
.settings-message.note-edit-warning.js-edit-warning
|
||||
Finish editing this message first!
|
||||
= submit_tag 'Save Comment', class: 'btn btn-nr btn-save js-comment-button'
|
||||
= submit_tag 'Save comment', class: 'btn btn-nr btn-save js-comment-button'
|
||||
%button.btn.btn-nr.btn-cancel.note-edit-cancel{ type: 'button' }
|
||||
Cancel
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue