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

Merge remote-tracking branch 'upstream/master' into fix-git-hooks-when-creating-file

* upstream/master: (657 commits)
  Use single quote for strings
  Ue svg from SVGs object
  Dont trigger CI builds [ci skip]
  Revert "Test only migrations"
  Add custom copy for each empty stage
  Fetch only one revision
  Highlight nav item on hover
  Test only migrations
  Fix migration paths tests
  Scroll CA stage panel on mobile
  Fix CSS declaration
  administer to administrator
  Move SVGs to JS objects for easy reuse
  Improve deploy command message
  No enough data to Not enough data
  Keep the cookie name as before
  Fix variable usage
  Evalute time_ago method instead of printing it
  Removed button styling from restricted visibility levels and added checkboxes with icons
  Do not show overview message if there’s already CA data
  ...
parents 3e69c716 56b420ae
......@@ -23,7 +23,9 @@
"spyOn": false,
"spyOnEvent": false,
"Turbolinks": false,
"window": false
"window": false,
"Vue": false,
"Flash": false,
"Cookies": false
}
}
CHANGELOG.md merge=union
*.js.es6 gitlab-language=javascript
......@@ -71,11 +71,23 @@ update-knapsack:
- mysql:latest
- redis:alpine
setup-test-env:
<<: *use-db
stage: prepare
script:
- bundle exec rake assets:precompile 2>/dev/null
- bundle exec ruby -Ispec -e 'require "spec_helper" ; TestEnv.init'
artifacts:
expire_in: 7d
paths:
- public/assets
- tmp/tests
.rspec-knapsack: &rspec-knapsack
stage: test
<<: *use-db
script:
- bundle exec rake assets:precompile 2>/dev/null
- JOB_NAME=( $CI_BUILD_NAME )
- export CI_NODE_INDEX=${JOB_NAME[1]}
- export CI_NODE_TOTAL=${JOB_NAME[2]}
......@@ -93,7 +105,6 @@ update-knapsack:
stage: test
<<: *use-db
script:
- bundle exec rake assets:precompile 2>/dev/null
- JOB_NAME=( $CI_BUILD_NAME )
- export CI_NODE_INDEX=${JOB_NAME[1]}
- export CI_NODE_TOTAL=${JOB_NAME[2]}
......@@ -308,12 +319,11 @@ migration paths:
- master@gitlab/gitlabhq
- master@gitlab/gitlab-ee
script:
- git checkout HEAD .
- git fetch --tags
- git checkout v8.5.9
- git fetch origin v8.5.9
- git checkout -f FETCH_HEAD
- cp config/resque.yml.example config/resque.yml
- sed -i 's/localhost/redis/g' config/resque.yml
- bundle install --without postgres production --jobs $(nproc) "${FLAGS[@]}" --retry=3
- bundle install --without postgres production --jobs $(nproc) ${FLAGS[@]} --retry=3
- rake db:drop db:create db:schema:load db:seed_fu
- git checkout $CI_BUILD_REF
- source scripts/prepare_build.sh
......
......@@ -4,37 +4,6 @@ entry.
## 8.14.0 (2016-11-22)
- Use separate email-token for incoming email and revert back the inactive feature. !5914
- Replace jQuery.timeago with timeago.js. !6274 (ClemMakesApps)
- Add CI notifications. Who triggered a pipeline would receive an email after the pipeline is succeeded or failed. Users could also update notification settings accordingly. !6342
- Finer-grained Git gargage collection. !6588
- Introduce better credential and error checking to `rake gitlab:ldap:check`. !6601
- Process commits using a dedicated Sidekiq worker. !6802
- Fix showing pipeline status for a given commit from correct branch. !7034
- Add query param to filter users by external & blocked type. !7109 (Yatish Mehta)
- Issues atom feed url reflect filters on dashboard. !7114 (Lucas Deschamps)
- Add setting to only allow merge requests to be merged when all discussions are resolved. !7125 (Rodolfo Arruda)
- Remove an extra leading space from diff paste data. !7133 (Hiroyuki Sato)
- Fix 404 on network page when entering non-existent git revision. !7172 (Hiroyuki Sato)
- Rewrite git blame spinach feature tests to rspec feature tests. !7197 (Lisanne Fellinger)
- Only skip group when it's actually a group in the "Share with group" select. !7262
- Introduce round-robin project creation to spread load over multiple shards. !7266
- Ensure merge request's "remove branch" accessors return booleans. !7267
- Expose label IDs in API. !7275 (Rares Sfirlogea)
- Fix invalid filename validation on eslint. !7281
- API: Ability to retrieve version information. !7286 (Robert Schilling)
- Set default Sidekiq retries to 3. !7294
- Return 400 when creating a system hook fails. !7350 (Robert Schilling)
- Use the Gitlab Workhorse HTTP header in the admin dashboard. (Chris Wright)
- Add an index for project_id in project_import_data to improve performance.
- Fix broken link to observatory cli on Frontend Dev Guide. (Sam Rose)
- Faster search inside Project.
- Clicking "force remove source branch" label now toggles the checkbox again.
- Allow to test JIRA service settings without having a repository.
- Fix: Guest sees some repository details and gets 404.
- Bump omniauth-gitlab to 1.0.2 to fix incompatibility with omniauth-oauth2.
- Fix: Todos Filter Shows All Users.
- Fix broken commits search.
- Show correct environment log in admin/logs (@duk3luk3 !7191)
- Fix Milestone dropdown not stay selected for `Upcoming` and `No Milestone` option !7117
- Diff collapse won't shift when collapsing.
......@@ -63,6 +32,7 @@ entry.
- Fix sidekiq stats in admin area (blackst0ne)
- Added label description as tooltip to issue board list title
- Created cycle analytics bundle JavaScript file
- Make the milestone page more responsive (yury-n)
- Hides container registry when repository is disabled
- API: Fix booleans not recognized as such when using the `to_boolean` helper
- Removed delete branch tooltip !6954
......@@ -104,8 +74,22 @@ entry.
- Fix applying GitHub-imported labels when importing job is interrupted
- Allow to search for user by secondary email address in the admin interface(/admin/users) !7115 (YarNayar)
- Updated commit SHA styling on the branches page.
- Fix "Without projects" filter. !6611 (Ben Bodenmiller)
- Fix 404 when visit /projects page
## 8.13.6 (2016-11-17)
- Omniauth auto link LDAP user falls back to find by DN when user cannot be found by UID. !7002
- Fix Milestone dropdown not stay selected for `Upcoming` and `No Milestone` option. !7117
- Fix relative links in Markdown wiki when displayed in "Project" tab. !7218
- Fix no "Register" tab if ldap auth is enabled (#24038). !7274 (Luc Didry)
- Fix cache for commit status in commits list to respect branches. !7372
- Fix issue causing Labels not to appear in sidebar on MR page. !7416 (Alex Sanford)
- Limit labels returned for a specific project as an administrator. !7496
- Clicking "force remove source branch" label now toggles the checkbox again.
- Allow commit note to be visible if repo is visible.
- Fix project Visibility Level selector not using default values.
## 8.13.5 (2016-11-08)
- Restore unauthenticated access to public container registries
......@@ -133,7 +117,6 @@ entry.
- Removes any symlinks before importing a project export file. CVE-2016-9086
- Fixed Import/Export foreign key issue to do with project members.
- Fix relative links in Markdown wiki when displayed in "Project" tab !7218
- Changed build dropdown list length to be 6,5 builds long in the pipeline graph
## 8.13.2 (2016-10-31)
......
......@@ -9,8 +9,6 @@
- [Helping others](#helping-others)
- [I want to contribute!](#i-want-to-contribute)
- [Implement design & UI elements](#implement-design-ui-elements)
- [Design reference](#design-reference)
- [UI development kit](#ui-development-kit)
- [Issue tracker](#issue-tracker)
- [Feature proposals](#feature-proposals)
- [Issue tracker guidelines](#issue-tracker-guidelines)
......@@ -90,7 +88,7 @@ This was inspired by [an article by Kent C. Dodds][medium-up-for-grabs].
## Implement design & UI elements
Please see the [UI Guide for building GitLab].
Please see the [UX Guide for GitLab].
## Issue tracker
......@@ -218,7 +216,10 @@ associated with in the description of the issue.
We welcome merge requests with fixes and improvements to GitLab code, tests,
and/or documentation. The features we would really like a merge request for are
listed with the label [`Accepting Merge Requests` on our issue tracker for CE][accepting-mrs-ce]
and [EE][accepting-mrs-ee] but other improvements are also welcome.
and [EE][accepting-mrs-ee] but other improvements are also welcome. Please note
that if an issue is marked for the current milestone either before or while you
are working on it, a team member may take over the merge request in order to
ensure the work is finished before the release date.
If you want to add a new feature that is not labeled it is best to first create
a feedback issue (if there isn't one already) and leave a comment asking for it
......@@ -469,5 +470,5 @@ available at [http://contributor-covenant.org/version/1/1/0/](http://contributor
[doc-styleguide]: doc/development/doc_styleguide.md "Documentation styleguide"
[scss-styleguide]: doc/development/scss_styleguide.md "SCSS styleguide"
[newlines-styleguide]: doc/development/newlines_styleguide.md "Newlines styleguide"
[UI Guide for building GitLab]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/development/ui_guide.md
[UX Guide for GitLab]: http://docs.gitlab.com/ce/development/ux_guide/
[license-finder-doc]: doc/development/licensing.md
......@@ -330,13 +330,10 @@ gem 'octokit', '~> 4.3.0'
gem 'mail_room', '~> 0.9.0'
gem 'email_reply_parser', '~> 0.5.8'
gem 'html2text'
gem 'ruby-prof', '~> 0.16.2'
## CI
gem 'activerecord-session_store', '~> 1.0.0'
gem 'nested_form', '~> 0.3.2'
# OAuth
gem 'oauth2', '~> 1.2.0'
......
......@@ -32,12 +32,6 @@ GEM
activemodel (= 4.2.7.1)
activesupport (= 4.2.7.1)
arel (~> 6.0)
activerecord-session_store (1.0.0)
actionpack (>= 4.0, < 5.1)
activerecord (>= 4.0, < 5.1)
multi_json (~> 1.11, >= 1.11.2)
rack (>= 1.5.2, < 3)
railties (>= 4.0, < 5.1)
activerecord_sane_schema_dumper (0.2)
rails (>= 4, < 5)
activesupport (4.2.7.1)
......@@ -345,6 +339,8 @@ GEM
html-pipeline (1.11.0)
activesupport (>= 2)
nokogiri (~> 1.4)
html2text (0.2.0)
nokogiri (~> 1.6)
htmlentities (4.3.4)
httparty (0.13.7)
json (~> 1.8)
......@@ -416,7 +412,6 @@ GEM
multi_xml (0.5.5)
multipart-post (2.0.0)
mysql2 (0.3.20)
nested_form (0.3.2)
net-ldap (0.12.1)
net-ssh (3.0.1)
newrelic_rpm (3.16.0.318)
......@@ -598,7 +593,7 @@ GEM
railties (>= 4.2.0, < 5.1)
rinku (2.0.0)
rotp (2.1.2)
rouge (2.0.6)
rouge (2.0.7)
rqrcode (0.7.0)
chunky_png
rqrcode-rails3 (0.1.7)
......@@ -809,7 +804,6 @@ PLATFORMS
DEPENDENCIES
RedCloth (~> 4.3.2)
ace-rails-ap (~> 4.1.0)
activerecord-session_store (~> 1.0.0)
activerecord_sane_schema_dumper (= 0.2)
acts-as-taggable-on (~> 4.0)
addressable (~> 2.3.8)
......@@ -881,6 +875,7 @@ DEPENDENCIES
health_check (~> 2.2.0)
hipchat (~> 1.5.0)
html-pipeline (~> 1.11.0)
html2text
httparty (~> 0.13.3)
influxdb (~> 0.2)
jira-ruby (~> 1.1.2)
......@@ -901,7 +896,6 @@ DEPENDENCIES
minitest (~> 5.7.0)
mousetrap-rails (~> 1.4.6)
mysql2 (~> 0.3.16)
nested_form (~> 0.3.2)
net-ssh (~> 3.0.1)
newrelic_rpm (~> 3.16)
nokogiri (~> 1.6.7, >= 1.6.7.2)
......
/* eslint-disable */
(function() {
this.Activities = (function() {
function Activities() {
Pager.init(20, true, false, this.updateTooltips);
$(".event-filter-link").on("click", (function(_this) {
return function(event) {
event.preventDefault();
_this.toggleFilter($(event.currentTarget));
return _this.reloadActivities();
};
})(this));
}
Activities.prototype.updateTooltips = function() {
gl.utils.localTimeAgo($('.js-timeago', '.content_list'));
};
Activities.prototype.reloadActivities = function() {
$(".content_list").html('');
Pager.init(20, true, false, this.updateTooltips);
};
Activities.prototype.toggleFilter = function(sender) {
var filter = sender.attr("id").split("_")[0];
$('.event-filter .active').removeClass("active");
Cookies.set("event_filter", filter);
sender.closest('li').toggleClass("active");
};
return Activities;
})();
}).call(this);
/* eslint-disable no-param-reassign, class-methods-use-this */
/* global Pager, Cookies */
((global) => {
class Activities {
constructor() {
Pager.init(20, true, false, this.updateTooltips);
$('.event-filter-link').on('click', (e) => {
e.preventDefault();
this.toggleFilter(e.currentTarget);
this.reloadActivities();
});
}
updateTooltips() {
gl.utils.localTimeAgo($('.js-timeago', '.content_list'));
}
reloadActivities() {
$('.content_list').html('');
Pager.init(20, true, false, this.updateTooltips);
}
toggleFilter(sender) {
const $sender = $(sender);
const filter = $sender.attr('id').split('_')[0];
$('.event-filter .active').removeClass('active');
Cookies.set('event_filter', filter);
$sender.closest('li').toggleClass('active');
}
}
global.Activities = Activities;
})(window.gl || (window.gl = {}));
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren, wrap-iife, one-var, no-var, one-var-declaration-per-line, no-unused-vars, no-else-return, prefer-arrow-callback, camelcase, quotes, comma-dangle, no-undef, padded-blocks, max-len */
(function() {
this.Admin = (function() {
function Admin() {
......
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren, quotes, object-shorthand, camelcase, no-var, no-undef, comma-dangle, prefer-arrow-callback, indent, object-curly-spacing, quote-props, no-param-reassign, padded-blocks, max-len */
(function() {
this.Api = {
groupsPath: "/api/:version/groups.json",
......
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren, no-var, no-undef, quotes, consistent-return, prefer-arrow-callback, comma-dangle, object-shorthand, no-new, max-len */
// This is a manifest file that'll be compiled into including all the files listed below.
// Add new JavaScript code in separate files in this directory and they'll automatically
// be included in the compiled file accessible from http://example.com/assets/application.js
......@@ -53,6 +53,7 @@
/*= require_directory ./u2f */
/*= require_directory . */
/*= require fuzzaldrin-plus */
/*= require es6-promise.auto */
(function () {
document.addEventListener('page:fetch', gl.utils.cleanupBeforeFetch);
......
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren, wrap-iife, quotes, prefer-arrow-callback, no-var, one-var, one-var-declaration-per-line, no-else-return, padded-blocks, max-len */
(function() {
this.Aside = (function() {
function Aside() {
......
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-param-reassign, quotes, prefer-template, no-var, one-var, no-unused-vars, one-var-declaration-per-line, no-void, consistent-return, no-empty, padded-blocks, max-len */
(function() {
this.Autosave = (function() {
function Autosave(field, key) {
......
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren, wrap-iife, max-len, no-var, spaced-comment, prefer-arrow-callback, consistent-return, one-var, one-var-declaration-per-line, no-unused-vars, no-else-return, prefer-template, quotes, comma-dangle, no-param-reassign, no-void, radix, keyword-spacing, space-before-blocks, brace-style, no-underscore-dangle, no-undef, no-plusplus, no-return-assign, camelcase, padded-blocks, max-len */
(function() {
this.AwardsHandler = (function() {
var FROM_SENTENCE_REGEX = /(?:, and | and |, )/; //For separating lists produced by ruby's Array#toSentence
......
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren, prefer-arrow-callback, no-var, consistent-return, no-undef, padded-blocks, max-len */
/*= require jquery.ba-resize */
/*= require autosize */
......
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren, prefer-arrow-callback, quotes, no-var, vars-on-top, padded-blocks, max-len */
(function() {
$(function() {
$("body").on("click", ".js-details-target", function() {
......
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren, one-var, no-var, one-var-declaration-per-line, no-undef, prefer-arrow-callback, camelcase, max-len, consistent-return, quotes, object-shorthand, comma-dangle, padded-blocks, max-len */
// Quick Submit behavior
//
// When a child field of a form with a `js-quick-submit` class receives a
......
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren, one-var, no-var, one-var-declaration-per-line, quotes, prefer-template, prefer-arrow-callback, no-else-return, consistent-return, padded-blocks, max-len */
// Requires Input behavior
//
// When called on a form with input fields with the `required` attribute, the
......
/* eslint-disable */
/* eslint-disable wrap-iife, func-names, space-before-function-paren, prefer-arrow-callback, vars-on-top, no-var, max-len */
(function(w) {
$(function() {
// Toggle button. Show/hide content inside parent container.
......
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren, wrap-iife, one-var, no-var, one-var-declaration-per-line, camelcase, no-undef, object-shorthand, quotes, comma-dangle, prefer-arrow-callback, no-unused-vars, prefer-template, no-useless-escape, no-alert, padded-blocks, max-len */
(function() {
this.BlobFileDropzone = (function() {
function BlobFileDropzone(form, method) {
......
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren, max-len, one-var, no-var, no-restricted-syntax, vars-on-top, no-use-before-define, no-param-reassign, new-cap, no-underscore-dangle, wrap-iife, prefer-rest-params, no-undef, padded-blocks, max-len */
/*= require blob/template_selector */
......
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, no-unused-expressions, no-cond-assign, no-sequences, no-undef, comma-dangle, padded-blocks, max-len */
(function() {
this.BlobGitignoreSelectors = (function() {
function BlobGitignoreSelectors(opts) {
......
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren, max-len, one-var, no-var, no-restricted-syntax, vars-on-top, no-use-before-define, no-param-reassign, new-cap, no-underscore-dangle, wrap-iife, prefer-rest-params, comma-dangle, no-undef, padded-blocks, max-len */
/*= require blob/template_selector */
......
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren, prefer-arrow-callback, no-var, quotes, vars-on-top, no-unused-vars, no-undef, no-new, padded-blocks, max-len */
/*= require_tree . */
(function() {
......
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren, no-var, space-before-blocks, prefer-rest-params, wrap-iife, camelcase, no-param-reassign, no-undef, quotes, prefer-template, no-new, comma-dangle, one-var, one-var-declaration-per-line, prefer-arrow-callback, no-else-return, no-unused-vars, padded-blocks, max-len */
(function() {
var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
......
/* eslint-disable */
/* eslint-disable wrap-iife, func-names, strict, indent, no-tabs, no-var, vars-on-top, no-param-reassign, object-shorthand, no-shadow, comma-dangle, prefer-template, consistent-return, no-mixed-operators, no-unused-vars, object-curly-spacing, no-unused-expressions, prefer-arrow-callback, max-len */
(function () {
'use strict';
......
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren, wrap-iife, one-var, no-var, one-var-declaration-per-line, quotes, no-shadow, prefer-arrow-callback, prefer-template, consistent-return, padded-blocks, no-return-assign, new-parens, no-param-reassign, no-undef, max-len */
(function() {
this.Breakpoints = (function() {
var BreakpointInstance, instance;
......
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren, prefer-arrow-callback, no-var, quotes, no-else-return, object-shorthand, comma-dangle, padded-blocks, max-len */
(function() {
$(function() {
var previewPath;
......
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren, no-var, space-before-blocks, prefer-rest-params, wrap-iife, no-use-before-define, no-param-reassign, no-undef, quotes, yoda, no-else-return, consistent-return, comma-dangle, semi, object-shorthand, prefer-template, one-var, one-var-declaration-per-line, no-unused-vars, max-len, vars-on-top, padded-blocks, max-len */
(function() {
var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
......@@ -172,7 +172,7 @@
$date = $('.js-artifacts-remove');
if ($date.length) {
date = $date.text();
return $date.text(gl.utils.timefor(new Date(date.replace(/([0-9]+)-([0-9]+)-([0-9]+)/g, '$1/$2/$3')), ' '));
return $date.text(gl.utils.timeFor(new Date(date.replace(/([0-9]+)-([0-9]+)-([0-9]+)/g, '$1/$2/$3')), ' '));
}
};
......
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren, wrap-iife, prefer-arrow-callback, no-unused-vars, no-return-assign, padded-blocks, max-len */
(function() {
this.BuildArtifacts = (function() {
function BuildArtifacts() {
......
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-undef, padded-blocks */
(function() {
this.Commit = (function() {
function Commit() {
......
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-new, no-undef, padded-blocks, max-len */
(function() {
this.CommitFile = (function() {
function CommitFile(file) {
......
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, no-use-before-define, prefer-arrow-callback, no-else-return, consistent-return, prefer-template, quotes, one-var, one-var-declaration-per-line, no-unused-vars, no-return-assign, comma-dangle, quote-props, no-unused-expressions, no-sequences, object-shorthand, padded-blocks, max-len */
(function() {
this.ImageFile = (function() {
var prepareFrames;
......
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren, wrap-iife, quotes, consistent-return, no-undef, no-return-assign, no-param-reassign, one-var, no-var, one-var-declaration-per-line, no-unused-vars, prefer-template, object-shorthand, comma-dangle, padded-blocks, max-len */
(function() {
this.CommitsList = (function() {
function CommitsList() {}
......
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren, wrap-iife, quotes, no-var, object-shorthand, consistent-return, no-unused-vars, comma-dangle, vars-on-top, prefer-template, padded-blocks, max-len */
(function() {
this.Compare = (function() {
function Compare(opts) {
......
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren, wrap-iife, one-var, no-var, camelcase, one-var-declaration-per-line, no-else-return, padded-blocks, max-len */
(function() {
this.ConfirmDangerModal = (function() {
function ConfirmDangerModal(form, text) {
......
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren, one-var, no-var, one-var-declaration-per-line, no-undef, prefer-template, quotes, no-unused-vars, prefer-arrow-callback, padded-blocks, max-len */
/*= require clipboard */
......
/* eslint-disable no-param-reassign */
((global) => {
global.cycleAnalytics = global.cycleAnalytics || {};
global.cycleAnalytics.StageCodeComponent = Vue.extend({
props: {
items: Array,
stage: Object,
},
template: `
<div>
<div class="events-description">
{{ stage.description }}
</div>
<ul class="stage-event-list">
<li v-for="mergeRequest in items" class="stage-event-item">
<div class="item-details">
<img class="avatar" :src="mergeRequest.author.avatarUrl">
<h5 class="item-title merge-merquest-title">
<a :href="mergeRequest.url">
{{ mergeRequest.title }}
</a>
</h5>
<a :href="mergeRequest.url" class="issue-link">!{{ mergeRequest.iid }}</a>
&middot;
<span>
Opened
<a :href="mergeRequest.url" class="issue-date">{{ mergeRequest.createdAt }}</a>
</span>
<span>
by
<a :href="mergeRequest.author.webUrl" class="issue-author-link">{{ mergeRequest.author.name }}</a>
</span>
</div>
<div class="item-time">
<total-time :time="mergeRequest.totalTime"></total-time>
</div>
</li>
</ul>
</div>
`,
});
})(window.gl || (window.gl = {}));
/* eslint-disable no-param-reassign */
((global) => {
global.cycleAnalytics = global.cycleAnalytics || {};
global.cycleAnalytics.StageIssueComponent = Vue.extend({
props: {
items: Array,
stage: Object,
},
template: `
<div>
<div class="events-description">
{{ stage.description }}
</div>
<ul class="stage-event-list">
<li v-for="issue in items" class="stage-event-item">
<div class="item-details">
<img class="avatar" :src="issue.author.avatarUrl">
<h5 class="item-title issue-title">
<a class="issue-title" :href="issue.url">
{{ issue.title }}
</a>
</h5>
<a :href="issue.url" class="issue-link">#{{ issue.iid }}</a>
&middot;
<span>
Opened
<a :href="issue.url" class="issue-date">{{ issue.createdAt }}</a>
</span>
<span>
by
<a :href="issue.author.webUrl" class="issue-author-link">
{{ issue.author.name }}
</a>
</span>
</div>
<div class="item-time">
<total-time :time="issue.totalTime"></total-time>
</div>
</li>
</ul>
</div>
`,
});
})(window.gl || (window.gl = {}));
/* eslint-disable no-param-reassign */
((global) => {
global.cycleAnalytics = global.cycleAnalytics || {};
global.cycleAnalytics.StagePlanComponent = Vue.extend({
props: {
items: Array,
stage: Object,
},
template: `
<div>
<div class="events-description">
{{ stage.description }}
</div>
<ul class="stage-event-list">
<li v-for="commit in items" class="stage-event-item">
<div class="item-details item-conmmit-component">
<img class="avatar" :src="commit.author.avatarUrl">
<h5 class="item-title commit-title">
<a :href="commit.commitUrl">
{{ commit.title }}
</a>
</h5>
<span>
First
<span class="commit-icon">${global.cycleAnalytics.svgs.iconCommit}</span>
<a :href="commit.commitUrl" class="commit-hash-link monospace">{{ commit.shortSha }}</a>
pushed by
<a :href="commit.author.webUrl" class="commit-author-link">
{{ commit.author.name }}
</a>
</span>
</div>
<div class="item-time">
<total-time :time="commit.totalTime"></total-time>
</div>
</li>
</ul>
</div>
`,
});
})(window.gl || (window.gl = {}));
/* eslint-disable no-param-reassign */
((global) => {
global.cycleAnalytics = global.cycleAnalytics || {};
global.cycleAnalytics.StageProductionComponent = Vue.extend({
props: {
items: Array,
stage: Object,
},
template: `
<div>
<div class="events-description">
{{ stage.description }}
</div>
<ul class="stage-event-list">
<li v-for="issue in items" class="stage-event-item">
<div class="item-details">
<img class="avatar" :src="issue.author.avatarUrl">
<h5 class="item-title issue-title">
<a class="issue-title" :href="issue.url">
{{ issue.title }}
</a>
</h5>
<a :href="issue.url" class="issue-link">#{{ issue.iid }}</a>
&middot;
<span>
Opened
<a :href="issue.url" class="issue-date">{{ issue.createdAt }}</a>
</span>
<span>
by
<a :href="issue.author.webUrl" class="issue-author-link">
{{ issue.author.name }}
</a>
</span>
</div>
<div class="item-time">
<total-time :time="issue.totalTime"></total-time>
</div>
</li>
</ul>
</div>
`,
});
})(window.gl || (window.gl = {}));
/* eslint-disable no-param-reassign */
((global) => {
global.cycleAnalytics = global.cycleAnalytics || {};
global.cycleAnalytics.StageReviewComponent = Vue.extend({
props: {
items: Array,
stage: Object,
},
template: `
<div>
<div class="events-description">
{{ stage.description }}
</div>
<ul class="stage-event-list">
<li v-for="mergeRequest in items" class="stage-event-item">
<div class="item-details">
<img class="avatar" :src="mergeRequest.author.avatarUrl">
<h5 class="item-title merge-merquest-title">
<a :href="mergeRequest.url">
{{ mergeRequest.title }}
</a>
</h5>
<a :href="mergeRequest.url" class="issue-link">!{{ mergeRequest.iid }}</a>
&middot;
<span>
Opened
<a :href="mergeRequest.url" class="issue-date">{{ mergeRequest.createdAt }}</a>
</span>
<span>
by
<a :href="mergeRequest.author.webUrl" class="issue-author-link">{{ mergeRequest.author.name }}</a>
</span>
<template v-if="mergeRequest.state === 'closed'">
<span class="merge-request-state">
<i class="fa fa-ban"></i>
{{ mergeRequest.state.toUpperCase() }}
</span>
</template>
<template v-else>
<span class="merge-request-branch" v-if="mergeRequest.branch">
<i class= "fa fa-code-fork"></i>
<a :href="mergeRequest.branch.url">{{ mergeRequest.branch.name }}</a>
</span>
</template>
</div>
<div class="item-time">
<total-time :time="mergeRequest.totalTime"></total-time>
</div>
</li>
</ul>
</div>
`,
});
})(window.gl || (window.gl = {}));
/* eslint-disable no-param-reassign */
((global) => {
global.cycleAnalytics = global.cycleAnalytics || {};
global.cycleAnalytics.StageStagingComponent = Vue.extend({
props: {
items: Array,
stage: Object,
},
template: `
<div>
<div class="events-description">
{{ stage.description }}
</div>
<ul class="stage-event-list">
<li v-for="build in items" class="stage-event-item item-build-component">
<div class="item-details">
<img class="avatar" :src="build.author.avatarUrl">
<h5 class="item-title">
<a :href="build.url" class="pipeline-id">#{{ build.id }}</a>
<i class="fa fa-code-fork"></i>
<a :href="build.branch.url" class="branch-name monospace">{{ build.branch.name }}</a>
<span class="icon-branch">${global.cycleAnalytics.svgs.iconBranch}</span>
<a :href="build.commitUrl" class="short-sha monospace">{{ build.shortSha }}</a>
</h5>
<span>
<a :href="build.url" class="build-date">{{ build.date }}</a>
by
<a :href="build.author.webUrl" class="issue-author-link">
{{ build.author.name }}
</a>
</span>
</div>
<div class="item-time">
<total-time :time="build.totalTime"></total-time>
</div>
</li>
</ul>
</div>
`,
});
})(window.gl || (window.gl = {}));
/* eslint-disable no-param-reassign */
((global) => {
global.cycleAnalytics = global.cycleAnalytics || {};
global.cycleAnalytics.StageTestComponent = Vue.extend({
props: {
items: Array,
stage: Object,
},
template: `
<div>
<div class="events-description">
{{ stage.description }}
</div>
<ul class="stage-event-list">
<li v-for="build in items" class="stage-event-item item-build-component">
<div class="item-details">
<h5 class="item-title">
<span class="icon-build-status">${global.cycleAnalytics.svgs.iconBuildStatus}</span>
<a :href="build.url" class="item-build-name">{{ build.name }}</a>
&middot;
<a :href="build.url" class="pipeline-id">#{{ build.id }}</a>
<i class="fa fa-code-fork"></i>
<a :href="build.branch.url" class="branch-name monospace">{{ build.branch.name }}</a>
<span class="icon-branch">${global.cycleAnalytics.svgs.iconBranch}</span>
<a :href="build.commitUrl" class="short-sha monospace">{{ build.shortSha }}</a>
</h5>
<span>
<a :href="build.url" class="issue-date">
{{ build.date }}
</a>
</span>
</div>
<div class="item-time">
<total-time :time="build.totalTime"></total-time>
</div>
</li>
</ul>
</div>
`,
});
})(window.gl || (window.gl = {}));
/* eslint-disable no-param-reassign */
((global) => {
global.cycleAnalytics = global.cycleAnalytics || {};
global.cycleAnalytics.TotalTimeComponent = Vue.extend({
props: {
time: Object,
},
template: `
<span class="total-time">
<template v-if="time.days">{{ time.days }} <span>{{ time.days === 1 ? 'day' : 'days' }}</span></template>
<template v-if="time.hours">{{ time.hours }} <span>hr</span></template>
<template v-if="time.mins && !time.days">{{ time.mins }} <span>mins</span></template>
<template v-if="time.seconds && Object.keys(time).length === 1 || time.seconds === 0">{{ time.seconds }} <span>s</span></template>
</span>
`,
});
})(window.gl || (window.gl = {}));
/* eslint-disable */
//= require vue
((global) => {
const COOKIE_NAME = 'cycle_analytics_help_dismissed';
const store = gl.cycleAnalyticsStore = {
isLoading: true,
hasError: false,
isHelpDismissed: Cookies.get(COOKIE_NAME),
analytics: {}
};
gl.CycleAnalytics = class CycleAnalytics {
constructor() {
const that = this;
this.vue = new Vue({
el: '#cycle-analytics',
name: 'CycleAnalytics',
created: this.fetchData(),
data: store,
methods: {
dismissLanding() {
that.dismissLanding();
}
//= require_tree ./svg
//= require_tree .
$(() => {
const OVERVIEW_DIALOG_COOKIE = 'cycle_analytics_help_dismissed';
const cycleAnalyticsEl = document.querySelector('#cycle-analytics');
const cycleAnalyticsStore = gl.cycleAnalytics.CycleAnalyticsStore;
const cycleAnalyticsService = new gl.cycleAnalytics.CycleAnalyticsService({
requestPath: cycleAnalyticsEl.dataset.requestPath,
});
gl.cycleAnalyticsApp = new Vue({
el: '#cycle-analytics',
name: 'CycleAnalytics',
data: {
state: cycleAnalyticsStore.state,
isLoading: false,
isLoadingStage: false,
isEmptyStage: false,
hasError: false,
startDate: 30,
isOverviewDialogDismissed: Cookies.get(OVERVIEW_DIALOG_COOKIE),
},
computed: {
currentStage() {
return cycleAnalyticsStore.currentActiveStage();
},
},
components: {
'stage-issue-component': gl.cycleAnalytics.StageIssueComponent,
'stage-plan-component': gl.cycleAnalytics.StagePlanComponent,
'stage-code-component': gl.cycleAnalytics.StageCodeComponent,
'stage-test-component': gl.cycleAnalytics.StageTestComponent,
'stage-review-component': gl.cycleAnalytics.StageReviewComponent,
'stage-staging-component': gl.cycleAnalytics.StageStagingComponent,
'stage-production-component': gl.cycleAnalytics.StageProductionComponent,
},
created() {
this.fetchCycleAnalyticsData();
},
methods: {
handleError() {
cycleAnalyticsStore.setErrorState(true);
return new Flash('There was an error while fetching cycle analytics data.');
},
initDropdown() {
const $dropdown = $('.js-ca-dropdown');
const $label = $dropdown.find('.dropdown-label');
$dropdown.find('li a').off('click').on('click', (e) => {
e.preventDefault();
const $target = $(e.currentTarget);
this.startDate = $target.data('value');
$label.text($target.text().trim());
this.fetchCycleAnalyticsData({ startDate: this.startDate });
});
},
fetchCycleAnalyticsData(options) {
const fetchOptions = options || { startDate: this.startDate };
this.isLoading = true;
cycleAnalyticsService
.fetchCycleAnalyticsData(fetchOptions)
.done((response) => {
cycleAnalyticsStore.setCycleAnalyticsData(response);
this.selectDefaultStage();
this.initDropdown();
})
.error(() => {
this.handleError();
})
.always(() => {
this.isLoading = false;
});
},
selectDefaultStage() {
const stage = this.state.stages.first();
this.selectStage(stage);
},
selectStage(stage) {
if (this.isLoadingStage) return;
if (this.currentStage === stage) return;
if (!stage.isUserAllowed) {
cycleAnalyticsStore.setActiveStage(stage);
return;
}
});
}
fetchData(options) {
store.isLoading = true;
options = options || { startDate: 30 };
$.ajax({
url: $('#cycle-analytics').data('request-path'),
method: 'GET',
dataType: 'json',
contentType: 'application/json',
data: {
cycle_analytics: {
start_date: options.startDate
}
}
}).done((data) => {
this.decorateData(data);
this.initDropdown();
})
.error((data) => {
this.handleError(data);
})
.always(() => {
store.isLoading = false;
})
}
decorateData(data) {
data.summary = data.summary || [];
data.stats = data.stats || [];
data.summary.forEach((item) => {
item.value = item.value || '-';
});
data.stats.forEach((item) => {
item.value = item.value || '- - -';
});
store.analytics = data;
}
handleError(data) {
store.hasError = true;
new Flash('There was an error while fetching cycle analytics data.', 'alert');
}
dismissLanding() {
store.isHelpDismissed = true;
Cookies.set(COOKIE_NAME, true);
}
initDropdown() {
const $dropdown = $('.js-ca-dropdown');
const $label = $dropdown.find('.dropdown-label');
$dropdown.find('li a').off('click').on('click', (e) => {
e.preventDefault();
const $target = $(e.currentTarget);
const value = $target.data('value');
$label.text($target.text().trim());
this.fetchData({ startDate: value });
})
}
}
})(window.gl || (window.gl = {}));
this.isLoadingStage = true;
cycleAnalyticsStore.setStageEvents([]);
cycleAnalyticsStore.setActiveStage(stage);
cycleAnalyticsService
.fetchStageData({
stage,
startDate: this.startDate,
})
.done((response) => {
this.isEmptyStage = !response.events.length;
cycleAnalyticsStore.setStageEvents(response.events);
})
.error(() => {
this.isEmptyStage = true;
})
.always(() => {
this.isLoadingStage = false;
});
},
dismissOverviewDialog() {
this.isOverviewDialogDismissed = true;
Cookies.set(OVERVIEW_DIALOG_COOKIE, '1');
},
},
});
// Register global components
Vue.component('total-time', gl.cycleAnalytics.TotalTimeComponent);
});
/* eslint-disable no-param-reassign */
((global) => {
global.cycleAnalytics = global.cycleAnalytics || {};
class CycleAnalyticsService {
constructor(options) {
this.requestPath = options.requestPath;
}
fetchCycleAnalyticsData(options) {
options = options || { startDate: 30 };
return $.ajax({
url: this.requestPath,
method: 'GET',
dataType: 'json',
contentType: 'application/json',
data: {
cycle_analytics: {
start_date: options.startDate,
},
},
});
}
fetchStageData(options) {
const {
stage,
startDate,
} = options;
return $.get(`${this.requestPath}/events/${stage.title.toLowerCase()}.json`, {
cycle_analytics: {
start_date: startDate,
},
});
}
}
global.cycleAnalytics.CycleAnalyticsService = CycleAnalyticsService;
})(window.gl || (window.gl = {}));
/* eslint-disable no-param-reassign */
((global) => {
global.cycleAnalytics = global.cycleAnalytics || {};
const EMPTY_STAGE_TEXTS = {
issue: 'The issue stage shows the time it takes from creating an issue to assigning the issue to a milestone, or add the issue to a list on your Issue Board. Begin creating issues to see data for this stage.',
plan: 'The planning stage shows the time from the previous step to pushing your first commit. This time will be added automatically once you push your first commit.',
code: 'The coding stage shows the time from the first commit to creating the merge request. The data will automatically be added here once you create your first merge request.',
test: 'The testing stage shows the time GitLab CI takes to run every pipeline for the related merge request. The data will automatically be added after your first pipeline finishes running.',
review: 'The review stage shows the time from creating the merge request to merging it. The data will automatically be added after you merge your first merge request.',
staging: 'The staging stage shows the time between merging the MR and deploying code to the production environment. The data will be automatically added once you deploy to production for the first time.',
production: 'The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle.',
};
global.cycleAnalytics.CycleAnalyticsStore = {
state: {
summary: '',
stats: '',
analytics: '',
events: [],
stages: [],
},
setCycleAnalyticsData(data) {
this.state = Object.assign(this.state, this.decorateData(data));
},
decorateData(data) {
const newData = {};
newData.stages = data.stats || [];
newData.summary = data.summary || [];
newData.summary.forEach((item) => {
item.value = item.value || '-';
});
newData.stages.forEach((item) => {
const stageName = item.title.toLowerCase();
item.active = false;
item.isUserAllowed = data.permissions[stageName];
item.emptyStageText = EMPTY_STAGE_TEXTS[stageName];
item.component = `stage-${stageName}-component`;
});
newData.analytics = data;
return newData;
},
setLoadingState(state) {
this.state.isLoading = state;
},
setErrorState(state) {
this.state.hasError = state;
},
deactivateAllStages() {
this.state.stages.forEach((stage) => {
stage.active = false;
});
},
setActiveStage(stage) {
this.deactivateAllStages();
stage.active = true;
},
setStageEvents(events) {
this.state.events = this.decorateEvents(events);
},
decorateEvents(events) {
const newEvents = events;
newEvents.forEach((item) => {
item.totalTime = item.total_time;
item.author.webUrl = item.author.web_url;
item.author.avatarUrl = item.author.avatar_url;
if (item.created_at) item.createdAt = item.created_at;
if (item.short_sha) item.shortSha = item.short_sha;
if (item.commit_url) item.commitUrl = item.commit_url;
delete item.author.web_url;
delete item.author.avatar_url;
delete item.total_time;
delete item.created_at;
delete item.short_sha;
delete item.commit_url;
});
return newEvents;
},
currentActiveStage() {
return this.state.stages.find(stage => stage.active);
},
};
})(window.gl || (window.gl = {}));
/* eslint-disable no-param-reassign */
((global) => {
global.cycleAnalytics = global.cycleAnalytics || {};
global.cycleAnalytics.svgs = global.cycleAnalytics.svgs || {};
global.cycleAnalytics.svgs.iconBranch = '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14"><path fill="#8C8C8C" fill-rule="evenodd" d="M9.678 6.722C9.353 5.167 8.053 4 6.5 4S3.647 5.167 3.322 6.722h-2.6c-.397 0-.722.35-.722.778 0 .428.325.778.722.778h2.6C3.647 9.833 4.947 11 6.5 11s2.853-1.167 3.178-2.722h2.6c.397 0 .722-.35.722-.778 0-.428-.325-.778-.722-.778h-2.6zM4.694 7.5c0-1.09.795-1.944 1.806-1.944 1.01 0 1.806.855 1.806 1.944 0 1.09-.795 1.944-1.806 1.944-1.01 0-1.806-.855-1.806-1.944z"/></svg>';
})(window.gl || (window.gl = {}));
/* eslint-disable no-param-reassign */
((global) => {
global.cycleAnalytics = global.cycleAnalytics || {};
global.cycleAnalytics.svgs = global.cycleAnalytics.svgs || {};
global.cycleAnalytics.svgs.iconBuildStatus = '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14"><g fill="#31AF64" fill-rule="evenodd"><path d="M12.5 7c0-3.038-2.462-5.5-5.5-5.5S1.5 3.962 1.5 7s2.462 5.5 5.5 5.5 5.5-2.462 5.5-5.5zM0 7c0-3.866 3.134-7 7-7s7 3.134 7 7-3.134 7-7 7-7-3.134-7-7z"/><path d="M6.28 7.697L5.045 6.464c-.117-.117-.305-.117-.42-.002l-.614.614c-.11.113-.11.303.007.42l1.91 1.91c.19.19.51.197.703.004l.264-.265L9.997 6.04c.108-.107.107-.293-.01-.408l-.612-.614c-.114-.113-.298-.12-.41-.01L6.28 7.7z"/></g></svg>';
})(window.gl || (window.gl = {}));
/* eslint-disable no-param-reassign */
((global) => {
global.cycleAnalytics = global.cycleAnalytics || {};
global.cycleAnalytics.svgs = global.cycleAnalytics.svgs || {};
global.cycleAnalytics.svgs.iconCommit = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40"><path fill="#8F8F8F" fill-rule="evenodd" d="M28.777 18c-.91-4.008-4.494-7-8.777-7-4.283 0-7.868 2.992-8.777 7H4.01C2.9 18 2 18.895 2 20c0 1.112.9 2 2.01 2h7.213c.91 4.008 4.494 7 8.777 7 4.283 0 7.868-2.992 8.777-7h7.214C37.1 22 38 21.105 38 20c0-1.112-.9-2-2.01-2h-7.213zM20 25c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5z"/></svg>';
})(window.gl || (window.gl = {}));
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, max-len, one-var, camelcase, one-var-declaration-per-line, no-unused-vars, no-unused-expressions, no-sequences, object-shorthand, comma-dangle, prefer-arrow-callback, semi, radix, padded-blocks, max-len */
(function() {
this.Diff = (function() {
var UNFOLD_COUNT;
......
......@@ -110,10 +110,10 @@
Issuable.init();
break;
case 'dashboard:activity':
new Activities();
new gl.Activities();
break;
case 'dashboard:projects:starred':
new Activities();
new gl.Activities();
break;
case 'projects:commit:show':
new Commit();
......@@ -139,7 +139,7 @@
new gl.Pipelines();
break;
case 'groups:activity':
new Activities();
new gl.Activities();
break;
case 'groups:show':
shortcut_handler = new ShortcutsNavigation();
......@@ -208,9 +208,6 @@
new gl.ProtectedBranchCreate();
new gl.ProtectedBranchEditList();
break;
case 'projects:cycle_analytics:show':
new gl.CycleAnalytics();
break;
}
switch (path.first()) {
case 'admin':
......
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren, wrap-iife, max-len, one-var, no-var, one-var-declaration-per-line, no-unused-vars, camelcase, no-undef, quotes, no-useless-concat, prefer-template, quote-props, comma-dangle, object-shorthand, consistent-return, no-plusplus, prefer-arrow-callback, padded-blocks, max-len */
/*= require preview_markdown */
......
//= require vue
//= require vue-resource
//= require_tree ../services/
//= require ./environment_item
/* globals Vue, EnvironmentsService */
/* eslint-disable no-param-reassign */
(() => { // eslint-disable-line
window.gl = window.gl || {};
/**
* Given the visibility prop provided by the url query parameter and which
* changes according to the active tab we need to filter which environments
* should be visible.
*
* The environments array is a recursive tree structure and we need to filter
* both root level environments and children environments.
*
* In order to acomplish that, both `filterState` and `filterEnvironmnetsByState`
* functions work together.
* The first one works as the filter that verifies if the given environment matches
* the given state.
* The second guarantees both root level and children elements are filtered as well.
*/
const filterState = state => environment => environment.state === state && environment;
/**
* Given the filter function and the array of environments will return only
* the environments that match the state provided to the filter function.
*
* @param {Function} fn
* @param {Array} array
* @return {Array}
*/
const filterEnvironmnetsByState = (fn, arr) => arr.map((item) => {
if (item.children) {
const filteredChildren = filterEnvironmnetsByState(fn, item.children).filter(Boolean);
if (filteredChildren.length) {
item.children = filteredChildren;
return item;
}
}
return fn(item);
}).filter(Boolean);
window.gl.environmentsList.EnvironmentsComponent = Vue.component('environment-component', {
props: {
store: {
type: Object,
required: true,
default: () => ({}),
},
},
components: {
'environment-item': window.gl.environmentsList.EnvironmentItem,
},
data() {
const environmentsData = document.querySelector('#environments-list-view').dataset;
return {
state: this.store.state,
visibility: 'available',
isLoading: false,
cssContainerClass: environmentsData.cssClass,
endpoint: environmentsData.environmentsDataEndpoint,
canCreateDeployment: environmentsData.canCreateDeployment,
canReadEnvironment: environmentsData.canReadEnvironment,
canCreateEnvironment: environmentsData.canCreateEnvironment,
projectEnvironmentsPath: environmentsData.projectEnvironmentsPath,
projectStoppedEnvironmentsPath: environmentsData.projectStoppedEnvironmentsPath,
newEnvironmentPath: environmentsData.newEnvironmentPath,
helpPagePath: environmentsData.helpPagePath,
};
},
computed: {
filteredEnvironments() {
return filterEnvironmnetsByState(filterState(this.visibility), this.state.environments);
},
scope() {
return this.$options.getQueryParameter('scope');
},
canReadEnvironmentParsed() {
return this.$options.convertPermissionToBoolean(this.canReadEnvironment);
},
canCreateDeploymentParsed() {
return this.$options.convertPermissionToBoolean(this.canCreateDeployment);
},
canCreateEnvironmentParsed() {
return this.$options.convertPermissionToBoolean(this.canCreateEnvironment);
},
},
/**
* Fetches all the environmnets and stores them.
* Toggles loading property.
*/
created() {
gl.environmentsService = new EnvironmentsService(this.endpoint);
const scope = this.$options.getQueryParameter('scope');
if (scope) {
this.visibility = scope;
}
this.isLoading = true;
return gl.environmentsService.all()
.then(resp => resp.json())
.then((json) => {
this.store.storeEnvironments(json);
this.isLoading = false;
});
},
/**
* Transforms the url parameter into an object and
* returns the one requested.
*
* @param {String} param
* @returns {String} The value of the requested parameter.
*/
getQueryParameter(parameter) {
return window.location.search.substring(1).split('&').reduce((acc, param) => {
const paramSplited = param.split('=');
acc[paramSplited[0]] = paramSplited[1];
return acc;
}, {})[parameter];
},
/**
* Converts permission provided as strings to booleans.
* @param {String} string
* @returns {Boolean}
*/
convertPermissionToBoolean(string) {
return string === 'true';
},
methods: {
toggleRow(model) {
return this.store.toggleFolder(model.name);
},
},
template: `
<div :class="cssContainerClass">
<div class="top-area">
<ul v-if="!isLoading" class="nav-links">
<li v-bind:class="{ 'active': scope === undefined }">
<a :href="projectEnvironmentsPath">
Available
<span class="badge js-available-environments-count">
{{state.availableCounter}}
</span>
</a>
</li>
<li v-bind:class="{ 'active' : scope === 'stopped' }">
<a :href="projectStoppedEnvironmentsPath">
Stopped
<span class="badge js-stopped-environments-count">
{{state.stoppedCounter}}
</span>
</a>
</li>
</ul>
<div v-if="canCreateEnvironmentParsed && !isLoading" class="nav-controls">
<a :href="newEnvironmentPath" class="btn btn-create">
New environment
</a>
</div>
</div>
<div class="environments-container">
<div class="environments-list-loading text-center" v-if="isLoading">
<i class="fa fa-spinner spin"></i>
</div>
<div class="blank-state blank-state-no-icon"
v-if="!isLoading && state.environments.length === 0">
<h2 class="blank-state-title">
You don't have any environments right now.
</h2>
<p class="blank-state-text">
Environments are places where code gets deployed, such as staging or production.
<br />
<a :href="helpPagePath">
Read more about environments
</a>
</p>
<a
v-if="canCreateEnvironmentParsed"
:href="newEnvironmentPath"
class="btn btn-create">
New Environment
</a>
</div>
<div class="table-holder"
v-if="!isLoading && state.environments.length > 0">
<table class="table ci-table environments">
<thead>
<tr>
<th>Environment</th>
<th>Last deployment</th>
<th>Build</th>
<th>Commit</th>
<th></th>
<th class="hidden-xs"></th>
</tr>
</thead>
<tbody>
<template v-for="model in filteredEnvironments"
v-bind:model="model">
<tr
is="environment-item"
:model="model"
:toggleRow="toggleRow.bind(model)"
:can-create-deployment="canCreateDeploymentParsed"
:can-read-environment="canReadEnvironmentParsed"></tr>
<tr v-if="model.isOpen && model.children && model.children.length > 0"
is="environment-item"
v-for="children in model.children"
:model="children"
:toggleRow="toggleRow.bind(children)"
:can-create-deployment="canCreateDeploymentParsed"
:can-read-environment="canReadEnvironmentParsed">
</tr>
</template>
</tbody>
</table>
</div>
</div>
</div>
`,
});
})();
/*= require vue */
/* global Vue */
(() => {
window.gl = window.gl || {};
window.gl.environmentsList = window.gl.environmentsList || {};
window.gl.environmentsList.ActionsComponent = Vue.component('actions-component', {
props: {
actions: {
type: Array,
required: false,
default: () => [],
},
},
/**
* Appends the svg icon that were render in the index page.
* In order to reuse the svg instead of copy and paste in this template
* we need to render it outside this component using =custom_icon partial.
*
* TODO: Remove this when webpack is merged.
*
*/
mounted() {
const playIcon = document.querySelector('.play-icon-svg.hidden svg');
const dropdownContainer = this.$el.querySelector('.dropdown-play-icon-container');
const actionContainers = this.$el.querySelectorAll('.action-play-icon-container');
// Phantomjs does not have support to iterate a nodelist.
const actionsArray = [].slice.call(actionContainers);
if (playIcon && actionsArray && dropdownContainer) {
dropdownContainer.appendChild(playIcon.cloneNode(true));
actionsArray.forEach((element) => {
element.appendChild(playIcon.cloneNode(true));
});
}
},
template: `
<div class="inline">
<div class="dropdown">
<a class="dropdown-new btn btn-default" data-toggle="dropdown">
<span class="dropdown-play-icon-container"></span>
<i class="fa fa-caret-down"></i>
</a>
<ul class="dropdown-menu dropdown-menu-align-right">
<li v-for="action in actions">
<a :href="action.play_path"
data-method="post"
rel="nofollow"
class="js-manual-action-link">
<span class="action-play-icon-container"></span>
<span>
{{action.name}}
</span>
</a>
</li>
</ul>
</div>
</div>
`,
});
})();
/*= require vue */
/* global Vue */
(() => {
window.gl = window.gl || {};
window.gl.environmentsList = window.gl.environmentsList || {};
window.gl.environmentsList.ExternalUrlComponent = Vue.component('external-url-component', {
props: {
external_url: {
type: String,
default: '',
},
},
template: `
<a class="btn external_url" :href="external_url" target="_blank">
<i class="fa fa-external-link"></i>
</a>
`,
});
})();
/*= require vue */
/* global Vue */
(() => {
window.gl = window.gl || {};
window.gl.environmentsList = window.gl.environmentsList || {};
window.gl.environmentsList.RollbackComponent = Vue.component('rollback-component', {
props: {
retry_url: {
type: String,
default: '',
},
is_last_deployment: {
type: Boolean,
default: true,
},
},
template: `
<a class="btn" :href="retry_url" data-method="post" rel="nofollow">
<span v-if="is_last_deployment">
Re-deploy
</span>
<span v-else>
Rollback
</span>
</a>
`,
});
})();
/*= require vue */
/* global Vue */
(() => {
window.gl = window.gl || {};
window.gl.environmentsList = window.gl.environmentsList || {};
window.gl.environmentsList.StopComponent = Vue.component('stop-component', {
props: {
stop_url: {
type: String,
default: '',
},
},
template: `
<a class="btn stop-env-link"
:href="stop_url"
data-confirm="Are you sure you want to stop this environment?"
data-method="post"
rel="nofollow">
<i class="fa fa-stop stop-env-icon"></i>
</a>
`,
});
})();
//= require vue
//= require_tree ./stores/
//= require ./components/environment
//= require ./vue_resource_interceptor
$(() => {
window.gl = window.gl || {};
if (window.gl.EnvironmentsListApp) {
window.gl.EnvironmentsListApp.$destroy(true);
}
const Store = window.gl.environmentsList.EnvironmentsStore;
window.gl.EnvironmentsListApp = new window.gl.environmentsList.EnvironmentsComponent({
el: document.querySelector('#environments-list-view'),
propsData: {
store: Store.create(),
},
});
});
/* globals Vue */
/* eslint-disable no-unused-vars, no-param-reassign */
class EnvironmentsService {
constructor(root) {
Vue.http.options.root = root;
this.environments = Vue.resource(root);
Vue.http.interceptors.push((request, next) => {
// needed in order to not break the tests.
if ($.rails) {
request.headers['X-CSRF-Token'] = $.rails.csrfToken();
}
next();
});
}
all() {
return this.environments.get();
}
}
/* eslint-disable no-param-reassign */
(() => {
window.gl = window.gl || {};
window.gl.environmentsList = window.gl.environmentsList || {};
gl.environmentsList.EnvironmentsStore = {
state: {},
create() {
this.state.environments = [];
this.state.stoppedCounter = 0;
this.state.availableCounter = 0;
return this;
},
/**
* In order to display a tree view we need to modify the received
* data in to a tree structure based on `environment_type`
* sorted alphabetically.
* In each children a `vue-` property will be added. This property will be
* used to know if an item is a children mostly for css purposes. This is
* needed because the children row is a fragment instance and therfore does
* not accept non-prop attributes.
*
*
* @example
* it will transform this:
* [
* { name: "environment", environment_type: "review" },
* { name: "environment_1", environment_type: null }
* { name: "environment_2, environment_type: "review" }
* ]
* into this:
* [
* { name: "review", children:
* [
* { name: "environment", environment_type: "review", vue-isChildren: true},
* { name: "environment_2", environment_type: "review", vue-isChildren: true}
* ]
* },
* {name: "environment_1", environment_type: null}
* ]
*
*
* @param {Array} environments List of environments.
* @returns {Array} Tree structured array with the received environments.
*/
storeEnvironments(environments = []) {
this.state.stoppedCounter = this.countByState(environments, 'stopped');
this.state.availableCounter = this.countByState(environments, 'available');
const environmentsTree = environments.reduce((acc, environment) => {
if (environment.environment_type !== null) {
const occurs = acc.filter(element => element.children &&
element.name === environment.environment_type);
environment['vue-isChildren'] = true;
if (occurs.length) {
acc[acc.indexOf(occurs[0])].children.push(environment);
acc[acc.indexOf(occurs[0])].children.sort(this.sortByName);
} else {
acc.push({
name: environment.environment_type,
children: [environment],
isOpen: false,
'vue-isChildren': environment['vue-isChildren'],
});
}
} else {
acc.push(environment);
}
return acc;
}, []).sort(this.sortByName);
this.state.environments = environmentsTree;
return environmentsTree;
},
/**
* Toggles folder open property given the environment type.
*
* @param {String} envType
* @return {Array}
*/
toggleFolder(envType) {
const environments = this.state.environments;
const environmentsCopy = environments.map((env) => {
if (env['vue-isChildren'] && env.name === envType) {
env.isOpen = !env.isOpen;
}
return env;
});
this.state.environments = environmentsCopy;
return environmentsCopy;
},
/**
* Given an array of environments, returns the number of environments
* that have the given state.
*
* @param {Array} environments
* @param {String} state
* @returns {Number}
*/
countByState(environments, state) {
return environments.filter(env => env.state === state).length;
},
/**
* Sorts the two objects provided by their name.
*
* @param {Object} a
* @param {Object} b
* @returns {Number}
*/
sortByName(a, b) {
const nameA = a.name.toUpperCase();
const nameB = b.name.toUpperCase();
return nameA < nameB ? -1 : nameA > nameB ? 1 : 0; // eslint-disable-line
},
};
})();
/* global Vue */
Vue.http.interceptors.push((request, next) => {
Vue.activeResources = Vue.activeResources ? Vue.activeResources + 1 : 1;
next((response) => {
if (typeof response.data === 'string') {
response.data = JSON.parse(response.data); // eslint-disable-line
}
Vue.activeResources--; // eslint-disable-line
});
});
/* eslint-disable */
/* eslint-disable no-extend-native, func-names, space-before-function-paren, semi, space-infix-ops, max-len */
Array.prototype.first = function() {
return this[0];
}
......
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren, object-shorthand, comma-dangle, padded-blocks, max-len */
// Disable an element and add the 'disabled' Bootstrap class
(function() {
$.fn.extend({
......
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren, no-var, space-before-blocks, 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, padded-blocks, consistent-return, no-undef, max-len */
(function() {
var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
......
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, one-var, one-var-declaration-per-line, no-param-reassign, quotes, quote-props, prefer-template, comma-dangle, padded-blocks, max-len */
(function() {
this.Flash = (function() {
var hideFlash;
......
......@@ -16,7 +16,7 @@
},
// Team Members
Members: {
template: '<li>${username} <small>${title}</small></li>'
template: '<li>${avatarTag} ${username} <small>${title}</small></li>'
},
Labels: {
template: '<li><span class="dropdown-label-box" style="background: ${color}"></span> ${title}</li>'
......@@ -35,7 +35,7 @@
DefaultOptions: {
sorter: function(query, items, searchKey) {
// Highlight first item only if at least one char was typed
this.setting.highlightFirst = query.length > 0;
this.setting.highlightFirst = this.setting.alwaysHighlightFirst || query.length > 0;
if ((items[0].name != null) && items[0].name === 'loading') {
return items;
}
......@@ -112,13 +112,14 @@
insertTpl: '${atwho-at}${username}',
searchKey: 'search',
data: ['loading'],
alwaysHighlightFirst: true,
callbacks: {
sorter: this.DefaultOptions.sorter,
filter: this.DefaultOptions.filter,
beforeInsert: this.DefaultOptions.beforeInsert,
beforeSave: function(members) {
return $.map(members, function(m) {
var title;
let title = '';
if (m.username == null) {
return m;
}
......@@ -126,8 +127,14 @@
if (m.count) {
title += " (" + m.count + ")";
}
const autoCompleteAvatar = m.avatar_url || m.username.charAt(0).toUpperCase();
const imgAvatar = `<img src="${m.avatar_url}" alt="${m.username}" class="avatar avatar-inline center s26"/>`;
const txtAvatar = `<div class="avatar center avatar-inline s26">${autoCompleteAvatar}</div>`;
return {
username: m.username,
avatarTag: autoCompleteAvatar.length === 1 ? txtAvatar : imgAvatar,
title: gl.utils.sanitize(title),
search: gl.utils.sanitize(m.username + " " + m.name)
};
......
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren, no-var, one-var, one-var-declaration-per-line, space-before-blocks, prefer-rest-params, max-len, vars-on-top, no-plusplus, wrap-iife, no-unused-vars, quotes, no-shadow, no-cond-assign, prefer-arrow-callback, semi, no-return-assign, no-else-return, camelcase, no-undef, comma-dangle, no-lonely-if, guard-for-in, no-restricted-syntax, consistent-return, padded-blocks, prefer-template, no-param-reassign, no-loop-func, no-extra-semi, keyword-spacing, no-mixed-operators, max-len */
(function() {
var GitLabDropdown, GitLabDropdownFilter, GitLabDropdownRemote,
bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
......@@ -249,7 +249,7 @@
_this.fullData = data;
_this.parseData(_this.fullData);
_this.focusTextInput();
if (_this.options.filterable && _this.filter && _this.filter.input) {
if (_this.options.filterable && _this.filter && _this.filter.input && _this.filter.input.val().trim() !== '') {
return _this.filter.input.trigger('input');
}
};
......
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, no-undef, no-new, padded-blocks, max-len */
(function() {
this.GLForm = (function() {
function GLForm(form) {
......
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren */
// This is a manifest file that'll be compiled into including all the files listed below.
// Add new JavaScript code in separate files in this directory and they'll automatically
// be included in the compiled file accessible from http://example.com/assets/application.js
......
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-return-assign, padded-blocks, max-len */
(function() {
this.StatGraph = (function() {
function StatGraph() {}
......
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, one-var, camelcase, one-var-declaration-per-line, no-undef, quotes, no-param-reassign, quote-props, comma-dangle, prefer-template, max-len, no-return-assign, padded-blocks, max-len */
/*= require d3 */
......
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren, one-var, no-var, space-before-blocks, 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, padded-blocks, no-undef, newline-per-chained-call, no-else-return, max-len */
/*= require d3 */
......
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren, object-shorthand, no-var, one-var, camelcase, one-var-declaration-per-line, no-plusplus, 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, padded-blocks, max-len */
(function() {
window.ContributorsStatGraphUtil = {
parse_log: function(log) {
......
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren, wrap-iife, quotes, no-var, one-var, one-var-declaration-per-line, no-useless-escape, padded-blocks, max-len */
(function() {
this.GroupAvatar = (function() {
function GroupAvatar() {
......
/* eslint-disable */
(function(global) {
class GroupLabelSubscription {
constructor(container) {
const $container = $(container);
this.$dropdown = $container.find('.dropdown');
this.$subscribeButtons = $container.find('.js-subscribe-button');
this.$unsubscribeButtons = $container.find('.js-unsubscribe-button');
this.$subscribeButtons.on('click', this.subscribe.bind(this));
this.$unsubscribeButtons.on('click', this.unsubscribe.bind(this));
}
unsubscribe(event) {
event.preventDefault();
const url = this.$unsubscribeButtons.attr('data-url');
$.ajax({
type: 'POST',
url: url
}).done(() => {
this.toggleSubscriptionButtons();
this.$unsubscribeButtons.removeAttr('data-url');
});
}
subscribe(event) {
event.preventDefault();
const $btn = $(event.currentTarget);
const url = $btn.attr('data-url');
this.$unsubscribeButtons.attr('data-url', url);
$.ajax({
type: 'POST',
url: url
}).done(() => {
this.toggleSubscriptionButtons();
});
}
toggleSubscriptionButtons() {
this.$dropdown.toggleClass('hidden');
this.$subscribeButtons.toggleClass('hidden');
this.$unsubscribeButtons.toggleClass('hidden');
}
}
global.GroupLabelSubscription = GroupLabelSubscription;
})(window.gl || (window.gl = {}));
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren, no-var, wrap-iife, one-var, camelcase, one-var-declaration-per-line, quotes, object-shorthand, no-undef, prefer-arrow-callback, comma-dangle, consistent-return, yoda, prefer-rest-params, prefer-spread, no-unused-vars, prefer-template, padded-blocks, max-len */
(function() {
var slice = [].slice;
......
/* eslint-disable */
/* eslint-disable wrap-iife, func-names, space-before-function-paren, padded-blocks, prefer-arrow-callback, no-var, max-len */
(function() {
$(document).on('todo:toggle', function(e, count) {
......
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren, wrap-iife, camelcase, no-var, one-var, one-var-declaration-per-line, prefer-template, quotes, object-shorthand, comma-dangle, no-unused-vars, prefer-arrow-callback, no-else-return, padded-blocks, vars-on-top, no-new, no-undef, max-len */
(function() {
this.ImporterStatus = (function() {
function ImporterStatus(jobs_url, import_url) {
......
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-new, no-undef, comma-dangle, quotes, prefer-arrow-callback, consistent-return, one-var, no-var, one-var-declaration-per-line, no-underscore-dangle, padded-blocks, max-len */
(function() {
this.IssuableContext = (function() {
function IssuableContext(currentUser) {
......
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren, no-var, space-before-blocks, prefer-rest-params, wrap-iife, no-use-before-define, no-useless-escape, no-undef, no-new, quotes, object-shorthand, no-unused-vars, comma-dangle, radix, no-alert, consistent-return, no-else-return, prefer-template, one-var, one-var-declaration-per-line, curly, padded-blocks, max-len */
(function() {
var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
......
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren, no-var, space-before-blocks, prefer-rest-params, wrap-iife, one-var, no-underscore-dangle, one-var-declaration-per-line, object-shorthand, no-unused-vars, no-undef, no-new, comma-dangle, consistent-return, quotes, dot-notation, quote-props, prefer-arrow-callback, padded-blocks, max-len */
/*= require flash */
/*= require jquery.waitforimages */
......
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, quotes, object-shorthand, no-unused-vars, no-shadow, one-var, one-var-declaration-per-line, comma-dangle, padded-blocks, max-len */
(function() {
this.IssueStatusSelect = (function() {
function IssueStatusSelect() {
......
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren, no-var, space-before-blocks, prefer-rest-params, wrap-iife, vars-on-top, no-unused-vars, padded-blocks, max-len */
(function() {
var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
......
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, no-underscore-dangle, prefer-arrow-callback, max-len, one-var, no-unused-vars, one-var-declaration-per-line, prefer-template, no-new, consistent-return, object-shorthand, comma-dangle, no-shadow, no-param-reassign, brace-style, vars-on-top, quotes, no-lonely-if, no-else-return, no-undef, semi, dot-notation, no-empty, no-return-assign, camelcase, prefer-spread, padded-blocks, max-len */
(function() {
this.LabelsSelect = (function() {
function LabelsSelect() {
......
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren, no-var, prefer-arrow-callback, no-unused-vars, one-var, one-var-declaration-per-line, indent, vars-on-top, padded-blocks, max-len */
(function() {
var hideEndFade;
......
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren */
/*= require Chart */
......
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren */
/*= require cropper */
......
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren */
/*= require d3 */
......
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren */
/*= require raphael */
/*= require g.raphael */
......
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-param-reassign, no-void, prefer-template, no-var, new-cap, prefer-arrow-callback, consistent-return, padded-blocks, max-len */
(function() {
(function(w) {
if (w.gl == null) {
......
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, no-unused-expressions, no-param-reassign, no-else-return, quotes, object-shorthand, comma-dangle, camelcase, one-var, vars-on-top, one-var-declaration-per-line, no-return-assign, consistent-return, padded-blocks, max-len */
(function() {
(function(w) {
var base;
......@@ -125,6 +125,11 @@
// Close any open tooltips
$('.has-tooltip, [data-toggle="tooltip"]').tooltip('destroy');
};
gl.utils.isMetaKey = function(e) {
return e.metaKey || e.ctrlKey || e.altKey || e.shiftKey;
};
})(window);
}).call(this);
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, no-param-reassign, no-cond-assign, no-undef, comma-dangle, no-unused-expressions, prefer-template, padded-blocks, max-len */
(function() {
(function(w) {
var base;
......
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, one-var, one-var-declaration-per-line, consistent-return, no-undef, prefer-arrow-callback, no-return-assign, object-shorthand, comma-dangle, no-param-reassign, padded-blocks, max-len */
(function() {
(function(w) {
var notificationGranted, notifyMe, notifyPermissions;
......
(() => {
/*
* TODO: Make these methods more configurable (e.g. parseSeconds timePeriodContstraints,
* stringifyTime condensed or non-condensed, abbreviateTimelengths)
* */
class PrettyTime {
/*
* Accepts seconds and returns a timeObject { weeks: #, days: #, hours: #, minutes: # }
* Seconds can be negative or positive, zero or non-zero.
*/
static parseSeconds(seconds) {
const DAYS_PER_WEEK = 5;
const HOURS_PER_DAY = 8;
const MINUTES_PER_HOUR = 60;
const MINUTES_PER_WEEK = DAYS_PER_WEEK * HOURS_PER_DAY * MINUTES_PER_HOUR;
const MINUTES_PER_DAY = HOURS_PER_DAY * MINUTES_PER_HOUR;
const timePeriodConstraints = {
weeks: MINUTES_PER_WEEK,
days: MINUTES_PER_DAY,
hours: MINUTES_PER_HOUR,
minutes: 1,
};
let unorderedMinutes = PrettyTime.secondsToMinutes(seconds);
return _.mapObject(timePeriodConstraints, (minutesPerPeriod) => {
const periodCount = Math.floor(unorderedMinutes / minutesPerPeriod);
unorderedMinutes -= (periodCount * minutesPerPeriod);
return periodCount;
});
}
/*
* Accepts a timeObject and returns a condensed string representation of it
* (e.g. '1w 2d 3h 1m' or '1h 30m'). Zero value units are not included.
*/
static stringifyTime(timeObject) {
const reducedTime = _.reduce(timeObject, (memo, unitValue, unitName) => {
const isNonZero = !!unitValue;
return isNonZero ? `${memo} ${unitValue}${unitName.charAt(0)}` : memo;
}, '').trim();
return reducedTime.length ? reducedTime : '0m';
}
/*
* Accepts a time string of any size (e.g. '1w 2d 3h 5m' or '1w 2d') and returns
* the first non-zero unit/value pair.
*/
static abbreviateTime(timeStr) {
return timeStr.split(' ')
.filter(unitStr => unitStr.charAt(0) !== '0')[0];
}
static secondsToMinutes(seconds) {
return Math.abs(seconds / 60);
}
}
gl.PrettyTime = PrettyTime;
})(window.gl || (window.gl = {}));
/* eslint-disable */
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, no-param-reassign, no-cond-assign, quotes, semi, one-var, one-var-declaration-per-line, operator-assignment, no-else-return, prefer-template, prefer-arrow-callback, no-empty, max-len, consistent-return, no-unused-vars, no-return-assign, padded-blocks, max-len */
(function() {
(function(w) {
var base;
......@@ -112,6 +112,9 @@
gl.text.removeListeners = function(form) {
return $('.js-md', form).off();
};
gl.text.humanize = function(string) {
return string.charAt(0).toUpperCase() + string.replace(/_/g, ' ').slice(1);
}
return gl.text.truncate = function(string, maxLength) {
return string.substr(0, (maxLength - 3)) + '...';
};
......
/* eslint-disable no-unused-expressions, wrap-iife, func-names, curly, no-param-reassign, no-trailing-spaces, prefer-arrow-callback, no-var, one-var, quote-props, space-before-function-paren, vars-on-top, radix, prefer-template, space-infix-ops, no-use-before-define, newline-per-chained-call, no-useless-escape, no-nested-ternary, indent, no-undef, no-plusplus, one-var-declaration-per-line, operator-assignment, consistent-return, keyword-spacing, max-len, space-unary-ops, no-shadow, no-restricted-syntax, guard-for-in, eol-last, max-len */
/**
* Copyright (c) 2016 hustcc
* License: MIT
......
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.
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.
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