Commit ad0511f5 authored by Lin Jen-Shin's avatar Lin Jen-Shin

Merge remote-tracking branch 'upstream/master' into pipeline-hooks

* upstream/master: (368 commits)
  Don't fail on an empty database
  Refactor authorization_for_merge_requests.md
  Support MySQL too, when removing gitorious from import_sources
  Remove gitorious from import_sources on ApplicationSetting model
  Add links to new docs in merge_requests.md and workflow/README.md
  Move merge request versions to its own document
  Move "Only allow merge requests to be merged if the build succeeds" to new location
  Move revert_changes.md to new location
  Move cherry_pick_changes.md to new location
  Move `wip_merge_requests.md` to a new location
  Move merge_when_build_succeeds.md to new location
  Fix missing flash messages on service edit page
  Move authorization_for_merge_requests.md to new location
  Move `workflow/merge_requests.md` to `user/project/merge_requests.md`
  Update README.md
  Fix randomly failing specs in expand_collapse_diff_spec:
  Add link on API docs index page
  Move CHANGELOG entries of !5361, !5451 and !5887 from 8.11 to 8.12
  Remove suggested colors hover underline
  Fix markdown anchor icon interaction
  ...
parents da1acf04 ad599eb6
### Summary
(Summarize the bug encountered concisely)
### Steps to reproduce
(How one can reproduce the issue - this is very important)
### Expected behavior
(What you should see instead)
### Actual behavior
(What actually happens)
### Relevant logs and/or screenshots
(Paste any relevant logs - please use code blocks (```) to format console output,
logs, and code as it's very hard to read otherwise.)
### Output of checks
#### Results of GitLab application Check
(For installations with omnibus-gitlab package run and paste the output of:
`sudo gitlab-rake gitlab:check SANITIZE=true`)
(For installations from source run and paste the output of:
`sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production SANITIZE=true`)
(we will only investigate if the tests are passing)
#### Results of GitLab environment info
(For installations with omnibus-gitlab package run and paste the output of:
`sudo gitlab-rake gitlab:env:info`)
(For installations from source run and paste the output of:
`sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production`)
### Possible fixes
(If you can, link to the line of code that might be responsible for the problem)
### Description
(Include problem, use cases, benefits, and/or goals)
### Proposal
### Links / references
See the general Documentation guidelines http://docs.gitlab.com/ce/development/doc_styleguide.html.
## What does this MR do?
(briefly describe what this MR is about)
## Moving docs to a new location?
See the guidelines: http://docs.gitlab.com/ce/development/doc_styleguide.html#changing-document-location
- [ ] Make sure the old link is not removed and has its contents replaced with a link to the new location.
- [ ] Make sure internal links pointing to the document in question are not broken.
- [ ] Search and replace any links referring to old docs in GitLab Rails app, specifically under the `app/views/` directory.
- [ ] If working on CE, submit an MR to EE with the changes as well.
......@@ -5,8 +5,8 @@ require:
inherit_from: .rubocop_todo.yml
AllCops:
TargetRubyVersion: 2.1
# Cop names are not displayed in offense messages by default. Change behavior
TargetRubyVersion: 2.3
# Cop names are not d§splayed in offense messages by default. Change behavior
# by overriding DisplayCopNames, or by giving the -D/--display-cop-names
# option.
DisplayCopNames: true
......@@ -192,6 +192,9 @@ Style/FlipFlop:
Style/For:
Enabled: true
# Checks if there is a magic comment to enforce string literals
Style/FrozenStringLiteralComment:
Enabled: false
# Do not introduce global variables.
Style/GlobalVars:
Enabled: true
......
Please view this file on the master branch, on stable branches it's out of date.
v 8.12.0 (unreleased)
- Prepend blank line to `Closes` message on merge request linked to issue (lukehowell)
- Filter tags by name !6121
- Make push events have equal vertical spacing.
- Add two-factor recovery endpoint to internal API !5510
- Remove vendor prefixes for linear-gradient CSS (ClemMakesApps)
- Add font color contrast to external label in admin area (ClemMakesApps)
- Change logo animation to CSS (ClemMakesApps)
- Instructions for enabling Git packfile bitmaps !6104
- Change merge_error column from string to text type
- Reduce contributions calendar data payload (ClemMakesApps)
- Add `web_url` field to issue, merge request, and snippet API objects (Ben Boeckel)
- Expose `sha` and `merge_commit_sha` in merge request API (Ben Boeckel)
- Set path for all JavaScript cookies to honor GitLab's subdirectory setting !5627 (Mike Greiling)
- Fix bug where pagination is still displayed despite all todos marked as done (ClemMakesApps)
- Center build stage columns in pipeline overview (ClemMakesApps)
- Rename behaviour to behavior in bug issue template for consistency (ClemMakesApps)
- Remove suggested colors hover underline (ClemMakesApps)
- Shorten task status phrase (ClemMakesApps)
- Add hover color to emoji icon (ClemMakesApps)
- Fix branches page dropdown sort alignment (ClemMakesApps)
- Add white background for no readme container (ClemMakesApps)
- API: Expose issue confidentiality flag. (Robert Schilling)
- Fix markdown anchor icon interaction (ClemMakesApps)
- Optimistic locking for Issues and Merge Requests (title and description overriding prevention)
- Add `wiki_page_events` to project hook APIs (Ben Boeckel)
- Remove Gitorious import
- Fix inconsistent background color for filter input field (ClemMakesApps)
- Remove prefixes from transition CSS property (ClemMakesApps)
- Add Sentry logging to API calls
- Add BroadcastMessage API
- Use 'git update-ref' for safer web commits !6130
- Automatically expand hidden discussions when accessed by a permalink !5585 (Mike Greiling)
- Remove unused mixins (ClemMakesApps)
- Add search to all issue board lists
- Fix groups sort dropdown alignment (ClemMakesApps)
- Add horizontal scrolling to all sub-navs on mobile viewports (ClemMakesApps)
- Use JavaScript tooltips for mentions !5301 (winniehell)
- Add hover state to todos !5361 (winniehell)
- Fix icon alignment of star and fork buttons !5451 (winniehell)
- Fix alignment of icon buttons !5887 (winniehell)
- Fix markdown help references (ClemMakesApps)
- Add last commit time to repo view (ClemMakesApps)
- Fix accessibility and visibility of project list dropdown button !6140
- Fix missing flash messages on service edit page (airatshigapov)
- Added project specific enable/disable setting for LFS !5997
- Don't expose a user's token in the `/api/v3/user` API (!6047)
- Remove redundant js-timeago-pending from user activity log (ClemMakesApps)
- Ability to manage project issues, snippets, wiki, merge requests and builds access level
- Remove inconsistent font weight for sidebar's labels (ClemMakesApps)
- Align add button on repository view (ClemMakesApps)
- Added tests for diff notes
- Add pipeline events to Slack integration !5525
- Add a button to download latest successful artifacts for branches and tags !5142
- Remove redundant pipeline tooltips (ClemMakesApps)
- Expire commit info views after one day, instead of two weeks, to allow for user email updates
- Add delimiter to project stars and forks count (ClemMakesApps)
- Fix badge count alignment (ClemMakesApps)
- Remove green outline from `New branch unavailable` button on issue page !5858 (winniehell)
- Fix repo title alignment (ClemMakesApps)
- Fix branch title trailing space on hover (ClemMakesApps)
- Award emoji tooltips containing more than 10 usernames are now truncated !4780 (jlogandavison)
- Fix duplicate "me" in award emoji tooltip !5218 (jlogandavison)
- Order award emoji tooltips in order they were added (EspadaV8)
- Fix spacing and vertical alignment on build status icon on commits page (ClemMakesApps)
- Update merge_requests.md with a simpler way to check out a merge request. !5944
- Fix button missing type (ClemMakesApps)
- Move to project dropdown with infinite scroll for better performance
- Fix leaking of submit buttons outside the width of a main container !18731 (originally by @pavelloz)
- Load branches asynchronously in Cherry Pick and Revert dialogs.
- Convert datetime coffeescript spec to ES6 (ClemMakesApps)
- Add merge request versions !5467
- Change using size to use count and caching it for number of group members. !5935
- Replace play icon font with svg (ClemMakesApps)
- Added 'only_allow_merge_if_build_succeeds' project setting in the API. !5930 (Duck)
- Reduce number of database queries on builds tab
- Wrap text in commit message containers
- Capitalize mentioned issue timeline notes (ClemMakesApps)
- Fix inconsistent checkbox alignment (ClemMakesApps)
- Use the default branch for displaying the project icon instead of master !5792 (Hannes Rosenögger)
- Adds response mime type to transaction metric action when it's not HTML
v 8.11.3 (unreleased)
- Fix hover leading space bug in pipeline graph !5980
- User can edit closed MR with deleted fork (Katarzyna Kobierska Ula Budziszewska) !5496
- Fixed invisible scroll controls on build page on iPhone
- Fix error on raw build trace download for old builds stored in database !4822
v 8.11.5 (unreleased)
- Optimize branch lookups and force a repository reload for Repository#find_branch
- Fix member expiration date picker after update
- Fix suggested colors options for new labels in the admin area. !6138
- Fix GitLab import button
- Remove gitorious from import_sources
v 8.11.4
- Fix resolving conflicts on forks. !6082
- Fix diff commenting on merge requests created prior to 8.10. !6029
- Fix pipelines tab layout regression. !5952
- Fix "Wiki" link not appearing in navigation for projects with external wiki. !6057
- Do not enforce using hash with hidden key in CI configuration. !6079
- Fix hover leading space bug in pipeline graph !5980
- Fix sorting issues by "last updated" doesn't work after import from GitHub
- GitHub importer use default project visibility for non-private projects
- Creating an issue through our API now emails label subscribers !5720
- Block concurrent updates for Pipeline
- Don't create groups for unallowed users when importing projects
- Fix resolving conflicts on forks
- Fix diff commenting on merge requests created prior to 8.10
- Don't create groups for unallowed users when importing projects
- Scope webhooks/services that will run for confidential issues
- Fix issue boards leak private label names and descriptions
- Fix broken gitlab:backup:restore because of bad permissions on repo storage !6098 (Dirk Hörner)
- Remove gitorious. !5866
v 8.11.3
- Allow system info page to handle case where info is unavailable
- Label list shows all issues (opened or closed) with that label
- Don't show resolve conflicts link before MR status is updated
- Fix IE11 fork button bug !5982
- Don't prevent viewing the MR when git refs for conflicts can't be found on disk
- Fix external issue tracker "Issues" link leading to 404s
- Don't try to show merge conflict resolution info if a merge conflict contains non-UTF-8 characters
- Automatically expand hidden discussions when accessed by a permalink !5585 (Mike Greiling)
v 8.11.2
- Show "Create Merge Request" widget for push events to fork projects on the source project. !5978
......@@ -107,8 +190,6 @@ v 8.11.0
- Update `timeago` plugin to use multiple string/locale settings
- Remove unused images (ClemMakesApps)
- Get issue and merge request description templates from repositories
- Add hover state to todos !5361 (winniehell)
- Fix icon alignment of star and fork buttons !5451 (winniehell)
- Enforce 2FA restrictions on API authentication endpoints !5820
- Limit git rev-list output count to one in forced push check
- Show deployment status on merge requests with external URLs
......
......@@ -129,7 +129,7 @@ request that potentially fixes it.
### Feature proposals
To create a feature proposal for CE and CI, open an issue on the
To create a feature proposal for CE, open an issue on the
[issue tracker of CE][ce-tracker].
For feature proposals for EE, open an issue on the
......@@ -144,16 +144,7 @@ code snippet right after your description in a new line: `~"feature proposal"`.
Please keep feature proposals as small and simple as possible, complex ones
might be edited to make them small and simple.
You are encouraged to use the template below for feature proposals.
```
## Description
Include problem, use cases, benefits, and/or goals
## Proposal
## Links / references
```
Please submit Feature Proposals using the ['Feature Proposal' issue template](.gitlab/issue_templates/Feature Proposal.md) provided on the issue tracker.
For changes in the interface, it can be helpful to create a mockup first.
If you want to create something yourself, consider opening an issue first to
......@@ -166,55 +157,11 @@ submitting your own, there's a good chance somebody else had the same issue or
feature proposal. Show your support with an award emoji and/or join the
discussion.
Please submit bugs using the following template in the issue description area.
Please submit bugs using the ['Bug' issue template](.gitlab/issue_templates/Bug.md) provided on the issue tracker.
The text in the parenthesis is there to help you with what to include. Omit it
when submitting the actual issue. You can copy-paste it and then edit as you
see fit.
```
## Summary
(Summarize your issue in one sentence - what goes wrong, what did you expect to happen)
## Steps to reproduce
(How one can reproduce the issue - this is very important)
## Expected behavior
(What you should see instead)
## Relevant logs and/or screenshots
(Paste any relevant logs - please use code blocks (```) to format console output,
logs, and code as it's very hard to read otherwise.)
## Output of checks
### Results of GitLab Application Check
(For installations with omnibus-gitlab package run and paste the output of:
sudo gitlab-rake gitlab:check SANITIZE=true)
(For installations from source run and paste the output of:
sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production SANITIZE=true)
(we will only investigate if the tests are passing)
### Results of GitLab Environment Info
(For installations with omnibus-gitlab package run and paste the output of:
sudo gitlab-rake gitlab:env:info)
(For installations from source run and paste the output of:
sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production)
## Possible fixes
(If you can, link to the line of code that might be responsible for the problem)
```
### Issue weight
Issue weight allows us to get an idea of the amount of work required to solve
......@@ -340,6 +287,8 @@ request is as follows:
migrations on a fresh database before the MR is reviewed. If the review leads
to large changes in the MR, do this again once the review is complete.
1. For more complex migrations, write tests.
1. Merge requests **must** adhere to the [merge request performance
guidelines](doc/development/merge_request_performance_guidelines.md).
The **official merge window** is in the beginning of the month from the 1st to
the 7th day of the month. This is the best time to submit an MR and get
......
......@@ -53,7 +53,7 @@ gem 'browser', '~> 2.2'
# Extracting information from a git repository
# Provide access to Gitlab::Git library
gem 'gitlab_git', '~> 10.4.7'
gem 'gitlab_git', '~> 10.5'
# LDAP Auth
# GitLab fork with several improvements to original library. For full list of changes
......@@ -97,9 +97,6 @@ gem 'fog-rackspace', '~> 0.1.1'
# for aws storage
gem 'unf', '~> 0.1.4'
# Authorization
gem 'six', '~> 0.2.0'
# Seed data
gem 'seed-fu', '~> 2.3.5'
......
......@@ -279,7 +279,7 @@ GEM
diff-lcs (~> 1.1)
mime-types (>= 1.16, < 3)
posix-spawn (~> 0.3)
gitlab_git (10.4.7)
gitlab_git (10.5.0)
activesupport (~> 4.0)
charlock_holmes (~> 0.7.3)
github-linguist (~> 4.7.0)
......@@ -683,7 +683,6 @@ GEM
rack (~> 1.5)
rack-protection (~> 1.4)
tilt (>= 1.3, < 3)
six (0.2.0)
slack-notifier (1.2.1)
slop (3.6.0)
spinach (0.8.10)
......@@ -859,7 +858,7 @@ DEPENDENCIES
github-linguist (~> 4.7.0)
github-markup (~> 1.4)
gitlab-flowdock-git-hook (~> 1.0.1)
gitlab_git (~> 10.4.7)
gitlab_git (~> 10.5)
gitlab_meta (= 7.0)
gitlab_omniauth-ldap (~> 1.2.1)
gollum-lib (~> 4.2)
......@@ -954,7 +953,6 @@ DEPENDENCIES
sidekiq-cron (~> 0.4.0)
simplecov (= 0.12.0)
sinatra (~> 1.4.4)
six (~> 0.2.0)
slack-notifier (~> 1.2.0)
spinach-rails (~> 0.2.1)
spinach-rerun-reporter (~> 0.0.2)
......
......@@ -50,7 +50,7 @@ etc.).
The most important thing is making sure valid issues receive feedback from the
development team. Therefore the priority is mentioning developers that can help
on those issue. Please select someone with relevant experience from
on those issues. Please select someone with relevant experience from
[GitLab core team][core-team]. If there is nobody mentioned with that expertise
look in the commit history for the affected files to find someone. Avoid
mentioning the lead developer, this is the person that is least likely to give a
......
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path fill="#333" fill-rule="evenodd" d="M9.683 6.676l-.047-.048C8.27 5.26 6.07 5.243 4.726 6.588l-2.29 2.29c-1.344 1.344-1.328 3.544.04 4.91 1.366 1.368 3.564 1.385 4.908.04l1.753-1.752c-.695.074-1.457-.078-2.176-.444L5.934 12.66c-.634.634-1.67.625-2.312-.017-.642-.643-.65-1.677-.017-2.312L6.035 7.9c.634-.634 1.67-.625 2.312.017.024.024.048.05.07.075l.003-.002c.36.36.943.366 1.3.01.355-.356.35-.938-.01-1.3l-.027-.024zM6.58 9.586l.048.05c1.367 1.366 3.565 1.384 4.91.04l2.29-2.292c1.344-1.343 1.328-3.542-.04-4.91-1.366-1.366-3.564-1.384-4.908-.04L7.127 4.187c.695-.074 1.457.078 2.176.444l1.028-1.027c.635-.634 1.67-.624 2.313.017.643.644.652 1.678.018 2.312l-2.43 2.432c-.635.634-1.67.624-2.313-.018-.024-.024-.048-.05-.07-.075l-.003.004c-.36-.362-.943-.367-1.3-.01-.355.355-.35.937.01 1.3.01.007.018.015.027.023z"/></svg>
\ No newline at end of file
......@@ -12,7 +12,7 @@
}
Activities.prototype.updateTooltips = function() {
return gl.utils.localTimeAgo($('.js-timeago', '#activity'));
return gl.utils.localTimeAgo($('.js-timeago', '.content_list'));
};
Activities.prototype.reloadActivities = function() {
......
(function(w) {
$(function() {
$('.js-toggle-button').on('click', function(e) {
$('body').on('click', '.js-toggle-button', function(e) {
e.preventDefault();
$(this)
.find('.fa')
......
......@@ -54,4 +54,11 @@ $(() => {
});
}
});
gl.IssueBoardsSearch = new Vue({
el: '#js-boards-seach',
data: {
filters: Store.state.filters
}
});
});
......@@ -21,15 +21,10 @@
},
data () {
return {
query: '',
filters: Store.state.filters
};
},
watch: {
query () {
this.list.filters = this.getFilterData();
this.list.getIssues(true);
},
filters: {
handler () {
this.list.page = 1;
......@@ -38,16 +33,6 @@
deep: true
}
},
methods: {
getFilterData () {
const filters = this.filters;
let queryData = { search: this.query };
Object.keys(filters).forEach((key) => { queryData[key] = filters[key]; });
return queryData;
}
},
ready () {
const options = gl.issueBoards.getBoardSortableDefaultOptions({
disabled: this.disabled,
......
......@@ -20,7 +20,8 @@
data () {
return {
scrollOffset: 250,
filters: Store.state.filters
filters: Store.state.filters,
showCount: false
};
},
watch: {
......@@ -30,6 +31,15 @@
this.$els.list.scrollTop = 0;
},
deep: true
},
issues () {
this.$nextTick(() => {
if (this.scrollHeight() > this.listHeight()) {
this.showCount = true;
} else {
this.showCount = false;
}
});
}
},
methods: {
......@@ -58,6 +68,7 @@
group: 'issues',
sort: false,
disabled: this.disabled,
filter: '.board-list-count',
onStart: (e) => {
const card = this.$refs.issue[e.oldIndex];
......
......@@ -11,6 +11,7 @@ class List {
this.loading = true;
this.loadingMore = false;
this.issues = [];
this.issuesSize = 0;
if (obj.label) {
this.label = new ListLabel(obj.label);
......@@ -51,17 +52,13 @@ class List {
}
nextPage () {
if (Math.floor(this.issues.length / 20) === this.page) {
if (this.issuesSize > this.issues.length) {
this.page++;
return this.getIssues(false);
}
}
canSearch () {
return this.type === 'backlog';
}
getIssues (emptyIssues = true) {
const filters = this.filters;
let data = { page: this.page };
......@@ -80,12 +77,13 @@ class List {
.then((resp) => {
const data = resp.json();
this.loading = false;
this.issuesSize = data.size;
if (emptyIssues) {
this.issues = [];
}
this.createIssues(data);
this.createIssues(data.issues);
});
}
......@@ -96,14 +94,20 @@ class List {
}
addIssue (issue, listFrom) {
this.issues.push(issue);
if (!this.findIssue(issue.id)) {
this.issues.push(issue);
if (this.label) {
issue.addLabel(this.label);
}
if (this.label) {
issue.addLabel(this.label);
}
if (listFrom) {
gl.boardService.moveIssue(issue.id, listFrom.id, this.id);
if (listFrom) {
this.issuesSize++;
gl.boardService.moveIssue(issue.id, listFrom.id, this.id)
.then(() => {
listFrom.getIssues(false);
});
}
}
}
......@@ -116,6 +120,7 @@ class List {
const matchesRemove = removeIssue.id === issue.id;
if (matchesRemove) {
this.issuesSize--;
issue.removeLabel(this.label);
}
......
......@@ -15,7 +15,8 @@
author_id: gl.utils.getParameterValues('author_id')[0],
assignee_id: gl.utils.getParameterValues('assignee_id')[0],
milestone_title: gl.utils.getParameterValues('milestone_title')[0],
label_name: gl.utils.getParameterValues('label_name[]')
label_name: gl.utils.getParameterValues('label_name[]'),
search: ''
};
},
addList (listObj) {
......
......@@ -199,6 +199,7 @@
break;
case 'labels':
switch (path[2]) {
case 'new':
case 'edit':
new Labels();
}
......
......@@ -117,7 +117,7 @@
}
});
} else {
return elements.show();
return elements.show().removeClass('option-hidden');
}
}
};
......@@ -190,9 +190,9 @@
currentIndex = -1;
NON_SELECTABLE_CLASSES = '.divider, .separator, .dropdown-header, .dropdown-menu-empty-link, .option-hidden';
NON_SELECTABLE_CLASSES = '.divider, .separator, .dropdown-header, .dropdown-menu-empty-link';
SELECTABLE_CLASSES = ".dropdown-content li:not(" + NON_SELECTABLE_CLASSES + ")";
SELECTABLE_CLASSES = ".dropdown-content li:not(" + NON_SELECTABLE_CLASSES + ", .option-hidden)";
CURSOR_SELECT_SCROLL_PADDING = 5
......@@ -556,7 +556,7 @@
if (isInput) {
field = $(this.el);
} else {
field = this.dropdown.parent().find("input[name='" + fieldName + "'][value='" + value + "']");
field = this.dropdown.parent().find("input[name='" + fieldName + "'][value='" + escape(value) + "']");
}
if (el.hasClass(ACTIVE_CLASS)) {
el.removeClass(ACTIVE_CLASS);
......@@ -565,10 +565,6 @@
} else {
field.remove();
}
if (this.options.toggleLabel) {
this.updateLabel(selectedObject, el, this);
}
return selectedObject;
} else if (el.hasClass(INDETERMINATE_CLASS)) {
el.addClass(ACTIVE_CLASS);
el.removeClass(INDETERMINATE_CLASS);
......@@ -578,7 +574,6 @@
if (!field.length && fieldName) {
this.addInput(fieldName, value, selectedObject);
}
return selectedObject;
} else {
if (!this.options.multiSelect || el.hasClass('dropdown-clear-active')) {
this.dropdown.find("." + ACTIVE_CLASS).removeClass(ACTIVE_CLASS);
......@@ -590,9 +585,6 @@
field.remove();
}
el.addClass(ACTIVE_CLASS);
if (this.options.toggleLabel) {
this.updateLabel(selectedObject, el, this);
}
if (value != null) {
if (!field.length && fieldName) {
this.addInput(fieldName, value, selectedObject);
......@@ -600,8 +592,14 @@
field.val(value).trigger('change');
}
}
return selectedObject;
}
// Update label right after input has been added
if (this.options.toggleLabel) {
this.updateLabel(selectedObject, el, this);
}
return selectedObject;
};
GitLabDropdown.prototype.addInput = function(fieldName, value, selectedObject) {
......
......@@ -10,21 +10,24 @@
ImporterStatus.prototype.initStatusPage = function() {
$('.js-add-to-import').off('click').on('click', (function(_this) {
return function(e) {
var $btn, $namespace_input, $target_field, $tr, id, new_namespace;
var $btn, $namespace_input, $target_field, $tr, id, target_namespace;
$btn = $(e.currentTarget);
$tr = $btn.closest('tr');
$target_field = $tr.find('.import-target');
$namespace_input = $target_field.find('input');
id = $tr.attr('id').replace('repo_', '');
new_namespace = null;
target_namespace = null;
if ($namespace_input.length > 0) {
new_namespace = $namespace_input.prop('value');
$target_field.empty().append(new_namespace + "/" + ($target_field.data('project_name')));
target_namespace = $namespace_input.prop('value');
$target_field.empty().append(target_namespace + "/" + ($target_field.data('project_name')));
}
$btn.disable().addClass('is-loading');
return $.post(_this.import_url, {
repo_id: id,
new_namespace: new_namespace
target_namespace: target_namespace
}, {
dataType: 'script'
});
......@@ -70,7 +73,7 @@
if ($('.js-importer-status').length) {
var jobsImportPath = $('.js-importer-status').data('jobs-import-path');
var importPath = $('.js-importer-status').data('import-path');
new ImporterStatus(jobsImportPath, importPath);
}
});
......
......@@ -127,7 +127,7 @@
Issue.prototype.initCanCreateBranch = function() {
var $container;
$container = $('div#new-branch');
$container = $('#new-branch');
if ($container.length === 0) {
return;
}
......@@ -139,7 +139,6 @@
if (data.can_create_branch) {
$container.find('.checking').hide();
$container.find('.available').show();
return $container.find('a').attr('disabled', false);
} else {
$container.find('.checking').hide();
return $container.find('.unavailable').show();
......
......@@ -164,7 +164,7 @@
instance.addInput(this.fieldName, label.id);
}
}
if ($form.find("input[type='hidden'][name='" + ($dropdown.data('fieldName')) + "'][value='" + (this.id(label)) + "']").length) {
if ($form.find("input[type='hidden'][name='" + ($dropdown.data('fieldName')) + "'][value='" + escape(this.id(label)) + "']").length) {
selectedClass.push('is-active');
}
if ($dropdown.hasClass('js-multiselect') && removesAll) {
......
(function() {
var clearHighlights, currentTimer, defaultClass, delay, firstPiece, pieceIndex, pieces, start, stop, work;
Turbolinks.enableProgressBar();
defaultClass = 'tanuki-shape';
pieces = ['path#tanuki-right-cheek', 'path#tanuki-right-eye, path#tanuki-right-ear', 'path#tanuki-nose', 'path#tanuki-left-eye, path#tanuki-left-ear', 'path#tanuki-left-cheek'];
pieceIndex = 0;
firstPiece = pieces[0];
currentTimer = null;
delay = 150;
clearHighlights = function() {
return $("." + defaultClass + ".highlight").attr('class', defaultClass);
};
start = function() {
clearHighlights();
pieceIndex = 0;
if (pieces[0] !== firstPiece) {
pieces.reverse();
}
if (currentTimer) {
clearInterval(currentTimer);
}
return currentTimer = setInterval(work, delay);
};
stop = function() {
clearInterval(currentTimer);
return clearHighlights();
};
work = function() {
clearHighlights();
$(pieces[pieceIndex]).attr('class', defaultClass + " highlight");
if (pieceIndex === pieces.length - 1) {
pieceIndex = 0;
return pieces.reverse();
} else {
return pieceIndex++;
}
};
$(document).on('page:fetch', start);
$(document).on('page:fetch', function() {
$('.tanuki-logo').addClass('animate');
});
$(document).on('page:change', stop);
$(document).on('page:change', function() {
$('.tanuki-logo').removeClass('animate');
});
}).call(this);
......@@ -75,10 +75,8 @@ class MergeConflictResolver {
window.location.href = data.redirect_to;
})
.error(() => {
new Flash('Something went wrong!');
})
.always(() => {
this.vue.isSubmitting = false;
new Flash('Something went wrong!');
});
}
......
......@@ -4,6 +4,8 @@
this.ProjectNew = (function() {
function ProjectNew() {
this.toggleSettings = bind(this.toggleSettings, this);
this.$selects = $('.features select');
$('.project-edit-container').on('ajax:before', (function(_this) {
return function() {
$('.project-edit-container').hide();
......@@ -15,18 +17,24 @@
}
ProjectNew.prototype.toggleSettings = function() {
this._showOrHide('#project_builds_enabled', '.builds-feature');
return this._showOrHide('#project_merge_requests_enabled', '.merge-requests-feature');
var self = this;
this.$selects.each(function () {
var $select = $(this),
className = $select.data('field').replace(/_/g, '-')
.replace('access-level', 'feature');
self._showOrHide($select, '.' + className);
});
};
ProjectNew.prototype.toggleSettingsOnclick = function() {
return $('#project_builds_enabled, #project_merge_requests_enabled').on('click', this.toggleSettings);
this.$selects.on('change', this.toggleSettings);
};
ProjectNew.prototype._showOrHide = function(checkElement, container) {
var $container;
$container = $(container);
if ($(checkElement).prop('checked')) {
var $container = $(container);
if ($(checkElement).val() !== '0') {
return $container.show();
} else {
return $container.hide();
......
......@@ -13,6 +13,7 @@
this.perPage = this.el.data('perPage');
this.clearListeners();
this.initBtnListeners();
this.initFilters();
}
Todos.prototype.clearListeners = function() {
......@@ -27,6 +28,31 @@
return $('.todo').on('click', this.goToTodoUrl);
};
Todos.prototype.initFilters = function() {
new UsersSelect();
this.initFilterDropdown($('.js-project-search'), 'project_id', ['text']);
this.initFilterDropdown($('.js-type-search'), 'type');
this.initFilterDropdown($('.js-action-search'), 'action_id');
$('form.filter-form').on('submit', function (event) {
event.preventDefault();
Turbolinks.visit(this.action + '&' + $(this).serialize());
});
};
Todos.prototype.initFilterDropdown = function($dropdown, fieldName, searchFields) {
$dropdown.glDropdown({
selectable: true,
filterable: searchFields ? true : false,
fieldName: fieldName,
search: { fields: searchFields },
data: $dropdown.data('data'),
clicked: function() {
return $dropdown.closest('form.filter-form').submit();
}
})
};
Todos.prototype.doneClicked = function(e) {
var $this;
e.preventDefault();
......@@ -66,7 +92,7 @@
success: (function(_this) {
return function(data) {
$this.remove();
$('.js-todos-list').remove();
$('.prepend-top-default').html('<div class="nothing-here-block">You\'re all done!</div>');
return _this.updateBadges(data);
};
})(this)
......
(function() {
this.User = (function() {
function User(opts) {
(global => {
global.User = class {
constructor(opts) {
this.opts = opts;
$('.profile-groups-avatars').tooltip({
"placement": "top"
});
this.placeProfileAvatarsToTop();
this.initTabs();
$('.hide-project-limit-message').on('click', function(e) {
$.cookie('hide_project_limit_message', 'false', {
path: gon.relative_url_root || '/'
});
$(this).parents('.project-limit-message').remove();
return e.preventDefault();
this.hideProjectLimitMessage();
}
placeProfileAvatarsToTop() {
$('.profile-groups-avatars').tooltip({
placement: 'top'
});
}
User.prototype.initTabs = function() {
initTabs() {
return new UserTabs({
parentEl: '.user-profile',
action: this.opts.action
});
};
return User;
})();
}
}).call(this);
hideProjectLimitMessage() {
$('.hide-project-limit-message').on('click', e => {
e.preventDefault();
const path = gon.relative_url_root || '/';
$.cookie('hide_project_limit_message', 'false', {
path: path
});
$(this).parents('.project-limit-message').remove();
});
}
}
})(window.gl || (window.gl = {}));
......@@ -24,6 +24,7 @@
@import "framework/issue_box.scss";
@import "framework/jquery.scss";
@import "framework/lists.scss";
@import "framework/logo.scss";
@import "framework/markdown_area.scss";
@import "framework/mobile.scss";
@import "framework/modal.scss";
......
......@@ -200,13 +200,15 @@
svg {
height: 15px;
width: auto;
width: 15px;
position: relative;
top: 2px;
}
svg, .fa {
margin-right: 3px;
&:not(:last-child) {
margin-right: 3px;
}
}
}
......
......@@ -53,7 +53,7 @@ pre {
&.well-pre {
border: 1px solid #eee;
background: #f9f9f9;
background: $gray-light;
border-radius: 0;
color: #555;
}
......@@ -225,7 +225,7 @@ li.note {
.milestone {
&.milestone-closed {
background: #f9f9f9;
background: $gray-light;
}
.progress {
margin-bottom: 0;
......
......@@ -183,6 +183,13 @@
&.dropdown-menu-user-link {
line-height: 16px;
}
.icon-play {
fill: $table-text-gray;
margin-right: 6px;
height: 12px;
width: 11px;
}
}
.dropdown-header {
......@@ -195,6 +202,12 @@
.separator + .dropdown-header {
padding-top: 2px;
}
.unclickable {
cursor: not-allowed;
padding: 5px 8px;
color: $dropdown-header-color;
}
}
.dropdown-menu-large {
......
......@@ -115,7 +115,7 @@
padding: 0;
}
td.blame-commit {
background: #f9f9f9;
background: $gray-light;
min-width: 350px;
.commit-author-link {
......
......@@ -19,7 +19,6 @@ input[type='text'].danger {
}
.form-actions {
margin: -$gl-padding;
margin-top: 0;
margin-bottom: -$gl-padding;
padding: $gl-padding;
......
......@@ -2,16 +2,6 @@
* Application Header
*
*/
@mixin tanuki-logo-colors($path-color) {
fill: $path-color;
transition: all 0.8s;
&:hover,
&.highlight {
fill: lighten($path-color, 25%);
transition: all 0.1s;
}
}
header {
transition: padding $sidebar-transition-duration;
......@@ -25,7 +15,7 @@ header {
margin: 8px 0;
text-align: center;
#tanuki-logo, img {
.tanuki-logo, img {
height: 36px;
}
}
......@@ -94,7 +84,7 @@ header {
.side-nav-toggle {
position: absolute;
left: -10px;
margin: 6px 0;
margin: 7px 0;
font-size: 18px;
padding: 6px 10px;
border: none;
......@@ -146,6 +136,8 @@ header {
}
.title {
position: relative;
padding-right: 20px;
margin: 0;
font-size: 19px;
max-width: 400px;
......@@ -158,7 +150,11 @@ header {
vertical-align: top;
white-space: nowrap;
@media (max-width: $screen-sm-max) {
@media (min-width: $screen-sm-min) and (max-width: $screen-sm-max) {
max-width: 300px;
}
@media (max-width: $screen-xs-max) {
max-width: 190px;
}
......@@ -170,11 +166,15 @@ header {
}
.dropdown-toggle-caret {
position: relative;
top: -2px;
color: $gl-text-color;
border: transparent;
background: transparent;
position: absolute;
right: 3px;
width: 12px;
line-height: 12px;
margin-left: 5px;
line-height: 19px;
margin-top: (($header-height - 19) / 2);
padding: 0;
font-size: 10px;
text-align: center;
cursor: pointer;
......@@ -205,26 +205,6 @@ header {
}
}
#tanuki-logo {
#tanuki-left-ear,
#tanuki-right-ear,
#tanuki-nose {
@include tanuki-logo-colors($tanuki-red);
}
#tanuki-left-eye,
#tanuki-right-eye {
@include tanuki-logo-colors($tanuki-orange);
}
#tanuki-left-cheek,
#tanuki-right-cheek {
@include tanuki-logo-colors($tanuki-yellow);
}
}
@media (max-width: $screen-xs-max) {
header .container-fluid {
font-size: 18px;
......
@mixin unique-keyframes {
$animation-name: unique-id();
@include webkit-prefix(animation-name, $animation-name);
@-webkit-keyframes #{$animation-name} {
@content;
}
@keyframes #{$animation-name} {
@content;
}
}
@mixin tanuki-logo-colors($path-color) {
fill: $path-color;
transition: all 0.8s;
&:hover {
fill: lighten($path-color, 25%);
transition: all 0.1s;
}
}
@mixin tanuki-second-highlight-animations($tanuki-color) {
@include unique-keyframes {
10%, 80% {
fill: #{$tanuki-color}
}
20%, 90% {
fill: lighten($tanuki-color, 25%);
}
}
}
@mixin tanuki-forth-highlight-animations($tanuki-color) {
@include unique-keyframes {
30%, 60% {
fill: #{$tanuki-color};
}
40%, 70% {
fill: lighten($tanuki-color, 25%);
}
}
}
.tanuki-logo {
.tanuki-left-ear,
.tanuki-right-ear,
.tanuki-nose {
@include tanuki-logo-colors($tanuki-red);
}
.tanuki-left-eye,
.tanuki-right-eye {
@include tanuki-logo-colors($tanuki-orange);
}
.tanuki-left-cheek,
.tanuki-right-cheek {
@include tanuki-logo-colors($tanuki-yellow);
}
&.animate {
.tanuki-shape {
@include webkit-prefix(animation-duration, 1.5s);
@include webkit-prefix(animation-iteration-count, infinite);
}
.tanuki-left-cheek {
@include unique-keyframes {
0%, 10%, 100% {
fill: lighten($tanuki-yellow, 25%);
}
90% {
fill: $tanuki-yellow;
}
}
}
.tanuki-left-eye {
@include tanuki-second-highlight-animations($tanuki-orange);
}
.tanuki-left-ear {
@include tanuki-second-highlight-animations($tanuki-red);
}
.tanuki-nose {
@include unique-keyframes {
20%, 70% {
fill: $tanuki-red;
}
30%, 80% {
fill: lighten($tanuki-red, 25%);
}
}
}
.tanuki-right-eye {
@include tanuki-forth-highlight-animations($tanuki-orange);
}
.tanuki-right-ear {
@include tanuki-forth-highlight-animations($tanuki-red);
}
.tanuki-right-cheek {
@include unique-keyframes {
40% {
fill: $tanuki-yellow;
}
60% {
fill: lighten($tanuki-yellow, 25%);
}
}
}
}
}
\ No newline at end of file
......@@ -9,43 +9,11 @@
border-radius: $radius;
}
@mixin border-radius-left($radius) {
@include border-radius($radius 0 0 $radius)
}
@mixin border-radius-right($radius) {
@include border-radius(0 0 $radius $radius)
}
@mixin linear-gradient($from, $to) {
background-image: -webkit-gradient(linear, 0 0, 0 100%, from($from), to($to));
background-image: -webkit-linear-gradient($from, $to);
background-image: -moz-linear-gradient($from, $to);
background-image: -ms-linear-gradient($from, $to);
background-image: -o-linear-gradient($from, $to);
}
@mixin transition($transition) {
-webkit-transition: $transition;
-moz-transition: $transition;
-ms-transition: $transition;
-o-transition: $transition;
transition: $transition;
}
/**
* Prefilled mixins
* Mixins with fixed values
*/
@mixin shade {
@include box-shadow(0 0 3px #ddd);
}
@mixin solid-shade {
@include box-shadow(0 0 0 3px #f1f1f1);
}
@mixin str-truncated($max_width: 82%) {
display: inline-block;
overflow: hidden;
......@@ -76,7 +44,7 @@
}
&.active {
background: #f9f9f9;
background: $gray-light;
a {
font-weight: 600;
}
......@@ -94,23 +62,6 @@
}
}
@mixin input-big {
height: 36px;
padding: 5px 10px;
font-size: 16px;
line-height: 24px;
color: #7f8fa4;
background-color: #fff;
border-color: #e7e9ed;
}
@mixin btn-big {
height: 36px;
padding: 5px 10px;
font-size: 16px;
line-height: 24px;
}
@mixin bulleted-list {
> ul {
list-style-type: disc;
......@@ -129,3 +80,8 @@
color: rgba(255, 255, 255, 0.3);
background: rgba(255, 255, 255, 0.1);
}
@mixin webkit-prefix($property, $value) {
#{'-webkit-' + $property}: $value;
#{$property}: $value;
}
@mixin fade($gradient-direction, $rgba, $gradient-color) {
@mixin fade($gradient-direction, $gradient-color) {
visibility: hidden;
opacity: 0;
z-index: 2;
......@@ -8,10 +8,7 @@
height: 30px;
transition-duration: .3s;
-webkit-transform: translateZ(0);
background: -webkit-linear-gradient($gradient-direction, $rgba, $gradient-color 45%);
background: -o-linear-gradient($gradient-direction, $rgba, $gradient-color 45%);
background: -moz-linear-gradient($gradient-direction, $rgba, $gradient-color 45%);
background: linear-gradient($gradient-direction, $rgba, $gradient-color 45%);
background: linear-gradient(to $gradient-direction, $gradient-color 45%, rgba($gradient-color, 0.4));
&.scrolling {
visibility: visible;
......@@ -71,7 +68,7 @@
.badge {
font-weight: normal;
background-color: #eee;
color: #78a;
color: $btn-transparent-color;
vertical-align: baseline;
}
}
......@@ -161,6 +158,7 @@
> .dropdown {
margin-right: $gl-padding-top;
display: inline-block;
vertical-align: top;
&:last-child {
margin-right: 0;
......@@ -210,12 +208,6 @@
}
}
.project-filter-form {
input {
background-color: $background-color;
}
}
@media (max-width: $screen-xs-max) {
padding-bottom: 0;
width: 100%;
......@@ -335,10 +327,6 @@
}
}
.badge {
color: $gl-icon-color;
}
&:hover {
a, i {
color: $black;
......@@ -356,7 +344,7 @@
}
.fade-right {
@include fade(left, rgba(255, 255, 255, 0.4), $background-color);
@include fade(left, $background-color);
right: -5px;
.fa {
......@@ -365,7 +353,7 @@
}
.fade-left {
@include fade(right, rgba(255, 255, 255, 0.4), $background-color);
@include fade(right, $background-color);
left: -5px;
.fa {
......@@ -376,6 +364,7 @@
&.sub-nav-scroll {
.fade-right {
@include fade(left, $dark-background-color);
right: 0;
.fa {
......@@ -384,6 +373,7 @@
}
.fade-left {
@include fade(right, $dark-background-color);
left: 0;
.fa {
......@@ -400,7 +390,7 @@
@include scrolling-links();
.fade-right {
@include fade(left, rgba(255, 255, 255, 0.4), $white-light);
@include fade(left, $white-light);
right: -5px;
.fa {
......@@ -409,7 +399,7 @@
}
.fade-left {
@include fade(right, rgba(255, 255, 255, 0.4), $white-light);
@include fade(right, $white-light);
left: -5px;
.fa {
......
......@@ -151,7 +151,7 @@
background-position: right 0 bottom 6px;
border: 1px solid $input-border;
@include border-radius($border-radius-default);
@include transition(border-color ease-in-out .15s, box-shadow ease-in-out .15s);
transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
&:focus {
border-color: $input-border-focus;
......
......@@ -125,7 +125,7 @@ $panel-inner-border: $border-color;
//
//##
$well-bg: #f9f9f9;
$well-bg: $gray-light;
$well-border: #eee;
//== Code
......
......@@ -159,25 +159,18 @@
position: relative;
a.anchor {
// Setting `display: none` would prevent the anchor being scrolled to, so
// instead we set the height to 0 and it gets updated on hover.
height: 0;
left: -16px;
position: absolute;
text-decoration: none;
&:after {
content: url('icon_anchor.svg');
visibility: hidden;
}
}
&:hover > a.anchor {
$size: 14px;
position: absolute;
right: 100%;
top: 50%;
margin-top: -11px;
margin-right: 0;
padding-right: 15px;
display: inline-block;
width: $size;
height: $size;
background-image: image-url("icon-link.png");
background-size: contain;
background-repeat: no-repeat;
&:hover > a.anchor:after {
visibility: visible;
}
}
}
......
......@@ -9,13 +9,79 @@ $gutter_inner_width: 258px;
$sidebar-transition-duration: .15s;
$sidebar-breakpoint: 1024px;
/*
* Color schema
*/
$white-light: #fff;
$white-normal: #ededed;
$white-dark: #ececec;
$gray-light: #fafafa;
$gray-normal: #f5f5f5;
$gray-dark: #ededed;
$gray-darkest: #c9c9c9;
$green-light: #38ae67;
$green-normal: #2faa60;
$green-dark: #2ca05b;
$blue-light: #2ea8e5;
$blue-normal: #2d9fd8;
$blue-dark: #2897ce;
$blue-medium-light: #3498cb;
$blue-medium: #2f8ebf;
$blue-medium-dark: #2d86b4;
$orange-light: #fc8a51;
$orange-normal: #e75e40;
$orange-dark: #ce5237;
$red-light: #e52c5a;
$red-normal: #d22852;
$red-dark: darken($red-normal, 5%);
$black: #000;
$black-transparent: rgba(0, 0, 0, 0.3);
$border-white-light: #f1f2f4;
$border-white-normal: #d6dae2;
$border-white-dark: #c6cacf;
$border-gray-light: #dcdcdc;
$border-gray-normal: #d7d7d7;
$border-gray-dark: #c6cacf;
$border-green-light: #2faa60;
$border-green-normal: #2ca05b;
$border-green-dark: #279654;
$border-blue-light: #2d9fd8;
$border-blue-normal: #2897ce;
$border-blue-dark: #258dc1;
$border-orange-light: #fc6d26;
$border-orange-normal: #ce5237;
$border-orange-dark: #c14e35;
$border-red-light: #d22852;
$border-red-normal: #ca264f;
$border-red-dark: darken($border-red-normal, 5%);
$help-well-bg: $gray-light;
$help-well-border: #e5e5e5;
$warning-message-bg: #fbf2d9;
$warning-message-color: #9e8e60;
$warning-message-border: #f0e2bb;
/*
* UI elements
*/
$border-color: #e5e5e5;
$focus-border-color: #3aabf0;
$table-border-color: #f0f0f0;
$background-color: #fafafa;
$background-color: $gray-light;
$dark-background-color: #f5f5f5;
$table-text-gray: #8f8f8f;
......@@ -90,73 +156,6 @@ $btn-side-margin: 10px;
$btn-sm-side-margin: 7px;
$btn-xs-side-margin: 5px;
/*
* Color schema
*/
$white-light: #fff;
$white-normal: #ededed;
$white-dark: #ececec;
$gray-light: #faf9f9;
$gray-normal: #f5f5f5;
$gray-dark: #ededed;
$gray-darkest: #c9c9c9;
$green-light: #38ae67;
$green-normal: #2faa60;
$green-dark: #2ca05b;
$blue-light: #2ea8e5;
$blue-normal: #2d9fd8;
$blue-dark: #2897ce;
$blue-medium-light: #3498cb;
$blue-medium: #2f8ebf;
$blue-medium-dark: #2d86b4;
$orange-light: #fc8a51;
$orange-normal: #e75e40;
$orange-dark: #ce5237;
$red-light: #e52c5a;
$red-normal: #d22852;
$red-dark: darken($red-normal, 5%);
$black: #000;
$black-transparent: rgba(0, 0, 0, 0.3);
$border-white-light: #f1f2f4;
$border-white-normal: #d6dae2;
$border-white-dark: #c6cacf;
$border-gray-light: #dcdcdc;
$border-gray-normal: #d7d7d7;
$border-gray-dark: #c6cacf;
$border-green-light: #2faa60;
$border-green-normal: #2ca05b;
$border-green-dark: #279654;
$border-blue-light: #2d9fd8;
$border-blue-normal: #2897ce;
$border-blue-dark: #258dc1;
$border-orange-light: #fc6d26;
$border-orange-normal: #ce5237;
$border-orange-dark: #c14e35;
$border-red-light: #d22852;
$border-red-normal: #ca264f;
$border-red-dark: darken($border-red-normal, 5%);
$help-well-bg: #fafafa;
$help-well-border: #e5e5e5;
$warning-message-bg: #fbf2d9;
$warning-message-color: #9e8e60;
$warning-message-border: #f0e2bb;
/* tanuki logo colors */
$tanuki-red: #e24329;
$tanuki-orange: #fc6d26;
......@@ -186,7 +185,7 @@ $line-removed-dark: #fac5cd;
$line-number-old: #f9d7dc;
$line-number-new: #ddfbe6;
$line-number-select: #fbf2da;
$match-line: #fafafa;
$match-line: $gray-light;
$table-border-gray: #f0f0f0;
$line-target-blue: #eaf3fc;
$line-select-yellow: #fcf8e7;
......@@ -267,7 +266,7 @@ $zen-control-hover-color: #111;
$calendar-header-color: #b8b8b8;
$calendar-hover-bg: #ecf3fe;
$calendar-border-color: rgba(#000, .1);
$calendar-unselectable-bg: #faf9f9;
$calendar-unselectable-bg: $gray-light;
/*
* Personal Access Tokens
......
......@@ -96,6 +96,10 @@
line-height: inherit;
}
}
.label-default {
color: $btn-transparent-color;
}
}
.abuse-reports {
......
......@@ -10,7 +10,7 @@
.is-dragging {
// Important because plugin sets inline CSS
opacity: 1!important;
* {
// !important to make sure no style can override this when dragging
cursor: -webkit-grabbing!important;
......@@ -142,11 +142,6 @@
}
}
.board-header-loading-spinner {
margin-right: 10px;
color: $gray-darkest;
}
.board-inner-container {
border-bottom: 1px solid $border-color;
padding: $gl-padding;
......@@ -160,40 +155,6 @@
border-bottom: 1px solid $border-color;
}
.board-search-container {
position: relative;
background-color: #fff;
.form-control {
padding-right: 30px;
}
}
.board-search-icon,
.board-search-clear-btn {
position: absolute;
right: $gl-padding + 10px;
top: 50%;
margin-top: -7px;
font-size: 14px;
}
.board-search-icon {
color: $gl-placeholder-color;
}
.board-search-clear-btn {
padding: 0;
line-height: 1;
background: transparent;
border: 0;
outline: 0;
&:hover {
color: $gl-link-color;
}
}
.board-delete {
margin-right: 10px;
padding: 0;
......@@ -304,3 +265,22 @@
margin-right: 8px;
font-weight: 500;
}
.issue-boards-search {
width: 335px;
.form-control {
display: inline-block;
width: 210px;
}
}
.board-list-count {
padding: 10px 0;
color: $gl-placeholder-color;
font-size: 13px;
> .fa {
margin-right: 5px;
}
}
......@@ -36,6 +36,7 @@
&.affix {
right: 30px;
bottom: 15px;
z-index: 1;
@media (min-width: $screen-md-min) {
right: 26%;
......@@ -107,7 +108,7 @@
}
.blocks-container {
padding: $gl-padding;
padding: 0 $gl-padding;
}
.block {
......@@ -122,6 +123,13 @@
}
}
.retry-link {
color: $gl-link-color;
&:hover {
text-decoration: underline;
}
}
.stage-item {
cursor: pointer;
......@@ -131,7 +139,7 @@
}
.build-dropdown {
padding: 0 $gl-padding;
padding: $gl-padding 0;
.dropdown-menu-toggle {
margin-top: 8px;
......@@ -145,7 +153,6 @@
}
.builds-container {
margin-top: $gl-padding;
background-color: $white-light;
border-top: 1px solid $border-color;
border-bottom: 1px solid $border-color;
......
......@@ -113,11 +113,13 @@
.commit-row-description {
font-size: 14px;
border-left: 1px solid #eee;
border-left: 1px solid $btn-gray-hover;
padding: 10px 15px;
margin: 10px 0;
background: #f9f9f9;
background: $gray-light;
display: none;
white-space: pre-line;
word-break: normal;
pre {
border: none;
......
......@@ -4,8 +4,9 @@
margin: 0;
}
.fa-play {
font-size: 14px;
.icon-play {
height: 13px;
width: 12px;
}
.dropdown-new {
......
......@@ -60,7 +60,7 @@
pre {
border: none;
background: #f9f9f9;
background: $gray-light;
border-radius: 0;
color: #777;
margin: 0 20px;
......@@ -92,7 +92,7 @@
border: 1px solid #eee;
padding: 5px;
@include border-radius(5px);
background: #f9f9f9;
background: $gray-light;
margin-left: 10px;
top: -6px;
img {
......@@ -115,11 +115,8 @@
}
&.commits-stat {
margin-top: 3px;
display: block;
padding: 3px;
padding-left: 0;
padding: 0 3px 0 0;
&:hover {
background: none;
}
......
......@@ -12,6 +12,10 @@
padding-right: 8px;
margin-bottom: 10px;
min-width: 15px;
.selected_issue {
vertical-align: text-top;
}
}
.issue-labels {
......@@ -68,12 +72,12 @@ form.edit-issue {
}
&.closed {
background: #f9f9f9;
background: $gray-light;
border-color: #e5e5e5;
}
&.merged {
background: #f9f9f9;
background: $gray-light;
border-color: #e5e5e5;
}
}
......
......@@ -7,6 +7,7 @@
display: inline-block;
margin-right: 10px;
margin-bottom: 10px;
text-decoration: none;
}
&.suggest-colors-dropdown {
......
......@@ -16,7 +16,7 @@ $colors: (
white_button_origin_chosen : #268ced,
white_header_not_chosen : #f0f0f0,
white_line_not_chosen : #f9f9f9,
white_line_not_chosen : $gray-light,
dark_header_head_neutral : rgba(#3f3, .2),
......
......@@ -2,6 +2,7 @@
.stage {
max-width: 90px;
width: 90px;
text-align: center;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
......@@ -146,6 +147,7 @@
}
.stage-cell {
text-align: center;
svg {
height: 18px;
......@@ -153,10 +155,6 @@
vertical-align: middle;
overflow: visible;
}
.light {
width: 3px;
}
}
.duration,
......@@ -215,6 +213,13 @@
border-color: $border-white-normal;
}
}
.btn {
.icon-play {
height: 13px;
width: 12px;
}
}
}
}
......@@ -273,7 +278,7 @@
.stage-column {
display: inline-block;
vertical-align: top;
margin-right: 50px;
margin-right: 65px;
li {
list-style: none;
......@@ -319,6 +324,14 @@
a {
color: $layout-link-gray;
text-decoration: none;
&:hover {
.ci-status-text {
text-decoration: underline;
}
}
}
}
......@@ -334,9 +347,9 @@
content: '';
position: absolute;
top: 50%;
right: -54px;
right: -69px;
border-top: 2px solid $border-color;
width: 54px;
width: 69px;
height: 1px;
}
}
......@@ -356,22 +369,25 @@
&::after {
right: -20px;
border-right: 2px solid $border-color;
border-radius: 0 0 50px;
border-radius: 0 0 15px;
}
// Left connecting curves
&::before {
left: -20px;
border-left: 2px solid $border-color;
border-radius: 0 0 0 50px;
border-radius: 0 0 0 15px;
}
}
// Connect second build to first build with smaller curved line
&:nth-child(2) {
&::after, &::before {
height: 45px;
top: -26px;
height: 29px;
top: -10px;
}
.curve {
display: block;
}
}
}
......@@ -390,6 +406,12 @@
border: none;
}
}
// Remove opposite curve
.curve {
&::before {
display: none;
}
}
}
}
......@@ -401,6 +423,39 @@
border: none;
}
}
// Remove opposite curve
.curve {
&::after {
display: none;
}
}
}
}
// Curve first child connecting lines in opposite direction
.curve {
display: none;
&::before,
&::after {
content: '';
width: 21px;
height: 25px;
position: absolute;
top: -28.5px;
border-top: 2px solid $border-color;
}
&::after {
left: -39px;
border-right: 2px solid $border-color;
border-radius: 0 15px;
}
&::before {
right: -39px;
border-left: 2px solid $border-color;
border-radius: 15px 0 0;
}
}
}
......@@ -419,11 +474,22 @@
.pipelines.tab-pane {
.content-list.pipelines {
overflow: scroll;
overflow: auto;
}
.stage {
max-width: 60px;
width: 60px;
max-width: 100px;
width: 100px;
}
.pipeline-actions {
min-width: initial;
}
}
.ci-status-icon-created {
svg {
fill: $table-text-gray;
}
}
......@@ -311,6 +311,14 @@ a.deploy-project-label {
color: $gl-success;
}
.lfs-enabled {
color: $gl-success;
}
.lfs-disabled {
color: $gl-warning;
}
.breadcrumb.repo-breadcrumb {
padding: 0;
background: transparent;
......@@ -600,18 +608,25 @@ pre.light-well {
}
}
.project-show-readme .readme-holder {
padding: $gl-padding 0;
border-top: 0;
.edit-project-readme {
z-index: 2;
position: relative;
.project-show-readme {
.row-content-block {
background-color: inherit;
border: none;
}
.wiki h1 {
border-bottom: none;
padding: 0;
.readme-holder {
padding: $gl-padding 0;
border-top: 0;
.edit-project-readme {
z-index: 2;
position: relative;
}
.wiki h1 {
border-bottom: none;
padding: 0;
}
}
}
......
......@@ -80,7 +80,7 @@
.search-icon {
@extend .fa-search;
@include transition(color .15s);
transition: color 0.15s;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
......@@ -125,7 +125,7 @@
}
.location-badge {
@include transition(all .15s);
transition: all 0.15s;
background-color: $location-badge-active-bg;
color: $white-light;
}
......
......@@ -43,6 +43,15 @@
border-color: $blue-normal;
}
&.ci-created {
color: $table-text-gray;
border-color: $table-text-gray;
svg {
fill: $table-text-gray;
}
}
svg {
height: 13px;
width: 13px;
......
......@@ -99,7 +99,7 @@
pre {
border: none;
background: #f9f9f9;
background: $gray-light;
border-radius: 0;
color: #777;
margin: 0 20px;
......
......@@ -11,6 +11,20 @@
}
}
.add-to-tree {
vertical-align: top;
}
.last-commit {
max-width: 506px;
.last-commit-content {
@include str-truncated;
width: calc(100% - 140px);
margin-left: 3px;
}
}
.tree-table {
margin-bottom: 0;
......
......@@ -20,6 +20,9 @@
$l-cyan: #8abeb7;
$l-white: $ci-text-color;
.term-bold {
font-weight: bold;
}
.term-italic {
font-style: italic;
}
......
......@@ -24,7 +24,7 @@ class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
helper_method :abilities, :can?, :current_application_settings
helper_method :can?, :current_application_settings
helper_method :import_sources_enabled?, :github_import_enabled?, :github_import_configured?, :gitlab_import_enabled?, :gitlab_import_configured?, :bitbucket_import_enabled?, :bitbucket_import_configured?, :google_code_import_enabled?, :fogbugz_import_enabled?, :git_import_enabled?, :gitlab_project_import_enabled?
rescue_from Encoding::CompatibilityError do |exception|
......@@ -97,12 +97,8 @@ class ApplicationController < ActionController::Base
current_application_settings.after_sign_out_path.presence || new_user_session_path
end
def abilities
Ability.abilities
end
def can?(object, action, subject)
abilities.allowed?(object, action, subject)
Ability.allowed?(object, action, subject)
end
def access_denied!
......
......@@ -13,7 +13,7 @@ module ServiceParams
# `issue_events` and `merge_request_events` (singular!)
# See app/helpers/services_helper.rb for how we
# make those event names plural as special case.
:issues_events, :merge_requests_events,
:issues_events, :confidential_issues_events, :merge_requests_events,
:notify_only_broken_builds, :notify_only_broken_pipelines,
:add_pusher, :send_from_committer_email, :disable_diffs,
:external_wiki_url, :notify, :color,
......
......@@ -8,10 +8,14 @@ module ToggleAwardEmoji
def toggle_award_emoji
name = params.require(:name)
awardable.toggle_award_emoji(name, current_user)
TodoService.new.new_award_emoji(to_todoable(awardable), current_user)
if awardable.user_can_award?(current_user, name)
awardable.toggle_award_emoji(name, current_user)
TodoService.new.new_award_emoji(to_todoable(awardable), current_user)
render json: { ok: true }
render json: { ok: true }
else
render json: { ok: false }
end
end
private
......
class Import::BaseController < ApplicationController
private
def get_or_create_namespace
def find_or_create_namespace(name, owner)
return current_user.namespace if name == owner
return current_user.namespace unless current_user.can_create_group?
begin
namespace = Group.create!(name: @target_namespace, path: @target_namespace, owner: current_user)
name = params[:target_namespace].presence || name
namespace = Group.create!(name: name, path: name, owner: current_user)
namespace.add_owner(current_user)
namespace
rescue ActiveRecord::RecordNotUnique, ActiveRecord::RecordInvalid
namespace = Namespace.find_by_path_or_name(@target_namespace)
unless current_user.can?(:create_projects, namespace)
@already_been_taken = true
return false
end
Namespace.find_by_path_or_name(name)
end
namespace
end
end
......@@ -35,23 +35,20 @@ class Import::BitbucketController < Import::BaseController
end
def create
@repo_id = params[:repo_id] || ""
repo = client.project(@repo_id.gsub("___", "/"))
@project_name = repo["slug"]
repo_owner = repo["owner"]
repo_owner = current_user.username if repo_owner == client.user["user"]["username"]
@target_namespace = params[:new_namespace].presence || repo_owner
namespace = get_or_create_namespace || (render and return)
@repo_id = params[:repo_id].to_s
repo = client.project(@repo_id.gsub('___', '/'))
@project_name = repo['slug']
@target_namespace = find_or_create_namespace(repo['owner'], client.user['user']['username'])
unless Gitlab::BitbucketImport::KeyAdder.new(repo, current_user, access_params).execute
@access_denied = true
render
return
render 'deploy_key' and return
end
@project = Gitlab::BitbucketImport::ProjectCreator.new(repo, namespace, current_user, access_params).execute
if current_user.can?(:create_projects, @target_namespace)
@project = Gitlab::BitbucketImport::ProjectCreator.new(repo, @target_namespace, current_user, access_params).execute
else
render 'unauthorized'
end
end
private
......
......@@ -41,14 +41,13 @@ class Import::GithubController < Import::BaseController
@repo_id = params[:repo_id].to_i
repo = client.repo(@repo_id)
@project_name = repo.name
@target_namespace = find_or_create_namespace(repo.owner.login, client.user.login)
repo_owner = repo.owner.login
repo_owner = current_user.username if repo_owner == client.user.login
@target_namespace = params[:new_namespace].presence || repo_owner
namespace = get_or_create_namespace || (render and return)
@project = Gitlab::GithubImport::ProjectCreator.new(repo, namespace, current_user, access_params).execute
if current_user.can?(:create_projects, @target_namespace)
@project = Gitlab::GithubImport::ProjectCreator.new(repo, @target_namespace, current_user, access_params).execute
else
render 'unauthorized'
end
end
private
......
......@@ -26,15 +26,14 @@ class Import::GitlabController < Import::BaseController
def create
@repo_id = params[:repo_id].to_i
repo = client.project(@repo_id)
@project_name = repo["name"]
@project_name = repo['name']
@target_namespace = find_or_create_namespace(repo['namespace']['path'], client.user['username'])
repo_owner = repo["namespace"]["path"]
repo_owner = current_user.username if repo_owner == client.user["username"]
@target_namespace = params[:new_namespace].presence || repo_owner
namespace = get_or_create_namespace || (render and return)
@project = Gitlab::GitlabImport::ProjectCreator.new(repo, namespace, current_user, access_params).execute
if current_user.can?(:create_projects, @target_namespace)
@project = Gitlab::GitlabImport::ProjectCreator.new(repo, @target_namespace, current_user, access_params).execute
else
render 'unauthorized'
end
end
private
......
......@@ -37,7 +37,7 @@ class JwtController < ApplicationController
def authenticate_project(login, password)
if login == 'gitlab-ci-token'
Project.find_by(builds_enabled: true, runners_token: password)
Project.with_builds_enabled.find_by(runners_token: password)
end
end
......
......@@ -14,7 +14,7 @@ class NamespacesController < ApplicationController
if user
redirect_to user_path(user)
elsif group && can?(current_user, :read_group, namespace)
elsif group && can?(current_user, :read_group, group)
redirect_to group_path(group)
elsif current_user.nil?
authenticate_user!
......
......@@ -88,6 +88,6 @@ class Projects::ApplicationController < ApplicationController
end
def builds_enabled
return render_404 unless @project.builds_enabled?
return render_404 unless @project.feature_available?(:builds, current_user)
end
end
class Projects::ArtifactsController < Projects::ApplicationController
include ExtractsPath
layout 'project'
before_action :authorize_read_build!
before_action :authorize_update_build!, only: [:keep]
before_action :extract_ref_name_and_path
before_action :validate_artifacts!
def download
unless artifacts_file.file_storage?
return redirect_to artifacts_file.url
if artifacts_file.file_storage?
send_file artifacts_file.path, disposition: 'attachment'
else
redirect_to artifacts_file.url
end
send_file artifacts_file.path, disposition: 'attachment'
end
def browse
directory = params[:path] ? "#{params[:path]}/" : ''
@entry = build.artifacts_metadata_entry(directory)
return render_404 unless @entry.exists?
render_404 unless @entry.exists?
end
def file
......@@ -34,14 +37,41 @@ class Projects::ArtifactsController < Projects::ApplicationController
redirect_to namespace_project_build_path(project.namespace, project, build)
end
def latest_succeeded
target_path = artifacts_action_path(@path, project, build)
if target_path
redirect_to(target_path)
else
render_404
end
end
private
def extract_ref_name_and_path
return unless params[:ref_name_and_path]
@ref_name, @path = extract_ref(params[:ref_name_and_path])
end
def validate_artifacts!
render_404 unless build.artifacts?
render_404 unless build && build.artifacts?
end
def build
@build ||= project.builds.find_by!(id: params[:build_id])
@build ||= build_from_id || build_from_ref
end
def build_from_id
project.builds.find_by(id: params[:build_id]) if params[:build_id]
end
def build_from_ref
return unless @ref_name
builds = project.latest_successful_builds_for(@ref_name)
builds.find_by(name: params[:job])
end
def artifacts_file
......
......@@ -8,12 +8,15 @@ module Projects
issues = ::Boards::Issues::ListService.new(project, current_user, filter_params).execute
issues = issues.page(params[:page])
render json: issues.as_json(
only: [:iid, :title, :confidential],
include: {
assignee: { only: [:id, :name, :username], methods: [:avatar_url] },
labels: { only: [:id, :title, :description, :color, :priority], methods: [:text_color] }
})
render json: {
issues: issues.as_json(
only: [:iid, :title, :confidential],
include: {
assignee: { only: [:id, :name, :username], methods: [:avatar_url] },
labels: { only: [:id, :title, :description, :color, :priority], methods: [:text_color] }
}),
size: issues.total_count
}
end
def update
......
......@@ -78,8 +78,8 @@ class Projects::BuildsController < Projects::ApplicationController
end
def raw
if @build.has_trace?
send_file @build.path_to_trace, type: 'text/plain; charset=utf-8', disposition: 'inline'
if @build.has_trace_file?
send_file @build.trace_file_path, type: 'text/plain; charset=utf-8', disposition: 'inline'
else
render_404
end
......
......@@ -38,6 +38,6 @@ class Projects::DiscussionsController < Projects::ApplicationController
end
def module_enabled
render_404 unless @project.merge_requests_enabled
render_404 unless @project.feature_available?(:merge_requests, current_user)
end
end
......@@ -59,6 +59,7 @@ class Projects::HooksController < Projects::ApplicationController
:pipeline_events,
:enable_ssl_verification,
:issues_events,
:confidential_issues_events,
:merge_requests_events,
:note_events,
:push_events,
......
......@@ -201,7 +201,7 @@ class Projects::IssuesController < Projects::ApplicationController
end
def module_enabled
return render_404 unless @project.issues_enabled && @project.default_issues_tracker?
return render_404 unless @project.feature_available?(:issues, current_user) && @project.default_issues_tracker?
end
def redirect_to_external_issue_tracker
......
......@@ -99,7 +99,7 @@ class Projects::LabelsController < Projects::ApplicationController
protected
def module_enabled
unless @project.issues_enabled || @project.merge_requests_enabled
unless @project.feature_available?(:issues, current_user) || @project.feature_available?(:merge_requests, current_user)
return render_404
end
end
......
......@@ -413,7 +413,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end
def module_enabled
return render_404 unless @project.merge_requests_enabled
return render_404 unless @project.feature_available?(:merge_requests, current_user)
end
def validates_merge_request
......
......@@ -106,7 +106,7 @@ class Projects::MilestonesController < Projects::ApplicationController
end
def module_enabled
unless @project.issues_enabled || @project.merge_requests_enabled
unless @project.feature_available?(:issues, current_user) || @project.feature_available?(:merge_requests, current_user)
return render_404
end
end
......
......@@ -20,9 +20,8 @@ class Projects::ServicesController < Projects::ApplicationController
def update
if @service.update_attributes(service_params[:service])
redirect_to(
edit_namespace_project_service_path(@project.namespace, @project,
@service.to_param, notice:
'Successfully updated.')
edit_namespace_project_service_path(@project.namespace, @project, @service.to_param),
notice: 'Successfully updated.'
)
else
render 'edit'
......
......@@ -94,7 +94,7 @@ class Projects::SnippetsController < Projects::ApplicationController
end
def module_enabled
return render_404 unless @project.snippets_enabled
return render_404 unless @project.feature_available?(:snippets, current_user)
end
def snippet_params
......
class Projects::TagsController < Projects::ApplicationController
include SortingHelper
# Authorize
before_action :require_non_empty_project
before_action :authorize_download_code!
......@@ -6,8 +8,10 @@ class Projects::TagsController < Projects::ApplicationController
before_action :authorize_admin_project!, only: [:destroy]
def index
@sort = params[:sort] || 'name'
@tags = @repository.tags_sorted_by(@sort)
params[:sort] = params[:sort].presence || 'name'
@sort = params[:sort]
@tags = TagsFinder.new(@repository, params).execute
@tags = Kaminari.paginate_array(@tags).page(params[:page])
@releases = project.releases.where(tag: @tags.map(&:name))
......
......@@ -303,13 +303,23 @@ class ProjectsController < Projects::ApplicationController
end
def project_params
project_feature_attributes =
{
project_feature_attributes:
[
:issues_access_level, :builds_access_level,
:wiki_access_level, :merge_requests_access_level, :snippets_access_level
]
}
params.require(:project).permit(
:name, :path, :description, :issues_tracker, :tag_list, :runners_token,
:issues_enabled, :merge_requests_enabled, :snippets_enabled, :container_registry_enabled,
:container_registry_enabled,
:issues_tracker_id, :default_branch,
:wiki_enabled, :visibility_level, :import_url, :last_activity_at, :namespace_id, :avatar,
:builds_enabled, :build_allow_git_fetch, :build_timeout_in_minutes, :build_coverage_regex,
:public_builds, :only_allow_merge_if_build_succeeds, :request_access_enabled
:visibility_level, :import_url, :last_activity_at, :namespace_id, :avatar,
:build_allow_git_fetch, :build_timeout_in_minutes, :build_coverage_regex,
:public_builds, :only_allow_merge_if_build_succeeds, :request_access_enabled,
:lfs_enabled, project_feature_attributes
)
end
......
......@@ -64,7 +64,7 @@ class IssuableFinder
if project?
@project = Project.find(params[:project_id])
unless Ability.abilities.allowed?(current_user, :read_project, @project)
unless Ability.allowed?(current_user, :read_project, @project)
@project = nil
end
else
......
class TagsFinder
def initialize(repository, params)
@repository = repository
@params = params
end
def execute
tags = @repository.tags_sorted_by(sort)
filter_by_name(tags)
end
private
def sort
@params[:sort].presence
end
def search
@params[:search].presence
end
def filter_by_name(tags)
if search
tags.select { |tag| tag.name.include?(search) }
else
tags
end
end
end
......@@ -83,7 +83,7 @@ class TodosFinder
if project?
@project = Project.find(params[:project_id])
unless Ability.abilities.allowed?(current_user, :read_project, @project)
unless Ability.allowed?(current_user, :read_project, @project)
@project = nil
end
else
......
......@@ -110,7 +110,7 @@ module ApplicationHelper
project = event.project
# Skip if project repo is empty or MR disabled
return false unless project && !project.empty_repo? && project.merge_requests_enabled
return false unless project && !project.empty_repo? && project.feature_available?(:merge_requests, current_user)
# Skip if user already created appropriate MR
return false if project.merge_requests.where(source_branch: event.branch_name).opened.any?
......
......@@ -25,6 +25,11 @@ module CiStatusHelper
end
end
def ci_status_for_statuseable(subject)
status = subject.try(:status) || 'not found'
status.humanize
end
def ci_icon_for_status(status)
icon_name =
case status
......@@ -41,7 +46,7 @@ module CiStatusHelper
when 'play'
'icon_play'
when 'created'
'icon_status_pending'
'icon_status_created'
else
'icon_status_cancel'
end
......@@ -66,10 +71,10 @@ module CiStatusHelper
Ci::Runner.shared.blank?
end
def render_status_with_link(type, status, path = nil, tooltip_placement: 'auto left', cssclass: '')
def render_status_with_link(type, status, path = nil, tooltip_placement: 'auto left', cssclass: '', container: 'body')
klass = "ci-status-link ci-status-icon-#{status.dasherize} #{cssclass}"
title = "#{type.titleize}: #{ci_label_for_status(status)}"
data = { toggle: 'tooltip', placement: tooltip_placement }
data = { toggle: 'tooltip', placement: tooltip_placement, container: container }
if path
link_to ci_icon_for_status(status), path,
......
......@@ -3,7 +3,7 @@ module CompareHelper
from.present? &&
to.present? &&
from != to &&
project.merge_requests_enabled &&
project.feature_available?(:merge_requests, current_user) &&
project.repository.branch_names.include?(from) &&
project.repository.branch_names.include?(to)
end
......
......@@ -149,4 +149,20 @@ module GitlabRoutingHelper
def resend_invite_group_member_path(group_member, *args)
resend_invite_group_group_member_path(group_member.source, group_member)
end
# Artifacts
def artifacts_action_path(path, project, build)
action, path_params = path.split('/', 2)
args = [project.namespace, project, build, path_params]
case action
when 'download'
download_namespace_project_build_artifacts_path(*args)
when 'browse'
browse_namespace_project_build_artifacts_path(*args)
when 'file'
file_namespace_project_build_artifacts_path(*args)
end
end
end
module ImportHelper
def import_project_target(owner, name)
namespace = current_user.can_create_group? ? owner : current_user.namespace_path
"#{namespace}/#{name}"
end
def github_project_link(path_with_namespace)
link_to path_with_namespace, github_project_url(path_with_namespace), target: '_blank'
end
......
......@@ -49,6 +49,19 @@ module IssuablesHelper
end
end
def project_dropdown_label(project_id, default_label)
return default_label if project_id.nil?
return "Any project" if project_id == "0"
project = Project.find_by(id: project_id)
if project
project.name_with_namespace
else
default_label
end
end
def milestone_dropdown_label(milestone_title, default_label = "Milestone")
if milestone_title == Milestone::Upcoming.name
milestone_title = Milestone::Upcoming.title
......
......@@ -23,10 +23,14 @@ module LfsHelper
end
def lfs_download_access?
return false unless project.lfs_enabled?
project.public? || ci? || (user && user.can?(:download_code, project))
end
def lfs_upload_access?
return false unless project.lfs_enabled?
user && user.can?(:push_code, project)
end
......
......@@ -98,6 +98,6 @@ module MergeRequestsHelper
end
def merge_request_button_visibility(merge_request, closed)
return 'hidden' if merge_request.closed? == closed || (merge_request.merged? == closed && !merge_request.closed?)
return 'hidden' if merge_request.closed? == closed || (merge_request.merged? == closed && !merge_request.closed?) || merge_request.closed_without_fork?
end
end
......@@ -25,6 +25,8 @@ module NavHelper
current_path?('merge_requests#commits') ||
current_path?('merge_requests#builds') ||
current_path?('merge_requests#conflicts') ||
current_path?('merge_requests#pipelines') ||
current_path?('issues#show')
if cookies[:collapsed_gutter] == 'true'
"page-gutter right-sidebar-collapsed"
......
......@@ -61,7 +61,9 @@ module ProjectsHelper
project_link = link_to simple_sanitize(project.name), project_path(project), { class: "project-item-select-holder" }
if current_user
project_link << icon("chevron-down", class: "dropdown-toggle-caret js-projects-dropdown-toggle", aria: { label: "Toggle switch project dropdown" }, data: { target: ".js-dropdown-menu-projects", toggle: "dropdown" })
project_link << button_tag(type: 'button', class: "dropdown-toggle-caret js-projects-dropdown-toggle", aria: { label: "Toggle switch project dropdown" }, data: { target: ".js-dropdown-menu-projects", toggle: "dropdown" }) do
icon("chevron-down")
end
end
full_title = "#{namespace_link} / #{project_link}".html_safe
......@@ -187,6 +189,18 @@ module ProjectsHelper
nav_tabs.flatten
end
def project_lfs_status(project)
if project.lfs_enabled?
content_tag(:span, class: 'lfs-enabled') do
'Enabled'
end
else
content_tag(:span, class: 'lfs-disabled') do
'Disabled'
end
end
end
def git_user_name
if current_user
current_user.name
......@@ -400,4 +414,23 @@ module ProjectsHelper
message.strip.gsub(project.repository_storage_path.chomp('/'), "[REPOS PATH]")
end
def project_feature_options
{
'Disabled' => ProjectFeature::DISABLED,
'Only team members' => ProjectFeature::PRIVATE,
'Everyone with access' => ProjectFeature::ENABLED
}
end
def project_feature_access_select(field)
# Don't show option "everyone with access" if project is private
options = project_feature_options
level = @project.project_feature.public_send(field)
options.delete('Everyone with access') if @project.private? && level != ProjectFeature::ENABLED
options = options_for_select(options, selected: @project.project_feature.public_send(field) || ProjectFeature::ENABLED)
content_tag(:select, options, name: "project[project_feature_attributes][#{field.to_s}]", id: "project_project_feature_attributes_#{field.to_s}", class: "pull-right form-control", data: { field: field }).html_safe
end
end
......@@ -44,7 +44,7 @@ module SearchHelper
def help_autocomplete
[
{ category: "Help", label: "API Help", url: help_page_path("api/README") },
{ category: "Help", label: "Markdown Help", url: help_page_path("markdown/markdown") },
{ category: "Help", label: "Markdown Help", url: help_page_path("user/markdown") },
{ category: "Help", label: "Permissions Help", url: help_page_path("user/permissions") },
{ category: "Help", label: "Public Access Help", url: help_page_path("public_access/public_access") },
{ category: "Help", label: "Rake Tasks Help", url: help_page_path("raketasks/README") },
......
module SentryHelper
def sentry_enabled?
Rails.env.production? && current_application_settings.sentry_enabled?
Gitlab::Sentry.enabled?
end
def sentry_context
return unless sentry_enabled?
if current_user
Raven.user_context(
id: current_user.id,
email: current_user.email,
username: current_user.username,
)
end
Raven.tags_context(program: sentry_program_context)
end
def sentry_program_context
if Sidekiq.server?
'sidekiq'
else
'rails'
end
Gitlab::Sentry.context(current_user)
end
end
......@@ -8,7 +8,9 @@ module ServicesHelper
when "note"
"Event will be triggered when someone adds a comment"
when "issue"
"Event will be triggered when an issue is created/updated/merged"
"Event will be triggered when an issue is created/updated/closed"
when "confidential_issue"
"Event will be triggered when a confidential issue is created/updated/closed"
when "merge_request"
"Event will be triggered when a merge request is created/updated/merged"
when "build"
......@@ -19,7 +21,7 @@ module ServicesHelper
end
def service_event_field_name(event)
event = event.pluralize if %w[merge_request issue].include?(event)
event = event.pluralize if %w[merge_request issue confidential_issue].include?(event)
"#{event}_events"
end
end
......@@ -3,6 +3,16 @@ module TagsHelper
"/tags/#{tag}"
end
def filter_tags_path(options = {})
exist_opts = {
search: params[:search],
sort: params[:sort]
}
options = exist_opts.merge(options)
namespace_project_tags_path(@project.namespace, @project, @id, options)
end
def tag_list(project)
html = ''
project.tag_list.each do |tag|
......
......@@ -78,13 +78,11 @@ module TodosHelper
end
def todo_actions_options
actions = [
OpenStruct.new(id: '', title: 'Any Action'),
OpenStruct.new(id: Todo::ASSIGNED, title: 'Assigned'),
OpenStruct.new(id: Todo::MENTIONED, title: 'Mentioned')
[
{ id: '', text: 'Any Action' },
{ id: Todo::ASSIGNED, text: 'Assigned' },
{ id: Todo::MENTIONED, text: 'Mentioned' }
]
options_from_collection_for_select(actions, 'id', 'title', params[:action_id])
end
def todo_projects_options
......@@ -92,22 +90,28 @@ module TodosHelper
projects = projects.includes(:namespace)
projects = projects.map do |project|
OpenStruct.new(id: project.id, title: project.name_with_namespace)
{ id: project.id, text: project.name_with_namespace }
end
projects.unshift(OpenStruct.new(id: '', title: 'Any Project'))
options_from_collection_for_select(projects, 'id', 'title', params[:project_id])
projects.unshift({ id: '', text: 'Any Project' }).to_json
end
def todo_types_options
types = [
OpenStruct.new(title: 'Any Type', name: ''),
OpenStruct.new(title: 'Issue', name: 'Issue'),
OpenStruct.new(title: 'Merge Request', name: 'MergeRequest')
[
{ id: '', text: 'Any Type' },
{ id: 'Issue', text: 'Issue' },
{ id: 'MergeRequest', text: 'Merge Request' }
]
end
def todo_actions_dropdown_label(selected_action_id, default_action)
selected_action = todo_actions_options.find { |action| action[:id] == selected_action_id.to_i}
selected_action ? selected_action[:text] : default_action
end
options_from_collection_for_select(types, 'name', 'title', params[:type])
def todo_types_dropdown_label(selected_type, default_type)
selected_type = todo_types_options.find { |type| type[:id] == selected_type && type[:id] != '' }
selected_type ? selected_type[:text] : default_type
end
private
......
......@@ -9,7 +9,7 @@ class BaseMailer < ActionMailer::Base
default reply_to: Proc.new { default_reply_to_address.format }
def can?
Ability.abilities.allowed?(current_user, action, subject)
Ability.allowed?(current_user, action, subject)
end
private
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment