Merge branch 'master' into zj-create-mattermost-team
This commit is contained in:
commit
ddfd09c09c
|
|
@ -23,6 +23,7 @@ AllCops:
|
|||
- 'tmp/**/*'
|
||||
- 'bin/**/*'
|
||||
- 'generator_templates/**/*'
|
||||
- 'builds/**/*'
|
||||
|
||||
# Gems in consecutive lines should be alphabetically sorted
|
||||
Bundler/OrderedGems:
|
||||
|
|
|
|||
25
CHANGELOG.md
25
CHANGELOG.md
|
|
@ -2,6 +2,25 @@
|
|||
documentation](doc/development/changelog.md) for instructions on adding your own
|
||||
entry.
|
||||
|
||||
## 8.17.2 (2017-03-01)
|
||||
|
||||
- Expire all webpack assets after 8.17.1 included a badly compiled asset. !9602
|
||||
|
||||
## 8.17.1 (2017-02-28)
|
||||
|
||||
- Replace setInterval with setTimeout to prevent highly frequent requests. !9271 (Takuya Noguchi)
|
||||
- Disable unused tags count cache for Projects, Builds and Runners.
|
||||
- Spam check and reCAPTCHA improvements.
|
||||
- Allow searching issues for strings containing colons.
|
||||
- Disabled tooltip on add issues button in usse boards.
|
||||
- Fixed commit search UI.
|
||||
- Fix MR changes tab size count when there are over 100 files in the diff.
|
||||
- Disable invalid service templates.
|
||||
- Use default branch as target_branch when parameter is missing.
|
||||
- Upgrade GitLab Pages to v0.3.2.
|
||||
- Add performance query regression fix for !9088 affecting #27267.
|
||||
- Chat slash commands show labels correctly.
|
||||
|
||||
## 8.17.0 (2017-02-22)
|
||||
|
||||
- API: Fix file downloading. !0 (8267)
|
||||
|
|
@ -182,6 +201,12 @@ entry.
|
|||
- Remove deprecated GitlabCiService.
|
||||
- Requeue pending deletion projects.
|
||||
|
||||
## 8.16.7 (2017-02-27)
|
||||
|
||||
- No changes.
|
||||
- No changes.
|
||||
- Fix MR changes tab size count when there are over 100 files in the diff.
|
||||
|
||||
## 8.16.6 (2017-02-17)
|
||||
|
||||
- API: Fix file downloading. !0 (8267)
|
||||
|
|
|
|||
|
|
@ -1,32 +1,48 @@
|
|||
## Contributor license agreement
|
||||
|
||||
By submitting code as an individual you agree to the
|
||||
[individual contributor license agreement](doc/legal/individual_contributor_license_agreement.md).
|
||||
By submitting code as an entity you agree to the
|
||||
[corporate contributor license agreement](doc/legal/corporate_contributor_license_agreement.md).
|
||||
|
||||
_This notice should stay as the first item in the CONTRIBUTING.MD file._
|
||||
|
||||
---
|
||||
|
||||
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
||||
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
||||
**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*
|
||||
|
||||
- [Contributor license agreement](#contributor-license-agreement)
|
||||
- [Contribute to GitLab](#contribute-to-gitlab)
|
||||
- [Contributor license agreement](#contributor-license-agreement)
|
||||
- [Security vulnerability disclosure](#security-vulnerability-disclosure)
|
||||
- [Closing policy for issues and merge requests](#closing-policy-for-issues-and-merge-requests)
|
||||
- [Helping others](#helping-others)
|
||||
- [I want to contribute!](#i-want-to-contribute)
|
||||
- [Implement design & UI elements](#implement-design-ui-elements)
|
||||
- [Issue tracker](#issue-tracker)
|
||||
- [Feature proposals](#feature-proposals)
|
||||
- [Issue tracker guidelines](#issue-tracker-guidelines)
|
||||
- [Issue weight](#issue-weight)
|
||||
- [Regression issues](#regression-issues)
|
||||
- [Technical debt](#technical-debt)
|
||||
- [Stewardship](#stewardship)
|
||||
- [Merge requests](#merge-requests)
|
||||
- [Merge request guidelines](#merge-request-guidelines)
|
||||
- [Contribution acceptance criteria](#contribution-acceptance-criteria)
|
||||
- [Changes for Stable Releases](#changes-for-stable-releases)
|
||||
- [Definition of done](#definition-of-done)
|
||||
- [Style guides](#style-guides)
|
||||
- [Code of conduct](#code-of-conduct)
|
||||
- [Security vulnerability disclosure](#security-vulnerability-disclosure)
|
||||
- [Closing policy for issues and merge requests](#closing-policy-for-issues-and-merge-requests)
|
||||
- [Helping others](#helping-others)
|
||||
- [I want to contribute!](#i-want-to-contribute)
|
||||
- [Implement design & UI elements](#implement-design-ui-elements)
|
||||
- [Release retrospective and kickoff](#release-retrospective-and-kickoff)
|
||||
- [Retrospective](#retrospective)
|
||||
- [Kickoff](#kickoff)
|
||||
- [Issue tracker](#issue-tracker)
|
||||
- [Feature proposals](#feature-proposals)
|
||||
- [Issue tracker guidelines](#issue-tracker-guidelines)
|
||||
- [Issue weight](#issue-weight)
|
||||
- [Regression issues](#regression-issues)
|
||||
- [Technical debt](#technical-debt)
|
||||
- [Stewardship](#stewardship)
|
||||
- [Merge requests](#merge-requests)
|
||||
- [Merge request guidelines](#merge-request-guidelines)
|
||||
- [Contribution acceptance criteria](#contribution-acceptance-criteria)
|
||||
- [Changes for Stable Releases](#changes-for-stable-releases)
|
||||
- [Definition of done](#definition-of-done)
|
||||
- [Style guides](#style-guides)
|
||||
- [Code of conduct](#code-of-conduct)
|
||||
|
||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||
|
||||
# Contribute to GitLab
|
||||
---
|
||||
|
||||
## Contribute to GitLab
|
||||
|
||||
Thank you for your interest in contributing to GitLab. This guide details how
|
||||
to contribute to GitLab in a way that is efficient for everyone.
|
||||
|
|
@ -41,13 +57,6 @@ operates please see [the GitLab contributing process](PROCESS.md).
|
|||
|
||||
- [GitLab Inc engineers should refer to the engineering workflow document](https://about.gitlab.com/handbook/engineering/workflow/)
|
||||
|
||||
## Contributor license agreement
|
||||
|
||||
By submitting code as an individual you agree to the
|
||||
[individual contributor license agreement](doc/legal/individual_contributor_license_agreement.md).
|
||||
By submitting code as an entity you agree to the
|
||||
[corporate contributor license agreement](doc/legal/corporate_contributor_license_agreement.md).
|
||||
|
||||
## Security vulnerability disclosure
|
||||
|
||||
Please report suspected security vulnerabilities in private to
|
||||
|
|
|
|||
9
Gemfile
9
Gemfile
|
|
@ -20,7 +20,7 @@ gem 'rugged', '~> 0.24.0'
|
|||
# Authentication libraries
|
||||
gem 'devise', '~> 4.2'
|
||||
gem 'doorkeeper', '~> 4.2.0'
|
||||
gem 'omniauth', '~> 1.3.2'
|
||||
gem 'omniauth', '~> 1.4.2'
|
||||
gem 'omniauth-auth0', '~> 1.4.1'
|
||||
gem 'omniauth-azure-oauth2', '~> 0.0.6'
|
||||
gem 'omniauth-cas3', '~> 1.1.2'
|
||||
|
|
@ -68,7 +68,7 @@ gem 'gollum-rugged_adapter', '~> 0.4.2', require: false
|
|||
gem 'github-linguist', '~> 4.7.0', require: 'linguist'
|
||||
|
||||
# API
|
||||
gem 'grape', '~> 0.18.0'
|
||||
gem 'grape', '~> 0.19.0'
|
||||
gem 'grape-entity', '~> 0.6.0'
|
||||
gem 'rack-cors', '~> 0.4.0', require: 'rack/cors'
|
||||
|
||||
|
|
@ -329,8 +329,6 @@ group :test do
|
|||
gem 'timecop', '~> 0.8.0'
|
||||
end
|
||||
|
||||
gem 'newrelic_rpm', '~> 3.16'
|
||||
|
||||
gem 'octokit', '~> 4.6.2'
|
||||
|
||||
gem 'mail_room', '~> 0.9.1'
|
||||
|
|
@ -352,3 +350,6 @@ gem 'health_check', '~> 2.2.0'
|
|||
# System information
|
||||
gem 'vmstat', '~> 2.3.0'
|
||||
gem 'sys-filesystem', '~> 1.1.6'
|
||||
|
||||
# Gitaly GRPC client
|
||||
gem 'gitaly', '~> 0.2.1'
|
||||
|
|
|
|||
30
Gemfile.lock
30
Gemfile.lock
|
|
@ -245,6 +245,9 @@ GEM
|
|||
json
|
||||
get_process_mem (0.2.0)
|
||||
gherkin-ruby (0.3.2)
|
||||
gitaly (0.2.1)
|
||||
google-protobuf (~> 3.1)
|
||||
grpc (~> 1.0)
|
||||
github-linguist (4.7.6)
|
||||
charlock_holmes (~> 0.7.3)
|
||||
escape_utils (~> 1.1.0)
|
||||
|
|
@ -296,6 +299,7 @@ GEM
|
|||
multi_json (~> 1.10)
|
||||
retriable (~> 1.4)
|
||||
signet (~> 0.6)
|
||||
google-protobuf (3.2.0)
|
||||
googleauth (0.5.1)
|
||||
faraday (~> 0.9)
|
||||
jwt (~> 1.4)
|
||||
|
|
@ -304,7 +308,7 @@ GEM
|
|||
multi_json (~> 1.11)
|
||||
os (~> 0.9)
|
||||
signet (~> 0.7)
|
||||
grape (0.18.0)
|
||||
grape (0.19.1)
|
||||
activesupport
|
||||
builder
|
||||
hashie (>= 2.1.0)
|
||||
|
|
@ -317,6 +321,9 @@ GEM
|
|||
grape-entity (0.6.0)
|
||||
activesupport
|
||||
multi_json (>= 1.3.2)
|
||||
grpc (1.1.2)
|
||||
google-protobuf (~> 3.1)
|
||||
googleauth (~> 0.5.1)
|
||||
haml (4.0.7)
|
||||
tilt
|
||||
haml_lint (0.21.0)
|
||||
|
|
@ -328,7 +335,7 @@ GEM
|
|||
temple (~> 0.7.6)
|
||||
thor
|
||||
tilt
|
||||
hashie (3.4.4)
|
||||
hashie (3.5.5)
|
||||
health_check (2.2.1)
|
||||
rails (>= 4.0)
|
||||
hipchat (1.5.2)
|
||||
|
|
@ -353,8 +360,8 @@ GEM
|
|||
json (~> 1.8)
|
||||
multi_xml (>= 0.5.2)
|
||||
httpclient (2.8.2)
|
||||
i18n (0.8.0)
|
||||
ice_nine (0.11.1)
|
||||
i18n (0.8.1)
|
||||
ice_nine (0.11.2)
|
||||
influxdb (0.2.3)
|
||||
cause
|
||||
json
|
||||
|
|
@ -417,7 +424,7 @@ GEM
|
|||
minitest (5.7.0)
|
||||
mousetrap-rails (1.4.6)
|
||||
multi_json (1.12.1)
|
||||
multi_xml (0.5.5)
|
||||
multi_xml (0.6.0)
|
||||
multipart-post (2.0.0)
|
||||
mustermann (0.4.0)
|
||||
tool (~> 0.2)
|
||||
|
|
@ -427,7 +434,6 @@ GEM
|
|||
net-ldap (0.12.1)
|
||||
net-ssh (3.0.1)
|
||||
netrc (0.11.0)
|
||||
newrelic_rpm (3.16.0.318)
|
||||
nokogiri (1.6.8.1)
|
||||
mini_portile2 (~> 2.1.0)
|
||||
numerizer (0.1.1)
|
||||
|
|
@ -441,7 +447,7 @@ GEM
|
|||
octokit (4.6.2)
|
||||
sawyer (~> 0.8.0, >= 0.5.3)
|
||||
oj (2.17.4)
|
||||
omniauth (1.3.2)
|
||||
omniauth (1.4.2)
|
||||
hashie (>= 1.2, < 4)
|
||||
rack (>= 1.0, < 3)
|
||||
omniauth-auth0 (1.4.1)
|
||||
|
|
@ -758,7 +764,7 @@ GEM
|
|||
eventmachine (~> 1.0, >= 1.0.4)
|
||||
rack (>= 1, < 3)
|
||||
thor (0.19.4)
|
||||
thread_safe (0.3.5)
|
||||
thread_safe (0.3.6)
|
||||
tilt (2.0.6)
|
||||
timecop (0.8.1)
|
||||
timfel-krb5-auth (0.8.3)
|
||||
|
|
@ -878,6 +884,7 @@ DEPENDENCIES
|
|||
fuubar (~> 2.0.0)
|
||||
gemnasium-gitlab-service (~> 0.2)
|
||||
gemojione (~> 3.0)
|
||||
gitaly (~> 0.2.1)
|
||||
github-linguist (~> 4.7.0)
|
||||
gitlab-flowdock-git-hook (~> 1.0.1)
|
||||
gitlab-markup (~> 1.5.1)
|
||||
|
|
@ -886,7 +893,7 @@ DEPENDENCIES
|
|||
gollum-rugged_adapter (~> 0.4.2)
|
||||
gon (~> 6.1.0)
|
||||
google-api-client (~> 0.8.6)
|
||||
grape (~> 0.18.0)
|
||||
grape (~> 0.19.0)
|
||||
grape-entity (~> 0.6.0)
|
||||
haml_lint (~> 0.21.0)
|
||||
hamlit (~> 2.6.1)
|
||||
|
|
@ -915,12 +922,11 @@ DEPENDENCIES
|
|||
mousetrap-rails (~> 1.4.6)
|
||||
mysql2 (~> 0.3.16)
|
||||
net-ssh (~> 3.0.1)
|
||||
newrelic_rpm (~> 3.16)
|
||||
nokogiri (~> 1.6.7, >= 1.6.7.2)
|
||||
oauth2 (~> 1.2.0)
|
||||
octokit (~> 4.6.2)
|
||||
oj (~> 2.17.4)
|
||||
omniauth (~> 1.3.2)
|
||||
omniauth (~> 1.4.2)
|
||||
omniauth-auth0 (~> 1.4.1)
|
||||
omniauth-authentiq (~> 0.3.0)
|
||||
omniauth-azure-oauth2 (~> 0.0.6)
|
||||
|
|
@ -1011,4 +1017,4 @@ DEPENDENCIES
|
|||
wikicloth (= 0.8.1)
|
||||
|
||||
BUNDLED WITH
|
||||
1.14.3
|
||||
1.14.4
|
||||
|
|
|
|||
|
|
@ -6,13 +6,7 @@
|
|||
/* global AwardsHandler */
|
||||
/* global Aside */
|
||||
|
||||
function requireAll(context) { return context.keys().map(context); }
|
||||
|
||||
window.$ = window.jQuery = require('jquery');
|
||||
require('jquery-ui/ui/autocomplete');
|
||||
require('jquery-ui/ui/draggable');
|
||||
require('jquery-ui/ui/effect-highlight');
|
||||
require('jquery-ui/ui/sortable');
|
||||
require('jquery-ujs');
|
||||
require('vendor/jquery.endless-scroll');
|
||||
require('vendor/jquery.highlight');
|
||||
|
|
@ -46,15 +40,176 @@ require('./shortcuts_dashboard_navigation');
|
|||
require('./shortcuts_issuable');
|
||||
require('./shortcuts_network');
|
||||
require('vendor/jquery.nicescroll');
|
||||
requireAll(require.context('./behaviors', false, /^\.\/.*\.(js|es6)$/));
|
||||
requireAll(require.context('./blob', false, /^\.\/.*\.(js|es6)$/));
|
||||
requireAll(require.context('./templates', false, /^\.\/.*\.(js|es6)$/));
|
||||
requireAll(require.context('./commit', false, /^\.\/.*\.(js|es6)$/));
|
||||
requireAll(require.context('./extensions', false, /^\.\/.*\.(js|es6)$/));
|
||||
requireAll(require.context('./lib/utils', false, /^\.\/.*\.(js|es6)$/));
|
||||
requireAll(require.context('./u2f', false, /^\.\/.*\.(js|es6)$/));
|
||||
requireAll(require.context('./droplab', false, /^\.\/.*\.(js|es6)$/));
|
||||
requireAll(require.context('.', false, /^\.\/(?!application\.js).*\.(js|es6)$/));
|
||||
|
||||
// behaviors
|
||||
require('./behaviors/autosize');
|
||||
require('./behaviors/details_behavior');
|
||||
require('./behaviors/quick_submit');
|
||||
require('./behaviors/requires_input');
|
||||
require('./behaviors/toggler_behavior');
|
||||
|
||||
// blob
|
||||
require('./blob/blob_ci_yaml');
|
||||
require('./blob/blob_dockerfile_selector');
|
||||
require('./blob/blob_dockerfile_selectors');
|
||||
require('./blob/blob_file_dropzone');
|
||||
require('./blob/blob_gitignore_selector');
|
||||
require('./blob/blob_gitignore_selectors');
|
||||
require('./blob/blob_license_selector');
|
||||
require('./blob/blob_license_selectors');
|
||||
require('./blob/template_selector');
|
||||
|
||||
// templates
|
||||
require('./templates/issuable_template_selector');
|
||||
require('./templates/issuable_template_selectors');
|
||||
|
||||
// commit
|
||||
require('./commit/file.js');
|
||||
require('./commit/image_file.js');
|
||||
|
||||
// extensions
|
||||
require('./extensions/array');
|
||||
require('./extensions/custom_event');
|
||||
require('./extensions/element');
|
||||
require('./extensions/jquery');
|
||||
require('./extensions/object');
|
||||
|
||||
// lib/utils
|
||||
require('./lib/utils/animate');
|
||||
require('./lib/utils/bootstrap_linked_tabs');
|
||||
require('./lib/utils/common_utils');
|
||||
require('./lib/utils/datetime_utility');
|
||||
require('./lib/utils/notify');
|
||||
require('./lib/utils/pretty_time');
|
||||
require('./lib/utils/text_utility');
|
||||
require('./lib/utils/type_utility');
|
||||
require('./lib/utils/url_utility');
|
||||
|
||||
// u2f
|
||||
require('./u2f/authenticate');
|
||||
require('./u2f/error');
|
||||
require('./u2f/register');
|
||||
require('./u2f/util');
|
||||
|
||||
// droplab
|
||||
require('./droplab/droplab');
|
||||
require('./droplab/droplab_ajax');
|
||||
require('./droplab/droplab_ajax_filter');
|
||||
require('./droplab/droplab_filter');
|
||||
|
||||
// everything else
|
||||
require('./abuse_reports');
|
||||
require('./activities');
|
||||
require('./admin');
|
||||
require('./ajax_loading_spinner');
|
||||
require('./api');
|
||||
require('./aside');
|
||||
require('./autosave');
|
||||
require('./awards_handler');
|
||||
require('./breakpoints');
|
||||
require('./broadcast_message');
|
||||
require('./build');
|
||||
require('./build_artifacts');
|
||||
require('./build_variables');
|
||||
require('./ci_lint_editor');
|
||||
require('./commit');
|
||||
require('./commits');
|
||||
require('./compare');
|
||||
require('./compare_autocomplete');
|
||||
require('./confirm_danger_modal');
|
||||
require('./copy_as_gfm');
|
||||
require('./copy_to_clipboard');
|
||||
require('./create_label');
|
||||
require('./diff');
|
||||
require('./dispatcher');
|
||||
require('./dropzone_input');
|
||||
require('./due_date_select');
|
||||
require('./files_comment_button');
|
||||
require('./flash');
|
||||
require('./gfm_auto_complete');
|
||||
require('./gl_dropdown');
|
||||
require('./gl_field_error');
|
||||
require('./gl_field_errors');
|
||||
require('./gl_form');
|
||||
require('./group_avatar');
|
||||
require('./group_label_subscription');
|
||||
require('./groups_select');
|
||||
require('./header');
|
||||
require('./importer_status');
|
||||
require('./issuable');
|
||||
require('./issuable_context');
|
||||
require('./issuable_form');
|
||||
require('./issue');
|
||||
require('./issue_status_select');
|
||||
require('./issues_bulk_assignment');
|
||||
require('./label_manager');
|
||||
require('./labels');
|
||||
require('./labels_select');
|
||||
require('./layout_nav');
|
||||
require('./line_highlighter');
|
||||
require('./logo');
|
||||
require('./member_expiration_date');
|
||||
require('./members');
|
||||
require('./merge_request');
|
||||
require('./merge_request_tabs');
|
||||
require('./merge_request_widget');
|
||||
require('./merged_buttons');
|
||||
require('./milestone');
|
||||
require('./milestone_select');
|
||||
require('./mini_pipeline_graph_dropdown');
|
||||
require('./namespace_select');
|
||||
require('./new_branch_form');
|
||||
require('./new_commit_form');
|
||||
require('./notes');
|
||||
require('./notifications_dropdown');
|
||||
require('./notifications_form');
|
||||
require('./pager');
|
||||
require('./pipelines');
|
||||
require('./preview_markdown');
|
||||
require('./project');
|
||||
require('./project_avatar');
|
||||
require('./project_find_file');
|
||||
require('./project_fork');
|
||||
require('./project_import');
|
||||
require('./project_label_subscription');
|
||||
require('./project_new');
|
||||
require('./project_select');
|
||||
require('./project_show');
|
||||
require('./project_variables');
|
||||
require('./projects_list');
|
||||
require('./render_gfm');
|
||||
require('./render_math');
|
||||
require('./right_sidebar');
|
||||
require('./search');
|
||||
require('./search_autocomplete');
|
||||
require('./shortcuts');
|
||||
require('./shortcuts_blob');
|
||||
require('./shortcuts_dashboard_navigation');
|
||||
require('./shortcuts_find_file');
|
||||
require('./shortcuts_issuable');
|
||||
require('./shortcuts_navigation');
|
||||
require('./shortcuts_network');
|
||||
require('./signin_tabs_memoizer');
|
||||
require('./single_file_diff');
|
||||
require('./smart_interval');
|
||||
require('./snippets_list');
|
||||
require('./star');
|
||||
require('./subbable_resource');
|
||||
require('./subscription');
|
||||
require('./subscription_select');
|
||||
require('./syntax_highlight');
|
||||
require('./task_list');
|
||||
require('./todos');
|
||||
require('./tree');
|
||||
require('./user');
|
||||
require('./user_tabs');
|
||||
require('./username_validator');
|
||||
require('./users_select');
|
||||
require('./version_check_image');
|
||||
require('./visibility_select');
|
||||
require('./wikis');
|
||||
require('./zen_mode');
|
||||
|
||||
require('vendor/fuzzaldrin-plus');
|
||||
require('es6-promise').polyfill();
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,69 @@
|
|||
/* global Vue */
|
||||
require('./issue_card_inner');
|
||||
|
||||
const Store = gl.issueBoards.BoardsStore;
|
||||
|
||||
export default {
|
||||
name: 'BoardsIssueCard',
|
||||
template: `
|
||||
<li class="card"
|
||||
:class="{ 'user-can-drag': !disabled && issue.id, 'is-disabled': disabled || !issue.id, 'is-active': issueDetailVisible }"
|
||||
:index="index"
|
||||
:data-issue-id="issue.id"
|
||||
@mousedown="mouseDown"
|
||||
@mousemove="mouseMove"
|
||||
@mouseup="showIssue($event)">
|
||||
<issue-card-inner
|
||||
:list="list"
|
||||
:issue="issue"
|
||||
:issue-link-base="issueLinkBase"
|
||||
:root-path="rootPath" />
|
||||
</li>
|
||||
`,
|
||||
components: {
|
||||
'issue-card-inner': gl.issueBoards.IssueCardInner,
|
||||
},
|
||||
props: {
|
||||
list: Object,
|
||||
issue: Object,
|
||||
issueLinkBase: String,
|
||||
disabled: Boolean,
|
||||
index: Number,
|
||||
rootPath: String,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showDetail: false,
|
||||
detailIssue: Store.detail,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
issueDetailVisible() {
|
||||
return this.detailIssue.issue && this.detailIssue.issue.id === this.issue.id;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
mouseDown() {
|
||||
this.showDetail = true;
|
||||
},
|
||||
mouseMove() {
|
||||
this.showDetail = false;
|
||||
},
|
||||
showIssue(e) {
|
||||
const targetTagName = e.target.tagName.toLowerCase();
|
||||
|
||||
if (targetTagName === 'a' || targetTagName === 'button') return;
|
||||
|
||||
if (this.showDetail) {
|
||||
this.showDetail = false;
|
||||
|
||||
if (Store.detail.issue && Store.detail.issue.id === this.issue.id) {
|
||||
Store.detail.issue = {};
|
||||
} else {
|
||||
Store.detail.issue = this.issue;
|
||||
Store.detail.list = this.list;
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
/* eslint-disable comma-dangle, space-before-function-paren, dot-notation */
|
||||
/* global Vue */
|
||||
|
||||
require('./issue_card_inner');
|
||||
|
||||
(() => {
|
||||
const Store = gl.issueBoards.BoardsStore;
|
||||
|
||||
window.gl = window.gl || {};
|
||||
window.gl.issueBoards = window.gl.issueBoards || {};
|
||||
|
||||
gl.issueBoards.BoardCard = Vue.extend({
|
||||
template: '#js-board-list-card',
|
||||
components: {
|
||||
'issue-card-inner': gl.issueBoards.IssueCardInner,
|
||||
},
|
||||
props: {
|
||||
list: Object,
|
||||
issue: Object,
|
||||
issueLinkBase: String,
|
||||
disabled: Boolean,
|
||||
index: Number,
|
||||
rootPath: String,
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
showDetail: false,
|
||||
detailIssue: Store.detail
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
issueDetailVisible () {
|
||||
return this.detailIssue.issue && this.detailIssue.issue.id === this.issue.id;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
mouseDown () {
|
||||
this.showDetail = true;
|
||||
},
|
||||
mouseMove() {
|
||||
this.showDetail = false;
|
||||
},
|
||||
showIssue (e) {
|
||||
const targetTagName = e.target.tagName.toLowerCase();
|
||||
|
||||
if (targetTagName === 'a' || targetTagName === 'button') return;
|
||||
|
||||
if (this.showDetail) {
|
||||
this.showDetail = false;
|
||||
|
||||
if (Store.detail.issue && Store.detail.issue.id === this.issue.id) {
|
||||
Store.detail.issue = {};
|
||||
} else {
|
||||
Store.detail.issue = this.issue;
|
||||
Store.detail.list = this.list;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
|
@ -2,8 +2,8 @@
|
|||
/* global Vue */
|
||||
/* global Sortable */
|
||||
|
||||
require('./board_card');
|
||||
require('./board_new_issue');
|
||||
import boardNewIssue from './board_new_issue';
|
||||
import boardCard from './board_card';
|
||||
|
||||
(() => {
|
||||
const Store = gl.issueBoards.BoardsStore;
|
||||
|
|
@ -14,8 +14,8 @@ require('./board_new_issue');
|
|||
gl.issueBoards.BoardList = Vue.extend({
|
||||
template: '#js-board-list-template',
|
||||
components: {
|
||||
'board-card': gl.issueBoards.BoardCard,
|
||||
'board-new-issue': gl.issueBoards.BoardNewIssue
|
||||
boardCard,
|
||||
boardNewIssue,
|
||||
},
|
||||
props: {
|
||||
disabled: Boolean,
|
||||
|
|
@ -81,6 +81,12 @@ require('./board_new_issue');
|
|||
});
|
||||
}
|
||||
},
|
||||
toggleForm() {
|
||||
this.showIssueForm = !this.showIssueForm;
|
||||
},
|
||||
},
|
||||
created() {
|
||||
gl.IssueBoardsApp.$on(`hide-issue-form-${this.list.id}`, this.toggleForm);
|
||||
},
|
||||
mounted () {
|
||||
const options = gl.issueBoards.getBoardSortableDefaultOptions({
|
||||
|
|
@ -115,6 +121,9 @@ require('./board_new_issue');
|
|||
this.loadNextPage();
|
||||
}
|
||||
};
|
||||
}
|
||||
},
|
||||
beforeDestroy() {
|
||||
gl.IssueBoardsApp.$off(`hide-issue-form-${this.list.id}`, this.toggleForm);
|
||||
},
|
||||
});
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,92 @@
|
|||
/* global ListIssue */
|
||||
const Store = gl.issueBoards.BoardsStore;
|
||||
|
||||
export default {
|
||||
name: 'BoardNewIssue',
|
||||
props: {
|
||||
list: Object,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
title: '',
|
||||
error: false,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
submit(e) {
|
||||
e.preventDefault();
|
||||
if (this.title.trim() === '') return;
|
||||
|
||||
this.error = false;
|
||||
|
||||
const labels = this.list.label ? [this.list.label] : [];
|
||||
const issue = new ListIssue({
|
||||
title: this.title,
|
||||
labels,
|
||||
subscribed: true,
|
||||
});
|
||||
|
||||
this.list.newIssue(issue)
|
||||
.then(() => {
|
||||
// Need this because our jQuery very kindly disables buttons on ALL form submissions
|
||||
$(this.$refs.submitButton).enable();
|
||||
|
||||
Store.detail.issue = issue;
|
||||
Store.detail.list = this.list;
|
||||
})
|
||||
.catch(() => {
|
||||
// Need this because our jQuery very kindly disables buttons on ALL form submissions
|
||||
$(this.$refs.submitButton).enable();
|
||||
|
||||
// Remove the issue
|
||||
this.list.removeIssue(issue);
|
||||
|
||||
// Show error message
|
||||
this.error = true;
|
||||
});
|
||||
|
||||
this.cancel();
|
||||
},
|
||||
cancel() {
|
||||
this.title = '';
|
||||
gl.IssueBoardsApp.$emit(`hide-issue-form-${this.list.id}`);
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.$refs.input.focus();
|
||||
},
|
||||
template: `
|
||||
<div class="card board-new-issue-form">
|
||||
<form @submit="submit($event)">
|
||||
<div class="flash-container"
|
||||
v-if="error">
|
||||
<div class="flash-alert">
|
||||
An error occured. Please try again.
|
||||
</div>
|
||||
</div>
|
||||
<label class="label-light"
|
||||
:for="list.id + '-title'">
|
||||
Title
|
||||
</label>
|
||||
<input class="form-control"
|
||||
type="text"
|
||||
v-model="title"
|
||||
ref="input"
|
||||
:id="list.id + '-title'" />
|
||||
<div class="clearfix prepend-top-10">
|
||||
<button class="btn btn-success pull-left"
|
||||
type="submit"
|
||||
:disabled="title === ''"
|
||||
ref="submit-button">
|
||||
Submit issue
|
||||
</button>
|
||||
<button class="btn btn-default pull-right"
|
||||
type="button"
|
||||
@click="cancel">
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
`,
|
||||
};
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
/* eslint-disable comma-dangle, no-unused-vars */
|
||||
/* global Vue */
|
||||
/* global ListIssue */
|
||||
|
||||
(() => {
|
||||
const Store = gl.issueBoards.BoardsStore;
|
||||
|
||||
window.gl = window.gl || {};
|
||||
|
||||
gl.issueBoards.BoardNewIssue = Vue.extend({
|
||||
props: {
|
||||
list: Object,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
title: '',
|
||||
error: false
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
submit(e) {
|
||||
e.preventDefault();
|
||||
if (this.title.trim() === '') return;
|
||||
|
||||
this.error = false;
|
||||
|
||||
const labels = this.list.label ? [this.list.label] : [];
|
||||
const issue = new ListIssue({
|
||||
title: this.title,
|
||||
labels,
|
||||
subscribed: true
|
||||
});
|
||||
|
||||
this.list.newIssue(issue)
|
||||
.then((data) => {
|
||||
// Need this because our jQuery very kindly disables buttons on ALL form submissions
|
||||
$(this.$refs.submitButton).enable();
|
||||
|
||||
Store.detail.issue = issue;
|
||||
Store.detail.list = this.list;
|
||||
})
|
||||
.catch(() => {
|
||||
// Need this because our jQuery very kindly disables buttons on ALL form submissions
|
||||
$(this.$refs.submitButton).enable();
|
||||
|
||||
// Remove the issue
|
||||
this.list.removeIssue(issue);
|
||||
|
||||
// Show error message
|
||||
this.error = true;
|
||||
});
|
||||
|
||||
this.cancel();
|
||||
},
|
||||
cancel() {
|
||||
this.title = '';
|
||||
this.$parent.showIssueForm = false;
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$refs.input.focus();
|
||||
},
|
||||
});
|
||||
})();
|
||||
|
|
@ -123,14 +123,18 @@ class List {
|
|||
|
||||
if (listFrom) {
|
||||
this.issuesSize += 1;
|
||||
gl.boardService.moveIssue(issue.id, listFrom.id, this.id)
|
||||
.then(() => {
|
||||
listFrom.getIssues(false);
|
||||
});
|
||||
this.updateIssueLabel(issue, listFrom);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateIssueLabel(issue, listFrom) {
|
||||
gl.boardService.moveIssue(issue.id, listFrom.id, this.id)
|
||||
.then(() => {
|
||||
listFrom.getIssues(false);
|
||||
});
|
||||
}
|
||||
|
||||
findIssue (id) {
|
||||
return this.issues.filter(issue => issue.id === id)[0];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -92,9 +92,12 @@
|
|||
const issueLists = issue.getLists();
|
||||
const listLabels = issueLists.map(listIssue => listIssue.label);
|
||||
|
||||
// Add to new lists issues if it doesn't already exist
|
||||
if (!issueTo) {
|
||||
// Add to new lists issues if it doesn't already exist
|
||||
listTo.addIssue(issue, listFrom, newIndex);
|
||||
} else {
|
||||
listTo.updateIssueLabel(issue, listFrom);
|
||||
issueTo.removeLabel(listFrom.label);
|
||||
}
|
||||
|
||||
if (listTo.type === 'done') {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
var DOWN_BUILD_TRACE = '#down-build-trace';
|
||||
|
||||
this.Build = (function() {
|
||||
Build.interval = null;
|
||||
Build.timeout = null;
|
||||
|
||||
Build.state = null;
|
||||
|
||||
|
|
@ -31,7 +31,7 @@
|
|||
this.$scrollBottomBtn = $('#scroll-bottom');
|
||||
this.$buildRefreshAnimation = $('.js-build-refresh');
|
||||
|
||||
clearInterval(Build.interval);
|
||||
clearTimeout(Build.timeout);
|
||||
// Init breakpoint checker
|
||||
this.bp = Breakpoints.get();
|
||||
|
||||
|
|
@ -52,17 +52,7 @@
|
|||
this.getInitialBuildTrace();
|
||||
this.initScrollButtonAffix();
|
||||
}
|
||||
if (this.buildStatus === "running" || this.buildStatus === "pending") {
|
||||
Build.interval = setInterval((function(_this) {
|
||||
// Check for new build output if user still watching build page
|
||||
// Only valid for runnig build when output changes during time
|
||||
return function() {
|
||||
if (_this.location() === _this.pageUrl) {
|
||||
return _this.getBuildTrace();
|
||||
}
|
||||
};
|
||||
})(this), 4000);
|
||||
}
|
||||
this.invokeBuildTrace();
|
||||
}
|
||||
|
||||
Build.prototype.initSidebar = function() {
|
||||
|
|
@ -75,6 +65,22 @@
|
|||
return window.location.href.split("#")[0];
|
||||
};
|
||||
|
||||
Build.prototype.invokeBuildTrace = function() {
|
||||
var continueRefreshStatuses = ['running', 'pending'];
|
||||
// Continue to update build trace when build is running or pending
|
||||
if (continueRefreshStatuses.indexOf(this.buildStatus) !== -1) {
|
||||
// Check for new build output if user still watching build page
|
||||
// Only valid for runnig build when output changes during time
|
||||
Build.timeout = setTimeout((function(_this) {
|
||||
return function() {
|
||||
if (_this.location() === _this.pageUrl) {
|
||||
return _this.getBuildTrace();
|
||||
}
|
||||
};
|
||||
})(this), 4000);
|
||||
}
|
||||
};
|
||||
|
||||
Build.prototype.getInitialBuildTrace = function() {
|
||||
var removeRefreshStatuses = ['success', 'failed', 'canceled', 'skipped'];
|
||||
|
||||
|
|
@ -86,7 +92,7 @@
|
|||
if (window.location.hash === DOWN_BUILD_TRACE) {
|
||||
$("html,body").scrollTop(this.$buildTrace.height());
|
||||
}
|
||||
if (removeRefreshStatuses.indexOf(buildData.status) >= 0) {
|
||||
if (removeRefreshStatuses.indexOf(buildData.status) !== -1) {
|
||||
this.$buildRefreshAnimation.remove();
|
||||
return this.initScrollMonitor();
|
||||
}
|
||||
|
|
@ -105,6 +111,7 @@
|
|||
if (log.state) {
|
||||
_this.state = log.state;
|
||||
}
|
||||
_this.invokeBuildTrace();
|
||||
if (log.status === "running") {
|
||||
if (log.append) {
|
||||
$('.js-build-output').append(log.html);
|
||||
|
|
|
|||
|
|
@ -52,6 +52,30 @@
|
|||
return this.views[viewMode].call(this);
|
||||
};
|
||||
|
||||
ImageFile.prototype.initDraggable = function($el, padding, callback) {
|
||||
var dragging = false;
|
||||
var $body = $('body');
|
||||
var $offsetEl = $el.parent();
|
||||
|
||||
$el.off('mousedown').on('mousedown', function() {
|
||||
dragging = true;
|
||||
$body.css('user-select', 'none');
|
||||
});
|
||||
|
||||
$body.off('mouseup').off('mousemove').on('mouseup', function() {
|
||||
dragging = false;
|
||||
$body.css('user-select', '');
|
||||
})
|
||||
.on('mousemove', function(e) {
|
||||
var left;
|
||||
if (!dragging) return;
|
||||
|
||||
left = e.pageX - ($offsetEl.offset().left + padding);
|
||||
|
||||
callback(e, left);
|
||||
});
|
||||
};
|
||||
|
||||
prepareFrames = function(view) {
|
||||
var maxHeight, maxWidth;
|
||||
maxWidth = 0;
|
||||
|
|
@ -96,26 +120,30 @@
|
|||
maxHeight = 0;
|
||||
return $('.swipe.view', this.file).each((function(_this) {
|
||||
return function(index, view) {
|
||||
var ref;
|
||||
var $swipeWrap, $swipeBar, $swipeFrame, wrapPadding, ref;
|
||||
ref = prepareFrames(view), maxWidth = ref[0], maxHeight = ref[1];
|
||||
$('.swipe-frame', view).css({
|
||||
$swipeFrame = $('.swipe-frame', view);
|
||||
$swipeWrap = $('.swipe-wrap', view);
|
||||
$swipeBar = $('.swipe-bar', view);
|
||||
|
||||
$swipeFrame.css({
|
||||
width: maxWidth + 16,
|
||||
height: maxHeight + 28
|
||||
});
|
||||
$('.swipe-wrap', view).css({
|
||||
$swipeWrap.css({
|
||||
width: maxWidth + 1,
|
||||
height: maxHeight + 2
|
||||
});
|
||||
return $('.swipe-bar', view).css({
|
||||
$swipeBar.css({
|
||||
left: 0
|
||||
}).draggable({
|
||||
axis: 'x',
|
||||
containment: 'parent',
|
||||
drag: function(event) {
|
||||
return $('.swipe-wrap', view).width((maxWidth + 1) - $(this).position().left);
|
||||
},
|
||||
stop: function(event) {
|
||||
return $('.swipe-wrap', view).width((maxWidth + 1) - $(this).position().left);
|
||||
});
|
||||
|
||||
wrapPadding = parseInt($swipeWrap.css('right').replace('px', ''), 10);
|
||||
|
||||
_this.initDraggable($swipeBar, wrapPadding, function(e, left) {
|
||||
if (left > 0 && left < $swipeFrame.width() - (wrapPadding * 2)) {
|
||||
$swipeWrap.width((maxWidth + 1) - left);
|
||||
$swipeBar.css('left', left);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
|
@ -128,9 +156,14 @@
|
|||
dragTrackWidth = $('.drag-track', this.file).width() - $('.dragger', this.file).width();
|
||||
return $('.onion-skin.view', this.file).each((function(_this) {
|
||||
return function(index, view) {
|
||||
var ref;
|
||||
var $frame, $track, $dragger, $frameAdded, framePadding, ref, dragging = false;
|
||||
ref = prepareFrames(view), maxWidth = ref[0], maxHeight = ref[1];
|
||||
$('.onion-skin-frame', view).css({
|
||||
$frame = $('.onion-skin-frame', view);
|
||||
$frameAdded = $('.frame.added', view);
|
||||
$track = $('.drag-track', view);
|
||||
$dragger = $('.dragger', $track);
|
||||
|
||||
$frame.css({
|
||||
width: maxWidth + 16,
|
||||
height: maxHeight + 28
|
||||
});
|
||||
|
|
@ -138,16 +171,18 @@
|
|||
width: maxWidth + 1,
|
||||
height: maxHeight + 2
|
||||
});
|
||||
return $('.dragger', view).css({
|
||||
$dragger.css({
|
||||
left: dragTrackWidth
|
||||
}).draggable({
|
||||
axis: 'x',
|
||||
containment: 'parent',
|
||||
drag: function(event) {
|
||||
return $('.frame.added', view).css('opacity', $(this).position().left / dragTrackWidth);
|
||||
},
|
||||
stop: function(event) {
|
||||
return $('.frame.added', view).css('opacity', $(this).position().left / dragTrackWidth);
|
||||
});
|
||||
|
||||
framePadding = parseInt($frameAdded.css('right').replace('px', ''), 10);
|
||||
|
||||
_this.initDraggable($dragger, framePadding, function(e, left) {
|
||||
var opacity = left / dragTrackWidth;
|
||||
|
||||
if (opacity >= 0 && opacity <= 1) {
|
||||
$dragger.css('left', left);
|
||||
$frameAdded.css('opacity', opacity);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -69,7 +69,9 @@ const PipelineStore = require('./pipelines_store');
|
|||
return pipelinesService.all()
|
||||
.then(response => response.json())
|
||||
.then((json) => {
|
||||
this.store.storePipelines(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(() => {
|
||||
|
|
|
|||
|
|
@ -75,8 +75,11 @@ const DEFAULT_EVENT_OBJECTS = require('./default_event_objects');
|
|||
const eventItem = Object.assign({}, DEFAULT_EVENT_OBJECTS[stage.slug], item);
|
||||
|
||||
eventItem.totalTime = eventItem.total_time;
|
||||
eventItem.author.webUrl = eventItem.author.web_url;
|
||||
eventItem.author.avatarUrl = eventItem.author.avatar_url;
|
||||
|
||||
if (eventItem.author) {
|
||||
eventItem.author.webUrl = eventItem.author.web_url;
|
||||
eventItem.author.avatarUrl = eventItem.author.avatar_url;
|
||||
}
|
||||
|
||||
if (eventItem.created_at) eventItem.createdAt = eventItem.created_at;
|
||||
if (eventItem.short_sha) eventItem.shortSha = eventItem.short_sha;
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
/* global Shortcuts */
|
||||
|
||||
const ShortcutsBlob = require('./shortcuts_blob');
|
||||
const UserCallout = require('./user_callout');
|
||||
|
||||
(function() {
|
||||
var Dispatcher;
|
||||
|
|
@ -280,6 +281,9 @@ const ShortcutsBlob = require('./shortcuts_blob');
|
|||
case 'ci:lints:show':
|
||||
new gl.CILintEditor();
|
||||
break;
|
||||
case 'users:show':
|
||||
new UserCallout();
|
||||
break;
|
||||
}
|
||||
switch (path.first()) {
|
||||
case 'sessions':
|
||||
|
|
@ -316,6 +320,7 @@ const ShortcutsBlob = require('./shortcuts_blob');
|
|||
case 'dashboard':
|
||||
case 'root':
|
||||
shortcut_handler = new ShortcutsDashboardNavigation();
|
||||
new UserCallout();
|
||||
break;
|
||||
case 'profiles':
|
||||
new NotificationsForm();
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ module.exports = Vue.component('environment-component', {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="environments-container">
|
||||
<div class="content-list environments-container">
|
||||
<div class="environments-list-loading text-center" v-if="isLoading">
|
||||
<i class="fa fa-spinner fa-spin"></i>
|
||||
</div>
|
||||
|
|
@ -181,12 +181,12 @@ module.exports = Vue.component('environment-component', {
|
|||
:terminal-icon-svg="terminalIconSvg"
|
||||
:commit-icon-svg="commitIconSvg">
|
||||
</environment-table>
|
||||
|
||||
<table-pagination v-if="state.paginationInformation && state.paginationInformation.totalPages > 1"
|
||||
:change="changePage"
|
||||
:pageInfo="state.paginationInformation">
|
||||
</table-pagination>
|
||||
</div>
|
||||
|
||||
<table-pagination v-if="state.paginationInformation && state.paginationInformation.totalPages > 1"
|
||||
:change="changePage"
|
||||
:pageInfo="state.paginationInformation">
|
||||
</table-pagination>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
|
|
|
|||
|
|
@ -503,32 +503,30 @@ module.exports = Vue.component('environment-item', {
|
|||
</span>
|
||||
</td>
|
||||
|
||||
<td class="hidden-xs">
|
||||
<div v-if="!model.isFolder">
|
||||
<div class="btn-group" role="group">
|
||||
<actions-component v-if="hasManualActions && canCreateDeployment"
|
||||
:play-icon-svg="playIconSvg"
|
||||
:actions="manualActions">
|
||||
</actions-component>
|
||||
<td class="environments-actions">
|
||||
<div v-if="!model.isFolder" class="btn-group pull-right" role="group">
|
||||
<actions-component v-if="hasManualActions && canCreateDeployment"
|
||||
:play-icon-svg="playIconSvg"
|
||||
:actions="manualActions">
|
||||
</actions-component>
|
||||
|
||||
<external-url-component v-if="externalURL && canReadEnvironment"
|
||||
:external-url="externalURL">
|
||||
</external-url-component>
|
||||
<external-url-component v-if="externalURL && canReadEnvironment"
|
||||
:external-url="externalURL">
|
||||
</external-url-component>
|
||||
|
||||
<stop-component v-if="hasStopAction && canCreateDeployment"
|
||||
:stop-url="model.stop_path">
|
||||
</stop-component>
|
||||
<stop-component v-if="hasStopAction && canCreateDeployment"
|
||||
:stop-url="model.stop_path">
|
||||
</stop-component>
|
||||
|
||||
<terminal-button-component v-if="model && model.terminal_path"
|
||||
:terminal-icon-svg="terminalIconSvg"
|
||||
:terminal-path="model.terminal_path">
|
||||
</terminal-button-component>
|
||||
<terminal-button-component v-if="model && model.terminal_path"
|
||||
:terminal-icon-svg="terminalIconSvg"
|
||||
:terminal-path="model.terminal_path">
|
||||
</terminal-button-component>
|
||||
|
||||
<rollback-component v-if="canRetry && canCreateDeployment"
|
||||
:is-last-deployment="isLastDeployment"
|
||||
:retry-url="retryUrl">
|
||||
</rollback-component>
|
||||
</div>
|
||||
<rollback-component v-if="canRetry && canCreateDeployment"
|
||||
:is-last-deployment="isLastDeployment"
|
||||
:retry-url="retryUrl">
|
||||
</rollback-component>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ module.exports = Vue.component('environment-table-component', {
|
|||
},
|
||||
|
||||
template: `
|
||||
<table class="table ci-table environments">
|
||||
<table class="table ci-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="environments-name">Environment</th>
|
||||
|
|
@ -54,7 +54,7 @@ module.exports = Vue.component('environment-table-component', {
|
|||
<th class="environments-build">Job</th>
|
||||
<th class="environments-commit">Commit</th>
|
||||
<th class="environments-date">Updated</th>
|
||||
<th class="hidden-xs environments-actions"></th>
|
||||
<th class="environments-actions"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
|
|
|||
|
|
@ -1,16 +1,16 @@
|
|||
/* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, max-len, one-var, one-var-declaration-per-line, quotes, prefer-template, newline-per-chained-call, comma-dangle, new-cap, no-else-return, consistent-return */
|
||||
/* global FilesCommentButton */
|
||||
/* global notes */
|
||||
|
||||
(function() {
|
||||
let $commentButtonTemplate;
|
||||
var bind = function(fn, me) { return function() { return fn.apply(me, arguments); }; };
|
||||
|
||||
this.FilesCommentButton = (function() {
|
||||
var COMMENT_BUTTON_CLASS, COMMENT_BUTTON_TEMPLATE, DEBOUNCE_TIMEOUT_DURATION, EMPTY_CELL_CLASS, LINE_COLUMN_CLASSES, LINE_CONTENT_CLASS, LINE_HOLDER_CLASS, LINE_NUMBER_CLASS, OLD_LINE_CLASS, TEXT_FILE_SELECTOR, UNFOLDABLE_LINE_CLASS;
|
||||
var COMMENT_BUTTON_CLASS, EMPTY_CELL_CLASS, LINE_COLUMN_CLASSES, LINE_CONTENT_CLASS, LINE_HOLDER_CLASS, LINE_NUMBER_CLASS, OLD_LINE_CLASS, TEXT_FILE_SELECTOR, UNFOLDABLE_LINE_CLASS;
|
||||
|
||||
COMMENT_BUTTON_CLASS = '.add-diff-note';
|
||||
|
||||
COMMENT_BUTTON_TEMPLATE = _.template('<button name="button" type="submit" class="btn <%- COMMENT_BUTTON_CLASS %> js-add-diff-note-button" title="Add a comment to this line"><i class="fa fa-comment-o"></i></button>');
|
||||
|
||||
LINE_HOLDER_CLASS = '.line_holder';
|
||||
|
||||
LINE_NUMBER_CLASS = 'diff-line-num';
|
||||
|
|
@ -27,26 +27,29 @@
|
|||
|
||||
TEXT_FILE_SELECTOR = '.text-file';
|
||||
|
||||
DEBOUNCE_TIMEOUT_DURATION = 100;
|
||||
|
||||
function FilesCommentButton(filesContainerElement) {
|
||||
var debounce;
|
||||
this.filesContainerElement = filesContainerElement;
|
||||
this.destroy = bind(this.destroy, this);
|
||||
this.render = bind(this.render, this);
|
||||
this.VIEW_TYPE = $('input#view[type=hidden]').val();
|
||||
debounce = _.debounce(this.render, DEBOUNCE_TIMEOUT_DURATION);
|
||||
$(this.filesContainerElement).off('mouseover', LINE_COLUMN_CLASSES).off('mouseleave', LINE_COLUMN_CLASSES).on('mouseover', LINE_COLUMN_CLASSES, debounce).on('mouseleave', LINE_COLUMN_CLASSES, this.destroy);
|
||||
this.hideButton = bind(this.hideButton, this);
|
||||
this.isParallelView = notes.isParallelView();
|
||||
filesContainerElement.on('mouseover', LINE_COLUMN_CLASSES, this.render)
|
||||
.on('mouseleave', LINE_COLUMN_CLASSES, this.hideButton);
|
||||
}
|
||||
|
||||
FilesCommentButton.prototype.render = function(e) {
|
||||
var $currentTarget, buttonParentElement, lineContentElement, textFileElement;
|
||||
var $currentTarget, buttonParentElement, lineContentElement, textFileElement, $button;
|
||||
$currentTarget = $(e.currentTarget);
|
||||
|
||||
buttonParentElement = this.getButtonParent($currentTarget);
|
||||
if (!this.validateButtonParent(buttonParentElement)) return;
|
||||
lineContentElement = this.getLineContent($currentTarget);
|
||||
if (!this.validateLineContent(lineContentElement)) return;
|
||||
buttonParentElement = this.getButtonParent($currentTarget);
|
||||
|
||||
if (!this.validateButtonParent(buttonParentElement) || !this.validateLineContent(lineContentElement)) return;
|
||||
|
||||
$button = $(COMMENT_BUTTON_CLASS, buttonParentElement);
|
||||
buttonParentElement.addClass('is-over')
|
||||
.nextUntil(`.${LINE_CONTENT_CLASS}`).addClass('is-over');
|
||||
|
||||
if ($button.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
textFileElement = this.getTextFileElement($currentTarget);
|
||||
buttonParentElement.append(this.buildButton({
|
||||
|
|
@ -61,19 +64,16 @@
|
|||
}));
|
||||
};
|
||||
|
||||
FilesCommentButton.prototype.destroy = function(e) {
|
||||
if (this.isMovingToSameType(e)) {
|
||||
return;
|
||||
}
|
||||
$(COMMENT_BUTTON_CLASS, this.getButtonParent($(e.currentTarget))).remove();
|
||||
FilesCommentButton.prototype.hideButton = function(e) {
|
||||
var $currentTarget = $(e.currentTarget);
|
||||
var buttonParentElement = this.getButtonParent($currentTarget);
|
||||
|
||||
buttonParentElement.removeClass('is-over')
|
||||
.nextUntil(`.${LINE_CONTENT_CLASS}`).removeClass('is-over');
|
||||
};
|
||||
|
||||
FilesCommentButton.prototype.buildButton = function(buttonAttributes) {
|
||||
var initializedButtonTemplate;
|
||||
initializedButtonTemplate = COMMENT_BUTTON_TEMPLATE({
|
||||
COMMENT_BUTTON_CLASS: COMMENT_BUTTON_CLASS.substr(1)
|
||||
});
|
||||
return $(initializedButtonTemplate).attr({
|
||||
return $commentButtonTemplate.clone().attr({
|
||||
'data-noteable-type': buttonAttributes.noteableType,
|
||||
'data-noteable-id': buttonAttributes.noteableID,
|
||||
'data-commit-id': buttonAttributes.commitID,
|
||||
|
|
@ -86,14 +86,14 @@
|
|||
};
|
||||
|
||||
FilesCommentButton.prototype.getTextFileElement = function(hoveredElement) {
|
||||
return $(hoveredElement.closest(TEXT_FILE_SELECTOR));
|
||||
return hoveredElement.closest(TEXT_FILE_SELECTOR);
|
||||
};
|
||||
|
||||
FilesCommentButton.prototype.getLineContent = function(hoveredElement) {
|
||||
if (hoveredElement.hasClass(LINE_CONTENT_CLASS)) {
|
||||
return hoveredElement;
|
||||
}
|
||||
if (this.VIEW_TYPE === 'inline') {
|
||||
if (!this.isParallelView) {
|
||||
return $(hoveredElement).closest(LINE_HOLDER_CLASS).find("." + LINE_CONTENT_CLASS);
|
||||
} else {
|
||||
return $(hoveredElement).next("." + LINE_CONTENT_CLASS);
|
||||
|
|
@ -101,7 +101,7 @@
|
|||
};
|
||||
|
||||
FilesCommentButton.prototype.getButtonParent = function(hoveredElement) {
|
||||
if (this.VIEW_TYPE === 'inline') {
|
||||
if (!this.isParallelView) {
|
||||
if (hoveredElement.hasClass(OLD_LINE_CLASS)) {
|
||||
return hoveredElement;
|
||||
}
|
||||
|
|
@ -114,17 +114,8 @@
|
|||
}
|
||||
};
|
||||
|
||||
FilesCommentButton.prototype.isMovingToSameType = function(e) {
|
||||
var newButtonParent;
|
||||
newButtonParent = this.getButtonParent($(e.toElement));
|
||||
if (!newButtonParent) {
|
||||
return false;
|
||||
}
|
||||
return newButtonParent.is(this.getButtonParent($(e.currentTarget)));
|
||||
};
|
||||
|
||||
FilesCommentButton.prototype.validateButtonParent = function(buttonParentElement) {
|
||||
return !buttonParentElement.hasClass(EMPTY_CELL_CLASS) && !buttonParentElement.hasClass(UNFOLDABLE_LINE_CLASS) && $(COMMENT_BUTTON_CLASS, buttonParentElement).length === 0;
|
||||
return !buttonParentElement.hasClass(EMPTY_CELL_CLASS) && !buttonParentElement.hasClass(UNFOLDABLE_LINE_CLASS);
|
||||
};
|
||||
|
||||
FilesCommentButton.prototype.validateLineContent = function(lineContentElement) {
|
||||
|
|
@ -135,6 +126,8 @@
|
|||
})();
|
||||
|
||||
$.fn.filesCommentButton = function() {
|
||||
$commentButtonTemplate = $('<button name="button" type="submit" class="add-diff-note js-add-diff-note-button" title="Add a comment to this line"><i class="fa fa-comment-o"></i></button>');
|
||||
|
||||
if (!(this && (this.parent().data('can-create-note') != null))) {
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,7 +48,11 @@
|
|||
}
|
||||
|
||||
setOffset(offset = 0) {
|
||||
this.dropdown.style.left = `${offset}px`;
|
||||
if (window.innerWidth > 480) {
|
||||
this.dropdown.style.left = `${offset}px`;
|
||||
} else {
|
||||
this.dropdown.style.left = '0px';
|
||||
}
|
||||
}
|
||||
|
||||
renderContent(forceShowList = false) {
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@
|
|||
}
|
||||
|
||||
GitLabDropdownFilter.prototype.shouldBlur = function(keyCode) {
|
||||
return BLUR_KEYCODES.indexOf(keyCode) >= 0;
|
||||
return BLUR_KEYCODES.indexOf(keyCode) !== -1;
|
||||
};
|
||||
|
||||
GitLabDropdownFilter.prototype.filter = function(search_text) {
|
||||
|
|
@ -605,7 +605,7 @@
|
|||
var occurrences;
|
||||
occurrences = fuzzaldrinPlus.match(text, term);
|
||||
return text.split('').map(function(character, i) {
|
||||
if (indexOf.call(occurrences, i) >= 0) {
|
||||
if (indexOf.call(occurrences, i) !== -1) {
|
||||
return "<b>" + character + "</b>";
|
||||
} else {
|
||||
return character;
|
||||
|
|
@ -748,7 +748,7 @@
|
|||
return function(e) {
|
||||
var $listItems, PREV_INDEX, currentKeyCode;
|
||||
currentKeyCode = e.which;
|
||||
if (ARROW_KEY_CODES.indexOf(currentKeyCode) >= 0) {
|
||||
if (ARROW_KEY_CODES.indexOf(currentKeyCode) !== -1) {
|
||||
e.preventDefault();
|
||||
e.stopImmediatePropagation();
|
||||
PREV_INDEX = currentIndex;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
require('./stat_graph_contributors_graph');
|
||||
require('./stat_graph_contributors_util');
|
||||
require('./stat_graph_contributors');
|
||||
require('./stat_graph');
|
||||
import ContributorsStatGraph from './stat_graph_contributors';
|
||||
|
||||
// export to global scope
|
||||
window.ContributorsStatGraph = ContributorsStatGraph;
|
||||
|
|
|
|||
|
|
@ -1,18 +0,0 @@
|
|||
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-return-assign, max-len */
|
||||
(function() {
|
||||
this.StatGraph = (function() {
|
||||
function StatGraph() {}
|
||||
|
||||
StatGraph.log = {};
|
||||
|
||||
StatGraph.get_log = function() {
|
||||
return this.log;
|
||||
};
|
||||
|
||||
StatGraph.set_log = function(data) {
|
||||
return this.log = data;
|
||||
};
|
||||
|
||||
return StatGraph;
|
||||
})();
|
||||
}).call(window);
|
||||
|
|
@ -1,116 +1,111 @@
|
|||
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, one-var, camelcase, one-var-declaration-per-line, quotes, no-param-reassign, quote-props, comma-dangle, prefer-template, max-len, no-return-assign */
|
||||
/* global ContributorsGraph */
|
||||
/* global ContributorsAuthorGraph */
|
||||
/* global ContributorsMasterGraph */
|
||||
/* global ContributorsStatGraphUtil */
|
||||
/* global d3 */
|
||||
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, one-var, camelcase, one-var-declaration-per-line, quotes, no-param-reassign, quote-props, comma-dangle, prefer-template, max-len, no-return-assign, no-shadow */
|
||||
|
||||
window.d3 = require('d3');
|
||||
import d3 from 'd3';
|
||||
import { ContributorsGraph, ContributorsAuthorGraph, ContributorsMasterGraph } from './stat_graph_contributors_graph';
|
||||
import ContributorsStatGraphUtil from './stat_graph_contributors_util';
|
||||
|
||||
(function() {
|
||||
this.ContributorsStatGraph = (function() {
|
||||
function ContributorsStatGraph() {}
|
||||
export default (function() {
|
||||
function ContributorsStatGraph() {}
|
||||
|
||||
ContributorsStatGraph.prototype.init = function(log) {
|
||||
var author_commits, total_commits;
|
||||
this.parsed_log = ContributorsStatGraphUtil.parse_log(log);
|
||||
this.set_current_field("commits");
|
||||
total_commits = ContributorsStatGraphUtil.get_total_data(this.parsed_log, this.field);
|
||||
author_commits = ContributorsStatGraphUtil.get_author_data(this.parsed_log, this.field);
|
||||
this.add_master_graph(total_commits);
|
||||
this.add_authors_graph(author_commits);
|
||||
return this.change_date_header();
|
||||
};
|
||||
ContributorsStatGraph.prototype.init = function(log) {
|
||||
var author_commits, total_commits;
|
||||
this.parsed_log = ContributorsStatGraphUtil.parse_log(log);
|
||||
this.set_current_field("commits");
|
||||
total_commits = ContributorsStatGraphUtil.get_total_data(this.parsed_log, this.field);
|
||||
author_commits = ContributorsStatGraphUtil.get_author_data(this.parsed_log, this.field);
|
||||
this.add_master_graph(total_commits);
|
||||
this.add_authors_graph(author_commits);
|
||||
return this.change_date_header();
|
||||
};
|
||||
|
||||
ContributorsStatGraph.prototype.add_master_graph = function(total_data) {
|
||||
this.master_graph = new ContributorsMasterGraph(total_data);
|
||||
return this.master_graph.draw();
|
||||
};
|
||||
ContributorsStatGraph.prototype.add_master_graph = function(total_data) {
|
||||
this.master_graph = new ContributorsMasterGraph(total_data);
|
||||
return this.master_graph.draw();
|
||||
};
|
||||
|
||||
ContributorsStatGraph.prototype.add_authors_graph = function(author_data) {
|
||||
var limited_author_data;
|
||||
this.authors = [];
|
||||
limited_author_data = author_data.slice(0, 100);
|
||||
return _.each(limited_author_data, (function(_this) {
|
||||
return function(d) {
|
||||
var author_graph, author_header;
|
||||
author_header = _this.create_author_header(d);
|
||||
$(".contributors-list").append(author_header);
|
||||
_this.authors[d.author_name] = author_graph = new ContributorsAuthorGraph(d.dates);
|
||||
return author_graph.draw();
|
||||
};
|
||||
})(this));
|
||||
};
|
||||
ContributorsStatGraph.prototype.add_authors_graph = function(author_data) {
|
||||
var limited_author_data;
|
||||
this.authors = [];
|
||||
limited_author_data = author_data.slice(0, 100);
|
||||
return _.each(limited_author_data, (function(_this) {
|
||||
return function(d) {
|
||||
var author_graph, author_header;
|
||||
author_header = _this.create_author_header(d);
|
||||
$(".contributors-list").append(author_header);
|
||||
_this.authors[d.author_name] = author_graph = new ContributorsAuthorGraph(d.dates);
|
||||
return author_graph.draw();
|
||||
};
|
||||
})(this));
|
||||
};
|
||||
|
||||
ContributorsStatGraph.prototype.format_author_commit_info = function(author) {
|
||||
var commits;
|
||||
commits = $('<span/>', {
|
||||
"class": 'graph-author-commits-count'
|
||||
});
|
||||
commits.text(author.commits + " commits");
|
||||
return $('<span/>').append(commits);
|
||||
};
|
||||
ContributorsStatGraph.prototype.format_author_commit_info = function(author) {
|
||||
var commits;
|
||||
commits = $('<span/>', {
|
||||
"class": 'graph-author-commits-count'
|
||||
});
|
||||
commits.text(author.commits + " commits");
|
||||
return $('<span/>').append(commits);
|
||||
};
|
||||
|
||||
ContributorsStatGraph.prototype.create_author_header = function(author) {
|
||||
var author_commit_info, author_commit_info_span, author_email, author_name, list_item;
|
||||
list_item = $('<li/>', {
|
||||
"class": 'person',
|
||||
style: 'display: block;'
|
||||
});
|
||||
author_name = $('<h4>' + author.author_name + '</h4>');
|
||||
author_email = $('<p class="graph-author-email">' + author.author_email + '</p>');
|
||||
author_commit_info_span = $('<span/>', {
|
||||
"class": 'commits'
|
||||
});
|
||||
author_commit_info = this.format_author_commit_info(author);
|
||||
author_commit_info_span.html(author_commit_info);
|
||||
list_item.append(author_name);
|
||||
list_item.append(author_email);
|
||||
list_item.append(author_commit_info_span);
|
||||
return list_item;
|
||||
};
|
||||
ContributorsStatGraph.prototype.create_author_header = function(author) {
|
||||
var author_commit_info, author_commit_info_span, author_email, author_name, list_item;
|
||||
list_item = $('<li/>', {
|
||||
"class": 'person',
|
||||
style: 'display: block;'
|
||||
});
|
||||
author_name = $('<h4>' + author.author_name + '</h4>');
|
||||
author_email = $('<p class="graph-author-email">' + author.author_email + '</p>');
|
||||
author_commit_info_span = $('<span/>', {
|
||||
"class": 'commits'
|
||||
});
|
||||
author_commit_info = this.format_author_commit_info(author);
|
||||
author_commit_info_span.html(author_commit_info);
|
||||
list_item.append(author_name);
|
||||
list_item.append(author_email);
|
||||
list_item.append(author_commit_info_span);
|
||||
return list_item;
|
||||
};
|
||||
|
||||
ContributorsStatGraph.prototype.redraw_master = function() {
|
||||
var total_data;
|
||||
total_data = ContributorsStatGraphUtil.get_total_data(this.parsed_log, this.field);
|
||||
this.master_graph.set_data(total_data);
|
||||
return this.master_graph.redraw();
|
||||
};
|
||||
ContributorsStatGraph.prototype.redraw_master = function() {
|
||||
var total_data;
|
||||
total_data = ContributorsStatGraphUtil.get_total_data(this.parsed_log, this.field);
|
||||
this.master_graph.set_data(total_data);
|
||||
return this.master_graph.redraw();
|
||||
};
|
||||
|
||||
ContributorsStatGraph.prototype.redraw_authors = function() {
|
||||
var author_commits, x_domain;
|
||||
$("ol").html("");
|
||||
x_domain = ContributorsGraph.prototype.x_domain;
|
||||
author_commits = ContributorsStatGraphUtil.get_author_data(this.parsed_log, this.field, x_domain);
|
||||
return _.each(author_commits, (function(_this) {
|
||||
return function(d) {
|
||||
_this.redraw_author_commit_info(d);
|
||||
$(_this.authors[d.author_name].list_item).appendTo("ol");
|
||||
_this.authors[d.author_name].set_data(d.dates);
|
||||
return _this.authors[d.author_name].redraw();
|
||||
};
|
||||
})(this));
|
||||
};
|
||||
ContributorsStatGraph.prototype.redraw_authors = function() {
|
||||
var author_commits, x_domain;
|
||||
$("ol").html("");
|
||||
x_domain = ContributorsGraph.prototype.x_domain;
|
||||
author_commits = ContributorsStatGraphUtil.get_author_data(this.parsed_log, this.field, x_domain);
|
||||
return _.each(author_commits, (function(_this) {
|
||||
return function(d) {
|
||||
_this.redraw_author_commit_info(d);
|
||||
$(_this.authors[d.author_name].list_item).appendTo("ol");
|
||||
_this.authors[d.author_name].set_data(d.dates);
|
||||
return _this.authors[d.author_name].redraw();
|
||||
};
|
||||
})(this));
|
||||
};
|
||||
|
||||
ContributorsStatGraph.prototype.set_current_field = function(field) {
|
||||
return this.field = field;
|
||||
};
|
||||
ContributorsStatGraph.prototype.set_current_field = function(field) {
|
||||
return this.field = field;
|
||||
};
|
||||
|
||||
ContributorsStatGraph.prototype.change_date_header = function() {
|
||||
var print, print_date_format, x_domain;
|
||||
x_domain = ContributorsGraph.prototype.x_domain;
|
||||
print_date_format = d3.time.format("%B %e %Y");
|
||||
print = print_date_format(x_domain[0]) + " - " + print_date_format(x_domain[1]);
|
||||
return $("#date_header").text(print);
|
||||
};
|
||||
ContributorsStatGraph.prototype.change_date_header = function() {
|
||||
var print, print_date_format, x_domain;
|
||||
x_domain = ContributorsGraph.prototype.x_domain;
|
||||
print_date_format = d3.time.format("%B %e %Y");
|
||||
print = print_date_format(x_domain[0]) + " - " + print_date_format(x_domain[1]);
|
||||
return $("#date_header").text(print);
|
||||
};
|
||||
|
||||
ContributorsStatGraph.prototype.redraw_author_commit_info = function(author) {
|
||||
var author_commit_info, author_list_item;
|
||||
author_list_item = $(this.authors[author.author_name].list_item);
|
||||
author_commit_info = this.format_author_commit_info(author);
|
||||
return author_list_item.find("span").html(author_commit_info);
|
||||
};
|
||||
ContributorsStatGraph.prototype.redraw_author_commit_info = function(author) {
|
||||
var author_commit_info, author_list_item;
|
||||
author_list_item = $(this.authors[author.author_name].list_item);
|
||||
author_commit_info = this.format_author_commit_info(author);
|
||||
return author_list_item.find("span").html(author_commit_info);
|
||||
};
|
||||
|
||||
return ContributorsStatGraph;
|
||||
})();
|
||||
}).call(window);
|
||||
return ContributorsStatGraph;
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -1,276 +1,272 @@
|
|||
/* eslint-disable func-names, space-before-function-paren, one-var, no-var, prefer-rest-params, max-len, no-restricted-syntax, vars-on-top, no-use-before-define, no-param-reassign, new-cap, no-underscore-dangle, wrap-iife, comma-dangle, no-return-assign, prefer-arrow-callback, quotes, prefer-template, newline-per-chained-call, no-else-return */
|
||||
/* global d3 */
|
||||
/* global ContributorsGraph */
|
||||
/* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, max-len, no-restricted-syntax, vars-on-top, no-use-before-define, no-param-reassign, new-cap, no-underscore-dangle, wrap-iife, comma-dangle, no-return-assign, prefer-arrow-callback, quotes, prefer-template, newline-per-chained-call, no-else-return, no-shadow */
|
||||
|
||||
window.d3 = require('d3');
|
||||
import d3 from 'd3';
|
||||
|
||||
(function() {
|
||||
var bind = function(fn, me) { return function() { return fn.apply(me, arguments); }; },
|
||||
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;
|
||||
const bind = function(fn, me) { return function() { return fn.apply(me, arguments); }; };
|
||||
const 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; };
|
||||
const hasProp = {}.hasOwnProperty;
|
||||
|
||||
this.ContributorsGraph = (function() {
|
||||
function ContributorsGraph() {}
|
||||
export const ContributorsGraph = (function() {
|
||||
function ContributorsGraph() {}
|
||||
|
||||
ContributorsGraph.prototype.MARGIN = {
|
||||
top: 20,
|
||||
right: 20,
|
||||
bottom: 30,
|
||||
left: 50
|
||||
};
|
||||
ContributorsGraph.prototype.MARGIN = {
|
||||
top: 20,
|
||||
right: 20,
|
||||
bottom: 30,
|
||||
left: 50
|
||||
};
|
||||
|
||||
ContributorsGraph.prototype.x_domain = null;
|
||||
ContributorsGraph.prototype.x_domain = null;
|
||||
|
||||
ContributorsGraph.prototype.y_domain = null;
|
||||
ContributorsGraph.prototype.y_domain = null;
|
||||
|
||||
ContributorsGraph.prototype.dates = [];
|
||||
ContributorsGraph.prototype.dates = [];
|
||||
|
||||
ContributorsGraph.set_x_domain = function(data) {
|
||||
return ContributorsGraph.prototype.x_domain = data;
|
||||
};
|
||||
ContributorsGraph.set_x_domain = function(data) {
|
||||
return ContributorsGraph.prototype.x_domain = data;
|
||||
};
|
||||
|
||||
ContributorsGraph.set_y_domain = function(data) {
|
||||
return ContributorsGraph.prototype.y_domain = [
|
||||
0, d3.max(data, function(d) {
|
||||
return d.commits = d.commits || d.additions || d.deletions;
|
||||
})
|
||||
];
|
||||
};
|
||||
ContributorsGraph.set_y_domain = function(data) {
|
||||
return ContributorsGraph.prototype.y_domain = [
|
||||
0, d3.max(data, function(d) {
|
||||
return d.commits = d.commits || d.additions || d.deletions;
|
||||
})
|
||||
];
|
||||
};
|
||||
|
||||
ContributorsGraph.init_x_domain = function(data) {
|
||||
return ContributorsGraph.prototype.x_domain = d3.extent(data, function(d) {
|
||||
return d.date;
|
||||
});
|
||||
};
|
||||
ContributorsGraph.init_x_domain = function(data) {
|
||||
return ContributorsGraph.prototype.x_domain = d3.extent(data, function(d) {
|
||||
return d.date;
|
||||
});
|
||||
};
|
||||
|
||||
ContributorsGraph.init_y_domain = function(data) {
|
||||
return ContributorsGraph.prototype.y_domain = [
|
||||
0, d3.max(data, function(d) {
|
||||
return d.commits = d.commits || d.additions || d.deletions;
|
||||
})
|
||||
];
|
||||
};
|
||||
ContributorsGraph.init_y_domain = function(data) {
|
||||
return ContributorsGraph.prototype.y_domain = [
|
||||
0, d3.max(data, function(d) {
|
||||
return d.commits = d.commits || d.additions || d.deletions;
|
||||
})
|
||||
];
|
||||
};
|
||||
|
||||
ContributorsGraph.init_domain = function(data) {
|
||||
ContributorsGraph.init_x_domain(data);
|
||||
return ContributorsGraph.init_y_domain(data);
|
||||
};
|
||||
ContributorsGraph.init_domain = function(data) {
|
||||
ContributorsGraph.init_x_domain(data);
|
||||
return ContributorsGraph.init_y_domain(data);
|
||||
};
|
||||
|
||||
ContributorsGraph.set_dates = function(data) {
|
||||
return ContributorsGraph.prototype.dates = data;
|
||||
};
|
||||
ContributorsGraph.set_dates = function(data) {
|
||||
return ContributorsGraph.prototype.dates = data;
|
||||
};
|
||||
|
||||
ContributorsGraph.prototype.set_x_domain = function() {
|
||||
return this.x.domain(this.x_domain);
|
||||
};
|
||||
ContributorsGraph.prototype.set_x_domain = function() {
|
||||
return this.x.domain(this.x_domain);
|
||||
};
|
||||
|
||||
ContributorsGraph.prototype.set_y_domain = function() {
|
||||
return this.y.domain(this.y_domain);
|
||||
};
|
||||
ContributorsGraph.prototype.set_y_domain = function() {
|
||||
return this.y.domain(this.y_domain);
|
||||
};
|
||||
|
||||
ContributorsGraph.prototype.set_domain = function() {
|
||||
this.set_x_domain();
|
||||
return this.set_y_domain();
|
||||
};
|
||||
ContributorsGraph.prototype.set_domain = function() {
|
||||
this.set_x_domain();
|
||||
return this.set_y_domain();
|
||||
};
|
||||
|
||||
ContributorsGraph.prototype.create_scale = function(width, height) {
|
||||
this.x = d3.time.scale().range([0, width]).clamp(true);
|
||||
return this.y = d3.scale.linear().range([height, 0]).nice();
|
||||
};
|
||||
ContributorsGraph.prototype.create_scale = function(width, height) {
|
||||
this.x = d3.time.scale().range([0, width]).clamp(true);
|
||||
return this.y = d3.scale.linear().range([height, 0]).nice();
|
||||
};
|
||||
|
||||
ContributorsGraph.prototype.draw_x_axis = function() {
|
||||
return this.svg.append("g").attr("class", "x axis").attr("transform", "translate(0, " + this.height + ")").call(this.x_axis);
|
||||
};
|
||||
ContributorsGraph.prototype.draw_x_axis = function() {
|
||||
return this.svg.append("g").attr("class", "x axis").attr("transform", "translate(0, " + this.height + ")").call(this.x_axis);
|
||||
};
|
||||
|
||||
ContributorsGraph.prototype.draw_y_axis = function() {
|
||||
return this.svg.append("g").attr("class", "y axis").call(this.y_axis);
|
||||
};
|
||||
ContributorsGraph.prototype.draw_y_axis = function() {
|
||||
return this.svg.append("g").attr("class", "y axis").call(this.y_axis);
|
||||
};
|
||||
|
||||
ContributorsGraph.prototype.set_data = function(data) {
|
||||
return this.data = data;
|
||||
};
|
||||
ContributorsGraph.prototype.set_data = function(data) {
|
||||
return this.data = data;
|
||||
};
|
||||
|
||||
return ContributorsGraph;
|
||||
})();
|
||||
return ContributorsGraph;
|
||||
})();
|
||||
|
||||
this.ContributorsMasterGraph = (function(superClass) {
|
||||
extend(ContributorsMasterGraph, superClass);
|
||||
export const ContributorsMasterGraph = (function(superClass) {
|
||||
extend(ContributorsMasterGraph, superClass);
|
||||
|
||||
function ContributorsMasterGraph(data1) {
|
||||
this.data = data1;
|
||||
this.update_content = bind(this.update_content, this);
|
||||
this.width = $('.content').width() - 70;
|
||||
this.height = 200;
|
||||
this.x = null;
|
||||
this.y = null;
|
||||
this.x_axis = null;
|
||||
this.y_axis = null;
|
||||
this.area = null;
|
||||
this.svg = null;
|
||||
this.brush = null;
|
||||
this.x_max_domain = null;
|
||||
function ContributorsMasterGraph(data1) {
|
||||
this.data = data1;
|
||||
this.update_content = bind(this.update_content, this);
|
||||
this.width = $('.content').width() - 70;
|
||||
this.height = 200;
|
||||
this.x = null;
|
||||
this.y = null;
|
||||
this.x_axis = null;
|
||||
this.y_axis = null;
|
||||
this.area = null;
|
||||
this.svg = null;
|
||||
this.brush = null;
|
||||
this.x_max_domain = null;
|
||||
}
|
||||
|
||||
ContributorsMasterGraph.prototype.process_dates = function(data) {
|
||||
var dates;
|
||||
dates = this.get_dates(data);
|
||||
this.parse_dates(data);
|
||||
return ContributorsGraph.set_dates(dates);
|
||||
};
|
||||
|
||||
ContributorsMasterGraph.prototype.get_dates = function(data) {
|
||||
return _.pluck(data, 'date');
|
||||
};
|
||||
|
||||
ContributorsMasterGraph.prototype.parse_dates = function(data) {
|
||||
var parseDate;
|
||||
parseDate = d3.time.format("%Y-%m-%d").parse;
|
||||
return data.forEach(function(d) {
|
||||
return d.date = parseDate(d.date);
|
||||
});
|
||||
};
|
||||
|
||||
ContributorsMasterGraph.prototype.create_scale = function() {
|
||||
return ContributorsMasterGraph.__super__.create_scale.call(this, this.width, this.height);
|
||||
};
|
||||
|
||||
ContributorsMasterGraph.prototype.create_axes = function() {
|
||||
this.x_axis = d3.svg.axis().scale(this.x).orient("bottom");
|
||||
return this.y_axis = d3.svg.axis().scale(this.y).orient("left").ticks(5);
|
||||
};
|
||||
|
||||
ContributorsMasterGraph.prototype.create_svg = function() {
|
||||
return this.svg = d3.select("#contributors-master").append("svg").attr("width", this.width + this.MARGIN.left + this.MARGIN.right).attr("height", this.height + this.MARGIN.top + this.MARGIN.bottom).attr("class", "tint-box").append("g").attr("transform", "translate(" + this.MARGIN.left + "," + this.MARGIN.top + ")");
|
||||
};
|
||||
|
||||
ContributorsMasterGraph.prototype.create_area = function(x, y) {
|
||||
return this.area = d3.svg.area().x(function(d) {
|
||||
return x(d.date);
|
||||
}).y0(this.height).y1(function(d) {
|
||||
d.commits = d.commits || d.additions || d.deletions;
|
||||
return y(d.commits);
|
||||
}).interpolate("basis");
|
||||
};
|
||||
|
||||
ContributorsMasterGraph.prototype.create_brush = function() {
|
||||
return this.brush = d3.svg.brush().x(this.x).on("brushend", this.update_content);
|
||||
};
|
||||
|
||||
ContributorsMasterGraph.prototype.draw_path = function(data) {
|
||||
return this.svg.append("path").datum(data).attr("class", "area").attr("d", this.area);
|
||||
};
|
||||
|
||||
ContributorsMasterGraph.prototype.add_brush = function() {
|
||||
return this.svg.append("g").attr("class", "selection").call(this.brush).selectAll("rect").attr("height", this.height);
|
||||
};
|
||||
|
||||
ContributorsMasterGraph.prototype.update_content = function() {
|
||||
ContributorsGraph.set_x_domain(this.brush.empty() ? this.x_max_domain : this.brush.extent());
|
||||
return $("#brush_change").trigger('change');
|
||||
};
|
||||
|
||||
ContributorsMasterGraph.prototype.draw = function() {
|
||||
this.process_dates(this.data);
|
||||
this.create_scale();
|
||||
this.create_axes();
|
||||
ContributorsGraph.init_domain(this.data);
|
||||
this.x_max_domain = this.x_domain;
|
||||
this.set_domain();
|
||||
this.create_area(this.x, this.y);
|
||||
this.create_svg();
|
||||
this.create_brush();
|
||||
this.draw_path(this.data);
|
||||
this.draw_x_axis();
|
||||
this.draw_y_axis();
|
||||
return this.add_brush();
|
||||
};
|
||||
|
||||
ContributorsMasterGraph.prototype.redraw = function() {
|
||||
this.process_dates(this.data);
|
||||
ContributorsGraph.set_y_domain(this.data);
|
||||
this.set_y_domain();
|
||||
this.svg.select("path").datum(this.data);
|
||||
this.svg.select("path").attr("d", this.area);
|
||||
return this.svg.select(".y.axis").call(this.y_axis);
|
||||
};
|
||||
|
||||
return ContributorsMasterGraph;
|
||||
})(ContributorsGraph);
|
||||
|
||||
export const ContributorsAuthorGraph = (function(superClass) {
|
||||
extend(ContributorsAuthorGraph, superClass);
|
||||
|
||||
function ContributorsAuthorGraph(data1) {
|
||||
this.data = data1;
|
||||
// Don't split graph size in half for mobile devices.
|
||||
if ($(window).width() < 768) {
|
||||
this.width = $('.content').width() - 80;
|
||||
} else {
|
||||
this.width = ($('.content').width() / 2) - 100;
|
||||
}
|
||||
this.height = 200;
|
||||
this.x = null;
|
||||
this.y = null;
|
||||
this.x_axis = null;
|
||||
this.y_axis = null;
|
||||
this.area = null;
|
||||
this.svg = null;
|
||||
this.list_item = null;
|
||||
}
|
||||
|
||||
ContributorsMasterGraph.prototype.process_dates = function(data) {
|
||||
var dates;
|
||||
dates = this.get_dates(data);
|
||||
this.parse_dates(data);
|
||||
return ContributorsGraph.set_dates(dates);
|
||||
};
|
||||
ContributorsAuthorGraph.prototype.create_scale = function() {
|
||||
return ContributorsAuthorGraph.__super__.create_scale.call(this, this.width, this.height);
|
||||
};
|
||||
|
||||
ContributorsMasterGraph.prototype.get_dates = function(data) {
|
||||
return _.pluck(data, 'date');
|
||||
};
|
||||
ContributorsAuthorGraph.prototype.create_axes = function() {
|
||||
this.x_axis = d3.svg.axis().scale(this.x).orient("bottom").ticks(8);
|
||||
return this.y_axis = d3.svg.axis().scale(this.y).orient("left").ticks(5);
|
||||
};
|
||||
|
||||
ContributorsMasterGraph.prototype.parse_dates = function(data) {
|
||||
ContributorsAuthorGraph.prototype.create_area = function(x, y) {
|
||||
return this.area = d3.svg.area().x(function(d) {
|
||||
var parseDate;
|
||||
parseDate = d3.time.format("%Y-%m-%d").parse;
|
||||
return data.forEach(function(d) {
|
||||
return d.date = parseDate(d.date);
|
||||
});
|
||||
};
|
||||
return x(parseDate(d));
|
||||
}).y0(this.height).y1((function(_this) {
|
||||
return function(d) {
|
||||
if (_this.data[d] != null) {
|
||||
return y(_this.data[d]);
|
||||
} else {
|
||||
return y(0);
|
||||
}
|
||||
};
|
||||
})(this)).interpolate("basis");
|
||||
};
|
||||
|
||||
ContributorsMasterGraph.prototype.create_scale = function() {
|
||||
return ContributorsMasterGraph.__super__.create_scale.call(this, this.width, this.height);
|
||||
};
|
||||
ContributorsAuthorGraph.prototype.create_svg = function() {
|
||||
this.list_item = d3.selectAll(".person")[0].pop();
|
||||
return this.svg = d3.select(this.list_item).append("svg").attr("width", this.width + this.MARGIN.left + this.MARGIN.right).attr("height", this.height + this.MARGIN.top + this.MARGIN.bottom).attr("class", "spark").append("g").attr("transform", "translate(" + this.MARGIN.left + "," + this.MARGIN.top + ")");
|
||||
};
|
||||
|
||||
ContributorsMasterGraph.prototype.create_axes = function() {
|
||||
this.x_axis = d3.svg.axis().scale(this.x).orient("bottom");
|
||||
return this.y_axis = d3.svg.axis().scale(this.y).orient("left").ticks(5);
|
||||
};
|
||||
ContributorsAuthorGraph.prototype.draw_path = function(data) {
|
||||
return this.svg.append("path").datum(data).attr("class", "area-contributor").attr("d", this.area);
|
||||
};
|
||||
|
||||
ContributorsMasterGraph.prototype.create_svg = function() {
|
||||
return this.svg = d3.select("#contributors-master").append("svg").attr("width", this.width + this.MARGIN.left + this.MARGIN.right).attr("height", this.height + this.MARGIN.top + this.MARGIN.bottom).attr("class", "tint-box").append("g").attr("transform", "translate(" + this.MARGIN.left + "," + this.MARGIN.top + ")");
|
||||
};
|
||||
ContributorsAuthorGraph.prototype.draw = function() {
|
||||
this.create_scale();
|
||||
this.create_axes();
|
||||
this.set_domain();
|
||||
this.create_area(this.x, this.y);
|
||||
this.create_svg();
|
||||
this.draw_path(this.dates);
|
||||
this.draw_x_axis();
|
||||
return this.draw_y_axis();
|
||||
};
|
||||
|
||||
ContributorsMasterGraph.prototype.create_area = function(x, y) {
|
||||
return this.area = d3.svg.area().x(function(d) {
|
||||
return x(d.date);
|
||||
}).y0(this.height).y1(function(d) {
|
||||
d.commits = d.commits || d.additions || d.deletions;
|
||||
return y(d.commits);
|
||||
}).interpolate("basis");
|
||||
};
|
||||
ContributorsAuthorGraph.prototype.redraw = function() {
|
||||
this.set_domain();
|
||||
this.svg.select("path").datum(this.dates);
|
||||
this.svg.select("path").attr("d", this.area);
|
||||
this.svg.select(".x.axis").call(this.x_axis);
|
||||
return this.svg.select(".y.axis").call(this.y_axis);
|
||||
};
|
||||
|
||||
ContributorsMasterGraph.prototype.create_brush = function() {
|
||||
return this.brush = d3.svg.brush().x(this.x).on("brushend", this.update_content);
|
||||
};
|
||||
|
||||
ContributorsMasterGraph.prototype.draw_path = function(data) {
|
||||
return this.svg.append("path").datum(data).attr("class", "area").attr("d", this.area);
|
||||
};
|
||||
|
||||
ContributorsMasterGraph.prototype.add_brush = function() {
|
||||
return this.svg.append("g").attr("class", "selection").call(this.brush).selectAll("rect").attr("height", this.height);
|
||||
};
|
||||
|
||||
ContributorsMasterGraph.prototype.update_content = function() {
|
||||
ContributorsGraph.set_x_domain(this.brush.empty() ? this.x_max_domain : this.brush.extent());
|
||||
return $("#brush_change").trigger('change');
|
||||
};
|
||||
|
||||
ContributorsMasterGraph.prototype.draw = function() {
|
||||
this.process_dates(this.data);
|
||||
this.create_scale();
|
||||
this.create_axes();
|
||||
ContributorsGraph.init_domain(this.data);
|
||||
this.x_max_domain = this.x_domain;
|
||||
this.set_domain();
|
||||
this.create_area(this.x, this.y);
|
||||
this.create_svg();
|
||||
this.create_brush();
|
||||
this.draw_path(this.data);
|
||||
this.draw_x_axis();
|
||||
this.draw_y_axis();
|
||||
return this.add_brush();
|
||||
};
|
||||
|
||||
ContributorsMasterGraph.prototype.redraw = function() {
|
||||
this.process_dates(this.data);
|
||||
ContributorsGraph.set_y_domain(this.data);
|
||||
this.set_y_domain();
|
||||
this.svg.select("path").datum(this.data);
|
||||
this.svg.select("path").attr("d", this.area);
|
||||
return this.svg.select(".y.axis").call(this.y_axis);
|
||||
};
|
||||
|
||||
return ContributorsMasterGraph;
|
||||
})(ContributorsGraph);
|
||||
|
||||
this.ContributorsAuthorGraph = (function(superClass) {
|
||||
extend(ContributorsAuthorGraph, superClass);
|
||||
|
||||
function ContributorsAuthorGraph(data1) {
|
||||
this.data = data1;
|
||||
// Don't split graph size in half for mobile devices.
|
||||
if ($(window).width() < 768) {
|
||||
this.width = $('.content').width() - 80;
|
||||
} else {
|
||||
this.width = ($('.content').width() / 2) - 100;
|
||||
}
|
||||
this.height = 200;
|
||||
this.x = null;
|
||||
this.y = null;
|
||||
this.x_axis = null;
|
||||
this.y_axis = null;
|
||||
this.area = null;
|
||||
this.svg = null;
|
||||
this.list_item = null;
|
||||
}
|
||||
|
||||
ContributorsAuthorGraph.prototype.create_scale = function() {
|
||||
return ContributorsAuthorGraph.__super__.create_scale.call(this, this.width, this.height);
|
||||
};
|
||||
|
||||
ContributorsAuthorGraph.prototype.create_axes = function() {
|
||||
this.x_axis = d3.svg.axis().scale(this.x).orient("bottom").ticks(8);
|
||||
return this.y_axis = d3.svg.axis().scale(this.y).orient("left").ticks(5);
|
||||
};
|
||||
|
||||
ContributorsAuthorGraph.prototype.create_area = function(x, y) {
|
||||
return this.area = d3.svg.area().x(function(d) {
|
||||
var parseDate;
|
||||
parseDate = d3.time.format("%Y-%m-%d").parse;
|
||||
return x(parseDate(d));
|
||||
}).y0(this.height).y1((function(_this) {
|
||||
return function(d) {
|
||||
if (_this.data[d] != null) {
|
||||
return y(_this.data[d]);
|
||||
} else {
|
||||
return y(0);
|
||||
}
|
||||
};
|
||||
})(this)).interpolate("basis");
|
||||
};
|
||||
|
||||
ContributorsAuthorGraph.prototype.create_svg = function() {
|
||||
this.list_item = d3.selectAll(".person")[0].pop();
|
||||
return this.svg = d3.select(this.list_item).append("svg").attr("width", this.width + this.MARGIN.left + this.MARGIN.right).attr("height", this.height + this.MARGIN.top + this.MARGIN.bottom).attr("class", "spark").append("g").attr("transform", "translate(" + this.MARGIN.left + "," + this.MARGIN.top + ")");
|
||||
};
|
||||
|
||||
ContributorsAuthorGraph.prototype.draw_path = function(data) {
|
||||
return this.svg.append("path").datum(data).attr("class", "area-contributor").attr("d", this.area);
|
||||
};
|
||||
|
||||
ContributorsAuthorGraph.prototype.draw = function() {
|
||||
this.create_scale();
|
||||
this.create_axes();
|
||||
this.set_domain();
|
||||
this.create_area(this.x, this.y);
|
||||
this.create_svg();
|
||||
this.draw_path(this.dates);
|
||||
this.draw_x_axis();
|
||||
return this.draw_y_axis();
|
||||
};
|
||||
|
||||
ContributorsAuthorGraph.prototype.redraw = function() {
|
||||
this.set_domain();
|
||||
this.svg.select("path").datum(this.dates);
|
||||
this.svg.select("path").attr("d", this.area);
|
||||
this.svg.select(".x.axis").call(this.x_axis);
|
||||
return this.svg.select(".y.axis").call(this.y_axis);
|
||||
};
|
||||
|
||||
return ContributorsAuthorGraph;
|
||||
})(ContributorsGraph);
|
||||
}).call(window);
|
||||
return ContributorsAuthorGraph;
|
||||
})(ContributorsGraph);
|
||||
|
|
|
|||
|
|
@ -1,138 +1,137 @@
|
|||
/* eslint-disable func-names, space-before-function-paren, object-shorthand, no-var, one-var, camelcase, one-var-declaration-per-line, comma-dangle, no-param-reassign, no-return-assign, quotes, prefer-arrow-callback, wrap-iife, consistent-return, no-unused-vars, max-len, no-cond-assign, no-else-return, max-len */
|
||||
(function() {
|
||||
window.ContributorsStatGraphUtil = {
|
||||
parse_log: function(log) {
|
||||
var by_author, by_email, data, entry, i, len, total, normalized_email;
|
||||
total = {};
|
||||
by_author = {};
|
||||
by_email = {};
|
||||
for (i = 0, len = log.length; i < len; i += 1) {
|
||||
entry = log[i];
|
||||
if (total[entry.date] == null) {
|
||||
this.add_date(entry.date, total);
|
||||
}
|
||||
normalized_email = entry.author_email.toLowerCase();
|
||||
data = by_author[entry.author_name] || by_email[normalized_email];
|
||||
if (data == null) {
|
||||
data = this.add_author(entry, by_author, by_email);
|
||||
}
|
||||
if (!data[entry.date]) {
|
||||
this.add_date(entry.date, data);
|
||||
}
|
||||
this.store_data(entry, total[entry.date], data[entry.date]);
|
||||
|
||||
export default {
|
||||
parse_log: function(log) {
|
||||
var by_author, by_email, data, entry, i, len, total, normalized_email;
|
||||
total = {};
|
||||
by_author = {};
|
||||
by_email = {};
|
||||
for (i = 0, len = log.length; i < len; i += 1) {
|
||||
entry = log[i];
|
||||
if (total[entry.date] == null) {
|
||||
this.add_date(entry.date, total);
|
||||
}
|
||||
total = _.toArray(total);
|
||||
by_author = _.toArray(by_author);
|
||||
return {
|
||||
total: total,
|
||||
by_author: by_author
|
||||
};
|
||||
},
|
||||
add_date: function(date, collection) {
|
||||
collection[date] = {};
|
||||
return collection[date].date = date;
|
||||
},
|
||||
add_author: function(author, by_author, by_email) {
|
||||
var data, normalized_email;
|
||||
data = {};
|
||||
data.author_name = author.author_name;
|
||||
data.author_email = author.author_email;
|
||||
normalized_email = author.author_email.toLowerCase();
|
||||
by_author[author.author_name] = data;
|
||||
by_email[normalized_email] = data;
|
||||
return data;
|
||||
},
|
||||
store_data: function(entry, total, by_author) {
|
||||
this.store_commits(total, by_author);
|
||||
this.store_additions(entry, total, by_author);
|
||||
return this.store_deletions(entry, total, by_author);
|
||||
},
|
||||
store_commits: function(total, by_author) {
|
||||
this.add(total, "commits", 1);
|
||||
return this.add(by_author, "commits", 1);
|
||||
},
|
||||
add: function(collection, field, value) {
|
||||
if (collection[field] == null) {
|
||||
collection[field] = 0;
|
||||
normalized_email = entry.author_email.toLowerCase();
|
||||
data = by_author[entry.author_name] || by_email[normalized_email];
|
||||
if (data == null) {
|
||||
data = this.add_author(entry, by_author, by_email);
|
||||
}
|
||||
return collection[field] += value;
|
||||
},
|
||||
store_additions: function(entry, total, by_author) {
|
||||
if (entry.additions == null) {
|
||||
entry.additions = 0;
|
||||
}
|
||||
this.add(total, "additions", entry.additions);
|
||||
return this.add(by_author, "additions", entry.additions);
|
||||
},
|
||||
store_deletions: function(entry, total, by_author) {
|
||||
if (entry.deletions == null) {
|
||||
entry.deletions = 0;
|
||||
}
|
||||
this.add(total, "deletions", entry.deletions);
|
||||
return this.add(by_author, "deletions", entry.deletions);
|
||||
},
|
||||
get_total_data: function(parsed_log, field) {
|
||||
var log, total_data;
|
||||
log = parsed_log.total;
|
||||
total_data = this.pick_field(log, field);
|
||||
return _.sortBy(total_data, function(d) {
|
||||
return d.date;
|
||||
});
|
||||
},
|
||||
pick_field: function(log, field) {
|
||||
var total_data;
|
||||
total_data = [];
|
||||
_.each(log, function(d) {
|
||||
return total_data.push(_.pick(d, [field, 'date']));
|
||||
});
|
||||
return total_data;
|
||||
},
|
||||
get_author_data: function(parsed_log, field, date_range) {
|
||||
var author_data, log;
|
||||
if (date_range == null) {
|
||||
date_range = null;
|
||||
}
|
||||
log = parsed_log.by_author;
|
||||
author_data = [];
|
||||
_.each(log, (function(_this) {
|
||||
return function(log_entry) {
|
||||
var parsed_log_entry;
|
||||
parsed_log_entry = _this.parse_log_entry(log_entry, field, date_range);
|
||||
if (!_.isEmpty(parsed_log_entry.dates)) {
|
||||
return author_data.push(parsed_log_entry);
|
||||
}
|
||||
};
|
||||
})(this));
|
||||
return _.sortBy(author_data, function(d) {
|
||||
return d[field];
|
||||
}).reverse();
|
||||
},
|
||||
parse_log_entry: function(log_entry, field, date_range) {
|
||||
var parsed_entry;
|
||||
parsed_entry = {};
|
||||
parsed_entry.author_name = log_entry.author_name;
|
||||
parsed_entry.author_email = log_entry.author_email;
|
||||
parsed_entry.dates = {};
|
||||
parsed_entry.commits = parsed_entry.additions = parsed_entry.deletions = 0;
|
||||
_.each(_.omit(log_entry, 'author_name', 'author_email'), (function(_this) {
|
||||
return function(value, key) {
|
||||
if (_this.in_range(value.date, date_range)) {
|
||||
parsed_entry.dates[value.date] = value[field];
|
||||
parsed_entry.commits += value.commits;
|
||||
parsed_entry.additions += value.additions;
|
||||
return parsed_entry.deletions += value.deletions;
|
||||
}
|
||||
};
|
||||
})(this));
|
||||
return parsed_entry;
|
||||
},
|
||||
in_range: function(date, date_range) {
|
||||
var ref;
|
||||
if (date_range === null || (date_range[0] <= (ref = new Date(date)) && ref <= date_range[1])) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
if (!data[entry.date]) {
|
||||
this.add_date(entry.date, data);
|
||||
}
|
||||
this.store_data(entry, total[entry.date], data[entry.date]);
|
||||
}
|
||||
};
|
||||
}).call(window);
|
||||
total = _.toArray(total);
|
||||
by_author = _.toArray(by_author);
|
||||
return {
|
||||
total: total,
|
||||
by_author: by_author
|
||||
};
|
||||
},
|
||||
add_date: function(date, collection) {
|
||||
collection[date] = {};
|
||||
return collection[date].date = date;
|
||||
},
|
||||
add_author: function(author, by_author, by_email) {
|
||||
var data, normalized_email;
|
||||
data = {};
|
||||
data.author_name = author.author_name;
|
||||
data.author_email = author.author_email;
|
||||
normalized_email = author.author_email.toLowerCase();
|
||||
by_author[author.author_name] = data;
|
||||
by_email[normalized_email] = data;
|
||||
return data;
|
||||
},
|
||||
store_data: function(entry, total, by_author) {
|
||||
this.store_commits(total, by_author);
|
||||
this.store_additions(entry, total, by_author);
|
||||
return this.store_deletions(entry, total, by_author);
|
||||
},
|
||||
store_commits: function(total, by_author) {
|
||||
this.add(total, "commits", 1);
|
||||
return this.add(by_author, "commits", 1);
|
||||
},
|
||||
add: function(collection, field, value) {
|
||||
if (collection[field] == null) {
|
||||
collection[field] = 0;
|
||||
}
|
||||
return collection[field] += value;
|
||||
},
|
||||
store_additions: function(entry, total, by_author) {
|
||||
if (entry.additions == null) {
|
||||
entry.additions = 0;
|
||||
}
|
||||
this.add(total, "additions", entry.additions);
|
||||
return this.add(by_author, "additions", entry.additions);
|
||||
},
|
||||
store_deletions: function(entry, total, by_author) {
|
||||
if (entry.deletions == null) {
|
||||
entry.deletions = 0;
|
||||
}
|
||||
this.add(total, "deletions", entry.deletions);
|
||||
return this.add(by_author, "deletions", entry.deletions);
|
||||
},
|
||||
get_total_data: function(parsed_log, field) {
|
||||
var log, total_data;
|
||||
log = parsed_log.total;
|
||||
total_data = this.pick_field(log, field);
|
||||
return _.sortBy(total_data, function(d) {
|
||||
return d.date;
|
||||
});
|
||||
},
|
||||
pick_field: function(log, field) {
|
||||
var total_data;
|
||||
total_data = [];
|
||||
_.each(log, function(d) {
|
||||
return total_data.push(_.pick(d, [field, 'date']));
|
||||
});
|
||||
return total_data;
|
||||
},
|
||||
get_author_data: function(parsed_log, field, date_range) {
|
||||
var author_data, log;
|
||||
if (date_range == null) {
|
||||
date_range = null;
|
||||
}
|
||||
log = parsed_log.by_author;
|
||||
author_data = [];
|
||||
_.each(log, (function(_this) {
|
||||
return function(log_entry) {
|
||||
var parsed_log_entry;
|
||||
parsed_log_entry = _this.parse_log_entry(log_entry, field, date_range);
|
||||
if (!_.isEmpty(parsed_log_entry.dates)) {
|
||||
return author_data.push(parsed_log_entry);
|
||||
}
|
||||
};
|
||||
})(this));
|
||||
return _.sortBy(author_data, function(d) {
|
||||
return d[field];
|
||||
}).reverse();
|
||||
},
|
||||
parse_log_entry: function(log_entry, field, date_range) {
|
||||
var parsed_entry;
|
||||
parsed_entry = {};
|
||||
parsed_entry.author_name = log_entry.author_name;
|
||||
parsed_entry.author_email = log_entry.author_email;
|
||||
parsed_entry.dates = {};
|
||||
parsed_entry.commits = parsed_entry.additions = parsed_entry.deletions = 0;
|
||||
_.each(_.omit(log_entry, 'author_name', 'author_email'), (function(_this) {
|
||||
return function(value, key) {
|
||||
if (_this.in_range(value.date, date_range)) {
|
||||
parsed_entry.dates[value.date] = value[field];
|
||||
parsed_entry.commits += value.commits;
|
||||
parsed_entry.additions += value.additions;
|
||||
return parsed_entry.deletions += value.deletions;
|
||||
}
|
||||
};
|
||||
})(this));
|
||||
return parsed_entry;
|
||||
},
|
||||
in_range: function(date, date_range) {
|
||||
var ref;
|
||||
if (date_range === null || (date_range[0] <= (ref = new Date(date)) && ref <= date_range[1])) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@
|
|||
formData = $.param(formData);
|
||||
formAction = form.attr('action');
|
||||
issuesUrl = formAction;
|
||||
issuesUrl += "" + (formAction.indexOf('?') < 0 ? '?' : '&');
|
||||
issuesUrl += "" + (formAction.indexOf('?') === -1 ? '?' : '&');
|
||||
issuesUrl += formData;
|
||||
return gl.utils.visitUrl(issuesUrl);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -79,12 +79,12 @@ require('./comparison_pane');
|
|||
<div class='help-button pull-right'
|
||||
v-if='!showHelpState'
|
||||
@click='toggleHelpState(true)'>
|
||||
<i class='fa fa-question-circle'></i>
|
||||
<i class='fa fa-question-circle' aria-hidden='true'></i>
|
||||
</div>
|
||||
<div class='close-help-button pull-right'
|
||||
v-if='showHelpState'
|
||||
@click='toggleHelpState(false)'>
|
||||
<i class='fa fa-close'></i>
|
||||
<i class='fa fa-close' aria-hidden='true'></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class='time-tracking-content hide-collapsed'>
|
||||
|
|
|
|||
|
|
@ -39,8 +39,9 @@ require('../../subbable_resource');
|
|||
listenForSlashCommands() {
|
||||
$(document).on('ajax:success', '.gfm-form', (e, data) => {
|
||||
const subscribedCommands = ['spend_time', 'time_estimate'];
|
||||
const changedCommands = data.commands_changes;
|
||||
|
||||
const changedCommands = data.commands_changes
|
||||
? Object.keys(data.commands_changes)
|
||||
: [];
|
||||
if (changedCommands && _.intersection(subscribedCommands, changedCommands).length) {
|
||||
this.fetchIssuable();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -296,5 +296,58 @@
|
|||
* @returns {Boolean}
|
||||
*/
|
||||
w.gl.utils.convertPermissionToBoolean = permission => permission === 'true';
|
||||
|
||||
/**
|
||||
* Back Off exponential algorithm
|
||||
* backOff :: (Function<next, stop>, Number) -> Promise<Any, Error>
|
||||
*
|
||||
* @param {Function<next, stop>} fn function to be called
|
||||
* @param {Number} timeout
|
||||
* @return {Promise<Any, Error>}
|
||||
* @example
|
||||
* ```
|
||||
* backOff(function (next, stop) {
|
||||
* // Let's perform this function repeatedly for 60s or for the timeout provided.
|
||||
*
|
||||
* ourFunction()
|
||||
* .then(function (result) {
|
||||
* // continue if result is not what we need
|
||||
* next();
|
||||
*
|
||||
* // when result is what we need let's stop with the repetions and jump out of the cycle
|
||||
* stop(result);
|
||||
* })
|
||||
* .catch(function (error) {
|
||||
* // if there is an error, we need to stop this with an error.
|
||||
* stop(error);
|
||||
* })
|
||||
* }, 60000)
|
||||
* .then(function (result) {})
|
||||
* .catch(function (error) {
|
||||
* // deal with errors passed to stop()
|
||||
* })
|
||||
* ```
|
||||
*/
|
||||
w.gl.utils.backOff = (fn, timeout = 60000) => {
|
||||
const maxInterval = 32000;
|
||||
let nextInterval = 2000;
|
||||
|
||||
const startTime = Date.now();
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const stop = arg => ((arg instanceof Error) ? reject(arg) : resolve(arg));
|
||||
|
||||
const next = () => {
|
||||
if (Date.now() - startTime < timeout) {
|
||||
setTimeout(fn.bind(null, next, stop), nextInterval);
|
||||
nextInterval = Math.min(nextInterval + nextInterval, maxInterval);
|
||||
} else {
|
||||
reject(new Error('BACKOFF_TIMEOUT'));
|
||||
}
|
||||
};
|
||||
|
||||
fn(next, stop);
|
||||
});
|
||||
};
|
||||
})(window);
|
||||
}).call(window);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
/**
|
||||
* exports HTTP status codes
|
||||
*/
|
||||
|
||||
const statusCodes = {
|
||||
NO_CONTENT: 204,
|
||||
OK: 200,
|
||||
};
|
||||
|
||||
module.exports = statusCodes;
|
||||
|
|
@ -83,7 +83,7 @@ require('./smart_interval');
|
|||
return function() {
|
||||
var page;
|
||||
page = $('body').data('page').split(':').last();
|
||||
if (allowedPages.indexOf(page) < 0) {
|
||||
if (allowedPages.indexOf(page) === -1) {
|
||||
return _this.clearEventListeners();
|
||||
}
|
||||
};
|
||||
|
|
@ -233,7 +233,7 @@ require('./smart_interval');
|
|||
}
|
||||
$('.ci_widget').hide();
|
||||
allowed_states = ["failed", "canceled", "running", "pending", "success", "success_with_warnings", "skipped", "not_found"];
|
||||
if (indexOf.call(allowed_states, state) >= 0) {
|
||||
if (indexOf.call(allowed_states, state) !== -1) {
|
||||
$('.ci_widget.ci-' + state).show();
|
||||
switch (state) {
|
||||
case "failed":
|
||||
|
|
|
|||
|
|
@ -21,9 +21,9 @@
|
|||
});
|
||||
|
||||
$(document)
|
||||
.off('click', '.merge_when_build_succeeds')
|
||||
.on('click', '.merge_when_build_succeeds', () => {
|
||||
$('#merge_when_build_succeeds').val('1');
|
||||
.off('click', '.merge_when_pipeline_succeeds')
|
||||
.on('click', '.merge_when_pipeline_succeeds', () => {
|
||||
$('#merge_when_pipeline_succeeds').val('1');
|
||||
});
|
||||
|
||||
$(document)
|
||||
|
|
|
|||
|
|
@ -78,7 +78,6 @@
|
|||
} else {
|
||||
$(element).find('.assignee-icon').empty();
|
||||
}
|
||||
return $(element).effect('highlight');
|
||||
};
|
||||
|
||||
function Milestone() {
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@
|
|||
$value = $block.find('.value');
|
||||
$loading = $block.find('.block-loading').fadeOut();
|
||||
if (issueUpdateURL) {
|
||||
milestoneLinkTemplate = _.template('<a href="/<%- namespace %>/<%- path %>/milestones/<%- iid %>" class="bold has-tooltip" data-container="body" title="<%- remaining %>"><%- title %></a>');
|
||||
milestoneLinkTemplate = _.template('<a href="/<%- full_path %>/milestones/<%- iid %>" class="bold has-tooltip" data-container="body" title="<%- remaining %>"><%- title %></a>');
|
||||
milestoneLinkNoneTemplate = '<span class="no-value">None</span>';
|
||||
collapsedSidebarLabelTemplate = _.template('<span class="has-tooltip" data-container="body" title="<%- remaining %>" data-placement="left"> <%- title %> </span>');
|
||||
}
|
||||
|
|
@ -181,8 +181,7 @@
|
|||
$selectbox.hide();
|
||||
$value.css('display', '');
|
||||
if (data.milestone != null) {
|
||||
data.milestone.namespace = _this.currentProject.namespace;
|
||||
data.milestone.path = _this.currentProject.path;
|
||||
data.milestone.full_path = _this.currentProject.full_path;
|
||||
data.milestone.remaining = gl.utils.timeFor(data.milestone.due_date);
|
||||
$value.html(milestoneLinkTemplate(data.milestone));
|
||||
return $sidebarCollapsedValue.find('span').html(collapsedSidebarLabelTemplate(data.milestone));
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* eslint-disable func-names, space-before-function-paren, no-var, one-var, prefer-rest-params, max-len, vars-on-top, wrap-iife, consistent-return, comma-dangle, one-var-declaration-per-line, quotes, no-return-assign, prefer-arrow-callback, prefer-template, no-shadow, no-else-return, max-len */
|
||||
/* eslint-disable func-names, space-before-function-paren, no-var, one-var, prefer-rest-params, max-len, vars-on-top, wrap-iife, consistent-return, comma-dangle, one-var-declaration-per-line, quotes, no-return-assign, prefer-arrow-callback, prefer-template, no-shadow, no-else-return, max-len, object-shorthand */
|
||||
(function() {
|
||||
var bind = function(fn, me) { return function() { return fn.apply(me, arguments); }; },
|
||||
indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i += 1) { if (i in this && this[i] === item) return i; } return -1; };
|
||||
|
|
@ -20,15 +20,35 @@
|
|||
};
|
||||
|
||||
NewBranchForm.prototype.init = function() {
|
||||
if (this.name.val().length > 0) {
|
||||
if (this.name.length && this.name.val().length > 0) {
|
||||
return this.name.trigger('blur');
|
||||
}
|
||||
};
|
||||
|
||||
NewBranchForm.prototype.setupAvailableRefs = function(availableRefs) {
|
||||
return this.ref.autocomplete({
|
||||
source: availableRefs,
|
||||
minLength: 1
|
||||
var $branchSelect = $('.js-branch-select');
|
||||
|
||||
$branchSelect.glDropdown({
|
||||
data: availableRefs,
|
||||
filterable: true,
|
||||
filterByText: true,
|
||||
remote: false,
|
||||
fieldName: $branchSelect.data('field-name'),
|
||||
selectable: true,
|
||||
isSelectable: function(branch, $el) {
|
||||
return !$el.hasClass('is-active');
|
||||
},
|
||||
text: function(branch) {
|
||||
return branch;
|
||||
},
|
||||
id: function(branch) {
|
||||
return branch;
|
||||
},
|
||||
toggleLabel: function(branch) {
|
||||
if (branch) {
|
||||
return branch;
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -61,7 +81,7 @@
|
|||
var errorMessage, errors, formatter, unique, validator;
|
||||
this.branchNameError.empty();
|
||||
unique = function(values, value) {
|
||||
if (indexOf.call(values, value) < 0) {
|
||||
if (indexOf.call(values, value) === -1) {
|
||||
values.push(value);
|
||||
}
|
||||
return values;
|
||||
|
|
|
|||
|
|
@ -246,12 +246,21 @@ require('./task_list');
|
|||
};
|
||||
|
||||
Notes.prototype.handleCreateChanges = function(note) {
|
||||
var votesBlock;
|
||||
if (typeof note === 'undefined') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (note.commands_changes && note.commands_changes.indexOf('merge') !== -1) {
|
||||
$.get(mrRefreshWidgetUrl);
|
||||
if (note.commands_changes) {
|
||||
if ('merge' in note.commands_changes) {
|
||||
$.get(mrRefreshWidgetUrl);
|
||||
}
|
||||
|
||||
if ('emoji_award' in note.commands_changes) {
|
||||
votesBlock = $('.js-awards-block').eq(0);
|
||||
gl.awardsHandler.addAwardToEmojiBar(votesBlock, note.commands_changes.emoji_award);
|
||||
return gl.awardsHandler.scrollToAwards();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -262,26 +271,16 @@ require('./task_list');
|
|||
*/
|
||||
|
||||
Notes.prototype.renderNote = function(note) {
|
||||
var $notesList, votesBlock;
|
||||
var $notesList;
|
||||
if (!note.valid) {
|
||||
if (note.award) {
|
||||
new Flash('You have already awarded this emoji!', 'alert', this.parentTimeline);
|
||||
}
|
||||
else {
|
||||
if (note.errors.commands_only) {
|
||||
new Flash(note.errors.commands_only, 'notice', this.parentTimeline);
|
||||
this.refresh();
|
||||
}
|
||||
if (note.errors.commands_only) {
|
||||
new Flash(note.errors.commands_only, 'notice', this.parentTimeline);
|
||||
this.refresh();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (note.award) {
|
||||
votesBlock = $('.js-awards-block').eq(0);
|
||||
gl.awardsHandler.addAwardToEmojiBar(votesBlock, note.name);
|
||||
return gl.awardsHandler.scrollToAwards();
|
||||
// render note if it not present in loaded list
|
||||
// or skip if rendered
|
||||
} else if (this.isNewNote(note)) {
|
||||
|
||||
if (this.isNewNote(note)) {
|
||||
this.note_ids.push(note.id);
|
||||
$notesList = $('ul.main-notes-list');
|
||||
$notesList.append(note.html).syntaxHighlight();
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
this.onPickImageClick = this.onPickImageClick.bind(this);
|
||||
this.fileInput = $(input);
|
||||
this.modalCropImg = _.isString(this.modalCropImg) ? $(this.modalCropImg) : this.modalCropImg;
|
||||
this.fileInput.attr('name', `${this.fileInput.attr('name')}-trigger`).attr('id', `this.fileInput.attr('id')-trigger`);
|
||||
this.fileInput.attr('name', `${this.fileInput.attr('name')}-trigger`).attr('id', `${this.fileInput.attr('id')}-trigger`);
|
||||
this.exportWidth = exportWidth;
|
||||
this.exportHeight = exportHeight;
|
||||
this.cropBoxWidth = cropBoxWidth;
|
||||
|
|
|
|||
|
|
@ -84,13 +84,14 @@
|
|||
}
|
||||
|
||||
$(function() {
|
||||
$(document).on('focusout.ssh_key', '#key_key', function() {
|
||||
$(document).on('input.ssh_key', '#key_key', function() {
|
||||
const $title = $('#key_title');
|
||||
const comment = $(this).val().match(/^\S+ \S+ (.+)\n?$/);
|
||||
if (comment && comment.length > 1 && $title.val() === '') {
|
||||
|
||||
// Extract the SSH Key title from its comment
|
||||
if (comment && comment.length > 1) {
|
||||
return $title.val(comment[1]).change();
|
||||
}
|
||||
// Extract the SSH Key title from its comment
|
||||
});
|
||||
if (global.utils.getPagePath() === 'profiles') {
|
||||
return new Profile();
|
||||
|
|
|
|||
|
|
@ -1,3 +1,2 @@
|
|||
// require everything else in this directory
|
||||
function requireAll(context) { return context.keys().map(context); }
|
||||
requireAll(require.context('.', false, /^\.\/(?!profile_bundle).*\.(js|es6)$/));
|
||||
require('./gl_crop');
|
||||
require('./profile');
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@
|
|||
if ($('input[name="ref"]').length) {
|
||||
var $form = $dropdown.closest('form');
|
||||
var action = $form.attr('action');
|
||||
var divider = action.indexOf('?') < 0 ? '?' : '&';
|
||||
var divider = action.indexOf('?') === -1 ? '?' : '&';
|
||||
gl.utils.visitUrl(action + '' + divider + '' + $form.serialize());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,9 @@
|
|||
// Do not update if one dropdown has not selected any option
|
||||
if (!($allowedToMergeInput.length && $allowedToPushInput.length)) return;
|
||||
|
||||
this.$allowedToMergeDropdown.disable();
|
||||
this.$allowedToPushDropdown.disable();
|
||||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: this.$wrap.data('url'),
|
||||
|
|
@ -53,13 +56,13 @@
|
|||
}]
|
||||
}
|
||||
},
|
||||
success: () => {
|
||||
this.$wrap.effect('highlight');
|
||||
},
|
||||
error() {
|
||||
$.scrollTo(0);
|
||||
new Flash('Failed to update branch!');
|
||||
}
|
||||
}).always(() => {
|
||||
this.$allowedToMergeDropdown.enable();
|
||||
this.$allowedToPushDropdown.enable();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
// require everything else in this directory
|
||||
function requireAll(context) { return context.keys().map(context); }
|
||||
requireAll(require.context('.', false, /^\.\/(?!protected_branches_bundle).*\.(js|es6)$/));
|
||||
require('./protected_branch_access_dropdown');
|
||||
require('./protected_branch_create');
|
||||
require('./protected_branch_dropdown');
|
||||
require('./protected_branch_edit');
|
||||
require('./protected_branch_edit_list');
|
||||
|
|
|
|||
|
|
@ -1,10 +1,6 @@
|
|||
/* eslint-disable func-names, space-before-function-paren, prefer-arrow-callback, no-var, quotes, max-len */
|
||||
/* global ace */
|
||||
|
||||
// require everything else in this directory
|
||||
function requireAll(context) { return context.keys().map(context); }
|
||||
requireAll(require.context('.', false, /^\.\/(?!snippet_bundle).*\.(js|es6)$/));
|
||||
|
||||
(function() {
|
||||
$(function() {
|
||||
var editor = ace.edit("editor");
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
/* global Flash */
|
||||
require('vendor/task_list');
|
||||
|
||||
class TaskList {
|
||||
|
|
@ -6,6 +7,16 @@ class TaskList {
|
|||
this.dataType = options.dataType;
|
||||
this.fieldName = options.fieldName;
|
||||
this.onSuccess = options.onSuccess || (() => {});
|
||||
this.onError = function showFlash(response) {
|
||||
let errorMessages = '';
|
||||
|
||||
if (response.responseJSON) {
|
||||
errorMessages = response.responseJSON.errors.join(' ');
|
||||
}
|
||||
|
||||
return new Flash(errorMessages || 'Update failed', 'alert');
|
||||
};
|
||||
|
||||
this.init();
|
||||
}
|
||||
|
||||
|
|
@ -32,6 +43,7 @@ class TaskList {
|
|||
url: $target.data('update-url') || $('form.js-issuable-update').attr('action'),
|
||||
data: patchData,
|
||||
success: this.onSuccess,
|
||||
error: this.onError,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,58 @@
|
|||
/* global Cookies */
|
||||
|
||||
const userCalloutElementName = '.user-callout';
|
||||
const closeButton = '.close-user-callout';
|
||||
const userCalloutBtn = '.user-callout-btn';
|
||||
const userCalloutSvgAttrName = 'callout-svg';
|
||||
|
||||
const USER_CALLOUT_COOKIE = 'user_callout_dismissed';
|
||||
|
||||
const USER_CALLOUT_TEMPLATE = `
|
||||
<div class="bordered-box landing content-block">
|
||||
<button class="btn btn-default close close-user-callout" type="button">
|
||||
<i class="fa fa-times dismiss-icon"></i>
|
||||
</button>
|
||||
<div class="row">
|
||||
<div class="col-sm-3 col-xs-12 svg-container">
|
||||
</div>
|
||||
<div class="col-sm-8 col-xs-12 inner-content">
|
||||
<h4>
|
||||
Customize your experience
|
||||
</h4>
|
||||
<p>
|
||||
Change syntax themes, default project pages, and more in preferences.
|
||||
</p>
|
||||
<a class="btn user-callout-btn" href="/profile/preferences">Check it out</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
class UserCallout {
|
||||
constructor() {
|
||||
this.isCalloutDismissed = Cookies.get(USER_CALLOUT_COOKIE);
|
||||
this.userCalloutBody = $(userCalloutElementName);
|
||||
this.userCalloutSvg = $(userCalloutElementName).attr(userCalloutSvgAttrName);
|
||||
$(userCalloutElementName).removeAttr(userCalloutSvgAttrName);
|
||||
this.init();
|
||||
}
|
||||
|
||||
init() {
|
||||
const $template = $(USER_CALLOUT_TEMPLATE);
|
||||
if (!this.isCalloutDismissed || this.isCalloutDismissed === 'false') {
|
||||
$template.find('.svg-container').append(this.userCalloutSvg);
|
||||
this.userCalloutBody.append($template);
|
||||
$template.find(closeButton).on('click', e => this.dismissCallout(e));
|
||||
$template.find(userCalloutBtn).on('click', e => this.dismissCallout(e));
|
||||
}
|
||||
}
|
||||
|
||||
dismissCallout(e) {
|
||||
Cookies.set(USER_CALLOUT_COOKIE, 'true');
|
||||
const $currentTarget = $(e.currentTarget);
|
||||
if ($currentTarget.hasClass('close-user-callout')) {
|
||||
this.userCalloutBody.empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = UserCallout;
|
||||
|
|
@ -1,3 +1 @@
|
|||
// require everything else in this directory
|
||||
function requireAll(context) { return context.keys().map(context); }
|
||||
requireAll(require.context('.', false, /^\.\/(?!users_bundle).*\.(js|es6)$/));
|
||||
require('./calendar');
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/* global Vue, Flash, gl */
|
||||
/* eslint-disable no-param-reassign */
|
||||
/* eslint-disable no-param-reassign, no-alert */
|
||||
|
||||
((gl) => {
|
||||
gl.VuePipelineActions = Vue.extend({
|
||||
|
|
@ -16,21 +16,33 @@
|
|||
download(name) {
|
||||
return `Download ${name} artifacts`;
|
||||
},
|
||||
|
||||
/**
|
||||
* Shows a dialog when the user clicks in the cancel button.
|
||||
* We need to prevent the default behavior and stop propagation because the
|
||||
* link relies on UJS.
|
||||
*
|
||||
* @param {Event} event
|
||||
*/
|
||||
confirmAction(event) {
|
||||
if (!confirm('Are you sure you want to cancel this pipeline?')) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
},
|
||||
},
|
||||
template: `
|
||||
<td class="pipeline-actions hidden-xs">
|
||||
<div class="controls pull-right">
|
||||
<div class="btn-group inline">
|
||||
<div class="btn-group">
|
||||
<td class="pipeline-actions">
|
||||
<div class="pull-right">
|
||||
<div class="btn-group">
|
||||
<div class="btn-group" v-if="actions">
|
||||
<button
|
||||
v-if='actions'
|
||||
class="dropdown-toggle btn btn-default has-tooltip js-pipeline-dropdown-manual-actions"
|
||||
data-toggle="dropdown"
|
||||
title="Manual job"
|
||||
data-placement="top"
|
||||
aria-label="Manual job"
|
||||
>
|
||||
<span v-html='svgs.iconPlay' aria-hidden="true"></span>
|
||||
aria-label="Manual job">
|
||||
<span v-html="svgs.iconPlay" aria-hidden="true"></span>
|
||||
<i class="fa fa-caret-down" aria-hidden="true"></i>
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-menu-align-right">
|
||||
|
|
@ -38,23 +50,21 @@
|
|||
<a
|
||||
rel="nofollow"
|
||||
data-method="post"
|
||||
:href='action.path'
|
||||
>
|
||||
<span v-html='svgs.iconPlay' aria-hidden="true"></span>
|
||||
:href="action.path">
|
||||
<span v-html="svgs.iconPlay" aria-hidden="true"></span>
|
||||
<span>{{action.name}}</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="btn-group">
|
||||
|
||||
<div class="btn-group" v-if="artifacts">
|
||||
<button
|
||||
v-if='artifacts'
|
||||
class="dropdown-toggle btn btn-default build-artifacts has-tooltip js-pipeline-dropdown-download"
|
||||
title="Artifacts"
|
||||
data-placement="top"
|
||||
data-toggle="dropdown"
|
||||
aria-label="Artifacts"
|
||||
>
|
||||
aria-label="Artifacts">
|
||||
<i class="fa fa-download" aria-hidden="true"></i>
|
||||
<i class="fa fa-caret-down" aria-hidden="true"></i>
|
||||
</button>
|
||||
|
|
@ -62,41 +72,39 @@
|
|||
<li v-for='artifact in pipeline.details.artifacts'>
|
||||
<a
|
||||
rel="nofollow"
|
||||
download
|
||||
:href='artifact.path'
|
||||
>
|
||||
:href="artifact.path">
|
||||
<i class="fa fa-download" aria-hidden="true"></i>
|
||||
<span>{{download(artifact.name)}}</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cancel-retry-btns inline">
|
||||
<a
|
||||
v-if='pipeline.flags.retryable'
|
||||
class="btn has-tooltip"
|
||||
title="Retry"
|
||||
rel="nofollow"
|
||||
data-method="post"
|
||||
data-placement="top"
|
||||
data-toggle="dropdown"
|
||||
:href='pipeline.retry_path'
|
||||
aria-label="Retry">
|
||||
<i class="fa fa-repeat" aria-hidden="true"></i>
|
||||
</a>
|
||||
<a
|
||||
v-if='pipeline.flags.cancelable'
|
||||
class="btn btn-remove has-tooltip"
|
||||
title="Cancel"
|
||||
rel="nofollow"
|
||||
data-method="post"
|
||||
data-placement="top"
|
||||
data-toggle="dropdown"
|
||||
:href='pipeline.cancel_path'
|
||||
aria-label="Cancel">
|
||||
<i class="fa fa-remove" aria-hidden="true"></i>
|
||||
</a>
|
||||
<div class="btn-group" v-if="pipeline.flags.retryable">
|
||||
<a
|
||||
class="btn btn-default btn-retry has-tooltip"
|
||||
title="Retry"
|
||||
rel="nofollow"
|
||||
data-method="post"
|
||||
data-placement="top"
|
||||
data-toggle="dropdown"
|
||||
:href='pipeline.retry_path'
|
||||
aria-label="Retry">
|
||||
<i class="fa fa-repeat" aria-hidden="true"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="btn-group" v-if="pipeline.flags.cancelable">
|
||||
<a
|
||||
class="btn btn-remove has-tooltip"
|
||||
title="Cancel"
|
||||
rel="nofollow"
|
||||
data-method="post"
|
||||
data-placement="top"
|
||||
data-toggle="dropdown"
|
||||
:href='pipeline.cancel_path'
|
||||
aria-label="Cancel">
|
||||
<i class="fa fa-remove" aria-hidden="true"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
|
|
|
|||
|
|
@ -45,18 +45,15 @@ const CommitPipelinesStoreWithTimeAgo = require('../commit/pipelines/pipelines_s
|
|||
|
||||
methods: {
|
||||
/**
|
||||
* Changes the URL according to the pagination component.
|
||||
* Will change the page number and update the URL.
|
||||
*
|
||||
* If no scope is provided, 'all' is assumed.
|
||||
*
|
||||
* Pagination component sends "null" when no scope is provided.
|
||||
*
|
||||
* @param {Number} pagenum
|
||||
* @param {String} apiScope = 'all'
|
||||
* @param {Number} pageNumber desired page to go to.
|
||||
*/
|
||||
change(pagenum, apiScope) {
|
||||
if (!apiScope) apiScope = 'all';
|
||||
gl.utils.visitUrl(`?scope=${apiScope}&page=${pagenum}`);
|
||||
change(pageNumber) {
|
||||
const param = gl.utils.setParamInURL('page', pageNumber);
|
||||
|
||||
gl.utils.visitUrl(param);
|
||||
return param;
|
||||
},
|
||||
},
|
||||
template: `
|
||||
|
|
|
|||
|
|
@ -23,6 +23,13 @@
|
|||
required: true,
|
||||
},
|
||||
},
|
||||
|
||||
updated() {
|
||||
if (this.builds) {
|
||||
this.stopDropdownClickPropagation();
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
fetchBuilds(e) {
|
||||
const areaExpanded = e.currentTarget.attributes['aria-expanded'];
|
||||
|
|
@ -37,17 +44,19 @@
|
|||
return flash;
|
||||
});
|
||||
},
|
||||
keepGraph(e) {
|
||||
const { target } = e;
|
||||
|
||||
if (target.className.indexOf('js-ci-action-icon') >= 0) return null;
|
||||
|
||||
if (
|
||||
target.parentElement &&
|
||||
(target.parentElement.className.indexOf('js-ci-action-icon') >= 0)
|
||||
) return null;
|
||||
|
||||
return e.stopPropagation();
|
||||
/**
|
||||
* When the user right clicks or cmd/ctrl + click in the job name
|
||||
* the dropdown should not be closed and the link should open in another tab,
|
||||
* so we stop propagation of the click event inside the dropdown.
|
||||
*
|
||||
* Since this component is rendered multiple times per page we need to guarantee we only
|
||||
* target the click event of this component.
|
||||
*/
|
||||
stopDropdownClickPropagation() {
|
||||
$(this.$el.querySelectorAll('.js-builds-dropdown-list a.mini-pipeline-graph-dropdown-item')).on('click', (e) => {
|
||||
e.stopPropagation();
|
||||
});
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
|
|
@ -76,13 +85,13 @@
|
|||
template: `
|
||||
<div>
|
||||
<button
|
||||
@click='fetchBuilds($event)'
|
||||
@click="fetchBuilds($event)"
|
||||
:class="triggerButtonClass"
|
||||
:title='stage.title'
|
||||
:title="stage.title"
|
||||
data-placement="top"
|
||||
data-toggle="dropdown"
|
||||
type="button"
|
||||
:aria-label='stage.title'
|
||||
:aria-label="stage.title"
|
||||
>
|
||||
<span v-html="svg" aria-hidden="true"></span>
|
||||
<i class="fa fa-caret-down" aria-hidden="true"></i>
|
||||
|
|
@ -90,7 +99,6 @@
|
|||
<ul class="dropdown-menu mini-pipeline-graph-dropdown-menu js-builds-dropdown-container">
|
||||
<div class="arrow-up" aria-hidden="true"></div>
|
||||
<div
|
||||
@click='keepGraph($event)'
|
||||
:class="dropdownClass"
|
||||
class="js-builds-dropdown-list scrollable-menu"
|
||||
v-html="buildsOrSpinner"
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ require('../lib/utils/datetime_utility');
|
|||
},
|
||||
},
|
||||
template: `
|
||||
<td>
|
||||
<td class="pipelines-time-ago">
|
||||
<p class="duration" v-if='duration'>
|
||||
<span v-html='svgs.iconTimer'></span>
|
||||
{{duration}}
|
||||
|
|
@ -65,8 +65,7 @@ require('../lib/utils/datetime_utility');
|
|||
data-toggle="tooltip"
|
||||
data-placement="top"
|
||||
data-container="body"
|
||||
:data-original-title='localTimeFinished'
|
||||
>
|
||||
:data-original-title='localTimeFinished'>
|
||||
{{timeStopped.words}}
|
||||
</time>
|
||||
</p>
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ require('./pipelines_table_row');
|
|||
<th class="js-pipeline-commit pipeline-commit">Commit</th>
|
||||
<th class="js-pipeline-stages pipeline-stages">Stages</th>
|
||||
<th class="js-pipeline-date pipeline-date"></th>
|
||||
<th class="js-pipeline-actions pipeline-actions hidden-xs"></th>
|
||||
<th class="js-pipeline-actions pipeline-actions"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@ window.Vue = require('vue');
|
|||
|
||||
Here is an example `change` method:
|
||||
|
||||
change(pagenum, apiScope) {
|
||||
gl.utils.visitUrl(`?scope=${apiScope}&p=${pagenum}`);
|
||||
change(pagenum) {
|
||||
gl.utils.visitUrl(`?page=${pagenum}`);
|
||||
},
|
||||
*/
|
||||
|
||||
|
|
@ -57,8 +57,6 @@ window.Vue = require('vue');
|
|||
},
|
||||
methods: {
|
||||
changePage(e) {
|
||||
const apiScope = gl.utils.getParameterByName('scope');
|
||||
|
||||
const text = e.target.innerText;
|
||||
const { totalPages, nextPage, previousPage } = this.pageInfo;
|
||||
|
||||
|
|
@ -66,19 +64,19 @@ window.Vue = require('vue');
|
|||
case SPREAD:
|
||||
break;
|
||||
case LAST:
|
||||
this.change(totalPages, apiScope);
|
||||
this.change(totalPages);
|
||||
break;
|
||||
case NEXT:
|
||||
this.change(nextPage, apiScope);
|
||||
this.change(nextPage);
|
||||
break;
|
||||
case PREV:
|
||||
this.change(previousPage, apiScope);
|
||||
this.change(previousPage);
|
||||
break;
|
||||
case FIRST:
|
||||
this.change(1, apiScope);
|
||||
this.change(1);
|
||||
break;
|
||||
default:
|
||||
this.change(+text, apiScope);
|
||||
this.change(+text);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
* This is a manifest file that'll automatically include all the stylesheets available in this directory
|
||||
* and any sub-directories. You're free to add application-wide styles to this file and they'll appear at
|
||||
* the top of the compiled file, but it's generally better to create a new file per style scope.
|
||||
*= require jquery-ui/autocomplete
|
||||
*= require jquery.atwho
|
||||
*= require select2
|
||||
*= require_self
|
||||
|
|
|
|||
|
|
@ -229,7 +229,7 @@
|
|||
.controls {
|
||||
float: right;
|
||||
margin-top: 8px;
|
||||
padding-bottom: 7px;
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 1px solid $border-color;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
.calender-block {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
border-top: 0;
|
||||
direction: rtl;
|
||||
|
||||
@media (min-width: $screen-sm-min) and (max-width: $screen-md-max) {
|
||||
|
|
|
|||
|
|
@ -271,6 +271,7 @@ span.idiff {
|
|||
font-size: 13px;
|
||||
line-height: 28px;
|
||||
display: inline-block;
|
||||
float: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,11 @@
|
|||
.filtered-search-container {
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
|
||||
@media (max-width: $screen-xs-min) {
|
||||
-webkit-flex-direction: column;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
.filtered-search-input-container {
|
||||
|
|
@ -34,6 +39,20 @@
|
|||
position: relative;
|
||||
width: 100%;
|
||||
|
||||
@media (max-width: $screen-xs-min) {
|
||||
-webkit-flex: 1 1 100%;
|
||||
flex: 1 1 100%;
|
||||
margin-bottom: 10px;
|
||||
|
||||
.dropdown-menu {
|
||||
width: auto;
|
||||
left: 0;
|
||||
right: 0;
|
||||
max-width: none;
|
||||
min-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.form-control {
|
||||
padding-left: 25px;
|
||||
padding-right: 25px;
|
||||
|
|
@ -79,6 +98,31 @@
|
|||
overflow: auto;
|
||||
}
|
||||
|
||||
@media (max-width: $screen-xs-min) {
|
||||
.issues-details-filters {
|
||||
padding: 0 0 10px;
|
||||
background-color: $white-light;
|
||||
border-top: 0;
|
||||
}
|
||||
|
||||
.filter-dropdown-container {
|
||||
.dropdown-toggle,
|
||||
.dropdown {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.dropdown {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.fa-chevron-down {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
%filter-dropdown-item-btn-hover {
|
||||
background-color: $dropdown-hover-color;
|
||||
color: $white-light;
|
||||
|
|
@ -148,4 +192,4 @@
|
|||
|
||||
.filter-dropdown-loading {
|
||||
padding: 8px 16px;
|
||||
}
|
||||
}
|
||||
|
|
@ -148,16 +148,11 @@ header {
|
|||
}
|
||||
|
||||
.header-logo {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
display: inline-block;
|
||||
margin: 0 8px 0 3px;
|
||||
position: relative;
|
||||
top: 7px;
|
||||
transition-duration: .3s;
|
||||
z-index: 999;
|
||||
|
||||
#logo {
|
||||
position: relative;
|
||||
left: -50%;
|
||||
}
|
||||
|
||||
svg,
|
||||
img {
|
||||
|
|
@ -167,15 +162,6 @@ header {
|
|||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@media (max-width: $screen-xs-max) {
|
||||
right: 20px;
|
||||
left: auto;
|
||||
|
||||
#logo {
|
||||
left: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
|
|
@ -183,7 +169,6 @@ header {
|
|||
padding-right: 20px;
|
||||
margin: 0;
|
||||
font-size: 18px;
|
||||
max-width: 385px;
|
||||
display: inline-block;
|
||||
line-height: $header-height;
|
||||
font-weight: normal;
|
||||
|
|
@ -193,14 +178,18 @@ header {
|
|||
vertical-align: top;
|
||||
white-space: nowrap;
|
||||
|
||||
@media (min-width: $screen-sm-min) and (max-width: $screen-sm-max) {
|
||||
max-width: 300px;
|
||||
}
|
||||
|
||||
@media (max-width: $screen-xs-max) {
|
||||
max-width: 190px;
|
||||
}
|
||||
|
||||
@media (min-width: $screen-sm-min) and (max-width: $screen-md-max) {
|
||||
max-width: 428px;
|
||||
}
|
||||
|
||||
@media (min-width: $screen-lg-min) {
|
||||
max-width: 685px;
|
||||
}
|
||||
|
||||
a {
|
||||
color: $gl-text-color;
|
||||
|
||||
|
|
|
|||
|
|
@ -2,17 +2,6 @@
|
|||
font-family: $regular_font;
|
||||
font-size: $font-size-base;
|
||||
|
||||
&.ui-autocomplete {
|
||||
border-color: $jq-ui-border;
|
||||
padding: 0;
|
||||
margin-top: 2px;
|
||||
z-index: 1001;
|
||||
|
||||
.ui-menu-item a {
|
||||
padding: 4px 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.ui-state-default {
|
||||
border: 1px solid $white-light;
|
||||
background: $white-light;
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ $dark-highlight-bg: #ffe792;
|
|||
$dark-highlight-color: $black;
|
||||
$dark-pre-hll-bg: #373b41;
|
||||
$dark-hll-bg: #373b41;
|
||||
$dark-over-bg: #9f9ab5;
|
||||
$dark-expanded-bg: #3e3e3e;
|
||||
$dark-c: #969896;
|
||||
$dark-err: #c66;
|
||||
$dark-k: #b294bb;
|
||||
|
|
@ -139,9 +141,37 @@ $dark-il: #de935f;
|
|||
}
|
||||
}
|
||||
|
||||
.diff-line-num {
|
||||
&.is-over,
|
||||
&.hll:not(.empty-cell).is-over {
|
||||
background-color: $dark-over-bg;
|
||||
border-color: darken($dark-over-bg, 5%);
|
||||
|
||||
a {
|
||||
color: darken($dark-over-bg, 15%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.line_content.match {
|
||||
@include dark-diff-match-line;
|
||||
}
|
||||
|
||||
&:not(.diff-expanded) + .diff-expanded,
|
||||
&.diff-expanded + .line_holder:not(.diff-expanded) {
|
||||
> .diff-line-num,
|
||||
> .line_content {
|
||||
border-top: 1px solid $black;
|
||||
}
|
||||
}
|
||||
|
||||
&.diff-expanded {
|
||||
> .diff-line-num,
|
||||
> .line_content {
|
||||
background: $dark-expanded-bg;
|
||||
border-color: $dark-expanded-bg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// highlight line via anchor
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ $monokai-line-empty-bg: #49483e;
|
|||
$monokai-line-empty-border: darken($monokai-line-empty-bg, 15%);
|
||||
$monokai-diff-border: #808080;
|
||||
$monokai-highlight-bg: #ffe792;
|
||||
$monokai-over-bg: #9f9ab5;
|
||||
$monokai-expanded-bg: #3e3e3e;
|
||||
|
||||
$monokai-new-bg: rgba(166, 226, 46, 0.1);
|
||||
$monokai-new-idiff: rgba(166, 226, 46, 0.15);
|
||||
|
|
@ -139,9 +141,37 @@ $monokai-gi: #a6e22e;
|
|||
}
|
||||
}
|
||||
|
||||
.diff-line-num {
|
||||
&.is-over,
|
||||
&.hll:not(.empty-cell).is-over {
|
||||
background-color: $monokai-over-bg;
|
||||
border-color: darken($monokai-over-bg, 5%);
|
||||
|
||||
a {
|
||||
color: darken($monokai-over-bg, 15%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.line_content.match {
|
||||
@include dark-diff-match-line;
|
||||
}
|
||||
|
||||
&:not(.diff-expanded) + .diff-expanded,
|
||||
&.diff-expanded + .line_holder:not(.diff-expanded) {
|
||||
> .diff-line-num,
|
||||
> .line_content {
|
||||
border-top: 1px solid $black;
|
||||
}
|
||||
}
|
||||
|
||||
&.diff-expanded {
|
||||
> .diff-line-num,
|
||||
> .line_content {
|
||||
background: $monokai-expanded-bg;
|
||||
border-color: $monokai-expanded-bg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// highlight line via anchor
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ $solarized-dark-line-color-new: #5a766c;
|
|||
$solarized-dark-line-color-old: #7a6c71;
|
||||
$solarized-dark-highlight: #094554;
|
||||
$solarized-dark-hll-bg: #174652;
|
||||
$solarized-dark-over-bg: #9f9ab5;
|
||||
$solarized-dark-expanded-bg: #010d10;
|
||||
$solarized-dark-c: #586e75;
|
||||
$solarized-dark-err: #93a1a1;
|
||||
$solarized-dark-g: #93a1a1;
|
||||
|
|
@ -143,9 +145,37 @@ $solarized-dark-il: #2aa198;
|
|||
}
|
||||
}
|
||||
|
||||
.diff-line-num {
|
||||
&.is-over,
|
||||
&.hll:not(.empty-cell).is-over {
|
||||
background-color: $solarized-dark-over-bg;
|
||||
border-color: darken($solarized-dark-over-bg, 5%);
|
||||
|
||||
a {
|
||||
color: darken($solarized-dark-over-bg, 15%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.line_content.match {
|
||||
@include dark-diff-match-line;
|
||||
}
|
||||
|
||||
&:not(.diff-expanded) + .diff-expanded,
|
||||
&.diff-expanded + .line_holder:not(.diff-expanded) {
|
||||
> .diff-line-num,
|
||||
> .line_content {
|
||||
border-top: 1px solid $black;
|
||||
}
|
||||
}
|
||||
|
||||
&.diff-expanded {
|
||||
> .diff-line-num,
|
||||
> .line_content {
|
||||
background: $solarized-dark-expanded-bg;
|
||||
border-color: $solarized-dark-expanded-bg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// highlight line via anchor
|
||||
|
|
|
|||
|
|
@ -18,6 +18,9 @@ $solarized-light-line-color-new: #a1a080;
|
|||
$solarized-light-line-color-old: #ad9186;
|
||||
$solarized-light-highlight: #eee8d5;
|
||||
$solarized-light-hll-bg: #ddd8c5;
|
||||
$solarized-light-over-bg: #ded7fc;
|
||||
$solarized-light-expanded-border: #d2cdbd;
|
||||
$solarized-light-expanded-bg: #ece6d4;
|
||||
$solarized-light-c: #93a1a1;
|
||||
$solarized-light-err: #586e75;
|
||||
$solarized-light-g: #586e75;
|
||||
|
|
@ -150,9 +153,37 @@ $solarized-light-il: #2aa198;
|
|||
}
|
||||
}
|
||||
|
||||
.diff-line-num {
|
||||
&.is-over,
|
||||
&.hll:not(.empty-cell).is-over {
|
||||
background-color: $solarized-light-over-bg;
|
||||
border-color: darken($solarized-light-over-bg, 5%);
|
||||
|
||||
a {
|
||||
color: darken($solarized-light-over-bg, 15%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.line_content.match {
|
||||
@include matchLine;
|
||||
}
|
||||
|
||||
&:not(.diff-expanded) + .diff-expanded,
|
||||
&.diff-expanded + .line_holder:not(.diff-expanded) {
|
||||
> .diff-line-num,
|
||||
> .line_content {
|
||||
border-top: 1px solid $solarized-light-expanded-border;
|
||||
}
|
||||
}
|
||||
|
||||
&.diff-expanded {
|
||||
> .diff-line-num,
|
||||
> .line_content {
|
||||
background: $solarized-light-expanded-bg;
|
||||
border-color: $solarized-light-expanded-bg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// highlight line via anchor
|
||||
|
|
|
|||
|
|
@ -7,6 +7,9 @@ $white-code-color: $gl-text-color;
|
|||
$white-highlight: #fafe3d;
|
||||
$white-pre-hll-bg: #f8eec7;
|
||||
$white-hll-bg: #f8f8f8;
|
||||
$white-over-bg: #ded7fc;
|
||||
$white-expanded-border: #e0e0e0;
|
||||
$white-expanded-bg: #f7f7f7;
|
||||
$white-c: #998;
|
||||
$white-err: #a61717;
|
||||
$white-err-bg: #e3d2d2;
|
||||
|
|
@ -123,12 +126,38 @@ $white-gc-bg: #eaf2f5;
|
|||
}
|
||||
}
|
||||
|
||||
&.is-over,
|
||||
&.hll:not(.empty-cell).is-over {
|
||||
background-color: $white-over-bg;
|
||||
border-color: darken($white-over-bg, 5%);
|
||||
|
||||
a {
|
||||
color: darken($white-over-bg, 15%);
|
||||
}
|
||||
}
|
||||
|
||||
&.hll:not(.empty-cell) {
|
||||
background-color: $line-number-select;
|
||||
border-color: $line-select-yellow-dark;
|
||||
}
|
||||
}
|
||||
|
||||
&:not(.diff-expanded) + .diff-expanded,
|
||||
&.diff-expanded + .line_holder:not(.diff-expanded) {
|
||||
> .diff-line-num,
|
||||
> .line_content {
|
||||
border-top: 1px solid $white-expanded-border;
|
||||
}
|
||||
}
|
||||
|
||||
&.diff-expanded {
|
||||
> .diff-line-num,
|
||||
> .line_content {
|
||||
background: $white-expanded-bg;
|
||||
border-color: $white-expanded-bg;
|
||||
}
|
||||
}
|
||||
|
||||
.line_content {
|
||||
&.old {
|
||||
background-color: $line-removed;
|
||||
|
|
|
|||
|
|
@ -89,6 +89,10 @@
|
|||
|
||||
.diff-line-num {
|
||||
width: 50px;
|
||||
|
||||
a {
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
|
||||
.line_holder td {
|
||||
|
|
@ -109,10 +113,6 @@
|
|||
td.line_content.parallel {
|
||||
width: 46%;
|
||||
}
|
||||
|
||||
.add-diff-note {
|
||||
margin-left: -65px;
|
||||
}
|
||||
}
|
||||
|
||||
.old_line,
|
||||
|
|
@ -133,8 +133,13 @@
|
|||
width: 35px;
|
||||
font-weight: normal;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
&[disabled] {
|
||||
cursor: default;
|
||||
|
||||
&:hover,
|
||||
&:active {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,112 +15,97 @@
|
|||
padding-top: 20px;
|
||||
}
|
||||
|
||||
@media (max-width: $screen-xs-max) {
|
||||
.environments-container {
|
||||
.environments-container {
|
||||
.table-holder {
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.environments {
|
||||
table-layout: fixed;
|
||||
|
||||
.environments-commit,
|
||||
.environments-actions,
|
||||
.environments-deploy,
|
||||
.environments-build,
|
||||
.environments-date {
|
||||
position: static;
|
||||
float: none;
|
||||
display: table-cell;
|
||||
}
|
||||
|
||||
.environments-commit,
|
||||
.environments-actions {
|
||||
width: 20%;
|
||||
}
|
||||
|
||||
.environments-date {
|
||||
width: 10%;
|
||||
}
|
||||
|
||||
.environments-name,
|
||||
.environments-deploy,
|
||||
.environments-build {
|
||||
width: 15%;
|
||||
}
|
||||
|
||||
.environment-name,
|
||||
.environments-build-cell,
|
||||
.deployment-column {
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.deployment-column {
|
||||
.avatar {
|
||||
float: none;
|
||||
.table.ci-table {
|
||||
.environments-actions {
|
||||
min-width: 200px;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-group {
|
||||
.environments-commit,
|
||||
.environments-actions {
|
||||
width: 20%;
|
||||
}
|
||||
|
||||
> a {
|
||||
.environments-date {
|
||||
width: 10%;
|
||||
}
|
||||
|
||||
.environments-name,
|
||||
.environments-deploy,
|
||||
.environments-build {
|
||||
width: 15%;
|
||||
}
|
||||
|
||||
.deployment-column {
|
||||
> span {
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
float: none;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-group {
|
||||
|
||||
> a {
|
||||
color: $gl-text-color-secondary;
|
||||
}
|
||||
|
||||
svg path {
|
||||
fill: $gl-text-color-secondary;
|
||||
}
|
||||
|
||||
.dropdown {
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
||||
.commit-title {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.avatar-image-container {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.icon-play {
|
||||
height: 13px;
|
||||
width: 12px;
|
||||
}
|
||||
|
||||
.external-url,
|
||||
.dropdown-new {
|
||||
color: $gl-text-color-secondary;
|
||||
}
|
||||
|
||||
svg path {
|
||||
fill: $gl-text-color-secondary;
|
||||
.dropdown-menu {
|
||||
.fa {
|
||||
margin-right: 6px;
|
||||
color: $gl-text-color-secondary;
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown {
|
||||
outline: none;
|
||||
.build-link,
|
||||
.branch-name {
|
||||
color: $gl-text-color;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.commit-title {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.avatar-image-container {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.icon-play {
|
||||
height: 13px;
|
||||
width: 12px;
|
||||
}
|
||||
|
||||
.external-url,
|
||||
.dropdown-new {
|
||||
color: $gl-text-color-secondary;
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
|
||||
.fa {
|
||||
margin-right: 6px;
|
||||
.stop-env-link,
|
||||
.external-url {
|
||||
color: $gl-text-color-secondary;
|
||||
|
||||
.stop-env-icon {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.build-link,
|
||||
.branch-name {
|
||||
color: $gl-text-color;
|
||||
}
|
||||
|
||||
.stop-env-link,
|
||||
.external-url {
|
||||
color: $gl-text-color-secondary;
|
||||
|
||||
.stop-env-icon {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.deployment {
|
||||
.build-column {
|
||||
|
||||
.deployment .build-column {
|
||||
.build-link {
|
||||
color: $gl-text-color;
|
||||
}
|
||||
|
|
@ -129,34 +114,32 @@
|
|||
float: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.folder-icon {
|
||||
margin-right: 3px;
|
||||
color: $gl-text-color-secondary;
|
||||
display: inline-block;
|
||||
|
||||
.fa:nth-child(1) {
|
||||
.folder-icon {
|
||||
margin-right: 3px;
|
||||
color: $gl-text-color-secondary;
|
||||
display: inline-block;
|
||||
|
||||
.fa:nth-child(1) {
|
||||
margin-right: 3px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.folder-name {
|
||||
cursor: pointer;
|
||||
color: $gl-text-color-secondary;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
.folder-name {
|
||||
cursor: pointer;
|
||||
color: $gl-text-color-secondary;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.table.ci-table.environments {
|
||||
.icon-container {
|
||||
width: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
.icon-container {
|
||||
width: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.branch-commit {
|
||||
.commit-id {
|
||||
margin-right: 0;
|
||||
.branch-commit {
|
||||
.commit-id {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -452,36 +452,37 @@ ul.notes {
|
|||
* Line note button on the side of diffs
|
||||
*/
|
||||
|
||||
.diff-file tr.line_holder {
|
||||
@mixin show-add-diff-note {
|
||||
display: inline-block;
|
||||
.add-diff-note {
|
||||
display: none;
|
||||
margin-top: -2px;
|
||||
border-radius: 50%;
|
||||
background: $white-light;
|
||||
padding: 1px 5px;
|
||||
font-size: 12px;
|
||||
color: $gl-link-color;
|
||||
margin-left: -55px;
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
width: 23px;
|
||||
height: 23px;
|
||||
border: 1px solid $border-color;
|
||||
transition: transform .1s ease-in-out;
|
||||
|
||||
&:hover {
|
||||
background: $gl-info;
|
||||
color: $white-light;
|
||||
transform: scale(1.15);
|
||||
}
|
||||
|
||||
.add-diff-note {
|
||||
margin-top: -8px;
|
||||
border-radius: 40px;
|
||||
background: $white-light;
|
||||
padding: 4px;
|
||||
font-size: 16px;
|
||||
color: $gl-link-color;
|
||||
margin-left: -56px;
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
width: 32px;
|
||||
// "hide" it by default
|
||||
display: none;
|
||||
|
||||
&:hover {
|
||||
background: $gl-info;
|
||||
color: $white-light;
|
||||
@include show-add-diff-note;
|
||||
}
|
||||
&:active {
|
||||
outline: 0;
|
||||
}
|
||||
}
|
||||
|
||||
// "show" the icon also if we just hover somewhere over the line
|
||||
&:hover > td {
|
||||
.diff-file {
|
||||
.is-over {
|
||||
.add-diff-note {
|
||||
@include show-add-diff-note;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,21 +13,16 @@
|
|||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.table-holder {
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.commit-title {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.controls {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.btn {
|
||||
margin: 4px;
|
||||
}
|
||||
|
||||
.table.ci-table {
|
||||
min-width: 1200px;
|
||||
table-layout: fixed;
|
||||
|
||||
.label {
|
||||
margin-bottom: 3px;
|
||||
|
|
@ -37,16 +32,72 @@
|
|||
color: $black;
|
||||
}
|
||||
|
||||
.pipeline-date,
|
||||
.pipeline-status {
|
||||
width: 10%;
|
||||
.stage-cell {
|
||||
min-width: 130px; // Guarantees we show at least 4 stages in line
|
||||
width: 20%;
|
||||
}
|
||||
|
||||
.pipelines-time-ago {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.pipeline-info,
|
||||
.pipeline-commit,
|
||||
.pipeline-stages,
|
||||
.pipeline-actions {
|
||||
width: 20%;
|
||||
padding-right: 0;
|
||||
min-width: 170px; //Guarantees buttons don't break in several lines.
|
||||
|
||||
.btn-default {
|
||||
color: $gl-text-color-secondary;
|
||||
}
|
||||
|
||||
.btn.btn-retry:hover,
|
||||
.btn.btn-retry:focus {
|
||||
border-color: $gray-darkest;
|
||||
background-color: $white-normal;
|
||||
}
|
||||
|
||||
svg path {
|
||||
fill: $gl-text-color-secondary;
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
max-height: 250px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.dropdown-toggle,
|
||||
.dropdown-menu {
|
||||
color: $gl-text-color-secondary;
|
||||
|
||||
.fa {
|
||||
color: $gl-text-color-secondary;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
svg,
|
||||
.fa {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-group {
|
||||
&.open {
|
||||
.btn-default {
|
||||
background-color: $white-normal;
|
||||
border-color: $border-white-normal;
|
||||
}
|
||||
}
|
||||
|
||||
.btn {
|
||||
.icon-play {
|
||||
height: 13px;
|
||||
width: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tooltip {
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -54,6 +105,7 @@
|
|||
@media (max-width: $screen-md-max) {
|
||||
.content-list {
|
||||
&.pipelines,
|
||||
&.environments-container,
|
||||
&.builds-content-list {
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
|
|
@ -61,27 +113,10 @@
|
|||
}
|
||||
}
|
||||
|
||||
.content-list.pipelines .table-holder {
|
||||
min-height: 300px;
|
||||
}
|
||||
|
||||
.pipeline-holder {
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.table.ci-table {
|
||||
min-width: 900px;
|
||||
|
||||
&.pipeline {
|
||||
min-width: 650px;
|
||||
}
|
||||
|
||||
&.builds-page {
|
||||
|
||||
tr {
|
||||
height: 71px;
|
||||
}
|
||||
&.builds-page tr {
|
||||
height: 71px;
|
||||
}
|
||||
|
||||
tr {
|
||||
|
|
@ -94,12 +129,16 @@
|
|||
padding: 10px 8px;
|
||||
}
|
||||
|
||||
td.environments-actions {
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
td.stage-cell {
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
.commit-link {
|
||||
padding: 9px 8px 10px;
|
||||
padding: 9px 8px 10px 2px;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -206,72 +245,8 @@
|
|||
}
|
||||
}
|
||||
|
||||
.pipeline-actions {
|
||||
min-width: 140px;
|
||||
|
||||
.btn {
|
||||
margin: 0;
|
||||
color: $gl-text-color-secondary;
|
||||
}
|
||||
|
||||
.cancel-retry-btns {
|
||||
vertical-align: middle;
|
||||
|
||||
.btn:not(:first-child) {
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
max-height: 250px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.dropdown-toggle,
|
||||
.dropdown-menu {
|
||||
color: $gl-text-color-secondary;
|
||||
|
||||
.fa {
|
||||
color: $gl-text-color-secondary;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
svg,
|
||||
.fa {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-remove {
|
||||
color: $white-light;
|
||||
}
|
||||
|
||||
.btn-group {
|
||||
&.open {
|
||||
.btn-default {
|
||||
background-color: $white-normal;
|
||||
border-color: $border-white-normal;
|
||||
}
|
||||
}
|
||||
|
||||
.btn {
|
||||
.icon-play {
|
||||
height: 13px;
|
||||
width: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tooltip {
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.build-link {
|
||||
|
||||
a {
|
||||
color: $gl-text-color;
|
||||
}
|
||||
.build-link a {
|
||||
color: $gl-text-color;
|
||||
}
|
||||
|
||||
.btn-group.open .dropdown-toggle {
|
||||
|
|
@ -335,31 +310,8 @@
|
|||
}
|
||||
|
||||
.tab-pane {
|
||||
&.pipelines {
|
||||
.ci-table {
|
||||
min-width: 900px;
|
||||
}
|
||||
|
||||
.content-list.pipelines {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.stage {
|
||||
max-width: 100px;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.pipeline-actions {
|
||||
min-width: initial;
|
||||
}
|
||||
}
|
||||
|
||||
&.builds {
|
||||
.ci-table {
|
||||
tr {
|
||||
height: 71px;
|
||||
}
|
||||
}
|
||||
&.builds .ci-table tr {
|
||||
height: 71px;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -277,3 +277,41 @@ table.u2f-registrations {
|
|||
padding-left: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
.user-callout {
|
||||
margin: 24px auto 0;
|
||||
|
||||
.bordered-box {
|
||||
border: 1px solid $border-color;
|
||||
border-radius: $border-radius-default;
|
||||
}
|
||||
|
||||
.landing {
|
||||
margin-bottom: $gl-padding;
|
||||
|
||||
.close {
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.dismiss-icon {
|
||||
float: right;
|
||||
cursor: pointer;
|
||||
color: $cycle-analytics-dismiss-icon-color;
|
||||
}
|
||||
|
||||
.svg-container {
|
||||
text-align: center;
|
||||
|
||||
svg {
|
||||
width: 136px;
|
||||
height: 136px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media(max-width: $screen-xs-max) {
|
||||
.inner-content {
|
||||
padding-left: 30px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -638,14 +638,6 @@ pre.light-well {
|
|||
margin: 0;
|
||||
}
|
||||
|
||||
.activity-filter-block {
|
||||
.controls {
|
||||
padding-bottom: 7px;
|
||||
margin-top: 8px;
|
||||
border-bottom: 1px solid $border-color;
|
||||
}
|
||||
}
|
||||
|
||||
.commits-search-form {
|
||||
.input-short {
|
||||
min-width: 200px;
|
||||
|
|
|
|||
|
|
@ -83,6 +83,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
|
|||
:akismet_api_key,
|
||||
:akismet_enabled,
|
||||
:container_registry_token_expire_delay,
|
||||
:default_artifacts_expire_in,
|
||||
:default_branch_protection,
|
||||
:default_group_visibility,
|
||||
:default_project_visibility,
|
||||
|
|
|
|||
|
|
@ -72,14 +72,6 @@ class ApplicationController < ActionController::Base
|
|||
end
|
||||
end
|
||||
|
||||
def authenticate_user!(*args)
|
||||
if redirect_to_home_page_url?
|
||||
return redirect_to current_application_settings.home_page_url
|
||||
end
|
||||
|
||||
super(*args)
|
||||
end
|
||||
|
||||
def log_exception(exception)
|
||||
application_trace = ActionDispatch::ExceptionWrapper.new(env, exception).application_trace
|
||||
application_trace.map!{ |t| " #{t}\n" }
|
||||
|
|
@ -287,19 +279,6 @@ class ApplicationController < ActionController::Base
|
|||
session[:skip_tfa] && session[:skip_tfa] > Time.current
|
||||
end
|
||||
|
||||
def redirect_to_home_page_url?
|
||||
# If user is not signed-in and tries to access root_path - redirect him to landing page
|
||||
# Don't redirect to the default URL to prevent endless redirections
|
||||
return false unless current_application_settings.home_page_url.present?
|
||||
|
||||
home_page_url = current_application_settings.home_page_url.chomp('/')
|
||||
root_urls = [Gitlab.config.gitlab['url'].chomp('/'), root_url.chomp('/')]
|
||||
|
||||
return false if root_urls.include?(home_page_url)
|
||||
|
||||
current_user.nil? && root_path == request.path
|
||||
end
|
||||
|
||||
# U2F (universal 2nd factor) devices need a unique identifier for the application
|
||||
# to perform authentication.
|
||||
# https://developers.yubico.com/U2F/App_ID.html
|
||||
|
|
|
|||
|
|
@ -26,6 +26,23 @@ module IssuableActions
|
|||
|
||||
private
|
||||
|
||||
def render_conflict_response
|
||||
respond_to do |format|
|
||||
format.html do
|
||||
@conflict = true
|
||||
render :edit
|
||||
end
|
||||
|
||||
format.json do
|
||||
render json: {
|
||||
errors: [
|
||||
"Someone edited this #{issuable.human_class_name} at the same time you did. Please refresh your browser and make sure your changes will not unintentionally remove theirs."
|
||||
]
|
||||
}, status: 409
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def labels
|
||||
@labels ||= LabelsFinder.new(current_user, project_id: @project.id).execute
|
||||
end
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ module ServiceParams
|
|||
:issues_url,
|
||||
:jira_issue_transition_id,
|
||||
:merge_requests_events,
|
||||
:mock_service_url,
|
||||
:namespace,
|
||||
:new_issue_url,
|
||||
:notify,
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ class Projects::BlobController < Projects::ApplicationController
|
|||
include ActionView::Helpers::SanitizeHelper
|
||||
|
||||
# Raised when given an invalid file path
|
||||
class InvalidPathError < StandardError; end
|
||||
InvalidPathError = Class.new(StandardError)
|
||||
|
||||
before_action :require_non_empty_project, except: [:new, :create]
|
||||
before_action :authorize_download_code!
|
||||
|
|
|
|||
|
|
@ -134,8 +134,7 @@ class Projects::IssuesController < Projects::ApplicationController
|
|||
end
|
||||
|
||||
rescue ActiveRecord::StaleObjectError
|
||||
@conflict = true
|
||||
render :edit
|
||||
render_conflict_response
|
||||
end
|
||||
|
||||
def referenced_merge_requests
|
||||
|
|
|
|||
|
|
@ -10,11 +10,11 @@ class Projects::MergeRequestsController < Projects::ApplicationController
|
|||
before_action :module_enabled
|
||||
before_action :merge_request, only: [
|
||||
:edit, :update, :show, :diffs, :commits, :conflicts, :conflict_for_path, :pipelines, :merge, :merge_check,
|
||||
:ci_status, :ci_environments_status, :toggle_subscription, :cancel_merge_when_build_succeeds, :remove_wip, :resolve_conflicts, :assign_related_issues
|
||||
:ci_status, :ci_environments_status, :toggle_subscription, :cancel_merge_when_pipeline_succeeds, :remove_wip, :resolve_conflicts, :assign_related_issues
|
||||
]
|
||||
before_action :validates_merge_request, only: [:show, :diffs, :commits, :pipelines]
|
||||
before_action :define_show_vars, only: [:show, :diffs, :commits, :conflicts, :conflict_for_path, :builds, :pipelines]
|
||||
before_action :define_widget_vars, only: [:merge, :cancel_merge_when_build_succeeds, :merge_check]
|
||||
before_action :define_widget_vars, only: [:merge, :cancel_merge_when_pipeline_succeeds, :merge_check]
|
||||
before_action :define_commit_vars, only: [:diffs]
|
||||
before_action :define_diff_comment_vars, only: [:diffs]
|
||||
before_action :ensure_ref_fetched, only: [:show, :diffs, :commits, :builds, :conflicts, :conflict_for_path, :pipelines]
|
||||
|
|
@ -245,9 +245,11 @@ class Projects::MergeRequestsController < Projects::ApplicationController
|
|||
format.json do
|
||||
define_pipelines_vars
|
||||
|
||||
render json: PipelineSerializer
|
||||
render json: {
|
||||
pipelines: PipelineSerializer
|
||||
.new(project: @project, user: @current_user)
|
||||
.represent(@pipelines)
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -296,22 +298,21 @@ class Projects::MergeRequestsController < Projects::ApplicationController
|
|||
def update
|
||||
@merge_request = MergeRequests::UpdateService.new(project, current_user, merge_request_params).execute(@merge_request)
|
||||
|
||||
if @merge_request.valid?
|
||||
respond_to do |format|
|
||||
format.html do
|
||||
redirect_to([@merge_request.target_project.namespace.becomes(Namespace),
|
||||
@merge_request.target_project, @merge_request])
|
||||
end
|
||||
format.json do
|
||||
render json: @merge_request.to_json(include: { milestone: {}, assignee: { methods: :avatar_url }, labels: { methods: :text_color } }, methods: [:task_status, :task_status_short])
|
||||
respond_to do |format|
|
||||
format.html do
|
||||
if @merge_request.valid?
|
||||
redirect_to([@merge_request.target_project.namespace.becomes(Namespace), @merge_request.target_project, @merge_request])
|
||||
else
|
||||
render :edit
|
||||
end
|
||||
end
|
||||
else
|
||||
render "edit"
|
||||
|
||||
format.json do
|
||||
render json: @merge_request.to_json(include: { milestone: {}, assignee: { methods: :avatar_url }, labels: { methods: :text_color } }, methods: [:task_status, :task_status_short])
|
||||
end
|
||||
end
|
||||
rescue ActiveRecord::StaleObjectError
|
||||
@conflict = true
|
||||
render :edit
|
||||
render_conflict_response
|
||||
end
|
||||
|
||||
def remove_wip
|
||||
|
|
@ -327,8 +328,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController
|
|||
render partial: "projects/merge_requests/widget/show.html.haml", layout: false
|
||||
end
|
||||
|
||||
def cancel_merge_when_build_succeeds
|
||||
unless @merge_request.can_cancel_merge_when_build_succeeds?(current_user)
|
||||
def cancel_merge_when_pipeline_succeeds
|
||||
unless @merge_request.can_cancel_merge_when_pipeline_succeeds?(current_user)
|
||||
return access_denied!
|
||||
end
|
||||
|
||||
|
|
@ -340,9 +341,9 @@ class Projects::MergeRequestsController < Projects::ApplicationController
|
|||
def merge
|
||||
return access_denied! unless @merge_request.can_be_merged_by?(current_user)
|
||||
|
||||
# Disable the CI check if merge_when_build_succeeds is enabled since we have
|
||||
# Disable the CI check if merge_when_pipeline_succeeds is enabled since we have
|
||||
# to wait until CI completes to know
|
||||
unless @merge_request.mergeable?(skip_ci_check: merge_when_build_succeeds_active?)
|
||||
unless @merge_request.mergeable?(skip_ci_check: merge_when_pipeline_succeeds_active?)
|
||||
@status = :failed
|
||||
return
|
||||
end
|
||||
|
|
@ -354,7 +355,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
|
|||
|
||||
@merge_request.update(merge_error: nil)
|
||||
|
||||
if params[:merge_when_build_succeeds].present?
|
||||
if params[:merge_when_pipeline_succeeds].present?
|
||||
unless @merge_request.head_pipeline
|
||||
@status = :failed
|
||||
return
|
||||
|
|
@ -365,7 +366,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
|
|||
.new(@project, current_user, merge_params)
|
||||
.execute(@merge_request)
|
||||
|
||||
@status = :merge_when_build_succeeds
|
||||
@status = :merge_when_pipeline_succeeds
|
||||
elsif @merge_request.head_pipeline.success?
|
||||
# This can be triggered when a user clicks the auto merge button while
|
||||
# the tests finish at about the same time
|
||||
|
|
@ -382,8 +383,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController
|
|||
|
||||
def merge_widget_refresh
|
||||
@status =
|
||||
if merge_request.merge_when_build_succeeds
|
||||
:merge_when_build_succeeds
|
||||
if merge_request.merge_when_pipeline_succeeds
|
||||
:merge_when_pipeline_succeeds
|
||||
else
|
||||
# Only MRs that can be merged end in this action
|
||||
# MR can be already picked up for merge / merged already or can be waiting for worker to be picked up
|
||||
|
|
@ -673,8 +674,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController
|
|||
@merge_request.ensure_ref_fetched
|
||||
end
|
||||
|
||||
def merge_when_build_succeeds_active?
|
||||
params[:merge_when_build_succeeds].present? &&
|
||||
def merge_when_pipeline_succeeds_active?
|
||||
params[:merge_when_pipeline_succeeds].present? &&
|
||||
@merge_request.head_pipeline && @merge_request.head_pipeline.active?
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -148,17 +148,10 @@ class Projects::NotesController < Projects::ApplicationController
|
|||
|
||||
def note_json(note)
|
||||
attrs = {
|
||||
award: false,
|
||||
id: note.id
|
||||
}
|
||||
|
||||
if note.is_a?(AwardEmoji)
|
||||
attrs.merge!(
|
||||
valid: note.valid?,
|
||||
award: true,
|
||||
name: note.name
|
||||
)
|
||||
elsif note.persisted?
|
||||
if note.persisted?
|
||||
Banzai::NoteRenderer.render([note], @project, current_user)
|
||||
|
||||
attrs.merge!(
|
||||
|
|
@ -198,7 +191,7 @@ class Projects::NotesController < Projects::ApplicationController
|
|||
)
|
||||
end
|
||||
|
||||
attrs[:commands_changes] = note.commands_changes unless attrs[:award]
|
||||
attrs[:commands_changes] = note.commands_changes
|
||||
attrs
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -314,7 +314,7 @@ class ProjectsController < Projects::ApplicationController
|
|||
:name,
|
||||
:namespace_id,
|
||||
:only_allow_merge_if_all_discussions_are_resolved,
|
||||
:only_allow_merge_if_build_succeeds,
|
||||
:only_allow_merge_if_pipeline_succeeds,
|
||||
:path,
|
||||
:public_builds,
|
||||
:request_access_enabled,
|
||||
|
|
|
|||
|
|
@ -8,7 +8,9 @@
|
|||
# `DashboardController#show`, which is the default.
|
||||
class RootController < Dashboard::ProjectsController
|
||||
skip_before_action :authenticate_user!, only: [:index]
|
||||
before_action :redirect_to_custom_dashboard, only: [:index]
|
||||
|
||||
before_action :redirect_unlogged_user, if: -> { current_user.nil? }
|
||||
before_action :redirect_logged_user, if: -> { current_user.present? }
|
||||
|
||||
def index
|
||||
super
|
||||
|
|
@ -16,23 +18,38 @@ class RootController < Dashboard::ProjectsController
|
|||
|
||||
private
|
||||
|
||||
def redirect_to_custom_dashboard
|
||||
return redirect_to new_user_session_path unless current_user
|
||||
def redirect_unlogged_user
|
||||
if redirect_to_home_page_url?
|
||||
redirect_to(current_application_settings.home_page_url)
|
||||
else
|
||||
redirect_to(new_user_session_path)
|
||||
end
|
||||
end
|
||||
|
||||
def redirect_logged_user
|
||||
case current_user.dashboard
|
||||
when 'stars'
|
||||
flash.keep
|
||||
redirect_to starred_dashboard_projects_path
|
||||
redirect_to(starred_dashboard_projects_path)
|
||||
when 'project_activity'
|
||||
redirect_to activity_dashboard_path
|
||||
redirect_to(activity_dashboard_path)
|
||||
when 'starred_project_activity'
|
||||
redirect_to activity_dashboard_path(filter: 'starred')
|
||||
redirect_to(activity_dashboard_path(filter: 'starred'))
|
||||
when 'groups'
|
||||
redirect_to dashboard_groups_path
|
||||
redirect_to(dashboard_groups_path)
|
||||
when 'todos'
|
||||
redirect_to dashboard_todos_path
|
||||
else
|
||||
return
|
||||
redirect_to(dashboard_todos_path)
|
||||
end
|
||||
end
|
||||
|
||||
def redirect_to_home_page_url?
|
||||
# If user is not signed-in and tries to access root_path - redirect him to landing page
|
||||
# Don't redirect to the default URL to prevent endless redirections
|
||||
return false unless current_application_settings.home_page_url.present?
|
||||
|
||||
home_page_url = current_application_settings.home_page_url.chomp('/')
|
||||
root_urls = [Gitlab.config.gitlab['url'].chomp('/'), root_url.chomp('/')]
|
||||
|
||||
root_urls.exclude?(home_page_url)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -15,4 +15,11 @@ module BuildsHelper
|
|||
log_state: @build.trace_with_state[:state].to_s
|
||||
}
|
||||
end
|
||||
|
||||
def build_failed_issue_options
|
||||
{
|
||||
title: "Build Failed ##{@build.id}",
|
||||
description: namespace_project_build_url(@project.namespace, @project, @build)
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ module ButtonHelper
|
|||
title = data[:title] || 'Copy to clipboard'
|
||||
data = { toggle: 'tooltip', placement: 'bottom', container: 'body' }.merge(data)
|
||||
content_tag :button,
|
||||
icon('clipboard'),
|
||||
icon('clipboard', 'aria-hidden': 'true'),
|
||||
class: "btn #{css_class}",
|
||||
data: data,
|
||||
type: :button,
|
||||
|
|
@ -34,7 +34,7 @@ module ButtonHelper
|
|||
|
||||
content_tag (append_link ? :a : :span), protocol,
|
||||
class: klass,
|
||||
href: (project.http_url_to_repo if append_link),
|
||||
href: (project.http_url_to_repo(current_user) if append_link),
|
||||
data: {
|
||||
html: true,
|
||||
placement: placement,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
module IssuablesHelper
|
||||
def sidebar_gutter_toggle_icon
|
||||
sidebar_gutter_collapsed? ? icon('angle-double-left') : icon('angle-double-right')
|
||||
sidebar_gutter_collapsed? ? icon('angle-double-left', { 'aria-hidden': 'true' }) : icon('angle-double-right', { 'aria-hidden': 'true' })
|
||||
end
|
||||
|
||||
def sidebar_gutter_collapsed_class
|
||||
|
|
@ -52,7 +52,7 @@ module IssuablesHelper
|
|||
field_name: 'issuable_template',
|
||||
selected: selected_template(issuable),
|
||||
project_path: ref_project.path,
|
||||
namespace_path: ref_project.namespace.path
|
||||
namespace_path: ref_project.namespace.full_path
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@ module MergeRequestsHelper
|
|||
|
||||
def merge_params(merge_request)
|
||||
{
|
||||
merge_when_build_succeeds: true,
|
||||
merge_when_pipeline_succeeds: true,
|
||||
should_remove_source_branch: true,
|
||||
sha: merge_request.diff_head_sha
|
||||
}.merge(merge_params_ee(merge_request))
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ module MilestonesHelper
|
|||
|
||||
def milestone_date_range(milestone)
|
||||
if milestone.start_date && milestone.due_date
|
||||
"#{milestone.start_date.to_s(:medium)} - #{milestone.due_date.to_s(:medium)}"
|
||||
"#{milestone.start_date.to_s(:medium)}–#{milestone.due_date.to_s(:medium)}"
|
||||
elsif milestone.due_date
|
||||
if milestone.due_date.past?
|
||||
"expired on #{milestone.due_date.to_s(:medium)}"
|
||||
|
|
|
|||
|
|
@ -241,7 +241,7 @@ module ProjectsHelper
|
|||
when 'ssh'
|
||||
project.ssh_url_to_repo
|
||||
else
|
||||
project.http_url_to_repo
|
||||
project.http_url_to_repo(current_user)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -76,6 +76,12 @@ class ApplicationSetting < ActiveRecord::Base
|
|||
presence: true,
|
||||
numericality: { only_integer: true, greater_than: 0 }
|
||||
|
||||
validates :max_artifacts_size,
|
||||
presence: true,
|
||||
numericality: { only_integer: true, greater_than: 0 }
|
||||
|
||||
validates :default_artifacts_expire_in, presence: true, duration: true
|
||||
|
||||
validates :container_registry_token_expire_delay,
|
||||
presence: true,
|
||||
numericality: { only_integer: true, greater_than: 0 }
|
||||
|
|
@ -168,6 +174,7 @@ class ApplicationSetting < ActiveRecord::Base
|
|||
after_sign_up_text: nil,
|
||||
akismet_enabled: false,
|
||||
container_registry_token_expire_delay: 5,
|
||||
default_artifacts_expire_in: '30 days',
|
||||
default_branch_protection: Settings.gitlab['default_branch_protection'],
|
||||
default_project_visibility: Settings.gitlab.default_projects_features['visibility_level'],
|
||||
default_projects_limit: Settings.gitlab['default_projects_limit'],
|
||||
|
|
@ -201,9 +208,9 @@ class ApplicationSetting < ActiveRecord::Base
|
|||
sign_in_text: nil,
|
||||
signin_enabled: Settings.gitlab['signin_enabled'],
|
||||
signup_enabled: Settings.gitlab['signup_enabled'],
|
||||
terminal_max_session_time: 0,
|
||||
two_factor_grace_period: 48,
|
||||
user_default_external: false,
|
||||
terminal_max_session_time: 0
|
||||
user_default_external: false
|
||||
}
|
||||
end
|
||||
|
||||
|
|
@ -215,6 +222,14 @@ class ApplicationSetting < ActiveRecord::Base
|
|||
create(defaults)
|
||||
end
|
||||
|
||||
def self.human_attribute_name(attr, _options = {})
|
||||
if attr == :default_artifacts_expire_in
|
||||
'Default artifacts expiration'
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
def home_page_url_column_exist
|
||||
ActiveRecord::Base.connection.column_exists?(:application_settings, :home_page_url)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -55,15 +55,6 @@ module Ci
|
|||
pending.unstarted.order('created_at ASC').first
|
||||
end
|
||||
|
||||
def create_from(build)
|
||||
new_build = build.dup
|
||||
new_build.status = 'pending'
|
||||
new_build.runner_id = nil
|
||||
new_build.trigger_request_id = nil
|
||||
new_build.token = nil
|
||||
new_build.save
|
||||
end
|
||||
|
||||
def retry(build, current_user)
|
||||
Ci::RetryBuildService
|
||||
.new(build.project, current_user)
|
||||
|
|
@ -484,7 +475,7 @@ module Ci
|
|||
def artifacts_expire_in=(value)
|
||||
self.artifacts_expire_at =
|
||||
if value
|
||||
Time.now + ChronicDuration.parse(value)
|
||||
ChronicDuration.parse(value)&.seconds&.from_now
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
class Uniquify
|
||||
# Return a version of the given 'base' string that is unique
|
||||
# by appending a counter to it. Uniqueness is determined by
|
||||
# repeated calls to the passed block.
|
||||
#
|
||||
# If `base` is a function/proc, we expect that calling it with a
|
||||
# candidate counter returns a string to test/return.
|
||||
def string(base)
|
||||
@base = base
|
||||
@counter = nil
|
||||
|
||||
increment_counter! while yield(base_string)
|
||||
base_string
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def base_string
|
||||
if @base.respond_to?(:call)
|
||||
@base.call(@counter)
|
||||
else
|
||||
"#{@base}#{@counter}"
|
||||
end
|
||||
end
|
||||
|
||||
def increment_counter!
|
||||
@counter ||= 0
|
||||
@counter += 1
|
||||
end
|
||||
end
|
||||
|
|
@ -36,7 +36,7 @@ class Event < ActiveRecord::Base
|
|||
scope :code_push, -> { where(action: PUSHED) }
|
||||
|
||||
scope :in_projects, ->(projects) do
|
||||
where(project_id: projects).recent
|
||||
where(project_id: projects.pluck(:id)).recent
|
||||
end
|
||||
|
||||
scope :with_associations, -> { includes(:author, :project, project: :namespace).preload(:target) }
|
||||
|
|
|
|||
|
|
@ -91,17 +91,13 @@ class MergeRequest < ActiveRecord::Base
|
|||
around_transition do |merge_request, transition, block|
|
||||
Gitlab::Timeless.timeless(merge_request, &block)
|
||||
end
|
||||
|
||||
after_transition unchecked: :cannot_be_merged do |merge_request, transition|
|
||||
TodoService.new.merge_request_became_unmergeable(merge_request)
|
||||
end
|
||||
end
|
||||
|
||||
validates :source_project, presence: true, unless: [:allow_broken, :importing?, :closed_without_fork?]
|
||||
validates :source_branch, presence: true
|
||||
validates :target_project, presence: true
|
||||
validates :target_branch, presence: true
|
||||
validates :merge_user, presence: true, if: :merge_when_build_succeeds?, unless: :importing?
|
||||
validates :merge_user, presence: true, if: :merge_when_pipeline_succeeds?, unless: :importing?
|
||||
validate :validate_branches, unless: [:allow_broken, :importing?, :closed_without_fork?]
|
||||
validate :validate_fork, unless: :closed_without_fork?
|
||||
|
||||
|
|
@ -440,7 +436,7 @@ class MergeRequest < ActiveRecord::Base
|
|||
true
|
||||
end
|
||||
|
||||
def can_cancel_merge_when_build_succeeds?(current_user)
|
||||
def can_cancel_merge_when_pipeline_succeeds?(current_user)
|
||||
can_be_merged_by?(current_user) || self.author == current_user
|
||||
end
|
||||
|
||||
|
|
@ -648,10 +644,10 @@ class MergeRequest < ActiveRecord::Base
|
|||
message.join("\n\n")
|
||||
end
|
||||
|
||||
def reset_merge_when_build_succeeds
|
||||
return unless merge_when_build_succeeds?
|
||||
def reset_merge_when_pipeline_succeeds
|
||||
return unless merge_when_pipeline_succeeds?
|
||||
|
||||
self.merge_when_build_succeeds = false
|
||||
self.merge_when_pipeline_succeeds = false
|
||||
self.merge_user = nil
|
||||
if merge_params
|
||||
merge_params.delete('should_remove_source_branch')
|
||||
|
|
@ -710,7 +706,7 @@ class MergeRequest < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def mergeable_ci_state?
|
||||
return true unless project.only_allow_merge_if_build_succeeds?
|
||||
return true unless project.only_allow_merge_if_pipeline_succeeds?
|
||||
|
||||
!head_pipeline || head_pipeline.success? || head_pipeline.skipped?
|
||||
end
|
||||
|
|
|
|||
|
|
@ -99,14 +99,8 @@ class Namespace < ActiveRecord::Base
|
|||
# Work around that by setting their username to "blank", followed by a counter.
|
||||
path = "blank" if path.blank?
|
||||
|
||||
counter = 0
|
||||
base = path
|
||||
while Namespace.find_by_path_or_name(path)
|
||||
counter += 1
|
||||
path = "#{base}#{counter}"
|
||||
end
|
||||
|
||||
path
|
||||
uniquify = Uniquify.new
|
||||
uniquify.string(path) { |s| Namespace.find_by_path_or_name(s) }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -231,10 +231,6 @@ class Note < ActiveRecord::Base
|
|||
note =~ /\A#{Banzai::Filter::EmojiFilter.emoji_pattern}\s?\Z/
|
||||
end
|
||||
|
||||
def award_emoji_name
|
||||
note.match(Banzai::Filter::EmojiFilter.emoji_pattern)[1]
|
||||
end
|
||||
|
||||
def to_ability_name
|
||||
for_personal_snippet? ? 'personal_snippet' : noteable_type.underscore
|
||||
end
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ class Project < ActiveRecord::Base
|
|||
|
||||
extend Gitlab::ConfigHelper
|
||||
|
||||
class BoardLimitExceeded < StandardError; end
|
||||
BoardLimitExceeded = Class.new(StandardError)
|
||||
|
||||
NUMBER_OF_PERMITTED_BOARDS = 1
|
||||
UNKNOWN_IMPORT_URL = 'http://unknown.git'.freeze
|
||||
|
|
@ -359,7 +359,7 @@ class Project < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def reference_pattern
|
||||
name_pattern = Gitlab::Regex::NAMESPACE_REGEX_STR
|
||||
name_pattern = Gitlab::Regex::FULL_NAMESPACE_REGEX_STR
|
||||
|
||||
%r{
|
||||
((?<namespace>#{name_pattern})\/)?
|
||||
|
|
@ -847,10 +847,6 @@ class Project < ActiveRecord::Base
|
|||
gitlab_shell.url_to_repo(path_with_namespace)
|
||||
end
|
||||
|
||||
def namespace_dir
|
||||
namespace.try(:path) || ''
|
||||
end
|
||||
|
||||
def repo_exists?
|
||||
@repo_exists ||= repository.exists?
|
||||
rescue
|
||||
|
|
@ -873,8 +869,14 @@ class Project < ActiveRecord::Base
|
|||
url_to_repo
|
||||
end
|
||||
|
||||
def http_url_to_repo
|
||||
"#{web_url}.git"
|
||||
def http_url_to_repo(user = nil)
|
||||
url = web_url
|
||||
|
||||
if user
|
||||
url.sub!(%r{\Ahttps?://}) { |protocol| "#{protocol}#{user.username}@" }
|
||||
end
|
||||
|
||||
"#{url}.git"
|
||||
end
|
||||
|
||||
# Check if current branch name is marked as protected in the system
|
||||
|
|
@ -899,8 +901,8 @@ class Project < ActiveRecord::Base
|
|||
|
||||
def rename_repo
|
||||
path_was = previous_changes['path'].first
|
||||
old_path_with_namespace = File.join(namespace_dir, path_was)
|
||||
new_path_with_namespace = File.join(namespace_dir, path)
|
||||
old_path_with_namespace = File.join(namespace.full_path, path_was)
|
||||
new_path_with_namespace = File.join(namespace.full_path, path)
|
||||
|
||||
Rails.logger.error "Attempting to rename #{old_path_with_namespace} -> #{new_path_with_namespace}"
|
||||
|
||||
|
|
|
|||
|
|
@ -33,8 +33,15 @@ class ProjectGroupLink < ActiveRecord::Base
|
|||
private
|
||||
|
||||
def different_group
|
||||
if self.group && self.project && self.project.group == self.group
|
||||
errors.add(:base, "Project cannot be shared with the project it is in.")
|
||||
return unless self.group && self.project
|
||||
|
||||
project_group = self.project.group
|
||||
return unless project_group
|
||||
|
||||
group_ids = project_group.ancestors.map(&:id).push(project_group.id)
|
||||
|
||||
if group_ids.include?(self.group.id)
|
||||
errors.add(:base, "Project cannot be shared with the group it is in or one of its ancestors.")
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -15,10 +15,10 @@ class MattermostService < ChatNotificationService
|
|||
'This service sends notifications about projects events to Mattermost channels.<br />
|
||||
To set up this service:
|
||||
<ol>
|
||||
<li><a href="https://docs.mattermost.com/developer/webhooks-incoming.html#enabling-incoming-webhooks">Enable incoming webhooks</a> in your Mattermost installation. </li>
|
||||
<li><a href="https://docs.mattermost.com/developer/webhooks-incoming.html#creating-integrations-using-incoming-webhooks">Add an incoming webhook</a> in your Mattermost team. The default channel can be overridden for each event. </li>
|
||||
<li>Paste the webhook <strong>URL</strong> into the field bellow. </li>
|
||||
<li>Select events below to enable notifications. The channel and username are optional. </li>
|
||||
<li><a href="https://docs.mattermost.com/developer/webhooks-incoming.html#enabling-incoming-webhooks">Enable incoming webhooks</a> in your Mattermost installation.</li>
|
||||
<li><a href="https://docs.mattermost.com/developer/webhooks-incoming.html#creating-integrations-using-incoming-webhooks">Add an incoming webhook</a> in your Mattermost team. The default channel can be overridden for each event.</li>
|
||||
<li>Paste the webhook <strong>URL</strong> into the field below.</li>
|
||||
<li>Select events below to enable notifications. The <strong>Channel handle</strong> and <strong>Username</strong> fields are optional.</li>
|
||||
</ol>'
|
||||
end
|
||||
|
||||
|
|
@ -28,14 +28,14 @@ class MattermostService < ChatNotificationService
|
|||
|
||||
def default_fields
|
||||
[
|
||||
{ type: 'text', name: 'webhook', placeholder: 'http://mattermost_host/hooks/...' },
|
||||
{ type: 'text', name: 'username', placeholder: 'username' },
|
||||
{ type: 'text', name: 'webhook', placeholder: 'e.g. http://mattermost_host/hooks/…' },
|
||||
{ type: 'text', name: 'username', placeholder: 'e.g. GitLab' },
|
||||
{ type: 'checkbox', name: 'notify_only_broken_builds' },
|
||||
{ type: 'checkbox', name: 'notify_only_broken_pipelines' },
|
||||
]
|
||||
end
|
||||
|
||||
def default_channel_placeholder
|
||||
"town-square"
|
||||
"Channel handle (e.g. town-square)"
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue